nervur 0.19.2 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -101
- package/dist/being/being.d.ts +7 -15
- package/dist/being/being.js +16 -67
- package/dist/being/digest.d.ts +1 -1
- package/dist/being/digest.js +7 -27
- package/dist/being/faculty.d.ts +9 -0
- package/dist/being/faculty.js +68 -0
- package/dist/being/index.d.ts +4 -5
- package/dist/being/index.js +5 -5
- package/dist/being/types.d.ts +35 -62
- package/dist/being/types.js +3 -57
- package/dist/being/words.d.ts +13 -0
- package/dist/being/words.js +14 -0
- package/dist/contract/index.d.ts +26 -0
- package/dist/contract/index.js +19 -0
- package/dist/crypto/aes.d.ts +3 -0
- package/dist/crypto/aes.js +24 -0
- package/dist/crypto/bytes.d.ts +6 -0
- package/dist/crypto/bytes.js +33 -0
- package/dist/crypto/ed25519.d.ts +3 -0
- package/dist/crypto/ed25519.js +85 -0
- package/dist/crypto/hash.d.ts +2 -0
- package/dist/crypto/hash.js +11 -0
- package/dist/crypto/index.d.ts +7 -0
- package/dist/crypto/index.js +10 -0
- package/dist/crypto/json.d.ts +8 -0
- package/dist/crypto/json.js +250 -0
- package/dist/crypto/mlkem.d.ts +12 -0
- package/dist/crypto/mlkem.js +36 -0
- package/dist/crypto/subtle.d.ts +10 -0
- package/dist/crypto/subtle.js +29 -0
- package/dist/crypto/x25519.d.ts +2 -0
- package/dist/crypto/x25519.js +21 -0
- package/dist/folder/index.d.ts +13 -0
- package/dist/folder/index.js +125 -0
- package/dist/harbor/dock.d.ts +19 -0
- package/dist/harbor/dock.js +92 -0
- package/dist/harbor/harbor.d.ts +22 -0
- package/dist/harbor/harbor.js +84 -0
- package/dist/harbor/index.d.ts +4 -10
- package/dist/harbor/index.js +5 -18
- package/dist/harbor/registry.d.ts +7 -0
- package/dist/harbor/registry.js +13 -0
- package/dist/harbor/terrain.d.ts +8 -0
- package/dist/harbor/terrain.js +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +14 -0
- package/dist/pointer/bodies.d.ts +20 -0
- package/dist/pointer/bodies.js +45 -0
- package/dist/pointer/index.d.ts +2 -0
- package/dist/pointer/index.js +4 -0
- package/dist/pointer/world.d.ts +34 -0
- package/dist/pointer/world.js +76 -0
- package/dist/quo/door.d.ts +34 -0
- package/dist/quo/door.js +172 -0
- package/dist/quo/index.d.ts +8 -0
- package/dist/quo/index.js +11 -0
- package/dist/quo/invitation.d.ts +7 -0
- package/dist/quo/invitation.js +15 -0
- package/dist/quo/keys.d.ts +40 -0
- package/dist/quo/keys.js +79 -0
- package/dist/quo/payload.d.ts +15 -0
- package/dist/quo/payload.js +55 -0
- package/dist/quo/relations.d.ts +40 -0
- package/dist/quo/relations.js +33 -0
- package/dist/quo/reply.d.ts +13 -0
- package/dist/quo/reply.js +35 -0
- package/dist/quo/seal.d.ts +42 -0
- package/dist/quo/seal.js +78 -0
- package/dist/quo/standing.d.ts +39 -0
- package/dist/quo/standing.js +90 -0
- package/dist/ward/allowance.d.ts +13 -9
- package/dist/ward/allowance.js +28 -67
- package/dist/ward/cells.d.ts +6 -6
- package/dist/ward/cells.js +67 -179
- package/dist/ward/index.d.ts +5 -10
- package/dist/ward/index.js +6 -13
- package/dist/ward/partition.d.ts +44 -60
- package/dist/ward/partition.js +56 -285
- package/dist/ward/stance.d.ts +29 -20
- package/dist/ward/stance.js +173 -406
- package/dist/ward/ward-being.d.ts +33 -0
- package/dist/ward/ward-being.js +76 -0
- package/dist/ward/ward.d.ts +43 -11
- package/dist/ward/ward.js +215 -363
- package/package.json +19 -33
- package/src/being/being.ts +31 -78
- package/src/being/digest.ts +7 -35
- package/src/being/faculty.ts +66 -0
- package/src/being/index.ts +5 -6
- package/src/being/types.ts +47 -145
- package/src/being/words.ts +31 -0
- package/src/contract/index.ts +44 -0
- package/src/crypto/aes.ts +26 -0
- package/src/crypto/bytes.ts +37 -0
- package/src/crypto/ed25519.ts +84 -0
- package/src/crypto/hash.ts +14 -0
- package/src/crypto/index.ts +10 -0
- package/src/crypto/json.ts +241 -0
- package/src/crypto/mlkem.ts +38 -0
- package/src/crypto/subtle.ts +33 -0
- package/src/crypto/x25519.ts +21 -0
- package/src/folder/index.ts +134 -0
- package/src/harbor/dock.ts +101 -0
- package/src/harbor/harbor.ts +105 -0
- package/src/harbor/index.ts +5 -19
- package/src/harbor/registry.ts +20 -0
- package/src/harbor/terrain.ts +13 -0
- package/src/index.ts +20 -0
- package/src/pointer/bodies.ts +47 -0
- package/src/pointer/index.ts +4 -0
- package/src/pointer/world.ts +91 -0
- package/src/quo/door.ts +178 -0
- package/src/quo/index.ts +11 -0
- package/src/quo/invitation.ts +15 -0
- package/src/quo/keys.ts +91 -0
- package/src/quo/payload.ts +61 -0
- package/src/quo/relations.ts +62 -0
- package/src/quo/reply.ts +38 -0
- package/src/quo/seal.ts +101 -0
- package/src/quo/standing.ts +111 -0
- package/src/stand/main.ts +19 -0
- package/src/stand/stand.ts +178 -0
- package/src/ward/allowance.ts +37 -75
- package/src/ward/cells.ts +63 -176
- package/src/ward/index.ts +6 -17
- package/src/ward/partition.ts +86 -326
- package/src/ward/stance.ts +185 -420
- package/src/ward/ward-being.ts +97 -0
- package/src/ward/ward.ts +229 -363
- package/dist/being/lent.d.ts +0 -32
- package/dist/being/lent.js +0 -72
- package/dist/being/silence.d.ts +0 -12
- package/dist/being/silence.js +0 -41
- package/dist/conformance/assert.d.ts +0 -11
- package/dist/conformance/assert.js +0 -106
- package/dist/conformance/beings.d.ts +0 -199
- package/dist/conformance/beings.js +0 -188
- package/dist/conformance/estate.d.ts +0 -5
- package/dist/conformance/estate.js +0 -388
- package/dist/conformance/index.d.ts +0 -80
- package/dist/conformance/index.js +0 -819
- package/dist/conformance/reach.d.ts +0 -10
- package/dist/conformance/reach.js +0 -72
- package/dist/conformance/store.d.ts +0 -5
- package/dist/conformance/store.js +0 -113
- package/dist/harbor/box.d.ts +0 -121
- package/dist/harbor/box.js +0 -121
- package/dist/harbor/core.d.ts +0 -55
- package/dist/harbor/core.js +0 -662
- package/dist/harbor/dial.d.ts +0 -9
- package/dist/harbor/dial.js +0 -81
- package/dist/harbor/memory.d.ts +0 -29
- package/dist/harbor/memory.js +0 -104
- package/dist/harbor/reach.d.ts +0 -36
- package/dist/harbor/reach.js +0 -199
- package/dist/harbor/store.d.ts +0 -35
- package/dist/harbor/store.js +0 -62
- package/dist/vector/cases.d.ts +0 -42
- package/dist/vector/cases.js +0 -223
- package/dist/vector/index.d.ts +0 -6
- package/dist/vector/index.js +0 -8
- package/dist/vector/stand.d.ts +0 -9
- package/dist/vector/stand.js +0 -77
- package/dist/vector/world.d.ts +0 -144
- package/dist/vector/world.js +0 -209
- package/dist/ward/arithmetic.d.ts +0 -31
- package/dist/ward/arithmetic.js +0 -249
- package/dist/ward/door.d.ts +0 -18
- package/dist/ward/door.js +0 -186
- package/dist/ward/ground.d.ts +0 -29
- package/dist/ward/ground.js +0 -56
- package/dist/ward/heirs.d.ts +0 -13
- package/dist/ward/heirs.js +0 -117
- package/dist/ward/json.d.ts +0 -2
- package/dist/ward/json.js +0 -163
- package/dist/ward/owner.d.ts +0 -13
- package/dist/ward/owner.js +0 -220
- package/dist/ward/seal.d.ts +0 -52
- package/dist/ward/seal.js +0 -150
- package/src/being/lent.ts +0 -72
- package/src/being/silence.ts +0 -46
- package/src/conformance/assert.ts +0 -100
- package/src/conformance/beings.ts +0 -188
- package/src/conformance/estate.ts +0 -412
- package/src/conformance/index.ts +0 -965
- package/src/conformance/reach.ts +0 -83
- package/src/conformance/store.ts +0 -125
- package/src/harbor/box.ts +0 -131
- package/src/harbor/core.ts +0 -699
- package/src/harbor/dial.ts +0 -112
- package/src/harbor/memory.ts +0 -123
- package/src/harbor/reach.ts +0 -221
- package/src/harbor/store.ts +0 -91
- package/src/vector/cases.ts +0 -257
- package/src/vector/index.ts +0 -11
- package/src/vector/stand.ts +0 -76
- package/src/vector/world.ts +0 -232
- package/src/ward/arithmetic.ts +0 -251
- package/src/ward/door.ts +0 -186
- package/src/ward/ground.ts +0 -142
- package/src/ward/heirs.ts +0 -116
- package/src/ward/json.ts +0 -144
- package/src/ward/owner.ts +0 -214
- package/src/ward/seal.ts +0 -178
package/dist/ward/heirs.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { GONE } from './partition.js';
|
|
2
|
-
// How wide the span is, is the spec's and never a ward's. Wider is more
|
|
3
|
-
// forgiving of a rough road, and that is exactly why it is not a ward's to
|
|
4
|
-
// choose: a peer tells two doors apart by being refused at one and answered
|
|
5
|
-
// at the other, which is one relation dying over one number.
|
|
6
|
-
const SPAN = 64;
|
|
7
|
-
export class Heirs {
|
|
8
|
-
#p;
|
|
9
|
-
#wrote;
|
|
10
|
-
constructor(p, wrote = () => { }) {
|
|
11
|
-
this.#p = p;
|
|
12
|
-
this.#wrote = wrote;
|
|
13
|
-
}
|
|
14
|
-
open(heir, being, id) {
|
|
15
|
-
this.#p.heirs[heir] = { being, id, current: heir, announced: null, fresh: true, mark: 0, spent: [] };
|
|
16
|
-
this.#wrote();
|
|
17
|
-
}
|
|
18
|
-
// The id was removed. The heir is forgotten, and its last keys are kept
|
|
19
|
-
// apart, bounded, so that whoever still holds them hears `removed` at the
|
|
20
|
-
// door, once they have signed as themselves, and nobody else hears a thing.
|
|
21
|
-
close(heir) {
|
|
22
|
-
const h = this.#p.heirs[heir];
|
|
23
|
-
if (!h)
|
|
24
|
-
return;
|
|
25
|
-
delete this.#p.heirs[heir];
|
|
26
|
-
this.#p.gone[heir] = { current: h.current, announced: h.announced };
|
|
27
|
-
const keys = Object.keys(this.#p.gone);
|
|
28
|
-
for (const old of keys.slice(0, Math.max(0, keys.length - GONE)))
|
|
29
|
-
delete this.#p.gone[old];
|
|
30
|
-
this.#wrote();
|
|
31
|
-
}
|
|
32
|
-
// May `by` speak for a relation she removed? True only for the keys the
|
|
33
|
-
// door held when the id went, which nobody but their holder has.
|
|
34
|
-
gone(heir, by) {
|
|
35
|
-
const g = this.#p.gone[heir];
|
|
36
|
-
return !!g && (by === g.current || by === g.announced);
|
|
37
|
-
}
|
|
38
|
-
// May `by` speak for this heir? Returns the record if so, null if not.
|
|
39
|
-
// Does not write: the caller verifies the signature first, then settles.
|
|
40
|
-
admits(heir, by) {
|
|
41
|
-
const h = this.#p.heirs[heir];
|
|
42
|
-
if (!h)
|
|
43
|
-
return null;
|
|
44
|
-
if (h.fresh)
|
|
45
|
-
return by === h.current ? h : null;
|
|
46
|
-
return by === h.current || by === h.announced ? h : null;
|
|
47
|
-
}
|
|
48
|
-
// Once only. A number above the mark is honoured and moves it; a number
|
|
49
|
-
// inside the span is honoured once and never again; a number at or below
|
|
50
|
-
// the span is refused, because a door that remembered every number ever
|
|
51
|
-
// seen would be a door with unbounded memory. Counting starts where
|
|
52
|
-
// strangers must agree: the first legal number is one.
|
|
53
|
-
//
|
|
54
|
-
// The number rides inside the signed body, so bytes caught on the road
|
|
55
|
-
// carry the number they were sent under and are refused as themselves. A
|
|
56
|
-
// caller who means to ask again asks again, under the next number, and is
|
|
57
|
-
// heard: retry and fire-and-forget stay hers to build. Only the accident
|
|
58
|
-
// and the interception are refused.
|
|
59
|
-
//
|
|
60
|
-
// Writes, so the caller settles it only once the signature has checked out.
|
|
61
|
-
// The same bytes twice are one honoured call and one silence.
|
|
62
|
-
spend(h, seq) {
|
|
63
|
-
if (!Number.isSafeInteger(seq) || seq < 1)
|
|
64
|
-
return false;
|
|
65
|
-
if (seq > h.mark) {
|
|
66
|
-
if (h.mark > 0)
|
|
67
|
-
h.spent.push(h.mark);
|
|
68
|
-
h.mark = seq;
|
|
69
|
-
h.spent = h.spent.filter((past) => past > seq - SPAN);
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
if (seq === h.mark || seq <= h.mark - SPAN || h.spent.includes(seq))
|
|
73
|
-
return false;
|
|
74
|
-
h.spent.push(seq);
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
// The signature checked out. Spend the number and settle the keys, or do
|
|
78
|
-
// neither: a call that binds nothing must not burn a number on its way to
|
|
79
|
-
// being refused, or a stranger who cannot be heard would still leave a mark
|
|
80
|
-
// behind her. Every write below this line is one that is going to hold.
|
|
81
|
-
// This is where a knock is judged and where `unannounced` is said. settle
|
|
82
|
-
// below is the writing alone, and it judges nothing: one owner for the
|
|
83
|
-
// question, one for the answer.
|
|
84
|
-
honour(h, by, next, seq) {
|
|
85
|
-
if (h.fresh && (next === null || next === h.current))
|
|
86
|
-
return 'unannounced'; // a knock without a key of her own binds nothing, and the heir is not a key of her own
|
|
87
|
-
if (!this.spend(h, seq))
|
|
88
|
-
return 'repeated';
|
|
89
|
-
this.settle(h, by, next);
|
|
90
|
-
this.#wrote(); // the number and the keys moved together
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
// The signature checked out and honour has judged. Settle the keys: a fresh
|
|
94
|
-
// heir rotates at once to what it announced, which honour has already held
|
|
95
|
-
// to being something other than itself, so that the heir dies as it speaks;
|
|
96
|
-
// a current key replaces its announcement; an announced key becomes current.
|
|
97
|
-
settle(h, by, next) {
|
|
98
|
-
if (h.fresh) {
|
|
99
|
-
if (next === null)
|
|
100
|
-
return; // honour judged this. the compiler has not read it, so the narrowing stays.
|
|
101
|
-
h.current = next;
|
|
102
|
-
h.announced = null;
|
|
103
|
-
h.fresh = false;
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (by === h.announced)
|
|
107
|
-
h.current = by;
|
|
108
|
-
// A send that announced nothing leaves the spare standing. This kit
|
|
109
|
-
// announces on every send but a public one, which holds no heir and
|
|
110
|
-
// reaches none of this; a kit that skips one is a kit whose own next is
|
|
111
|
-
// still the key it announced last time, and forgetting it here would meet
|
|
112
|
-
// that key with silence and kill a healthy relation. Nothing is dropped
|
|
113
|
-
// that was vouched for until something replaces it.
|
|
114
|
-
if (next !== null)
|
|
115
|
-
h.announced = next;
|
|
116
|
-
}
|
|
117
|
-
}
|
package/dist/ward/json.d.ts
DELETED
package/dist/ward/json.js
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The one reader of JSON that crossed an edge. A runtime's own parser is
|
|
3
|
-
// where two kits stop agreeing: it keeps the last of two keys of one name,
|
|
4
|
-
// rounds a whole number no double holds, reads a number past the doubles as
|
|
5
|
-
// infinity, and mends bytes that are not UTF-8 into a replacement character.
|
|
6
|
-
// Each of those is text two kits read two ways, so each is refused here, where
|
|
7
|
-
// it is read, with a throw the caller already turns into what bytes that said
|
|
8
|
-
// nothing are.
|
|
9
|
-
//
|
|
10
|
-
// What a value is beyond its text, a lone surrogate, a key named `__proto__`,
|
|
11
|
-
// a nesting past the bound, is the value rule's, and `cellFault` in cells.ts
|
|
12
|
-
// is its one reader. This file holds the rules that live only in the text.
|
|
13
|
-
const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
|
|
14
|
-
const fail = (at, why) => {
|
|
15
|
-
throw new Error(`JSON at ${at}: ${why}`);
|
|
16
|
-
};
|
|
17
|
-
// A number text, held to the Values chapter. A text naming a whole number
|
|
18
|
-
// stands only if that number is exactly a double, or if the text is how
|
|
19
|
-
// ECMAScript writes the double it reads as. A text past the largest double,
|
|
20
|
-
// or naming a value other than zero that rounds to zero, is refused, and so
|
|
21
|
-
// is minus zero in any spelling.
|
|
22
|
-
export function numberFault(literal) {
|
|
23
|
-
const m = /^(-?)(0|[1-9]\d*)(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/.exec(literal);
|
|
24
|
-
if (!m)
|
|
25
|
-
return 'not a number';
|
|
26
|
-
const [, sign, whole, frac = '', exp = '0'] = m;
|
|
27
|
-
const v = Number(literal);
|
|
28
|
-
if (!Number.isFinite(v))
|
|
29
|
-
return 'past the largest double';
|
|
30
|
-
let digits = (whole + frac).replace(/^0+/, '');
|
|
31
|
-
if (v === 0) {
|
|
32
|
-
if (digits !== '')
|
|
33
|
-
return 'a value other than zero that rounds to zero';
|
|
34
|
-
return sign ? 'minus zero' : null;
|
|
35
|
-
}
|
|
36
|
-
// The exact value is digits times ten to e. A finite double bounds e from
|
|
37
|
-
// above, so the power below is never larger than the double's own width.
|
|
38
|
-
let e = BigInt(exp) - BigInt(frac.length);
|
|
39
|
-
const trimmed = digits.replace(/0+$/, '');
|
|
40
|
-
e += BigInt(digits.length - trimmed.length);
|
|
41
|
-
digits = trimmed;
|
|
42
|
-
if (e < 0n)
|
|
43
|
-
return null; // a fraction: the double nearest it, as every reader takes it
|
|
44
|
-
const exact = BigInt(digits) * 10n ** e;
|
|
45
|
-
if (exact === (v < 0 ? -BigInt(v) : BigInt(v)))
|
|
46
|
-
return null;
|
|
47
|
-
return literal === String(v) ? null : 'a whole number that is not exactly a double';
|
|
48
|
-
}
|
|
49
|
-
// Bytes to a value, or a throw.
|
|
50
|
-
export function readJson(input) {
|
|
51
|
-
const s = typeof input === 'string' ? input : utf8.decode(input);
|
|
52
|
-
let at = 0;
|
|
53
|
-
const space = () => {
|
|
54
|
-
for (;;) {
|
|
55
|
-
const c = s.charCodeAt(at);
|
|
56
|
-
if (c === 0x20 || c === 0x09 || c === 0x0a || c === 0x0d)
|
|
57
|
-
at += 1;
|
|
58
|
-
else
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
const string = () => {
|
|
63
|
-
const start = at;
|
|
64
|
-
at += 1;
|
|
65
|
-
for (;;) {
|
|
66
|
-
const c = s.charCodeAt(at);
|
|
67
|
-
if (Number.isNaN(c))
|
|
68
|
-
fail(start, 'an unterminated string');
|
|
69
|
-
if (c === 0x22)
|
|
70
|
-
break;
|
|
71
|
-
if (c < 0x20)
|
|
72
|
-
fail(at, 'a control character in a string');
|
|
73
|
-
at += c === 0x5c ? 2 : 1;
|
|
74
|
-
}
|
|
75
|
-
at += 1;
|
|
76
|
-
// The escapes are JSON's own, and the runtime reads them the one way.
|
|
77
|
-
return JSON.parse(s.slice(start, at));
|
|
78
|
-
};
|
|
79
|
-
const value = () => {
|
|
80
|
-
space();
|
|
81
|
-
const c = s[at];
|
|
82
|
-
if (c === '{') {
|
|
83
|
-
at += 1;
|
|
84
|
-
const out = {};
|
|
85
|
-
const keys = new Set();
|
|
86
|
-
space();
|
|
87
|
-
if (s[at] === '}') {
|
|
88
|
-
at += 1;
|
|
89
|
-
return out;
|
|
90
|
-
}
|
|
91
|
-
for (;;) {
|
|
92
|
-
space();
|
|
93
|
-
if (s[at] !== '"')
|
|
94
|
-
fail(at, 'a key that is not a string');
|
|
95
|
-
const where = at;
|
|
96
|
-
const k = string();
|
|
97
|
-
if (keys.has(k))
|
|
98
|
-
fail(where, `two keys named ${JSON.stringify(k)}`);
|
|
99
|
-
keys.add(k);
|
|
100
|
-
space();
|
|
101
|
-
if (s[at] !== ':')
|
|
102
|
-
fail(at, 'a key with no colon');
|
|
103
|
-
at += 1;
|
|
104
|
-
// Defined, never assigned: a key named `__proto__` is an own key here
|
|
105
|
-
// as it is in JSON.parse, and the value rule refuses it after.
|
|
106
|
-
Object.defineProperty(out, k, { value: value(), enumerable: true, writable: true, configurable: true });
|
|
107
|
-
space();
|
|
108
|
-
if (s[at] === ',')
|
|
109
|
-
at += 1;
|
|
110
|
-
else if (s[at] === '}') {
|
|
111
|
-
at += 1;
|
|
112
|
-
return out;
|
|
113
|
-
}
|
|
114
|
-
else
|
|
115
|
-
fail(at, 'an object not closed');
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (c === '[') {
|
|
119
|
-
at += 1;
|
|
120
|
-
const out = [];
|
|
121
|
-
space();
|
|
122
|
-
if (s[at] === ']') {
|
|
123
|
-
at += 1;
|
|
124
|
-
return out;
|
|
125
|
-
}
|
|
126
|
-
for (;;) {
|
|
127
|
-
out.push(value());
|
|
128
|
-
space();
|
|
129
|
-
if (s[at] === ',')
|
|
130
|
-
at += 1;
|
|
131
|
-
else if (s[at] === ']') {
|
|
132
|
-
at += 1;
|
|
133
|
-
return out;
|
|
134
|
-
}
|
|
135
|
-
else
|
|
136
|
-
fail(at, 'a list not closed');
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
if (c === '"')
|
|
140
|
-
return string();
|
|
141
|
-
for (const [word, v] of [['true', true], ['false', false], ['null', null]]) {
|
|
142
|
-
if (s.startsWith(word, at)) {
|
|
143
|
-
at += word.length;
|
|
144
|
-
return v;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
const m = /-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/y;
|
|
148
|
-
m.lastIndex = at;
|
|
149
|
-
const hit = m.exec(s);
|
|
150
|
-
if (!hit)
|
|
151
|
-
return fail(at, 'no value');
|
|
152
|
-
const why = numberFault(hit[0]);
|
|
153
|
-
if (why !== null)
|
|
154
|
-
fail(at, `${hit[0]} is ${why}`);
|
|
155
|
-
at += hit[0].length;
|
|
156
|
-
return Number(hit[0]);
|
|
157
|
-
};
|
|
158
|
-
const out = value();
|
|
159
|
-
space();
|
|
160
|
-
if (at !== s.length)
|
|
161
|
-
fail(at, 'text after the value');
|
|
162
|
-
return out;
|
|
163
|
-
}
|
package/dist/ward/owner.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { Ask, Asker, Json, JsonObject } from '../being/types.ts';
|
|
2
|
-
import type { Resident } from './ward.ts';
|
|
3
|
-
export type OwnerSide = {
|
|
4
|
-
pk: string;
|
|
5
|
-
doors: Map<string, Resident>;
|
|
6
|
-
absent(): Record<string, string | null>;
|
|
7
|
-
publicKey(): string | null;
|
|
8
|
-
instantiate(className: string, key: string): Resident | 'threw' | null;
|
|
9
|
-
unboot(key: string): string[] | null;
|
|
10
|
-
setPublic(key: string | null): void;
|
|
11
|
-
};
|
|
12
|
-
export declare const OWNER_ASKS: Ask[];
|
|
13
|
-
export declare function ownerAnswer(w: OwnerSide, asker: Asker, method: string | undefined, args: JsonObject): Promise<Json>;
|
package/dist/ward/owner.js
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The owner's asks. The root owner holds the ask pointer; every other owner
|
|
3
|
-
// is an occupant of the ward itself, invited by the root. The ward is a
|
|
4
|
-
// being to her owner: the empty ask is her describe, and it carries her asks
|
|
5
|
-
// with a description and an input each, so a side renders them as it
|
|
6
|
-
// renders any being's. Seven asks: boot, public, invite, knock, remove and
|
|
7
|
-
// unboot, which is boot's inverse and takes her relations with her, and ask,
|
|
8
|
-
// which reaches into a being and asks her. The knock is a being's knock made
|
|
9
|
-
// for her, and the standing is written into her cells under the id the owner
|
|
10
|
-
// gave; remove takes a relation out of her by id, the mirror of it.
|
|
11
|
-
import { isSilence, isWord, wordOf } from '../being/silence.js';
|
|
12
|
-
import { OWNER } from '../being/types.js';
|
|
13
|
-
import { put } from './partition.js';
|
|
14
|
-
import { seen, answered } from './door.js';
|
|
15
|
-
import { within, allow, DEFAULT, LATE } from './allowance.js';
|
|
16
|
-
const str = { type: 'string' };
|
|
17
|
-
export const OWNER_ASKS = [
|
|
18
|
-
{ name: 'boot', description: 'boot a being by class name, under a key the owner chooses', input: { type: 'object', properties: { key: str, class: str }, required: ['key', 'class'] } },
|
|
19
|
-
{ name: 'public', description: 'mark a booted being as the one public being of the ward, reached by anyone at the bare pk; null takes the mark off and leaves her booted', input: { type: 'object', properties: { key: str }, required: ['key'] } },
|
|
20
|
-
{ name: 'invite', description: 'mint an invitation on a being of the ward, under the id she will know the occupant by, with the notes she will read on it; on the ward pk it mints an owner, and only the root may', input: { type: 'object', properties: { being: str, id: str, notes: { type: 'object' } }, required: ['being', 'id'] } },
|
|
21
|
-
{
|
|
22
|
-
name: 'knock',
|
|
23
|
-
description: 'knock for a being of the ward with an invitation, and take the standing under id if answered; being is a key booted, or { boot: class, key } to boot her first',
|
|
24
|
-
input: { type: 'object', properties: { being: { description: 'a key, or { boot, key }' }, id: str, invitation: { type: 'object' }, method: str, args: { type: 'object' }, wanted: { type: 'object', properties: { time: { type: 'number' } } } }, required: ['being', 'id', 'invitation'] },
|
|
25
|
-
},
|
|
26
|
-
{ name: 'remove', description: 'take a relation out of a being of the ward by id, occupant or standing; on the ward pk it unseats an owner, and only the root may', input: { type: 'object', properties: { being: str, id: str }, required: ['being', 'id'] } },
|
|
27
|
-
{ name: 'unboot', description: 'take a being out of the ward, with every relation she holds; her occupants hear removed, and the ward itself is refused', input: { type: 'object', properties: { being: str }, required: ['being'] } },
|
|
28
|
-
{
|
|
29
|
-
name: 'ask',
|
|
30
|
-
description: 'ask a being of the ward, as the owner; with no being it is the public being asked as nobody, which is what a stranger would hear',
|
|
31
|
-
input: { type: 'object', properties: { being: str, method: str, args: { type: 'object' }, wanted: { type: 'object', properties: { time: { type: 'number' } } } } },
|
|
32
|
-
},
|
|
33
|
-
];
|
|
34
|
-
export async function ownerAnswer(w, asker, method, args) {
|
|
35
|
-
// Every name the owner gives is a string, or it is nothing. Coerced instead
|
|
36
|
-
// of checked, an object passed where a name belongs becomes the string
|
|
37
|
-
// "[object Object]", and two owners who each got the shape wrong would be
|
|
38
|
-
// handed one being. Not `word`: a word in this tree is what a ward says when
|
|
39
|
-
// no object came back, and this file imports those.
|
|
40
|
-
const named = (v) => (typeof v === 'string' ? v : null);
|
|
41
|
-
if (method === undefined)
|
|
42
|
-
return describe(w);
|
|
43
|
-
if (method === 'boot') {
|
|
44
|
-
const key = named(args.key), className = named(args.class);
|
|
45
|
-
if (key === null || className === null)
|
|
46
|
-
return { error: 'no such class, or key taken' };
|
|
47
|
-
const door = w.instantiate(className, key);
|
|
48
|
-
if (door === 'threw')
|
|
49
|
-
return { error: 'threw at birth' };
|
|
50
|
-
return door ? { booted: door.key } : { error: 'no such class, or key taken' };
|
|
51
|
-
}
|
|
52
|
-
if (method === 'public') {
|
|
53
|
-
// A ward may have one public being, and no more. Marking a second would
|
|
54
|
-
// leave the first holding every relation she had, reachable by nobody at
|
|
55
|
-
// the bare pk, and told by nobody that she had been replaced. One absent
|
|
56
|
-
// this run is reachable by nobody already, so the mark may move off her.
|
|
57
|
-
// Null takes the mark off: the being stays and keeps every relation she
|
|
58
|
-
// holds, and the ward answers arrivals for no heir with silence, as one
|
|
59
|
-
// that never had a public being does. Retiring her is not destroying her.
|
|
60
|
-
if (args.key === null) {
|
|
61
|
-
w.setPublic(null);
|
|
62
|
-
return { public: null };
|
|
63
|
-
}
|
|
64
|
-
const key = named(args.key);
|
|
65
|
-
if (key === null || key === w.pk || !w.doors.has(key))
|
|
66
|
-
return { error: 'no such being' };
|
|
67
|
-
const standing = w.publicKey();
|
|
68
|
-
if (standing !== null && standing !== key && w.doors.has(standing))
|
|
69
|
-
return { error: 'a ward has one public being' };
|
|
70
|
-
w.setPublic(key);
|
|
71
|
-
return { public: key };
|
|
72
|
-
}
|
|
73
|
-
if (method === 'invite') {
|
|
74
|
-
// On the ward itself, only the root may invite: an occupant of the ward
|
|
75
|
-
// is an owner, and ownership is minted by the ask pointer alone. An owner
|
|
76
|
-
// at the door asking to invite on the ward is refused, so that a carried
|
|
77
|
-
// key can pilot but never hand piloting on.
|
|
78
|
-
const being = named(args.being), id = named(args.id);
|
|
79
|
-
if (being === null || id === null)
|
|
80
|
-
return { error: 'no such being' };
|
|
81
|
-
if (being === w.pk && asker.id !== OWNER)
|
|
82
|
-
return { error: 'no such being' };
|
|
83
|
-
// The notes are the terms the owner mints under, and the being reads them
|
|
84
|
-
// on her gate. Placing an occupant is the owner's, and saying what it may
|
|
85
|
-
// do is part of placing it; the work behind the gate is still hers alone.
|
|
86
|
-
const notes = args.notes;
|
|
87
|
-
const door = w.doors.get(being);
|
|
88
|
-
if (!door)
|
|
89
|
-
return { error: 'no such being' };
|
|
90
|
-
return await door.stance.occupants.invite(id, notes !== null && typeof notes === 'object' && !Array.isArray(notes) ? (notes) : undefined);
|
|
91
|
-
}
|
|
92
|
-
if (method === 'knock') {
|
|
93
|
-
const b = args.being;
|
|
94
|
-
let door = typeof b === 'string' ? w.doors.get(b) : undefined;
|
|
95
|
-
if (!door && b && typeof b === 'object') {
|
|
96
|
-
// new or existing: the owner names a being of theirs, and a key already
|
|
97
|
-
// booted is a being of theirs, not a class that failed to instantiate.
|
|
98
|
-
const key = named(b.key), className = named(b.boot);
|
|
99
|
-
if (key === null || className === null)
|
|
100
|
-
return { error: 'no such being' };
|
|
101
|
-
const made = w.instantiate(className, key);
|
|
102
|
-
if (made === 'threw')
|
|
103
|
-
return { error: 'threw at birth' };
|
|
104
|
-
// Made or already there, the door is the one under the key she named:
|
|
105
|
-
// instantiate boots under that key or refuses, and never another.
|
|
106
|
-
door = w.doors.get(key);
|
|
107
|
-
}
|
|
108
|
-
const id = named(args.id);
|
|
109
|
-
// Never for the ward itself, for the reason invite refuses it: the ward
|
|
110
|
-
// is a being to nobody outside, and holds no relation of its own. A
|
|
111
|
-
// standing written into its cells would be the owner's reach dressed as
|
|
112
|
-
// a being's, and no ask of the ward's could ever use it.
|
|
113
|
-
if (!door || id === null || door.key === w.pk)
|
|
114
|
-
return { error: 'no such being' };
|
|
115
|
-
const inv = args.invitation;
|
|
116
|
-
// The owner is a caller like any other and may say what this knock may
|
|
117
|
-
// spend. Saying nothing is the ward's default, as it is for a being.
|
|
118
|
-
const out = await door.stance.standings.knock(inv, args.method, args.args ?? {}, args.wanted);
|
|
119
|
-
if (isSilence(out))
|
|
120
|
-
return { error: 'silence' };
|
|
121
|
-
if (isWord(out))
|
|
122
|
-
return { error: wordOf(out) }; // the owner hears objects: the word is the error's name
|
|
123
|
-
return { taken: await door.stance.standings.take(id, inv), answer: out };
|
|
124
|
-
}
|
|
125
|
-
if (method === 'remove') {
|
|
126
|
-
// The mirror of knock: a relation out of a being, by id, occupant or
|
|
127
|
-
// standing, since the two share one namespace. On the ward itself the
|
|
128
|
-
// id is an owner, and only the root may unseat one, for the reason only
|
|
129
|
-
// the root may invite one: ownership moves by the root alone.
|
|
130
|
-
const being = named(args.being), id = named(args.id);
|
|
131
|
-
if (being === null || id === null)
|
|
132
|
-
return { error: 'no such being' };
|
|
133
|
-
if (being === w.pk && asker.id !== OWNER)
|
|
134
|
-
return { error: 'no such being' };
|
|
135
|
-
const door = w.doors.get(being);
|
|
136
|
-
if (!door)
|
|
137
|
-
return { error: 'no such being' };
|
|
138
|
-
if (Object.hasOwn(door.cells.occupants, id))
|
|
139
|
-
door.stance.occupants.remove(id);
|
|
140
|
-
else if (Object.hasOwn(door.cells.standings, id))
|
|
141
|
-
door.stance.standings.remove(id);
|
|
142
|
-
else
|
|
143
|
-
return { error: 'nothing to remove' };
|
|
144
|
-
return { removed: id };
|
|
145
|
-
}
|
|
146
|
-
if (method === 'unboot') {
|
|
147
|
-
// The inverse of boot, and the only way a being leaves a ward. Her
|
|
148
|
-
// relations go with her, so an occupant of hers hears `removed` from the
|
|
149
|
-
// keys the door kept, exactly as it would had the owner removed each id
|
|
150
|
-
// by hand; the owner hears which ids those were. The ward itself is
|
|
151
|
-
// refused, for the reason knock is: it is a being to nobody outside, and
|
|
152
|
-
// unbooting it would be a ward deleting itself from inside its own map,
|
|
153
|
-
// leaving its owners bound to a door that is gone.
|
|
154
|
-
const being = named(args.being);
|
|
155
|
-
if (being === null || being === w.pk)
|
|
156
|
-
return { error: 'no such being' };
|
|
157
|
-
const removed = w.unboot(being);
|
|
158
|
-
return removed === null ? { error: 'no such being' } : { unbooted: being, removed };
|
|
159
|
-
}
|
|
160
|
-
if (method === 'ask') {
|
|
161
|
-
// The owner's other power: to reach into a being and ask her. It is
|
|
162
|
-
// strictly less than unboot, which takes her out with every relation she
|
|
163
|
-
// holds, and it is the third asker of the ward-to-being edge finally
|
|
164
|
-
// filled in by the ward rather than minted by whoever holds the pointer.
|
|
165
|
-
// Bounded, judged and named here, so no side outside the ward ever holds
|
|
166
|
-
// a being's answer and writes the door's discipline again beside it.
|
|
167
|
-
const being = args.being === undefined ? null : named(args.being);
|
|
168
|
-
if (args.being !== undefined && being === null)
|
|
169
|
-
return { error: 'no such being' };
|
|
170
|
-
// A method is a name or it is the empty ask. Coerced instead of checked,
|
|
171
|
-
// a shape passed where a name belongs becomes a string she never declared,
|
|
172
|
-
// and she would answer `unknown ask` to something nobody asked.
|
|
173
|
-
if (args.method !== undefined && typeof args.method !== 'string')
|
|
174
|
-
return { error: 'an ask is named by a word' };
|
|
175
|
-
// No being named is the in-process twin of bytes for nobody: the public
|
|
176
|
-
// being, asked as nobody, unbound, so a throw of hers is silence. Her
|
|
177
|
-
// insides are not a stranger's to read, and a device serving her to
|
|
178
|
-
// strangers must hear what a stranger hears and not one word more.
|
|
179
|
-
const key = being ?? w.publicKey();
|
|
180
|
-
const door = key === null ? undefined : w.doors.get(key);
|
|
181
|
-
if (!door || door.key === w.pk)
|
|
182
|
-
return { error: 'no such being' };
|
|
183
|
-
const bound = being !== null;
|
|
184
|
-
// The owner is a caller like any other: wanted says what this ask may
|
|
185
|
-
// spend, and saying nothing is the ward's default. A wait that ran out is
|
|
186
|
-
// late, the same word a being would hear, said as the object an owner hears.
|
|
187
|
-
const out = await within(allow(args.wanted).time, answered(door, bound ? { id: OWNER } : {}, args.method, args.args ?? {}, bound));
|
|
188
|
-
if (out === LATE)
|
|
189
|
-
return { error: 'late' };
|
|
190
|
-
if ('quo' in out)
|
|
191
|
-
return { error: out.quo };
|
|
192
|
-
if (!('object' in out))
|
|
193
|
-
return { error: 'silence' };
|
|
194
|
-
return out.object;
|
|
195
|
-
}
|
|
196
|
-
return { error: 'unknown ask' };
|
|
197
|
-
}
|
|
198
|
-
// The ward's describe for its owner: its beings, their classes, a digest each,
|
|
199
|
-
// as she would describe herself to the owner. A being absent this run is
|
|
200
|
-
// listed too, with a null digest and absent true, so the owner can see her
|
|
201
|
-
// and take her out.
|
|
202
|
-
async function describe(w) {
|
|
203
|
-
const beings = {};
|
|
204
|
-
// Every being is asked at once and each is bounded on her own. One being
|
|
205
|
-
// whose describe never settles is one null digest, not a ward that never
|
|
206
|
-
// answers its owner: the harbor learns the pk by this very ask at boot, so
|
|
207
|
-
// an unbounded wait here is a ward no restart can bring back.
|
|
208
|
-
const asked = [...w.doors].filter(([key]) => key !== w.pk);
|
|
209
|
-
const digests = await Promise.all(asked.map(async ([, door]) => (await within(DEFAULT.time, seen(door, { id: OWNER })))));
|
|
210
|
-
for (const [i, [key, door]] of asked.entries()) {
|
|
211
|
-
const d = digests[i];
|
|
212
|
-
put(beings, key, { class: door.cells.class ?? null, public: w.publicKey() === key, digest: d === LATE ? null : d });
|
|
213
|
-
}
|
|
214
|
-
for (const [key, cls] of Object.entries(w.absent()))
|
|
215
|
-
put(beings, key, { class: cls, public: w.publicKey() === key, digest: null, absent: true });
|
|
216
|
-
return {
|
|
217
|
-
asks: OWNER_ASKS,
|
|
218
|
-
notes: { pk: w.pk, beings },
|
|
219
|
-
};
|
|
220
|
-
}
|
package/dist/ward/seal.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { DoorWord, Json, JsonObject } from '../being/types.ts';
|
|
2
|
-
export type WardKey = {
|
|
3
|
-
sign: Uint8Array;
|
|
4
|
-
padlock: Uint8Array;
|
|
5
|
-
signPk: Uint8Array;
|
|
6
|
-
padlockPk: Uint8Array;
|
|
7
|
-
pk: string;
|
|
8
|
-
};
|
|
9
|
-
export declare const SIZE: number;
|
|
10
|
-
export declare function wardKey(seed: string | Uint8Array): Promise<WardKey>;
|
|
11
|
-
export declare const wardSignPk: (pk: string) => Uint8Array;
|
|
12
|
-
export declare const wardPadlock: (pk: string) => Uint8Array;
|
|
13
|
-
export declare const isWardPk: (pk: unknown) => pk is string;
|
|
14
|
-
export declare const isHex: (v: unknown) => v is string;
|
|
15
|
-
export declare function beingKey(seed: Uint8Array): Promise<{
|
|
16
|
-
seed: string;
|
|
17
|
-
pk: string;
|
|
18
|
-
}>;
|
|
19
|
-
export type AskPayload = {
|
|
20
|
-
by: string;
|
|
21
|
-
next: string | null;
|
|
22
|
-
seq: number;
|
|
23
|
-
time: number;
|
|
24
|
-
hops?: number;
|
|
25
|
-
method?: string;
|
|
26
|
-
args: JsonObject;
|
|
27
|
-
};
|
|
28
|
-
export type ReplyPayload = {
|
|
29
|
-
object: Json;
|
|
30
|
-
seen: string | null;
|
|
31
|
-
} | {
|
|
32
|
-
silence: true;
|
|
33
|
-
} | {
|
|
34
|
-
quo: DoorWord;
|
|
35
|
-
};
|
|
36
|
-
export declare function sealAsk(to: string | null, payload: AskPayload, signer: Uint8Array, padlock: Uint8Array, seed: Uint8Array): Promise<{
|
|
37
|
-
bytes: Uint8Array;
|
|
38
|
-
ephemeral: Uint8Array;
|
|
39
|
-
}>;
|
|
40
|
-
export declare function openAsk(bytes: Uint8Array, padlockSecret: Uint8Array): Promise<{
|
|
41
|
-
to: string | null;
|
|
42
|
-
payload: AskPayload;
|
|
43
|
-
body: Uint8Array;
|
|
44
|
-
signature: Uint8Array;
|
|
45
|
-
ephemeralPk: Uint8Array;
|
|
46
|
-
} | null>;
|
|
47
|
-
export declare const verifyAsk: (a: {
|
|
48
|
-
body: Uint8Array;
|
|
49
|
-
signature: Uint8Array;
|
|
50
|
-
}, pk: string) => Promise<boolean>;
|
|
51
|
-
export declare function sealReply(reply: ReplyPayload, ephemeralPk: Uint8Array, wardSign: Uint8Array, seed: Uint8Array): Promise<Uint8Array>;
|
|
52
|
-
export declare function openReply(bytes: unknown, ephemeralSecret: Uint8Array, signPk: Uint8Array): Promise<ReplyPayload | null>;
|