#!/usr/bin/env node /** * check-composite-embed-knobs.mjs — a composite must pass the host's TOKEN and PROVIDER down to the * map it nests, on somebody else's page. * * THE DEFECT THIS EXISTS FOR, MEASURED 2026-09-24. Two shipped composites declared NO PROPS at all, * so the `profile-config` a partner writes was read by nobody: * * -> "No Mapbox access token * provided", 0 tiles, no canvas * * and after the token was threaded, the SAME hole was still open one knob over: * * -> child still on mapbox, * so it demanded a token * * Every existing gate missed all of it, and not by accident: they load a composite on its OWN * generated leaf, and that leaf BAKES a token and assigns window.MAP_TOKEN, which the shared-token * bridge hands to the nested map. The leaf supplies the very thing under test. The failure exists * only where there is no leaf — which is exactly the partner page the published embed snippet is * written for, and exactly the case nobody was testing. * * WHY THESE TWO KNOBS AND NOT A LONGER LIST. They are the two the snippet documents and the two the * product promises: `tk` is how a partner supplies their own key, and `provider` is the one prop that * is supposed to swap the engine. A keyless MapLibre embed is the whole reason MapLibre support was * built — partners at volume who do not want a Mapbox key — so a composite that drops `provider` * does not degrade the feature, it cancels it, and reports the loss as a token error. * * HOW. Serves the built tree from a FREE port (ACAO:* via serve-strict, production parity) and the * partner page from `localhost` — a genuinely different origin, so CORS is exercised rather than * assumed. Free ports asked of the OS, never fixed ones: a stray server on a fixed port answers in * place of the tree under test and the gate then passes a build it never loaded. * * ASSERTIONS, per composite that nests a map: * tk — given ONLY {"tk": }, a canvas appears and at least one * api.mapbox.com style/tile request succeeds. No token error in the console. * provider — given ONLY {"provider":"maplibre"} and NO token, a canvas appears and there are * ZERO requests to api.mapbox.com. Zero is the assertion: "it rendered" would pass on * a build that quietly fell back to mapbox with a baked key. * * NEGATIVE-TESTED: reverting either fix in research-map-plus-grid.vue makes the matching case FAIL * naming the composite and the knob; both restored, both pass. Removing the zero-request assertion * from the provider case makes it pass on a build that ignores the prop, which is what it is for. * * Exit: 0 pass or SKIP (no built tree, no browser, no baked token to test with) · 1 fail. */ import { createServer } from 'node:http' import { spawn } from 'node:child_process' import { existsSync, readFileSync } from 'node:fs' import { resolve, dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { TREE_NAME } from './_tree-name.mjs' const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..') const MANIFEST = join(ROOT, 'public', TREE_NAME, 'manifest.json') if (!existsSync(MANIFEST)) { console.log('COMPOSITE-EMBED-KNOBS: SKIP — no built manifest (run `bun run tree` first).') process.exit(0) } let chromium try { ({ chromium } = await import('playwright')) } catch { console.log('COMPOSITE-EMBED-KNOBS: SKIP — playwright is not installed.') process.exit(0) } const manifest = JSON.parse(readFileSync(MANIFEST, 'utf8')) // Which bundles nest a MAP? A composite declares `composes`; a bundle is a map if any of its // profiles is isMap. Asking the manifest keeps this list correct when a composite is added. const mapBundles = new Set() for (const b of manifest.bundles || []) { if ((b.profiles || []).some((p) => p.isMap)) mapBundles.add(b.bundle) } const targets = [] for (const b of manifest.bundles || []) { // TWO WAYS A COMPOSITE DECLARES ITSELF, and taking only the first under-covered this gate. // `composes` is written when a composite mounts children BY TAG; a composite that BAKES its // children in (an imported .vue) lists nothing there, and country-posters-mfe — one of the three // composites this defect was measured on — was silently not a target. The profile TYPE says so in // both cases, so ask for either. const composes = b.composes || [] const byCompose = composes.some((c) => mapBundles.has(c)) const profile = (b.profiles || []).find((p) => p.element && (byCompose || p.type === 'nested-elements-mfe')) if (!profile || !b.scriptUrl) continue targets.push({ bundle: b.bundle, element: profile.element, script: `${b.bundle}/${b.bundle}.js` }) } if (!targets.length) { console.log('COMPOSITE-EMBED-KNOBS: SKIP — the manifest declares no composite that nests a map.') process.exit(0) } // The token to hand the partner page is the one the tree already bakes into its own leaves: this // gate must not invent a key, and a token that is not this tree's would 401 and look like our bug. const bakedToken = (() => { for (const b of manifest.bundles || []) { for (const p of b.profiles || []) { if (!p.isMap || !p.iframeUrl) continue const leaf = join(ROOT, 'public', TREE_NAME, String(p.iframeUrl).replace(/^\.\//, '')) if (!existsSync(leaf)) continue const m = readFileSync(leaf, 'utf8').match(/BAKED_TOKEN\s*=\s*"(pk\.[^"]+)"/) if (m) return m[1] } } return '' })() const freePort = () => new Promise((ok) => { const s = createServer().listen(0, '127.0.0.1', () => { const p = s.address().port; s.close(() => ok(p)) }) }) const TREE_PORT = await freePort() const HOST_PORT = await freePort() const TREE = `http://127.0.0.1:${TREE_PORT}/${TREE_NAME}` let pageHtml = 'nothing yet' const tree = spawn(process.execPath, ['internal/serve-strict.mjs', '--port', String(TREE_PORT)], { cwd: ROOT, stdio: 'ignore' }) const host = createServer((_, r) => { r.writeHead(200, { 'content-type': 'text/html' }); r.end(pageHtml) }).listen(HOST_PORT, 'localhost') const cleanup = () => { try { tree.kill() } catch { /* already gone */ } try { host.close() } catch { /* already closed */ } } await new Promise((r) => setTimeout(r, 900)) const reachable = await fetch(`${TREE}/manifest.json`, { signal: AbortSignal.timeout(4000) }).then((r) => r.ok).catch(() => false) if (!reachable) { cleanup() console.log('COMPOSITE-EMBED-KNOBS: SKIP — could not serve the built tree locally.') process.exit(0) } const CASES = [ { knob: 'tk', config: (tok) => ({ tk: tok }), needsToken: true }, { knob: 'provider', config: () => ({ provider: 'maplibre' }), needsToken: false }, ] const browser = await chromium.launch({ args: ['--enable-unsafe-swiftshader', '--use-gl=angle', '--use-angle=swiftshader'] }) const fails = [] const lines = [] // Elements whose tk case actually drew a map — the only ones whose provider case can mean anything. const renders = new Set() try { for (const t of targets) { for (const c of CASES) { // Do not pay for a page load we already know cannot mean anything: if this element's tk case // drew no map, its provider case has nothing to compare against. Short-circuiting here is what // keeps the whole gate near two minutes instead of five on a nine-composite tree. if (c.knob === 'provider' && !renders.has(t.element)) { lines.push(` · ${t.element} [provider] UNMEASURED — its tk case never drew a map, so there is nothing to compare against.`) continue } if (c.needsToken && !bakedToken) { lines.push(` · ${t.element} [${c.knob}] SKIPPED — no baked token in this tree to hand the host`) continue } const cfg = JSON.stringify(c.config(bakedToken)).replace(/'/g, ''') pageHtml = `partner
HOST HEADER
<${t.element} profile-config='${cfg}'> ` const page = await browser.newPage({ viewport: { width: 1280, height: 900 } }) let mapboxOk = 0, mapboxBad = 0 const errs = [] page.on('response', (r) => { if (!/api\.mapbox\.com|tiles\.mapbox\.com/.test(r.url())) return if (r.status() >= 400) mapboxBad++; else mapboxOk++ }) page.on('console', (m) => { if (m.type() === 'error') errs.push(m.text().slice(0, 120)) }) await page.goto(`http://localhost:${HOST_PORT}/`, { waitUntil: 'load' }).catch(() => {}) // WAIT FOR THE THING, NOT FOR A CLOCK. A flat 14s per case made this gate cost four minutes // of wall time on a nine-composite tree, most of it spent watching a map that had already // drawn. Poll for a canvas instead, then settle briefly so late tile requests are counted — // the provider case asserts ZERO requests to api.mapbox.com, so it must not stop measuring // the moment something paints. An element that never draws still costs the full budget, which // is correct: that is the case whose absence is the finding. const CANVAS_BUDGET_MS = 16000 const deadline = Date.now() + CANVAS_BUDGET_MS let canvas = 0 const countCanvas = `(() => { let n = 0 const visit = (r) => { n += r.querySelectorAll('canvas').length; for (const el of r.querySelectorAll('*')) if (el.shadowRoot) visit(el.shadowRoot) } visit(document) return n })()` while (Date.now() < deadline) { canvas = await page.evaluate(countCanvas).catch(() => 0) if (canvas) break await page.waitForTimeout(500) } await page.waitForTimeout(2500) canvas = await page.evaluate(countCanvas).catch(() => canvas) const tokenErr = errs.find((e) => /access token/i.test(e)) const label = `${t.element} [${c.knob}]` const mapboxAll = mapboxOk + mapboxBad // ★ FAIL ONLY WHERE THE EVIDENCE POINTS AT THE KNOB. An element that draws no map under a // MINIMAL config is not thereby broken: several composites need a `profile` to select which // of their profiles to show, and this gate deliberately passes only the knob under test. The // first draft failed nine of them for that, which would have red-gated other people's plugins // over a claim it had not measured. The distinguishing evidence is the console: a token WAS // supplied, so "No Mapbox access token provided" means the knob did not cross the boundary — // that is this defect. No canvas and no such complaint is simply not measurable here, and is // reported as UNMEASURED rather than dressed up as a finding. if (c.knob === 'tk') { if (canvas && mapboxOk > 0) { renders.add(t.element); lines.push(` ok ${label} — canvas ${canvas}, api.mapbox.com requests ${mapboxAll}`) } else if (canvas && mapboxOk === 0) fails.push(`${label}: canvas drew but NOTHING loaded from api.mapbox.com — the host's token never reached the map`) else if (tokenErr) fails.push(`${label}: a token was supplied and the element still says "${tokenErr}" — it never read the host's profile-config`) else lines.push(` · ${label} UNMEASURED — no map canvas under a minimal config, and no token complaint. This element likely needs a \`profile\` to show its map; not a knob failure.`) } else { if (canvas && mapboxAll === 0) lines.push(` ok ${label} — canvas ${canvas}, api.mapbox.com requests 0 (keyless, as asked)`) else if (mapboxAll > 0) fails.push(`${label}: asked for maplibre and still made ${mapboxAll} request(s) to api.mapbox.com — the prop did not cross the composite boundary`) else fails.push(`${label}: asked for maplibre with no token and drew nothing${tokenErr ? ` — ${tokenErr}` : ''}`) } await page.close() } } } finally { await browser.close() cleanup() } console.log(`COMPOSITE-EMBED-KNOBS: ${targets.length} composite(s) that nest a map, on a foreign origin`) for (const l of lines) console.log(l) if (fails.length) { console.error(`\nCOMPOSITE-EMBED-KNOBS: FAIL — ${fails.length} case(s)`) for (const f of fails) console.error(' - ' + f) console.error('\n A composite reads the host\'s profile-config and hands `tk` and `provider` to the map it') console.error(' nests. Our own leaves bake a token and assign window.MAP_TOKEN, so this only ever breaks') console.error(' on a partner page — the case the published embed snippet is written for.') process.exit(1) } console.log(`\nCOMPOSITE-EMBED-KNOBS: PASS — the host's token and provider reach every nested map.`)