@ethisyscore/extension-runtime 1.6.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.
Files changed (39) hide show
  1. package/README.md +42 -0
  2. package/bin/mock-host.cjs +14 -0
  3. package/dist/host/index.cjs +600 -0
  4. package/dist/host/index.cjs.map +1 -0
  5. package/dist/host/index.d.cts +260 -0
  6. package/dist/host/index.d.ts +260 -0
  7. package/dist/host/index.js +577 -0
  8. package/dist/host/index.js.map +1 -0
  9. package/dist/index.cjs +16 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.d.cts +6 -0
  12. package/dist/index.d.ts +6 -0
  13. package/dist/index.js +10 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/mock-host/cli.cjs +800 -0
  16. package/dist/mock-host/cli.cjs.map +1 -0
  17. package/dist/mock-host/cli.d.cts +155 -0
  18. package/dist/mock-host/cli.d.ts +155 -0
  19. package/dist/mock-host/cli.js +770 -0
  20. package/dist/mock-host/cli.js.map +1 -0
  21. package/dist/mock-host/index.cjs +74 -0
  22. package/dist/mock-host/index.cjs.map +1 -0
  23. package/dist/mock-host/index.d.cts +95 -0
  24. package/dist/mock-host/index.d.ts +95 -0
  25. package/dist/mock-host/index.js +71 -0
  26. package/dist/mock-host/index.js.map +1 -0
  27. package/dist/plugin/index.cjs +113 -0
  28. package/dist/plugin/index.cjs.map +1 -0
  29. package/dist/plugin/index.d.cts +120 -0
  30. package/dist/plugin/index.d.ts +120 -0
  31. package/dist/plugin/index.js +107 -0
  32. package/dist/plugin/index.js.map +1 -0
  33. package/dist/registry-DpCx_LxF.d.cts +25 -0
  34. package/dist/registry-DpCx_LxF.d.ts +25 -0
  35. package/dist/transport-73otePiw.d.cts +307 -0
  36. package/dist/transport-73otePiw.d.ts +307 -0
  37. package/dist/transport-DVn2GVZh.d.cts +32 -0
  38. package/dist/transport-DVn2GVZh.d.ts +32 -0
  39. package/package.json +78 -0
@@ -0,0 +1,260 @@
1
+ import { ReactElement } from 'react';
2
+ import { C as ComponentRegistry } from '../registry-DpCx_LxF.js';
3
+ export { P as PrimitiveProps } from '../registry-DpCx_LxF.js';
4
+ import { SduiNode } from '@ethisyscore/protocol';
5
+ export { PrimitiveName, SduiNode } from '@ethisyscore/protocol';
6
+ export { D as DEFAULT_MAX_CONCURRENT_MCP_REQUESTS, I as InputEventPayload, M as McpHttpClient, a as McpHttpRequest, W as WORKER_TRANSPORT_PROTOCOL, b as WorkerCtor, c as WorkerHandshakePayload, d as WorkerLike, e as WorkerRemoteDomTransport, f as WorkerRemoteDomTransportOptions } from '../transport-73otePiw.js';
7
+ export { RemoteReceiver, RemoteReceiverComment, RemoteReceiverElement, RemoteReceiverNode, RemoteReceiverParent, RemoteReceiverRoot, RemoteReceiverText } from '@remote-dom/core/receivers';
8
+ export { RemoteComponentRendererMap, RemoteComponentRendererProps, RemoteRootRenderer, RemoteRootRendererProps, createRemoteComponentRenderer } from '@remote-dom/react/host';
9
+
10
+ /**
11
+ * Resolution context for `var` references. Keys are looked up via dot-path
12
+ * traversal; missing paths resolve to `undefined`.
13
+ */
14
+ type EvaluatorContext = Record<string, unknown>;
15
+ /**
16
+ * Evaluate a JsonLogic expression in the closed operator subset against the
17
+ * supplied context.
18
+ *
19
+ * @param expr The expression tree. Scalars (`string | number | boolean | null`)
20
+ * evaluate to themselves; arrays map element-wise; operator
21
+ * objects must contain exactly one key from
22
+ * {@link KNOWN_OPERATORS}.
23
+ * @param context The context bag for `var` resolution. Dot-paths traverse
24
+ * nested objects.
25
+ *
26
+ * @throws Error if `expr` contains an unknown operator, a function-typed value,
27
+ * an operator object with a number of keys other than one, or any
28
+ * other unsupported shape (e.g. `undefined`, `Symbol`, `bigint`).
29
+ */
30
+ declare function evaluate(expr: unknown, context: EvaluatorContext): unknown;
31
+
32
+ /**
33
+ * Walk a parsed SDUI tree and render it as a React element by looking up each
34
+ * node's `type` in the supplied {@link ComponentRegistry}.
35
+ *
36
+ * The interpreter is purely structural:
37
+ *
38
+ * - It owns no UI styling, layout, or data fetching.
39
+ * - It never reads `node.props` — props are forwarded opaquely to the host
40
+ * component, which owns interpretation per primitive.
41
+ * - It does not evaluate `node.bindings` — reactive rules are handled in a
42
+ * separate task (E2.S2). For v1 the interpreter passes through the static
43
+ * tree only.
44
+ *
45
+ * Each child is given a stable React `key` derived from its position so that
46
+ * React's reconciler can identify list items across renders. The key is a
47
+ * sibling-local index; the registry consumer is responsible for opting into a
48
+ * stable identity if it has a domain-meaningful `props.key`.
49
+ *
50
+ * @throws Error when `node.type` is not present in the registry. This is the
51
+ * fail-loud behaviour required by the closed v1 vocabulary — unknown
52
+ * primitives must not silently degrade.
53
+ */
54
+ declare function interpret(node: SduiNode, registry: ComponentRegistry): ReactElement;
55
+
56
+ /**
57
+ * Semantic component registry for Contract B (worker remote-runtime)
58
+ * extensions.
59
+ *
60
+ * Worker-side plugin code references UI primitives by name — e.g.
61
+ * `<DataTable />`, `<Drawer />`, `<CanvasSurface />`. The host owns rendering:
62
+ * a {@link SemanticComponentRegistry} maps each name to a concrete component
63
+ * type, and the Remote DOM host receiver consults the registry on every
64
+ * worker-emitted mutation. The closed primitive vocabulary {@link CONTRACT_B_PRIMITIVES}
65
+ * is intentionally narrow — adding a primitive is a coordinated host change so
66
+ * plugins cannot extend the contract ad hoc.
67
+ *
68
+ * **Alignment with SDUI:** Where the Contract B name overlaps with the
69
+ * `@ethisyscore/protocol` SDUI primitive vocabulary (`DataTable`, `Form`), the
70
+ * names are identical to avoid synonym drift. SDUI's `Action` is intentionally
71
+ * NOT reused — Contract B's interactive primitive is named `Button` so the
72
+ * worker authoring API stays close to React DOM idioms. The two vocabularies
73
+ * may converge as they evolve, but the host registries (Contract A SDUI vs
74
+ * Contract B Semantic) remain distinct surfaces today.
75
+ *
76
+ * The registry is renderer-agnostic — the generic `TComponent` parameter is
77
+ * whatever component type the host supplies (React `ComponentType` in
78
+ * production; plain objects in tests). This keeps the registry free of a
79
+ * React peer-dep requirement and lets tests assert behaviour without rendering.
80
+ */
81
+ /**
82
+ * The mandatory Contract B (worker remote-runtime) semantic primitive vocabulary.
83
+ *
84
+ * Adding a primitive requires a coordinated host change + protocol bump —
85
+ * plugins cannot extend this set. Each name has a host-supplied concrete
86
+ * component (gogo-ui in production); the registry enforces 1:1 substitution.
87
+ */
88
+ declare const CONTRACT_B_PRIMITIVES: readonly ["Button", "DataTable", "Form", "EntityPicker", "CommandBar", "Drawer", "Modal", "CanvasSurface", "WebGLSurface"];
89
+ /**
90
+ * Union type of the Contract B semantic primitive names — exported so callers
91
+ * (tests, hosts) get full IntelliSense and compile-time exhaustiveness checks.
92
+ */
93
+ type SemanticPrimitiveName = typeof CONTRACT_B_PRIMITIVES[number];
94
+ /**
95
+ * Map of semantic primitive name → concrete component for Contract B
96
+ * extensions.
97
+ *
98
+ * Construction is open-ended (callers register primitives one at a time) or
99
+ * eager via {@link SemanticComponentRegistry.fromMap} which forces a complete
100
+ * map up front and aborts if any primitive is missing.
101
+ *
102
+ * @typeParam TComponent - The host's concrete component shape. React hosts pass
103
+ * `ComponentType<P>`; tests pass any tagged object.
104
+ */
105
+ declare class SemanticComponentRegistry<TComponent> {
106
+ private readonly entries;
107
+ /**
108
+ * Register a primitive → component binding.
109
+ *
110
+ * Throws if `name` is not in {@link CONTRACT_B_PRIMITIVES} (drift prevention)
111
+ * or if `name` is already registered (silent-override prevention).
112
+ */
113
+ register(name: SemanticPrimitiveName, component: TComponent): void;
114
+ /**
115
+ * Resolve a primitive name to its concrete component. Throws if the name is
116
+ * outside the Contract B vocabulary OR if the registry has no binding —
117
+ * silent fallthrough would let typos render blank components, which is
118
+ * worse than a fast failure for plugin authors.
119
+ */
120
+ resolve(name: SemanticPrimitiveName): TComponent;
121
+ /**
122
+ * Cheap presence probe — never throws. Use this when callers want to
123
+ * fall back to a default component instead of erroring.
124
+ */
125
+ has(name: SemanticPrimitiveName): boolean;
126
+ /**
127
+ * Sorted list of registered primitive names. Stable output makes registry
128
+ * diagnostics and snapshot tests deterministic.
129
+ */
130
+ listRegistered(): SemanticPrimitiveName[];
131
+ /**
132
+ * Build a registry from a complete `Record<SemanticPrimitiveName, T>` map.
133
+ *
134
+ * The `Record` type forces TypeScript to refuse incomplete literals at
135
+ * compile time, AND we re-check at runtime so callers who type-erase the
136
+ * record (e.g., via `as any`) still get a fast failure.
137
+ */
138
+ static fromMap<T>(map: Record<SemanticPrimitiveName, T>): SemanticComponentRegistry<T>;
139
+ }
140
+
141
+ /**
142
+ * OffscreenCanvas transfer helpers + pointer/keyboard coalescing for
143
+ * Contract B (worker remote-runtime) extensions.
144
+ *
145
+ * **Architecture.** Hosts that expose a {@link import("./component-registry").SemanticComponentRegistry}'s
146
+ * `CanvasSurface` / `WebGLSurface` primitive create a host-side `<canvas>`,
147
+ * transfer control to the worker via {@link createOffscreenCanvasTransfer}, and
148
+ * the plugin (running inside the worker realm) calls `offscreen.getContext()`
149
+ * to render. The `<canvas>` is owned by the host DOM tree (so layout, theming,
150
+ * and accessibility properties stay on the host side) but every pixel is
151
+ * produced inside the worker — no per-frame `postMessage` cost, no main-thread
152
+ * blocking.
153
+ *
154
+ * **Pointer / keyboard delivery.** Input events still originate on the host
155
+ * `<canvas>`. To avoid spraying the worker port with per-event traffic the
156
+ * host should wrap pointer-move / wheel / scroll callbacks in
157
+ * {@link createInputEventCoalescer}, matching the trailing-edge coalescer
158
+ * already documented in {@link import("./transport").WorkerRemoteDomTransport}
159
+ * (default 16ms ≈ one rAF). Keyboard events MUST use `discrete: true` —
160
+ * coalescing them would drop characters.
161
+ *
162
+ * **Security.** No capability token, no MCP traffic, and no host-only globals
163
+ * cross via the offscreen transfer. The transfer envelope is plain JSON with a
164
+ * single `OffscreenCanvas` handle in the transfer list — the worker side
165
+ * receives an opaque drawing surface and nothing else.
166
+ */
167
+ /**
168
+ * Default trailing-edge coalesce window for pointer / wheel / scroll events,
169
+ * in milliseconds. 16ms ≈ one animation frame at 60Hz. Matches the default
170
+ * documented in {@link import("./transport").WorkerRemoteDomTransport}.
171
+ */
172
+ declare const DEFAULT_OFFSCREEN_COALESCE_MS = 16;
173
+ /**
174
+ * Host → worker envelope shape for an `OffscreenCanvas` transfer. Stable wire
175
+ * contract — the worker side decodes by `type` and uses `surfaceId` to bind
176
+ * the offscreen to the right host slot when a plugin renders multiple
177
+ * canvases concurrently.
178
+ */
179
+ interface OffscreenTransferMessage {
180
+ type: "ethisys:offscreen:transfer";
181
+ surfaceId: string;
182
+ width: number;
183
+ height: number;
184
+ offscreen: OffscreenCanvas;
185
+ }
186
+ /**
187
+ * Construction options for {@link createOffscreenCanvasTransfer}.
188
+ */
189
+ interface OffscreenCanvasTransferOptions {
190
+ /**
191
+ * The host-owned `<canvas>` element. Its `width` / `height` are captured
192
+ * before transfer so the worker sees the intended pixel dimensions even if
193
+ * the host element resizes later (host should send a separate resize
194
+ * message in that case).
195
+ */
196
+ canvas: HTMLCanvasElement;
197
+ /**
198
+ * Stable identifier the worker uses to route the offscreen to the matching
199
+ * surface slot. Typically the SDUI node id of the `CanvasSurface` /
200
+ * `WebGLSurface` primitive that the worker will draw into.
201
+ */
202
+ surfaceId: string;
203
+ /**
204
+ * Host-side postMessage function — typically the
205
+ * {@link import("./transport").WorkerRemoteDomTransport}'s port-side
206
+ * `postMessage`. Tests inject a spy.
207
+ */
208
+ postMessage(message: OffscreenTransferMessage, transfer: Transferable[]): void;
209
+ }
210
+ /**
211
+ * Successful transfer result. The caller retains a reference to the
212
+ * `OffscreenCanvas` only for observability (e.g., to wire to the worker's
213
+ * reply handshake) — direct rendering from the host side is forbidden because
214
+ * control has already been transferred and any host-side draw call would
215
+ * throw.
216
+ */
217
+ interface OffscreenCanvasTransferResult {
218
+ offscreen: OffscreenCanvas;
219
+ }
220
+ /**
221
+ * Transfer control of a host-owned `<canvas>` to the worker.
222
+ *
223
+ * Throws if:
224
+ * - the environment lacks `HTMLCanvasElement.prototype.transferControlToOffscreen`
225
+ * (the helper does NOT silently fall back — Contract B clients must require
226
+ * the API and surface a clear error in unsupported browsers);
227
+ * - the same canvas has already had control transferred (idempotency is the
228
+ * caller's responsibility — re-transferring would throw in the browser
229
+ * anyway, but we raise a clearer, diagnosable message ahead of that).
230
+ */
231
+ declare function createOffscreenCanvasTransfer(options: OffscreenCanvasTransferOptions): OffscreenCanvasTransferResult;
232
+ /**
233
+ * Construction options for {@link createInputEventCoalescer}.
234
+ */
235
+ interface InputEventCoalescerOptions {
236
+ /**
237
+ * Coalesce window in milliseconds. Ignored when {@link discrete} is true.
238
+ * Defaults to {@link DEFAULT_OFFSCREEN_COALESCE_MS} (16ms — one rAF).
239
+ */
240
+ coalesceMs?: number;
241
+ /**
242
+ * When `true`, forward every payload synchronously without coalescing.
243
+ * Use this for keyboard events — coalescing would drop characters by
244
+ * collapsing multiple key strokes into one trailing delivery.
245
+ */
246
+ discrete?: boolean;
247
+ }
248
+ /**
249
+ * Build a trailing-edge input-event coalescer. The pattern matches
250
+ * {@link import("./transport").WorkerRemoteDomTransport.createCoalescer} —
251
+ * factored out here so OffscreenCanvas callers don't need to construct a full
252
+ * transport just to coalesce pointer-move events.
253
+ *
254
+ * Trailing-edge semantics: every burst within a coalesce window collapses to
255
+ * a single delivery carrying the **last** payload seen in the window. A new
256
+ * payload arriving after a window has flushed starts a fresh window.
257
+ */
258
+ declare function createInputEventCoalescer<T>(sink: (payload: T) => void, options?: InputEventCoalescerOptions): (payload: T) => void;
259
+
260
+ export { CONTRACT_B_PRIMITIVES, ComponentRegistry, DEFAULT_OFFSCREEN_COALESCE_MS, type EvaluatorContext, type InputEventCoalescerOptions, type OffscreenCanvasTransferOptions, type OffscreenCanvasTransferResult, type OffscreenTransferMessage, SemanticComponentRegistry, type SemanticPrimitiveName, createInputEventCoalescer, createOffscreenCanvasTransfer, evaluate, interpret };