@lapxo/bound 0.1.9 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -121
- package/TARGET.bound +85 -14
- package/assets/wasm/guest.js +4 -0
- package/assets/wasm/manifest.json +27 -0
- package/assets/wasm/runtime.js +6 -0
- package/assets/wasm/runtime.wasm +0 -0
- package/dist/cli/pass.js +3 -3
- package/dist/cli/place.js +7 -4
- package/dist/cli/standing-result.js +4 -3
- package/dist/cli/verb.js +79 -9
- package/dist/engine/encoding.js +2 -0
- package/dist/engine/index.d.ts +13 -0
- package/dist/engine/index.js +11 -0
- package/dist/engine/object.js +38 -0
- package/dist/engine/ports.d.ts +32 -0
- package/dist/engine/ports.js +103 -0
- package/dist/fold/closed.js +22 -5
- package/dist/fold/digests.js +3 -2
- package/dist/fold/object.js +2 -38
- package/dist/fold/resolved.js +1 -1
- package/dist/host/admitted-place.js +10 -1
- package/dist/host/cell-receipts.js +1 -1
- package/dist/host/contextual-place.js +2 -2
- package/dist/host/io.js +2 -2
- package/dist/host/objects.js +24 -4
- package/dist/host/reading-closures.js +11 -13
- package/dist/host/reference-authenticated.d.ts +40 -0
- package/dist/host/reference-authenticated.js +100 -0
- package/dist/host/reference-contracts.js +6 -0
- package/dist/host/reference-export.d.ts +33 -0
- package/dist/host/reference-export.js +81 -0
- package/dist/host/reference-native-api.d.ts +3 -0
- package/dist/host/reference-native-api.js +3 -0
- package/dist/host/reference-native.d.ts +30 -0
- package/dist/host/reference-native.js +74 -0
- package/dist/host/reference-profile.d.ts +23 -0
- package/dist/host/reference-profile.js +63 -0
- package/dist/host/reference-standing.js +18 -0
- package/dist/host/reference.js +24 -0
- package/dist/host/refusals.d.ts +14 -0
- package/dist/host/refusals.js +43 -0
- package/dist/host/selected-topos.js +9 -1
- package/dist/host/signing.js +7 -1
- package/dist/observe/files.js +11 -1
- package/dist/observe/regions.js +109 -1
- package/dist/wasm/adapter.d.ts +51 -0
- package/dist/wasm/adapter.js +180 -0
- package/dist/wasm/node-worker.js +13 -0
- package/dist/wasm/object.js +76 -0
- package/dist/wasm/worker.js +7 -0
- package/docs/contracts/authenticated-reference.publication.json +25 -0
- package/docs/contracts/engine-object-projection.publication.json +25 -0
- package/docs/contracts/engine.md +39 -0
- package/docs/contracts/host-ports.md +23 -0
- package/docs/contracts/host-ports.publication.json +25 -0
- package/docs/contracts/native-publication.inventory.json +14 -0
- package/docs/contracts/optional-wasm-adapter.publication.json +25 -0
- package/docs/contracts/publication-additions.inventory.json +8 -0
- package/docs/contracts/readme.publication.json +25 -0
- package/docs/contracts/reference-backend.md +24 -0
- package/docs/contracts/reference-backend.publication.json +25 -0
- package/docs/contracts/reference-export.md +31 -0
- package/docs/contracts/reference-export.publication.json +25 -0
- package/docs/contracts/reference-port.md +40 -0
- package/docs/contracts/reference-port.publication.json +25 -0
- package/docs/contracts/refusals.bound +94 -0
- package/docs/contracts/refusals.md +47 -0
- package/docs/contracts/refusals.publication.json +25 -0
- package/docs/contracts/standing.bound +9 -0
- package/docs/contracts/standing.md +24 -0
- package/docs/contracts/standing.publication.json +25 -0
- package/licenses/wasm/bound.txt +21 -0
- package/licenses/wasm/fast-text-encoding.txt +201 -0
- package/licenses/wasm/jitl-quickjs-ffi-types.txt +21 -0
- package/licenses/wasm/jitl-quickjs-wasmfile-release-sync.txt +47 -0
- package/licenses/wasm/obligations.txt +21 -0
- package/licenses/wasm/quickjs-emscripten-core.txt +21 -0
- package/licenses/wasm/topos.txt +21 -0
- package/package.json +141 -6
- package/receipts.bound +9554 -613
- package/samples/authenticated-reference/compatibility.json +306 -0
- package/samples/authenticated-reference/no.json +31 -0
- package/samples/authenticated-reference/yes/editorial-state/TARGET.bound +57 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/arrival.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/coverage.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/era.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/order.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/signature.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.arrival.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.coverage.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.era.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.order.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.signature.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.yes.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/yes.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/TARGET.bound +57 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/arrival.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/coverage.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/era.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/order.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/signature.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.arrival.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.coverage.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.era.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.order.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.signature.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.yes.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/yes.json +1 -0
- package/samples/authenticated-reference/yes.json +19 -0
- package/samples/engine-alphabet/TARGET.bound +29 -0
- package/samples/engine-alphabet/inputs/sample.json +323 -0
- package/samples/engine-alphabet/package.json +1 -0
- package/samples/engine-alphabet/reader.js +1457 -0
- package/samples/engine-alphabet/receipts.bound +12 -0
- package/samples/engine-interval/TARGET.bound +29 -0
- package/samples/engine-interval/inputs/sample.json +277 -0
- package/samples/engine-interval/package.json +1 -0
- package/samples/engine-interval/reader.js +1457 -0
- package/samples/engine-interval/receipts.bound +12 -0
- package/samples/host-ports/no.json +16 -0
- package/samples/host-ports/yes.json +9 -0
- package/samples/no/engine-order/TARGET.bound +29 -0
- package/samples/no/engine-order/inputs/sample.json +277 -0
- package/samples/no/engine-order/package.json +1 -0
- package/samples/no/engine-order/reader.js +1457 -0
- package/samples/readme/no.json +1 -0
- package/samples/readme/yes.json +1 -0
- package/samples/reference-backend/no.json +1 -0
- package/samples/reference-backend/world-fixture.json +8 -0
- package/samples/reference-backend/yes.json +1 -0
- package/samples/reference-export/no.json +5 -0
- package/samples/reference-export/yes.json +15 -0
- package/samples/reference-port/no/catalog/TARGET.bound +33 -0
- package/samples/reference-port/no/catalog/standing.json +1 -0
- package/samples/reference-port/no/catalog/transport.json +1 -0
- package/samples/reference-port/no/route-notes/TARGET.bound +33 -0
- package/samples/reference-port/no/route-notes/standing.json +1 -0
- package/samples/reference-port/no/route-notes/transport.json +1 -0
- package/samples/reference-port/yes/catalog/TARGET.bound +33 -0
- package/samples/reference-port/yes/catalog/standing.json +1 -0
- package/samples/reference-port/yes/catalog/transport.json +1 -0
- package/samples/reference-port/yes/route-notes/TARGET.bound +33 -0
- package/samples/reference-port/yes/route-notes/standing.json +1 -0
- package/samples/reference-port/yes/route-notes/transport.json +1 -0
- package/samples/refusals/no.json +4 -0
- package/samples/refusals/yes.json +9 -0
- package/samples/standing/no.json +4 -0
- package/samples/standing/yes.json +21 -0
- package/samples/wasm/editorial-notes/TARGET.bound +65 -0
- package/samples/wasm/editorial-notes/esm.bound +59 -0
- package/samples/wasm/editorial-notes/no-deadline.bound +65 -0
- package/samples/wasm/editorial-notes/no-memory.bound +65 -0
- package/samples/wasm/editorial-notes/no-missing-limit.bound +64 -0
- package/samples/wasm/editorial-notes/receipts.bound +1 -0
- package/samples/wasm/water-level/TARGET.bound +65 -0
- package/samples/wasm/water-level/esm.bound +59 -0
- package/samples/wasm/water-level/no-deadline.bound +65 -0
- package/samples/wasm/water-level/no-memory.bound +65 -0
- package/samples/wasm/water-level/no-missing-limit.bound +64 -0
- package/samples/wasm/water-level/receipts.bound +1 -0
- package/vectors/engine-object.cli.json +548 -0
- package/vectors/native/authenticated-reference-formation.vector.json +107 -0
- package/vectors/native/authenticated-reference.cli.json +157 -0
- package/vectors/native/authenticated-reference.vector.json +76 -0
- package/vectors/native/host-ports.vector.json +107 -0
- package/vectors/native/readme.vector.json +76 -0
- package/vectors/native/reference-backend.vector.json +84 -0
- package/vectors/native/reference-export.vector.json +78 -0
- package/vectors/native/refusals.vector.json +95 -0
- package/vectors/native/standing.vector.json +116 -0
- package/vectors/reference-port.cli.json +688 -0
- package/vectors/wasm-object.cli.json +407 -0
- package/dist/cli/accept.d.ts +0 -28
- package/dist/cli/act-result.d.ts +0 -12
- package/dist/cli/args.d.ts +0 -11
- package/dist/cli/custodian.d.ts +0 -1
- package/dist/cli/host.d.ts +0 -1
- package/dist/cli/names.d.ts +0 -25
- package/dist/cli/native-descendant.d.ts +0 -1
- package/dist/cli/native.d.ts +0 -1
- package/dist/cli/observe.d.ts +0 -1
- package/dist/cli/owner.d.ts +0 -37
- package/dist/cli/pass.d.ts +0 -6
- package/dist/cli/place.d.ts +0 -74
- package/dist/cli/release-result.d.ts +0 -5
- package/dist/cli/standing-result.d.ts +0 -5
- package/dist/cli/takes.d.ts +0 -30
- package/dist/fold/admission-history.d.ts +0 -6
- package/dist/fold/ceilings.d.ts +0 -24
- package/dist/fold/claims.d.ts +0 -29
- package/dist/fold/closed.d.ts +0 -15
- package/dist/fold/configures.d.ts +0 -4
- package/dist/fold/digests.d.ts +0 -29
- package/dist/fold/evidence.d.ts +0 -32
- package/dist/fold/fold-worker.d.ts +0 -1
- package/dist/fold/kept.d.ts +0 -29
- package/dist/fold/keys.d.ts +0 -17
- package/dist/fold/laid.d.ts +0 -17
- package/dist/fold/nos.d.ts +0 -8
- package/dist/fold/observed.d.ts +0 -35
- package/dist/fold/opened.d.ts +0 -5
- package/dist/fold/own.d.ts +0 -24
- package/dist/fold/paid.d.ts +0 -11
- package/dist/fold/place-inputs.d.ts +0 -17
- package/dist/fold/places.d.ts +0 -24
- package/dist/fold/rank.d.ts +0 -3
- package/dist/fold/reach.d.ts +0 -18
- package/dist/fold/readers.d.ts +0 -47
- package/dist/fold/receipts.d.ts +0 -8
- package/dist/fold/region-declarations.d.ts +0 -2
- package/dist/fold/region.d.ts +0 -72
- package/dist/fold/release-policy.d.ts +0 -67
- package/dist/fold/resolved.d.ts +0 -18
- package/dist/fold/roles.d.ts +0 -17
- package/dist/fold/second.d.ts +0 -18
- package/dist/fold/shards.d.ts +0 -29
- package/dist/fold/signed.d.ts +0 -23
- package/dist/fold/signers.d.ts +0 -24
- package/dist/fold/stranger.d.ts +0 -3
- package/dist/fold/views.d.ts +0 -27
- package/dist/fold/wire.d.ts +0 -19
- package/dist/fold/zoom.d.ts +0 -16
- package/dist/host/act-cost.d.ts +0 -13
- package/dist/host/adapters/keys/ed25519.d.ts +0 -7
- package/dist/host/adapters/modules/javascript.d.ts +0 -3
- package/dist/host/adapters/transport/http.d.ts +0 -5
- package/dist/host/admitted-place.d.ts +0 -5
- package/dist/host/archive.d.ts +0 -11
- package/dist/host/capsule-process.d.ts +0 -21
- package/dist/host/capsule.d.ts +0 -19
- package/dist/host/cell-receipts.d.ts +0 -2
- package/dist/host/content-needed.d.ts +0 -5
- package/dist/host/content-store.d.ts +0 -8
- package/dist/host/contextual-place.d.ts +0 -59
- package/dist/host/digest.d.ts +0 -3
- package/dist/host/hash.d.ts +0 -9
- package/dist/host/io.d.ts +0 -11
- package/dist/host/lifetime.d.ts +0 -1
- package/dist/host/located.d.ts +0 -4
- package/dist/host/native/bounded-file.d.ts +0 -8
- package/dist/host/native/command.d.ts +0 -36
- package/dist/host/native/control-bridge-worker.d.ts +0 -1
- package/dist/host/native/control-bridge.d.ts +0 -30
- package/dist/host/native/control-selection.d.ts +0 -29
- package/dist/host/native/custody.d.ts +0 -5
- package/dist/host/native/deadline.d.ts +0 -12
- package/dist/host/native/descendants.d.ts +0 -1
- package/dist/host/native/generated-custodian.d.ts +0 -122
- package/dist/host/native/generated.d.ts +0 -217
- package/dist/host/native/image.d.ts +0 -36
- package/dist/host/native/jobs.d.ts +0 -75
- package/dist/host/native/loader.d.ts +0 -80
- package/dist/host/native/materialize.d.ts +0 -22
- package/dist/host/native/module-closure.d.ts +0 -27
- package/dist/host/native/module-syntax.d.ts +0 -8
- package/dist/host/native/native-binary.d.ts +0 -54
- package/dist/host/native/native-program.d.ts +0 -56
- package/dist/host/native/node-jobs.d.ts +0 -84
- package/dist/host/native/node-launch.d.ts +0 -72
- package/dist/host/native/preload.d.ts +0 -1
- package/dist/host/native/reading.d.ts +0 -91
- package/dist/host/native/receipt-environment.d.ts +0 -3
- package/dist/host/native/references.d.ts +0 -5
- package/dist/host/native/root.d.ts +0 -17
- package/dist/host/native/route.d.ts +0 -66
- package/dist/host/native/runtime.d.ts +0 -4
- package/dist/host/native-reader-context.d.ts +0 -3
- package/dist/host/objects.d.ts +0 -5
- package/dist/host/place-clock-selection.d.ts +0 -55
- package/dist/host/ports/ingress.d.ts +0 -24
- package/dist/host/ports/local-act.d.ts +0 -44
- package/dist/host/ports/place-act.d.ts +0 -46
- package/dist/host/ports/publication.d.ts +0 -10
- package/dist/host/ports/signing.d.ts +0 -31
- package/dist/host/ports/store.d.ts +0 -2
- package/dist/host/ports/transport.d.ts +0 -1
- package/dist/host/process-lifetime.d.ts +0 -11
- package/dist/host/provide.d.ts +0 -48
- package/dist/host/read-only.d.ts +0 -3
- package/dist/host/reading-closures.d.ts +0 -45
- package/dist/host/reading-context.d.ts +0 -29
- package/dist/host/release.d.ts +0 -14
- package/dist/host/root-clock-source.d.ts +0 -85
- package/dist/host/selected-capsules.d.ts +0 -8
- package/dist/host/selected-topos.d.ts +0 -24
- package/dist/host/signing.d.ts +0 -3
- package/dist/host/source-content.d.ts +0 -12
- package/dist/host/timing.d.ts +0 -2
- package/dist/host/walk.d.ts +0 -6
- package/dist/judge/late.d.ts +0 -7
- package/dist/judge/take.d.ts +0 -59
- package/dist/judge/widening.d.ts +0 -1
- package/dist/land/act.d.ts +0 -30
- package/dist/land/alias.d.ts +0 -10
- package/dist/land/held.d.ts +0 -7
- package/dist/land/inert.d.ts +0 -26
- package/dist/land/leaving.d.ts +0 -14
- package/dist/land/ledger.d.ts +0 -33
- package/dist/land/owned.d.ts +0 -23
- package/dist/land/sign.d.ts +0 -15
- package/dist/land/standing-pin.d.ts +0 -3
- package/dist/land/vouched.d.ts +0 -21
- package/dist/land/withdraw.d.ts +0 -14
- package/dist/observe/files.d.ts +0 -14
- package/dist/observe/identity.d.ts +0 -21
- package/dist/observe/match.d.ts +0 -1
- package/dist/observe/regions.d.ts +0 -29
- package/dist/observe/run.d.ts +0 -31
- package/dist/observe/runner.d.ts +0 -20
- package/dist/render/capsule.d.ts +0 -24
- package/dist/render/field.d.ts +0 -3
- package/dist/render/names.d.ts +0 -3
- package/dist/render/open.d.ts +0 -27
- package/dist/render/page.d.ts +0 -3
- package/dist/render/receipts.d.ts +0 -3
- package/dist/render/shape.d.ts +0 -16
- package/dist/render/target.d.ts +0 -18
- package/dist/render/view.d.ts +0 -22
- /package/dist/{fold → engine}/object.d.ts +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface WasmLimits {
|
|
2
|
+
readonly memoryBytes: number;
|
|
3
|
+
readonly stackBytes: number;
|
|
4
|
+
readonly executionMs: number;
|
|
5
|
+
}
|
|
6
|
+
export interface WasmTrust {
|
|
7
|
+
readonly runtime: string;
|
|
8
|
+
readonly wasm: string;
|
|
9
|
+
readonly modules: Readonly<Record<string, string>>;
|
|
10
|
+
readonly entry: string;
|
|
11
|
+
readonly aliases: Readonly<Record<string, string>>;
|
|
12
|
+
readonly limits: WasmLimits;
|
|
13
|
+
readonly byteLengths: {
|
|
14
|
+
readonly runtime: number;
|
|
15
|
+
readonly wasm: number;
|
|
16
|
+
readonly modules: Readonly<Record<string, number>>;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface WasmRequest {
|
|
20
|
+
readonly trusted: WasmTrust;
|
|
21
|
+
readonly assets: {
|
|
22
|
+
readonly runtime: Uint8Array | ArrayBuffer;
|
|
23
|
+
readonly wasm: Uint8Array | ArrayBuffer;
|
|
24
|
+
};
|
|
25
|
+
readonly modules: Readonly<Record<string, string>>;
|
|
26
|
+
readonly entry: string;
|
|
27
|
+
readonly aliases?: Readonly<Record<string, string>>;
|
|
28
|
+
readonly limits: WasmLimits;
|
|
29
|
+
}
|
|
30
|
+
export interface WasmResult {
|
|
31
|
+
readonly output: string;
|
|
32
|
+
readonly initializedMs: number;
|
|
33
|
+
readonly executionMs: number;
|
|
34
|
+
}
|
|
35
|
+
export interface WorkerPort {
|
|
36
|
+
postMessage(message: WasmRequest): void;
|
|
37
|
+
terminate(): unknown;
|
|
38
|
+
addEventListener?(type: string, listener: (event: {
|
|
39
|
+
data?: unknown;
|
|
40
|
+
message?: string;
|
|
41
|
+
}) => void): void;
|
|
42
|
+
on?(type: string, listener: (value: unknown) => void): void;
|
|
43
|
+
}
|
|
44
|
+
export declare function digest(bytes: Uint8Array): Promise<string>;
|
|
45
|
+
export declare function preflight(request: WasmRequest): void;
|
|
46
|
+
export declare function runWasmRequest(request: WasmRequest): Promise<WasmResult>;
|
|
47
|
+
export declare function evaluateWasm(request: WasmRequest, { workerFactory, signal, lifetimeMs }: {
|
|
48
|
+
readonly workerFactory?: () => WorkerPort;
|
|
49
|
+
readonly signal?: AbortSignal;
|
|
50
|
+
readonly lifetimeMs: number;
|
|
51
|
+
}): Promise<WasmResult>;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
const owns = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
10
|
+
const assetNames = ['runtime', 'wasm'], limitNames = ['memoryBytes', 'stackBytes', 'executionMs'];
|
|
11
|
+
// Host adapter only. Source integrity grants neither admission nor authority.
|
|
12
|
+
function refuse(cause) { throw Error('REFUSE·wasm ' + cause); }
|
|
13
|
+
export async function digest(bytes) { return 'sha256:' + Array.from(new Uint8Array(await crypto.subtle.digest('SHA-256', bytes.slice().buffer))).map(x => x.toString(16).padStart(2, '0')).join(''); }
|
|
14
|
+
async function verified(bytes, expected) { if (typeof SharedArrayBuffer !== 'undefined' && (bytes instanceof SharedArrayBuffer || (ArrayBuffer.isView(bytes) && bytes.buffer instanceof SharedArrayBuffer)))
|
|
15
|
+
refuse('shared assets unsupported'); const copy = (bytes instanceof Uint8Array ? new Uint8Array(bytes) : new Uint8Array(bytes)).slice(); if (!/^sha256:[a-f0-9]{64}$/.test(expected) || await digest(copy) !== expected)
|
|
16
|
+
refuse('integrity'); return copy; }
|
|
17
|
+
const text = new TextEncoder();
|
|
18
|
+
// Exact host-declared sizes bound copies, hashing and worker handoff before work.
|
|
19
|
+
export function preflight(request) {
|
|
20
|
+
if (!request || Object.keys(request).some(k => !['trusted', 'assets', 'modules', 'aliases', 'entry', 'limits'].includes(k)))
|
|
21
|
+
refuse('request fields');
|
|
22
|
+
const { trusted, assets, modules, entry, aliases = {}, limits } = request, sizes = trusted?.byteLengths;
|
|
23
|
+
if (!sizes || !modules || !assets)
|
|
24
|
+
refuse('declared byte sizes');
|
|
25
|
+
if (Object.keys(assets).length !== 2 || Object.keys(assets).some(k => !['runtime', 'wasm'].includes(k)))
|
|
26
|
+
refuse('asset fields');
|
|
27
|
+
if (!limits || Object.keys(limits).length !== 3 || Object.keys(limits).some(k => !['memoryBytes', 'stackBytes', 'executionMs'].includes(k)))
|
|
28
|
+
refuse('limit fields');
|
|
29
|
+
for (const name of limitNames)
|
|
30
|
+
if (!Number.isSafeInteger(limits[name]) || limits[name] <= 0 || limits[name] !== trusted.limits?.[name])
|
|
31
|
+
refuse('limit ' + name);
|
|
32
|
+
if (typeof entry !== 'string' || entry !== trusted.entry || !aliases || Object.values(aliases).some(v => typeof v !== 'string') || JSON.stringify(Object.entries(aliases).sort()) !== JSON.stringify(Object.entries(trusted.aliases ?? {}).sort()))
|
|
33
|
+
refuse('entry or aliases differ from trusted context');
|
|
34
|
+
const names = Object.keys(modules), expected = Object.keys(trusted.modules ?? {});
|
|
35
|
+
if (names.length !== expected.length || names.some(n => !owns(trusted.modules, n)))
|
|
36
|
+
refuse('module count');
|
|
37
|
+
const size = (n, want) => { if (!Number.isSafeInteger(want) || want < 0)
|
|
38
|
+
refuse('declared size ' + n); return want; };
|
|
39
|
+
for (const name of assetNames) {
|
|
40
|
+
const v = assets[name];
|
|
41
|
+
if (typeof SharedArrayBuffer !== 'undefined' && (v instanceof SharedArrayBuffer || (ArrayBuffer.isView(v) && v.buffer instanceof SharedArrayBuffer)))
|
|
42
|
+
refuse('shared assets unsupported');
|
|
43
|
+
if (!(v instanceof Uint8Array || v instanceof ArrayBuffer) || v.byteLength !== size(name, sizes[name]))
|
|
44
|
+
refuse('asset bytes ' + name);
|
|
45
|
+
}
|
|
46
|
+
for (const name of names) {
|
|
47
|
+
const source = modules[name], want = size(name, sizes.modules?.[name]);
|
|
48
|
+
if (typeof source !== 'string' || source.length > want)
|
|
49
|
+
refuse('module bytes ' + name);
|
|
50
|
+
let bytes = 0;
|
|
51
|
+
for (let i = 0; i < source.length; i++) {
|
|
52
|
+
const c = source.charCodeAt(i);
|
|
53
|
+
bytes += c < 128 ? 1 : c < 2048 ? 2 : c >= 55296 && c <= 56319 && i + 1 < source.length && source.charCodeAt(i + 1) >= 56320 && source.charCodeAt(i + 1) <= 57343 ? (i++, 4) : 3;
|
|
54
|
+
if (bytes > want)
|
|
55
|
+
refuse('module bytes ' + name);
|
|
56
|
+
}
|
|
57
|
+
if (bytes !== want)
|
|
58
|
+
refuse('module bytes ' + name);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export async function runWasmRequest(request) {
|
|
62
|
+
preflight(request);
|
|
63
|
+
try {
|
|
64
|
+
request = structuredClone(request);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
refuse('request is not cloneable');
|
|
68
|
+
}
|
|
69
|
+
const { trusted, assets, modules, aliases = {}, entry, limits } = request;
|
|
70
|
+
for (const name of limitNames)
|
|
71
|
+
if (!Number.isSafeInteger(limits?.[name]) || limits[name] <= 0 || limits[name] !== trusted?.limits?.[name])
|
|
72
|
+
refuse('limit ' + name);
|
|
73
|
+
if (entry !== trusted.entry || JSON.stringify(Object.entries(aliases).sort()) !== JSON.stringify(Object.entries(trusted.aliases ?? {}).sort()))
|
|
74
|
+
refuse('entry or aliases differ from trusted context');
|
|
75
|
+
const runtime = await verified(assets.runtime, trusted.runtime), wasm = await verified(assets.wasm, trusted.wasm), sources = {};
|
|
76
|
+
for (const [id, source] of Object.entries(modules)) {
|
|
77
|
+
if (!owns(trusted.modules, id))
|
|
78
|
+
refuse('undeclared module ' + id);
|
|
79
|
+
sources[id] = new TextDecoder('utf-8', { fatal: true }).decode(await verified(text.encode(source), trusted.modules[id]));
|
|
80
|
+
}
|
|
81
|
+
if (Object.keys(trusted.modules).some(id => !owns(sources, id)))
|
|
82
|
+
refuse('missing module');
|
|
83
|
+
if (!owns(sources, entry))
|
|
84
|
+
refuse('entry');
|
|
85
|
+
// The runtime is a closed esbuild ESM bundle: no imports and no second fetch.
|
|
86
|
+
const url = 'data:text/javascript;base64,' + bytesBase64(runtime), factory = await import(__rewriteRelativeImportExtension(url));
|
|
87
|
+
const started = performance.now(), quick = await factory.createQuickJS(wasm);
|
|
88
|
+
const rt = quick.newRuntime();
|
|
89
|
+
let context;
|
|
90
|
+
try {
|
|
91
|
+
context = rt.newContext();
|
|
92
|
+
const memory = rt.computeMemoryUsage();
|
|
93
|
+
let initializedMemory;
|
|
94
|
+
try {
|
|
95
|
+
initializedMemory = context.dump(memory);
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
memory.dispose();
|
|
99
|
+
}
|
|
100
|
+
const used = typeof initializedMemory === 'object' && initializedMemory !== null ? initializedMemory.memory_used_size : undefined;
|
|
101
|
+
if (typeof used !== 'number' || !Number.isSafeInteger(used) || used < 0)
|
|
102
|
+
refuse('initialized memory measurement unavailable');
|
|
103
|
+
if (used > limits.memoryBytes)
|
|
104
|
+
refuse('initialized memory ' + used + ' exceeds declared memory ' + limits.memoryBytes);
|
|
105
|
+
const initializedMs = performance.now() - started;
|
|
106
|
+
rt.setMemoryLimit(limits.memoryBytes);
|
|
107
|
+
rt.setMaxStackSize(limits.stackBytes);
|
|
108
|
+
const start = performance.now();
|
|
109
|
+
rt.setInterruptHandler(() => performance.now() - start > limits.executionMs);
|
|
110
|
+
rt.setModuleLoader(id => { if (!owns(sources, id))
|
|
111
|
+
refuse('undeclared import ' + id); return sources[id]; }, (parent, name) => { if (owns(aliases, name))
|
|
112
|
+
return aliases[name]; if (name.startsWith('.'))
|
|
113
|
+
return new URL(name, new URL(parent, 'file:///')).pathname; if (owns(sources, name))
|
|
114
|
+
return name; refuse('undeclared import ' + name); });
|
|
115
|
+
const result = context.evalCode(sources[entry], entry, { type: 'module' });
|
|
116
|
+
if (result.error) {
|
|
117
|
+
const e = context.dump(result.error);
|
|
118
|
+
result.error.dispose();
|
|
119
|
+
refuse('guest ' + JSON.stringify(e));
|
|
120
|
+
}
|
|
121
|
+
result.value.dispose();
|
|
122
|
+
const value = context.evalCode('globalThis.result');
|
|
123
|
+
if (value.error) {
|
|
124
|
+
const e = context.dump(value.error);
|
|
125
|
+
value.error.dispose();
|
|
126
|
+
refuse('result ' + JSON.stringify(e));
|
|
127
|
+
}
|
|
128
|
+
const output = context.dump(value.value);
|
|
129
|
+
value.value.dispose();
|
|
130
|
+
if (typeof output !== 'string')
|
|
131
|
+
refuse('result must be declared text');
|
|
132
|
+
return { output, initializedMs, executionMs: performance.now() - start };
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
context?.dispose();
|
|
136
|
+
rt.dispose();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function bytesBase64(bytes) { let binary = ''; for (const b of bytes)
|
|
140
|
+
binary += String.fromCharCode(b); return btoa(binary); }
|
|
141
|
+
// A separate worker makes external abort possible while synchronous WASM executes.
|
|
142
|
+
export async function evaluateWasm(request, { workerFactory = () => new Worker(new URL('./worker.js', import.meta.url), { type: 'module' }), signal, lifetimeMs }) {
|
|
143
|
+
if (!Number.isSafeInteger(lifetimeMs) || lifetimeMs <= 0)
|
|
144
|
+
refuse('worker lifetime');
|
|
145
|
+
if (signal?.aborted)
|
|
146
|
+
refuse('cancelled');
|
|
147
|
+
preflight(request);
|
|
148
|
+
return new Promise((resolve, reject) => { const worker = workerFactory(); let done = false; const finish = (error, value) => { if (done)
|
|
149
|
+
return; done = true; clearTimeout(timer); signal?.removeEventListener('abort', abort); worker.terminate(); error ? reject(error) : resolve(value); }; const abort = () => finish(Error('REFUSE·wasm cancelled')); const timer = setTimeout(() => finish(Error('REFUSE·wasm worker lifetime')), lifetimeMs); signal?.addEventListener('abort', abort, { once: true }); const message = (raw) => { const data = raw; if (!data || typeof data !== 'object' || typeof data.ok !== 'boolean') {
|
|
150
|
+
finish(Error('REFUSE·wasm malformed worker result'));
|
|
151
|
+
return;
|
|
152
|
+
} if (data.ok) {
|
|
153
|
+
if (!data.result || typeof data.result.output !== 'string') {
|
|
154
|
+
finish(Error('REFUSE·wasm malformed worker output'));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
finish(null, data.result);
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
finish(Error(typeof data.error === 'string' ? data.error : 'REFUSE·wasm worker failure')); }; if (typeof worker.addEventListener === 'function') {
|
|
161
|
+
worker.addEventListener('message', e => message(e.data));
|
|
162
|
+
worker.addEventListener('error', e => finish(Error('REFUSE·wasm worker ' + e.message)));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
if (!worker.on) {
|
|
166
|
+
finish(Error('REFUSE·wasm worker event port'));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
worker.on('message', message);
|
|
170
|
+
worker.on('error', e => finish(e instanceof Error ? e : Error(String(e))));
|
|
171
|
+
} if (signal?.aborted) {
|
|
172
|
+
abort();
|
|
173
|
+
return;
|
|
174
|
+
} try {
|
|
175
|
+
worker.postMessage(request);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
finish(Error('REFUSE·wasm request is not cloneable'));
|
|
179
|
+
} });
|
|
180
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { parentPort } from 'node:worker_threads';
|
|
2
|
+
import { runWasmRequest } from "./adapter.js";
|
|
3
|
+
if (!parentPort)
|
|
4
|
+
throw Error('REFUSE·wasm worker port missing');
|
|
5
|
+
const port = parentPort;
|
|
6
|
+
port.once('message', async (request) => {
|
|
7
|
+
try {
|
|
8
|
+
port.postMessage({ ok: true, result: await runWasmRequest(request) });
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
port.postMessage({ ok: false, error: error instanceof Error ? error.message : String(error) });
|
|
12
|
+
}
|
|
13
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { Worker } from 'node:worker_threads';
|
|
3
|
+
import { sha256 } from "../host/hash.js";
|
|
4
|
+
import { toposAt } from "../host/selected-topos.js";
|
|
5
|
+
import { storeOf } from "../land/ledger.js";
|
|
6
|
+
import { evaluateWasm } from "./adapter.js";
|
|
7
|
+
function refuse(cause) { throw Error('REFUSE·wasm object ' + cause); }
|
|
8
|
+
/** Configuration is the caller's already authenticated, live standing; selection grants no authority. */
|
|
9
|
+
export function usesWasmObject(configuration) {
|
|
10
|
+
const rows = configuration.filter(f => f.scope === 'engine/object' && f.value !== 'withdraw');
|
|
11
|
+
if (!rows.length)
|
|
12
|
+
return false;
|
|
13
|
+
if (rows.length !== 1 || rows[0].role !== 'writes' || rows[0].measure !== 'id' || rows[0].form !== 'alphabet' || !['esm@1', 'wasm@1'].includes(rows[0].value ?? ''))
|
|
14
|
+
refuse('unique declared backend required');
|
|
15
|
+
return rows[0].value === 'wasm@1';
|
|
16
|
+
}
|
|
17
|
+
function limit(configuration, name, measure) {
|
|
18
|
+
const rows = configuration.filter(f => f.scope === 'engine/wasm/' + name && f.value !== 'withdraw');
|
|
19
|
+
if (rows.length !== 1 || rows[0].form !== 'interval' || rows[0].measure !== measure || rows[0].role !== 'writes')
|
|
20
|
+
refuse('missing or ambiguous ' + name + ' limit');
|
|
21
|
+
const span = /^(0|[1-9][0-9]*)\.\.(0|[1-9][0-9]*)$/.exec(rows[0].value ?? '');
|
|
22
|
+
if (!span || !Number.isSafeInteger(Number(span[1])) || !Number.isSafeInteger(Number(span[2])) || Number(span[1]) > Number(span[2]) || Number(span[2]) < 1)
|
|
23
|
+
refuse('invalid ' + name + ' limit');
|
|
24
|
+
return Number(span[2]);
|
|
25
|
+
}
|
|
26
|
+
/** The installed instrument owns the asset/form closure; place input cannot choose executable bytes. */
|
|
27
|
+
export async function foldObjectsWithWasm(root, records, context, configuration, signal) {
|
|
28
|
+
if (!usesWasmObject(configuration))
|
|
29
|
+
refuse('backend not selected');
|
|
30
|
+
const limits = { memoryBytes: limit(configuration, 'memory', 'bytes'), stackBytes: limit(configuration, 'stack', 'bytes'), executionMs: limit(configuration, 'execution', 'milliseconds') }, lifetimeMs = limit(configuration, 'worker-lifetime', 'milliseconds'), responseBytes = limit(configuration, 'response', 'bytes');
|
|
31
|
+
const assets = new URL('../../assets/wasm/', import.meta.url), manifest = JSON.parse(readFileSync(new URL('manifest.json', assets), 'utf8'));
|
|
32
|
+
if (!manifest.forms)
|
|
33
|
+
refuse('installed form closure missing');
|
|
34
|
+
const codecs = {};
|
|
35
|
+
for (const record of records.filter(r => r.record === 'cell')) {
|
|
36
|
+
const pin = record.fields.topos, binding = manifest.forms[pin];
|
|
37
|
+
if (!binding || !['intervalForm', 'alphabetOfForm'].includes(binding.export) || binding.form !== record.fields.form)
|
|
38
|
+
refuse('unsupported form standing ' + pin);
|
|
39
|
+
const standing = toposAt(pin, storeOf(root)), selector = standing.parts.filter(f => f.scope === 'wire/topos/context-view');
|
|
40
|
+
if (selector.length !== 1)
|
|
41
|
+
refuse('context selection ' + pin);
|
|
42
|
+
const offers = standing.parts.filter(f => f.kind === 'check' && f.view === selector[0].value);
|
|
43
|
+
if (offers.length !== 1 || offers[0].value !== binding.contextArtifact || !(offers[0].restsOn ?? '').split('|').includes(binding.contextArtifact))
|
|
44
|
+
refuse('context implementation differs ' + pin);
|
|
45
|
+
const selected = context.resolve(record);
|
|
46
|
+
if (selected.digest !== pin || selected.form.id !== binding.form)
|
|
47
|
+
refuse('prepared form differs ' + record.fields.scope);
|
|
48
|
+
codecs[record.fields.scope] = { digest: pin, export: binding.export, params: selected.params };
|
|
49
|
+
}
|
|
50
|
+
const guestNames = Object.keys(manifest.modules);
|
|
51
|
+
if (guestNames.length !== 1)
|
|
52
|
+
refuse('installed guest module map');
|
|
53
|
+
const guestName = guestNames[0];
|
|
54
|
+
let program;
|
|
55
|
+
try {
|
|
56
|
+
program = `import{objectFold,intervalForm,alphabetOfForm}from${JSON.stringify(guestName)};const forms={intervalForm,alphabetOfForm},codecs=${JSON.stringify(codecs)},records=${JSON.stringify(records)};const context={resolve:cell=>{const c=codecs[cell.fields.scope];if(!c)throw Error('REFUSE unknown prepared cell');return{digest:c.digest,form:forms[c.export],params:c.params}}};globalThis.result=JSON.stringify(objectFold(records,context));`;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return refuse('context is not serializable');
|
|
60
|
+
}
|
|
61
|
+
const entry = guestName + '.entry', programDigest = sha256(program);
|
|
62
|
+
const guest = readFileSync(new URL('guest.js', assets), 'utf8'), modules = { [guestName]: guest, [entry]: program }, request = { trusted: { ...manifest, modules: { ...manifest.modules, [entry]: programDigest }, entry, aliases: {}, limits, byteLengths: { ...manifest.byteLengths, modules: { ...manifest.byteLengths.modules, [entry]: Buffer.byteLength(program) } } }, assets: { runtime: new Uint8Array(readFileSync(new URL('runtime.js', assets))), wasm: new Uint8Array(readFileSync(new URL('runtime.wasm', assets))) }, modules, entry, aliases: {}, limits };
|
|
63
|
+
const result = await evaluateWasm(request, { workerFactory: () => new Worker(new URL('./node-worker.js', import.meta.url)), lifetimeMs, ...(signal ? { signal } : {}) });
|
|
64
|
+
if (Buffer.byteLength(result.output) > responseBytes)
|
|
65
|
+
refuse('response bytes limit');
|
|
66
|
+
let readings;
|
|
67
|
+
try {
|
|
68
|
+
readings = JSON.parse(result.output);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return refuse('invalid projection text');
|
|
72
|
+
}
|
|
73
|
+
if (!Array.isArray(readings) || readings.some(r => !r || typeof r.cell !== 'string' || typeof r.state !== 'string'))
|
|
74
|
+
refuse('invalid projection shape');
|
|
75
|
+
return readings;
|
|
76
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scope": "contract/published/authenticated-reference",
|
|
3
|
+
"members": [
|
|
4
|
+
{
|
|
5
|
+
"role": "contract",
|
|
6
|
+
"path": "docs/contracts/reference-port.md",
|
|
7
|
+
"digest": "sha256:d6198b9ab177086cb334e9e9cd7adb5c67b0af7165a79d23812aa2496d17674c"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"role": "yes",
|
|
11
|
+
"path": "samples/authenticated-reference/yes/weather-reading/inputs/yes.json",
|
|
12
|
+
"digest": "sha256:f285a014cc9e9453aebd4c4ed94354fba5cac55c05929f4ad7cdd1b3348a9717"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"role": "vector",
|
|
16
|
+
"path": "vectors/native/authenticated-reference.vector.json",
|
|
17
|
+
"digest": "sha256:9aba7121fbbb98e63259dea78e52377cd71c628e0d17be20c9a51da27f2b31de"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"role": "no",
|
|
21
|
+
"path": "samples/authenticated-reference/yes/weather-reading/inputs/signature.json",
|
|
22
|
+
"digest": "sha256:2049bbbf88077727911a0cfec3193ab6ce7bccb8d4e3bb22fc537c59f5addf58"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scope": "contract/published/engine-object-projection",
|
|
3
|
+
"members": [
|
|
4
|
+
{
|
|
5
|
+
"role": "contract",
|
|
6
|
+
"path": "docs/contracts/engine.md",
|
|
7
|
+
"digest": "sha256:2d54ddc75386a0706a3bc500e36deedc85ca9e7dc965eff5c795f02b1a716078"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"role": "yes",
|
|
11
|
+
"path": "samples/engine-interval/inputs/sample.json",
|
|
12
|
+
"digest": "sha256:ef476bda8c15b4967a88dc27a188ab25cfac42bdf381fb82f4e57a482d2fd27d"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"role": "no",
|
|
16
|
+
"path": "samples/no/engine-order/inputs/sample.json",
|
|
17
|
+
"digest": "sha256:f2104a661541baf7f8e6d9224590210b272e24519dafce94ca7c588e5a78a20d"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"role": "vector",
|
|
21
|
+
"path": "vectors/engine-object.cli.json",
|
|
22
|
+
"digest": "sha256:191920f597e2d8bafc9aeeff13934645c64a790dcad94b22c562b30c5fe6baa0"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Pure object projection
|
|
2
|
+
|
|
3
|
+
`@lapxo/bound/engine` exports `objectFold` and the existing `ObjectReading`, `ObjectRecord` and `ObjectContext` types. The CLI and receipt paths use that same implementation. Its Obligations 0.3.5 algebra is unchanged.
|
|
4
|
+
|
|
5
|
+
The input is authenticated and context-admitted effective history with selected deterministic forms and parameters. This function does not admit records, verify signatures, resolve content, run commands, select clocks or write storage. Applications must perform preparation before projection.
|
|
6
|
+
|
|
7
|
+
Within each epoch, a cell declaration precedes its uses in effective order. A same-epoch act before its cell refuses in preparation by name: `object context: cell not declared before <act-id>`. Lower-epoch cell declarations remain eligible even when their envelope arrives later. Effective sign/join order is preserved; transport arrival does not authorize arbitrary semantic reordering. The consumed Topos contract must be published before this export is admitted for release.
|
|
8
|
+
|
|
9
|
+
Outputs preserve existing attributed origins, local and travelling marks, exact withdrawals, floor and ceiling parts and REQUIRED/FREE/FORBIDDEN/CONFLICT decisions. Raw object JSON is not a new canonical identity. Byte identity requires the existing declared reading projection.
|
|
10
|
+
|
|
11
|
+
Malformed or unauthenticated records are outside this pure projector's input contract. Refusal, authority and interrupted-admission vectors exercise the host boundary; they do not claim cryptographic admission inside WASM. No host callback calculates an algebraic result in a WASM comparison.
|
|
12
|
+
|
|
13
|
+
## Public conformance samples
|
|
14
|
+
|
|
15
|
+
`samples/engine-interval` and `samples/engine-alphabet` are formed places: TARGET.bound, receipts.bound, package.json, the declared reader.js and inputs/sample.json. The instrument exercises the same projector against prepared fixtures; its reader is not a command users invoke. `fold <sample-directory> --check` verifies each portable receipt. Cold native `fold --as receipts` recomputes the declared conformance reading without a private store.
|
|
16
|
+
|
|
17
|
+
`samples/no/engine-interval.json` and `samples/no/engine-alphabet.json` are negative data fixtures. Their captured native preparation refusal is `cell not declared before s-B`; no closed receipts are asserted for refusing input. The actual CLI vector is `vectors/engine-object.cli.json`. This conformance reader does not authenticate arbitrary signatures, coverage or clocks.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Optional WASM host adapter
|
|
21
|
+
|
|
22
|
+
The optional `@lapxo/bound/wasm` entry evaluates the existing pure projection in QuickJS WASM. It performs no admission, signature verification, state calculation of its own, transport, key discovery or effects. Host authentication must finish before records become projection inputs. A valid digest identifies bytes; it grants no authority or confinement guarantee.
|
|
23
|
+
|
|
24
|
+
The host supplies the trusted runtime/WASM/module digests, exact byte lengths, entry, aliases and limits. These expectations must come from its accepted configuration, independently of fetched place bytes. Closed request metadata and exact lengths are checked before copying, hashing or worker handoff. Shared assets refuse. Every supplied byte is verified and copied before execution; the closed runtime bundle has no imports and receives the already verified WASM binary. Guest imports resolve only within the verified module map. No second fetch occurs.
|
|
25
|
+
|
|
26
|
+
`runWasmRequest` returns declared text, without inventing a JSON canonicalization or number policy. The caller's declared entry chooses the serialization contract. Memory and stack limits govern the guest; they do not describe total host/WASM initialization memory. Guest memory, stack and execution budgets are explicit host inputs. Initialization and execution times are separate readings, not a speed guarantee.
|
|
27
|
+
|
|
28
|
+
`evaluateWasm` runs in a host worker. It accepts an AbortSignal and an explicit worker lifetime. Cancellation, timeout, malformed messages, failed serialization and worker errors terminate the worker and return no successful result. Guest state remains provisional until success; no host write port is supplied. A terminated computation produces no successful receipt. The direct `runWasmRequest` entry has deadline interruption but cannot asynchronously receive an external abort while synchronously executing; callers needing that contract use `evaluateWasm`.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Native optional WASM projection
|
|
32
|
+
|
|
33
|
+
The existing object view consumes an optional, authenticated live declaration `engine/object form=alphabet measure=id value=wasm@1`. With no selector it retains the ESM projection; a conflicting or unknown selector refuses. This profile selects only the explicit object view, not every other view of the place. The host admits and folds configuration with the existing authority and withdrawal rules before selecting execution.
|
|
34
|
+
|
|
35
|
+
The place declares five interval limits: `engine/wasm/memory`, `engine/wasm/stack` and `engine/wasm/response` in bytes; `engine/wasm/execution` and `engine/wasm/worker-lifetime` in milliseconds. Missing, ambiguous or invalid limits refuse; there is no inferred fallback. The installed instrument binds the guest module and supported form standings to their context implementation artifacts. A place cannot choose another verifier or executable through this selection; an unsupported form or different implementation refuses.
|
|
36
|
+
|
|
37
|
+
Context initialization is measured before place execution. If observed initialized guest memory exceeds the declared memory budget, the operation refuses without running place code. Host initialization memory is outside that guest execution limit; the worker lifetime bounds the entire attempt. During execution the unchanged declared memory, stack and execution limits apply. SIGINT reaches the worker cancellation port; cancellation or failure emits no successful object result.
|
|
38
|
+
|
|
39
|
+
For the opt-in `wasm@1` profile, the host verifies the selected context implementation before importing it. Every SHA-256 member declared by the context offer’s `restsOn` is checked by digest, and the existing `moduleClosure` validates the imported closure. Missing, altered, undeclared or unresolved imported members refuse before context code executes. This establishes content identity and import closure, not correctness, authority or sandbox confinement. Admission still precedes projection, and this check grants no permission to reuse a retained answer as current.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Public host ports
|
|
2
|
+
|
|
3
|
+
`/engine` and `/reference` export `readContent`, `retainContent` and `invokeSigningPort`, with `ContentReadPort`, `PersistencePort`, `SigningPort`, `DigestPort` and `PortLimits`. There is no default network, store, account or signer. `objectFold` remains pure and never calls a port.
|
|
4
|
+
|
|
5
|
+
Every operation takes an explicit positive safe-integer `timeoutMs` and `maxBytes`, and an optional AbortSignal. Invalid limits and pre-cancellation refuse before the callback. Acquisition, digest calculation and retention share the operation lifetime. A timeout aborts the supplied signal and returns no successful result. This is a cooperative host boundary, not preemption of synchronous JavaScript or sandbox confinement.
|
|
6
|
+
|
|
7
|
+
`readContent(source, digest, ports, limits, signal)` invokes the supplied read callback and SHA-256 callback, checks byte bounds before copying/hashing, rejects shared buffers, and verifies an owned snapshot against the requested digest. Location carries no authority.
|
|
8
|
+
|
|
9
|
+
`retainContent(digest, bytes, ports, limits, signal)` checks identity before calling the host's atomic byte-retention callback. Its acknowledgement contains only digest and byte count. It is not a signed receipt, admission or permission to reuse a response. The host must implement atomic retention and cooperate with cancellation. A callback that ignores cancellation may finish retaining bytes after the caller has refused; no success, act or authority follows from those bytes. Opening and projection never retain automatically.
|
|
10
|
+
|
|
11
|
+
`invokeSigningPort(lot, sign, limits, signal)` uses the existing Topos signing request/response framing. It acquires protocol-shaped signatures; it does not decide authority or certify them cryptographically. Native export can receive `hostSigner: {name, sign}` through `/reference/native`. The name must match the admitted signer selection, and cannot be combined with a key-file override. The existing consent path verifies every returned signature against the admitted key, era, scope and epoch before returning a carrier. No key material enters the engine.
|
|
12
|
+
|
|
13
|
+
Native opening accepts `content: {name, read}`. Its name must match the admitted transport selection, with that selection's existing byte and lifetime bounds. The host callback cannot be chosen by a carrier, reference or repository. The existing inspector verifies the returned carrier again and the selected backend projects only verified records. There is no backend fallback.
|
|
14
|
+
|
|
15
|
+
Public port failures use the machine refusal catalog: `host-port/budget`, `cancelled`, `timeout`, `failed`, `integrity`, `response`. Native acquisition failures retain their enclosing reference refusal. Host diagnostics are not returned as authority or parsed as codes.
|
|
16
|
+
|
|
17
|
+
Native vector output, in two real admitted places:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
PORTS owned content · verified retention · signer content persistence failures · budget integrity cancellation timeout refused
|
|
21
|
+
HOST host-sensor · declared signer and content injected · real signature verified · wrong binding refused · no commit
|
|
22
|
+
HOST host-editorial · declared signer and content injected · real signature verified · wrong binding refused · no commit
|
|
23
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scope": "contract/published/host-ports",
|
|
3
|
+
"members": [
|
|
4
|
+
{
|
|
5
|
+
"role": "contract",
|
|
6
|
+
"path": "docs/contracts/host-ports.md",
|
|
7
|
+
"digest": "sha256:f3d646da2399c719469a37293b329d53b72b0478ca97f961b90c1f4e6adc2ae6"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"role": "yes",
|
|
11
|
+
"path": "samples/host-ports/yes.json",
|
|
12
|
+
"digest": "sha256:f8dc3c6939bd8f4bb91cb57e3e9b52a865645cc80ee0f5ce5a11570ef3f31ce3"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"role": "vector",
|
|
16
|
+
"path": "vectors/native/host-ports.vector.json",
|
|
17
|
+
"digest": "sha256:58425f81fb4f1ef6e392d8fa3a5ee3a287ef6fbcbfb11e512fd2e30f24f465e6"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"role": "no",
|
|
21
|
+
"path": "samples/host-ports/no.json",
|
|
22
|
+
"digest": "sha256:ffc9dbb29743d4faa16c5c29eb73a7e0f24cf4da3255a979f628f5c3d8f4b7c1"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"profile": "quartet-process@1",
|
|
3
|
+
"scope": "contract/published/native",
|
|
4
|
+
"surface": [
|
|
5
|
+
"contract/published/optional-wasm-adapter",
|
|
6
|
+
"contract/published/authenticated-reference",
|
|
7
|
+
"contract/published/reference-export",
|
|
8
|
+
"contract/published/reference-backend",
|
|
9
|
+
"contract/published/standing",
|
|
10
|
+
"contract/published/refusals",
|
|
11
|
+
"contract/published/host-ports",
|
|
12
|
+
"contract/published/readme"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scope": "contract/published/optional-wasm-adapter",
|
|
3
|
+
"members": [
|
|
4
|
+
{
|
|
5
|
+
"role": "contract",
|
|
6
|
+
"path": "docs/contracts/engine.md",
|
|
7
|
+
"digest": "sha256:2d54ddc75386a0706a3bc500e36deedc85ca9e7dc965eff5c795f02b1a716078"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"role": "yes",
|
|
11
|
+
"path": "samples/wasm/water-level/TARGET.bound",
|
|
12
|
+
"digest": "sha256:d2f3efc176a6fa7f695dcaab93ed6f35fac4e601d0b7e47f485ac15109d11a0c"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"role": "vector",
|
|
16
|
+
"path": "vectors/wasm-object.cli.json",
|
|
17
|
+
"digest": "sha256:f0b970ede31b99e00e94f249970aa8c714880dccb03ed7952a3cf01bf24a7c17"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"role": "no",
|
|
21
|
+
"path": "samples/wasm/water-level/no-memory.bound",
|
|
22
|
+
"digest": "sha256:4c30cb6c77a9079a5961f0ff50c53830ad2c7ca8526ef63aa7c3eb4fa2af4554"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scope": "contract/published/readme",
|
|
3
|
+
"members": [
|
|
4
|
+
{
|
|
5
|
+
"role": "contract",
|
|
6
|
+
"path": "README.md",
|
|
7
|
+
"digest": "sha256:183fe27e7a8bfdb04f4aefaa785f2b1845da1c5a93562a06a300175a960c72da"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"role": "yes",
|
|
11
|
+
"path": "samples/readme/yes.json",
|
|
12
|
+
"digest": "sha256:37449e6ec4867f034463ca20218d370fe40c1d5dec759871c398fd73109f9f6e"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"role": "vector",
|
|
16
|
+
"path": "vectors/native/readme.vector.json",
|
|
17
|
+
"digest": "sha256:b97b50e102fb6c34851d2769d6029663fb4838e2eb70a9bdb4c168141b8964f3"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"role": "no",
|
|
21
|
+
"path": "samples/readme/no.json",
|
|
22
|
+
"digest": "sha256:6bb243445b009fd94ba021342fca34ea00cf4c5257378d9d7c05840c13166f73"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Authenticated native reference opening
|
|
2
|
+
|
|
3
|
+
`@lapxo/bound/reference/native` exports `exportAuthenticatedReference` and `openAuthenticatedReference`. This is the Node host boundary. The platform-free inspector stays in `/reference`; the pure projector stays in `/engine`.
|
|
4
|
+
|
|
5
|
+
The receiver admits one `engine/object` declaration: `esm@1` or `wasm@1`. Missing, ambiguous and unknown selections refuse. WASM never falls back to ESM. The native route shares one context preparation, authenticates the received original records, then calls the existing selected projector. It introduces no algebra or alternate interpreter.
|
|
6
|
+
|
|
7
|
+
The host admits `reference/snapshot`, `reference/epoch`, `reference/proof-scope`, `reference/policy`, `reference/form-implementation`, `reference/records`, and the standing/refusal contract digests. The policy is the independently accepted export policy, not a policy invented from the received carrier. The prepared form implementation must match the admitted expectation, and both interpretation contracts must match the installed bytes. A carrier's accompanying context is public data, not an authority anchor.
|
|
8
|
+
|
|
9
|
+
Content goes through the declared transport and its existing byte/time limits. The snapshot binds the declared public context, including resource budgets. The native opener accepts an AbortSignal and checks interruption before download and projection; the WASM worker uses its existing cancellation and lifetime contract. This does not claim cancellation of an in-flight native download, browser persistence or arbitrary browser capsules.
|
|
10
|
+
|
|
11
|
+
WASM uses the installed asset manifest, runtime, guest and exact supported form standings. The caller cannot replace that manifest with a convenient fixture. Its memory, stack, execution, worker-lifetime and response budgets remain explicit admitted interval lines. A form outside that installed closure refuses by name.
|
|
12
|
+
|
|
13
|
+
The positive fixture uses the previously published native reader archive named in `samples/reference-backend/world-fixture.json`, or the same supported standing and closed modules already laid by digest. Preparation verifies every byte before timed opening. The fixture archive is fetched or retained outside opening measurements; no private store or checkout path identifies it. No provider code executes during archive preparation.
|
|
14
|
+
|
|
15
|
+
The native quartet opens one signed reference in two unrelated places, once through each explicitly selected backend. It compares authenticated standing, records and canonical projection bytes. Authority-context identity describes authentication, not an execution receipt: equal outputs never authorize reuse of a receipt across implementations. Neither opening signs or commits an act.
|
|
16
|
+
|
|
17
|
+
Captured semantic markers:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
WASM water-level-reference · authenticated download · same standing · same records · byte-equal ESM projection · altered carrier refused · no commit
|
|
21
|
+
WASM editorial-reference · authenticated download · same standing · same records · byte-equal ESM projection · altered carrier refused · no commit
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The no sample changes the carrier while retaining its reference. Integrity refuses before projection. Existing vectors also retain unknown-backend, unsupported-form, byte-budget, authority and cancellation boundaries. The quartet descriptor is `reference-backend.publication.json`; installed-archive release acceptance and L6 remain separate obligations.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scope": "contract/published/reference-backend",
|
|
3
|
+
"members": [
|
|
4
|
+
{
|
|
5
|
+
"role": "contract",
|
|
6
|
+
"path": "docs/contracts/reference-backend.md",
|
|
7
|
+
"digest": "sha256:c69fbaac11276efcd8a436f242e07d4fda18137c9987f8bba183fe6d6ea801c6"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"role": "yes",
|
|
11
|
+
"path": "samples/reference-backend/yes.json",
|
|
12
|
+
"digest": "sha256:67657bf32a0b85053bf3778f8e1dc13478aaf7386e39200d6967cc9ff2ef5e6f"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"role": "vector",
|
|
16
|
+
"path": "vectors/native/reference-backend.vector.json",
|
|
17
|
+
"digest": "sha256:05257cf22466c859eb01e1abf660927afb5a9a160d3865053ebdf8649f0f5392"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"role": "no",
|
|
21
|
+
"path": "samples/reference-backend/no.json",
|
|
22
|
+
"digest": "sha256:a4e3dd23533925d117954666eb68c4f54165af3263317c330beed6d13a216626"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|