@lapxo/bound 0.2.4 → 0.2.6
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/CITATION.cff +1 -1
- package/README.md +20 -3
- package/TARGET.bound +85 -47
- package/dist/cli/accept.js +61 -590
- package/dist/cli/act-result.js +3 -103
- package/dist/cli/args.js +3 -44
- package/dist/cli/custodian.js +2 -29
- package/dist/cli/host.js +4 -32
- package/dist/cli/names.js +1 -12
- package/dist/cli/native-descendant.js +1 -19
- package/dist/cli/native.js +3 -60
- package/dist/cli/observe.js +1 -13
- package/dist/cli/owner.js +3 -139
- package/dist/cli/pass.js +22 -321
- package/dist/cli/place.js +6 -282
- package/dist/cli/release-result.js +3 -80
- package/dist/cli/retained-judgment.js +1 -25
- package/dist/cli/standing-result.js +4 -19
- package/dist/cli/takes.js +10 -112
- package/dist/cli/verb.d.ts +1 -2
- package/dist/cli/verb.js +85 -684
- package/dist/engine/computation.js +2 -0
- package/dist/engine/conformance.js +4 -0
- package/dist/engine/encoding.js +1 -2
- package/dist/engine/index.d.ts +1 -13
- package/dist/engine/index.js +2 -11
- package/dist/engine/object.js +1 -38
- package/dist/engine/ports.js +2 -117
- package/dist/fold/admission-history.js +1 -17
- package/dist/fold/bootstrap-anchor.js +1 -28
- package/dist/fold/ceilings.js +1 -142
- package/dist/fold/claims.js +2 -132
- package/dist/fold/closed.js +24 -235
- package/dist/fold/configures.js +1 -25
- package/dist/fold/digests.js +10 -226
- package/dist/fold/evidence.js +1 -22
- package/dist/fold/fold-worker.js +1 -13
- package/dist/fold/kept.js +12 -173
- package/dist/fold/keys.js +3 -91
- package/dist/fold/laid.js +3 -90
- package/dist/fold/nos.js +1 -48
- package/dist/fold/object.js +1 -2
- package/dist/fold/observed.js +28 -534
- package/dist/fold/opened.js +1 -33
- package/dist/fold/own.js +3 -217
- package/dist/fold/paid.js +1 -92
- package/dist/fold/place-inputs.js +1 -70
- package/dist/fold/places.js +3 -100
- package/dist/fold/rank.js +1 -9
- package/dist/fold/reach.js +1 -83
- package/dist/fold/readers.js +6 -142
- package/dist/fold/receipts.js +1 -47
- package/dist/fold/region-declarations.js +1 -13
- package/dist/fold/region.js +8 -286
- package/dist/fold/release-policy.js +1 -101
- package/dist/fold/resolved.js +6 -145
- package/dist/fold/roles.js +2 -59
- package/dist/fold/second.js +4 -71
- package/dist/fold/shards.js +12 -100
- package/dist/fold/signed.js +3 -81
- package/dist/fold/signers.js +1 -54
- package/dist/fold/stranger.js +6 -24
- package/dist/fold/views.js +1 -66
- package/dist/fold/wire.js +1 -46
- package/dist/fold/zoom.js +3 -81
- package/dist/host/act-cost.js +1 -25
- package/dist/host/adapters/keys/ed25519.js +1 -30
- package/dist/host/adapters/modules/javascript.js +1 -50
- package/dist/host/adapters/transport/http.js +1 -28
- package/dist/host/admitted-place.js +1 -35
- package/dist/host/archive.js +1 -152
- package/dist/host/call-context.js +1 -14
- package/dist/host/capsule-process.js +2 -62
- package/dist/host/capsule.js +9 -171
- package/dist/host/cell-receipts.js +12 -128
- package/dist/host/command-server.js +4 -0
- package/dist/host/commit-result.js +1 -5
- package/dist/host/content-needed.js +1 -8
- package/dist/host/content-store.js +1 -31
- package/dist/host/contextual-place.js +2 -72
- package/dist/host/digest.js +2 -15
- package/dist/host/hash.js +1 -9
- package/dist/host/host-controls.js +1 -19
- package/dist/host/in-process-act.js +3 -84
- package/dist/host/in-process-context.js +3 -91
- package/dist/host/in-process-root.js +6 -84
- package/dist/host/in-process.js +4 -55
- package/dist/host/index.d.ts +1 -15
- package/dist/host/index.js +1 -7
- package/dist/host/io.js +1 -11
- package/dist/host/lifetime.js +1 -79
- package/dist/host/located.js +6 -105
- package/dist/host/native/authority-card-view.js +5 -0
- package/dist/host/native/authority-card.js +1 -0
- package/dist/host/native/bounded-file.js +1 -32
- package/dist/host/native/command.js +1 -91
- package/dist/host/native/control-bridge-worker.js +2 -88
- package/dist/host/native/control-bridge.js +1 -110
- package/dist/host/native/control-selection.js +1 -32
- package/dist/host/native/custody.js +1 -91
- package/dist/host/native/deadline.js +1 -28
- package/dist/host/native/descendants.js +1 -528
- package/dist/host/native/generated-custodian.js +5 -267
- package/dist/host/native/generated.js +1 -379
- package/dist/host/native/image.js +1 -45
- package/dist/host/native/installed-package.d.ts +1 -0
- package/dist/host/native/installed-package.js +5 -0
- package/dist/host/native/jobs.js +2 -148
- package/dist/host/native/loader.js +1 -269
- package/dist/host/native/materialize.js +1 -175
- package/dist/host/native/module-closure.js +1 -130
- package/dist/host/native/module-delivery.d.ts +1 -62
- package/dist/host/native/module-delivery.js +1 -151
- package/dist/host/native/module-inventory.js +2 -0
- package/dist/host/native/module-syntax.js +1 -69
- package/dist/host/native/native-binary.js +1 -115
- package/dist/host/native/native-program.js +1 -72
- package/dist/host/native/node-jobs.js +3 -187
- package/dist/host/native/node-launch.js +1 -159
- package/dist/host/native/preload.js +1 -45
- package/dist/host/native/probes.js +1 -0
- package/dist/host/native/reading-witness-admission.js +5 -0
- package/dist/host/native/reading.js +1 -249
- package/dist/host/native/receipt-environment.js +1 -41
- package/dist/host/native/references.js +1 -30
- package/dist/host/native/root.js +1 -37
- package/dist/host/native/route.js +1 -216
- package/dist/host/native/runtime.js +1 -9
- package/dist/host/native-place-state.js +1 -0
- package/dist/host/native-reader-context.js +1 -8
- package/dist/host/native-receiver.js +1 -25
- package/dist/host/objects.js +1 -38
- package/dist/host/order.js +1 -2
- package/dist/host/persistent-host.js +1 -0
- package/dist/host/physical-lines.d.ts +1 -0
- package/dist/host/physical-lines.js +1 -0
- package/dist/host/place-act-transaction.js +4 -78
- package/dist/host/place-clock-selection.js +5 -124
- package/dist/host/ports/ingress.js +2 -57
- package/dist/host/ports/local-act.js +5 -183
- package/dist/host/ports/place-act.js +1 -134
- package/dist/host/ports/publication.js +1 -56
- package/dist/host/ports/signing.js +1 -74
- package/dist/host/ports/store.js +1 -18
- package/dist/host/ports/transport.js +1 -48
- package/dist/host/process-lifetime.js +1 -17
- package/dist/host/profile-composition.d.ts +1 -0
- package/dist/host/profile-composition.js +2 -0
- package/dist/host/provide.js +1 -183
- package/dist/host/read-only.js +1 -9
- package/dist/host/reading-closures.js +7 -227
- package/dist/host/reading-context.js +1 -53
- package/dist/host/reading-identity-types.js +0 -0
- package/dist/host/reading-identity.js +3 -0
- package/dist/host/reading-preparation.js +6 -0
- package/dist/host/reference-authenticated.d.ts +1 -40
- package/dist/host/reference-authenticated.js +3 -100
- package/dist/host/reference-contracts.js +1 -6
- package/dist/host/reference-export.js +6 -81
- package/dist/host/reference-native-api.d.ts +1 -3
- package/dist/host/reference-native-api.js +1 -3
- package/dist/host/reference-native.js +1 -74
- package/dist/host/reference-profile.js +1 -63
- package/dist/host/reference-standing.js +2 -18
- package/dist/host/reference.js +1 -24
- package/dist/host/refusals.js +2 -43
- package/dist/host/release.js +4 -256
- package/dist/host/root-clock-source.js +1 -307
- package/dist/host/selected-capsules.js +1 -50
- package/dist/host/selected-topos.js +1 -80
- package/dist/host/signature-era.js +1 -12
- package/dist/host/signing.js +2 -48
- package/dist/host/source-content.js +2 -111
- package/dist/host/standing-carrier.js +1 -18
- package/dist/host/standing-projection.js +1 -50
- package/dist/host/timing.js +1 -7
- package/dist/host/walk.js +20 -193
- package/dist/host/work-trace.js +1 -0
- package/dist/judge/late.js +1 -33
- package/dist/judge/take.js +2 -75
- package/dist/judge/widening.js +1 -25
- package/dist/land/act.js +8 -336
- package/dist/land/alias.js +1 -41
- package/dist/land/held.js +1 -23
- package/dist/land/inert.js +1 -33
- package/dist/land/leaving.js +1 -55
- package/dist/land/ledger.js +6 -188
- package/dist/land/owned.js +4 -66
- package/dist/land/sign.js +1 -53
- package/dist/land/standing-pin.js +1 -49
- package/dist/land/vouched.js +1 -112
- package/dist/land/withdraw.js +1 -24
- package/dist/observe/files.js +1 -88
- package/dist/observe/identity.js +1 -61
- package/dist/observe/match.js +1 -8
- package/dist/observe/regions.js +7 -306
- package/dist/observe/run.js +1 -41
- package/dist/observe/runner.js +4 -101
- package/dist/public-types.d.ts +2019 -0
- package/dist/render/capsule.js +1 -30
- package/dist/render/field.js +1 -40
- package/dist/render/names.js +1 -4
- package/dist/render/open.js +1 -61
- package/dist/render/page.js +1 -7
- package/dist/render/receipt-projection.js +1 -0
- package/dist/render/receipts.js +1 -47
- package/dist/render/shape.js +1 -74
- package/dist/render/target.js +4 -52
- package/dist/render/view.js +7 -197
- package/dist/vendor/bundle.json +1 -0
- package/dist/vendor/library14.js +1 -0
- package/dist/vendor/object-provider.js +42 -0
- package/dist/vendor/runtime.js +61 -0
- package/dist/wasm/adapter.d.ts +1 -51
- package/dist/wasm/adapter.js +1 -180
- package/dist/wasm/node-worker.js +1 -13
- package/dist/wasm/object.js +1 -76
- package/dist/wasm/worker.js +1 -7
- package/docs/contracts/authenticated-reference.publication.json +1 -1
- package/docs/contracts/authority-preflight.md +17 -0
- package/docs/contracts/authority-preflight.publication.json +25 -0
- package/docs/contracts/closure-delivery.md +1 -1
- package/docs/contracts/closure-delivery.publication.json +1 -1
- package/docs/contracts/conformance.json +142 -0
- package/docs/contracts/determinism.bound +9 -0
- package/docs/contracts/engine-object-projection.publication.json +1 -1
- package/docs/contracts/engine.md +21 -1
- package/docs/contracts/installed-package.md +21 -0
- package/docs/contracts/installed-package.publication.json +25 -0
- package/docs/contracts/materialized-leaf-sequence.md +15 -0
- package/docs/contracts/materialized-leaf-sequence.publication.json +25 -0
- package/docs/contracts/module-inventory.md +15 -0
- package/docs/contracts/module-inventory.publication.json +25 -0
- package/docs/contracts/native-host.md +29 -1
- package/docs/contracts/native-host.publication.json +4 -4
- package/docs/contracts/native-probes.md +13 -0
- package/docs/contracts/native-probes.publication.json +25 -0
- package/docs/contracts/native-publication.inventory.json +10 -1
- package/docs/contracts/native-view-batch.md +17 -0
- package/docs/contracts/native-view-batch.publication.json +25 -0
- package/docs/contracts/optional-wasm-adapter.publication.json +1 -1
- package/docs/contracts/physical-lines.md +19 -0
- package/docs/contracts/physical-lines.publication.json +25 -0
- package/docs/contracts/profile-composition.md +17 -0
- package/docs/contracts/profile-composition.publication.json +25 -0
- package/docs/contracts/profile-preparation-native-meaning.md +9 -0
- package/docs/contracts/publication.md +12 -0
- package/docs/contracts/reading-identity.md +61 -0
- package/docs/contracts/reading-identity.publication.json +25 -0
- package/docs/contracts/reading-witness-admission.md +49 -0
- package/docs/contracts/readme.publication.json +1 -1
- package/docs/contracts/reference-port.md +11 -0
- package/docs/contracts/reference-port.publication.json +1 -1
- package/docs/contracts/refusals.bound +346 -94
- package/docs/contracts/refusals.md +119 -39
- package/docs/contracts/refusals.publication.json +2 -2
- package/docs/contracts/views.md +8 -0
- package/docs/reference.md +9 -0
- package/licenses/wasm/{fast-text-encoding.txt → NOTICE.txt} +111 -0
- package/package.json +84 -34
- package/receipts.bound +12952 -10449
- package/samples/authority-preflight/no.json +6 -0
- package/samples/authority-preflight/yes.json +30 -0
- package/samples/engine-alphabet/reader.js +3 -1457
- package/samples/engine-alphabet/receipts.bound +7 -7
- package/samples/engine-interval/reader.js +3 -1457
- package/samples/engine-interval/receipts.bound +7 -7
- package/samples/installed-package/consumer.mjs +29 -0
- package/samples/installed-package/fixture.json +48 -0
- package/samples/installed-package/no.json +10 -0
- package/samples/installed-package/yes.json +52 -0
- package/samples/materialized-leaf-sequence/no.json +11 -0
- package/samples/materialized-leaf-sequence/yes.json +10 -0
- package/samples/module-inventory/yes.json +28 -0
- package/samples/native/physical-line-reader.mjs +1 -0
- package/samples/native/physical-line-reader.source.mjs +13 -0
- package/samples/native-host/no.json +6 -1
- package/samples/native-host/yes.json +18 -1
- package/samples/native-probes/inputs/inspection.json +28 -0
- package/samples/native-probes/no.json +7 -0
- package/samples/native-probes/yes.json +28 -0
- package/samples/native-view-batch/no.json +14 -0
- package/samples/native-view-batch/yes.json +10 -0
- package/samples/no/engine-order/reader.js +3 -1457
- package/samples/no/module-inventory/no.json +10 -0
- package/samples/physical-lines/no.json +5 -0
- package/samples/physical-lines/yes.json +9 -0
- package/samples/profile-composition/no.json +6 -0
- package/samples/profile-composition/yes.json +14 -0
- package/samples/reading-identity/no.json +26 -0
- package/samples/reading-identity/yes.json +69 -0
- package/vectors/native/authority-preflight.vector.json +55 -0
- package/vectors/native/installed-package.vector.json +31 -0
- package/vectors/native/materialized-leaf-sequence.vector.json +31 -0
- package/vectors/native/module-inventory.vector.json +56 -0
- package/vectors/native/native-host.vector.json +214 -0
- package/vectors/native/native-probes.vector.json +31 -0
- package/vectors/native/native-view-batch.vector.json +31 -0
- package/vectors/native/physical-lines.vector.json +105 -0
- package/vectors/native/profile-composition.vector.json +53 -0
- package/vectors/native/reading-identity.vector.json +139 -0
- package/vectors/native/refusals.vector.json +138 -0
- package/vendor/syntax/LICENSE.md +7 -0
- package/vendor/syntax/parser.js +1 -0
- package/.github/workflows/release.yml +0 -67
- package/.github/workflows/test.yml +0 -35
- package/dist/engine/object.d.ts +0 -17
- package/dist/engine/ports.d.ts +0 -37
- package/dist/fold/claims.d.ts +0 -29
- package/dist/host/call-context.d.ts +0 -20
- package/dist/host/commit-result.d.ts +0 -6
- package/dist/host/in-process-act.d.ts +0 -82
- package/dist/host/in-process-context.d.ts +0 -46
- package/dist/host/in-process-root.d.ts +0 -117
- package/dist/host/in-process.d.ts +0 -41
- package/dist/host/native/module-closure.d.ts +0 -35
- package/dist/host/native-receiver.d.ts +0 -19
- package/dist/host/place-act-transaction.d.ts +0 -24
- package/dist/host/place-clock-selection.d.ts +0 -55
- package/dist/host/ports/local-act.d.ts +0 -44
- package/dist/host/ports/place-act.d.ts +0 -49
- package/dist/host/ports/publication.d.ts +0 -10
- package/dist/host/reference-export.d.ts +0 -33
- package/dist/host/reference-native.d.ts +0 -30
- package/dist/host/reference-profile.d.ts +0 -23
- package/dist/host/refusals.d.ts +0 -14
- package/dist/host/root-clock-source.d.ts +0 -86
- package/licenses/wasm/jitl-quickjs-ffi-types.txt +0 -21
- package/licenses/wasm/jitl-quickjs-wasmfile-release-sync.txt +0 -47
- package/licenses/wasm/quickjs-emscripten-core.txt +0 -21
- package/licenses/wasm/topos.txt +0 -21
- /package/{licenses/wasm/bound.txt → dist/vendor/28cba430228db1c04f446c93f81b09a2705d6bf3e222d35adbe5a4cee4061884.LICENSE} +0 -0
- /package/{licenses/wasm/obligations.txt → dist/vendor/7aca161279d14bc0e054dcc281cd110aeb95be2e026b42fdf527a260e58b2aae.LICENSE} +0 -0
package/dist/host/native/jobs.js
CHANGED
|
@@ -1,148 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const utf8 = encodeUTF8;
|
|
4
|
-
const by = (a, b) => { const x = utf8(a), y = utf8(b); for (let i = 0; i < Math.min(x.length, y.length); i++)
|
|
5
|
-
if (x[i] !== y[i])
|
|
6
|
-
return x[i] - y[i]; return x.length - y.length; };
|
|
7
|
-
const text = (x) => typeof x === 'string' && x.length > 0;
|
|
8
|
-
const positive = (x) => Number.isSafeInteger(x) && Number(x) > 0;
|
|
9
|
-
function coordinate(s) { if (!text(s) || s.startsWith('/') || s.includes('\\') || s.split('/').some(p => p === '' || p === '.' || p === '..'))
|
|
10
|
-
fail('unknown member coordinate ' + String(s)); }
|
|
11
|
-
function capped(s, max) { if (s.length > max || utf8(s).byteLength > max)
|
|
12
|
-
fail('byte budget'); }
|
|
13
|
-
/** digest is selected by the instrument; it is a pure naming implementation,
|
|
14
|
-
* not a callback that answers whether untrusted bytes/authority are "verified". */
|
|
15
|
-
export function planJobs(host, framed, digest) {
|
|
16
|
-
if (!host || !host.budget)
|
|
17
|
-
fail('missing admitted host handoff');
|
|
18
|
-
for (const key of ['jobs', 'members', 'edges', 'bytes', 'payloadBytes', 'env'])
|
|
19
|
-
if (!positive(host.budget[key]))
|
|
20
|
-
fail('missing resource ' + key);
|
|
21
|
-
const budget = host.budget;
|
|
22
|
-
if (!(framed instanceof Uint8Array) || framed.byteLength > budget.bytes)
|
|
23
|
-
fail('request byte budget');
|
|
24
|
-
if (typeof digest !== 'function')
|
|
25
|
-
fail('missing instrument digest');
|
|
26
|
-
if (!text(host.place) || !text(host.instrument) || !text(host.policy) || !text(host.authoritySnapshot))
|
|
27
|
-
fail('missing authority context');
|
|
28
|
-
for (const s of [host.place, host.instrument, host.policy, host.authoritySnapshot])
|
|
29
|
-
capped(s, budget.bytes);
|
|
30
|
-
if (!Array.isArray(host.members) || !Array.isArray(host.loads) || !Array.isArray(host.bindings) || host.members.length > budget.members || host.loads.length > budget.edges || host.bindings.length > budget.jobs)
|
|
31
|
-
fail('handoff count budget');
|
|
32
|
-
let total = framed.byteLength;
|
|
33
|
-
const charge = (s) => { capped(s, budget.bytes); total += Math.max(1, utf8(s).byteLength); if (total > budget.bytes)
|
|
34
|
-
fail('handoff byte budget'); };
|
|
35
|
-
for (const s of [host.place, host.instrument, host.policy, host.authoritySnapshot])
|
|
36
|
-
charge(s);
|
|
37
|
-
const members = new Map();
|
|
38
|
-
for (const m of host.members) {
|
|
39
|
-
if (!m || !(m.bytes instanceof Uint8Array))
|
|
40
|
-
fail('missing handed member');
|
|
41
|
-
coordinate(m.coordinate);
|
|
42
|
-
if (!text(m.digest))
|
|
43
|
-
fail('missing member digest ' + m.coordinate);
|
|
44
|
-
charge(m.coordinate);
|
|
45
|
-
charge(m.digest);
|
|
46
|
-
total += m.bytes.byteLength;
|
|
47
|
-
if (total > budget.bytes)
|
|
48
|
-
fail('member byte budget');
|
|
49
|
-
if (members.has(m.coordinate))
|
|
50
|
-
fail('duplicate handed member ' + m.coordinate);
|
|
51
|
-
members.set(m.coordinate, m);
|
|
52
|
-
}
|
|
53
|
-
const edges = new Map();
|
|
54
|
-
for (const e of host.loads) {
|
|
55
|
-
if (!e || !['module', 'worker', 'program'].includes(e.kind))
|
|
56
|
-
fail('unknown load kind');
|
|
57
|
-
coordinate(e.from);
|
|
58
|
-
if (typeof e.target !== 'string')
|
|
59
|
-
fail('unknown computed target ' + e.from);
|
|
60
|
-
coordinate(e.target);
|
|
61
|
-
charge(e.from);
|
|
62
|
-
charge(e.target);
|
|
63
|
-
if (!members.has(e.from) || !members.has(e.target))
|
|
64
|
-
fail('unhanded load ' + e.from + ' -> ' + e.target);
|
|
65
|
-
const key = e.from + '\u0000' + e.kind + '\u0000' + e.target;
|
|
66
|
-
if ((edges.get(e.from) ?? []).some(x => x.kind === e.kind && x.target === e.target))
|
|
67
|
-
fail('duplicate load ' + key);
|
|
68
|
-
edges.set(e.from, [...(edges.get(e.from) ?? []), e]);
|
|
69
|
-
}
|
|
70
|
-
let launchEdges = host.loads.length;
|
|
71
|
-
const bindings = new Map();
|
|
72
|
-
for (const b of host.bindings) {
|
|
73
|
-
if (!b || !text(b.id) || bindings.has(b.id))
|
|
74
|
-
fail('duplicate or missing job binding');
|
|
75
|
-
charge(b.id);
|
|
76
|
-
if (!['process', 'worker'].includes(b.kind) || (b.kind === 'worker' && !b.entry))
|
|
77
|
-
fail('unknown or incomplete execution kind ' + b.id);
|
|
78
|
-
if (!Array.isArray(b.places) || !Array.isArray(b.args) || !Array.isArray(b.inputs) || !Array.isArray(b.environment) || b.environment.length > budget.env || [b.places, b.args, b.inputs].some(x => Array.isArray(x) && x.length > budget.bytes))
|
|
79
|
-
fail('incomplete job binding ' + b.id);
|
|
80
|
-
if (new Set(b.places).size !== b.places.length || new Set(b.inputs).size !== b.inputs.length)
|
|
81
|
-
fail('duplicate binding coordinate ' + b.id);
|
|
82
|
-
for (const s of [...b.places, ...b.args, ...b.inputs]) {
|
|
83
|
-
if (typeof s !== 'string')
|
|
84
|
-
fail('nonliteral host argument ' + b.id);
|
|
85
|
-
charge(s);
|
|
86
|
-
}
|
|
87
|
-
for (const field of ['timeMs', 'responseBytes', 'slots'])
|
|
88
|
-
if (!b.limits || !positive(b.limits[field]))
|
|
89
|
-
fail('missing launch resource ' + b.id + '/' + field);
|
|
90
|
-
if (b.limits.slots > budget.jobs)
|
|
91
|
-
fail('launch slots exceed admitted jobs ' + b.id);
|
|
92
|
-
const env = new Set();
|
|
93
|
-
for (const pair of b.environment) {
|
|
94
|
-
if (!Array.isArray(pair) || pair.length !== 2 || !text(pair[0]) || typeof pair[1] !== 'string' || env.has(pair[0]))
|
|
95
|
-
fail('ambiguous environment ' + b.id);
|
|
96
|
-
env.add(pair[0]);
|
|
97
|
-
charge(pair[0]);
|
|
98
|
-
charge(pair[1]);
|
|
99
|
-
}
|
|
100
|
-
for (const c of [b.program, b.interpreter, b.entry, ...b.inputs].filter(x => x !== undefined)) {
|
|
101
|
-
coordinate(c);
|
|
102
|
-
if (!members.has(c))
|
|
103
|
-
fail('unhanded launch member ' + c);
|
|
104
|
-
}
|
|
105
|
-
launchEdges += [b.program, b.interpreter, b.entry, ...b.inputs].filter(x => x !== undefined).length;
|
|
106
|
-
if (launchEdges > budget.edges)
|
|
107
|
-
fail('launch edge budget');
|
|
108
|
-
bindings.set(b.id, b);
|
|
109
|
-
}
|
|
110
|
-
// All byte/count/declaration checks precede hashing or parsing world data.
|
|
111
|
-
let proposals;
|
|
112
|
-
try {
|
|
113
|
-
proposals = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(framed));
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
fail('malformed proposal frame');
|
|
117
|
-
}
|
|
118
|
-
if (!Array.isArray(proposals) || proposals.length > budget.jobs)
|
|
119
|
-
return fail('proposal count budget');
|
|
120
|
-
const ids = new Set(), jobs = [];
|
|
121
|
-
for (const p of proposals) {
|
|
122
|
-
if (!p || typeof p !== 'object' || Array.isArray(p) || Object.keys(p).some(k => k !== 'id' && k !== 'payload') || !text(p.id) || typeof p.payload !== 'string')
|
|
123
|
-
fail('world may propose only job id and data');
|
|
124
|
-
if (ids.has(p.id))
|
|
125
|
-
fail('duplicate proposed job ' + p.id);
|
|
126
|
-
ids.add(p.id);
|
|
127
|
-
capped(p.id, budget.bytes);
|
|
128
|
-
capped(p.payload, budget.payloadBytes);
|
|
129
|
-
const b = bindings.get(p.id);
|
|
130
|
-
if (!b)
|
|
131
|
-
return fail('unknown computed job target ' + p.id);
|
|
132
|
-
if (!b.places.includes(host.place))
|
|
133
|
-
fail('job not covered at place ' + host.place + ' ' + p.id);
|
|
134
|
-
jobs.push(p);
|
|
135
|
-
}
|
|
136
|
-
for (const m of members.values())
|
|
137
|
-
if (digest(m.bytes) !== m.digest)
|
|
138
|
-
fail('member digest differs ' + m.coordinate);
|
|
139
|
-
return jobs.map(p => { const b = bindings.get(p.id); const ref = (c) => [c, members.get(c).digest]; const seen = new Set(), closed = []; const visit = (c) => { if (seen.has(c))
|
|
140
|
-
return; seen.add(c); for (const e of edges.get(c) ?? []) {
|
|
141
|
-
const target = e.target;
|
|
142
|
-
closed.push({ from: c, kind: e.kind, target, digest: members.get(target).digest });
|
|
143
|
-
visit(target);
|
|
144
|
-
} }; for (const c of [b.program, b.interpreter, b.entry, ...b.inputs].filter(x => x !== undefined))
|
|
145
|
-
visit(c); closed.sort((a, b) => by(JSON.stringify(a), JSON.stringify(b))); for (const [kind, c] of [['launch', b.program], ['interpreter', b.interpreter], ['worker-entry', b.entry], ...b.inputs.map(c => ['input', c])])
|
|
146
|
-
if (c !== undefined)
|
|
147
|
-
closed.push({ from: 'job:' + p.id, kind: kind, target: c, digest: members.get(c).digest }); closed.sort((a, b) => by(JSON.stringify(a), JSON.stringify(b))); const environment = b.environment.map(p => [...p]).sort((a, b) => by(a[0], b[0])); const payload = utf8(p.payload), tuple = ['host-job-proposal', host.place, host.instrument, host.policy, host.authoritySnapshot, p.id, b.kind, ref(b.program), b.interpreter ? ref(b.interpreter) : null, b.entry ? ref(b.entry) : null, b.args, b.inputs.map(ref), environment, [b.limits.timeMs, b.limits.responseBytes, b.limits.slots], closed, digest(payload)]; return { id: p.id, kind: b.kind, identity: digest(utf8(JSON.stringify(tuple) + '\n')), place: host.place, program: ref(b.program), ...(b.interpreter ? { interpreter: ref(b.interpreter) } : {}), ...(b.entry ? { entry: ref(b.entry) } : {}), args: [...b.args], payload, environment, limits: { ...b.limits }, edges: closed }; });
|
|
148
|
-
}
|
|
1
|
+
var x=Object.defineProperty;var g=(t,a)=>x(t,"name",{value:a,configurable:!0});import{encodeUTF8 as z}from"../io.js";const i=g(t=>{throw Error("REFUSE\xB7job "+t)},"fail"),u=z,v=g((t,a)=>{const c=u(t),o=u(a);for(let f=0;f<Math.min(c.length,o.length);f++)if(c[f]!==o[f])return c[f]-o[f];return c.length-o.length},"by"),m=g(t=>typeof t=="string"&&t.length>0,"text"),E=g(t=>Number.isSafeInteger(t)&&Number(t)>0,"positive");function S(t){(!m(t)||t.startsWith("/")||t.includes("\\")||t.split("/").some(a=>a===""||a==="."||a===".."))&&i("unknown member coordinate "+String(t))}g(S,"coordinate");function j(t,a){(t.length>a||u(t).byteLength>a)&&i("byte budget")}g(j,"capped");function q(t,a,c){(!t||!t.budget)&&i("missing admitted host handoff");for(const e of["jobs","members","edges","bytes","payloadBytes","env"])E(t.budget[e])||i("missing resource "+e);const o=t.budget;(!(a instanceof Uint8Array)||a.byteLength>o.bytes)&&i("request byte budget"),typeof c!="function"&&i("missing instrument digest"),(!m(t.place)||!m(t.instrument)||!m(t.policy)||!m(t.authoritySnapshot))&&i("missing authority context");for(const e of[t.place,t.instrument,t.policy,t.authoritySnapshot])j(e,o.bytes);(!Array.isArray(t.members)||!Array.isArray(t.loads)||!Array.isArray(t.bindings)||t.members.length>o.members||t.loads.length>o.edges||t.bindings.length>o.jobs)&&i("handoff count budget");let f=a.byteLength;const l=g(e=>{j(e,o.bytes),f+=Math.max(1,u(e).byteLength),f>o.bytes&&i("handoff byte budget")},"charge");for(const e of[t.place,t.instrument,t.policy,t.authoritySnapshot])l(e);const p=new Map;for(const e of t.members)(!e||!(e.bytes instanceof Uint8Array))&&i("missing handed member"),S(e.coordinate),m(e.digest)||i("missing member digest "+e.coordinate),l(e.coordinate),l(e.digest),f+=e.bytes.byteLength,f>o.bytes&&i("member byte budget"),p.has(e.coordinate)&&i("duplicate handed member "+e.coordinate),p.set(e.coordinate,e);const h=new Map;for(const e of t.loads){(!e||!["module","worker","program"].includes(e.kind))&&i("unknown load kind"),S(e.from),typeof e.target!="string"&&i("unknown computed target "+e.from),S(e.target),l(e.from),l(e.target),(!p.has(e.from)||!p.has(e.target))&&i("unhanded load "+e.from+" -> "+e.target);const r=e.from+"\0"+e.kind+"\0"+e.target;(h.get(e.from)??[]).some(n=>n.kind===e.kind&&n.target===e.target)&&i("duplicate load "+r),h.set(e.from,[...h.get(e.from)??[],e])}let N=t.loads.length;const k=new Map;for(const e of t.bindings){(!e||!m(e.id)||k.has(e.id))&&i("duplicate or missing job binding"),l(e.id),(!["process","worker"].includes(e.kind)||e.kind==="worker"&&!e.entry)&&i("unknown or incomplete execution kind "+e.id),(!Array.isArray(e.places)||!Array.isArray(e.args)||!Array.isArray(e.inputs)||!Array.isArray(e.environment)||e.environment.length>o.env||[e.places,e.args,e.inputs].some(n=>Array.isArray(n)&&n.length>o.bytes))&&i("incomplete job binding "+e.id),(new Set(e.places).size!==e.places.length||new Set(e.inputs).size!==e.inputs.length)&&i("duplicate binding coordinate "+e.id);for(const n of[...e.places,...e.args,...e.inputs])typeof n!="string"&&i("nonliteral host argument "+e.id),l(n);for(const n of["timeMs","responseBytes","slots"])(!e.limits||!E(e.limits[n]))&&i("missing launch resource "+e.id+"/"+n);e.limits.slots>o.jobs&&i("launch slots exceed admitted jobs "+e.id);const r=new Set;for(const n of e.environment)(!Array.isArray(n)||n.length!==2||!m(n[0])||typeof n[1]!="string"||r.has(n[0]))&&i("ambiguous environment "+e.id),r.add(n[0]),l(n[0]),l(n[1]);for(const n of[e.program,e.interpreter,e.entry,...e.inputs].filter(w=>w!==void 0))S(n),p.has(n)||i("unhanded launch member "+n);N+=[e.program,e.interpreter,e.entry,...e.inputs].filter(n=>n!==void 0).length,N>o.edges&&i("launch edge budget"),k.set(e.id,e)}let A;try{A=JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(a))}catch{i("malformed proposal frame")}if(!Array.isArray(A)||A.length>o.jobs)return i("proposal count budget");const J=new Set,M=[];for(const e of A){(!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).some(n=>n!=="id"&&n!=="payload")||!m(e.id)||typeof e.payload!="string")&&i("world may propose only job id and data"),J.has(e.id)&&i("duplicate proposed job "+e.id),J.add(e.id),j(e.id,o.bytes),j(e.payload,o.payloadBytes);const r=k.get(e.id);if(!r)return i("unknown computed job target "+e.id);r.places.includes(t.place)||i("job not covered at place "+t.place+" "+e.id),M.push(e)}for(const e of p.values())c(e.bytes)!==e.digest&&i("member digest differs "+e.coordinate);return M.map(e=>{const r=k.get(e.id),n=g(s=>[s,p.get(s).digest],"ref"),w=new Set,y=[],O=g(s=>{if(!w.has(s)){w.add(s);for(const d of h.get(s)??[]){const b=d.target;y.push({from:s,kind:d.kind,target:b,digest:p.get(b).digest}),O(b)}}},"visit");for(const s of[r.program,r.interpreter,r.entry,...r.inputs].filter(d=>d!==void 0))O(s);y.sort((s,d)=>v(JSON.stringify(s),JSON.stringify(d)));for(const[s,d]of[["launch",r.program],["interpreter",r.interpreter],["worker-entry",r.entry],...r.inputs.map(b=>["input",b])])d!==void 0&&y.push({from:"job:"+e.id,kind:s,target:d,digest:p.get(d).digest});y.sort((s,d)=>v(JSON.stringify(s),JSON.stringify(d)));const L=r.environment.map(s=>[...s]).sort((s,d)=>v(s[0],d[0])),B=u(e.payload),U=["host-job-proposal",t.place,t.instrument,t.policy,t.authoritySnapshot,e.id,r.kind,n(r.program),r.interpreter?n(r.interpreter):null,r.entry?n(r.entry):null,r.args,r.inputs.map(n),L,[r.limits.timeMs,r.limits.responseBytes,r.limits.slots],y,c(B)];return{id:e.id,kind:r.kind,identity:c(u(JSON.stringify(U)+`
|
|
2
|
+
`)),place:t.place,program:n(r.program),...r.interpreter?{interpreter:n(r.interpreter)}:{},...r.entry?{entry:n(r.entry)}:{},args:[...r.args],payload:B,environment:L,limits:{...r.limits},edges:y}})}g(q,"planJobs");export{q as planJobs};
|
|
@@ -1,269 +1 @@
|
|
|
1
|
-
var
|
|
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
|
-
import { sha256 as digest } from "../hash.js";
|
|
10
|
-
import { compareStrings as order } from "../order.js";
|
|
11
|
-
import { realpathSync } from 'node:fs';
|
|
12
|
-
import { dirname, join, relative, isAbsolute, sep } from 'node:path';
|
|
13
|
-
import { readBoundedFile } from "./bounded-file.js";
|
|
14
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
15
|
-
import * as nodeModule from 'node:module';
|
|
16
|
-
const { builtinModules } = nodeModule;
|
|
17
|
-
const moduleApi = nodeModule.createRequire(import.meta.url)('node:module');
|
|
18
|
-
const fixedRegisterHooks = moduleApi.registerHooks;
|
|
19
|
-
let registrationProtected = false;
|
|
20
|
-
/** Node loader registration is an executable capability, not merely a builtin
|
|
21
|
-
* name. The fixed host retains its captured registration API; imported programs
|
|
22
|
-
* cannot insert a loader returning invented bytes ahead of its load boundary.
|
|
23
|
-
* This does not establish confinement against arbitrary privileged JavaScript.
|
|
24
|
-
*/
|
|
25
|
-
export function protectNativeLoaderRegistration() {
|
|
26
|
-
if (registrationProtected)
|
|
27
|
-
return;
|
|
28
|
-
registrationProtected = true;
|
|
29
|
-
for (const name of ['registerHooks', 'register'])
|
|
30
|
-
if (typeof moduleApi[name] === 'function')
|
|
31
|
-
Object.defineProperty(moduleApi, name, { value: () => { throw Error('REFUSE·load runtime loader registration is not a fixed host capability'); }, writable: false, configurable: false });
|
|
32
|
-
nodeModule.syncBuiltinESMExports();
|
|
33
|
-
}
|
|
34
|
-
const resolutionKey = Symbol.for('bound.native.resolution@1');
|
|
35
|
-
let resolutionCheck;
|
|
36
|
-
let resolutionIdentity;
|
|
37
|
-
let resolutionLibraryNames = Object.freeze([]);
|
|
38
|
-
let resolutionLibraries = Object.freeze([]);
|
|
39
|
-
const resolutionCapability = Object.freeze({ profile: 'fixed-native-resolution@1', get libraryNames() { return resolutionLibraryNames; }, get libraries() { return resolutionLibraries; }, assertPins(pins) {
|
|
40
|
-
if (!Array.isArray(pins))
|
|
41
|
-
throw Error('REFUSE·load pinned library request invalid');
|
|
42
|
-
if (!resolutionCheck)
|
|
43
|
-
throw Error('REFUSE·load no current fixed library resolution');
|
|
44
|
-
resolutionCheck(pins);
|
|
45
|
-
} });
|
|
46
|
-
/** Fixed preload only: expose comparison with the installed resolution, never
|
|
47
|
-
* hook registration or a verifier supplied by a reader. A different module's
|
|
48
|
-
* marker cannot replace this host's closed capability before entry. */
|
|
49
|
-
export function installNativeResolutionReuse(declaration) {
|
|
50
|
-
const prior = Object.getOwnPropertyDescriptor(globalThis, resolutionKey);
|
|
51
|
-
if (prior && prior.value !== resolutionCapability)
|
|
52
|
-
throw Error('REFUSE·load fixed resolution capability collision');
|
|
53
|
-
if (!prior)
|
|
54
|
-
Object.defineProperty(globalThis, resolutionKey, { value: resolutionCapability, writable: false, configurable: false });
|
|
55
|
-
const fail = (why) => { throw Error('REFUSE·load pinned library ' + why); };
|
|
56
|
-
const actual = (path, why) => { try {
|
|
57
|
-
return realpathSync(path);
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
return fail(why);
|
|
61
|
-
} };
|
|
62
|
-
const files = declaration.members.map(member => ({ ...member, path: realpathSync(member.path) }));
|
|
63
|
-
const libraries = new Map(declaration.libraries.map(library => [library.name, realpathSync(library.manifest)]));
|
|
64
|
-
const coordinates = new Map(declaration.libraries.map(library => [library.name, library.coordinate]));
|
|
65
|
-
if (libraries.size !== declaration.libraries.length)
|
|
66
|
-
fail('ambiguous declaration');
|
|
67
|
-
const namedCoordinates = new Set();
|
|
68
|
-
for (const coordinate of coordinates.values())
|
|
69
|
-
if (coordinate !== undefined) {
|
|
70
|
-
if (typeof coordinate !== 'string' || !coordinate || isAbsolute(coordinate) || coordinate.includes('\\') || coordinate.split('/').some(step => !step || step === '.' || step === '..') || namedCoordinates.has(coordinate))
|
|
71
|
-
fail('invalid/ambiguous logical library coordinate');
|
|
72
|
-
namedCoordinates.add(coordinate);
|
|
73
|
-
}
|
|
74
|
-
const identity = digest(Buffer.from(JSON.stringify([declaration.platform, files.map(member => [member.path, member.digest, member.bytes]).sort((a, b) => order(String(a[0]), String(b[0]))), [...libraries].sort(([a], [b]) => order(a, b)).map(([name, manifest]) => [name, manifest, coordinates.get(name) ?? null])])));
|
|
75
|
-
if (resolutionIdentity !== undefined) {
|
|
76
|
-
if (identity !== resolutionIdentity)
|
|
77
|
-
fail('late resolution replacement');
|
|
78
|
-
if (!resolutionCheck)
|
|
79
|
-
fail('fixed resolution already closed');
|
|
80
|
-
return () => { };
|
|
81
|
-
}
|
|
82
|
-
resolutionIdentity = identity;
|
|
83
|
-
resolutionLibraryNames = Object.freeze([...libraries.keys()].sort(order));
|
|
84
|
-
resolutionLibraries = Object.freeze([...libraries].sort(([a], [b]) => order(a, b)).map(([name, manifest]) => Object.freeze({ name, manifest, ...(coordinates.get(name) === undefined ? {} : { coordinate: coordinates.get(name) }) })));
|
|
85
|
-
const inside = (base, path) => { const step = relative(base, path); return step !== '' && !isAbsolute(step) && step !== '..' && !step.startsWith('..' + sep); };
|
|
86
|
-
const check = (pins) => {
|
|
87
|
-
const names = new Set();
|
|
88
|
-
for (const pin of pins) {
|
|
89
|
-
if (!pin || typeof pin.name !== 'string' || typeof pin.at !== 'string' || !pin.at || names.has(pin.name))
|
|
90
|
-
fail('invalid/duplicate selection');
|
|
91
|
-
names.add(pin.name);
|
|
92
|
-
const manifest = libraries.get(pin.name) ?? fail('not declared ' + pin.name);
|
|
93
|
-
const root = dirname(manifest), pinned = actual(pin.at, 'tree absent ' + pin.name), nested = [...libraries.values()].map(dirname).filter(other => inside(root, other));
|
|
94
|
-
const members = files.filter(member => inside(root, member.path) && !nested.some(other => inside(other, member.path)));
|
|
95
|
-
if (!members.some(member => member.path === manifest))
|
|
96
|
-
fail('manifest not sealed ' + pin.name);
|
|
97
|
-
const manifestMember = members.find(member => member.path === manifest);
|
|
98
|
-
let pkg;
|
|
99
|
-
try {
|
|
100
|
-
pkg = JSON.parse(readBoundedFile(manifest, manifestMember.bytes, manifest).toString('utf8'));
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
return fail('manifest unreadable ' + pin.name);
|
|
104
|
-
}
|
|
105
|
-
if (pkg?.name !== pin.name)
|
|
106
|
-
fail('manifest name differs ' + pin.name);
|
|
107
|
-
for (const member of members) {
|
|
108
|
-
if (!Number.isSafeInteger(member.bytes) || member.bytes < 0 || !/^sha256:[a-f0-9]{64}$/.test(member.digest))
|
|
109
|
-
fail('member resource invalid ' + pin.name);
|
|
110
|
-
const target = actual(join(pinned, relative(root, member.path)), 'member absent ' + pin.name + '/' + relative(root, member.path));
|
|
111
|
-
if (!inside(pinned, target))
|
|
112
|
-
fail('target leaves pinned tree ' + pin.name);
|
|
113
|
-
if (digest(readBoundedFile(member.path, member.bytes, member.path)) !== member.digest || digest(readBoundedFile(target, member.bytes, target)) !== member.digest)
|
|
114
|
-
fail('member differs ' + pin.name + '/' + relative(root, member.path));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
resolutionCheck = check;
|
|
119
|
-
return () => { resolutionCheck = undefined; };
|
|
120
|
-
}
|
|
121
|
-
/** Resolution boundary for an instrument-selected native command. It checks
|
|
122
|
-
* actual target bytes before Node executes that target. Native commands remain
|
|
123
|
-
* privileged host implementations: this is not an arbitrary-JS sandbox and
|
|
124
|
-
* cannot prevent trusted code from replacing Node's hooks. That trust condition
|
|
125
|
-
* must be admitted separately; a world cannot claim it in a payload.
|
|
126
|
-
* Native ABI edges refer to the declared platform context, never a fictitious
|
|
127
|
-
* file digest. Completeness of the platform's backing images is not proved here.
|
|
128
|
-
*/
|
|
129
|
-
export function loadBoundary(declaration) {
|
|
130
|
-
const files = new Map(), libraries = new Map(), native = new Set(), edges = [];
|
|
131
|
-
let refused;
|
|
132
|
-
const fail = (why) => { refused ?? (refused = 'REFUSE·load ' + why); throw Error(refused); };
|
|
133
|
-
const verify = (url) => { let path; try {
|
|
134
|
-
path = realpathSync(fileURLToPath(url));
|
|
135
|
-
}
|
|
136
|
-
catch {
|
|
137
|
-
return fail('target absent ' + url);
|
|
138
|
-
} const expected = files.get(path); if (!expected)
|
|
139
|
-
return fail('target undeclared ' + url); if (digest(readBoundedFile(path, expected.bytes, path)) !== expected.digest)
|
|
140
|
-
return fail('target bytes differ ' + url); return expected.digest; };
|
|
141
|
-
for (const member of declaration.members) {
|
|
142
|
-
let path;
|
|
143
|
-
try {
|
|
144
|
-
path = realpathSync(member.path);
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
return fail('member absent ' + member.path);
|
|
148
|
-
}
|
|
149
|
-
if (files.has(path) || !Number.isSafeInteger(member.bytes) || member.bytes < 0 || !/^sha256:[0-9a-f]{64}$/.test(member.digest))
|
|
150
|
-
return fail('member ambiguous ' + member.path);
|
|
151
|
-
files.set(path, { ...member, path });
|
|
152
|
-
}
|
|
153
|
-
for (const member of declaration.members)
|
|
154
|
-
verify(pathToFileURL(member.path).href);
|
|
155
|
-
for (const lib of declaration.libraries) {
|
|
156
|
-
if (!/^(?:@[A-Za-z0-9_.-]+\/)?[A-Za-z0-9_.-]+$/.test(lib.name) || libraries.has(lib.name))
|
|
157
|
-
return fail('library ambiguous ' + lib.name);
|
|
158
|
-
const url = pathToFileURL(lib.manifest).href;
|
|
159
|
-
verify(url);
|
|
160
|
-
let pkg;
|
|
161
|
-
try {
|
|
162
|
-
pkg = JSON.parse(readBoundedFile(lib.manifest, files.get(realpathSync(lib.manifest)).bytes, lib.name).toString('utf8'));
|
|
163
|
-
}
|
|
164
|
-
catch {
|
|
165
|
-
return fail('library manifest invalid ' + lib.name);
|
|
166
|
-
}
|
|
167
|
-
if (!pkg || Array.isArray(pkg) || pkg.name !== lib.name)
|
|
168
|
-
return fail('library name differs ' + lib.name);
|
|
169
|
-
libraries.set(lib.name, { url, pkg });
|
|
170
|
-
}
|
|
171
|
-
for (const name of declaration.builtins) {
|
|
172
|
-
const normalized = name.startsWith('node:') ? name : 'node:' + name;
|
|
173
|
-
if (native.has(normalized) || (!builtinModules.includes(normalized) && !builtinModules.includes(normalized.slice(5))))
|
|
174
|
-
return fail('native ABI ambiguous ' + name);
|
|
175
|
-
native.add(normalized);
|
|
176
|
-
}
|
|
177
|
-
if (!/^sha256:[0-9a-f]{64}$/.test(declaration.platform))
|
|
178
|
-
return fail('declared platform identity absent');
|
|
179
|
-
const entry = pathToFileURL(declaration.entry).href;
|
|
180
|
-
verify(entry);
|
|
181
|
-
return {
|
|
182
|
-
entry,
|
|
183
|
-
resolve(specifier, context, next) {
|
|
184
|
-
if (refused)
|
|
185
|
-
throw Error(refused);
|
|
186
|
-
if (context.parentURL)
|
|
187
|
-
verify(context.parentURL);
|
|
188
|
-
const builtin = specifier.startsWith('node:') ? specifier : 'node:' + specifier;
|
|
189
|
-
if (builtinModules.includes(specifier) || specifier.startsWith('node:')) {
|
|
190
|
-
if (!native.has(builtin))
|
|
191
|
-
return fail('native ABI undeclared ' + specifier);
|
|
192
|
-
edges.push({ parent: context.parentURL ?? entry, target: builtin, platform: declaration.platform });
|
|
193
|
-
let resolved;
|
|
194
|
-
try {
|
|
195
|
-
resolved = next(builtin, context);
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
return fail('native target unresolved ' + builtin);
|
|
199
|
-
}
|
|
200
|
-
if (resolved.url !== builtin)
|
|
201
|
-
return fail('native target differs ' + builtin);
|
|
202
|
-
return resolved;
|
|
203
|
-
}
|
|
204
|
-
let selected = context, target = specifier;
|
|
205
|
-
if (!specifier.startsWith('.') && !specifier.startsWith('/') && !specifier.includes(':')) {
|
|
206
|
-
const name = specifier.startsWith('@') ? specifier.split('/').slice(0, 2).join('/') : specifier.split('/')[0];
|
|
207
|
-
const library = libraries.get(name);
|
|
208
|
-
if (!library)
|
|
209
|
-
return fail('library undeclared ' + name);
|
|
210
|
-
selected = { ...context, parentURL: library.url };
|
|
211
|
-
if (library.pkg.exports === undefined) {
|
|
212
|
-
const subpath = specifier.slice(name.length);
|
|
213
|
-
const main = subpath ? subpath.slice(1) : library.pkg.main;
|
|
214
|
-
if (typeof main !== 'string' || !main || main.startsWith('/') || main.includes('\\') || main.split('/').includes('..'))
|
|
215
|
-
return fail('library target undeclared ' + specifier);
|
|
216
|
-
target = main.startsWith('./') ? main : './' + main;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
// Node supplies package/relative resolution semantics. There is no fallback
|
|
220
|
-
// permission: its result still has to be an exact host-sealed member.
|
|
221
|
-
let resolved;
|
|
222
|
-
try {
|
|
223
|
-
resolved = next(target, selected);
|
|
224
|
-
}
|
|
225
|
-
catch {
|
|
226
|
-
return fail('target unresolved ' + specifier);
|
|
227
|
-
}
|
|
228
|
-
if (!resolved.url.startsWith('file:'))
|
|
229
|
-
return fail('target scheme undeclared ' + resolved.url);
|
|
230
|
-
const seal = verify(resolved.url);
|
|
231
|
-
edges.push({ parent: context.parentURL ?? entry, target: resolved.url, digest: seal });
|
|
232
|
-
return resolved;
|
|
233
|
-
},
|
|
234
|
-
load(url, context, next) {
|
|
235
|
-
if (url.startsWith('node:'))
|
|
236
|
-
return next(url, context);
|
|
237
|
-
verify(url);
|
|
238
|
-
const path = realpathSync(fileURLToPath(url)), member = files.get(path);
|
|
239
|
-
const loaded = next(url, context);
|
|
240
|
-
if (loaded.source === undefined || loaded.source === null)
|
|
241
|
-
return fail('file loader did not expose executable bytes ' + url);
|
|
242
|
-
const bytes = typeof loaded.source === 'string' ? Buffer.from(loaded.source, 'utf8') : loaded.source;
|
|
243
|
-
if (bytes.byteLength > member.bytes || digest(bytes) !== member.digest)
|
|
244
|
-
return fail('actual loaded source differs ' + url);
|
|
245
|
-
return loaded;
|
|
246
|
-
},
|
|
247
|
-
assertClosed() { if (refused)
|
|
248
|
-
throw Error(refused); for (const member of declaration.members)
|
|
249
|
-
verify(pathToFileURL(member.path).href); },
|
|
250
|
-
edges: () => edges.map(edge => ({ ...edge })),
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
/** Install before the entry of an instrument-selected privileged Node command.
|
|
254
|
-
* The bootstrap exception is restricted to this host function's exact selected
|
|
255
|
-
* entry. It is not a permission for a world to choose a verifier or a program.
|
|
256
|
-
* Hooks mediate imports; they do not establish a non-bypass JS sandbox.
|
|
257
|
-
*/
|
|
258
|
-
export function installBoundary(declaration) {
|
|
259
|
-
const boundary = loadBoundary(declaration);
|
|
260
|
-
const register = fixedRegisterHooks;
|
|
261
|
-
if (typeof register !== 'function')
|
|
262
|
-
throw Error('REFUSE·load native hook profile unsupported by runtime');
|
|
263
|
-
protectNativeLoaderRegistration();
|
|
264
|
-
const hooks = register({ resolve(specifier, context, next) {
|
|
265
|
-
const boot = context.parentURL === import.meta.url && specifier === boundary.entry;
|
|
266
|
-
return boundary.resolve(specifier, boot ? { ...context, parentURL: undefined } : context, next);
|
|
267
|
-
}, load: boundary.load });
|
|
268
|
-
return { loadEntry: () => import(__rewriteRelativeImportExtension(boundary.entry)), assertClosed: boundary.assertClosed, edges: boundary.edges, close: () => hooks.deregister() };
|
|
269
|
-
}
|
|
1
|
+
var H=Object.defineProperty;var c=(r,u)=>H(r,"name",{value:u,configurable:!0});var J=function(r,u){return typeof r=="string"&&/^\.\.?\//.test(r)?r.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i,function(i,h,p,l,n){return h?u?".jsx":".js":p&&(!l||!n)?i:p+l+"."+n.toLowerCase()+"js"}):r};import{sha256 as w}from"../hash.js";import{compareStrings as O}from"../order.js";import{realpathSync as R}from"node:fs";import{dirname as M,join as q,relative as W,isAbsolute as x,sep as Z}from"node:path";import{readBoundedFile as U}from"./bounded-file.js";import{fileURLToPath as C,pathToFileURL as z}from"node:url";import*as A from"node:module";const{builtinModules:F}=A,N=A.createRequire(import.meta.url)("node:module"),D=N.registerHooks;let I=!1;function K(){if(!I){I=!0;for(const r of["registerHooks","register"])typeof N[r]=="function"&&Object.defineProperty(N,r,{value:c(()=>{throw Error("REFUSE\xB7load runtime loader registration is not a fixed host capability")},"value"),writable:!1,configurable:!1});A.syncBuiltinESMExports()}}c(K,"protectNativeLoaderRegistration");const P=Symbol.for("bound.native.resolution@1");let j,B,_=Object.freeze([]),$=Object.freeze([]);const T=Object.freeze({profile:"fixed-native-resolution@1",get libraryNames(){return _},get libraries(){return $},assertPins(r){if(!Array.isArray(r))throw Error("REFUSE\xB7load pinned library request invalid");if(!j)throw Error("REFUSE\xB7load no current fixed library resolution");j(r)}});function ne(r){const u=Object.getOwnPropertyDescriptor(globalThis,P);if(u&&u.value!==T)throw Error("REFUSE\xB7load fixed resolution capability collision");u||Object.defineProperty(globalThis,P,{value:T,writable:!1,configurable:!1});const i=c(t=>{throw Error("REFUSE\xB7load pinned library "+t)},"fail"),h=c((t,o)=>{try{return R(t)}catch{return i(o)}},"actual"),p=r.members.map(t=>({...t,path:R(t.path)})),l=new Map(r.libraries.map(t=>[t.name,R(t.manifest)])),n=new Map(r.libraries.map(t=>[t.name,t.coordinate]));l.size!==r.libraries.length&&i("ambiguous declaration");const b=new Set;for(const t of n.values())t!==void 0&&((typeof t!="string"||!t||x(t)||t.includes("\\")||t.split("/").some(o=>!o||o==="."||o==="..")||b.has(t))&&i("invalid/ambiguous logical library coordinate"),b.add(t));const E=w(Buffer.from(JSON.stringify([r.platform,p.map(t=>[t.path,t.digest,t.bytes]).sort((t,o)=>O(String(t[0]),String(o[0]))),[...l].sort(([t],[o])=>O(t,o)).map(([t,o])=>[t,o,n.get(t)??null])])));if(B!==void 0)return E!==B&&i("late resolution replacement"),j||i("fixed resolution already closed"),()=>{};B=E,_=Object.freeze([...l.keys()].sort(O)),$=Object.freeze([...l].sort(([t],[o])=>O(t,o)).map(([t,o])=>Object.freeze({name:t,manifest:o,...n.get(t)===void 0?{}:{coordinate:n.get(t)}})));const e=c((t,o)=>{const a=W(t,o);return a!==""&&!x(a)&&a!==".."&&!a.startsWith(".."+Z)},"inside");return j=c(t=>{const o=new Set;for(const a of t){(!a||typeof a.name!="string"||typeof a.at!="string"||!a.at||o.has(a.name))&&i("invalid/duplicate selection"),o.add(a.name);const d=l.get(a.name)??i("not declared "+a.name),m=M(d),L=h(a.at,"tree absent "+a.name),y=[...l.values()].map(M).filter(f=>e(m,f)),v=p.filter(f=>e(m,f.path)&&!y.some(S=>e(S,f.path)));v.some(f=>f.path===d)||i("manifest not sealed "+a.name);const k=v.find(f=>f.path===d);let g;try{g=JSON.parse(U(d,k.bytes,d).toString("utf8"))}catch{return i("manifest unreadable "+a.name)}g?.name!==a.name&&i("manifest name differs "+a.name);for(const f of v){(!Number.isSafeInteger(f.bytes)||f.bytes<0||!/^sha256:[a-f0-9]{64}$/.test(f.digest))&&i("member resource invalid "+a.name);const S=h(q(L,W(m,f.path)),"member absent "+a.name+"/"+W(m,f.path));e(L,S)||i("target leaves pinned tree "+a.name),(w(U(f.path,f.bytes,f.path))!==f.digest||w(U(S,f.bytes,S))!==f.digest)&&i("member differs "+a.name+"/"+W(m,f.path))}}},"check"),()=>{j=void 0}}c(ne,"installNativeResolutionReuse");function G(r){const u=new Map,i=new Map,h=new Set,p=[];let l;const n=c(e=>{throw l??(l="REFUSE\xB7load "+e),Error(l)},"fail"),b=c(e=>{let s;try{s=R(C(e))}catch{return n("target absent "+e)}const t=u.get(s);return t?w(U(s,t.bytes,s))!==t.digest?n("target bytes differ "+e):t.digest:n("target undeclared "+e)},"verify");for(const e of r.members){let s;try{s=R(e.path)}catch{return n("member absent "+e.path)}if(u.has(s)||!Number.isSafeInteger(e.bytes)||e.bytes<0||!/^sha256:[0-9a-f]{64}$/.test(e.digest))return n("member ambiguous "+e.path);u.set(s,{...e,path:s})}for(const e of r.members)b(z(e.path).href);for(const e of r.libraries){if(!/^(?:@[A-Za-z0-9_.-]+\/)?[A-Za-z0-9_.-]+$/.test(e.name)||i.has(e.name))return n("library ambiguous "+e.name);const s=z(e.manifest).href;b(s);let t;try{t=JSON.parse(U(e.manifest,u.get(R(e.manifest)).bytes,e.name).toString("utf8"))}catch{return n("library manifest invalid "+e.name)}if(!t||Array.isArray(t)||t.name!==e.name)return n("library name differs "+e.name);i.set(e.name,{url:s,pkg:t})}for(const e of r.builtins){const s=e.startsWith("node:")?e:"node:"+e;if(h.has(s)||!F.includes(s)&&!F.includes(s.slice(5)))return n("native ABI ambiguous "+e);h.add(s)}if(!/^sha256:[0-9a-f]{64}$/.test(r.platform))return n("declared platform identity absent");const E=z(r.entry).href;return b(E),{entry:E,resolve(e,s,t){if(l)throw Error(l);s.parentURL&&b(s.parentURL);const o=e.startsWith("node:")?e:"node:"+e;if(F.includes(e)||e.startsWith("node:")){if(!h.has(o))return n("native ABI undeclared "+e);p.push({parent:s.parentURL??E,target:o,platform:r.platform});let y;try{y=t(o,s)}catch{return n("native target unresolved "+o)}return y.url!==o?n("native target differs "+o):y}let a=s,d=e;if(!e.startsWith(".")&&!e.startsWith("/")&&!e.includes(":")){const y=e.startsWith("@")?e.split("/").slice(0,2).join("/"):e.split("/")[0],v=i.get(y);if(!v)return n("library undeclared "+y);if(a={...s,parentURL:v.url},v.pkg.exports===void 0){const k=e.slice(y.length),g=k?k.slice(1):v.pkg.main;if(typeof g!="string"||!g||g.startsWith("/")||g.includes("\\")||g.split("/").includes(".."))return n("library target undeclared "+e);d=g.startsWith("./")?g:"./"+g}}let m;try{m=t(d,a)}catch{return n("target unresolved "+e)}if(!m.url.startsWith("file:"))return n("target scheme undeclared "+m.url);const L=b(m.url);return p.push({parent:s.parentURL??E,target:m.url,digest:L}),m},load(e,s,t){if(e.startsWith("node:"))return t(e,s);b(e);const o=R(C(e)),a=u.get(o),d=t(e,s);if(d.source===void 0||d.source===null)return n("file loader did not expose executable bytes "+e);const m=typeof d.source=="string"?Buffer.from(d.source,"utf8"):d.source;return m.byteLength>a.bytes||w(m)!==a.digest?n("actual loaded source differs "+e):d},assertClosed(){if(l)throw Error(l);for(const e of r.members)b(z(e.path).href)},edges:c(()=>p.map(e=>({...e})),"edges")}}c(G,"loadBoundary");function se(r){const u=G(r),i=D;if(typeof i!="function")throw Error("REFUSE\xB7load native hook profile unsupported by runtime");K();const h=i({resolve(p,l,n){const b=l.parentURL===import.meta.url&&p===u.entry;return u.resolve(p,b?{...l,parentURL:void 0}:l,n)},load:u.load});return{loadEntry:c(()=>import(J(u.entry)),"loadEntry"),assertClosed:u.assertClosed,edges:u.edges,close:c(()=>h.deregister(),"close")}}c(se,"installBoundary");export{se as installBoundary,ne as installNativeResolutionReuse,G as loadBoundary,K as protectNativeLoaderRegistration};
|
|
@@ -1,175 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/** Fixed host materialization from admitted logical references. Physical locations
|
|
3
|
-
* never arrive from a reader packet and never become semantic source identity.
|
|
4
|
-
*/
|
|
5
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, realpathSync, renameSync, chmodSync } from 'node:fs';
|
|
6
|
-
import { join, dirname, relative, sep, extname } from 'node:path';
|
|
7
|
-
import { fileURLToPath } from 'node:url';
|
|
8
|
-
import { gunzipSync } from 'node:zlib';
|
|
9
|
-
import { members as archiveMembers, archiveCoordinate } from "../archive.js";
|
|
10
|
-
import { blobAt, storeAt, holdStore } from "../../land/ledger.js";
|
|
11
|
-
import { ContentNeeded } from "../content-needed.js";
|
|
12
|
-
import { processOf, ownRoot } from "../../observe/runner.js";
|
|
13
|
-
import { instrumentCoordinates } from "../../fold/digests.js";
|
|
14
|
-
import { readBoundedFile } from "./bounded-file.js";
|
|
15
|
-
import { assertNativeRouteCurrent, nativeRouteStore, nativeMountIdentity } from "./route.js";
|
|
16
|
-
const fail = (why) => { throw Error('REFUSE·native materialize ' + why); };
|
|
17
|
-
const mounted = new Map();
|
|
18
|
-
function laid(store, digest, remaining) { const path = blobAt(store, digest); if (!existsSync(path))
|
|
19
|
-
throw new ContentNeeded(digest); const bytes = readBoundedFile(path, remaining, digest); if (sha(bytes) !== digest)
|
|
20
|
-
fail('laid bytes differ ' + digest); return { path, bytes }; }
|
|
21
|
-
/** Called under the actual Root lease before identity/cache preparation. Missing
|
|
22
|
-
* laid content is a named content demand, never a publisher authority fallback.
|
|
23
|
-
* One retained mount per immutable selection avoids copying it on each ask.
|
|
24
|
-
*/
|
|
25
|
-
export function materializeNativeRoute(route) {
|
|
26
|
-
assertNativeRouteCurrent(route);
|
|
27
|
-
const store = nativeRouteStore(route), mountIdentity = nativeMountIdentity(route.profile, route.binaries, route.control), key = store + '\0' + mountIdentity, old = mounted.get(key);
|
|
28
|
-
if (old) {
|
|
29
|
-
const members = new Map();
|
|
30
|
-
for (const member of route.profile.selection.members) {
|
|
31
|
-
if (members.has(member.coordinate))
|
|
32
|
-
fail('ambiguous image coordinate');
|
|
33
|
-
members.set(member.coordinate, member);
|
|
34
|
-
}
|
|
35
|
-
let bytes = 0;
|
|
36
|
-
for (const location of old.locations) {
|
|
37
|
-
const member = members.get(location.member) ?? fail('retained image member not selected ' + location.member);
|
|
38
|
-
const raw = readBoundedFile(location.path, route.profile.selection.budget.bytes - bytes, location.member);
|
|
39
|
-
bytes += raw.length;
|
|
40
|
-
if (sha(raw) !== member.digest)
|
|
41
|
-
fail('retained image member differs ' + member.coordinate);
|
|
42
|
-
if (location.kind === 'binary' && location.member !== route.profile.selection.runtime && !route.binaries.some(b => b.profile.entry.path === location.member && b.origin))
|
|
43
|
-
chmodSync(location.path, 0o555);
|
|
44
|
-
}
|
|
45
|
-
return old;
|
|
46
|
-
}
|
|
47
|
-
const selection = route.profile.selection, budget = selection.budget;
|
|
48
|
-
if (!Number.isSafeInteger(budget.bytes) || budget.bytes < 1 || !Number.isSafeInteger(budget.members) || budget.members < 1 || selection.members.length > budget.members)
|
|
49
|
-
fail('missing image resources');
|
|
50
|
-
const archive = laid(store, selection.archive, budget.bytes);
|
|
51
|
-
gunzipSync(archive.bytes, { maxOutputLength: budget.bytes });
|
|
52
|
-
const files = new Map(archiveMembers(archive.bytes).map(member => [member.name, member.bytes]));
|
|
53
|
-
let charged = archive.bytes.length, retainedBytes = 0;
|
|
54
|
-
const root = storeAt(store, 'cas', 'laid', mountIdentity.slice(7)), present = existsSync(root);
|
|
55
|
-
mkdirSync(dirname(root), { recursive: true });
|
|
56
|
-
const building = present ? root : mkdtempSync(root + '.part-'), seen = new Set();
|
|
57
|
-
try {
|
|
58
|
-
const locations = selection.members.map(member => {
|
|
59
|
-
const coordinate = archiveCoordinate(member.coordinate);
|
|
60
|
-
if (coordinate !== member.coordinate || seen.has(coordinate))
|
|
61
|
-
return fail('ambiguous image coordinate');
|
|
62
|
-
seen.add(coordinate);
|
|
63
|
-
const binary = route.binaries.filter(b => b.profile.entry.path === coordinate), origins = binary.flatMap(b => b.origin ? [b.origin] : []);
|
|
64
|
-
if (new Set(origins.map(o => o.path)).size > 1)
|
|
65
|
-
fail('conflicting binary origins');
|
|
66
|
-
const origin = origins[0];
|
|
67
|
-
if (origin && binary.some(b => !b.origin))
|
|
68
|
-
fail('conflicting relocation/origin meaning');
|
|
69
|
-
let bytes, path;
|
|
70
|
-
if (coordinate === selection.runtime) {
|
|
71
|
-
path = realpathSync(process.execPath);
|
|
72
|
-
bytes = readBoundedFile(path, budget.bytes - charged, coordinate);
|
|
73
|
-
}
|
|
74
|
-
else if (origin) {
|
|
75
|
-
path = origin.path;
|
|
76
|
-
bytes = readBoundedFile(path, budget.bytes - charged, coordinate);
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
const packed = files.get(coordinate);
|
|
80
|
-
if (packed !== undefined)
|
|
81
|
-
bytes = packed;
|
|
82
|
-
else
|
|
83
|
-
bytes = laid(store, member.digest, budget.bytes - charged).bytes;
|
|
84
|
-
path = join(building, coordinate);
|
|
85
|
-
}
|
|
86
|
-
if (binary.some(b => b.profile.entry.bytes !== bytes.length))
|
|
87
|
-
fail('binary entry byte count differs ' + coordinate);
|
|
88
|
-
if (bytes.length > budget.bytes - charged || (charged += bytes.length) > budget.bytes)
|
|
89
|
-
fail('aggregate image and archive bytes exceeded');
|
|
90
|
-
if (sha(bytes) !== member.digest)
|
|
91
|
-
fail('image member differs ' + coordinate);
|
|
92
|
-
if (coordinate !== selection.runtime && !origin) {
|
|
93
|
-
retainedBytes += bytes.length;
|
|
94
|
-
if (present) {
|
|
95
|
-
const actual = readBoundedFile(path, bytes.length, coordinate);
|
|
96
|
-
if (sha(actual) !== member.digest)
|
|
97
|
-
fail('retained image member differs ' + coordinate);
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
101
|
-
writeFileSync(path, bytes, { flag: 'wx', mode: binary.length ? 0o555 : 0o444 });
|
|
102
|
-
}
|
|
103
|
-
if (binary.length)
|
|
104
|
-
chmodSync(path, 0o555);
|
|
105
|
-
}
|
|
106
|
-
return { member: coordinate, path, kind: coordinate === selection.runtime || binary.length ? 'binary' : /\.(?:[mc]?js|ts)$/.test(coordinate) ? 'module' : 'data' };
|
|
107
|
-
});
|
|
108
|
-
if (!present) {
|
|
109
|
-
renameSync(building, root);
|
|
110
|
-
for (const location of locations)
|
|
111
|
-
if (location.member !== selection.runtime && !route.binaries.some(b => b.profile.entry.path === location.member && b.origin))
|
|
112
|
-
location.path = join(root, location.member);
|
|
113
|
-
holdStore(store, 'laid', mountIdentity, retainedBytes);
|
|
114
|
-
}
|
|
115
|
-
const result = { archive: archive.path, locations, cwd: root, mountIdentity };
|
|
116
|
-
mounted.set(key, result);
|
|
117
|
-
return result;
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
if (!present)
|
|
121
|
-
rmSync(building, { recursive: true, force: true });
|
|
122
|
-
throw error;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/** Fixed child, lifetime supervisor and transitive host modules enter identity
|
|
126
|
-
* before the cache key. Existing instrument closure resolves actual dependencies;
|
|
127
|
-
* this descriptor never executes a module and never accepts a world verifier.
|
|
128
|
-
*/
|
|
129
|
-
export function nativeExecutorInputs(route) {
|
|
130
|
-
const store = nativeRouteStore(route), all = new Map();
|
|
131
|
-
for (const entry of [...(route.control ? [fileURLToPath(new URL('./control-bridge-worker' + extname(new URL(import.meta.url).pathname), import.meta.url))] : []), processOf('native'), processOf('lifetime', 'host'), processOf('custodian'), processOf('native-descendant'), processOf('preload', 'host/native')])
|
|
132
|
-
for (const [path, digest] of instrumentCoordinates(store, entry, [], ownRoot(), [], true))
|
|
133
|
-
all.set(path, digest);
|
|
134
|
-
const refs = [];
|
|
135
|
-
let bytes = 0;
|
|
136
|
-
for (const [path, digest] of all) {
|
|
137
|
-
const held = readBoundedFile(path, route.profile.selection.budget.bytes - bytes, path);
|
|
138
|
-
bytes += held.length;
|
|
139
|
-
if (sha(held) !== digest)
|
|
140
|
-
fail('fixed executor changed during descriptor');
|
|
141
|
-
const local = relative(ownRoot(), path);
|
|
142
|
-
let name;
|
|
143
|
-
if (!local.startsWith('..' + sep) && local !== '..')
|
|
144
|
-
name = local.split(sep).join('/');
|
|
145
|
-
else {
|
|
146
|
-
let cursor = dirname(path);
|
|
147
|
-
for (;;) {
|
|
148
|
-
const manifest = join(cursor, 'package.json');
|
|
149
|
-
if (existsSync(manifest)) {
|
|
150
|
-
let pkg;
|
|
151
|
-
try {
|
|
152
|
-
const raw = readBoundedFile(manifest, route.profile.selection.budget.bytes - bytes, manifest);
|
|
153
|
-
bytes += raw.length;
|
|
154
|
-
pkg = JSON.parse(raw.toString('utf8'));
|
|
155
|
-
if (typeof pkg.name === 'string')
|
|
156
|
-
refs.push([['native/executor/library', pkg.name, 'package.json'].join('/'), sha(raw)]);
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
return fail('fixed dependency manifest invalid');
|
|
160
|
-
}
|
|
161
|
-
if (typeof pkg.name !== 'string')
|
|
162
|
-
return fail('fixed dependency has no declared name');
|
|
163
|
-
name = 'library/' + pkg.name + '/' + relative(cursor, path).split(sep).join('/');
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
const parent = dirname(cursor);
|
|
167
|
-
if (parent === cursor)
|
|
168
|
-
return fail('fixed dependency logical coordinates absent');
|
|
169
|
-
cursor = parent;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
refs.push(['native/executor/' + name, digest]);
|
|
173
|
-
}
|
|
174
|
-
return [...new Map(refs).entries()];
|
|
175
|
-
}
|
|
1
|
+
var W=Object.defineProperty;var N=(e,s)=>W(e,"name",{value:s,configurable:!0});import{sha256 as k}from"../hash.js";import{mkdtempSync as $,mkdirSync as F,writeFileSync as q,rmSync as D,existsSync as E,realpathSync as G,renameSync as H,chmodSync as O}from"node:fs";import{join as L,dirname as C,relative as A,sep as U,extname as K}from"node:path";import{fileURLToPath as Q}from"node:url";import{gunzipSync as V}from"node:zlib";import{members as X,archiveCoordinate as Y}from"../archive.js";import{blobAt as Z,storeAt as _,holdStore as ee}from"../../land/ledger.js";import{ContentNeeded as te}from"../content-needed.js";import{processOf as I,ownRoot as B}from"../../observe/runner.js";import{instrumentCoordinates as ie}from"../../fold/digests.js";import{readBoundedFile as S}from"./bounded-file.js";import{assertNativeRouteCurrent as ne,nativeRouteStore as P,nativeMountIdentity as re}from"./route.js";const o=N(e=>{throw Error("REFUSE\xB7native materialize "+e)},"fail"),J=new Map;function T(e,s,b){const d=Z(e,s);if(!E(d))throw new te(s);const c=S(d,b,s);return k(c)!==s&&o("laid bytes differ "+s),{path:d,bytes:c}}N(T,"laid");function ue(e){ne(e);const s=P(e),b=re(e.profile,e.binaries,e.control),d=s+"\0"+b,c=J.get(d);if(c){const f=new Map;for(const t of e.profile.selection.members)f.has(t.coordinate)&&o("ambiguous image coordinate"),f.set(t.coordinate,t);let R=0;for(const t of c.locations){const i=f.get(t.member)??o("retained image member not selected "+t.member),u=S(t.path,e.profile.selection.budget.bytes-R,t.member);R+=u.length,k(u)!==i.digest&&o("retained image member differs "+i.coordinate),t.kind==="binary"&&t.member!==e.profile.selection.runtime&&!e.binaries.some(j=>j.profile.entry.path===t.member&&j.origin)&&O(t.path,365)}return c}const r=e.profile.selection,n=r.budget;(!Number.isSafeInteger(n.bytes)||n.bytes<1||!Number.isSafeInteger(n.members)||n.members<1||r.members.length>n.members)&&o("missing image resources");const g=T(s,r.archive,n.bytes);V(g.bytes,{maxOutputLength:n.bytes});const M=new Map(X(g.bytes).map(f=>[f.name,f.bytes]));let y=g.bytes.length,v=0;const m=_(s,"cas","laid",b.slice(7)),w=E(m);F(C(m),{recursive:!0});const h=w?m:$(m+".part-"),x=new Set;try{const f=r.members.map(t=>{const i=Y(t.coordinate);if(i!==t.coordinate||x.has(i))return o("ambiguous image coordinate");x.add(i);const u=e.binaries.filter(a=>a.profile.entry.path===i),j=u.flatMap(a=>a.origin?[a.origin]:[]);new Set(j.map(a=>a.path)).size>1&&o("conflicting binary origins");const z=j[0];z&&u.some(a=>!a.origin)&&o("conflicting relocation/origin meaning");let l,p;if(i===r.runtime)p=G(process.execPath),l=S(p,n.bytes-y,i);else if(z)p=z.path,l=S(p,n.bytes-y,i);else{const a=M.get(i);a!==void 0?l=a:l=T(s,t.digest,n.bytes-y).bytes,p=L(h,i)}if(u.some(a=>a.profile.entry.bytes!==l.length)&&o("binary entry byte count differs "+i),(l.length>n.bytes-y||(y+=l.length)>n.bytes)&&o("aggregate image and archive bytes exceeded"),k(l)!==t.digest&&o("image member differs "+i),i!==r.runtime&&!z){if(v+=l.length,w){const a=S(p,l.length,i);k(a)!==t.digest&&o("retained image member differs "+i)}else F(C(p),{recursive:!0}),q(p,l,{flag:"wx",mode:u.length?365:292});u.length&&O(p,365)}return{member:i,path:p,kind:i===r.runtime||u.length?"binary":/\.(?:[mc]?js|ts)$/.test(i)?"module":"data"}});if(!w){H(h,m);for(const t of f)t.member!==r.runtime&&!e.binaries.some(i=>i.profile.entry.path===t.member&&i.origin)&&(t.path=L(m,t.member));ee(s,"laid",b,v)}const R={archive:g.path,locations:f,cwd:m,mountIdentity:b};return J.set(d,R),R}catch(f){throw w||D(h,{recursive:!0,force:!0}),f}}N(ue,"materializeNativeRoute");function ve(e){const s=P(e),b=new Map;for(const r of[...e.control?[Q(new URL("./control-bridge-worker"+K(new URL(import.meta.url).pathname),import.meta.url))]:[],I("native"),I("lifetime","host"),I("custodian"),I("native-descendant"),I("preload","host/native")])for(const[n,g]of ie(s,r,[],B(),[],!0))b.set(n,g);const d=[];let c=0;for(const[r,n]of b){const g=S(r,e.profile.selection.budget.bytes-c,r);c+=g.length,k(g)!==n&&o("fixed executor changed during descriptor");const M=A(B(),r);let y;if(!M.startsWith(".."+U)&&M!=="..")y=M.split(U).join("/");else{let v=C(r);for(;;){const m=L(v,"package.json");if(E(m)){let h;try{const x=S(m,e.profile.selection.budget.bytes-c,m);c+=x.length,h=JSON.parse(x.toString("utf8")),typeof h.name=="string"&&d.push([["native/executor/library",h.name,"package.json"].join("/"),k(x)])}catch{return o("fixed dependency manifest invalid")}if(typeof h.name!="string")return o("fixed dependency has no declared name");y="library/"+h.name+"/"+A(v,r).split(U).join("/");break}const w=C(v);if(w===v)return o("fixed dependency logical coordinates absent");v=w}}d.push(["native/executor/"+y,n])}return[...new Map(d).entries()]}N(ve,"nativeExecutorInputs");export{ue as materializeNativeRoute,ve as nativeExecutorInputs};
|