nervur 0.19.2 → 0.20.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.
Files changed (205) hide show
  1. package/README.md +66 -101
  2. package/dist/being/being.d.ts +7 -15
  3. package/dist/being/being.js +16 -67
  4. package/dist/being/digest.d.ts +1 -1
  5. package/dist/being/digest.js +7 -27
  6. package/dist/being/faculty.d.ts +9 -0
  7. package/dist/being/faculty.js +68 -0
  8. package/dist/being/index.d.ts +4 -5
  9. package/dist/being/index.js +5 -5
  10. package/dist/being/types.d.ts +35 -62
  11. package/dist/being/types.js +3 -57
  12. package/dist/being/words.d.ts +13 -0
  13. package/dist/being/words.js +14 -0
  14. package/dist/contract/index.d.ts +26 -0
  15. package/dist/contract/index.js +19 -0
  16. package/dist/crypto/aes.d.ts +3 -0
  17. package/dist/crypto/aes.js +24 -0
  18. package/dist/crypto/bytes.d.ts +6 -0
  19. package/dist/crypto/bytes.js +33 -0
  20. package/dist/crypto/ed25519.d.ts +3 -0
  21. package/dist/crypto/ed25519.js +85 -0
  22. package/dist/crypto/hash.d.ts +2 -0
  23. package/dist/crypto/hash.js +11 -0
  24. package/dist/crypto/index.d.ts +7 -0
  25. package/dist/crypto/index.js +10 -0
  26. package/dist/crypto/json.d.ts +8 -0
  27. package/dist/crypto/json.js +250 -0
  28. package/dist/crypto/mlkem.d.ts +12 -0
  29. package/dist/crypto/mlkem.js +36 -0
  30. package/dist/crypto/subtle.d.ts +10 -0
  31. package/dist/crypto/subtle.js +29 -0
  32. package/dist/crypto/x25519.d.ts +2 -0
  33. package/dist/crypto/x25519.js +21 -0
  34. package/dist/folder/index.d.ts +13 -0
  35. package/dist/folder/index.js +125 -0
  36. package/dist/harbor/dock.d.ts +19 -0
  37. package/dist/harbor/dock.js +92 -0
  38. package/dist/harbor/harbor.d.ts +22 -0
  39. package/dist/harbor/harbor.js +84 -0
  40. package/dist/harbor/index.d.ts +4 -10
  41. package/dist/harbor/index.js +5 -18
  42. package/dist/harbor/registry.d.ts +7 -0
  43. package/dist/harbor/registry.js +13 -0
  44. package/dist/harbor/terrain.d.ts +8 -0
  45. package/dist/harbor/terrain.js +2 -0
  46. package/dist/index.d.ts +7 -0
  47. package/dist/index.js +14 -0
  48. package/dist/pointer/bodies.d.ts +20 -0
  49. package/dist/pointer/bodies.js +45 -0
  50. package/dist/pointer/index.d.ts +2 -0
  51. package/dist/pointer/index.js +4 -0
  52. package/dist/pointer/world.d.ts +34 -0
  53. package/dist/pointer/world.js +76 -0
  54. package/dist/quo/door.d.ts +34 -0
  55. package/dist/quo/door.js +172 -0
  56. package/dist/quo/index.d.ts +8 -0
  57. package/dist/quo/index.js +11 -0
  58. package/dist/quo/invitation.d.ts +7 -0
  59. package/dist/quo/invitation.js +15 -0
  60. package/dist/quo/keys.d.ts +40 -0
  61. package/dist/quo/keys.js +79 -0
  62. package/dist/quo/payload.d.ts +15 -0
  63. package/dist/quo/payload.js +55 -0
  64. package/dist/quo/relations.d.ts +40 -0
  65. package/dist/quo/relations.js +33 -0
  66. package/dist/quo/reply.d.ts +13 -0
  67. package/dist/quo/reply.js +35 -0
  68. package/dist/quo/seal.d.ts +42 -0
  69. package/dist/quo/seal.js +78 -0
  70. package/dist/quo/standing.d.ts +39 -0
  71. package/dist/quo/standing.js +90 -0
  72. package/dist/ward/allowance.d.ts +13 -9
  73. package/dist/ward/allowance.js +28 -67
  74. package/dist/ward/cells.d.ts +6 -6
  75. package/dist/ward/cells.js +67 -179
  76. package/dist/ward/index.d.ts +5 -10
  77. package/dist/ward/index.js +6 -13
  78. package/dist/ward/partition.d.ts +44 -60
  79. package/dist/ward/partition.js +56 -285
  80. package/dist/ward/stance.d.ts +29 -20
  81. package/dist/ward/stance.js +173 -406
  82. package/dist/ward/ward-being.d.ts +33 -0
  83. package/dist/ward/ward-being.js +76 -0
  84. package/dist/ward/ward.d.ts +43 -11
  85. package/dist/ward/ward.js +215 -363
  86. package/package.json +19 -33
  87. package/src/being/being.ts +31 -78
  88. package/src/being/digest.ts +7 -35
  89. package/src/being/faculty.ts +66 -0
  90. package/src/being/index.ts +5 -6
  91. package/src/being/types.ts +47 -145
  92. package/src/being/words.ts +31 -0
  93. package/src/contract/index.ts +44 -0
  94. package/src/crypto/aes.ts +26 -0
  95. package/src/crypto/bytes.ts +37 -0
  96. package/src/crypto/ed25519.ts +84 -0
  97. package/src/crypto/hash.ts +14 -0
  98. package/src/crypto/index.ts +10 -0
  99. package/src/crypto/json.ts +241 -0
  100. package/src/crypto/mlkem.ts +38 -0
  101. package/src/crypto/subtle.ts +33 -0
  102. package/src/crypto/x25519.ts +21 -0
  103. package/src/folder/index.ts +134 -0
  104. package/src/harbor/dock.ts +101 -0
  105. package/src/harbor/harbor.ts +105 -0
  106. package/src/harbor/index.ts +5 -19
  107. package/src/harbor/registry.ts +20 -0
  108. package/src/harbor/terrain.ts +13 -0
  109. package/src/index.ts +20 -0
  110. package/src/pointer/bodies.ts +47 -0
  111. package/src/pointer/index.ts +4 -0
  112. package/src/pointer/world.ts +91 -0
  113. package/src/quo/door.ts +178 -0
  114. package/src/quo/index.ts +11 -0
  115. package/src/quo/invitation.ts +15 -0
  116. package/src/quo/keys.ts +91 -0
  117. package/src/quo/payload.ts +61 -0
  118. package/src/quo/relations.ts +62 -0
  119. package/src/quo/reply.ts +38 -0
  120. package/src/quo/seal.ts +101 -0
  121. package/src/quo/standing.ts +111 -0
  122. package/src/stand/main.ts +19 -0
  123. package/src/stand/stand.ts +178 -0
  124. package/src/ward/allowance.ts +37 -75
  125. package/src/ward/cells.ts +63 -176
  126. package/src/ward/index.ts +6 -17
  127. package/src/ward/partition.ts +86 -326
  128. package/src/ward/stance.ts +185 -420
  129. package/src/ward/ward-being.ts +97 -0
  130. package/src/ward/ward.ts +229 -363
  131. package/dist/being/lent.d.ts +0 -32
  132. package/dist/being/lent.js +0 -72
  133. package/dist/being/silence.d.ts +0 -12
  134. package/dist/being/silence.js +0 -41
  135. package/dist/conformance/assert.d.ts +0 -11
  136. package/dist/conformance/assert.js +0 -106
  137. package/dist/conformance/beings.d.ts +0 -199
  138. package/dist/conformance/beings.js +0 -188
  139. package/dist/conformance/estate.d.ts +0 -5
  140. package/dist/conformance/estate.js +0 -388
  141. package/dist/conformance/index.d.ts +0 -80
  142. package/dist/conformance/index.js +0 -819
  143. package/dist/conformance/reach.d.ts +0 -10
  144. package/dist/conformance/reach.js +0 -72
  145. package/dist/conformance/store.d.ts +0 -5
  146. package/dist/conformance/store.js +0 -113
  147. package/dist/harbor/box.d.ts +0 -121
  148. package/dist/harbor/box.js +0 -121
  149. package/dist/harbor/core.d.ts +0 -55
  150. package/dist/harbor/core.js +0 -662
  151. package/dist/harbor/dial.d.ts +0 -9
  152. package/dist/harbor/dial.js +0 -81
  153. package/dist/harbor/memory.d.ts +0 -29
  154. package/dist/harbor/memory.js +0 -104
  155. package/dist/harbor/reach.d.ts +0 -36
  156. package/dist/harbor/reach.js +0 -199
  157. package/dist/harbor/store.d.ts +0 -35
  158. package/dist/harbor/store.js +0 -62
  159. package/dist/vector/cases.d.ts +0 -42
  160. package/dist/vector/cases.js +0 -223
  161. package/dist/vector/index.d.ts +0 -6
  162. package/dist/vector/index.js +0 -8
  163. package/dist/vector/stand.d.ts +0 -9
  164. package/dist/vector/stand.js +0 -77
  165. package/dist/vector/world.d.ts +0 -144
  166. package/dist/vector/world.js +0 -209
  167. package/dist/ward/arithmetic.d.ts +0 -31
  168. package/dist/ward/arithmetic.js +0 -249
  169. package/dist/ward/door.d.ts +0 -18
  170. package/dist/ward/door.js +0 -186
  171. package/dist/ward/ground.d.ts +0 -29
  172. package/dist/ward/ground.js +0 -56
  173. package/dist/ward/heirs.d.ts +0 -13
  174. package/dist/ward/heirs.js +0 -117
  175. package/dist/ward/json.d.ts +0 -2
  176. package/dist/ward/json.js +0 -163
  177. package/dist/ward/owner.d.ts +0 -13
  178. package/dist/ward/owner.js +0 -220
  179. package/dist/ward/seal.d.ts +0 -52
  180. package/dist/ward/seal.js +0 -150
  181. package/src/being/lent.ts +0 -72
  182. package/src/being/silence.ts +0 -46
  183. package/src/conformance/assert.ts +0 -100
  184. package/src/conformance/beings.ts +0 -188
  185. package/src/conformance/estate.ts +0 -412
  186. package/src/conformance/index.ts +0 -965
  187. package/src/conformance/reach.ts +0 -83
  188. package/src/conformance/store.ts +0 -125
  189. package/src/harbor/box.ts +0 -131
  190. package/src/harbor/core.ts +0 -699
  191. package/src/harbor/dial.ts +0 -112
  192. package/src/harbor/memory.ts +0 -123
  193. package/src/harbor/reach.ts +0 -221
  194. package/src/harbor/store.ts +0 -91
  195. package/src/vector/cases.ts +0 -257
  196. package/src/vector/index.ts +0 -11
  197. package/src/vector/stand.ts +0 -76
  198. package/src/vector/world.ts +0 -232
  199. package/src/ward/arithmetic.ts +0 -251
  200. package/src/ward/door.ts +0 -186
  201. package/src/ward/ground.ts +0 -142
  202. package/src/ward/heirs.ts +0 -116
  203. package/src/ward/json.ts +0 -144
  204. package/src/ward/owner.ts +0 -214
  205. package/src/ward/seal.ts +0 -178
@@ -1,10 +1,5 @@
1
- export { Ward } from './ward.ts';
2
- export type { Ground, WardPointers, Memory } from './ground.ts';
3
- export { BOX, OFFER, RETRACT, volatile } from './ground.ts';
4
- export type { Partition, Heir, Bind, StandingKeys } from './partition.ts';
5
- export { GONE, MINTED, KNOCKS } from './partition.ts';
6
- export type { AskPayload, ReplyPayload } from './seal.ts';
7
- export * as seal from './seal.ts';
8
- export * as arithmetic from './arithmetic.ts';
9
- export { allow, spent, DEFAULT, CEILING } from './allowance.ts';
10
- export type { Allowance } from './allowance.ts';
1
+ export { allow, CEILING, DEFAULT } from './allowance.ts';
2
+ export { HEAD_ROW, Partition, type BeingRow, type Head, type StandingRow } from './partition.ts';
3
+ export { DEPTH } from './stance.ts';
4
+ export { DOCK, Ward, type Catalogue, type Lender, type WardParts } from './ward.ts';
5
+ export { ownerAsk, pilots, WardBeing, type Steward, type WardBeingStance } from './ward-being.ts';
@@ -1,14 +1,7 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
- // nervur/ward — one function. Every ward is the same ward.
3
- export { Ward } from './ward.js';
4
- export { BOX, OFFER, RETRACT, volatile } from './ground.js';
5
- // The three bounds on what a partition may hold, for a kit that must keep
6
- // the same ones and for a test that pins them.
7
- export { GONE, MINTED, KNOCKS } from './partition.js';
8
- // The seal and the arithmetic, for a kit in another language to check its
9
- // bytes against, and for tests that speak to a door directly.
10
- export * as seal from './seal.js';
11
- export * as arithmetic from './arithmetic.js';
12
- // The allowance every ask carries, for a kit in another language and for
13
- // tests that speak to a door directly.
14
- export { allow, spent, DEFAULT, CEILING } from './allowance.js';
2
+ // The ward: its partition, its stances, its ward-being, and the ward.
3
+ export { allow, CEILING, DEFAULT } from './allowance.js';
4
+ export { HEAD_ROW, Partition } from './partition.js';
5
+ export { DEPTH } from './stance.js';
6
+ export { DOCK, Ward } from './ward.js';
7
+ export { ownerAsk, pilots, WardBeing } from './ward-being.js';
@@ -1,65 +1,49 @@
1
- import type { Cells } from '../being/types.ts';
2
- export declare const VERSION = "pre-1.0.0";
3
- export declare const READS: readonly string[];
4
- export type Heir = {
5
- being: string;
6
- id: string;
7
- current: string;
8
- announced: string | null;
9
- fresh: boolean;
10
- mark: number;
11
- spent: number[];
12
- last?: {
13
- seq: number;
14
- reply: string;
15
- };
16
- };
17
- export type StandingKeys = {
18
- ward: string;
19
- heir: string | null;
20
- current: string;
21
- next: string | null;
22
- seq: number;
23
- };
24
- export type Bind = {
25
- standings: Record<string, StandingKeys>;
26
- occupants: Record<string, string>;
27
- knocks: Record<string, {
28
- current: string;
29
- next: string | null;
30
- spoke: boolean;
31
- sent: boolean;
32
- seq: number;
1
+ import type { Lock } from '../crypto/index.ts';
2
+ import { type HeirRecord, type Invitation, type KeptLock, type Relations, type StandingState } from '../quo/index.ts';
3
+ import type { Rows } from '../contract/index.ts';
4
+ import type { JsonObject } from '../being/index.ts';
5
+ export declare const HEAD_ROW = "";
6
+ export type Head = {
7
+ lock?: KeptLock;
8
+ heirs: Record<string, HeirRecord>;
9
+ gone: string[];
10
+ bind: Record<string, {
11
+ being: string;
12
+ id: string;
33
13
  }>;
34
- answered: Record<string, true>;
35
- minted: string[];
14
+ public: string | null;
36
15
  };
37
- export type Gone = {
38
- current: string;
39
- announced: string | null;
16
+ export type StandingRow = {
17
+ invitation: Invitation;
18
+ state: StandingState;
19
+ seen: string | null;
40
20
  };
41
- export declare const GONE = 256;
42
- export declare const MINTED = 8;
43
- export declare const KNOCKS = 64;
44
- export declare const prune: (knocks: Record<string, unknown>, answered: Record<string, true>) => void;
45
- export type Partition = {
46
- version: string;
47
- beings: Record<string, Cells & {
48
- class?: string;
21
+ export type BeingRow = {
22
+ class: string;
23
+ cells: JsonObject;
24
+ occupants: Record<string, {
25
+ heir: string;
26
+ notes: JsonObject;
49
27
  }>;
50
- bind: Record<string, Bind>;
51
- heirs: Record<string, Heir>;
52
- gone: Record<string, Gone>;
53
- public: string | null;
28
+ standings: Record<string, StandingRow>;
54
29
  };
55
- export declare function open(memory: Record<string, unknown>): Partition;
56
- export declare const at: <T>(rec: Record<string, T>, key: string) => T | undefined;
57
- export declare const put: <T>(rec: Record<string, T>, key: string, value: T) => T;
58
- export declare const drop: (rec: Record<string, unknown>, key: string) => void;
59
- export declare const emptyCells: () => Cells;
60
- export declare const emptyBind: () => Bind;
61
- export declare const HEAD = "";
62
- export declare const rowOf: (p: Partition, row: string) => Record<string, unknown> | undefined;
63
- export declare const rowsIn: (p: Record<string, unknown>) => string[];
64
- export declare const restoreRow: (p: Partition, row: string, value: Record<string, unknown> | undefined) => void;
65
- export declare const fromRows: (rows: Record<string, Record<string, unknown>>) => Record<string, unknown>;
30
+ export declare class Partition {
31
+ readonly memory: Rows;
32
+ constructor(memory: Rows);
33
+ get head(): Head;
34
+ get beings(): Record<string, BeingRow>;
35
+ being(key: string): BeingRow | undefined;
36
+ told(key: string): void;
37
+ toldHead(): void;
38
+ kept(): Promise<boolean>;
39
+ }
40
+ export declare class PartitionRelations implements Relations {
41
+ #private;
42
+ constructor(partition: Partition);
43
+ lock(): Lock | undefined;
44
+ setLock(lock: Lock): void;
45
+ get(heir: string): HeirRecord | undefined;
46
+ set(heir: string, record: HeirRecord): void;
47
+ delete(heir: string): void;
48
+ kept(): Promise<boolean>;
49
+ }
@@ -1,295 +1,66 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // The partition. The ward's cells, all the way down. Values only, so the
3
- // harbor may persist it as it likes. Everything durable a ward has is here,
4
- // every secret included. Nothing here is ever in a being's cells.
5
- import { unguarded } from './cells.js';
6
- // The shape of everything below. A ward stamps what it writes and refuses
7
- // what it cannot read: the partition outlives the ward that wrote it, and a
8
- // ward that guessed at a shape it did not know would not fail, it would answer
9
- // wrongly on relations it had silently misread.
10
- //
11
- // One value, and it does not move until 1.0.0. Before a release there is
12
- // nobody holding a partition of another shape to tell apart: if the types
13
- // below change, the partition is thrown away, not migrated to and not counted.
14
- // A number that climbed with every change would be a changelog, and the only
15
- // question asked here is answered by equality — is this a partition this ward
16
- // can read. At 1.0.0 this changes once, and from then on it means something.
17
- export const VERSION = 'pre-1.0.0';
18
- // Every version this ward can read, newest last. Today it is one, and the
19
- // seam below is what makes it able to be more than one later: a partition
20
- // written under an older readable version is carried forward by `upgrade`
21
- // before the ward touches it. The seam is here before 1.0.0 because after
22
- // 1.0.0 there is nowhere to put it. A partition holds every secret and every
23
- // relation a world has, so the first shape change after the freeze cannot be
24
- // answered by throwing it away, and a ward that meets a shape it has no seam
25
- // for refuses to boot with everything still inside it.
26
- export const READS = [VERSION];
27
- // Carry a partition written under an older readable version forward to this
28
- // one. There is nothing to carry today, because READS has one member. Each
29
- // step added here is from one member of READS to the next.
30
- function upgrade(p) {
31
- return p;
32
- }
33
- export const GONE = 256;
34
- // The last few pks a relation minted, and no more. A relation rotates on
35
- // every ask, so a list of all of them is a partition that grows for as long
36
- // as she keeps talking and can never be written down. It lives here, beside
37
- // the other bound on the durable shape, because it is a fact about what a
38
- // partition may hold and not about how a ward mints.
39
- export const MINTED = 8;
40
- // A knock record is a key she minted for one invitation, kept until she takes
41
- // it. Only take deletes one, so a being who knocks and never takes would grow
42
- // her bind table for the life of the ward, one secret seed at a time. The
43
- // list is bounded like `gone`: past the count the oldest go, and a relation
44
- // that answered outlives one that never did, since an answered knock is one
45
- // she may still take.
46
- export const KNOCKS = 64;
47
- export const prune = (knocks, answered) => {
48
- const names = Object.keys(knocks);
49
- if (names.length <= KNOCKS)
50
- return;
51
- const order = [...names.filter((n) => !answered[n]), ...names.filter((n) => answered[n])];
52
- for (const old of order.slice(0, names.length - KNOCKS)) {
53
- delete knocks[old];
54
- delete answered[old];
1
+ import { GONE, keptLock, lockOf } from '../quo/index.js';
2
+ export const HEAD_ROW = '';
3
+ export class Partition {
4
+ memory;
5
+ constructor(memory) {
6
+ this.memory = memory;
7
+ const rows = memory.rows;
8
+ rows.ward ??= { heirs: {}, gone: [], bind: {}, public: null };
9
+ rows.beings ??= {};
55
10
  }
56
- };
57
- // The shape, read before anything acts on it. A partition this ward wrote is
58
- // this shape by construction; one it adopted was written by a hand, another
59
- // kit, or a file that was cut short, and every field below is one the ward,
60
- // the door or the heirs then act on without looking again. A `spent` that is
61
- // not an array rejects the door's promise on the first bound ask, a `mark`
62
- // that is not a number honours every number ever sent and grows without
63
- // bound, a being row that is null refuses the whole ward at birth by
64
- // accident and says nothing about why. So the shape is read once, here, and
65
- // what is not it throws with the path that failed, which names the trouble
66
- // to whoever is holding the file.
67
- //
68
- // The rule, so the reader does not grow into a schema: read every field the
69
- // ward acts on, and refuse only what would make it act wrongly. So `minted`
70
- // must be a list, because she pushes to it, and the truth in `answered` is
71
- // not read, because anything there says answered and nothing else follows.
72
- // `last` is reserved and nobody reads it, so nobody reads its shape either;
73
- // the run that gives it a reader gives it a line here. A being's own cells
74
- // are hers, of any shape JSON carries, and only the two records the ward
75
- // keeps inside them are read.
76
- const fault = (path, want) => {
77
- throw new Error(`partition ${path} is not ${want}`);
78
- };
79
- const table = (v, path) => (typeof v === 'object' && v !== null && !Array.isArray(v) ? v : fault(path, 'an object'));
80
- const list = (v, path) => (Array.isArray(v) ? v : fault(path, 'an array'));
81
- const text = (v, path) => void (typeof v === 'string' || fault(path, 'a string'));
82
- const orNull = (v, path) => void (v === null || typeof v === 'string' || fault(path, 'a string or null'));
83
- const whole = (v, path) => void (Number.isSafeInteger(v) || fault(path, 'a whole number'));
84
- const flag = (v, path) => void (typeof v === 'boolean' || fault(path, 'true or false'));
85
- function read(p) {
86
- for (const [key, cells] of Object.entries(table(p.beings, 'beings'))) {
87
- const c = table(cells, `beings.${key}`);
88
- table(c.standings, `beings.${key}.standings`);
89
- table(c.occupants, `beings.${key}.occupants`);
90
- if (c.class !== undefined)
91
- text(c.class, `beings.${key}.class`);
11
+ get head() {
12
+ return this.memory.rows.ward;
92
13
  }
93
- for (const [key, bind] of Object.entries(table(p.bind, 'bind'))) {
94
- const b = table(bind, `bind.${key}`);
95
- for (const [id, keys] of Object.entries(table(b.standings, `bind.${key}.standings`))) {
96
- const w = `bind.${key}.standings.${id}`;
97
- const s = table(keys, w);
98
- text(s.ward, `${w}.ward`);
99
- orNull(s.heir, `${w}.heir`);
100
- text(s.current, `${w}.current`);
101
- orNull(s.next, `${w}.next`);
102
- whole(s.seq, `${w}.seq`);
103
- }
104
- for (const [id, pk] of Object.entries(table(b.occupants, `bind.${key}.occupants`)))
105
- text(pk, `bind.${key}.occupants.${id}`);
106
- for (const [name, keys] of Object.entries(table(b.knocks, `bind.${key}.knocks`))) {
107
- const w = `bind.${key}.knocks.${name}`;
108
- const k = table(keys, w);
109
- text(k.current, `${w}.current`);
110
- orNull(k.next, `${w}.next`);
111
- flag(k.spoke, `${w}.spoke`);
112
- flag(k.sent, `${w}.sent`);
113
- whole(k.seq, `${w}.seq`);
114
- }
115
- table(b.answered, `bind.${key}.answered`);
116
- for (const [i, pk] of list(b.minted, `bind.${key}.minted`).entries())
117
- text(pk, `bind.${key}.minted[${i}]`);
14
+ get beings() {
15
+ return this.memory.rows.beings;
118
16
  }
119
- for (const [pk, heir] of Object.entries(table(p.heirs, 'heirs'))) {
120
- const h = table(heir, `heirs.${pk}`);
121
- text(h.being, `heirs.${pk}.being`);
122
- text(h.id, `heirs.${pk}.id`);
123
- text(h.current, `heirs.${pk}.current`);
124
- orNull(h.announced, `heirs.${pk}.announced`);
125
- flag(h.fresh, `heirs.${pk}.fresh`);
126
- whole(h.mark, `heirs.${pk}.mark`);
127
- for (const [i, n] of list(h.spent, `heirs.${pk}.spent`).entries())
128
- whole(n, `heirs.${pk}.spent[${i}]`);
17
+ being(key) {
18
+ return Object.hasOwn(this.beings, key) ? this.beings[key] : undefined;
129
19
  }
130
- for (const [pk, gone] of Object.entries(table(p.gone, 'gone'))) {
131
- const g = table(gone, `gone.${pk}`);
132
- text(g.current, `gone.${pk}.current`);
133
- orNull(g.announced, `gone.${pk}.announced`);
20
+ told(key) {
21
+ this.memory.told(key);
134
22
  }
135
- orNull(p.public, 'public');
136
- return p;
137
- }
138
- // The one place a ward reads state that another ward wrote. A fresh
139
- // memory becomes a partition of this version; anything already written must
140
- // say it is this version and be the shape this version names, and a ward that
141
- // cannot read it does not boot. Birth is where a ward is allowed to be loud:
142
- // silence is the door's word, for asks that were made, and no ask has been
143
- // made yet.
144
- export function open(memory) {
145
- const p = memory;
146
- if (Object.keys(memory).length > 0 && p.version !== VERSION) {
147
- if (!READS.includes(p.version))
148
- throw new Error(`partition is version ${p.version}, this ward reads ${READS.join(', ')}`);
149
- upgrade(p).version = VERSION;
23
+ toldHead() {
24
+ this.memory.told(HEAD_ROW);
25
+ }
26
+ kept() {
27
+ return this.memory.kept().catch(() => false);
150
28
  }
151
- p.version ??= VERSION;
152
- p.beings ??= {};
153
- p.bind ??= {};
154
- p.heirs ??= {};
155
- p.gone ??= {};
156
- p.public ??= null;
157
- return read(p);
158
29
  }
159
- // One record, reached by a key a being or an owner chose. A bare lookup finds
160
- // every name on Object's prototype, so `__proto__` answers with the prototype
161
- // itself: read, it is there where nothing was put; written, it reaches every
162
- // object alive in the runtime. Own keys only, both ways, and a write that
163
- // names one of those lands on the record where it belongs.
164
- export const at = (rec, key) => (Object.hasOwn(rec, key) ? rec[key] : undefined);
165
- export const put = (rec, key, value) => {
166
- Object.defineProperty(rec, key, { value, writable: true, enumerable: true, configurable: true });
167
- return value;
168
- };
169
- export const drop = (rec, key) => {
170
- if (Object.hasOwn(rec, key))
171
- delete rec[key];
172
- };
173
- export const emptyCells = () => ({ standings: {}, occupants: {} });
174
- export const emptyBind = () => ({ standings: {}, occupants: {}, knocks: {}, answered: {}, minted: [] });
175
- // ---- the partition in rows, for a store that keeps it
176
- //
177
- // A ward hands a harbor one object, so a being who writes one cell has every
178
- // other being in her ward written down beside her. What a being holds is the
179
- // one thing here that grows without limit, so she is a row: her cells and her
180
- // bind table, under her key. Everything else is one head row, and every part
181
- // of it is bounded already, one record per occupant and two lists that drop
182
- // their oldest.
183
- //
184
- // The split is here, where the shape is, and not in the harbor, which keeps
185
- // what it is given and reads none of it. A store is handed the rows that
186
- // moved; what it does with that is its own, and one that writes every row is
187
- // as correct as one that writes the few.
188
- export const HEAD = ''; // the row that is not a being: no being's key is empty
189
- // What a put back never moves: the two sides of a relation. `beings` and
190
- // `bind` are the tables the rows hang under and are never written whole.
191
- // `heirs` and `gone` are the door's side of every relation this ward holds,
192
- // and a being's own `bind` row is her side of hers.
193
- //
194
- // A relation cannot be put back, only broken. Her keys rotate when a reply
195
- // opens and the door's rotate when it honours, so the two move at different
196
- // moments and neither side holds the seed of a key it has moved past. Stand
197
- // either one at an earlier moment and it speaks under a key the other will
198
- // not admit, with no way back: the seed is gone. The count needs no help
199
- // here, because a door honours any unseen number inside its span and a
200
- // caller's count climbs at every attempt, so numbers find each other again
201
- // on their own. Keys do not.
202
- //
203
- // Ahead of the device is survivable and behind the far side is not, so what
204
- // a refusal puts back is what a being wrote and never what her relations are
205
- // standing on. What it costs is that her keys are then ahead of what the
206
- // store kept, which a restart can undo: a smaller hole, and the same one a
207
- // restart has anyway.
208
- const STANDING = new Set(['beings', 'bind', 'heirs', 'gone']);
209
- // One row's value: a being, or the head, which is everything the partition
210
- // holds that is not filed under a being. The head is read as what is left
211
- // rather than as a list of names, so a store keeps whatever it was handed and
212
- // hands the same thing back, and a field this file grows later needs no line
213
- // in a store to survive a round trip.
214
- //
215
- // Undefined where the key names nobody, which is a row the store drops.
216
- export const rowOf = (p, row) => {
217
- const all = p;
218
- if (row === HEAD)
219
- return Object.fromEntries(Object.entries(all).filter(([k]) => k !== 'beings' && k !== 'bind'));
220
- const cells = at(p.beings ?? {}, row);
221
- return cells === undefined ? undefined : { cells, bind: at(p.bind ?? {}, row) ?? emptyBind() };
222
- };
223
- export const rowsIn = (p) => [HEAD, ...Object.keys(p.beings ?? {})];
224
- // One row put back to what a store holds for it. A store that refused a row
225
- // left the ward's memory ahead of the device, and everything written to that
226
- // being afterwards would be lost at the next reload while she went on
227
- // answering out of a memory nobody keeps. So the row is written back to the
228
- // last value that was kept, and she stands at what is on the device.
229
- //
230
- // In place, always. A booted being holds her cells and her bind table by
231
- // reference: her stance, her guard and her door all point at the objects the
232
- // partition already has, so a row replaced by a fresh object would strand her
233
- // on cells nothing keeps. Only the head may be written whole, because
234
- // everything under it is read through the partition each time.
235
- //
236
- // A row the store does not hold is a being it never kept, and what is kept
237
- // for her is nothing: her row goes, the way the store's own is already gone.
238
- export const restoreRow = (p, row, value) => {
239
- const all = p;
240
- if (row === HEAD) {
241
- for (const k of Object.keys(all))
242
- if (!STANDING.has(k))
243
- drop(all, k);
244
- for (const [k, v] of Object.entries(value ?? {}))
245
- if (!STANDING.has(k))
246
- put(all, k, v);
247
- return;
30
+ // The door's memory, written into the head.
31
+ export class PartitionRelations {
32
+ #partition;
33
+ constructor(partition) {
34
+ this.#partition = partition;
35
+ }
36
+ get #head() {
37
+ return this.#partition.head;
248
38
  }
249
- if (value === undefined) {
250
- drop(p.beings ?? {}, row);
251
- // Her bind goes with her: a being the store never kept has no relation
252
- // anybody is standing on, so there is nothing to leave forward.
253
- drop(p.bind ?? {}, row);
254
- return;
39
+ lock() {
40
+ return lockOf(this.#head.lock);
255
41
  }
256
- // Behind the guard and never through it: a being's cells in a partition
257
- // are the guarded object her stance writes through, and the guard is hers.
258
- // What the harbor puts back is not a write of hers, so it says nothing to
259
- // the ward and marks nothing dirty.
260
- const into = (rows, kept) => {
261
- const guarded = at(rows, row);
262
- if (guarded === undefined)
263
- return void put(rows, row, kept);
264
- const held = unguarded(guarded);
265
- for (const k of Object.keys(held))
266
- drop(held, k);
267
- for (const [k, v] of Object.entries(kept))
268
- put(held, k, v);
269
- };
270
- into(p.beings ?? {}, (value.cells ?? emptyCells()));
271
- };
272
- // The partition back from its rows. A head that is absent is a partition
273
- // nobody has written, and `open` makes an empty one of it.
274
- export const fromRows = (rows) => {
275
- const out = { ...(rows[HEAD] ?? {}) };
276
- const beings = {};
277
- const bind = {};
278
- let any = Object.keys(out).length > 0;
279
- for (const [row, value] of Object.entries(rows)) {
280
- if (row === HEAD)
281
- continue;
282
- put(beings, row, value.cells);
283
- put(bind, row, value.bind);
284
- any = true;
42
+ setLock(lock) {
43
+ this.#head.lock = keptLock(lock);
44
+ this.#partition.toldHead();
285
45
  }
286
- // Nothing kept is nothing handed back. Rows that say only that there are no
287
- // rows must come back as the empty memory they are, because `open` reads an
288
- // empty one as a ward's first breath and anything else as a partition
289
- // somebody wrote, which must then say which version wrote it.
290
- if (!any)
291
- return {};
292
- out.beings = beings;
293
- out.bind = bind;
294
- return out;
295
- };
46
+ get(heir) {
47
+ return Object.hasOwn(this.#head.heirs, heir) ? this.#head.heirs[heir] : undefined;
48
+ }
49
+ set(heir, record) {
50
+ const head = this.#head;
51
+ head.heirs[heir] = record;
52
+ if (record.state === 'kept') {
53
+ head.gone.push(heir);
54
+ while (head.gone.length > GONE)
55
+ delete head.heirs[head.gone.shift()];
56
+ }
57
+ this.#partition.toldHead();
58
+ }
59
+ delete(heir) {
60
+ delete this.#head.heirs[heir];
61
+ this.#partition.toldHead();
62
+ }
63
+ kept() {
64
+ return this.#partition.kept();
65
+ }
66
+ }
@@ -1,20 +1,29 @@
1
- import type { Cells, Invitation, JsonObject, Silence, Stance, Wanted, Word } from '../being/types.ts';
2
- import { type Bind, type StandingKeys } from './partition.ts';
3
- import { type ReplyPayload } from './seal.ts';
4
- export type Inside = {
5
- pk: string;
6
- live(): boolean;
7
- mintKey(bind: Bind): Promise<{
8
- seed: string;
9
- pk: string;
10
- }>;
11
- openHeir(heir: string, being: string, id: string): void;
12
- closeHeir(heir: string): void;
13
- send(bind: Bind, keys: StandingKeys, method: string | undefined, args: JsonObject, wanted: Wanted | undefined): Promise<ReplyPayload | Silence | Word>;
14
- instantiate(className: string, key: string): string | null;
15
- relate(key: string, id: string): Promise<Invitation | null>;
16
- lend(name: string, take: (invitation: Invitation) => Promise<boolean>): Promise<boolean>;
17
- unmake(key: string): void;
18
- wrote(): void;
19
- };
20
- export declare function buildStance(inside: Inside, key: string, cells: Cells, bind: Bind): Stance;
1
+ import { type Door, type Draw, type Invitation } from '../quo/index.ts';
2
+ import type { Clock } from '../contract/index.ts';
3
+ import { type JsonObject, type Occupants, type Stance, type Standings } from '../being/index.ts';
4
+ import type { BeingRow, Partition } from './partition.ts';
5
+ import { DEPTH } from './cells.ts';
6
+ export { DEPTH };
7
+ export interface Inside {
8
+ readonly partition: Partition;
9
+ readonly door: Door;
10
+ readonly draw: Draw;
11
+ readonly clock: Clock;
12
+ live(key: string, row: BeingRow): boolean;
13
+ send(pk: string, bytes: Uint8Array): Promise<Uint8Array | null>;
14
+ boot(maker: string, className: string, key: string, id?: string): Promise<string | null>;
15
+ offer(contract: string): Promise<Invitation | null>;
16
+ retract(contract: string, heir: string): Promise<void>;
17
+ }
18
+ export declare class WardStance implements Stance {
19
+ #private;
20
+ readonly key: string;
21
+ readonly occupants: Occupants;
22
+ readonly standings: Standings;
23
+ constructor(inside: Inside, key: string, row: BeingRow);
24
+ get cells(): JsonObject;
25
+ boot(className: string, key: string, id?: string): Promise<string | null>;
26
+ lend(contract: {
27
+ readonly name: string;
28
+ }, id: string): Promise<string | null>;
29
+ }