nervur 0.22.0 → 0.22.1
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/LICENSE +1 -1
- package/NOTICE +6 -2
- package/README.md +22 -10
- package/dist/core/edge/kit.js +1 -1
- package/dist/core/harbor/carrying.d.ts +1 -2
- package/dist/core/harbor/carrying.js +3 -6
- package/dist/core/harbor/harbor.js +14 -4
- package/dist/core/ward/house.d.ts +3 -0
- package/dist/core/ward/house.js +34 -8
- package/dist/core/ward/partition.d.ts +1 -0
- package/dist/core/ward/stance.d.ts +3 -1
- package/dist/core/ward/stance.js +12 -5
- package/package.json +22 -4
- package/src/core/harbor/carrying.ts +4 -7
- package/src/core/harbor/harbor.ts +12 -4
- package/src/core/ward/house.ts +33 -7
- package/src/core/ward/partition.ts +5 -2
- package/src/core/ward/stance.ts +13 -5
|
@@ -37,8 +37,7 @@ export declare abstract class CarrierFaculty extends Faculty {
|
|
|
37
37
|
abstract accepts(address: string): boolean;
|
|
38
38
|
abstract dial(address: string, pk: string, bytes: Uint8Array): Promise<Dialed>;
|
|
39
39
|
listening(): string[];
|
|
40
|
-
|
|
41
|
-
relay(_pk: string, _bytes: Uint8Array): Promise<Uint8Array | null>;
|
|
40
|
+
relay(_pk: string, _bytes: Uint8Array): Promise<Uint8Array | null> | null;
|
|
42
41
|
heard(): Promise<void>;
|
|
43
42
|
awake(): Promise<void>;
|
|
44
43
|
sleep(): Promise<void>;
|
|
@@ -34,13 +34,10 @@ export class CarrierFaculty extends Faculty {
|
|
|
34
34
|
listening() {
|
|
35
35
|
return [];
|
|
36
36
|
}
|
|
37
|
-
//
|
|
38
|
-
// relay does, and
|
|
39
|
-
relays(_pk) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
37
|
+
// Its answer to a box for a ward pk no door of this harbor holds, where
|
|
38
|
+
// it answers for that pk, as a relay does, and null where it does not.
|
|
42
39
|
relay(_pk, _bytes) {
|
|
43
|
-
return
|
|
40
|
+
return null;
|
|
44
41
|
}
|
|
45
42
|
// A push the device heard, which says only that something waits: a
|
|
46
43
|
// carrier that collects for this harbor collects now.
|
|
@@ -212,7 +212,7 @@ export class Harbor {
|
|
|
212
212
|
const ward = this.#door(pk);
|
|
213
213
|
if (ward)
|
|
214
214
|
return (await ward.door.arrive(bytes)).bytes;
|
|
215
|
-
return (await this.#
|
|
215
|
+
return (await this.#relayed(pk, bytes)) ?? null;
|
|
216
216
|
}
|
|
217
217
|
// Whether one of this harbor's doors is that ward's.
|
|
218
218
|
holds(pk) {
|
|
@@ -345,8 +345,11 @@ export class Harbor {
|
|
|
345
345
|
// order, each to the carrier that dials it, and with no route the
|
|
346
346
|
// terrain's carrier.
|
|
347
347
|
async #carry(pk, bytes) {
|
|
348
|
-
if (this.holds(pk)
|
|
348
|
+
if (this.holds(pk))
|
|
349
349
|
return this.arrive(pk, bytes);
|
|
350
|
+
const relayed = this.#relayed(pk, bytes);
|
|
351
|
+
if (relayed !== undefined)
|
|
352
|
+
return relayed;
|
|
350
353
|
const at = this.#dock.routes[pk];
|
|
351
354
|
if (at === undefined)
|
|
352
355
|
return this.#terrain.carrier.carry(pk, bytes);
|
|
@@ -396,8 +399,15 @@ export class Harbor {
|
|
|
396
399
|
.map((key) => this.#box.being(key))
|
|
397
400
|
.filter((being) => being instanceof CarrierFaculty);
|
|
398
401
|
}
|
|
399
|
-
|
|
400
|
-
|
|
402
|
+
// The answer of the first carrier that answers for a pk no door holds,
|
|
403
|
+
// or undefined where none does.
|
|
404
|
+
#relayed(pk, bytes) {
|
|
405
|
+
for (const carrier of this.#carriers) {
|
|
406
|
+
const out = carrier.relay(pk, bytes);
|
|
407
|
+
if (out !== null)
|
|
408
|
+
return out;
|
|
409
|
+
}
|
|
410
|
+
return undefined;
|
|
401
411
|
}
|
|
402
412
|
#dialable(at) {
|
|
403
413
|
return at.some((address) => this.#carriers.some((carrier) => carrier.accepts(address)));
|
|
@@ -56,6 +56,9 @@ export declare class House implements Behind, Inside {
|
|
|
56
56
|
root(method?: string, args?: JsonObject): Promise<Answer>;
|
|
57
57
|
get zero(): boolean;
|
|
58
58
|
answer(heir: string | null, p: Payload): Promise<Choice>;
|
|
59
|
+
within(heir: string, take: boolean, method?: string, args?: string): Promise<Choice | {
|
|
60
|
+
readonly quo: 'removed';
|
|
61
|
+
}>;
|
|
59
62
|
send(pk: string, bytes: Uint8Array): Promise<Uint8Array | null>;
|
|
60
63
|
offer(contract: string): Promise<Invitation | null>;
|
|
61
64
|
retract(contract: string, heir: string): Promise<void>;
|
package/dist/core/ward/house.js
CHANGED
|
@@ -223,17 +223,44 @@ export class House {
|
|
|
223
223
|
const row = key === WARD || this.#parts.stands ? undefined : this.partition.being(key);
|
|
224
224
|
return row !== undefined && this.#classOf(row) !== undefined;
|
|
225
225
|
}
|
|
226
|
-
|
|
226
|
+
answer(heir, p) {
|
|
227
|
+
return this.#choose(heir, p.method, p.args);
|
|
228
|
+
}
|
|
229
|
+
// An ask on a relation between two beings of this ward, with no seal:
|
|
230
|
+
// both ends are this house's, so a seal would prove nothing to it. A take
|
|
231
|
+
// binds a fresh heir here and takes it from the door, so no box ever
|
|
232
|
+
// speaks under it again; an ask speaks while the heir stays bound here,
|
|
233
|
+
// and hears `removed` once its occupant is gone. A take that brings no
|
|
234
|
+
// object leaves the heir fresh on the door, as it was.
|
|
235
|
+
async within(heir, take, method, args) {
|
|
236
|
+
const { bind } = this.partition.head;
|
|
237
|
+
const bound = Object.hasOwn(bind, heir) ? bind[heir] : undefined;
|
|
238
|
+
if (!take)
|
|
239
|
+
return bound?.inside ? this.#choose(heir, method, args) : { quo: 'removed' };
|
|
240
|
+
if (!bound || bound.inside || this.door.relations.get(heir)?.state !== 'fresh')
|
|
241
|
+
return { silence: true };
|
|
242
|
+
const inside = { ...bound, inside: true };
|
|
243
|
+
this.door.relations.delete(heir);
|
|
244
|
+
bind[heir] = inside;
|
|
245
|
+
this.partition.toldHead();
|
|
246
|
+
const choice = await this.#choose(heir, method, args);
|
|
247
|
+
if ('object' in choice || bind[heir] !== inside)
|
|
248
|
+
return choice;
|
|
249
|
+
bind[heir] = bound;
|
|
250
|
+
this.door.relations.set(heir, { state: 'fresh' });
|
|
251
|
+
return choice;
|
|
252
|
+
}
|
|
253
|
+
async #choose(heir, method, text) {
|
|
227
254
|
const bound = heir === null ? undefined : this.partition.head.bind[heir];
|
|
228
255
|
const key = heir === null ? this.partition.head.public : bound?.being;
|
|
229
256
|
const asker = bound ? { id: bound.id } : {};
|
|
230
|
-
const args =
|
|
257
|
+
const args = text === undefined ? {} : readValue(text, DEPTH + 1);
|
|
231
258
|
if (key === null || key === undefined || typeof args !== 'object' || args === null || Array.isArray(args))
|
|
232
259
|
return { silence: true };
|
|
233
260
|
let seen = null;
|
|
234
261
|
const out = await this.#kept([key], () => this.#with(key, silence, async (being) => {
|
|
235
|
-
const reply = await this.#reply(being, asker,
|
|
236
|
-
if (
|
|
262
|
+
const reply = await this.#reply(being, asker, method, args);
|
|
263
|
+
if (method !== undefined && !isSilence(reply) && !isWord(reply) && being.describe)
|
|
237
264
|
seen = await digest(being.describe(asker));
|
|
238
265
|
return reply;
|
|
239
266
|
}));
|
|
@@ -306,10 +333,9 @@ export class House {
|
|
|
306
333
|
return row ? new HouseStance(this, key, row, this.#parts.carries ?? {}) : undefined;
|
|
307
334
|
}
|
|
308
335
|
// Inside: what every stance of this ward stands on.
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return (await this.door.arrive(bytes)).bytes;
|
|
336
|
+
// A box to another ward's door, wherever it stands; this ward's own
|
|
337
|
+
// relations speak `within`.
|
|
338
|
+
send(pk, bytes) {
|
|
313
339
|
return this.#parts.carrier.carry(pk, bytes);
|
|
314
340
|
}
|
|
315
341
|
// A lend: the ward lends herself, as the dock does, or asks the dock
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Door, type Draw, type Invitation } from '../quo/index.ts';
|
|
1
|
+
import { type Door, type Draw, type Invitation, type Read } from '../quo/index.ts';
|
|
2
2
|
import type { Clock } from '../contract/index.ts';
|
|
3
3
|
import { type JsonObject, type Occupants, type Stance, type Standings } from '../being/index.ts';
|
|
4
4
|
import type { BeingRow, Partition } from './partition.ts';
|
|
@@ -9,8 +9,10 @@ export interface Inside {
|
|
|
9
9
|
readonly door: Door;
|
|
10
10
|
readonly draw: Draw;
|
|
11
11
|
readonly clock: Clock;
|
|
12
|
+
readonly pk: string;
|
|
12
13
|
live(key: string, row: BeingRow): boolean;
|
|
13
14
|
send(pk: string, bytes: Uint8Array): Promise<Uint8Array | null>;
|
|
15
|
+
within(heir: string, take: boolean, method?: string, args?: string): Promise<Read>;
|
|
14
16
|
boot(maker: string, className: string, key: string, id?: string): Promise<string | null>;
|
|
15
17
|
offer(contract: string): Promise<Invitation | null>;
|
|
16
18
|
retract(contract: string, heir: string): Promise<void>;
|
package/dist/core/ward/stance.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// One being's stance: her cells, the ids she invited, the relations she
|
|
3
|
-
// holds, and boot.
|
|
4
|
-
// standing, one
|
|
3
|
+
// holds, and boot. A relation on another ward speaks through `quo/`'s
|
|
4
|
+
// standing, one on her own ward straight to her ward, each one send at a
|
|
5
|
+
// time, inside her allowance.
|
|
5
6
|
import { readValue, writeValue } from '../crypto/index.js';
|
|
6
7
|
import { readInvitation, Standing as Wire, freshStanding } from '../quo/index.js';
|
|
7
8
|
import { OWNER, ownKind, silence, word } from '../being/index.js';
|
|
@@ -120,6 +121,8 @@ export class HouseStance {
|
|
|
120
121
|
await this.#inside.learn(invitation.ward, invitation.at);
|
|
121
122
|
const wire = new Wire(invitation, freshStanding(), this.#inside.draw);
|
|
122
123
|
const read = await this.#lanes.run(`take:${id}`, async () => {
|
|
124
|
+
if (invitation.ward === this.#inside.pk)
|
|
125
|
+
return this.#inside.within(invitation.heir, true);
|
|
123
126
|
// A knock that brought nothing back may have bound: the standing asks
|
|
124
127
|
// under its own key, then knocks again as the same bytes.
|
|
125
128
|
let out = await this.#send(wire);
|
|
@@ -157,9 +160,13 @@ export class HouseStance {
|
|
|
157
160
|
return word('dropped');
|
|
158
161
|
if (bell.rang)
|
|
159
162
|
return word('late');
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
row.
|
|
163
|
+
// A relation inside this ward speaks with no seal, any other
|
|
164
|
+
// through the far ward's door.
|
|
165
|
+
const inside = row.invitation.ward === this.#inside.pk;
|
|
166
|
+
const wire = inside ? null : new Wire(row.invitation, row.state, this.#inside.draw);
|
|
167
|
+
const read = await bell.race(wire ? this.#send(wire, method, text) : this.#inside.within(row.invitation.heir, false, method, text));
|
|
168
|
+
if (wire)
|
|
169
|
+
row.state = wire.state;
|
|
163
170
|
if (read === LATE)
|
|
164
171
|
return word('late');
|
|
165
172
|
if ('object' in read)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nervur",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"description": "Nervur's kit of Quo: an object asks another object and gets an answer, without knowing where it is.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"quo",
|
|
@@ -8,9 +8,16 @@
|
|
|
8
8
|
"capability",
|
|
9
9
|
"object-capability"
|
|
10
10
|
],
|
|
11
|
-
"author": "
|
|
11
|
+
"author": "Bookarest Digital SRL",
|
|
12
12
|
"license": "Apache-2.0",
|
|
13
13
|
"homepage": "https://nervur.org",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/nervur-org/nervur.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/nervur-org/nervur/issues"
|
|
20
|
+
},
|
|
14
21
|
"type": "module",
|
|
15
22
|
"bin": {
|
|
16
23
|
"nervur": "dist/cli.js"
|
|
@@ -58,8 +65,8 @@
|
|
|
58
65
|
},
|
|
59
66
|
"scripts": {
|
|
60
67
|
"build": "rm -rf dist && tsc -p tsconfig.build.json && node kit.mjs",
|
|
61
|
-
"check": "tsc -p tsconfig.json && npm run build &&node
|
|
62
|
-
"deep": "node
|
|
68
|
+
"check": "tsc -p tsconfig.json && npm run build &&node test.mjs \"test/core/**/*.test.ts\" \"test/defaults/**/*.test.ts\" \"test/kit/*.test.ts\"",
|
|
69
|
+
"deep": "node test.mjs \"test/terrain/*.test.ts\"",
|
|
63
70
|
"cover": "node test/cover.mjs",
|
|
64
71
|
"mutate": "node test/mutate.mjs",
|
|
65
72
|
"prepublishOnly": "test \"$NERVUR_GATED\" = 1 || { echo 'a publish is /release, from the root, on the human'\"'\"'s word' >&2; exit 1; }"
|
|
@@ -82,6 +89,17 @@
|
|
|
82
89
|
"NOTICE"
|
|
83
90
|
],
|
|
84
91
|
"devDependencies": {
|
|
92
|
+
"@stryker-mutator/core": "^10.0.0",
|
|
93
|
+
"@stryker-mutator/instrumenter": "^10.0.0",
|
|
94
|
+
"@types/node": "^26.4.1",
|
|
95
|
+
"bun": "^1.4.0",
|
|
96
|
+
"deno": "^2.9.6",
|
|
97
|
+
"esbuild": "^0.28.2",
|
|
98
|
+
"istanbul-lib-coverage": "^3.2.2",
|
|
99
|
+
"playwright": "^1.62.1",
|
|
100
|
+
"typescript": "^7.0.2",
|
|
101
|
+
"v8-to-istanbul": "^9.3.0",
|
|
102
|
+
"workerd": "^1.20260904.1",
|
|
85
103
|
"wrangler": "^4.134.0"
|
|
86
104
|
}
|
|
87
105
|
}
|
|
@@ -87,13 +87,10 @@ export abstract class CarrierFaculty extends Faculty {
|
|
|
87
87
|
return [];
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
//
|
|
91
|
-
// relay does, and
|
|
92
|
-
|
|
93
|
-
return
|
|
94
|
-
}
|
|
95
|
-
relay(_pk: string, _bytes: Uint8Array): Promise<Uint8Array | null> {
|
|
96
|
-
return Promise.resolve(null);
|
|
90
|
+
// Its answer to a box for a ward pk no door of this harbor holds, where
|
|
91
|
+
// it answers for that pk, as a relay does, and null where it does not.
|
|
92
|
+
relay(_pk: string, _bytes: Uint8Array): Promise<Uint8Array | null> | null {
|
|
93
|
+
return null;
|
|
97
94
|
}
|
|
98
95
|
|
|
99
96
|
// A push the device heard, which says only that something waits: a
|
|
@@ -209,7 +209,7 @@ export class Harbor {
|
|
|
209
209
|
async arrive(pk: string, bytes: Uint8Array): Promise<Uint8Array | null> {
|
|
210
210
|
const ward = this.#door(pk);
|
|
211
211
|
if (ward) return (await ward.door.arrive(bytes)).bytes;
|
|
212
|
-
return (await this.#
|
|
212
|
+
return (await this.#relayed(pk, bytes)) ?? null;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
// Whether one of this harbor's doors is that ward's.
|
|
@@ -342,7 +342,9 @@ export class Harbor {
|
|
|
342
342
|
// order, each to the carrier that dials it, and with no route the
|
|
343
343
|
// terrain's carrier.
|
|
344
344
|
async #carry(pk: string, bytes: Uint8Array): Promise<Uint8Array | null> {
|
|
345
|
-
if (this.holds(pk)
|
|
345
|
+
if (this.holds(pk)) return this.arrive(pk, bytes);
|
|
346
|
+
const relayed = this.#relayed(pk, bytes);
|
|
347
|
+
if (relayed !== undefined) return relayed;
|
|
346
348
|
const at = this.#dock.routes[pk];
|
|
347
349
|
if (at === undefined) return this.#terrain.carrier.carry(pk, bytes);
|
|
348
350
|
for (const address of at) {
|
|
@@ -390,8 +392,14 @@ export class Harbor {
|
|
|
390
392
|
.filter((being): being is CarrierFaculty => being instanceof CarrierFaculty);
|
|
391
393
|
}
|
|
392
394
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
+
// The answer of the first carrier that answers for a pk no door holds,
|
|
396
|
+
// or undefined where none does.
|
|
397
|
+
#relayed(pk: string, bytes: Uint8Array): Promise<Uint8Array | null> | undefined {
|
|
398
|
+
for (const carrier of this.#carriers) {
|
|
399
|
+
const out = carrier.relay(pk, bytes);
|
|
400
|
+
if (out !== null) return out;
|
|
401
|
+
}
|
|
402
|
+
return undefined;
|
|
395
403
|
}
|
|
396
404
|
|
|
397
405
|
#dialable(at: readonly string[]): boolean {
|
package/src/core/ward/house.ts
CHANGED
|
@@ -284,17 +284,43 @@ export class House implements Behind, Inside {
|
|
|
284
284
|
return row !== undefined && this.#classOf(row) !== undefined;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
|
|
287
|
+
answer(heir: string | null, p: Payload): Promise<Choice> {
|
|
288
|
+
return this.#choose(heir, p.method, p.args);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// An ask on a relation between two beings of this ward, with no seal:
|
|
292
|
+
// both ends are this house's, so a seal would prove nothing to it. A take
|
|
293
|
+
// binds a fresh heir here and takes it from the door, so no box ever
|
|
294
|
+
// speaks under it again; an ask speaks while the heir stays bound here,
|
|
295
|
+
// and hears `removed` once its occupant is gone. A take that brings no
|
|
296
|
+
// object leaves the heir fresh on the door, as it was.
|
|
297
|
+
async within(heir: string, take: boolean, method?: string, args?: string): Promise<Choice | { readonly quo: 'removed' }> {
|
|
298
|
+
const { bind } = this.partition.head;
|
|
299
|
+
const bound = Object.hasOwn(bind, heir) ? bind[heir]! : undefined;
|
|
300
|
+
if (!take) return bound?.inside ? this.#choose(heir, method, args) : { quo: 'removed' };
|
|
301
|
+
if (!bound || bound.inside || this.door.relations.get(heir)?.state !== 'fresh') return { silence: true };
|
|
302
|
+
const inside = { ...bound, inside: true as const };
|
|
303
|
+
this.door.relations.delete(heir);
|
|
304
|
+
bind[heir] = inside;
|
|
305
|
+
this.partition.toldHead();
|
|
306
|
+
const choice = await this.#choose(heir, method, args);
|
|
307
|
+
if ('object' in choice || bind[heir] !== inside) return choice;
|
|
308
|
+
bind[heir] = bound;
|
|
309
|
+
this.door.relations.set(heir, { state: 'fresh' });
|
|
310
|
+
return choice;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async #choose(heir: string | null, method: string | undefined, text: string | undefined): Promise<Choice> {
|
|
288
314
|
const bound = heir === null ? undefined : this.partition.head.bind[heir];
|
|
289
315
|
const key = heir === null ? this.partition.head.public : bound?.being;
|
|
290
316
|
const asker: Asker = bound ? { id: bound.id } : {};
|
|
291
|
-
const args =
|
|
317
|
+
const args = text === undefined ? {} : readValue(text, DEPTH + 1);
|
|
292
318
|
if (key === null || key === undefined || typeof args !== 'object' || args === null || Array.isArray(args)) return { silence: true };
|
|
293
319
|
let seen: string | null = null;
|
|
294
320
|
const out = await this.#kept([key], () =>
|
|
295
321
|
this.#with(key, silence, async (being) => {
|
|
296
|
-
const reply = await this.#reply(being, asker,
|
|
297
|
-
if (
|
|
322
|
+
const reply = await this.#reply(being, asker, method, args);
|
|
323
|
+
if (method !== undefined && !isSilence(reply) && !isWord(reply) && being.describe) seen = await digest(being.describe(asker));
|
|
298
324
|
return reply;
|
|
299
325
|
}),
|
|
300
326
|
);
|
|
@@ -366,9 +392,9 @@ export class House implements Behind, Inside {
|
|
|
366
392
|
|
|
367
393
|
// Inside: what every stance of this ward stands on.
|
|
368
394
|
|
|
369
|
-
//
|
|
370
|
-
|
|
371
|
-
|
|
395
|
+
// A box to another ward's door, wherever it stands; this ward's own
|
|
396
|
+
// relations speak `within`.
|
|
397
|
+
send(pk: string, bytes: Uint8Array): Promise<Uint8Array | null> {
|
|
372
398
|
return this.#parts.carrier.carry(pk, bytes);
|
|
373
399
|
}
|
|
374
400
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// its terrain opened for it.
|
|
4
4
|
//
|
|
5
5
|
// rows.ward the door's lock, heirs and gone, which being and id
|
|
6
|
-
// each heir belongs to
|
|
6
|
+
// each heir belongs to and whether a being of this
|
|
7
|
+
// ward took it, and the public being
|
|
7
8
|
// rows.beings[key] one being: her class and the registry it resolves
|
|
8
9
|
// through, cells, occupants and standings
|
|
9
10
|
//
|
|
@@ -21,7 +22,9 @@ export type Head = {
|
|
|
21
22
|
lock?: KeptLock;
|
|
22
23
|
heirs: Record<string, HeirRecord>;
|
|
23
24
|
gone: string[];
|
|
24
|
-
|
|
25
|
+
// `inside` where a being of this ward took the heir: its relation lives
|
|
26
|
+
// here alone and no door holds it.
|
|
27
|
+
bind: Record<string, { being: string; id: string; inside?: true }>;
|
|
25
28
|
public: string | null;
|
|
26
29
|
};
|
|
27
30
|
|
package/src/core/ward/stance.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// One being's stance: her cells, the ids she invited, the relations she
|
|
3
|
-
// holds, and boot.
|
|
4
|
-
// standing, one
|
|
3
|
+
// holds, and boot. A relation on another ward speaks through `quo/`'s
|
|
4
|
+
// standing, one on her own ward straight to her ward, each one send at a
|
|
5
|
+
// time, inside her allowance.
|
|
5
6
|
import { readValue, writeValue } from '../crypto/index.ts';
|
|
6
7
|
import { readInvitation, Standing as Wire, freshStanding, type Door, type Draw, type Invitation, type Read } from '../quo/index.ts';
|
|
7
8
|
import type { Clock } from '../contract/index.ts';
|
|
@@ -18,8 +19,11 @@ export interface Inside {
|
|
|
18
19
|
readonly door: Door;
|
|
19
20
|
readonly draw: Draw;
|
|
20
21
|
readonly clock: Clock;
|
|
22
|
+
readonly pk: string;
|
|
21
23
|
live(key: string, row: BeingRow): boolean;
|
|
22
24
|
send(pk: string, bytes: Uint8Array): Promise<Uint8Array | null>;
|
|
25
|
+
// A relation whose both ends are this ward's, taken or asked with no seal.
|
|
26
|
+
within(heir: string, take: boolean, method?: string, args?: string): Promise<Read>;
|
|
23
27
|
boot(maker: string, className: string, key: string, id?: string): Promise<string | null>;
|
|
24
28
|
// An offer from the faculty the dock opened for a contract, and its
|
|
25
29
|
// retraction when the offer was not taken.
|
|
@@ -145,6 +149,7 @@ export class HouseStance implements Stance {
|
|
|
145
149
|
if (invitation.at) await this.#inside.learn(invitation.ward, invitation.at);
|
|
146
150
|
const wire = new Wire(invitation, freshStanding(), this.#inside.draw);
|
|
147
151
|
const read = await this.#lanes.run(`take:${id}`, async () => {
|
|
152
|
+
if (invitation.ward === this.#inside.pk) return this.#inside.within(invitation.heir, true);
|
|
148
153
|
// A knock that brought nothing back may have bound: the standing asks
|
|
149
154
|
// under its own key, then knocks again as the same bytes.
|
|
150
155
|
let out = await this.#send(wire);
|
|
@@ -179,9 +184,12 @@ export class HouseStance implements Stance {
|
|
|
179
184
|
const row = Object.hasOwn(this.#row.standings, id) ? this.#row.standings[id] : undefined;
|
|
180
185
|
if (!this.#live || row === undefined) return word('dropped');
|
|
181
186
|
if (bell.rang) return word('late');
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
row.
|
|
187
|
+
// A relation inside this ward speaks with no seal, any other
|
|
188
|
+
// through the far ward's door.
|
|
189
|
+
const inside = row.invitation.ward === this.#inside.pk;
|
|
190
|
+
const wire = inside ? null : new Wire(row.invitation, row.state, this.#inside.draw);
|
|
191
|
+
const read = await bell.race(wire ? this.#send(wire, method as string | undefined, text) : this.#inside.within(row.invitation.heir, false, method as string | undefined, text));
|
|
192
|
+
if (wire) row.state = wire.state;
|
|
185
193
|
if (read === LATE) return word('late');
|
|
186
194
|
if ('object' in read) row.seen = read.seen;
|
|
187
195
|
this.#told();
|