@lapxo/bound 0.2.3 → 0.2.5
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 +19 -0
- package/TARGET.bound +95 -39
- package/dist/cli/accept.js +72 -558
- 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 +21 -321
- package/dist/cli/place.js +6 -281
- package/dist/cli/release-result.js +3 -80
- package/dist/cli/retained-judgment.js +1 -25
- package/dist/cli/standing-result.js +4 -21
- package/dist/cli/takes.js +10 -111
- package/dist/cli/verb.d.ts +1 -2
- package/dist/cli/verb.js +83 -683
- 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 -103
- 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 -131
- package/dist/fold/closed.js +24 -234
- 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 +27 -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 -63
- package/dist/host/archive.js +1 -152
- package/dist/host/call-context.js +1 -0
- package/dist/host/capsule-process.js +2 -61
- package/dist/host/capsule.js +9 -168
- package/dist/host/cell-receipts.js +12 -128
- package/dist/host/commit-result.js +1 -0
- package/dist/host/content-needed.js +1 -8
- package/dist/host/content-store.js +1 -31
- package/dist/host/contextual-place.js +2 -77
- package/dist/host/digest.js +2 -15
- package/dist/host/hash.js +1 -9
- package/dist/host/host-controls.js +1 -0
- package/dist/host/in-process-act.js +3 -0
- package/dist/host/in-process-context.js +3 -0
- package/dist/host/in-process-root.js +6 -0
- package/dist/host/in-process.js +4 -0
- package/dist/host/index.d.ts +1 -0
- package/dist/host/index.js +1 -0
- 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/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/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-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/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-reader-context.js +1 -8
- package/dist/host/native-receiver.js +1 -0
- package/dist/host/objects.js +1 -38
- package/dist/host/order.js +1 -2
- package/dist/host/place-act-transaction.js +4 -0
- 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 -172
- package/dist/host/ports/place-act.js +1 -169
- 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/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 -305
- package/dist/host/selected-capsules.js +1 -50
- package/dist/host/selected-topos.js +1 -80
- package/dist/host/signature-era.js +1 -0
- package/dist/host/signing.js +2 -48
- package/dist/host/source-content.js +2 -110
- package/dist/host/standing-carrier.js +1 -0
- package/dist/host/standing-projection.js +1 -0
- package/dist/host/timing.js +1 -7
- package/dist/host/walk.js +20 -193
- 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 -302
- 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 +7 -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 +2 -40
- package/dist/observe/runner.js +4 -93
- package/dist/public-types.d.ts +1114 -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/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/50086958553b9376d600583f7dff354196bfeb41170fc6d1482ca7bea7c493e2.LICENSE +21 -0
- package/dist/vendor/b3e938d28f88a1851af303a40c749e12ebd5a686daac4f0b343b5cdd2e040419.LICENSE +21 -0
- package/dist/vendor/bundle.json +1 -0
- package/dist/vendor/library11.js +1 -0
- package/dist/vendor/object-provider.js +42 -0
- package/dist/vendor/runtime.js +38 -0
- package/dist/vendor/sources.json +1 -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/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/native-host.md +21 -0
- package/docs/contracts/native-host.publication.json +25 -0
- package/docs/contracts/native-publication.inventory.json +3 -1
- package/docs/contracts/optional-wasm-adapter.publication.json +1 -1
- package/docs/contracts/publication.inventory.json +29 -0
- package/docs/contracts/reading-identity.md +37 -0
- package/docs/contracts/reading-identity.publication.json +25 -0
- package/docs/contracts/refusals.bound +51 -0
- package/docs/contracts/refusals.md +18 -3
- package/docs/contracts/refusals.publication.json +2 -2
- package/docs/contracts/views.md +8 -0
- package/docs/guide.md +10 -0
- package/docs/reference.md +40 -0
- package/docs/why.md +109 -0
- package/package.json +37 -18
- package/receipts.bound +11675 -9725
- package/samples/native-host/no.json +10 -0
- package/samples/native-host/yes.json +20 -0
- package/samples/reading-identity/no.json +20 -0
- package/samples/reading-identity/yes.json +46 -0
- package/vectors/native/native-host.vector.json +62 -0
- package/vectors/native/reading-identity.vector.json +101 -0
- package/vectors/native/refusals.vector.json +104 -0
- package/vendor/syntax/LICENSE.md +7 -0
- package/vendor/syntax/parser.js +1 -0
- package/dist/engine/object.d.ts +0 -17
- package/dist/engine/ports.d.ts +0 -32
- package/dist/host/native/module-closure.d.ts +0 -35
- 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
|
@@ -1,88 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { createConnection } from 'node:net';
|
|
4
|
-
const { endpoint, deadlineMs, shared, inputBytes, outputBytes } = workerData;
|
|
5
|
-
const port = parentPort;
|
|
6
|
-
if (!port)
|
|
7
|
-
throw Error('REFUSE·Root control transport parent absent');
|
|
8
|
-
const header = new Int32Array(shared, 0, 8), input = new Uint8Array(shared, 32, inputBytes), output = new Uint8Array(shared, 32 + inputBytes, outputBytes);
|
|
9
|
-
const initial = Math.min(endpoint.timeoutMs, deadlineMs - Date.now());
|
|
10
|
-
const deadline = process.hrtime.bigint() + BigInt(Math.max(0, initial)) * 1000000n;
|
|
11
|
-
const remaining = () => Math.max(0, Number((deadline - process.hrtime.bigint() + 999999n) / 1000000n));
|
|
12
|
-
let busy = false, red, active;
|
|
13
|
-
function finish(state, bytes) {
|
|
14
|
-
if (bytes.byteLength > outputBytes) {
|
|
15
|
-
state = 3;
|
|
16
|
-
bytes = Buffer.from('REFUSE·reply bytes').subarray(0, outputBytes);
|
|
17
|
-
}
|
|
18
|
-
output.set(bytes);
|
|
19
|
-
Atomics.store(header, 3, bytes.byteLength);
|
|
20
|
-
Atomics.store(header, 0, state);
|
|
21
|
-
Atomics.notify(header, 0);
|
|
22
|
-
}
|
|
23
|
-
// Timer slices never widen the original monotonic deadline.
|
|
24
|
-
let timer;
|
|
25
|
-
function arm() {
|
|
26
|
-
const left = remaining();
|
|
27
|
-
if (left > 0) {
|
|
28
|
-
timer = setTimeout(arm, Math.min(left, 2147483647));
|
|
29
|
-
timer.unref();
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
red ?? (red = 'REFUSE·parent deadline');
|
|
33
|
-
active?.destroy(Error(red));
|
|
34
|
-
if (Atomics.load(header, 0) === 1)
|
|
35
|
-
finish(3, Buffer.from(red).subarray(0, outputBytes));
|
|
36
|
-
port.close();
|
|
37
|
-
}
|
|
38
|
-
arm();
|
|
39
|
-
port.on('close', () => { clearTimeout(timer); active?.destroy(); });
|
|
40
|
-
port.on('message', async (message) => {
|
|
41
|
-
if (busy || red || message !== Atomics.load(header, 1) || Atomics.load(header, 0) !== 1) {
|
|
42
|
-
red ?? (red = 'REFUSE·sequence/state');
|
|
43
|
-
finish(3, Buffer.from(red).subarray(0, outputBytes));
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
busy = true;
|
|
47
|
-
try {
|
|
48
|
-
const length = Atomics.load(header, 2);
|
|
49
|
-
if (length < 1 || length > inputBytes)
|
|
50
|
-
throw Error('REFUSE·request bytes');
|
|
51
|
-
if (remaining() <= 0)
|
|
52
|
-
throw Error('REFUSE·parent deadline');
|
|
53
|
-
const frame = Buffer.from(input.slice(0, length));
|
|
54
|
-
const bytes = await new Promise((resolve, reject) => {
|
|
55
|
-
const socket = createConnection(endpoint.socket);
|
|
56
|
-
active = socket;
|
|
57
|
-
const chunks = [];
|
|
58
|
-
let size = 0, done = false;
|
|
59
|
-
const end = (error) => { if (done)
|
|
60
|
-
return; done = true; if (error)
|
|
61
|
-
reject(error);
|
|
62
|
-
else
|
|
63
|
-
resolve(Buffer.concat(chunks)); };
|
|
64
|
-
socket.once('connect', () => socket.write(Buffer.concat([frame, Buffer.from('\n')])));
|
|
65
|
-
socket.on('data', chunk => { size += chunk.length; if (size > outputBytes)
|
|
66
|
-
socket.destroy(Error('REFUSE·reply bytes'));
|
|
67
|
-
else
|
|
68
|
-
chunks.push(chunk); });
|
|
69
|
-
socket.once('error', end);
|
|
70
|
-
socket.once('close', () => end());
|
|
71
|
-
});
|
|
72
|
-
active = undefined;
|
|
73
|
-
if (!bytes.length)
|
|
74
|
-
throw Error('REFUSE·interrupted before reply');
|
|
75
|
-
if (remaining() <= 0)
|
|
76
|
-
throw Error('REFUSE·parent deadline');
|
|
77
|
-
busy = false;
|
|
78
|
-
finish(2, bytes);
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
active = undefined;
|
|
82
|
-
red ?? (red = error instanceof Error ? error.message : String(error));
|
|
83
|
-
busy = false;
|
|
84
|
-
finish(3, Buffer.from(red).subarray(0, outputBytes));
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
Atomics.store(header, 5, 1);
|
|
88
|
-
Atomics.notify(header, 5);
|
|
1
|
+
var F=Object.defineProperty;var a=(r,e)=>F(r,"name",{value:e,configurable:!0});import{parentPort as M,workerData as k}from"node:worker_threads";import{createConnection as q}from"node:net";const{endpoint:A,deadlineMs:x,shared:l,inputBytes:d,outputBytes:s}=k,c=M;if(!c)throw Error("REFUSE\xB7Root control transport parent absent");const o=new Int32Array(l,0,8),D=new Uint8Array(l,32,d),I=new Uint8Array(l,32+d,s),L=Math.min(A.timeoutMs,x-Date.now()),P=process.hrtime.bigint()+BigInt(Math.max(0,L))*1000000n,E=a(()=>Math.max(0,Number((P-process.hrtime.bigint()+999999n)/1000000n)),"remaining");let u=!1,t,f;function m(r,e){e.byteLength>s&&(r=3,e=Buffer.from("REFUSE\xB7reply bytes").subarray(0,s)),I.set(e),Atomics.store(o,3,e.byteLength),Atomics.store(o,0,r),Atomics.notify(o,0)}a(m,"finish");let y;function B(){const r=E();if(r>0){y=setTimeout(B,Math.min(r,2147483647)),y.unref();return}t??(t="REFUSE\xB7parent deadline"),f?.destroy(Error(t)),Atomics.load(o,0)===1&&m(3,Buffer.from(t).subarray(0,s)),c.close()}a(B,"arm"),B(),c.on("close",()=>{clearTimeout(y),f?.destroy()}),c.on("message",async r=>{if(u||t||r!==Atomics.load(o,1)||Atomics.load(o,0)!==1){t??(t="REFUSE\xB7sequence/state"),m(3,Buffer.from(t).subarray(0,s));return}u=!0;try{const e=Atomics.load(o,2);if(e<1||e>d)throw Error("REFUSE\xB7request bytes");if(E()<=0)throw Error("REFUSE\xB7parent deadline");const U=Buffer.from(D.slice(0,e)),h=await new Promise((R,S)=>{const n=q(A.socket);f=n;const p=[];let b=0,w=!1;const g=a(i=>{w||(w=!0,i?S(i):R(Buffer.concat(p)))},"end");n.once("connect",()=>n.write(Buffer.concat([U,Buffer.from(`
|
|
2
|
+
`)]))),n.on("data",i=>{b+=i.length,b>s?n.destroy(Error("REFUSE\xB7reply bytes")):p.push(i)}),n.once("error",g),n.once("close",()=>g())});if(f=void 0,!h.length)throw Error("REFUSE\xB7interrupted before reply");if(E()<=0)throw Error("REFUSE\xB7parent deadline");u=!1,m(2,h)}catch(e){f=void 0,t??(t=e instanceof Error?e.message:String(e)),u=!1,m(3,Buffer.from(t).subarray(0,s))}}),Atomics.store(o,5,1),Atomics.notify(o,5);
|
|
@@ -1,110 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/** Root-fixed synchronous transport. It retains no grants or command results. */
|
|
3
|
-
import { Worker, isMainThread } from 'node:worker_threads';
|
|
4
|
-
import { readBoundedFile } from "./bounded-file.js";
|
|
5
|
-
import { remainingDeadlineMs } from "./deadline.js";
|
|
6
|
-
const FixedWorker = Worker;
|
|
7
|
-
const HEADER_BYTES = 32;
|
|
8
|
-
let controlWorkerOccupied = false;
|
|
9
|
-
export function createFixedControlBridge(inputBinding) {
|
|
10
|
-
// @1 is one main-thread control worker per OS process, never a WorldWorker grant.
|
|
11
|
-
if (!isMainThread)
|
|
12
|
-
throw Error('REFUSE·Root control transport requires main-thread realm');
|
|
13
|
-
const refuse = (why) => { throw Error('REFUSE·Root control transport ' + why); };
|
|
14
|
-
const integer = (value) => Number.isSafeInteger(value) && value > 0;
|
|
15
|
-
const sourceBytes = inputBinding.workerBytes;
|
|
16
|
-
const workerSelection = Object.freeze({ ...inputBinding.worker });
|
|
17
|
-
if (!(sourceBytes instanceof Uint8Array) || !workerSelection.coordinate || !integer(workerSelection.bytes) || sourceBytes.byteLength !== workerSelection.bytes)
|
|
18
|
-
refuse('selected worker bytes/type bound differs before copy');
|
|
19
|
-
const binding = Object.freeze({ ...inputBinding,
|
|
20
|
-
endpoint: Object.freeze({ ...inputBinding.endpoint }), resources: Object.freeze({ ...inputBinding.resources }),
|
|
21
|
-
runtime: Object.freeze({ ...inputBinding.runtime }), worker: workerSelection,
|
|
22
|
-
workerBytes: Buffer.from(sourceBytes) });
|
|
23
|
-
const { endpoint, resources, runtime, worker: selected } = binding;
|
|
24
|
-
if (!selected.coordinate || !integer(selected.bytes) || binding.workerBytes.byteLength !== selected.bytes || digest(binding.workerBytes) !== selected.digest)
|
|
25
|
-
refuse('selected worker bytes differ');
|
|
26
|
-
if (runtime.path !== process.execPath || !integer(runtime.bytes) || digest(readBoundedFile(runtime.path, runtime.bytes, runtime.path)) !== runtime.digest)
|
|
27
|
-
refuse('selected runtime bytes differ');
|
|
28
|
-
if (![endpoint.timeoutMs, endpoint.responseBytes, endpoint.deadlineMs, binding.deadlineMs].every(integer) || binding.deadlineMs > endpoint.deadlineMs)
|
|
29
|
-
refuse('parent time/byte resource absent or widened');
|
|
30
|
-
// host-control-transport@1 encodes each byte length in a signed Int32 cell.
|
|
31
|
-
// Refuse an incompatible declaration; never wrap or clamp its bound.
|
|
32
|
-
if (resources.inputBytes > 2147483647 || resources.outputBytes > 2147483647)
|
|
33
|
-
refuse('host-control-transport@1 signed Int32 length representation');
|
|
34
|
-
const sharedBytes = HEADER_BYTES + resources.inputBytes + resources.outputBytes;
|
|
35
|
-
if (!Object.values(resources).every(integer) || !Number.isSafeInteger(sharedBytes) || resources.inputBytes > endpoint.responseBytes || resources.outputBytes > endpoint.responseBytes || sharedBytes > resources.sharedBytes)
|
|
36
|
-
refuse('shared/input/output resource absent or exceeded');
|
|
37
|
-
const remainingMs = Math.min(endpoint.timeoutMs, binding.deadlineMs - Date.now());
|
|
38
|
-
if (remainingMs <= 0)
|
|
39
|
-
refuse('parent deadline');
|
|
40
|
-
const deadline = process.hrtime.bigint() + BigInt(remainingMs) * 1000000n;
|
|
41
|
-
const remaining = remainingDeadlineMs.bind(undefined, deadline);
|
|
42
|
-
if (controlWorkerOccupied)
|
|
43
|
-
refuse('one live main-thread control worker resource exhausted');
|
|
44
|
-
let shared;
|
|
45
|
-
try {
|
|
46
|
-
shared = new SharedArrayBuffer(sharedBytes);
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
return refuse('shared resource allocation');
|
|
50
|
-
}
|
|
51
|
-
const header = new Int32Array(shared, 0, 8), input = new Uint8Array(shared, HEADER_BYTES, resources.inputBytes), output = new Uint8Array(shared, HEADER_BYTES + resources.inputBytes, resources.outputBytes);
|
|
52
|
-
// Independently sealed bytes are immutable here. A payload cannot select a path or verifier.
|
|
53
|
-
const code = Buffer.from(binding.workerBytes).toString('base64');
|
|
54
|
-
controlWorkerOccupied = true;
|
|
55
|
-
let worker;
|
|
56
|
-
try {
|
|
57
|
-
worker = new FixedWorker(new URL('data:text/javascript;base64,' + code), { execArgv: [], env: {}, workerData: { endpoint: { ...endpoint }, deadlineMs: binding.deadlineMs, shared, inputBytes: resources.inputBytes, outputBytes: resources.outputBytes } });
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
controlWorkerOccupied = false;
|
|
61
|
-
return refuse('worker construction interrupted');
|
|
62
|
-
}
|
|
63
|
-
let termination;
|
|
64
|
-
const stop = () => termination ?? (termination = worker.terminate().finally(() => { controlWorkerOccupied = false; }));
|
|
65
|
-
worker.once('exit', () => { controlWorkerOccupied = false; });
|
|
66
|
-
worker.unref();
|
|
67
|
-
let red, closed = false, sequence = 0;
|
|
68
|
-
const fail = (why) => { red ?? (red = 'REFUSE·Root control transport ' + why); void stop(); throw Error(red); };
|
|
69
|
-
// Error events still need a listener when a synchronous wait prevents JS callbacks.
|
|
70
|
-
worker.on('error', error => { red ?? (red = 'REFUSE·Root control transport worker interrupted: ' + error.message); });
|
|
71
|
-
if (Atomics.load(header, 5) !== 1 && Atomics.wait(header, 5, 0, remaining()) === 'timed-out')
|
|
72
|
-
fail('startup deadline/interruption');
|
|
73
|
-
return {
|
|
74
|
-
exchange(frame) {
|
|
75
|
-
if (red)
|
|
76
|
-
throw Error(red);
|
|
77
|
-
if (closed)
|
|
78
|
-
fail('closed');
|
|
79
|
-
if (remaining() <= 0)
|
|
80
|
-
fail('parent deadline');
|
|
81
|
-
if (typeof frame !== 'string' || !frame.length || Buffer.byteLength(frame, 'utf8') > resources.inputBytes)
|
|
82
|
-
fail('request bytes before copy');
|
|
83
|
-
const bytes = Buffer.from(frame, 'utf8');
|
|
84
|
-
if (Atomics.load(header, 0) !== 0 || sequence >= 2147483647)
|
|
85
|
-
fail('overlapping request/sequence');
|
|
86
|
-
input.set(bytes);
|
|
87
|
-
Atomics.store(header, 2, bytes.length);
|
|
88
|
-
Atomics.store(header, 1, ++sequence);
|
|
89
|
-
Atomics.store(header, 0, 1);
|
|
90
|
-
worker.postMessage(sequence);
|
|
91
|
-
if (Atomics.wait(header, 0, 1, remaining()) === 'timed-out' || remaining() <= 0)
|
|
92
|
-
fail('deadline/interruption');
|
|
93
|
-
const state = Atomics.load(header, 0), length = Atomics.load(header, 3);
|
|
94
|
-
if (length < 1 || length > resources.outputBytes)
|
|
95
|
-
fail('reply bytes');
|
|
96
|
-
let reply;
|
|
97
|
-
try {
|
|
98
|
-
reply = new TextDecoder('utf-8', { fatal: true }).decode(output.slice(0, length));
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
101
|
-
return fail('reply encoding');
|
|
102
|
-
}
|
|
103
|
-
if (state !== 2)
|
|
104
|
-
fail(reply);
|
|
105
|
-
Atomics.store(header, 0, 0);
|
|
106
|
-
return reply;
|
|
107
|
-
},
|
|
108
|
-
async close() { closed = true; await stop(); }
|
|
109
|
-
};
|
|
110
|
-
}
|
|
1
|
+
var D=Object.defineProperty;var f=(n,r)=>D(n,"name",{value:r,configurable:!0});import{sha256 as U}from"../hash.js";import{Worker as I,isMainThread as L}from"node:worker_threads";import{readBoundedFile as T}from"./bounded-file.js";import{remainingDeadlineMs as W}from"./deadline.js";const N=I,E=32;let p=!1;function G(n){if(!L)throw Error("REFUSE\xB7Root control transport requires main-thread realm");const r=f(t=>{throw Error("REFUSE\xB7Root control transport "+t)},"refuse"),l=f(t=>Number.isSafeInteger(t)&&t>0,"integer"),w=n.workerBytes,m=Object.freeze({...n.worker});(!(w instanceof Uint8Array)||!m.coordinate||!l(m.bytes)||w.byteLength!==m.bytes)&&r("selected worker bytes/type bound differs before copy");const i=Object.freeze({...n,endpoint:Object.freeze({...n.endpoint}),resources:Object.freeze({...n.resources}),runtime:Object.freeze({...n.runtime}),worker:m,workerBytes:Buffer.from(w)}),{endpoint:a,resources:e,runtime:d,worker:b}=i;(!b.coordinate||!l(b.bytes)||i.workerBytes.byteLength!==b.bytes||U(i.workerBytes)!==b.digest)&&r("selected worker bytes differ"),(d.path!==process.execPath||!l(d.bytes)||U(T(d.path,d.bytes,d.path))!==d.digest)&&r("selected runtime bytes differ"),(![a.timeoutMs,a.responseBytes,a.deadlineMs,i.deadlineMs].every(l)||i.deadlineMs>a.deadlineMs)&&r("parent time/byte resource absent or widened"),(e.inputBytes>2147483647||e.outputBytes>2147483647)&&r("host-control-transport@1 signed Int32 length representation");const B=E+e.inputBytes+e.outputBytes;(!Object.values(e).every(l)||!Number.isSafeInteger(B)||e.inputBytes>a.responseBytes||e.outputBytes>a.responseBytes||B>e.sharedBytes)&&r("shared/input/output resource absent or exceeded");const M=Math.min(a.timeoutMs,i.deadlineMs-Date.now());M<=0&&r("parent deadline");const j=process.hrtime.bigint()+BigInt(M)*1000000n,h=W.bind(void 0,j);p&&r("one live main-thread control worker resource exhausted");let y;try{y=new SharedArrayBuffer(B)}catch{return r("shared resource allocation")}const o=new Int32Array(y,0,8),F=new Uint8Array(y,E,e.inputBytes),O=new Uint8Array(y,E+e.inputBytes,e.outputBytes),q=Buffer.from(i.workerBytes).toString("base64");p=!0;let u;try{u=new N(new URL("data:text/javascript;base64,"+q),{execArgv:[],env:{},workerData:{endpoint:{...a},deadlineMs:i.deadlineMs,shared:y,inputBytes:e.inputBytes,outputBytes:e.outputBytes}})}catch{return p=!1,r("worker construction interrupted")}let x;const R=f(()=>x??(x=u.terminate().finally(()=>{p=!1})),"stop");u.once("exit",()=>{p=!1}),u.unref();let c,S=!1,g=0;const s=f(t=>{throw c??(c="REFUSE\xB7Root control transport "+t),R(),Error(c)},"fail");return u.on("error",t=>{c??(c="REFUSE\xB7Root control transport worker interrupted: "+t.message)}),Atomics.load(o,5)!==1&&Atomics.wait(o,5,0,h())==="timed-out"&&s("startup deadline/interruption"),{exchange(t){if(c)throw Error(c);S&&s("closed"),h()<=0&&s("parent deadline"),(typeof t!="string"||!t.length||Buffer.byteLength(t,"utf8")>e.inputBytes)&&s("request bytes before copy");const v=Buffer.from(t,"utf8");(Atomics.load(o,0)!==0||g>=2147483647)&&s("overlapping request/sequence"),F.set(v),Atomics.store(o,2,v.length),Atomics.store(o,1,++g),Atomics.store(o,0,1),u.postMessage(g),(Atomics.wait(o,0,1,h())==="timed-out"||h()<=0)&&s("deadline/interruption");const z=Atomics.load(o,0),k=Atomics.load(o,3);(k<1||k>e.outputBytes)&&s("reply bytes");let A;try{A=new TextDecoder("utf-8",{fatal:!0}).decode(O.slice(0,k))}catch{return s("reply encoding")}return z!==2&&s(A),Atomics.store(o,0,0),A},async close(){S=!0,await R()}}}f(G,"createFixedControlBridge");export{G as createFixedControlBridge};
|
|
@@ -1,32 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* never a world's worker permission or a change to producer message/work caps.
|
|
3
|
-
* One retained control worker belongs only to the main thread of each process;
|
|
4
|
-
* other Node realms keep the existing bounded fixed-client transport. */
|
|
5
|
-
import { parsedLine as parse } from "../../fold/claims.js";
|
|
6
|
-
import { authenticateSignedPort } from "./reading.js";
|
|
7
|
-
const fail = (why) => { throw Error('REFUSE·host control ' + why); };
|
|
8
|
-
const keys = (value) => value && typeof value === 'object' && !Array.isArray(value) ? Object.keys(value).sort().join(',') : '';
|
|
9
|
-
const digest = (value) => typeof value === 'string' && /^sha256:[a-f0-9]{64}$/.test(value);
|
|
10
|
-
export function selectedHostControl(root, parent) {
|
|
11
|
-
const coordinate = [parent.port.coordinate, 'control'].join('/'), rows = root.live.filter(line => { const got = parse(line); return got.kind === 'fact' && got.value.fields.scope === coordinate; });
|
|
12
|
-
if (!rows.length)
|
|
13
|
-
return undefined;
|
|
14
|
-
const selected = authenticateSignedPort(root, coordinate), profile = selected.profile, parsed = parse(selected.line);
|
|
15
|
-
if (parsed.kind !== 'fact' || parsed.value.fields.by !== root.signer.id)
|
|
16
|
-
fail('selection is not Root signed ' + coordinate);
|
|
17
|
-
if (keys(profile) !== 'coordinate,limits,profile,realm,runtime,selector,worker' || profile.profile !== 'host-control-transport@1' || profile.realm !== 'main-thread' || profile.coordinate !== coordinate || keys(profile.selector) !== 'implementation,port' || profile.selector.port !== parent.port.coordinate || profile.selector.implementation !== parent.port.implementation)
|
|
18
|
-
fail('profile selector differs ' + coordinate);
|
|
19
|
-
if (keys(profile.worker) !== 'bytes,coordinate,digest' || !/^native\/executor\/(?:dist|src)\/host\/native\/control-bridge-worker\.(?:js|ts)$/.test(profile.worker.coordinate) || !digest(profile.worker.digest) || !Number.isSafeInteger(profile.worker.bytes) || profile.worker.bytes < 1)
|
|
20
|
-
fail('fixed worker binding absent ' + coordinate);
|
|
21
|
-
const runtime = parent.selection.members.find(member => member.coordinate === parent.selection.runtime);
|
|
22
|
-
if (keys(profile.runtime) !== 'coordinate,digest' || !runtime || profile.runtime.coordinate !== runtime.coordinate || profile.runtime.digest !== runtime.digest)
|
|
23
|
-
fail('fixed runtime selection differs ' + coordinate);
|
|
24
|
-
if (keys(profile.limits) !== 'inFlight,sharedBytes,workersPerProcess' || profile.limits.workersPerProcess !== 1 || profile.limits.inFlight !== 1 || !Number.isSafeInteger(profile.limits.sharedBytes) || profile.limits.sharedBytes < 32)
|
|
25
|
-
fail('named resource invalid ' + coordinate);
|
|
26
|
-
if (!Number.isSafeInteger(parent.port.responseBytes) || parent.port.responseBytes < 1 || parent.port.responseBytes > 2147483647)
|
|
27
|
-
fail('message cap outside declared signed Int32 representation ' + coordinate);
|
|
28
|
-
const required = 32 + 2 * parent.port.responseBytes;
|
|
29
|
-
if (!Number.isSafeInteger(required) || profile.limits.sharedBytes < required)
|
|
30
|
-
fail('shared resource cannot preserve message caps ' + coordinate);
|
|
31
|
-
return Object.freeze({ line: selected.line, profile });
|
|
32
|
-
}
|
|
1
|
+
var g=Object.defineProperty;var s=(r,t)=>g(r,"name",{value:t,configurable:!0});import{parsedLine as p}from"../../fold/claims.js";import{authenticateSignedPort as u}from"./reading.js";const o=s(r=>{throw Error("REFUSE\xB7host control "+r)},"fail"),n=s(r=>r&&typeof r=="object"&&!Array.isArray(r)?Object.keys(r).sort().join(","):"","keys"),y=s(r=>typeof r=="string"&&/^sha256:[a-f0-9]{64}$/.test(r),"digest");function B(r,t){const i=[t.port.coordinate,"control"].join("/");if(!r.live.filter(l=>{const m=p(l);return m.kind==="fact"&&m.value.fields.scope===i}).length)return;const c=u(r,i),e=c.profile,a=p(c.line);(a.kind!=="fact"||a.value.fields.by!==r.signer.id)&&o("selection is not Root signed "+i),(n(e)!=="coordinate,limits,profile,realm,runtime,selector,worker"||e.profile!=="host-control-transport@1"||e.realm!=="main-thread"||e.coordinate!==i||n(e.selector)!=="implementation,port"||e.selector.port!==t.port.coordinate||e.selector.implementation!==t.port.implementation)&&o("profile selector differs "+i),(n(e.worker)!=="bytes,coordinate,digest"||!/^native\/executor\/(?:dist|src)\/host\/native\/control-bridge-worker\.(?:js|ts)$/.test(e.worker.coordinate)||!y(e.worker.digest)||!Number.isSafeInteger(e.worker.bytes)||e.worker.bytes<1)&&o("fixed worker binding absent "+i);const d=t.selection.members.find(l=>l.coordinate===t.selection.runtime);(n(e.runtime)!=="coordinate,digest"||!d||e.runtime.coordinate!==d.coordinate||e.runtime.digest!==d.digest)&&o("fixed runtime selection differs "+i),(n(e.limits)!=="inFlight,sharedBytes,workersPerProcess"||e.limits.workersPerProcess!==1||e.limits.inFlight!==1||!Number.isSafeInteger(e.limits.sharedBytes)||e.limits.sharedBytes<32)&&o("named resource invalid "+i),(!Number.isSafeInteger(t.port.responseBytes)||t.port.responseBytes<1||t.port.responseBytes>2147483647)&&o("message cap outside declared signed Int32 representation "+i);const f=32+2*t.port.responseBytes;return(!Number.isSafeInteger(f)||e.limits.sharedBytes<f)&&o("shared resource cannot preserve message caps "+i),Object.freeze({line:c.line,profile:e})}s(B,"selectedHostControl");export{B as selectedHostControl};
|
|
@@ -1,91 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* authenticated Root records matching the already planned native parent job.
|
|
3
|
-
*/
|
|
4
|
-
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
|
|
5
|
-
import { tmpdir } from 'node:os';
|
|
6
|
-
import { join, extname } from 'node:path';
|
|
7
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
8
|
-
import { createHash } from 'node:crypto';
|
|
9
|
-
import { parse } from '@lapxo/topos/wire';
|
|
10
|
-
import { processOf, ownRoot } from "../../observe/runner.js";
|
|
11
|
-
import { selectedHostControl } from "./control-selection.js";
|
|
12
|
-
import { readBoundedFile } from "./bounded-file.js";
|
|
13
|
-
import { authenticateSignedPort } from "./reading.js";
|
|
14
|
-
import { createProducerJobCustody } from "./generated-custodian.js";
|
|
15
|
-
const fail = (why) => { throw Error('REFUSE·native custody ' + why); };
|
|
16
|
-
const sha = (raw) => 'sha256:' + createHash('sha256').update(raw).digest('hex');
|
|
17
|
-
export function nativeRootJobCustody(root, profile, handoff, image, logical) {
|
|
18
|
-
const data = logical.members.map(member => { const location = image.locations.find(loc => loc.member === member.coordinate); if (!location)
|
|
19
|
-
return fail('literal member absent'); return { path: location.path, digest: member.digest }; }), libraries = logical.libraries.map(lib => { const location = image.locations.find(loc => loc.member === lib.manifest); if (!location)
|
|
20
|
-
return fail('library absent'); return { name: lib.name, manifest: location.path, coordinate: lib.manifest }; });
|
|
21
|
-
const candidates = root.live.flatMap(line => { const row = parse(line); if (row.kind !== 'fact' || !row.value.fields.scope.startsWith('port/'))
|
|
22
|
-
return []; let p; try {
|
|
23
|
-
p = JSON.parse(row.value.fields.about ?? '');
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return [];
|
|
27
|
-
} return p?.selector?.port === profile.port.coordinate ? [{ coordinate: row.value.fields.scope, profile: p }] : []; });
|
|
28
|
-
return { async open(parent) {
|
|
29
|
-
const matching = candidates.filter(candidate => candidate.profile.selector.binding === parent.binding && candidate.profile.selector.implementation === parent.implementation);
|
|
30
|
-
const producers = matching.filter(candidate => candidate.profile.profile === 'host-generated-executable@3');
|
|
31
|
-
if (producers.length !== 1)
|
|
32
|
-
return fail('requires one current Root producer for ' + parent.binding);
|
|
33
|
-
const selected = producers[0];
|
|
34
|
-
authenticateSignedPort(root, selected.coordinate);
|
|
35
|
-
const control = selectedHostControl(root, profile);
|
|
36
|
-
const implementation = fileURLToPath(new URL('./generated' + extname(new URL(import.meta.url).pathname), import.meta.url)), implementationBytes = readBoundedFile(implementation, root.budget.bytes, implementation);
|
|
37
|
-
const runtime = image.locations.find(location => location.member === image.runtime), runtimeMember = handoff.members.find(member => member.coordinate === image.runtime);
|
|
38
|
-
if (!runtime || !runtimeMember)
|
|
39
|
-
return fail('fixed actual runtime absent');
|
|
40
|
-
const binaries = matching.filter(candidate => ['host-native-binary@1', 'host-native-binary-origin@1'].includes(candidate.profile.profile)).map(candidate => { const p = candidate.profile, location = image.locations.find(loc => loc.member === p.entry?.path), member = handoff.members.find(m => m.coordinate === p.entry?.path); if (!location || !member)
|
|
41
|
-
return fail('binary outside actual selected image'); return { coordinate: candidate.coordinate, privateBinding: { coordinate: member.coordinate, path: location.path, digest: member.digest } }; });
|
|
42
|
-
const programs = matching.filter(candidate => candidate.profile.profile === 'host-native-program@1').map(candidate => ({ coordinate: candidate.coordinate, runtimeBinding: { coordinate: image.runtime, path: runtime.path, digest: runtimeMember.digest, members: image.locations.map(location => ({ coordinate: location.member, path: location.path })) } }));
|
|
43
|
-
const directory = mkdtempSync(join(tmpdir(), 'bound-native-custody-')), contextFile = join(directory, 'context.json'), configFile = join(directory, 'loader.json');
|
|
44
|
-
let acquired;
|
|
45
|
-
try {
|
|
46
|
-
const service = createProducerJobCustody({ root, coordinate: selected.coordinate, implementationBytes, snapshot: { budget: { members: handoff.budget.members, bytes: handoff.budget.bytes }, members: data, libraries, builtins: logical.builtins, platform: logical.platform }, nativeImplementations: new Set(logical.members.map(member => member.digest)), directory, contextFile, nativeBinaries: binaries, programSelections: programs });
|
|
47
|
-
acquired = await service.open(parent);
|
|
48
|
-
const client = processOf('custodian'), clientBytes = readBoundedFile(client, parent.responseBytes, client), preload = new URL(pathToFileURL(processOf('native-descendant')).href);
|
|
49
|
-
preload.searchParams.set('config', configFile);
|
|
50
|
-
preload.searchParams.set('bytes', String(handoff.budget.bytes));
|
|
51
|
-
let controlEnvelope;
|
|
52
|
-
if (control) {
|
|
53
|
-
const worker = control.profile.worker, path = join(ownRoot(), worker.coordinate.slice('native/executor/'.length)), raw = readBoundedFile(path, worker.bytes, worker.coordinate);
|
|
54
|
-
if (raw.length !== worker.bytes || sha(raw) !== worker.digest)
|
|
55
|
-
return fail('sealed control worker bytes differ');
|
|
56
|
-
if (control.profile.runtime.coordinate !== image.runtime || control.profile.runtime.digest !== runtimeMember.digest)
|
|
57
|
-
return fail('sealed control runtime differs');
|
|
58
|
-
const shared = 32 + 2 * parent.responseBytes;
|
|
59
|
-
if (!Number.isSafeInteger(shared) || shared > control.profile.limits.sharedBytes)
|
|
60
|
-
return fail('shared control resource absent');
|
|
61
|
-
controlEnvelope = { profileLine: control.line, realm: control.profile.realm, worker: { ...worker, path }, resources: { inputBytes: parent.responseBytes, outputBytes: parent.responseBytes, sharedBytes: control.profile.limits.sharedBytes } };
|
|
62
|
-
}
|
|
63
|
-
const config = { ...(controlEnvelope ? { control: controlEnvelope } : {}), members: data, libraries, builtins: logical.builtins, platform: logical.platform, executableDigests: logical.members.filter(member => /\.(?:[mc]?js|ts)$/.test(member.coordinate)).map(member => member.digest), metadataDigests: logical.members.filter(member => member.coordinate.endsWith('.json')).map(member => member.digest), inputBytes: handoff.budget.bytes, runtimeBytes: runtimeMember.bytes.byteLength, clientBytes: clientBytes.length, contextBytes: parent.responseBytes, custodian: { contextFile, client, runtime: runtime.path, preload: preload.href, runtimeDigest: runtimeMember.digest, clientDigest: sha(clientBytes) } };
|
|
64
|
-
// Loader metadata describes the authenticated input image, not the command's
|
|
65
|
-
// stdout. Its declared input budget stays separate from responseBytes.
|
|
66
|
-
const raw = Buffer.from(JSON.stringify(config));
|
|
67
|
-
if (raw.length > handoff.budget.bytes)
|
|
68
|
-
return fail('operational descendant envelope bytes');
|
|
69
|
-
writeFileSync(configFile, raw, { flag: 'wx', mode: 0o400 });
|
|
70
|
-
// The URL carries an independently fixed expected digest of the private host
|
|
71
|
-
// envelope. This is operational custody, never authority from JSON.
|
|
72
|
-
preload.searchParams.set('digest', sha(raw));
|
|
73
|
-
config.custodian.preload = preload.href;
|
|
74
|
-
// The recursive preload URL excludes its own digest while writing the file;
|
|
75
|
-
// its fixed child validates the exact file before installing any hook.
|
|
76
|
-
const descendant = { ...config, custodian: { ...config.custodian, preload: preload.href } };
|
|
77
|
-
const held = acquired;
|
|
78
|
-
return { descendant, assertClosed: () => held.assertClosed(), async close() { try {
|
|
79
|
-
await held.close();
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
rmSync(directory, { recursive: true, force: true });
|
|
83
|
-
} } };
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
await acquired?.close();
|
|
87
|
-
rmSync(directory, { recursive: true, force: true });
|
|
88
|
-
throw error;
|
|
89
|
-
}
|
|
90
|
-
} };
|
|
91
|
-
}
|
|
1
|
+
var _=Object.defineProperty;var h=(i,g)=>_(i,"name",{value:g,configurable:!0});import{mkdtempSync as $,writeFileSync as z,rmSync as O}from"node:fs";import{tmpdir as A}from"node:os";import{join as B,extname as G}from"node:path";import{fileURLToPath as K,pathToFileURL as Q}from"node:url";import{createHash as V}from"node:crypto";import{library11_parse as X}from"../../vendor/runtime.js";import{processOf as q,ownRoot as Y}from"../../observe/runner.js";import{selectedHostControl as Z}from"./control-selection.js";import{readBoundedFile as R}from"./bounded-file.js";import{authenticateSignedPort as ee}from"./reading.js";import{createProducerJobCustody as te}from"./generated-custodian.js";const d=h(i=>{throw Error("REFUSE\xB7native custody "+i)},"fail"),L=h(i=>"sha256:"+V("sha256").update(i).digest("hex"),"sha");function fe(i,g,p,a,c){const k=c.members.map(t=>{const o=a.locations.find(s=>s.member===t.coordinate);return o?{path:o.path,digest:t.digest}:d("literal member absent")}),F=c.libraries.map(t=>{const o=a.locations.find(s=>s.member===t.manifest);return o?{name:t.name,manifest:o.path,coordinate:t.manifest}:d("library absent")}),H=i.live.flatMap(t=>{const o=X(t);if(o.kind!=="fact"||!o.value.fields.scope.startsWith("port/"))return[];let s;try{s=JSON.parse(o.value.fields.about??"")}catch{return[]}return s?.selector?.port===g.port.coordinate?[{coordinate:o.value.fields.scope,profile:s}]:[]});return{async open(t){const o=H.filter(e=>e.profile.selector.binding===t.binding&&e.profile.selector.implementation===t.implementation),s=o.filter(e=>e.profile.profile==="host-generated-executable@3");if(s.length!==1)return d("requires one current Root producer for "+t.binding);const P=s[0];ee(i,P.coordinate);const l=Z(i,g),U=K(new URL("./generated"+G(new URL(import.meta.url).pathname),import.meta.url)),I=R(U,i.budget.bytes,U),w=a.locations.find(e=>e.member===a.runtime),f=p.members.find(e=>e.coordinate===a.runtime);if(!w||!f)return d("fixed actual runtime absent");const M=o.filter(e=>["host-native-binary@1","host-native-binary-origin@1"].includes(e.profile.profile)).map(e=>{const m=e.profile,y=a.locations.find(u=>u.member===m.entry?.path),n=p.members.find(u=>u.coordinate===m.entry?.path);return!y||!n?d("binary outside actual selected image"):{coordinate:e.coordinate,privateBinding:{coordinate:n.coordinate,path:y.path,digest:n.digest}}}),T=o.filter(e=>e.profile.profile==="host-native-program@1").map(e=>({coordinate:e.coordinate,runtimeBinding:{coordinate:a.runtime,path:w.path,digest:f.digest,members:a.locations.map(m=>({coordinate:m.member,path:m.path}))}})),b=$(B(A(),"bound-native-custody-")),j=B(b,"context.json"),C=B(b,"loader.json");let x;try{x=await te({root:i,coordinate:P.coordinate,implementationBytes:I,snapshot:{budget:{members:p.budget.members,bytes:p.budget.bytes},members:k,libraries:F,builtins:c.builtins,platform:c.platform},nativeImplementations:new Set(c.members.map(r=>r.digest)),directory:b,contextFile:j,nativeBinaries:M,programSelections:T}).open(t);const m=q("custodian"),y=R(m,t.responseBytes,m),n=new URL(Q(q("native-descendant")).href);n.searchParams.set("config",C),n.searchParams.set("bytes",String(p.budget.bytes));let u;if(l){const r=l.profile.worker,E=B(Y(),r.coordinate.slice(16)),J=R(E,r.bytes,r.coordinate);if(J.length!==r.bytes||L(J)!==r.digest)return d("sealed control worker bytes differ");if(l.profile.runtime.coordinate!==a.runtime||l.profile.runtime.digest!==f.digest)return d("sealed control runtime differs");const N=32+2*t.responseBytes;if(!Number.isSafeInteger(N)||N>l.profile.limits.sharedBytes)return d("shared control resource absent");u={profileLine:l.line,realm:l.profile.realm,worker:{...r,path:E},resources:{inputBytes:t.responseBytes,outputBytes:t.responseBytes,sharedBytes:l.profile.limits.sharedBytes}}}const v={...u?{control:u}:{},members:k,libraries:F,builtins:c.builtins,platform:c.platform,executableDigests:c.members.filter(r=>/\.(?:[mc]?js|ts)$/.test(r.coordinate)).map(r=>r.digest),metadataDigests:c.members.filter(r=>r.coordinate.endsWith(".json")).map(r=>r.digest),inputBytes:p.budget.bytes,runtimeBytes:f.bytes.byteLength,clientBytes:y.length,contextBytes:t.responseBytes,custodian:{contextFile:j,client:m,runtime:w.path,preload:n.href,runtimeDigest:f.digest,clientDigest:L(y)}},S=Buffer.from(JSON.stringify(v));if(S.length>p.budget.bytes)return d("operational descendant envelope bytes");z(C,S,{flag:"wx",mode:256}),n.searchParams.set("digest",L(S)),v.custodian.preload=n.href;const W={...v,custodian:{...v.custodian,preload:n.href}},D=x;return{descendant:W,assertClosed:h(()=>D.assertClosed(),"assertClosed"),async close(){try{await D.close()}finally{O(b,{recursive:!0,force:!0})}}}}catch(e){throw await x?.close(),O(b,{recursive:!0,force:!0}),e}}}}h(fe,"nativeRootJobCustody");export{fe as nativeRootJobCustody};
|
|
@@ -1,28 +1 @@
|
|
|
1
|
-
const
|
|
2
|
-
/** Remaining monotonic lease, rounded up for host APIs that accept milliseconds. */
|
|
3
|
-
export function remainingDeadlineMs(deadline) {
|
|
4
|
-
return Math.max(0, Number((deadline - process.hrtime.bigint() + 999999n) / 1000000n));
|
|
5
|
-
}
|
|
6
|
-
const native = { now: () => process.hrtime.bigint(), schedule: (callback, delay) => setTimeout(callback, delay), cancel: handle => clearTimeout(handle) };
|
|
7
|
-
/** The admitted deadline is never clamped to the platform timer range. Each
|
|
8
|
-
* timer is merely a wake-up slice; expiry checks the original monotonic clock.
|
|
9
|
-
* Injected clock exists only for deterministic platform-boundary vectors. */
|
|
10
|
-
export function scheduleDeadline(deadline, expire, clock = native) {
|
|
11
|
-
let active = true, handle;
|
|
12
|
-
const arm = () => {
|
|
13
|
-
if (!active)
|
|
14
|
-
return;
|
|
15
|
-
const remaining = deadline - clock.now();
|
|
16
|
-
if (remaining <= 0n) {
|
|
17
|
-
active = false;
|
|
18
|
-
expire();
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
const ceilMs = (remaining + 999999n) / 1000000n;
|
|
22
|
-
const slice = ceilMs > BigInt(TIMER_MAX_MS) ? TIMER_MAX_MS : Number(ceilMs);
|
|
23
|
-
handle = clock.schedule(arm, slice);
|
|
24
|
-
};
|
|
25
|
-
arm();
|
|
26
|
-
return () => { active = false; if (handle !== undefined)
|
|
27
|
-
clock.cancel(handle); };
|
|
28
|
-
}
|
|
1
|
+
var l=Object.defineProperty;var n=(e,t)=>l(e,"name",{value:t,configurable:!0});const d=2147483647;function f(e){return Math.max(0,Number((e-process.hrtime.bigint()+999999n)/1000000n))}n(f,"remainingDeadlineMs");const M={now:n(()=>process.hrtime.bigint(),"now"),schedule:n((e,t)=>setTimeout(e,t),"schedule"),cancel:n(e=>clearTimeout(e),"cancel")};function h(e,t,i=M){let r=!0,s;const c=n(()=>{if(!r)return;const a=e-i.now();if(a<=0n){r=!1,t();return}const u=(a+999999n)/1000000n,o=u>BigInt(2147483647)?2147483647:Number(u);s=i.schedule(c,o)},"arm");return c(),()=>{r=!1,s!==void 0&&i.cancel(s)}}n(h,"scheduleDeadline");export{f as remainingDeadlineMs,h as scheduleDeadline};
|