@lapxo/bound 0.1.0
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.
- package/CONTRIBUTING.md +44 -0
- package/LICENSE +22 -0
- package/README.md +97 -0
- package/TARGET.bound +361 -0
- package/dist/cli/accept.d.ts +23 -0
- package/dist/cli/accept.js +423 -0
- package/dist/cli/args.d.ts +10 -0
- package/dist/cli/args.js +34 -0
- package/dist/cli/host.d.ts +1 -0
- package/dist/cli/host.js +32 -0
- package/dist/cli/names.d.ts +25 -0
- package/dist/cli/names.js +12 -0
- package/dist/cli/observe.d.ts +1 -0
- package/dist/cli/observe.js +6 -0
- package/dist/cli/owner.d.ts +35 -0
- package/dist/cli/owner.js +119 -0
- package/dist/cli/pass.d.ts +6 -0
- package/dist/cli/pass.js +309 -0
- package/dist/cli/place.d.ts +74 -0
- package/dist/cli/place.js +290 -0
- package/dist/cli/takes.d.ts +30 -0
- package/dist/cli/takes.js +108 -0
- package/dist/cli/verb.d.ts +2 -0
- package/dist/cli/verb.js +478 -0
- package/dist/fold/ceilings.d.ts +24 -0
- package/dist/fold/ceilings.js +129 -0
- package/dist/fold/claims.d.ts +25 -0
- package/dist/fold/claims.js +107 -0
- package/dist/fold/closed.d.ts +15 -0
- package/dist/fold/closed.js +168 -0
- package/dist/fold/configures.d.ts +4 -0
- package/dist/fold/configures.js +22 -0
- package/dist/fold/digests.d.ts +29 -0
- package/dist/fold/digests.js +211 -0
- package/dist/fold/evidence.d.ts +32 -0
- package/dist/fold/evidence.js +22 -0
- package/dist/fold/fold-worker.d.ts +1 -0
- package/dist/fold/fold-worker.js +13 -0
- package/dist/fold/kept.d.ts +29 -0
- package/dist/fold/kept.js +142 -0
- package/dist/fold/keys.d.ts +17 -0
- package/dist/fold/keys.js +84 -0
- package/dist/fold/laid.d.ts +17 -0
- package/dist/fold/laid.js +90 -0
- package/dist/fold/nos.d.ts +8 -0
- package/dist/fold/nos.js +48 -0
- package/dist/fold/object.d.ts +17 -0
- package/dist/fold/object.js +38 -0
- package/dist/fold/observed.d.ts +33 -0
- package/dist/fold/observed.js +444 -0
- package/dist/fold/opened.d.ts +5 -0
- package/dist/fold/opened.js +33 -0
- package/dist/fold/own.d.ts +24 -0
- package/dist/fold/own.js +215 -0
- package/dist/fold/paid.d.ts +11 -0
- package/dist/fold/paid.js +92 -0
- package/dist/fold/place-inputs.d.ts +17 -0
- package/dist/fold/place-inputs.js +70 -0
- package/dist/fold/places.d.ts +20 -0
- package/dist/fold/places.js +84 -0
- package/dist/fold/rank.d.ts +3 -0
- package/dist/fold/rank.js +9 -0
- package/dist/fold/reach.d.ts +13 -0
- package/dist/fold/reach.js +65 -0
- package/dist/fold/readers.d.ts +44 -0
- package/dist/fold/readers.js +132 -0
- package/dist/fold/receipts.d.ts +8 -0
- package/dist/fold/receipts.js +47 -0
- package/dist/fold/region.d.ts +72 -0
- package/dist/fold/region.js +286 -0
- package/dist/fold/release-policy.d.ts +67 -0
- package/dist/fold/release-policy.js +103 -0
- package/dist/fold/resolved.d.ts +18 -0
- package/dist/fold/resolved.js +123 -0
- package/dist/fold/roles.d.ts +17 -0
- package/dist/fold/roles.js +59 -0
- package/dist/fold/second.d.ts +18 -0
- package/dist/fold/second.js +68 -0
- package/dist/fold/shards.d.ts +29 -0
- package/dist/fold/shards.js +100 -0
- package/dist/fold/signed.d.ts +18 -0
- package/dist/fold/signed.js +75 -0
- package/dist/fold/signers.d.ts +24 -0
- package/dist/fold/signers.js +58 -0
- package/dist/fold/stranger.d.ts +3 -0
- package/dist/fold/stranger.js +24 -0
- package/dist/fold/views.d.ts +27 -0
- package/dist/fold/views.js +66 -0
- package/dist/fold/wire.d.ts +19 -0
- package/dist/fold/wire.js +41 -0
- package/dist/fold/zoom.d.ts +16 -0
- package/dist/fold/zoom.js +80 -0
- package/dist/host/adapters/keys/ed25519.d.ts +7 -0
- package/dist/host/adapters/keys/ed25519.js +30 -0
- package/dist/host/archive.d.ts +11 -0
- package/dist/host/archive.js +152 -0
- package/dist/host/capsule-process.d.ts +20 -0
- package/dist/host/capsule-process.js +54 -0
- package/dist/host/capsule.d.ts +13 -0
- package/dist/host/capsule.js +149 -0
- package/dist/host/cell-receipts.d.ts +2 -0
- package/dist/host/cell-receipts.js +124 -0
- package/dist/host/digest.d.ts +3 -0
- package/dist/host/digest.js +15 -0
- package/dist/host/hash.d.ts +2 -0
- package/dist/host/hash.js +3 -0
- package/dist/host/io.d.ts +9 -0
- package/dist/host/io.js +9 -0
- package/dist/host/located.d.ts +4 -0
- package/dist/host/located.js +105 -0
- package/dist/host/objects.d.ts +5 -0
- package/dist/host/objects.js +18 -0
- package/dist/host/ports/store.d.ts +2 -0
- package/dist/host/ports/store.js +18 -0
- package/dist/host/provide.d.ts +23 -0
- package/dist/host/provide.js +81 -0
- package/dist/host/release.d.ts +12 -0
- package/dist/host/release.js +213 -0
- package/dist/host/selected-capsules.d.ts +8 -0
- package/dist/host/selected-capsules.js +19 -0
- package/dist/host/selected-topos.d.ts +17 -0
- package/dist/host/selected-topos.js +61 -0
- package/dist/host/source-content.d.ts +10 -0
- package/dist/host/source-content.js +94 -0
- package/dist/host/timing.d.ts +2 -0
- package/dist/host/timing.js +7 -0
- package/dist/judge/late.d.ts +7 -0
- package/dist/judge/late.js +33 -0
- package/dist/judge/take.d.ts +57 -0
- package/dist/judge/take.js +75 -0
- package/dist/judge/widening.d.ts +1 -0
- package/dist/judge/widening.js +25 -0
- package/dist/land/act.d.ts +4 -0
- package/dist/land/act.js +209 -0
- package/dist/land/alias.d.ts +10 -0
- package/dist/land/alias.js +41 -0
- package/dist/land/held.d.ts +7 -0
- package/dist/land/held.js +23 -0
- package/dist/land/inert.d.ts +26 -0
- package/dist/land/inert.js +33 -0
- package/dist/land/leaving.d.ts +14 -0
- package/dist/land/leaving.js +51 -0
- package/dist/land/ledger.d.ts +28 -0
- package/dist/land/ledger.js +148 -0
- package/dist/land/owned.d.ts +23 -0
- package/dist/land/owned.js +65 -0
- package/dist/land/sign.d.ts +16 -0
- package/dist/land/sign.js +30 -0
- package/dist/land/vouched.d.ts +21 -0
- package/dist/land/vouched.js +112 -0
- package/dist/land/withdraw.d.ts +14 -0
- package/dist/land/withdraw.js +24 -0
- package/dist/observe/files.d.ts +14 -0
- package/dist/observe/files.js +68 -0
- package/dist/observe/identity.d.ts +19 -0
- package/dist/observe/identity.js +61 -0
- package/dist/observe/match.d.ts +1 -0
- package/dist/observe/match.js +8 -0
- package/dist/observe/regions.d.ts +29 -0
- package/dist/observe/regions.js +200 -0
- package/dist/observe/run.d.ts +30 -0
- package/dist/observe/run.js +34 -0
- package/dist/observe/runner.d.ts +16 -0
- package/dist/observe/runner.js +83 -0
- package/dist/render/capsule.d.ts +24 -0
- package/dist/render/capsule.js +30 -0
- package/dist/render/field.d.ts +9 -0
- package/dist/render/field.js +46 -0
- package/dist/render/names.d.ts +3 -0
- package/dist/render/names.js +4 -0
- package/dist/render/open.d.ts +27 -0
- package/dist/render/open.js +61 -0
- package/dist/render/page.d.ts +3 -0
- package/dist/render/page.js +7 -0
- package/dist/render/receipts.d.ts +3 -0
- package/dist/render/receipts.js +46 -0
- package/dist/render/shape.d.ts +16 -0
- package/dist/render/shape.js +74 -0
- package/dist/render/target.d.ts +18 -0
- package/dist/render/target.js +52 -0
- package/dist/render/view.d.ts +22 -0
- package/dist/render/view.js +191 -0
- package/docs/readme-assets/atlas.svg +169 -0
- package/docs/usage.md +53 -0
- package/package.json +48 -0
- package/receipts.bound +59 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PlaceFold } from '../cli/place.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The points a fold folds: each coordinate the place holds at the digest its readers last read it, with what they said of
|
|
4
|
+
* it there, the lines that stand, and the receipts the store keeps. A coordinate is never a digest it had before nor a coordinate
|
|
5
|
+
* of another place, so an edit elsewhere moves nothing here; and a reader is what it said, so a reader edit that says
|
|
6
|
+
* the same moves nothing either. A fold is a function of these points, so a fold that was not found is never a
|
|
7
|
+
* mystery — what moved is the difference between the points kept beside the last one and the points there are now.
|
|
8
|
+
*/
|
|
9
|
+
export type PlaceReads = {
|
|
10
|
+
readonly owned: readonly string[];
|
|
11
|
+
readonly scopes: ReadonlySet<string>;
|
|
12
|
+
readonly place: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function foldPoints(store: string, standing: readonly string[], under: string | undefined, keeper?: string, instrument?: string, observed?: readonly string[], root?: string, answered?: ReadonlyMap<string, string>, reads?: PlaceReads): readonly string[];
|
|
15
|
+
/**
|
|
16
|
+
* What a reader said at one digest, as one digest: every point of a fold that stands for an answer is this. The writer
|
|
17
|
+
* whose class the lock names live is judged when read, so a fold keeps what it said — which lines it found standing and
|
|
18
|
+
* which ledger it folded — and not when.
|
|
19
|
+
*/
|
|
20
|
+
export declare const saidDigest: (store: string, lines: readonly string[]) => string;
|
|
21
|
+
export declare function movedPoints(store: string, now: readonly string[], key: string): {
|
|
22
|
+
readonly gone: readonly string[];
|
|
23
|
+
readonly came: readonly string[];
|
|
24
|
+
} | undefined;
|
|
25
|
+
export declare const foldsElsewhere: () => number;
|
|
26
|
+
export declare function keptPlace(store: string, under?: string): PlaceFold | undefined;
|
|
27
|
+
export declare const keptRender: (store: string, key: string, name: string) => string | undefined;
|
|
28
|
+
export declare const keepRender: (store: string, _signer: string, key: string, name: string, _epoch: number, text_: string) => void;
|
|
29
|
+
export declare function keepFold(store: string, key: string, fold: PlaceFold, points: readonly string[], instrument?: string): void;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { createHash, dirname, existsSync, join, mkdirSync, readdirSync, renameSync, writeFileSync } from "../host/io.js";
|
|
2
|
+
import { bytesDigest, coordinateDigest } from "./digests.js";
|
|
3
|
+
import { viewsOf } from "./views.js";
|
|
4
|
+
import { landMemo, ledgerLines, memoAt } from "../land/ledger.js";
|
|
5
|
+
import { observeText } from "../observe/files.js";
|
|
6
|
+
import { EXTENSION, fieldOf } from "./claims.js";
|
|
7
|
+
import { keyFor, lockSigners } from "./keys.js";
|
|
8
|
+
import { sourceOf, vouching } from "../land/vouched.js";
|
|
9
|
+
import { wordsOf } from "./wire.js";
|
|
10
|
+
import { ownLock } from "../observe/runner.js";
|
|
11
|
+
const text = (s) => new TextEncoder().encode(s);
|
|
12
|
+
const atOf = (line) => {
|
|
13
|
+
if (line.includes(' about='))
|
|
14
|
+
return fieldOf(line, 'at');
|
|
15
|
+
const from = line.indexOf(' at=') + ' at='.length;
|
|
16
|
+
return line.slice(from, line.indexOf(' ', from));
|
|
17
|
+
};
|
|
18
|
+
export function foldPoints(store, standing, under, keeper, instrument = '', observed = [], root = dirname(store), answered, reads) {
|
|
19
|
+
const said = new Map();
|
|
20
|
+
for (const line of answered === undefined ? observed : []) {
|
|
21
|
+
if (line.includes(' measure=observed '))
|
|
22
|
+
continue;
|
|
23
|
+
const key = `${fieldOf(line, 'by').split(':')[1] ?? ''} ${atOf(line)}`;
|
|
24
|
+
(said.get(key) ?? said.set(key, []).get(key)).push(line);
|
|
25
|
+
}
|
|
26
|
+
const coordinates = observed
|
|
27
|
+
.filter((line) => line.includes(' measure=observed ') && atOf(line).startsWith('place:') && (!under || fieldOf(line, 'scope').startsWith(under)))
|
|
28
|
+
.map((line) => ((key) => `${fieldOf(line, 'scope')} ${atOf(line)} ${answered?.get(key) ?? saidDigest(store, said.get(key) ?? [])}`)(`${fieldOf(line, 'by').split(':')[1] ?? ''} ${atOf(line)}`));
|
|
29
|
+
const signers = new Set(reads ? lockSigners(store) : []);
|
|
30
|
+
const tree = reads ? vouching(standing) : undefined;
|
|
31
|
+
const digestOf = (lines) => bytesDigest(store, text(lines.join('\n')));
|
|
32
|
+
const narrowed = reads === undefined ? [] : [
|
|
33
|
+
`lock ${digestOf([...reads.owned].sort())}`,
|
|
34
|
+
`judge ${digestOf(ledgerLines(store, 'judge').filter((line) => reads.scopes.has(fieldOf(line, 'scope'))))}`,
|
|
35
|
+
`take ${digestOf(ledgerLines(store, 'take').filter((line) => reads.scopes.has(fieldOf(line, 'scope').replace(/^take\//, ''))))}`,
|
|
36
|
+
`tree ${digestOf(ledgerLines(store, tree ?? '').filter((line) => (sourceOf(line) ?? '').startsWith(reads.place)))}`,
|
|
37
|
+
];
|
|
38
|
+
const heads = (existsSync(join(store, 'ledger')) ? readdirSync(join(store, 'ledger')) : []).filter((name) => name.endsWith(EXTENSION)).map((name) => name.slice(0, -EXTENSION.length))
|
|
39
|
+
.filter((writer) => writer !== keeper && writer !== 'gate' && !writer.startsWith('reader') && !(reads && (signers.has(writer) || writer === 'judge' || writer === 'take' || writer === tree)))
|
|
40
|
+
.map((writer) => `${writer} ${writer === liveWriter(store, standing) ? lastWord(store, writer) : bytesDigest(store, text(ledgerLines(store, writer).join('\n')))}`);
|
|
41
|
+
const written = [...new Set([...viewsOf(standing).values()].flatMap((view) => ('regions' in view && view.shape ? [view.shape] : [])))].sort()
|
|
42
|
+
.map((shape) => `written ${shape} ${coordinateDigest(store, join(root, under ?? '', shape)) ?? 'absent'}`);
|
|
43
|
+
const lined = ownLock().filter((line) => fieldOf(line, 'scope').startsWith('region/') && fieldOf(line, 'measure') === 'lines' && fieldOf(line, 'value') !== 'withdraw')
|
|
44
|
+
.flatMap((line) => fieldOf(line, 'value').split('|').filter(Boolean)).sort().map((coordinate) => `lines ${coordinate} ${coordinateDigest(store, join(root, under ?? '', coordinate)) ?? 'absent'}`);
|
|
45
|
+
return [
|
|
46
|
+
`place ${under ?? '.'}`,
|
|
47
|
+
`instrument ${instrument}`,
|
|
48
|
+
...written,
|
|
49
|
+
...lined,
|
|
50
|
+
...[...new Set(coordinates)].sort(),
|
|
51
|
+
...heads.sort(),
|
|
52
|
+
...narrowed,
|
|
53
|
+
`lines ${bytesDigest(store, text([...standing].sort().join('\n')))}`,
|
|
54
|
+
...(existsSync(join(store, 'cas', 'receipts')) ? readdirSync(join(store, 'cas', 'receipts')).sort() : []),
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* What a reader said at one digest, as one digest: every point of a fold that stands for an answer is this. The writer
|
|
59
|
+
* whose class the lock names live is judged when read, so a fold keeps what it said — which lines it found standing and
|
|
60
|
+
* which ledger it folded — and not when.
|
|
61
|
+
*/
|
|
62
|
+
export const saidDigest = (store, lines) => bytesDigest(store, text([...new Set(lines
|
|
63
|
+
.filter((line) => !line.includes(' measure=observed ') && !line.includes(' scope=cost/'))
|
|
64
|
+
.map((line) => `${fieldOf(line, 'scope')} ${fieldOf(line, 'measure')} ${fieldOf(line, 'value')}`))].sort().join('\n')));
|
|
65
|
+
function liveWriter(store, standing) {
|
|
66
|
+
if (!wordsOf(standing, 'live').includes('attest'))
|
|
67
|
+
return undefined;
|
|
68
|
+
try {
|
|
69
|
+
return keyFor(store, 'attest');
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const lastWord = (store, writer) => ((last) => `${fieldOf(last, 'at')} ${fieldOf(last, 'restsOn')} ${fieldOf(last, 'value')}`)(ledgerLines(store, writer).filter((line) => fieldOf(line, 'scope') === `${writer}/target`).at(-1) ?? '');
|
|
76
|
+
export function movedPoints(store, now, key) {
|
|
77
|
+
const last = observeText(memoAt(store, lastOf(now)))?.trim();
|
|
78
|
+
const held = last === undefined || last === key ? undefined : observeText(memoAt(store, `fold/${last}`));
|
|
79
|
+
if (held === undefined)
|
|
80
|
+
return undefined;
|
|
81
|
+
const was = new Set((JSON.parse(held).points ?? []));
|
|
82
|
+
const has = new Set(now);
|
|
83
|
+
return { gone: [...was].filter((one) => !has.has(one)), came: now.filter((one) => !was.has(one)) };
|
|
84
|
+
}
|
|
85
|
+
const lastOf = (points) => `last/${createHash('sha256').update(points[0] ?? '').digest('hex')}`;
|
|
86
|
+
/**
|
|
87
|
+
* A fold is kept under its key and a view's text under the key and the view's name, in the store's memos: the first to
|
|
88
|
+
* keep a key keeps it, since one point set folds into one set of bytes, and a fold kept by another instrument is
|
|
89
|
+
* another origin's, readable as history and never as this instrument's own state.
|
|
90
|
+
*/
|
|
91
|
+
const elsewhere = { folds: 0 };
|
|
92
|
+
export const foldsElsewhere = () => elsewhere.folds;
|
|
93
|
+
const joined = (lines) => lines.join('\n');
|
|
94
|
+
const split = (text) => (text === '' ? [] : text.split('\n'));
|
|
95
|
+
const linesOf = (value) => value === undefined ? [] : typeof value === 'string' ? split(value) : value;
|
|
96
|
+
export function keptPlace(store, under) {
|
|
97
|
+
const key = observeText(memoAt(store, lastOf([`place ${under ?? '.'}`])))?.trim();
|
|
98
|
+
if (key === undefined || key === '')
|
|
99
|
+
return undefined;
|
|
100
|
+
const held = observeText(memoAt(store, `fold/${key}`));
|
|
101
|
+
if (held === undefined)
|
|
102
|
+
return undefined;
|
|
103
|
+
const blob = JSON.parse(held);
|
|
104
|
+
const fold = blob.fold;
|
|
105
|
+
return {
|
|
106
|
+
...fold,
|
|
107
|
+
standing: linesOf(fold.standing),
|
|
108
|
+
observed: linesOf(fold.observed),
|
|
109
|
+
grey: linesOf(fold.grey),
|
|
110
|
+
refused: linesOf(fold.refused),
|
|
111
|
+
demands: linesOf(fold.demands),
|
|
112
|
+
paid: linesOf(fold.paid),
|
|
113
|
+
missing: linesOf(fold.missing),
|
|
114
|
+
history: linesOf(fold.history),
|
|
115
|
+
orphans: linesOf(fold.orphans),
|
|
116
|
+
signed: new Map(fold.signed),
|
|
117
|
+
kept: true,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export const keptRender = (store, key, name) => observeText(memoAt(store, `render/${key}/${name}`));
|
|
121
|
+
export const keepRender = (store, _signer, key, name, _epoch, text_) => { landMemo(store, `render/${key}/${name}`, text(text_)); };
|
|
122
|
+
export function keepFold(store, key, fold, points, instrument = '') {
|
|
123
|
+
const packed = {
|
|
124
|
+
...fold,
|
|
125
|
+
standing: joined(fold.standing),
|
|
126
|
+
observed: joined(fold.observed),
|
|
127
|
+
grey: joined(fold.grey),
|
|
128
|
+
refused: joined(fold.refused),
|
|
129
|
+
demands: joined(fold.demands),
|
|
130
|
+
paid: joined(fold.paid),
|
|
131
|
+
missing: joined(fold.missing),
|
|
132
|
+
history: joined(fold.history),
|
|
133
|
+
orphans: joined(fold.orphans),
|
|
134
|
+
signed: [...fold.signed],
|
|
135
|
+
kept: false,
|
|
136
|
+
};
|
|
137
|
+
landMemo(store, `fold/${key}`, text(JSON.stringify({ fold: packed, points, instrument })));
|
|
138
|
+
const at = memoAt(store, lastOf(points));
|
|
139
|
+
mkdirSync(dirname(at), { recursive: true });
|
|
140
|
+
writeFileSync(`${at}.${process.pid}.part`, `${key}\n`);
|
|
141
|
+
renameSync(`${at}.${process.pid}.part`, at);
|
|
142
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whose lines carry a class of writing, as the lock says it. Every ledger the store keeps is read, the key claims
|
|
3
|
+
* folded, and the class answered with the id the lock admitted first for it: no module here holds a signer's name, so
|
|
4
|
+
* the day another head runs the same work its lines come out under its own name without a letter changing.
|
|
5
|
+
*/
|
|
6
|
+
export declare const keyOf: (store: string, kind: string, told?: readonly string[]) => string | undefined;
|
|
7
|
+
export declare function keyFor(store: string, kind: string, told?: readonly string[]): string;
|
|
8
|
+
export declare function lockSigners(store: string, told?: readonly string[]): readonly string[];
|
|
9
|
+
export declare function lockLines(store: string): readonly string[];
|
|
10
|
+
/** What stands of the lock, folded once per landing of any of its ledgers: lockLines is the bytes, lockSigners the ids that write them, signedLockLines the same lines still carrying their signatures. */
|
|
11
|
+
export declare function lockStanding(store: string): readonly string[];
|
|
12
|
+
export declare function signedLockLines(store: string, told?: readonly string[]): string[];
|
|
13
|
+
/**
|
|
14
|
+
* A release's lock, where the store signs no key of its own: the lock as it was laid is the place's only lines, read
|
|
15
|
+
* and never written. What it says is true where a pin names the release; no ledger is made of it.
|
|
16
|
+
*/
|
|
17
|
+
export declare function releaseOf(store: string): readonly string[] | undefined;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { dirname, existsSync, join } from "../host/io.js";
|
|
2
|
+
import { ledgerLines, signedLines } from "../land/ledger.js";
|
|
3
|
+
import { EXTENSION, fieldOf, foldClaims, isWire, LOCK, selfName } from "./claims.js";
|
|
4
|
+
import { entriesIn, observeText } from "../observe/files.js";
|
|
5
|
+
const held = new Map();
|
|
6
|
+
const merged = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Whose lines carry a class of writing, as the lock says it. Every ledger the store keeps is read, the key claims
|
|
9
|
+
* folded, and the class answered with the id the lock admitted first for it: no module here holds a signer's name, so
|
|
10
|
+
* the day another head runs the same work its lines come out under its own name without a letter changing.
|
|
11
|
+
*/
|
|
12
|
+
export const keyOf = (store, kind, told = []) => keysOf(store, told).classes.get(kind)?.[0];
|
|
13
|
+
export function keyFor(store, kind, told = []) {
|
|
14
|
+
const id = keyOf(store, kind, told);
|
|
15
|
+
if (id === undefined) {
|
|
16
|
+
throw new Error(`${selfName()}: REFUSE·keys the lock admits no key of class \`${kind}\`: name one as \`keys/<id> measure=class value=${kind}\``);
|
|
17
|
+
}
|
|
18
|
+
return id;
|
|
19
|
+
}
|
|
20
|
+
export function lockSigners(store, told = []) {
|
|
21
|
+
const keys = keysOf(store, told);
|
|
22
|
+
const attests = new Set(keys.classes.get('attest') ?? []);
|
|
23
|
+
return keys.signers.filter((id) => !attests.has(id));
|
|
24
|
+
}
|
|
25
|
+
export function lockLines(store) {
|
|
26
|
+
const release = releaseOf(store);
|
|
27
|
+
if (release)
|
|
28
|
+
return release;
|
|
29
|
+
const parts = lockSigners(store).map((id) => ledgerLines(store, id)).filter((part) => part.length > 0);
|
|
30
|
+
const last = merged.get(store);
|
|
31
|
+
if (last !== undefined && last.parts.length === parts.length && last.parts.every((part, i) => part === parts[i]))
|
|
32
|
+
return last.lines;
|
|
33
|
+
const lines = parts.length === 1 ? parts[0] : parts.flat();
|
|
34
|
+
merged.set(store, { parts, lines });
|
|
35
|
+
return lines;
|
|
36
|
+
}
|
|
37
|
+
const standings = new WeakMap();
|
|
38
|
+
/** What stands of the lock, folded once per landing of any of its ledgers: lockLines is the bytes, lockSigners the ids that write them, signedLockLines the same lines still carrying their signatures. */
|
|
39
|
+
export function lockStanding(store) {
|
|
40
|
+
const lines = lockLines(store);
|
|
41
|
+
return standings.get(lines) ?? standings.set(lines, foldClaims(signedLockLines(store)).standing).get(lines);
|
|
42
|
+
}
|
|
43
|
+
export function signedLockLines(store, told = []) {
|
|
44
|
+
const release = releaseOf(store);
|
|
45
|
+
if (release)
|
|
46
|
+
return [...release];
|
|
47
|
+
return lockSigners(store, told).flatMap((id) => signedLines(store, id));
|
|
48
|
+
}
|
|
49
|
+
function keysOf(store, told) {
|
|
50
|
+
const mine = told.length ? read(store, told) : held.get(store) ?? read(store);
|
|
51
|
+
if (!told.length)
|
|
52
|
+
held.set(store, mine);
|
|
53
|
+
return mine;
|
|
54
|
+
}
|
|
55
|
+
const ledgerKeyLines = (store) => (existsSync(join(store, 'ledger')) ? entriesIn(join(store, 'ledger')).map((entry) => entry.name) : [])
|
|
56
|
+
.filter((name) => name.endsWith(EXTENSION)).flatMap((name) => ledgerLines(store, name.slice(0, -EXTENSION.length)))
|
|
57
|
+
.filter((line) => /\bsig=/.test(line) && /(?:^|\s)scope=keys\/[^/\s]+\s/.test(line));
|
|
58
|
+
const releases = new Map();
|
|
59
|
+
/**
|
|
60
|
+
* A release's lock, where the store signs no key of its own: the lock as it was laid is the place's only lines, read
|
|
61
|
+
* and never written. What it says is true where a pin names the release; no ledger is made of it.
|
|
62
|
+
*/
|
|
63
|
+
export function releaseOf(store) {
|
|
64
|
+
if (releases.has(store))
|
|
65
|
+
return releases.get(store);
|
|
66
|
+
const at = join(dirname(store), LOCK);
|
|
67
|
+
const lines = ledgerKeyLines(store).length || !existsSync(at) ? [] : (observeText(at) ?? '').split('\n').filter(isWire);
|
|
68
|
+
const got = lines.some((line) => fieldOf(line, 'scope') === 'publish/bootstrap' && fieldOf(line, 'value') !== 'withdraw') ? lines : undefined;
|
|
69
|
+
releases.set(store, got);
|
|
70
|
+
return got;
|
|
71
|
+
}
|
|
72
|
+
function read(store, told = []) {
|
|
73
|
+
const said = [...ledgerKeyLines(store), ...releaseOf(store) ?? [], ...told]
|
|
74
|
+
.filter((line) => /\bsig=/.test(line) && /(?:^|\s)scope=keys\/[^/\s]+\s/.test(line));
|
|
75
|
+
const standing = foldClaims(said).standing.filter((line) => fieldOf(line, 'value') !== 'withdraw')
|
|
76
|
+
.sort((a, b) => (Number(fieldOf(a, 'epoch')) || 0) - (Number(fieldOf(b, 'epoch')) || 0));
|
|
77
|
+
const idOf = (line) => fieldOf(line, 'scope').slice('keys/'.length);
|
|
78
|
+
const classes = new Map();
|
|
79
|
+
for (const line of standing.filter((one) => fieldOf(one, 'measure') === 'class'))
|
|
80
|
+
classes.set(fieldOf(line, 'value'), [...(classes.get(fieldOf(line, 'value')) ?? []), idOf(line)]);
|
|
81
|
+
const named = new Set(standing.filter((one) => fieldOf(one, 'measure') === 'public-key').map(idOf));
|
|
82
|
+
const signers = [...new Set(standing.filter((one) => fieldOf(one, 'measure') === 'class').map(idOf))].filter((id) => named.has(id));
|
|
83
|
+
return { classes, signers };
|
|
84
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A release is named by the digest of its folder, and what is laid is read again from its bytes by the same method: every
|
|
3
|
+
* coordinate but those the tree's roles call foreign, a dotted one only where the folder's own lock writes into it, sorted, each a
|
|
4
|
+
* ustar entry of mode 0644, owner 0 and time 0, then two empty blocks, gzipped at level nine. The mark the host writes is
|
|
5
|
+
* none of those coordinates, so the digest of a place is the digest of the release laid there, or it is not that release.
|
|
6
|
+
*/
|
|
7
|
+
export declare function releaseDigest(store: string, place: string): {
|
|
8
|
+
readonly state: string;
|
|
9
|
+
readonly digest: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* What the pass lands after it lays: for each release the own lock lays where it needs it, the digest its bytes give, by
|
|
13
|
+
* the stamps of the bytes it read. What is read is the receipt of the bytes as they lie now: none is a count, and one
|
|
14
|
+
* whose digest is not the one the lock names is a count.
|
|
15
|
+
*/
|
|
16
|
+
export declare function landLaid(store: string, own: string, lock: readonly string[], folder: string | undefined): void;
|
|
17
|
+
export declare const laidDiffers: (store: string, own: string, lock: readonly string[], folder: string | undefined) => number;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createHash, gzipSync, join } from "../host/io.js";
|
|
2
|
+
import { canonical, LOCK } from '@lapxo/topos/wire';
|
|
3
|
+
import { fieldOf, isWire } from "./claims.js";
|
|
4
|
+
import { memoized } from "./digests.js";
|
|
5
|
+
import { rolesOf } from "./roles.js";
|
|
6
|
+
import { said } from "./wire.js";
|
|
7
|
+
import { releasesOf } from "../host/release.js";
|
|
8
|
+
import { land, landBlob, ledgerLines } from "../land/ledger.js";
|
|
9
|
+
import { coordinatesUnder, observeFile, observeText, stampOf } from "../observe/files.js";
|
|
10
|
+
import { ownLock } from "../observe/runner.js";
|
|
11
|
+
const RECEIPT = 'laid/';
|
|
12
|
+
const DIGEST = '{digest}';
|
|
13
|
+
/** The host's marks, named by the lock: `release/asset` on this place, else the asset and archive the tree already writes. */
|
|
14
|
+
const assetsOf = (_store) => said(ownLock(), 'release/asset');
|
|
15
|
+
const marked = (coordinate, tokens) => tokens.some((token) => {
|
|
16
|
+
const at = token.indexOf(DIGEST);
|
|
17
|
+
if (at < 0)
|
|
18
|
+
return !token.includes('{') && coordinate === token;
|
|
19
|
+
const head = token.slice(0, at);
|
|
20
|
+
const tail = token.slice(at + DIGEST.length);
|
|
21
|
+
return coordinate.startsWith(head) && coordinate.endsWith(tail)
|
|
22
|
+
&& coordinate.length === head.length + tail.length + 64
|
|
23
|
+
&& /^[0-9a-f]{64}$/.test(coordinate.slice(head.length, coordinate.length - tail.length));
|
|
24
|
+
});
|
|
25
|
+
const coordinatesOf = (store, place) => {
|
|
26
|
+
const roleOf = rolesOf(store);
|
|
27
|
+
const written = new Set((observeText(join(place, LOCK)) ?? '').split('\n').filter(isWire)
|
|
28
|
+
.map((line) => fieldOf(line, 'shape').split('/')[0] ?? ''));
|
|
29
|
+
const held = (coordinate) => !coordinate || (roleOf(coordinate) !== 'foreign' && (!coordinate.startsWith('.') || written.has(coordinate.split('/')[0] ?? '')));
|
|
30
|
+
const marks = assetsOf(store);
|
|
31
|
+
return coordinatesUnder(place, place, held).filter((coordinate) => held(coordinate) && !marked(coordinate, marks)).sort();
|
|
32
|
+
};
|
|
33
|
+
const stateOf = (place, files) => createHash('sha256').update(files.map((coordinate) => `${coordinate} ${stampOf(join(place, coordinate))?.stamp ?? ''}`).join('\n')).digest('hex');
|
|
34
|
+
/**
|
|
35
|
+
* A release is named by the digest of its folder, and what is laid is read again from its bytes by the same method: every
|
|
36
|
+
* coordinate but those the tree's roles call foreign, a dotted one only where the folder's own lock writes into it, sorted, each a
|
|
37
|
+
* ustar entry of mode 0644, owner 0 and time 0, then two empty blocks, gzipped at level nine. The mark the host writes is
|
|
38
|
+
* none of those coordinates, so the digest of a place is the digest of the release laid there, or it is not that release.
|
|
39
|
+
*/
|
|
40
|
+
export function releaseDigest(store, place) {
|
|
41
|
+
const files = coordinatesOf(store, place);
|
|
42
|
+
const state = stateOf(place, files);
|
|
43
|
+
return { state, digest: memoized(store, `laid ${state}`, () => {
|
|
44
|
+
const blocks = [];
|
|
45
|
+
for (const coordinate of files) {
|
|
46
|
+
const bytes = Buffer.from(observeFile(join(place, coordinate)) ?? new Uint8Array());
|
|
47
|
+
const header = Buffer.alloc(512);
|
|
48
|
+
const cut = coordinate.length <= 100 ? -1 : coordinate.lastIndexOf('/');
|
|
49
|
+
header.write(cut < 0 ? coordinate : coordinate.slice(cut + 1), 0, 100, 'utf8');
|
|
50
|
+
header.write('0000644\0', 100, 8, 'utf8');
|
|
51
|
+
header.write('0000000\0', 108, 8, 'utf8');
|
|
52
|
+
header.write('0000000\0', 116, 8, 'utf8');
|
|
53
|
+
header.write(`${bytes.length.toString(8).padStart(11, '0')}\0`, 124, 12, 'utf8');
|
|
54
|
+
header.write('00000000000\0', 136, 12, 'utf8');
|
|
55
|
+
header.write(' ', 148, 8, 'utf8');
|
|
56
|
+
header.write('0', 156, 1, 'utf8');
|
|
57
|
+
header.write('ustar\0', 257, 6, 'utf8');
|
|
58
|
+
header.write('00', 263, 2, 'utf8');
|
|
59
|
+
header.write(cut < 0 ? '' : coordinate.slice(0, cut), 345, 155, 'utf8');
|
|
60
|
+
header.write(`${header.reduce((sum, byte) => sum + byte, 0).toString(8).padStart(6, '0')}\0 `, 148, 8, 'utf8');
|
|
61
|
+
blocks.push(header, bytes, Buffer.alloc((512 - (bytes.length % 512)) % 512));
|
|
62
|
+
}
|
|
63
|
+
blocks.push(Buffer.alloc(1024));
|
|
64
|
+
const archive = gzipSync(Buffer.concat(blocks), { level: 9 });
|
|
65
|
+
const digest = `sha256:${createHash('sha256').update(archive).digest('hex')}`;
|
|
66
|
+
landBlob(store, digest, archive);
|
|
67
|
+
return digest;
|
|
68
|
+
}) };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* What the pass lands after it lays: for each release the own lock lays where it needs it, the digest its bytes give, by
|
|
72
|
+
* the stamps of the bytes it read. What is read is the receipt of the bytes as they lie now: none is a count, and one
|
|
73
|
+
* whose digest is not the one the lock names is a count.
|
|
74
|
+
*/
|
|
75
|
+
export function landLaid(store, own, lock, folder) {
|
|
76
|
+
if (folder === undefined)
|
|
77
|
+
return;
|
|
78
|
+
land(store, folder, releasesOf(lock).filter((line) => fieldOf(line, 'needs')).map((line) => ((got) => canonical({
|
|
79
|
+
scope: `${RECEIPT}${fieldOf(line, 'scope').slice('dep/'.length)}/digest`, role: 'writes', form: 'alphabet', measure: 'digest',
|
|
80
|
+
value: got.digest, by: folder, at: `place:${got.state}`,
|
|
81
|
+
}))(releaseDigest(store, join(own, fieldOf(line, 'needs'))))));
|
|
82
|
+
}
|
|
83
|
+
export const laidDiffers = (store, own, lock, folder) => {
|
|
84
|
+
const said = new Map((folder === undefined ? [] : ledgerLines(store, folder)).filter((line) => fieldOf(line, 'scope').startsWith(RECEIPT))
|
|
85
|
+
.map((line) => [`${fieldOf(line, 'scope')} ${fieldOf(line, 'at')}`, fieldOf(line, 'value')]));
|
|
86
|
+
return releasesOf(lock).filter((line) => fieldOf(line, 'needs')).filter((line) => {
|
|
87
|
+
const place = join(own, fieldOf(line, 'needs'));
|
|
88
|
+
return said.get(`${RECEIPT}${fieldOf(line, 'scope').slice('dep/'.length)}/digest place:${stateOf(place, coordinatesOf(store, place))}`) !== fieldOf(line, 'value');
|
|
89
|
+
}).length;
|
|
90
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A bug found lands as a no of the law it broke. From the epoch the lock asks for it on — the next one while no line
|
|
3
|
+
* asks yet, the epoch an accept would sign it at — every law of the place a witness names, a demand or a ceiling, holds
|
|
4
|
+
* its bug in a no: a need under the wire's sample family /<area>/no/, or a no of the place named after the law. What this
|
|
5
|
+
* counts is each law witnessed since then that holds none. When the lock lists no sample family, every such law is a
|
|
6
|
+
* demand: the folder is not guessed.
|
|
7
|
+
*/
|
|
8
|
+
export declare function bugsWithoutANo(root: string, store: string, standing: readonly string[], place: string, measure: string): number;
|
package/dist/fold/nos.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { existsSync, join } from "../host/io.js";
|
|
2
|
+
import { fieldOf } from "./claims.js";
|
|
3
|
+
import { lockLines } from "./keys.js";
|
|
4
|
+
import { wordsOf } from "./wire.js";
|
|
5
|
+
import { entriesIn } from "../observe/files.js";
|
|
6
|
+
const sampleWord = (standing, root, place) => wordsOf(standing, 'families').find((one) => [one, `${one}s`].some((name) => existsSync(join(root, place, name))));
|
|
7
|
+
const noOf = (need, word) => {
|
|
8
|
+
const steps = need.split('/');
|
|
9
|
+
const i = steps.findIndex((step) => step === word || step === `${word}s`);
|
|
10
|
+
if (i < 0 || steps[i + 2] !== 'no')
|
|
11
|
+
return undefined;
|
|
12
|
+
const file = steps[i + 3];
|
|
13
|
+
return file === undefined || file.includes('*') ? undefined : file.replace(/\.[^.]+$/, '');
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A bug found lands as a no of the law it broke. From the epoch the lock asks for it on — the next one while no line
|
|
17
|
+
* asks yet, the epoch an accept would sign it at — every law of the place a witness names, a demand or a ceiling, holds
|
|
18
|
+
* its bug in a no: a need under the wire's sample family /<area>/no/, or a no of the place named after the law. What this
|
|
19
|
+
* counts is each law witnessed since then that holds none. When the lock lists no sample family, every such law is a
|
|
20
|
+
* demand: the folder is not guessed.
|
|
21
|
+
*/
|
|
22
|
+
export function bugsWithoutANo(root, store, standing, place, measure) {
|
|
23
|
+
const epoch = (line) => Number(fieldOf(line, 'epoch'));
|
|
24
|
+
const asking = standing.filter((line) => fieldOf(line, 'measure') === measure && fieldOf(line, 'value') !== 'withdraw').map(epoch);
|
|
25
|
+
const from = asking.length ? Math.min(...asking) : lockLines(store).reduce((most, line) => Math.max(most, epoch(line)), 0) + 1;
|
|
26
|
+
const word = sampleWord(standing, root, place);
|
|
27
|
+
const nos = new Set();
|
|
28
|
+
for (const line of standing)
|
|
29
|
+
for (const need of fieldOf(line, 'needs').split('|').filter(Boolean)) {
|
|
30
|
+
const name = word === undefined ? undefined : noOf(need, word);
|
|
31
|
+
if (name)
|
|
32
|
+
nos.add(name);
|
|
33
|
+
}
|
|
34
|
+
if (word !== undefined) {
|
|
35
|
+
const dir = [word, `${word}s`].map((name) => join(root, place, name)).find((at) => existsSync(at));
|
|
36
|
+
if (dir !== undefined)
|
|
37
|
+
for (const area of entriesIn(dir).filter((one) => one.dir)) {
|
|
38
|
+
for (const one of entriesIn(join(dir, area.name, 'no')))
|
|
39
|
+
nos.add(one.name.replace(/\.[^.]+$/, ''));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const named = (scope) => scope.slice(scope.lastIndexOf('/') + 1);
|
|
43
|
+
const holds = (line) => nos.has(named(fieldOf(line, 'scope')))
|
|
44
|
+
|| (word !== undefined && fieldOf(line, 'needs').split('|').some((need) => noOf(need, word) !== undefined && existsSync(join(root, need))));
|
|
45
|
+
return standing.filter((line) => fieldOf(line, 'at').startsWith('witness:') && fieldOf(line, 'value') !== 'withdraw' && epoch(line) >= from
|
|
46
|
+
&& fieldOf(line, 'scope').startsWith(`${place}/`)
|
|
47
|
+
&& (fieldOf(line, 'role') === 'demands' || fieldOf(line, 'form') === 'interval') && !holds(line)).length;
|
|
48
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Mark, Cell } from '@lapxo/obligations/views/field';
|
|
2
|
+
import type { ObjectRecord, ObjectContext } from '@lapxo/topos/wire';
|
|
3
|
+
/** Projection dispatches admitted acts into Obligatory; it defines no meet or propagation. */
|
|
4
|
+
export interface ObjectReading {
|
|
5
|
+
cell: string;
|
|
6
|
+
state: string;
|
|
7
|
+
parts: Cell<unknown>;
|
|
8
|
+
rest: readonly string[];
|
|
9
|
+
ownMarks: readonly (string | undefined)[];
|
|
10
|
+
ownClaims: readonly {
|
|
11
|
+
id: string | undefined;
|
|
12
|
+
origin: string;
|
|
13
|
+
}[];
|
|
14
|
+
marks: readonly Mark<unknown>[];
|
|
15
|
+
claims: readonly unknown[];
|
|
16
|
+
}
|
|
17
|
+
export declare function objectFold(records: readonly ObjectRecord[], context: ObjectContext): readonly ObjectReading[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { cell, sign, join, require as requireFloor, observe, mark, parts, state, live, restOf } from '@lapxo/obligations/views/field';
|
|
2
|
+
import { restCoordinates } from '@lapxo/topos/wire';
|
|
3
|
+
export function objectFold(records, context) {
|
|
4
|
+
let world = new Map();
|
|
5
|
+
const definitions = new Map(records.filter(r => r.record === 'cell').map(r => [r.fields.scope, r]));
|
|
6
|
+
const codecs = new Map([...definitions].map(([name, c]) => [name, context.resolve(c)]));
|
|
7
|
+
const ids = new Map(records.map(r => [r.fields.id, r]));
|
|
8
|
+
for (const record of [...records].sort((a, b) => Number(a.fields.epoch) - Number(b.fields.epoch))) {
|
|
9
|
+
const f = record.fields, name = f.scope, at = Number(f.epoch);
|
|
10
|
+
if (record.record === 'cell') {
|
|
11
|
+
world = new Map([...world, [name, cell(name, at, [], restCoordinates(f.restsOn))]]);
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const codec = codecs.get(name), L = codec.form.lattice(codec.params), held = world.get(name);
|
|
15
|
+
if (record.record === 'claim') {
|
|
16
|
+
const target = f.sign === '-1' ? ids.get(f.takes).fields : f;
|
|
17
|
+
const changed = observe(held, { id: f.id, at, origin: target.origin, span: codec.form.parse(codec.params, target.value), ...(f.takes ? { takes: f.takes } : {}) }, f.sign === '-1' ? -1 : 1);
|
|
18
|
+
const seen = [...changed.seen];
|
|
19
|
+
seen[seen.length - 1] = { ...seen.at(-1), id: f.id };
|
|
20
|
+
world = new Map([...world, [name, { ...changed, seen }]]);
|
|
21
|
+
}
|
|
22
|
+
else if (f.sign === '-1') {
|
|
23
|
+
const target = ids.get(f.takes).fields;
|
|
24
|
+
world = new Map([...world, [name, { ...held, marks: [...(held.marks ?? []), mark({ id: f.id, at, takes: f.takes, pole: target.pole, reach: 'local', span: codec.form.parse(codec.params, target.value) })] }]]);
|
|
25
|
+
}
|
|
26
|
+
else if (f.widens !== undefined) {
|
|
27
|
+
const changed = join(L, held, codec.form.parse(codec.params, f.value), f.widens, at);
|
|
28
|
+
const marks = [...(changed.marks ?? [])];
|
|
29
|
+
marks[marks.length - 1] = { ...marks.at(-1), id: f.id };
|
|
30
|
+
world = new Map([...world, [name, { ...changed, marks }]]);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const span = codec.form.parse(codec.params, f.value);
|
|
34
|
+
world = f.pole === 'floor' ? requireFloor(L, world, name, span, { id: f.id, at }) : sign(L, world, name, span, { id: f.id, at });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return [...world].map(([name, c]) => { const codec = codecs.get(name), L = codec.form.lattice(codec.params); return { cell: name, state: state(L, c, world), parts: parts(L, c, world), rest: restOf(c, world), ownMarks: live(c.marks ?? []).map(m => m.id), ownClaims: live(c.seen).map(s => ({ id: s.id, origin: s.origin })), marks: live(c.marks ?? []), claims: live(c.seen) }; });
|
|
38
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare const cased: (question: string) => boolean;
|
|
2
|
+
export declare function isReaderLock(line: string): boolean;
|
|
3
|
+
export declare function readerModules(store: string): readonly string[];
|
|
4
|
+
type Placed = {
|
|
5
|
+
readonly question: string;
|
|
6
|
+
readonly measure: string;
|
|
7
|
+
readonly value: string;
|
|
8
|
+
readonly place: string;
|
|
9
|
+
readonly by: string;
|
|
10
|
+
readonly at: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function placedReadings(observed: readonly string[]): readonly Placed[];
|
|
13
|
+
export declare function casesHeld(observed: readonly string[]): number;
|
|
14
|
+
export declare const readersBehind: () => readonly {
|
|
15
|
+
readonly module: string;
|
|
16
|
+
readonly places: number;
|
|
17
|
+
}[];
|
|
18
|
+
export declare function readerLines(store: string): readonly string[];
|
|
19
|
+
/**
|
|
20
|
+
* A reader never blocks a fold that did not ask to wait: what it read before is served at once, and a reader whose
|
|
21
|
+
* identity is new, or whose places moved, is grey by name and runs behind the fold. A fold that judges waits. A fold
|
|
22
|
+
* that reaches only some regions observes only those, and a place with no reader reads what it carries.
|
|
23
|
+
*/
|
|
24
|
+
export declare const carriesOnly: (root: string, store: string) => boolean;
|
|
25
|
+
/** A reader whose `needs` meet the reach runs, wherever its module lives. The module path is not the region it reads. */
|
|
26
|
+
export declare function readerReaches(reach: readonly string[] | undefined, where: readonly string[]): boolean;
|
|
27
|
+
export declare function observedClaims(root: string, store: string, options?: {
|
|
28
|
+
readonly wait?: boolean;
|
|
29
|
+
readonly only?: string;
|
|
30
|
+
readonly reach?: readonly string[];
|
|
31
|
+
readonly answered?: Map<string, string>;
|
|
32
|
+
}): readonly string[];
|
|
33
|
+
export {};
|