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/being/types.d.ts
CHANGED
|
@@ -1,89 +1,61 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
1
|
+
import type { Json } from '../crypto/index.ts';
|
|
2
|
+
import type { Invitation } from '../quo/index.ts';
|
|
3
|
+
import type { Silence, Word } from './words.ts';
|
|
4
|
+
export type { Invitation, Json };
|
|
5
5
|
export type JsonObject = {
|
|
6
6
|
[key: string]: Json;
|
|
7
7
|
};
|
|
8
8
|
export type Asker = {
|
|
9
|
-
id: string;
|
|
9
|
+
readonly id: string;
|
|
10
10
|
} | {
|
|
11
|
-
id?: undefined;
|
|
11
|
+
readonly id?: undefined;
|
|
12
12
|
};
|
|
13
13
|
export declare const OWNER = "OWNER";
|
|
14
|
-
export declare const
|
|
15
|
-
export
|
|
16
|
-
export type
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
secret?: string;
|
|
14
|
+
export declare const WARD = "ward";
|
|
15
|
+
export type Answer = Json | Silence | Word;
|
|
16
|
+
export type Reply = Json | Silence | undefined;
|
|
17
|
+
export type Wanted = {
|
|
18
|
+
readonly time?: number;
|
|
20
19
|
};
|
|
21
|
-
export declare const invitationArgs: (inv: Invitation) => JsonObject;
|
|
22
|
-
export declare const isInvitation: (v: unknown) => v is Invitation;
|
|
23
20
|
export type Schema = JsonObject;
|
|
24
21
|
export type Ask = {
|
|
25
22
|
name: string;
|
|
26
23
|
description?: string;
|
|
27
24
|
input: Schema;
|
|
28
|
-
output?: Schema;
|
|
29
25
|
};
|
|
30
26
|
export type Blueprint = {
|
|
31
27
|
asks: Ask[];
|
|
32
28
|
notes: Json;
|
|
33
29
|
};
|
|
34
|
-
export
|
|
35
|
-
export type StandingRecord = {
|
|
36
|
-
id: string;
|
|
37
|
-
digest: string | null;
|
|
38
|
-
blueprint: Blueprint | null;
|
|
39
|
-
seen: string | null;
|
|
40
|
-
};
|
|
41
|
-
export type OccupantRecord = {
|
|
42
|
-
id: string;
|
|
43
|
-
notes: JsonObject;
|
|
44
|
-
};
|
|
45
|
-
export type Cells = {
|
|
46
|
-
standings: Record<string, StandingRecord>;
|
|
47
|
-
occupants: Record<string, OccupantRecord>;
|
|
48
|
-
[hers: string]: Json;
|
|
49
|
-
};
|
|
50
|
-
export type Silence = typeof silence;
|
|
51
|
-
export type DoorWord = 'removed' | 'absent' | 'unannounced' | 'repeated' | 'threw';
|
|
52
|
-
export type WardWord = 'unreached' | 'late' | 'invitation' | 'dropped';
|
|
53
|
-
export type WordName = DoorWord | WardWord;
|
|
54
|
-
export declare const WORD_KEY: unique symbol;
|
|
55
|
-
export type Word<W extends WordName = WordName> = {
|
|
56
|
-
readonly [K in typeof WORD_KEY]: W;
|
|
57
|
-
};
|
|
58
|
-
export type Unreached = Word<'unreached'>;
|
|
59
|
-
export type Answer = Json | Silence | Word;
|
|
60
|
-
export type Reply = Json | Silence;
|
|
61
|
-
export type Wanted = {
|
|
62
|
-
time?: number;
|
|
63
|
-
};
|
|
64
|
-
export type Standing = {
|
|
30
|
+
export interface Standing {
|
|
65
31
|
readonly id: string;
|
|
66
32
|
ask(method?: string, args?: JsonObject, wanted?: Wanted): Promise<Answer>;
|
|
67
|
-
}
|
|
68
|
-
export
|
|
69
|
-
knock(invitation: Invitation, method?: string, args?: JsonObject, wanted?: Wanted): Promise<Answer>;
|
|
33
|
+
}
|
|
34
|
+
export interface Standings {
|
|
70
35
|
take(id: string, invitation: Invitation): Promise<string | null>;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
export
|
|
36
|
+
get(id: string): Standing | undefined;
|
|
37
|
+
ids(): string[];
|
|
38
|
+
remove(id: string): boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface Occupants {
|
|
76
41
|
invite(id: string, notes?: JsonObject): Promise<Invitation | null>;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
42
|
+
notes(id: string): JsonObject | undefined;
|
|
43
|
+
ids(): string[];
|
|
44
|
+
remove(id: string): boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface Stance {
|
|
47
|
+
readonly key: string;
|
|
48
|
+
readonly cells: JsonObject;
|
|
81
49
|
readonly occupants: Occupants;
|
|
82
50
|
readonly standings: Standings;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
51
|
+
boot(kind: string, key: string, id?: string): Promise<string | null>;
|
|
52
|
+
lend(contract: abstract new (...args: never[]) => unknown, id: string): Promise<string | null>;
|
|
53
|
+
}
|
|
86
54
|
export interface BeingLike {
|
|
87
|
-
answer(asker: Asker, method
|
|
55
|
+
answer(asker: Asker, method: string | undefined, args: JsonObject): Reply | Promise<Reply>;
|
|
56
|
+
describe?(asker: Asker): Blueprint;
|
|
88
57
|
}
|
|
89
|
-
export type BeingClass = new (stance: Stance) => BeingLike
|
|
58
|
+
export type BeingClass = (new (stance: Stance) => BeingLike) & {
|
|
59
|
+
readonly name: string;
|
|
60
|
+
readonly kind: string;
|
|
61
|
+
};
|
package/dist/being/types.js
CHANGED
|
@@ -1,58 +1,4 @@
|
|
|
1
|
-
// The ids the ward speaks under, and no being may mint. An asker id is hers:
|
|
2
|
-
// she chooses the strings, and the ward has no business in her namespace. But
|
|
3
|
-
// the ward must sometimes stand at her door itself — its describe asks every
|
|
4
|
-
// being under OWNER — and an id it shares with one of her occupants is two
|
|
5
|
-
// different parties wearing one name. She could not tell them apart, and the
|
|
6
|
-
// ward would shape its describe through an occupant's gate.
|
|
7
|
-
//
|
|
8
|
-
// So the ward's words are shouted, and refused at the mint. A word can only
|
|
9
|
-
// be reserved before anyone has used it: a partition already holding an
|
|
10
|
-
// occupant of that name could never have it taken back. PUBLIC guards nothing
|
|
11
|
-
// today — a public asker is {} and carries no id at all — and that is exactly
|
|
12
|
-
// why it is claimed now, while claiming it is free.
|
|
13
1
|
export const OWNER = 'OWNER';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// who hands one on sends it as args, and args are values; this is the one
|
|
18
|
-
// place that is spelled, so nobody spells it with a cast. Absent stays absent:
|
|
19
|
-
// an invitation to a public being carries no heir and no secret, and a key
|
|
20
|
-
// present and undefined is not the same object once JSON has been through it.
|
|
21
|
-
export const invitationArgs = (inv) => ({
|
|
22
|
-
ward: inv.ward,
|
|
23
|
-
...(inv.heir !== undefined ? { heir: inv.heir } : {}),
|
|
24
|
-
...(inv.secret !== undefined ? { secret: inv.secret } : {}),
|
|
25
|
-
});
|
|
26
|
-
// Whether a value that arrived is an invitation. The shape is the spec's, so
|
|
27
|
-
// the reading of it is too, and it is one reading: a form that
|
|
28
|
-
// asks a guest for one, a lent being handed one to wake her maker by, and a
|
|
29
|
-
// shell that finds one in a link all ask the same question, and a kinder
|
|
30
|
-
// answer in one of them is a value that fails at a door instead of at the
|
|
31
|
-
// edge it came in by. A ward pk is a hundred and twenty-eight lowercase hex,
|
|
32
|
-
// and a heir comes with its secret or neither comes: an invitation to a
|
|
33
|
-
// public being carries no heir, and a heir with no secret opens nothing.
|
|
34
|
-
export const isInvitation = (v) => {
|
|
35
|
-
if (v === null || typeof v !== 'object' || Array.isArray(v))
|
|
36
|
-
return false;
|
|
37
|
-
const o = v;
|
|
38
|
-
if (typeof o.ward !== 'string' || !/^[0-9a-f]{128}$/.test(o.ward))
|
|
39
|
-
return false;
|
|
40
|
-
const heir = typeof o.heir === 'string', secret = typeof o.secret === 'string';
|
|
41
|
-
return (heir && secret) || (!heir && !secret && !('heir' in o) && !('secret' in o));
|
|
42
|
-
};
|
|
43
|
-
// Whether what came back from an empty ask is a blueprint. Every describe on
|
|
44
|
-
// the far side of a door is somebody else's code, so nothing may be written
|
|
45
|
-
// into a standing's record as a blueprint without being read as one first: a
|
|
46
|
-
// side walks `asks` by name, and a list of anything else, or no list at all,
|
|
47
|
-
// is a side that breaks on a far ward's answer. The asks are checked to the
|
|
48
|
-
// depth a side reads them, a name and an input each, and no further: what a
|
|
49
|
-
// far being puts beside those is hers.
|
|
50
|
-
export const isBlueprint = (v) => {
|
|
51
|
-
if (v === null || typeof v !== 'object' || Array.isArray(v))
|
|
52
|
-
return false;
|
|
53
|
-
const { asks, notes } = v;
|
|
54
|
-
if (!Array.isArray(asks) || notes === undefined)
|
|
55
|
-
return false;
|
|
56
|
-
return asks.every((a) => a !== null && typeof a === 'object' && !Array.isArray(a) && typeof a.name === 'string' && a.input !== null && typeof a.input === 'object' && !Array.isArray(a.input));
|
|
57
|
-
};
|
|
58
|
-
export const WORD_KEY = Symbol.for('quo.word');
|
|
2
|
+
// The ward-being's key in her ward, and so the id every being she makes
|
|
3
|
+
// knows her by.
|
|
4
|
+
export const WARD = 'ward';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Word as DoorWord } from '../quo/index.ts';
|
|
2
|
+
export declare const silence: unique symbol;
|
|
3
|
+
export type Silence = typeof silence;
|
|
4
|
+
export declare const isSilence: (x: unknown) => x is Silence;
|
|
5
|
+
export type WordName = DoorWord | 'unreached' | 'late' | 'dropped' | 'invitation';
|
|
6
|
+
declare const KEY: unique symbol;
|
|
7
|
+
export type Word<W extends WordName = WordName> = {
|
|
8
|
+
readonly [KEY]: W;
|
|
9
|
+
};
|
|
10
|
+
export declare const word: <W extends WordName>(name: W) => Word<W>;
|
|
11
|
+
export declare const isWord: (x: unknown) => x is Word;
|
|
12
|
+
export declare const told: (x: unknown) => unknown;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const silence = Symbol.for('nervur.silence');
|
|
2
|
+
export const isSilence = (x) => x === silence;
|
|
3
|
+
const KEY = Symbol.for('nervur.word');
|
|
4
|
+
const made = new Map();
|
|
5
|
+
export const word = (name) => {
|
|
6
|
+
let w = made.get(name);
|
|
7
|
+
if (!w)
|
|
8
|
+
made.set(name, (w = Object.freeze({ [KEY]: name })));
|
|
9
|
+
return w;
|
|
10
|
+
};
|
|
11
|
+
export const isWord = (x) => typeof x === 'object' && x !== null && typeof x[KEY] === 'string';
|
|
12
|
+
// A word by its name, and anything else as it is, so one comparison says
|
|
13
|
+
// which answer came back.
|
|
14
|
+
export const told = (x) => (isWord(x) ? x[KEY] : x);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { JsonObject } from '../being/index.ts';
|
|
2
|
+
import type { RootRequest } from '../harbor/index.ts';
|
|
3
|
+
export declare const parse: (argv: string[]) => {
|
|
4
|
+
command?: string;
|
|
5
|
+
words: string[];
|
|
6
|
+
flags: Record<string, string>;
|
|
7
|
+
};
|
|
8
|
+
export declare const requestOf: (command: string, words: string[], flags: Record<string, string>) => RootRequest;
|
|
9
|
+
export declare const main: (argv: string[], env: Record<string, string | undefined>, print: (line: string) => void) => Promise<number>;
|
|
10
|
+
export declare const pilotRequests: (name: string, invitation: JsonObject, at: string) => RootRequest[];
|
|
11
|
+
export declare const via: (pilot: string, far: RootRequest) => RootRequest;
|
|
12
|
+
export declare const farAnswer: (local: JsonObject) => JsonObject;
|
|
13
|
+
export declare const SERVING = -1;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// `nervur`: a harbor on this machine. Each command is one root request, the
|
|
3
|
+
// same the root line carries from any front, printed as one JSON line.
|
|
4
|
+
//
|
|
5
|
+
// nervur init [--dir D] the harbor made: its seed drawn,
|
|
6
|
+
// its catalogue stood, and an owner
|
|
7
|
+
// invitation for whoever made it
|
|
8
|
+
// nervur serve [--dir D] [--host H] [--port P] the harbor served: Quo over TCP,
|
|
9
|
+
// and the root line on its socket
|
|
10
|
+
// nervur module add <file> a module the catalogue runs
|
|
11
|
+
// nervur module remove <module> a module it runs no more
|
|
12
|
+
// nervur modules what the catalogue runs
|
|
13
|
+
// nervur census [--ward W] the empty ask
|
|
14
|
+
// nervur open <key> <kind> a faculty stands in the box ward
|
|
15
|
+
// nervur host <ward> [--seed S] a hosted ward stands
|
|
16
|
+
// nervur route <ward pk> <host:port | none> where a ward is reached
|
|
17
|
+
// nervur boot [--ward W] <key> <kind> a being stands
|
|
18
|
+
// nervur unboot [--ward W] <being> a being goes
|
|
19
|
+
// nervur public [--ward W] <key | none> the being a stranger reaches
|
|
20
|
+
// nervur invite [--ward W] <being> <id> an invitation on a being
|
|
21
|
+
// nervur ask [--ward W] [being] [method] [args] a being, asked as the owner
|
|
22
|
+
// nervur own [--ward W] <id> an invitation for an owner
|
|
23
|
+
// nervur disown [--ward W] <id> an owner no more
|
|
24
|
+
// nervur pilot <name> <invitation> <host:port> a far ward held as its owner, by a
|
|
25
|
+
// pilot being of the box ward
|
|
26
|
+
// nervur <command> --via <name> ... the command asked of the far ward
|
|
27
|
+
// that pilot holds, as its owner
|
|
28
|
+
//
|
|
29
|
+
// D is --dir, then $NERVUR_DIR, then ~/.nervur. A module file is named from
|
|
30
|
+
// where the command runs and kept by its absolute path. No --ward is the box
|
|
31
|
+
// ward, and a pilot holds one ward, so --via takes no --ward. The exit is 1
|
|
32
|
+
// when the answer is an error.
|
|
33
|
+
import { existsSync } from 'node:fs';
|
|
34
|
+
import { homedir } from 'node:os';
|
|
35
|
+
import { join, resolve } from 'node:path';
|
|
36
|
+
import { open, request, serve } from './harbor.js';
|
|
37
|
+
const USAGE = 'usage: nervur <init|serve|module|modules|census|open|host|route|boot|unboot|public|invite|ask|own|disown|pilot> [args] [--dir D] [--ward W] [--via V] [--seed S] [--host H] [--port P]';
|
|
38
|
+
const FLAGS = new Set(['dir', 'ward', 'via', 'seed', 'host', 'port']);
|
|
39
|
+
export const parse = (argv) => {
|
|
40
|
+
const flags = {};
|
|
41
|
+
const words = [];
|
|
42
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
43
|
+
const arg = argv[i];
|
|
44
|
+
const name = arg.startsWith('--') ? arg.slice(2) : undefined;
|
|
45
|
+
if (name === undefined)
|
|
46
|
+
words.push(arg);
|
|
47
|
+
else if (!FLAGS.has(name) || argv[i + 1] === undefined)
|
|
48
|
+
throw new Error(`--${name} is no flag with a value`);
|
|
49
|
+
else
|
|
50
|
+
flags[name] = argv[(i += 1)];
|
|
51
|
+
}
|
|
52
|
+
const [command, ...rest] = words;
|
|
53
|
+
return { ...(command === undefined ? {} : { command }), words: rest, flags };
|
|
54
|
+
};
|
|
55
|
+
const none = (word) => (word === 'none' ? null : word);
|
|
56
|
+
const json = (word) => (word === undefined ? undefined : JSON.parse(word));
|
|
57
|
+
const catalogue = (method, args = {}) => ({ method: 'ask', args: { being: 'catalogue', method, args } });
|
|
58
|
+
// The root request a command names, or a throw saying what it lacks.
|
|
59
|
+
export const requestOf = (command, words, flags) => {
|
|
60
|
+
const need = (n) => {
|
|
61
|
+
if (words.length !== n)
|
|
62
|
+
throw new Error(`${command} takes ${n} argument${n === 1 ? '' : 's'}`);
|
|
63
|
+
return words;
|
|
64
|
+
};
|
|
65
|
+
const at = flags.ward === undefined ? {} : { ward: flags.ward };
|
|
66
|
+
switch (command) {
|
|
67
|
+
case 'module': {
|
|
68
|
+
const [verb, what] = need(2);
|
|
69
|
+
if (verb === 'add')
|
|
70
|
+
return catalogue('add', { from: resolve(what) });
|
|
71
|
+
if (verb === 'remove')
|
|
72
|
+
return catalogue('remove', { module: what });
|
|
73
|
+
throw new Error('module is add or remove');
|
|
74
|
+
}
|
|
75
|
+
case 'modules':
|
|
76
|
+
return (need(0), catalogue('modules'));
|
|
77
|
+
case 'census':
|
|
78
|
+
return (need(0), at);
|
|
79
|
+
case 'open': {
|
|
80
|
+
const [key, kind] = need(2);
|
|
81
|
+
return { method: 'open', args: { key: key, class: kind } };
|
|
82
|
+
}
|
|
83
|
+
case 'host': {
|
|
84
|
+
const [ward] = need(1);
|
|
85
|
+
return { method: 'host', args: { ward: ward, ...(flags.seed === undefined ? {} : { seed: flags.seed }) } };
|
|
86
|
+
}
|
|
87
|
+
case 'route': {
|
|
88
|
+
const [ward, where] = need(2);
|
|
89
|
+
return { method: 'route', args: { ward: ward, at: none(where) } };
|
|
90
|
+
}
|
|
91
|
+
case 'boot': {
|
|
92
|
+
const [key, kind] = need(2);
|
|
93
|
+
return { ...at, method: 'boot', args: { key: key, class: kind } };
|
|
94
|
+
}
|
|
95
|
+
case 'unboot':
|
|
96
|
+
return { ...at, method: 'unboot', args: { being: need(1)[0] } };
|
|
97
|
+
case 'public':
|
|
98
|
+
return { ...at, method: 'public', args: { key: none(need(1)[0]) } };
|
|
99
|
+
case 'invite': {
|
|
100
|
+
const [being, id] = need(2);
|
|
101
|
+
return { ...at, method: 'invite', args: { being: being, id: id } };
|
|
102
|
+
}
|
|
103
|
+
case 'ask': {
|
|
104
|
+
if (words.length > 3)
|
|
105
|
+
throw new Error('ask takes at most a being, a method and its args');
|
|
106
|
+
const [being, method, args] = words;
|
|
107
|
+
return { ...at, method: 'ask', args: { ...(being === undefined ? {} : { being }), ...(method === undefined ? {} : { method }), ...(args === undefined ? {} : { args: json(args) }) } };
|
|
108
|
+
}
|
|
109
|
+
case 'own':
|
|
110
|
+
case 'disown':
|
|
111
|
+
return { ...at, method: command, args: { id: need(1)[0] } };
|
|
112
|
+
default:
|
|
113
|
+
throw new Error(USAGE);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
// An error answer at any depth the root line or an ask carries it.
|
|
117
|
+
const failed = (answer) => {
|
|
118
|
+
if (typeof answer !== 'object' || answer === null)
|
|
119
|
+
return false;
|
|
120
|
+
const a = answer;
|
|
121
|
+
return 'error' in a || failed(a.answer);
|
|
122
|
+
};
|
|
123
|
+
export const main = async (argv, env, print) => {
|
|
124
|
+
const { command, words, flags } = parse(argv);
|
|
125
|
+
if (command === undefined)
|
|
126
|
+
throw new Error(USAGE);
|
|
127
|
+
const dir = flags.dir ?? env.NERVUR_DIR ?? join(homedir(), '.nervur');
|
|
128
|
+
const out = (answer) => {
|
|
129
|
+
print(JSON.stringify(answer));
|
|
130
|
+
return failed(answer) ? 1 : 0;
|
|
131
|
+
};
|
|
132
|
+
if (command === 'init') {
|
|
133
|
+
if (words.length > 0)
|
|
134
|
+
throw new Error('init takes no argument');
|
|
135
|
+
if (existsSync(join(dir, 'seed')))
|
|
136
|
+
return out({ error: `a harbor stands at ${dir}` });
|
|
137
|
+
const { harbor, carrier } = await open(dir);
|
|
138
|
+
try {
|
|
139
|
+
const owner = await harbor.root('own', { id: 'owner' });
|
|
140
|
+
return out({ pk: harbor.box.pk, owner: owner });
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
await carrier.close();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (command === 'serve') {
|
|
147
|
+
if (words.length > 0)
|
|
148
|
+
throw new Error('serve takes no argument');
|
|
149
|
+
const served = await serve(dir, flags.host, flags.port === undefined ? undefined : Number(flags.port));
|
|
150
|
+
const stop = () => void served.close().then(() => process.exit(0));
|
|
151
|
+
process.once('SIGINT', stop);
|
|
152
|
+
process.once('SIGTERM', stop);
|
|
153
|
+
print(JSON.stringify({ pk: served.pk, at: served.at, root: served.root }));
|
|
154
|
+
return SERVING;
|
|
155
|
+
}
|
|
156
|
+
if (command === 'pilot') {
|
|
157
|
+
if (words.length !== 3)
|
|
158
|
+
throw new Error('pilot takes 3 arguments');
|
|
159
|
+
const [name, invitation, at] = words;
|
|
160
|
+
const held = JSON.parse(invitation);
|
|
161
|
+
for (const req of pilotRequests(name, held, at)) {
|
|
162
|
+
const answer = await request(dir, req);
|
|
163
|
+
if (!failed(answer))
|
|
164
|
+
continue;
|
|
165
|
+
if (req.method === 'ask')
|
|
166
|
+
await request(dir, { method: 'unboot', args: { being: name } });
|
|
167
|
+
return out(answer);
|
|
168
|
+
}
|
|
169
|
+
return out({ piloting: name, ward: held.ward });
|
|
170
|
+
}
|
|
171
|
+
if (flags.via === undefined)
|
|
172
|
+
return out(await request(dir, requestOf(command, words, flags)));
|
|
173
|
+
if (flags.ward !== undefined)
|
|
174
|
+
throw new Error('--via takes no --ward');
|
|
175
|
+
return out(farAnswer(await request(dir, via(flags.via, requestOf(command, words, flags)))));
|
|
176
|
+
};
|
|
177
|
+
// The root requests that hold a far ward: its route, the pilot, the take.
|
|
178
|
+
export const pilotRequests = (name, invitation, at) => [
|
|
179
|
+
{ method: 'route', args: { ward: invitation.ward ?? null, at } },
|
|
180
|
+
{ method: 'boot', args: { key: name, class: 'org.nervur.pilot' } },
|
|
181
|
+
{ method: 'ask', args: { being: name, method: 'hold', args: { invitation } } },
|
|
182
|
+
];
|
|
183
|
+
// A root request, asked of the far ward a pilot holds.
|
|
184
|
+
export const via = (pilot, far) => ({
|
|
185
|
+
method: 'ask',
|
|
186
|
+
args: { being: pilot, method: 'pilot', args: { ...(far.method === undefined ? {} : { method: far.method }), ...(far.args === undefined ? {} : { args: far.args }) } },
|
|
187
|
+
});
|
|
188
|
+
// The far ward-being's answer out of the pilot's, or the local error.
|
|
189
|
+
export const farAnswer = (local) => {
|
|
190
|
+
const inner = local.answer?.answer;
|
|
191
|
+
return typeof inner === 'object' && inner !== null && !Array.isArray(inner) ? inner : local;
|
|
192
|
+
};
|
|
193
|
+
// What `main` answers for a harbor it keeps serving: no exit yet.
|
|
194
|
+
export const SERVING = -1;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { JsonObject } from '../being/index.ts';
|
|
2
|
+
import { Loader, type Loaded } from '../contract/index.ts';
|
|
3
|
+
import { Harbor, type RootRequest } from '../harbor/index.ts';
|
|
4
|
+
import { TcpCarrier } from '../tcp/index.ts';
|
|
5
|
+
export declare const socketOf: (dir: string) => string;
|
|
6
|
+
export declare class ImportLoader extends Loader {
|
|
7
|
+
load(from: string): Promise<Loaded | null>;
|
|
8
|
+
}
|
|
9
|
+
export type Opened = {
|
|
10
|
+
harbor: Harbor;
|
|
11
|
+
carrier: TcpCarrier;
|
|
12
|
+
};
|
|
13
|
+
export declare const open: (dir: string) => Promise<Opened>;
|
|
14
|
+
export declare const request: (dir: string, req: RootRequest) => Promise<JsonObject>;
|
|
15
|
+
export type Served = {
|
|
16
|
+
pk: string;
|
|
17
|
+
at: string;
|
|
18
|
+
root: string;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
export declare const serve: (dir: string, host?: string, port?: number) => Promise<Served>;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
10
|
+
// A harbor on this machine, as the `nervur` command stands it: its seed and
|
|
11
|
+
// sealed memory in a folder, its code imported from the files its
|
|
12
|
+
// catalogue names, Quo over TCP as its carrier, and the root line on a
|
|
13
|
+
// local socket beside them.
|
|
14
|
+
//
|
|
15
|
+
// <dir>/seed the harbor's seed
|
|
16
|
+
// <dir>/<place>/ its sealed memory
|
|
17
|
+
// <dir>/root.sock the root line while the harbor is served, open to
|
|
18
|
+
// this user alone, or in the temporary folder for a
|
|
19
|
+
// folder too deep for a socket path
|
|
20
|
+
//
|
|
21
|
+
// A root request goes to a served harbor over its socket. With none served,
|
|
22
|
+
// the command unpacks the harbor from its folder, asks, and closes it, so
|
|
23
|
+
// one process at a time writes the folder.
|
|
24
|
+
import { createHash } from 'node:crypto';
|
|
25
|
+
import { chmod, rm } from 'node:fs/promises';
|
|
26
|
+
import { connect, createServer } from 'node:net';
|
|
27
|
+
import { tmpdir } from 'node:os';
|
|
28
|
+
import { join, resolve } from 'node:path';
|
|
29
|
+
import { pathToFileURL } from 'node:url';
|
|
30
|
+
import { Loader } from '../contract/index.js';
|
|
31
|
+
import { FolderCustody, FolderMemory } from '../folder/index.js';
|
|
32
|
+
import { Harbor, rootLine } from '../harbor/index.js';
|
|
33
|
+
import { CryptoEntropy, PointerTerrain } from '../pointer/index.js';
|
|
34
|
+
import { TcpCarrier, TcpListener } from '../tcp/index.js';
|
|
35
|
+
// A socket path has a hundred bytes or so on every system, so a folder too
|
|
36
|
+
// deep for one puts its socket in this user's temporary folder, under a
|
|
37
|
+
// name drawn from the folder's own path.
|
|
38
|
+
const SOCKET_PATH = 100;
|
|
39
|
+
export const socketOf = (dir) => {
|
|
40
|
+
const beside = join(resolve(dir), 'root.sock');
|
|
41
|
+
if (Buffer.byteLength(beside) <= SOCKET_PATH)
|
|
42
|
+
return beside;
|
|
43
|
+
return join(tmpdir(), `nervur-${createHash('sha256').update(resolve(dir)).digest('hex').slice(0, 32)}.sock`);
|
|
44
|
+
};
|
|
45
|
+
// Code from a file: a module that exports `module`, `version` and
|
|
46
|
+
// `classes`, found again by its absolute path. A file that cannot be
|
|
47
|
+
// imported, or exports no module, is none.
|
|
48
|
+
export class ImportLoader extends Loader {
|
|
49
|
+
async load(from) {
|
|
50
|
+
const path = resolve(from);
|
|
51
|
+
let exported;
|
|
52
|
+
try {
|
|
53
|
+
exported = (await import(__rewriteRelativeImportExtension(pathToFileURL(path).href)));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const { module, version, classes } = exported;
|
|
59
|
+
if (typeof module !== 'string' || typeof version !== 'string' || !Array.isArray(classes))
|
|
60
|
+
return null;
|
|
61
|
+
return { module, version, classes, from: path };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export const open = async (dir) => {
|
|
65
|
+
const entropy = new CryptoEntropy();
|
|
66
|
+
const carrier = new TcpCarrier();
|
|
67
|
+
const harbor = await Harbor.open(new PointerTerrain({ entropy, carrier, loader: new ImportLoader(), custody: new FolderCustody(dir, entropy), memory: new FolderMemory(dir) }));
|
|
68
|
+
return { harbor, carrier };
|
|
69
|
+
};
|
|
70
|
+
// One root request over a served harbor's socket, or undefined where none
|
|
71
|
+
// is served.
|
|
72
|
+
const overSocket = (dir, request) => new Promise((done, fail) => {
|
|
73
|
+
const socket = connect(socketOf(dir));
|
|
74
|
+
let text = '';
|
|
75
|
+
socket.once('connect', () => socket.write(`${JSON.stringify(request)}\n`));
|
|
76
|
+
socket.on('data', (chunk) => {
|
|
77
|
+
text += chunk.toString('utf8');
|
|
78
|
+
const end = text.indexOf('\n');
|
|
79
|
+
if (end < 0)
|
|
80
|
+
return;
|
|
81
|
+
socket.end();
|
|
82
|
+
done(JSON.parse(text.slice(0, end)));
|
|
83
|
+
});
|
|
84
|
+
socket.once('error', (e) => (e.code === 'ENOENT' || e.code === 'ECONNREFUSED' ? done(undefined) : fail(e)));
|
|
85
|
+
});
|
|
86
|
+
export const request = async (dir, req) => {
|
|
87
|
+
const served = await overSocket(dir, req);
|
|
88
|
+
if (served !== undefined)
|
|
89
|
+
return served;
|
|
90
|
+
const { harbor, carrier } = await open(dir);
|
|
91
|
+
try {
|
|
92
|
+
return await rootLine(harbor, req);
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
await carrier.close();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
// The harbor served: Quo over TCP on host and port, the root line on the
|
|
99
|
+
// socket. A socket file nobody answers on is a stale one, and is replaced.
|
|
100
|
+
export const serve = async (dir, host, port) => {
|
|
101
|
+
if ((await overSocket(dir, {})) !== undefined)
|
|
102
|
+
throw new Error(`a harbor is already served from ${dir}`);
|
|
103
|
+
const { harbor, carrier } = await open(dir);
|
|
104
|
+
const listener = await TcpListener.listen(harbor, host, port);
|
|
105
|
+
const root = socketOf(dir);
|
|
106
|
+
await rm(root, { force: true });
|
|
107
|
+
const server = createServer((socket) => {
|
|
108
|
+
let text = '';
|
|
109
|
+
socket.on('data', (chunk) => {
|
|
110
|
+
text += chunk.toString('utf8');
|
|
111
|
+
for (let end = text.indexOf('\n'); end >= 0; end = text.indexOf('\n')) {
|
|
112
|
+
const line = text.slice(0, end);
|
|
113
|
+
text = text.slice(end + 1);
|
|
114
|
+
let value;
|
|
115
|
+
try {
|
|
116
|
+
value = JSON.parse(line);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
value = undefined;
|
|
120
|
+
}
|
|
121
|
+
void rootLine(harbor, value)
|
|
122
|
+
.catch(() => ({ error: 'the harbor threw' }))
|
|
123
|
+
.then((answer) => socket.write(`${JSON.stringify(answer)}\n`));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
socket.on('error', () => socket.destroy());
|
|
127
|
+
});
|
|
128
|
+
await new Promise((done) => server.listen(root, done));
|
|
129
|
+
await chmod(root, 0o600);
|
|
130
|
+
return {
|
|
131
|
+
pk: harbor.box.pk,
|
|
132
|
+
at: listener.at,
|
|
133
|
+
root,
|
|
134
|
+
close: async () => {
|
|
135
|
+
await new Promise((done) => server.close(done));
|
|
136
|
+
await rm(root, { force: true });
|
|
137
|
+
await listener.close();
|
|
138
|
+
await carrier.close();
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
};
|
package/dist/cli/main.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// The `nervur` program: `command.ts` over this process's arguments. A
|
|
4
|
+
// command that cannot run exits 2 and says why on stderr.
|
|
5
|
+
import { main, SERVING } from './command.js';
|
|
6
|
+
try {
|
|
7
|
+
const code = await main(process.argv.slice(2), process.env, (line) => process.stdout.write(`${line}\n`));
|
|
8
|
+
if (code !== SERVING)
|
|
9
|
+
process.exitCode = code;
|
|
10
|
+
}
|
|
11
|
+
catch (e) {
|
|
12
|
+
process.stderr.write(`nervur: ${e.message}\n`);
|
|
13
|
+
process.exitCode = 2;
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Draw } from '../quo/index.ts';
|
|
2
|
+
export declare abstract class Entropy {
|
|
3
|
+
abstract draw(length: number): Uint8Array;
|
|
4
|
+
get drawer(): Draw;
|
|
5
|
+
}
|
|
6
|
+
export declare abstract class Clock {
|
|
7
|
+
abstract now(): number;
|
|
8
|
+
abstract wait(ms: number): {
|
|
9
|
+
done: Promise<void>;
|
|
10
|
+
cancel(): void;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface Rows {
|
|
14
|
+
readonly rows: Record<string, unknown>;
|
|
15
|
+
told(row: string): void;
|
|
16
|
+
kept(): Promise<boolean>;
|
|
17
|
+
}
|
|
18
|
+
export declare abstract class Memory {
|
|
19
|
+
abstract read(place: string): Promise<Map<string, Uint8Array>>;
|
|
20
|
+
abstract write(place: string, entries: ReadonlyMap<string, Uint8Array | null>): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export declare abstract class Custody {
|
|
23
|
+
abstract seed(): Promise<Uint8Array>;
|
|
24
|
+
}
|
|
25
|
+
export type Module = {
|
|
26
|
+
readonly module: string;
|
|
27
|
+
readonly version: string;
|
|
28
|
+
readonly classes: readonly unknown[];
|
|
29
|
+
};
|
|
30
|
+
export type Loaded = Module & {
|
|
31
|
+
readonly from: string;
|
|
32
|
+
};
|
|
33
|
+
export declare abstract class Loader {
|
|
34
|
+
abstract load(from: string): Promise<Loaded | null>;
|
|
35
|
+
}
|
|
36
|
+
export declare abstract class Carrier {
|
|
37
|
+
abstract carry(pk: string, bytes: Uint8Array): Promise<Uint8Array | null>;
|
|
38
|
+
route(_pk: string, _at: string | null): boolean;
|
|
39
|
+
}
|