@polyengine/runtime 0.1.0-pre.g633468a

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 (126) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +23 -0
  3. package/esm/cabi/async_values.js +162 -0
  4. package/esm/cabi/bulk_lists.js +198 -0
  5. package/esm/cabi/context.js +42 -0
  6. package/esm/cabi/flatten.js +145 -0
  7. package/esm/cabi/float.js +67 -0
  8. package/esm/cabi/handles.js +253 -0
  9. package/esm/cabi/layout.js +149 -0
  10. package/esm/cabi/lift.js +196 -0
  11. package/esm/cabi/load.js +146 -0
  12. package/esm/cabi/lower.js +141 -0
  13. package/esm/cabi/memory.js +182 -0
  14. package/esm/cabi/mod.js +22 -0
  15. package/esm/cabi/store.js +186 -0
  16. package/esm/cabi/strings.js +336 -0
  17. package/esm/cabi/trap.js +38 -0
  18. package/esm/cabi/types.js +264 -0
  19. package/esm/cabi/values.js +64 -0
  20. package/esm/cache/core.js +156 -0
  21. package/esm/cache/dir.js +170 -0
  22. package/esm/cache/mod.js +4 -0
  23. package/esm/cache/web.js +136 -0
  24. package/esm/digest/digest.js +332 -0
  25. package/esm/digest/mod.js +3 -0
  26. package/esm/digest/verify.js +129 -0
  27. package/esm/embedder/casing.js +56 -0
  28. package/esm/embedder/copy.js +42 -0
  29. package/esm/embedder/errors.js +26 -0
  30. package/esm/embedder/imports.js +63 -0
  31. package/esm/embedder/instantiate.js +978 -0
  32. package/esm/embedder/mod.js +40 -0
  33. package/esm/embedder/resources.js +406 -0
  34. package/esm/embedder/streams.js +770 -0
  35. package/esm/embedder/values.js +450 -0
  36. package/esm/embedder/version.js +273 -0
  37. package/esm/exec/boundary.js +1902 -0
  38. package/esm/exec/executor.js +1004 -0
  39. package/esm/exec/host_streams.js +818 -0
  40. package/esm/exec/mod.js +4 -0
  41. package/esm/intrinsics/async_builtins.js +510 -0
  42. package/esm/intrinsics/context.js +90 -0
  43. package/esm/intrinsics/errors.js +13 -0
  44. package/esm/intrinsics/fact_calls.js +865 -0
  45. package/esm/intrinsics/mod.js +564 -0
  46. package/esm/intrinsics/stream_builtins.js +578 -0
  47. package/esm/intrinsics/transcode.js +443 -0
  48. package/esm/jspi/bridge.js +579 -0
  49. package/esm/jspi/mechanics.js +89 -0
  50. package/esm/jspi/mod.js +5 -0
  51. package/esm/jspi/suspending.js +15 -0
  52. package/esm/jspi/types.js +29 -0
  53. package/esm/package.json +3 -0
  54. package/esm/plan/format.js +5 -0
  55. package/esm/plan/loader.js +657 -0
  56. package/esm/plan/mod.js +3 -0
  57. package/esm/shim/mod.js +2 -0
  58. package/esm/shim/translator.js +94 -0
  59. package/esm/task/mod.js +483 -0
  60. package/esm/task/scheduler.js +1028 -0
  61. package/esm/task/streams.js +786 -0
  62. package/esm/task/subtask.js +135 -0
  63. package/esm/task/thread.js +255 -0
  64. package/esm/task/waitable.js +144 -0
  65. package/package.json +91 -0
  66. package/types/cabi/async_values.d.ts +35 -0
  67. package/types/cabi/bulk_lists.d.ts +18 -0
  68. package/types/cabi/context.d.ts +59 -0
  69. package/types/cabi/flatten.d.ts +14 -0
  70. package/types/cabi/float.d.ts +14 -0
  71. package/types/cabi/handles.d.ts +70 -0
  72. package/types/cabi/layout.d.ts +13 -0
  73. package/types/cabi/lift.d.ts +25 -0
  74. package/types/cabi/load.d.ts +14 -0
  75. package/types/cabi/lower.d.ts +10 -0
  76. package/types/cabi/memory.d.ts +58 -0
  77. package/types/cabi/mod.d.ts +15 -0
  78. package/types/cabi/store.d.ts +12 -0
  79. package/types/cabi/strings.d.ts +23 -0
  80. package/types/cabi/trap.d.ts +11 -0
  81. package/types/cabi/types.d.ts +206 -0
  82. package/types/cabi/values.d.ts +5 -0
  83. package/types/cache/core.d.ts +97 -0
  84. package/types/cache/dir.d.ts +6 -0
  85. package/types/cache/mod.d.ts +3 -0
  86. package/types/cache/web.d.ts +10 -0
  87. package/types/digest/digest.d.ts +17 -0
  88. package/types/digest/mod.d.ts +2 -0
  89. package/types/digest/verify.d.ts +48 -0
  90. package/types/embedder/casing.d.ts +40 -0
  91. package/types/embedder/copy.d.ts +24 -0
  92. package/types/embedder/errors.d.ts +11 -0
  93. package/types/embedder/imports.d.ts +47 -0
  94. package/types/embedder/instantiate.d.ts +88 -0
  95. package/types/embedder/mod.d.ts +11 -0
  96. package/types/embedder/resources.d.ts +158 -0
  97. package/types/embedder/streams.d.ts +202 -0
  98. package/types/embedder/values.d.ts +70 -0
  99. package/types/embedder/version.d.ts +85 -0
  100. package/types/exec/boundary.d.ts +360 -0
  101. package/types/exec/executor.d.ts +125 -0
  102. package/types/exec/host_streams.d.ts +165 -0
  103. package/types/exec/mod.d.ts +3 -0
  104. package/types/intrinsics/async_builtins.d.ts +69 -0
  105. package/types/intrinsics/context.d.ts +28 -0
  106. package/types/intrinsics/errors.d.ts +5 -0
  107. package/types/intrinsics/fact_calls.d.ts +120 -0
  108. package/types/intrinsics/mod.d.ts +187 -0
  109. package/types/intrinsics/stream_builtins.d.ts +113 -0
  110. package/types/intrinsics/transcode.d.ts +21 -0
  111. package/types/jspi/bridge.d.ts +227 -0
  112. package/types/jspi/mechanics.d.ts +50 -0
  113. package/types/jspi/mod.d.ts +3 -0
  114. package/types/jspi/suspending.d.ts +1 -0
  115. package/types/jspi/types.d.ts +26 -0
  116. package/types/plan/format.d.ts +369 -0
  117. package/types/plan/loader.d.ts +113 -0
  118. package/types/plan/mod.d.ts +2 -0
  119. package/types/shim/mod.d.ts +1 -0
  120. package/types/shim/translator.d.ts +55 -0
  121. package/types/task/mod.d.ts +257 -0
  122. package/types/task/scheduler.d.ts +421 -0
  123. package/types/task/streams.d.ts +370 -0
  124. package/types/task/subtask.d.ts +96 -0
  125. package/types/task/thread.d.ts +73 -0
  126. package/types/task/waitable.d.ts +67 -0
@@ -0,0 +1,227 @@
1
+ import { type SuspendingImport } from "./mechanics.js";
2
+ import type { Cancelled, SchedulableThread, Store } from "../task/mod.js";
3
+ /** Which suspension discipline an instantiation runs under. */
4
+ export type SuspensionMode = "plain" | "jspi";
5
+ /**
6
+ * Decide the mode for one instantiation.
7
+ *
8
+ * `requested` is the embedder's opt-in. We additionally require the engine to
9
+ * actually implement JSPI: on an engine without it every blocking site falls
10
+ * back to the precise `NeedsJspi` it raised before this module existed, which
11
+ * is the M3 browser-matrix degradation path (docs/milestones.md M3).
12
+ */
13
+ export declare function chooseMode(requested: boolean | undefined, needed?: boolean): SuspensionMode;
14
+ /**
15
+ * Does a call through this trampoline declaration genuinely block — i.e. is
16
+ * it a reason a component NEEDS suspension support at all?
17
+ *
18
+ * Sharper than a kind list, and it must be: the async *form* of every copy /
19
+ * cancel built-in NEVER blocks — it returns `BLOCKED` and delivers the result
20
+ * through an event (definitions.py `stream_copy` line 2530 / `cancel_copy`
21
+ * 2636 / `canon_subtask_cancel` 2469, each `if not async_: ... else return
22
+ * BLOCKED`). Classifying by kind alone marked every instance that imports an
23
+ * async-form built-in as suspension-capable, which promising-wrapped its
24
+ * eagerly-completing FACT callees — and a wrapped eager callee reports
25
+ * STARTED where the reference reports RETURNED, and parks on a
26
+ * non-cancellable `awaitValue` where the reference delivers a synchronous
27
+ * cancellation (both asserted by big-interleaving-test.wast's expect-codes).
28
+ *
29
+ * Where the async-ness lives varies by kind, following wasmtime's trampoline
30
+ * layout (component/info.rs): copy built-ins carry an options index (the
31
+ * flag is `canonicalOptions[i].async`); the cancel forms and `subtask.cancel`
32
+ * carry `async` on the declaration itself; `waitable-set.wait`,
33
+ * `thread.yield` and `sync-start-call` are unconditionally block-capable
34
+ * (their non-blocking counterparts are separate kinds: poll, the YIELD
35
+ * callback code, async-start-call).
36
+ */
37
+ export declare function trampolineNeedsSuspension(t: {
38
+ kind: string;
39
+ async?: unknown;
40
+ options?: unknown;
41
+ }, optionsAsync: (index: number) => boolean): boolean;
42
+ /**
43
+ * Must the executor hand this trampoline to wasm as a `Suspending` import in
44
+ * jspi mode?
45
+ *
46
+ * A superset of `trampolineNeedsSuspension` by exactly two kinds, both for
47
+ * the same reason: they never block in the reference or in plain mode, but
48
+ * under jspi they may park the CALLER until a callee's state is determinate,
49
+ * because the engine defers a resumed activation's continuation to a
50
+ * microtask (jspi pin (j), `fastpath_hop_test.ts`):
51
+ *
52
+ * * `async-start-call` — parks until the freshly-started callee reaches
53
+ * resolution / completion / a genuine block (fact_calls.ts);
54
+ * * the async form of `subtask.cancel` — parks until a cancellation
55
+ * delivered by settling the callee's suspension has actually landed
56
+ * (async_builtins.ts; cancellable.wast asserts the reference's
57
+ * synchronous-delivery answers).
58
+ *
59
+ * Neither is a *reason* to choose jspi mode, and neither marks its importer
60
+ * suspendable (`Executor.suspendableFuncs`): their parks only ever trigger
61
+ * when the nested callee is itself promising-wrapped, i.e. when a genuine
62
+ * blocker has already contaminated the adapter through the transitive import
63
+ * rule. Marking on these kinds is not only unnecessary — it is wrong: the
64
+ * FACT adapter's `[adapter-callee]*` pass-through exports are what get
65
+ * passed to `*-start-call` as lift callees, and marking the whole adapter
66
+ * instance promoted every eagerly-completing callee to promising, recreating
67
+ * the STARTED-vs-RETURNED divergence one level up.
68
+ */
69
+ export declare function trampolineCanBlock(t: {
70
+ kind: string;
71
+ async?: unknown;
72
+ options?: unknown;
73
+ }, optionsAsync: (index: number) => boolean): boolean;
74
+ /**
75
+ * Does this component contain anything that can block a wasm frame?
76
+ *
77
+ * Computed from the plan, on the runtime side, so embedders (and the
78
+ * conformance harness) stay dumb — no plan v3 field, no flag to thread
79
+ * through. Deliberately a slight over-approximation: it asks "could this
80
+ * component ever reach a blocking built-in", not "will this call". A false
81
+ * positive costs a promising-wrapped entry (the export returns a Promise); a
82
+ * false negative would be a hard trap at the blocking site, so the bias is the
83
+ * safe one.
84
+ *
85
+ * The two sources of blocking, both straight from the reference:
86
+ *
87
+ * * a **stackful async lift** — async canonical options with no callback
88
+ * (`canon_lift` line 2179 runs the callee to completion on its own stack);
89
+ * * a **blocking built-in** reached synchronously — see
90
+ * `trampolineNeedsSuspension`.
91
+ */
92
+ export declare function planNeedsSuspension(plan: {
93
+ canonicalOptions: {
94
+ async: boolean;
95
+ callback: number | null;
96
+ }[];
97
+ trampolines: {
98
+ kind: string;
99
+ async?: unknown;
100
+ options?: unknown;
101
+ }[];
102
+ }): boolean;
103
+ /**
104
+ * Wrap a JS→wasm entry according to the mode.
105
+ *
106
+ * In `plain` mode this is the identity. In `jspi` mode the returned function
107
+ * always yields a Promise (empirical fact (e)), which is why the mode is an
108
+ * embedder opt-in: it changes the shape of every lifted export.
109
+ */
110
+ export declare function enterWasm<T extends (...a: never[]) => unknown>(fn: T, mode: SuspensionMode): T;
111
+ export declare function suspendingImport<T extends (...a: never[]) => unknown>(fn: T, mode: SuspensionMode): T | SuspendingImport;
112
+ /**
113
+ * Fail loudly at instantiate time if the two wrapping sites disagree.
114
+ *
115
+ * The dangerous direction, per jspi pin (c), is a `Suspending` import
116
+ * reachable from a non-`promising` activation — that traps unconditionally,
117
+ * even on the plain-value path. Entry wrapping in jspi mode is unconditional
118
+ * (every lifted export, callback, and block-capable FACT callee), so the
119
+ * structural invariant is `importsWrapped ⇒ entriesWrapped`, per mode.
120
+ *
121
+ * Entries-without-imports is legitimate: per-declaration classification
122
+ * (`trampolineNeedsSuspension`) wraps no imports in a component whose
123
+ * built-ins are all non-blocking async forms, while the mode can still be
124
+ * jspi via the lift-shape over-approximation in `planNeedsSuspension`
125
+ * (canonical options carrying `async` with no callback are counted whether
126
+ * they belong to a lift or to a copy built-in — the plan does not say which,
127
+ * and the false positive only costs Promise-shaped exports).
128
+ */
129
+ export declare function assertModeConsistent(mode: SuspensionMode, entriesWrapped: boolean, importsWrapped: boolean): void;
130
+ export declare class SuspensionPoint<T = unknown> implements SchedulableThread {
131
+ #private;
132
+ readonly task: any;
133
+ /** Resumable once this holds; `null` = only an explicit resume. */
134
+ readonly readyFunc: (() => boolean) | null;
135
+ readonly cancellable: boolean;
136
+ /** Produces the value to hand back to wasm at resume time. */
137
+ private readonly produce;
138
+ /**
139
+ * `finally`-style hook: runs EXACTLY ONCE, on whichever terminal
140
+ * transition this point takes — produce-success, produce-throw, or
141
+ * `abandon` (issue #102). It is the seam a blocking built-in uses to
142
+ * discharge state it owns for the duration of the park (the FACT
143
+ * start-calls' borrow-lender scopes, contracts/intrinsics.md v0.2
144
+ * amendment 2) without having to trust that `produce` runs.
145
+ *
146
+ * INVARIANTS this hook must respect, so bridge.ts's own contracts are
147
+ * not disturbed:
148
+ * * it must not throw (a throw here would escape `resume` *after* the
149
+ * import's Promise was settled, i.e. into whatever drained the
150
+ * scheduler); it is called inside a `try`/`catch` that reports such
151
+ * a throw rather than propagating it;
152
+ * * it must be idempotent-safe by construction anyway, because it runs
153
+ * AFTER `produce` on the success path — a built-in that already did
154
+ * its cleanup inside `produce` (to pin cleanup ordering relative to
155
+ * the produced value) sees this as a no-op backstop;
156
+ * * it must not resume/abandon this or any other suspension point.
157
+ */
158
+ private readonly onSettled?;
159
+ readonly promise: Promise<T>;
160
+ /**
161
+ * WHO the engine will resume when this point's promise settles.
162
+ *
163
+ * Captured HERE, at construction, and not derived at resume time: the
164
+ * blocking built-in that mints this point is running under the suspending
165
+ * activation's own ambient, so the ambient names that activation exactly.
166
+ * This is the replacement for the async-context store the scheduler
167
+ * used to rely on (M3A-1): same value, obtained by construction instead of
168
+ * by asking the platform to carry a context across the engine's resumption.
169
+ * `task.implicitThread` is the fallback for the one shape that has no
170
+ * ambient at all — a built-in reached during instantiation.
171
+ */
172
+ readonly owner: any;
173
+ constructor(store: Store, task: any,
174
+ /** Resumable once this holds; `null` = only an explicit resume. */
175
+ readyFunc: (() => boolean) | null, cancellable: boolean,
176
+ /** Produces the value to hand back to wasm at resume time. */
177
+ produce: (cancelled: Cancelled) => T, owner?: any,
178
+ /**
179
+ * `finally`-style hook: runs EXACTLY ONCE, on whichever terminal
180
+ * transition this point takes — produce-success, produce-throw, or
181
+ * `abandon` (issue #102). It is the seam a blocking built-in uses to
182
+ * discharge state it owns for the duration of the park (the FACT
183
+ * start-calls' borrow-lender scopes, contracts/intrinsics.md v0.2
184
+ * amendment 2) without having to trust that `produce` runs.
185
+ *
186
+ * INVARIANTS this hook must respect, so bridge.ts's own contracts are
187
+ * not disturbed:
188
+ * * it must not throw (a throw here would escape `resume` *after* the
189
+ * import's Promise was settled, i.e. into whatever drained the
190
+ * scheduler); it is called inside a `try`/`catch` that reports such
191
+ * a throw rather than propagating it;
192
+ * * it must be idempotent-safe by construction anyway, because it runs
193
+ * AFTER `produce` on the success path — a built-in that already did
194
+ * its cleanup inside `produce` (to pin cleanup ordering relative to
195
+ * the produced value) sees this as a no-op backstop;
196
+ * * it must not resume/abandon this or any other suspension point.
197
+ */
198
+ onSettled?: (() => void) | undefined);
199
+ waiting(): boolean;
200
+ ready(): boolean;
201
+ /** Settle the import's Promise; the engine resumes the wasm activation. */
202
+ resume(cancelled?: Cancelled): void;
203
+ /** Abandon this suspension without resuming the guest (teardown paths). */
204
+ abandon(reason: unknown): void;
205
+ }
206
+ /**
207
+ * The single shape every blocking built-in needs: "park the calling wasm frame
208
+ * until `readyFunc` holds, then hand it `produce()`".
209
+ *
210
+ * In `plain` mode the caller must not reach here — it raises `NeedsJspi` at
211
+ * its own site, with a message naming the operation, exactly as before. In
212
+ * `jspi` mode this returns a Promise, and because the built-in was
213
+ * `Suspending`-wrapped the engine suspends the activation on it.
214
+ */
215
+ export declare function blockCurrentActivation<T>(input: {
216
+ store: Store;
217
+ task: any;
218
+ readyFunc: (() => boolean) | null;
219
+ cancellable: boolean;
220
+ produce: (cancelled: Cancelled) => T;
221
+ /**
222
+ * Optional `finally`-style hook — see `SuspensionPoint.onSettled`. Use it
223
+ * for state that must be discharged however the park ends, including the
224
+ * settle paths that never call `produce` (issue #102).
225
+ */
226
+ onSettled?: () => void;
227
+ }): Promise<T>;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Opaque public alias for `WebAssembly.Suspending` instances.
3
+ *
4
+ * JSPI is not in the standard TS libs and JSR forbids global-type
5
+ * augmentation, so the engine surface is module-scoped (`jspiApi()` in
6
+ * ./types.ts) and the public API names this opaque brand; the value is
7
+ * exactly a `WebAssembly.Suspending`, usable anywhere an import value is
8
+ * expected.
9
+ */
10
+ export type SuspendingImport = {
11
+ readonly __polyengineSuspending: unique symbol;
12
+ };
13
+ /** True if the current engine implements `WebAssembly.promising` and
14
+ * `WebAssembly.Suspending`. Both are phase-4 API surface (docs/architecture.md §3): no
15
+ * fallback path exists or is planned for engines without them. */
16
+ export declare function isSupported(): boolean;
17
+ /** Throws if JSPI is not available in the current engine. Call this before
18
+ * using anything else in this module if you want a clear error instead of a
19
+ * `TypeError: WebAssembly.promising is not a function`. */
20
+ export declare function assertSupported(): void;
21
+ /**
22
+ * Wrap a wasm-exported function (as retrieved from
23
+ * `instance.exports.someExport`) so that calling it:
24
+ * - always returns a Promise,
25
+ * - suspends the underlying wasm activation (rather than trapping) the
26
+ * first time it calls a `Suspending`-wrapped import that itself returns
27
+ * a genuine Promise,
28
+ * - resolves that Promise with the export's return value once the wasm
29
+ * activation runs to completion (after zero or more suspend/resume
30
+ * cycles).
31
+ *
32
+ * This is a direct type-safe pass-through of `WebAssembly.promising`; it
33
+ * does no extra bookkeeping. `TArgs`/`TReturn` are the caller's own
34
+ * annotation of the underlying export's signature (not reflected — see
35
+ * docs/architecture.md §3's note on js-types being flagged/phase-3).
36
+ */
37
+ export declare function makePromising<TArgs extends unknown[] = unknown[], TReturn = unknown>(wasmExport: (...args: TArgs) => TReturn): (...args: TArgs) => Promise<TReturn>;
38
+ /**
39
+ * Wrap a JS function as a `Suspending` import: when a `promising`-suspendable
40
+ * wasm activation calls it (per the frame rule above) and it returns a
41
+ * genuine Promise, the wasm activation suspends until that Promise settles;
42
+ * if it returns a non-Promise value (or the call site is not suspension-
43
+ * eligible), the value passes straight through — the "fast path", pinned in
44
+ * `suspending_import_test.ts::non_promise_return_is_fast_path`.
45
+ *
46
+ * The returned value is an opaque `WebAssembly.Suspending` instance; hand it
47
+ * directly to the instantiation `imports` object in the slot the wasm module
48
+ * expects a function import.
49
+ */
50
+ export declare function makeSuspending<TArgs extends unknown[] = unknown[], TReturn = unknown>(fn: (...args: TArgs) => TReturn | Promise<TReturn>): SuspendingImport;
@@ -0,0 +1,3 @@
1
+ export * from "./mechanics.js";
2
+ export * from "./bridge.js";
3
+ export * from "./suspending.js";
@@ -0,0 +1 @@
1
+ export { anySuspendingImport, isSuspending, suspending } from "@polyengine/protocol";
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The engine's JSPI surface, as probed.
3
+ *
4
+ * `Suspending` wraps a JS function that returns a Promise (or any value —
5
+ * the fast path pinned in `suspending_import_test.ts`) so it can be called
6
+ * as a wasm import that may suspend the calling wasm activation. It must
7
+ * only actually suspend while every frame between the nearest enclosing
8
+ * `promising`-wrapped entry and the call is a wasm frame — the "frame
9
+ * rule" (docs/architecture.md §5; `frame_rule_test.ts` pins the observed
10
+ * error shape).
11
+ *
12
+ * `promising` wraps a wasm-exported function so that calling it returns a
13
+ * Promise instead of (potentially) suspending the JS caller: the wasm
14
+ * activation becomes suspendable, and any `Suspending` import it calls
15
+ * transfers control back to the event loop instead of trapping.
16
+ */
17
+ export interface JspiApi {
18
+ Suspending: new (fn: (...args: any[]) => any) => object;
19
+ promising: (fn: (...args: any[]) => any) => (...args: any[]) => Promise<any>;
20
+ }
21
+ /**
22
+ * The engine's JSPI API, or `null` where the proposal is not implemented.
23
+ * The one sanctioned way to reach `WebAssembly.Suspending`/`promising`
24
+ * from this codebase's published modules.
25
+ */
26
+ export declare function jspiApi(): JspiApi | null;
@@ -0,0 +1,369 @@
1
+ /** Core wasm lane types as emitted in `coreType` and `rep` fields. */
2
+ export type WireCoreType = "i32" | "i64" | "f32" | "f64";
3
+ export interface WirePlan {
4
+ formatVersion: number;
5
+ producer: {
6
+ shimVersion: string;
7
+ wasmtimeEnviron: string;
8
+ features: string[];
9
+ };
10
+ component: {
11
+ sha256: string;
12
+ len: number;
13
+ };
14
+ modules: WireModule[];
15
+ initializers: WireInitializer[];
16
+ trampolines: WireTrampoline[];
17
+ canonicalOptions: WireCanonicalOptions[];
18
+ types: WireTypeDecl[];
19
+ resourceTables: WireResourceTable[];
20
+ /**
21
+ * Stream-table metadata (plan v2), index space == wasmtime's
22
+ * `TypeStreamTableIndex`; referenced by the `streamTable` field of every
23
+ * `stream.*` trampoline. `element` is the `T` of `stream<T>`, `null` for the
24
+ * zero-width payload.
25
+ *
26
+ * ISSUE #94(2): the shim never `skip_serializing_if`s this field
27
+ * (crates/translator-shim/src/plan.rs), so every v2 plan the producer
28
+ * emits carries it (`[]` when empty). Required, not optional: the loader
29
+ * only ever accepts `formatVersion === 2` (strict equality,
30
+ * `SUPPORTED_FORMAT_VERSION`), so there is no live v1-compat path that
31
+ * needs this to be absent.
32
+ */
33
+ streamTables: WireAsyncTable[];
34
+ /** Future-table metadata (plan v2); see `streamTables`. */
35
+ futureTables: WireAsyncTable[];
36
+ /**
37
+ * Error-context-table metadata (plan v3), index space == wasmtime's
38
+ * `TypeComponentLocalErrorContextTableIndex` — the space the
39
+ * `error-context-transfer` trampoline's `srcTable`/`dstTable` *runtime*
40
+ * arguments live in. No element type: wasmtime's `TypeErrorContextTable`
41
+ * is `{ instance }` and nothing else.
42
+ *
43
+ * Required for the same reason as `streamTables`/`futureTables`: the shim
44
+ * always serializes it and the loader accepts only `formatVersion === 3`.
45
+ */
46
+ errorContextTables: WireErrorContextTable[];
47
+ /**
48
+ * Resource types the component imports, in `ResourceIndex` order:
49
+ * `ResourceIndex = importedResources.length + DefinedResourceIndex`
50
+ * (wasmtime `Component::resource_index`).
51
+ *
52
+ * plan-format.md v0.1 amendment #2 documents this as a *gap*; the field is
53
+ * a **v0.2 proposal** emitted by the shim. Optional here so plans produced
54
+ * by a v0.1 shim still load — absent is read as "no imported resources",
55
+ * which is exactly what v0.1 asserted.
56
+ */
57
+ importedResources?: WireImportedResource[];
58
+ imports: WireImport[];
59
+ exports: WireExport[];
60
+ worldDigest: string;
61
+ }
62
+ export type WireModule = {
63
+ kind: "embedded";
64
+ offset: number;
65
+ len: number;
66
+ } | {
67
+ kind: "adapter";
68
+ file: string;
69
+ len: number;
70
+ intrinsics: WireIntrinsicEntry[];
71
+ };
72
+ export interface WireIntrinsicEntry {
73
+ module: string;
74
+ name: string;
75
+ category: string;
76
+ def: WireCoreDef;
77
+ }
78
+ export type WireInitializer = {
79
+ op: "instantiate-module";
80
+ module: number;
81
+ instance: number | null;
82
+ args: WireCoreDef[];
83
+ } | {
84
+ op: "lower-import";
85
+ index: number;
86
+ import: number;
87
+ } | {
88
+ op: "extract-memory";
89
+ index: number;
90
+ export: WireCoreExport;
91
+ } | {
92
+ op: "extract-realloc";
93
+ index: number;
94
+ def: WireCoreDef;
95
+ } | {
96
+ op: "extract-callback";
97
+ index: number;
98
+ def: WireCoreDef;
99
+ } | {
100
+ op: "extract-post-return";
101
+ index: number;
102
+ def: WireCoreDef;
103
+ } | {
104
+ op: "extract-table";
105
+ index: number;
106
+ export: WireCoreExport;
107
+ } | {
108
+ op: "resource";
109
+ index: number;
110
+ rep: WireCoreType;
111
+ dtor: WireCoreDef | null;
112
+ instance: number;
113
+ };
114
+ export type WireCoreDef = {
115
+ kind: "export";
116
+ instance: number;
117
+ item: WireExportItem;
118
+ } | {
119
+ kind: "instance-flags";
120
+ instance: number;
121
+ } | {
122
+ kind: "trampoline";
123
+ index: number;
124
+ }
125
+ /**
126
+ * `CoreDef::UnsafeIntrinsic` (plan v1 / contracts/plan-format.md v0.3).
127
+ * `intrinsic` is wasmtime's stable symbol name
128
+ * (`UnsafeIntrinsic::name()`), not an enum ordinal. The executor
129
+ * materializes `context-{get,set}-i32-{0,1}` as host functions over the
130
+ * current thread's context storage (definitions.py `canon_context_get` /
131
+ * `canon_context_set`, lines 2348/2358) and fails at instantiate time on
132
+ * every other symbol.
133
+ */
134
+ | {
135
+ kind: "unsafe-intrinsic";
136
+ intrinsic: string;
137
+ } | {
138
+ kind: "task-may-block";
139
+ };
140
+ export interface WireCoreExport {
141
+ instance: number;
142
+ item: WireExportItem;
143
+ }
144
+ export interface WireExportItem {
145
+ name: string;
146
+ space: "func" | "table" | "memory" | "global" | "tag" | "unknown";
147
+ }
148
+ /**
149
+ * Trampoline declarations, tag-for-tag with the wasmtime `Trampoline` enum.
150
+ * Only the M0-relevant variants are given precise field types; the rest are
151
+ * matched by `kind` and rejected at instantiate time with milestone-aware
152
+ * errors (contracts/intrinsics.md §B).
153
+ */
154
+ export type WireTrampoline = {
155
+ kind: "lower-import";
156
+ index: number;
157
+ lowered: number;
158
+ options: number;
159
+ type: number;
160
+ } | {
161
+ kind: "trap";
162
+ index: number;
163
+ } | {
164
+ kind: "enter-sync-call";
165
+ index: number;
166
+ } | {
167
+ kind: "exit-sync-call";
168
+ index: number;
169
+ } | {
170
+ kind: "task-return";
171
+ index: number;
172
+ instance: number;
173
+ /**
174
+ * The **raw** wasmtime `TypeTupleIndex` of the task's declared results
175
+ * (plan v3; in v2 this field held the interned `plan.types` index that
176
+ * `resultType` now carries). It is the key FACT's `prepare-call` passes
177
+ * as `task_return_type` at runtime, so it is what lets a FACT callee task
178
+ * find its own declared result type.
179
+ */
180
+ results: number;
181
+ /**
182
+ * `results` interned into `plan.types` as a tuple type (plan v3,
183
+ * contracts/plan-format.md v3 amendment 3). `null` is accepted on the
184
+ * wire for a task with no declared result type; the current producer
185
+ * never emits it (wasmtime's `TaskReturn.results` is not an `Option` —
186
+ * a no-result task carries the empty tuple).
187
+ */
188
+ resultType: number | null;
189
+ options: number;
190
+ } | {
191
+ kind: "resource-drop" | "resource-new" | "resource-rep";
192
+ index: number;
193
+ instance: number;
194
+ resource: number;
195
+ } | {
196
+ kind: string;
197
+ index: number;
198
+ [field: string]: unknown;
199
+ };
200
+ export interface WireCanonicalOptions {
201
+ instance: number;
202
+ stringEncoding: "utf8" | "utf16" | "latin1+utf16";
203
+ memory: number | null;
204
+ realloc: number | null;
205
+ postReturn: number | null;
206
+ callback: number | null;
207
+ async: boolean;
208
+ cancellable: boolean;
209
+ coreType: {
210
+ params: WireCoreType[];
211
+ results: WireCoreType[];
212
+ };
213
+ }
214
+ /** descriptor-ir.md ValType JSON (nested structurally). */
215
+ export type WireValType = {
216
+ kind: "bool" | "s8" | "u8" | "s16" | "u16" | "s32" | "u32" | "s64" | "u64" | "f32" | "f64" | "char" | "string" | "error-context";
217
+ } | {
218
+ kind: "list";
219
+ element: WireValType;
220
+ length?: number;
221
+ } | {
222
+ kind: "record";
223
+ fields: {
224
+ label: string;
225
+ type: WireValType;
226
+ }[];
227
+ } | {
228
+ kind: "tuple";
229
+ elements: WireValType[];
230
+ } | {
231
+ kind: "variant";
232
+ cases: {
233
+ label: string;
234
+ type: WireValType | null;
235
+ }[];
236
+ } | {
237
+ kind: "enum";
238
+ labels: string[];
239
+ } | {
240
+ kind: "option";
241
+ type: WireValType;
242
+ } | {
243
+ kind: "result";
244
+ ok: WireValType | null;
245
+ err: WireValType | null;
246
+ } | {
247
+ kind: "map";
248
+ key: WireValType;
249
+ value: WireValType;
250
+ } | {
251
+ kind: "flags";
252
+ labels: string[];
253
+ } | {
254
+ kind: "own";
255
+ resource: number;
256
+ } | {
257
+ kind: "borrow";
258
+ resource: number;
259
+ } | {
260
+ kind: "stream";
261
+ element: WireValType | null;
262
+ } | {
263
+ kind: "future";
264
+ element: WireValType | null;
265
+ };
266
+ export type WireTypeDecl = {
267
+ kind: "func";
268
+ params: {
269
+ label: string;
270
+ type: WireValType;
271
+ }[];
272
+ results: WireValType[];
273
+ async: boolean;
274
+ } | WireValType;
275
+ export type WireResourceTable = {
276
+ kind: "concrete";
277
+ resource: number;
278
+ instance: number;
279
+ } | {
280
+ kind: "abstract";
281
+ id: number;
282
+ };
283
+ /** One stream or future table (plan v2). */
284
+ /** One error-context table: the owning component instance, nothing else. */
285
+ export interface WireErrorContextTable {
286
+ instance: number;
287
+ }
288
+ export interface WireAsyncTable {
289
+ element: WireValType | null;
290
+ instance: number;
291
+ }
292
+ /** One imported resource type: back-reference into `plan.imports`. */
293
+ export interface WireImportedResource {
294
+ /** `RuntimeImportIndex` — index into `plan.imports`. */
295
+ import: number;
296
+ }
297
+ export interface WireImport {
298
+ name: string;
299
+ path: string[];
300
+ kind: string;
301
+ type?: number;
302
+ }
303
+ export type WireExport = {
304
+ kind: "lifted-func";
305
+ name: string;
306
+ coreDef: WireCoreDef;
307
+ options: number;
308
+ type: number;
309
+ } | {
310
+ kind: "instance";
311
+ name: string;
312
+ exports: WireExport[];
313
+ } | {
314
+ kind: "type";
315
+ name: string;
316
+ type: WireTypeExport;
317
+ }
318
+ /**
319
+ * An exported embedded core module; `module` indexes the static module
320
+ * space (`modules`). plan-format.md v4 amendment 2.
321
+ */
322
+ | {
323
+ kind: "module";
324
+ name: string;
325
+ module: number;
326
+ };
327
+ export type WireTypeExport = {
328
+ kind: "resource";
329
+ resource: number;
330
+ } | {
331
+ kind: "value";
332
+ type: number;
333
+ };
334
+ /**
335
+ * The shim's C-ABI envelope: plan + adapter artifacts in one JSON document
336
+ * (crates/translator-shim/README.md documents the 1:1 mapping to the
337
+ * contract's artifact set).
338
+ */
339
+ export interface WireEnvelope {
340
+ plan?: WirePlan;
341
+ adapters?: {
342
+ file: string;
343
+ wasm: string;
344
+ }[];
345
+ /** Failure message (v0.1 shape; unchanged meaning). */
346
+ error?: string;
347
+ /**
348
+ * Structured verdict accompanying `error` (contracts v0.2 proposal). Absent
349
+ * from v0.1 producers; consumers must tolerate that (treat as phase
350
+ * `"internal"`, i.e. "not a statement about the component").
351
+ */
352
+ errorDetail?: WireErrorDetail;
353
+ }
354
+ /**
355
+ * Structured translation failure.
356
+ *
357
+ * `phase` is the load-bearing field: only `"validation"` means *the component
358
+ * is invalid/malformed* — the verdict the official suite's `assert_invalid` /
359
+ * `assert_malformed` commands require. `"unsupported"` means the component is
360
+ * valid but uses a shape this plan-format version cannot express, and
361
+ * `"internal"` is a shim bug. Neither of the latter two may be scored as a
362
+ * correct rejection.
363
+ */
364
+ export interface WireErrorDetail {
365
+ phase: "validation" | "unsupported" | "internal";
366
+ message: string;
367
+ /** Full error chain, diagnostics only. */
368
+ detail?: string;
369
+ }