Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit b0f8d2b65d196f89dbff133c639c811bb68b0812
parent 46c1b05cb44875d4d6ff68f5fc0dbc74770df92e
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Sat, 12 Sep 2026 02:58:38 -0400

common, export: one shipsPwa(), and the comment about it is now true

The predicate "does this build ship an installable PWA" existed twice —
compose-site.ts and export/app/lib/mode.ts — each carrying a "keep in sync
with the other" comment, which is the shape of a bug that has not happened
yet. S1 put the one copy in lib/archive/contract.ts; this deletes both.

export/app/lib/mode.ts loses its hub short-circuit with it. It was true
twice over: currentSite() in hub mode returns hubSite(), which sets
`pwa: true`, and the contract predicate reads INSTANCE_MODE itself. Same
answer in both modes, one call.

The kept caller stays SERVER-side, deliberately. contract.ts's own comment
claimed Next inlines `process.env.INSTANCE_MODE` into the client bundle and
that a `typeof process` guard would therefore break hub mode; the S1 review
checked and that is false — INSTANCE_MODE is neither NEXT_PUBLIC_ nor in a
next.config `env:` block, so a client bundle would read undefined. The bare
read is fine for the real reason: nothing in a browser evaluates it. Its
callers are a build script and a server component (and currentSite() reads
the sites dir, so mode.ts could not be client-side anyway). The comment now
says that, and says what a future client caller would owe.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Mcommon/bin/compose-site.ts | 8+-------
Mcommon/lib/archive/contract.ts | 16++++++++++++----
Mexport/app/lib/mode.ts | 31++++++++++++++++++++-----------
3 files changed, 33 insertions(+), 22 deletions(-)

diff --git a/common/bin/compose-site.ts b/common/bin/compose-site.ts @@ -32,6 +32,7 @@ import type { Manifest, SubsManifest } from "../lib/manifest"; import type { PostsManifest } from "../lib/posts"; import type { DigestsManifest } from "../lib/digests"; import { buildSiteDescriptor, type PublicSiteDescriptor } from "../lib/siteDescriptor"; +import { shipsPwa } from "../lib/archive/contract"; import { effectiveSiteAliases } from "../lib/aliasesStore"; import { buildSiteCorpus, @@ -201,13 +202,6 @@ async function emitAiFiles(paths: ReturnType<typeof getPaths>): Promise<void> { } } -// Whether this build ships an installable PWA. Resolved from the site's `pwa` -// config flag (site builds are dumb instances by default) or forced on in hub -// mode. Keep in sync with export/app/lib/mode.ts shipsPwa(). -function shipsPwa(site: Site): boolean { - return site.pwa === true || process.env.INSTANCE_MODE === "hub"; -} - // Compose the service worker into the served public dir ONLY when this instance // ships a PWA. The SW source lives outside public/ (export/service-worker/) so // a dumb instance emits no /sw.js at all — not just an unregistered one. Mirrors diff --git a/common/lib/archive/contract.ts b/common/lib/archive/contract.ts @@ -143,10 +143,18 @@ export function pageUrl( // installable) and opts in per site via the `pwa` config flag. // // Was two copies with "keep in sync" comments on each (compose-site.ts and -// export/app/lib/mode.ts); this is the one. `process.env.INSTANCE_MODE` is read -// here exactly as both copies read it — Next inlines that member expression -// into the client bundle at build time, so a `typeof process` guard around it -// would turn hub mode OFF in the browser rather than make it safer. +// export/app/lib/mode.ts); S2c deleted both, and this is the one. +// +// `process.env.INSTANCE_MODE` is read bare, exactly as both copies read it, and +// the reason that is safe is NOT that Next inlines it — it does not: +// INSTANCE_MODE is neither `NEXT_PUBLIC_` nor listed in a next.config `env:` +// block, so a client bundle would read `undefined` here. (An earlier draft of +// this comment claimed the opposite; the S1 review checked.) It is safe because +// no browser evaluates it: the only caller in the export app is +// export/app/lib/mode.ts, whose only caller is export/app/layout.tsx, a SERVER +// component, and the other caller is compose-site.ts, a build script. If this +// ever becomes reachable from a client module it needs a +// `typeof process !== "undefined"` guard AND an env var the client can see. export function shipsPwa(site: { pwa?: boolean }): boolean { return site.pwa === true || process.env.INSTANCE_MODE === "hub"; } diff --git a/export/app/lib/mode.ts b/export/app/lib/mode.ts @@ -1,4 +1,5 @@ import { currentSite } from "./site"; +import { shipsPwa as contractShipsPwa } from "yt-dlp-transcript-common/lib/archive/contract"; // The export app renders one of two shells, selected at build time: // site (default): a single-site archive, exactly as before. @@ -13,17 +14,25 @@ export function instanceMode(): InstanceMode { } // Whether this build ships an installable PWA — the "dangerous permissions" -// surface: a service worker, a web manifest, and installability. This is an -// axis INDEPENDENT of the shell: -// - hub mode always ships the PWA (Archilyzer IS the installable app); -// - site mode is a dumb instance by default (federatable JSON only, not -// installable) and opts in per site via the `pwa` config flag. +// surface: a service worker, a web manifest, and installability. See +// lib/archive/contract.ts shipsPwa() for what the axis means; this wrapper only +// supplies the site, which the export app resolves at build/render time. // -// Resolved purely from config that is already available at build/render time -// (INSTANCE_MODE env + the selected site's `pwa`), so the app shell and the -// compose step agree without threading an extra env var. Keep this in sync with -// compose-site.ts's shipsPwa(). +// Was a second copy of the predicate with a "keep in sync" comment pointing at +// compose-site.ts's copy. Both are gone; there is one. +// +// Hub mode needs no branch of its own any more: currentSite() already returns +// hubSite(), which sets `pwa: true` (export/app/lib/site.ts), and the contract +// predicate reads INSTANCE_MODE itself — so the old +// `if (instanceMode() === "hub") return true` short-circuit was true twice over. +// +// SERVER-ONLY, deliberately: the contract predicate reads +// `process.env.INSTANCE_MODE`, which is not a `NEXT_PUBLIC_` var and is not in a +// next.config `env:` block, so Next does NOT inline it into a client bundle. +// The only caller is export/app/layout.tsx, a server component — and +// currentSite() is server-only regardless, since it reads the sites dir. +// Calling this from a client component would read `undefined` and silently turn +// hub mode off; that would need a guard there, not an assumption here. export function shipsPwa(): boolean { - if (instanceMode() === "hub") return true; - return currentSite().pwa === true; + return contractShipsPwa(currentSite()); }