@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.
- package/README.md +42 -0
- package/bin/mock-host.cjs +14 -0
- package/dist/host/index.cjs +600 -0
- package/dist/host/index.cjs.map +1 -0
- package/dist/host/index.d.cts +260 -0
- package/dist/host/index.d.ts +260 -0
- package/dist/host/index.js +577 -0
- package/dist/host/index.js.map +1 -0
- package/dist/index.cjs +16 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/mock-host/cli.cjs +800 -0
- package/dist/mock-host/cli.cjs.map +1 -0
- package/dist/mock-host/cli.d.cts +155 -0
- package/dist/mock-host/cli.d.ts +155 -0
- package/dist/mock-host/cli.js +770 -0
- package/dist/mock-host/cli.js.map +1 -0
- package/dist/mock-host/index.cjs +74 -0
- package/dist/mock-host/index.cjs.map +1 -0
- package/dist/mock-host/index.d.cts +95 -0
- package/dist/mock-host/index.d.ts +95 -0
- package/dist/mock-host/index.js +71 -0
- package/dist/mock-host/index.js.map +1 -0
- package/dist/plugin/index.cjs +113 -0
- package/dist/plugin/index.cjs.map +1 -0
- package/dist/plugin/index.d.cts +120 -0
- package/dist/plugin/index.d.ts +120 -0
- package/dist/plugin/index.js +107 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/registry-DpCx_LxF.d.cts +25 -0
- package/dist/registry-DpCx_LxF.d.ts +25 -0
- package/dist/transport-73otePiw.d.cts +307 -0
- package/dist/transport-73otePiw.d.ts +307 -0
- package/dist/transport-DVn2GVZh.d.cts +32 -0
- package/dist/transport-DVn2GVZh.d.ts +32 -0
- 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 };
|