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.
- package/README.md +66 -101
- package/dist/being/being.d.ts +7 -15
- package/dist/being/being.js +16 -67
- package/dist/being/digest.d.ts +1 -1
- package/dist/being/digest.js +7 -27
- package/dist/being/faculty.d.ts +9 -0
- package/dist/being/faculty.js +68 -0
- package/dist/being/index.d.ts +4 -5
- package/dist/being/index.js +5 -5
- package/dist/being/types.d.ts +35 -62
- package/dist/being/types.js +3 -57
- package/dist/being/words.d.ts +13 -0
- package/dist/being/words.js +14 -0
- package/dist/contract/index.d.ts +26 -0
- package/dist/contract/index.js +19 -0
- package/dist/crypto/aes.d.ts +3 -0
- package/dist/crypto/aes.js +24 -0
- package/dist/crypto/bytes.d.ts +6 -0
- package/dist/crypto/bytes.js +33 -0
- package/dist/crypto/ed25519.d.ts +3 -0
- package/dist/crypto/ed25519.js +85 -0
- package/dist/crypto/hash.d.ts +2 -0
- package/dist/crypto/hash.js +11 -0
- package/dist/crypto/index.d.ts +7 -0
- package/dist/crypto/index.js +10 -0
- package/dist/crypto/json.d.ts +8 -0
- package/dist/crypto/json.js +250 -0
- package/dist/crypto/mlkem.d.ts +12 -0
- package/dist/crypto/mlkem.js +36 -0
- package/dist/crypto/subtle.d.ts +10 -0
- package/dist/crypto/subtle.js +29 -0
- package/dist/crypto/x25519.d.ts +2 -0
- package/dist/crypto/x25519.js +21 -0
- package/dist/folder/index.d.ts +13 -0
- package/dist/folder/index.js +125 -0
- package/dist/harbor/dock.d.ts +19 -0
- package/dist/harbor/dock.js +92 -0
- package/dist/harbor/harbor.d.ts +22 -0
- package/dist/harbor/harbor.js +84 -0
- package/dist/harbor/index.d.ts +4 -10
- package/dist/harbor/index.js +5 -18
- package/dist/harbor/registry.d.ts +7 -0
- package/dist/harbor/registry.js +13 -0
- package/dist/harbor/terrain.d.ts +8 -0
- package/dist/harbor/terrain.js +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +14 -0
- package/dist/pointer/bodies.d.ts +20 -0
- package/dist/pointer/bodies.js +45 -0
- package/dist/pointer/index.d.ts +2 -0
- package/dist/pointer/index.js +4 -0
- package/dist/pointer/world.d.ts +34 -0
- package/dist/pointer/world.js +76 -0
- package/dist/quo/door.d.ts +34 -0
- package/dist/quo/door.js +172 -0
- package/dist/quo/index.d.ts +8 -0
- package/dist/quo/index.js +11 -0
- package/dist/quo/invitation.d.ts +7 -0
- package/dist/quo/invitation.js +15 -0
- package/dist/quo/keys.d.ts +40 -0
- package/dist/quo/keys.js +79 -0
- package/dist/quo/payload.d.ts +15 -0
- package/dist/quo/payload.js +55 -0
- package/dist/quo/relations.d.ts +40 -0
- package/dist/quo/relations.js +33 -0
- package/dist/quo/reply.d.ts +13 -0
- package/dist/quo/reply.js +35 -0
- package/dist/quo/seal.d.ts +42 -0
- package/dist/quo/seal.js +78 -0
- package/dist/quo/standing.d.ts +39 -0
- package/dist/quo/standing.js +90 -0
- package/dist/ward/allowance.d.ts +13 -9
- package/dist/ward/allowance.js +28 -67
- package/dist/ward/cells.d.ts +6 -6
- package/dist/ward/cells.js +67 -179
- package/dist/ward/index.d.ts +5 -10
- package/dist/ward/index.js +6 -13
- package/dist/ward/partition.d.ts +44 -60
- package/dist/ward/partition.js +56 -285
- package/dist/ward/stance.d.ts +29 -20
- package/dist/ward/stance.js +173 -406
- package/dist/ward/ward-being.d.ts +33 -0
- package/dist/ward/ward-being.js +76 -0
- package/dist/ward/ward.d.ts +43 -11
- package/dist/ward/ward.js +215 -363
- package/package.json +19 -33
- package/src/being/being.ts +31 -78
- package/src/being/digest.ts +7 -35
- package/src/being/faculty.ts +66 -0
- package/src/being/index.ts +5 -6
- package/src/being/types.ts +47 -145
- package/src/being/words.ts +31 -0
- package/src/contract/index.ts +44 -0
- package/src/crypto/aes.ts +26 -0
- package/src/crypto/bytes.ts +37 -0
- package/src/crypto/ed25519.ts +84 -0
- package/src/crypto/hash.ts +14 -0
- package/src/crypto/index.ts +10 -0
- package/src/crypto/json.ts +241 -0
- package/src/crypto/mlkem.ts +38 -0
- package/src/crypto/subtle.ts +33 -0
- package/src/crypto/x25519.ts +21 -0
- package/src/folder/index.ts +134 -0
- package/src/harbor/dock.ts +101 -0
- package/src/harbor/harbor.ts +105 -0
- package/src/harbor/index.ts +5 -19
- package/src/harbor/registry.ts +20 -0
- package/src/harbor/terrain.ts +13 -0
- package/src/index.ts +20 -0
- package/src/pointer/bodies.ts +47 -0
- package/src/pointer/index.ts +4 -0
- package/src/pointer/world.ts +91 -0
- package/src/quo/door.ts +178 -0
- package/src/quo/index.ts +11 -0
- package/src/quo/invitation.ts +15 -0
- package/src/quo/keys.ts +91 -0
- package/src/quo/payload.ts +61 -0
- package/src/quo/relations.ts +62 -0
- package/src/quo/reply.ts +38 -0
- package/src/quo/seal.ts +101 -0
- package/src/quo/standing.ts +111 -0
- package/src/stand/main.ts +19 -0
- package/src/stand/stand.ts +178 -0
- package/src/ward/allowance.ts +37 -75
- package/src/ward/cells.ts +63 -176
- package/src/ward/index.ts +6 -17
- package/src/ward/partition.ts +86 -326
- package/src/ward/stance.ts +185 -420
- package/src/ward/ward-being.ts +97 -0
- package/src/ward/ward.ts +229 -363
- package/dist/being/lent.d.ts +0 -32
- package/dist/being/lent.js +0 -72
- package/dist/being/silence.d.ts +0 -12
- package/dist/being/silence.js +0 -41
- package/dist/conformance/assert.d.ts +0 -11
- package/dist/conformance/assert.js +0 -106
- package/dist/conformance/beings.d.ts +0 -199
- package/dist/conformance/beings.js +0 -188
- package/dist/conformance/estate.d.ts +0 -5
- package/dist/conformance/estate.js +0 -388
- package/dist/conformance/index.d.ts +0 -80
- package/dist/conformance/index.js +0 -819
- package/dist/conformance/reach.d.ts +0 -10
- package/dist/conformance/reach.js +0 -72
- package/dist/conformance/store.d.ts +0 -5
- package/dist/conformance/store.js +0 -113
- package/dist/harbor/box.d.ts +0 -121
- package/dist/harbor/box.js +0 -121
- package/dist/harbor/core.d.ts +0 -55
- package/dist/harbor/core.js +0 -662
- package/dist/harbor/dial.d.ts +0 -9
- package/dist/harbor/dial.js +0 -81
- package/dist/harbor/memory.d.ts +0 -29
- package/dist/harbor/memory.js +0 -104
- package/dist/harbor/reach.d.ts +0 -36
- package/dist/harbor/reach.js +0 -199
- package/dist/harbor/store.d.ts +0 -35
- package/dist/harbor/store.js +0 -62
- package/dist/vector/cases.d.ts +0 -42
- package/dist/vector/cases.js +0 -223
- package/dist/vector/index.d.ts +0 -6
- package/dist/vector/index.js +0 -8
- package/dist/vector/stand.d.ts +0 -9
- package/dist/vector/stand.js +0 -77
- package/dist/vector/world.d.ts +0 -144
- package/dist/vector/world.js +0 -209
- package/dist/ward/arithmetic.d.ts +0 -31
- package/dist/ward/arithmetic.js +0 -249
- package/dist/ward/door.d.ts +0 -18
- package/dist/ward/door.js +0 -186
- package/dist/ward/ground.d.ts +0 -29
- package/dist/ward/ground.js +0 -56
- package/dist/ward/heirs.d.ts +0 -13
- package/dist/ward/heirs.js +0 -117
- package/dist/ward/json.d.ts +0 -2
- package/dist/ward/json.js +0 -163
- package/dist/ward/owner.d.ts +0 -13
- package/dist/ward/owner.js +0 -220
- package/dist/ward/seal.d.ts +0 -52
- package/dist/ward/seal.js +0 -150
- package/src/being/lent.ts +0 -72
- package/src/being/silence.ts +0 -46
- package/src/conformance/assert.ts +0 -100
- package/src/conformance/beings.ts +0 -188
- package/src/conformance/estate.ts +0 -412
- package/src/conformance/index.ts +0 -965
- package/src/conformance/reach.ts +0 -83
- package/src/conformance/store.ts +0 -125
- package/src/harbor/box.ts +0 -131
- package/src/harbor/core.ts +0 -699
- package/src/harbor/dial.ts +0 -112
- package/src/harbor/memory.ts +0 -123
- package/src/harbor/reach.ts +0 -221
- package/src/harbor/store.ts +0 -91
- package/src/vector/cases.ts +0 -257
- package/src/vector/index.ts +0 -11
- package/src/vector/stand.ts +0 -76
- package/src/vector/world.ts +0 -232
- package/src/ward/arithmetic.ts +0 -251
- package/src/ward/door.ts +0 -186
- package/src/ward/ground.ts +0 -142
- package/src/ward/heirs.ts +0 -116
- package/src/ward/json.ts +0 -144
- package/src/ward/owner.ts +0 -214
- package/src/ward/seal.ts +0 -178
package/dist/ward/ward.js
CHANGED
|
@@ -1,396 +1,248 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
import { OWNER,
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const w = await Self.boot(ground);
|
|
22
|
-
return { door: w.door, ask: w.ask };
|
|
2
|
+
// The ward: one door, one partition, and the beings behind the door. It
|
|
3
|
+
// unpacks from its seed, its memory and a catalogue of classes, the
|
|
4
|
+
// ward-being first and every other being from her own row, and it stands
|
|
5
|
+
// what is behind its door for `quo/`.
|
|
6
|
+
import { readValue, writeValue } from '../crypto/index.js';
|
|
7
|
+
import { Door, readInvitation, WardKey } from '../quo/index.js';
|
|
8
|
+
import { digest, isSilence, isWord, OWNER, silence, WARD, word } from '../being/index.js';
|
|
9
|
+
import { Partition, PartitionRelations } from './partition.js';
|
|
10
|
+
import { DEPTH, WardStance } from './stance.js';
|
|
11
|
+
import { WardBeing } from './ward-being.js';
|
|
12
|
+
// The standing every hosted ward's ward-being holds on the dock.
|
|
13
|
+
export const DOCK = 'dock';
|
|
14
|
+
const lends = (being) => typeof being.offer === 'function';
|
|
15
|
+
class RootStance extends WardStance {
|
|
16
|
+
steward;
|
|
17
|
+
constructor(inside, row, steward) {
|
|
18
|
+
super(inside, WARD, row);
|
|
19
|
+
this.steward = steward;
|
|
20
|
+
}
|
|
23
21
|
}
|
|
24
|
-
class
|
|
22
|
+
export class Ward {
|
|
25
23
|
key;
|
|
26
|
-
|
|
27
|
-
g;
|
|
28
|
-
p;
|
|
29
|
-
heirs;
|
|
30
|
-
doors = new Map();
|
|
31
|
-
#birthing = new Set(); // keys whose constructor is running: taken, though no door and no row say so yet
|
|
24
|
+
partition;
|
|
32
25
|
door;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return w;
|
|
26
|
+
clock;
|
|
27
|
+
#parts;
|
|
28
|
+
#residents = new Map();
|
|
29
|
+
#birthing = new Set();
|
|
30
|
+
constructor(parts, key) {
|
|
31
|
+
this.#parts = parts;
|
|
32
|
+
this.key = key;
|
|
33
|
+
this.clock = parts.clock;
|
|
34
|
+
this.partition = new Partition(parts.memory);
|
|
35
|
+
this.door = new Door(key, new PartitionRelations(this.partition), this, parts.entropy.drawer);
|
|
44
36
|
}
|
|
45
|
-
// The
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
async
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
37
|
+
// The ward-being first, then every being her row names. A class the
|
|
38
|
+
// catalogue lacks, or one that throws, leaves that being absent and her
|
|
39
|
+
// row as it was.
|
|
40
|
+
static async unpack(parts) {
|
|
41
|
+
const ward = new Ward(parts, await WardKey.from(parts.seed));
|
|
42
|
+
if (!ward.partition.being(WARD)) {
|
|
43
|
+
ward.partition.beings[WARD] = { class: '', cells: {}, occupants: {}, standings: {} };
|
|
44
|
+
ward.partition.told(WARD);
|
|
45
|
+
ward.partition.toldHead();
|
|
46
|
+
}
|
|
47
|
+
const own = ward.partition.being(WARD);
|
|
48
|
+
const stance = new RootStance(ward, own, ward.#steward);
|
|
49
|
+
const being = parts.root ? parts.root(stance) : new WardBeing(stance);
|
|
50
|
+
own.class = being.constructor.name;
|
|
51
|
+
ward.#residents.set(WARD, { being, row: own, stance });
|
|
52
|
+
if (parts.dock && !Object.hasOwn(own.standings, DOCK))
|
|
53
|
+
await stance.standings.take(DOCK, parts.dock);
|
|
54
|
+
for (const [key, row] of Object.entries(ward.partition.beings)) {
|
|
55
|
+
const C = key === WARD ? undefined : parts.catalogue.classOf(row.class);
|
|
56
|
+
if (C)
|
|
57
|
+
ward.#bear(key, row, C);
|
|
58
|
+
}
|
|
59
|
+
return ward;
|
|
57
60
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// and takes it. The ward reads nothing in the value but that it is one.
|
|
61
|
-
async #lend(name, take) {
|
|
62
|
-
const box = this.doors.get(this.pk)?.stance.standings[BOX];
|
|
63
|
-
if (!box)
|
|
64
|
-
return false;
|
|
65
|
-
const inv = await box.ask(OFFER, { name });
|
|
66
|
-
if (!isInvitation(inv))
|
|
67
|
-
return false;
|
|
68
|
-
const took = await take(inv);
|
|
69
|
-
if (!took)
|
|
70
|
-
await box.ask(RETRACT, { name, heir: inv.heir ?? null });
|
|
71
|
-
return took;
|
|
61
|
+
get pk() {
|
|
62
|
+
return this.key.pk;
|
|
72
63
|
}
|
|
73
|
-
|
|
74
|
-
this.
|
|
75
|
-
this.key = key;
|
|
76
|
-
this.pk = key.pk;
|
|
77
|
-
this.p = open(ground.memory.rows); // the partition: the ward's own state, and every being's row
|
|
78
|
-
// Opening is itself a write: a memory nobody has written comes back with
|
|
79
|
-
// a version stamped on it and the ward's own tables under it. A ward that
|
|
80
|
-
// said nothing here would have every being of it kept and the head that
|
|
81
|
-
// says which version they are written under kept by nobody, so the next
|
|
82
|
-
// boot would read a partition of no version and refuse it.
|
|
83
|
-
this.#wrote(HEAD);
|
|
84
|
-
this.heirs = new Heirs(this.p, () => this.#wrote(HEAD));
|
|
85
|
-
this.door = makeDoor(key, this.heirs, this.doors, () => this.p.public, (n) => ground.random(n), () => this.#keep()); // pointer one
|
|
86
|
-
this.#boot(this.pk, () => this); // the ward's ward is itself
|
|
87
|
-
// pointer two. the owner. the same answer every named asker gets, asker filled in as owner.
|
|
88
|
-
this.ask = async (method, args = {}) => {
|
|
89
|
-
try {
|
|
90
|
-
const out = await this.answer({ id: OWNER }, method, args);
|
|
91
|
-
// The same question the door asks, in the same place: after she has
|
|
92
|
-
// answered and before the owner holds the answer. Silence is what a
|
|
93
|
-
// failed ask says here, so a store that refused is silence, and the
|
|
94
|
-
// owner reads it as it reads every other ask that did not take.
|
|
95
|
-
if (!(await this.#keep().catch(() => false)))
|
|
96
|
-
return silence;
|
|
97
|
-
return isSilence(out) || isWord(out) ? silence : out;
|
|
98
|
-
}
|
|
99
|
-
catch {
|
|
100
|
-
return silence;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
64
|
+
get draw() {
|
|
65
|
+
return this.#parts.entropy.drawer;
|
|
103
66
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// A throw on a boot the owner asked for is that boot's error, and nothing
|
|
107
|
-
// half-lives. This boot nobody asked for, and there is nobody to hand an
|
|
108
|
-
// error to. Any constructor may throw, a default that is not a value, an
|
|
109
|
-
// author's mistake, a shape she does not recognise after an upgrade, and
|
|
110
|
-
// let through here it is one being taking down the ward and every other
|
|
111
|
-
// being in it, on a restart. She is absent instead: no door, so silence
|
|
112
|
-
// at the door, and her cells sit untouched, waiting for the run that can
|
|
113
|
-
// read them. Her row stays hers: nobody boots another class over it, the
|
|
114
|
-
// owner sees her as absent, and the owner may unboot her.
|
|
115
|
-
for (const [k, c] of Object.entries(this.p.beings)) {
|
|
116
|
-
const className = c.class;
|
|
117
|
-
if (k === this.pk || !className)
|
|
118
|
-
continue;
|
|
119
|
-
try {
|
|
120
|
-
this.#boot(k, (stance) => this.g.instantiate(className, stance));
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
/* she is not here this run. the ward is, and so is everyone else. */
|
|
124
|
-
}
|
|
125
|
-
}
|
|
67
|
+
get wardBeing() {
|
|
68
|
+
return this.#residents.get(WARD).being;
|
|
126
69
|
}
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
// names nobody the ward did not bind.
|
|
131
|
-
async answer(asker, method, args = {}) {
|
|
132
|
-
// Nobody is not an owner. The door names nobody the ward did not bind, so
|
|
133
|
-
// the only way here unnamed is a partition that says the ward is its own
|
|
134
|
-
// public being, which no owner ask will write. Silence, not an error
|
|
135
|
-
// object: an unnamed asker is a stranger, and a stranger hears one thing.
|
|
136
|
-
if (asker.id === undefined)
|
|
137
|
-
return silence;
|
|
138
|
-
return ownerAnswer({
|
|
139
|
-
pk: this.pk,
|
|
140
|
-
doors: this.doors,
|
|
141
|
-
absent: () => this.#absent(),
|
|
142
|
-
publicKey: () => this.p.public,
|
|
143
|
-
instantiate: (className, key) => this.#instantiate(className, key),
|
|
144
|
-
unboot: (key) => this.#unboot(key),
|
|
145
|
-
setPublic: (key) => {
|
|
146
|
-
this.p.public = key;
|
|
147
|
-
this.#wrote(HEAD);
|
|
148
|
-
},
|
|
149
|
-
}, asker, method, args);
|
|
70
|
+
// The unsealed ask: the ward-being, asked by whoever holds this ward.
|
|
71
|
+
async root(method, args = {}) {
|
|
72
|
+
return this.#kept(WARD, () => this.#answer(WARD, { id: OWNER }, method, args));
|
|
150
73
|
}
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
this.
|
|
74
|
+
// A being's answer, kept. Where the memory refuses, what she wrote is
|
|
75
|
+
// put back and her answer is silence. What her relations stand on is not
|
|
76
|
+
// put back: a relation's keys move only as far as its standing follows.
|
|
77
|
+
async #kept(key, work) {
|
|
78
|
+
const row = this.partition.being(key);
|
|
79
|
+
const before = row && JSON.stringify(row.cells);
|
|
80
|
+
const out = await work();
|
|
81
|
+
if (await this.partition.kept())
|
|
82
|
+
return out;
|
|
83
|
+
if (row && before !== undefined) {
|
|
84
|
+
for (const k of Object.keys(row.cells))
|
|
85
|
+
delete row.cells[k];
|
|
86
|
+
for (const [k, v] of Object.entries(JSON.parse(before)))
|
|
87
|
+
Object.defineProperty(row.cells, k, { value: v, enumerable: true, writable: true, configurable: true });
|
|
88
|
+
this.partition.told(key);
|
|
89
|
+
}
|
|
90
|
+
return silence;
|
|
159
91
|
}
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return this.g.memory.kept();
|
|
92
|
+
// Behind: the zero head reaches the public being, a heir the being that
|
|
93
|
+
// invited it.
|
|
94
|
+
get zero() {
|
|
95
|
+
const key = this.partition.head.public;
|
|
96
|
+
return key !== null && this.#residents.has(key);
|
|
166
97
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
98
|
+
async answer(heir, p) {
|
|
99
|
+
const bound = heir === null ? undefined : this.partition.head.bind[heir];
|
|
100
|
+
const key = heir === null ? this.partition.head.public : bound?.being;
|
|
101
|
+
const asker = bound ? { id: bound.id } : {};
|
|
102
|
+
const args = p.args === undefined ? {} : readValue(p.args, DEPTH + 1);
|
|
103
|
+
if (key === null || key === undefined || typeof args !== 'object' || args === null || Array.isArray(args))
|
|
104
|
+
return { silence: true };
|
|
105
|
+
const out = await this.#kept(key, () => this.#answer(key, asker, p.method, args));
|
|
106
|
+
const object = isSilence(out) || isWord(out) ? undefined : writeValue(out, DEPTH);
|
|
107
|
+
if (object === undefined)
|
|
108
|
+
return { silence: true };
|
|
109
|
+
const being = this.#residents.get(key)?.being;
|
|
110
|
+
const seen = p.method === undefined || !being?.describe ? null : await digest(being.describe(asker));
|
|
111
|
+
return { object, seen };
|
|
175
112
|
}
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// constructor can reach the stance and boot: a class that boots its own
|
|
184
|
-
// key from inside itself would pass all three, since neither its door nor
|
|
185
|
-
// its row exists yet, and the two objects would then share one row. A key
|
|
186
|
-
// being born is a key taken, for as long as the birth lasts.
|
|
187
|
-
if (typeof key !== 'string' || typeof className !== 'string' || !key || this.doors.has(key) || at(this.p.beings, key) || this.#birthing.has(key))
|
|
188
|
-
return null;
|
|
189
|
-
let door;
|
|
190
|
-
this.#birthing.add(key);
|
|
113
|
+
// Every path that reaches a being's answer. A throw, a word out of her,
|
|
114
|
+
// or nothing at all is silence.
|
|
115
|
+
async #answer(key, asker, method, args) {
|
|
116
|
+
const resident = this.#residents.get(key);
|
|
117
|
+
if (!resident)
|
|
118
|
+
return silence;
|
|
119
|
+
let out;
|
|
191
120
|
try {
|
|
192
|
-
|
|
121
|
+
out = await resident.being.answer(asker, method, args);
|
|
193
122
|
}
|
|
194
123
|
catch {
|
|
195
|
-
return
|
|
196
|
-
}
|
|
197
|
-
finally {
|
|
198
|
-
this.#birthing.delete(key);
|
|
124
|
+
return silence;
|
|
199
125
|
}
|
|
200
|
-
|
|
201
|
-
return null;
|
|
202
|
-
unguarded(door.cells).class = className; // so a restart finds her. the ward's key, written behind her guard
|
|
203
|
-
this.#wrote(key);
|
|
204
|
-
return door;
|
|
126
|
+
return out === undefined || isWord(out) ? silence : out;
|
|
205
127
|
}
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
// and boot her again. An absent being leaves the same way: she has no
|
|
213
|
-
// stance to speak for her, so the ward closes her heirs itself.
|
|
214
|
-
#unboot(key) {
|
|
215
|
-
if (key === this.pk)
|
|
216
|
-
return null;
|
|
217
|
-
const door = this.doors.get(key);
|
|
218
|
-
const cells = door?.cells ?? at(this.p.beings, key);
|
|
219
|
-
if (!cells)
|
|
220
|
-
return null;
|
|
221
|
-
const ids = (r) => (r !== null && typeof r === 'object' ? Object.keys(r) : []);
|
|
222
|
-
const occupants = ids(cells.occupants), standings = ids(cells.standings);
|
|
223
|
-
if (door) {
|
|
224
|
-
for (const id of occupants)
|
|
225
|
-
door.stance.occupants.remove(id);
|
|
226
|
-
for (const id of standings)
|
|
227
|
-
door.stance.standings.remove(id);
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
const bind = at(this.p.bind, key);
|
|
231
|
-
for (const heir of Object.values(bind?.occupants ?? {}))
|
|
232
|
-
this.heirs.close(heir);
|
|
233
|
-
}
|
|
234
|
-
// A ward whose public being is gone answers arrivals for no heir with
|
|
235
|
-
// silence, as a ward that never had one does.
|
|
236
|
-
if (this.p.public === key)
|
|
237
|
-
this.p.public = null;
|
|
238
|
-
drop(this.p.beings, key);
|
|
239
|
-
drop(this.p.bind, key);
|
|
240
|
-
this.doors.delete(key);
|
|
241
|
-
this.#wrote(key); // she is gone, and her row goes with her
|
|
242
|
-
this.#wrote(HEAD); // her heirs were closed, and the public being may have been her
|
|
243
|
-
return [...occupants, ...standings];
|
|
128
|
+
// Inside: what every stance of this ward stands on.
|
|
129
|
+
// One path through a door for every ask, this ward's own included.
|
|
130
|
+
async send(pk, bytes) {
|
|
131
|
+
if (pk === this.pk)
|
|
132
|
+
return (await this.door.arrive(bytes)).bytes;
|
|
133
|
+
return this.#parts.carrier.carry(pk, bytes);
|
|
244
134
|
}
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const cells = guardCells(at(this.p.beings, key) ?? emptyCells(), () => this.#wrote(key));
|
|
254
|
-
const bind = at(this.p.bind, key) ?? emptyBind();
|
|
255
|
-
const stance = buildStance({
|
|
256
|
-
pk: this.pk,
|
|
257
|
-
// This stance, not merely this key: unboot and boot again under the
|
|
258
|
-
// same key makes a new being, and the old stance is not hers.
|
|
259
|
-
live: () => this.doors.get(key)?.stance === stance,
|
|
260
|
-
mintKey: (b) => this.#mintKey(b, key),
|
|
261
|
-
openHeir: (heir, being, id) => this.heirs.open(heir, being, id),
|
|
262
|
-
closeHeir: (heir) => this.heirs.close(heir),
|
|
263
|
-
send: (b, keys, method, args, wanted) => this.#send(b, keys, method, args, wanted, key),
|
|
264
|
-
// A throw at birth is null to her, not a throw in her method: she asked
|
|
265
|
-
// for a being and got none, and her own answer is still hers to give.
|
|
266
|
-
instantiate: (className, k) => {
|
|
267
|
-
const made = this.#instantiate(className, k);
|
|
268
|
-
return made && made !== 'threw' ? made.key : null;
|
|
269
|
-
},
|
|
270
|
-
// The two halves of a maker's way back, each the ward's own call: the
|
|
271
|
-
// being made mints an occupant for her maker, and a relation that
|
|
272
|
-
// never came about takes her out again.
|
|
273
|
-
relate: async (k, id) => (await this.doors.get(k)?.stance.occupants.invite(id)) ?? null,
|
|
274
|
-
unmake: (k) => void this.#unboot(k),
|
|
275
|
-
lend: (name, take) => this.#lend(name, take),
|
|
276
|
-
wrote: () => this.#wrote(key),
|
|
277
|
-
}, key, cells, bind);
|
|
278
|
-
const being = make(stance);
|
|
279
|
-
if (!being || typeof being.answer !== 'function')
|
|
280
|
-
return null; // a being is anything with an answer, and nothing without one
|
|
281
|
-
put(this.p.beings, key, cells);
|
|
282
|
-
put(this.p.bind, key, bind);
|
|
283
|
-
const door = { key, cells, bind, stance, being };
|
|
284
|
-
this.doors.set(key, door);
|
|
285
|
-
this.#wrote(key);
|
|
286
|
-
return door;
|
|
135
|
+
// A lend: the ward-being lends herself, as the dock does, or asks the dock
|
|
136
|
+
// through her standing.
|
|
137
|
+
async offer(contract) {
|
|
138
|
+
const own = this.#residents.get(WARD);
|
|
139
|
+
if (lends(own.being))
|
|
140
|
+
return own.being.offer(contract);
|
|
141
|
+
const out = await own.stance.standings.get(DOCK)?.ask('lend', { contract });
|
|
142
|
+
return readInvitation(out?.invitation);
|
|
287
143
|
}
|
|
288
|
-
async
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
// but the keys of the moment.
|
|
294
|
-
bind.minted.push(k.pk);
|
|
295
|
-
if (bind.minted.length > MINTED)
|
|
296
|
-
bind.minted.splice(0, bind.minted.length - MINTED);
|
|
297
|
-
this.#wrote(row);
|
|
298
|
-
return k;
|
|
144
|
+
async retract(contract, heir) {
|
|
145
|
+
const own = this.#residents.get(WARD);
|
|
146
|
+
if (lends(own.being))
|
|
147
|
+
return own.being.withdraw(contract, heir);
|
|
148
|
+
await own.stance.standings.get(DOCK)?.ask('retract', { contract, heir });
|
|
299
149
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
//
|
|
304
|
-
// the
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const
|
|
150
|
+
live(key, row) {
|
|
151
|
+
return this.#residents.get(key)?.row === row;
|
|
152
|
+
}
|
|
153
|
+
// A being boots another of this ward. With an id, the new being invites
|
|
154
|
+
// her maker under the maker's key, and the maker takes it under id; a
|
|
155
|
+
// relation that could not be made unmakes the new being.
|
|
156
|
+
async boot(maker, className, key, id) {
|
|
157
|
+
if ((await this.#make(key, className)) !== 'booted')
|
|
158
|
+
return null;
|
|
159
|
+
if (id === undefined)
|
|
160
|
+
return key;
|
|
161
|
+
const invitation = await this.#residents.get(key).stance.occupants.invite(maker);
|
|
162
|
+
const taken = invitation ? await this.#residents.get(maker)?.stance.standings.take(id, invitation) : null;
|
|
163
|
+
if (taken)
|
|
164
|
+
return key;
|
|
165
|
+
this.#unboot(key);
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
async #make(key, className) {
|
|
169
|
+
if (key === '' || key === WARD || this.partition.being(key) || this.#birthing.has(key))
|
|
170
|
+
return 'key taken';
|
|
171
|
+
const C = this.#parts.catalogue.classOf(className);
|
|
172
|
+
if (!C)
|
|
173
|
+
return 'no such class';
|
|
174
|
+
this.#birthing.add(key);
|
|
313
175
|
try {
|
|
314
|
-
|
|
176
|
+
const row = { class: className, cells: {}, occupants: {}, standings: {} };
|
|
177
|
+
this.partition.beings[key] = row;
|
|
178
|
+
if (!this.#bear(key, row, C)) {
|
|
179
|
+
delete this.partition.beings[key];
|
|
180
|
+
return 'threw at birth';
|
|
181
|
+
}
|
|
182
|
+
this.partition.told(key);
|
|
183
|
+
return 'booted';
|
|
315
184
|
}
|
|
316
185
|
finally {
|
|
317
|
-
|
|
186
|
+
this.#birthing.delete(key);
|
|
318
187
|
}
|
|
319
188
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
// the default, and asking for more than the ceiling is the ceiling: budget
|
|
323
|
-
// is granted by a ward, never minted by a being.
|
|
324
|
-
const budget = allow(wanted);
|
|
325
|
-
const by = (await beingKey(unhex(keys.current))).pk;
|
|
326
|
-
// A public being is reached without a heir, and the door keeps nothing for
|
|
327
|
-
// whoever asked: no key it vouched for, so nothing to announce and nothing
|
|
328
|
-
// to rotate to. A standing on her signs with one key for life. Every other
|
|
329
|
-
// ask announces its next: there is no send that does not.
|
|
330
|
-
if (keys.next === null && keys.heir !== null)
|
|
331
|
-
keys.next = (await this.#mintKey(bind, row)).seed;
|
|
332
|
-
const next = keys.next === null ? null : (await beingKey(unhex(keys.next))).pk;
|
|
333
|
-
// Her count for this relation, one higher every call and never reused. The
|
|
334
|
-
// far door honours each number once. One relation sends one at a time, so
|
|
335
|
-
// the numbers leave in the order they were taken.
|
|
336
|
-
const seq = (keys.seq += 1);
|
|
337
|
-
// Named here, before the bytes go out, and not at the end with the keys.
|
|
338
|
-
// The far door honours a number once, and it honours it before this side
|
|
339
|
-
// hears anything back: a reply that is lost, a wait that ran out, a road
|
|
340
|
-
// that took the bytes and said nothing, all end this call before the end
|
|
341
|
-
// of it is reached. A count named only there is a count a restart forgets
|
|
342
|
-
// while the door remembers, and she then speaks a number that door has
|
|
343
|
-
// already spent, which it refuses as the replay it cannot tell it from.
|
|
344
|
-
// So the rule is the send and not the reply: what she spoke under is
|
|
345
|
-
// written down because she spoke it.
|
|
346
|
-
this.#wrote(row);
|
|
347
|
-
// Args that will not go through the seal are args that never left. A
|
|
348
|
-
// being holds three answers and a throw is not one of them, so an ask
|
|
349
|
-
// that cannot be sealed is told what is true of it: no door was reached.
|
|
350
|
-
// One object of values, by the rule her cells keep and the far door
|
|
351
|
-
// reads: a Date would arrive as a string, a function would not arrive at
|
|
352
|
-
// all, a list or a string would be refused as a stranger's bytes, and
|
|
353
|
-
// she would never know the far being was asked something other than
|
|
354
|
-
// what she said.
|
|
355
|
-
if (args === null || typeof args !== 'object' || Array.isArray(args) || cellFault(args, 'args') !== null)
|
|
356
|
-
return unreached();
|
|
357
|
-
let sealed;
|
|
189
|
+
#bear(key, row, C) {
|
|
190
|
+
const stance = new WardStance(this, key, row);
|
|
358
191
|
try {
|
|
359
|
-
|
|
192
|
+
this.#residents.set(key, { being: new C(stance), row, stance });
|
|
193
|
+
return true;
|
|
360
194
|
}
|
|
361
195
|
catch {
|
|
362
|
-
|
|
196
|
+
this.#residents.delete(key);
|
|
197
|
+
return false;
|
|
363
198
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
// What comes back late is not read.
|
|
373
|
-
//
|
|
374
|
-
// A wait that ran out is `late`, never unreached. Unreached promises
|
|
375
|
-
// nothing was delivered and is safe to retry; a bound that expired knows
|
|
376
|
-
// no such thing, because the far door may have heard and be working still.
|
|
377
|
-
//
|
|
378
|
-
// A harbor answers bytes or nothing. One that throws instead has answered
|
|
379
|
-
// nothing in a louder voice, and is read as nothing: no door was reached.
|
|
380
|
-
const carried = (keys.ward === this.pk ? this.door(new Uint8Array(bytes)).then((r) => r.bytes) : this.g.carry(keys.ward, bytes)).then((b) => b, () => undefined);
|
|
381
|
-
const out = await within(budget.time, carried);
|
|
382
|
-
if (out === LATE)
|
|
383
|
-
return word('late');
|
|
384
|
-
if (out === undefined)
|
|
385
|
-
return unreached(); // nothing came back. no door was reached.
|
|
386
|
-
const reply = await openReply(out, ephemeral, wardSignPk(keys.ward));
|
|
387
|
-
if (!reply)
|
|
388
|
-
return silence; // did not open, or not from that ward: not Quo's bytes
|
|
389
|
-
if ('object' in reply && keys.next !== null) {
|
|
390
|
-
keys.current = keys.next; // the far door holds `next` as announced. move to it.
|
|
391
|
-
keys.next = null;
|
|
199
|
+
}
|
|
200
|
+
#unboot(key) {
|
|
201
|
+
const row = key === WARD ? undefined : this.partition.being(key);
|
|
202
|
+
if (!row)
|
|
203
|
+
return false;
|
|
204
|
+
for (const { heir } of Object.values(row.occupants)) {
|
|
205
|
+
this.door.remove(heir);
|
|
206
|
+
delete this.partition.head.bind[heir];
|
|
392
207
|
}
|
|
393
|
-
this
|
|
394
|
-
|
|
208
|
+
if (this.partition.head.public === key)
|
|
209
|
+
this.partition.head.public = null;
|
|
210
|
+
delete this.partition.beings[key];
|
|
211
|
+
this.#residents.delete(key);
|
|
212
|
+
this.partition.toldHead();
|
|
213
|
+
this.partition.told(key);
|
|
214
|
+
return true;
|
|
395
215
|
}
|
|
216
|
+
// What the ward-being asks of her ward.
|
|
217
|
+
#steward = {
|
|
218
|
+
pk: () => this.pk,
|
|
219
|
+
classOf: (name) => this.#parts.catalogue.classOf(name),
|
|
220
|
+
beings: () => {
|
|
221
|
+
const out = {};
|
|
222
|
+
for (const [key, row] of Object.entries(this.partition.beings)) {
|
|
223
|
+
if (key !== WARD)
|
|
224
|
+
out[key] = { class: row.class, public: this.partition.head.public === key, absent: !this.#residents.has(key) };
|
|
225
|
+
}
|
|
226
|
+
return out;
|
|
227
|
+
},
|
|
228
|
+
boot: (key, className) => this.#make(key, className),
|
|
229
|
+
unboot: (key) => this.#unboot(key),
|
|
230
|
+
publish: (key) => {
|
|
231
|
+
if (key !== null && (key === WARD || !this.partition.being(key)))
|
|
232
|
+
return false;
|
|
233
|
+
this.partition.head.public = key;
|
|
234
|
+
this.partition.toldHead();
|
|
235
|
+
return true;
|
|
236
|
+
},
|
|
237
|
+
invite: (being, id, notes) => {
|
|
238
|
+
const resident = being === WARD ? undefined : this.#residents.get(being);
|
|
239
|
+
return resident ? resident.stance.occupants.invite(id, notes) : Promise.resolve(null);
|
|
240
|
+
},
|
|
241
|
+
ask: (being, method, args) => {
|
|
242
|
+
const key = being ?? this.partition.head.public;
|
|
243
|
+
if (key === null || key === WARD)
|
|
244
|
+
return Promise.resolve(word('unreached'));
|
|
245
|
+
return this.#answer(key, being === null ? {} : { id: OWNER }, method, args);
|
|
246
|
+
},
|
|
247
|
+
};
|
|
396
248
|
}
|