nervur 0.19.2 → 0.20.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/README.md +156 -104
- package/dist/being/being.d.ts +8 -15
- package/dist/being/being.js +20 -67
- package/dist/being/digest.d.ts +1 -1
- package/dist/being/digest.js +7 -27
- package/dist/being/faculty.d.ts +10 -0
- package/dist/being/faculty.js +74 -0
- package/dist/being/index.d.ts +5 -5
- package/dist/being/index.js +6 -5
- package/dist/being/kind.d.ts +4 -0
- package/dist/being/kind.js +28 -0
- package/dist/being/types.d.ts +35 -63
- package/dist/being/types.js +3 -57
- package/dist/being/words.d.ts +13 -0
- package/dist/being/words.js +14 -0
- package/dist/cli/command.d.ts +13 -0
- package/dist/cli/command.js +194 -0
- package/dist/cli/harbor.d.ts +21 -0
- package/dist/cli/harbor.js +141 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +14 -0
- package/dist/contract/index.d.ts +39 -0
- package/dist/contract/index.js +33 -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 +14 -0
- package/dist/folder/index.js +87 -0
- package/dist/harbor/catalogue.d.ts +25 -0
- package/dist/harbor/catalogue.js +93 -0
- package/dist/harbor/dock.d.ts +29 -0
- package/dist/harbor/dock.js +122 -0
- package/dist/harbor/harbor.d.ts +31 -0
- package/dist/harbor/harbor.js +146 -0
- package/dist/harbor/index.d.ts +7 -10
- package/dist/harbor/index.js +9 -18
- package/dist/harbor/package.d.ts +10 -0
- package/dist/harbor/package.js +115 -0
- package/dist/harbor/registry.d.ts +9 -0
- package/dist/harbor/registry.js +78 -0
- package/dist/harbor/root-line.d.ts +9 -0
- package/dist/harbor/root-line.js +36 -0
- package/dist/harbor/terrain.d.ts +9 -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 +26 -0
- package/dist/pointer/bodies.js +64 -0
- package/dist/pointer/index.d.ts +2 -0
- package/dist/pointer/index.js +4 -0
- package/dist/pointer/world.d.ts +35 -0
- package/dist/pointer/world.js +85 -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/tcp/frame.d.ts +29 -0
- package/dist/tcp/frame.js +74 -0
- package/dist/tcp/index.d.ts +18 -0
- package/dist/tcp/index.js +164 -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 +6 -10
- package/dist/ward/index.js +7 -13
- package/dist/ward/partition.d.ts +44 -60
- package/dist/ward/partition.js +56 -285
- package/dist/ward/pilot.d.ts +8 -0
- package/dist/ward/pilot.js +50 -0
- package/dist/ward/stance.d.ts +27 -20
- package/dist/ward/stance.js +174 -406
- package/dist/ward/ward-being.d.ts +35 -0
- package/dist/ward/ward-being.js +82 -0
- package/dist/ward/ward.d.ts +45 -11
- package/dist/ward/ward.js +239 -357
- package/package.json +24 -31
- package/src/being/being.ts +35 -78
- package/src/being/digest.ts +7 -35
- package/src/being/faculty.ts +73 -0
- package/src/being/index.ts +6 -6
- package/src/being/kind.ts +30 -0
- package/src/being/types.ts +50 -146
- package/src/being/words.ts +31 -0
- package/src/cli/command.ts +188 -0
- package/src/cli/harbor.ts +137 -0
- package/src/cli/main.ts +13 -0
- package/src/contract/index.ts +73 -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 +92 -0
- package/src/harbor/catalogue.ts +110 -0
- package/src/harbor/dock.ts +137 -0
- package/src/harbor/harbor.ts +180 -0
- package/src/harbor/index.ts +9 -19
- package/src/harbor/package.ts +131 -0
- package/src/harbor/registry.ts +73 -0
- package/src/harbor/root-line.ts +36 -0
- package/src/harbor/terrain.ts +15 -0
- package/src/index.ts +20 -0
- package/src/pointer/bodies.ts +65 -0
- package/src/pointer/index.ts +4 -0
- package/src/pointer/world.ts +94 -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 +20 -0
- package/src/stand/stand.ts +220 -0
- package/src/tcp/frame.ts +78 -0
- package/src/tcp/index.ts +173 -0
- package/src/ward/allowance.ts +37 -75
- package/src/ward/cells.ts +63 -176
- package/src/ward/index.ts +7 -17
- package/src/ward/partition.ts +86 -326
- package/src/ward/pilot.ts +50 -0
- package/src/ward/stance.ts +186 -420
- package/src/ward/ward-being.ts +103 -0
- package/src/ward/ward.ts +256 -359
- 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/harbor/dial.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { REFUSED, Socket } from './reach.js';
|
|
2
|
-
export function dial(harbor, url) {
|
|
3
|
-
const d = { url, socket: null, wake: () => { }, close: () => { } };
|
|
4
|
-
let stopped = false, wait = 1000, timer, line, // the line in hand, open or still opening: close() closes it either way
|
|
5
|
-
held; // the one this dialer owns now, and how it gives back what the line took
|
|
6
|
-
const connect = () => {
|
|
7
|
-
timer = undefined; // no wait pending: this is the dial it was waiting for
|
|
8
|
-
if (stopped)
|
|
9
|
-
return;
|
|
10
|
-
line = new WebSocket(url.replace(/\/$/, '').replace(/^http/, 'ws'));
|
|
11
|
-
const s = new Socket(line, (pk, bytes) => harbor.deliver(pk, bytes), (far) => {
|
|
12
|
-
// A line that opened is not a line that works. The wait goes back to
|
|
13
|
-
// a second here, where the far side has answered and been taken, and
|
|
14
|
-
// not at the handshake: a listener that opens and then refuses every
|
|
15
|
-
// time would otherwise be dialed at a fixed two seconds for good.
|
|
16
|
-
wait = 1000;
|
|
17
|
-
void harbor.bind(far, s, false); // the listener's claims, each proven at its door: reached through this socket, not held for others
|
|
18
|
-
}, (why) => {
|
|
19
|
-
shed();
|
|
20
|
-
// A line this dialer already put down. Its close arrives whenever the
|
|
21
|
-
// system gets round to noticing, which on a socket that died under a
|
|
22
|
-
// sleeping device is minutes; by then the line dialed in its place is
|
|
23
|
-
// the one in hand, so this one gives back what it took and dials
|
|
24
|
-
// nothing. Only the line the dialer still holds dials again.
|
|
25
|
-
if (held?.socket !== s)
|
|
26
|
-
return;
|
|
27
|
-
held = undefined;
|
|
28
|
-
// A suite this listener will not speak is not a line that dropped. It
|
|
29
|
-
// will not become speakable by asking again sooner, so the wait goes
|
|
30
|
-
// straight to the ceiling and stays there until it changes its mind.
|
|
31
|
-
if (why.code === REFUSED)
|
|
32
|
-
wait = 30000;
|
|
33
|
-
if (!stopped)
|
|
34
|
-
timer = setTimeout(connect, wait);
|
|
35
|
-
wait = Math.min(wait * 2, 30000);
|
|
36
|
-
});
|
|
37
|
-
// Everything this line took from the harbor, given back. Said when it
|
|
38
|
-
// closes, and when the dialer puts it down without waiting for that.
|
|
39
|
-
const shed = () => {
|
|
40
|
-
harbor.announcers.delete(say);
|
|
41
|
-
harbor.unbind(s);
|
|
42
|
-
if (d.socket === s)
|
|
43
|
-
d.socket = null;
|
|
44
|
-
const at = harbor.fallbacks.indexOf(s);
|
|
45
|
-
if (at !== -1)
|
|
46
|
-
harbor.fallbacks.splice(at, 1); // this line only: another dialer's stays
|
|
47
|
-
};
|
|
48
|
-
held = { socket: s, shed };
|
|
49
|
-
harbor.fallbacks.push(s); // from the moment it is dialed: an ask made before the handshake waits on the socket, and is not unreached
|
|
50
|
-
// What this harbor holds, said when the line opens and again whenever it
|
|
51
|
-
// changes. A ward booted or adopted after the handshake is announced on
|
|
52
|
-
// the line already in hand, and a dropped one stops being claimed at once.
|
|
53
|
-
const say = () => s.announce([...harbor.doors.keys()]);
|
|
54
|
-
line.addEventListener('open', () => {
|
|
55
|
-
if (stopped)
|
|
56
|
-
return s.close(); // closed while it was opening: it opens into nothing
|
|
57
|
-
d.socket = s;
|
|
58
|
-
harbor.announcers.add(say);
|
|
59
|
-
say();
|
|
60
|
-
});
|
|
61
|
-
};
|
|
62
|
-
d.wake = () => {
|
|
63
|
-
if (stopped)
|
|
64
|
-
return;
|
|
65
|
-
clearTimeout(timer);
|
|
66
|
-
timer = undefined;
|
|
67
|
-
wait = 1000; // the device is back, and the wait it froze belongs to the sleep, not to this line
|
|
68
|
-
const old = held;
|
|
69
|
-
held = undefined; // put down before the new one is dialed, so a fallback list never holds the dead line ahead of the live one
|
|
70
|
-
old?.shed();
|
|
71
|
-
old?.socket.close();
|
|
72
|
-
connect();
|
|
73
|
-
};
|
|
74
|
-
d.close = () => {
|
|
75
|
-
stopped = true;
|
|
76
|
-
clearTimeout(timer);
|
|
77
|
-
line?.close(); // open or opening: a line closed while connecting fires close and never open
|
|
78
|
-
};
|
|
79
|
-
connect();
|
|
80
|
-
return d;
|
|
81
|
-
}
|
package/dist/harbor/memory.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { BeingClass, BeingLike, Invitation } from '../being/types.ts';
|
|
2
|
-
import { type Ground, type WardPointers } from '../ward/ground.ts';
|
|
3
|
-
export type Booted = WardPointers & {
|
|
4
|
-
pk: string;
|
|
5
|
-
};
|
|
6
|
-
export type WardFactory = (ground: Ground) => Promise<WardPointers>;
|
|
7
|
-
export declare class MemoryHarbor {
|
|
8
|
-
readonly doors: Map<string, (bytes: Uint8Array) => Promise<{
|
|
9
|
-
bytes: Uint8Array;
|
|
10
|
-
heard: boolean;
|
|
11
|
-
}>>;
|
|
12
|
-
readonly down: Set<string>;
|
|
13
|
-
readonly wire: string[];
|
|
14
|
-
readonly refused: Map<string, number>;
|
|
15
|
-
readonly peers: Set<MemoryHarbor>;
|
|
16
|
-
cut: boolean;
|
|
17
|
-
readonly partitions: Map<string, Record<string, unknown>>;
|
|
18
|
-
readonly wards: Map<string, Booted>;
|
|
19
|
-
readonly objects: WeakMap<object, BeingLike>;
|
|
20
|
-
random: Ground['random'];
|
|
21
|
-
route(farPk: string, bytes: Uint8Array): Promise<Uint8Array | undefined>;
|
|
22
|
-
link(harbor: MemoryHarbor): void;
|
|
23
|
-
boot(seed: string, Ward: WardFactory, classes: Record<string, BeingClass>, box?: Invitation): Promise<Booted>;
|
|
24
|
-
reboot(seed: string, Ward: WardFactory, classes: Record<string, BeingClass>, box?: Invitation): Promise<Booted>;
|
|
25
|
-
up(Ward: WardFactory, lent?: Record<string, BeingClass>): Promise<Booted>;
|
|
26
|
-
get box(): Booted | undefined;
|
|
27
|
-
host(seed: string, Ward: WardFactory, classes: Record<string, BeingClass>): Promise<Booted>;
|
|
28
|
-
hosted(Ward: WardFactory, classes: Record<string, BeingClass>): Promise<string[]>;
|
|
29
|
-
}
|
package/dist/harbor/memory.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { maker, entropy, learnPk, volatile } from '../ward/ground.js';
|
|
2
|
-
import { hex } from '../ward/arithmetic.js';
|
|
3
|
-
import { Box, BOX_SEED, stand, offerTo, roll } from './box.js';
|
|
4
|
-
export class MemoryHarbor {
|
|
5
|
-
doors = new Map(); // ward pk -> door
|
|
6
|
-
down = new Set(); // ward pks this harbor cannot reach right now
|
|
7
|
-
wire = []; // every byte string that ever crossed, as hex. for inspection
|
|
8
|
-
refused = new Map(); // ward pk -> arrivals its door would not admit: strangers, counted
|
|
9
|
-
peers = new Set();
|
|
10
|
-
cut = false;
|
|
11
|
-
partitions = new Map(); // seed -> memory. the harbor keeps it and reads nothing
|
|
12
|
-
wards = new Map(); // seed -> pointers
|
|
13
|
-
objects = new WeakMap(); // cells -> being object. what instantiate constructed. a hand for tests, never the ward's; it follows the cells out when she is unbooted
|
|
14
|
-
// Where the wards this harbor boots draw their entropy. The device's own
|
|
15
|
-
// by default. A harbor may hand a fixed stream instead, which is what pins
|
|
16
|
-
// bytes: every key a ward mints and every nonce it seals under comes from
|
|
17
|
-
// here, so a ward on a known seed with a known stream answers the same
|
|
18
|
-
// bytes every run, and a corpus of them is a corpus and not a sample.
|
|
19
|
-
random = entropy;
|
|
20
|
-
// the directory: its own doors, else a peer it is linked to. Quo says nothing about how.
|
|
21
|
-
async route(farPk, bytes) {
|
|
22
|
-
if (this.down.has(farPk))
|
|
23
|
-
return undefined;
|
|
24
|
-
const door = this.doors.get(farPk);
|
|
25
|
-
if (door) {
|
|
26
|
-
const r = await door(bytes);
|
|
27
|
-
if (!r.heard)
|
|
28
|
-
this.refused.set(farPk, (this.refused.get(farPk) ?? 0) + 1);
|
|
29
|
-
return r.bytes;
|
|
30
|
-
}
|
|
31
|
-
const peer = [...this.peers].find((h) => h.doors.has(farPk) && !h.down.has(farPk));
|
|
32
|
-
if (!peer || this.cut)
|
|
33
|
-
return undefined; // nothing. the harbor has no word silence
|
|
34
|
-
return peer.route(farPk, bytes);
|
|
35
|
-
}
|
|
36
|
-
link(harbor) {
|
|
37
|
-
this.peers.add(harbor);
|
|
38
|
-
harbor.peers.add(this);
|
|
39
|
-
}
|
|
40
|
-
// boot by seed. the harbor gets a door and an ask, and learns the pk by
|
|
41
|
-
// asking. `box` is the invitation on this device's box being, for this
|
|
42
|
-
// ward: left out, the ward holds no box and every lend is null.
|
|
43
|
-
async boot(seed, Ward, classes, box) {
|
|
44
|
-
this.partitions.set(seed, {});
|
|
45
|
-
return this.reboot(seed, Ward, classes, box);
|
|
46
|
-
}
|
|
47
|
-
// a restart: same seed, same partition, fresh ward. the ward's files are the harbor's to keep.
|
|
48
|
-
async reboot(seed, Ward, classes, box) {
|
|
49
|
-
const rows = this.partitions.get(seed);
|
|
50
|
-
if (!rows)
|
|
51
|
-
throw new Error(`no partition for ${seed}`);
|
|
52
|
-
const ground = {
|
|
53
|
-
seed,
|
|
54
|
-
memory: volatile(rows),
|
|
55
|
-
...(box ? { box } : {}),
|
|
56
|
-
// One objects map for the whole harbor, not one per ward: every ward
|
|
57
|
-
// here is in this process and a test reaches any being of any of them.
|
|
58
|
-
instantiate: maker(this.objects, classes),
|
|
59
|
-
// bytes cross, copied, never a reference. both ways.
|
|
60
|
-
carry: async (farPk, bytes) => {
|
|
61
|
-
this.wire.push(hex(bytes));
|
|
62
|
-
const back = await this.route(farPk, new Uint8Array(bytes));
|
|
63
|
-
return back === undefined ? undefined : new Uint8Array(back);
|
|
64
|
-
},
|
|
65
|
-
random: (n) => this.random(n),
|
|
66
|
-
};
|
|
67
|
-
const w = await Ward(ground);
|
|
68
|
-
const booted = { ...w, pk: await learnPk(w) };
|
|
69
|
-
this.doors.set(booted.pk, booted.door);
|
|
70
|
-
this.wards.set(seed, booted);
|
|
71
|
-
return booted;
|
|
72
|
-
}
|
|
73
|
-
// Act one. The box's own ward, the box's being and the lent beings named,
|
|
74
|
-
// each booted under its name and held by her under it. Run again on a
|
|
75
|
-
// harbor whose box ward stands, it changes nothing.
|
|
76
|
-
async up(Ward, lent = {}) {
|
|
77
|
-
const classes = { Box };
|
|
78
|
-
for (const C of Object.values(lent))
|
|
79
|
-
classes[C.name] = C;
|
|
80
|
-
const box = this.wards.get(BOX_SEED) ?? (await this.boot(BOX_SEED, Ward, classes));
|
|
81
|
-
await stand(box, lent);
|
|
82
|
-
return box;
|
|
83
|
-
}
|
|
84
|
-
get box() {
|
|
85
|
-
return this.wards.get(BOX_SEED);
|
|
86
|
-
}
|
|
87
|
-
// Act two, one ward: on the roll and handed one invitation on the box's being.
|
|
88
|
-
// A harbor with no box ward up hosts as `boot` does, with nothing.
|
|
89
|
-
async host(seed, Ward, classes) {
|
|
90
|
-
const box = this.box;
|
|
91
|
-
const inv = box ? await offerTo(box, seed) : undefined;
|
|
92
|
-
return this.partitions.has(seed) ? this.reboot(seed, Ward, classes, inv) : this.boot(seed, Ward, classes, inv);
|
|
93
|
-
}
|
|
94
|
-
// Act two, whole: the box's being says who is hosted, and each comes up.
|
|
95
|
-
async hosted(Ward, classes) {
|
|
96
|
-
const box = this.box;
|
|
97
|
-
if (!box)
|
|
98
|
-
return [];
|
|
99
|
-
const seeds = await roll(box);
|
|
100
|
-
for (const seed of seeds)
|
|
101
|
-
await this.host(seed, Ward, classes);
|
|
102
|
-
return seeds;
|
|
103
|
-
}
|
|
104
|
-
}
|
package/dist/harbor/reach.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export type Carry = (pk: string, bytes: Uint8Array) => Promise<Uint8Array | undefined>;
|
|
2
|
-
export type Reach = {
|
|
3
|
-
carry: Carry;
|
|
4
|
-
close(): void;
|
|
5
|
-
};
|
|
6
|
-
export declare function request(url: string): Reach;
|
|
7
|
-
export declare const SUITE = 1;
|
|
8
|
-
export declare const REFUSED = 4001;
|
|
9
|
-
export type Line = {
|
|
10
|
-
readyState: number;
|
|
11
|
-
binaryType: string;
|
|
12
|
-
send(data: string | Uint8Array): void;
|
|
13
|
-
close(code?: number, reason?: string): void;
|
|
14
|
-
addEventListener(type: 'open' | 'error', fn: () => void): void;
|
|
15
|
-
addEventListener(type: 'close', fn: (e?: {
|
|
16
|
-
code?: number;
|
|
17
|
-
reason?: string;
|
|
18
|
-
}) => void): void;
|
|
19
|
-
addEventListener(type: 'message', fn: (e: {
|
|
20
|
-
data: unknown;
|
|
21
|
-
}) => void): void;
|
|
22
|
-
};
|
|
23
|
-
export type Announce = (pks: string[]) => void;
|
|
24
|
-
export declare class Socket implements Reach {
|
|
25
|
-
#private;
|
|
26
|
-
readonly line: Line;
|
|
27
|
-
readonly pending: Map<number, (bytes: Uint8Array | undefined) => void>;
|
|
28
|
-
far: string[];
|
|
29
|
-
constructor(line: Line, deliver: Carry, onAnnounce: Announce, onClose: (why: {
|
|
30
|
-
code?: number;
|
|
31
|
-
reason?: string;
|
|
32
|
-
}) => void);
|
|
33
|
-
announce(pks: string[]): void;
|
|
34
|
-
carry(pk: string, bytes: Uint8Array): Promise<Uint8Array | undefined>;
|
|
35
|
-
close(): void;
|
|
36
|
-
}
|
package/dist/harbor/reach.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// Reach: carrying bytes to a pk off the device. One interface, two
|
|
3
|
-
// implementations:
|
|
4
|
-
//
|
|
5
|
-
// request a URL. POST the bytes to `<url>/<pk>`, get bytes back.
|
|
6
|
-
// Listener to listener.
|
|
7
|
-
// socket a held WebSocket at `<url>`, opened by whichever side can
|
|
8
|
-
// dial, used in both directions with a frame id. Each side
|
|
9
|
-
// announces the ward pks it holds when the socket opens, and the
|
|
10
|
-
// other binds them.
|
|
11
|
-
//
|
|
12
|
-
// Both are written on what every terrain has: fetch, and the standard
|
|
13
|
-
// WebSocket surface, which a browser, Node, an edge worker's pair and the
|
|
14
|
-
// `ws` server all offer. The listener half of a socket is the terrain's
|
|
15
|
-
// own and stays outside this tree; what is here is the framing, either end
|
|
16
|
-
// of a line, and the request. Nothing here names a runtime, and
|
|
17
|
-
// `src/conformance/reach.ts` is what every reach passes. A reach carries and returns; it reads
|
|
18
|
-
// nothing. `undefined` is a promise that nothing was delivered: no such pk
|
|
19
|
-
// at the far end, a connection that would not open, a socket that is gone.
|
|
20
|
-
// A reach that sent the bytes and lost the line afterwards answers nothing
|
|
21
|
-
// at all, and the ward's own bound ends the ask.
|
|
22
|
-
import { concat, hex, unhex } from '../ward/arithmetic.js';
|
|
23
|
-
import { readJson } from '../ward/json.js';
|
|
24
|
-
const never = () => new Promise(() => { }); // sent, and no word since: the ward's bound decides
|
|
25
|
-
// A request reach to one listener.
|
|
26
|
-
export function request(url) {
|
|
27
|
-
const base = url.replace(/\/$/, '');
|
|
28
|
-
return {
|
|
29
|
-
close: () => { },
|
|
30
|
-
carry: async (pk, bytes) => {
|
|
31
|
-
let res;
|
|
32
|
-
// A body of its own, not the caller's view: fetch reads it after this
|
|
33
|
-
// line returns, and a buffer somebody else may write is not a body. The
|
|
34
|
-
// copy is its own ArrayBuffer, which is what a body is; the bytes handed
|
|
35
|
-
// in are typed as backed by anything, shared memory included.
|
|
36
|
-
const body = new Uint8Array(bytes.length);
|
|
37
|
-
body.set(bytes);
|
|
38
|
-
try {
|
|
39
|
-
res = await fetch(`${base}/${pk}`, { method: 'POST', headers: { 'content-type': 'application/octet-stream', 'quo-suite': String(SUITE) }, body });
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
return undefined; // the connection never opened: nothing was delivered
|
|
43
|
-
}
|
|
44
|
-
// A status that says the listener did not take the bytes is nothing
|
|
45
|
-
// delivered: no reach for that pk, a request it refused on its face, a
|
|
46
|
-
// gateway with nobody behind it. Any other failure is a listener that
|
|
47
|
-
// took them and failed after, which is sent and no word since.
|
|
48
|
-
if (res.status === 404 || (res.status >= 400 && res.status < 500) || res.status === 502 || res.status === 503 || res.status === 504)
|
|
49
|
-
return undefined;
|
|
50
|
-
if (!res.ok)
|
|
51
|
-
return never();
|
|
52
|
-
return new Uint8Array(await res.arrayBuffer());
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
// The frames on a socket. Binary, one byte of kind first.
|
|
57
|
-
// ask [0][id: 4 bytes][pk: 64 bytes][bytes]
|
|
58
|
-
// reply [1][id: 4 bytes][bytes]
|
|
59
|
-
// none [2][id: 4 bytes] nothing was delivered
|
|
60
|
-
// And one text frame, JSON: { announce: [pk, ...], suite }, the ward pks this
|
|
61
|
-
// side holds and the wire suite it speaks, sent when the socket opens and
|
|
62
|
-
// whenever the pks change.
|
|
63
|
-
const ASK = 0, REPLY = 1, NONE = 2;
|
|
64
|
-
// The wire suite: which frames these are and which five algorithms seal what
|
|
65
|
-
// they carry. One value, and it is not negotiated. It rides in the handshake
|
|
66
|
-
// and never on an ask, so an ask stays bytes nobody can tell from noise, and
|
|
67
|
-
// a line still learns before it carries anything whether the far side speaks
|
|
68
|
-
// what this side speaks. A side meeting a suite it does not know carries
|
|
69
|
-
// nothing for it and closes: the alternative is bytes that will never open,
|
|
70
|
-
// answered by a silence that says nothing about why, forever. Nothing
|
|
71
|
-
// changes this number before 1.0.0. After it, this is the one place a second
|
|
72
|
-
// suite can be told from a first without guessing.
|
|
73
|
-
export const SUITE = 1;
|
|
74
|
-
// The close a side sends when it refuses a suite, in the range a protocol
|
|
75
|
-
// may spend on itself. A line that just closes tells the far side nothing,
|
|
76
|
-
// and a dialer that learns nothing dials again on its backoff for good: the
|
|
77
|
-
// whole reason this number exists is that a kit which cannot be understood
|
|
78
|
-
// should be told so instead of meeting a silence that names no reason. So
|
|
79
|
-
// the refusal names itself on the way out, and the far side may read it.
|
|
80
|
-
export const REFUSED = 4001;
|
|
81
|
-
const OPEN = 1; // WebSocket.OPEN, on every terrain
|
|
82
|
-
// How many asks a socket keeps a resolver for. An ask the far side never
|
|
83
|
-
// answers is ended by the ward's bound, and its resolver stays until the
|
|
84
|
-
// line closes; a far side that answers nothing for long enough would grow
|
|
85
|
-
// the map for as long as this side asks, so the oldest goes when it is full.
|
|
86
|
-
const PENDING = 4096;
|
|
87
|
-
// One held socket, either side of it. `deliver` is what this side does with
|
|
88
|
-
// an ask that arrives for a pk: its own door, or a socket it holds for that
|
|
89
|
-
// pk, and nothing else. `onAnnounce` learns the far side's pks; `onClose`
|
|
90
|
-
// forgets them.
|
|
91
|
-
export class Socket {
|
|
92
|
-
line;
|
|
93
|
-
pending = new Map();
|
|
94
|
-
far = []; // the pks the far side announced
|
|
95
|
-
#id = 1;
|
|
96
|
-
#open;
|
|
97
|
-
constructor(line, deliver, onAnnounce, onClose) {
|
|
98
|
-
this.line = line;
|
|
99
|
-
line.binaryType = 'arraybuffer';
|
|
100
|
-
// A line that opens is a reach; one that errors, or closes before it
|
|
101
|
-
// opened, is a reach that failed, and an ask waiting on the handshake is
|
|
102
|
-
// nothing delivered.
|
|
103
|
-
this.#open =
|
|
104
|
-
line.readyState === OPEN
|
|
105
|
-
? Promise.resolve()
|
|
106
|
-
: new Promise((ok, no) => {
|
|
107
|
-
line.addEventListener('open', ok);
|
|
108
|
-
line.addEventListener('error', no);
|
|
109
|
-
line.addEventListener('close', () => no(new Error('closed before it opened')));
|
|
110
|
-
});
|
|
111
|
-
this.#open.catch(() => { }); // a handshake refused is a reach that failed, not a process that dies
|
|
112
|
-
line.addEventListener('message', (e) => {
|
|
113
|
-
if (typeof e.data === 'string') {
|
|
114
|
-
try {
|
|
115
|
-
const m = readJson(e.data);
|
|
116
|
-
if (m === null || typeof m !== 'object')
|
|
117
|
-
return;
|
|
118
|
-
// Absent is this suite: a side that says nothing says one.
|
|
119
|
-
if (m.suite !== undefined && m.suite !== SUITE) {
|
|
120
|
-
this.far = [];
|
|
121
|
-
line.close(REFUSED, 'suite');
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (Array.isArray(m.announce)) {
|
|
125
|
-
this.far = m.announce.filter((x) => typeof x === 'string');
|
|
126
|
-
onAnnounce(this.far);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
/* not for us */
|
|
131
|
-
}
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
const buf = e.data instanceof ArrayBuffer ? new Uint8Array(e.data) : ArrayBuffer.isView(e.data) ? new Uint8Array(e.data.buffer, e.data.byteOffset, e.data.byteLength) : undefined;
|
|
135
|
-
// A frame that is none of the three is not a frame: an unknown kind, an
|
|
136
|
-
// ask too short to hold a pk, a nothing with bytes after its id. It is
|
|
137
|
-
// dropped, and tells no ask waiting on its id that nothing was delivered.
|
|
138
|
-
if (!buf || buf.length < 5)
|
|
139
|
-
return;
|
|
140
|
-
const kind = buf[0], id = new DataView(buf.buffer, buf.byteOffset, buf.byteLength).getUint32(1);
|
|
141
|
-
if (kind > NONE || (kind === ASK && buf.length < 69) || (kind === NONE && buf.length !== 5))
|
|
142
|
-
return;
|
|
143
|
-
if (kind === ASK) {
|
|
144
|
-
const pk = hex(buf.subarray(5, 69));
|
|
145
|
-
// A deliver that rejects has delivered nothing this side can vouch
|
|
146
|
-
// for, and a listener does not die of it: the far side hears none.
|
|
147
|
-
void deliver(pk, new Uint8Array(buf.subarray(69)))
|
|
148
|
-
.then((back) => back, () => undefined)
|
|
149
|
-
.then((back) => {
|
|
150
|
-
const head = new Uint8Array(5);
|
|
151
|
-
head[0] = back === undefined ? NONE : REPLY;
|
|
152
|
-
new DataView(head.buffer).setUint32(1, id);
|
|
153
|
-
if (line.readyState === OPEN)
|
|
154
|
-
line.send(back === undefined ? head : concat([head, back]));
|
|
155
|
-
});
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const waiting = this.pending.get(id);
|
|
159
|
-
if (!waiting)
|
|
160
|
-
return;
|
|
161
|
-
this.pending.delete(id);
|
|
162
|
-
waiting(kind === REPLY ? new Uint8Array(buf.subarray(5)) : undefined);
|
|
163
|
-
});
|
|
164
|
-
line.addEventListener('error', () => { });
|
|
165
|
-
line.addEventListener('close', (e) => {
|
|
166
|
-
this.pending.clear(); // in flight and no word since: nothing is answered
|
|
167
|
-
onClose({ code: e?.code, reason: e?.reason });
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
// Say which ward pks this side holds.
|
|
171
|
-
announce(pks) {
|
|
172
|
-
if (this.line.readyState === OPEN)
|
|
173
|
-
this.line.send(JSON.stringify({ announce: pks, suite: SUITE }));
|
|
174
|
-
}
|
|
175
|
-
async carry(pk, bytes) {
|
|
176
|
-
try {
|
|
177
|
-
await this.#open;
|
|
178
|
-
}
|
|
179
|
-
catch {
|
|
180
|
-
return undefined;
|
|
181
|
-
}
|
|
182
|
-
if (this.line.readyState !== OPEN)
|
|
183
|
-
return undefined;
|
|
184
|
-
const id = this.#id++;
|
|
185
|
-
const head = new Uint8Array(69);
|
|
186
|
-
head[0] = ASK;
|
|
187
|
-
new DataView(head.buffer).setUint32(1, id);
|
|
188
|
-
head.set(unhex(pk), 5);
|
|
189
|
-
return new Promise((ok) => {
|
|
190
|
-
if (this.pending.size >= PENDING)
|
|
191
|
-
this.pending.delete(this.pending.keys().next().value); // the oldest, which the ward's bound ended long ago
|
|
192
|
-
this.pending.set(id, ok);
|
|
193
|
-
this.line.send(concat([head, bytes]));
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
close() {
|
|
197
|
-
this.line.close();
|
|
198
|
-
}
|
|
199
|
-
}
|
package/dist/harbor/store.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export type WardRecord = {
|
|
2
|
-
pk: string;
|
|
3
|
-
code: string;
|
|
4
|
-
user: string;
|
|
5
|
-
};
|
|
6
|
-
export type Kept = {
|
|
7
|
-
seed: Uint8Array;
|
|
8
|
-
partition: Record<string, unknown>;
|
|
9
|
-
record: WardRecord;
|
|
10
|
-
};
|
|
11
|
-
export type Store = {
|
|
12
|
-
list(): Promise<string[]>;
|
|
13
|
-
load(name: string): Promise<Kept | undefined>;
|
|
14
|
-
put(name: string, kept: Kept): Promise<void>;
|
|
15
|
-
save(name: string, partition: Record<string, unknown>, rows: readonly string[]): Promise<void>;
|
|
16
|
-
record(name: string, record: WardRecord): Promise<void>;
|
|
17
|
-
take(name: string): Promise<Kept | undefined>;
|
|
18
|
-
};
|
|
19
|
-
export declare const values: (p: Record<string, unknown>) => Record<string, unknown>;
|
|
20
|
-
export declare const rowsOf: (partition: Record<string, unknown>, rows: readonly string[]) => [string, Record<string, unknown> | undefined][];
|
|
21
|
-
type Row = {
|
|
22
|
-
seed: Uint8Array;
|
|
23
|
-
parts: Map<string, Record<string, unknown>>;
|
|
24
|
-
record: WardRecord;
|
|
25
|
-
};
|
|
26
|
-
export declare class MemoryStore implements Store {
|
|
27
|
-
readonly rows: Map<string, Row>;
|
|
28
|
-
list(): Promise<string[]>;
|
|
29
|
-
load(name: string): Promise<Kept | undefined>;
|
|
30
|
-
put(name: string, kept: Kept): Promise<void>;
|
|
31
|
-
save(name: string, partition: Record<string, unknown>, rows: readonly string[]): Promise<void>;
|
|
32
|
-
record(name: string, record: WardRecord): Promise<void>;
|
|
33
|
-
take(name: string): Promise<Kept | undefined>;
|
|
34
|
-
}
|
|
35
|
-
export {};
|
package/dist/harbor/store.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The store: keeping wards by name. A ward is three things and the store
|
|
3
|
-
// keeps all three under one name: the seed, the partition and the ward
|
|
4
|
-
// record, which says where the class bodies come from and which being is
|
|
5
|
-
// the user's. The store reads nothing it keeps; the partition is
|
|
6
|
-
// values the ward wrote, and the seed is bytes only the ward derives from.
|
|
7
|
-
// Every terrain has one: files on a disk, IndexedDB in a tab, an object's
|
|
8
|
-
// storage on the edge; the memory store below is the library's own, for a
|
|
9
|
-
// harbor core with no device under it. `src/conformance/store.ts` is what
|
|
10
|
-
// every one of them passes.
|
|
11
|
-
import { fromRows, rowOf, rowsIn } from '../ward/partition.js';
|
|
12
|
-
// The partition is values only, and the ward hands it out through a guard,
|
|
13
|
-
// so a store takes a copy of the values the way a file would: through JSON.
|
|
14
|
-
export const values = (p) => JSON.parse(JSON.stringify(p));
|
|
15
|
-
// The rows a store was told about, as values, ready to be written down. A row
|
|
16
|
-
// whose key names nobody is a being who left, and comes back undefined, which
|
|
17
|
-
// is the store dropping what it holds for her.
|
|
18
|
-
export const rowsOf = (partition, rows) => rows.map((row) => {
|
|
19
|
-
const value = rowOf(partition, row);
|
|
20
|
-
return [row, value === undefined ? undefined : (values(value))];
|
|
21
|
-
});
|
|
22
|
-
// One store's copy, brought up to date with the rows it was told about.
|
|
23
|
-
const keep = (row, partition, rows) => {
|
|
24
|
-
for (const [id, value] of rowsOf(partition, rows)) {
|
|
25
|
-
if (value === undefined)
|
|
26
|
-
row.parts.delete(id);
|
|
27
|
-
else
|
|
28
|
-
row.parts.set(id, value);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
export class MemoryStore {
|
|
32
|
-
rows = new Map();
|
|
33
|
-
async list() {
|
|
34
|
-
return [...this.rows.keys()];
|
|
35
|
-
}
|
|
36
|
-
async load(name) {
|
|
37
|
-
const row = this.rows.get(name);
|
|
38
|
-
return row && { seed: new Uint8Array(row.seed), partition: fromRows(Object.fromEntries(row.parts)), record: { ...row.record } };
|
|
39
|
-
}
|
|
40
|
-
async put(name, kept) {
|
|
41
|
-
if (this.rows.has(name))
|
|
42
|
-
throw new Error(`ward ${name} already exists here`);
|
|
43
|
-
const row = { seed: new Uint8Array(kept.seed), parts: new Map(), record: { ...kept.record } };
|
|
44
|
-
this.rows.set(name, row);
|
|
45
|
-
keep(row, kept.partition, rowsIn(kept.partition));
|
|
46
|
-
}
|
|
47
|
-
async save(name, partition, rows) {
|
|
48
|
-
const row = this.rows.get(name);
|
|
49
|
-
if (row)
|
|
50
|
-
keep(row, partition, rows);
|
|
51
|
-
}
|
|
52
|
-
async record(name, record) {
|
|
53
|
-
const row = this.rows.get(name);
|
|
54
|
-
if (row)
|
|
55
|
-
row.record = { ...record };
|
|
56
|
-
}
|
|
57
|
-
async take(name) {
|
|
58
|
-
const kept = await this.load(name);
|
|
59
|
-
this.rows.delete(name);
|
|
60
|
-
return kept;
|
|
61
|
-
}
|
|
62
|
-
}
|
package/dist/vector/cases.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { Json, JsonObject } from '../being/types.ts';
|
|
2
|
-
import type { Booted } from '../harbor/memory.ts';
|
|
3
|
-
import type { World, Sealed } from './world.ts';
|
|
4
|
-
export type DoorRecord = {
|
|
5
|
-
case: string;
|
|
6
|
-
name: string;
|
|
7
|
-
state: string;
|
|
8
|
-
ward: string;
|
|
9
|
-
kind: 'silence' | 'word' | 'object';
|
|
10
|
-
heard: boolean;
|
|
11
|
-
ask: string;
|
|
12
|
-
reply: string;
|
|
13
|
-
opens: Json | null;
|
|
14
|
-
draws: number;
|
|
15
|
-
blueprint?: JsonObject;
|
|
16
|
-
wrote: boolean;
|
|
17
|
-
};
|
|
18
|
-
export type Pin = () => Promise<void>;
|
|
19
|
-
export type Arrival = {
|
|
20
|
-
kind: DoorRecord['kind'];
|
|
21
|
-
door: Booted;
|
|
22
|
-
ask: Sealed | {
|
|
23
|
-
bytes: Uint8Array;
|
|
24
|
-
open: null;
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
export type Case = {
|
|
28
|
-
case: string;
|
|
29
|
-
name: string;
|
|
30
|
-
state: string;
|
|
31
|
-
ward: string;
|
|
32
|
-
arrive: (w: World, pin: Pin) => Promise<Arrival>;
|
|
33
|
-
};
|
|
34
|
-
export declare function stand(c: Case): Promise<{
|
|
35
|
-
w: World;
|
|
36
|
-
before: string;
|
|
37
|
-
draws: number;
|
|
38
|
-
arrival: Arrival;
|
|
39
|
-
}>;
|
|
40
|
-
export declare function doorCases(): Promise<DoorRecord[]>;
|
|
41
|
-
export declare const caseNamed: (kase: string, name: string) => Case | undefined;
|
|
42
|
-
export declare const cases: Case[];
|