@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.
Files changed (242) hide show
  1. package/CITATION.cff +19 -0
  2. package/TARGET.bound +95 -39
  3. package/dist/cli/accept.js +72 -558
  4. package/dist/cli/act-result.js +3 -103
  5. package/dist/cli/args.js +3 -44
  6. package/dist/cli/custodian.js +2 -29
  7. package/dist/cli/host.js +4 -32
  8. package/dist/cli/names.js +1 -12
  9. package/dist/cli/native-descendant.js +1 -19
  10. package/dist/cli/native.js +3 -60
  11. package/dist/cli/observe.js +1 -13
  12. package/dist/cli/owner.js +3 -139
  13. package/dist/cli/pass.js +21 -321
  14. package/dist/cli/place.js +6 -281
  15. package/dist/cli/release-result.js +3 -80
  16. package/dist/cli/retained-judgment.js +1 -25
  17. package/dist/cli/standing-result.js +4 -21
  18. package/dist/cli/takes.js +10 -111
  19. package/dist/cli/verb.d.ts +1 -2
  20. package/dist/cli/verb.js +83 -683
  21. package/dist/engine/computation.js +2 -0
  22. package/dist/engine/conformance.js +4 -0
  23. package/dist/engine/encoding.js +1 -2
  24. package/dist/engine/index.d.ts +1 -13
  25. package/dist/engine/index.js +2 -11
  26. package/dist/engine/object.js +1 -38
  27. package/dist/engine/ports.js +2 -103
  28. package/dist/fold/admission-history.js +1 -17
  29. package/dist/fold/bootstrap-anchor.js +1 -28
  30. package/dist/fold/ceilings.js +1 -142
  31. package/dist/fold/claims.js +2 -131
  32. package/dist/fold/closed.js +24 -234
  33. package/dist/fold/configures.js +1 -25
  34. package/dist/fold/digests.js +10 -226
  35. package/dist/fold/evidence.js +1 -22
  36. package/dist/fold/fold-worker.js +1 -13
  37. package/dist/fold/kept.js +12 -173
  38. package/dist/fold/keys.js +3 -91
  39. package/dist/fold/laid.js +3 -90
  40. package/dist/fold/nos.js +1 -48
  41. package/dist/fold/object.js +1 -2
  42. package/dist/fold/observed.js +27 -534
  43. package/dist/fold/opened.js +1 -33
  44. package/dist/fold/own.js +3 -217
  45. package/dist/fold/paid.js +1 -92
  46. package/dist/fold/place-inputs.js +1 -70
  47. package/dist/fold/places.js +3 -100
  48. package/dist/fold/rank.js +1 -9
  49. package/dist/fold/reach.js +1 -83
  50. package/dist/fold/readers.js +6 -142
  51. package/dist/fold/receipts.js +1 -47
  52. package/dist/fold/region-declarations.js +1 -13
  53. package/dist/fold/region.js +8 -286
  54. package/dist/fold/release-policy.js +1 -101
  55. package/dist/fold/resolved.js +6 -145
  56. package/dist/fold/roles.js +2 -59
  57. package/dist/fold/second.js +4 -71
  58. package/dist/fold/shards.js +12 -100
  59. package/dist/fold/signed.js +3 -81
  60. package/dist/fold/signers.js +1 -54
  61. package/dist/fold/stranger.js +6 -24
  62. package/dist/fold/views.js +1 -66
  63. package/dist/fold/wire.js +1 -46
  64. package/dist/fold/zoom.js +3 -81
  65. package/dist/host/act-cost.js +1 -25
  66. package/dist/host/adapters/keys/ed25519.js +1 -30
  67. package/dist/host/adapters/modules/javascript.js +1 -50
  68. package/dist/host/adapters/transport/http.js +1 -28
  69. package/dist/host/admitted-place.js +1 -63
  70. package/dist/host/archive.js +1 -152
  71. package/dist/host/call-context.js +1 -0
  72. package/dist/host/capsule-process.js +2 -61
  73. package/dist/host/capsule.js +9 -168
  74. package/dist/host/cell-receipts.js +12 -128
  75. package/dist/host/commit-result.js +1 -0
  76. package/dist/host/content-needed.js +1 -8
  77. package/dist/host/content-store.js +1 -31
  78. package/dist/host/contextual-place.js +2 -77
  79. package/dist/host/digest.js +2 -15
  80. package/dist/host/hash.js +1 -9
  81. package/dist/host/host-controls.js +1 -0
  82. package/dist/host/in-process-act.js +3 -0
  83. package/dist/host/in-process-context.js +3 -0
  84. package/dist/host/in-process-root.js +6 -0
  85. package/dist/host/in-process.js +4 -0
  86. package/dist/host/index.d.ts +1 -0
  87. package/dist/host/index.js +1 -0
  88. package/dist/host/io.js +1 -11
  89. package/dist/host/lifetime.js +1 -79
  90. package/dist/host/located.js +6 -105
  91. package/dist/host/native/bounded-file.js +1 -32
  92. package/dist/host/native/command.js +1 -91
  93. package/dist/host/native/control-bridge-worker.js +2 -88
  94. package/dist/host/native/control-bridge.js +1 -110
  95. package/dist/host/native/control-selection.js +1 -32
  96. package/dist/host/native/custody.js +1 -91
  97. package/dist/host/native/deadline.js +1 -28
  98. package/dist/host/native/descendants.js +1 -528
  99. package/dist/host/native/generated-custodian.js +5 -267
  100. package/dist/host/native/generated.js +1 -379
  101. package/dist/host/native/image.js +1 -45
  102. package/dist/host/native/jobs.js +2 -148
  103. package/dist/host/native/loader.js +1 -269
  104. package/dist/host/native/materialize.js +1 -175
  105. package/dist/host/native/module-closure.js +1 -130
  106. package/dist/host/native/module-delivery.d.ts +1 -62
  107. package/dist/host/native/module-delivery.js +1 -151
  108. package/dist/host/native/module-syntax.js +1 -69
  109. package/dist/host/native/native-binary.js +1 -115
  110. package/dist/host/native/native-program.js +1 -72
  111. package/dist/host/native/node-jobs.js +3 -187
  112. package/dist/host/native/node-launch.js +1 -159
  113. package/dist/host/native/preload.js +1 -45
  114. package/dist/host/native/reading.js +1 -249
  115. package/dist/host/native/receipt-environment.js +1 -41
  116. package/dist/host/native/references.js +1 -30
  117. package/dist/host/native/root.js +1 -37
  118. package/dist/host/native/route.js +1 -216
  119. package/dist/host/native/runtime.js +1 -9
  120. package/dist/host/native-reader-context.js +1 -8
  121. package/dist/host/native-receiver.js +1 -0
  122. package/dist/host/objects.js +1 -38
  123. package/dist/host/order.js +1 -2
  124. package/dist/host/place-act-transaction.js +4 -0
  125. package/dist/host/place-clock-selection.js +5 -124
  126. package/dist/host/ports/ingress.js +2 -57
  127. package/dist/host/ports/local-act.js +5 -172
  128. package/dist/host/ports/place-act.js +1 -169
  129. package/dist/host/ports/publication.js +1 -56
  130. package/dist/host/ports/signing.js +1 -74
  131. package/dist/host/ports/store.js +1 -18
  132. package/dist/host/ports/transport.js +1 -48
  133. package/dist/host/process-lifetime.js +1 -17
  134. package/dist/host/provide.js +1 -183
  135. package/dist/host/read-only.js +1 -9
  136. package/dist/host/reading-closures.js +7 -227
  137. package/dist/host/reading-context.js +1 -53
  138. package/dist/host/reading-identity-types.js +0 -0
  139. package/dist/host/reading-identity.js +3 -0
  140. package/dist/host/reading-preparation.js +6 -0
  141. package/dist/host/reference-authenticated.d.ts +1 -40
  142. package/dist/host/reference-authenticated.js +3 -100
  143. package/dist/host/reference-contracts.js +1 -6
  144. package/dist/host/reference-export.js +6 -81
  145. package/dist/host/reference-native-api.d.ts +1 -3
  146. package/dist/host/reference-native-api.js +1 -3
  147. package/dist/host/reference-native.js +1 -74
  148. package/dist/host/reference-profile.js +1 -63
  149. package/dist/host/reference-standing.js +2 -18
  150. package/dist/host/reference.js +1 -24
  151. package/dist/host/refusals.js +2 -43
  152. package/dist/host/release.js +4 -256
  153. package/dist/host/root-clock-source.js +1 -305
  154. package/dist/host/selected-capsules.js +1 -50
  155. package/dist/host/selected-topos.js +1 -80
  156. package/dist/host/signature-era.js +1 -0
  157. package/dist/host/signing.js +2 -48
  158. package/dist/host/source-content.js +2 -110
  159. package/dist/host/standing-carrier.js +1 -0
  160. package/dist/host/standing-projection.js +1 -0
  161. package/dist/host/timing.js +1 -7
  162. package/dist/host/walk.js +20 -193
  163. package/dist/judge/late.js +1 -33
  164. package/dist/judge/take.js +2 -75
  165. package/dist/judge/widening.js +1 -25
  166. package/dist/land/act.js +8 -302
  167. package/dist/land/alias.js +1 -41
  168. package/dist/land/held.js +1 -23
  169. package/dist/land/inert.js +1 -33
  170. package/dist/land/leaving.js +1 -55
  171. package/dist/land/ledger.js +7 -188
  172. package/dist/land/owned.js +4 -66
  173. package/dist/land/sign.js +1 -53
  174. package/dist/land/standing-pin.js +1 -49
  175. package/dist/land/vouched.js +1 -112
  176. package/dist/land/withdraw.js +1 -24
  177. package/dist/observe/files.js +1 -88
  178. package/dist/observe/identity.js +1 -61
  179. package/dist/observe/match.js +1 -8
  180. package/dist/observe/regions.js +7 -306
  181. package/dist/observe/run.js +2 -40
  182. package/dist/observe/runner.js +4 -93
  183. package/dist/public-types.d.ts +1114 -0
  184. package/dist/render/capsule.js +1 -30
  185. package/dist/render/field.js +1 -40
  186. package/dist/render/names.js +1 -4
  187. package/dist/render/open.js +1 -61
  188. package/dist/render/page.js +1 -7
  189. package/dist/render/receipts.js +1 -47
  190. package/dist/render/shape.js +1 -74
  191. package/dist/render/target.js +4 -52
  192. package/dist/render/view.js +7 -197
  193. package/dist/vendor/50086958553b9376d600583f7dff354196bfeb41170fc6d1482ca7bea7c493e2.LICENSE +21 -0
  194. package/dist/vendor/b3e938d28f88a1851af303a40c749e12ebd5a686daac4f0b343b5cdd2e040419.LICENSE +21 -0
  195. package/dist/vendor/bundle.json +1 -0
  196. package/dist/vendor/library11.js +1 -0
  197. package/dist/vendor/object-provider.js +42 -0
  198. package/dist/vendor/runtime.js +38 -0
  199. package/dist/vendor/sources.json +1 -0
  200. package/dist/wasm/adapter.d.ts +1 -51
  201. package/dist/wasm/adapter.js +1 -180
  202. package/dist/wasm/node-worker.js +1 -13
  203. package/dist/wasm/object.js +1 -76
  204. package/dist/wasm/worker.js +1 -7
  205. package/docs/contracts/closure-delivery.md +1 -1
  206. package/docs/contracts/closure-delivery.publication.json +1 -1
  207. package/docs/contracts/conformance.json +142 -0
  208. package/docs/contracts/determinism.bound +9 -0
  209. package/docs/contracts/engine-object-projection.publication.json +1 -1
  210. package/docs/contracts/engine.md +21 -1
  211. package/docs/contracts/native-host.md +21 -0
  212. package/docs/contracts/native-host.publication.json +25 -0
  213. package/docs/contracts/native-publication.inventory.json +3 -1
  214. package/docs/contracts/optional-wasm-adapter.publication.json +1 -1
  215. package/docs/contracts/publication.inventory.json +29 -0
  216. package/docs/contracts/reading-identity.md +37 -0
  217. package/docs/contracts/reading-identity.publication.json +25 -0
  218. package/docs/contracts/refusals.bound +51 -0
  219. package/docs/contracts/refusals.md +18 -3
  220. package/docs/contracts/refusals.publication.json +2 -2
  221. package/docs/contracts/views.md +8 -0
  222. package/docs/guide.md +10 -0
  223. package/docs/reference.md +40 -0
  224. package/docs/why.md +109 -0
  225. package/package.json +37 -18
  226. package/receipts.bound +11675 -9725
  227. package/samples/native-host/no.json +10 -0
  228. package/samples/native-host/yes.json +20 -0
  229. package/samples/reading-identity/no.json +20 -0
  230. package/samples/reading-identity/yes.json +46 -0
  231. package/vectors/native/native-host.vector.json +62 -0
  232. package/vectors/native/reading-identity.vector.json +101 -0
  233. package/vectors/native/refusals.vector.json +104 -0
  234. package/vendor/syntax/LICENSE.md +7 -0
  235. package/vendor/syntax/parser.js +1 -0
  236. package/dist/engine/object.d.ts +0 -17
  237. package/dist/engine/ports.d.ts +0 -32
  238. package/dist/host/native/module-closure.d.ts +0 -35
  239. package/dist/host/reference-export.d.ts +0 -33
  240. package/dist/host/reference-native.d.ts +0 -30
  241. package/dist/host/reference-profile.d.ts +0 -23
  242. package/dist/host/refusals.d.ts +0 -14
@@ -1,267 +1,5 @@
1
- import { sha256 as sha } from "../hash.js";
2
- /** One asynchronous Root custodian owns aggregate counters for one actual job.
3
- * Endpoint is injected by instrument code, never selected by a world payload. */
4
- import { createServer, createConnection } from 'node:net';
5
- import { chmodSync, rmSync, realpathSync, writeFileSync, renameSync, existsSync } from 'node:fs';
6
- import { join } from 'node:path';
7
- import { randomBytes } from 'node:crypto';
8
- import { canonicalJson } from "./reading.js";
9
- import { verifyNativeBinary, nativeBinaryProjection } from "./native-binary.js";
10
- import { commandRequest, commandResponse } from '@lapxo/topos/contract';
11
- import { assertProducerInterpretation, chargeProducerRequest, createGeneratedProducer, readBounded, validateDescendantInvocation, sealGeneratedFile, sealNativeEval, sealInterpretation, recordProducerEmission, recordProducerEmissions, registerProducerCandidates, gateDerived, producerTransport, producerUsage } from "./generated.js";
12
- import { retainedNativeEvalMatches } from "./node-launch.js";
13
- import { verifyNativeProgram, nativeProgramProjection } from "./native-program.js";
14
- /** Refusal transport is bounded too; an undersized channel closes without a
15
- * frame while the parent retains the named refusal. No truncation is success. */
16
- export function boundedRefusalFrame(endpoint, why) { if (why.length > endpoint.responseBytes || Buffer.byteLength(why) > endpoint.responseBytes)
17
- return; const frame = JSON.stringify({ protocol: 'command-lot/1', coordinate: endpoint.coordinate, implementation: endpoint.implementation, identity: endpoint.identity, responses: [{ kind: 'refuse', why }] }) + '\n'; return Buffer.byteLength(frame) <= endpoint.responseBytes ? frame : undefined; }
18
- export async function startProducerCustodian(handle, snapshot, nativeImplementations, directory, inputNativePrograms = []) {
19
- const nativePrograms = inputNativePrograms.map(grant => ({ identity: grant.identity, program: { ...grant.program } }));
20
- if (nativePrograms.some(g => !/^sha256:[0-9a-f]{64}$/.test(g.identity) || g.program.kind !== 'native-binary' || typeof g.program.alias !== 'string' || !g.program.alias.length || !g.program.entry.startsWith('/') || !/^sha256:[0-9a-f]{64}$/.test(g.program.entryDigest) || !Number.isSafeInteger(g.program.entryBytes) || g.program.entryBytes < 1 || g.program.entryBytes > snapshot.budget.bytes || !g.program.condition) || new Set(nativePrograms.map(g => g.program.alias)).size !== nativePrograms.length)
21
- throw Error('REFUSE·producer native program selection ambiguous/over budget');
22
- const selected = producerTransport(handle), endpoint = { ...selected, deadlineMs: Date.now() + selected.timeoutMs, socket: join(directory, 'p-' + randomBytes(6).toString('hex')), token: randomBytes(32).toString('hex') }, connections = new Set(), unfinishedRequests = new Set(), refusals = [], knownDigests = new Set(snapshot.members.map(m => m.digest));
23
- const retainedContexts = new Map(), retainedValues = new Map();
24
- let contextBytes = 0;
25
- const reconstruct = (compact) => { const full = { ...compact }; for (const key of ['invocation', 'edges'])
26
- if (full[key]?.retainedValue) {
27
- const value = retainedValues.get(full[key].retainedValue);
28
- if (value === undefined)
29
- throw Error('REFUSE·producer retained value absent');
30
- full[key] = value;
31
- } return full; };
32
- const retainContext = (context) => { const held = retainedContexts.get(context.identity); if (held) {
33
- if (canonicalJson(reconstruct(held)) !== canonicalJson(context))
34
- throw Error('REFUSE·producer context identity collision');
35
- return;
36
- } const compact = { ...context }, fresh = new Map(); for (const key of ['invocation', 'edges']) {
37
- const value = context[key];
38
- if (value && typeof value === 'object') {
39
- const encoded = canonicalJson(value), id = sha(encoded), prior = retainedValues.get(id);
40
- if (prior !== undefined && canonicalJson(prior) !== encoded)
41
- throw Error('REFUSE·producer retained value collision');
42
- if (prior === undefined && !fresh.has(id))
43
- fresh.set(id, JSON.parse(encoded));
44
- compact[key] = { retainedValue: id };
45
- }
46
- } let bytes = Buffer.byteLength(canonicalJson(compact)); for (const [id, value] of fresh)
47
- bytes += Buffer.byteLength(canonicalJson([id, value])); if (bytes > selected.responseBytes - contextBytes)
48
- throw Error('REFUSE·producer retained contexts bytes'); for (const [id, value] of fresh)
49
- retainedValues.set(id, value); retainedContexts.set(context.identity, compact); contextBytes += bytes; };
50
- const server = createServer(socket => {
51
- try {
52
- chargeProducerRequest(handle);
53
- if (Date.now() >= endpoint.deadlineMs)
54
- throw Error('REFUSE·producer parent deadline');
55
- }
56
- catch (error) {
57
- refusals.push(error instanceof Error ? error.message : String(error));
58
- socket.destroy();
59
- return;
60
- }
61
- connections.add(socket);
62
- unfinishedRequests.add(socket);
63
- const finishReply = (reply) => { const done = () => unfinishedRequests.delete(socket); if (reply === undefined)
64
- socket.end(done);
65
- else
66
- socket.end(reply, done); };
67
- socket.once('error', () => { if (!refusals.length)
68
- refusals.push('REFUSE·producer IPC response interrupted'); });
69
- socket.setTimeout(Math.max(1, endpoint.deadlineMs - Date.now()), () => { refusals.push('REFUSE·producer IPC timeout'); socket.destroy(); });
70
- const chunks = [];
71
- let bytes = 0, handled = false;
72
- socket.on('data', chunk => {
73
- bytes += chunk.length;
74
- if (bytes > endpoint.responseBytes) {
75
- refusals.push('REFUSE·producer IPC request bytes');
76
- socket.destroy();
77
- return;
78
- }
79
- chunks.push(chunk);
80
- if (!chunk.includes(10))
81
- return;
82
- if (handled)
83
- return;
84
- handled = true;
85
- socket.pause();
86
- try {
87
- const raw = Buffer.concat(chunks).toString('utf8');
88
- if (refusals.length)
89
- throw Error(refusals[0]);
90
- const frame = JSON.parse(raw.trim());
91
- if (frame.protocol !== 'command-lot/1' || frame.coordinate !== endpoint.coordinate || frame.implementation !== endpoint.implementation || frame.identity !== endpoint.identity || !Array.isArray(frame.requests) || frame.requests.length !== 1)
92
- throw Error('REFUSE·producer IPC frame');
93
- const body = JSON.parse(frame.requests[0]);
94
- if (body.token !== endpoint.token || !['entry', 'emission', 'emission-batch', 'native-program', 'interpretation', 'eval-context', 'violation'].includes(body.operation))
95
- throw Error('REFUSE·producer IPC capability');
96
- if (body.operation === 'violation') {
97
- if (typeof body.why !== 'string' || body.why.length > endpoint.responseBytes || Buffer.byteLength(body.why) > endpoint.responseBytes)
98
- throw Error('REFUSE·producer violation bytes');
99
- throw Error('REFUSE·producer pre-entry ' + body.why);
100
- }
101
- let context;
102
- if (body.operation === 'eval-context') {
103
- const actual = body.request;
104
- const matches = [...retainedContexts.values()].map(reconstruct).filter(record => retainedNativeEvalMatches(record, actual));
105
- if (matches.length !== 1)
106
- throw Error('REFUSE·producer retained eval context ' + (matches.length ? 'ambiguous' : 'absent'));
107
- context = matches[0];
108
- }
109
- else if (body.operation === 'emission-batch') {
110
- const request = body.request;
111
- if (!request || !Array.isArray(request.outputs) || request.outputs.length > selected.limits.work)
112
- throw Error('REFUSE·producer emission batch context/count absent');
113
- context = recordProducerEmissions(handle, request.outputs, request.invocation);
114
- }
115
- else if (body.operation === 'emission') {
116
- const request = body.request;
117
- if (!request || typeof request.path !== 'string')
118
- throw Error('REFUSE·producer emission context absent');
119
- context = recordProducerEmission(handle, request.path, request.invocation);
120
- }
121
- else if (body.operation === 'native-program') {
122
- const request = body.request;
123
- if (!request || typeof request.alias !== 'string' || typeof request.path !== 'string')
124
- throw Error('REFUSE·producer native invocation absent');
125
- const grant = nativePrograms.find(g => g.program.alias === request.alias);
126
- if (!grant)
127
- throw Error('REFUSE·producer native program alias undeclared ' + request.alias);
128
- const invocation = validateDescendantInvocation(handle, request.invocation);
129
- let actual;
130
- try {
131
- actual = realpathSync(request.path);
132
- }
133
- catch {
134
- throw Error('REFUSE·producer native program target absent');
135
- }
136
- if (actual !== grant.program.entry)
137
- throw Error('REFUSE·producer native program route differs');
138
- const bytes = readBounded(actual, grant.program.entryBytes), digest = sha(bytes);
139
- if (bytes.length !== grant.program.entryBytes || digest !== grant.program.entryDigest)
140
- throw Error('REFUSE·producer native program bytes differ');
141
- const transaction = { kind: 'native-program-transaction/1', parent: selected.parent, producer: selected.identity, program: grant.identity, alias: grant.program.alias, target: actual, digest, byteLength: bytes.length, invocation, condition: grant.program.condition };
142
- context = { ...transaction, identity: sha(JSON.stringify(transaction)) };
143
- }
144
- else if (body.operation === 'interpretation') {
145
- const request = body.request;
146
- if (!request || typeof request.path !== 'string' || typeof request.interpretation !== 'string')
147
- throw Error('REFUSE·producer interpretation context absent');
148
- context = sealInterpretation(handle, request.path, request.interpretation, request.invocation);
149
- }
150
- else {
151
- const request = body.request;
152
- if (!request || !['module', 'commonjs'].includes(request.mode))
153
- throw Error('REFUSE·producer unknown entry mode');
154
- if (request.candidates !== undefined)
155
- registerProducerCandidates(handle, request.candidates);
156
- if (request.kind === 'file') {
157
- if (request.interpretation !== undefined) {
158
- assertProducerInterpretation(handle, request.interpretation);
159
- if (request.interpretation !== 'node-ambiguous-javascript@1')
160
- throw Error('REFUSE·producer entry interpretation unsupported');
161
- }
162
- if (!request.path)
163
- throw Error('REFUSE·producer missing path');
164
- const path = realpathSync(request.path), actual = readBounded(path, snapshot.budget.bytes);
165
- if (actual.length > snapshot.budget.bytes)
166
- throw Error('REFUSE·producer static input bytes');
167
- const digest = sha(actual);
168
- if (knownDigests.has(digest)) {
169
- context = { kind: 'mounted-executable/1', parent: selected.parent, producer: selected.identity, path, digest, mode: request.mode, ...(request.interpretation === undefined ? {} : { interpretation: request.interpretation }), invocation: validateDescendantInvocation(handle, request.invocation), identity: sha(JSON.stringify([selected.parent, selected.identity, path, digest, request.mode, request.invocation, ...(request.interpretation === undefined ? [] : [request.interpretation])])), qualification: nativeImplementations.has(digest) ? 'separately selected privileged native implementation' : 'same sealed content mounted at actual path' };
170
- }
171
- else {
172
- const record = sealGeneratedFile(handle, path, request.mode, request.invocation, request.interpretation), edges = gateDerived(handle, record, { path }, snapshot, nativeImplementations);
173
- context = { ...record, edges };
174
- }
175
- }
176
- else if (request.kind === 'eval') {
177
- if (!request.argv || !request.rootPrefix)
178
- throw Error('REFUSE·producer missing eval binding');
179
- const record = sealNativeEval(handle, request.argv, request.rootPrefix, request.invocation);
180
- if (record.mode !== request.mode)
181
- throw Error('REFUSE·producer eval mode differs from argv');
182
- const edges = gateDerived(handle, record, { argv: request.argv }, snapshot, nativeImplementations);
183
- context = { ...record, edges };
184
- }
185
- else
186
- throw Error('REFUSE·producer unknown entry kind');
187
- }
188
- retainContext(context);
189
- const reply = JSON.stringify({ protocol: 'command-lot/1', coordinate: endpoint.coordinate, implementation: endpoint.implementation, identity: endpoint.identity, responses: [{ kind: 'entry-context', context, usage: producerUsage(handle) }] }) + '\n';
190
- if (Buffer.byteLength(reply) > endpoint.responseBytes)
191
- throw Error('REFUSE·producer IPC response bytes');
192
- finishReply(reply);
193
- }
194
- catch (error) {
195
- const why = error instanceof Error ? error.message : String(error);
196
- if (!refusals.length)
197
- refusals.push(why);
198
- const refusal = boundedRefusalFrame(endpoint, why);
199
- if (refusal === undefined) {
200
- finishReply();
201
- return;
202
- }
203
- finishReply(refusal);
204
- }
205
- });
206
- socket.once('close', () => { if (unfinishedRequests.delete(socket) && !refusals.length)
207
- refusals.push('REFUSE·producer IPC interrupted before bounded reply'); connections.delete(socket); });
208
- });
209
- await new Promise((resolve, reject) => { server.once('error', reject); server.listen(endpoint.socket, () => { chmodSync(endpoint.socket, 0o600); resolve(); }); });
210
- const deadline = setTimeout(() => { refusals.push('REFUSE·producer parent deadline'); for (const socket of connections)
211
- socket.destroy(); }, endpoint.timeoutMs);
212
- return { endpoint, get contexts() { return [...retainedContexts.values()].map(reconstruct); }, retention: () => ({ bytes: contextBytes, contexts: [...retainedContexts.values()].map(value => JSON.parse(canonicalJson(value))), values: [...retainedValues].map(([id, value]) => [id, JSON.parse(canonicalJson(value))]) }), assertClosed: () => { if (Date.now() >= endpoint.deadlineMs)
213
- throw Error('REFUSE·producer parent deadline'); if (refusals.length)
214
- throw Error(refusals[0]); if (unfinishedRequests.size)
215
- throw Error('REFUSE·producer IPC unfinished'); }, refusals, usage: () => producerUsage(handle), close: async () => { clearTimeout(deadline); for (const socket of connections)
216
- socket.destroy(); await new Promise(resolve => server.close(() => resolve())); rmSync(endpoint.socket, { force: true }); } };
217
- }
218
- /** Asynchronous client for original async native APIs. Original sync APIs use
219
- * the fixed client executable; both address this SAME custodian/counters. */
220
- export async function requestRetainedEvalContext(endpoint, actual) { return requestProducerOperation(endpoint, 'eval-context', actual); }
221
- export async function requestProducerEntry(endpoint, request) { return requestProducerOperation(endpoint, 'entry', request); }
222
- export async function requestProducerInterpretation(endpoint, request) { return requestProducerOperation(endpoint, 'interpretation', request); }
223
- export async function requestNativeProgram(endpoint, request) { return requestProducerOperation(endpoint, 'native-program', request); }
224
- export async function requestProducerEmission(endpoint, request) { return requestProducerOperation(endpoint, 'emission', request); }
225
- export async function requestProducerEmissionBatch(endpoint, request) { return requestProducerOperation(endpoint, 'emission-batch', request); }
226
- async function requestProducerOperation(endpoint, operation, request) { const port = { coordinate: endpoint.coordinate, implementation: endpoint.implementation, closure: [endpoint.implementation], timeoutMs: endpoint.timeoutMs, responseBytes: endpoint.responseBytes, environment: [], stderr: 'reject' }, lot = { identity: endpoint.identity, requests: [JSON.stringify({ operation, token: endpoint.token, request })] }, frame = commandRequest(port, lot); if (Buffer.byteLength(frame) > endpoint.responseBytes)
227
- throw Error('REFUSE·producer IPC request bytes'); const raw = await new Promise((resolve, reject) => { const socket = createConnection(endpoint.socket), chunks = [], timer = setTimeout(() => socket.destroy(Error('REFUSE·producer IPC timeout')), Math.max(1, Math.min(endpoint.timeoutMs, endpoint.deadlineMs - Date.now()))); let bytes = 0; socket.on('connect', () => socket.write(frame + '\n')); socket.on('data', c => { bytes += c.length; if (bytes > endpoint.responseBytes)
228
- socket.destroy(Error('REFUSE·producer IPC response bytes'));
229
- else
230
- chunks.push(c); }); socket.once('error', reject); socket.once('close', () => { clearTimeout(timer); resolve(Buffer.concat(chunks).toString('utf8')); }); }); const values = commandResponse(port, lot, { status: 0, interrupted: false, stdout: raw, stderr: '' }, value => !!value && typeof value === 'object' && ['entry-context', 'refuse'].includes(value.kind)); const one = values[0]; if (one.kind === 'refuse')
231
- throw Error(one.why); return one.context; }
232
- /** Bound's guarded host constructs this factory, not a world. The transport path
233
- * is selected by the sealed native preload configuration, not a grant in data.
234
- * A shared context file cannot be multiplexed across simultaneous bindings. */
235
- export function createProducerJobCustody(input) { let active = false; return { async open(parent) { if (active || existsSync(input.contextFile))
236
- throw Error('REFUSE·producer execution context occupied'); active = true; let service; const temporary = input.contextFile + '.' + randomBytes(6).toString('hex'); try {
237
- const programs = (input.programSelections ?? []).map(selected => nativeProgramProjection(verifyNativeProgram(input.root, selected.coordinate, parent, selected.runtimeBinding)));
238
- const handle = createGeneratedProducer(input.root, input.coordinate, parent, input.implementationBytes);
239
- const nativePrograms = (input.nativeBinaries ?? []).map(binding => { const verified = verifyNativeBinary(input.root, binding.coordinate, parent, binding.privateBinding); return { identity: verified.identity, program: nativeBinaryProjection(verified) }; });
240
- service = await startProducerCustodian(handle, input.snapshot, input.nativeImplementations, input.directory, nativePrograms);
241
- const declaredPrograms = [...programs, ...nativePrograms.map(g => g.program)];
242
- if (new Set(declaredPrograms.map(p => p.alias)).size !== declaredPrograms.length)
243
- throw Error('REFUSE·producer native alias ambiguous');
244
- const text = JSON.stringify({ endpoint: service.endpoint, parentExecution: parent, programs: declaredPrograms });
245
- if (Buffer.byteLength(text) > parent.responseBytes)
246
- throw Error('REFUSE·producer execution context bytes');
247
- writeFileSync(temporary, text, { flag: 'wx', mode: 0o600 });
248
- renameSync(temporary, input.contextFile);
249
- const held = service;
250
- return { assertClosed: () => held.assertClosed(), async close() { try {
251
- await held.close();
252
- }
253
- finally {
254
- rmSync(input.contextFile, { force: true });
255
- active = false;
256
- } } };
257
- }
258
- catch (error) {
259
- rmSync(temporary, { force: true });
260
- await service?.close();
261
- active = false;
262
- throw error;
263
- } } }; }
264
- /** Fixed Root preload reports a local before-entry refusal to the SAME parent
265
- * custodian. A caught child error therefore cannot become a success receipt. */
266
- export async function reportProducerViolation(endpoint, why) { if (typeof why !== 'string' || why.length > endpoint.responseBytes || Buffer.byteLength(why) > endpoint.responseBytes)
267
- throw Error('REFUSE·producer violation bytes'); const frame = JSON.stringify({ protocol: 'command-lot/1', coordinate: endpoint.coordinate, implementation: endpoint.implementation, identity: endpoint.identity, requests: [JSON.stringify({ operation: 'violation', token: endpoint.token, why })] }); await new Promise((resolve, reject) => { const socket = createConnection(endpoint.socket), timer = setTimeout(() => socket.destroy(Error('REFUSE·producer IPC timeout')), Math.max(1, endpoint.deadlineMs - Date.now())); socket.once('connect', () => socket.write(frame + '\n')); socket.on('data', () => { }); socket.once('error', reject); socket.once('close', () => { clearTimeout(timer); resolve(); }); }); throw Error('REFUSE·producer pre-entry ' + why); }
1
+ var Q=Object.defineProperty;var a=(e,o)=>Q(e,"name",{value:o,configurable:!0});import{sha256 as I}from"../hash.js";import{createServer as X,createConnection as V}from"node:net";import{chmodSync as Y,rmSync as D,realpathSync as A,writeFileSync as Z,renameSync as ee,existsSync as re}from"node:fs";import{join as te}from"node:path";import{randomBytes as L}from"node:crypto";import{canonicalJson as B}from"./reading.js";import{verifyNativeBinary as oe,nativeBinaryProjection as ne}from"./native-binary.js";import{library2_commandRequest as ie,library2_commandResponse as se}from"../../vendor/runtime.js";import{assertProducerInterpretation as ae,chargeProducerRequest as ce,createGeneratedProducer as de,readBounded as z,validateDescendantInvocation as G,sealGeneratedFile as ue,sealNativeEval as pe,sealInterpretation as me,recordProducerEmission as fe,recordProducerEmissions as le,registerProducerCandidates as ye,gateDerived as _,producerTransport as Ee,producerUsage as $}from"./generated.js";import{retainedNativeEvalMatches as ge}from"./node-launch.js";import{verifyNativeProgram as he,nativeProgramProjection as ve}from"./native-program.js";function Se(e,o){if(o.length>e.responseBytes||Buffer.byteLength(o)>e.responseBytes)return;const m=JSON.stringify({protocol:"command-lot/1",coordinate:e.coordinate,implementation:e.implementation,identity:e.identity,responses:[{kind:"refuse",why:o}]})+`
2
+ `;return Buffer.byteLength(m)<=e.responseBytes?m:void 0}a(Se,"boundedRefusalFrame");async function we(e,o,m,S,b=[]){const u=b.map(t=>({identity:t.identity,program:{...t.program}}));if(u.some(t=>!/^sha256:[0-9a-f]{64}$/.test(t.identity)||t.program.kind!=="native-binary"||typeof t.program.alias!="string"||!t.program.alias.length||!t.program.entry.startsWith("/")||!/^sha256:[0-9a-f]{64}$/.test(t.program.entryDigest)||!Number.isSafeInteger(t.program.entryBytes)||t.program.entryBytes<1||t.program.entryBytes>o.budget.bytes||!t.program.condition)||new Set(u.map(t=>t.program.alias)).size!==u.length)throw Error("REFUSE\xB7producer native program selection ambiguous/over budget");const f=Ee(e),i={...f,deadlineMs:Date.now()+f.timeoutMs,socket:te(S,"p-"+L(6).toString("hex")),token:L(32).toString("hex")},v=new Set,h=new Set,c=[],d=new Set(o.members.map(t=>t.digest)),w=new Map,P=new Map;let q=0;const C=a(t=>{const y={...t};for(const R of["invocation","edges"])if(y[R]?.retainedValue){const F=P.get(y[R].retainedValue);if(F===void 0)throw Error("REFUSE\xB7producer retained value absent");y[R]=F}return y},"reconstruct"),W=a(t=>{const y=w.get(t.identity);if(y){if(B(C(y))!==B(t))throw Error("REFUSE\xB7producer context identity collision");return}const R={...t},F=new Map;for(const p of["invocation","edges"]){const l=t[p];if(l&&typeof l=="object"){const E=B(l),n=I(E),g=P.get(n);if(g!==void 0&&B(g)!==E)throw Error("REFUSE\xB7producer retained value collision");g===void 0&&!F.has(n)&&F.set(n,JSON.parse(E)),R[p]={retainedValue:n}}}let k=Buffer.byteLength(B(R));for(const[p,l]of F)k+=Buffer.byteLength(B([p,l]));if(k>f.responseBytes-q)throw Error("REFUSE\xB7producer retained contexts bytes");for(const[p,l]of F)P.set(p,l);w.set(t.identity,R),q+=k},"retainContext"),O=X(t=>{try{if(ce(e),Date.now()>=i.deadlineMs)throw Error("REFUSE\xB7producer parent deadline")}catch(p){c.push(p instanceof Error?p.message:String(p)),t.destroy();return}v.add(t),h.add(t);const y=a(p=>{const l=a(()=>h.delete(t),"done");p===void 0?t.end(l):t.end(p,l)},"finishReply");t.once("error",()=>{c.length||c.push("REFUSE\xB7producer IPC response interrupted")}),t.setTimeout(Math.max(1,i.deadlineMs-Date.now()),()=>{c.push("REFUSE\xB7producer IPC timeout"),t.destroy()});const R=[];let F=0,k=!1;t.on("data",p=>{if(F+=p.length,F>i.responseBytes){c.push("REFUSE\xB7producer IPC request bytes"),t.destroy();return}if(R.push(p),!!p.includes(10)&&!k){k=!0,t.pause();try{const l=Buffer.concat(R).toString("utf8");if(c.length)throw Error(c[0]);const E=JSON.parse(l.trim());if(E.protocol!=="command-lot/1"||E.coordinate!==i.coordinate||E.implementation!==i.implementation||E.identity!==i.identity||!Array.isArray(E.requests)||E.requests.length!==1)throw Error("REFUSE\xB7producer IPC frame");const n=JSON.parse(E.requests[0]);if(n.token!==i.token||!["entry","emission","emission-batch","native-program","interpretation","eval-context","violation"].includes(n.operation))throw Error("REFUSE\xB7producer IPC capability");if(n.operation==="violation")throw typeof n.why!="string"||n.why.length>i.responseBytes||Buffer.byteLength(n.why)>i.responseBytes?Error("REFUSE\xB7producer violation bytes"):Error("REFUSE\xB7producer pre-entry "+n.why);let g;if(n.operation==="eval-context"){const r=n.request,s=[...w.values()].map(C).filter(U=>ge(U,r));if(s.length!==1)throw Error("REFUSE\xB7producer retained eval context "+(s.length?"ambiguous":"absent"));g=s[0]}else if(n.operation==="emission-batch"){const r=n.request;if(!r||!Array.isArray(r.outputs)||r.outputs.length>f.limits.work)throw Error("REFUSE\xB7producer emission batch context/count absent");g=le(e,r.outputs,r.invocation)}else if(n.operation==="emission"){const r=n.request;if(!r||typeof r.path!="string")throw Error("REFUSE\xB7producer emission context absent");g=fe(e,r.path,r.invocation)}else if(n.operation==="native-program"){const r=n.request;if(!r||typeof r.alias!="string"||typeof r.path!="string")throw Error("REFUSE\xB7producer native invocation absent");const s=u.find(K=>K.program.alias===r.alias);if(!s)throw Error("REFUSE\xB7producer native program alias undeclared "+r.alias);const U=G(e,r.invocation);let x;try{x=A(r.path)}catch{throw Error("REFUSE\xB7producer native program target absent")}if(x!==s.program.entry)throw Error("REFUSE\xB7producer native program route differs");const M=z(x,s.program.entryBytes),J=I(M);if(M.length!==s.program.entryBytes||J!==s.program.entryDigest)throw Error("REFUSE\xB7producer native program bytes differ");const T={kind:"native-program-transaction/1",parent:f.parent,producer:f.identity,program:s.identity,alias:s.program.alias,target:x,digest:J,byteLength:M.length,invocation:U,condition:s.program.condition};g={...T,identity:I(JSON.stringify(T))}}else if(n.operation==="interpretation"){const r=n.request;if(!r||typeof r.path!="string"||typeof r.interpretation!="string")throw Error("REFUSE\xB7producer interpretation context absent");g=me(e,r.path,r.interpretation,r.invocation)}else{const r=n.request;if(!r||!["module","commonjs"].includes(r.mode))throw Error("REFUSE\xB7producer unknown entry mode");if(r.candidates!==void 0&&ye(e,r.candidates),r.kind==="file"){if(r.interpretation!==void 0&&(ae(e,r.interpretation),r.interpretation!=="node-ambiguous-javascript@1"))throw Error("REFUSE\xB7producer entry interpretation unsupported");if(!r.path)throw Error("REFUSE\xB7producer missing path");const s=A(r.path),U=z(s,o.budget.bytes);if(U.length>o.budget.bytes)throw Error("REFUSE\xB7producer static input bytes");const x=I(U);if(d.has(x))g={kind:"mounted-executable/1",parent:f.parent,producer:f.identity,path:s,digest:x,mode:r.mode,...r.interpretation===void 0?{}:{interpretation:r.interpretation},invocation:G(e,r.invocation),identity:I(JSON.stringify([f.parent,f.identity,s,x,r.mode,r.invocation,...r.interpretation===void 0?[]:[r.interpretation]])),qualification:m.has(x)?"separately selected privileged native implementation":"same sealed content mounted at actual path"};else{const M=ue(e,s,r.mode,r.invocation,r.interpretation),J=_(e,M,{path:s},o,m);g={...M,edges:J}}}else if(r.kind==="eval"){if(!r.argv||!r.rootPrefix)throw Error("REFUSE\xB7producer missing eval binding");const s=pe(e,r.argv,r.rootPrefix,r.invocation);if(s.mode!==r.mode)throw Error("REFUSE\xB7producer eval mode differs from argv");const U=_(e,s,{argv:r.argv},o,m);g={...s,edges:U}}else throw Error("REFUSE\xB7producer unknown entry kind")}W(g);const j=JSON.stringify({protocol:"command-lot/1",coordinate:i.coordinate,implementation:i.implementation,identity:i.identity,responses:[{kind:"entry-context",context:g,usage:$(e)}]})+`
3
+ `;if(Buffer.byteLength(j)>i.responseBytes)throw Error("REFUSE\xB7producer IPC response bytes");y(j)}catch(l){const E=l instanceof Error?l.message:String(l);c.length||c.push(E);const n=Se(i,E);if(n===void 0){y();return}y(n)}}}),t.once("close",()=>{h.delete(t)&&!c.length&&c.push("REFUSE\xB7producer IPC interrupted before bounded reply"),v.delete(t)})});await new Promise((t,y)=>{O.once("error",y),O.listen(i.socket,()=>{Y(i.socket,384),t()})});const H=setTimeout(()=>{c.push("REFUSE\xB7producer parent deadline");for(const t of v)t.destroy()},i.timeoutMs);return{endpoint:i,get contexts(){return[...w.values()].map(C)},retention:a(()=>({bytes:q,contexts:[...w.values()].map(t=>JSON.parse(B(t))),values:[...P].map(([t,y])=>[t,JSON.parse(B(y))])}),"retention"),assertClosed:a(()=>{if(Date.now()>=i.deadlineMs)throw Error("REFUSE\xB7producer parent deadline");if(c.length)throw Error(c[0]);if(h.size)throw Error("REFUSE\xB7producer IPC unfinished")},"assertClosed"),refusals:c,usage:a(()=>$(e),"usage"),close:a(async()=>{clearTimeout(H);for(const t of v)t.destroy();await new Promise(t=>O.close(()=>t())),D(i.socket,{force:!0})},"close")}}a(we,"startProducerCustodian");async function Ie(e,o){return N(e,"eval-context",o)}a(Ie,"requestRetainedEvalContext");async function Je(e,o){return N(e,"entry",o)}a(Je,"requestProducerEntry");async function Oe(e,o){return N(e,"interpretation",o)}a(Oe,"requestProducerInterpretation");async function De(e,o){return N(e,"native-program",o)}a(De,"requestNativeProgram");async function Le(e,o){return N(e,"emission",o)}a(Le,"requestProducerEmission");async function je(e,o){return N(e,"emission-batch",o)}a(je,"requestProducerEmissionBatch");async function N(e,o,m){const S={coordinate:e.coordinate,implementation:e.implementation,closure:[e.implementation],timeoutMs:e.timeoutMs,responseBytes:e.responseBytes,environment:[],stderr:"reject"},b={identity:e.identity,requests:[JSON.stringify({operation:o,token:e.token,request:m})]},u=ie(S,b);if(Buffer.byteLength(u)>e.responseBytes)throw Error("REFUSE\xB7producer IPC request bytes");const f=await new Promise((h,c)=>{const d=V(e.socket),w=[],P=setTimeout(()=>d.destroy(Error("REFUSE\xB7producer IPC timeout")),Math.max(1,Math.min(e.timeoutMs,e.deadlineMs-Date.now())));let q=0;d.on("connect",()=>d.write(u+`
4
+ `)),d.on("data",C=>{q+=C.length,q>e.responseBytes?d.destroy(Error("REFUSE\xB7producer IPC response bytes")):w.push(C)}),d.once("error",c),d.once("close",()=>{clearTimeout(P),h(Buffer.concat(w).toString("utf8"))})}),v=se(S,b,{status:0,interrupted:!1,stdout:f,stderr:""},h=>!!h&&typeof h=="object"&&["entry-context","refuse"].includes(h.kind))[0];if(v.kind==="refuse")throw Error(v.why);return v.context}a(N,"requestProducerOperation");function Te(e){let o=!1;return{async open(m){if(o||re(e.contextFile))throw Error("REFUSE\xB7producer execution context occupied");o=!0;let S;const b=e.contextFile+"."+L(6).toString("hex");try{const u=(e.programSelections??[]).map(d=>ve(he(e.root,d.coordinate,m,d.runtimeBinding))),f=de(e.root,e.coordinate,m,e.implementationBytes),i=(e.nativeBinaries??[]).map(d=>{const w=oe(e.root,d.coordinate,m,d.privateBinding);return{identity:w.identity,program:ne(w)}});S=await we(f,e.snapshot,e.nativeImplementations,e.directory,i);const v=[...u,...i.map(d=>d.program)];if(new Set(v.map(d=>d.alias)).size!==v.length)throw Error("REFUSE\xB7producer native alias ambiguous");const h=JSON.stringify({endpoint:S.endpoint,parentExecution:m,programs:v});if(Buffer.byteLength(h)>m.responseBytes)throw Error("REFUSE\xB7producer execution context bytes");Z(b,h,{flag:"wx",mode:384}),ee(b,e.contextFile);const c=S;return{assertClosed:a(()=>c.assertClosed(),"assertClosed"),async close(){try{await c.close()}finally{D(e.contextFile,{force:!0}),o=!1}}}}catch(u){throw D(b,{force:!0}),await S?.close(),o=!1,u}}}}a(Te,"createProducerJobCustody");async function Ve(e,o){if(typeof o!="string"||o.length>e.responseBytes||Buffer.byteLength(o)>e.responseBytes)throw Error("REFUSE\xB7producer violation bytes");const m=JSON.stringify({protocol:"command-lot/1",coordinate:e.coordinate,implementation:e.implementation,identity:e.identity,requests:[JSON.stringify({operation:"violation",token:e.token,why:o})]});throw await new Promise((S,b)=>{const u=V(e.socket),f=setTimeout(()=>u.destroy(Error("REFUSE\xB7producer IPC timeout")),Math.max(1,e.deadlineMs-Date.now()));u.once("connect",()=>u.write(m+`
5
+ `)),u.on("data",()=>{}),u.once("error",b),u.once("close",()=>{clearTimeout(f),S()})}),Error("REFUSE\xB7producer pre-entry "+o)}a(Ve,"reportProducerViolation");export{Se as boundedRefusalFrame,Te as createProducerJobCustody,Ve as reportProducerViolation,De as requestNativeProgram,Le as requestProducerEmission,je as requestProducerEmissionBatch,Je as requestProducerEntry,Oe as requestProducerInterpretation,Ie as requestRetainedEvalContext,we as startProducerCustodian};