@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.
- package/LICENSE +202 -0
- package/README.md +23 -0
- package/esm/cabi/async_values.js +162 -0
- package/esm/cabi/bulk_lists.js +198 -0
- package/esm/cabi/context.js +42 -0
- package/esm/cabi/flatten.js +145 -0
- package/esm/cabi/float.js +67 -0
- package/esm/cabi/handles.js +253 -0
- package/esm/cabi/layout.js +149 -0
- package/esm/cabi/lift.js +196 -0
- package/esm/cabi/load.js +146 -0
- package/esm/cabi/lower.js +141 -0
- package/esm/cabi/memory.js +182 -0
- package/esm/cabi/mod.js +22 -0
- package/esm/cabi/store.js +186 -0
- package/esm/cabi/strings.js +336 -0
- package/esm/cabi/trap.js +38 -0
- package/esm/cabi/types.js +264 -0
- package/esm/cabi/values.js +64 -0
- package/esm/cache/core.js +156 -0
- package/esm/cache/dir.js +170 -0
- package/esm/cache/mod.js +4 -0
- package/esm/cache/web.js +136 -0
- package/esm/digest/digest.js +332 -0
- package/esm/digest/mod.js +3 -0
- package/esm/digest/verify.js +129 -0
- package/esm/embedder/casing.js +56 -0
- package/esm/embedder/copy.js +42 -0
- package/esm/embedder/errors.js +26 -0
- package/esm/embedder/imports.js +63 -0
- package/esm/embedder/instantiate.js +978 -0
- package/esm/embedder/mod.js +40 -0
- package/esm/embedder/resources.js +406 -0
- package/esm/embedder/streams.js +770 -0
- package/esm/embedder/values.js +450 -0
- package/esm/embedder/version.js +273 -0
- package/esm/exec/boundary.js +1902 -0
- package/esm/exec/executor.js +1004 -0
- package/esm/exec/host_streams.js +818 -0
- package/esm/exec/mod.js +4 -0
- package/esm/intrinsics/async_builtins.js +510 -0
- package/esm/intrinsics/context.js +90 -0
- package/esm/intrinsics/errors.js +13 -0
- package/esm/intrinsics/fact_calls.js +865 -0
- package/esm/intrinsics/mod.js +564 -0
- package/esm/intrinsics/stream_builtins.js +578 -0
- package/esm/intrinsics/transcode.js +443 -0
- package/esm/jspi/bridge.js +579 -0
- package/esm/jspi/mechanics.js +89 -0
- package/esm/jspi/mod.js +5 -0
- package/esm/jspi/suspending.js +15 -0
- package/esm/jspi/types.js +29 -0
- package/esm/package.json +3 -0
- package/esm/plan/format.js +5 -0
- package/esm/plan/loader.js +657 -0
- package/esm/plan/mod.js +3 -0
- package/esm/shim/mod.js +2 -0
- package/esm/shim/translator.js +94 -0
- package/esm/task/mod.js +483 -0
- package/esm/task/scheduler.js +1028 -0
- package/esm/task/streams.js +786 -0
- package/esm/task/subtask.js +135 -0
- package/esm/task/thread.js +255 -0
- package/esm/task/waitable.js +144 -0
- package/package.json +91 -0
- package/types/cabi/async_values.d.ts +35 -0
- package/types/cabi/bulk_lists.d.ts +18 -0
- package/types/cabi/context.d.ts +59 -0
- package/types/cabi/flatten.d.ts +14 -0
- package/types/cabi/float.d.ts +14 -0
- package/types/cabi/handles.d.ts +70 -0
- package/types/cabi/layout.d.ts +13 -0
- package/types/cabi/lift.d.ts +25 -0
- package/types/cabi/load.d.ts +14 -0
- package/types/cabi/lower.d.ts +10 -0
- package/types/cabi/memory.d.ts +58 -0
- package/types/cabi/mod.d.ts +15 -0
- package/types/cabi/store.d.ts +12 -0
- package/types/cabi/strings.d.ts +23 -0
- package/types/cabi/trap.d.ts +11 -0
- package/types/cabi/types.d.ts +206 -0
- package/types/cabi/values.d.ts +5 -0
- package/types/cache/core.d.ts +97 -0
- package/types/cache/dir.d.ts +6 -0
- package/types/cache/mod.d.ts +3 -0
- package/types/cache/web.d.ts +10 -0
- package/types/digest/digest.d.ts +17 -0
- package/types/digest/mod.d.ts +2 -0
- package/types/digest/verify.d.ts +48 -0
- package/types/embedder/casing.d.ts +40 -0
- package/types/embedder/copy.d.ts +24 -0
- package/types/embedder/errors.d.ts +11 -0
- package/types/embedder/imports.d.ts +47 -0
- package/types/embedder/instantiate.d.ts +88 -0
- package/types/embedder/mod.d.ts +11 -0
- package/types/embedder/resources.d.ts +158 -0
- package/types/embedder/streams.d.ts +202 -0
- package/types/embedder/values.d.ts +70 -0
- package/types/embedder/version.d.ts +85 -0
- package/types/exec/boundary.d.ts +360 -0
- package/types/exec/executor.d.ts +125 -0
- package/types/exec/host_streams.d.ts +165 -0
- package/types/exec/mod.d.ts +3 -0
- package/types/intrinsics/async_builtins.d.ts +69 -0
- package/types/intrinsics/context.d.ts +28 -0
- package/types/intrinsics/errors.d.ts +5 -0
- package/types/intrinsics/fact_calls.d.ts +120 -0
- package/types/intrinsics/mod.d.ts +187 -0
- package/types/intrinsics/stream_builtins.d.ts +113 -0
- package/types/intrinsics/transcode.d.ts +21 -0
- package/types/jspi/bridge.d.ts +227 -0
- package/types/jspi/mechanics.d.ts +50 -0
- package/types/jspi/mod.d.ts +3 -0
- package/types/jspi/suspending.d.ts +1 -0
- package/types/jspi/types.d.ts +26 -0
- package/types/plan/format.d.ts +369 -0
- package/types/plan/loader.d.ts +113 -0
- package/types/plan/mod.d.ts +2 -0
- package/types/shim/mod.d.ts +1 -0
- package/types/shim/translator.d.ts +55 -0
- package/types/task/mod.d.ts +257 -0
- package/types/task/scheduler.d.ts +421 -0
- package/types/task/streams.d.ts +370 -0
- package/types/task/subtask.d.ts +96 -0
- package/types/task/thread.d.ts +73 -0
- package/types/task/waitable.d.ts +67 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { WirePlan } from "../plan/format.js";
|
|
2
|
+
/**
|
|
3
|
+
* The minimal surface `translateCached`/`keyFor` need from a translator.
|
|
4
|
+
* Structural (not `Translator` itself) so tests can substitute a spy that
|
|
5
|
+
* proves the shim path was/wasn't exercised, without subclassing the real
|
|
6
|
+
* wasm-backed client.
|
|
7
|
+
*/
|
|
8
|
+
export interface TranslatorLike {
|
|
9
|
+
readonly buildHash: string | null;
|
|
10
|
+
translateRaw(componentBytes: Uint8Array): string;
|
|
11
|
+
}
|
|
12
|
+
/** Cache layout version. Bumped on any incompatible on-disk/on-Cache-API
|
|
13
|
+
* schema change; an unrecognized version is read back as a miss (never a
|
|
14
|
+
* crash) so stale caches from an older build self-heal by re-translating —
|
|
15
|
+
* and this self-healing holds even when the cache root itself is
|
|
16
|
+
* unwritable (issue #196): the eviction attempt that a layout mismatch
|
|
17
|
+
* triggers is swallowed internally by the backend, so a read-only
|
|
18
|
+
* pre-warmed cache from an older layout degrades to "always miss, always
|
|
19
|
+
* re-translate" rather than throwing. */
|
|
20
|
+
export declare const CACHE_LAYOUT_VERSION = 1;
|
|
21
|
+
/** The three-part identity a translation is content-addressed by. */
|
|
22
|
+
export interface CacheKey {
|
|
23
|
+
/** hex sha256 of the component bytes (matches `plan.component.sha256`). */
|
|
24
|
+
componentSha256: string;
|
|
25
|
+
/**
|
|
26
|
+
* hex sha256 of the translator (shim) wasm bytes — `Translator.buildHash`.
|
|
27
|
+
* NOT the envelope's `producer.shimVersion`/`wasmtimeEnviron`: those don't
|
|
28
|
+
* change across a shim rebuild with identical pinned versions but
|
|
29
|
+
* different generated code (see `Translator.buildHash` docs).
|
|
30
|
+
*/
|
|
31
|
+
translatorBuildHash: string;
|
|
32
|
+
/** wasmparser feature set used, order-insensitive. */
|
|
33
|
+
features: string[];
|
|
34
|
+
}
|
|
35
|
+
/** What a cache hit returns: enough to instantiate, given the caller's own
|
|
36
|
+
* (already-in-hand) component bytes. */
|
|
37
|
+
export interface CachedArtifacts {
|
|
38
|
+
plan: WirePlan;
|
|
39
|
+
/** Adapter artifacts keyed by `plan.modules[].file`, same shape as
|
|
40
|
+
* `TranslationResult.adapters`. */
|
|
41
|
+
adapters: Map<string, Uint8Array>;
|
|
42
|
+
}
|
|
43
|
+
export interface ArtifactCache {
|
|
44
|
+
get(key: CacheKey): Promise<CachedArtifacts | null>;
|
|
45
|
+
put(key: CacheKey, artifacts: CachedArtifacts): Promise<void>;
|
|
46
|
+
/** Remove a poisoned/stale entry. Cache backends also call this
|
|
47
|
+
* internally on a failed integrity check during `get`. */
|
|
48
|
+
evict(key: CacheKey): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
/** On-disk / on-Cache-API metadata envelope stored alongside the plan. */
|
|
51
|
+
export interface CacheMeta {
|
|
52
|
+
layoutVersion: number;
|
|
53
|
+
componentSha256: string;
|
|
54
|
+
translatorBuildHash: string;
|
|
55
|
+
features: string[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The stable cache key string: sha256 over a canonical JSON encoding of the
|
|
59
|
+
* `CacheKey` (features sorted so order never causes a spurious miss).
|
|
60
|
+
*/
|
|
61
|
+
export declare function keyHex(key: CacheKey): Promise<string>;
|
|
62
|
+
/** Compute the `CacheKey` for a `(translator, componentBytes)` pair. Throws
|
|
63
|
+
* if the translator has no `buildHash` (constructed from a pre-compiled
|
|
64
|
+
* `WebAssembly.Module` with no bytes available — see `Translator.create`). */
|
|
65
|
+
export declare function keyFor(translator: TranslatorLike, componentBytes: Uint8Array, features?: string[]): Promise<CacheKey>;
|
|
66
|
+
export interface TranslateCachedOptions {
|
|
67
|
+
features?: string[];
|
|
68
|
+
/**
|
|
69
|
+
* Opt-in determinism guard (tests only, per dispatch): after a cache miss,
|
|
70
|
+
* translate a second time and assert byte-identical envelope JSON before
|
|
71
|
+
* trusting/storing the result. Throws `Error` on mismatch.
|
|
72
|
+
*/
|
|
73
|
+
verifyDeterminism?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Opt-in diagnostic (issue #196): invoked when a `cache.get`/`cache.put`
|
|
76
|
+
* failure is swallowed so the degradation is observable without this
|
|
77
|
+
* library ever writing to the console itself. `op` identifies which
|
|
78
|
+
* call failed; `err` is the original thrown value, unmodified. Default
|
|
79
|
+
* is to do nothing. If this callback itself throws, that throw is also
|
|
80
|
+
* swallowed — a diagnostic hook must never become a new way to fail a
|
|
81
|
+
* translation.
|
|
82
|
+
*/
|
|
83
|
+
onCacheError?: (op: "get" | "put", err: unknown) => void;
|
|
84
|
+
}
|
|
85
|
+
export interface TranslateCachedResult {
|
|
86
|
+
plan: WirePlan;
|
|
87
|
+
adapters: Map<string, Uint8Array>;
|
|
88
|
+
/** Whether this result came from the cache (`true`) or a fresh shim
|
|
89
|
+
* translation (`false`). Exposed for tests/observability; not part of the
|
|
90
|
+
* `ArtifactCache` contract itself. */
|
|
91
|
+
fromCache: boolean;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Orchestration helper: cache hit -> stored artifacts, cache miss ->
|
|
95
|
+
* translate with the shim, store, return.
|
|
96
|
+
*/
|
|
97
|
+
export declare function translateCached(translator: TranslatorLike, componentBytes: Uint8Array, cache: ArtifactCache, opts?: TranslateCachedOptions): Promise<TranslateCachedResult>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ArtifactCache } from "./core.js";
|
|
2
|
+
/** A filesystem-backed `ArtifactCache` rooted at `path` (created on first
|
|
3
|
+
* `put` if missing). Deno only: every method calls `Deno.*` directly. On other
|
|
4
|
+
* platforms use `webCache()` (./web.ts), or supply your own `ArtifactCache` —
|
|
5
|
+
* the interface is three methods (./core.ts). */
|
|
6
|
+
export declare function dirCache(path: string): ArtifactCache;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ArtifactCache } from "./core.js";
|
|
2
|
+
/** Thrown when the Cache API isn't available in this environment. */
|
|
3
|
+
export declare class WebCacheUnavailableError extends Error {
|
|
4
|
+
constructor();
|
|
5
|
+
}
|
|
6
|
+
/** A `Cache`-API-backed `ArtifactCache` under the given cache name. Throws
|
|
7
|
+
* `WebCacheUnavailableError` (at call time, not construction time, so
|
|
8
|
+
* feature-detection failures surface where they're actually hit) when
|
|
9
|
+
* `globalThis.caches` doesn't exist. */
|
|
10
|
+
export declare function webCache(name: string): ArtifactCache;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { WirePlan } from "../plan/format.js";
|
|
2
|
+
export declare const CEWD_VERSION = 1;
|
|
3
|
+
export declare class DigestError extends Error {
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
export interface WorldDigestResult {
|
|
7
|
+
canonicalJson: string;
|
|
8
|
+
digest: string;
|
|
9
|
+
}
|
|
10
|
+
/** Compute the canonical world digest from a loaded wire plan. */
|
|
11
|
+
export declare function computeWorldDigest(plan: WirePlan): Promise<WorldDigestResult>;
|
|
12
|
+
/**
|
|
13
|
+
* Recursively sort object keys (alphabetically) and serialize with no extra
|
|
14
|
+
* whitespace. Array order is preserved verbatim — this must match
|
|
15
|
+
* `crates/bindgen/src/digest.rs::canonical_string` byte-for-byte.
|
|
16
|
+
*/
|
|
17
|
+
export declare function canonicalStringify(v: unknown): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { WirePlan } from "../plan/format.js";
|
|
2
|
+
export interface DigestMismatch {
|
|
3
|
+
expected: string;
|
|
4
|
+
actual: string;
|
|
5
|
+
/** Human-readable description of the first structural divergence found,
|
|
6
|
+
* or `null` if a divergence exists but no finer-grained cause could be
|
|
7
|
+
* isolated (e.g. the two canonical JSON trees have the same top-level
|
|
8
|
+
* shape but the digest still differs — should not happen in practice
|
|
9
|
+
* since the digest is a pure hash of that JSON, but guarded anyway). */
|
|
10
|
+
firstDivergence: string | null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Thrown by generated `instantiate` wrappers when the loaded plan's world
|
|
14
|
+
* digest does not match the constant bindgen embedded at generation time
|
|
15
|
+
* (contracts/digest.md: "fails fast with a structural diff on mismatch").
|
|
16
|
+
* Raised BEFORE the component is instantiated, so no guest code has run
|
|
17
|
+
* when a caller catches this.
|
|
18
|
+
*
|
|
19
|
+
* Named and catchable: `err instanceof WorldDigestMismatchError`, or
|
|
20
|
+
* `err.name === "WorldDigestMismatchError"` across realms.
|
|
21
|
+
*/
|
|
22
|
+
export declare class WorldDigestMismatchError extends Error {
|
|
23
|
+
readonly name = "WorldDigestMismatchError";
|
|
24
|
+
/** The world these bindings were generated from. */
|
|
25
|
+
readonly world: string;
|
|
26
|
+
/** The full mismatch report (expected/actual digest, first divergence). */
|
|
27
|
+
readonly mismatch: DigestMismatch;
|
|
28
|
+
constructor(world: string, mismatch: DigestMismatch);
|
|
29
|
+
/** Digest the generated bindings were built against. */
|
|
30
|
+
get expected(): string;
|
|
31
|
+
/** Digest computed from the plan actually loaded. */
|
|
32
|
+
get actual(): string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Verify `plan`'s computed world digest against `expectedDigest` (the
|
|
36
|
+
* constant bindgen embedded at generation time). Returns `null` on match,
|
|
37
|
+
* or a `DigestMismatch` report naming the first divergent path on
|
|
38
|
+
* mismatch.
|
|
39
|
+
*/
|
|
40
|
+
export declare function verifyWorldDigest(plan: WirePlan, expectedDigest: string): Promise<DigestMismatch | null>;
|
|
41
|
+
/**
|
|
42
|
+
* `diffWorldDigest` — richer variant for tests/tooling: compare against
|
|
43
|
+
* another plan's (or a WIT-derived) canonical JSON directly, walking both
|
|
44
|
+
* trees in parallel to name the first divergent import/export/type path.
|
|
45
|
+
* `expectedCanonicalJson` is normally produced by `crates/bindgen`'s
|
|
46
|
+
* `digest --json` output, or by `computeWorldDigest` on a reference plan.
|
|
47
|
+
*/
|
|
48
|
+
export declare function diffWorldDigest(plan: WirePlan, expectedCanonicalJson: string): Promise<DigestMismatch | null>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `get-resolution` -> `getResolution`.
|
|
3
|
+
*
|
|
4
|
+
* The rule, stated exactly: split the label on `-`; the first fragment is
|
|
5
|
+
* unchanged; every later fragment has its first character upper-cased and its
|
|
6
|
+
* remainder preserved. Preserving the remainder is what keeps acronym
|
|
7
|
+
* fragments intact — `outgoing-HTTP-request` -> `outgoingHTTPRequest` — which
|
|
8
|
+
* a naive `toLowerCase()` of the tail would destroy.
|
|
9
|
+
*
|
|
10
|
+
* WIT labels are already lower-kebab in practice, so the first fragment needs
|
|
11
|
+
* no adjustment; nothing here lower-cases anything.
|
|
12
|
+
*/
|
|
13
|
+
export declare function camelCase(label: string): string;
|
|
14
|
+
/** `tcp-socket` -> `TcpSocket` (resource class names). */
|
|
15
|
+
export declare function pascalCase(label: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* A leaf name in `plan.exports` / `plan.imports`, decoded.
|
|
18
|
+
*
|
|
19
|
+
* The Component Model mangles resource membership into the name itself
|
|
20
|
+
* (`[constructor]counter`, `[method]counter.increment`,
|
|
21
|
+
* `[static]counter.merge`); C0 finding #2 was embedders hand-transcribing
|
|
22
|
+
* these. Assembling and disassembling them is a runtime obligation.
|
|
23
|
+
*/
|
|
24
|
+
export type LeafName = {
|
|
25
|
+
form: "plain";
|
|
26
|
+
name: string;
|
|
27
|
+
} | {
|
|
28
|
+
form: "constructor";
|
|
29
|
+
resource: string;
|
|
30
|
+
} | {
|
|
31
|
+
form: "method";
|
|
32
|
+
resource: string;
|
|
33
|
+
member: string;
|
|
34
|
+
} | {
|
|
35
|
+
form: "static";
|
|
36
|
+
resource: string;
|
|
37
|
+
member: string;
|
|
38
|
+
};
|
|
39
|
+
/** Decode a mangled leaf name; unmangled names come back as `plain`. */
|
|
40
|
+
export declare function parseLeafName(raw: string): LeafName;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** The URL of this copy of the runtime. Identity of the copy. */
|
|
2
|
+
export declare const COPY_URL: string;
|
|
3
|
+
/**
|
|
4
|
+
* The `@polyengine/runtime` version this copy was built from, recorded in the copy
|
|
5
|
+
* registry alongside the URL.
|
|
6
|
+
*
|
|
7
|
+
* Hardcoded on purpose: embedder code paths run without filesystem
|
|
8
|
+
* permissions (and a browser bundle has no filesystem at all), so reading
|
|
9
|
+
* `runtime/deno.json` at runtime is not an option.
|
|
10
|
+
*
|
|
11
|
+
* INVARIANT: keep in sync with `version` in runtime/deno.json — pinned by
|
|
12
|
+
* runtime/tests/embedder/cross_copy_test.ts.
|
|
13
|
+
*/
|
|
14
|
+
export declare const RUNTIME_VERSION = "0.1.0";
|
|
15
|
+
/**
|
|
16
|
+
* Compose a cross-copy diagnostic: what was foreign, which copy is speaking,
|
|
17
|
+
* the census of every copy in the graph, and the by-value remediation.
|
|
18
|
+
*
|
|
19
|
+
* Kept to one line but complete — the whole point of A9's stateful half is
|
|
20
|
+
* that "recognized but foreign" is a NAMED failure, never a silent
|
|
21
|
+
* adaptation (a foreign `Stream` pumped as an async iterable) and never a
|
|
22
|
+
* misleading generic ("handle is not an error-context").
|
|
23
|
+
*/
|
|
24
|
+
export declare function describeCrossCopy(what: string, remedy?: string): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { DroppedError, InvalidHandleError, isDroppedError, isInvalidHandleError, isPeerTrappedError, isStreamProducerError, isTrap, isComponentException, PeerTrappedError, Trap, ComponentException, } from "@polyengine/protocol";
|
|
2
|
+
/**
|
|
3
|
+
* Two WIT labels in one scope camelCase to the same JS name.
|
|
4
|
+
*
|
|
5
|
+
* A footgun is a design defect (contract principle 2): silently letting one
|
|
6
|
+
* field/flag/function shadow another would corrupt values at the boundary with
|
|
7
|
+
* no diagnostic anywhere. Refused at facade build instead.
|
|
8
|
+
*/
|
|
9
|
+
export declare class NameCollisionError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { WirePlan } from "../plan/format.js";
|
|
2
|
+
import type { LoadedPlan } from "../plan/loader.js";
|
|
3
|
+
import type { ValType } from "../cabi/types.js";
|
|
4
|
+
import { type LeafName } from "./casing.js";
|
|
5
|
+
/** Function type summary of an import leaf (names are docs-only; §"Functions"). */
|
|
6
|
+
export interface FuncSummary {
|
|
7
|
+
params: {
|
|
8
|
+
name: string;
|
|
9
|
+
type: ValType;
|
|
10
|
+
}[];
|
|
11
|
+
results: ValType[];
|
|
12
|
+
/** True for an `async func` — an import may then be a plain async function. */
|
|
13
|
+
async: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** One linkable import leaf. */
|
|
16
|
+
export interface ImportLeaf {
|
|
17
|
+
/**
|
|
18
|
+
* The record key this leaf is provided under: a fully-qualified WIT
|
|
19
|
+
* interface id verbatim (version included) for interface imports, or the
|
|
20
|
+
* component's bare world-level import name.
|
|
21
|
+
*/
|
|
22
|
+
interfaceId: string;
|
|
23
|
+
/** Path from the record key to the leaf, verbatim (mangled names included). */
|
|
24
|
+
path: string[];
|
|
25
|
+
/** The raw, still-mangled leaf name (`[method]counter.increment`). */
|
|
26
|
+
leaf: string;
|
|
27
|
+
/** `func`, `resource`, `instance`, … — the plan's own kind string. */
|
|
28
|
+
kind: string;
|
|
29
|
+
/** Decoded resource membership of `leaf`. */
|
|
30
|
+
member: LeafName;
|
|
31
|
+
/**
|
|
32
|
+
* The JS name this leaf is looked up under: camelCase for functions and
|
|
33
|
+
* world-level imports, PascalCase for a resource *type* (the class), and —
|
|
34
|
+
* for a mangled leaf — the JS name of the class **member** it dispatches to.
|
|
35
|
+
*/
|
|
36
|
+
jsName: string;
|
|
37
|
+
/** For a mangled leaf: the PascalCase class it belongs to. */
|
|
38
|
+
jsClass?: string;
|
|
39
|
+
/** Present for `kind === "func"`. */
|
|
40
|
+
type?: FuncSummary;
|
|
41
|
+
}
|
|
42
|
+
/** Anything `requiredImports` accepts. */
|
|
43
|
+
export type PlanLike = WirePlan | LoadedPlan | {
|
|
44
|
+
plan: WirePlan;
|
|
45
|
+
};
|
|
46
|
+
/** Enumerate the component's linkable import leaves. */
|
|
47
|
+
export declare function requiredImports(input: PlanLike): ImportLeaf[];
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { WirePlan } from "../plan/format.js";
|
|
2
|
+
import { type ComponentHandle } from "../exec/mod.js";
|
|
3
|
+
import { Translator } from "../shim/mod.js";
|
|
4
|
+
import { type ImportLeaf } from "./imports.js";
|
|
5
|
+
/** The shim's output plus the component bytes it describes. */
|
|
6
|
+
export interface ComponentArtifacts {
|
|
7
|
+
plan: WirePlan;
|
|
8
|
+
componentBytes: Uint8Array;
|
|
9
|
+
adapters?: Map<string, Uint8Array>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Untranslated alternative to `ComponentArtifacts` (embedder-api.md
|
|
13
|
+
* amendment A3): hand `instantiate` the raw component plus the translator
|
|
14
|
+
* and it runs the translation internally — the pipeline collapses to
|
|
15
|
+
* bytes-in, instance-out.
|
|
16
|
+
*
|
|
17
|
+
* `translator` accepts the translator-shim wasm bytes (simplest; compiles
|
|
18
|
+
* the shim per call) or an already-created `Translator` (preferred when
|
|
19
|
+
* instantiating more than one component, or the same component more than
|
|
20
|
+
* once — create it once and reuse; translation itself is sub-millisecond
|
|
21
|
+
* warm, the wasm compile is the cost being shared). `requiredImports`
|
|
22
|
+
* still needs a plan: translate explicitly when you want to inspect the
|
|
23
|
+
* import surface before instantiating.
|
|
24
|
+
*/
|
|
25
|
+
export interface UntranslatedArtifacts {
|
|
26
|
+
componentBytes: Uint8Array;
|
|
27
|
+
translator: Uint8Array | Translator;
|
|
28
|
+
}
|
|
29
|
+
/** Either artifacts shape accepted by `instantiate`. */
|
|
30
|
+
export type InstantiateSource = ComponentArtifacts | UntranslatedArtifacts;
|
|
31
|
+
/**
|
|
32
|
+
* Reconstitute `ComponentArtifacts` from a translation ENVELOPE — the
|
|
33
|
+
* single-file JSON emitted by build-time translation (`tools/translate`,
|
|
34
|
+
* or `Translator.translateRaw`), carrying the plan and the FACT adapter
|
|
35
|
+
* modules. The production deploy set is `component.wasm` + its envelope +
|
|
36
|
+
* the runtime: no translator ships (embedder-api.md amendment A4).
|
|
37
|
+
*
|
|
38
|
+
* Pure and fetch-agnostic: acquire the two blobs however the platform
|
|
39
|
+
* likes (HTTP, fs, bundler asset) and hand them over. The envelope embeds
|
|
40
|
+
* the component's sha-256, which `instantiate` verifies — a mismatched
|
|
41
|
+
* pair fails loudly at instantiation, never subtly at runtime.
|
|
42
|
+
*/
|
|
43
|
+
export declare function artifactsFromEnvelope(envelopeJson: string, componentBytes: Uint8Array): ComponentArtifacts;
|
|
44
|
+
/**
|
|
45
|
+
* Normalize either accepted input form to `ComponentArtifacts` — i.e. make
|
|
46
|
+
* the PLAN available without instantiating anything. Exported because the
|
|
47
|
+
* world-digest handshake (contracts/digest.md) must complete before any
|
|
48
|
+
* guest code runs: generated `instantiate` wrappers call this, verify the
|
|
49
|
+
* plan, and only then delegate to `instantiate` below.
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveArtifacts(src: InstantiateSource): Promise<ComponentArtifacts>;
|
|
52
|
+
export interface EmbedderOptions {
|
|
53
|
+
/** Opt in to JSPI-backed suspension (see `InstantiateInput.jspi`). */
|
|
54
|
+
jspi?: boolean;
|
|
55
|
+
/** Verify `plan.component.sha256` against the bytes (default true). */
|
|
56
|
+
verifyHash?: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** An instantiated component, conventions-shaped. */
|
|
59
|
+
export interface EmbedderInstance {
|
|
60
|
+
/**
|
|
61
|
+
* Nested record keyed by verbatim WIT interface id; world-level exports at
|
|
62
|
+
* the top level under camelCase names.
|
|
63
|
+
*/
|
|
64
|
+
exports: Record<string, any>;
|
|
65
|
+
/** The raw runtime handle. Internal surface, no stability promise. */
|
|
66
|
+
handle: ComponentHandle;
|
|
67
|
+
/** The leaves this component required (the same list `requiredImports` gives). */
|
|
68
|
+
imports: ImportLeaf[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Instantiate a component behind the embedder conventions.
|
|
72
|
+
*
|
|
73
|
+
* `imports` is the canonical nested record of
|
|
74
|
+
* contracts/embedder-api.md §"Module wiring and instantiation": keys are
|
|
75
|
+
* verbatim WIT interface ids (version included) or world-level camelCase
|
|
76
|
+
* names; interface-id keys additionally participate in compatibility-track
|
|
77
|
+
* resolution (see `version.ts`).
|
|
78
|
+
*/
|
|
79
|
+
export declare function instantiate(source: InstantiateSource, imports?: Record<string, unknown>, opts?: EmbedderOptions): Promise<EmbedderInstance>;
|
|
80
|
+
/** Alias matching the C2 dispatch's spelling. */
|
|
81
|
+
export declare const instantiateEmbedder: typeof instantiate;
|
|
82
|
+
/**
|
|
83
|
+
* Symbol-keyed, deliberately NOT re-exported from `mod.ts`: the
|
|
84
|
+
* host-resource registries of an instance, by `ResourceIndex`. Diagnostics and
|
|
85
|
+
* white-box tests only — it is not part of the embedder API surface and no
|
|
86
|
+
* generated code may depend on it.
|
|
87
|
+
*/
|
|
88
|
+
export declare const INTERNAL_HOST_REGISTRIES: unique symbol;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { COPY_URL, RUNTIME_VERSION } from "./copy.js";
|
|
2
|
+
export { copyCensus, DROPPED, ERROR_CONTEXT, FUTURE, hasBrand, INVALID_HANDLE, isDroppedError, isInvalidHandleError, isPeerTrappedError, isStreamProducerError, isSuspending, isTrap, isComponentException, PEER_TRAPPED, PROTOCOL_GENERATION, registerRuntimeCopy, RESOURCE_STATE, type RuntimeCopy, runtimeCopies, STREAM, STREAM_PRODUCER, SUSPENDING, TRAP, COMPONENT_EXCEPTION, } from "@polyengine/protocol";
|
|
3
|
+
export { artifactsFromEnvelope, type ComponentArtifacts, type EmbedderInstance, type EmbedderOptions, type InstantiateSource, type UntranslatedArtifacts, instantiate, instantiateEmbedder, resolveArtifacts, } from "./instantiate.js";
|
|
4
|
+
export { type FuncSummary, type ImportLeaf, type PlanLike, requiredImports } from "./imports.js";
|
|
5
|
+
export { DroppedError, InvalidHandleError, NameCollisionError, PeerTrappedError, Trap, ComponentException, } from "./errors.js";
|
|
6
|
+
export { type Chunk, type ElemCodec, ErrorContext, Future, type FutureSource, Stream, StreamProducerError, type StreamSource, StreamWriter, } from "./streams.js";
|
|
7
|
+
export { GuestResource, HostResourceRegistry } from "./resources.js";
|
|
8
|
+
export { camelCase, type LeafName, parseLeafName, pascalCase } from "./casing.js";
|
|
9
|
+
export { suspending } from "../jspi/suspending.js";
|
|
10
|
+
export { asTrackKeySpelling, compareSemver, ImportRegistrationError, ImportResolutionError, ImportResolver, type ParsedId, parseInterfaceId, parseSemver, type Semver, trackKey, } from "./version.js";
|
|
11
|
+
export { type AdapterOptions, BorrowScope, fromHost, toHost, type ValueBridge, } from "./values.js";
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { ResourceTypeInfo, ValType } from "../cabi/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Internal state of a guest-resource wrapper.
|
|
4
|
+
*
|
|
5
|
+
* The KEY is the process-global `polyengine.resourceState/1` brand since amendment
|
|
6
|
+
* A9 (it used to be a module-local `Symbol(...)`, on the now-repealed
|
|
7
|
+
* assumption that bundle and source runtimes are never mixed in one process —
|
|
8
|
+
* issue #83 showed they routinely are). The state SHAPE stays strictly
|
|
9
|
+
* runtime-internal, exactly as the A9 brand table notes: another copy may
|
|
10
|
+
* RECOGNIZE a wrapper, and must never read or write this object. `copyUrl` is
|
|
11
|
+
* what lets this copy tell its own wrappers from a foreign copy's.
|
|
12
|
+
*/
|
|
13
|
+
declare const STATE: symbol;
|
|
14
|
+
interface WrapperState {
|
|
15
|
+
/** The runtime copy that minted this wrapper (A9). */
|
|
16
|
+
copyUrl: string;
|
|
17
|
+
rep: number;
|
|
18
|
+
/** False once the handle was transferred away or dropped. */
|
|
19
|
+
valid: boolean;
|
|
20
|
+
/** True for `own` wrappers, which are responsible for dropping. */
|
|
21
|
+
owns: boolean;
|
|
22
|
+
rt: ResourceTypeInfo;
|
|
23
|
+
className: string;
|
|
24
|
+
/**
|
|
25
|
+
* Host-side `ResourceHandle.num_lends` (#86). The reference models a
|
|
26
|
+
* host-held `own` as a table entry whose `num_lends` is bumped every time
|
|
27
|
+
* it is lifted as a `borrow` (definitions.py `Subtask.add_lender`, line
|
|
28
|
+
* 890, reached from `lift_borrow`, line 1516) and decremented when the
|
|
29
|
+
* borrowing call's subtask delivers its resolution (`deliver_resolve`,
|
|
30
|
+
* line 902). `lift_own` and `canon_resource_drop` both trap while it is
|
|
31
|
+
* non-zero (lines 1508 / 2325).
|
|
32
|
+
*
|
|
33
|
+
* Here the host holds bare reps rather than table entries, so the counter
|
|
34
|
+
* lives on the wrapper. Its lifecycle point is the *lowering scope* of the
|
|
35
|
+
* call the wrapper was passed into (`instantiate.ts` `#lowerParams`), which
|
|
36
|
+
* is released exactly when that call ends — the host-side analogue of the
|
|
37
|
+
* subtask's resolve delivery.
|
|
38
|
+
*/
|
|
39
|
+
lends: number;
|
|
40
|
+
/**
|
|
41
|
+
* A drop (explicit or via the GC backstop) that arrived while `lends > 0`.
|
|
42
|
+
* The reference would trap; the host has no frame to trap into by then, so
|
|
43
|
+
* the drop is deferred to the last release instead of running the dtor
|
|
44
|
+
* under a live guest borrow (which is the use-after-free #86 reports).
|
|
45
|
+
*/
|
|
46
|
+
pendingDrop: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** Base of every runtime-built guest-resource class. */
|
|
49
|
+
export declare class GuestResource {
|
|
50
|
+
[STATE]: WrapperState;
|
|
51
|
+
/** Drop the handle (alias of `[Symbol.dispose]`, so TS `using` works). */
|
|
52
|
+
drop(): void;
|
|
53
|
+
[Symbol.dispose](): void;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Simulate the GC backstop firing for `w` (the FinalizationRegistry callback,
|
|
57
|
+
* verbatim). Test seam: real GC finalization is unschedulable, and #86 is
|
|
58
|
+
* precisely about what the backstop does in a window a test must control.
|
|
59
|
+
*
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
export declare function simulateFinalizationForTest(w: object): void;
|
|
63
|
+
export declare function initWrapper(w: GuestResource, state: Omit<WrapperState, "copyUrl"> & {
|
|
64
|
+
copyUrl?: string;
|
|
65
|
+
}): void;
|
|
66
|
+
/**
|
|
67
|
+
* This copy's state for a wrapper, or `undefined`.
|
|
68
|
+
*
|
|
69
|
+
* A wrapper minted by ANOTHER copy carries the same (process-global) brand key
|
|
70
|
+
* but its state belongs to that copy — reading it here would be reading a
|
|
71
|
+
* foreign copy's private shape (A9). So it is not a state: it is
|
|
72
|
+
* `undefined` here, and `requireLive` turns that into the named cross-copy
|
|
73
|
+
* error rather than a misleading "not a resource handle" / "not live".
|
|
74
|
+
*/
|
|
75
|
+
export declare function wrapperState(w: object): WrapperState | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Record that a host-held `own` wrapper was lowered as `borrow<R>` into a
|
|
78
|
+
* guest call, and return the (idempotent) release for the end of that call.
|
|
79
|
+
*
|
|
80
|
+
* definitions.py: `lift_borrow` -> `Subtask.add_lender` (line 890) on the way
|
|
81
|
+
* in, `Subtask.deliver_resolve` (line 902) on the way out.
|
|
82
|
+
*/
|
|
83
|
+
export declare function lendWrapper(w: object): () => void;
|
|
84
|
+
/** Host-side `num_lends` — diagnostics and white-box tests. */
|
|
85
|
+
export declare function wrapperLends(w: object): number;
|
|
86
|
+
/** Invalidate a wrapper without dropping (used to end a borrow's lifetime). */
|
|
87
|
+
export declare function invalidateWrapper(w: object): void;
|
|
88
|
+
/** Read a wrapper's rep for a lowering site, applying the ownership rule. */
|
|
89
|
+
export declare function takeRep(w: unknown, own: boolean, what: string): number;
|
|
90
|
+
/** Everything needed to build one guest-resource class. */
|
|
91
|
+
export interface GuestResourceSpec {
|
|
92
|
+
/** WIT resource name (kebab). */
|
|
93
|
+
name: string;
|
|
94
|
+
/** The raw `[constructor]r` lifted function, if the resource has one. */
|
|
95
|
+
ctor: ((...a: unknown[]) => unknown) | null;
|
|
96
|
+
ctorParams: ValType[] | null;
|
|
97
|
+
methods: {
|
|
98
|
+
member: string;
|
|
99
|
+
raw: (...a: unknown[]) => unknown;
|
|
100
|
+
params: ValType[];
|
|
101
|
+
results: ValType[];
|
|
102
|
+
}[];
|
|
103
|
+
statics: {
|
|
104
|
+
member: string;
|
|
105
|
+
raw: (...a: unknown[]) => unknown;
|
|
106
|
+
params: ValType[];
|
|
107
|
+
results: ValType[];
|
|
108
|
+
}[];
|
|
109
|
+
}
|
|
110
|
+
export type CallAdapter = (raw: (...a: unknown[]) => unknown, params: ValType[], results: ValType[], where: string, args: unknown[]) => Promise<unknown>;
|
|
111
|
+
/**
|
|
112
|
+
* Build the class for a guest-implemented resource.
|
|
113
|
+
*
|
|
114
|
+
* The JS constructor is **synchronous**: a JS constructor cannot return a
|
|
115
|
+
* Promise, so the contract's "exports are uniformly Promise-shaped" rule has
|
|
116
|
+
* one unavoidable exception here. A guest constructor that does not complete
|
|
117
|
+
* synchronously is reported as such rather than silently returning a
|
|
118
|
+
* half-built object (see the report's contract-friction list).
|
|
119
|
+
*/
|
|
120
|
+
export declare function buildGuestResourceClass(spec: GuestResourceSpec, rt: ResourceTypeInfo, adapt: CallAdapter, lowerArgs: (args: unknown[], params: ValType[], where: string) => unknown[]): any;
|
|
121
|
+
/** Materialize an `own`/`borrow` wrapper for a rep coming out of a guest. */
|
|
122
|
+
export declare function makeWrapper(cls: any, rep: number, rt: ResourceTypeInfo, owns: boolean): GuestResource;
|
|
123
|
+
/**
|
|
124
|
+
* Runtime-owned instance <-> rep mapping for a host-implemented resource.
|
|
125
|
+
*
|
|
126
|
+
* The rep->instance direction is a **strong** map for exactly as long as the
|
|
127
|
+
* guest holds handles: the guest's handle is the only reference keeping a
|
|
128
|
+
* host object alive across calls, and a weak map here would let it be
|
|
129
|
+
* collected under the guest's feet.
|
|
130
|
+
*/
|
|
131
|
+
export declare class HostResourceRegistry {
|
|
132
|
+
#private;
|
|
133
|
+
readonly className: string;
|
|
134
|
+
constructor(className: string);
|
|
135
|
+
/** The host is passing an instance to the guest: allocate (or reuse) a rep. */
|
|
136
|
+
repFor(instance: unknown): number;
|
|
137
|
+
/** Is this instance already registered with a live rep? */
|
|
138
|
+
hasInstance(instance: unknown): boolean;
|
|
139
|
+
/** Is `rep` live? Diagnostics and white-box tests. */
|
|
140
|
+
hasRep(rep: number): boolean;
|
|
141
|
+
/** Release a rep if it is still live; no dtor, no error when already gone. */
|
|
142
|
+
releaseIfPresent(rep: number): void;
|
|
143
|
+
/** A `borrow<R>` arrived from the guest: the host's own instance, mapping kept. */
|
|
144
|
+
lookup(rep: number): object;
|
|
145
|
+
/**
|
|
146
|
+
* An `own<R>` arrived from the guest: the host gets its instance back, the
|
|
147
|
+
* guest's handle is gone, and **no dispose runs** (the contract's 2x4 table).
|
|
148
|
+
*/
|
|
149
|
+
release(rep: number): object;
|
|
150
|
+
/**
|
|
151
|
+
* The guest dropped its last own handle: run the destructor. This is the
|
|
152
|
+
* `HostResourceType` dtor the executor calls from `canon_resource_drop`.
|
|
153
|
+
*/
|
|
154
|
+
dtor(rep: number): void;
|
|
155
|
+
/** Live handle count — diagnostics and tests. */
|
|
156
|
+
get liveCount(): number;
|
|
157
|
+
}
|
|
158
|
+
export {};
|