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/being/lent.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Being } from './being.ts';
|
|
2
|
-
import type { Asker, Blueprint, JsonObject, Reply } from './types.ts';
|
|
3
|
-
export declare const BOX = "box";
|
|
4
|
-
export declare const LENT_ASKS: {
|
|
5
|
-
offer: {
|
|
6
|
-
name: string;
|
|
7
|
-
description: string;
|
|
8
|
-
input: {
|
|
9
|
-
type: string;
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
retract: {
|
|
13
|
-
name: string;
|
|
14
|
-
description: string;
|
|
15
|
-
input: {
|
|
16
|
-
type: string;
|
|
17
|
-
properties: {
|
|
18
|
-
heir: {
|
|
19
|
-
type: string;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
required: string[];
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
export declare class Lent extends Being {
|
|
27
|
-
#private;
|
|
28
|
-
offer(): Promise<JsonObject>;
|
|
29
|
-
retract(args: JsonObject): JsonObject;
|
|
30
|
-
describe(asker: Asker): Blueprint;
|
|
31
|
-
answer(asker: Asker, method?: string, args?: JsonObject): Promise<Reply>;
|
|
32
|
-
}
|
package/dist/being/lent.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// A lent being: a being of the box's own ward, standing for one thing the
|
|
3
|
-
// device can do. What makes her one is two asks the box's being alone may
|
|
4
|
-
// make, whom she knows as the occupant `box`. `offer`: she mints an
|
|
5
|
-
// invitation on herself and answers it, so that a ward the box vouches for
|
|
6
|
-
// may knock and take a standing at her. `retract`: an offer that was not
|
|
7
|
-
// taken, named by its heir, is removed, so a refused lend leaves nothing.
|
|
8
|
-
//
|
|
9
|
-
// The two are the base's and never a subclass's to declare: a class says
|
|
10
|
-
// her own asks and nothing of the seam she is lent through, so they are
|
|
11
|
-
// answered here before her asks are read, and shown to the box alone. No
|
|
12
|
-
// root mints for her, and nothing else about her is decided here.
|
|
13
|
-
//
|
|
14
|
-
// A convenience, not a contract: a being that answers the two the same way
|
|
15
|
-
// to `box` is lendable, whatever she extends.
|
|
16
|
-
import { Being } from './being.js';
|
|
17
|
-
// The one word for the box's being: her key in the box's ward, the id every
|
|
18
|
-
// lent being knows her by, and the standing every hosted ward takes at
|
|
19
|
-
// birth.
|
|
20
|
-
export const BOX = 'box';
|
|
21
|
-
export const LENT_ASKS = {
|
|
22
|
-
offer: { name: 'offer', description: 'an invitation on me, for a ward the box vouches for', input: { type: 'object' } },
|
|
23
|
-
retract: { name: 'retract', description: 'an offer that was not taken, by its heir', input: { type: 'object', properties: { heir: { type: 'string' } }, required: ['heir'] } },
|
|
24
|
-
};
|
|
25
|
-
export class Lent extends Being {
|
|
26
|
-
// The offers she has open, heir to the id she minted under.
|
|
27
|
-
#open() {
|
|
28
|
-
return (this.cells.open ??= {});
|
|
29
|
-
}
|
|
30
|
-
async offer() {
|
|
31
|
-
const n = (this.cells.lent ?? 0) + 1;
|
|
32
|
-
this.cells.lent = n;
|
|
33
|
-
const id = `lent:${n}`;
|
|
34
|
-
const inv = await this.invite(id);
|
|
35
|
-
if (inv === null)
|
|
36
|
-
return { error: 'could not mint' };
|
|
37
|
-
this.#open()[inv.heir] = id;
|
|
38
|
-
return inv;
|
|
39
|
-
}
|
|
40
|
-
retract(args) {
|
|
41
|
-
const open = this.#open();
|
|
42
|
-
const heir = typeof args.heir === 'string' ? args.heir : '';
|
|
43
|
-
const id = Object.hasOwn(open, heir) ? open[heir] : undefined;
|
|
44
|
-
if (id === undefined)
|
|
45
|
-
return { retracted: null };
|
|
46
|
-
this.occupants.remove(id);
|
|
47
|
-
delete open[heir];
|
|
48
|
-
return { retracted: id };
|
|
49
|
-
}
|
|
50
|
-
describe(asker) {
|
|
51
|
-
const bp = super.describe(asker);
|
|
52
|
-
if (asker.id !== BOX)
|
|
53
|
-
return bp;
|
|
54
|
-
return { ...bp, asks: [...bp.asks, LENT_ASKS.offer, LENT_ASKS.retract] };
|
|
55
|
-
}
|
|
56
|
-
// An offer is open until it is taken or retracted. The taker's knock is the
|
|
57
|
-
// first word she hears from the occupant she minted for it, so hearing
|
|
58
|
-
// from that id closes the offer, and `open` holds only offers still
|
|
59
|
-
// waiting and not every lend she ever made.
|
|
60
|
-
async answer(asker, method, args = {}) {
|
|
61
|
-
const open = this.cells.open;
|
|
62
|
-
if (open && asker.id !== undefined && asker.id !== BOX)
|
|
63
|
-
for (const [heir, id] of Object.entries(open))
|
|
64
|
-
if (id === asker.id)
|
|
65
|
-
delete open[heir];
|
|
66
|
-
if (asker.id === BOX && method === 'offer')
|
|
67
|
-
return this.offer();
|
|
68
|
-
if (asker.id === BOX && method === 'retract')
|
|
69
|
-
return this.retract(args);
|
|
70
|
-
return super.answer(asker, method, args);
|
|
71
|
-
}
|
|
72
|
-
}
|
package/dist/being/silence.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { type DoorWord, type Unreached, type Word, type WordName } from './types.ts';
|
|
2
|
-
export declare const silence: unique symbol;
|
|
3
|
-
export declare const isSilence: (x: unknown) => x is typeof silence;
|
|
4
|
-
export declare const DOOR_WORDS: readonly DoorWord[];
|
|
5
|
-
export declare const isDoorWord: (s: unknown) => s is DoorWord;
|
|
6
|
-
export declare const word: <W extends WordName>(name: W) => Word<W>;
|
|
7
|
-
export declare const isWord: (x: unknown) => x is Word;
|
|
8
|
-
export declare const wordOf: (x: Word) => WordName;
|
|
9
|
-
export declare const answered: <T>(x: T) => x is Exclude<T, typeof silence | Word>;
|
|
10
|
-
export declare const told: (x: unknown) => unknown;
|
|
11
|
-
export declare const unreached: () => Unreached;
|
|
12
|
-
export declare const isUnreached: (x: unknown) => x is Unreached;
|
package/dist/being/silence.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// Silence is one distinguished value. Null is an answer. Silence is no answer.
|
|
3
|
-
//
|
|
4
|
-
// The ward's words are the other distinguished values: what her ward tells
|
|
5
|
-
// her when no object came back and it knows why. Each is one frozen object
|
|
6
|
-
// under one symbol key, so a being cannot make one by accident, none of them
|
|
7
|
-
// crosses an edge as a value, and a being who compares against them needs
|
|
8
|
-
// no fourth shape. `unreached` is one of them.
|
|
9
|
-
import { WORD_KEY } from './types.js';
|
|
10
|
-
export const silence = Symbol.for('quo.silence');
|
|
11
|
-
export const isSilence = (x) => x === silence;
|
|
12
|
-
// The words a door says to a key it has bound, and no other. They ride on
|
|
13
|
-
// the wire as `{ quo: word }`, so a reply is checked against this list.
|
|
14
|
-
export const DOOR_WORDS = ['removed', 'absent', 'unannounced', 'repeated', 'threw'];
|
|
15
|
-
export const isDoorWord = (s) => typeof s === 'string' && DOOR_WORDS.includes(s);
|
|
16
|
-
const WORDS = new Map();
|
|
17
|
-
export const word = (name) => {
|
|
18
|
-
let w = WORDS.get(name);
|
|
19
|
-
if (!w)
|
|
20
|
-
WORDS.set(name, (w = Object.freeze({ [WORD_KEY]: name })));
|
|
21
|
-
return w;
|
|
22
|
-
};
|
|
23
|
-
export const isWord = (x) => x !== null && typeof x === 'object' && typeof x[WORD_KEY] === 'string';
|
|
24
|
-
export const wordOf = (x) => x[WORD_KEY];
|
|
25
|
-
// What came back is an answer and not one of the two things that are not
|
|
26
|
-
// answers. A being who only wants the object writes one test instead of
|
|
27
|
-
// three, and the three shapes stay three shapes: silence is no answer, a word
|
|
28
|
-
// is her ward telling her why there is none.
|
|
29
|
-
export const answered = (x) => !isSilence(x) && !isWord(x);
|
|
30
|
-
// What she was told, with a word given its name and everything else left
|
|
31
|
-
// exactly as it came. One value to compare against, so asking which word came
|
|
32
|
-
// back is one test and not two joined by an and: `told(out) === 'late'` says
|
|
33
|
-
// what `isWord(out) && wordOf(out) === 'late'` says, and says which answer
|
|
34
|
-
// arrived instead when it is wrong, where the pair collapses to false and
|
|
35
|
-
// names nothing. Silence stays the symbol it is, and an object stays itself.
|
|
36
|
-
export const told = (x) => (isWord(x) ? wordOf(x) : x);
|
|
37
|
-
// Unreached: no far door was reached. Nothing is known to have been
|
|
38
|
-
// delivered, so asking again is safe. A being cannot produce it: a ward that
|
|
39
|
-
// sees a word come out of a being reads it as her having thrown.
|
|
40
|
-
export const unreached = () => word('unreached');
|
|
41
|
-
export const isUnreached = (x) => isWord(x) && wordOf(x) === 'unreached';
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export declare class Failed extends Error {
|
|
2
|
-
}
|
|
3
|
-
export declare function same(a: unknown, b: unknown): boolean;
|
|
4
|
-
export type Assert = {
|
|
5
|
-
ok(value: unknown, message?: string): asserts value;
|
|
6
|
-
equal(actual: unknown, expected: unknown, message?: string): void;
|
|
7
|
-
notEqual(actual: unknown, expected: unknown, message?: string): void;
|
|
8
|
-
deepEqual(actual: unknown, expected: unknown, message?: string): void;
|
|
9
|
-
match(actual: string, re: RegExp, message?: string): void;
|
|
10
|
-
};
|
|
11
|
-
export declare const assert: Assert;
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The five assertions the conformance suite makes, and no more. Node has all
|
|
3
|
-
// five in `node:assert/strict`, and naming that module would tie the suite to
|
|
4
|
-
// one terrain -- the suite is the ward's truth, and the ward's truth has to be
|
|
5
|
-
// checkable wherever a ward runs. So they are written here, in the language
|
|
6
|
-
// alone, and `test/assert.test.ts` holds them to Node's own behaviour.
|
|
7
|
-
export class Failed extends Error {
|
|
8
|
-
}
|
|
9
|
-
const show = (v) => {
|
|
10
|
-
if (typeof v === 'symbol')
|
|
11
|
-
return v.toString();
|
|
12
|
-
if (typeof v === 'bigint')
|
|
13
|
-
return `${v}n`;
|
|
14
|
-
if (v === undefined)
|
|
15
|
-
return 'undefined';
|
|
16
|
-
if (typeof v === 'function')
|
|
17
|
-
return `[function ${v.name}]`;
|
|
18
|
-
// A ward's word is a frozen object under one symbol key, and JSON shows it
|
|
19
|
-
// as `{}`. A red estate chapter saying `{} is not {}` names nothing, so a
|
|
20
|
-
// value whose own keys are all symbols is shown by its keys.
|
|
21
|
-
if (v !== null && typeof v === 'object') {
|
|
22
|
-
const keys = Object.keys(v);
|
|
23
|
-
const syms = Object.getOwnPropertySymbols(v).filter((s) => Object.getOwnPropertyDescriptor(v, s).enumerable);
|
|
24
|
-
if (keys.length === 0 && syms.length > 0)
|
|
25
|
-
return `{ ${syms.map((s) => `${s.toString()}: ${show(v[s])}`).join(', ')} }`;
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
return JSON.stringify(v) ?? Object.prototype.toString.call(v);
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return Object.prototype.toString.call(v); // a cycle, or a null prototype
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
const fail = (why, message) => {
|
|
35
|
-
throw new Failed(message ? `${message}: ${why}` : why);
|
|
36
|
-
};
|
|
37
|
-
// Structural, and strict about shape the way `node:assert/strict` is: a value
|
|
38
|
-
// is not equal to one of another kind, and an array is not equal to an object
|
|
39
|
-
// that happens to hold the same keys.
|
|
40
|
-
// The four kinds this compares, and every other object is refused rather than
|
|
41
|
-
// guessed at. A Date, a RegExp, a boxed primitive and a class instance each
|
|
42
|
-
// carry state no key walk can see, so two of them with the same keys are
|
|
43
|
-
// equal here and unequal in node, which is a wrong yes: the one answer a
|
|
44
|
-
// suite must never give. A refusal is a red test that says so.
|
|
45
|
-
const KNOWN = [Object.prototype, null, Array.prototype, Uint8Array.prototype];
|
|
46
|
-
// What node compares: own enumerable keys, strings then enumerable symbols.
|
|
47
|
-
// Not `Reflect.ownKeys`, which also lists what a definition hid.
|
|
48
|
-
const keysOf = (v) => [...Object.keys(v), ...Object.getOwnPropertySymbols(v).filter((s) => Object.getOwnPropertyDescriptor(v, s).enumerable)];
|
|
49
|
-
export function same(a, b) {
|
|
50
|
-
if (Object.is(a, b))
|
|
51
|
-
return true;
|
|
52
|
-
if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)
|
|
53
|
-
return false;
|
|
54
|
-
const proto = Object.getPrototypeOf(a);
|
|
55
|
-
if (proto !== Object.getPrototypeOf(b))
|
|
56
|
-
return false;
|
|
57
|
-
if (!KNOWN.includes(proto))
|
|
58
|
-
return false; // a Date, a RegExp, a boxed number, a class of hers
|
|
59
|
-
if (Array.isArray(a) !== Array.isArray(b))
|
|
60
|
-
return false;
|
|
61
|
-
if (a instanceof Uint8Array && b instanceof Uint8Array)
|
|
62
|
-
return a.length === b.length && a.every((x, i) => x === b[i]);
|
|
63
|
-
// An array is its indices and whatever else was hung on it, and a hole is
|
|
64
|
-
// not a present undefined: `[, 1]` and `[undefined, 1]` differ in node and
|
|
65
|
-
// must differ here. `every` skips holes, so the loop is written out.
|
|
66
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
67
|
-
if (a.length !== b.length)
|
|
68
|
-
return false;
|
|
69
|
-
for (let i = 0; i < a.length; i += 1) {
|
|
70
|
-
if (i in a !== i in b)
|
|
71
|
-
return false;
|
|
72
|
-
if (i in a && !same(a[i], b[i]))
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
const extra = (v) => keysOf(v).filter((k) => typeof k !== 'string' || !/^(?:0|[1-9]\d*)$/.test(k));
|
|
76
|
-
const xa = extra(a), xb = extra(b);
|
|
77
|
-
const at = (v, k) => v[k];
|
|
78
|
-
return xa.length === xb.length && xa.every((k) => xb.includes(k) && same(at(a, k), at(b, k)));
|
|
79
|
-
}
|
|
80
|
-
const ka = keysOf(a), kb = keysOf(b);
|
|
81
|
-
if (ka.length !== kb.length)
|
|
82
|
-
return false;
|
|
83
|
-
return ka.every((k) => kb.includes(k) && same(a[k], b[k]));
|
|
84
|
-
}
|
|
85
|
-
export const assert = {
|
|
86
|
-
ok(value, message) {
|
|
87
|
-
if (!value)
|
|
88
|
-
fail(`${show(value)} is not truthy`, message);
|
|
89
|
-
},
|
|
90
|
-
equal(actual, expected, message) {
|
|
91
|
-
if (!Object.is(actual, expected))
|
|
92
|
-
fail(`${show(actual)} !== ${show(expected)}`, message);
|
|
93
|
-
},
|
|
94
|
-
notEqual(actual, expected, message) {
|
|
95
|
-
if (Object.is(actual, expected))
|
|
96
|
-
fail(`${show(actual)} === ${show(expected)}`, message);
|
|
97
|
-
},
|
|
98
|
-
deepEqual(actual, expected, message) {
|
|
99
|
-
if (!same(actual, expected))
|
|
100
|
-
fail(`${show(actual)} is not ${show(expected)}`, message);
|
|
101
|
-
},
|
|
102
|
-
match(actual, re, message) {
|
|
103
|
-
if (typeof actual !== 'string' || !re.test(actual))
|
|
104
|
-
fail(`${show(actual)} does not match ${String(re)}`, message);
|
|
105
|
-
},
|
|
106
|
-
};
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { Being } from '../being/being.ts';
|
|
2
|
-
import { Lent } from '../being/lent.ts';
|
|
3
|
-
import type { Asker, Blueprint, Invitation, Json, JsonObject, OccupantRecord, Reply, Stance } from '../being/types.ts';
|
|
4
|
-
export declare class Printer extends Being {
|
|
5
|
-
static cells: {
|
|
6
|
-
jobs: JsonObject[];
|
|
7
|
-
asks: JsonObject[];
|
|
8
|
-
};
|
|
9
|
-
static asks: {
|
|
10
|
-
print: {
|
|
11
|
-
input: {
|
|
12
|
-
type: string;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
describe(): Blueprint;
|
|
17
|
-
print({ doc }: JsonObject, asker: Asker): {
|
|
18
|
-
printed: string | number | boolean | Json[] | {
|
|
19
|
-
[key: string]: Json;
|
|
20
|
-
} | null;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
export declare class Shop extends Being {
|
|
24
|
-
static cells: {
|
|
25
|
-
printerId: string | null;
|
|
26
|
-
sales: JsonObject[];
|
|
27
|
-
minted: number;
|
|
28
|
-
};
|
|
29
|
-
static asks: {
|
|
30
|
-
hello: {
|
|
31
|
-
input: {
|
|
32
|
-
type: string;
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
buy: {
|
|
36
|
-
input: {
|
|
37
|
-
type: string;
|
|
38
|
-
properties: {
|
|
39
|
-
item: {
|
|
40
|
-
type: string;
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
refund: {
|
|
46
|
-
input: {
|
|
47
|
-
type: string;
|
|
48
|
-
};
|
|
49
|
-
for: (rec: OccupantRecord | undefined) => boolean;
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
|
-
answer(asker: Asker, method?: string, args?: JsonObject): Promise<Reply>;
|
|
53
|
-
invite(tier?: string): Promise<Invitation>;
|
|
54
|
-
keepPrinter(invitation: Invitation): Promise<boolean>;
|
|
55
|
-
hello({ invitation }: JsonObject, asker: Asker): Promise<{
|
|
56
|
-
welcome: boolean;
|
|
57
|
-
}>;
|
|
58
|
-
buy({ item }: JsonObject, asker: Asker): Promise<{
|
|
59
|
-
error: string;
|
|
60
|
-
retry?: undefined;
|
|
61
|
-
ok?: undefined;
|
|
62
|
-
receipt?: undefined;
|
|
63
|
-
} | {
|
|
64
|
-
error: string;
|
|
65
|
-
retry: boolean;
|
|
66
|
-
ok?: undefined;
|
|
67
|
-
receipt?: undefined;
|
|
68
|
-
} | {
|
|
69
|
-
error?: undefined;
|
|
70
|
-
retry?: undefined;
|
|
71
|
-
ok: boolean;
|
|
72
|
-
receipt: Json;
|
|
73
|
-
}>;
|
|
74
|
-
refund(): {
|
|
75
|
-
ok: boolean;
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
export declare class Customer extends Being {
|
|
79
|
-
static cells: {
|
|
80
|
-
heard: JsonObject[];
|
|
81
|
-
};
|
|
82
|
-
static asks: {
|
|
83
|
-
hi: {
|
|
84
|
-
input: {
|
|
85
|
-
type: string;
|
|
86
|
-
};
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
join(invitation: Invitation): Promise<string | number | boolean | typeof import("../being/silence.ts").silence | Json[] | import("../being/types.ts").Word<import("../being/types.ts").WordName> | {
|
|
90
|
-
[key: string]: Json;
|
|
91
|
-
} | null>;
|
|
92
|
-
buy(item: string): Promise<import("../being/types.ts").Answer>;
|
|
93
|
-
learn(): Promise<import("../being/types.ts").Answer>;
|
|
94
|
-
hi(_args: JsonObject, asker: Asker): {
|
|
95
|
-
heard: string;
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
export declare class Echo {
|
|
99
|
-
s: Stance;
|
|
100
|
-
constructor(stance: Stance);
|
|
101
|
-
answer(asker: Asker, method?: string, args?: JsonObject): Reply;
|
|
102
|
-
}
|
|
103
|
-
export declare class Maker extends Being {
|
|
104
|
-
static cells: {
|
|
105
|
-
made: string[];
|
|
106
|
-
};
|
|
107
|
-
static asks: {
|
|
108
|
-
open: {
|
|
109
|
-
input: {
|
|
110
|
-
type: string;
|
|
111
|
-
properties: {
|
|
112
|
-
class: {
|
|
113
|
-
type: string;
|
|
114
|
-
};
|
|
115
|
-
key: {
|
|
116
|
-
type: string;
|
|
117
|
-
};
|
|
118
|
-
id: {
|
|
119
|
-
type: string;
|
|
120
|
-
};
|
|
121
|
-
};
|
|
122
|
-
required: string[];
|
|
123
|
-
};
|
|
124
|
-
};
|
|
125
|
-
say: {
|
|
126
|
-
input: {
|
|
127
|
-
type: string;
|
|
128
|
-
properties: {
|
|
129
|
-
id: {
|
|
130
|
-
type: string;
|
|
131
|
-
};
|
|
132
|
-
};
|
|
133
|
-
required: string[];
|
|
134
|
-
};
|
|
135
|
-
};
|
|
136
|
-
borrow: {
|
|
137
|
-
input: {
|
|
138
|
-
type: string;
|
|
139
|
-
properties: {
|
|
140
|
-
name: {
|
|
141
|
-
type: string;
|
|
142
|
-
};
|
|
143
|
-
id: {
|
|
144
|
-
type: string;
|
|
145
|
-
};
|
|
146
|
-
};
|
|
147
|
-
required: string[];
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
|
-
};
|
|
151
|
-
open({ class: className, key, id }: JsonObject): Promise<{
|
|
152
|
-
made: string | null;
|
|
153
|
-
}>;
|
|
154
|
-
say({ id }: JsonObject): Promise<{
|
|
155
|
-
said: Json;
|
|
156
|
-
}>;
|
|
157
|
-
borrow({ name, id }: JsonObject): Promise<{
|
|
158
|
-
lent: string | null;
|
|
159
|
-
}>;
|
|
160
|
-
}
|
|
161
|
-
export declare class Member extends Lent {
|
|
162
|
-
static cells: {
|
|
163
|
-
heard: JsonObject[];
|
|
164
|
-
};
|
|
165
|
-
static asks: {
|
|
166
|
-
ping: {
|
|
167
|
-
input: {
|
|
168
|
-
type: string;
|
|
169
|
-
};
|
|
170
|
-
};
|
|
171
|
-
relay: {
|
|
172
|
-
input: {
|
|
173
|
-
type: string;
|
|
174
|
-
properties: {
|
|
175
|
-
id: {
|
|
176
|
-
type: string;
|
|
177
|
-
};
|
|
178
|
-
method: {
|
|
179
|
-
type: string;
|
|
180
|
-
};
|
|
181
|
-
time: {
|
|
182
|
-
type: string;
|
|
183
|
-
};
|
|
184
|
-
};
|
|
185
|
-
required: string[];
|
|
186
|
-
};
|
|
187
|
-
};
|
|
188
|
-
};
|
|
189
|
-
ping(_args: JsonObject, asker: Asker): {
|
|
190
|
-
pong: string | null;
|
|
191
|
-
};
|
|
192
|
-
relay({ id, method, args, time }: JsonObject): Promise<{
|
|
193
|
-
said: string;
|
|
194
|
-
out: null;
|
|
195
|
-
} | {
|
|
196
|
-
said: null;
|
|
197
|
-
out: Json;
|
|
198
|
-
}>;
|
|
199
|
-
}
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The fixture beings. Fixed, so that the ward is what varies. A printer, a
|
|
3
|
-
// shop, a customer on the base class, a maker, a member, and one raw being
|
|
4
|
-
// with no base at all.
|
|
5
|
-
import { Being } from '../being/being.js';
|
|
6
|
-
import { Lent } from '../being/lent.js';
|
|
7
|
-
import { answered, isSilence, isUnreached, isWord, wordOf } from '../being/silence.js';
|
|
8
|
-
import { invitationArgs } from '../being/types.js';
|
|
9
|
-
// A printer. Invites whom she is told to, prints for her occupants. Her
|
|
10
|
-
// blueprint lives in her cells so a test can change her shape.
|
|
11
|
-
export class Printer extends Being {
|
|
12
|
-
static cells = { jobs: [], asks: [{ name: 'print', input: { type: 'object' } }] };
|
|
13
|
-
static asks = { print: { input: { type: 'object' } } };
|
|
14
|
-
describe() {
|
|
15
|
-
// Her own cells, which a test writes to change her shape. Cells are Json
|
|
16
|
-
// to the ward, so the asks are named for what she keeps in them.
|
|
17
|
-
return { asks: this.cells.asks, notes: { model: 'LX-2' } };
|
|
18
|
-
}
|
|
19
|
-
print({ doc }, asker) {
|
|
20
|
-
this.cells.jobs.push({ by: asker.id ?? null, doc: doc ?? null });
|
|
21
|
-
return { printed: doc ?? null };
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
// A shop. Invites customers in her own time. Keeps a printer as a standing.
|
|
25
|
-
// Takes a gold customer back if the customer offers a way. Counts every ask
|
|
26
|
-
// per occupant, by wrapping answer.
|
|
27
|
-
export class Shop extends Being {
|
|
28
|
-
static cells = { printerId: null, sales: [], minted: 0 };
|
|
29
|
-
static asks = {
|
|
30
|
-
hello: { input: { type: 'object' } },
|
|
31
|
-
buy: { input: { type: 'object', properties: { item: { type: 'string' } } } },
|
|
32
|
-
refund: { input: { type: 'object' }, for: (rec) => rec?.notes.tier === 'gold' },
|
|
33
|
-
};
|
|
34
|
-
async answer(asker, method, args) {
|
|
35
|
-
const rec = this.occupant(asker);
|
|
36
|
-
if (rec && method !== undefined)
|
|
37
|
-
rec.notes.asks = (Number(rec.notes.asks) || 0) + 1;
|
|
38
|
-
return super.answer(asker, method, args);
|
|
39
|
-
}
|
|
40
|
-
// Outside any ask. She mints, her ward seals, she hands it out by mail.
|
|
41
|
-
async invite(tier = 'plain') {
|
|
42
|
-
const id = `cust${++this.cells.minted}`;
|
|
43
|
-
const inv = (await super.invite(id));
|
|
44
|
-
this.cells.occupants[id].notes.tier = tier;
|
|
45
|
-
return inv;
|
|
46
|
-
}
|
|
47
|
-
async keepPrinter(invitation) {
|
|
48
|
-
const bp = await this.knock(invitation);
|
|
49
|
-
if (!answered(bp))
|
|
50
|
-
return false;
|
|
51
|
-
this.cells.printerId = await this.take('prn', invitation);
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
async hello({ invitation }, asker) {
|
|
55
|
-
const rec = this.occupant(asker);
|
|
56
|
-
if (rec?.notes.tier === 'gold' && invitation) {
|
|
57
|
-
const back = await this.knock(invitation, 'hi');
|
|
58
|
-
if (answered(back))
|
|
59
|
-
await this.take(`vip-${asker.id}`, invitation);
|
|
60
|
-
}
|
|
61
|
-
return { welcome: true };
|
|
62
|
-
}
|
|
63
|
-
async buy({ item }, asker) {
|
|
64
|
-
if (typeof item !== 'string')
|
|
65
|
-
return { error: 'no such item' }; // args are hers to check
|
|
66
|
-
const id = this.cells.printerId;
|
|
67
|
-
const printer = id ? this.standings[id] : undefined;
|
|
68
|
-
if (!printer)
|
|
69
|
-
return { error: 'no printer' };
|
|
70
|
-
const out = await printer.ask('print', { doc: `receipt for ${item}` });
|
|
71
|
-
if (isUnreached(out))
|
|
72
|
-
return { error: 'printer unreachable', retry: true };
|
|
73
|
-
if (!answered(out))
|
|
74
|
-
return { error: 'printer refused' };
|
|
75
|
-
const st = this.cells.standings[id];
|
|
76
|
-
if (st.seen !== st.digest)
|
|
77
|
-
this.occupant(asker).notes.printerChanged = true;
|
|
78
|
-
this.cells.sales.push({ item: item ?? null, by: asker.id ?? null });
|
|
79
|
-
return { ok: true, receipt: out.printed };
|
|
80
|
-
}
|
|
81
|
-
refund() {
|
|
82
|
-
return { ok: true };
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// A customer. Consumes an invitation, and only then decides to keep the
|
|
86
|
-
// shop. Offers the shop a way back so the shop can reach her.
|
|
87
|
-
export class Customer extends Being {
|
|
88
|
-
static cells = { heard: [] };
|
|
89
|
-
static asks = { hi: { input: { type: 'object' } } };
|
|
90
|
-
async join(invitation) {
|
|
91
|
-
// A way back for the shop, if she can mint one. She may not: two joins on
|
|
92
|
-
// one invitation race, and the second finds the id taken. Then she offers
|
|
93
|
-
// nothing and knocks all the same, which is what the shop is asked to
|
|
94
|
-
// survive. The old shape said `!` here and was wrong about it.
|
|
95
|
-
const mine = await this.invite('shop-back');
|
|
96
|
-
const out = await this.knock(invitation, 'hello', { invitation: mine === null ? null : invitationArgs(mine) });
|
|
97
|
-
if (!answered(out))
|
|
98
|
-
return out; // nothing was born
|
|
99
|
-
await this.take('shop', invitation); // now, and only now
|
|
100
|
-
return out;
|
|
101
|
-
}
|
|
102
|
-
buy(item) {
|
|
103
|
-
return this.standings.shop.ask('buy', { item });
|
|
104
|
-
}
|
|
105
|
-
learn() {
|
|
106
|
-
return this.standings.shop.ask();
|
|
107
|
-
}
|
|
108
|
-
hi(_args, asker) {
|
|
109
|
-
this.cells.heard.push({ from: asker.id ?? null, method: 'hi' });
|
|
110
|
-
return { heard: 'hi' };
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
// The raw shape. No base class, no import from the kit. A being all the same.
|
|
114
|
-
export class Echo {
|
|
115
|
-
s;
|
|
116
|
-
constructor(stance) {
|
|
117
|
-
this.s = stance;
|
|
118
|
-
}
|
|
119
|
-
answer(asker, method, args = {}) {
|
|
120
|
-
if (method === undefined)
|
|
121
|
-
return { asks: [{ name: 'echo', input: {} }], notes: {} };
|
|
122
|
-
return { from: asker.id ?? null, ...args };
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
// A member of an estate. Nothing scripted: she invites whom she is told to,
|
|
126
|
-
// knocks where she is told to, and answers `ping` with the asker's own name.
|
|
127
|
-
// The estate chapter drives her, and what it drives is the graph, not her.
|
|
128
|
-
// A being who makes beings. `boot` is on every stance, so it is the ward's
|
|
129
|
-
// promise and not this kit's, and a second kit that never wired it hands its
|
|
130
|
-
// beings a call that answers null for ever. She says what came of it: the key
|
|
131
|
-
// back, or null for a key already taken, a class the harbor does not hold, or
|
|
132
|
-
// a constructor that threw. With an id she also asks for a way back, and then
|
|
133
|
-
// she holds a standing to what she made like any other.
|
|
134
|
-
export class Maker extends Being {
|
|
135
|
-
static cells = { made: [] };
|
|
136
|
-
static asks = {
|
|
137
|
-
open: { input: { type: 'object', properties: { class: { type: 'string' }, key: { type: 'string' }, id: { type: 'string' } }, required: ['class', 'key'] } },
|
|
138
|
-
say: { input: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] } },
|
|
139
|
-
borrow: { input: { type: 'object', properties: { name: { type: 'string' }, id: { type: 'string' } }, required: ['name', 'id'] } },
|
|
140
|
-
};
|
|
141
|
-
async open({ class: className, key, id }) {
|
|
142
|
-
const made = await this.boot(className, key, id);
|
|
143
|
-
if (made !== null)
|
|
144
|
-
this.cells.made.push(made);
|
|
145
|
-
return { made };
|
|
146
|
-
}
|
|
147
|
-
async say({ id }) {
|
|
148
|
-
const standing = this.standings[id];
|
|
149
|
-
return { said: standing === undefined ? null : (await standing.ask('ping')) };
|
|
150
|
-
}
|
|
151
|
-
// Making's other half: a standing at something the box already has, by the
|
|
152
|
-
// name the box knows it under. She is handed the id and never the value.
|
|
153
|
-
async borrow({ name, id }) {
|
|
154
|
-
return { lent: await this.lend(name, id) };
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
// A member is also lendable: lent by a box that stands her in its own ward,
|
|
158
|
-
// she offers an invitation on herself when the box's being asks, and is an
|
|
159
|
-
// ordinary being to everyone else.
|
|
160
|
-
export class Member extends Lent {
|
|
161
|
-
static cells = { ...Lent.cells, heard: [] };
|
|
162
|
-
static asks = {
|
|
163
|
-
...Lent.asks,
|
|
164
|
-
ping: { input: { type: 'object' } },
|
|
165
|
-
relay: { input: { type: 'object', properties: { id: { type: 'string' }, method: { type: 'string' }, time: { type: 'number' } }, required: ['id'] } },
|
|
166
|
-
};
|
|
167
|
-
ping(_args, asker) {
|
|
168
|
-
this.cells.heard.push({ from: asker.id ?? null });
|
|
169
|
-
return { pong: asker.id ?? null };
|
|
170
|
-
}
|
|
171
|
-
// She asks on one of her standings from inside her own answer, and says
|
|
172
|
-
// what came back as a word rather than as the word itself, since a word is
|
|
173
|
-
// her ward's value and never a thing that crosses. `time` is what she is
|
|
174
|
-
// willing to wait, which is the whole of what the third argument is for.
|
|
175
|
-
// Two members holding each other and relaying make a cycle, and a cycle is
|
|
176
|
-
// how a suite that owns no clock can see a wait end.
|
|
177
|
-
async relay({ id, method, args, time }) {
|
|
178
|
-
const standing = this.standings[id];
|
|
179
|
-
if (standing === undefined)
|
|
180
|
-
return { said: 'no standing', out: null };
|
|
181
|
-
const out = await standing.ask(method, (args ?? {}), time === undefined ? undefined : { time: time });
|
|
182
|
-
if (isSilence(out))
|
|
183
|
-
return { said: 'silence', out: null };
|
|
184
|
-
if (isWord(out))
|
|
185
|
-
return { said: wordOf(out), out: null };
|
|
186
|
-
return { said: null, out: out };
|
|
187
|
-
}
|
|
188
|
-
}
|