{"version":3,"sources":["../src/markers.ts"],"sourcesContent":["// Runtime emission of the boot `ir.*` markers (LOAD_PROFILING_SPEC §3/§3.2, R3-46).\n//\n// The host already MERGED the receive end: it validates a forwarded\n// `{ type:'ir-marker', name, at, attrs? }` against the LP-5 allowlist\n// (`irMarkers.ts`) and brackets request→interactive, treating an accepted\n// `ir.interactive` as the root-render-commit signal (site-main\n// `routePerfMessage`/`perfTimeline`). This module is the SANDBOX-side emitter for\n// the boot marks the SDK owns — `ir.fmp` (first meaningful paint) and\n// `ir.interactive` (root render commit) — forwarded over the same transport as\n// `reportReady()` (`ready.ts`). The per-marker timestamp is the sandbox-relative\n// `performance.now()` at emission (§3.2).\n//\n// Mirrors `ready.ts`'s dependency seam so the emission is unit-testable without a\n// host transport, and is idempotent per name so React StrictMode's double-invoke\n// (or any re-commit) can't mint a boot mark twice. The seam and the `realNow`\n// fallback are a deliberate second copy, not an oversight: sharing them would mean\n// a new module-level export, and this package's surface is additive-only, so every\n// export is a public subpath API a pinned app can import forever.\nimport { sendMessage as defaultSend } from './sandboxUtils';\nimport { isIrMarkerName, type IrMarkerName } from './irMarkers';\n\ninterface MarkerDeps {\n  send: (type: string, data?: Record<string, unknown>) => void;\n  now: () => number;\n}\n\nconst realNow = (): number =>\n  typeof performance !== 'undefined' && typeof performance.now === 'function' ? performance.now() : Date.now();\n\nconst defaultDeps: MarkerDeps = { send: defaultSend, now: realNow };\n\nlet deps: MarkerDeps = defaultDeps;\nconst emitted = new Set<string>();\n\n/**\n * Forward one `ir.*` marker to the host (`ir-marker`). The host re-validates against\n * the allowlist, so a bad name/attr is dropped there; we only emit names the SDK\n * itself owns. A transport that isn't ready yet is swallowed — a missing boot mark\n * must never break the app's boot.\n */\nexport function emitMarker(name: IrMarkerName, attrs?: Record<string, unknown>): void {\n  if (!isIrMarkerName(name)) return;\n  try {\n    deps.send('ir-marker', { name, at: deps.now(), ...(attrs !== undefined ? { attrs } : {}) });\n  } catch {\n    /* transport not ready — boot continues; the host simply lacks this mark */\n  }\n}\n\n/** Emit a boot one-shot at most once per name (idempotent across StrictMode/re-commit). */\nexport function emitMarkerOnce(name: IrMarkerName, attrs?: Record<string, unknown>): void {\n  if (emitted.has(name)) return;\n  emitted.add(name);\n  emitMarker(name, attrs);\n}\n\n/** Test seam: override the transport/clock. */\nexport function __setMarkerDeps(d: Partial<MarkerDeps>): void {\n  deps = { ...defaultDeps, ...d };\n}\n\n/** Test seam: reset module state (the once-guard + deps) between cases. */\nexport function __resetMarkers(): void {\n  deps = defaultDeps;\n  emitted.clear();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBA,0BAA2C;AAC3C,uBAAkD;AAOlD,MAAM,UAAU,MACd,OAAO,gBAAgB,eAAe,OAAO,YAAY,QAAQ,aAAa,YAAY,IAAI,IAAI,KAAK,IAAI;AAE7G,MAAM,cAA0B,EAAE,MAAM,oBAAAA,aAAa,KAAK,QAAQ;AAElE,IAAI,OAAmB;AACvB,MAAM,UAAU,oBAAI,IAAY;AAQzB,SAAS,WAAW,MAAoB,OAAuC;AACpF,MAAI,KAAC,iCAAe,IAAI,EAAG;AAC3B,MAAI;AACF,SAAK,KAAK,aAAa,EAAE,MAAM,IAAI,KAAK,IAAI,GAAG,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC,EAAG,CAAC;AAAA,EAC5F,QAAQ;AAAA,EAER;AACF;AAGO,SAAS,eAAe,MAAoB,OAAuC;AACxF,MAAI,QAAQ,IAAI,IAAI,EAAG;AACvB,UAAQ,IAAI,IAAI;AAChB,aAAW,MAAM,KAAK;AACxB;AAGO,SAAS,gBAAgB,GAA8B;AAC5D,SAAO,EAAE,GAAG,aAAa,GAAG,EAAE;AAChC;AAGO,SAAS,iBAAuB;AACrC,SAAO;AACP,UAAQ,MAAM;AAChB;","names":["defaultSend"]}