Files
iptvnator/.changes
4grayandClaude Fable 5 ae923c6a83 chore(deps): coordinated security sweep for open Dependabot alerts
Closes all 69 open Dependabot alerts with one coordinated update instead
of per-alert bot branches.

Runtime scope (ships in the packaged Electron app):
- js-yaml override 4.3.0 -> 4.3.1 (quadratic CPU DoS in !!omap, via
  electron-updater; second selector added for the new ^4.3.0 declarers).
  The dev-only js-yaml@3.15.1 copy is outside the advisory range
  (>=4.0.0 <4.3.1) and has no 3.x backport, so it stays.
- fast-uri override 3.1.4 -> 3.1.6 (CVE-2026-18446 host confusion, via
  electron-conf -> ajv).

Dev scope:
- astro 5.18.1 -> 7.2.4 (+@astrojs/mdx 7.0.7); the deprecated
  @astrojs/tailwind integration only supports Astro <= 5, so Tailwind v3
  now runs through apps/website/postcss.config.mjs (+autoprefixer).
  Astro 7's prerender entry externalizes cookie/html-escaper/mrmime/zod,
  which pnpm's strict layout cannot resolve from the emitted chunk
  location - declared as root devDependencies at astro's own versions.
  Astro's transitive vite 6.x/esbuild 0.27/sharp 0.34 copies leave the
  tree with it; the patched root vite@7.3.6 pin is untouched.
- hono -> 4.12.34, @hono/node-server -> 1.19.17, undici 7.x -> 7.29.0,
  postcss 8.5.6 -> 8.5.26, immutable -> 5.1.9, svgo 4.0.0 -> 4.0.2,
  serialize-javascript 6.0.2 -> 7.1.0, minimatch 3.1.2 -> 3.1.5,
  ip-address -> 10.5.0, qs -> 6.15.3, picomatch 4.0.3 -> 4.0.5,
  uuid 8.3.2 -> 11.1.1, brace-expansion 1.x -> 1.1.18, ws (jsdom) ->
  8.21.3, esbuild (drizzle-kit's @esbuild-kit loader) -> 0.25.12.

eslint now ignores generated **/.astro output, which Astro 7 emits with
patterns the flat config rejects.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 09:01:14 +02:00
..

Release notes (.changes/)

Every PR with a user-visible change drops one file here describing that change in plain language. At release time tools/release/build-release-notes.mjs turns the accumulated files into the GitHub release body, the CHANGELOG.md section, and a blog-post scaffold for the website — then deletes them.

The point is to write the note while the context is still fresh, instead of reconstructing three months of work from commit titles at release time.

File

Name it <area>-<short-slug>.md, e.g. .changes/playback-up-next-rail.md.

---
type: feature
area: playback
issues: [1187]
screenshot: up-next-rail
---

Series now show an "Up Next" rail beside the player on wide windows: the rest
of the current season, watch progress, and click-to-play inline.
Field Required Value
type yes breaking, feature, fix, perf, or internal
area yes lowercase slug, same as the conventional-commit scope
issues no issue numbers this closes — [1187] or 1187
screenshot no slug from tools/release/screenshots.manifest.json

There is no version field. The release version is chosen deliberately at release time, not derived from these files.

You never write a PR number: the generator resolves it from the commit that added the file.

Writing the body

One to three sentences, present tense, written for a user, not a reviewer. The body is capped at 400 characters — depth belongs in the blog post.

  • ❌ "Refactor WebVideoControlsAdapter to hoist volume state into the session"

  • ✅ "The player now remembers volume between episodes"

  • ❌ "Fix off-by-one in resolveEnrichmentSeasonNumber"

  • ✅ "Series whose title carries a season marker no longer show the wrong season"

type: internal records invisible maintenance. Internal notes stay collapsed in CHANGELOG.md, are omitted from the blog scaffold, and are removed from the authored public GitHub body by extract-changelog-section.mjs --public. GitHub's generated commit list remains separate. An internal-only release can therefore have an empty authored body.

When a note is not needed

The gate auto-exempts website, E2E and mock-server apps, *.spec.{js,ts}, *.e2e.{js,ts}, snapshots, any /testing/ path, and Markdown. For other test-only, documentation, CI/workflow, or pure-refactor changes under apps//libs/, apply no-release-note when no user-visible note is warranted.

Commands

pnpm run release:notes:validate
pnpm run release:notes:github
pnpm run release:notes:changelog
pnpm run release:notes:blog
node tools/release/build-release-notes.mjs --consume

The release version comes from the root package.json — bump it first, then generate. --version 0.24.0 overrides it to preview a release before the bump:

pnpm run release:notes:github --version 0.24.0

A bare -- separator is accepted and ignored, so the npm habit of pnpm run release:notes:github -- --version 0.24.0 works too: pnpm forwards that separator to the script rather than consuming it the way npm does.

--validate and --format github only read and print. --format changelog and --format blog write their target file (rerunning changelog for the same version replaces that section rather than duplicating it). Only --consume deletes anything.

The release sequence is: bump the version → release:notes:changelog → release:notes:blog → --consume → commit → tag → push. The tag build then extracts the new CHANGELOG.md section into the GitHub release body (tools/release/extract-changelog-section.mjs) and fails the release if the section is missing — a tag cut without the changelog step cannot silently ship PR-title-only notes.

The website publishes one post per minor version (v0-18 … v0-22), and release screenshots live under the matching blog/v0-24/ directory. A patch release therefore edits the existing post rather than generating a new one, so --format blog refuses to overwrite unless you pass --force.

Screenshots

pnpm run release:screenshots captures every manifest shot in dark and light against the built app plus the Xtream mock server — never a real account. The run is fail-closed: it proves the real ~/.iptvnator/databases directory (including the SQLite WAL sidecars, checked after Electron exits) was not touched, launches the app with an allowlisted environment, records and blocks all non-localhost traffic, scans every frame for external resources and credential-shaped text, and asserts TMDB enrichment stays disabled. Frames are staged outside the repository and published only once every shot and every guard has passed.

Adding a shot for a new feature = one entry in tools/release/screenshots.manifest.json (plus, if navigation is new, one named action in tools/release/capture-navigation.ts).

pnpm nx run electron-backend:build-e2e   # once, before capturing
pnpm run release:screenshots             # all shots, both themes
pnpm run release:screenshots -- --only dashboard --theme dark
pnpm run release:screenshots -- --release v0-24