@lapxo/bound 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/CITATION.cff +19 -0
  2. package/TARGET.bound +95 -39
  3. package/dist/cli/accept.js +72 -558
  4. package/dist/cli/act-result.js +3 -103
  5. package/dist/cli/args.js +3 -44
  6. package/dist/cli/custodian.js +2 -29
  7. package/dist/cli/host.js +4 -32
  8. package/dist/cli/names.js +1 -12
  9. package/dist/cli/native-descendant.js +1 -19
  10. package/dist/cli/native.js +3 -60
  11. package/dist/cli/observe.js +1 -13
  12. package/dist/cli/owner.js +3 -139
  13. package/dist/cli/pass.js +21 -321
  14. package/dist/cli/place.js +6 -281
  15. package/dist/cli/release-result.js +3 -80
  16. package/dist/cli/retained-judgment.js +1 -25
  17. package/dist/cli/standing-result.js +4 -21
  18. package/dist/cli/takes.js +10 -111
  19. package/dist/cli/verb.d.ts +1 -2
  20. package/dist/cli/verb.js +83 -683
  21. package/dist/engine/computation.js +2 -0
  22. package/dist/engine/conformance.js +4 -0
  23. package/dist/engine/encoding.js +1 -2
  24. package/dist/engine/index.d.ts +1 -13
  25. package/dist/engine/index.js +2 -11
  26. package/dist/engine/object.js +1 -38
  27. package/dist/engine/ports.js +2 -103
  28. package/dist/fold/admission-history.js +1 -17
  29. package/dist/fold/bootstrap-anchor.js +1 -28
  30. package/dist/fold/ceilings.js +1 -142
  31. package/dist/fold/claims.js +2 -131
  32. package/dist/fold/closed.js +24 -234
  33. package/dist/fold/configures.js +1 -25
  34. package/dist/fold/digests.js +10 -226
  35. package/dist/fold/evidence.js +1 -22
  36. package/dist/fold/fold-worker.js +1 -13
  37. package/dist/fold/kept.js +12 -173
  38. package/dist/fold/keys.js +3 -91
  39. package/dist/fold/laid.js +3 -90
  40. package/dist/fold/nos.js +1 -48
  41. package/dist/fold/object.js +1 -2
  42. package/dist/fold/observed.js +27 -534
  43. package/dist/fold/opened.js +1 -33
  44. package/dist/fold/own.js +3 -217
  45. package/dist/fold/paid.js +1 -92
  46. package/dist/fold/place-inputs.js +1 -70
  47. package/dist/fold/places.js +3 -100
  48. package/dist/fold/rank.js +1 -9
  49. package/dist/fold/reach.js +1 -83
  50. package/dist/fold/readers.js +6 -142
  51. package/dist/fold/receipts.js +1 -47
  52. package/dist/fold/region-declarations.js +1 -13
  53. package/dist/fold/region.js +8 -286
  54. package/dist/fold/release-policy.js +1 -101
  55. package/dist/fold/resolved.js +6 -145
  56. package/dist/fold/roles.js +2 -59
  57. package/dist/fold/second.js +4 -71
  58. package/dist/fold/shards.js +12 -100
  59. package/dist/fold/signed.js +3 -81
  60. package/dist/fold/signers.js +1 -54
  61. package/dist/fold/stranger.js +6 -24
  62. package/dist/fold/views.js +1 -66
  63. package/dist/fold/wire.js +1 -46
  64. package/dist/fold/zoom.js +3 -81
  65. package/dist/host/act-cost.js +1 -25
  66. package/dist/host/adapters/keys/ed25519.js +1 -30
  67. package/dist/host/adapters/modules/javascript.js +1 -50
  68. package/dist/host/adapters/transport/http.js +1 -28
  69. package/dist/host/admitted-place.js +1 -63
  70. package/dist/host/archive.js +1 -152
  71. package/dist/host/call-context.js +1 -0
  72. package/dist/host/capsule-process.js +2 -61
  73. package/dist/host/capsule.js +9 -168
  74. package/dist/host/cell-receipts.js +12 -128
  75. package/dist/host/commit-result.js +1 -0
  76. package/dist/host/content-needed.js +1 -8
  77. package/dist/host/content-store.js +1 -31
  78. package/dist/host/contextual-place.js +2 -77
  79. package/dist/host/digest.js +2 -15
  80. package/dist/host/hash.js +1 -9
  81. package/dist/host/host-controls.js +1 -0
  82. package/dist/host/in-process-act.js +3 -0
  83. package/dist/host/in-process-context.js +3 -0
  84. package/dist/host/in-process-root.js +6 -0
  85. package/dist/host/in-process.js +4 -0
  86. package/dist/host/index.d.ts +1 -0
  87. package/dist/host/index.js +1 -0
  88. package/dist/host/io.js +1 -11
  89. package/dist/host/lifetime.js +1 -79
  90. package/dist/host/located.js +6 -105
  91. package/dist/host/native/bounded-file.js +1 -32
  92. package/dist/host/native/command.js +1 -91
  93. package/dist/host/native/control-bridge-worker.js +2 -88
  94. package/dist/host/native/control-bridge.js +1 -110
  95. package/dist/host/native/control-selection.js +1 -32
  96. package/dist/host/native/custody.js +1 -91
  97. package/dist/host/native/deadline.js +1 -28
  98. package/dist/host/native/descendants.js +1 -528
  99. package/dist/host/native/generated-custodian.js +5 -267
  100. package/dist/host/native/generated.js +1 -379
  101. package/dist/host/native/image.js +1 -45
  102. package/dist/host/native/jobs.js +2 -148
  103. package/dist/host/native/loader.js +1 -269
  104. package/dist/host/native/materialize.js +1 -175
  105. package/dist/host/native/module-closure.js +1 -130
  106. package/dist/host/native/module-delivery.d.ts +1 -62
  107. package/dist/host/native/module-delivery.js +1 -151
  108. package/dist/host/native/module-syntax.js +1 -69
  109. package/dist/host/native/native-binary.js +1 -115
  110. package/dist/host/native/native-program.js +1 -72
  111. package/dist/host/native/node-jobs.js +3 -187
  112. package/dist/host/native/node-launch.js +1 -159
  113. package/dist/host/native/preload.js +1 -45
  114. package/dist/host/native/reading.js +1 -249
  115. package/dist/host/native/receipt-environment.js +1 -41
  116. package/dist/host/native/references.js +1 -30
  117. package/dist/host/native/root.js +1 -37
  118. package/dist/host/native/route.js +1 -216
  119. package/dist/host/native/runtime.js +1 -9
  120. package/dist/host/native-reader-context.js +1 -8
  121. package/dist/host/native-receiver.js +1 -0
  122. package/dist/host/objects.js +1 -38
  123. package/dist/host/order.js +1 -2
  124. package/dist/host/place-act-transaction.js +4 -0
  125. package/dist/host/place-clock-selection.js +5 -124
  126. package/dist/host/ports/ingress.js +2 -57
  127. package/dist/host/ports/local-act.js +5 -172
  128. package/dist/host/ports/place-act.js +1 -169
  129. package/dist/host/ports/publication.js +1 -56
  130. package/dist/host/ports/signing.js +1 -74
  131. package/dist/host/ports/store.js +1 -18
  132. package/dist/host/ports/transport.js +1 -48
  133. package/dist/host/process-lifetime.js +1 -17
  134. package/dist/host/provide.js +1 -183
  135. package/dist/host/read-only.js +1 -9
  136. package/dist/host/reading-closures.js +7 -227
  137. package/dist/host/reading-context.js +1 -53
  138. package/dist/host/reading-identity-types.js +0 -0
  139. package/dist/host/reading-identity.js +3 -0
  140. package/dist/host/reading-preparation.js +6 -0
  141. package/dist/host/reference-authenticated.d.ts +1 -40
  142. package/dist/host/reference-authenticated.js +3 -100
  143. package/dist/host/reference-contracts.js +1 -6
  144. package/dist/host/reference-export.js +6 -81
  145. package/dist/host/reference-native-api.d.ts +1 -3
  146. package/dist/host/reference-native-api.js +1 -3
  147. package/dist/host/reference-native.js +1 -74
  148. package/dist/host/reference-profile.js +1 -63
  149. package/dist/host/reference-standing.js +2 -18
  150. package/dist/host/reference.js +1 -24
  151. package/dist/host/refusals.js +2 -43
  152. package/dist/host/release.js +4 -256
  153. package/dist/host/root-clock-source.js +1 -305
  154. package/dist/host/selected-capsules.js +1 -50
  155. package/dist/host/selected-topos.js +1 -80
  156. package/dist/host/signature-era.js +1 -0
  157. package/dist/host/signing.js +2 -48
  158. package/dist/host/source-content.js +2 -110
  159. package/dist/host/standing-carrier.js +1 -0
  160. package/dist/host/standing-projection.js +1 -0
  161. package/dist/host/timing.js +1 -7
  162. package/dist/host/walk.js +20 -193
  163. package/dist/judge/late.js +1 -33
  164. package/dist/judge/take.js +2 -75
  165. package/dist/judge/widening.js +1 -25
  166. package/dist/land/act.js +8 -302
  167. package/dist/land/alias.js +1 -41
  168. package/dist/land/held.js +1 -23
  169. package/dist/land/inert.js +1 -33
  170. package/dist/land/leaving.js +1 -55
  171. package/dist/land/ledger.js +7 -188
  172. package/dist/land/owned.js +4 -66
  173. package/dist/land/sign.js +1 -53
  174. package/dist/land/standing-pin.js +1 -49
  175. package/dist/land/vouched.js +1 -112
  176. package/dist/land/withdraw.js +1 -24
  177. package/dist/observe/files.js +1 -88
  178. package/dist/observe/identity.js +1 -61
  179. package/dist/observe/match.js +1 -8
  180. package/dist/observe/regions.js +7 -306
  181. package/dist/observe/run.js +2 -40
  182. package/dist/observe/runner.js +4 -93
  183. package/dist/public-types.d.ts +1114 -0
  184. package/dist/render/capsule.js +1 -30
  185. package/dist/render/field.js +1 -40
  186. package/dist/render/names.js +1 -4
  187. package/dist/render/open.js +1 -61
  188. package/dist/render/page.js +1 -7
  189. package/dist/render/receipts.js +1 -47
  190. package/dist/render/shape.js +1 -74
  191. package/dist/render/target.js +4 -52
  192. package/dist/render/view.js +7 -197
  193. package/dist/vendor/50086958553b9376d600583f7dff354196bfeb41170fc6d1482ca7bea7c493e2.LICENSE +21 -0
  194. package/dist/vendor/b3e938d28f88a1851af303a40c749e12ebd5a686daac4f0b343b5cdd2e040419.LICENSE +21 -0
  195. package/dist/vendor/bundle.json +1 -0
  196. package/dist/vendor/library11.js +1 -0
  197. package/dist/vendor/object-provider.js +42 -0
  198. package/dist/vendor/runtime.js +38 -0
  199. package/dist/vendor/sources.json +1 -0
  200. package/dist/wasm/adapter.d.ts +1 -51
  201. package/dist/wasm/adapter.js +1 -180
  202. package/dist/wasm/node-worker.js +1 -13
  203. package/dist/wasm/object.js +1 -76
  204. package/dist/wasm/worker.js +1 -7
  205. package/docs/contracts/closure-delivery.md +1 -1
  206. package/docs/contracts/closure-delivery.publication.json +1 -1
  207. package/docs/contracts/conformance.json +142 -0
  208. package/docs/contracts/determinism.bound +9 -0
  209. package/docs/contracts/engine-object-projection.publication.json +1 -1
  210. package/docs/contracts/engine.md +21 -1
  211. package/docs/contracts/native-host.md +21 -0
  212. package/docs/contracts/native-host.publication.json +25 -0
  213. package/docs/contracts/native-publication.inventory.json +3 -1
  214. package/docs/contracts/optional-wasm-adapter.publication.json +1 -1
  215. package/docs/contracts/publication.inventory.json +29 -0
  216. package/docs/contracts/reading-identity.md +37 -0
  217. package/docs/contracts/reading-identity.publication.json +25 -0
  218. package/docs/contracts/refusals.bound +51 -0
  219. package/docs/contracts/refusals.md +18 -3
  220. package/docs/contracts/refusals.publication.json +2 -2
  221. package/docs/contracts/views.md +8 -0
  222. package/docs/guide.md +10 -0
  223. package/docs/reference.md +40 -0
  224. package/docs/why.md +109 -0
  225. package/package.json +37 -18
  226. package/receipts.bound +11675 -9725
  227. package/samples/native-host/no.json +10 -0
  228. package/samples/native-host/yes.json +20 -0
  229. package/samples/reading-identity/no.json +20 -0
  230. package/samples/reading-identity/yes.json +46 -0
  231. package/vectors/native/native-host.vector.json +62 -0
  232. package/vectors/native/reading-identity.vector.json +101 -0
  233. package/vectors/native/refusals.vector.json +104 -0
  234. package/vendor/syntax/LICENSE.md +7 -0
  235. package/vendor/syntax/parser.js +1 -0
  236. package/dist/engine/object.d.ts +0 -17
  237. package/dist/engine/ports.d.ts +0 -32
  238. package/dist/host/native/module-closure.d.ts +0 -35
  239. package/dist/host/reference-export.d.ts +0 -33
  240. package/dist/host/reference-native.d.ts +0 -30
  241. package/dist/host/reference-profile.d.ts +0 -23
  242. package/dist/host/refusals.d.ts +0 -14
@@ -1,55 +1 @@
1
- import { readOnly } from "../host/read-only.js";
2
- import { meets } from "../fold/closed.js";
3
- import { fieldOf } from "../fold/claims.js";
4
- import { sourced } from "./vouched.js";
5
- import { observedClaims } from "../fold/observed.js";
6
- /**
7
- * A file goes from the tree through a line, never through a hand: its path withdrawn in the family the lock sources files
8
- * by is the only way a file goes, and the fold refuses it while a block still reads the file — what a run depends on is judged by the run's
9
- * own memo, which names every file each block read, and not by a search for the file's name in a test. A search misses
10
- * a name built in a loop; the memo does not. A test file goes with its own blocks, and is refused while one of them
11
- * is the only run of a vector or a sample, which it names.
12
- */
13
- export function coordinatesWithdrawn(root, store, signed, standing) {
14
- const family = sourced(standing);
15
- const asked = signed.filter((line) => fieldOf(line, 'scope').startsWith(`${family}/`) && fieldOf(line, 'value') === 'withdraw')
16
- .map((line) => fieldOf(line, 'scope').slice(family.length + 1));
17
- if (!asked.length)
18
- return { taken: [], refused: [] };
19
- if (readOnly() && !meets(root, store, ''))
20
- throw Error('REFUSE·withdraw current native receipts are required to judge file removal; fold the declared inputs first');
21
- /** A run rewrites every block of a test file under one observation, so a block whose title moved still holds a row
22
- * from an older one: what reads a file now is what the latest run of each test file wrote, and nothing older. */
23
- const memo = observedClaims(root, store, { wait: false }).filter((line) => fieldOf(line, 'measure') === 'memo');
24
- const fileOf = (scope) => scope.split('/').slice(0, 2).join('/');
25
- const last = new Map();
26
- for (const line of memo)
27
- last.set(fileOf(fieldOf(line, 'scope')), fieldOf(line, 'at'));
28
- const latest = new Map();
29
- for (const line of memo) {
30
- const scope = fieldOf(line, 'scope');
31
- if (fieldOf(line, 'at') === last.get(fileOf(scope)))
32
- latest.set(scope, fieldOf(line, 'value'));
33
- }
34
- const refused = [];
35
- const taken = [];
36
- const ownOf = (inside) => (/^test\/[^/]+\.test\.ts$/.test(inside) ? `vector-memo/${inside.slice('test/'.length)}/` : undefined);
37
- const leaving = asked.map((path) => ownOf(path.slice(path.indexOf('/') + 1))).filter((own) => own !== undefined);
38
- const runs = (value) => value.split('|').filter((token) => token.startsWith('read:') && !token.includes('#')).map((token) => token.slice('read:'.length));
39
- for (const path of asked) {
40
- const inside = path.slice(path.indexOf('/') + 1);
41
- const own = ownOf(inside);
42
- const reads = (value) => value.split('|').some((token) => token.startsWith(`in:${inside}:`) && /^[0-9a-f]{12}$/.test(token.slice(`in:${inside}:`.length)));
43
- const by = [...latest].find(([scope, value]) => (own === undefined || !scope.startsWith(own)) && reads(value))?.[0];
44
- const elsewhere = new Set([...latest].filter(([scope]) => !leaving.some((one) => scope.startsWith(one))).flatMap(([, value]) => runs(value)));
45
- const only = own === undefined ? undefined : [...latest].filter(([scope]) => scope.startsWith(own))
46
- .flatMap(([scope, value]) => runs(value).filter((name) => !elsewhere.has(name)).map((name) => `${scope}, the only run of ${name}`))[0];
47
- if (by !== undefined)
48
- refused.push({ path, by });
49
- else if (only !== undefined)
50
- refused.push({ path, by: only });
51
- else
52
- taken.push(path);
53
- }
54
- return { taken, refused };
55
- }
1
+ var j=Object.defineProperty;var o=(r,f)=>j(r,"name",{value:f,configurable:!0});import{readOnly as S}from"../host/read-only.js";import{meets as k}from"../fold/closed.js";import{fieldOf as n}from"../fold/claims.js";import{sourced as q}from"./vouched.js";import{observedClaims as C}from"../fold/observed.js";function D(r,f,O,M){const p=q(M),c=O.filter(e=>n(e,"scope").startsWith(`${p}/`)&&n(e,"value")==="withdraw").map(e=>n(e,"scope").slice(p.length+1));if(!c.length)return{taken:[],refused:[]};if(S()&&!k(r,f,""))throw Error("REFUSE\xB7withdraw current native receipts are required to judge file removal; fold the declared inputs first");const u=C(r,f,{wait:!1}).filter(e=>n(e,"measure")==="memo"),h=o(e=>e.split("/").slice(0,2).join("/"),"fileOf"),w=new Map;for(const e of u)w.set(h(n(e,"scope")),n(e,"at"));const l=new Map;for(const e of u){const t=n(e,"scope");n(e,"at")===w.get(h(t))&&l.set(t,n(e,"value"))}const d=[],g=[],$=o(e=>/^test\/[^/]+\.test\.ts$/.test(e)?`vector-memo/${e.slice(5)}/`:void 0,"ownOf"),b=c.map(e=>$(e.slice(e.indexOf("/")+1))).filter(e=>e!==void 0),v=o(e=>e.split("|").filter(t=>t.startsWith("read:")&&!t.includes("#")).map(t=>t.slice(5)),"runs");for(const e of c){const t=e.slice(e.indexOf("/")+1),a=$(t),x=o(s=>s.split("|").some(i=>i.startsWith(`in:${t}:`)&&/^[0-9a-f]{12}$/.test(i.slice(`in:${t}:`.length))),"reads"),W=[...l].find(([s,i])=>(a===void 0||!s.startsWith(a))&&x(i))?.[0],E=new Set([...l].filter(([s])=>!b.some(i=>s.startsWith(i))).flatMap(([,s])=>v(s))),y=a===void 0?void 0:[...l].filter(([s])=>s.startsWith(a)).flatMap(([s,i])=>v(i).filter(m=>!E.has(m)).map(m=>`${s}, the only run of ${m}`))[0];W!==void 0?d.push({path:e,by:W}):y!==void 0?d.push({path:e,by:y}):g.push(e)}return{taken:g,refused:d}}o(D,"coordinatesWithdrawn");export{D as coordinatesWithdrawn};
@@ -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};