@lapxo/bound 0.2.4 → 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 (250) hide show
  1. package/CITATION.cff +1 -1
  2. package/TARGET.bound +44 -39
  3. package/dist/cli/accept.js +72 -590
  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 -282
  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 -19
  18. package/dist/cli/takes.js +10 -112
  19. package/dist/cli/verb.d.ts +1 -2
  20. package/dist/cli/verb.js +83 -684
  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 -117
  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 -132
  32. package/dist/fold/closed.js +24 -235
  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 -35
  70. package/dist/host/archive.js +1 -152
  71. package/dist/host/call-context.js +1 -14
  72. package/dist/host/capsule-process.js +2 -62
  73. package/dist/host/capsule.js +9 -171
  74. package/dist/host/cell-receipts.js +12 -128
  75. package/dist/host/commit-result.js +1 -5
  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 -72
  79. package/dist/host/digest.js +2 -15
  80. package/dist/host/hash.js +1 -9
  81. package/dist/host/host-controls.js +1 -19
  82. package/dist/host/in-process-act.js +3 -84
  83. package/dist/host/in-process-context.js +3 -91
  84. package/dist/host/in-process-root.js +6 -84
  85. package/dist/host/in-process.js +4 -55
  86. package/dist/host/index.d.ts +1 -15
  87. package/dist/host/index.js +1 -7
  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 -25
  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 -78
  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 -183
  128. package/dist/host/ports/place-act.js +1 -134
  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 -307
  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 -12
  157. package/dist/host/signing.js +2 -48
  158. package/dist/host/source-content.js +2 -111
  159. package/dist/host/standing-carrier.js +1 -18
  160. package/dist/host/standing-projection.js +1 -50
  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 -336
  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 -41
  182. package/dist/observe/runner.js +4 -101
  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-publication.inventory.json +2 -1
  212. package/docs/contracts/optional-wasm-adapter.publication.json +1 -1
  213. package/docs/contracts/reading-identity.md +37 -0
  214. package/docs/contracts/reading-identity.publication.json +25 -0
  215. package/docs/contracts/refusals.bound +51 -0
  216. package/docs/contracts/refusals.md +18 -3
  217. package/docs/contracts/refusals.publication.json +2 -2
  218. package/docs/contracts/views.md +8 -0
  219. package/docs/reference.md +1 -0
  220. package/package.json +23 -34
  221. package/receipts.bound +11627 -10323
  222. package/samples/reading-identity/no.json +20 -0
  223. package/samples/reading-identity/yes.json +46 -0
  224. package/vectors/native/reading-identity.vector.json +101 -0
  225. package/vectors/native/refusals.vector.json +104 -0
  226. package/vendor/syntax/LICENSE.md +7 -0
  227. package/vendor/syntax/parser.js +1 -0
  228. package/.github/workflows/release.yml +0 -67
  229. package/.github/workflows/test.yml +0 -35
  230. package/dist/engine/object.d.ts +0 -17
  231. package/dist/engine/ports.d.ts +0 -37
  232. package/dist/fold/claims.d.ts +0 -29
  233. package/dist/host/call-context.d.ts +0 -20
  234. package/dist/host/commit-result.d.ts +0 -6
  235. package/dist/host/in-process-act.d.ts +0 -82
  236. package/dist/host/in-process-context.d.ts +0 -46
  237. package/dist/host/in-process-root.d.ts +0 -117
  238. package/dist/host/in-process.d.ts +0 -41
  239. package/dist/host/native/module-closure.d.ts +0 -35
  240. package/dist/host/native-receiver.d.ts +0 -19
  241. package/dist/host/place-act-transaction.d.ts +0 -24
  242. package/dist/host/place-clock-selection.d.ts +0 -55
  243. package/dist/host/ports/local-act.d.ts +0 -44
  244. package/dist/host/ports/place-act.d.ts +0 -49
  245. package/dist/host/ports/publication.d.ts +0 -10
  246. package/dist/host/reference-export.d.ts +0 -33
  247. package/dist/host/reference-native.d.ts +0 -30
  248. package/dist/host/reference-profile.d.ts +0 -23
  249. package/dist/host/refusals.d.ts +0 -14
  250. package/dist/host/root-clock-source.d.ts +0 -86
@@ -1,188 +1,7 @@
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 Z=Object.defineProperty;var i=(e,t)=>Z(e,"name",{value:t,configurable:!0});import{preparingView as R,viewInput as M}from"../host/reading-context.js";import{actLines as g,committedLocalActs as x}from"../host/ports/local-act.js";import{readdirSync as V}from"node:fs";import{requireEffects as z}from"../host/read-only.js";import{appendFileSync as X,closeSync as B,dirname as S,existsSync as u,join as $,linkSync as C,mkdirSync as b,openSync as J,readFileSync as w,readSync as P,renameSync as q,rmSync as D,statSync as G,writeFileSync as A}from"../host/io.js";import{storeRoot as H}from"../host/ports/store.js";import{library11_canonical as K,library11_EXTENSION as d,library11_PROTOCOL as m}from"../vendor/runtime.js";import{fieldOf as p}from"../fold/claims.js";import{observeText as Q}from"../observe/files.js";function he(e){return $(H(e),d)}i(he,"storeOf");function h(e,...t){return $(e,...t)}i(h,"storeAt");function O(e,t){return h(e,"ledger",`${t.replace(/[^a-zA-Z0-9_-]/g,"")}${d}`)}i(O,"writerFile");const L=new Map;function E(e,t){return N(e,t,".",v(O(e,t)))}i(E,"ledgerLines");function W(e,t,n){return h(e,"ledger",t.replace(/[^a-zA-Z0-9_-]/g,""),`${n.replace(/\/+$/,"")||"@"}${d}`)}i(W,"shardFile");const ye=i((e,t,n)=>N(e,t,n,v(W(e,t,n))),"shardLines"),_=new Map;function N(e,t,n,r){const o=x(e).flatMap(f=>f.bundle.placements?.filter(l=>l.place===n).flatMap(l=>g(l.records).filter(k=>p(k,"by")===t))??[]);if(!o.length)return r;const s=[...new Set([...r,...o])],c=e+"\0"+t+"\0"+n,a=_.get(c);return a?.length===s.length&&a.every((f,l)=>f===s[l])?a:(_.set(c,s),s)}i(N,"journalLines");function T(e){const t=$(e,"ledger");return M("ledger-writers:"+t,()=>u(t)?V(t).filter(n=>n.endsWith(d)).map(n=>n.slice(0,-d.length)):[],!1)}i(T,"legacyWriters");function ge(e){const t=T(e),n=x(e).flatMap(r=>r.bundle.placements?.filter(o=>o.place===".").flatMap(o=>g(o.records).map(s=>p(s,"by")))??[]);return[...new Set([...t,...n])]}i(ge,"ledgerWriters");function xe(e){const t=T(e),r=x(e).flatMap(s=>s.bundle.placements?.filter(c=>c.place===".").flatMap(c=>g(c.records))??[]);return[...new Set([...t,...r.map(s=>p(s,"by"))])].flatMap(s=>{const c=O(e,s),a=u(c)?w(c,"utf8").split(`
2
+ `).filter(l=>l.startsWith(m)):[],f=r.filter(l=>p(l,"by")===s);return f.length?[...new Set([...a,...f])]:a})}i(xe,"rootLedgerLines");function Se(e,t,n,r){return j(W(e,t,n),r)}i(Se,"landShard");function v(e){if(R())return M("ledger:"+e,()=>u(e)?w(e,"utf8").split(`
3
+ `).filter(c=>c.startsWith(m)):[],!1);const t=G(e,{throwIfNoEntry:!1});if(!t)return[];const n=`${Math.floor(t.mtimeMs)}-${t.size}`,r=L.get(e);if(r?.stamp===n)return r.lines;const o=r!==void 0&&r.size>0&&t.size>r.size?U(e,r.size,t.size):void 0,s=o!==void 0&&r!==void 0?[...r.lines,...o.split(`
4
+ `).filter(c=>c.startsWith(m))]:w(e,"utf8").split(`
5
+ `).filter(c=>c.startsWith(m));return L.set(e,{stamp:n,size:t.size,lines:s}),s}i(v,"linesAt");function U(e,t,n){const r=J(e,"r");try{const o=Buffer.alloc(n-t+1);return P(r,o,0,o.length,t-1),o[0]===10?o.subarray(1).toString("utf8"):void 0}finally{B(r)}}i(U,"tailOf");function j(e,t){const n=new Set(v(e)),r=[...new Set(t)].filter(o=>o.startsWith(m)&&!n.has(o));return r.length&&(b(S(e),{recursive:!0}),X(e,`${r.join(`
6
+ `)}
7
+ `)),r.length}i(j,"appendNew");function $e(e,t){return E(e,t).filter(n=>n.includes(`by=${t}`)&&/\bsig=/.test(n))}i($e,"signedLines");function Y(e,t){return h(e,"cas","blobs",t.slice(t.indexOf(":")+1))}i(Y,"blobAt");function F(e,t){return u(e)||ee(e,t),e}i(F,"landWhole");function ee(e,t){z("persistent replacement"),b(S(e),{recursive:!0});const n=`${e}.${process.pid}.part`;A(n,t),q(n,e)}i(ee,"replaceWhole");const be=i((e,t,n)=>{const r=F(Y(e,t),n);return te(e,"blobs",t,n.byteLength),r},"landBlob");function te(e,t,n,r){const o=n.replace(/^[^:]*:/,""),s=`cas/${t}/${o}`,c=E(e,"store").filter(a=>p(a,"scope")===s);c.length&&p(c[c.length-1],"value")!=="withdraw"||re(e,"store",[K({scope:s,role:"writes",form:"interval",measure:"bytes",value:`${r}..${r}`,at:`place:${t==="answers"?o:`sha256:${o}`}`,by:"store"})])}i(te,"holdStore");const I=i((e,t)=>h(e,"cas","memo",...t.split("/").map(n=>n.replace(/[^a-zA-Z0-9._@-]/g,"_"))),"memoAt");function ne(e,t,n){const r=I(e,t);if(u(r))return r;b(S(r),{recursive:!0});const o=`${r}.${process.pid}.part`;A(o,n);try{C(o,r)}catch(s){if(s.code!=="EEXIST")throw s}finally{D(o,{force:!0})}return r}i(ne,"landMemo");const we=i((e,t,n)=>F(h(e,"cas","envelopes",`${t.slice(t.indexOf(":")+1)}.json`),n),"landEnvelope");function re(e,t,n){z("ledger admission");const r=O(e,t);return{at:r,appended:j(r,n)}}i(re,"land");const y=i(e=>e.replace(/[^a-zA-Z0-9._@-]/g,"_"),"step");function oe(e,t,n){return I(e,`verdict/${y(t)}/${y(n)}`)}i(oe,"verdictAt");function Oe(e,t,n){const r=Q(oe(e,t,n));if(r!==void 0)try{const o=JSON.parse(r);return Array.isArray(o)?o:void 0}catch{return}}i(Oe,"keptVerdict");function ve(e,t,n,r){ne(e,`verdict/${y(t)}/${y(n)}`,new TextEncoder().encode(JSON.stringify(r)))}i(ve,"keepVerdict");export{Y as blobAt,te as holdStore,ve as keepVerdict,Oe as keptVerdict,re as land,be as landBlob,we as landEnvelope,ne as landMemo,Se as landShard,E as ledgerLines,ge as ledgerWriters,I as memoAt,ee as replaceWhole,xe as rootLedgerLines,W as shardFile,ye as shardLines,$e as signedLines,h as storeAt,he as storeOf,O 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 u=Object.defineProperty;var a=(t,e)=>u(t,"name",{value:e,configurable:!0});import{library11_canonical as l,library11_parse as y,library11_parseForSigning as p,library11_signedBytes as d,library11_signedFieldsOf as h}from"../vendor/runtime.js";import{verifyBytes as g}from"../host/adapters/keys/ed25519.js";import{SigningFailure as b}from"../host/ports/signing.js";function k(t,e){const o=p(t);if(o.kind!=="fact")return{kind:"refuse",why:"REFUSE\xB7accept not a claim line"};const i=o.value.fields,s=i.scope??"?";if(i.sig!==void 0)return{kind:"refuse",why:`REFUSE\xB7accept ${s} is already signed`};if(i.by!=="target")return{kind:"refuse",why:`REFUSE\xB7accept ${s} must be drafted by=target`};const n=h(i,e.by);return e.epoch!==void 0&&(n.epoch=String(e.epoch)),{kind:"fact",fields:n}}a(k,"prepareConsentLine");async function m(t,e,o,i,s){const n=[];for(const r of t){const f=k(r,e);if(f.kind==="refuse")return f;n.push(f.fields)}if(!n.length)return{kind:"refuse",why:`REFUSE\xB7signer ${e.by} empty lot`};let c;try{c=await s({bytes:n.map(r=>d(r)),keyId:e.by,algorithm:e.algorithm})}catch(r){return{kind:"refuse",why:r instanceof b?r.message:`REFUSE\xB7signer ${e.by} acquisition failed`}}return c.length!==n.length||c.some((r,f)=>r.keyId!==e.by||!g(d(n[f]),o,r.signature,i))?{kind:"refuse",why:`REFUSE\xB7signer ${e.by} signature does not verify`}:{kind:"fact",lines:n.map((r,f)=>l({...r,sig:c[f].signature}))}}a(m,"signConsentLot");function v(t,e,o){const i=y(t);if(i.kind!=="fact")return!1;const{sig:s,...n}=i.value.fields;return typeof s=="string"&&g(d(n),e,s,o)}a(v,"verifiesOwnerLine");function R(t,e,o){const{sig:i,...s}=t;return typeof i=="string"&&g(d(s),e,i,o)}a(R,"verifiesFields");export{m as signConsentLot,R as verifiesFields,v 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{library7_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{library12_point as _,library12_region as B,library12_within as E}from"../vendor/runtime.js";import{library11_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{library11_ENVELOPE as c}from"../vendor/runtime.js";import{fieldsOf as l}from"../fold/claims.js";import{library4_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 k=Object.defineProperty;var i=(e,n)=>k(e,"name",{value:n,configurable:!0});import{preparingView as w,viewInput as m}from"../host/reading-context.js";import{existsSync as p,lstatSync as x,statSync as D,readFileSync as a,readdirSync as h,readlinkSync as F}from"node:fs";import{join as v,relative as E,sep as T}from"node:path";const y=new Map;function $(e){let n=d(e);if(n?.isSymbolicLink())try{n=D(e)}catch{return}if(n===void 0||n.isDirectory()||!p(e))return;const r=`${n.ino}-${n.size}-${n.mtimeMs}`,s=y.get(e);if(s?.stamp===r)return s.bytes;let t;try{t=a(e)}catch(c){if(c.code!=="ENOENT")throw c;y.delete(e);return}return y.set(e,{stamp:r,bytes:t}),t}i($,"bytesAt");function S(e){if(!w())return $(e);const n=m("file:"+e,()=>{try{return a(e).toString("base64")}catch(r){if(["ENOENT","EISDIR"].includes(r.code??""))return;throw r}});return n===void 0?void 0:Buffer.from(n,"base64")}i(S,"viewBytes");const N=i(e=>(n=>n===void 0?void 0:new Uint8Array(n))(S(e)),"observeFile"),O=i(e=>S(e)?.toString("utf8"),"observeText"),j=i(e=>p(e),"exists");function z(e){const n=d(e);return n?{kind:n.isSymbolicLink()?"link":n.isDirectory()?"dir":n.isFile()?"file":"other",stamp:`${Math.floor(n.mtimeMs)}-${n.size}`}:void 0}i(z,"stampOf");function d(e){try{return x(e)}catch{return}}i(d,"stampable");const A=i(e=>F(e),"linkOf");function B(e){return d(e)?.isDirectory()?m("entries:"+e,()=>h(e,{withFileTypes:!0}).map(n=>({name:n.name,dir:n.isDirectory()}))):[]}i(B,"entriesIn");function U(e,n,r=()=>!0){const s=[],t=i(o=>E(n,o).split(T).join("/"),"name"),c=i((o,l)=>{if(l!=="link"){if(l==="file"){s.push(t(o));return}if(!(l!=="dir"||!r(t(o))))for(const u of h(o,{withFileTypes:!0})){const b=v(o,u.name);u.isSymbolicLink()||c(b,u.isFile()?"file":u.isDirectory()?"dir":"other")}}},"walk"),f=d(e);return c(e,f?f.isSymbolicLink()?"link":f.isDirectory()?"dir":f.isFile()?"file":"other":"other"),s}i(U,"coordinatesUnder");export{U as coordinatesUnder,B as entriesIn,j as exists,A as linkOf,N as observeFile,O as observeText,z as stampOf};