@invinite-org/chartlang-host-worker 1.0.1
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 +228 -0
- package/LICENSE +21 -0
- package/README.md +70 -0
- package/dist/createWorkerBoot.d.ts +45 -0
- package/dist/createWorkerBoot.d.ts.map +1 -0
- package/dist/createWorkerBoot.js +122 -0
- package/dist/createWorkerBoot.js.map +1 -0
- package/dist/createWorkerHost.d.ts +55 -0
- package/dist/createWorkerHost.d.ts.map +1 -0
- package/dist/createWorkerHost.js +167 -0
- package/dist/createWorkerHost.js.map +1 -0
- package/dist/defaultWorkerFactory.d.ts +19 -0
- package/dist/defaultWorkerFactory.d.ts.map +1 -0
- package/dist/defaultWorkerFactory.js +23 -0
- package/dist/defaultWorkerFactory.js.map +1 -0
- package/dist/filterEmissions.d.ts +21 -0
- package/dist/filterEmissions.d.ts.map +1 -0
- package/dist/filterEmissions.js +107 -0
- package/dist/filterEmissions.js.map +1 -0
- package/dist/idb.d.ts +2 -0
- package/dist/idb.d.ts.map +1 -0
- package/dist/idb.js +4 -0
- package/dist/idb.js.map +1 -0
- package/dist/idbStateStore.d.ts +22 -0
- package/dist/idbStateStore.d.ts.map +1 -0
- package/dist/idbStateStore.js +255 -0
- package/dist/idbStateStore.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/limits.d.ts +40 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +48 -0
- package/dist/limits.js.map +1 -0
- package/dist/protocol.d.ts +70 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +4 -0
- package/dist/protocol.js.map +1 -0
- package/dist/types.d.ts +164 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/worker-boot.d.ts +6 -0
- package/dist/worker-boot.js +14999 -0
- package/dist/worker-boot.js.map +7 -0
- package/dist/workerBoot.d.ts +2 -0
- package/dist/workerBoot.d.ts.map +1 -0
- package/dist/workerBoot.js +18 -0
- package/dist/workerBoot.js.map +1 -0
- package/package.json +57 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# @invinite-org/chartlang-host-worker
|
|
2
|
+
|
|
3
|
+
## 1.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d1de692: Fix end-user-blocking Node-ESM packaging bug. Every published `dist/index.js` previously failed to load under Node's strict ESM resolver because `tsc` had been configured with `moduleResolution: "Bundler"` and emitted relative specifiers verbatim, so `dist/index.js` carried `from "./api"` (extensionless) and Node rejected the resolution. Workspace consumers never saw this because tsx / vitest / Vite resolve loosely, but `npm install @invinite-org/chartlang-compiler` followed by `import` failed immediately for any Node consumer, and `examples/react-demo/vite.config.ts`'s server-side compile plugin broke at dev-config-load time.
|
|
8
|
+
|
|
9
|
+
This release switches `tsconfig.base.json` to `module: "NodeNext"` / `moduleResolution: "NodeNext"`, and rewrites every relative import / export / dynamic-import / `typeof import("…")` specifier across all packages' source to carry an explicit `.js` (or `/index.js`) suffix. The new resolution mode also surfaces this bug class as a compile error rather than runtime breakage, so it cannot regress.
|
|
10
|
+
|
|
11
|
+
No behavioural change for runtime consumers — the rewritten specifiers resolve to the same TypeScript sources at build time and the same `dist/<path>.js` files at consumer-load time.
|
|
12
|
+
|
|
13
|
+
- 4d44a9c: Three host-robustness fixes discovered during real end-user testing:
|
|
14
|
+
|
|
15
|
+
- **`host-worker`**: `createWorkerHost().load(...)` no longer hangs forever when the underlying `Worker` fails to boot (module fetch fails, exception during construction, OS-level crash). The host now subscribes to the worker's `error` event and rejects any in-flight (or subsequent) `load()` call with `worker failed to boot: <message>`. A new `HostLimits.maxLoadTimeoutMs` (default `30_000`) bounds the wait independently — a silently-dead worker that never fires `error` also can't hang a consumer. `MessagePort`-backed `WorkerLike` test seams remain compatible: the `error` subscription is silently ignored by ports that don't deliver that event.
|
|
16
|
+
- **`host-worker`**: Added a `./worker-boot` subpath export so Vite consumers can write `new Worker(new URL("@invinite-org/chartlang-host-worker/worker-boot", import.meta.url), { type: "module" })` instead of digging into `dist/`. The bundle is regenerated by `pnpm build` and now ships a minimal `.d.ts` next to it so NodeNext type-checking does not error on the bare specifier.
|
|
17
|
+
- **`host-quickjs`**: Added an in-process freshness gate (`dispatcherFreshness.test.ts`) that rebundles `src/dispatcher.ts` in memory via the same `bundleDispatcher()` function `pnpm build:dispatcher` uses, hashes both sides, and fails with a "run `pnpm build`" hint when the committed `dist/dispatcher.js` is stale. Prevents the "source fix landed but tests still pass against the old dispatcher" failure mode.
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [4d44a9c]
|
|
20
|
+
- Updated dependencies [98599b2]
|
|
21
|
+
- Updated dependencies [d1de692]
|
|
22
|
+
- Updated dependencies [98599b2]
|
|
23
|
+
- @invinite-org/chartlang-adapter-kit@1.1.0
|
|
24
|
+
- @invinite-org/chartlang-runtime@1.0.1
|
|
25
|
+
- @invinite-org/chartlang-core@1.0.1
|
|
26
|
+
|
|
27
|
+
## 1.0.0
|
|
28
|
+
|
|
29
|
+
### Major Changes
|
|
30
|
+
|
|
31
|
+
- chartlang `1.0.0` -- the `apiVersion: 1` standard.
|
|
32
|
+
|
|
33
|
+
- `apiVersion: 1` frozen: compiler accepts only the frozen language
|
|
34
|
+
version; `STATEFUL_PRIMITIVES` locked at 172 entries by exact
|
|
35
|
+
name-set; every shipping export `@stable`; pre-1.0 deprecations
|
|
36
|
+
removed (`PHASE_1_SCENARIOS`).
|
|
37
|
+
- Canonical language spec published (`docs/spec/`): grammar,
|
|
38
|
+
semantics, manifest, emissions, versioning -- self-contained for
|
|
39
|
+
alternate implementations. The `v1.0.0` tag is the frozen spec
|
|
40
|
+
snapshot.
|
|
41
|
+
- Public conformance reports: `pnpm conformance --report` emits
|
|
42
|
+
`CONFORMANCE.md` + `conformance-report.json`; canvas2d reference
|
|
43
|
+
report published and drift-gated.
|
|
44
|
+
- Adapter-author path proven end-to-end: scaffolded adapters ship a
|
|
45
|
+
wired conformance test; full writing-an-adapter tutorial +
|
|
46
|
+
Lightweight Charts porting walkthrough.
|
|
47
|
+
- Pine migration guide finalised with a pattern-coverage matrix
|
|
48
|
+
audited against the top ~50 Pine scripts.
|
|
49
|
+
|
|
50
|
+
### Minor Changes
|
|
51
|
+
|
|
52
|
+
- d14a034: Add phase 5 server alerts, multi-timeframe request handling, runtime persistence, QuickJS hosting, expanded plot and table rendering, color helpers, alert conditions, and volume profile primitives.
|
|
53
|
+
|
|
54
|
+
### Patch Changes
|
|
55
|
+
|
|
56
|
+
- Pre-1.0 surface cleanup: remove the deprecated `PHASE_1_SCENARIOS`
|
|
57
|
+
alias (use `ALL_SCENARIOS`) and promote every shipping export from
|
|
58
|
+
`@experimental` to `@stable` ahead of the `apiVersion: 1` freeze.
|
|
59
|
+
- Updated dependencies [d14a034]
|
|
60
|
+
- Updated dependencies [3cfff10]
|
|
61
|
+
- Updated dependencies [3cfff10]
|
|
62
|
+
- Updated dependencies [3cfff10]
|
|
63
|
+
- Updated dependencies [3cfff10]
|
|
64
|
+
- Updated dependencies [3cfff10]
|
|
65
|
+
- Updated dependencies [3cfff10]
|
|
66
|
+
- Updated dependencies
|
|
67
|
+
- Updated dependencies
|
|
68
|
+
- Updated dependencies
|
|
69
|
+
- @invinite-org/chartlang-adapter-kit@1.0.0
|
|
70
|
+
- @invinite-org/chartlang-core@1.0.0
|
|
71
|
+
- @invinite-org/chartlang-runtime@1.0.0
|
|
72
|
+
|
|
73
|
+
## 0.5.0
|
|
74
|
+
|
|
75
|
+
### Phase 5
|
|
76
|
+
|
|
77
|
+
#### Minor Changes
|
|
78
|
+
|
|
79
|
+
- Add the `@invinite-org/chartlang-host-worker/idb` subpath with an
|
|
80
|
+
IndexedDB-backed `PersistentStateStore` for browser warm starts, per PLAN.md
|
|
81
|
+
§6.9 and §8.2.
|
|
82
|
+
- Replace the Phase 4 `request.security` NaN-only path with real
|
|
83
|
+
multi-timeframe secondary stream alignment per PLAN.md §6.8 and §7.2.
|
|
84
|
+
Adapters can route tagged `CandleEvent.streamKey` candles, the worker
|
|
85
|
+
host dispatches them through `ScriptRunner.push`, conformance includes
|
|
86
|
+
MTF scenarios, and the private canvas2d reference adapter now declares
|
|
87
|
+
`multiTimeframe: true`.
|
|
88
|
+
|
|
89
|
+
#### Patch Changes
|
|
90
|
+
|
|
91
|
+
- Updated dependencies
|
|
92
|
+
- Updated dependencies
|
|
93
|
+
- Updated dependencies
|
|
94
|
+
- Updated dependencies
|
|
95
|
+
- Updated dependencies
|
|
96
|
+
- Updated dependencies
|
|
97
|
+
- Updated dependencies
|
|
98
|
+
- Updated dependencies
|
|
99
|
+
- Updated dependencies
|
|
100
|
+
- Updated dependencies
|
|
101
|
+
- Updated dependencies
|
|
102
|
+
- Updated dependencies
|
|
103
|
+
- Updated dependencies
|
|
104
|
+
- Updated dependencies
|
|
105
|
+
- Updated dependencies
|
|
106
|
+
- @invinite-org/chartlang-core@0.5.0
|
|
107
|
+
- @invinite-org/chartlang-adapter-kit@0.5.0
|
|
108
|
+
- @invinite-org/chartlang-runtime@0.5.0
|
|
109
|
+
|
|
110
|
+
## 0.4.0
|
|
111
|
+
|
|
112
|
+
### Minor Changes
|
|
113
|
+
|
|
114
|
+
- 3f3ce38: Phase-1 walking-skeleton: ship the canvas2d reference adapter
|
|
115
|
+
(`examples/canvas2d-adapter`). The private example package now
|
|
116
|
+
exports `createCanvas2dAdapter`, `runRendererLoop`,
|
|
117
|
+
`CANVAS2D_CAPABILITIES`, `DEFAULT_PALETTE`, plus a
|
|
118
|
+
`./testing` sub-path entry carrying `MockCanvas2DContext` +
|
|
119
|
+
`hashCallLog` for sibling-package conformance tests (Task 12).
|
|
120
|
+
|
|
121
|
+
Two cross-package adjustments rode along:
|
|
122
|
+
|
|
123
|
+
- `@invinite-org/chartlang-host-worker` adds `createWorkerBoot`
|
|
124
|
+
and `WorkerBootScope` to its public barrel so consumer-repo
|
|
125
|
+
tests (and Task 10's integration test) can pair the worker host
|
|
126
|
+
against a `MessageChannel`-backed scope. The boot factory was
|
|
127
|
+
always testable from within the package; this exposes it as a
|
|
128
|
+
stable surface.
|
|
129
|
+
- `@invinite-org/chartlang-runtime`'s `makeSeriesView` Proxy now
|
|
130
|
+
defines a `has` trap so `"current" in series` (and
|
|
131
|
+
`"length" in series`, `"<n>" in series`) returns `true`. This
|
|
132
|
+
unblocks `runtime/src/emit/plot.ts`'s `isSeriesNumber` check —
|
|
133
|
+
previously the Proxy reported `false` for `in`, so calls like
|
|
134
|
+
`plot(ta.ema(...))` with the real runtime Series threw the
|
|
135
|
+
"outside an active script step" sentinel. Discovered via Task
|
|
136
|
+
10's end-to-end integration test driving an EMA-cross bundle
|
|
137
|
+
through the worker host into the canvas2d renderer.
|
|
138
|
+
|
|
139
|
+
- 3f3ce38: Land the Phase-1 browser-default `ScriptHost`. `createWorkerHost`
|
|
140
|
+
boots a Web Worker, loads a compiled chartlang bundle via a
|
|
141
|
+
`data:` URL dynamic import, and round-trips `CandleEvent` /
|
|
142
|
+
`RunnerEmissions` over a structured-clone-safe postMessage
|
|
143
|
+
protocol (`HostToWorker` / `WorkerToHost`). The `load` frame
|
|
144
|
+
carries the adapter's `Capabilities` bag and the host's
|
|
145
|
+
`HostLimits`; the worker boot is stateless about both. A
|
|
146
|
+
measurement-only watchdog times every `candleEvent` dispatch
|
|
147
|
+
against `maxCpuMsPerStep` and posts `step-overshoot` (no
|
|
148
|
+
preemption — real interrupt-based caps land with the QuickJS
|
|
149
|
+
host in Phase 5). Drains validate every plot / alert through
|
|
150
|
+
`adapter-kit`'s `validateEmission` before posting; malformed
|
|
151
|
+
emissions become `malformed-emission` diagnostics. Replaces the
|
|
152
|
+
Phase-0 `PACKAGE_VERSION` placeholder.
|
|
153
|
+
- Resolve runtime `input.*` overrides at mount, add adapter input resolver wiring, and audit universal `ta.*` offset support.
|
|
154
|
+
|
|
155
|
+
### Patch Changes
|
|
156
|
+
|
|
157
|
+
- Updated dependencies [3f3ce38]
|
|
158
|
+
- Updated dependencies [3f3ce38]
|
|
159
|
+
- Updated dependencies [3f3ce38]
|
|
160
|
+
- Updated dependencies [3f3ce38]
|
|
161
|
+
- Updated dependencies [3f3ce38]
|
|
162
|
+
- Updated dependencies [3f3ce38]
|
|
163
|
+
- Updated dependencies [3f3ce38]
|
|
164
|
+
- Updated dependencies [38fb475]
|
|
165
|
+
- Updated dependencies [38fb475]
|
|
166
|
+
- Updated dependencies [38fb475]
|
|
167
|
+
- Updated dependencies [38fb475]
|
|
168
|
+
- Updated dependencies [38fb475]
|
|
169
|
+
- Updated dependencies [38fb475]
|
|
170
|
+
- Updated dependencies [38fb475]
|
|
171
|
+
- Updated dependencies [38fb475]
|
|
172
|
+
- Updated dependencies [38fb475]
|
|
173
|
+
- Updated dependencies [38fb475]
|
|
174
|
+
- Updated dependencies [38fb475]
|
|
175
|
+
- Updated dependencies [38fb475]
|
|
176
|
+
- Updated dependencies [38fb475]
|
|
177
|
+
- Updated dependencies [38fb475]
|
|
178
|
+
- Updated dependencies [38fb475]
|
|
179
|
+
- Updated dependencies [38fb475]
|
|
180
|
+
- Updated dependencies [38fb475]
|
|
181
|
+
- Updated dependencies [38fb475]
|
|
182
|
+
- Updated dependencies [38fb475]
|
|
183
|
+
- Updated dependencies [38fb475]
|
|
184
|
+
- Updated dependencies [38fb475]
|
|
185
|
+
- Updated dependencies [38fb475]
|
|
186
|
+
- Updated dependencies [38fb475]
|
|
187
|
+
- Updated dependencies [38fb475]
|
|
188
|
+
- Updated dependencies [38fb475]
|
|
189
|
+
- Updated dependencies [38fb475]
|
|
190
|
+
- Updated dependencies [38fb475]
|
|
191
|
+
- Updated dependencies [38fb475]
|
|
192
|
+
- Updated dependencies [38fb475]
|
|
193
|
+
- Updated dependencies [38fb475]
|
|
194
|
+
- Updated dependencies [38fb475]
|
|
195
|
+
- Updated dependencies [b0d296b]
|
|
196
|
+
- Updated dependencies [b0d296b]
|
|
197
|
+
- Updated dependencies [b0d296b]
|
|
198
|
+
- Updated dependencies [b0d296b]
|
|
199
|
+
- Updated dependencies [b0d296b]
|
|
200
|
+
- Updated dependencies [b0d296b]
|
|
201
|
+
- Updated dependencies [b0d296b]
|
|
202
|
+
- Updated dependencies [b0d296b]
|
|
203
|
+
- Updated dependencies [b0d296b]
|
|
204
|
+
- Updated dependencies [b0d296b]
|
|
205
|
+
- Updated dependencies [b0d296b]
|
|
206
|
+
- Updated dependencies [b0d296b]
|
|
207
|
+
- Updated dependencies [b0d296b]
|
|
208
|
+
- Updated dependencies [b0d296b]
|
|
209
|
+
- Updated dependencies [b0d296b]
|
|
210
|
+
- Updated dependencies [b0d296b]
|
|
211
|
+
- Updated dependencies [b0d296b]
|
|
212
|
+
- Updated dependencies [b0d296b]
|
|
213
|
+
- Updated dependencies [b0d296b]
|
|
214
|
+
- Updated dependencies
|
|
215
|
+
- Updated dependencies
|
|
216
|
+
- Updated dependencies
|
|
217
|
+
- Updated dependencies
|
|
218
|
+
- Updated dependencies
|
|
219
|
+
- Updated dependencies
|
|
220
|
+
- Updated dependencies
|
|
221
|
+
- Updated dependencies
|
|
222
|
+
- Updated dependencies
|
|
223
|
+
- Updated dependencies
|
|
224
|
+
- Updated dependencies
|
|
225
|
+
- Updated dependencies
|
|
226
|
+
- @invinite-org/chartlang-adapter-kit@0.4.0
|
|
227
|
+
- @invinite-org/chartlang-runtime@0.4.0
|
|
228
|
+
- @invinite-org/chartlang-core@0.4.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Invinite
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# @invinite-org/chartlang-host-worker
|
|
2
|
+
|
|
3
|
+
`experimental`
|
|
4
|
+
|
|
5
|
+
Browser-default `ScriptHost` for chartlang. Boots a Web Worker, loads a
|
|
6
|
+
compiled script bundle, and round-trips `CandleEvent` / `RunnerEmissions`
|
|
7
|
+
across a structured-clone-safe postMessage protocol.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @invinite-org/chartlang-host-worker
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Public surface
|
|
16
|
+
|
|
17
|
+
- `createWorkerHost(opts) → ScriptHost` — main-side factory; the canvas2d
|
|
18
|
+
reference adapter (Task 10) consumes the returned host.
|
|
19
|
+
- `DEFAULT_LIMITS` — Phase-1 `HostLimits` defaults
|
|
20
|
+
(`maxCpuMsPerStep: 50`, `maxHeapBytes: 64 MiB`, `maxRingBufferBars: 5000`,
|
|
21
|
+
`maxLoadTimeoutMs: 30000`).
|
|
22
|
+
- `idbStateStore(opts)` from `@invinite-org/chartlang-host-worker/idb` —
|
|
23
|
+
IndexedDB `PersistentStateStore` for browser warm starts.
|
|
24
|
+
- Persists one snapshot per `StateStoreKey`; default cap is 50 MiB.
|
|
25
|
+
- Oldest snapshots are evicted first when writes exceed the cap.
|
|
26
|
+
- `@invinite-org/chartlang-host-worker/worker-boot` — bundled worker entry
|
|
27
|
+
for Vite / bundler `new Worker(new URL(...))` patterns. Side-effect only.
|
|
28
|
+
- Types: `ScriptHost`, `HostLimits`, `WorkerLike`, `HostCompiledScript`,
|
|
29
|
+
`HostToWorker`, `WorkerToHost`, `CreateWorkerHostOpts`.
|
|
30
|
+
|
|
31
|
+
## Minimum-viable API call
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { createWorkerHost } from "@invinite-org/chartlang-host-worker";
|
|
35
|
+
// host: ScriptHost — passed to an adapter at construction time.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Vite worker URL
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
const url = new URL(
|
|
42
|
+
"@invinite-org/chartlang-host-worker/worker-boot",
|
|
43
|
+
import.meta.url,
|
|
44
|
+
);
|
|
45
|
+
const worker = new Worker(url, { type: "module" });
|
|
46
|
+
const host = createWorkerHost({ capabilities, workerLike: worker });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Stability
|
|
50
|
+
|
|
51
|
+
Phase 1 ships the postMessage wire protocol + a measurement-based CPU
|
|
52
|
+
watchdog (`step-overshoot` reports observed elapsed ms; no preemption).
|
|
53
|
+
Deferred to Phase 5 (per PLAN §19):
|
|
54
|
+
|
|
55
|
+
- Worker-side CSP enforcement.
|
|
56
|
+
- Hard heap caps (`maxHeapBytes` is advisory today — no browser API
|
|
57
|
+
exposes a reliable per-worker heap limit).
|
|
58
|
+
- Real preemption via `setInterruptHandler` (lands with the QuickJS
|
|
59
|
+
host).
|
|
60
|
+
- Fingerprint-only globals (`Math.random`, `Date.now`, …) — Phase 1
|
|
61
|
+
relies on the compiler's `forbiddenConstructs` pass to scrub these
|
|
62
|
+
from the bundle before it ever reaches a worker.
|
|
63
|
+
|
|
64
|
+
## Docs
|
|
65
|
+
|
|
66
|
+
See [`docs/hosts/worker.md`](../../docs/hosts/worker.md).
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
MIT
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { HostToWorker, WorkerToHost } from "./protocol.js";
|
|
2
|
+
/**
|
|
3
|
+
* Duck-typed slice of the worker global scope the boot factory needs. Lets
|
|
4
|
+
* tests drive `createWorkerBoot` against a `MessageChannel` port without
|
|
5
|
+
* faking the full `WorkerGlobalScope`.
|
|
6
|
+
*
|
|
7
|
+
* @since 0.1
|
|
8
|
+
* @stable
|
|
9
|
+
* @example
|
|
10
|
+
* const scope: WorkerBootScope = {
|
|
11
|
+
* addEventListener: () => {},
|
|
12
|
+
* postMessage: () => {},
|
|
13
|
+
* };
|
|
14
|
+
* void scope;
|
|
15
|
+
*/
|
|
16
|
+
export type WorkerBootScope = {
|
|
17
|
+
addEventListener(type: "message", listener: (ev: MessageEvent<HostToWorker>) => void): void;
|
|
18
|
+
postMessage(msg: WorkerToHost): void;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Wire `scope` to the host-worker postMessage protocol. Lazily imports the
|
|
22
|
+
* compiled module via a `data:` URL so the same code path runs inside a real
|
|
23
|
+
* browser `Worker` and inside Node tests (`MessageChannel`-backed).
|
|
24
|
+
*
|
|
25
|
+
* Lifecycle:
|
|
26
|
+
*
|
|
27
|
+
* - `load` → dynamic import → `createScriptRunner(...)` → cache `limits`.
|
|
28
|
+
* Posts `loaded` on success or `loadError` on failure.
|
|
29
|
+
* - `candleEvent` → wrap dispatch in `watchStep(...)`; post `step-overshoot`
|
|
30
|
+
* when over budget. Errors map to `fatal`.
|
|
31
|
+
* - `drain` → validate every plot / alert emission; sink malformed ones into
|
|
32
|
+
* the diagnostics array; post `emissions` with the original nonce.
|
|
33
|
+
* - `dispose` → release the runner; subsequent messages map to `fatal`.
|
|
34
|
+
*
|
|
35
|
+
* @since 0.1
|
|
36
|
+
* @stable
|
|
37
|
+
* @example
|
|
38
|
+
* // import { createWorkerBoot } from "@invinite-org/chartlang-host-worker";
|
|
39
|
+
* // const scope = self;
|
|
40
|
+
* // createWorkerBoot(scope);
|
|
41
|
+
* const fn: typeof createWorkerBoot = createWorkerBoot;
|
|
42
|
+
* void fn;
|
|
43
|
+
*/
|
|
44
|
+
export declare function createWorkerBoot(scope: WorkerBootScope): void;
|
|
45
|
+
//# sourceMappingURL=createWorkerBoot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorkerBoot.d.ts","sourceRoot":"","sources":["../src/createWorkerBoot.ts"],"names":[],"mappings":"AAOA,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;AAiBF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAkF7D"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Copyright (c) 2026 Invinite. Licensed under the MIT License.
|
|
2
|
+
// See the LICENSE file in the repo root for full license text.
|
|
3
|
+
import { createScriptRunner } from "@invinite-org/chartlang-runtime";
|
|
4
|
+
import { filterEmissions } from "./filterEmissions.js";
|
|
5
|
+
import { watchStep } from "./limits.js";
|
|
6
|
+
async function importCompiledModule(moduleSource) {
|
|
7
|
+
// `encodeURIComponent` preserves multi-byte UTF-8 across the data URL
|
|
8
|
+
// without the Annex-B `unescape` round-trip. ESM `import("data:…")`
|
|
9
|
+
// accepts percent-encoded text/javascript directly in both browsers
|
|
10
|
+
// and Node 20+.
|
|
11
|
+
const url = `data:text/javascript;charset=utf-8,${encodeURIComponent(moduleSource)}`;
|
|
12
|
+
return (await import(/* @vite-ignore */ url));
|
|
13
|
+
}
|
|
14
|
+
function isFrame(value) {
|
|
15
|
+
if (value === null || typeof value !== "object")
|
|
16
|
+
return false;
|
|
17
|
+
const k = value.kind;
|
|
18
|
+
return typeof k === "string";
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Wire `scope` to the host-worker postMessage protocol. Lazily imports the
|
|
22
|
+
* compiled module via a `data:` URL so the same code path runs inside a real
|
|
23
|
+
* browser `Worker` and inside Node tests (`MessageChannel`-backed).
|
|
24
|
+
*
|
|
25
|
+
* Lifecycle:
|
|
26
|
+
*
|
|
27
|
+
* - `load` → dynamic import → `createScriptRunner(...)` → cache `limits`.
|
|
28
|
+
* Posts `loaded` on success or `loadError` on failure.
|
|
29
|
+
* - `candleEvent` → wrap dispatch in `watchStep(...)`; post `step-overshoot`
|
|
30
|
+
* when over budget. Errors map to `fatal`.
|
|
31
|
+
* - `drain` → validate every plot / alert emission; sink malformed ones into
|
|
32
|
+
* the diagnostics array; post `emissions` with the original nonce.
|
|
33
|
+
* - `dispose` → release the runner; subsequent messages map to `fatal`.
|
|
34
|
+
*
|
|
35
|
+
* @since 0.1
|
|
36
|
+
* @stable
|
|
37
|
+
* @example
|
|
38
|
+
* // import { createWorkerBoot } from "@invinite-org/chartlang-host-worker";
|
|
39
|
+
* // const scope = self;
|
|
40
|
+
* // createWorkerBoot(scope);
|
|
41
|
+
* const fn: typeof createWorkerBoot = createWorkerBoot;
|
|
42
|
+
* void fn;
|
|
43
|
+
*/
|
|
44
|
+
export function createWorkerBoot(scope) {
|
|
45
|
+
let runner = null;
|
|
46
|
+
let limits = null;
|
|
47
|
+
scope.addEventListener("message", async (ev) => {
|
|
48
|
+
const msg = ev.data;
|
|
49
|
+
if (!isFrame(msg)) {
|
|
50
|
+
scope.postMessage({
|
|
51
|
+
kind: "fatal",
|
|
52
|
+
message: "malformed host frame: not a plain object with a string 'kind'",
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (msg.kind === "load") {
|
|
57
|
+
try {
|
|
58
|
+
const mod = await importCompiledModule(msg.compiled.moduleSource);
|
|
59
|
+
runner = createScriptRunner({
|
|
60
|
+
compiled: mod.default,
|
|
61
|
+
capabilities: msg.capabilities,
|
|
62
|
+
...(msg.symInfo !== undefined ? { symInfo: msg.symInfo } : {}),
|
|
63
|
+
...(msg.inputOverrides !== undefined
|
|
64
|
+
? { inputOverrides: msg.inputOverrides }
|
|
65
|
+
: {}),
|
|
66
|
+
});
|
|
67
|
+
limits = msg.limits;
|
|
68
|
+
scope.postMessage({ kind: "loaded" });
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
scope.postMessage({
|
|
72
|
+
kind: "loadError",
|
|
73
|
+
message: err instanceof Error ? err.message : String(err),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
switch (msg.kind) {
|
|
80
|
+
case "candleEvent": {
|
|
81
|
+
if (runner === null || limits === null) {
|
|
82
|
+
throw new Error("candleEvent before load");
|
|
83
|
+
}
|
|
84
|
+
const r = runner;
|
|
85
|
+
const { overshoot } = await watchStep(() => r.push(msg.event), limits.maxCpuMsPerStep);
|
|
86
|
+
if (overshoot > 0) {
|
|
87
|
+
scope.postMessage({ kind: "step-overshoot", observedMs: overshoot });
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case "drain": {
|
|
92
|
+
if (runner === null) {
|
|
93
|
+
throw new Error("drain before load");
|
|
94
|
+
}
|
|
95
|
+
const cleaned = filterEmissions(runner.drain());
|
|
96
|
+
scope.postMessage({
|
|
97
|
+
kind: "emissions",
|
|
98
|
+
nonce: msg.nonce,
|
|
99
|
+
emissions: cleaned,
|
|
100
|
+
});
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case "dispose": {
|
|
104
|
+
await runner?.dispose();
|
|
105
|
+
runner = null;
|
|
106
|
+
limits = null;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
default: {
|
|
110
|
+
throw new Error(`unknown frame kind: ${msg.kind}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
scope.postMessage({
|
|
116
|
+
kind: "fatal",
|
|
117
|
+
message: err instanceof Error ? err.message : String(err),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=createWorkerBoot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorkerBoot.js","sourceRoot":"","sources":["../src/createWorkerBoot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { AdapterSymInfo, Capabilities } from "@invinite-org/chartlang-adapter-kit";
|
|
2
|
+
import type { HostLimits, ScriptHost, WorkerLike } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Constructor options for {@link createWorkerHost}.
|
|
5
|
+
*
|
|
6
|
+
* - `capabilities` — the adapter's declared capability bag. Bolted onto every
|
|
7
|
+
* `load` postMessage; the worker boot never falls back to a default.
|
|
8
|
+
* - `symInfo` — optional adapter-supplied metadata for runtime `syminfo.*`.
|
|
9
|
+
* - `resolveInputs` — optional adapter callback. The host resolves it during
|
|
10
|
+
* `load()` and sends the plain override record to the worker.
|
|
11
|
+
* - `workerLike` — injection seam for tests. Production callers omit it; the
|
|
12
|
+
* host then constructs a real `Worker` via {@link defaultWorkerFactory}.
|
|
13
|
+
* - `limits` — partial `HostLimits` overrides; missing fields fall through to
|
|
14
|
+
* {@link DEFAULT_LIMITS}.
|
|
15
|
+
* - `onWorkerError` — called when the worker posts `step-overshoot` or
|
|
16
|
+
* `fatal`. The host does not synthesize diagnostics into the next
|
|
17
|
+
* `drain()` — Phase 1 keeps overshoot surfacing on the adapter.
|
|
18
|
+
*
|
|
19
|
+
* @since 0.1
|
|
20
|
+
* @stable
|
|
21
|
+
* @example
|
|
22
|
+
* const opts: CreateWorkerHostOpts = {
|
|
23
|
+
* capabilities: {} as Capabilities,
|
|
24
|
+
* };
|
|
25
|
+
* void opts;
|
|
26
|
+
*/
|
|
27
|
+
export type CreateWorkerHostOpts = {
|
|
28
|
+
readonly capabilities: Capabilities;
|
|
29
|
+
readonly symInfo?: AdapterSymInfo;
|
|
30
|
+
readonly resolveInputs?: (scriptId: string) => Readonly<Record<string, unknown>>;
|
|
31
|
+
readonly workerLike?: WorkerLike;
|
|
32
|
+
readonly limits?: Partial<HostLimits>;
|
|
33
|
+
readonly onWorkerError?: (message: string) => void;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Build a browser-default `ScriptHost` around a Web Worker. The host
|
|
37
|
+
* round-trips `load` / `push` / `drain` / `dispose` calls across the worker
|
|
38
|
+
* boundary via structured-clone-safe postMessage frames defined in
|
|
39
|
+
* {@link HostToWorker} / {@link WorkerToHost}.
|
|
40
|
+
*
|
|
41
|
+
* The host owns the `nonce` counter for `drain` correlation, the in-flight
|
|
42
|
+
* `load` promise, and the in-flight drain registry. `dispose` posts the
|
|
43
|
+
* tear-down message, calls `terminate()` when the underlying `WorkerLike`
|
|
44
|
+
* supports it, and clears the pending-drain map.
|
|
45
|
+
*
|
|
46
|
+
* @since 0.1
|
|
47
|
+
* @stable
|
|
48
|
+
* @example
|
|
49
|
+
* import { createWorkerHost } from "@invinite-org/chartlang-host-worker";
|
|
50
|
+
* // const host = createWorkerHost({ capabilities });
|
|
51
|
+
* const fn: typeof createWorkerHost = createWorkerHost;
|
|
52
|
+
* void fn;
|
|
53
|
+
*/
|
|
54
|
+
export declare function createWorkerHost(opts: CreateWorkerHostOpts): ScriptHost;
|
|
55
|
+
//# sourceMappingURL=createWorkerHost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorkerHost.d.ts","sourceRoot":"","sources":["../src/createWorkerHost.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,cAAc,EACd,YAAY,EAEf,MAAM,qCAAqC,CAAC;AAK7C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAoB,UAAU,EAAE,MAAM,YAAY,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAC/B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACjF,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACtC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtD,CAAC;AAaF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,UAAU,CA+IvE"}
|