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.
Files changed (205) hide show
  1. package/README.md +66 -101
  2. package/dist/being/being.d.ts +7 -15
  3. package/dist/being/being.js +16 -67
  4. package/dist/being/digest.d.ts +1 -1
  5. package/dist/being/digest.js +7 -27
  6. package/dist/being/faculty.d.ts +9 -0
  7. package/dist/being/faculty.js +68 -0
  8. package/dist/being/index.d.ts +4 -5
  9. package/dist/being/index.js +5 -5
  10. package/dist/being/types.d.ts +35 -62
  11. package/dist/being/types.js +3 -57
  12. package/dist/being/words.d.ts +13 -0
  13. package/dist/being/words.js +14 -0
  14. package/dist/contract/index.d.ts +26 -0
  15. package/dist/contract/index.js +19 -0
  16. package/dist/crypto/aes.d.ts +3 -0
  17. package/dist/crypto/aes.js +24 -0
  18. package/dist/crypto/bytes.d.ts +6 -0
  19. package/dist/crypto/bytes.js +33 -0
  20. package/dist/crypto/ed25519.d.ts +3 -0
  21. package/dist/crypto/ed25519.js +85 -0
  22. package/dist/crypto/hash.d.ts +2 -0
  23. package/dist/crypto/hash.js +11 -0
  24. package/dist/crypto/index.d.ts +7 -0
  25. package/dist/crypto/index.js +10 -0
  26. package/dist/crypto/json.d.ts +8 -0
  27. package/dist/crypto/json.js +250 -0
  28. package/dist/crypto/mlkem.d.ts +12 -0
  29. package/dist/crypto/mlkem.js +36 -0
  30. package/dist/crypto/subtle.d.ts +10 -0
  31. package/dist/crypto/subtle.js +29 -0
  32. package/dist/crypto/x25519.d.ts +2 -0
  33. package/dist/crypto/x25519.js +21 -0
  34. package/dist/folder/index.d.ts +13 -0
  35. package/dist/folder/index.js +125 -0
  36. package/dist/harbor/dock.d.ts +19 -0
  37. package/dist/harbor/dock.js +92 -0
  38. package/dist/harbor/harbor.d.ts +22 -0
  39. package/dist/harbor/harbor.js +84 -0
  40. package/dist/harbor/index.d.ts +4 -10
  41. package/dist/harbor/index.js +5 -18
  42. package/dist/harbor/registry.d.ts +7 -0
  43. package/dist/harbor/registry.js +13 -0
  44. package/dist/harbor/terrain.d.ts +8 -0
  45. package/dist/harbor/terrain.js +2 -0
  46. package/dist/index.d.ts +7 -0
  47. package/dist/index.js +14 -0
  48. package/dist/pointer/bodies.d.ts +20 -0
  49. package/dist/pointer/bodies.js +45 -0
  50. package/dist/pointer/index.d.ts +2 -0
  51. package/dist/pointer/index.js +4 -0
  52. package/dist/pointer/world.d.ts +34 -0
  53. package/dist/pointer/world.js +76 -0
  54. package/dist/quo/door.d.ts +34 -0
  55. package/dist/quo/door.js +172 -0
  56. package/dist/quo/index.d.ts +8 -0
  57. package/dist/quo/index.js +11 -0
  58. package/dist/quo/invitation.d.ts +7 -0
  59. package/dist/quo/invitation.js +15 -0
  60. package/dist/quo/keys.d.ts +40 -0
  61. package/dist/quo/keys.js +79 -0
  62. package/dist/quo/payload.d.ts +15 -0
  63. package/dist/quo/payload.js +55 -0
  64. package/dist/quo/relations.d.ts +40 -0
  65. package/dist/quo/relations.js +33 -0
  66. package/dist/quo/reply.d.ts +13 -0
  67. package/dist/quo/reply.js +35 -0
  68. package/dist/quo/seal.d.ts +42 -0
  69. package/dist/quo/seal.js +78 -0
  70. package/dist/quo/standing.d.ts +39 -0
  71. package/dist/quo/standing.js +90 -0
  72. package/dist/ward/allowance.d.ts +13 -9
  73. package/dist/ward/allowance.js +28 -67
  74. package/dist/ward/cells.d.ts +6 -6
  75. package/dist/ward/cells.js +67 -179
  76. package/dist/ward/index.d.ts +5 -10
  77. package/dist/ward/index.js +6 -13
  78. package/dist/ward/partition.d.ts +44 -60
  79. package/dist/ward/partition.js +56 -285
  80. package/dist/ward/stance.d.ts +29 -20
  81. package/dist/ward/stance.js +173 -406
  82. package/dist/ward/ward-being.d.ts +33 -0
  83. package/dist/ward/ward-being.js +76 -0
  84. package/dist/ward/ward.d.ts +43 -11
  85. package/dist/ward/ward.js +215 -363
  86. package/package.json +19 -33
  87. package/src/being/being.ts +31 -78
  88. package/src/being/digest.ts +7 -35
  89. package/src/being/faculty.ts +66 -0
  90. package/src/being/index.ts +5 -6
  91. package/src/being/types.ts +47 -145
  92. package/src/being/words.ts +31 -0
  93. package/src/contract/index.ts +44 -0
  94. package/src/crypto/aes.ts +26 -0
  95. package/src/crypto/bytes.ts +37 -0
  96. package/src/crypto/ed25519.ts +84 -0
  97. package/src/crypto/hash.ts +14 -0
  98. package/src/crypto/index.ts +10 -0
  99. package/src/crypto/json.ts +241 -0
  100. package/src/crypto/mlkem.ts +38 -0
  101. package/src/crypto/subtle.ts +33 -0
  102. package/src/crypto/x25519.ts +21 -0
  103. package/src/folder/index.ts +134 -0
  104. package/src/harbor/dock.ts +101 -0
  105. package/src/harbor/harbor.ts +105 -0
  106. package/src/harbor/index.ts +5 -19
  107. package/src/harbor/registry.ts +20 -0
  108. package/src/harbor/terrain.ts +13 -0
  109. package/src/index.ts +20 -0
  110. package/src/pointer/bodies.ts +47 -0
  111. package/src/pointer/index.ts +4 -0
  112. package/src/pointer/world.ts +91 -0
  113. package/src/quo/door.ts +178 -0
  114. package/src/quo/index.ts +11 -0
  115. package/src/quo/invitation.ts +15 -0
  116. package/src/quo/keys.ts +91 -0
  117. package/src/quo/payload.ts +61 -0
  118. package/src/quo/relations.ts +62 -0
  119. package/src/quo/reply.ts +38 -0
  120. package/src/quo/seal.ts +101 -0
  121. package/src/quo/standing.ts +111 -0
  122. package/src/stand/main.ts +19 -0
  123. package/src/stand/stand.ts +178 -0
  124. package/src/ward/allowance.ts +37 -75
  125. package/src/ward/cells.ts +63 -176
  126. package/src/ward/index.ts +6 -17
  127. package/src/ward/partition.ts +86 -326
  128. package/src/ward/stance.ts +185 -420
  129. package/src/ward/ward-being.ts +97 -0
  130. package/src/ward/ward.ts +229 -363
  131. package/dist/being/lent.d.ts +0 -32
  132. package/dist/being/lent.js +0 -72
  133. package/dist/being/silence.d.ts +0 -12
  134. package/dist/being/silence.js +0 -41
  135. package/dist/conformance/assert.d.ts +0 -11
  136. package/dist/conformance/assert.js +0 -106
  137. package/dist/conformance/beings.d.ts +0 -199
  138. package/dist/conformance/beings.js +0 -188
  139. package/dist/conformance/estate.d.ts +0 -5
  140. package/dist/conformance/estate.js +0 -388
  141. package/dist/conformance/index.d.ts +0 -80
  142. package/dist/conformance/index.js +0 -819
  143. package/dist/conformance/reach.d.ts +0 -10
  144. package/dist/conformance/reach.js +0 -72
  145. package/dist/conformance/store.d.ts +0 -5
  146. package/dist/conformance/store.js +0 -113
  147. package/dist/harbor/box.d.ts +0 -121
  148. package/dist/harbor/box.js +0 -121
  149. package/dist/harbor/core.d.ts +0 -55
  150. package/dist/harbor/core.js +0 -662
  151. package/dist/harbor/dial.d.ts +0 -9
  152. package/dist/harbor/dial.js +0 -81
  153. package/dist/harbor/memory.d.ts +0 -29
  154. package/dist/harbor/memory.js +0 -104
  155. package/dist/harbor/reach.d.ts +0 -36
  156. package/dist/harbor/reach.js +0 -199
  157. package/dist/harbor/store.d.ts +0 -35
  158. package/dist/harbor/store.js +0 -62
  159. package/dist/vector/cases.d.ts +0 -42
  160. package/dist/vector/cases.js +0 -223
  161. package/dist/vector/index.d.ts +0 -6
  162. package/dist/vector/index.js +0 -8
  163. package/dist/vector/stand.d.ts +0 -9
  164. package/dist/vector/stand.js +0 -77
  165. package/dist/vector/world.d.ts +0 -144
  166. package/dist/vector/world.js +0 -209
  167. package/dist/ward/arithmetic.d.ts +0 -31
  168. package/dist/ward/arithmetic.js +0 -249
  169. package/dist/ward/door.d.ts +0 -18
  170. package/dist/ward/door.js +0 -186
  171. package/dist/ward/ground.d.ts +0 -29
  172. package/dist/ward/ground.js +0 -56
  173. package/dist/ward/heirs.d.ts +0 -13
  174. package/dist/ward/heirs.js +0 -117
  175. package/dist/ward/json.d.ts +0 -2
  176. package/dist/ward/json.js +0 -163
  177. package/dist/ward/owner.d.ts +0 -13
  178. package/dist/ward/owner.js +0 -220
  179. package/dist/ward/seal.d.ts +0 -52
  180. package/dist/ward/seal.js +0 -150
  181. package/src/being/lent.ts +0 -72
  182. package/src/being/silence.ts +0 -46
  183. package/src/conformance/assert.ts +0 -100
  184. package/src/conformance/beings.ts +0 -188
  185. package/src/conformance/estate.ts +0 -412
  186. package/src/conformance/index.ts +0 -965
  187. package/src/conformance/reach.ts +0 -83
  188. package/src/conformance/store.ts +0 -125
  189. package/src/harbor/box.ts +0 -131
  190. package/src/harbor/core.ts +0 -699
  191. package/src/harbor/dial.ts +0 -112
  192. package/src/harbor/memory.ts +0 -123
  193. package/src/harbor/reach.ts +0 -221
  194. package/src/harbor/store.ts +0 -91
  195. package/src/vector/cases.ts +0 -257
  196. package/src/vector/index.ts +0 -11
  197. package/src/vector/stand.ts +0 -76
  198. package/src/vector/world.ts +0 -232
  199. package/src/ward/arithmetic.ts +0 -251
  200. package/src/ward/door.ts +0 -186
  201. package/src/ward/ground.ts +0 -142
  202. package/src/ward/heirs.ts +0 -116
  203. package/src/ward/json.ts +0 -144
  204. package/src/ward/owner.ts +0 -214
  205. package/src/ward/seal.ts +0 -178
@@ -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
- }
@@ -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
- }
@@ -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;
@@ -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
- }
@@ -1,5 +0,0 @@
1
- import type { Runner, World } from './index.ts';
2
- export declare function estate(label: string, make: () => Promise<World>, { canDown, test }: {
3
- canDown: boolean;
4
- test: Runner;
5
- }): void;