@quo-systems/quo 0.2.9 → 0.2.11
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 +19 -10
- package/SPEC.md +301 -110
- package/dist/being/being.d.ts +2 -2
- package/dist/being/being.js +34 -12
- package/dist/being/digest.js +26 -8
- package/dist/being/index.d.ts +2 -2
- package/dist/being/index.js +2 -2
- package/dist/being/silence.d.ts +2 -0
- package/dist/being/silence.js +12 -0
- package/dist/being/types.d.ts +4 -2
- package/dist/being/types.js +25 -0
- package/dist/conformance/assert.js +40 -6
- package/dist/conformance/beings.d.ts +48 -5
- package/dist/conformance/beings.js +39 -8
- package/dist/conformance/estate.js +110 -21
- package/dist/conformance/index.d.ts +5 -2
- package/dist/conformance/index.js +165 -7
- package/dist/harbor/core.d.ts +5 -2
- package/dist/harbor/core.js +195 -45
- package/dist/harbor/dial.js +32 -15
- package/dist/harbor/index.d.ts +1 -0
- package/dist/harbor/index.js +3 -0
- package/dist/harbor/memory.d.ts +3 -3
- package/dist/harbor/memory.js +7 -12
- package/dist/harbor/reach.js +42 -17
- package/dist/ward/allowance.js +15 -4
- package/dist/ward/arithmetic.d.ts +1 -0
- package/dist/ward/arithmetic.js +22 -6
- package/dist/ward/cells.d.ts +3 -1
- package/dist/ward/cells.js +79 -21
- package/dist/ward/door.d.ts +3 -2
- package/dist/ward/door.js +38 -10
- package/dist/ward/ground.d.ts +5 -1
- package/dist/ward/ground.js +38 -1
- package/dist/ward/heirs.d.ts +2 -3
- package/dist/ward/heirs.js +19 -13
- package/dist/ward/index.d.ts +1 -0
- package/dist/ward/index.js +3 -0
- package/dist/ward/owner.d.ts +6 -27
- package/dist/ward/owner.js +59 -33
- package/dist/ward/partition.d.ts +3 -0
- package/dist/ward/partition.js +109 -4
- package/dist/ward/seal.d.ts +1 -0
- package/dist/ward/seal.js +41 -13
- package/dist/ward/stance.d.ts +7 -3
- package/dist/ward/stance.js +156 -66
- package/dist/ward/ward.d.ts +10 -0
- package/dist/ward/ward.js +123 -51
- package/package.json +4 -2
- package/src/being/being.ts +33 -11
- package/src/being/digest.ts +28 -13
- package/src/being/index.ts +2 -2
- package/src/being/silence.ts +14 -0
- package/src/being/types.ts +39 -5
- package/src/conformance/assert.ts +37 -4
- package/src/conformance/beings.ts +41 -10
- package/src/conformance/estate.ts +107 -20
- package/src/conformance/index.ts +188 -13
- package/src/harbor/core.ts +203 -46
- package/src/harbor/dial.ts +46 -17
- package/src/harbor/index.ts +3 -0
- package/src/harbor/memory.ts +8 -13
- package/src/harbor/reach.ts +47 -21
- package/src/ward/allowance.ts +15 -4
- package/src/ward/arithmetic.ts +25 -8
- package/src/ward/cells.ts +76 -25
- package/src/ward/door.ts +38 -12
- package/src/ward/ground.ts +52 -3
- package/src/ward/heirs.ts +19 -13
- package/src/ward/index.ts +3 -0
- package/src/ward/owner.ts +65 -46
- package/src/ward/partition.ts +109 -5
- package/src/ward/seal.ts +41 -12
- package/src/ward/stance.ts +163 -64
- package/src/ward/ward.ts +124 -52
- package/vectors/arithmetic.json +7 -0
- package/vectors/framing.json +30 -15
- package/vectors/wire.json +4 -4
package/dist/ward/stance.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// The one stance builder. Used for every being the ward boots. Nothing
|
|
3
3
|
// outer is in what she holds: ids in, values out, keys in the bind table.
|
|
4
|
-
import { silence, isSilence,
|
|
4
|
+
import { silence, isSilence, isWord, word, wordOf } from '../being/silence.js';
|
|
5
5
|
import { digest } from '../being/digest.js';
|
|
6
|
-
import { RESERVED_IDS } from '../being/types.js';
|
|
7
|
-
import { at, put, drop } from './partition.js';
|
|
6
|
+
import { RESERVED_IDS, isBlueprint } from '../being/types.js';
|
|
7
|
+
import { at, put, drop, prune } from './partition.js';
|
|
8
8
|
import { allow, within, LATE } from './allowance.js';
|
|
9
|
-
import { isWardPk } from './seal.js';
|
|
9
|
+
import { isHex, isWardPk } from './seal.js';
|
|
10
|
+
import { cellFault } from './cells.js';
|
|
10
11
|
// The three calls on `standings` share the object with the ids she takes, so
|
|
11
12
|
// a standing named after one of them would be unreachable: `standings.knock`
|
|
12
13
|
// is the call, whatever record sits under that name. One namespace means one
|
|
@@ -28,7 +29,7 @@ export function buildStance(inside, key, cells, bind) {
|
|
|
28
29
|
return false;
|
|
29
30
|
if (i.heir === undefined)
|
|
30
31
|
return i.secret === undefined;
|
|
31
|
-
return
|
|
32
|
+
return isHex(i.heir) && isHex(i.secret);
|
|
32
33
|
};
|
|
33
34
|
// One relation, one ask at a time. The rotation is a conversation: a send
|
|
34
35
|
// reads the key that speaks now, announces the next, and moves to it once
|
|
@@ -51,9 +52,9 @@ export function buildStance(inside, key, cells, bind) {
|
|
|
51
52
|
// Every ask a being makes, bounded. The bound is outside the lane on
|
|
52
53
|
// purpose: an ask that waits its turn behind a relation that comes back
|
|
53
54
|
// round never reaches a send, and a bound that only watched the wire would
|
|
54
|
-
// never see it hang. A bound that ran out is
|
|
55
|
-
// unreached promises nothing was delivered and is safe to ask
|
|
56
|
-
// wait that gave up knows no such thing.
|
|
55
|
+
// never see it hang. A bound that ran out is the word late, never
|
|
56
|
+
// unreached: unreached promises nothing was delivered and is safe to ask
|
|
57
|
+
// again, and a wait that gave up knows no such thing.
|
|
57
58
|
//
|
|
58
59
|
// The bell rings before the work is reached, too: an ask that was still
|
|
59
60
|
// waiting its turn when the wait ran out is never sent. Sent then, it would
|
|
@@ -67,56 +68,95 @@ export function buildStance(inside, key, cells, bind) {
|
|
|
67
68
|
});
|
|
68
69
|
return out === LATE ? word('late') : out;
|
|
69
70
|
};
|
|
70
|
-
const
|
|
71
|
-
const r = await inside.send(bind, keys, true, method, args, wanted);
|
|
71
|
+
const read = (r) => {
|
|
72
72
|
if (isSilence(r) || isWord(r))
|
|
73
|
-
return r;
|
|
73
|
+
return { answer: r, door: false, seen: null };
|
|
74
74
|
if ('silence' in r)
|
|
75
|
-
return silence;
|
|
75
|
+
return { answer: silence, door: true, seen: null };
|
|
76
76
|
if ('quo' in r)
|
|
77
|
-
return word(r.quo); // the far door's word for her, sealed to her lid
|
|
78
|
-
|
|
77
|
+
return { answer: word(r.quo), door: true, seen: null }; // the far door's word for her, sealed to her lid
|
|
78
|
+
return { answer: r.object, door: true, seen: r.seen };
|
|
79
|
+
};
|
|
80
|
+
// Whether the door spent the heir this send spoke under. An object, the
|
|
81
|
+
// door's silence and threw all mean it was honoured. A refusal word wrote
|
|
82
|
+
// nothing and says so. Anything that is not the door speaking says nothing.
|
|
83
|
+
const honoured = (r) => r.door && !(isWord(r.answer) && wordOf(r.answer) !== 'threw');
|
|
84
|
+
const answered = (r) => r.door && !isSilence(r.answer) && !isWord(r.answer);
|
|
85
|
+
// The ask is bounded twice with one budget, once around the lane and once
|
|
86
|
+
// around the wire, and the two bells are microseconds apart. A reply that
|
|
87
|
+
// lands between them is a reply she was already told was late: its keys are
|
|
88
|
+
// rotated, since the far door rotated too and nothing may un-rotate that,
|
|
89
|
+
// but nothing of it is written into her cells. What she was handed is the
|
|
90
|
+
// last word on what she saw.
|
|
91
|
+
const send = async (keys, method, args, wanted, rec, live = () => true) => {
|
|
92
|
+
const r = read(await inside.send(bind, keys, method, args, wanted));
|
|
93
|
+
if (rec && method !== undefined && r.seen !== null && live())
|
|
79
94
|
rec.seen = r.seen; // the digest rode along
|
|
80
|
-
return r.
|
|
95
|
+
return r.answer;
|
|
81
96
|
};
|
|
82
|
-
const knocking = async (inv, method, args, wanted) => {
|
|
97
|
+
const knocking = async (inv, method, args, wanted, live = () => true) => {
|
|
83
98
|
const name = nameOf(inv);
|
|
99
|
+
// Taken while this knock waited its turn: the relation lives in the
|
|
100
|
+
// standing now and speaks on its lane, under its keys and its count.
|
|
101
|
+
const taken = takenAs(name);
|
|
102
|
+
if (taken !== undefined) {
|
|
103
|
+
const keys = at(bind.standings, taken);
|
|
104
|
+
if (!keys)
|
|
105
|
+
return word('dropped');
|
|
106
|
+
return lane(`ask:${taken}`, () => asking(taken, keys, at(cells.standings, taken), method, args, wanted, live));
|
|
107
|
+
}
|
|
84
108
|
// her own key for this relation, minted once: rotation two. reused if she knocks again.
|
|
85
109
|
const k = (bind.knocks[name] ??= { current: (await inside.mintKey(bind)).seed, next: null, spoke: false, sent: false, seq: 0 });
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
// spent
|
|
90
|
-
//
|
|
110
|
+
prune(bind.knocks, bind.answered); // this one is the newest, so it stays and the oldest never answered goes
|
|
111
|
+
// The first knock on a heir speaks as the heir, the key the inviter
|
|
112
|
+
// handed out, and announces her own. Once the door has honoured it the
|
|
113
|
+
// heir is spent, whatever she then said, and her own key speaks; a heir
|
|
114
|
+
// spent once stays spent.
|
|
115
|
+
//
|
|
116
|
+
// She sent once as the heir and the door did not speak: nothing came
|
|
117
|
+
// back, or bytes that were not Quo's, or the wait ran out. Either the
|
|
118
|
+
// door heard, spent the heir and rotated to the key she announced, or
|
|
119
|
+
// nothing arrived and the heir still stands. Only the far door knows,
|
|
120
|
+
// and it will not say.
|
|
91
121
|
//
|
|
92
122
|
// So she asks, and the asking tells her. Under her own key: if the door
|
|
93
|
-
// heard, that key is the one it admits, and she is answered
|
|
94
|
-
// not, the key means nothing there, the ask is
|
|
95
|
-
// that door writes nothing
|
|
96
|
-
// she knocks as the heir, as she would
|
|
97
|
-
// one case where a reply was lost, and
|
|
123
|
+
// heard, that key is the one it admits, and she is answered, or told the
|
|
124
|
+
// door's word. If it did not, the key means nothing there, the ask is
|
|
125
|
+
// refused, and a refusal at that door writes nothing: the heir is
|
|
126
|
+
// untouched and still speaks. Then she knocks as the heir, as she would
|
|
127
|
+
// have. One extra round trip in the one case where a reply was lost, and
|
|
128
|
+
// the relation is not stranded.
|
|
98
129
|
//
|
|
99
130
|
// No stranger gains anything by it: whoever holds the invitation could
|
|
100
131
|
// always knock as the heir, and her own key is admitted only where the
|
|
101
132
|
// door already bound it to her.
|
|
102
133
|
if (inv.heir !== undefined && !k.spoke && k.sent) {
|
|
103
134
|
const own = { ward: inv.ward, heir: inv.heir, current: k.current, next: k.next, seq: k.seq };
|
|
104
|
-
const r = await inside.send(bind, own,
|
|
135
|
+
const r = read(await inside.send(bind, own, method, args, wanted));
|
|
105
136
|
k.seq = own.seq;
|
|
106
137
|
k.current = own.current;
|
|
107
138
|
k.next = own.next;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
139
|
+
inside.wrote();
|
|
140
|
+
if (!r.door) {
|
|
141
|
+
// Nothing the door said. Unreached and late are hers to hear now; bytes
|
|
142
|
+
// that were not Quo's leave her where she was, and the heir is tried.
|
|
143
|
+
if (!isSilence(r.answer))
|
|
144
|
+
return r.answer;
|
|
145
|
+
}
|
|
146
|
+
else if (!isSilence(r.answer)) {
|
|
147
|
+
// The door spoke to her own key, so it heard the first knock: this is
|
|
148
|
+
// the answer, or the door's word for her. Its silence alone cannot be
|
|
149
|
+
// told from a refusal, so silence is followed by the knock as the heir,
|
|
150
|
+
// which the door then refuses if it had heard, and she hears silence.
|
|
151
|
+
k.spoke = true;
|
|
152
|
+
if (answered(r))
|
|
153
|
+
bind.answered[name] = true;
|
|
154
|
+
return r.answer;
|
|
114
155
|
}
|
|
115
|
-
// Refused. The door never heard her, so the heir is still hers to spend.
|
|
116
156
|
}
|
|
117
157
|
const first = inv.heir !== undefined && !k.spoke;
|
|
118
158
|
const keys = first ? { ward: inv.ward, heir: inv.heir, current: inv.secret, next: k.current, seq: k.seq } : { ward: inv.ward, heir: inv.heir ?? null, current: k.current, next: k.next, seq: k.seq };
|
|
119
|
-
const r = await inside.send(bind, keys,
|
|
159
|
+
const r = read(await inside.send(bind, keys, method, args, wanted));
|
|
120
160
|
k.sent = true; // bytes went out. whether they arrived is the far door's to know.
|
|
121
161
|
// The number she spoke under, and the key she announced, kept whoever
|
|
122
162
|
// answered and kept when nobody did. A reply lost on the way back is a
|
|
@@ -127,28 +167,28 @@ export function buildStance(inside, key, cells, bind) {
|
|
|
127
167
|
k.current = keys.current;
|
|
128
168
|
k.next = keys.next;
|
|
129
169
|
}
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (isSilence(r) || isWord(r))
|
|
137
|
-
return r;
|
|
138
|
-
if ('silence' in r)
|
|
139
|
-
return silence;
|
|
140
|
-
if ('quo' in r)
|
|
141
|
-
return word(r.quo);
|
|
142
|
-
bind.answered[name] = true;
|
|
143
|
-
return r.object;
|
|
170
|
+
if (honoured(r))
|
|
171
|
+
k.spoke = true;
|
|
172
|
+
if (answered(r))
|
|
173
|
+
bind.answered[name] = true;
|
|
174
|
+
inside.wrote();
|
|
175
|
+
return r.answer;
|
|
144
176
|
};
|
|
145
177
|
// The id she took this relation under, if she took it. One relation is one
|
|
146
178
|
// ward and one heir whichever door it is reached by, so the standing and the
|
|
147
179
|
// invitation answer to the same name.
|
|
148
180
|
const keyName = (k) => (k.heir === null ? `public:${k.ward}` : `${k.ward}:${k.heir}`);
|
|
149
181
|
const takenAs = (name) => Object.keys(bind.standings).find((id) => keyName(bind.standings[id]) === name);
|
|
182
|
+
// A being the ward has taken out reaches nothing through the stance she
|
|
183
|
+
// still holds. Her relations went with her, so every one of them reads as
|
|
184
|
+
// dropped, and nothing she asks for is made: a heir written here would name
|
|
185
|
+
// a being no door holds, and an id minted here would be handed to whoever
|
|
186
|
+
// is booted under her key next.
|
|
187
|
+
const gone = () => !inside.live();
|
|
150
188
|
const calls = {
|
|
151
189
|
knock: async (inv, method, args = {}, wanted) => {
|
|
190
|
+
if (gone())
|
|
191
|
+
return word('dropped');
|
|
152
192
|
if (!valid(inv))
|
|
153
193
|
return word('invitation'); // S1. nothing is sent
|
|
154
194
|
// She may knock again, and after take that knock is an ask: the relation
|
|
@@ -157,8 +197,8 @@ export function buildStance(inside, key, cells, bind) {
|
|
|
157
197
|
// same relation, and the two would refuse each other.
|
|
158
198
|
const id = takenAs(nameOf(inv));
|
|
159
199
|
if (id !== undefined)
|
|
160
|
-
return
|
|
161
|
-
return bounded(wanted, (live) => lane(`knock:${nameOf(inv)}`, () => (live() ? knocking(inv, method, args, wanted) : Promise.resolve(word('late')))));
|
|
200
|
+
return standingAt(id).ask(method, args, wanted);
|
|
201
|
+
return bounded(wanted, (live) => lane(`knock:${nameOf(inv)}`, () => (live() ? knocking(inv, method, args, wanted, live) : Promise.resolve(word('late')))));
|
|
162
202
|
},
|
|
163
203
|
// Take consumes. Until now the relation lived in the knock record, under
|
|
164
204
|
// the ward and the heir; from now it lives in the standing, under her id.
|
|
@@ -178,7 +218,7 @@ export function buildStance(inside, key, cells, bind) {
|
|
|
178
218
|
// ask on it is refused. The relation she took correctly would be dead
|
|
179
219
|
// because a second knock on the same invitation was careless.
|
|
180
220
|
take: async (id, inv) => {
|
|
181
|
-
if (!valid(inv))
|
|
221
|
+
if (gone() || !valid(inv))
|
|
182
222
|
return null;
|
|
183
223
|
const name = nameOf(inv);
|
|
184
224
|
return lane(`knock:${name}`, () => {
|
|
@@ -194,12 +234,16 @@ export function buildStance(inside, key, cells, bind) {
|
|
|
194
234
|
put(cells.standings, id, { id, digest: null, blueprint: null, seen: null });
|
|
195
235
|
delete bind.knocks[name];
|
|
196
236
|
delete bind.answered[name];
|
|
237
|
+
inside.wrote();
|
|
197
238
|
return Promise.resolve(id);
|
|
198
239
|
});
|
|
199
240
|
},
|
|
200
241
|
remove: (id) => {
|
|
242
|
+
if (gone())
|
|
243
|
+
return;
|
|
201
244
|
drop(cells.standings, id);
|
|
202
245
|
drop(bind.standings, id);
|
|
246
|
+
inside.wrote();
|
|
203
247
|
},
|
|
204
248
|
};
|
|
205
249
|
const standingAt = (id) => ({
|
|
@@ -208,20 +252,33 @@ export function buildStance(inside, key, cells, bind) {
|
|
|
208
252
|
// issued while the standing stood is answered even if she drops it in
|
|
209
253
|
// the next line. Waiting for the lane is not a reason to lose it.
|
|
210
254
|
ask: (method, args = {}, wanted) => {
|
|
255
|
+
if (gone())
|
|
256
|
+
return Promise.resolve(word('dropped'));
|
|
211
257
|
const keys = at(bind.standings, id);
|
|
212
258
|
if (!keys)
|
|
213
259
|
return Promise.resolve(word('dropped')); // S2. she dropped it between one line and the next
|
|
214
260
|
const rec = at(cells.standings, id);
|
|
215
|
-
return bounded(wanted, (live) => lane(`ask:${id}`, () => (live() ? asking(id, keys, rec, method, args, wanted) : Promise.resolve(word('late')))));
|
|
261
|
+
return bounded(wanted, (live) => lane(`ask:${id}`, () => (live() ? asking(id, keys, rec, method, args, wanted, live) : Promise.resolve(word('late')))));
|
|
216
262
|
},
|
|
217
263
|
});
|
|
218
|
-
|
|
219
|
-
|
|
264
|
+
// The record an ask writes into is the one it was issued on. A standing
|
|
265
|
+
// dropped and re-taken under the same id while the ask was in flight is
|
|
266
|
+
// another relation, and the blueprint that came back is not hers.
|
|
267
|
+
const asking = async (id, keys, rec, method, args, wanted, live = () => true) => {
|
|
268
|
+
const out = await send(keys, method, args, wanted, rec, live);
|
|
220
269
|
if (method === undefined && !isSilence(out) && !isWord(out)) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
270
|
+
// A blueprint her cells cannot keep, nested past the bound or carrying
|
|
271
|
+
// a key no harbor writes, is not Quo's bytes: silence, and nothing written.
|
|
272
|
+
if (cellFault(out, 'blueprint') !== null)
|
|
273
|
+
return silence;
|
|
274
|
+
if (rec && live() && at(cells.standings, id) === rec) {
|
|
275
|
+
// Read as a blueprint before it is kept as one. A far describe is
|
|
276
|
+
// somebody else's code and may answer anything; what is not a
|
|
277
|
+
// blueprint is not written as one, and she holds no blueprint for
|
|
278
|
+
// that relation rather than one a side would walk and break on. The
|
|
279
|
+
// answer itself is hers either way: it is returned below, unread.
|
|
280
|
+
rec.blueprint = isBlueprint(out) ? out : null;
|
|
281
|
+
rec.digest = rec.seen = await digest(out);
|
|
225
282
|
}
|
|
226
283
|
}
|
|
227
284
|
return out;
|
|
@@ -236,28 +293,61 @@ export function buildStance(inside, key, cells, bind) {
|
|
|
236
293
|
cells,
|
|
237
294
|
// A being may make. The ward refuses what it refuses the owner: a key
|
|
238
295
|
// already booted, a class the harbor does not hold, and a throw at birth
|
|
239
|
-
// leaves the partition as it was. Reaching into
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
|
|
296
|
+
// leaves the partition as it was. Reaching into another is still the
|
|
297
|
+
// owner's alone: what a maker may have is a relation to what she made,
|
|
298
|
+
// by naming an id, and it is made the way every relation is. The being
|
|
299
|
+
// made mints an occupant for her maker under the maker's own key, so she
|
|
300
|
+
// knows who made her by that name and by nothing else; her maker knocks,
|
|
301
|
+
// takes it under the id she gave, and holds one standing like any other.
|
|
302
|
+
// Nothing half-lives: a relation that could not be made unmakes the
|
|
303
|
+
// being, who is a moment old and known to nobody.
|
|
304
|
+
boot: async (className, made, id) => {
|
|
305
|
+
if (gone())
|
|
306
|
+
return null;
|
|
307
|
+
if (id !== undefined && (reserved(id) || at(cells.standings, id) || at(cells.occupants, id)))
|
|
308
|
+
return null;
|
|
309
|
+
const born = inside.instantiate(className, made);
|
|
310
|
+
if (born === null || id === undefined)
|
|
311
|
+
return born;
|
|
312
|
+
const inv = await inside.relate(born, key);
|
|
313
|
+
if (inv) {
|
|
314
|
+
const out = await calls.knock(inv);
|
|
315
|
+
if (!isSilence(out) && !isWord(out) && (await calls.take(id, inv)) === id)
|
|
316
|
+
return born;
|
|
317
|
+
}
|
|
318
|
+
inside.unmake(born);
|
|
319
|
+
return null;
|
|
320
|
+
},
|
|
243
321
|
occupants: {
|
|
244
322
|
// rotation one: the ward mints the occupant's first key and gives the secret away.
|
|
245
323
|
// it keeps the pk beside the id and nothing else. the invitation IS the key.
|
|
246
|
-
invite: async (id) => {
|
|
247
|
-
if (reserved(id) || at(cells.occupants, id) || at(cells.standings, id))
|
|
324
|
+
invite: async (id, notes) => {
|
|
325
|
+
if (gone() || reserved(id) || at(cells.occupants, id) || at(cells.standings, id))
|
|
248
326
|
return null;
|
|
249
|
-
|
|
327
|
+
// The key first, and nothing written until it exists: a record put
|
|
328
|
+
// before the mint would be a record a remove in the meantime drops
|
|
329
|
+
// with no heir to close, and the heir opened after it would name an
|
|
330
|
+
// id nobody holds, for a later invite under that id to resurrect.
|
|
250
331
|
const k = await inside.mintKey(bind);
|
|
332
|
+
if (reserved(id) || at(cells.occupants, id) || at(cells.standings, id))
|
|
333
|
+
return null; // taken while the key was minted
|
|
334
|
+
// The notes are the terms the inviter minted under, hers to read on her
|
|
335
|
+
// gate. She may write more later; nobody outside ever writes them.
|
|
336
|
+
put(cells.occupants, id, { id, notes: notes ? { ...notes } : {} });
|
|
251
337
|
inside.openHeir(k.pk, key, id);
|
|
252
338
|
put(bind.occupants, id, k.pk);
|
|
339
|
+
inside.wrote();
|
|
253
340
|
return { ward: inside.pk, heir: k.pk, secret: k.seed };
|
|
254
341
|
},
|
|
255
342
|
remove: (id) => {
|
|
343
|
+
if (gone())
|
|
344
|
+
return;
|
|
256
345
|
drop(cells.occupants, id);
|
|
257
346
|
const heir = at(bind.occupants, id);
|
|
258
347
|
drop(bind.occupants, id);
|
|
259
348
|
if (heir)
|
|
260
349
|
inside.closeHeir(heir); // the heir dies with the id
|
|
350
|
+
inside.wrote();
|
|
261
351
|
},
|
|
262
352
|
},
|
|
263
353
|
standings,
|
package/dist/ward/ward.d.ts
CHANGED
|
@@ -1,2 +1,12 @@
|
|
|
1
|
+
import type { Cells, Stance } from '../being/types.ts';
|
|
1
2
|
import type { Ground, WardPointers } from './ground.ts';
|
|
3
|
+
import { type Bind } from './partition.ts';
|
|
4
|
+
import { type Door } from './door.ts';
|
|
5
|
+
export type Resident = Door & {
|
|
6
|
+
bind: Bind;
|
|
7
|
+
stance: Stance;
|
|
8
|
+
cells: Cells & {
|
|
9
|
+
class?: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
2
12
|
export declare function Ward(ground: Ground): Promise<WardPointers>;
|