/** * generate-boot — compile the pre-hydration boot into a checked-in artifact. * * The boot writes the preference attributes on `` before first * paint. It must agree, byte for byte of BEHAVIOUR, with what * `createActiveUix` + `ActiveEidos` write after hydration — same * dimensions, same resolver, same attribute names. The only way to * guarantee that is to compile the runtime's own modules into the * snippet instead of writing a second implementation of the cascade by * hand. `src/uix/active-uix/boot/entry.ts` is the entry; * `src/uix/active-uix/generated/boot.js` is the artifact, checked in so * a consumer never needs this script, and guarded by * `src/uix/active-uix/boot/generated-boot.test.ts` so it can never lag * the source. * * **Two constants, not a bundle.** The artifact is an ES module that * exports the exact text that goes INSIDE the tag and the CSP hash of * that text. Two consequences, both load-bearing: * - `render.ts` IMPORTS it, so no build has to find a file on disk * next to a server chunk (`pack.test.ts` is the guard); * - nothing wraps the compiled text by hand any more. The entry is * self-executing and reads its parameters from its own * `data-uix-boot` attribute, so the body is CONSTANT per framework * version and `UIX_BOOT_CSP_HASH` is a constant a site can name in * `svelte.config.js`. "Compiled, not written" now covers the * wrapper too. * * The `.js` extension is deliberate, and the reason is the CONSUMER, not * this repo. `svelte.config.js` imports `UIX_BOOT_CSP_HASH` from here and * is loaded by plain Node, with no bundler in front of it. Measured on * Node 24.9: a `.ts` twin inside the repo imports fine (type stripping is * on by default since 23.6), the same file under `node_modules` throws * `ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING` — which is exactly where * this artifact lands once UIX is a dependency. `.js` is what makes the * recipe portable, and it is what it already was. * * The text guard is NOT here, it is in * `src/uix/active-uix/boot/script-guard.ts`: `render.ts` runs it too, on * the artifact a site hands the `artifact` door, and it could not import * a module that pulls esbuild in behind it. * * esbuild is SCAFFOLDING, not a shipped dependency: nothing at runtime * imports it. Same posture as `generate-eidos-css.ts` and `tsx`. It is * declared in `devDependencies` and pinned EXACT (`0.27.4`, no range) on * purpose: the body is esbuild's minified output and `UIX_BOOT_CSP_HASH` * is a digest of those bytes, so another esbuild version can emit other * bytes from the same source — and an upgrade inside a `^` range would * put the checked-in artifact out of sync with a fresh compile (the sync * test and the staleness guard go red) without a line of source moving. * `node:crypto` is scaffolding too — it computes the hash here and never * ships. * * Aliases come from `uix.aliases.js`, the one table Vite, SvelteKit, * `docs-check.ts` and this compiler all import: the boot resolves every * specifier exactly as the runtime it must agree with does. * * **And it RUNS what it writes.** The text guards are static, and a boot * that throws on line one passes every one of them: measured, this * compiler used to write a dead artifact with exit 0 and a valid hash, * and the page it produced stamped nothing while reporting nothing * (`assertBootRuns`). A compiler whose output does not run is not a * compiler. * * **It is a COMPILER, and the site is a caller.** `--schema ` * builds the boot around the site's own preference schema instead of * UIX's default, and `--out ` writes the site's own artifact. Not a * convenience: a boot compiled around the default schema knows ONE * language, so on a multi-language site it stamps `dir="ltr"` for an * Arabic user and the page paints in the wrong direction until hydration * corrects it (`prefs-schema.ts`, `composeUixPrefsSchema`). Because the * site is the caller, the guards * below are COMPILER ERRORS with messages aimed at whoever wrote the * schema, not assertions about framework code. * * **A schema module must import DEEP modules, never the `$prefs` * barrel.** `$prefs/index.ts` re-exports `createActivePrefs` from a * `.svelte.ts`, so the barrel drags `$state(` into a plain `