@invinite-org/chartlang-host-worker 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,105 @@
1
1
  # @invinite-org/chartlang-host-worker
2
2
 
3
+ ## 1.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1efb49c: Add multi-symbol support to `request.security`. `request.security({ symbol,
8
+ interval })` now reads a **different instrument** (not just a higher
9
+ timeframe), e.g. `request.security({ symbol: "AMEX:SPY", interval: "1D" })`.
10
+ `symbol` is optional (defaults to the chart symbol) and must be a compile-time
11
+ literal (`input.symbol` / `input.enum` resolved). A new `multiSymbol` adapter
12
+ capability gates non-chart-symbol requests: a different-symbol request against
13
+ an adapter declaring `multiSymbol: false` degrades to an all-NaN
14
+ bar/series with a single deduped `multi-symbol-not-supported` diagnostic,
15
+ mirroring `multi-timeframe-not-supported` (the symbol gate precedes the
16
+ timeframe gate, so a both-different request emits only the symbol diagnostic).
17
+ The Pine converter now lowers `request.security("OTHER", tf, expr)`, and the
18
+ `chartlang scaffold-adapter` template advertises `multiSymbol`.
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies [189493a]
23
+ - Updated dependencies [8bc628e]
24
+ - Updated dependencies [ab8b218]
25
+ - Updated dependencies [8bc628e]
26
+ - Updated dependencies [ab8b218]
27
+ - Updated dependencies [189493a]
28
+ - Updated dependencies [e620ba8]
29
+ - Updated dependencies [08cba38]
30
+ - Updated dependencies [1efb49c]
31
+ - Updated dependencies [1efb49c]
32
+ - @invinite-org/chartlang-adapter-kit@1.6.0
33
+ - @invinite-org/chartlang-core@1.3.0
34
+ - @invinite-org/chartlang-runtime@1.3.0
35
+
36
+ ## 1.2.0
37
+
38
+ ### Minor Changes
39
+
40
+ - 073f41b: Add the higher-timeframe expression/callback overload to `request.security`.
41
+ Alongside the existing data form `request.security({ interval })` →
42
+ `SecurityBar`, scripts can now write `request.security({ interval }, (bar) =>
43
+ …)` → `Series<number>`, where the callback runs on the **higher-timeframe
44
+ clock** — `request.security({ interval: "1W" }, (bar) => ta.ema(bar.close, 20))`
45
+ is a true weekly EMA(20) (20 weekly bars), not 20 main bars of a weekly-stepped
46
+ series. The result is aligned no-lookahead down to the main timeline.
47
+
48
+ - **core** — the `SecurityExpr` callback type (re-exported from the package
49
+ root), the second `security` overload, and the shared `statefulPrimitives`
50
+ entry annotated as covering both arities.
51
+ - **compiler** — records one `SecurityExpressionDescriptor { slotId, interval,
52
+ paramName }` per expression callsite in `manifest.securityExpressions`
53
+ (sorted by `slotId`, omitted for the data-only form), and validates each
54
+ callback against the allowed subset — its `bar` parameter and body locals,
55
+ the ambient `ta` / `inputs`, safe `Math.*` globals, and literals — rejecting
56
+ any captured outer binding with the new
57
+ `request-security-expr-captures-local` diagnostic.
58
+ - **runtime** — mounts one `SecurityExprRunner` per manifest entry: the
59
+ callback is captured lazily on the first main compute, driven once per HTF bar
60
+ close through a dedicated fold `StreamState` so `ta.*` accumulate on the HTF
61
+ clock, and one sampled value per HTF bar feeds a per-slot output buffer that
62
+ `request.security(opts, expr)` returns aligned no-lookahead to the main
63
+ timeline. Capability / interval / stream fallbacks return an all-NaN series
64
+ with a deduped diagnostic.
65
+ - **host-worker / host-quickjs** — boot the expression form unchanged; the
66
+ `__manifest` sidecar already carries `securityExpressions`.
67
+ - **pine-converter** — Pine's `request.security(sym, "D", ta.ema(close, 9))`
68
+ now lowers to the chartlang callback form
69
+ `request.security({ interval: "1d" }, (bar) => ta.ema(bar.close, 9))` (a bare
70
+ OHLCV third arg keeps lowering to the data form).
71
+ - **conformance** — new scenarios prove the weekly expression value differs
72
+ from a same-length main-timeframe EMA, plus the `multiTimeframe: false` NaN
73
+ fallback.
74
+
75
+ ### Patch Changes
76
+
77
+ - 850ae21: Fix single-script multi-timeframe loads dropping their secondary streams.
78
+ Both host boots now adopt the compiler's object-form `__manifest` sidecar
79
+ as the authoritative manifest for a single-script module
80
+ (`buildBundleFromModule` in host-worker, the bundle builder in
81
+ host-quickjs's `dispatcherCore`). The runtime `defineIndicator` stub zeroes
82
+ compiler-derived fields (`requestedIntervals`, `outputs`, `plots`,
83
+ `maxLookback`), so using `mod.default.manifest` left `requestedIntervals`
84
+ empty — a `request.security` script never registered its secondary streams
85
+ and every secondary candle was dropped with an `unknown-secondary-stream`
86
+ warning. Single-object detection goes through a dedicated `isSingleManifest`
87
+ guard (TS #17002: `Array.isArray` does not subtract a `ReadonlyArray` union
88
+ member). Cross-host parity is preserved.
89
+ - Updated dependencies [850ae21]
90
+ - Updated dependencies [ca19e20]
91
+ - Updated dependencies [6235ad7]
92
+ - Updated dependencies [3bf391a]
93
+ - Updated dependencies [8086003]
94
+ - Updated dependencies [850ae21]
95
+ - Updated dependencies [850ae21]
96
+ - Updated dependencies [073f41b]
97
+ - Updated dependencies [5a9c24d]
98
+ - Updated dependencies [08c536c]
99
+ - @invinite-org/chartlang-core@1.2.0
100
+ - @invinite-org/chartlang-runtime@1.2.0
101
+ - @invinite-org/chartlang-adapter-kit@1.3.0
102
+
3
103
  ## 1.1.1
4
104
 
5
105
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"createWorkerBoot.d.ts","sourceRoot":"","sources":["../src/createWorkerBoot.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGhE;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,GAAG;IAC1B,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC5F,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAAC;CACxC,CAAC;AA2EF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CA6F7D"}
1
+ {"version":3,"file":"createWorkerBoot.d.ts","sourceRoot":"","sources":["../src/createWorkerBoot.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGhE;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,GAAG;IAC1B,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC5F,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAAC;CACxC,CAAC;AA+FF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CA6F7D"}
@@ -17,6 +17,12 @@ function isFrame(value) {
17
17
  const k = value.kind;
18
18
  return typeof k === "string";
19
19
  }
20
+ // `Array.isArray` narrows to `any[]`, which does not subtract a
21
+ // `ReadonlyArray<T>` member from a union (TS #17002), so the single-object
22
+ // `__manifest` form needs this dedicated guard.
23
+ function isSingleManifest(manifest) {
24
+ return manifest !== undefined && !Array.isArray(manifest);
25
+ }
20
26
  function isCompiledScriptObject(v) {
21
27
  if (v === null || typeof v !== "object")
22
28
  return false;
@@ -43,6 +49,17 @@ function buildBundleFromModule(mod) {
43
49
  const dependencies = mod.__dependencies ?? [];
44
50
  const isBundle = Array.isArray(manifest) || dependencies.length > 0;
45
51
  if (!isBundle) {
52
+ // Single-script form: the compiler's `__manifest` sidecar is the
53
+ // authoritative manifest (it carries compiler-derived fields the
54
+ // runtime `defineIndicator` cannot know — `requestedIntervals`,
55
+ // `outputs`, `plots`, `maxLookback`). `mod.default.manifest` is the
56
+ // runtime stub with those fields zeroed, so an MTF script would
57
+ // never register its secondary streams if we used it directly.
58
+ // `isBundle` is false here, so `manifest` (when present) is the
59
+ // single-object form.
60
+ if (isSingleManifest(manifest)) {
61
+ return Object.freeze({ ...mod.default, manifest });
62
+ }
46
63
  return mod.default;
47
64
  }
48
65
  const siblings = [];
@@ -1 +1 @@
1
- {"version":3,"file":"createWorkerBoot.js","sourceRoot":"","sources":["../src/createWorkerBoot.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type { CompiledScriptBundle, CompiledScriptObject } from \"@invinite-org/chartlang-core\";\nimport { createScriptRunner } from \"@invinite-org/chartlang-runtime\";\n\nimport { filterEmissions } from \"./filterEmissions.js\";\nimport { watchStep } from \"./limits.js\";\nimport type { HostToWorker, WorkerToHost } from \"./protocol.js\";\nimport type { CompiledModuleExport, HostLimits, ScriptRunnerHandle } from \"./types.js\";\n\n/**\n * Duck-typed slice of the worker global scope the boot factory needs. Lets\n * tests drive `createWorkerBoot` against a `MessageChannel` port without\n * faking the full `WorkerGlobalScope`.\n *\n * @since 0.1\n * @stable\n * @example\n * const scope: WorkerBootScope = {\n * addEventListener: () => {},\n * postMessage: () => {},\n * };\n * void scope;\n */\nexport type WorkerBootScope = {\n addEventListener(type: \"message\", listener: (ev: MessageEvent<HostToWorker>) => void): void;\n postMessage(msg: WorkerToHost): void;\n};\n\nasync function importCompiledModule(moduleSource: string): Promise<CompiledModuleExport> {\n // `encodeURIComponent` preserves multi-byte UTF-8 across the data URL\n // without the Annex-B `unescape` round-trip. ESM `import(\"data:…\")`\n // accepts percent-encoded text/javascript directly in both browsers\n // and Node 20+.\n const url = `data:text/javascript;charset=utf-8,${encodeURIComponent(moduleSource)}`;\n return (await import(/* @vite-ignore */ url)) as CompiledModuleExport;\n}\n\nfunction isFrame(value: unknown): value is HostToWorker {\n if (value === null || typeof value !== \"object\") return false;\n const k = (value as { readonly kind?: unknown }).kind;\n return typeof k === \"string\";\n}\n\nfunction isCompiledScriptObject(v: unknown): v is CompiledScriptObject {\n if (v === null || typeof v !== \"object\") return false;\n const o = v as { readonly compute?: unknown; readonly manifest?: unknown };\n return typeof o.compute === \"function\" && typeof o.manifest === \"object\" && o.manifest !== null;\n}\n\n/**\n * Bridge a dynamically-imported compiled module into the runtime's\n * single-or-bundle compiled-script shape. Detects the §22.10\n * indicator-composition bundle by either (a) the array form of\n * `__manifest` or (b) a non-empty `__dependencies` export — both are\n * additive over the Phase-1 single-script wire format. Single-script\n * callers see the same `mod.default` `CompiledScriptObject` they did\n * before, byte-identical.\n *\n * Sibling exports are recovered by reading each non-`default` manifest\n * entry's `exportName` off the array sidecar and pulling the matching\n * named export off the module namespace object. Entries the local\n * `isCompiledScriptObject` guard rejects are skipped silently so a\n * malformed bundle still loads its primary script.\n */\nfunction buildBundleFromModule(\n mod: CompiledModuleExport,\n): CompiledScriptObject | CompiledScriptBundle {\n const manifest = mod.__manifest;\n const dependencies = mod.__dependencies ?? [];\n const isBundle = Array.isArray(manifest) || dependencies.length > 0;\n if (!isBundle) {\n return mod.default;\n }\n const siblings: Array<{\n readonly exportName: string;\n readonly compiled: CompiledScriptObject;\n }> = [];\n if (Array.isArray(manifest)) {\n for (let i = 1; i < manifest.length; i += 1) {\n const entry = manifest[i];\n const exportName = entry.exportName;\n if (exportName === undefined || exportName === \"default\") continue;\n const compiled = mod[exportName];\n if (!isCompiledScriptObject(compiled)) continue;\n siblings.push(Object.freeze({ exportName, compiled }));\n }\n }\n const frozenDeps = dependencies.map((d) =>\n Object.freeze({\n localId: d.localId,\n compiled: d.compiled,\n ...(d.inputOverrides === undefined ? {} : { inputOverrides: d.inputOverrides }),\n }),\n );\n return Object.freeze({\n primary: mod.default,\n siblings: Object.freeze(siblings),\n dependencies: Object.freeze(frozenDeps),\n });\n}\n\n/**\n * Wire `scope` to the host-worker postMessage protocol. Lazily imports the\n * compiled module via a `data:` URL so the same code path runs inside a real\n * browser `Worker` and inside Node tests (`MessageChannel`-backed).\n *\n * Lifecycle:\n *\n * - `load` → dynamic import → `createScriptRunner(...)` → cache `limits`.\n * Posts `loaded` on success or `loadError` on failure.\n * - `candleEvent` → wrap dispatch in `watchStep(...)`; post `step-overshoot`\n * when over budget. Errors map to `fatal`.\n * - `drain` → validate every plot / alert emission; sink malformed ones into\n * the diagnostics array; post `emissions` with the original nonce.\n * - `dispose` → release the runner; subsequent messages map to `fatal`.\n *\n * @since 0.1\n * @stable\n * @example\n * // import { createWorkerBoot } from \"@invinite-org/chartlang-host-worker\";\n * // const scope = self;\n * // createWorkerBoot(scope);\n * const fn: typeof createWorkerBoot = createWorkerBoot;\n * void fn;\n */\nexport function createWorkerBoot(scope: WorkerBootScope): void {\n let runner: ScriptRunnerHandle | null = null;\n let limits: HostLimits | null = null;\n\n scope.addEventListener(\"message\", async (ev: MessageEvent<HostToWorker>) => {\n const msg = ev.data;\n if (!isFrame(msg)) {\n scope.postMessage({\n kind: \"fatal\",\n message: \"malformed host frame: not a plain object with a string 'kind'\",\n });\n return;\n }\n if (msg.kind === \"load\") {\n try {\n const mod = await importCompiledModule(msg.compiled.moduleSource);\n const compiled = buildBundleFromModule(mod);\n runner = createScriptRunner({\n compiled,\n capabilities: msg.capabilities,\n ...(msg.symInfo !== undefined ? { symInfo: msg.symInfo } : {}),\n ...(msg.inputOverrides !== undefined\n ? { inputOverrides: msg.inputOverrides }\n : {}),\n ...(msg.plotOverrides !== undefined\n ? { plotOverrides: msg.plotOverrides }\n : {}),\n });\n limits = msg.limits;\n scope.postMessage({ kind: \"loaded\" });\n } catch (err) {\n scope.postMessage({\n kind: \"loadError\",\n message: err instanceof Error ? err.message : String(err),\n });\n }\n return;\n }\n\n try {\n switch (msg.kind) {\n case \"candleEvent\": {\n if (runner === null || limits === null) {\n throw new Error(\"candleEvent before load\");\n }\n const r = runner;\n const { overshoot } = await watchStep(\n () => r.push(msg.event),\n limits.maxCpuMsPerStep,\n );\n if (overshoot > 0) {\n scope.postMessage({ kind: \"step-overshoot\", observedMs: overshoot });\n }\n break;\n }\n case \"setPlotOverrides\": {\n if (runner === null) {\n throw new Error(\"setPlotOverrides before load\");\n }\n runner.setPlotOverrides(msg.overrides);\n break;\n }\n case \"drain\": {\n if (runner === null) {\n throw new Error(\"drain before load\");\n }\n const cleaned = filterEmissions(runner.drain());\n scope.postMessage({\n kind: \"emissions\",\n nonce: msg.nonce,\n emissions: cleaned,\n });\n break;\n }\n case \"dispose\": {\n await runner?.dispose();\n runner = null;\n limits = null;\n break;\n }\n default: {\n throw new Error(\n `unknown frame kind: ${(msg as { readonly kind: string }).kind}`,\n );\n }\n }\n } catch (err) {\n scope.postMessage({\n kind: \"fatal\",\n message: err instanceof Error ? err.message : String(err),\n });\n }\n });\n}\n"]}
1
+ {"version":3,"file":"createWorkerBoot.js","sourceRoot":"","sources":["../src/createWorkerBoot.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type {\n CompiledScriptBundle,\n CompiledScriptObject,\n ScriptManifest,\n} from \"@invinite-org/chartlang-core\";\nimport { createScriptRunner } from \"@invinite-org/chartlang-runtime\";\n\nimport { filterEmissions } from \"./filterEmissions.js\";\nimport { watchStep } from \"./limits.js\";\nimport type { HostToWorker, WorkerToHost } from \"./protocol.js\";\nimport type { CompiledModuleExport, HostLimits, ScriptRunnerHandle } from \"./types.js\";\n\n/**\n * Duck-typed slice of the worker global scope the boot factory needs. Lets\n * tests drive `createWorkerBoot` against a `MessageChannel` port without\n * faking the full `WorkerGlobalScope`.\n *\n * @since 0.1\n * @stable\n * @example\n * const scope: WorkerBootScope = {\n * addEventListener: () => {},\n * postMessage: () => {},\n * };\n * void scope;\n */\nexport type WorkerBootScope = {\n addEventListener(type: \"message\", listener: (ev: MessageEvent<HostToWorker>) => void): void;\n postMessage(msg: WorkerToHost): void;\n};\n\nasync function importCompiledModule(moduleSource: string): Promise<CompiledModuleExport> {\n // `encodeURIComponent` preserves multi-byte UTF-8 across the data URL\n // without the Annex-B `unescape` round-trip. ESM `import(\"data:…\")`\n // accepts percent-encoded text/javascript directly in both browsers\n // and Node 20+.\n const url = `data:text/javascript;charset=utf-8,${encodeURIComponent(moduleSource)}`;\n return (await import(/* @vite-ignore */ url)) as CompiledModuleExport;\n}\n\nfunction isFrame(value: unknown): value is HostToWorker {\n if (value === null || typeof value !== \"object\") return false;\n const k = (value as { readonly kind?: unknown }).kind;\n return typeof k === \"string\";\n}\n\n// `Array.isArray` narrows to `any[]`, which does not subtract a\n// `ReadonlyArray<T>` member from a union (TS #17002), so the single-object\n// `__manifest` form needs this dedicated guard.\nfunction isSingleManifest(\n manifest: ScriptManifest | ReadonlyArray<ScriptManifest> | undefined,\n): manifest is ScriptManifest {\n return manifest !== undefined && !Array.isArray(manifest);\n}\n\nfunction isCompiledScriptObject(v: unknown): v is CompiledScriptObject {\n if (v === null || typeof v !== \"object\") return false;\n const o = v as { readonly compute?: unknown; readonly manifest?: unknown };\n return typeof o.compute === \"function\" && typeof o.manifest === \"object\" && o.manifest !== null;\n}\n\n/**\n * Bridge a dynamically-imported compiled module into the runtime's\n * single-or-bundle compiled-script shape. Detects the §22.10\n * indicator-composition bundle by either (a) the array form of\n * `__manifest` or (b) a non-empty `__dependencies` export — both are\n * additive over the Phase-1 single-script wire format. Single-script\n * callers see the same `mod.default` `CompiledScriptObject` they did\n * before, byte-identical.\n *\n * Sibling exports are recovered by reading each non-`default` manifest\n * entry's `exportName` off the array sidecar and pulling the matching\n * named export off the module namespace object. Entries the local\n * `isCompiledScriptObject` guard rejects are skipped silently so a\n * malformed bundle still loads its primary script.\n */\nfunction buildBundleFromModule(\n mod: CompiledModuleExport,\n): CompiledScriptObject | CompiledScriptBundle {\n const manifest = mod.__manifest;\n const dependencies = mod.__dependencies ?? [];\n const isBundle = Array.isArray(manifest) || dependencies.length > 0;\n if (!isBundle) {\n // Single-script form: the compiler's `__manifest` sidecar is the\n // authoritative manifest (it carries compiler-derived fields the\n // runtime `defineIndicator` cannot know — `requestedIntervals`,\n // `outputs`, `plots`, `maxLookback`). `mod.default.manifest` is the\n // runtime stub with those fields zeroed, so an MTF script would\n // never register its secondary streams if we used it directly.\n // `isBundle` is false here, so `manifest` (when present) is the\n // single-object form.\n if (isSingleManifest(manifest)) {\n return Object.freeze({ ...mod.default, manifest });\n }\n return mod.default;\n }\n const siblings: Array<{\n readonly exportName: string;\n readonly compiled: CompiledScriptObject;\n }> = [];\n if (Array.isArray(manifest)) {\n for (let i = 1; i < manifest.length; i += 1) {\n const entry = manifest[i];\n const exportName = entry.exportName;\n if (exportName === undefined || exportName === \"default\") continue;\n const compiled = mod[exportName];\n if (!isCompiledScriptObject(compiled)) continue;\n siblings.push(Object.freeze({ exportName, compiled }));\n }\n }\n const frozenDeps = dependencies.map((d) =>\n Object.freeze({\n localId: d.localId,\n compiled: d.compiled,\n ...(d.inputOverrides === undefined ? {} : { inputOverrides: d.inputOverrides }),\n }),\n );\n return Object.freeze({\n primary: mod.default,\n siblings: Object.freeze(siblings),\n dependencies: Object.freeze(frozenDeps),\n });\n}\n\n/**\n * Wire `scope` to the host-worker postMessage protocol. Lazily imports the\n * compiled module via a `data:` URL so the same code path runs inside a real\n * browser `Worker` and inside Node tests (`MessageChannel`-backed).\n *\n * Lifecycle:\n *\n * - `load` → dynamic import → `createScriptRunner(...)` → cache `limits`.\n * Posts `loaded` on success or `loadError` on failure.\n * - `candleEvent` → wrap dispatch in `watchStep(...)`; post `step-overshoot`\n * when over budget. Errors map to `fatal`.\n * - `drain` → validate every plot / alert emission; sink malformed ones into\n * the diagnostics array; post `emissions` with the original nonce.\n * - `dispose` → release the runner; subsequent messages map to `fatal`.\n *\n * @since 0.1\n * @stable\n * @example\n * // import { createWorkerBoot } from \"@invinite-org/chartlang-host-worker\";\n * // const scope = self;\n * // createWorkerBoot(scope);\n * const fn: typeof createWorkerBoot = createWorkerBoot;\n * void fn;\n */\nexport function createWorkerBoot(scope: WorkerBootScope): void {\n let runner: ScriptRunnerHandle | null = null;\n let limits: HostLimits | null = null;\n\n scope.addEventListener(\"message\", async (ev: MessageEvent<HostToWorker>) => {\n const msg = ev.data;\n if (!isFrame(msg)) {\n scope.postMessage({\n kind: \"fatal\",\n message: \"malformed host frame: not a plain object with a string 'kind'\",\n });\n return;\n }\n if (msg.kind === \"load\") {\n try {\n const mod = await importCompiledModule(msg.compiled.moduleSource);\n const compiled = buildBundleFromModule(mod);\n runner = createScriptRunner({\n compiled,\n capabilities: msg.capabilities,\n ...(msg.symInfo !== undefined ? { symInfo: msg.symInfo } : {}),\n ...(msg.inputOverrides !== undefined\n ? { inputOverrides: msg.inputOverrides }\n : {}),\n ...(msg.plotOverrides !== undefined\n ? { plotOverrides: msg.plotOverrides }\n : {}),\n });\n limits = msg.limits;\n scope.postMessage({ kind: \"loaded\" });\n } catch (err) {\n scope.postMessage({\n kind: \"loadError\",\n message: err instanceof Error ? err.message : String(err),\n });\n }\n return;\n }\n\n try {\n switch (msg.kind) {\n case \"candleEvent\": {\n if (runner === null || limits === null) {\n throw new Error(\"candleEvent before load\");\n }\n const r = runner;\n const { overshoot } = await watchStep(\n () => r.push(msg.event),\n limits.maxCpuMsPerStep,\n );\n if (overshoot > 0) {\n scope.postMessage({ kind: \"step-overshoot\", observedMs: overshoot });\n }\n break;\n }\n case \"setPlotOverrides\": {\n if (runner === null) {\n throw new Error(\"setPlotOverrides before load\");\n }\n runner.setPlotOverrides(msg.overrides);\n break;\n }\n case \"drain\": {\n if (runner === null) {\n throw new Error(\"drain before load\");\n }\n const cleaned = filterEmissions(runner.drain());\n scope.postMessage({\n kind: \"emissions\",\n nonce: msg.nonce,\n emissions: cleaned,\n });\n break;\n }\n case \"dispose\": {\n await runner?.dispose();\n runner = null;\n limits = null;\n break;\n }\n default: {\n throw new Error(\n `unknown frame kind: ${(msg as { readonly kind: string }).kind}`,\n );\n }\n }\n } catch (err) {\n scope.postMessage({\n kind: \"fatal\",\n message: err instanceof Error ? err.message : String(err),\n });\n }\n });\n}\n"]}