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
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The harbor: the onion, unpacked from a terrain alone, in three levels.
|
|
3
|
-
// Each level stands the next and leaves it alone.
|
|
4
|
-
//
|
|
5
|
-
// L1, the boot, the harbor's own, the core alone
|
|
6
|
-
// the seed and the package the harbor's one secret, from custody,
|
|
7
|
-
// opens its sealed memory, the vault
|
|
8
|
-
// the box ward unpacked as every ward is, under the
|
|
9
|
-
// harbor's seed, no being standing yet
|
|
10
|
-
// the catalogue the core's registry, stood from the core
|
|
11
|
-
// on empty memory and from her row after;
|
|
12
|
-
// every module the commit `live` names is
|
|
13
|
-
// run through the terrain's loader
|
|
14
|
-
// the registries every box faculty the catalogue resolves
|
|
15
|
-
// to a registry, where her row names the
|
|
16
|
-
// catalogue as hers
|
|
17
|
-
// the dock the box ward's ward, of the class her row
|
|
18
|
-
// names through its registry, the default
|
|
19
|
-
// dock where it does not stand; the door is
|
|
20
|
-
// hers from here, and `open` returns
|
|
21
|
-
// L2, the dock's her `stand` ask: every other faculty, the
|
|
22
|
-
// routes, and every hosted ward, each ward
|
|
23
|
-
// standing on the class, the registry and
|
|
24
|
-
// the memory the dock keeps for it
|
|
25
|
-
// L3, each ward's beings born from her rows for the asks that
|
|
26
|
-
// reach them, and dropped after; nothing
|
|
27
|
-
// stands them
|
|
28
|
-
//
|
|
29
|
-
// L1 is one call and no ask can make it. After it the harbor takes asks
|
|
30
|
-
// alone. Whoever holds a harbor has five things of it and no other:
|
|
31
|
-
//
|
|
32
|
-
// Harbor.open(terrain?) the boot
|
|
33
|
-
// ask(request) the root line, a ward asked as its root
|
|
34
|
-
// arrive(pk, box) a Quo box at one of its doors
|
|
35
|
-
// holds(pk) whether one of its doors is that ward's
|
|
36
|
-
// close() every carrier asleep, and the ground let go
|
|
37
|
-
//
|
|
38
|
-
// What stands inside it, the wards, the dock, the catalogue and the
|
|
39
|
-
// carriers, is reached by an ask and never by a hand. The box ward's
|
|
40
|
-
// stance carries the harbor's `ground`, the one thing the dock, the
|
|
41
|
-
// catalogue and every faculty of the box are handed.
|
|
42
|
-
//
|
|
43
|
-
// The harbor fails only where the seed or the box ward's own place cannot
|
|
44
|
-
// be read, or the catalogue does not stand. A module, a registry, a
|
|
45
|
-
// faculty, a route, a hosted ward or a being that cannot stand fails
|
|
46
|
-
// alone, and the census names it.
|
|
47
|
-
//
|
|
48
|
-
// Genesis and wake are one path: on empty memory the box ward holds no
|
|
49
|
-
// catalogue, and the harbor writes her from the core; the root's asks
|
|
50
|
-
// write the rest, and nothing enters unasked.
|
|
51
|
-
import { isSilence, isWord, told, type BeingClass, type Invitation, type Json, type JsonObject } from '../being/index.ts';
|
|
52
|
-
import type { Carrier } from '../contract/index.ts';
|
|
53
|
-
import { hex, isHex, unhex } from '../crypto/index.ts';
|
|
54
|
-
import { unspecified, WardKey } from '../quo/index.ts';
|
|
55
|
-
import { DOCK, House, type Classes, type HouseParts, type Routes, type WardClass } from '../ward/index.ts';
|
|
56
|
-
import { Catalogue, CATALOGUE, type Cataloguing } from './catalogue.ts';
|
|
57
|
-
import { CarrierFaculty, UNDIALED, type Ground } from './carrying.ts';
|
|
58
|
-
import { BOX, Dock, hostable, type Failures, type Hosted, type Hosting } from './dock.ts';
|
|
59
|
-
import { Dna } from './dna.ts';
|
|
60
|
-
import { Package, type Keeper } from './package.ts';
|
|
61
|
-
import { MemoryFaculty } from './memory.ts';
|
|
62
|
-
import { registers, RegistryFaculty } from './registry.ts';
|
|
63
|
-
import { probeGround, type Probing } from './probe.ts';
|
|
64
|
-
import { readRootRequest } from './root-line.ts';
|
|
65
|
-
import { Terrain, type Defaults } from './terrain.ts';
|
|
66
|
-
|
|
67
|
-
// The box ward's ward is a dock, the terrain's default at genesis and
|
|
68
|
-
// while her row's kind does not resolve.
|
|
69
|
-
const boxWard = ({ dock }: Defaults): WardClass => ({ genesis: dock.kind, contract: 'dock', fits: (C) => Dock.fulfils(C), fallback: dock });
|
|
70
|
-
|
|
71
|
-
// A hosted ward's ward is a ward and no dock, of the kind `host` named or
|
|
72
|
-
// the terrain's default at genesis.
|
|
73
|
-
const hostedWard = ({ ward }: Defaults, kind: string = ward.kind): WardClass => ({ genesis: kind, contract: 'hosted ward', fits: hostable });
|
|
74
|
-
|
|
75
|
-
// What the box ward's stance carries: the dock hosts through it, the
|
|
76
|
-
// catalogue runs code through it, and every faculty of the box reaches its
|
|
77
|
-
// terrain and the harbor's doors through it.
|
|
78
|
-
export type HarborGround = Hosting & Cataloguing & Ground;
|
|
79
|
-
|
|
80
|
-
export class Harbor {
|
|
81
|
-
readonly #terrain: Terrain;
|
|
82
|
-
readonly #package: Package;
|
|
83
|
-
readonly #wards = new Map<string, House>();
|
|
84
|
-
readonly #failed: Failures = { wards: {}, routes: {} };
|
|
85
|
-
readonly #ground: HarborGround;
|
|
86
|
-
// Every ward speaks through the harbor: a pk of one of its doors goes to
|
|
87
|
-
// that door, any other along its route or to the terrain's carrier.
|
|
88
|
-
readonly #carrier: Carrier = { carry: (pk, bytes) => this.#carry(pk, bytes) };
|
|
89
|
-
// Every class a row names, through the registry faculty of the box the
|
|
90
|
-
// row names, or the catalogue.
|
|
91
|
-
readonly #classes: Classes = { classOf: (kind, registry) => this.#classOf(kind, registry) };
|
|
92
|
-
|
|
93
|
-
private constructor(terrain: Terrain, pack: Package) {
|
|
94
|
-
const { dock, ward, classes } = terrain.defaults;
|
|
95
|
-
if (!Dock.fulfils(dock)) throw new Error('the default dock is no dock');
|
|
96
|
-
if (!hostable(ward)) throw new Error('the default ward is no hosted ward');
|
|
97
|
-
this.#terrain = terrain;
|
|
98
|
-
this.#package = pack;
|
|
99
|
-
const dna = new Dna(terrain.memory, pack);
|
|
100
|
-
// The kit's classes the catalogue resolves: her own, the core's alone,
|
|
101
|
-
// then the defaults the terrain hands in.
|
|
102
|
-
const kit = [Catalogue, dock, ward, ...classes];
|
|
103
|
-
this.#ground = {
|
|
104
|
-
terrain,
|
|
105
|
-
dna,
|
|
106
|
-
kit,
|
|
107
|
-
foreground: terrain.foreground,
|
|
108
|
-
arrive: (pk, bytes) => this.arrive(pk, bytes),
|
|
109
|
-
host: (name, invitation, seed, memory, kind, registry) => this.#host(name, invitation, seed, memory, kind, registry),
|
|
110
|
-
stand: (hosted) => this.#stand(hosted),
|
|
111
|
-
move: (name, seed, from, to) => this.#move(name, seed, from, to),
|
|
112
|
-
release: async (name, memory) => this.#keeper(memory).forget(await this.#package.place(name)),
|
|
113
|
-
route: (pk, at) => this.#route(pk, at),
|
|
114
|
-
reached: (pk, at) => {
|
|
115
|
-
if (!this.#dialable(at)) this.#failed.routes[pk] = 'no carrier dials it';
|
|
116
|
-
},
|
|
117
|
-
keep: () => this.#box.partition.kept(),
|
|
118
|
-
failures: () => this.#failures(),
|
|
119
|
-
sweep: () => this.#sweep(),
|
|
120
|
-
awaken: async (key) => {
|
|
121
|
-
const being = this.#box.being(key);
|
|
122
|
-
if (being instanceof CarrierFaculty) await being.awake();
|
|
123
|
-
},
|
|
124
|
-
rouse: async (key) => {
|
|
125
|
-
if (terrain.wakes) await this.#ground.awaken(key);
|
|
126
|
-
},
|
|
127
|
-
lull: async (key) => {
|
|
128
|
-
const being = this.#box.being(key);
|
|
129
|
-
if (being instanceof CarrierFaculty) await being.sleep();
|
|
130
|
-
},
|
|
131
|
-
listening: () => this.#carriers.flatMap((carrier) => carrier.listening()),
|
|
132
|
-
heard: async () => {
|
|
133
|
-
await Promise.all(this.#carriers.map((carrier) => carrier.heard()));
|
|
134
|
-
},
|
|
135
|
-
ran: () => {
|
|
136
|
-
for (const house of this.#wards.values()) house.renew();
|
|
137
|
-
return Promise.resolve();
|
|
138
|
-
},
|
|
139
|
-
stands: (kinds) => [...this.#wards.values()].some((house) => Object.values(house.partition.beings).some((row) => kinds.includes(row.class))),
|
|
140
|
-
kept: () => [...new Set([...this.#wards.values()].flatMap((house) => Object.values(house.partition.beings).map((row) => row.class)))],
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// A harbor on the terrain handed in, or, with none, on the ground the
|
|
145
|
-
// probe finds here. A ground another run holds refuses, and what the
|
|
146
|
-
// ground serves beside the harbor stands once it is whole.
|
|
147
|
-
static async open(from: Terrain | Probing = {}): Promise<Harbor> {
|
|
148
|
-
const terrain = from instanceof Terrain ? from : probeGround(from).terrain;
|
|
149
|
-
await terrain.claim();
|
|
150
|
-
let harbor: Harbor;
|
|
151
|
-
try {
|
|
152
|
-
harbor = await Harbor.#boot(terrain);
|
|
153
|
-
} catch (e) {
|
|
154
|
-
await terrain.release();
|
|
155
|
-
throw e;
|
|
156
|
-
}
|
|
157
|
-
try {
|
|
158
|
-
await terrain.stand(harbor);
|
|
159
|
-
} catch (e) {
|
|
160
|
-
await harbor.close();
|
|
161
|
-
throw e;
|
|
162
|
-
}
|
|
163
|
-
return harbor;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// L1, the one call no ask makes, ending with the door handed to the dock.
|
|
167
|
-
// What stands beyond it stands because someone asked `stand`.
|
|
168
|
-
static async #boot(terrain: Terrain): Promise<Harbor> {
|
|
169
|
-
const seed = await terrain.custody.seed();
|
|
170
|
-
const harbor = new Harbor(terrain, await Package.open(terrain.memory, terrain.entropy, seed));
|
|
171
|
-
const box = await harbor.#unpack(BOX, seed, { ward: boxWard(terrain.defaults), carries: { ground: harbor.#ground }, classes: harbor.#classes, stands: true });
|
|
172
|
-
if (box.partition.being(CATALOGUE)) box.stand(CATALOGUE);
|
|
173
|
-
else if ((await box.make(CATALOGUE, Catalogue.kind)) !== 'booted' || !(await box.partition.kept())) throw new Error('the catalogue did not stand');
|
|
174
|
-
const catalogue = box.being(CATALOGUE);
|
|
175
|
-
if (!(catalogue instanceof Catalogue)) throw new Error('the catalogue did not stand');
|
|
176
|
-
await catalogue.wake();
|
|
177
|
-
for (const [key, row] of Object.entries(box.partition.beings)) {
|
|
178
|
-
if (row.registry === undefined && registers(catalogue.classOf(row.class))) box.stand(key);
|
|
179
|
-
}
|
|
180
|
-
await box.standWard();
|
|
181
|
-
return harbor;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// The root line: one request, `{ ward?, method?, args? }`, asked of the
|
|
185
|
-
// box ward or the hosted ward named as its root, and one plain JSON
|
|
186
|
-
// answer, whatever front carried it.
|
|
187
|
-
//
|
|
188
|
-
// { answer } what the ward said
|
|
189
|
-
// { silence: true } she said nothing
|
|
190
|
-
// { word } a kit word: unreached, late, ...
|
|
191
|
-
// { error } the request was none, or names no ward that
|
|
192
|
-
// stands, with the reason one did not
|
|
193
|
-
async ask(value: unknown): Promise<JsonObject> {
|
|
194
|
-
const request = readRootRequest(value);
|
|
195
|
-
if (request === null) return { error: 'not a root request' };
|
|
196
|
-
const ward = request.ward === undefined ? this.#box : this.#wards.get(request.ward);
|
|
197
|
-
if (ward === undefined) {
|
|
198
|
-
const failed = this.#failures().wards[request.ward!];
|
|
199
|
-
return failed === undefined ? { error: 'no such ward' } : { error: 'the ward did not stand', reason: failed };
|
|
200
|
-
}
|
|
201
|
-
const out = await ward.root(request.method, request.args);
|
|
202
|
-
if (isSilence(out)) return { silence: true };
|
|
203
|
-
if (isWord(out)) return { word: told(out) as string };
|
|
204
|
-
return { answer: out as Json };
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Bytes for one of this harbor's doors, or for a ward a relay of this
|
|
208
|
-
// harbor answers for, or nothing.
|
|
209
|
-
async arrive(pk: string, bytes: Uint8Array): Promise<Uint8Array | null> {
|
|
210
|
-
const ward = this.#door(pk);
|
|
211
|
-
if (ward) return (await ward.door.arrive(bytes)).bytes;
|
|
212
|
-
return (await this.#relaying(pk)?.relay(pk, bytes)) ?? null;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Whether one of this harbor's doors is that ward's.
|
|
216
|
-
holds(pk: string): boolean {
|
|
217
|
-
return this.#door(pk) !== undefined;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Every carrier asleep, the last opened first: nothing listens and no
|
|
221
|
-
// line stays open.
|
|
222
|
-
async close(): Promise<void> {
|
|
223
|
-
for (const carrier of this.#carriers.reverse()) await carrier.sleep();
|
|
224
|
-
await this.#terrain.release();
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
get #box(): House {
|
|
228
|
-
return this.#wards.get(BOX)!;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
get #dock(): Dock {
|
|
232
|
-
return this.#box.ward as Dock;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// A kind, through the registry faculty of the box named, or the
|
|
236
|
-
// catalogue. The catalogue's own kind is the core's, and resolves before
|
|
237
|
-
// any registry stands.
|
|
238
|
-
#classOf(kind: string, registry: string = CATALOGUE): BeingClass | undefined {
|
|
239
|
-
if (kind === Catalogue.kind) return Catalogue;
|
|
240
|
-
const found = this.#wards.get(BOX)?.being(registry);
|
|
241
|
-
return found instanceof RegistryFaculty ? found.classOf(kind) : undefined;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// The classes of a hosted ward, every one through the registry the dock
|
|
245
|
-
// keeps for it.
|
|
246
|
-
#through(registry: string | undefined): Classes {
|
|
247
|
-
return { classOf: (kind) => this.#classOf(kind, registry) };
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// A hosted ward standing, as the dock's cells name it.
|
|
251
|
-
async #stand(hosted: Hosted): Promise<boolean> {
|
|
252
|
-
const fresh = !this.#wards.has(hosted.ward);
|
|
253
|
-
try {
|
|
254
|
-
if (fresh) await this.#unpack(hosted.ward, unhex(hosted.seed), { ward: hostedWard(this.#terrain.defaults), classes: this.#through(hosted.registry) }, this.#keeper(hosted.memory));
|
|
255
|
-
await this.#wards.get(hosted.ward)!.standWard();
|
|
256
|
-
delete this.#failed.wards[hosted.ward];
|
|
257
|
-
return fresh;
|
|
258
|
-
} catch (e) {
|
|
259
|
-
this.#wards.delete(hosted.ward);
|
|
260
|
-
this.#failed.wards[hosted.ward] = e instanceof Error ? e.message : String(e);
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Every place of the root memory and of each memory faculty that the
|
|
266
|
-
// dock does not name there, gone. A crash inside `host` or `move` leaves
|
|
267
|
-
// such a place, sealed under a seed nothing kept or kept elsewhere, and
|
|
268
|
-
// nothing else writes one. A place a memory faculty keeps in the root
|
|
269
|
-
// memory is the memory faculty's.
|
|
270
|
-
async #sweep(): Promise<string[]> {
|
|
271
|
-
const named = async (memory: string | undefined): Promise<Set<string>> => {
|
|
272
|
-
const wards = this.#dock.hosted.filter((h) => h.memory === memory).map((h) => h.ward);
|
|
273
|
-
return new Set(await Promise.all((memory === undefined ? [BOX, ...wards] : wards).map((name) => this.#package.place(name))));
|
|
274
|
-
};
|
|
275
|
-
const memories = this.#memories();
|
|
276
|
-
const swept: string[] = [];
|
|
277
|
-
const root = await named(undefined);
|
|
278
|
-
for (const place of await this.#terrain.memory.places()) {
|
|
279
|
-
if (root.has(place) || Dna.occupies(place) || memories.some(([, s]) => s.occupies(place))) continue;
|
|
280
|
-
await this.#terrain.memory.forget(place);
|
|
281
|
-
swept.push(place);
|
|
282
|
-
}
|
|
283
|
-
for (const [key, memory] of memories) {
|
|
284
|
-
const mine = await named(key);
|
|
285
|
-
for (const place of await memory.places()) {
|
|
286
|
-
if (mine.has(place)) continue;
|
|
287
|
-
await memory.forget(place);
|
|
288
|
-
swept.push(place);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return swept;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// A standing ward, carried whole to another keeper. The ward leaves the
|
|
295
|
-
// harbor's doors while it moves, so no arrival lands on the keeper it
|
|
296
|
-
// leaves.
|
|
297
|
-
async #move(name: string, seed: string, from: string | undefined, to: string | undefined): Promise<string | null> {
|
|
298
|
-
const ward = this.#wards.get(name);
|
|
299
|
-
if (!ward) return 'the ward does not stand';
|
|
300
|
-
const source = this.#keeper(from);
|
|
301
|
-
const target = this.#keeper(to);
|
|
302
|
-
this.#wards.delete(name);
|
|
303
|
-
try {
|
|
304
|
-
if (!(await ward.partition.kept())) throw new Error('the ward was not kept');
|
|
305
|
-
const place = await this.#package.place(name);
|
|
306
|
-
const entries = new Map<string, Uint8Array | null>(await source.read(place));
|
|
307
|
-
for (const entry of (await target.read(place)).keys()) if (!entries.has(entry)) entries.set(entry, null);
|
|
308
|
-
await target.write(place, entries);
|
|
309
|
-
const registry = this.#dock.hosted.find((h) => h.ward === name)?.registry;
|
|
310
|
-
const moved = await this.#unpack(name, unhex(seed), { ward: hostedWard(this.#terrain.defaults), classes: this.#through(registry) }, target);
|
|
311
|
-
await moved.standWard();
|
|
312
|
-
return null;
|
|
313
|
-
} catch (e) {
|
|
314
|
-
this.#wards.set(name, ward);
|
|
315
|
-
return e instanceof Error ? e.message : String(e);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// The root memory, or the memory faculty standing under the key named.
|
|
320
|
-
#keeper(memory: string | undefined): Keeper {
|
|
321
|
-
if (memory === undefined) return this.#terrain.memory;
|
|
322
|
-
const being = this.#box.being(memory);
|
|
323
|
-
if (being instanceof MemoryFaculty) return being;
|
|
324
|
-
throw new Error(`the memory faculty ${memory} does not stand`);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
#memories(): [string, MemoryFaculty][] {
|
|
328
|
-
return Object.keys(this.#box.partition.beings).flatMap((key): [string, MemoryFaculty][] => {
|
|
329
|
-
const being = this.#box.being(key);
|
|
330
|
-
return being instanceof MemoryFaculty ? [[key, being]] : [];
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// What did not stand when the harbor opened, each alone, and why the box
|
|
335
|
-
// ward stands the default dock where her row names another.
|
|
336
|
-
#failures(): Failures {
|
|
337
|
-
const fault = this.#box.fault;
|
|
338
|
-
return { wards: { ...this.#failed.wards, ...(fault === null ? {} : { [BOX]: fault }) }, routes: { ...this.#failed.routes } };
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// This harbor's own doors and relays first, then a route's addresses in
|
|
342
|
-
// order, each to the carrier that dials it, and with no route the
|
|
343
|
-
// terrain's carrier.
|
|
344
|
-
async #carry(pk: string, bytes: Uint8Array): Promise<Uint8Array | null> {
|
|
345
|
-
if (this.holds(pk) || this.#relaying(pk)) return this.arrive(pk, bytes);
|
|
346
|
-
const at = this.#dock.routes[pk];
|
|
347
|
-
if (at === undefined) return this.#terrain.carrier.carry(pk, bytes);
|
|
348
|
-
for (const address of at) {
|
|
349
|
-
const carrier = this.#carriers.find((c) => c.accepts(address));
|
|
350
|
-
const out = carrier ? await carrier.dial(address, pk, bytes) : UNDIALED;
|
|
351
|
-
if (out !== UNDIALED) return out;
|
|
352
|
-
}
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// A ward the dock hosts stands now, under the seed named or a drawn one,
|
|
357
|
-
// and the seed it stands under comes back. A ward whose key another ward
|
|
358
|
-
// of this harbor already has does not stand.
|
|
359
|
-
async #host(name: string, invitation: Invitation, seed?: string, memory?: string, kind?: string, registry?: string): Promise<string | null> {
|
|
360
|
-
if (this.#wards.has(name)) return null;
|
|
361
|
-
const bytes = seed === undefined ? this.#terrain.entropy.draw(32) : isHex(seed, 32) ? unhex(seed) : null;
|
|
362
|
-
if (bytes === null || this.holds((await WardKey.from(bytes)).pk)) return null;
|
|
363
|
-
let house: House;
|
|
364
|
-
try {
|
|
365
|
-
house = await this.#unpack(name, bytes, { dock: invitation, ward: hostedWard(this.#terrain.defaults, kind), classes: this.#through(registry) }, this.#keeper(memory));
|
|
366
|
-
await house.standWard();
|
|
367
|
-
} catch {
|
|
368
|
-
this.#wards.delete(name);
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
371
|
-
if (!house.ward.stance.standings.get(DOCK)) {
|
|
372
|
-
this.#wards.delete(name);
|
|
373
|
-
return null;
|
|
374
|
-
}
|
|
375
|
-
return hex(bytes);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// A route is taken where a carrier of this harbor dials one of its
|
|
379
|
-
// addresses; forgetting one always is.
|
|
380
|
-
#route(pk: string, at: readonly string[] | null): boolean {
|
|
381
|
-
const taken = isHex(pk, 64) && (at === null || this.#dialable(at));
|
|
382
|
-
if (taken) delete this.#failed.routes[pk];
|
|
383
|
-
return taken;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// The carrier faculties standing in the box ward.
|
|
387
|
-
get #carriers(): CarrierFaculty[] {
|
|
388
|
-
return Object.keys(this.#box.partition.beings)
|
|
389
|
-
.map((key) => this.#box.being(key))
|
|
390
|
-
.filter((being): being is CarrierFaculty => being instanceof CarrierFaculty);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
#relaying(pk: string): CarrierFaculty | undefined {
|
|
394
|
-
return this.#carriers.find((carrier) => carrier.relays(pk));
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
#dialable(at: readonly string[]): boolean {
|
|
398
|
-
return at.some((address) => this.#carriers.some((carrier) => carrier.accepts(address)));
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
async #unpack(name: string, seed: Uint8Array, own: Pick<HouseParts, 'dock' | 'ward' | 'carries' | 'classes' | 'stands'>, keeper?: Keeper): Promise<House> {
|
|
402
|
-
const { entropy, clock } = this.#terrain;
|
|
403
|
-
const ward = await House.unpack({
|
|
404
|
-
seed,
|
|
405
|
-
memory: await this.#package.rows(name, keeper),
|
|
406
|
-
entropy,
|
|
407
|
-
clock,
|
|
408
|
-
carrier: this.#carrier,
|
|
409
|
-
routes: this.#routes,
|
|
410
|
-
...own,
|
|
411
|
-
});
|
|
412
|
-
this.#wards.set(name, ward);
|
|
413
|
-
return ward;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// Every ward is reached where the harbor is: where the root's `reach`
|
|
417
|
-
// says, and where it said nothing, where its carriers listen, save the
|
|
418
|
-
// unspecified host. What a ward learns from an invitation's `at` is the
|
|
419
|
-
// dock's to keep. A ward of this harbor needs no route.
|
|
420
|
-
readonly #routes: Routes = {
|
|
421
|
-
reach: () => {
|
|
422
|
-
if (!this.#wards.has(BOX)) return [];
|
|
423
|
-
const set = this.#dock.addresses;
|
|
424
|
-
return set.length > 0 ? set : this.#carriers.flatMap((carrier) => carrier.listening()).filter((address) => !unspecified(address));
|
|
425
|
-
},
|
|
426
|
-
learn: (ward, at) => (this.holds(ward) ? Promise.resolve() : this.#dock.learn(ward, at)),
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
#door(pk: string): House | undefined {
|
|
430
|
-
for (const ward of this.#wards.values()) if (ward.pk === pk) return ward;
|
|
431
|
-
return undefined;
|
|
432
|
-
}
|
|
433
|
-
}
|
package/src/core/harbor/index.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The onion: a terrain, the package, the dock, the catalogue and its
|
|
3
|
-
// registry, and the harbor.
|
|
4
|
-
export { Catalogue, CATALOGUE, type Cataloguing } from './catalogue.ts';
|
|
5
|
-
export { Dna } from './dna.ts';
|
|
6
|
-
export { BOX, Dock, type DockStance, type Failures, type Hosted, type Hosting } from './dock.ts';
|
|
7
|
-
export { CarrierFaculty, carrierIn, groundOf, UNDIALED, type Arrivals, type Dialed, type Ground, type Sockets, type TcpListening, type WebListen, type WebListener, type WebServe } from './carrying.ts';
|
|
8
|
-
export { Harbor } from './harbor.ts';
|
|
9
|
-
export { carryPlaces, copyPackage, landPlaces, Package, readCarried, type Carried } from './package.ts';
|
|
10
|
-
export { readRootRequest, type RootRequest } from './root-line.ts';
|
|
11
|
-
export { addGround, grounds, probeGround, type GroundProbe, type KnownGround, type Probing } from './probe.ts';
|
|
12
|
-
export { registers, Registry, REGISTRY, RegistryFaculty } from './registry.ts';
|
|
13
|
-
export { MEMORY, MemoryFaculty } from './memory.ts';
|
|
14
|
-
export { Terrain, type Defaults } from './terrain.ts';
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The memory faculty: a faculty that keeps a hosted ward's place, where the
|
|
3
|
-
// root memory does not. It makes the same promise the Memory body makes,
|
|
4
|
-
// lent once the dock stands: sealed entries in places, each keep whole or
|
|
5
|
-
// not at all. The box ward never moves off the root memory, since the
|
|
6
|
-
// memory faculty itself stands from the box ward's cells.
|
|
7
|
-
//
|
|
8
|
-
// A ward is the unit a memory faculty holds: its head, its ward and every
|
|
9
|
-
// being of it are one place and one keep, so an answer's cells and the
|
|
10
|
-
// door's keys move together, whichever memory faculty keeps them. A memory
|
|
11
|
-
// faculty of a disk, a cloud, a database or a ledger is a class fulfilling
|
|
12
|
-
// `org.nervur.memory`.
|
|
13
|
-
import { Faculty, ships } from '../being/index.ts';
|
|
14
|
-
|
|
15
|
-
export const MEMORY = 'org.nervur.memory';
|
|
16
|
-
|
|
17
|
-
export abstract class MemoryFaculty extends Faculty {
|
|
18
|
-
static override readonly kind: string = MEMORY;
|
|
19
|
-
static {
|
|
20
|
-
ships(this);
|
|
21
|
-
}
|
|
22
|
-
abstract read(place: string): Promise<Map<string, Uint8Array>>;
|
|
23
|
-
abstract write(place: string, entries: ReadonlyMap<string, Uint8Array | null>): Promise<void>;
|
|
24
|
-
abstract places(): Promise<string[]>;
|
|
25
|
-
abstract forget(place: string): Promise<void>;
|
|
26
|
-
// Whether a place of the root memory is this memory faculty's own, so the root's
|
|
27
|
-
// sweep leaves it.
|
|
28
|
-
occupies(_place: string): boolean {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The package: a harbor's memory, sealed under the harbor's seed. The
|
|
3
|
-
// terrain keeps its bytes and reads neither a ward's name, nor a being's
|
|
4
|
-
// key, nor anything a row holds.
|
|
5
|
-
//
|
|
6
|
-
// key HKDF-SHA-256 of the seed under `nervur-package`
|
|
7
|
-
// place 16 bytes under ["place", ward], as hex
|
|
8
|
-
// entry 16 bytes under ["entry", ward, row], as hex
|
|
9
|
-
// seal 32 bytes under ["seal", ward]
|
|
10
|
-
// entry bytes nonce (12) || AES-256-GCM( JSON { row, value } ),
|
|
11
|
-
// the entry's name as additional data
|
|
12
|
-
//
|
|
13
|
-
// A row is the head, under the empty name, or one being, under her key. An
|
|
14
|
-
// entry that does not open refuses the whole ward, so nothing unpacks from
|
|
15
|
-
// bytes the package did not seal.
|
|
16
|
-
import { concat, decrypt, encrypt, hex, hkdf, isHex, unhex, utf8 } from '../crypto/index.ts';
|
|
17
|
-
import type { Entropy, Memory, Rows } from '../contract/index.ts';
|
|
18
|
-
import { HEAD_ROW } from '../ward/index.ts';
|
|
19
|
-
|
|
20
|
-
// Every place of one memory, written into another, and the places
|
|
21
|
-
// carried. The bytes are the package's own, sealed under a seed neither
|
|
22
|
-
// memory holds, so a harbor opened on the second memory under that seed
|
|
23
|
-
// stands what the first one stood. A place the second memory already
|
|
24
|
-
// holds is written over.
|
|
25
|
-
export const copyPackage = async (from: Memory, to: Memory): Promise<string[]> => {
|
|
26
|
-
const places = await from.places();
|
|
27
|
-
for (const place of places) await to.write(place, await from.read(place));
|
|
28
|
-
return places;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// A harbor as one JSON value, for carrying it to another ground: every
|
|
32
|
-
// place of its memory with its sealed entries as hex, its DNA among them,
|
|
33
|
-
// and its seed only where the one who carries it says so.
|
|
34
|
-
export type Carried = { seed?: string; places: Record<string, Record<string, string>> };
|
|
35
|
-
|
|
36
|
-
// A carried harbor as JSON reads, or null for anything else.
|
|
37
|
-
export const readCarried = (value: unknown): Carried | null => {
|
|
38
|
-
if (typeof value !== 'object' || value === null) return null;
|
|
39
|
-
const { seed, places } = value as { seed?: unknown; places?: unknown };
|
|
40
|
-
if (seed !== undefined && !isHex(seed, 32)) return null;
|
|
41
|
-
if (typeof places !== 'object' || places === null || Array.isArray(places)) return null;
|
|
42
|
-
for (const entries of Object.values(places)) {
|
|
43
|
-
if (typeof entries !== 'object' || entries === null || Array.isArray(entries)) return null;
|
|
44
|
-
for (const bytes of Object.values(entries)) if (!isHex(bytes)) return null;
|
|
45
|
-
}
|
|
46
|
-
return { ...(seed === undefined ? {} : { seed }), places: places as Carried['places'] };
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// Every place of a memory, as a carried harbor holds it.
|
|
50
|
-
export const carryPlaces = async (memory: Memory): Promise<Carried['places']> => {
|
|
51
|
-
const places: Carried['places'] = {};
|
|
52
|
-
for (const place of await memory.places()) {
|
|
53
|
-
places[place] = Object.fromEntries([...(await memory.read(place))].map(([name, bytes]) => [name, hex(bytes)]));
|
|
54
|
-
}
|
|
55
|
-
return places;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// A carried harbor's places, written into a memory, and their names.
|
|
59
|
-
export const landPlaces = async (memory: Memory, carried: Carried): Promise<string[]> => {
|
|
60
|
-
for (const [place, entries] of Object.entries(carried.places)) {
|
|
61
|
-
await memory.write(place, new Map(Object.entries(entries).map(([name, bytes]) => [name, unhex(bytes)])));
|
|
62
|
-
}
|
|
63
|
-
return Object.keys(carried.places);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const NONCE = 12;
|
|
67
|
-
const LABEL = utf8('nervur-package');
|
|
68
|
-
|
|
69
|
-
type Sealed = { row: string; value: unknown };
|
|
70
|
-
|
|
71
|
-
class PackageRows implements Rows {
|
|
72
|
-
readonly rows: Record<string, unknown>;
|
|
73
|
-
readonly #ward: WardPlace;
|
|
74
|
-
readonly #told = new Set<string>();
|
|
75
|
-
#line: Promise<boolean> = Promise.resolve(true);
|
|
76
|
-
|
|
77
|
-
constructor(ward: WardPlace, rows: Record<string, unknown>) {
|
|
78
|
-
this.#ward = ward;
|
|
79
|
-
this.rows = rows;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
told(row: string): void {
|
|
83
|
-
this.#told.add(row);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Every row told since the last keep, sealed and written as one keep, one
|
|
87
|
-
// keep at a time. Where nothing was told, nothing is written, so an ask
|
|
88
|
-
// that only reads keeps even where the keeper refuses every write.
|
|
89
|
-
kept(): Promise<boolean> {
|
|
90
|
-
const rows = [...this.#told];
|
|
91
|
-
this.#told.clear();
|
|
92
|
-
this.#line = this.#line.then(() => this.#write(rows)).catch(() => false);
|
|
93
|
-
return this.#line;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async #write(told: string[]): Promise<boolean> {
|
|
97
|
-
if (told.length === 0) return true;
|
|
98
|
-
const beings = (this.rows.beings ?? {}) as Record<string, unknown>;
|
|
99
|
-
const entries = new Map<string, Uint8Array | null>();
|
|
100
|
-
for (const row of told) {
|
|
101
|
-
const value = row === HEAD_ROW ? (this.rows.ward ?? null) : Object.hasOwn(beings, row) ? beings[row] : undefined;
|
|
102
|
-
entries.set(await this.#ward.entry(row), value === undefined ? null : await this.#ward.seal(row, value));
|
|
103
|
-
}
|
|
104
|
-
await this.#ward.write(entries);
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// What keeps a ward's place: the root memory, or a memory faculty the dock
|
|
110
|
-
// lends.
|
|
111
|
-
export type Keeper = Pick<Memory, 'read' | 'write' | 'places' | 'forget'>;
|
|
112
|
-
|
|
113
|
-
class WardPlace {
|
|
114
|
-
readonly #pack: Package;
|
|
115
|
-
readonly #name: string;
|
|
116
|
-
readonly #seal: Uint8Array;
|
|
117
|
-
readonly #keeper: Keeper;
|
|
118
|
-
readonly place: string;
|
|
119
|
-
|
|
120
|
-
constructor(pack: Package, name: string, seal: Uint8Array, place: string, keeper: Keeper) {
|
|
121
|
-
this.#pack = pack;
|
|
122
|
-
this.#name = name;
|
|
123
|
-
this.#seal = seal;
|
|
124
|
-
this.place = place;
|
|
125
|
-
this.#keeper = keeper;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
read(): Promise<Map<string, Uint8Array>> {
|
|
129
|
-
return this.#keeper.read(this.place);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
entry(row: string): Promise<string> {
|
|
133
|
-
return this.#pack.derive(['entry', this.#name, row], 16).then(hex);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async seal(row: string, value: unknown): Promise<Uint8Array> {
|
|
137
|
-
const nonce = this.#pack.entropy.draw(NONCE);
|
|
138
|
-
const text = utf8(JSON.stringify({ row, value } satisfies Sealed));
|
|
139
|
-
return concat(nonce, await encrypt(this.#seal, nonce, utf8(await this.entry(row)), text));
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// The name is the additional data, so an entry moved under another name
|
|
143
|
-
// does not open either.
|
|
144
|
-
async open(name: string, bytes: Uint8Array): Promise<Sealed> {
|
|
145
|
-
const text = bytes.length > NONCE ? await decrypt(this.#seal, bytes.subarray(0, NONCE), utf8(name), bytes.subarray(NONCE)) : null;
|
|
146
|
-
if (text === null) throw new Error('an entry the package did not seal');
|
|
147
|
-
return JSON.parse(new TextDecoder().decode(text)) as Sealed;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
write(entries: ReadonlyMap<string, Uint8Array | null>): Promise<void> {
|
|
151
|
-
return this.#keeper.write(this.place, entries);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export class Package {
|
|
156
|
-
readonly memory: Memory;
|
|
157
|
-
readonly entropy: Entropy;
|
|
158
|
-
readonly #key: Uint8Array;
|
|
159
|
-
|
|
160
|
-
private constructor(memory: Memory, entropy: Entropy, key: Uint8Array) {
|
|
161
|
-
this.memory = memory;
|
|
162
|
-
this.entropy = entropy;
|
|
163
|
-
this.#key = key;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
static async open(memory: Memory, entropy: Entropy, seed: Uint8Array): Promise<Package> {
|
|
167
|
-
return new Package(memory, entropy, await hkdf(seed, LABEL, 32));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
derive(info: string[], length: number): Promise<Uint8Array> {
|
|
171
|
-
return hkdf(this.#key, utf8(JSON.stringify(info)), length);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// The place a ward's rows live in.
|
|
175
|
-
place(name: string): Promise<string> {
|
|
176
|
-
return this.derive(['place', name], 16).then(hex);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// One ward's rows, as its keeper kept them: the root memory unless a
|
|
180
|
-
// memory faculty is named.
|
|
181
|
-
async rows(name: string, keeper: Keeper = this.memory): Promise<Rows> {
|
|
182
|
-
const ward = new WardPlace(this, name, await this.derive(['seal', name], 32), await this.place(name), keeper);
|
|
183
|
-
const rows: Record<string, unknown> = {};
|
|
184
|
-
const beings: Record<string, unknown> = {};
|
|
185
|
-
let any = false;
|
|
186
|
-
for (const [entry, bytes] of await ward.read()) {
|
|
187
|
-
const { row, value } = await ward.open(entry, bytes);
|
|
188
|
-
any = true;
|
|
189
|
-
if (row === HEAD_ROW) rows.ward = value;
|
|
190
|
-
else beings[row] = value;
|
|
191
|
-
}
|
|
192
|
-
if (any) rows.beings = beings;
|
|
193
|
-
return new PackageRows(ward, rows);
|
|
194
|
-
}
|
|
195
|
-
}
|