nervur 0.22.0 → 0.22.2-3
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/AUTHORING.md +741 -0
- package/KIT-SPEC.md +286 -0
- package/LICENSE +1 -1
- package/NOTICE +6 -2
- package/README.md +97 -424
- package/dist/app/app-ground.d.ts +18 -0
- package/dist/app/app-ground.js +25 -0
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.js +5 -0
- package/dist/app/native.d.ts +46 -0
- package/dist/app/native.js +101 -0
- package/dist/being/being.d.ts +229 -0
- package/dist/being/being.js +20 -0
- package/dist/being/covers.d.ts +9 -0
- package/dist/being/covers.js +21 -0
- package/dist/being/index.d.ts +3 -0
- package/dist/being/index.js +5 -0
- package/dist/being/need.d.ts +49 -0
- package/dist/being/need.js +33 -0
- package/dist/being/schema.d.ts +100 -0
- package/dist/being/schema.js +132 -0
- package/dist/being/table.d.ts +42 -0
- package/dist/being/table.js +288 -0
- package/dist/bench/bench-ground.d.ts +55 -0
- package/dist/bench/bench-ground.js +101 -0
- package/dist/bench/bench.d.ts +87 -0
- package/dist/bench/bench.js +260 -0
- package/dist/bench/fake-carry.d.ts +32 -0
- package/dist/bench/fake-carry.js +56 -0
- package/dist/bench/fake-clock.d.ts +17 -0
- package/dist/bench/fake-clock.js +34 -0
- package/dist/bench/fake-custody.d.ts +9 -0
- package/dist/bench/fake-custody.js +10 -0
- package/dist/bench/fake-faculty.d.ts +25 -0
- package/dist/bench/fake-faculty.js +48 -0
- package/dist/bench/fake-keys.d.ts +5 -0
- package/dist/bench/fake-keys.js +9 -0
- package/dist/bench/fake-memory.d.ts +14 -0
- package/dist/bench/fake-memory.js +46 -0
- package/dist/bench/fake-network.d.ts +57 -0
- package/dist/bench/fake-network.js +169 -0
- package/dist/bench/index.d.ts +11 -0
- package/dist/bench/index.js +13 -0
- package/dist/bench/seeded.d.ts +11 -0
- package/dist/bench/seeded.js +37 -0
- package/dist/bench/settle.d.ts +2 -0
- package/dist/bench/settle.js +49 -0
- package/dist/bench/stewards.d.ts +17 -0
- package/dist/bench/stewards.js +20 -0
- package/dist/bodies/class-list.d.ts +14 -0
- package/dist/bodies/class-list.js +33 -0
- package/dist/bodies/joined-carry.d.ts +23 -0
- package/dist/bodies/joined-carry.js +42 -0
- package/dist/bodies/noble-crypto.d.ts +22 -0
- package/dist/bodies/noble-crypto.js +88 -0
- package/dist/bodies/seed-keys.d.ts +10 -0
- package/dist/bodies/seed-keys.js +42 -0
- package/dist/bodies/strict-tools.d.ts +10 -0
- package/dist/bodies/strict-tools.js +306 -0
- package/dist/bodies/web-carry.d.ts +65 -0
- package/dist/bodies/web-carry.js +224 -0
- package/dist/bodies/web-clock.d.ts +12 -0
- package/dist/bodies/web-clock.js +33 -0
- package/dist/browser/browser-ground.d.ts +69 -0
- package/dist/browser/browser-ground.js +219 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.js +7 -0
- package/dist/browser/indexeddb-memory.d.ts +17 -0
- package/dist/browser/indexeddb-memory.js +97 -0
- package/dist/browser/locked-custody.d.ts +25 -0
- package/dist/browser/locked-custody.js +89 -0
- package/dist/browser/origin-classes.d.ts +7 -0
- package/dist/browser/origin-classes.js +31 -0
- package/dist/foundation.d.ts +150 -0
- package/dist/foundation.js +4 -0
- package/dist/ground/ground.d.ts +177 -0
- package/dist/ground/ground.js +363 -0
- package/dist/house/crossing.d.ts +37 -0
- package/dist/house/crossing.js +131 -0
- package/dist/house/house.d.ts +80 -0
- package/dist/house/house.js +1753 -0
- package/dist/house/rows-shape.d.ts +103 -0
- package/dist/house/rows-shape.js +12 -0
- package/dist/house/rows.d.ts +27 -0
- package/dist/house/rows.js +168 -0
- package/dist/index.d.ts +29 -1
- package/dist/index.js +25 -14
- package/dist/node/bridge.d.ts +17 -0
- package/dist/node/bridge.js +188 -0
- package/dist/node/cli.js +170 -0
- package/dist/node/custody.d.ts +20 -0
- package/dist/node/custody.js +34 -0
- package/dist/node/file-keys.d.ts +7 -0
- package/dist/node/file-keys.js +30 -0
- package/dist/node/file-memory.d.ts +13 -0
- package/dist/node/file-memory.js +91 -0
- package/dist/node/folder-classes.d.ts +5 -0
- package/dist/node/folder-classes.js +40 -0
- package/dist/node/gone.d.ts +2 -0
- package/dist/node/gone.js +7 -0
- package/dist/node/hand.d.ts +29 -0
- package/dist/node/hand.js +85 -0
- package/dist/node/held-keys.d.ts +14 -0
- package/dist/node/held-keys.js +36 -0
- package/dist/node/http.d.ts +11 -0
- package/dist/node/http.js +90 -0
- package/dist/node/index.d.ts +13 -0
- package/dist/node/index.js +15 -0
- package/dist/node/keychain-keys.d.ts +10 -0
- package/dist/node/keychain-keys.js +51 -0
- package/dist/node/ledger-memory.d.ts +17 -0
- package/dist/node/ledger-memory.js +151 -0
- package/dist/node/lock.d.ts +10 -0
- package/dist/node/lock.js +78 -0
- package/dist/node/node-ground.d.ts +33 -0
- package/dist/node/node-ground.js +147 -0
- package/dist/node/notify.d.ts +1 -0
- package/dist/node/notify.js +18 -0
- package/dist/node/tcp-carry.d.ts +39 -0
- package/dist/node/tcp-carry.js +216 -0
- package/dist/node/websocket.d.ts +6 -0
- package/dist/node/websocket.js +118 -0
- package/dist/quo/frame.d.ts +20 -0
- package/dist/quo/frame.js +48 -0
- package/dist/quo/room.d.ts +154 -0
- package/dist/quo/room.js +362 -0
- package/dist/serve/index.d.ts +27 -0
- package/dist/serve/index.js +55 -0
- package/package.json +49 -47
- package/dist/browser.d.ts +0 -1
- package/dist/browser.js +0 -8
- package/dist/cli.js +0 -16
- package/dist/core/being/being.d.ts +0 -17
- package/dist/core/being/being.js +0 -72
- package/dist/core/being/digest.d.ts +0 -3
- package/dist/core/being/digest.js +0 -17
- package/dist/core/being/faculty.d.ts +0 -10
- package/dist/core/being/faculty.js +0 -77
- package/dist/core/being/index.d.ts +0 -6
- package/dist/core/being/index.js +0 -8
- package/dist/core/being/kind.d.ts +0 -6
- package/dist/core/being/kind.js +0 -34
- package/dist/core/being/types.d.ts +0 -61
- package/dist/core/being/types.js +0 -4
- package/dist/core/being/words.d.ts +0 -13
- package/dist/core/being/words.js +0 -14
- package/dist/core/browser/index.d.ts +0 -37
- package/dist/core/browser/index.js +0 -196
- package/dist/core/browser/worker.d.ts +0 -11
- package/dist/core/browser/worker.js +0 -37
- package/dist/core/cli/command.d.ts +0 -13
- package/dist/core/cli/command.js +0 -330
- package/dist/core/cli/edge.d.ts +0 -7
- package/dist/core/cli/edge.js +0 -79
- package/dist/core/cli/harbor.d.ts +0 -25
- package/dist/core/cli/harbor.js +0 -115
- package/dist/core/contract/index.d.ts +0 -42
- package/dist/core/contract/index.js +0 -34
- package/dist/core/contract/link.d.ts +0 -4
- package/dist/core/contract/link.js +0 -45
- package/dist/core/crypto/aes.d.ts +0 -3
- package/dist/core/crypto/aes.js +0 -24
- package/dist/core/crypto/bytes.d.ts +0 -6
- package/dist/core/crypto/bytes.js +0 -33
- package/dist/core/crypto/ed25519.d.ts +0 -3
- package/dist/core/crypto/ed25519.js +0 -93
- package/dist/core/crypto/hash.d.ts +0 -2
- package/dist/core/crypto/hash.js +0 -11
- package/dist/core/crypto/index.d.ts +0 -7
- package/dist/core/crypto/index.js +0 -10
- package/dist/core/crypto/json.d.ts +0 -8
- package/dist/core/crypto/json.js +0 -250
- package/dist/core/crypto/mlkem.d.ts +0 -12
- package/dist/core/crypto/mlkem.js +0 -36
- package/dist/core/crypto/subtle.d.ts +0 -3
- package/dist/core/crypto/subtle.js +0 -11
- package/dist/core/crypto/x25519.d.ts +0 -2
- package/dist/core/crypto/x25519.js +0 -24
- package/dist/core/edge/index.d.ts +0 -164
- package/dist/core/edge/index.js +0 -739
- package/dist/core/edge/kit.d.ts +0 -2
- package/dist/core/edge/kit.js +0 -2
- package/dist/core/folder/index.d.ts +0 -18
- package/dist/core/folder/index.js +0 -130
- package/dist/core/git/http.d.ts +0 -6
- package/dist/core/git/http.js +0 -102
- package/dist/core/git/index.d.ts +0 -5
- package/dist/core/git/index.js +0 -10
- package/dist/core/git/object.d.ts +0 -40
- package/dist/core/git/object.js +0 -103
- package/dist/core/git/pack.d.ts +0 -9
- package/dist/core/git/pack.js +0 -171
- package/dist/core/git/store.d.ts +0 -23
- package/dist/core/git/store.js +0 -120
- package/dist/core/git/zlib.d.ts +0 -6
- package/dist/core/git/zlib.js +0 -210
- package/dist/core/harbor/carrying.d.ts +0 -51
- package/dist/core/harbor/carrying.js +0 -69
- package/dist/core/harbor/catalogue.d.ts +0 -33
- package/dist/core/harbor/catalogue.js +0 -365
- package/dist/core/harbor/dna.d.ts +0 -13
- package/dist/core/harbor/dna.js +0 -120
- package/dist/core/harbor/dock.d.ts +0 -62
- package/dist/core/harbor/dock.js +0 -381
- package/dist/core/harbor/harbor.d.ts +0 -16
- package/dist/core/harbor/harbor.js +0 -438
- package/dist/core/harbor/index.d.ts +0 -11
- package/dist/core/harbor/index.js +0 -14
- package/dist/core/harbor/memory.d.ts +0 -10
- package/dist/core/harbor/memory.js +0 -25
- package/dist/core/harbor/package.d.ts +0 -20
- package/dist/core/harbor/package.js +0 -172
- package/dist/core/harbor/probe.d.ts +0 -22
- package/dist/core/harbor/probe.js +0 -15
- package/dist/core/harbor/registry.d.ts +0 -15
- package/dist/core/harbor/registry.js +0 -110
- package/dist/core/harbor/root-line.d.ts +0 -7
- package/dist/core/harbor/root-line.js +0 -9
- package/dist/core/harbor/terrain.d.ts +0 -25
- package/dist/core/harbor/terrain.js +0 -28
- package/dist/core/http/index.d.ts +0 -2
- package/dist/core/http/index.js +0 -154
- package/dist/core/http/websocket.d.ts +0 -29
- package/dist/core/http/websocket.js +0 -133
- package/dist/core/line/answer.d.ts +0 -8
- package/dist/core/line/answer.js +0 -60
- package/dist/core/line/frame.d.ts +0 -29
- package/dist/core/line/frame.js +0 -77
- package/dist/core/line/ground.d.ts +0 -3
- package/dist/core/line/ground.js +0 -7
- package/dist/core/line/index.d.ts +0 -4
- package/dist/core/line/index.js +0 -8
- package/dist/core/line/web.d.ts +0 -12
- package/dist/core/line/web.js +0 -117
- package/dist/core/node/index.d.ts +0 -23
- package/dist/core/node/index.js +0 -124
- package/dist/core/pointer/bodies.d.ts +0 -31
- package/dist/core/pointer/bodies.js +0 -118
- package/dist/core/pointer/index.d.ts +0 -2
- package/dist/core/pointer/index.js +0 -4
- package/dist/core/pointer/world.d.ts +0 -45
- package/dist/core/pointer/world.js +0 -106
- package/dist/core/proof/contracts.d.ts +0 -19
- package/dist/core/proof/contracts.js +0 -116
- package/dist/core/proof/expect.d.ts +0 -6
- package/dist/core/proof/expect.js +0 -18
- package/dist/core/proof/index.d.ts +0 -3
- package/dist/core/proof/index.js +0 -14
- package/dist/core/proof/law.d.ts +0 -25
- package/dist/core/proof/law.js +0 -715
- package/dist/core/quo/address.d.ts +0 -19
- package/dist/core/quo/address.js +0 -84
- package/dist/core/quo/door.d.ts +0 -34
- package/dist/core/quo/door.js +0 -174
- package/dist/core/quo/index.d.ts +0 -9
- package/dist/core/quo/index.js +0 -12
- package/dist/core/quo/invitation.d.ts +0 -8
- package/dist/core/quo/invitation.js +0 -19
- package/dist/core/quo/keys.d.ts +0 -40
- package/dist/core/quo/keys.js +0 -79
- package/dist/core/quo/payload.d.ts +0 -15
- package/dist/core/quo/payload.js +0 -55
- package/dist/core/quo/relations.d.ts +0 -40
- package/dist/core/quo/relations.js +0 -33
- package/dist/core/quo/reply.d.ts +0 -13
- package/dist/core/quo/reply.js +0 -35
- package/dist/core/quo/seal.d.ts +0 -42
- package/dist/core/quo/seal.js +0 -78
- package/dist/core/quo/standing.d.ts +0 -39
- package/dist/core/quo/standing.js +0 -90
- package/dist/core/tcp/index.d.ts +0 -27
- package/dist/core/tcp/index.js +0 -209
- package/dist/core/ward/allowance.d.ts +0 -14
- package/dist/core/ward/allowance.js +0 -32
- package/dist/core/ward/cells.d.ts +0 -7
- package/dist/core/ward/cells.js +0 -74
- package/dist/core/ward/house.d.ts +0 -67
- package/dist/core/ward/house.js +0 -473
- package/dist/core/ward/index.d.ts +0 -5
- package/dist/core/ward/index.js +0 -7
- package/dist/core/ward/partition.d.ts +0 -50
- package/dist/core/ward/partition.js +0 -66
- package/dist/core/ward/stance.d.ts +0 -29
- package/dist/core/ward/stance.js +0 -186
- package/dist/core/ward/ward.d.ts +0 -44
- package/dist/core/ward/ward.js +0 -140
- package/dist/core.d.ts +0 -10
- package/dist/core.js +0 -19
- package/dist/defaults/dock/index.d.ts +0 -4
- package/dist/defaults/dock/index.js +0 -11
- package/dist/defaults/index.d.ts +0 -5
- package/dist/defaults/index.js +0 -10
- package/dist/defaults/memory/index.d.ts +0 -12
- package/dist/defaults/memory/index.js +0 -39
- package/dist/defaults/tcp/index.d.ts +0 -16
- package/dist/defaults/tcp/index.js +0 -82
- package/dist/defaults/ward/index.d.ts +0 -4
- package/dist/defaults/ward/index.js +0 -11
- package/dist/defaults/web/index.d.ts +0 -15
- package/dist/defaults/web/index.js +0 -90
- package/dist/edge.d.ts +0 -1
- package/dist/edge.js +0 -9
- package/dist/kit.d.ts +0 -4
- package/dist/kit.js +0 -12
- package/dist/node.d.ts +0 -1
- package/dist/node.js +0 -8
- package/src/browser.ts +0 -10
- package/src/cli.ts +0 -15
- package/src/core/being/being.ts +0 -84
- package/src/core/being/digest.ts +0 -18
- package/src/core/being/faculty.ts +0 -76
- package/src/core/being/index.ts +0 -8
- package/src/core/being/kind.ts +0 -37
- package/src/core/being/types.ts +0 -74
- package/src/core/being/words.ts +0 -31
- package/src/core/browser/index.ts +0 -219
- package/src/core/browser/worker.ts +0 -63
- package/src/core/cli/command.ts +0 -311
- package/src/core/cli/edge.ts +0 -86
- package/src/core/cli/harbor.ts +0 -120
- package/src/core/contract/index.ts +0 -82
- package/src/core/contract/link.ts +0 -58
- package/src/core/crypto/aes.ts +0 -26
- package/src/core/crypto/bytes.ts +0 -37
- package/src/core/crypto/ed25519.ts +0 -92
- package/src/core/crypto/hash.ts +0 -14
- package/src/core/crypto/index.ts +0 -10
- package/src/core/crypto/json.ts +0 -241
- package/src/core/crypto/mlkem.ts +0 -38
- package/src/core/crypto/subtle.ts +0 -13
- package/src/core/crypto/x25519.ts +0 -23
- package/src/core/edge/index.ts +0 -865
- package/src/core/folder/index.ts +0 -137
- package/src/core/git/http.ts +0 -103
- package/src/core/git/index.ts +0 -10
- package/src/core/git/object.ts +0 -116
- package/src/core/git/pack.ts +0 -147
- package/src/core/git/store.ts +0 -122
- package/src/core/git/zlib.ts +0 -197
- package/src/core/harbor/carrying.ts +0 -124
- package/src/core/harbor/catalogue.ts +0 -386
- package/src/core/harbor/dna.ts +0 -116
- package/src/core/harbor/dock.ts +0 -420
- package/src/core/harbor/harbor.ts +0 -433
- package/src/core/harbor/index.ts +0 -14
- package/src/core/harbor/memory.ts +0 -31
- package/src/core/harbor/package.ts +0 -195
- package/src/core/harbor/probe.ts +0 -39
- package/src/core/harbor/registry.ts +0 -107
- package/src/core/harbor/root-line.ts +0 -19
- package/src/core/harbor/terrain.ts +0 -54
- package/src/core/http/index.ts +0 -147
- package/src/core/http/websocket.ts +0 -124
- package/src/core/line/answer.ts +0 -60
- package/src/core/line/frame.ts +0 -83
- package/src/core/line/ground.ts +0 -18
- package/src/core/line/index.ts +0 -8
- package/src/core/line/web.ts +0 -123
- package/src/core/node/index.ts +0 -139
- package/src/core/pointer/bodies.ts +0 -122
- package/src/core/pointer/index.ts +0 -4
- package/src/core/pointer/world.ts +0 -134
- package/src/core/proof/contracts.ts +0 -134
- package/src/core/proof/expect.ts +0 -25
- package/src/core/proof/index.ts +0 -14
- package/src/core/proof/law.ts +0 -742
- package/src/core/quo/address.ts +0 -87
- package/src/core/quo/door.ts +0 -180
- package/src/core/quo/index.ts +0 -12
- package/src/core/quo/invitation.ts +0 -19
- package/src/core/quo/keys.ts +0 -91
- package/src/core/quo/payload.ts +0 -61
- package/src/core/quo/relations.ts +0 -62
- package/src/core/quo/reply.ts +0 -38
- package/src/core/quo/seal.ts +0 -101
- package/src/core/quo/standing.ts +0 -111
- package/src/core/stand/main.ts +0 -20
- package/src/core/stand/stand.ts +0 -259
- package/src/core/tcp/index.ts +0 -227
- package/src/core/ward/allowance.ts +0 -47
- package/src/core/ward/cells.ts +0 -77
- package/src/core/ward/house.ts +0 -524
- package/src/core/ward/index.ts +0 -7
- package/src/core/ward/partition.ts +0 -117
- package/src/core/ward/stance.ts +0 -207
- package/src/core/ward/ward.ts +0 -166
- package/src/core.ts +0 -55
- package/src/defaults/dock/index.ts +0 -12
- package/src/defaults/index.ts +0 -10
- package/src/defaults/memory/index.ts +0 -50
- package/src/defaults/tcp/index.ts +0 -89
- package/src/defaults/ward/index.ts +0 -12
- package/src/defaults/web/index.ts +0 -97
- package/src/edge.ts +0 -11
- package/src/index.ts +0 -18
- package/src/kit.ts +0 -15
- package/src/node.ts +0 -10
- /package/dist/{cli.d.ts → node/cli.d.ts} +0 -0
package/src/core/line/web.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// Quo over the web, `quo/CARRIER-WEB.md`, on what every engine has: fetch
|
|
3
|
-
// and the WebSocket client.
|
|
4
|
-
//
|
|
5
|
-
// WebDialer bytes to a ward pk at an address: `http` and `https` as
|
|
6
|
-
// one post each, `ws` and `wss` on one held line per
|
|
7
|
-
// address, which many asks share
|
|
8
|
-
//
|
|
9
|
-
// A post that comes back with status 200 and a body is a reply, and every
|
|
10
|
-
// other status is nothing. A post the network refused, or a held line
|
|
11
|
-
// that did not open, was not dialed. A line that carried a box and closed
|
|
12
|
-
// answers nothing.
|
|
13
|
-
import { concat, hex, isHex, unhex } from '../crypto/index.ts';
|
|
14
|
-
import { UNDIALED, type Dialed } from '../harbor/index.ts';
|
|
15
|
-
import { webAddress, type WebAddress } from '../quo/index.ts';
|
|
16
|
-
import { askBody, readBody } from './frame.ts';
|
|
17
|
-
|
|
18
|
-
export const MIN_POST = 65;
|
|
19
|
-
export const MAX_POST = 64 + 1_048_576;
|
|
20
|
-
const MAX_ID = 0xffff_ffff;
|
|
21
|
-
|
|
22
|
-
// Bytes on a buffer of their own, as a body and a message take them.
|
|
23
|
-
const own = (bytes: Uint8Array): Uint8Array<ArrayBuffer> => new Uint8Array(bytes);
|
|
24
|
-
|
|
25
|
-
// One held line to one address.
|
|
26
|
-
class HeldLine {
|
|
27
|
-
readonly #socket: WebSocket;
|
|
28
|
-
readonly #waiting = new Map<number, (box: Uint8Array | null) => void>();
|
|
29
|
-
#next = 1;
|
|
30
|
-
|
|
31
|
-
private constructor(socket: WebSocket) {
|
|
32
|
-
this.#socket = socket;
|
|
33
|
-
socket.binaryType = 'arraybuffer';
|
|
34
|
-
socket.addEventListener('message', (e: MessageEvent) => {
|
|
35
|
-
const frame = typeof e.data === 'string' ? null : readBody(new Uint8Array(e.data as ArrayBuffer));
|
|
36
|
-
if (frame === null) return this.close();
|
|
37
|
-
if (frame.kind === 'ask') return;
|
|
38
|
-
const done = this.#waiting.get(frame.id);
|
|
39
|
-
this.#waiting.delete(frame.id);
|
|
40
|
-
done?.(frame.kind === 'reply' ? frame.box : null);
|
|
41
|
-
});
|
|
42
|
-
socket.addEventListener('close', () => {
|
|
43
|
-
for (const done of this.#waiting.values()) done(null);
|
|
44
|
-
this.#waiting.clear();
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// A line that opened with the subprotocol `quo`, or null.
|
|
49
|
-
static open(href: string, onClose: () => void): Promise<HeldLine | null> {
|
|
50
|
-
return new Promise((resolve) => {
|
|
51
|
-
let socket: WebSocket;
|
|
52
|
-
try {
|
|
53
|
-
socket = new WebSocket(href, 'quo');
|
|
54
|
-
} catch {
|
|
55
|
-
resolve(null);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const line = new HeldLine(socket);
|
|
59
|
-
socket.addEventListener('open', () => (socket.protocol === 'quo' ? resolve(line) : (socket.close(), resolve(null))));
|
|
60
|
-
socket.addEventListener('close', () => {
|
|
61
|
-
onClose();
|
|
62
|
-
resolve(null);
|
|
63
|
-
});
|
|
64
|
-
socket.addEventListener('error', () => resolve(null));
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
ask(pk: Uint8Array, box: Uint8Array): Promise<Uint8Array | null> {
|
|
69
|
-
if (this.#socket.readyState !== WebSocket.OPEN) return Promise.resolve(null);
|
|
70
|
-
const id = this.#next;
|
|
71
|
-
this.#next = this.#next === MAX_ID ? 1 : this.#next + 1;
|
|
72
|
-
return new Promise((resolve) => {
|
|
73
|
-
this.#waiting.set(id, resolve);
|
|
74
|
-
this.#socket.send(own(askBody(id, pk, box)));
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
close(): void {
|
|
79
|
-
this.#socket.close();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export class WebDialer {
|
|
84
|
-
readonly #lines = new Map<string, Promise<HeldLine | null>>();
|
|
85
|
-
|
|
86
|
-
dial(at: string, pk: string, bytes: Uint8Array): Promise<Dialed> {
|
|
87
|
-
const address = webAddress(at);
|
|
88
|
-
if (address === null || !isHex(pk, 64)) return Promise.resolve(UNDIALED);
|
|
89
|
-
return address.held ? this.#held(address, pk, bytes) : this.#post(address, pk, bytes);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async #post(address: WebAddress, pk: string, bytes: Uint8Array): Promise<Dialed> {
|
|
93
|
-
let response: Response;
|
|
94
|
-
try {
|
|
95
|
-
response = await fetch(address.href, { method: 'POST', body: own(concat(unhex(pk), bytes)) });
|
|
96
|
-
} catch {
|
|
97
|
-
return UNDIALED;
|
|
98
|
-
}
|
|
99
|
-
const body = new Uint8Array(await response.arrayBuffer().catch(() => new ArrayBuffer(0)));
|
|
100
|
-
return response.status === 200 && body.length > 0 ? body : null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async #held(address: WebAddress, pk: string, bytes: Uint8Array): Promise<Dialed> {
|
|
104
|
-
let line = this.#lines.get(address.href);
|
|
105
|
-
if (!line) {
|
|
106
|
-
line = HeldLine.open(address.href, () => this.#lines.delete(address.href));
|
|
107
|
-
this.#lines.set(address.href, line);
|
|
108
|
-
void line.then((held) => held ?? this.#lines.delete(address.href));
|
|
109
|
-
}
|
|
110
|
-
const held = await line;
|
|
111
|
-
return held ? held.ask(unhex(pk), bytes) : UNDIALED;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async close(): Promise<void> {
|
|
115
|
-
const lines = [...this.#lines.values()];
|
|
116
|
-
this.#lines.clear();
|
|
117
|
-
for (const line of await Promise.all(lines)) line?.close();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// The ward pk and box a post carries, or null for a body that is no ask.
|
|
122
|
-
export const readPost = (body: Uint8Array): { pk: string; box: Uint8Array } | null =>
|
|
123
|
-
body.length < MIN_POST || body.length > MAX_POST ? null : { pk: hex(body.subarray(0, 64)), box: body.slice(64) };
|
package/src/core/node/index.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// `nervur/node`: the Node ground. A harbor keeps its seed and sealed
|
|
3
|
-
// memory in a folder, its DNA among it, runs a module's source by
|
|
4
|
-
// importing it, hands its carriers Node's sockets and HTTP server, and
|
|
5
|
-
// serves the root line on a local
|
|
6
|
-
// socket, so the `nervur` command reaches it while it stands.
|
|
7
|
-
//
|
|
8
|
-
// <dir>/seed the harbor's seed
|
|
9
|
-
// <dir>/<place>/ its sealed memory
|
|
10
|
-
// <dir>/root.sock the root line while the harbor is served, open to
|
|
11
|
-
// this user alone, or in the temporary folder for a
|
|
12
|
-
// folder too deep for a socket path
|
|
13
|
-
//
|
|
14
|
-
// One run holds a folder: a terrain refuses a folder another run serves.
|
|
15
|
-
import { createHash } from 'node:crypto';
|
|
16
|
-
import { chmod, rm } from 'node:fs/promises';
|
|
17
|
-
import { connect, createServer, type Server } from 'node:net';
|
|
18
|
-
import { homedir, tmpdir } from 'node:os';
|
|
19
|
-
import { join, resolve } from 'node:path';
|
|
20
|
-
import type { JsonObject } from '../being/index.ts';
|
|
21
|
-
import { FolderCustody, FolderMemory } from '../folder/index.ts';
|
|
22
|
-
import type { Defaults, GroundProbe, Harbor, RootRequest } from '../harbor/index.ts';
|
|
23
|
-
import { webServe } from '../http/index.ts';
|
|
24
|
-
import { CryptoEntropy, PointerTerrain, SourceLoader } from '../pointer/index.ts';
|
|
25
|
-
import { NodeSockets } from '../tcp/index.ts';
|
|
26
|
-
|
|
27
|
-
export const NODE = 'node';
|
|
28
|
-
|
|
29
|
-
// Where a harbor of this user lives unless named: $NERVUR_DIR, then
|
|
30
|
-
// ~/.nervur.
|
|
31
|
-
export const harborDir = (env: Record<string, string | undefined> = process.env): string => env.NERVUR_DIR ?? join(homedir(), '.nervur');
|
|
32
|
-
|
|
33
|
-
// A socket path has a hundred bytes or so on every system, so a folder too
|
|
34
|
-
// deep for one puts its socket in this user's temporary folder, under a
|
|
35
|
-
// name drawn from the folder's own path.
|
|
36
|
-
const SOCKET_PATH = 100;
|
|
37
|
-
export const socketOf = (dir: string): string => {
|
|
38
|
-
const beside = join(resolve(dir), 'root.sock');
|
|
39
|
-
if (Buffer.byteLength(beside) <= SOCKET_PATH) return beside;
|
|
40
|
-
return join(tmpdir(), `nervur-${createHash('sha256').update(resolve(dir)).digest('hex').slice(0, 32)}.sock`);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// One root request over a served harbor's socket, or undefined where none
|
|
44
|
-
// is served.
|
|
45
|
-
export const askServed = (dir: string, request: RootRequest): Promise<JsonObject | undefined> =>
|
|
46
|
-
new Promise((done, fail) => {
|
|
47
|
-
const socket = connect(socketOf(dir));
|
|
48
|
-
let text = '';
|
|
49
|
-
socket.once('connect', () => socket.write(`${JSON.stringify(request)}\n`));
|
|
50
|
-
socket.on('data', (chunk: Buffer) => {
|
|
51
|
-
text += chunk.toString('utf8');
|
|
52
|
-
const end = text.indexOf('\n');
|
|
53
|
-
if (end < 0) return;
|
|
54
|
-
socket.end();
|
|
55
|
-
done(JSON.parse(text.slice(0, end)) as JsonObject);
|
|
56
|
-
});
|
|
57
|
-
socket.once('error', (e: NodeJS.ErrnoException) => (e.code === 'ENOENT' || e.code === 'ECONNREFUSED' ? done(undefined) : fail(e)));
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
export type NodeParts = {
|
|
61
|
-
readonly dir: string;
|
|
62
|
-
readonly defaults: Defaults;
|
|
63
|
-
// Whether its carriers wake, and whether it serves the root line.
|
|
64
|
-
readonly wakes?: boolean;
|
|
65
|
-
readonly serves?: boolean;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export class NodeTerrain extends PointerTerrain {
|
|
69
|
-
readonly dir: string;
|
|
70
|
-
readonly serves: boolean;
|
|
71
|
-
#server: Server | undefined;
|
|
72
|
-
|
|
73
|
-
constructor(parts: NodeParts) {
|
|
74
|
-
const entropy = new CryptoEntropy();
|
|
75
|
-
super({
|
|
76
|
-
entropy,
|
|
77
|
-
loader: new SourceLoader(),
|
|
78
|
-
custody: new FolderCustody(parts.dir, entropy),
|
|
79
|
-
memory: new FolderMemory(parts.dir),
|
|
80
|
-
tcp: () => new NodeSockets(),
|
|
81
|
-
web: webServe,
|
|
82
|
-
defaults: parts.defaults,
|
|
83
|
-
wakes: parts.wakes ?? true,
|
|
84
|
-
});
|
|
85
|
-
this.dir = parts.dir;
|
|
86
|
-
this.serves = parts.serves ?? true;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
override async claim(): Promise<void> {
|
|
90
|
-
if ((await askServed(this.dir, {})) !== undefined) throw new Error(`a harbor is already served from ${this.dir}`);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// The root line on the socket. A socket file nobody answers on is a
|
|
94
|
-
// stale one, and is replaced.
|
|
95
|
-
override async stand(harbor: Harbor): Promise<void> {
|
|
96
|
-
if (!this.serves) return;
|
|
97
|
-
const root = socketOf(this.dir);
|
|
98
|
-
await rm(root, { force: true });
|
|
99
|
-
const server = createServer((socket) => {
|
|
100
|
-
let text = '';
|
|
101
|
-
socket.on('data', (chunk: Buffer) => {
|
|
102
|
-
text += chunk.toString('utf8');
|
|
103
|
-
for (let end = text.indexOf('\n'); end >= 0; end = text.indexOf('\n')) {
|
|
104
|
-
const line = text.slice(0, end);
|
|
105
|
-
text = text.slice(end + 1);
|
|
106
|
-
let value: unknown;
|
|
107
|
-
try {
|
|
108
|
-
value = JSON.parse(line);
|
|
109
|
-
} catch {
|
|
110
|
-
value = undefined;
|
|
111
|
-
}
|
|
112
|
-
void harbor
|
|
113
|
-
.ask(value)
|
|
114
|
-
.catch(() => ({ error: 'the harbor threw' }))
|
|
115
|
-
.then((answer) => socket.write(`${JSON.stringify(answer)}\n`));
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
socket.on('error', () => socket.destroy());
|
|
119
|
-
});
|
|
120
|
-
await new Promise<void>((done) => server.listen(root, done));
|
|
121
|
-
await chmod(root, 0o600);
|
|
122
|
-
this.#server = server;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
override async release(): Promise<void> {
|
|
126
|
-
const server = this.#server;
|
|
127
|
-
if (!server) return;
|
|
128
|
-
this.#server = undefined;
|
|
129
|
-
await new Promise((done) => server.close(done));
|
|
130
|
-
await rm(socketOf(this.dir), { force: true });
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Node, and the engines that answer as Node does.
|
|
135
|
-
export const nodeGround: GroundProbe = {
|
|
136
|
-
name: NODE,
|
|
137
|
-
fits: () => typeof process !== 'undefined' && typeof process.versions?.node === 'string',
|
|
138
|
-
terrain: ({ where }, defaults) => new NodeTerrain({ dir: where ?? harborDir(), defaults }),
|
|
139
|
-
};
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The pointer terrain's bodies: each contract fulfilled in one process,
|
|
3
|
-
// with nothing beyond JavaScript.
|
|
4
|
-
import { Clock, Custody, Entropy, linked, Loader, Memory, moduleOf, type Bundled, type Module } from '../contract/index.ts';
|
|
5
|
-
import { blob, idOf } from '../git/index.ts';
|
|
6
|
-
|
|
7
|
-
export class CryptoEntropy extends Entropy {
|
|
8
|
-
draw(length: number): Uint8Array {
|
|
9
|
-
return globalThis.crypto.getRandomValues(new Uint8Array(length));
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class SystemClock extends Clock {
|
|
14
|
-
now(): number {
|
|
15
|
-
return Date.now();
|
|
16
|
-
}
|
|
17
|
-
wait(ms: number): { done: Promise<void>; cancel(): void } {
|
|
18
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
19
|
-
const done = new Promise<void>((resolve) => (timer = setTimeout(resolve, ms)));
|
|
20
|
-
return { done, cancel: () => clearTimeout(timer) };
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// The harbor's seed, drawn once and held by this object.
|
|
25
|
-
export class HeldCustody extends Custody {
|
|
26
|
-
readonly #seed: Uint8Array;
|
|
27
|
-
constructor(entropy: Entropy) {
|
|
28
|
-
super();
|
|
29
|
-
this.#seed = entropy.draw(32);
|
|
30
|
-
}
|
|
31
|
-
seed(): Promise<Uint8Array> {
|
|
32
|
-
return Promise.resolve(this.#seed.slice());
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// How this engine imports a module it is handed as text: from a Blob URL
|
|
37
|
-
// where it imports one, as a browser, Deno and Bun do, and else from a
|
|
38
|
-
// data: URL, as Node does. Bun reads a data: URL as a module that exports
|
|
39
|
-
// nothing, so the Blob URL is tried first, once, with a module of one
|
|
40
|
-
// export.
|
|
41
|
-
type Importer = (text: string) => Promise<unknown>;
|
|
42
|
-
const fromBlob: Importer = async (text) => {
|
|
43
|
-
const url = URL.createObjectURL(new Blob([text], { type: 'text/javascript' }));
|
|
44
|
-
try {
|
|
45
|
-
return await import(url);
|
|
46
|
-
} finally {
|
|
47
|
-
URL.revokeObjectURL(url);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
const fromData: Importer = (text) => import(`data:text/javascript;charset=utf-8,${encodeURIComponent(text)}`);
|
|
51
|
-
let importer: Promise<Importer> | undefined;
|
|
52
|
-
const importerHere = (): Promise<Importer> =>
|
|
53
|
-
(importer ??= fromBlob('export const probe = 1;').then(
|
|
54
|
-
(m) => ((m as { probe?: unknown }).probe === 1 ? fromBlob : fromData),
|
|
55
|
-
() => fromData,
|
|
56
|
-
));
|
|
57
|
-
|
|
58
|
-
// A module's source run by the engine's own `import()`, its `'nervur'`
|
|
59
|
-
// linked to the kit running: Node, Deno, Bun, a browser's page and shared
|
|
60
|
-
// worker, and every engine that imports what it is handed.
|
|
61
|
-
export class SourceLoader extends Loader {
|
|
62
|
-
async load(source: string): Promise<Module> {
|
|
63
|
-
const text = linked(source);
|
|
64
|
-
let exported: unknown;
|
|
65
|
-
try {
|
|
66
|
-
exported = await (await importerHere())(text);
|
|
67
|
-
} catch (e) {
|
|
68
|
-
throw new Error(`the module did not load: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
69
|
-
}
|
|
70
|
-
return moduleOf(exported);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// The modules a bundle carries, found by content alone: the git id of a
|
|
75
|
-
// source's blob names the module built from it. An edge evaluates no code
|
|
76
|
-
// it is handed, so a source whose blob the bundle does not carry needs a
|
|
77
|
-
// deploy that carries it.
|
|
78
|
-
export class BundleLoader extends Loader {
|
|
79
|
-
readonly #bundle: readonly Bundled[];
|
|
80
|
-
#ids: Promise<Map<string, Module>> | undefined;
|
|
81
|
-
constructor(bundle: readonly Bundled[] = []) {
|
|
82
|
-
super();
|
|
83
|
-
this.#bundle = bundle;
|
|
84
|
-
}
|
|
85
|
-
async load(_source: string, id: string): Promise<Module> {
|
|
86
|
-
this.#ids ??= Promise.all(this.#bundle.map(async (b): Promise<[string, Module]> => [await idOf(blob(b.source)), b.module])).then((ids) => new Map(ids));
|
|
87
|
-
const found = (await this.#ids).get(id);
|
|
88
|
-
if (found) return moduleOf(found);
|
|
89
|
-
const carried = this.#bundle.map((b) => b.module.module);
|
|
90
|
-
throw new Error(`redeploy needed: blob ${id} is no module this bundle carries${carried.length === 0 ? ', and it carries none' : `: it carries ${carried.join(', ')}`}`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Entries that live as long as this object, copied in and out, which is
|
|
95
|
-
// what a restart in one process finds.
|
|
96
|
-
export class VolatileMemory extends Memory {
|
|
97
|
-
readonly #places = new Map<string, Map<string, Uint8Array>>();
|
|
98
|
-
read(place: string): Promise<Map<string, Uint8Array>> {
|
|
99
|
-
const entries = this.#places.get(place) ?? new Map<string, Uint8Array>();
|
|
100
|
-
return Promise.resolve(new Map([...entries].map(([name, bytes]) => [name, bytes.slice()])));
|
|
101
|
-
}
|
|
102
|
-
// One object holds it, so a keep is whole by the run of one turn.
|
|
103
|
-
write(place: string, entries: ReadonlyMap<string, Uint8Array | null>): Promise<void> {
|
|
104
|
-
let kept = this.#places.get(place);
|
|
105
|
-
if (!kept) this.#places.set(place, (kept = new Map()));
|
|
106
|
-
for (const [name, bytes] of entries) {
|
|
107
|
-
if (bytes === null) kept.delete(name);
|
|
108
|
-
else kept.set(name, bytes.slice());
|
|
109
|
-
}
|
|
110
|
-
if (kept.size === 0) this.#places.delete(place);
|
|
111
|
-
return Promise.resolve();
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
places(): Promise<string[]> {
|
|
115
|
-
return Promise.resolve([...this.#places.keys()]);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
forget(place: string): Promise<void> {
|
|
119
|
-
this.#places.delete(place);
|
|
120
|
-
return Promise.resolve();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The pointer dock: a whole world with `nervur` alone.
|
|
3
|
-
export { BundleLoader, CryptoEntropy, HeldCustody, SourceLoader, SystemClock, VolatileMemory } from './bodies.ts';
|
|
4
|
-
export { NoCarrier, PointerCarrier, PointerTerrain, World, type PointerParts, type WorldParts } from './world.ts';
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The pointer world: harbors in one process, an address book from ward pk
|
|
3
|
-
// to harbor that stands in for the internet, and weather between them. A
|
|
4
|
-
// restart drops a harbor and opens a new one on the terrain the world
|
|
5
|
-
// keeps for it, so only what its memory kept comes back.
|
|
6
|
-
import { Carrier, type Clock, type Custody, type Entropy, type Loader, type Memory } from '../contract/index.ts';
|
|
7
|
-
import { Harbor, Terrain, type Defaults, type Sockets, type WebServe } from '../harbor/index.ts';
|
|
8
|
-
import { CryptoEntropy, HeldCustody, SourceLoader, SystemClock, VolatileMemory } from './bodies.ts';
|
|
9
|
-
|
|
10
|
-
// A carrier that reaches no one: a harbor alone.
|
|
11
|
-
export class NoCarrier extends Carrier {
|
|
12
|
-
carry(): Promise<Uint8Array | null> {
|
|
13
|
-
return Promise.resolve(null);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Bytes to whichever harbor of a world holds the ward pk.
|
|
18
|
-
export class PointerCarrier extends Carrier {
|
|
19
|
-
readonly #world: World;
|
|
20
|
-
constructor(world: World) {
|
|
21
|
-
super();
|
|
22
|
-
this.#world = world;
|
|
23
|
-
}
|
|
24
|
-
carry(pk: string, bytes: Uint8Array): Promise<Uint8Array | null> {
|
|
25
|
-
return this.#world.carry(pk, bytes);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// The bodies a pointer terrain is built of, each the pointer's own where
|
|
30
|
-
// none is handed, save the defaults, which the core never names and an
|
|
31
|
-
// entry always hands.
|
|
32
|
-
export type PointerParts = {
|
|
33
|
-
entropy?: Entropy;
|
|
34
|
-
clock?: Clock;
|
|
35
|
-
custody?: Custody;
|
|
36
|
-
memory?: Memory;
|
|
37
|
-
carrier?: Carrier;
|
|
38
|
-
loader?: Loader;
|
|
39
|
-
tcp?: () => Sockets;
|
|
40
|
-
web?: WebServe;
|
|
41
|
-
defaults: Defaults;
|
|
42
|
-
wakes?: boolean;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export class PointerTerrain extends Terrain {
|
|
46
|
-
readonly entropy: Entropy;
|
|
47
|
-
readonly clock: Clock;
|
|
48
|
-
readonly custody: Custody;
|
|
49
|
-
readonly memory: Memory;
|
|
50
|
-
readonly carrier: Carrier;
|
|
51
|
-
readonly loader: Loader;
|
|
52
|
-
readonly defaults: Defaults;
|
|
53
|
-
override readonly tcp: (() => Sockets) | undefined;
|
|
54
|
-
override readonly web: WebServe | undefined;
|
|
55
|
-
override readonly wakes: boolean;
|
|
56
|
-
|
|
57
|
-
constructor(parts: PointerParts) {
|
|
58
|
-
super();
|
|
59
|
-
this.entropy = parts.entropy ?? new CryptoEntropy();
|
|
60
|
-
this.clock = parts.clock ?? new SystemClock();
|
|
61
|
-
this.custody = parts.custody ?? new HeldCustody(this.entropy);
|
|
62
|
-
this.memory = parts.memory ?? new VolatileMemory();
|
|
63
|
-
this.carrier = parts.carrier ?? new NoCarrier();
|
|
64
|
-
this.loader = parts.loader ?? new SourceLoader();
|
|
65
|
-
this.defaults = parts.defaults;
|
|
66
|
-
this.tcp = parts.tcp;
|
|
67
|
-
this.web = parts.web;
|
|
68
|
-
this.wakes = parts.wakes ?? true;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
type Place = { harbor: Harbor; terrain: Terrain };
|
|
73
|
-
|
|
74
|
-
// Bodies a harbor of a world is built of beside the world's own.
|
|
75
|
-
export type WorldParts = Partial<Omit<PointerParts, 'carrier'>>;
|
|
76
|
-
|
|
77
|
-
export class World {
|
|
78
|
-
readonly #places = new Map<string, Place>();
|
|
79
|
-
readonly #defaults: Defaults;
|
|
80
|
-
// Harbors the world reaches no one in, nor anyone out of.
|
|
81
|
-
readonly cut = new Set<string>();
|
|
82
|
-
|
|
83
|
-
// A world whose harbors run the defaults handed, unless one is handed
|
|
84
|
-
// others.
|
|
85
|
-
constructor(defaults: Defaults) {
|
|
86
|
-
this.#defaults = defaults;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// A harbor of this world. `parts` replaces the pointer bodies, a folder's
|
|
90
|
-
// memory and custody among them, and a bundle's loader for an engine
|
|
91
|
-
// that imports no source. The harbor runs only the modules its catalogue
|
|
92
|
-
// was told to add. The world holds it as a program does, so once it
|
|
93
|
-
// opens the world asks its `stand`.
|
|
94
|
-
async harbor(name: string, parts: WorldParts = {}): Promise<Harbor> {
|
|
95
|
-
if (this.#places.has(name)) throw new Error(`a harbor named ${name} stands`);
|
|
96
|
-
const terrain = new PointerTerrain({ defaults: this.#defaults, ...parts, carrier: new PointerCarrier(this) });
|
|
97
|
-
const harbor = await World.#standing(terrain);
|
|
98
|
-
this.#places.set(name, { harbor, terrain });
|
|
99
|
-
return harbor;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
static async #standing(terrain: Terrain): Promise<Harbor> {
|
|
103
|
-
const harbor = await Harbor.open(terrain);
|
|
104
|
-
await harbor.ask({ method: 'stand' });
|
|
105
|
-
return harbor;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
get(name: string): Harbor {
|
|
109
|
-
const place = this.#places.get(name);
|
|
110
|
-
if (!place) throw new Error(`no harbor named ${name}`);
|
|
111
|
-
return place.harbor;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// The harbor opened again on its own terrain. `parts` replaces bodies of
|
|
115
|
-
// the terrain, as a new process would build them over the same disk, or
|
|
116
|
-
// with other code.
|
|
117
|
-
async restart(name: string, parts?: WorldParts): Promise<Harbor> {
|
|
118
|
-
const place = this.#places.get(name);
|
|
119
|
-
if (!place) throw new Error(`no harbor named ${name}`);
|
|
120
|
-
const t = place.terrain;
|
|
121
|
-
const kept = { entropy: t.entropy, clock: t.clock, custody: t.custody, memory: t.memory, loader: t.loader, defaults: t.defaults, ...(t.tcp ? { tcp: t.tcp } : {}), ...(t.web ? { web: t.web } : {}) };
|
|
122
|
-
const terrain = parts ? new PointerTerrain({ ...kept, ...parts, carrier: t.carrier }) : t;
|
|
123
|
-
const harbor = await World.#standing(terrain);
|
|
124
|
-
this.#places.set(name, { harbor, terrain });
|
|
125
|
-
return harbor;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
carry(pk: string, bytes: Uint8Array): Promise<Uint8Array | null> {
|
|
129
|
-
for (const [name, { harbor }] of this.#places) {
|
|
130
|
-
if (harbor.holds(pk)) return this.cut.has(name) ? Promise.resolve(null) : harbor.arrive(pk, bytes);
|
|
131
|
-
}
|
|
132
|
-
return Promise.resolve(null);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The suites of the bodies, Custody, Memory, Entropy and Loader, as scenes
|
|
3
|
-
// with no platform under them, so Node's runner, every engine and a
|
|
4
|
-
// stranger's own runner hold a body to the same assertions.
|
|
5
|
-
import { Custody, Entropy, Loader, Memory } from '../contract/index.ts';
|
|
6
|
-
import type { Expect } from './expect.ts';
|
|
7
|
-
|
|
8
|
-
export type Scene = [string, () => Promise<void>];
|
|
9
|
-
|
|
10
|
-
const bytes = (...values: number[]): Uint8Array => Uint8Array.from(values);
|
|
11
|
-
// A place as plain values, in name order, so two can be compared as JSON.
|
|
12
|
-
const plain = (place: ReadonlyMap<string, Uint8Array>): [string, number[]][] => [...place].map(([n, b]): [string, number[]] => [n, [...b]]).sort(([a], [b]) => (a < b ? -1 : 1));
|
|
13
|
-
|
|
14
|
-
// `make` gives two bodies over one keeping, as two runs would build them,
|
|
15
|
-
// and a fresh keeping each call.
|
|
16
|
-
export const custodyScenes = (name: string, make: () => [Custody, Custody], expect: Expect): Scene[] => [
|
|
17
|
-
[
|
|
18
|
-
`[contract] ${name} fulfils Custody: one seed of thirty-two bytes, the same every time`,
|
|
19
|
-
async () => {
|
|
20
|
-
const [custody, again] = make();
|
|
21
|
-
expect.ok(custody instanceof Custody);
|
|
22
|
-
const seed = await custody.seed();
|
|
23
|
-
expect.equal(seed.length, 32);
|
|
24
|
-
const first = [...seed];
|
|
25
|
-
seed.fill(0);
|
|
26
|
-
expect.same([...(await custody.seed())], first, 'a seed handed out is a copy');
|
|
27
|
-
expect.same([...(await again.seed())], first, 'another body over the keeping holds the same');
|
|
28
|
-
expect.ok([...(await make()[0].seed())].join() !== first.join(), 'another keeping holds another seed');
|
|
29
|
-
const [fresh, rival] = make();
|
|
30
|
-
const [a, b] = await Promise.all([fresh.seed(), rival.seed()]);
|
|
31
|
-
expect.same([...a], [...b], 'two first asks at once keep one seed');
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
// `cut` is a body whose next keep stops partway, as a run that dies inside
|
|
37
|
-
// one does, and `fresh` the memory a new run opens on the same keeping. A
|
|
38
|
-
// body no crash can cut short, holding its places in one object, names
|
|
39
|
-
// none.
|
|
40
|
-
export type Cut = { cut: Memory; fresh: Memory };
|
|
41
|
-
|
|
42
|
-
export const memoryScenes = (name: string, make: () => [Memory, Memory], expect: Expect, half?: () => Cut): Scene[] => [
|
|
43
|
-
[
|
|
44
|
-
`[contract] ${name} fulfils Memory: it names its places, and forgets one whole`,
|
|
45
|
-
async () => {
|
|
46
|
-
const [memory, again] = make();
|
|
47
|
-
expect.same(await memory.places(), []);
|
|
48
|
-
await memory.write('aa', new Map([['01', bytes(1)]]));
|
|
49
|
-
await memory.write('bb', new Map([['01', bytes(2)], ['02', bytes(3)]]));
|
|
50
|
-
expect.same([...(await again.places())].sort(), ['aa', 'bb']);
|
|
51
|
-
await memory.forget('aa');
|
|
52
|
-
expect.same(await again.places(), ['bb']);
|
|
53
|
-
expect.same(plain(await again.read('aa')), []);
|
|
54
|
-
await memory.forget('aa');
|
|
55
|
-
await memory.write('bb', new Map([['01', null], ['02', null]]));
|
|
56
|
-
expect.same(await again.places(), [], 'a place holding nothing is no place');
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
...(half
|
|
60
|
-
? [
|
|
61
|
-
[
|
|
62
|
-
`[contract] ${name} fulfils Memory: a keep that stops partway is whole or is nothing`,
|
|
63
|
-
async () => {
|
|
64
|
-
const { cut, fresh } = half();
|
|
65
|
-
await cut.write('aa', new Map([['01', bytes(1)], ['02', bytes(2)]])).catch(() => undefined);
|
|
66
|
-
const before = plain(await fresh.read('aa'));
|
|
67
|
-
await cut.write('aa', new Map([['01', bytes(9)], ['02', null], ['03', bytes(3)]])).catch(() => undefined);
|
|
68
|
-
const after = JSON.stringify(plain(await fresh.read('aa')));
|
|
69
|
-
const whole = JSON.stringify(plain(new Map([['01', bytes(9)], ['03', bytes(3)]])));
|
|
70
|
-
expect.ok(after === JSON.stringify(before) || after === whole, `a keep cut short left ${after}`);
|
|
71
|
-
},
|
|
72
|
-
] satisfies Scene,
|
|
73
|
-
]
|
|
74
|
-
: []),
|
|
75
|
-
[
|
|
76
|
-
`[contract] ${name} fulfils Memory: a place read again holds what was kept, and nothing else`,
|
|
77
|
-
async () => {
|
|
78
|
-
const [memory, again] = make();
|
|
79
|
-
expect.ok(memory instanceof Memory);
|
|
80
|
-
expect.same(plain(await memory.read('aa')), []);
|
|
81
|
-
const written = bytes(1, 2, 3);
|
|
82
|
-
await memory.write('aa', new Map([['01', written], ['02', bytes(4)]]));
|
|
83
|
-
written[0] = 9;
|
|
84
|
-
await memory.write('bb', new Map([['01', bytes(5)]]));
|
|
85
|
-
await memory.write('aa', new Map([['02', null], ['03', bytes()], ['04', null]]));
|
|
86
|
-
const read = await again.read('aa');
|
|
87
|
-
expect.same(plain(read), [['01', [1, 2, 3]], ['03', []]]);
|
|
88
|
-
expect.ok(read.get('01') instanceof Uint8Array, 'an entry is bytes');
|
|
89
|
-
read.get('01')![0] = 7;
|
|
90
|
-
expect.same([...(await memory.read('aa')).get('01')!], [1, 2, 3], 'an entry handed out is a copy');
|
|
91
|
-
expect.same(plain(await again.read('bb')), [['01', [5]]]);
|
|
92
|
-
expect.same(plain(await again.read('cc')), []);
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
export const entropyScenes = (name: string, make: () => Entropy, expect: Expect): Scene[] => [
|
|
98
|
-
[
|
|
99
|
-
`[contract] ${name} fulfils Entropy: bytes of the length asked, never the same twice`,
|
|
100
|
-
() => {
|
|
101
|
-
const entropy = make();
|
|
102
|
-
expect.ok(entropy instanceof Entropy);
|
|
103
|
-
expect.equal(entropy.draw(0).length, 0);
|
|
104
|
-
expect.equal(entropy.drawer(33).length, 33);
|
|
105
|
-
expect.ok([...entropy.draw(32)].join() !== [...entropy.draw(32)].join(), 'two draws differ');
|
|
106
|
-
return Promise.resolve();
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
];
|
|
110
|
-
|
|
111
|
-
// A module's source as bytes and its blob's git id, the two things a
|
|
112
|
-
// loader is handed.
|
|
113
|
-
export type Source = { source: string; id: string };
|
|
114
|
-
|
|
115
|
-
// `make` gives a loader, a module's source it runs, and a source it
|
|
116
|
-
// refuses: one that does not load, or, for a bundle, one it does not carry.
|
|
117
|
-
export const loaderScenes = (name: string, make: () => { loader: Loader; found: Source; refused: Source }, expect: Expect): Scene[] => [
|
|
118
|
-
[
|
|
119
|
-
`[contract] ${name} fulfils Loader: a module's source becomes that module, the same again, and a source it cannot run throws`,
|
|
120
|
-
async () => {
|
|
121
|
-
const { loader, found, refused } = make();
|
|
122
|
-
expect.ok(loader instanceof Loader);
|
|
123
|
-
const loaded = await loader.load(found.source, found.id);
|
|
124
|
-
expect.equal(typeof loaded.module, 'string');
|
|
125
|
-
expect.equal(typeof loaded.version, 'string');
|
|
126
|
-
expect.ok(Array.isArray(loaded.classes) && loaded.classes.length > 0 && loaded.classes.every((C) => typeof C === 'function'), 'the classes are classes');
|
|
127
|
-
const again = await loader.load(found.source, found.id);
|
|
128
|
-
expect.same({ module: again.module, version: again.version }, { module: loaded.module, version: loaded.version });
|
|
129
|
-
let said = '';
|
|
130
|
-
await loader.load(refused.source, refused.id).catch((e: Error) => (said = e.message));
|
|
131
|
-
expect.ok(said !== '', 'a source it cannot run throws, saying why');
|
|
132
|
-
},
|
|
133
|
-
],
|
|
134
|
-
];
|
package/src/core/proof/expect.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The few assertions a scene needs, with no platform under them, so the
|
|
3
|
-
// same scene runs in Node's runner and inside any other engine.
|
|
4
|
-
export type Expect = {
|
|
5
|
-
equal(actual: unknown, expected: unknown, message?: string): void;
|
|
6
|
-
same(actual: unknown, expected: unknown, message?: string): void;
|
|
7
|
-
ok(value: unknown, message?: string): void;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const fail = (message: string | undefined, detail: string): never => {
|
|
11
|
-
throw new Error(`${message ? `${message}: ` : ''}${detail}`);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const expect: Expect = {
|
|
15
|
-
equal: (actual, expected, message) => {
|
|
16
|
-
if (!Object.is(actual, expected)) fail(message, `${String(actual)} is not ${String(expected)}`);
|
|
17
|
-
},
|
|
18
|
-
same: (actual, expected, message) => {
|
|
19
|
-
const [a, b] = [JSON.stringify(actual), JSON.stringify(expected)];
|
|
20
|
-
if (a !== b) fail(message, `${a} is not ${b}`);
|
|
21
|
-
},
|
|
22
|
-
ok: (value, message) => {
|
|
23
|
-
if (!value) fail(message, 'not true');
|
|
24
|
-
},
|
|
25
|
-
};
|