@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,188 +1,6 @@
1
- import { actLines, committedLocalActs } from "../host/ports/local-act.js";
2
- import { readdirSync } from 'node:fs';
3
- import { requireEffects } from "../host/read-only.js";
4
- import { appendFileSync, closeSync, dirname, existsSync, join, linkSync, mkdirSync, openSync, readFileSync, readSync, renameSync, rmSync, statSync, writeFileSync } from "../host/io.js";
5
- import { storeRoot } from "../host/ports/store.js";
6
- import { canonical, EXTENSION, PROTOCOL } from '@lapxo/topos/wire';
7
- import { fieldOf } from "../fold/claims.js";
8
- import { observeText } from "../observe/files.js";
9
- export function storeOf(root) {
10
- return join(storeRoot(root), EXTENSION);
11
- }
12
- /**
13
- * The store of a place: every name under it is read here and nowhere else, whoever needs a place asks for it by its
14
- * steps, and one append-only file per writer stands beside the bytes kept by digest — one per region for a writer
15
- * whose lines are about regions, so a fold opens only the regions it reaches. A file is read once per stamp, and a
16
- * ledger only grows: what it held is kept, and only the bytes appended since, from where it last ended a line, are read.
17
- */
18
- export function storeAt(store, ...steps) {
19
- return join(store, ...steps);
20
- }
21
- export function writerFile(store, writer) {
22
- return storeAt(store, 'ledger', `${writer.replace(/[^a-zA-Z0-9_-]/g, '')}${EXTENSION}`);
23
- }
24
- const held = new Map();
25
- export function ledgerLines(store, writer) {
26
- return journalLines(store, writer, '.', linesAt(writerFile(store, writer)));
27
- }
28
- export function shardFile(store, writer, region) {
29
- return storeAt(store, 'ledger', writer.replace(/[^a-zA-Z0-9_-]/g, ''), `${region.replace(/\/+$/, '') || '@'}${EXTENSION}`);
30
- }
31
- export const shardLines = (store, writer, region) => journalLines(store, writer, region, linesAt(shardFile(store, writer, region)));
32
- const journalMemo = new Map();
33
- function journalLines(store, writer, place, legacy) {
34
- const fresh = committedLocalActs(store).flatMap(act => act.bundle.placements?.filter(p => p.place === place).flatMap(p => actLines(p.records).filter(line => fieldOf(line, 'by') === writer)) ?? []);
35
- if (!fresh.length)
36
- return legacy;
37
- const lines = [...new Set([...legacy, ...fresh])], key = store + '\0' + writer + '\0' + place, last = journalMemo.get(key);
38
- if (last?.length === lines.length && last.every((line, i) => line === lines[i]))
39
- return last;
40
- journalMemo.set(key, lines);
41
- return lines;
42
- }
43
- function legacyWriters(store) {
44
- const at = join(store, 'ledger');
45
- return existsSync(at) ? readdirSync(at).filter(name => name.endsWith(EXTENSION)).map(name => name.slice(0, -EXTENSION.length)) : [];
46
- }
47
- export function ledgerWriters(store) {
48
- const legacy = legacyWriters(store);
49
- const committed = committedLocalActs(store).flatMap(act => act.bundle.placements?.filter(p => p.place === '.').flatMap(p => actLines(p.records).map(line => fieldOf(line, 'by'))) ?? []);
50
- return [...new Set([...legacy, ...committed])];
51
- }
52
- /** One synchronous root-history read, not a retained authority snapshot.
53
- * Preserve writer order and each writer's legacy-before-committed ordering.
54
- * Every call rereads the complete committed inventory exactly once. */
55
- export function rootLedgerLines(store) {
56
- const legacy = legacyWriters(store), acts = committedLocalActs(store);
57
- const fresh = acts.flatMap(act => act.bundle.placements?.filter(p => p.place === '.').flatMap(p => actLines(p.records)) ?? []);
58
- const writers = [...new Set([...legacy, ...fresh.map(line => fieldOf(line, 'by'))])];
59
- return writers.flatMap(writer => {
60
- // Authority-history identity needs actual bytes. A writer's size and mtime
61
- // cannot distinguish a same-size edit or stand in for an admission proof.
62
- const at = writerFile(store, writer), prior = existsSync(at) ? readFileSync(at, 'utf8').split('\n').filter(line => line.startsWith(PROTOCOL)) : [];
63
- const committed = fresh.filter(line => fieldOf(line, 'by') === writer);
64
- return committed.length ? [...new Set([...prior, ...committed])] : prior;
65
- });
66
- }
67
- export function landShard(store, writer, region, lines) {
68
- return appendNew(shardFile(store, writer, region), lines);
69
- }
70
- function linesAt(at) {
71
- const st = statSync(at, { throwIfNoEntry: false });
72
- if (!st)
73
- return [];
74
- const stamp = `${Math.floor(st.mtimeMs)}-${st.size}`;
75
- const mine = held.get(at);
76
- if (mine?.stamp === stamp)
77
- return mine.lines;
78
- const grown = mine !== undefined && mine.size > 0 && st.size > mine.size ? tailOf(at, mine.size, st.size) : undefined;
79
- const lines = grown !== undefined && mine !== undefined ? [...mine.lines, ...grown.split('\n').filter((line) => line.startsWith(PROTOCOL))] : readFileSync(at, 'utf8').split('\n').filter((line) => line.startsWith(PROTOCOL));
80
- held.set(at, { stamp, size: st.size, lines });
81
- return lines;
82
- }
83
- function tailOf(at, from, to) {
84
- const fd = openSync(at, 'r');
85
- try {
86
- const bytes = Buffer.alloc(to - from + 1);
87
- readSync(fd, bytes, 0, bytes.length, from - 1);
88
- return bytes[0] === 0x0a ? bytes.subarray(1).toString('utf8') : undefined;
89
- }
90
- finally {
91
- closeSync(fd);
92
- }
93
- }
94
- function appendNew(at, lines) {
95
- const had = new Set(linesAt(at));
96
- const fresh = [...new Set(lines)].filter((line) => line.startsWith(PROTOCOL) && !had.has(line));
97
- if (fresh.length) {
98
- mkdirSync(dirname(at), { recursive: true });
99
- appendFileSync(at, `${fresh.join('\n')}\n`);
100
- }
101
- return fresh.length;
102
- }
103
- export function signedLines(store, writer) {
104
- return ledgerLines(store, writer).filter((line) => line.includes(`by=${writer}`) && /\bsig=/.test(line));
105
- }
106
- export function blobAt(store, digest) {
107
- return storeAt(store, 'cas', 'blobs', digest.slice(digest.indexOf(':') + 1));
108
- }
109
- /**
110
- * Where the bytes of one digest are kept: naming a blob is not reading it. A file named by the digest of its bytes lands
111
- * whole, once, whoever lands it: every writer writes the same bytes, so a
112
- * rename over one already there changes nothing, and a reader never meets half of it.
113
- */
114
- function landWhole(at, bytes) {
115
- if (existsSync(at))
116
- return at;
117
- replaceWhole(at, bytes);
118
- return at;
119
- }
120
- /** A file replaced whole: the bytes land in a temp beside it and the name moves in one rename, so a killed write keeps the temp, never a torn file under the name a later read parses. */
121
- export function replaceWhole(at, bytes) {
122
- requireEffects('persistent replacement');
123
- mkdirSync(dirname(at), { recursive: true });
124
- const part = `${at}.${process.pid}.part`;
125
- writeFileSync(part, bytes);
126
- renameSync(part, at);
127
- }
128
- export const landBlob = (store, digest, bytes) => {
129
- const at = landWhole(blobAt(store, digest), bytes);
130
- holdStore(store, 'blobs', digest, bytes.byteLength);
131
- return at;
132
- };
133
- export function holdStore(store, kind, name, bytes) {
134
- const hex = name.replace(/^[^:]*:/, '');
135
- const scope = `cas/${kind}/${hex}`;
136
- const held = ledgerLines(store, 'store').filter((line) => fieldOf(line, 'scope') === scope);
137
- if (held.length && fieldOf(held[held.length - 1], 'value') !== 'withdraw')
138
- return;
139
- land(store, 'store', [canonical({
140
- scope, role: 'writes', form: 'interval', measure: 'bytes',
141
- value: `${bytes}..${bytes}`, at: `place:${kind === 'answers' ? hex : `sha256:${hex}`}`, by: 'store',
142
- })]);
143
- }
144
- export const memoAt = (store, key) => storeAt(store, 'cas', 'memo', ...key.split('/').map((step) => step.replace(/[^a-zA-Z0-9._@-]/g, '_')));
145
- export function landMemo(store, key, bytes) {
146
- const at = memoAt(store, key);
147
- if (existsSync(at))
148
- return at;
149
- mkdirSync(dirname(at), { recursive: true });
150
- const part = `${at}.${process.pid}.part`;
151
- writeFileSync(part, bytes);
152
- try {
153
- linkSync(part, at);
154
- }
155
- catch (error) {
156
- if (error.code !== 'EEXIST')
157
- throw error;
158
- }
159
- finally {
160
- rmSync(part, { force: true });
161
- }
162
- return at;
163
- }
164
- export const landEnvelope = (store, digest, bytes) => landWhole(storeAt(store, 'cas', 'envelopes', `${digest.slice(digest.indexOf(':') + 1)}.json`), bytes);
165
- export function land(store, writer, lines) {
166
- requireEffects('ledger admission');
167
- const at = writerFile(store, writer);
168
- return { at, appended: appendNew(at, lines) };
169
- }
170
- const step = (value) => value.replace(/[^a-zA-Z0-9._@-]/g, '_');
171
- function verdictAt(store, tree, lot) {
172
- return memoAt(store, `verdict/${step(tree)}/${step(lot)}`);
173
- }
174
- export function keptVerdict(store, tree, lot) {
175
- const text = observeText(verdictAt(store, tree, lot));
176
- if (text === undefined)
177
- return undefined;
178
- try {
179
- const got = JSON.parse(text);
180
- return Array.isArray(got) ? got : undefined;
181
- }
182
- catch {
183
- return undefined;
184
- }
185
- }
186
- export function keepVerdict(store, tree, lot, judged) {
187
- landMemo(store, `verdict/${step(tree)}/${step(lot)}`, new TextEncoder().encode(JSON.stringify(judged)));
188
- }
1
+ var X=Object.defineProperty;var o=(e,t)=>X(e,"name",{value:t,configurable:!0});import{hostRequiresFreshBytes as q}from"../host/call-context.js";import{preparingView as C,viewInput as M}from"../host/reading-context.js";import{actLines as w,committedLocalActs as $}from"../host/ports/local-act.js";import{readdirSync as J}from"node:fs";import{requireEffects as A}from"../host/read-only.js";import{appendFileSync as P,closeSync as H,dirname as v,existsSync as h,join as O,linkSync as D,mkdirSync as z,openSync as G,readFileSync as E,readSync as K,renameSync as Q,rmSync as U,statSync as Y,writeFileSync as T}from"../host/io.js";import{storeRoot as ee}from"../host/ports/store.js";import{library14_canonical as te,library14_EXTENSION as d,library14_PROTOCOL as y}from"../vendor/runtime.js";import{fieldOf as p}from"../fold/claims.js";import{observeText as re}from"../observe/files.js";function we(e){return O(ee(e),d)}o(we,"storeOf");function m(e,...t){return O(e,...t)}o(m,"storeAt");function g(e,t){return m(e,"ledger",`${t.replace(/[^a-zA-Z0-9_-]/g,"")}${d}`)}o(g,"writerFile");const W=new Map,u=new Map;let x=0;function b(e){const t=h(e)?E(e,"utf8"):"",r=u.get(e);if(r?.text===t)return r.lines;const n=Object.freeze(t.split(`
2
+ `).filter(s=>s.startsWith(y))),i=Buffer.byteLength(t);if(r&&(x-=Buffer.byteLength(r.text),u.delete(e)),i<=32*1024*1024){for(;u.size>=32||x+i>32*1024*1024;){const s=u.keys().next().value;if(s===void 0)break;x-=Buffer.byteLength(u.get(s).text),u.delete(s)}u.set(e,{text:t,lines:n}),x+=i}return n}o(b,"currentLinesAt");function _(e,t){return B(e,t,".",L(g(e,t)))}o(_,"ledgerLines");function N(e,t,r){return m(e,"ledger",t.replace(/[^a-zA-Z0-9_-]/g,""),`${r.replace(/\/+$/,"")||"@"}${d}`)}o(N,"shardFile");const $e=o((e,t,r)=>B(e,t,r,L(N(e,t,r))),"shardLines"),j=new Map;function B(e,t,r,n){const i=$(e).flatMap(l=>l.bundle.placements?.filter(a=>a.place===r).flatMap(a=>w(a.records).filter(V=>p(V,"by")===t))??[]);if(!i.length)return n;const s=[...new Set([...n,...i])],c=e+"\0"+t+"\0"+r,f=j.get(c);return f?.length===s.length&&f.every((l,a)=>l===s[a])?f:(j.set(c,s),s)}o(B,"journalLines");function k(e){const t=O(e,"ledger");return M("ledger-writers:"+t,()=>h(t)?J(t).filter(r=>r.endsWith(d)).map(r=>r.slice(0,-d.length)):[],!1)}o(k,"legacyWriters");function ve(e){const t=k(e),r=$(e).flatMap(n=>n.bundle.placements?.filter(i=>i.place===".").flatMap(i=>w(i.records).map(s=>p(s,"by")))??[]);return[...new Set([...t,...r])]}o(ve,"ledgerWriters");let F;function Oe(e){const t=k(e),r=$(e);if(!r.length){const s=t.map(l=>b(g(e,l))),c=F;if(c?.store===e&&c.writers.length===t.length&&c.writers.every((l,a)=>l===t[a])&&c.parts.every((l,a)=>l===s[a]))return c.lines;const f=Object.freeze(s.flat());return F={store:e,writers:[...t],parts:s,lines:f},f}const n=r.flatMap(s=>s.bundle.placements?.filter(c=>c.place===".").flatMap(c=>w(c.records))??[]);return[...new Set([...t,...n.map(s=>p(s,"by"))])].flatMap(s=>{const c=g(e,s),f=b(c),l=n.filter(a=>p(a,"by")===s);return l.length?[...new Set([...f,...l])]:f})}o(Oe,"rootLedgerLines");function ze(e,t,r,n){return I(N(e,t,r),n)}o(ze,"landShard");function L(e){if(C())return M("ledger:"+e,()=>b(e),!1);if(q())return b(e);const t=Y(e,{throwIfNoEntry:!1});if(!t)return[];const r=`${Math.floor(t.mtimeMs)}-${t.size}`,n=W.get(e);if(n?.stamp===r)return n.lines;const i=n!==void 0&&n.size>0&&t.size>n.size?ne(e,n.size,t.size):void 0,s=i!==void 0&&n!==void 0?[...n.lines,...i.split(`
3
+ `).filter(c=>c.startsWith(y))]:E(e,"utf8").split(`
4
+ `).filter(c=>c.startsWith(y));return W.set(e,{stamp:r,size:t.size,lines:s}),s}o(L,"linesAt");function ne(e,t,r){const n=G(e,"r");try{const i=Buffer.alloc(r-t+1);return K(n,i,0,i.length,t-1),i[0]===10?i.subarray(1).toString("utf8"):void 0}finally{H(n)}}o(ne,"tailOf");function I(e,t){const r=new Set(L(e)),n=[...new Set(t)].filter(i=>i.startsWith(y)&&!r.has(i));return n.length&&(z(v(e),{recursive:!0}),P(e,`${n.join(`
5
+ `)}
6
+ `)),n.length}o(I,"appendNew");function Le(e,t){return _(e,t).filter(r=>r.includes(`by=${t}`)&&/\bsig=/.test(r))}o(Le,"signedLines");function ie(e,t){return m(e,"cas","blobs",t.slice(t.indexOf(":")+1))}o(ie,"blobAt");function R(e,t){return h(e)||se(e,t),e}o(R,"landWhole");function se(e,t){A("persistent replacement"),z(v(e),{recursive:!0});const r=`${e}.${process.pid}.part`;T(r,t),Q(r,e)}o(se,"replaceWhole");const Me=o((e,t,r)=>{const n=R(ie(e,t),r);return oe(e,"blobs",t,r.byteLength),n},"landBlob");function oe(e,t,r,n){const i=r.replace(/^[^:]*:/,""),s=`cas/${t}/${i}`,c=_(e,"store").filter(f=>p(f,"scope")===s);c.length&&p(c[c.length-1],"value")!=="withdraw"||le(e,"store",[te({scope:s,role:"writes",form:"interval",measure:"bytes",value:`${n}..${n}`,at:`place:${t==="answers"?i:`sha256:${i}`}`,by:"store"})])}o(oe,"holdStore");const Z=o((e,t)=>m(e,"cas","memo",...t.split("/").map(r=>r.replace(/[^a-zA-Z0-9._@-]/g,"_"))),"memoAt");function ce(e,t,r){const n=Z(e,t);if(h(n))return n;z(v(n),{recursive:!0});const i=`${n}.${process.pid}.part`;T(i,r);try{D(i,n)}catch(s){if(s.code!=="EEXIST")throw s}finally{U(i,{force:!0})}return n}o(ce,"landMemo");const Ae=o((e,t,r)=>R(m(e,"cas","envelopes",`${t.slice(t.indexOf(":")+1)}.json`),r),"landEnvelope");function le(e,t,r){A("ledger admission");const n=g(e,t);return{at:n,appended:I(n,r)}}o(le,"land");const S=o(e=>e.replace(/[^a-zA-Z0-9._@-]/g,"_"),"step");function fe(e,t,r){return Z(e,`verdict/${S(t)}/${S(r)}`)}o(fe,"verdictAt");function Ee(e,t,r){const n=re(fe(e,t,r));if(n!==void 0)try{const i=JSON.parse(n);return Array.isArray(i)?i:void 0}catch{return}}o(Ee,"keptVerdict");function Te(e,t,r,n){ce(e,`verdict/${S(t)}/${S(r)}`,new TextEncoder().encode(JSON.stringify(n)))}o(Te,"keepVerdict");export{ie as blobAt,oe as holdStore,Te as keepVerdict,Ee as keptVerdict,le as land,Me as landBlob,Ae as landEnvelope,ce as landMemo,ze as landShard,_ as ledgerLines,ve as ledgerWriters,Z as memoAt,se as replaceWhole,Oe as rootLedgerLines,N as shardFile,$e as shardLines,Le as signedLines,m as storeAt,we as storeOf,g as writerFile};
@@ -1,66 +1,4 @@
1
- import { join, renameSync, writeFileSync } from "../host/io.js";
2
- import { fieldOf, LOCK } from "../fold/claims.js";
3
- import { lockStanding } from "../fold/keys.js";
4
- import { placesIn } from "../fold/places.js";
5
- import { admittedIn, forksIn, tellOwn } from "../fold/signed.js";
6
- import { wordOf } from "../fold/wire.js";
7
- import { observeText } from "../observe/files.js";
8
- import { landShard, storeOf } from "./ledger.js";
9
- /**
10
- * A lot named with --place lands in those own locks and not the ledger: a lot never mixes. A line the ledger does not admit is a place's own when that place's own lock admits it: signed by a key the tree admits,
11
- * inside the window it held, inside its coverage of the place, the line's scope read as a region of the place. An own
12
- * lock speaks of its place without naming it, so a line whose scope names a place first is the ledger's alone, and the
13
- * same line can stand in many own locks: named places take every line they admit, and with none named a line lands in
14
- * the one own lock that admits it. The lines are told to their locks for the gates and land in them signed, beside what
15
- * the ledger takes. A line no lock admits, or one two locks would take and no place names, is admitted nowhere, and a
16
- * batch that holds one is refused whole: nothing is ever written into a lock bare. An own lot never forks a lock: lines
17
- * that would leave a place's lock with two standing claims where it had one are refused whole, so a lot for many places
18
- * lands the same lines at each, and lines meant for one place go in a lot of their own.
19
- */
20
- export function ownedOf(root, signed, admits, coverage, named = [], placedAt = () => undefined) {
21
- const places = placesIn(root);
22
- const headed = (line) => places.includes(fieldOf(line, 'scope').split('/')[0] ?? '');
23
- const ledger = named.length ? [] : signed.filter(admits);
24
- const rest = [...new Set(signed.filter((line) => (named.length || !admits(line)) && !headed(line)))];
25
- const placed = signed.filter((line) => !ledger.includes(line) && !rest.includes(line));
26
- if (!rest.length)
27
- return { ledger, own: new Map(), nowhere: placed, forked: [] };
28
- const family = wordOf(lockStanding(storeOf(root)), 'families', 'region');
29
- const covers = new Set(rest.map((line) => fieldOf(line, 'by')).flatMap((by) => coverage(by)));
30
- const namedOf = (line) => placedAt(line) ?? named;
31
- const asked = [...new Set(rest.flatMap((line) => (namedOf(line).length ? namedOf(line) : places)))].filter((place) => [...covers].some((prefix) => prefix === '*' || prefix.startsWith(`${family}/${place}/`) || prefix === `${family}/${place}`));
32
- const takers = new Map();
33
- for (const place of asked) {
34
- tellOwn(place, rest);
35
- for (const line of rest)
36
- if ((!namedOf(line).length || namedOf(line).includes(place)) && admittedIn(root, place, line))
37
- takers.set(line, [...(takers.get(line) ?? []), place]);
38
- tellOwn(place, []);
39
- }
40
- const lands = (line) => (namedOf(line).length ? (takers.get(line)?.length ?? 0) > 0 : takers.get(line)?.length === 1);
41
- const own = new Map();
42
- for (const line of rest.filter(lands))
43
- for (const place of takers.get(line))
44
- own.set(place, [...(own.get(place) ?? []), line]);
45
- const forked = [...own].flatMap(([place, lines]) => {
46
- tellOwn(place, []);
47
- const before = new Set(forksIn(root, place));
48
- tellOwn(place, lines);
49
- return forksIn(root, place).filter((key) => !before.has(key)).map((key) => ({ place, key }));
50
- });
51
- return { ledger, own, nowhere: [...placed, ...rest.filter((line) => !lands(line))], forked };
52
- }
53
- /** A place's own lock gains the lines a batch landed there, appended whole: a reader never meets half of it, and every line already there keeps its bytes as they were. */
54
- export function landOwned(root, place, lines, committed = false) {
55
- if (!lines.length)
56
- return tellOwn(place, []);
57
- const at = join(root, place, LOCK);
58
- const text = observeText(at) ?? '';
59
- if (!committed)
60
- for (const by of new Set(lines.map(line => fieldOf(line, 'by')))) {
61
- landShard(storeOf(root), by, `${place}/${LOCK}`, lines.filter(line => fieldOf(line, 'by') === by));
62
- }
63
- writeFileSync(`${at}.${process.pid}.landing`, `${text.replace(/\n*$/, '\n')}${lines.join('\n')}\n`);
64
- renameSync(`${at}.${process.pid}.landing`, at);
65
- tellOwn(place, []);
66
- }
1
+ var C=Object.defineProperty;var i=(n,o)=>C(n,"name",{value:o,configurable:!0});import{join as F,renameSync as K,writeFileSync as L}from"../host/io.js";import{fieldOf as g,LOCK as b}from"../fold/claims.js";import{lockStanding as T}from"../fold/keys.js";import{placesIn as W}from"../fold/places.js";import{admittedIn as q,forksIn as k,tellOwn as c}from"../fold/signed.js";import{wordOf as z}from"../fold/wire.js";import{observeText as A}from"../observe/files.js";import{landShard as B,storeOf as M}from"./ledger.js";function U(n,o,s,w,r=[],h=()=>{}){const l=W(n),a=i(t=>l.includes(g(t,"scope").split("/")[0]??""),"headed"),$=r.length?[]:o.filter(s),f=[...new Set(o.filter(t=>(r.length||!s(t))&&!a(t)))],S=o.filter(t=>!$.includes(t)&&!f.includes(t));if(!f.length)return{ledger:$,own:new Map,nowhere:S,forked:[]};const O=z(T(M(n)),"families","region"),I=new Set(f.map(t=>g(t,"by")).flatMap(t=>w(t))),d=i(t=>h(t)??r,"namedOf"),j=[...new Set(f.flatMap(t=>d(t).length?d(t):l))].filter(t=>[...I].some(e=>e==="*"||e.startsWith(`${O}/${t}/`)||e===`${O}/${t}`)),m=new Map;for(const t of j){c(t,f);for(const e of f)(!d(e).length||d(e).includes(t))&&q(n,t,e)&&m.set(e,[...m.get(e)??[],t]);c(t,[])}const y=i(t=>d(t).length?(m.get(t)?.length??0)>0:m.get(t)?.length===1,"lands"),p=new Map;for(const t of f.filter(y))for(const e of m.get(t))p.set(e,[...p.get(e)??[],t]);const v=[...p].flatMap(([t,e])=>{c(t,[]);const x=new Set(k(n,t));return c(t,e),k(n,t).filter(u=>!x.has(u)).map(u=>({place:t,key:u}))});return{ledger:$,own:p,nowhere:[...S,...f.filter(t=>!y(t))],forked:v}}i(U,"ownedOf");function V(n,o,s,w=!1){if(!s.length)return c(o,[]);const r=F(n,o,b),h=A(r)??"";if(!w)for(const l of new Set(s.map(a=>g(a,"by"))))B(M(n),l,`${o}/${b}`,s.filter(a=>g(a,"by")===l));L(`${r}.${process.pid}.landing`,`${h.replace(/\n*$/,`
2
+ `)}${s.join(`
3
+ `)}
4
+ `),K(`${r}.${process.pid}.landing`,r),c(o,[])}i(V,"landOwned");export{V as landOwned,U as ownedOf};
package/dist/land/sign.js CHANGED
@@ -1,53 +1 @@
1
- import { canonical, parse, parseForSigning, signedBytes, signedFieldsOf } from '@lapxo/topos/wire';
2
- import { verifyBytes } from "../host/adapters/keys/ed25519.js";
3
- import { SigningFailure } from "../host/ports/signing.js";
4
- function prepareConsentLine(line, stamp) {
5
- const got = parseForSigning(line);
6
- if (got.kind !== 'fact')
7
- return { kind: 'refuse', why: 'REFUSE·accept not a claim line' };
8
- const fields = got.value.fields;
9
- const scope = fields['scope'] ?? '?';
10
- if (fields['sig'] !== undefined)
11
- return { kind: 'refuse', why: `REFUSE·accept ${scope} is already signed` };
12
- if (fields['by'] !== 'target')
13
- return { kind: 'refuse', why: `REFUSE·accept ${scope} must be drafted by=target` };
14
- const covered = signedFieldsOf(fields, stamp.by);
15
- if (stamp.epoch !== undefined)
16
- covered['epoch'] = String(stamp.epoch);
17
- return { kind: 'fact', fields: covered };
18
- }
19
- /** Prepare and verify a whole lot. No key material and no output/admission side effects. */
20
- export async function signConsentLot(lines, stamp, publicKey, admitted, invoke) {
21
- const fields = [];
22
- for (const line of lines) {
23
- const prepared = prepareConsentLine(line, stamp);
24
- if (prepared.kind === 'refuse')
25
- return prepared;
26
- fields.push(prepared.fields);
27
- }
28
- if (!fields.length)
29
- return { kind: 'refuse', why: `REFUSE·signer ${stamp.by} empty lot` };
30
- let records;
31
- try {
32
- records = await invoke({ bytes: fields.map(f => signedBytes(f)), keyId: stamp.by, algorithm: stamp.algorithm });
33
- }
34
- catch (error) {
35
- return { kind: 'refuse', why: error instanceof SigningFailure ? error.message : `REFUSE·signer ${stamp.by} acquisition failed` };
36
- }
37
- if (records.length !== fields.length || records.some((record, i) => record.keyId !== stamp.by
38
- || !verifyBytes(signedBytes(fields[i]), publicKey, record.signature, admitted))) {
39
- return { kind: 'refuse', why: `REFUSE·signer ${stamp.by} signature does not verify` };
40
- }
41
- return { kind: 'fact', lines: fields.map((f, i) => canonical({ ...f, sig: records[i].signature })) };
42
- }
43
- export function verifiesOwnerLine(line, publicKeyPem, admitted) {
44
- const got = parse(line);
45
- if (got.kind !== 'fact')
46
- return false;
47
- const { sig, ...rest } = got.value.fields;
48
- return typeof sig === 'string' && verifyBytes(signedBytes(rest), publicKeyPem, sig, admitted);
49
- }
50
- export function verifiesFields(fields, publicKey, admitted) {
51
- const { sig, ...rest } = fields;
52
- return typeof sig === 'string' && verifyBytes(signedBytes(rest), publicKey, sig, admitted);
53
- }
1
+ var d=Object.defineProperty;var f=(r,e)=>d(r,"name",{value:e,configurable:!0});import{library14_canonical as p,library14_parse as h,library14_parseForSigning as b,library14_signedBytes as g,library14_signedFieldsOf as k}from"../vendor/runtime.js";import{verifyBytes as u}from"../host/adapters/keys/ed25519.js";import{SigningFailure as v}from"../host/ports/signing.js";function F(r,e){const a=b(r);if(a.kind!=="fact")return{kind:"refuse",why:"REFUSE\xB7accept not a claim line"};const s=a.value.fields,n=s.scope??"?";if(s.sig!==void 0)return{kind:"refuse",why:`REFUSE\xB7accept ${n} is already signed`};if(s.by!=="target")return{kind:"refuse",why:`REFUSE\xB7accept ${n} must be drafted by=target`};const i=k(s,e.by);return e.epoch!==void 0&&(i.epoch=String(e.epoch)),{kind:"fact",fields:i}}f(F,"prepareConsentLine");async function O(r,e,a,s,n){const i=[];for(const t of r){const o=F(t,e);if(o.kind==="refuse")return o;i.push(o.fields)}if(!i.length)return{kind:"refuse",why:`REFUSE\xB7signer ${e.by} empty lot`};let c;try{c=await n({bytes:i.map(t=>g(t)),keyId:e.by,algorithm:e.algorithm})}catch(t){return{kind:"refuse",why:t instanceof v?t.message:`REFUSE\xB7signer ${e.by} acquisition failed`}}return c.length!==i.length||c.some((t,o)=>t.keyId!==e.by||!u(g(i[o]),a,t.signature,s))?{kind:"refuse",why:`REFUSE\xB7signer ${e.by} signature does not verify`}:{kind:"fact",lines:i.map((t,o)=>p({...t,sig:c[o].signature}))}}f(O,"signConsentLot");function R(r,e,a){const s=h(r);if(s.kind!=="fact")return!1;const{sig:n,...i}=s.value.fields;return typeof n=="string"&&u(g(i),e,n,a)}f(R,"verifiesOwnerLine");const y=new WeakMap;function U(r,e,a){const s=JSON.stringify(a),n=y.get(r);if(n&&n.publicKey===e&&n.algorithms===s)return n.valid;const i=n!==void 0||Object.isFrozen(r)&&Object.prototype.hasOwnProperty.call(r,"sig")&&Object.values(Object.getOwnPropertyDescriptors(r)).every(l=>"value"in l&&typeof l.value=="string"),{sig:c,...t}=r,o=typeof c=="string"&&u(g(t),e,c,a);return i&&y.set(r,{publicKey:e,algorithms:s,valid:o}),o}f(U,"verifiesFields");export{O as signConsentLot,U as verifiesFields,R as verifiesOwnerLine};
@@ -1,49 +1 @@
1
- import { readStanding } from '@lapxo/topos/standing';
2
- import { fieldOf } from "../fold/claims.js";
3
- import { contentAt } from "../host/selected-topos.js";
4
- import { storeOf } from "./ledger.js";
5
- import { ContentNeeded } from "../host/content-needed.js";
6
- import { observeFile } from "../observe/files.js";
7
- import { createHash } from 'node:crypto';
8
- import { resolve, relative } from 'node:path';
9
- /** A declared local file is already held content. Check its bytes before
10
- * admission; neither fetch it nor write a CAS entry during this inspection. */
11
- function heldStanding(root, line) {
12
- const digest = fieldOf(line, 'value');
13
- try {
14
- return contentAt(digest, storeOf(root));
15
- }
16
- catch (error) {
17
- if (!(error instanceof ContentNeeded))
18
- throw error;
19
- }
20
- const name = fieldOf(line, 'needs');
21
- if (!name || name.includes('|') || name.includes('*'))
22
- throw new ContentNeeded(digest);
23
- const path = resolve(root, name), local = relative(resolve(root), path);
24
- if (!local || local === '..' || local.startsWith('../'))
25
- throw Error('standing coordinate is outside the place');
26
- const bytes = observeFile(path);
27
- if (bytes === undefined)
28
- throw new ContentNeeded(digest);
29
- const split = digest.indexOf(':'), algorithm = digest.slice(0, split), hex = digest.slice(split + 1);
30
- if (createHash(algorithm).update(bytes).digest('hex') !== hex)
31
- throw Error('standing coordinate content hash mismatch');
32
- return bytes;
33
- }
34
- /** A new world selection names standing bytes. Artifact aliases remain separate.
35
- * Admission reads laid content only; it never fetches or executes a provider. */
36
- export function admitStandingPins(root, lines, read) {
37
- for (const line of lines) {
38
- const scope = fieldOf(line, 'scope'), value = fieldOf(line, 'value');
39
- const parts = scope.split('/');
40
- if (!(scope === 'uses' || parts.slice(0, -1).includes('uses')) || value === 'withdraw')
41
- continue;
42
- try {
43
- readStanding(new TextDecoder('utf-8', { fatal: true }).decode(read ? read(value) : heldStanding(root, line)));
44
- }
45
- catch (error) {
46
- throw Error(`REFUSE·pin ${scope} ${value} · ${error instanceof Error ? error.message : String(error)} · nothing landed`);
47
- }
48
- }
49
- }
1
+ var u=Object.defineProperty;var d=(r,n)=>u(r,"name",{value:n,configurable:!0});import{library10_readStanding as g}from"../vendor/runtime.js";import{fieldOf as c}from"../fold/claims.js";import{contentAt as w}from"../host/selected-topos.js";import{storeOf as v}from"./ledger.js";import{ContentNeeded as f}from"../host/content-needed.js";import{observeFile as E}from"../observe/files.js";import{createHash as S}from"node:crypto";import{resolve as m,relative as x}from"node:path";function y(r,n){const t=c(n,"value");try{return w(t,v(r))}catch(l){if(!(l instanceof f))throw l}const e=c(n,"needs");if(!e||e.includes("|")||e.includes("*"))throw new f(t);const i=m(r,e),o=x(m(r),i);if(!o||o===".."||o.startsWith("../"))throw Error("standing coordinate is outside the place");const a=E(i);if(a===void 0)throw new f(t);const s=t.indexOf(":"),h=t.slice(0,s),p=t.slice(s+1);if(S(h).update(a).digest("hex")!==p)throw Error("standing coordinate content hash mismatch");return a}d(y,"heldStanding");function P(r,n,t){for(const e of n){const i=c(e,"scope"),o=c(e,"value"),a=i.split("/");if(!(!(i==="uses"||a.slice(0,-1).includes("uses"))||o==="withdraw"))try{g(new TextDecoder("utf-8",{fatal:!0}).decode(t?t(o):y(r,e)))}catch(s){throw Error(`REFUSE\xB7pin ${i} ${o} \xB7 ${s instanceof Error?s.message:String(s)} \xB7 nothing landed`)}}}d(P,"admitStandingPins");export{P as admitStandingPins};
@@ -1,112 +1 @@
1
- import { createHash, join } from "../host/io.js";
2
- import { said, wordOf, wordsOf } from "../fold/wire.js";
3
- import { fieldOf } from "../fold/claims.js";
4
- import { point, region, within } from '@lapxo/obligations/field';
5
- import { canonical } from '@lapxo/topos/wire';
6
- import { land, ledgerLines } from "./ledger.js";
7
- import { lockStanding } from "../fold/keys.js";
8
- import { ownLock } from "../observe/runner.js";
9
- import { entriesIn, linkOf, observeFile, observeText, stampOf } from "../observe/files.js";
10
- /** A location is a file or a directory; `x/*` names the directory `x/`. A deeper glob is not a location. */
11
- export function locationsOf(needs) {
12
- const locations = [];
13
- const refused = [];
14
- for (const raw of needs.split('|').map((n) => n.trim()).filter(Boolean)) {
15
- const steps = raw.split('/').filter(Boolean);
16
- while (steps[steps.length - 1] === '*' || steps[steps.length - 1] === '**')
17
- steps.pop();
18
- if (!steps.length || raw.includes('#') || steps.some((step) => step.includes('*'))) {
19
- refused.push(raw);
20
- continue;
21
- }
22
- locations.push(steps.join('/'));
23
- }
24
- return { locations, refused };
25
- }
26
- function digestOf(bytes) {
27
- return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
28
- }
29
- /**
30
- * The source coordinates under one location, by digest. A path whose role is not source is never walked, so nothing under
31
- * it is read. A link is a coordinate whose bytes are its target; it is never followed.
32
- */
33
- export function coordinatesOf(root, location, roleOf) {
34
- const out = new Map();
35
- const visit = (rel) => {
36
- if (roleOf(rel) !== 'source')
37
- return;
38
- const abs = join(root, rel);
39
- const st = stampOf(abs);
40
- if (!st)
41
- return;
42
- if (st.kind === 'link') {
43
- out.set(rel, digestOf(`link:${linkOf(abs)}`));
44
- return;
45
- }
46
- if (st.kind === 'dir') {
47
- for (const name of entriesIn(abs).map((entry) => entry.name).sort())
48
- visit(join(rel, name));
49
- return;
50
- }
51
- if (st.kind === 'file')
52
- out.set(rel, digestOf(Buffer.from(observeFile(abs) ?? new Uint8Array())));
53
- };
54
- visit(location.replace(/\/$/, ''));
55
- return out;
56
- }
57
- /** The law a witness file says it answers for: its own `witness=<law>` line, or its `"witness"` field. */
58
- export function witnessOf(root, coordinate) {
59
- if (stampOf(join(root, coordinate))?.kind !== 'file')
60
- return undefined;
61
- const text = observeText(join(root, coordinate)) ?? '';
62
- return /^witness=([^\s]+)/m.exec(text)?.[1] ?? /"witness"\s*:\s*"([^"]+)"/.exec(text)?.[1];
63
- }
64
- function storeFamily(standing, coordinate) {
65
- const names = said(ownLock(), coordinate);
66
- if (!names.length)
67
- throw new Error(`REFUSE·instrument ${coordinate} has no admitted declaration in the instrument lock`);
68
- return wordsOf(standing, 'families').length ? wordOf(standing, 'families', names) : names[0];
69
- }
70
- export const vouching = (standing) => storeFamily(standing, 'store/vouches');
71
- export const sourced = (standing) => storeFamily(standing, 'store/source');
72
- export const sourceOf = (line) => (fieldOf(line, 'measure') === 'digest' && fieldOf(line, 'scope').includes('/') ? fieldOf(line, 'scope').slice(fieldOf(line, 'scope').indexOf('/') + 1) : undefined);
73
- export function inside(path, location) {
74
- return within(point(path), region(location));
75
- }
76
- export function vouchedCoordinates(store) {
77
- const out = new Map();
78
- const standing = lockStanding(store);
79
- if (!wordsOf(standing, 'states').length)
80
- return out;
81
- const absent = wordOf(standing, 'states', 'absent');
82
- for (const line of ledgerLines(store, vouching(standing))) {
83
- const path = sourceOf(line);
84
- const value = fieldOf(line, 'value');
85
- if (!path || !value)
86
- continue;
87
- if (value === absent)
88
- out.delete(path);
89
- else
90
- out.set(path, value);
91
- }
92
- return out;
93
- }
94
- export function everLanded(store) {
95
- const out = new Set();
96
- for (const line of ledgerLines(store, vouching(lockStanding(store)))) {
97
- const path = sourceOf(line);
98
- if (path)
99
- out.add(path);
100
- }
101
- return out;
102
- }
103
- export function hasVouchedTree(store) {
104
- return ledgerLines(store, vouching(lockStanding(store))).length > 0;
105
- }
106
- export function landCoordinates(store, present, gone, at) {
107
- const standing = lockStanding(store);
108
- const line = (path, value) => canonical({
109
- scope: `${sourced(standing)}/${path}`, role: 'writes', form: 'alphabet', measure: 'digest', value, by: 'land', at,
110
- });
111
- return land(store, vouching(standing), [...[...present].map(([path, value]) => line(path, value)), ...gone.map((path) => line(path, wordOf(standing, 'states', 'absent')))]).appended;
112
- }
1
+ var v=Object.defineProperty;var r=(e,n)=>v(e,"name",{value:n,configurable:!0});import{createHash as y,join as u}from"../host/io.js";import{said as $,wordOf as d,wordsOf as h}from"../fold/wire.js";import{fieldOf as f}from"../fold/claims.js";import{library0_point as _,library0_region as B,library0_within as E}from"../vendor/runtime.js";import{library14_canonical as F}from"../vendor/runtime.js";import{land as L,ledgerLines as m}from"./ledger.js";import{lockStanding as p}from"../fold/keys.js";import{ownLock as S}from"../observe/runner.js";import{entriesIn as j,linkOf as C,observeFile as M,observeText as T,stampOf as g}from"../observe/files.js";function K(e){const n=[],o=[];for(const i of e.split("|").map(t=>t.trim()).filter(Boolean)){const t=i.split("/").filter(Boolean);for(;t[t.length-1]==="*"||t[t.length-1]==="**";)t.pop();if(!t.length||i.includes("#")||t.some(s=>s.includes("*"))){o.push(i);continue}n.push(t.join("/"))}return{locations:n,refused:o}}r(K,"locationsOf");function w(e){return`sha256:${y("sha256").update(e).digest("hex")}`}r(w,"digestOf");function N(e,n,o){const i=new Map,t=r(s=>{if(o(s)!=="source")return;const a=u(e,s),c=g(a);if(c){if(c.kind==="link"){i.set(s,w(`link:${C(a)}`));return}if(c.kind==="dir"){for(const O of j(a).map(k=>k.name).sort())t(u(s,O));return}c.kind==="file"&&i.set(s,w(Buffer.from(M(a)??new Uint8Array)))}},"visit");return t(n.replace(/\/$/,"")),i}r(N,"coordinatesOf");function P(e,n){if(g(u(e,n))?.kind!=="file")return;const o=T(u(e,n))??"";return/^witness=([^\s]+)/m.exec(o)?.[1]??/"witness"\s*:\s*"([^"]+)"/.exec(o)?.[1]}r(P,"witnessOf");function x(e,n){const o=$(S(),n);if(!o.length)throw new Error(`REFUSE\xB7instrument ${n} has no admitted declaration in the instrument lock`);return h(e,"families").length?d(e,"families",o):o[0]}r(x,"storeFamily");const l=r(e=>x(e,"store/vouches"),"vouching"),U=r(e=>x(e,"store/source"),"sourced"),b=r(e=>f(e,"measure")==="digest"&&f(e,"scope").includes("/")?f(e,"scope").slice(f(e,"scope").indexOf("/")+1):void 0,"sourceOf");function Q(e,n){return E(_(e),B(n))}r(Q,"inside");function W(e){const n=new Map,o=p(e);if(!h(o,"states").length)return n;const i=d(o,"states","absent");for(const t of m(e,l(o))){const s=b(t),a=f(t,"value");!s||!a||(a===i?n.delete(s):n.set(s,a))}return n}r(W,"vouchedCoordinates");function X(e){const n=new Set;for(const o of m(e,l(p(e)))){const i=b(o);i&&n.add(i)}return n}r(X,"everLanded");function Y(e){return m(e,l(p(e))).length>0}r(Y,"hasVouchedTree");function Z(e,n,o,i){const t=p(e),s=r((a,c)=>F({scope:`${U(t)}/${a}`,role:"writes",form:"alphabet",measure:"digest",value:c,by:"land",at:i}),"line");return L(e,l(t),[...[...n].map(([a,c])=>s(a,c)),...o.map(a=>s(a,d(t,"states","absent")))]).appended}r(Z,"landCoordinates");export{N as coordinatesOf,X as everLanded,Y as hasVouchedTree,Q as inside,Z as landCoordinates,K as locationsOf,b as sourceOf,U as sourced,W as vouchedCoordinates,l as vouching,P as witnessOf};
@@ -1,24 +1 @@
1
- import { ENVELOPE } from '@lapxo/topos/wire';
2
- import { fieldsOf } from "../fold/claims.js";
3
- import { declaredConfig as declared } from '@lapxo/topos/forms';
4
- /** A withdrawal takes every held line that states each field it states, its value and envelope aside. The signer's name is the envelope: a key whose coverage holds the scope takes a standing line of it, whoever signed that line. */
5
- function takes(withdraw, line) {
6
- const w = fieldsOf(withdraw);
7
- const f = fieldsOf(line);
8
- return Object.keys(w).filter((k) => !ENVELOPE.has(k) && k !== 'value').every((k) => f[k] === w[k]);
9
- }
10
- export function retractedTogether(signed) {
11
- const withdraws = signed.filter((line) => fieldsOf(line)['value'] === 'withdraw');
12
- const claims = signed.filter((line) => fieldsOf(line)['value'] !== 'withdraw');
13
- return withdraws.flatMap((withdraw) => claims.filter((line) => takes(withdraw, line)).map((line) => ({ withdraw, line })));
14
- }
15
- export function withdrawal(withdraws, held) {
16
- const taken = held.filter((line) => fieldsOf(line)['value'] !== 'withdraw' && withdraws.some((w) => takes(w, line)));
17
- const scaled = taken.map((line) => ({ line, got: declared(line) }));
18
- return {
19
- taken,
20
- exact: scaled.filter((x) => x.got.distributive === true).map((x) => x.line),
21
- inexact: scaled.filter((x) => x.got.distributive === false).map((x) => x.line),
22
- open: scaled.filter((x) => x.got.distributive === null).map((x) => x.line),
23
- };
24
- }
1
+ var s=Object.defineProperty;var o=(r,i)=>s(r,"name",{value:i,configurable:!0});import{library14_ENVELOPE as c}from"../vendor/runtime.js";import{fieldsOf as l}from"../fold/claims.js";import{library7_declaredConfig as u}from"../vendor/runtime.js";function f(r,i){const a=l(r),e=l(i);return Object.keys(a).filter(t=>!c.has(t)&&t!=="value").every(t=>e[t]===a[t])}o(f,"takes");function v(r){const i=r.filter(e=>l(e).value==="withdraw"),a=r.filter(e=>l(e).value!=="withdraw");return i.flatMap(e=>a.filter(t=>f(e,t)).map(t=>({withdraw:e,line:t})))}o(v,"retractedTogether");function b(r,i){const a=i.filter(t=>l(t).value!=="withdraw"&&r.some(n=>f(n,t))),e=a.map(t=>({line:t,got:u(t)}));return{taken:a,exact:e.filter(t=>t.got.distributive===!0).map(t=>t.line),inexact:e.filter(t=>t.got.distributive===!1).map(t=>t.line),open:e.filter(t=>t.got.distributive===null).map(t=>t.line)}}o(b,"withdrawal");export{v as retractedTogether,b as withdrawal};
@@ -1,88 +1 @@
1
- import { existsSync, lstatSync, statSync, readFileSync, readdirSync, readlinkSync } from 'node:fs';
2
- import { join, relative, sep } from 'node:path';
3
- /**
4
- * The one place the instrument reads the world: a coordinate's bytes, the entries of a directory, the coordinates under a place,
5
- * a link's target and a coordinate's stamp. Every fold, render and landing asks here, so each reading is made once and named.
6
- */
7
- const seen = new Map();
8
- /** A coordinate read once is kept by its stamp — its inode, size and time — and read again only when the stamp moves. */
9
- function bytesAt(at) {
10
- // Reading follows a link, so its cache stamp must describe the same target.
11
- // Directory links have no file bytes; traversal keeps its separate link policy.
12
- let st = stampable(at);
13
- if (st?.isSymbolicLink()) {
14
- try {
15
- st = statSync(at);
16
- }
17
- catch {
18
- return undefined;
19
- }
20
- }
21
- if (st === undefined || st.isDirectory() || !existsSync(at))
22
- return undefined;
23
- const stamp = `${st.ino}-${st.size}-${st.mtimeMs}`;
24
- const held = seen.get(at);
25
- if (held?.stamp === stamp)
26
- return held.bytes;
27
- let bytes;
28
- try {
29
- bytes = readFileSync(at);
30
- }
31
- catch (error) {
32
- // A concurrent act can retire a coordinate after its stamp was read.
33
- if (error.code !== 'ENOENT')
34
- throw error;
35
- seen.delete(at);
36
- return undefined;
37
- }
38
- seen.set(at, { stamp, bytes });
39
- return bytes;
40
- }
41
- export const observeFile = (at) => ((bytes) => (bytes === undefined ? undefined : new Uint8Array(bytes)))(bytesAt(at));
42
- export const observeText = (at) => bytesAt(at)?.toString('utf8');
43
- export const exists = (at) => existsSync(at);
44
- export function stampOf(at) {
45
- const st = stampable(at);
46
- if (!st)
47
- return undefined;
48
- const kind = st.isSymbolicLink() ? 'link' : st.isDirectory() ? 'dir' : st.isFile() ? 'file' : 'other';
49
- return { kind, stamp: `${Math.floor(st.mtimeMs)}-${st.size}` };
50
- }
51
- /** A coordinate listed a moment ago can be gone before it is read: a landing renames its file into place. Gone is none. */
52
- function stampable(at) {
53
- try {
54
- return lstatSync(at);
55
- }
56
- catch {
57
- return undefined;
58
- }
59
- }
60
- export const linkOf = (at) => readlinkSync(at);
61
- export function entriesIn(at) {
62
- if (!stampable(at)?.isDirectory())
63
- return [];
64
- return readdirSync(at, { withFileTypes: true }).map((entry) => ({ name: entry.name, dir: entry.isDirectory() }));
65
- }
66
- export function coordinatesUnder(dir, root, into = () => true) {
67
- const out = [];
68
- const name = (at) => relative(root, at).split(sep).join('/');
69
- const walk = (at, kind) => {
70
- if (kind === 'link')
71
- return;
72
- if (kind === 'file') {
73
- out.push(name(at));
74
- return;
75
- }
76
- if (kind !== 'dir' || !into(name(at)))
77
- return;
78
- for (const entry of readdirSync(at, { withFileTypes: true })) {
79
- const here = join(at, entry.name);
80
- if (entry.isSymbolicLink())
81
- continue;
82
- walk(here, entry.isFile() ? 'file' : entry.isDirectory() ? 'dir' : 'other');
83
- }
84
- };
85
- const st = stampable(dir);
86
- walk(dir, !st ? 'other' : st.isSymbolicLink() ? 'link' : st.isDirectory() ? 'dir' : st.isFile() ? 'file' : 'other');
87
- return out;
88
- }
1
+ var F=Object.defineProperty;var r=(e,t)=>F(e,"name",{value:t,configurable:!0});import{hostRequiresFreshBytes as T}from"../host/call-context.js";import{preparingView as E,viewInput as p}from"../host/reading-context.js";import{existsSync as b,lstatSync as I,statSync as v,readFileSync as a,readdirSync as g,readlinkSync as D}from"node:fs";import{join as L,relative as M,sep as B}from"node:path";const m=new Map;function N(e){let t=y(e);if(t?.isSymbolicLink())try{t=v(e)}catch{return}if(t===void 0||t.isDirectory()||!b(e))return;const n=`${t.ino}-${t.size}-${t.mtimeMs}`,o=m.get(e);if(o?.stamp===n)return o.bytes;let i;try{i=a(e)}catch(c){if(c.code!=="ENOENT")throw c;m.delete(e);return}return m.set(e,{stamp:n,bytes:i}),i}r(N,"bytesAt");const s=new Map;let f=0;const S=16*1024*1024,R=256;function w(e){let t;try{t=a(e)}catch(i){if(!["ENOENT","EISDIR"].includes(i.code??""))throw i;const c=s.get(e);c&&(f-=c.bytes.length,s.delete(e));return}const n=s.get(e);if(n&&t.equals(n.bytes))return n;n&&(f-=n.bytes.length,s.delete(e));const o={bytes:t,encoded:t.toString("base64")};if(t.length<=S){for(;s.size>=R||f+t.length>S;){const i=s.keys().next().value;f-=s.get(i).bytes.length,s.delete(i)}s.set(e,o),f+=t.length}return o}r(w,"currentFile");function k(e){if(!E())return T()?w(e)?.bytes:N(e);const t=p("file:"+e,()=>w(e)?.encoded);if(t===void 0)return;const n=s.get(e);return n?.encoded===t?n.bytes:Buffer.from(t,"base64")}r(k,"viewBytes");const j=r(e=>(t=>t===void 0?void 0:new Uint8Array(t))(k(e)),"observeFile"),q=r(e=>k(e)?.toString("utf8"),"observeText"),A=r(e=>b(e),"exists");function C(e){const t=y(e);return t?{kind:t.isSymbolicLink()?"link":t.isDirectory()?"dir":t.isFile()?"file":"other",stamp:`${Math.floor(t.mtimeMs)}-${t.size}`}:void 0}r(C,"stampOf");function y(e){try{return I(e)}catch{return}}r(y,"stampable");const V=r(e=>D(e),"linkOf");function Y(e){return y(e)?.isDirectory()?p("entries:"+e,()=>g(e,{withFileTypes:!0}).map(t=>({name:t.name,dir:t.isDirectory()}))):[]}r(Y,"entriesIn");function G(e,t,n=()=>!0){const o=[],i=r(u=>M(t,u).split(B).join("/"),"name"),c=r((u,h)=>{if(h!=="link"){if(h==="file"){o.push(i(u));return}if(!(h!=="dir"||!n(i(u))))for(const l of g(u,{withFileTypes:!0})){const x=L(u,l.name);l.isSymbolicLink()||c(x,l.isFile()?"file":l.isDirectory()?"dir":"other")}}},"walk"),d=y(e);return c(e,d?d.isSymbolicLink()?"link":d.isDirectory()?"dir":d.isFile()?"file":"other":"other"),o}r(G,"coordinatesUnder");export{G as coordinatesUnder,Y as entriesIn,A as exists,V as linkOf,j as observeFile,q as observeText,C as stampOf};