Code loaded at print time executes on partner pages, so it is pinned like every embed. The bundle carries the generator's sha384 (library/packet/poster-render.integrity.js, written by `bun run pin:poster-render`); posterSheets fetches <assets>/lib/poster-render.js as TEXT, hashes it with WebCrypto, and on a match imports the verified text from a blob: URL — never the network URL a second time. A mismatch refuses to run, with a message naming the URL and both hashes; the print falls back to what it can do without the generator. The page base is captured when posterSheets evaluates, and every URL it resolves (the generator, the boundaries, the places) resolves against it — not the bundle's location, and not a URL a single-page host changed after load. check:poster-render-pinned (gates:pre), two-sided: the pin equals the sha384 of the source and of the served copy (a stale pin names the command — proven by an unpinned edit); a TAMPERED copy is refused and its planted side effect never runs; the genuine copy loads and draws. check:poster-browser-equiv still passes byte-identical through the pinned path. country-posters 1,472,734 bytes (ceiling 1,500,000), my-upg-100-list 1,232,508, both carrying the pin; verify-bundles-shipped PASS; gates:pre 74/74. |
||
|---|---|---|
| .. | ||
| api | ||
| charts/whiteboard | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| dashboards | ||
| data | ||
| elements | ||
| i18n | ||
| layouts | ||
| lists | ||
| maps | ||
| packet | ||
| packets | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| vendor/cldr | ||
| index.js | ||
| ProfileLoader.vue | ||
| README.md | ||
library/ (@map) — the shared map template
The other half of the architecture (see ../plugin-designs/README.md):
every map in plugin-designs/<your-map>/ composes the reusable, parameterized pieces that live here.
Fix something here and every map benefits on the next build; break something here and every map
breaks — read components/WARNING.md before touching shared pieces.
| Folder | What lives there |
|---|---|
ProfileLoader.vue |
The root of every bundle: parses profile-config, loads the profile, provides the stores + config |
components/ |
Shared UI — map, legends, controls, popup (PeopleGroupDetail), tables, charts, hints (README) |
composables/ |
Shared logic — map engine (useMapInstance), provider switch, shadow-DOM styles, theming |
stores/ |
Per-instance Pinia stores (ui / map / data) — provided by ProfileLoader, injected by children |
api/ |
Data-source registry (sources.json) + fetch layer — the JAMstack runtime wiring |
colors/ |
Color sets maps opt into via profile-config.colorSet |
i18n/ |
The shared string catalogs (all maps speak the same languages) |
data/ |
Small shared datasets baked at build time (big served data lives in ../data/) |
constants/ |
Shared constants |
scripts/ |
Maintainer pipelines (posters, research) — not part of any bundle |
The rule of thumb (same as WARNING.md): custom code in your app-profile, reusable code here — and things only move from the first to the second once they've earned it.