@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,172 +1,5 @@
1
- import { hashText } from "../hash.js";
2
- import { existsSync, readFileSync, readdirSync } from 'node:fs';
3
- import { join } from 'node:path';
4
- import { createHash } from 'node:crypto';
5
- import { requireEffects } from "../read-only.js";
6
- import { underTheRegions } from "../../land/act.js";
7
- import { publishBundle, nativePublicationStorage } from "./publication.js";
8
- import { actIdentity, parse, canonical } from '@lapxo/topos/wire';
9
- import { fullDigest } from "../digest.js";
10
- const atOf = (store, identity) => {
11
- if (!identity || identity.includes('\0'))
12
- throw Error('REFUSE·act missing identity');
13
- return join(store, 'ledger', 'acts', 'committed-' + encodeURIComponent(identity));
14
- };
15
- const read = (at) => {
16
- try {
17
- const placements = readdirSync(at).filter(name => name.startsWith('place-') && name.endsWith('.bound')).map(name => ({
18
- place: decodeURIComponent(name.slice(6, -6)), records: readFileSync(join(at, name), 'utf8'),
19
- }));
20
- return {
21
- records: readFileSync(join(at, 'records.bound'), 'utf8'),
22
- receipt: readFileSync(join(at, 'receipt.bound'), 'utf8'),
23
- ...(placements.length ? { placements } : {}),
24
- };
25
- }
26
- catch (error) {
27
- throw Error(`REFUSE·act committed result unreadable · ${error.code ?? 'read failed'}`);
28
- }
29
- };
30
- export const actLines = (bytes) => {
31
- if (!bytes.endsWith('\n'))
32
- throw Error('REFUSE·act truncated committed lines');
33
- return bytes.slice(0, -1).split('\n');
34
- };
35
- /** Journal integrity is not authority. Signature/coverage checks remain the
36
- * same admission boundary; the hash algorithm here is the stored seal's named
37
- * algorithm, not a new selection of the place's wire.
38
- */
39
- export function intactLocalAct(identity, bundle) {
40
- if (!bundle.receipt.endsWith('\n') || bundle.receipt.slice(0, -1).includes('\n'))
41
- return false;
42
- const receipt = parse(bundle.receipt.slice(0, -1));
43
- if (receipt.kind !== 'fact' || !bundle.placements?.length)
44
- return false;
45
- const f = receipt.value.fields;
46
- if (canonical(f) !== bundle.receipt.slice(0, -1) || !/^(0|[1-9][0-9]*)$/.test(f['epoch'] ?? ''))
47
- return false;
48
- if (f['value'] !== identity || f['role'] !== 'writes' || f['form'] !== 'alphabet' || f['measure'] !== 'digest')
49
- return false;
50
- return actIdentity(actLines(bundle.records), { scope: f['scope'] ?? '', context: f['at'] ?? '',
51
- localEpoch: Number(f['epoch']), digest: bytes => fullDigest(bytes, identity.slice(0, identity.indexOf(':'))),
52
- placements: bundle.placements.map(p => ({ place: p.place, records: actLines(p.records) })),
53
- }) === identity;
54
- }
55
- /** One last integrity result only. Every call rereads all exact current bytes;
56
- * signatures, coverage and current authority are never retained here. */
57
- let lastIntactInventory;
58
- /** Internal integrity key only, not an act identity or a wire profile. */
59
- export function committedInventoryFingerprint(rows) {
60
- const hash = createHash('sha256');
61
- const text = hashText.bind(undefined, hash);
62
- text('committed-integrity-inventory');
63
- text(String(rows.length));
64
- for (const { identity, bundle } of rows) {
65
- text(identity);
66
- text(bundle.records);
67
- text(bundle.receipt);
68
- if (bundle.placements === undefined) {
69
- text('absent');
70
- continue;
71
- }
72
- text('present');
73
- text(String(bundle.placements.length));
74
- for (const placement of bundle.placements) {
75
- text(placement.place);
76
- text(placement.records);
77
- }
78
- }
79
- return hash.digest('hex');
80
- }
81
- /** Committed segments are part of this ledger, not a second authority source. */
82
- export function committedLocalActs(store) {
83
- const observed = observationAt(store);
84
- if (observed)
85
- return observed.rows;
86
- return readCommittedLocalActs(store);
87
- }
88
- let committedObservation;
89
- function observationAt(store) { for (let one = committedObservation; one; one = one.parent)
90
- if (one.store === store)
91
- return one; return undefined; }
92
- /** Fixed host observation only: one synchronous, coherent committed inventory.
93
- * It supplies no authority, verifier or async lifetime. Each outer invocation
94
- * rereads exact bodies before entering; current authorization still runs inside.
95
- */
96
- export function withCommittedLocalActObservation(store, body) {
97
- const prior = committedObservation, existing = observationAt(store);
98
- const rows = existing?.rows ?? Object.freeze(readCommittedLocalActs(store).map(row => Object.freeze({ identity: row.identity, bundle: Object.freeze({ ...row.bundle, ...(row.bundle.placements ? { placements: Object.freeze(row.bundle.placements.map(p => Object.freeze({ ...p }))) } : {}) }) })));
99
- committedObservation = { store, rows, parent: prior };
100
- try {
101
- const result = body();
102
- if (result !== null && (typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function')
103
- throw Error('REFUSE·act committed observation must be synchronous');
104
- return result;
105
- }
106
- finally {
107
- committedObservation = prior;
108
- }
109
- }
110
- function readCommittedLocalActs(store) {
111
- const root = join(store, 'ledger', 'acts');
112
- if (!existsSync(root))
113
- return [];
114
- const rows = readdirSync(root).filter(name => name.startsWith('committed-')).map(name => ({
115
- identity: decodeURIComponent(name.slice(10)), bundle: read(join(root, name)),
116
- }));
117
- // Ordered tuple framing commits every record, receipt and placement. No path,
118
- // mtime, authority snapshot or caller-supplied seal substitutes for bytes.
119
- const fingerprint = committedInventoryFingerprint(rows);
120
- if (fingerprint !== lastIntactInventory) {
121
- for (const { identity, bundle } of rows)
122
- if (!intactLocalAct(identity, bundle))
123
- throw Error('REFUSE·act committed journal seal does not verify');
124
- lastIntactInventory = fingerprint;
125
- }
126
- return rows.sort((a, b) => {
127
- const epoch = (one) => { const p = parse(one.receipt.trim()); return p.kind === 'fact' ? Number(p.value.fields['epoch']) : 0; };
128
- return epoch(a.bundle) - epoch(b.bundle);
129
- });
130
- }
131
- /** A public result is available only as a verified committed pair.
132
- * No writer-tail guess, newest-result selection or implicit authority.
133
- */
134
- export function localActResult(store, identity, verify) {
135
- const at = atOf(store, identity);
136
- const observed = observationAt(store);
137
- if (observed) {
138
- const bundle = observed.rows.find(row => row.identity === identity)?.bundle;
139
- if (!bundle)
140
- return undefined;
141
- if (verify(identity, bundle) !== true)
142
- throw Error('REFUSE·act committed result does not verify');
143
- return bundle;
144
- }
145
- if (!existsSync(at))
146
- return undefined;
147
- const bundle = read(at);
148
- if (verify(identity, bundle) !== true)
149
- throw Error('REFUSE·act committed result does not verify');
150
- return bundle;
151
- }
152
- /** One publication point for records and their native result. Re-delivery
153
- * reads the original pair without preparation, signing or a new local epoch.
154
- * The caller must also integrate this boundary into admission-history readers;
155
- * this storage port alone does not activate a grammar or land authority.
156
- */
157
- export async function commitLocalAct(store, identity, regions, prepare, verify, storage = nativePublicationStorage) {
158
- requireEffects('local act commitment');
159
- return underTheRegions(store, regions, 'land', async () => {
160
- const prior = localActResult(store, identity, verify);
161
- if (prior)
162
- return { kind: 'once', ...prior };
163
- const bundle = await prepare();
164
- if (!bundle.records || !bundle.receipt || verify(identity, bundle) !== true)
165
- throw Error('REFUSE·act prepared result does not verify');
166
- const files = { 'records.bound': bundle.records, 'receipt.bound': bundle.receipt };
167
- for (const p of bundle.placements ?? [])
168
- files['place-' + encodeURIComponent(p.place) + '.bound'] = p.records;
169
- publishBundle(atOf(store, identity), files, storage);
170
- return { kind: 'landed', ...bundle };
171
- });
172
- }
1
+ var U=Object.defineProperty;var i=(t,e)=>U(t,"name",{value:e,configurable:!0});import{hashText as F}from"../hash.js";import{ActCommitUnknown as I}from"../commit-result.js";import{assertHostNotCancelled as u}from"../host-controls.js";import{existsSync as E,readFileSync as m,readdirSync as y}from"node:fs";import{join as d}from"node:path";import{createHash as O}from"node:crypto";import{requireEffects as j}from"../read-only.js";import{underTheRegions as A}from"../../land/act.js";import{publishBundle as C,nativePublicationStorage as L}from"./publication.js";import{library11_actIdentity as k,library11_parse as g,library11_canonical as z}from"../../vendor/runtime.js";import{fullDigest as W}from"../digest.js";const v=i((t,e)=>{if(!e||e.includes("\0"))throw Error("REFUSE\xB7act missing identity");return d(t,"ledger","acts","committed-"+encodeURIComponent(e))},"atOf"),w=i(t=>{try{const e=y(t).filter(r=>r.startsWith("place-")&&r.endsWith(".bound")).map(r=>({place:decodeURIComponent(r.slice(6,-6)),records:m(d(t,r),"utf8")}));return{records:m(d(t,"records.bound"),"utf8"),receipt:m(d(t,"receipt.bound"),"utf8"),...e.length?{placements:e}:{}}}catch(e){throw Error(`REFUSE\xB7act committed result unreadable \xB7 ${e.code??"read failed"}`)}},"read"),x=i(t=>{if(!t.endsWith(`
2
+ `))throw Error("REFUSE\xB7act truncated committed lines");return t.slice(0,-1).split(`
3
+ `)},"actLines");function N(t,e){if(!e.receipt.endsWith(`
4
+ `)||e.receipt.slice(0,-1).includes(`
5
+ `))return!1;const r=g(e.receipt.slice(0,-1));if(r.kind!=="fact"||!e.placements?.length)return!1;const c=r.value.fields;return z(c)!==e.receipt.slice(0,-1)||!/^(0|[1-9][0-9]*)$/.test(c.epoch??"")||c.value!==t||c.role!=="writes"||c.form!=="alphabet"||c.measure!=="digest"?!1:k(x(e.records),{scope:c.scope??"",context:c.at??"",localEpoch:Number(c.epoch),digest:i(o=>W(o,t.slice(0,t.indexOf(":"))),"digest"),placements:e.placements.map(o=>({place:o.place,records:x(o.records)}))})===t}i(N,"intactLocalAct");let R;function _(t){const e=O("sha256"),r=F.bind(void 0,e);r("committed-integrity-inventory"),r(String(t.length));for(const{identity:c,bundle:o}of t){if(r(c),r(o.records),r(o.receipt),o.placements===void 0){r("absent");continue}r("present"),r(String(o.placements.length));for(const n of o.placements)r(n.place),r(n.records)}return e.digest("hex")}i(_,"committedInventoryFingerprint");function X(t){const e=h(t);return e?e.rows:S(t)}i(X,"committedLocalActs");let p;function h(t){for(let e=p;e;e=e.parent)if(e.store===t)return e}i(h,"observationAt");function Y(t,e){const r=p,o=h(t)?.rows??Object.freeze(S(t).map(n=>Object.freeze({identity:n.identity,bundle:Object.freeze({...n.bundle,...n.bundle.placements?{placements:Object.freeze(n.bundle.placements.map(s=>Object.freeze({...s})))}:{}})})));p={store:t,rows:o,parent:r};try{const n=e();if(n!==null&&(typeof n=="object"||typeof n=="function")&&typeof n.then=="function")throw Error("REFUSE\xB7act committed observation must be synchronous");return n}finally{p=r}}i(Y,"withCommittedLocalActObservation");function S(t){const e=d(t,"ledger","acts");if(!E(e))return[];const r=y(e).filter(o=>o.startsWith("committed-")).map(o=>({identity:decodeURIComponent(o.slice(10)),bundle:w(d(e,o))})),c=_(r);if(c!==R){for(const{identity:o,bundle:n}of r)if(!N(o,n))throw Error("REFUSE\xB7act committed journal seal does not verify");R=c}return r.sort((o,n)=>{const s=i(l=>{const a=g(l.receipt.trim());return a.kind==="fact"?Number(a.value.fields.epoch):0},"epoch");return s(o.bundle)-s(n.bundle)})}i(S,"readCommittedLocalActs");function H(t,e,r){const c=v(t,e),o=h(t);if(o){const s=o.rows.find(l=>l.identity===e)?.bundle;if(!s)return;if(r(e,s)!==!0)throw Error("REFUSE\xB7act committed result does not verify");return s}if(!E(c))return;const n=w(c);if(r(e,n)!==!0)throw Error("REFUSE\xB7act committed result does not verify");return n}i(H,"localActResult");async function Z(t,e,r,c,o,n=L,s){return j("local act commitment"),u(s),A(t,r,"land",async()=>{u(s);const l=H(t,e,o);if(l)return{kind:"once",...l};const a=await c();if(u(s),!a.records||!a.receipt||o(e,a)!==!0)throw Error("REFUSE\xB7act prepared result does not verify");const b={"records.bound":a.records,"receipt.bound":a.receipt};for(const f of a.placements??[])b["place-"+encodeURIComponent(f.place)+".bound"]=f.records;u(s);try{C(v(t,e),b,n)}catch(f){throw new I(e,f)}return{kind:"landed",...a}})}i(Z,"commitLocalAct");export{x as actLines,Z as commitLocalAct,_ as committedInventoryFingerprint,X as committedLocalActs,N as intactLocalAct,H as localActResult,Y as withCommittedLocalActObservation};
@@ -1,169 +1 @@
1
- import { existsSync, readdirSync, statSync, openSync, fstatSync, readSync, closeSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { readPlaceActContext, verifyPlaceActContext, placeActReceiptsOf } from '@lapxo/topos/core';
4
- import { underAuthorityRegions, underTheRegions, underRootProjection } from "../../land/act.js";
5
- import { requireEffects } from "../read-only.js";
6
- import { publishBundle, nativePublicationStorage } from "./publication.js";
7
- const fail = (why) => { throw Error('REFUSE·place act ' + why); };
8
- const clock = (n) => { if (!/^(0|[1-9][0-9]*)$/.test(n) || !Number.isSafeInteger(Number(n)))
9
- fail('unknown receiver clock'); return Number(n); };
10
- const rootBytes = (r) => JSON.stringify([r.namespace, r.snapshot, r.epoch, r.prefix, r.head, r.policies]);
11
- const budget = (b) => { if (!b || !Number.isSafeInteger(b.acts) || b.acts < 1 || !Number.isSafeInteger(b.bytes) || b.bytes < 1)
12
- fail('missing storage budget'); };
13
- const base = (store) => join(store, 'ledger', 'place-acts');
14
- const at = (store, id) => { if (!id || id.includes('\0'))
15
- fail('missing identity'); return join(base(store), 'committed-' + encodeURIComponent(id)); };
16
- function storedInventory(store, b) {
17
- budget(b);
18
- if (!existsSync(base(store)))
19
- return { names: [], bytes: 0 };
20
- const names = readdirSync(base(store)).filter(n => n.startsWith('committed-'));
21
- if (names.length > b.acts)
22
- fail('stored act budget');
23
- let bytes = 0;
24
- for (const name of names)
25
- for (const member of ['context.json', 'receipts.json', 'originals.json']) {
26
- const stat = statSync(join(base(store), name, member));
27
- if (!stat.isFile() || (bytes += stat.size) > b.bytes)
28
- fail('stored aggregate byte budget');
29
- }
30
- return { names, bytes };
31
- }
32
- function readBundle(path, b) {
33
- budget(b);
34
- let bytes = 0;
35
- const read = (name) => {
36
- const fd = openSync(join(path, name), 'r');
37
- try {
38
- const size = fstatSync(fd);
39
- if (!size.isFile() || size.size > b.bytes - bytes)
40
- fail('stored byte budget');
41
- const data = Buffer.alloc(size.size);
42
- let read = 0;
43
- while (read < data.length) {
44
- const count = readSync(fd, data, read, data.length - read, null);
45
- if (!count)
46
- fail('stored member changed while reading');
47
- read += count;
48
- }
49
- if (readSync(fd, Buffer.alloc(1), 0, 1, null) !== 0)
50
- fail('stored member changed while reading');
51
- bytes += read;
52
- return new TextDecoder('utf-8', { fatal: true }).decode(data);
53
- }
54
- finally {
55
- closeSync(fd);
56
- }
57
- };
58
- try {
59
- const context = read('context.json'), receipts = JSON.parse(read('receipts.json')), originals = JSON.parse(read('originals.json'));
60
- return { context, receipts, originals };
61
- }
62
- catch (e) {
63
- if (e instanceof Error && e.message.startsWith('REFUSE·'))
64
- throw e;
65
- return fail('committed bundle unreadable');
66
- }
67
- }
68
- function authenticated(bundle, id, contract) {
69
- const result = placeActReceiptsOf(bundle.context, bundle.receipts, contract), decoded = readPlaceActContext(bundle.context, contract.budget);
70
- if (result.identity !== id || JSON.stringify(bundle.originals) !== JSON.stringify(decoded.places.map(p => p.records)))
71
- fail('stored original/context identity mismatch');
72
- return decoded;
73
- }
74
- /** Historical result reads never produce a current authorization permit. */
75
- export function placeActResult(store, id, trust, limits) {
76
- const path = at(store, id);
77
- if (!existsSync(path))
78
- return undefined;
79
- const bundle = readBundle(path, limits);
80
- authenticated(bundle, id, trust.historical(bundle.context));
81
- return bundle;
82
- }
83
- /** Each receiver chain advances independently. Initial heads are explicit,
84
- * authenticated host inputs, not inferred zero or legacy global epochs. */
85
- export function placeActHeads(store, initial, trust, limits) {
86
- budget(limits);
87
- if (!initial.length || new Set(initial.map(h => h.place)).size !== initial.length)
88
- fail('missing/ambiguous initial heads');
89
- const heads = new Map(initial.map(h => { clock(h.epoch); if (!h.identity)
90
- fail('missing initial head'); return [h.place, { ...h }]; }));
91
- if (!existsSync(base(store)))
92
- return [...heads.values()];
93
- const { names } = storedInventory(store, limits);
94
- const pending = names.map(name => { const id = decodeURIComponent(name.slice(10)), bundle = readBundle(join(base(store), name), limits); const context = authenticated(bundle, id, trust.historical(bundle.context)); if (context.root.namespace !== trust.contract.root.namespace)
95
- fail('stored clock namespace mismatch'); return { id, context }; });
96
- while (pending.length) {
97
- const next = pending.findIndex(a => a.context.places.every(p => heads.get(p.place)?.identity === p.previous));
98
- if (next < 0)
99
- fail('receiver chain fork or missing predecessor');
100
- const act = pending.splice(next, 1)[0];
101
- for (const p of act.context.places) {
102
- const prior = heads.get(p.place);
103
- const epoch = clock(prior.epoch) + 1;
104
- if (!Number.isSafeInteger(epoch) || clock(p.epoch) !== epoch)
105
- fail('receiver chain clock mismatch');
106
- heads.set(p.place, { place: p.place, identity: act.id, epoch: p.epoch });
107
- }
108
- }
109
- return [...heads.values()];
110
- }
111
- /** Context, exact original bytes and complete signed receipts have one visibility
112
- * point. Real Root guard exclusion spans final authority/head comparison and
113
- * publication; this does not activate a CLI profile or reinterpret local-act@1. */
114
- export async function commitPlaceAct(store, encoded, receipts, trust, limits, storage = nativePublicationStorage) {
115
- requireEffects('place act commitment');
116
- budget(limits);
117
- const decoded = readPlaceActContext(encoded, trust.contract.budget), id = trust.contract.digest(encoded);
118
- const regions = decoded.places.map(p => { if (p.place === '.')
119
- return ''; const parts = p.place.split('/'); if (parts.length < 2 || parts.pop() !== 'TARGET.bound' || parts.some(s => s === '' || s === '.' || s === '..'))
120
- fail('unknown place namespace'); return parts.join('/'); });
121
- const enter = regions.includes('') ? underTheRegions : underAuthorityRegions;
122
- return enter(store, regions, 'place act', () => underRootProjection(store, 'place act publication', () => {
123
- const prior = placeActResult(store, id, trust, limits);
124
- if (prior) {
125
- if (prior.context !== encoded)
126
- fail('replay bytes differ');
127
- // Replay authenticates the supplied evidence too. Historical authentication
128
- // grants no current authority and leaves the committed result unchanged.
129
- placeActReceiptsOf(encoded, receipts, trust.historical(encoded));
130
- return { ...prior, identity: id, kind: 'once' };
131
- }
132
- const verified = verifyPlaceActContext(encoded, trust.contract);
133
- placeActReceiptsOf(encoded, receipts, trust.contract);
134
- const originals = decoded.places.map(p => p.records), files = { 'context.json': encoded, 'receipts.json': JSON.stringify(receipts) + '\n', 'originals.json': JSON.stringify(originals) + '\n' };
135
- const inventory = storedInventory(store, limits);
136
- if (inventory.bytes + Object.values(files).reduce((n, v) => n + Buffer.byteLength(v), 0) > limits.bytes)
137
- fail('publication byte budget');
138
- if (inventory.names.length >= limits.acts)
139
- fail('publication act budget');
140
- const current = trust.current();
141
- if (rootBytes(current.root) !== rootBytes(verified.dependencies))
142
- fail('authority changed before publication');
143
- if (new Set(current.heads.map(h => h.place)).size !== current.heads.length)
144
- fail('ambiguous receiver heads');
145
- const storedHeads = placeActHeads(store, trust.initialHeads, trust, limits);
146
- for (const p of decoded.places) {
147
- const actual = storedHeads.find(h => h.place === p.place), selected = current.heads.find(h => h.place === p.place);
148
- if (!actual || !selected || actual.identity !== selected.identity || actual.epoch !== selected.epoch)
149
- fail('receiver snapshot is not committed head ' + p.place);
150
- }
151
- for (const p of decoded.places) {
152
- const head = current.heads.find(h => h.place === p.place) ?? fail('missing receiver head ' + p.place);
153
- if (head.identity !== p.previous)
154
- fail('receiver head moved ' + p.place);
155
- const next = clock(head.epoch) + 1;
156
- if (!Number.isSafeInteger(next) || clock(p.epoch) !== next)
157
- fail('receiver epoch not next ' + p.place);
158
- }
159
- publishBundle(at(store, id), files, storage);
160
- return { context: encoded, receipts, originals, identity: id, kind: 'landed' };
161
- }));
162
- }
163
- /** Enumerates only committed, historically authenticated carriers. Namespace
164
- * projection is a caller's separate pure operation, never current permission. */
165
- export function committedPlaceActResults(store, trust, limits) {
166
- const { names } = storedInventory(store, limits);
167
- return names.map(name => { const identity = decodeURIComponent(name.slice(10)), bundle = placeActResult(store, identity, trust, limits); if (!bundle)
168
- fail('committed carrier vanished'); return { identity, bundle: bundle }; });
169
- }
1
+ var j=Object.defineProperty;var i=(e,c)=>j(e,"name",{value:c,configurable:!0});import{existsSync as g,readdirSync as I,statSync as E,openSync as N,fstatSync as C,readSync as S,closeSync as O}from"node:fs";import{join as f}from"node:path";import{library3_readPlaceActContext as z,library3_placeActReceiptsOf as U}from"../../vendor/runtime.js";import{transactPlaceAct as k}from"../place-act-transaction.js";import{canonicalActStore as B,underAuthorityRegions as F,underTheRegions as J,underRootProjection as H}from"../../land/act.js";import{requireEffects as T}from"../read-only.js";import{receiverClock as h}from"../host-controls.js";import{publishBundle as W,nativePublicationStorage as v}from"./publication.js";const s=i(e=>{throw Error("REFUSE\xB7place act "+e)},"fail"),y=i(e=>{(!e||!Number.isSafeInteger(e.acts)||e.acts<1||!Number.isSafeInteger(e.bytes)||e.bytes<1)&&s("missing storage budget")},"budget"),m=i(e=>f(e,"ledger","place-acts"),"base"),A=i((e,c)=>((!c||c.includes("\0"))&&s("missing identity"),f(m(e),"committed-"+encodeURIComponent(c))),"at");function b(e,c){if(y(c),!g(m(e)))return{names:[],bytes:0};const t=I(m(e)).filter(n=>n.startsWith("committed-"));t.length>c.acts&&s("stored act budget");let o=0;for(const n of t)for(const r of["context.json","receipts.json","originals.json"]){const l=E(f(m(e),n,r));(!l.isFile()||(o+=l.size)>c.bytes)&&s("stored aggregate byte budget")}return{names:t,bytes:o}}i(b,"storedInventory");function R(e,c){y(c);let t=0;const o=i(n=>{const r=N(f(e,n),"r");try{const l=C(r);(!l.isFile()||l.size>c.bytes-t)&&s("stored byte budget");const a=Buffer.alloc(l.size);let p=0;for(;p<a.length;){const d=S(r,a,p,a.length-p,null);d||s("stored member changed while reading"),p+=d}return S(r,Buffer.alloc(1),0,1,null)!==0&&s("stored member changed while reading"),t+=p,new TextDecoder("utf-8",{fatal:!0}).decode(a)}finally{O(r)}},"read");try{const n=o("context.json"),r=JSON.parse(o("receipts.json")),l=JSON.parse(o("originals.json"));return{context:n,receipts:r,originals:l}}catch(n){if(n instanceof Error&&n.message.startsWith("REFUSE\xB7"))throw n;return s("committed bundle unreadable")}}i(R,"readBundle");function w(e,c,t){const o=U(e.context,e.receipts,t),n=z(e.context,t.budget);return(o.identity!==c||JSON.stringify(e.originals)!==JSON.stringify(n.places.map(r=>r.records)))&&s("stored original/context identity mismatch"),n}i(w,"authenticated");function P(e,c,t,o){const n=A(e,c);if(!g(n))return;const r=R(n,o);return w(r,c,t.historical(r.context)),r}i(P,"placeActResult");function _(e,c,t,o){y(o),(!c.length||new Set(c.map(a=>a.place)).size!==c.length)&&s("missing/ambiguous initial heads");const n=new Map(c.map(a=>(h(a.epoch,s),a.identity||s("missing initial head"),[a.place,{...a}])));if(!g(m(e)))return[...n.values()];const{names:r}=b(e,o),l=r.map(a=>{const p=decodeURIComponent(a.slice(10)),d=R(f(m(e),a),o),u=w(d,p,t.historical(d.context));return u.root.namespace!==t.contract.root.namespace&&s("stored clock namespace mismatch"),{id:p,context:u}});for(;l.length;){const a=l.findIndex(d=>d.context.places.every(u=>n.get(u.place)?.identity===u.previous));a<0&&s("receiver chain fork or missing predecessor");const p=l.splice(a,1)[0];for(const d of p.context.places){const u=n.get(d.place),x=h(u.epoch,s)+1;(!Number.isSafeInteger(x)||h(d.epoch,s)!==x)&&s("receiver chain clock mismatch"),n.set(d.place,{place:d.place,identity:p.id,epoch:d.epoch})}}return[...n.values()]}i(_,"placeActHeads");function q(e,c=v){return e=B(e),{exclusive:i((t,o)=>(t.includes("")?J:F)(e,t,"place act",()=>H(e,"place act publication",o)),"exclusive"),result:i((t,o,n)=>P(e,t,o,n),"result"),inventory:i(t=>b(e,t),"inventory"),heads:i((t,o)=>_(e,t.initialHeads,t,o),"heads"),publish:i((t,o)=>W(A(e,t),o,c),"publish")}}i(q,"nativePlaceActPersistence");async function Z(e,c,t,o,n,r=v){return T("place act commitment"),k(c,t,o,n,q(e,r))}i(Z,"commitPlaceAct");function $(e,c,t){const{names:o}=b(e,t);return o.map(n=>{const r=decodeURIComponent(n.slice(10)),l=P(e,r,c,t);return l||s("committed carrier vanished"),{identity:r,bundle:l}})}i($,"committedPlaceActResults");export{Z as commitPlaceAct,$ as committedPlaceActResults,q as nativePlaceActPersistence,_ as placeActHeads,P as placeActResult};
@@ -1,56 +1 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { closeSync, fsyncSync, mkdirSync, openSync, renameSync, rmSync, writeFileSync } from 'node:fs';
3
- import { dirname, join } from 'node:path';
4
- import { requireEffects } from "../read-only.js";
5
- const syncDirectory = (path) => {
6
- const fd = openSync(path, 'r');
7
- try {
8
- fsyncSync(fd);
9
- }
10
- finally {
11
- closeSync(fd);
12
- }
13
- };
14
- export const nativePublicationStorage = {
15
- publish(staged, committed) { renameSync(staged, committed); syncDirectory(dirname(committed)); },
16
- };
17
- /** Publish prepared bytes as one directory. No identity, grammar or authority
18
- * is inferred here. Readers address the committed name, never staging files.
19
- * A failure after rename is not evidence of rollback: the caller must retain
20
- * the uncertainty and allow a verified read of the committed name.
21
- */
22
- export function publishBundle(committed, files, storage = nativePublicationStorage) {
23
- requireEffects('atomic publication');
24
- const entries = Object.entries(files);
25
- if (!entries.length || entries.some(([name]) => !name || name === '.' || name === '..' || /[\\/\0]/.test(name))) {
26
- throw Error('REFUSE·commit invalid publication members');
27
- }
28
- const root = dirname(committed);
29
- const created = mkdirSync(root, { recursive: true });
30
- // Persist newly created directory entries up to their existing parent too.
31
- if (created !== undefined)
32
- for (let at = root;; at = dirname(at)) {
33
- syncDirectory(at);
34
- if (at === dirname(created))
35
- break;
36
- }
37
- const staged = join(root, '.stage-' + randomUUID());
38
- mkdirSync(staged, { mode: 0o700 });
39
- try {
40
- for (const [name, bytes] of entries) {
41
- const fd = openSync(join(staged, name), 'wx', 0o600);
42
- try {
43
- writeFileSync(fd, bytes);
44
- fsyncSync(fd);
45
- }
46
- finally {
47
- closeSync(fd);
48
- }
49
- }
50
- syncDirectory(staged);
51
- storage.publish(staged, committed);
52
- }
53
- finally {
54
- rmSync(staged, { recursive: true, force: true });
55
- }
56
- }
1
+ var h=Object.defineProperty;var f=(o,t)=>h(o,"name",{value:t,configurable:!0});import{randomUUID as g}from"node:crypto";import{closeSync as a,fsyncSync as u,mkdirSync as m,openSync as p,renameSync as v,rmSync as E,writeFileSync as w}from"node:fs";import{dirname as n,join as b}from"node:path";import{requireEffects as x}from"../read-only.js";const l=f(o=>{const t=p(o,"r");try{u(t)}finally{a(t)}},"syncDirectory"),U={publish(o,t){v(o,t),l(n(t))}};function B(o,t,d=U){x("atomic publication");const i=Object.entries(t);if(!i.length||i.some(([r])=>!r||r==="."||r===".."||/[\\/\0]/.test(r)))throw Error("REFUSE\xB7commit invalid publication members");const c=n(o),y=m(c,{recursive:!0});if(y!==void 0)for(let r=c;l(r),r!==n(y);r=n(r));const e=b(c,".stage-"+g());m(e,{mode:448});try{for(const[r,S]of i){const s=p(b(e,r),"wx",384);try{w(s,S),u(s)}finally{a(s)}}l(e),d.publish(e,o)}finally{E(e,{recursive:!0,force:!0})}}f(B,"publishBundle");export{U as nativePublicationStorage,B as publishBundle};
@@ -1,74 +1 @@
1
- import { spawn } from 'node:child_process';
2
- import { readFileSync } from 'node:fs';
3
- import { signBytes } from "../adapters/keys/ed25519.js";
4
- /** Contains only host-controlled diagnostics, never child output. */
5
- export class SigningFailure extends Error {
6
- }
7
- /** Host-approved mechanism only. Repository declarations do not authorize execution. */
8
- export async function invokeSigner(lot, mechanism, protocol, limits) {
9
- if (!Number.isSafeInteger(limits.timeoutMs) || limits.timeoutMs <= 0
10
- || !Number.isSafeInteger(limits.responseBytes) || limits.responseBytes <= 0) {
11
- throw new SigningFailure(`REFUSE·signer ${lot.keyId} has no valid declared limits`);
12
- }
13
- const request = protocol.request(lot);
14
- let output;
15
- if (mechanism.kind === 'file') {
16
- try {
17
- const key = readFileSync(mechanism.path, 'utf8');
18
- output = protocol.response(lot.bytes.map(bytes => ({ keyId: lot.keyId, signature: signBytes(bytes, key, lot.algorithm) })));
19
- }
20
- catch {
21
- throw new SigningFailure(`REFUSE·signer ${lot.keyId} file mechanism failed`);
22
- }
23
- }
24
- else
25
- output = await new Promise((resolve, reject) => {
26
- const child = spawn(mechanism.executable, [...mechanism.args], { stdio: ['pipe', 'pipe', 'pipe'], shell: false });
27
- let size = 0;
28
- const chunks = [];
29
- let failure;
30
- const refuse = (why) => {
31
- if (failure)
32
- return;
33
- failure = why;
34
- child.kill('SIGKILL');
35
- clearTimeout(timer);
36
- child.stdin.destroy();
37
- child.stdout.destroy();
38
- child.stderr.destroy();
39
- reject(new SigningFailure(`REFUSE·signer ${lot.keyId} ${why} · status=none · signal=SIGKILL`));
40
- };
41
- const timer = setTimeout(() => refuse('timeout'), limits.timeoutMs);
42
- child.stdout.on('data', (chunk) => {
43
- size += chunk.length;
44
- if (size > limits.responseBytes)
45
- refuse('response exceeds declared limit');
46
- if (!failure)
47
- chunks.push(chunk);
48
- });
49
- // Drain, never forward or retain signer diagnostics.
50
- child.stderr.on('data', () => { });
51
- child.stdin.on('error', () => refuse('input delivery failed'));
52
- child.on('error', () => {
53
- clearTimeout(timer);
54
- reject(new SigningFailure(`REFUSE·signer ${lot.keyId} command could not start`));
55
- });
56
- child.on('close', (status, signal) => {
57
- clearTimeout(timer);
58
- if (failure || status !== 0) {
59
- reject(new SigningFailure(`REFUSE·signer ${lot.keyId} ${failure ?? 'command failed'} · status=${status ?? 'none'} · signal=${signal ?? 'none'}`));
60
- }
61
- else
62
- resolve(Buffer.concat(chunks).toString('utf8'));
63
- });
64
- child.stdin.end(request);
65
- });
66
- if (Buffer.byteLength(output) > limits.responseBytes)
67
- throw new SigningFailure(`REFUSE·signer ${lot.keyId} response exceeds declared limit`);
68
- try {
69
- return protocol.reply(output, lot);
70
- }
71
- catch {
72
- throw new SigningFailure(`REFUSE·signer ${lot.keyId} invalid response`);
73
- }
74
- }
1
+ var I=Object.defineProperty;var u=(e,i)=>I(e,"name",{value:i,configurable:!0});import{spawn as S}from"node:child_process";import{readFileSync as k}from"node:fs";import{signBytes as w}from"../adapters/keys/ed25519.js";class t extends Error{static{u(this,"SigningFailure")}}async function R(e,i,f,n){if(!Number.isSafeInteger(n.timeoutMs)||n.timeoutMs<=0||!Number.isSafeInteger(n.responseBytes)||n.responseBytes<=0)throw new t(`REFUSE\xB7signer ${e.keyId} has no valid declared limits`);const m=f.request(e);let a;if(i.kind==="file")try{const y=k(i.path,"utf8");a=f.response(e.bytes.map(o=>({keyId:e.keyId,signature:w(o,y,e.algorithm)})))}catch{throw new t(`REFUSE\xB7signer ${e.keyId} file mechanism failed`)}else a=await new Promise((y,o)=>{const r=S(i.executable,[...i.args],{stdio:["pipe","pipe","pipe"],shell:!1});let g=0;const l=[];let d;const c=u(s=>{d||(d=s,r.kill("SIGKILL"),clearTimeout(p),r.stdin.destroy(),r.stdout.destroy(),r.stderr.destroy(),o(new t(`REFUSE\xB7signer ${e.keyId} ${s} \xB7 status=none \xB7 signal=SIGKILL`)))},"refuse"),p=setTimeout(()=>c("timeout"),n.timeoutMs);r.stdout.on("data",s=>{g+=s.length,g>n.responseBytes&&c("response exceeds declared limit"),d||l.push(s)}),r.stderr.on("data",()=>{}),r.stdin.on("error",()=>c("input delivery failed")),r.on("error",()=>{clearTimeout(p),o(new t(`REFUSE\xB7signer ${e.keyId} command could not start`))}),r.on("close",(s,E)=>{clearTimeout(p),d||s!==0?o(new t(`REFUSE\xB7signer ${e.keyId} ${d??"command failed"} \xB7 status=${s??"none"} \xB7 signal=${E??"none"}`)):y(Buffer.concat(l).toString("utf8"))}),r.stdin.end(m)});if(Buffer.byteLength(a)>n.responseBytes)throw new t(`REFUSE\xB7signer ${e.keyId} response exceeds declared limit`);try{return f.reply(a,e)}catch{throw new t(`REFUSE\xB7signer ${e.keyId} invalid response`)}}u(R,"invokeSigner");export{t as SigningFailure,R as invokeSigner};
@@ -1,18 +1 @@
1
- /** The store root is the tree that holds a TARGET.bound beside its .bound store. */
2
- import { existsSync, readdirSync } from 'node:fs';
3
- import { dirname, join, resolve } from 'node:path';
4
- import { EXTENSION, LOCK } from '@lapxo/topos/wire';
5
- export function storeRoot(from) {
6
- const abs = resolve(from || '.');
7
- let at = abs;
8
- for (let i = 0; i < 64; i += 1) {
9
- if (existsSync(join(at, LOCK)) && existsSync(join(at, EXTENSION)))
10
- return at;
11
- const parent = dirname(at);
12
- if (parent === at)
13
- break;
14
- at = parent;
15
- }
16
- return abs;
17
- }
18
- export const storeDirs = (store) => existsSync(store) ? readdirSync(store, { withFileTypes: true }).filter((entry) => entry.isDirectory()).length : 0;
1
+ var f=Object.defineProperty;var i=(r,t)=>f(r,"name",{value:t,configurable:!0});import{existsSync as o,readdirSync as l}from"node:fs";import{dirname as c,join as a,resolve as m}from"node:path";import{library11_EXTENSION as p,library11_LOCK as y}from"../../vendor/runtime.js";function O(r){const t=m(r||".");let e=t;for(let n=0;n<64;n+=1){if(o(a(e,y))&&o(a(e,p)))return e;const s=c(e);if(s===e)break;e=s}return t}i(O,"storeRoot");const S=i(r=>o(r)?l(r,{withFileTypes:!0}).filter(t=>t.isDirectory()).length:0,"storeDirs");export{S as storeDirs,O as storeRoot};
@@ -1,48 +1 @@
1
- import { readFileSync } from 'node:fs';
2
- import { contentRequest, transportSelection, parse } from '@lapxo/topos/wire';
3
- import { boundedProcess } from "../process-lifetime.js";
4
- import { fetchBytes } from "../adapters/transport/http.js";
5
- export async function transportBytes(location, digest, lines) {
6
- const scheme = new URL(location).protocol.slice(0, -1);
7
- const fields = lines.flatMap(line => { const p = parse(line); return p.kind === 'fact' ? [p.value.fields] : []; });
8
- const selected = transportSelection(fields, scheme);
9
- if (selected === undefined)
10
- throw Error(`REFUSE·transport ${scheme} no admitted content-request/1 policy`);
11
- if (selected.name === 'fetch') {
12
- if (!['http', 'https'].includes(scheme))
13
- throw Error(`REFUSE·transport ${scheme} is not supported by this host adapter`);
14
- return fetchBytes(location, selected);
15
- }
16
- const registryPath = process.env['BOUND_TRANSPORTS'];
17
- if (!registryPath)
18
- throw Error(`REFUSE·transport ${scheme} no host binding for ${selected.name}`);
19
- let record;
20
- try {
21
- const registry = JSON.parse(readFileSync(registryPath, 'utf8'));
22
- if (!registry || typeof registry !== 'object' || !Object.prototype.hasOwnProperty.call(registry, selected.name))
23
- throw Error();
24
- const value = registry[selected.name];
25
- if (!value || typeof value !== 'object')
26
- throw Error();
27
- const f = value;
28
- if (f.kind !== 'command' || typeof f.executable !== 'string' || !f.executable || !Array.isArray(f.args) || !f.args.every(x => typeof x === 'string'))
29
- throw Error();
30
- if (f.environment !== undefined && (!Array.isArray(f.environment) || !f.environment.every(x => typeof x === 'string')))
31
- throw Error();
32
- const names = (f.environment ?? []);
33
- const env = {};
34
- if (process.env.PATH !== undefined)
35
- env.PATH = process.env.PATH;
36
- for (const name of names)
37
- if (process.env[name] !== undefined)
38
- env[name] = process.env[name];
39
- record = { executable: f.executable, args: f.args, env };
40
- }
41
- catch {
42
- throw Error(`REFUSE·transport ${scheme} host binding unavailable or invalid`);
43
- }
44
- const result = boundedProcess(record.executable, record.args, contentRequest(location, digest, selected), selected, undefined, record.env);
45
- if (result.status !== 0 || result.signal !== null)
46
- throw Error(`REFUSE·transport ${scheme} failed · status ${result.status ?? result.signal}`);
47
- return Buffer.from(result.stdoutBytes ?? '', 'base64');
48
- }
1
+ var h=Object.defineProperty;var u=(a,f)=>h(a,"name",{value:f,configurable:!0});import{readFileSync as E}from"node:fs";import{library11_contentRequest as b,library11_transportSelection as v,library11_parse as g}from"../../vendor/runtime.js";import{boundedProcess as w}from"../process-lifetime.js";import{fetchBytes as S}from"../adapters/transport/http.js";async function x(a,f,d){const t=new URL(a).protocol.slice(0,-1),y=d.flatMap(o=>{const s=g(o);return s.kind==="fact"?[s.value.fields]:[]}),e=v(y,t);if(e===void 0)throw Error(`REFUSE\xB7transport ${t} no admitted content-request/1 policy`);if(e.name==="fetch"){if(!["http","https"].includes(t))throw Error(`REFUSE\xB7transport ${t} is not supported by this host adapter`);return S(a,e)}const l=process.env.BOUND_TRANSPORTS;if(!l)throw Error(`REFUSE\xB7transport ${t} no host binding for ${e.name}`);let c;try{const o=JSON.parse(E(l,"utf8"));if(!o||typeof o!="object"||!Object.prototype.hasOwnProperty.call(o,e.name))throw Error();const s=o[e.name];if(!s||typeof s!="object")throw Error();const r=s;if(r.kind!=="command"||typeof r.executable!="string"||!r.executable||!Array.isArray(r.args)||!r.args.every(n=>typeof n=="string")||r.environment!==void 0&&(!Array.isArray(r.environment)||!r.environment.every(n=>typeof n=="string")))throw Error();const m=r.environment??[],p={};process.env.PATH!==void 0&&(p.PATH=process.env.PATH);for(const n of m)process.env[n]!==void 0&&(p[n]=process.env[n]);c={executable:r.executable,args:r.args,env:p}}catch{throw Error(`REFUSE\xB7transport ${t} host binding unavailable or invalid`)}const i=w(c.executable,c.args,b(a,f,e),e,void 0,c.env);if(i.status!==0||i.signal!==null)throw Error(`REFUSE\xB7transport ${t} failed \xB7 status ${i.status??i.signal}`);return Buffer.from(i.stdoutBytes??"","base64")}u(x,"transportBytes");export{x as transportBytes};
@@ -1,17 +1 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { processOf } from "../observe/runner.js";
3
- /** A synchronous fold waits on a supervising host process; the supervisor owns cancellation of its child group. */
4
- export function boundedProcess(command, args, input, limits, cwd, env) {
5
- if (!Number.isSafeInteger(limits.timeoutMs) || limits.timeoutMs <= 0 || !Number.isSafeInteger(limits.responseBytes) || limits.responseBytes <= 0)
6
- throw Error('REFUSE·reader invalid process limits');
7
- // The same monotonic deadline covers handoff, input and execution. Starting a
8
- // fresh timer after stdin closes would leave the handoff outside the policy.
9
- const deadline = process.hrtime.bigint() + BigInt(limits.timeoutMs) * 1000000n;
10
- const run = spawnSync(process.execPath, [processOf('lifetime', 'host'), String(deadline), String(limits.responseBytes)], { input: JSON.stringify({ command, args, input, limits, cwd, env }), encoding: 'utf8', maxBuffer: limits.responseBytes * 12 + 4096 });
11
- if (run.error || run.status !== 0)
12
- throw Error(`REFUSE·reader lifetime supervisor ${run.error?.message ?? run.signal ?? run.status}`);
13
- const result = JSON.parse(run.stdout);
14
- if (result.failure)
15
- throw Error(`REFUSE·reader ${result.failure} · status ${result.status ?? result.signal ?? 'cancelled'}${result.stderr ? ' · child stderr: ' + result.stderr : ''}`);
16
- return result;
17
- }
1
+ var c=Object.defineProperty;var n=(t,o)=>c(t,"name",{value:o,configurable:!0});import{spawnSync as d}from"node:child_process";import{processOf as p}from"../observe/runner.js";function m(t,o,i,e,a,u){if(!Number.isSafeInteger(e.timeoutMs)||e.timeoutMs<=0||!Number.isSafeInteger(e.responseBytes)||e.responseBytes<=0)throw Error("REFUSE\xB7reader invalid process limits");const f=process.hrtime.bigint()+BigInt(e.timeoutMs)*1000000n,s=d(process.execPath,[p("lifetime","host"),String(f),String(e.responseBytes)],{input:JSON.stringify({command:t,args:o,input:i,limits:e,cwd:a,env:u}),encoding:"utf8",maxBuffer:e.responseBytes*12+4096});if(s.error||s.status!==0)throw Error(`REFUSE\xB7reader lifetime supervisor ${s.error?.message??s.signal??s.status}`);const r=JSON.parse(s.stdout);if(r.failure)throw Error(`REFUSE\xB7reader ${r.failure} \xB7 status ${r.status??r.signal??"cancelled"}${r.stderr?" \xB7 child stderr: "+r.stderr:""}`);return r}n(m,"boundedProcess");export{m as boundedProcess};