@lapxo/bound 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/CITATION.cff +1 -1
  2. package/README.md +20 -3
  3. package/TARGET.bound +85 -47
  4. package/dist/cli/accept.js +61 -590
  5. package/dist/cli/act-result.js +3 -103
  6. package/dist/cli/args.js +3 -44
  7. package/dist/cli/custodian.js +2 -29
  8. package/dist/cli/host.js +4 -32
  9. package/dist/cli/names.js +1 -12
  10. package/dist/cli/native-descendant.js +1 -19
  11. package/dist/cli/native.js +3 -60
  12. package/dist/cli/observe.js +1 -13
  13. package/dist/cli/owner.js +3 -139
  14. package/dist/cli/pass.js +22 -321
  15. package/dist/cli/place.js +6 -282
  16. package/dist/cli/release-result.js +3 -80
  17. package/dist/cli/retained-judgment.js +1 -25
  18. package/dist/cli/standing-result.js +4 -19
  19. package/dist/cli/takes.js +10 -112
  20. package/dist/cli/verb.d.ts +1 -2
  21. package/dist/cli/verb.js +85 -684
  22. package/dist/engine/computation.js +2 -0
  23. package/dist/engine/conformance.js +4 -0
  24. package/dist/engine/encoding.js +1 -2
  25. package/dist/engine/index.d.ts +1 -13
  26. package/dist/engine/index.js +2 -11
  27. package/dist/engine/object.js +1 -38
  28. package/dist/engine/ports.js +2 -117
  29. package/dist/fold/admission-history.js +1 -17
  30. package/dist/fold/bootstrap-anchor.js +1 -28
  31. package/dist/fold/ceilings.js +1 -142
  32. package/dist/fold/claims.js +2 -132
  33. package/dist/fold/closed.js +24 -235
  34. package/dist/fold/configures.js +1 -25
  35. package/dist/fold/digests.js +10 -226
  36. package/dist/fold/evidence.js +1 -22
  37. package/dist/fold/fold-worker.js +1 -13
  38. package/dist/fold/kept.js +12 -173
  39. package/dist/fold/keys.js +3 -91
  40. package/dist/fold/laid.js +3 -90
  41. package/dist/fold/nos.js +1 -48
  42. package/dist/fold/object.js +1 -2
  43. package/dist/fold/observed.js +28 -534
  44. package/dist/fold/opened.js +1 -33
  45. package/dist/fold/own.js +3 -217
  46. package/dist/fold/paid.js +1 -92
  47. package/dist/fold/place-inputs.js +1 -70
  48. package/dist/fold/places.js +3 -100
  49. package/dist/fold/rank.js +1 -9
  50. package/dist/fold/reach.js +1 -83
  51. package/dist/fold/readers.js +6 -142
  52. package/dist/fold/receipts.js +1 -47
  53. package/dist/fold/region-declarations.js +1 -13
  54. package/dist/fold/region.js +8 -286
  55. package/dist/fold/release-policy.js +1 -101
  56. package/dist/fold/resolved.js +6 -145
  57. package/dist/fold/roles.js +2 -59
  58. package/dist/fold/second.js +4 -71
  59. package/dist/fold/shards.js +12 -100
  60. package/dist/fold/signed.js +3 -81
  61. package/dist/fold/signers.js +1 -54
  62. package/dist/fold/stranger.js +6 -24
  63. package/dist/fold/views.js +1 -66
  64. package/dist/fold/wire.js +1 -46
  65. package/dist/fold/zoom.js +3 -81
  66. package/dist/host/act-cost.js +1 -25
  67. package/dist/host/adapters/keys/ed25519.js +1 -30
  68. package/dist/host/adapters/modules/javascript.js +1 -50
  69. package/dist/host/adapters/transport/http.js +1 -28
  70. package/dist/host/admitted-place.js +1 -35
  71. package/dist/host/archive.js +1 -152
  72. package/dist/host/call-context.js +1 -14
  73. package/dist/host/capsule-process.js +2 -62
  74. package/dist/host/capsule.js +9 -171
  75. package/dist/host/cell-receipts.js +12 -128
  76. package/dist/host/command-server.js +4 -0
  77. package/dist/host/commit-result.js +1 -5
  78. package/dist/host/content-needed.js +1 -8
  79. package/dist/host/content-store.js +1 -31
  80. package/dist/host/contextual-place.js +2 -72
  81. package/dist/host/digest.js +2 -15
  82. package/dist/host/hash.js +1 -9
  83. package/dist/host/host-controls.js +1 -19
  84. package/dist/host/in-process-act.js +3 -84
  85. package/dist/host/in-process-context.js +3 -91
  86. package/dist/host/in-process-root.js +6 -84
  87. package/dist/host/in-process.js +4 -55
  88. package/dist/host/index.d.ts +1 -15
  89. package/dist/host/index.js +1 -7
  90. package/dist/host/io.js +1 -11
  91. package/dist/host/lifetime.js +1 -79
  92. package/dist/host/located.js +6 -105
  93. package/dist/host/native/authority-card-view.js +5 -0
  94. package/dist/host/native/authority-card.js +1 -0
  95. package/dist/host/native/bounded-file.js +1 -32
  96. package/dist/host/native/command.js +1 -91
  97. package/dist/host/native/control-bridge-worker.js +2 -88
  98. package/dist/host/native/control-bridge.js +1 -110
  99. package/dist/host/native/control-selection.js +1 -32
  100. package/dist/host/native/custody.js +1 -91
  101. package/dist/host/native/deadline.js +1 -28
  102. package/dist/host/native/descendants.js +1 -528
  103. package/dist/host/native/generated-custodian.js +5 -267
  104. package/dist/host/native/generated.js +1 -379
  105. package/dist/host/native/image.js +1 -45
  106. package/dist/host/native/installed-package.d.ts +1 -0
  107. package/dist/host/native/installed-package.js +5 -0
  108. package/dist/host/native/jobs.js +2 -148
  109. package/dist/host/native/loader.js +1 -269
  110. package/dist/host/native/materialize.js +1 -175
  111. package/dist/host/native/module-closure.js +1 -130
  112. package/dist/host/native/module-delivery.d.ts +1 -62
  113. package/dist/host/native/module-delivery.js +1 -151
  114. package/dist/host/native/module-inventory.js +2 -0
  115. package/dist/host/native/module-syntax.js +1 -69
  116. package/dist/host/native/native-binary.js +1 -115
  117. package/dist/host/native/native-program.js +1 -72
  118. package/dist/host/native/node-jobs.js +3 -187
  119. package/dist/host/native/node-launch.js +1 -159
  120. package/dist/host/native/preload.js +1 -45
  121. package/dist/host/native/probes.js +1 -0
  122. package/dist/host/native/reading-witness-admission.js +5 -0
  123. package/dist/host/native/reading.js +1 -249
  124. package/dist/host/native/receipt-environment.js +1 -41
  125. package/dist/host/native/references.js +1 -30
  126. package/dist/host/native/root.js +1 -37
  127. package/dist/host/native/route.js +1 -216
  128. package/dist/host/native/runtime.js +1 -9
  129. package/dist/host/native-place-state.js +1 -0
  130. package/dist/host/native-reader-context.js +1 -8
  131. package/dist/host/native-receiver.js +1 -25
  132. package/dist/host/objects.js +1 -38
  133. package/dist/host/order.js +1 -2
  134. package/dist/host/persistent-host.js +1 -0
  135. package/dist/host/physical-lines.d.ts +1 -0
  136. package/dist/host/physical-lines.js +1 -0
  137. package/dist/host/place-act-transaction.js +4 -78
  138. package/dist/host/place-clock-selection.js +5 -124
  139. package/dist/host/ports/ingress.js +2 -57
  140. package/dist/host/ports/local-act.js +5 -183
  141. package/dist/host/ports/place-act.js +1 -134
  142. package/dist/host/ports/publication.js +1 -56
  143. package/dist/host/ports/signing.js +1 -74
  144. package/dist/host/ports/store.js +1 -18
  145. package/dist/host/ports/transport.js +1 -48
  146. package/dist/host/process-lifetime.js +1 -17
  147. package/dist/host/profile-composition.d.ts +1 -0
  148. package/dist/host/profile-composition.js +2 -0
  149. package/dist/host/provide.js +1 -183
  150. package/dist/host/read-only.js +1 -9
  151. package/dist/host/reading-closures.js +7 -227
  152. package/dist/host/reading-context.js +1 -53
  153. package/dist/host/reading-identity-types.js +0 -0
  154. package/dist/host/reading-identity.js +3 -0
  155. package/dist/host/reading-preparation.js +6 -0
  156. package/dist/host/reference-authenticated.d.ts +1 -40
  157. package/dist/host/reference-authenticated.js +3 -100
  158. package/dist/host/reference-contracts.js +1 -6
  159. package/dist/host/reference-export.js +6 -81
  160. package/dist/host/reference-native-api.d.ts +1 -3
  161. package/dist/host/reference-native-api.js +1 -3
  162. package/dist/host/reference-native.js +1 -74
  163. package/dist/host/reference-profile.js +1 -63
  164. package/dist/host/reference-standing.js +2 -18
  165. package/dist/host/reference.js +1 -24
  166. package/dist/host/refusals.js +2 -43
  167. package/dist/host/release.js +4 -256
  168. package/dist/host/root-clock-source.js +1 -307
  169. package/dist/host/selected-capsules.js +1 -50
  170. package/dist/host/selected-topos.js +1 -80
  171. package/dist/host/signature-era.js +1 -12
  172. package/dist/host/signing.js +2 -48
  173. package/dist/host/source-content.js +2 -111
  174. package/dist/host/standing-carrier.js +1 -18
  175. package/dist/host/standing-projection.js +1 -50
  176. package/dist/host/timing.js +1 -7
  177. package/dist/host/walk.js +20 -193
  178. package/dist/host/work-trace.js +1 -0
  179. package/dist/judge/late.js +1 -33
  180. package/dist/judge/take.js +2 -75
  181. package/dist/judge/widening.js +1 -25
  182. package/dist/land/act.js +8 -336
  183. package/dist/land/alias.js +1 -41
  184. package/dist/land/held.js +1 -23
  185. package/dist/land/inert.js +1 -33
  186. package/dist/land/leaving.js +1 -55
  187. package/dist/land/ledger.js +6 -188
  188. package/dist/land/owned.js +4 -66
  189. package/dist/land/sign.js +1 -53
  190. package/dist/land/standing-pin.js +1 -49
  191. package/dist/land/vouched.js +1 -112
  192. package/dist/land/withdraw.js +1 -24
  193. package/dist/observe/files.js +1 -88
  194. package/dist/observe/identity.js +1 -61
  195. package/dist/observe/match.js +1 -8
  196. package/dist/observe/regions.js +7 -306
  197. package/dist/observe/run.js +1 -41
  198. package/dist/observe/runner.js +4 -101
  199. package/dist/public-types.d.ts +2019 -0
  200. package/dist/render/capsule.js +1 -30
  201. package/dist/render/field.js +1 -40
  202. package/dist/render/names.js +1 -4
  203. package/dist/render/open.js +1 -61
  204. package/dist/render/page.js +1 -7
  205. package/dist/render/receipt-projection.js +1 -0
  206. package/dist/render/receipts.js +1 -47
  207. package/dist/render/shape.js +1 -74
  208. package/dist/render/target.js +4 -52
  209. package/dist/render/view.js +7 -197
  210. package/dist/vendor/bundle.json +1 -0
  211. package/dist/vendor/library14.js +1 -0
  212. package/dist/vendor/object-provider.js +42 -0
  213. package/dist/vendor/runtime.js +61 -0
  214. package/dist/wasm/adapter.d.ts +1 -51
  215. package/dist/wasm/adapter.js +1 -180
  216. package/dist/wasm/node-worker.js +1 -13
  217. package/dist/wasm/object.js +1 -76
  218. package/dist/wasm/worker.js +1 -7
  219. package/docs/contracts/authenticated-reference.publication.json +1 -1
  220. package/docs/contracts/authority-preflight.md +17 -0
  221. package/docs/contracts/authority-preflight.publication.json +25 -0
  222. package/docs/contracts/closure-delivery.md +1 -1
  223. package/docs/contracts/closure-delivery.publication.json +1 -1
  224. package/docs/contracts/conformance.json +142 -0
  225. package/docs/contracts/determinism.bound +9 -0
  226. package/docs/contracts/engine-object-projection.publication.json +1 -1
  227. package/docs/contracts/engine.md +21 -1
  228. package/docs/contracts/installed-package.md +21 -0
  229. package/docs/contracts/installed-package.publication.json +25 -0
  230. package/docs/contracts/materialized-leaf-sequence.md +15 -0
  231. package/docs/contracts/materialized-leaf-sequence.publication.json +25 -0
  232. package/docs/contracts/module-inventory.md +15 -0
  233. package/docs/contracts/module-inventory.publication.json +25 -0
  234. package/docs/contracts/native-host.md +29 -1
  235. package/docs/contracts/native-host.publication.json +4 -4
  236. package/docs/contracts/native-probes.md +13 -0
  237. package/docs/contracts/native-probes.publication.json +25 -0
  238. package/docs/contracts/native-publication.inventory.json +10 -1
  239. package/docs/contracts/native-view-batch.md +17 -0
  240. package/docs/contracts/native-view-batch.publication.json +25 -0
  241. package/docs/contracts/optional-wasm-adapter.publication.json +1 -1
  242. package/docs/contracts/physical-lines.md +19 -0
  243. package/docs/contracts/physical-lines.publication.json +25 -0
  244. package/docs/contracts/profile-composition.md +17 -0
  245. package/docs/contracts/profile-composition.publication.json +25 -0
  246. package/docs/contracts/profile-preparation-native-meaning.md +9 -0
  247. package/docs/contracts/publication.md +12 -0
  248. package/docs/contracts/reading-identity.md +61 -0
  249. package/docs/contracts/reading-identity.publication.json +25 -0
  250. package/docs/contracts/reading-witness-admission.md +49 -0
  251. package/docs/contracts/readme.publication.json +1 -1
  252. package/docs/contracts/reference-port.md +11 -0
  253. package/docs/contracts/reference-port.publication.json +1 -1
  254. package/docs/contracts/refusals.bound +346 -94
  255. package/docs/contracts/refusals.md +119 -39
  256. package/docs/contracts/refusals.publication.json +2 -2
  257. package/docs/contracts/views.md +8 -0
  258. package/docs/reference.md +9 -0
  259. package/licenses/wasm/{fast-text-encoding.txt → NOTICE.txt} +111 -0
  260. package/package.json +84 -34
  261. package/receipts.bound +12952 -10449
  262. package/samples/authority-preflight/no.json +6 -0
  263. package/samples/authority-preflight/yes.json +30 -0
  264. package/samples/engine-alphabet/reader.js +3 -1457
  265. package/samples/engine-alphabet/receipts.bound +7 -7
  266. package/samples/engine-interval/reader.js +3 -1457
  267. package/samples/engine-interval/receipts.bound +7 -7
  268. package/samples/installed-package/consumer.mjs +29 -0
  269. package/samples/installed-package/fixture.json +48 -0
  270. package/samples/installed-package/no.json +10 -0
  271. package/samples/installed-package/yes.json +52 -0
  272. package/samples/materialized-leaf-sequence/no.json +11 -0
  273. package/samples/materialized-leaf-sequence/yes.json +10 -0
  274. package/samples/module-inventory/yes.json +28 -0
  275. package/samples/native/physical-line-reader.mjs +1 -0
  276. package/samples/native/physical-line-reader.source.mjs +13 -0
  277. package/samples/native-host/no.json +6 -1
  278. package/samples/native-host/yes.json +18 -1
  279. package/samples/native-probes/inputs/inspection.json +28 -0
  280. package/samples/native-probes/no.json +7 -0
  281. package/samples/native-probes/yes.json +28 -0
  282. package/samples/native-view-batch/no.json +14 -0
  283. package/samples/native-view-batch/yes.json +10 -0
  284. package/samples/no/engine-order/reader.js +3 -1457
  285. package/samples/no/module-inventory/no.json +10 -0
  286. package/samples/physical-lines/no.json +5 -0
  287. package/samples/physical-lines/yes.json +9 -0
  288. package/samples/profile-composition/no.json +6 -0
  289. package/samples/profile-composition/yes.json +14 -0
  290. package/samples/reading-identity/no.json +26 -0
  291. package/samples/reading-identity/yes.json +69 -0
  292. package/vectors/native/authority-preflight.vector.json +55 -0
  293. package/vectors/native/installed-package.vector.json +31 -0
  294. package/vectors/native/materialized-leaf-sequence.vector.json +31 -0
  295. package/vectors/native/module-inventory.vector.json +56 -0
  296. package/vectors/native/native-host.vector.json +214 -0
  297. package/vectors/native/native-probes.vector.json +31 -0
  298. package/vectors/native/native-view-batch.vector.json +31 -0
  299. package/vectors/native/physical-lines.vector.json +105 -0
  300. package/vectors/native/profile-composition.vector.json +53 -0
  301. package/vectors/native/reading-identity.vector.json +139 -0
  302. package/vectors/native/refusals.vector.json +138 -0
  303. package/vendor/syntax/LICENSE.md +7 -0
  304. package/vendor/syntax/parser.js +1 -0
  305. package/.github/workflows/release.yml +0 -67
  306. package/.github/workflows/test.yml +0 -35
  307. package/dist/engine/object.d.ts +0 -17
  308. package/dist/engine/ports.d.ts +0 -37
  309. package/dist/fold/claims.d.ts +0 -29
  310. package/dist/host/call-context.d.ts +0 -20
  311. package/dist/host/commit-result.d.ts +0 -6
  312. package/dist/host/in-process-act.d.ts +0 -82
  313. package/dist/host/in-process-context.d.ts +0 -46
  314. package/dist/host/in-process-root.d.ts +0 -117
  315. package/dist/host/in-process.d.ts +0 -41
  316. package/dist/host/native/module-closure.d.ts +0 -35
  317. package/dist/host/native-receiver.d.ts +0 -19
  318. package/dist/host/place-act-transaction.d.ts +0 -24
  319. package/dist/host/place-clock-selection.d.ts +0 -55
  320. package/dist/host/ports/local-act.d.ts +0 -44
  321. package/dist/host/ports/place-act.d.ts +0 -49
  322. package/dist/host/ports/publication.d.ts +0 -10
  323. package/dist/host/reference-export.d.ts +0 -33
  324. package/dist/host/reference-native.d.ts +0 -30
  325. package/dist/host/reference-profile.d.ts +0 -23
  326. package/dist/host/refusals.d.ts +0 -14
  327. package/dist/host/root-clock-source.d.ts +0 -86
  328. package/licenses/wasm/jitl-quickjs-ffi-types.txt +0 -21
  329. package/licenses/wasm/jitl-quickjs-wasmfile-release-sync.txt +0 -47
  330. package/licenses/wasm/quickjs-emscripten-core.txt +0 -21
  331. package/licenses/wasm/topos.txt +0 -21
  332. /package/{licenses/wasm/bound.txt → dist/vendor/28cba430228db1c04f446c93f81b09a2705d6bf3e222d35adbe5a4cee4061884.LICENSE} +0 -0
  333. /package/{licenses/wasm/obligations.txt → dist/vendor/7aca161279d14bc0e054dcc281cd110aeb95be2e026b42fdf527a260e58b2aae.LICENSE} +0 -0
@@ -1,379 +1 @@
1
- import { isSha256 } from "../hash.js";
2
- import { sha256 as sha } from "../hash.js";
3
- import { nodeLaunch } from "./node-launch.js";
4
- /** Content producer for a separately Root-authorized finite native program.
5
- * Outputs are provenance, not grants. No arbitrary-JS confinement is claimed. */
6
- import { openSync, fstatSync, readSync, closeSync, realpathSync } from 'node:fs';
7
- import { resolve, dirname, isAbsolute } from 'node:path';
8
- import { fileURLToPath } from 'node:url';
9
- import { builtinModules, createRequire } from 'node:module';
10
- import { moduleImportSyntax } from "./module-syntax.js";
11
- import { authenticateSignedPort, canonicalJson } from "./reading.js";
12
- const fail = (why) => { throw Error('REFUSE·producer ' + why); };
13
- const digest = isSha256;
14
- const contexts = new WeakMap();
15
- function state(handle) { const s = contexts.get(handle); if (!s)
16
- return fail('unknown Root context'); return s; }
17
- function charge(s, work, bytes = 0, members = 0) { if (s.work + work > s.profile.limits.work)
18
- fail('work exhausted'); if (s.bytes + bytes > s.profile.limits.bytes)
19
- fail('derived bytes exhausted'); if (s.members + members > s.profile.limits.members)
20
- fail('derived members exhausted'); s.work += work; s.bytes += bytes; s.members += members; }
21
- /** Call inside the parent's real authority guard BEFORE emission/work. Signature
22
- * and current eligibility are shared with the Root port constructor, unchanged. */
23
- export function createGeneratedProducer(root, coordinate, parent, implementationBytes) {
24
- const auth = authenticateSignedPort(root, coordinate), profile = auth.profile;
25
- if (!profile || Object.keys(profile).sort().join(',') !== 'coordinate,environmentNames,implementation,interpretations,limits,profile,selector' || profile.profile !== 'host-generated-executable@3' || profile.coordinate !== coordinate || Object.keys(profile.limits ?? {}).sort().join(',') !== 'argvBytes,argvItems,bytes,members,work' || Object.values(profile.limits).some(v => !Number.isSafeInteger(v) || v < 0))
26
- fail('capability/budget absent or unknown');
27
- if (!Array.isArray(profile.interpretations) || profile.interpretations.length > 3 || profile.interpretations.some(p => !['node-package-json@1', 'node-ambiguous-javascript@1', 'host-file-emission@1'].includes(p)) || new Set(profile.interpretations).size !== profile.interpretations.length)
28
- fail('interpretation declaration absent/ambiguous');
29
- if (!Array.isArray(profile.environmentNames) || profile.environmentNames.length > profile.limits.argvItems || profile.environmentNames.some(n => typeof n !== 'string' || !n.length || n.length > profile.limits.argvBytes || /[=*\0]/.test(n)) || new Set(profile.environmentNames).size !== profile.environmentNames.length || Buffer.byteLength(canonicalJson(profile.environmentNames)) > profile.limits.argvBytes)
30
- fail('derived environment declaration absent/ambiguous/over budget');
31
- if (Object.keys(profile.selector ?? {}).sort().join(',') !== 'binding,implementation,port' || canonicalJson(profile.selector) !== canonicalJson({ port: parent.port, binding: parent.binding, implementation: parent.implementation }))
32
- fail('producer selector differs from parent');
33
- if (!digest(parent.identity) || !digest(parent.instrument) || !digest(parent.policy) || !digest(parent.authority) || !digest(parent.implementation) || !isAbsolute(parent.cwd) || !isAbsolute(parent.runtime) || !Number.isSafeInteger(parent.timeoutMs) || parent.timeoutMs < 1 || !Number.isSafeInteger(parent.responseBytes) || parent.responseBytes < 1)
34
- fail('parent context unknown');
35
- if (!Array.isArray(parent.argv) || !Array.isArray(parent.inputs) || !Array.isArray(parent.environment) || [parent.argv, parent.inputs, parent.environment].some(a => a.length > root.budget.bytes))
36
- fail('parent metadata budget');
37
- if (profile.limits.bytes > parent.responseBytes || profile.limits.argvBytes > parent.responseBytes || implementationBytes.byteLength > root.budget.bytes)
38
- fail('producer exceeds parent byte resource');
39
- if (sha(implementationBytes) !== profile.implementation)
40
- fail('producer implementation bytes differ');
41
- if (parent.argv.length > profile.limits.argvItems || parent.argv.some(x => typeof x !== 'string' || x.length > profile.limits.argvBytes) || Buffer.byteLength(canonicalJson(parent.argv)) > profile.limits.argvBytes || parent.inputs.some(p => p.length !== 2 || typeof p[0] !== 'string' || !digest(p[1])) || new Set(parent.inputs.map(p => p[0])).size !== parent.inputs.length || parent.environment.some(p => p.length !== 2 || typeof p[0] !== 'string' || typeof p[1] !== 'string') || new Set(parent.environment.map(p => p[0])).size !== parent.environment.length)
42
- fail('parent inputs/argv/environment differ');
43
- const copy = JSON.parse(canonicalJson(parent)), handle = Object.freeze({ identity: sha(canonicalJson([auth.line, copy])) });
44
- contexts.set(handle, { candidates: new Map(), emissionInvocations: new Map(), emissions: new Map(), emissionDigests: new Map(), profile, parent: copy, members: 0, bytes: 0, work: 0, recordBytes: 0, retained: new Map(), executableDigests: new Set(), paths: new Map(), records: new Map(), interpretations: new Map() });
45
- return handle;
46
- }
47
- function checkedInvocation(s, input) { if (input && Array.isArray(input.environment)) {
48
- const unknown = input.environment.filter(p => Array.isArray(p) && typeof p[0] === 'string' && !s.parent.environment.some(q => q[0] === p[0]) && !s.profile.environmentNames.includes(p[0])).map(p => p[0]);
49
- if (unknown.length)
50
- fail('descendant environment undeclared ' + unknown.slice(0, 16).join(','));
51
- } if (input?.runtime !== s.parent.runtime)
52
- fail('descendant runtime differs'); if (!Number.isSafeInteger(input?.timeoutMs) || input.timeoutMs < 1 || input.timeoutMs > s.parent.timeoutMs)
53
- fail('descendant time outside parent'); if (!Number.isSafeInteger(input?.responseBytes) || input.responseBytes < 1 || input.responseBytes > s.parent.responseBytes)
54
- fail('descendant response bytes outside parent'); if (!input || typeof input.cwd !== 'string' || !Array.isArray(input.argv) || !Array.isArray(input.environment) || input.environment.length > s.profile.limits.argvItems || input.argv.some(x => typeof x !== 'string' || x.length > s.profile.limits.argvBytes) || input.environment.some(p => !Array.isArray(p) || p.length !== 2 || p.some(x => typeof x !== 'string' || x.length > s.profile.limits.argvBytes)) || !isAbsolute(input.cwd) || input.runtime !== s.parent.runtime || !Number.isSafeInteger(input.timeoutMs) || input.timeoutMs < 1 || input.timeoutMs > s.parent.timeoutMs || !Number.isSafeInteger(input.responseBytes) || input.responseBytes < 1 || input.responseBytes > s.parent.responseBytes || input.argv.length > s.profile.limits.argvItems || Buffer.byteLength(canonicalJson([input.argv, input.environment])) > s.profile.limits.argvBytes || input.argv.some(x => typeof x !== 'string') || input.environment.some(p => p.length !== 2 || typeof p[0] !== 'string' || typeof p[1] !== 'string') || new Set(input.environment.map(p => p[0])).size !== input.environment.length || input.environment.some(p => !s.parent.environment.some(q => q[0] === p[0]) && !s.profile.environmentNames.includes(p[0])))
55
- fail('descendant invocation context missing/over budget'); return JSON.parse(canonicalJson(input)); }
56
- export function validateDescendantInvocation(handle, input) { return checkedInvocation(state(handle), input); }
57
- export function producerTransport(handle) { const s = state(handle); return Object.freeze({ coordinate: s.profile.coordinate, implementation: s.profile.implementation, identity: handle.identity, parent: s.parent.identity, timeoutMs: s.parent.timeoutMs, responseBytes: Math.min(s.parent.responseBytes, s.profile.limits.argvBytes), limits: { ...s.profile.limits }, interpretations: [...s.profile.interpretations] }); }
58
- function physical(path) { try {
59
- return realpathSync(path);
60
- }
61
- catch {
62
- return fail('member path absent ' + path);
63
- } }
64
- export function readBounded(path, limit) { let fd; try {
65
- fd = openSync(path, 'r');
66
- }
67
- catch {
68
- return fail('executable member absent ' + path);
69
- } try {
70
- const stat = fstatSync(fd);
71
- if (!stat.isFile() || stat.size > limit)
72
- fail('member exceeds remaining bytes ' + path);
73
- const bytes = Buffer.alloc(stat.size), tail = Buffer.alloc(1);
74
- let got = 0;
75
- while (got < bytes.length) {
76
- const n = readSync(fd, bytes, got, bytes.length - got, got);
77
- if (!n)
78
- break;
79
- got += n;
80
- }
81
- if (got !== bytes.length || readSync(fd, tail, 0, 1, bytes.length) !== 0)
82
- fail('member changed during bounded read ' + path);
83
- return bytes;
84
- }
85
- finally {
86
- closeSync(fd);
87
- } }
88
- function remember(s, handle, body) { const serialized = canonicalJson([s.parent.identity, handle.identity, body]), identity = sha(serialized), held = s.records.get(identity); if (held)
89
- return held; const size = Buffer.byteLength(serialized); if (size > s.parent.responseBytes - s.recordBytes)
90
- fail('retained context bytes exhausted'); const record = { kind: 'derived-executable/1', parent: s.parent.identity, producer: handle.identity, ...body, identity: sha(serialized) }; s.recordBytes += size; s.records.set(record.identity, record); return Object.freeze(record); }
91
- export function assertProducerInterpretation(handle, name) { if (!state(handle).profile.interpretations.includes(name))
92
- fail('interpretation not declared ' + name); }
93
- /** Read work is paid each time; retained code bytes and member count are paid
94
- * once by digest. An alias earns no new origin and still needs actual rehash. */
95
- function retainedFile(s, path, executable) {
96
- if (executable && s.members >= s.profile.limits.members && !s.executableDigests.size)
97
- fail('derived members exhausted');
98
- charge(s, 1);
99
- const actual = physical(path), held = s.paths.get(actual), remaining = s.profile.limits.bytes - s.bytes;
100
- // Before allocation, bound verification by an existing retained length or
101
- // the remaining new-content allowance. No unknown-size/read fallback.
102
- const maxRetained = Math.max(0, ...s.retained.values()), bytes = readBounded(actual, held?.bytes ?? Math.max(remaining, maxRetained)), digest = sha(bytes);
103
- charge(s, 1);
104
- if (held && (held.digest !== digest || held.bytes !== bytes.length))
105
- fail('retained executable bytes differ ' + actual);
106
- retainContent(s, digest, bytes.length, executable);
107
- s.paths.set(actual, { digest, bytes: bytes.length });
108
- return { actual, bytes, digest };
109
- }
110
- function retainContent(s, digest, bytes, executable) { const newBytes = s.retained.has(digest) ? 0 : bytes, newMember = executable && !s.executableDigests.has(digest) ? 1 : 0; charge(s, 0, newBytes, newMember); if (!s.retained.has(digest))
111
- s.retained.set(digest, bytes); if (executable)
112
- s.executableDigests.add(digest); }
113
- export function sealGeneratedFile(handle, path, mode, invocation, interpretation) { const s = state(handle); if (interpretation !== undefined) {
114
- if (interpretation !== 'node-ambiguous-javascript@1')
115
- fail('executable interpretation unknown');
116
- assertProducerInterpretation(handle, interpretation);
117
- } if (!isAbsolute(path) || !['module', 'commonjs'].includes(mode))
118
- fail('unknown executable file/mode'); const checked = checkedInvocation(s, invocation), held = retainedFile(s, path, true); return remember(s, handle, { target: { kind: 'file', path: held.actual }, mode, ...(interpretation ? { interpretation } : {}), invocation: checked, digest: held.digest, byteLength: held.bytes.byteLength }); }
119
- /** Preserve the four consumed native eval forms exactly; no rewriting/default
120
- * flags/option blacklist. Prefix is the exact Root-selected inherited preload. */
121
- export function sealNativeEval(handle, actualArgv, rootPrefix, invocation) { const s = state(handle); const checked = checkedInvocation(s, invocation); charge(s, 1); if (actualArgv.length > s.profile.limits.argvItems || Buffer.byteLength(canonicalJson(actualArgv)) > s.profile.limits.argvBytes || actualArgv.some(x => typeof x !== 'string') || rootPrefix.some((x, i) => actualArgv[i] !== x))
122
- fail('eval argv exceeds/changes Root binding'); const argv = actualArgv.slice(rootPrefix.length); const launch = nodeLaunch(argv); if (launch.kind !== 'eval' || launch.imports.length)
123
- return fail('unsupported native eval argv/preload'); const mode = launch.mode, text = launch.text; if (Buffer.from(text, 'utf8').toString('utf8') !== text)
124
- fail('eval text is not scalar UTF-8'); const bytes = Buffer.from(text, 'utf8'); charge(s, 1); retainContent(s, sha(bytes), bytes.length, true); return remember(s, handle, { target: { kind: 'eval', cwd: checked.cwd, argv: [...actualArgv], text }, mode, invocation: checked, digest: sha(bytes), byteLength: bytes.length }); }
125
- /** Interpretive data is provenance, never an executable or an authority grant.
126
- * The finite interpretation is Root-signed before bounded IO/JSON work. */
127
- export function sealInterpretation(handle, path, interpretation, invocation) { const s = state(handle); if (!isAbsolute(path) || !s.profile.interpretations.includes(interpretation) || interpretation !== 'node-package-json@1')
128
- fail('interpretation not declared'); const checked = checkedInvocation(s, invocation); charge(s, 1); const actual = physical(path), bytes = readBounded(actual, Math.max(s.profile.limits.bytes - s.bytes, ...s.retained.values(), 0)); charge(s, 1); const candidate = s.candidates.get(actual); if (candidate?.reason)
129
- fail('required emission unmeasured ' + actual + ' ' + candidate.reason); if (candidate) {
130
- if (candidate.digest !== sha(bytes))
131
- fail('observed emission bytes differ ' + actual);
132
- if (!s.emissionDigests.has(candidate.digest))
133
- recordProducerEmissions(handle, [{ path: actual, digest: candidate.digest }], candidate.invocation);
134
- } let json; try {
135
- json = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
136
- }
137
- catch {
138
- return fail('package interpretation JSON invalid');
139
- } if (!json || typeof json !== 'object' || Array.isArray(json) || ('type' in json && json.type !== 'module' && json.type !== 'commonjs'))
140
- fail('package interpretation type invalid'); retainContent(s, sha(bytes), bytes.byteLength, false); const body = { path: actual, digest: sha(bytes), interpretation, invocation: checked, byteLength: bytes.byteLength }, serialized = canonicalJson([s.parent.identity, handle.identity, body]), identity = sha(serialized), held = s.interpretations.get(identity); if (held)
141
- return held; const size = Buffer.byteLength(serialized); if (size > s.parent.responseBytes - s.recordBytes)
142
- fail('retained context bytes exhausted'); const record = { kind: 'derived-interpretation/1', parent: s.parent.identity, producer: handle.identity, ...body, identity: sha(serialized) }; s.recordBytes += size; s.interpretations.set(record.identity, record); return Object.freeze(record); }
143
- /** Metadata from the fixed observer is only a candidate. No file is opened,
144
- * no emission accepted, and no execution permission follows from registration. */
145
- export function registerProducerCandidates(handle, groups) {
146
- const s = state(handle);
147
- assertProducerInterpretation(handle, 'host-file-emission@1');
148
- if (!Array.isArray(groups))
149
- fail('candidate inventory absent');
150
- const updates = new Map(), invocations = new Map();
151
- let bytes = s.recordBytes, work = 0;
152
- for (const group of groups) {
153
- const call = checkedInvocation(s, group.invocation), text = canonicalJson(call), id = sha(text);
154
- if (!Array.isArray(group.outputs))
155
- fail('candidate outputs absent');
156
- const existing = s.emissionInvocations.get(id) ?? invocations.get(id), invocation = existing ?? Object.freeze(call);
157
- if (!existing) {
158
- bytes += Buffer.byteLength(text);
159
- invocations.set(id, invocation);
160
- }
161
- for (const o of group.outputs) {
162
- if (!o || typeof o.path !== 'string' || !isAbsolute(o.path) || updates.has(o.path) || !((digest(o.digest) && o.reason === undefined) || (o.digest === undefined && typeof o.reason === 'string' && o.reason.length > 0)))
163
- fail('candidate output absent/ambiguous');
164
- const size = Buffer.byteLength(canonicalJson([o.path, o.digest ?? null, o.reason ?? null, id])), prior = s.candidates.get(o.path);
165
- bytes += size - (prior?.size ?? 0);
166
- updates.set(o.path, { path: o.path, ...(o.digest === undefined ? { reason: o.reason } : { digest: o.digest }), invocation, size });
167
- work++;
168
- }
169
- }
170
- if (bytes > s.parent.responseBytes)
171
- fail('retained candidate bytes exhausted');
172
- charge(s, work);
173
- s.recordBytes = bytes;
174
- for (const [id, call] of invocations)
175
- s.emissionInvocations.set(id, call);
176
- for (const [path, row] of updates)
177
- s.candidates.set(path, row);
178
- }
179
- /** Root-selected write observer records output provenance, not execution
180
- * authority. Bytes are bounded/rechecked by the same actual producer custody. */
181
- function emissionRecord(s, handle, actual, digest, byteLength, checked) {
182
- const invocationText = canonicalJson(checked), invocationIdentity = sha(invocationText), existing = s.emissionInvocations.get(invocationIdentity), invocation = existing ?? Object.freeze(checked);
183
- const body = { path: actual, digest, invocationIdentity, byteLength }, serialized = canonicalJson([s.parent.identity, handle.identity, body]), identity = sha(serialized), held = s.emissions.get(actual);
184
- if (held?.identity === identity)
185
- return held;
186
- const size = Buffer.byteLength(serialized) + (existing ? 0 : Buffer.byteLength(invocationText));
187
- if (size > s.parent.responseBytes - s.recordBytes)
188
- fail('retained context bytes exhausted');
189
- const record = Object.freeze({ kind: 'producer-emission/1', parent: s.parent.identity, producer: handle.identity, ...body, invocation, identity });
190
- s.recordBytes += size;
191
- if (!existing)
192
- s.emissionInvocations.set(invocationIdentity, invocation);
193
- s.emissions.set(actual, record);
194
- s.emissionDigests.set(digest, record);
195
- return record;
196
- }
197
- export function recordProducerEmission(handle, path, invocation) {
198
- const s = state(handle);
199
- assertProducerInterpretation(handle, 'host-file-emission@1');
200
- if (!isAbsolute(path))
201
- fail('emission path absent');
202
- const checked = checkedInvocation(s, invocation);
203
- charge(s, 1);
204
- const actual = physical(path), bytes = readBounded(actual, s.parent.responseBytes), digest = sha(bytes);
205
- charge(s, 1);
206
- return emissionRecord(s, handle, actual, digest, bytes.length, checked);
207
- }
208
- /** All observed outputs must match before any provenance is accepted. One
209
- * invocation context is committed once, with no code grant or quota widening. */
210
- export function recordProducerEmissions(handle, outputs, invocation) {
211
- const s = state(handle);
212
- assertProducerInterpretation(handle, 'host-file-emission@1');
213
- const checked = checkedInvocation(s, invocation);
214
- if (!Array.isArray(outputs) || !outputs.length || outputs.some(o => !o || typeof o.path !== 'string' || !isAbsolute(o.path) || !digest(o.digest)) || new Set(outputs.map(o => o.path)).size !== outputs.length)
215
- fail('emission batch absent/ambiguous');
216
- charge(s, 1 + outputs.length * 2);
217
- const verified = outputs.map(o => { const path = physical(o.path), bytes = readBounded(path, s.parent.responseBytes); if (sha(bytes) !== o.digest)
218
- fail('observed emission bytes differ ' + path); return { path, digest: o.digest, bytes: bytes.length }; });
219
- if (new Set(verified.map(o => o.path)).size !== verified.length)
220
- fail('emission batch physical coordinates ambiguous');
221
- // Preflight total retained context resource; transaction has no partial green.
222
- const invocationText = canonicalJson(checked), invocationIdentity = sha(invocationText);
223
- let size = s.emissionInvocations.has(invocationIdentity) ? 0 : Buffer.byteLength(invocationText);
224
- for (const o of verified) {
225
- const body = { path: o.path, digest: o.digest, invocationIdentity, byteLength: o.bytes }, serialized = canonicalJson([s.parent.identity, handle.identity, body]);
226
- if (s.emissions.get(o.path)?.identity !== sha(serialized))
227
- size += Buffer.byteLength(serialized);
228
- }
229
- if (size > s.parent.responseBytes - s.recordBytes)
230
- fail('retained context bytes exhausted');
231
- const records = verified.map(o => emissionRecord(s, handle, o.path, o.digest, o.bytes, checked)), rows = records.map(({ path, digest, identity, byteLength }) => ({ path, digest, identity, byteLength })), body = { kind: 'producer-emission-batch/1', parent: s.parent.identity, producer: handle.identity, invocation: checked, invocationIdentity, outputs: rows };
232
- return { ...body, identity: sha(canonicalJson(body)) };
233
- }
234
- /** Verify the ACTUAL body/argv again before execution. A record's existence
235
- * alone authorizes nothing and cannot be moved to another parent context. */
236
- export function verifyDerived(handle, record, actual) { const s = state(handle); charge(s, 1); const held = s.records.get(record.identity); if (!held || canonicalJson(held) !== canonicalJson(record) || record.parent !== s.parent.identity || record.producer !== handle.identity)
237
- fail('unknown/substituted derived context'); let bytes; if (record.target.kind === 'file') {
238
- if (!actual.path || physical(actual.path) !== record.target.path)
239
- fail('derived target route differs');
240
- bytes = readBounded(record.target.path, record.byteLength);
241
- }
242
- else {
243
- if (!actual.argv || canonicalJson(actual.argv) !== canonicalJson(record.target.argv))
244
- fail('actual eval argv differs');
245
- bytes = Buffer.from(record.target.text, 'utf8');
246
- } if (sha(bytes) !== record.digest || bytes.byteLength !== record.byteLength)
247
- fail('derived executable bytes differ'); return bytes; }
248
- /** Literal closure against Root-sealed targets/libraries BEFORE entry. No
249
- * resolver or verifier is selected by generated code. Unknown computed imports
250
- * or escaped require remain named refusals, not an empty graph. Root's actual
251
- * runtime hook must still verify its resolved target before handing it back. */
252
- /** The descriptor is fixed once per actual producer. Frozen descriptor metadata
253
- * cannot silently change between entries; actual target bytes are never cached. */
254
- function snapshotIndex(s, snapshot, nativeImplementations) {
255
- if (s.index) {
256
- if (s.index.snapshot !== snapshot || nativeImplementations.size !== s.index.nativeImplementations.size || [...nativeImplementations].some(d => !s.index.nativeImplementations.has(d)))
257
- fail('Root snapshot changed within producer');
258
- return s.index;
259
- }
260
- if (!digest(snapshot.platform) || !Number.isSafeInteger(snapshot.budget?.members) || snapshot.budget.members < 1 || !Number.isSafeInteger(snapshot.budget.bytes) || snapshot.budget.bytes < 1 || snapshot.members.length > snapshot.budget.members || snapshot.libraries.length > snapshot.budget.members)
261
- fail('literal snapshot budget/context absent');
262
- const files = new Map(), digests = new Set();
263
- for (const m of snapshot.members) {
264
- charge(s, 1);
265
- if (!digest(m.digest))
266
- fail('Root member digest absent');
267
- const path = physical(m.path);
268
- if (files.has(path))
269
- fail('ambiguous Root member');
270
- files.set(path, m.digest);
271
- digests.add(m.digest);
272
- Object.freeze(m);
273
- }
274
- if ([...nativeImplementations].some(d => !digests.has(d)))
275
- fail('native implementation outside authenticated snapshot');
276
- const libs = new Map();
277
- for (const l of snapshot.libraries) {
278
- charge(s, 1);
279
- if (libs.has(l.name))
280
- fail('ambiguous Root library');
281
- libs.set(l.name, l.manifest);
282
- Object.freeze(l);
283
- }
284
- const native = new Set();
285
- for (const n of snapshot.builtins) {
286
- charge(s, 1);
287
- native.add(n.startsWith('node:') ? n : 'node:' + n);
288
- }
289
- Object.freeze(snapshot.budget);
290
- Object.freeze(snapshot.members);
291
- Object.freeze(snapshot.libraries);
292
- Object.freeze(snapshot.builtins);
293
- Object.freeze(snapshot);
294
- const index = { snapshot, files, digests, libs, native, nativeImplementations: new Set(nativeImplementations), closures: new Map() };
295
- s.index = index;
296
- return index;
297
- }
298
- export function gateDerived(handle, record, actual, snapshot, nativeImplementations = new Set()) {
299
- const s = state(handle), bytes = verifyDerived(handle, record, actual), index = snapshotIndex(s, snapshot, nativeImplementations), { files, digests, libs, native } = index, edges = [], targets = new Map();
300
- const path = record.target.kind === 'file' ? record.target.path : resolve(record.target.cwd, record.mode === 'module' ? '[eval1].js' : '[eval].cjs'), key = canonicalJson([record.digest, path, record.mode]), held = index.closures.get(key);
301
- const readSizes = new Map();
302
- let staticReadBytes = 0;
303
- const verify = (path) => { const real = physical(path), expected = files.get(real); charge(s, 1); const remaining = snapshot.budget.bytes - staticReadBytes + (readSizes.get(real) ?? 0); const bytes = readBounded(real, remaining); if (!readSizes.has(real)) {
304
- staticReadBytes += bytes.length;
305
- readSizes.set(real, bytes.length);
306
- } const actualDigest = sha(bytes); if (expected && actualDigest !== expected)
307
- fail('Root target bytes differ ' + path); if (!expected && !digests.has(actualDigest)) {
308
- let emitted = s.emissionDigests.get(actualDigest);
309
- if (!emitted) {
310
- const candidate = s.candidates.get(real);
311
- if (candidate?.reason)
312
- fail('required emission unmeasured ' + real + ' ' + candidate.reason);
313
- if (candidate) {
314
- if (candidate.digest !== actualDigest)
315
- fail('observed emission bytes differ ' + real);
316
- recordProducerEmissions(handle, [{ path: real, digest: actualDigest }], candidate.invocation);
317
- emitted = s.emissionDigests.get(actualDigest);
318
- }
319
- }
320
- if (!emitted || emitted.parent !== s.parent.identity || emitted.producer !== handle.identity || emitted.byteLength !== bytes.length)
321
- fail('literal target outside Root snapshot or producer emissions ' + path);
322
- retainContent(s, actualDigest, bytes.length, !real.endsWith('.json'));
323
- } targets.set(real, { path: real, digest: actualDigest, bytes: bytes.length }); return { real, bytes, digest: actualDigest }; };
324
- if (held) {
325
- for (const target of held.targets) {
326
- const current = verify(target.path);
327
- if (current.digest !== target.digest || current.bytes.length !== target.bytes)
328
- fail('literal target bytes differ ' + target.path);
329
- }
330
- return held.edges.map(e => ({ ...e }));
331
- }
332
- edges.push(...traverseGeneratedClosure({ source: bytes, path, mode: record.mode, libs, native, platform: snapshot.platform, nativeImplementations, verify, step: () => charge(s, 1) }));
333
- index.closures.set(key, { edges: edges.map(e => Object.freeze({ ...e })), targets: [...targets.values()].map(t => Object.freeze({ ...t })) });
334
- return edges;
335
- }
336
- export function chargeProducerRequest(handle) { charge(state(handle), 1); }
337
- export function producerUsage(handle) { const s = state(handle); return Object.freeze({ members: s.members, bytes: s.bytes, work: s.work, retainedContents: s.retained.size, codeBytes: [...s.executableDigests].reduce((n, d) => n + (s.retained.get(d) ?? 0), 0), limits: { ...s.profile.limits } }); }
338
- /** Shared host traversal. The reader callback supplies verification; traversal
339
- * itself introduces no provenance or execution authority. */
340
- export function traverseGeneratedClosure(input) {
341
- const { libs, native, verify, nativeImplementations } = input, edges = [], seen = new Set();
342
- const walk = (source, path, mode) => { if (seen.has(path))
343
- return; seen.add(path); input.step(); const text = new TextDecoder('utf-8', { fatal: true }).decode(source), syntax = moduleImportSyntax(text, path); if (syntax.unresolved.length)
344
- fail('literal closure unresolved ' + path + ' ' + syntax.unresolved.join(' · ')); for (const specifier of syntax.imports) {
345
- const builtin = specifier.startsWith('node:') ? specifier : 'node:' + specifier;
346
- if (builtinModules.includes(specifier) || specifier.startsWith('node:')) {
347
- if (!native.has(builtin))
348
- fail('native edge undeclared ' + specifier);
349
- edges.push({ target: builtin, platform: input.platform });
350
- continue;
351
- }
352
- let target;
353
- if (specifier.startsWith('file:'))
354
- target = fileURLToPath(specifier);
355
- else if (isAbsolute(specifier))
356
- target = specifier;
357
- else if (specifier.startsWith('.'))
358
- target = mode === 'commonjs' ? createRequire(path).resolve(specifier) : resolve(dirname(path), specifier);
359
- else {
360
- const name = specifier.startsWith('@') ? specifier.split('/').slice(0, 2).join('/') : specifier.split('/')[0], manifest = libs.get(name);
361
- if (!manifest)
362
- fail('literal library absent ' + name);
363
- const pkg = verify(manifest);
364
- const data = JSON.parse(Buffer.from(pkg.bytes).toString('utf8')), key = specifier === name ? '.' : './' + specifier.slice(name.length + 1), exported = typeof data.exports === 'string' && key === '.' ? data.exports : data.exports?.[key];
365
- if (mode === 'commonjs')
366
- target = createRequire(manifest).resolve(specifier);
367
- else if (typeof exported === 'string')
368
- target = resolve(dirname(manifest), exported);
369
- else
370
- return fail('ESM library export needs exact native selection ' + specifier);
371
- }
372
- const member = verify(target);
373
- edges.push({ target: member.real, digest: member.digest });
374
- if (!member.real.endsWith('.json') && !nativeImplementations.has(member.digest))
375
- walk(member.bytes, member.real, mode);
376
- } };
377
- walk(input.source, input.path, input.mode);
378
- return edges;
379
- }
1
+ var X=Object.defineProperty;var l=(t,e)=>X(t,"name",{value:e,configurable:!0});import{isSha256 as Y}from"../hash.js";import{sha256 as p}from"../hash.js";import{nodeLaunch as Z}from"./node-launch.js";import{openSync as _,fstatSync as $,readSync as q,closeSync as ee,realpathSync as te}from"node:fs";import{resolve as F,dirname as C,isAbsolute as M}from"node:path";import{fileURLToPath as ie}from"node:url";import{builtinModules as ne,createRequire as U}from"node:module";import{moduleImportSyntax as se}from"./module-syntax.js";import{authenticateSignedPort as re,canonicalJson as u}from"./reading.js";const a=l(t=>{throw Error("REFUSE\xB7producer "+t)},"fail"),z=Y,G=new WeakMap;function k(t){const e=G.get(t);return e||a("unknown Root context")}l(k,"state");function w(t,e,i=0,s=0){t.work+e>t.profile.limits.work&&a("work exhausted"),t.bytes+i>t.profile.limits.bytes&&a("derived bytes exhausted"),t.members+s>t.profile.limits.members&&a("derived members exhausted"),t.work+=e,t.bytes+=i,t.members+=s}l(w,"charge");function xe(t,e,i,s){const o=re(t,e),n=o.profile;(!n||Object.keys(n).sort().join(",")!=="coordinate,environmentNames,implementation,interpretations,limits,profile,selector"||n.profile!=="host-generated-executable@3"||n.coordinate!==e||Object.keys(n.limits??{}).sort().join(",")!=="argvBytes,argvItems,bytes,members,work"||Object.values(n.limits).some(r=>!Number.isSafeInteger(r)||r<0))&&a("capability/budget absent or unknown"),(!Array.isArray(n.interpretations)||n.interpretations.length>3||n.interpretations.some(r=>!["node-package-json@1","node-ambiguous-javascript@1","host-file-emission@1"].includes(r))||new Set(n.interpretations).size!==n.interpretations.length)&&a("interpretation declaration absent/ambiguous"),(!Array.isArray(n.environmentNames)||n.environmentNames.length>n.limits.argvItems||n.environmentNames.some(r=>typeof r!="string"||!r.length||r.length>n.limits.argvBytes||/[=*\0]/.test(r))||new Set(n.environmentNames).size!==n.environmentNames.length||Buffer.byteLength(u(n.environmentNames))>n.limits.argvBytes)&&a("derived environment declaration absent/ambiguous/over budget"),(Object.keys(n.selector??{}).sort().join(",")!=="binding,implementation,port"||u(n.selector)!==u({port:i.port,binding:i.binding,implementation:i.implementation}))&&a("producer selector differs from parent"),(!z(i.identity)||!z(i.instrument)||!z(i.policy)||!z(i.authority)||!z(i.implementation)||!M(i.cwd)||!M(i.runtime)||!Number.isSafeInteger(i.timeoutMs)||i.timeoutMs<1||!Number.isSafeInteger(i.responseBytes)||i.responseBytes<1)&&a("parent context unknown"),(!Array.isArray(i.argv)||!Array.isArray(i.inputs)||!Array.isArray(i.environment)||[i.argv,i.inputs,i.environment].some(r=>r.length>t.budget.bytes))&&a("parent metadata budget"),(n.limits.bytes>i.responseBytes||n.limits.argvBytes>i.responseBytes||s.byteLength>t.budget.bytes)&&a("producer exceeds parent byte resource"),p(s)!==n.implementation&&a("producer implementation bytes differ"),(i.argv.length>n.limits.argvItems||i.argv.some(r=>typeof r!="string"||r.length>n.limits.argvBytes)||Buffer.byteLength(u(i.argv))>n.limits.argvBytes||i.inputs.some(r=>r.length!==2||typeof r[0]!="string"||!z(r[1]))||new Set(i.inputs.map(r=>r[0])).size!==i.inputs.length||i.environment.some(r=>r.length!==2||typeof r[0]!="string"||typeof r[1]!="string")||new Set(i.environment.map(r=>r[0])).size!==i.environment.length)&&a("parent inputs/argv/environment differ");const f=JSON.parse(u(i)),d=Object.freeze({identity:p(u([o.line,f]))});return G.set(d,{candidates:new Map,emissionInvocations:new Map,emissions:new Map,emissionDigests:new Map,profile:n,parent:f,members:0,bytes:0,work:0,recordBytes:0,retained:new Map,executableDigests:new Set,paths:new Map,records:new Map,interpretations:new Map}),d}l(xe,"createGeneratedProducer");function A(t,e){if(e&&Array.isArray(e.environment)){const i=e.environment.filter(s=>Array.isArray(s)&&typeof s[0]=="string"&&!t.parent.environment.some(o=>o[0]===s[0])&&!t.profile.environmentNames.includes(s[0])).map(s=>s[0]);i.length&&a("descendant environment undeclared "+i.slice(0,16).join(","))}return e?.runtime!==t.parent.runtime&&a("descendant runtime differs"),(!Number.isSafeInteger(e?.timeoutMs)||e.timeoutMs<1||e.timeoutMs>t.parent.timeoutMs)&&a("descendant time outside parent"),(!Number.isSafeInteger(e?.responseBytes)||e.responseBytes<1||e.responseBytes>t.parent.responseBytes)&&a("descendant response bytes outside parent"),(!e||typeof e.cwd!="string"||!Array.isArray(e.argv)||!Array.isArray(e.environment)||e.environment.length>t.profile.limits.argvItems||e.argv.some(i=>typeof i!="string"||i.length>t.profile.limits.argvBytes)||e.environment.some(i=>!Array.isArray(i)||i.length!==2||i.some(s=>typeof s!="string"||s.length>t.profile.limits.argvBytes))||!M(e.cwd)||e.runtime!==t.parent.runtime||!Number.isSafeInteger(e.timeoutMs)||e.timeoutMs<1||e.timeoutMs>t.parent.timeoutMs||!Number.isSafeInteger(e.responseBytes)||e.responseBytes<1||e.responseBytes>t.parent.responseBytes||e.argv.length>t.profile.limits.argvItems||Buffer.byteLength(u([e.argv,e.environment]))>t.profile.limits.argvBytes||e.argv.some(i=>typeof i!="string")||e.environment.some(i=>i.length!==2||typeof i[0]!="string"||typeof i[1]!="string")||new Set(e.environment.map(i=>i[0])).size!==e.environment.length||e.environment.some(i=>!t.parent.environment.some(s=>s[0]===i[0])&&!t.profile.environmentNames.includes(i[0])))&&a("descendant invocation context missing/over budget"),JSON.parse(u(e))}l(A,"checkedInvocation");function Be(t,e){return A(k(t),e)}l(Be,"validateDescendantInvocation");function we(t){const e=k(t);return Object.freeze({coordinate:e.profile.coordinate,implementation:e.profile.implementation,identity:t.identity,parent:e.parent.identity,timeoutMs:e.parent.timeoutMs,responseBytes:Math.min(e.parent.responseBytes,e.profile.limits.argvBytes),limits:{...e.profile.limits},interpretations:[...e.profile.interpretations]})}l(we,"producerTransport");function N(t){try{return te(t)}catch{return a("member path absent "+t)}}l(N,"physical");function W(t,e){let i;try{i=_(t,"r")}catch{return a("executable member absent "+t)}try{const s=$(i);(!s.isFile()||s.size>e)&&a("member exceeds remaining bytes "+t);const o=Buffer.alloc(s.size),n=Buffer.alloc(1);let f=0;for(;f<o.length;){const d=q(i,o,f,o.length-f,f);if(!d)break;f+=d}return(f!==o.length||q(i,n,0,1,o.length)!==0)&&a("member changed during bounded read "+t),o}finally{ee(i)}}l(W,"readBounded");function H(t,e,i){const s=u([t.parent.identity,e.identity,i]),o=p(s),n=t.records.get(o);if(n)return n;const f=Buffer.byteLength(s);f>t.parent.responseBytes-t.recordBytes&&a("retained context bytes exhausted");const d={kind:"derived-executable/1",parent:t.parent.identity,producer:e.identity,...i,identity:p(s)};return t.recordBytes+=f,t.records.set(d.identity,d),Object.freeze(d)}l(H,"remember");function T(t,e){k(t).profile.interpretations.includes(e)||a("interpretation not declared "+e)}l(T,"assertProducerInterpretation");function oe(t,e,i){i&&t.members>=t.profile.limits.members&&!t.executableDigests.size&&a("derived members exhausted"),w(t,1);const s=N(e),o=t.paths.get(s),n=t.profile.limits.bytes-t.bytes,f=Math.max(0,...t.retained.values()),d=W(s,o?.bytes??Math.max(n,f)),r=p(d);return w(t,1),o&&(o.digest!==r||o.bytes!==d.length)&&a("retained executable bytes differ "+s),J(t,r,d.length,i),t.paths.set(s,{digest:r,bytes:d.length}),{actual:s,bytes:d,digest:r}}l(oe,"retainedFile");function J(t,e,i,s){const o=t.retained.has(e)?0:i,n=s&&!t.executableDigests.has(e)?1:0;w(t,0,o,n),t.retained.has(e)||t.retained.set(e,i),s&&t.executableDigests.add(e)}l(J,"retainContent");function ke(t,e,i,s,o){const n=k(t);o!==void 0&&(o!=="node-ambiguous-javascript@1"&&a("executable interpretation unknown"),T(t,o)),(!M(e)||!["module","commonjs"].includes(i))&&a("unknown executable file/mode");const f=A(n,s),d=oe(n,e,!0);return H(n,t,{target:{kind:"file",path:d.actual},mode:i,...o?{interpretation:o}:{},invocation:f,digest:d.digest,byteLength:d.bytes.byteLength})}l(ke,"sealGeneratedFile");function je(t,e,i,s){const o=k(t),n=A(o,s);w(o,1),(e.length>o.profile.limits.argvItems||Buffer.byteLength(u(e))>o.profile.limits.argvBytes||e.some(v=>typeof v!="string")||i.some((v,m)=>e[m]!==v))&&a("eval argv exceeds/changes Root binding");const f=e.slice(i.length),d=Z(f);if(d.kind!=="eval"||d.imports.length)return a("unsupported native eval argv/preload");const r=d.mode,g=d.text;Buffer.from(g,"utf8").toString("utf8")!==g&&a("eval text is not scalar UTF-8");const y=Buffer.from(g,"utf8");return w(o,1),J(o,p(y),y.length,!0),H(o,t,{target:{kind:"eval",cwd:n.cwd,argv:[...e],text:g},mode:r,invocation:n,digest:p(y),byteLength:y.length})}l(je,"sealNativeEval");function ze(t,e,i,s){const o=k(t);(!M(e)||!o.profile.interpretations.includes(i)||i!=="node-package-json@1")&&a("interpretation not declared");const n=A(o,s);w(o,1);const f=N(e),d=W(f,Math.max(o.profile.limits.bytes-o.bytes,...o.retained.values(),0));w(o,1);const r=o.candidates.get(f);r?.reason&&a("required emission unmeasured "+f+" "+r.reason),r&&(r.digest!==p(d)&&a("observed emission bytes differ "+f),o.emissionDigests.has(r.digest)||Q(t,[{path:f,digest:r.digest}],r.invocation));let g;try{g=JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(d))}catch{return a("package interpretation JSON invalid")}(!g||typeof g!="object"||Array.isArray(g)||"type"in g&&g.type!=="module"&&g.type!=="commonjs")&&a("package interpretation type invalid"),J(o,p(d),d.byteLength,!1);const y={path:f,digest:p(d),interpretation:i,invocation:n,byteLength:d.byteLength},v=u([o.parent.identity,t.identity,y]),m=p(v),c=o.interpretations.get(m);if(c)return c;const b=Buffer.byteLength(v);b>o.parent.responseBytes-o.recordBytes&&a("retained context bytes exhausted");const h={kind:"derived-interpretation/1",parent:o.parent.identity,producer:t.identity,...y,identity:p(v)};return o.recordBytes+=b,o.interpretations.set(h.identity,h),Object.freeze(h)}l(ze,"sealInterpretation");function Se(t,e){const i=k(t);T(t,"host-file-emission@1"),Array.isArray(e)||a("candidate inventory absent");const s=new Map,o=new Map;let n=i.recordBytes,f=0;for(const d of e){const r=A(i,d.invocation),g=u(r),y=p(g);Array.isArray(d.outputs)||a("candidate outputs absent");const v=i.emissionInvocations.get(y)??o.get(y),m=v??Object.freeze(r);v||(n+=Buffer.byteLength(g),o.set(y,m));for(const c of d.outputs){(!c||typeof c.path!="string"||!M(c.path)||s.has(c.path)||!(z(c.digest)&&c.reason===void 0||c.digest===void 0&&typeof c.reason=="string"&&c.reason.length>0))&&a("candidate output absent/ambiguous");const b=Buffer.byteLength(u([c.path,c.digest??null,c.reason??null,y])),h=i.candidates.get(c.path);n+=b-(h?.size??0),s.set(c.path,{path:c.path,...c.digest===void 0?{reason:c.reason}:{digest:c.digest},invocation:m,size:b}),f++}}n>i.parent.responseBytes&&a("retained candidate bytes exhausted"),w(i,f),i.recordBytes=n;for(const[d,r]of o)i.emissionInvocations.set(d,r);for(const[d,r]of s)i.candidates.set(d,r)}l(Se,"registerProducerCandidates");function K(t,e,i,s,o,n){const f=u(n),d=p(f),r=t.emissionInvocations.get(d),g=r??Object.freeze(n),y={path:i,digest:s,invocationIdentity:d,byteLength:o},v=u([t.parent.identity,e.identity,y]),m=p(v),c=t.emissions.get(i);if(c?.identity===m)return c;const b=Buffer.byteLength(v)+(r?0:Buffer.byteLength(f));b>t.parent.responseBytes-t.recordBytes&&a("retained context bytes exhausted");const h=Object.freeze({kind:"producer-emission/1",parent:t.parent.identity,producer:e.identity,...y,invocation:g,identity:m});return t.recordBytes+=b,r||t.emissionInvocations.set(d,g),t.emissions.set(i,h),t.emissionDigests.set(s,h),h}l(K,"emissionRecord");function Me(t,e,i){const s=k(t);T(t,"host-file-emission@1"),M(e)||a("emission path absent");const o=A(s,i);w(s,1);const n=N(e),f=W(n,s.parent.responseBytes),d=p(f);return w(s,1),K(s,t,n,d,f.length,o)}l(Me,"recordProducerEmission");function Q(t,e,i){const s=k(t);T(t,"host-file-emission@1");const o=A(s,i);(!Array.isArray(e)||!e.length||e.some(m=>!m||typeof m.path!="string"||!M(m.path)||!z(m.digest))||new Set(e.map(m=>m.path)).size!==e.length)&&a("emission batch absent/ambiguous"),w(s,1+e.length*2);const n=e.map(m=>{const c=N(m.path),b=W(c,s.parent.responseBytes);return p(b)!==m.digest&&a("observed emission bytes differ "+c),{path:c,digest:m.digest,bytes:b.length}});new Set(n.map(m=>m.path)).size!==n.length&&a("emission batch physical coordinates ambiguous");const f=u(o),d=p(f);let r=s.emissionInvocations.has(d)?0:Buffer.byteLength(f);for(const m of n){const c={path:m.path,digest:m.digest,invocationIdentity:d,byteLength:m.bytes},b=u([s.parent.identity,t.identity,c]);s.emissions.get(m.path)?.identity!==p(b)&&(r+=Buffer.byteLength(b))}r>s.parent.responseBytes-s.recordBytes&&a("retained context bytes exhausted");const g=n.map(m=>K(s,t,m.path,m.digest,m.bytes,o)),y=g.map(({path:m,digest:c,identity:b,byteLength:h})=>({path:m,digest:c,identity:b,byteLength:h})),v={kind:"producer-emission-batch/1",parent:s.parent.identity,producer:t.identity,invocation:o,invocationIdentity:d,outputs:y};return{...v,identity:p(u(v))}}l(Q,"recordProducerEmissions");function ae(t,e,i){const s=k(t);w(s,1);const o=s.records.get(e.identity);(!o||u(o)!==u(e)||e.parent!==s.parent.identity||e.producer!==t.identity)&&a("unknown/substituted derived context");let n;return e.target.kind==="file"?((!i.path||N(i.path)!==e.target.path)&&a("derived target route differs"),n=W(e.target.path,e.byteLength)):((!i.argv||u(i.argv)!==u(e.target.argv))&&a("actual eval argv differs"),n=Buffer.from(e.target.text,"utf8")),(p(n)!==e.digest||n.byteLength!==e.byteLength)&&a("derived executable bytes differ"),n}l(ae,"verifyDerived");function de(t,e,i){if(t.index)return(t.index.snapshot!==e||i.size!==t.index.nativeImplementations.size||[...i].some(r=>!t.index.nativeImplementations.has(r)))&&a("Root snapshot changed within producer"),t.index;(!z(e.platform)||!Number.isSafeInteger(e.budget?.members)||e.budget.members<1||!Number.isSafeInteger(e.budget.bytes)||e.budget.bytes<1||e.members.length>e.budget.members||e.libraries.length>e.budget.members)&&a("literal snapshot budget/context absent");const s=new Map,o=new Set;for(const r of e.members){w(t,1),z(r.digest)||a("Root member digest absent");const g=N(r.path);s.has(g)&&a("ambiguous Root member"),s.set(g,r.digest),o.add(r.digest),Object.freeze(r)}[...i].some(r=>!o.has(r))&&a("native implementation outside authenticated snapshot");const n=new Map;for(const r of e.libraries)w(t,1),n.has(r.name)&&a("ambiguous Root library"),n.set(r.name,r.manifest),Object.freeze(r);const f=new Set;for(const r of e.builtins)w(t,1),f.add(r.startsWith("node:")?r:"node:"+r);Object.freeze(e.budget),Object.freeze(e.members),Object.freeze(e.libraries),Object.freeze(e.builtins),Object.freeze(e);const d={snapshot:e,files:s,digests:o,libs:n,native:f,nativeImplementations:new Set(i),closures:new Map};return t.index=d,d}l(de,"snapshotIndex");function Ie(t,e,i,s,o=new Set){const n=k(t),f=ae(t,e,i),d=de(n,s,o),{files:r,digests:g,libs:y,native:v}=d,m=[],c=new Map,b=e.target.kind==="file"?e.target.path:F(e.target.cwd,e.mode==="module"?"[eval1].js":"[eval].cjs"),h=u([e.digest,b,e.mode]),j=d.closures.get(h),I=new Map;let L=0;const P=l(B=>{const x=N(B),D=r.get(x);w(n,1);const V=s.budget.bytes-L+(I.get(x)??0),O=W(x,V);I.has(x)||(L+=O.length,I.set(x,O.length));const S=p(O);if(D&&S!==D&&a("Root target bytes differ "+B),!D&&!g.has(S)){let R=n.emissionDigests.get(S);if(!R){const E=n.candidates.get(x);E?.reason&&a("required emission unmeasured "+x+" "+E.reason),E&&(E.digest!==S&&a("observed emission bytes differ "+x),Q(t,[{path:x,digest:S}],E.invocation),R=n.emissionDigests.get(S))}(!R||R.parent!==n.parent.identity||R.producer!==t.identity||R.byteLength!==O.length)&&a("literal target outside Root snapshot or producer emissions "+B),J(n,S,O.length,!x.endsWith(".json"))}return c.set(x,{path:x,digest:S,bytes:O.length}),{real:x,bytes:O,digest:S}},"verify");if(j){for(const B of j.targets){const x=P(B.path);(x.digest!==B.digest||x.bytes.length!==B.bytes)&&a("literal target bytes differ "+B.path)}return j.edges.map(B=>({...B}))}return m.push(...ce({source:f,path:b,mode:e.mode,libs:y,native:v,platform:s.platform,nativeImplementations:o,verify:P,step:l(()=>w(n,1),"step")})),d.closures.set(h,{edges:m.map(B=>Object.freeze({...B})),targets:[...c.values()].map(B=>Object.freeze({...B}))}),m}l(Ie,"gateDerived");function Le(t){w(k(t),1)}l(Le,"chargeProducerRequest");function Oe(t){const e=k(t);return Object.freeze({members:e.members,bytes:e.bytes,work:e.work,retainedContents:e.retained.size,codeBytes:[...e.executableDigests].reduce((i,s)=>i+(e.retained.get(s)??0),0),limits:{...e.profile.limits}})}l(Oe,"producerUsage");function ce(t){const{libs:e,native:i,verify:s,nativeImplementations:o}=t,n=[],f=new Set,d=l((r,g,y)=>{if(f.has(g))return;f.add(g),t.step();const v=new TextDecoder("utf-8",{fatal:!0}).decode(r),m=se(v,g);m.unresolved.length&&a("literal closure unresolved "+g+" "+m.unresolved.join(" \xB7 "));for(const c of m.imports){const b=c.startsWith("node:")?c:"node:"+c;if(ne.includes(c)||c.startsWith("node:")){i.has(b)||a("native edge undeclared "+c),n.push({target:b,platform:t.platform});continue}let h;if(c.startsWith("file:"))h=ie(c);else if(M(c))h=c;else if(c.startsWith("."))h=y==="commonjs"?U(g).resolve(c):F(C(g),c);else{const I=c.startsWith("@")?c.split("/").slice(0,2).join("/"):c.split("/")[0],L=e.get(I);L||a("literal library absent "+I);const P=s(L),B=JSON.parse(Buffer.from(P.bytes).toString("utf8")),x=c===I?".":"./"+c.slice(I.length+1),D=typeof B.exports=="string"&&x==="."?B.exports:B.exports?.[x];if(y==="commonjs")h=U(L).resolve(c);else if(typeof D=="string")h=F(C(L),D);else return a("ESM library export needs exact native selection "+c)}const j=s(h);n.push({target:j.real,digest:j.digest}),!j.real.endsWith(".json")&&!o.has(j.digest)&&d(j.bytes,j.real,y)}},"walk");return d(t.source,t.path,t.mode),n}l(ce,"traverseGeneratedClosure");export{T as assertProducerInterpretation,Le as chargeProducerRequest,xe as createGeneratedProducer,Ie as gateDerived,we as producerTransport,Oe as producerUsage,W as readBounded,Me as recordProducerEmission,Q as recordProducerEmissions,Se as registerProducerCandidates,ke as sealGeneratedFile,ze as sealInterpretation,je as sealNativeEval,ce as traverseGeneratedClosure,Be as validateDescendantInvocation,ae as verifyDerived};
@@ -1,45 +1 @@
1
- import { sha256 as digest } from "../hash.js";
2
- import { isAbsolute } from 'node:path';
3
- import { realpathSync } from 'node:fs';
4
- import { release } from 'node:os';
5
- import { readBoundedBatch } from "./bounded-file.js";
6
- const fail = (why) => { throw Error('REFUSE·native image ' + why); };
7
- const coordinate = (name) => typeof name === 'string' && name !== '' && !isAbsolute(name) && !name.includes('\0') && !name.includes('\\') && !name.split('/').some(step => !step || step === '.' || step === '..');
8
- /** Identifies the admitted Node/OS ABI condition, not a seal of backing libraries
9
- * or portability proof. The signed image must explicitly name this condition.
10
- */
11
- export const nodePlatformIdentity = () => digest(JSON.stringify(['node-abi/1', process.platform, process.arch, process.versions, release()]));
12
- /** Mount only signed logical references at exact bytes. Physical locations are
13
- * an execution envelope and never a source of implementation identity.
14
- */
15
- export function mountNativeImage(loader, mounts, entry, budget) {
16
- if (!budget || !Number.isSafeInteger(budget.members) || budget.members < 1 || !Number.isSafeInteger(budget.bytes) || budget.bytes < 1)
17
- fail('missing input resources');
18
- if (!loader || !Array.isArray(loader.members) || !Array.isArray(loader.libraries) || !Array.isArray(loader.builtins) || !Array.isArray(loader.entries) || loader.members.length > budget.members || mounts.length !== loader.members.length || loader.libraries.length > budget.members || loader.builtins.length > budget.members || loader.entries.length > budget.members)
19
- fail('input member resources');
20
- if (loader.platform !== nodePlatformIdentity())
21
- fail('declared Node platform differs');
22
- const named = new Map();
23
- let total = 0;
24
- for (const member of loader.members) {
25
- if (!member || !coordinate(member.coordinate) || named.has(member.coordinate) || !/^sha256:[0-9a-f]{64}$/.test(member.digest) || !Number.isSafeInteger(member.bytes) || member.bytes < 0 || (total += member.bytes) > budget.bytes)
26
- fail('missing/duplicate/oversized member');
27
- named.set(member.coordinate, member);
28
- }
29
- const paths = new Map();
30
- for (const mount of mounts) {
31
- if (!coordinate(mount.coordinate) || !named.has(mount.coordinate) || paths.has(mount.coordinate) || !isAbsolute(mount.path))
32
- fail('unhanded or ambiguous mount');
33
- paths.set(mount.coordinate, realpathSync(mount.path));
34
- }
35
- if (!coordinate(entry) || !loader.entries.includes(entry) || new Set(loader.entries).size !== loader.entries.length || loader.entries.some(e => !named.has(e)))
36
- fail('entry outside signed image');
37
- const data = readBoundedBatch(loader.members.map(m => ({ path: paths.get(m.coordinate), coordinate: m.coordinate })), budget.bytes);
38
- loader.members.forEach((member, index) => { if (data[index].length !== member.bytes || digest(data[index]) !== member.digest)
39
- fail('actual bytes differ ' + member.coordinate); });
40
- const declarations = new Set();
41
- const libraries = loader.libraries.map(lib => { if (!lib || typeof lib.name !== 'string' || declarations.has(lib.name) || !named.has(lib.manifest))
42
- return fail('unknown or duplicate library'); declarations.add(lib.name); return { name: lib.name, manifest: paths.get(lib.manifest), coordinate: lib.manifest }; });
43
- const identity = digest(JSON.stringify(['logical-native-image/1', loader]));
44
- return { identity, declaration: { members: loader.members.map(m => ({ path: paths.get(m.coordinate), digest: m.digest, bytes: m.bytes })), libraries, builtins: [...loader.builtins], entry: paths.get(entry), platform: loader.platform }, entries: loader.entries.map(e => paths.get(e)) };
45
- }
1
+ var d=Object.defineProperty;var o=(t,i)=>d(t,"name",{value:i,configurable:!0});import{sha256 as c}from"../hash.js";import{isAbsolute as b}from"node:path";import{realpathSync as l}from"node:fs";import{release as A}from"node:os";import{readBoundedBatch as S}from"./bounded-file.js";const r=o(t=>{throw Error("REFUSE\xB7native image "+t)},"fail"),f=o(t=>typeof t=="string"&&t!==""&&!b(t)&&!t.includes("\0")&&!t.includes("\\")&&!t.split("/").some(i=>!i||i==="."||i===".."),"coordinate"),N=o(()=>c(JSON.stringify(["node-abi/1",process.platform,process.arch,process.versions,A()])),"nodePlatformIdentity");function M(t,i,m,s){(!s||!Number.isSafeInteger(s.members)||s.members<1||!Number.isSafeInteger(s.bytes)||s.bytes<1)&&r("missing input resources"),(!t||!Array.isArray(t.members)||!Array.isArray(t.libraries)||!Array.isArray(t.builtins)||!Array.isArray(t.entries)||t.members.length>s.members||i.length!==t.members.length||t.libraries.length>s.members||t.builtins.length>s.members||t.entries.length>s.members)&&r("input member resources"),t.platform!==N()&&r("declared Node platform differs");const a=new Map;let g=0;for(const e of t.members)(!e||!f(e.coordinate)||a.has(e.coordinate)||!/^sha256:[0-9a-f]{64}$/.test(e.digest)||!Number.isSafeInteger(e.bytes)||e.bytes<0||(g+=e.bytes)>s.bytes)&&r("missing/duplicate/oversized member"),a.set(e.coordinate,e);const n=new Map;for(const e of i)(!f(e.coordinate)||!a.has(e.coordinate)||n.has(e.coordinate)||!b(e.path))&&r("unhanded or ambiguous mount"),n.set(e.coordinate,l(e.path));(!f(m)||!t.entries.includes(m)||new Set(t.entries).size!==t.entries.length||t.entries.some(e=>!a.has(e)))&&r("entry outside signed image");const p=S(t.members.map(e=>({path:n.get(e.coordinate),coordinate:e.coordinate})),s.bytes);t.members.forEach((e,h)=>{(p[h].length!==e.bytes||c(p[h])!==e.digest)&&r("actual bytes differ "+e.coordinate)});const y=new Set,u=t.libraries.map(e=>!e||typeof e.name!="string"||y.has(e.name)||!a.has(e.manifest)?r("unknown or duplicate library"):(y.add(e.name),{name:e.name,manifest:n.get(e.manifest),coordinate:e.manifest}));return{identity:c(JSON.stringify(["logical-native-image/1",t])),declaration:{members:t.members.map(e=>({path:n.get(e.coordinate),digest:e.digest,bytes:e.bytes})),libraries:u,builtins:[...t.builtins],entry:n.get(m),platform:t.platform},entries:t.entries.map(e=>n.get(e))}}o(M,"mountNativeImage");export{M as mountNativeImage,N as nodePlatformIdentity};
@@ -0,0 +1 @@
1
+ export {public3_InstalledPackageMember as InstalledPackageMember,public3_InstalledPackagePin as InstalledPackagePin,public3_InstalledPackageRequest as InstalledPackageRequest,public3_installedPackageIdentity as installedPackageIdentity} from "../../public-types.js";
@@ -0,0 +1,5 @@
1
+ var G=Object.defineProperty;var h=(n,i)=>G(n,"name",{value:i,configurable:!0});import{lstatSync as I,readdirSync as H,realpathSync as F}from"node:fs";import{join as Q,posix as V,relative as P,sep as T,isAbsolute as X}from"node:path";import{library14_canonical as Y}from"../../vendor/runtime.js";import{library5_moduleInventory as Z,library5_inventoryBytes as $}from"../../vendor/runtime.js";import{archiveCoordinate as O}from"../archive.js";import{sha256 as l,isSha256 as _}from"../hash.js";import{compareStrings as A}from"../order.js";import{BoundRefusal as q,refuseBound as s}from"../refusals.js";import{readBoundedFile as ee}from"./bounded-file.js";import{deliverModuleClosure as te}from"./module-delivery.js";import{moduleInventory as se}from"./module-inventory.js";function ue(n){const{limits:i}=n;(!i||!Number.isSafeInteger(i.members)||i.members<1||!Number.isSafeInteger(i.bytes)||i.bytes<1||!Number.isSafeInteger(i.responseBytes)||i.responseBytes<1)&&s("installed/resources"),i.signal?.aborted&&s("installed/cancelled"),(!Array.isArray(n.members)||!n.members.length||n.members.length>i.members||!Array.isArray(n.exports)||!n.exports.length||n.exports.length>i.members||!Array.isArray(n.pins)||n.pins.length>i.members)&&s("installed/resources");const g=new Map;for(const e of n.members)(O(e.coordinate)!==e.coordinate||!_(e.digest)||g.has(e.coordinate))&&s("installed/inventory"),g.set(e.coordinate,e.digest);let b;try{(!I(n.directory).isDirectory()||I(n.directory).isSymbolicLink())&&s("installed/external-member"),b=F(n.directory)}catch(e){if(e instanceof q)throw e;return s("installed/missing-member")}const f=new Map;let v=0,z=0;function N(e){for(const t of H(e).sort(A)){i.signal?.aborted&&s("installed/cancelled"),++z>i.members*2&&s("installed/resources");const r=Q(e,t),a=P(b,r).split(T).join("/"),c=I(r);(c.isSymbolicLink()||!c.isDirectory()&&!c.isFile())&&s("installed/external-member");const M=P(b,F(r));if((X(M)||M===".."||M.startsWith(".."+T))&&s("installed/external-member"),c.isDirectory()){N(r);continue}const C=g.get(a);C===void 0&&s("installed/uninventoried-member");const j=ee(r,i.bytes-v,a);v+=j.length,l(j)!==C&&s("installed/member-integrity"),f.set(a,j)}}h(N,"walk"),N(b),f.size!==g.size&&s("installed/missing-member");const D=O(n.shape+".json"),y=f.get(D);y||s("installed/manifest");let o;try{o=JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(y))}catch{return s("installed/manifest")}(!o||typeof o.name!="string"||!o.name||typeof o.version!="string"||!o.version||o.type!=="module")&&s("installed/manifest");const m=h((e,t,r={})=>Y({scope:e,role:"writes",form:"alphabet",measure:"digest",value:t,by:"target",at:"place:installed-package",...r}),"line"),J=[...f].sort(([e],[t])=>A(e,t)).map(([e,t])=>m("file/"+e,l(t))),R=J.join(`
2
+ `)+`
3
+ `,d=l(R),u=l(y),W=new Map([...f].filter(([e])=>[".js",".mjs",".cjs",".ts",".json"].includes(V.extname(e))).map(([e,t])=>{let r;try{r=new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(t)}catch{return s("installed/text-member")}return[e,{source:r,digest:l(t)}]})),K=new Map([[u,y]]),x=new Map,U=n.exports.map(e=>{let t=o;e[0]!=="exports"&&s("installed/export");for(const c of e)(!t||typeof t!="object"||Array.isArray(t)||!Object.prototype.hasOwnProperty.call(t,c))&&s("installed/export"),t=t[c];(typeof t!="string"||!t.startsWith("./"))&&s("installed/export");const r=O(t.slice(2)),a=f.get(r);return a||s("installed/missing-member"),x.set(JSON.stringify(e),{identity:d,entry:r,members:W}),{source:o.name,version:o.version,holder:"installed-package",unitKind:"module",unit:r,reached:!0,reachedFrom:{digest:u,selector:e},moduleBytes:a}}),L=Z(U,{documents:K,digestBytes:l}),S=new Map;for(const e of n.pins){const t=JSON.stringify([e.parent==="self"?d:e.parent,e.specifier]);(S.has(t)||!_(e.snapshot)||e.module.identity!==e.snapshot)&&s("installed/pin"),S.set(t,e)}const w=new Map,p=te([...x.keys()],x,(e,t)=>{const r=JSON.stringify([t.identity,e]),a=S.get(r);return a&&w.set(r,a),a?.module},i,[{snapshot:d,coordinate:D,digest:u,source:new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(y)}]),k=new Map([[d,{snapshot:d,source:o.name,version:o.version}]]);for(const e of w.values()){const t=k.get(e.snapshot);t&&(t.source!==e.source||t.version!==e.version)&&s("installed/pin"),k.set(e.snapshot,{snapshot:e.snapshot,source:e.source,version:e.version})}const E=se(p.bytes,p.digest,i,[...k.values()],{scope:"installed/modules",by:"target",at:"place:installed-package"}),B=[m("installed/profile","bound-installed-package@1",{measure:"id"}),m("installed/manifest",u,{about:JSON.stringify([n.shape,o.name,o.version])}),...J,m("installed/exports",l($(L))),m("installed/closure",p.closure),m("installed/delivery",p.digest),...p.manifest.libraries.map(e=>m("installed/pins/"+encodeURIComponent(JSON.stringify([e.parent==="self"?d:e.parent,e.specifier])),e.snapshot,{about:e.entry}))].sort(A).join(`
4
+ `)+`
5
+ `;return Buffer.byteLength(B)>i.responseBytes&&s("installed/resources"),{format:"bound-installed-package/1",digest:l(B),lines:B,snapshot:d,manifest:u,members:n.members.length,bytes:v,exportInventory:L,modules:E,delivery:p,consumedPins:[...w.values()].map(({module:e,...t})=>t)}}h(ue,"installedPackageIdentity");export{ue as installedPackageIdentity};