nervur 0.21.4 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +215 -158
- package/dist/browser.js +4 -3
- package/dist/cli.js +16 -0
- package/dist/{being → core/being}/being.js +10 -0
- package/dist/{being → core/being}/faculty.js +5 -2
- package/dist/{being → core/being}/index.d.ts +1 -1
- package/dist/{being → core/being}/index.js +1 -1
- package/dist/{being → core/being}/kind.d.ts +2 -0
- package/dist/{being → core/being}/kind.js +6 -0
- package/dist/{being → core/being}/types.js +1 -1
- package/dist/{browser → core/browser}/index.d.ts +6 -5
- package/dist/{browser → core/browser}/index.js +10 -10
- package/dist/{browser → core/browser}/worker.d.ts +2 -3
- package/dist/{browser → core/browser}/worker.js +8 -11
- package/dist/{cli → core/cli}/command.d.ts +4 -4
- package/dist/{cli → core/cli}/command.js +116 -66
- package/dist/{cli → core/cli}/edge.js +4 -2
- package/dist/core/cli/harbor.d.ts +25 -0
- package/dist/{cli → core/cli}/harbor.js +45 -33
- package/dist/{contract → core/contract}/index.d.ts +6 -5
- package/dist/{contract → core/contract}/index.js +8 -9
- package/dist/core/contract/link.d.ts +4 -0
- package/dist/core/contract/link.js +45 -0
- package/dist/{crypto → core/crypto}/ed25519.js +22 -14
- package/dist/core/crypto/subtle.d.ts +3 -0
- package/dist/core/crypto/subtle.js +11 -0
- package/dist/core/crypto/x25519.js +24 -0
- package/dist/core/edge/index.d.ts +164 -0
- package/dist/core/edge/index.js +739 -0
- package/dist/core/edge/kit.d.ts +2 -0
- package/dist/core/edge/kit.js +2 -0
- package/dist/core/git/http.d.ts +6 -0
- package/dist/core/git/http.js +102 -0
- package/dist/core/git/index.d.ts +5 -0
- package/dist/core/git/index.js +10 -0
- package/dist/core/git/object.d.ts +40 -0
- package/dist/core/git/object.js +103 -0
- package/dist/core/git/pack.d.ts +9 -0
- package/dist/core/git/pack.js +171 -0
- package/dist/core/git/store.d.ts +23 -0
- package/dist/core/git/store.js +120 -0
- package/dist/core/git/zlib.d.ts +6 -0
- package/dist/core/git/zlib.js +210 -0
- package/dist/core/harbor/carrying.d.ts +51 -0
- package/dist/core/harbor/carrying.js +69 -0
- package/dist/core/harbor/catalogue.d.ts +33 -0
- package/dist/core/harbor/catalogue.js +365 -0
- package/dist/core/harbor/dna.d.ts +13 -0
- package/dist/core/harbor/dna.js +120 -0
- package/dist/{harbor → core/harbor}/dock.d.ts +22 -13
- package/dist/core/harbor/dock.js +381 -0
- package/dist/core/harbor/harbor.d.ts +16 -0
- package/dist/core/harbor/harbor.js +438 -0
- package/dist/core/harbor/index.d.ts +11 -0
- package/dist/{harbor → core/harbor}/index.js +5 -5
- package/dist/core/harbor/memory.d.ts +10 -0
- package/dist/core/harbor/memory.js +25 -0
- package/dist/{harbor → core/harbor}/package.d.ts +0 -1
- package/dist/{harbor → core/harbor}/package.js +9 -9
- package/dist/core/harbor/probe.d.ts +22 -0
- package/dist/core/harbor/probe.js +15 -0
- package/dist/core/harbor/registry.d.ts +15 -0
- package/dist/{harbor → core/harbor}/registry.js +26 -10
- package/dist/core/harbor/root-line.d.ts +7 -0
- package/dist/core/harbor/root-line.js +9 -0
- package/dist/{harbor → core/harbor}/terrain.d.ts +9 -6
- package/dist/{harbor → core/harbor}/terrain.js +5 -4
- package/dist/core/http/index.d.ts +2 -0
- package/dist/{http → core/http}/index.js +3 -5
- package/dist/{line → core/line}/answer.d.ts +2 -2
- package/dist/{line → core/line}/frame.d.ts +0 -5
- package/dist/{line → core/line}/frame.js +0 -4
- package/dist/core/line/ground.js +7 -0
- package/dist/core/line/index.d.ts +4 -0
- package/dist/core/line/index.js +8 -0
- package/dist/core/line/web.d.ts +12 -0
- package/dist/{line → core/line}/web.js +13 -77
- package/dist/{node → core/node}/index.d.ts +2 -15
- package/dist/core/node/index.js +124 -0
- package/dist/{pointer → core/pointer}/bodies.d.ts +7 -5
- package/dist/core/pointer/bodies.js +118 -0
- package/dist/core/pointer/index.d.ts +2 -0
- package/dist/{pointer → core/pointer}/index.js +1 -1
- package/dist/{pointer → core/pointer}/world.d.ts +13 -9
- package/dist/{pointer → core/pointer}/world.js +31 -16
- package/dist/{proof → core/proof}/contracts.d.ts +6 -2
- package/dist/{proof → core/proof}/contracts.js +11 -10
- package/dist/core/proof/index.d.ts +3 -0
- package/dist/{proof → core/proof}/index.js +2 -2
- package/dist/core/proof/law.d.ts +25 -0
- package/dist/core/proof/law.js +715 -0
- package/dist/{tcp → core/tcp}/index.d.ts +7 -4
- package/dist/{tcp → core/tcp}/index.js +11 -62
- package/dist/{ward/ward.d.ts → core/ward/house.d.ts} +24 -10
- package/dist/core/ward/house.js +473 -0
- package/dist/core/ward/index.d.ts +5 -0
- package/dist/core/ward/index.js +7 -0
- package/dist/{ward → core/ward}/partition.d.ts +1 -0
- package/dist/{ward → core/ward}/stance.d.ts +2 -2
- package/dist/{ward → core/ward}/stance.js +5 -2
- package/dist/{ward/ward-being.d.ts → core/ward/ward.d.ts} +14 -6
- package/dist/core/ward/ward.js +140 -0
- package/dist/core.d.ts +10 -0
- package/dist/core.js +19 -0
- package/dist/defaults/dock/index.d.ts +4 -0
- package/dist/defaults/dock/index.js +11 -0
- package/dist/defaults/index.d.ts +5 -0
- package/dist/defaults/index.js +10 -0
- package/dist/defaults/memory/index.d.ts +12 -0
- package/dist/defaults/memory/index.js +39 -0
- package/dist/defaults/tcp/index.d.ts +16 -0
- package/dist/defaults/tcp/index.js +82 -0
- package/dist/defaults/ward/index.d.ts +4 -0
- package/dist/defaults/ward/index.js +11 -0
- package/dist/defaults/web/index.d.ts +15 -0
- package/dist/defaults/web/index.js +90 -0
- package/dist/edge.js +4 -3
- package/dist/index.d.ts +1 -8
- package/dist/index.js +13 -18
- package/dist/kit.d.ts +4 -0
- package/dist/kit.js +12 -0
- package/dist/node.js +4 -3
- package/package.json +23 -18
- package/src/browser.ts +4 -3
- package/src/cli.ts +15 -0
- package/src/{being → core/being}/being.ts +4 -0
- package/src/{being → core/being}/faculty.ts +5 -2
- package/src/{being → core/being}/index.ts +1 -1
- package/src/{being → core/being}/kind.ts +7 -0
- package/src/{being → core/being}/types.ts +1 -1
- package/src/{browser → core/browser}/index.ts +16 -13
- package/src/{browser → core/browser}/worker.ts +11 -14
- package/src/{cli → core/cli}/command.ts +113 -66
- package/src/{cli → core/cli}/edge.ts +4 -2
- package/src/{cli → core/cli}/harbor.ts +48 -31
- package/src/{contract → core/contract}/index.ts +14 -14
- package/src/core/contract/link.ts +58 -0
- package/src/{crypto → core/crypto}/ed25519.ts +22 -14
- package/src/core/crypto/subtle.ts +13 -0
- package/src/core/crypto/x25519.ts +23 -0
- package/src/core/edge/index.ts +865 -0
- package/src/core/git/http.ts +103 -0
- package/src/core/git/index.ts +10 -0
- package/src/core/git/object.ts +116 -0
- package/src/core/git/pack.ts +147 -0
- package/src/core/git/store.ts +122 -0
- package/src/core/git/zlib.ts +197 -0
- package/src/core/harbor/carrying.ts +124 -0
- package/src/core/harbor/catalogue.ts +386 -0
- package/src/core/harbor/dna.ts +116 -0
- package/src/core/harbor/dock.ts +420 -0
- package/src/core/harbor/harbor.ts +433 -0
- package/src/core/harbor/index.ts +14 -0
- package/src/core/harbor/memory.ts +31 -0
- package/src/{harbor → core/harbor}/package.ts +15 -15
- package/src/core/harbor/probe.ts +39 -0
- package/src/{harbor → core/harbor}/registry.ts +28 -11
- package/src/core/harbor/root-line.ts +19 -0
- package/src/{harbor → core/harbor}/terrain.ts +14 -7
- package/src/{http → core/http}/index.ts +5 -8
- package/src/{line → core/line}/answer.ts +3 -2
- package/src/{line → core/line}/frame.ts +0 -5
- package/src/core/line/ground.ts +18 -0
- package/src/core/line/index.ts +8 -0
- package/src/{line → core/line}/web.ts +1 -105
- package/src/core/node/index.ts +139 -0
- package/src/core/pointer/bodies.ts +122 -0
- package/src/core/pointer/index.ts +4 -0
- package/src/{pointer → core/pointer}/world.ts +45 -21
- package/src/{proof → core/proof}/contracts.ts +18 -13
- package/src/{proof → core/proof}/index.ts +3 -3
- package/src/core/proof/law.ts +742 -0
- package/src/{stand → core/stand}/stand.ts +2 -2
- package/src/{tcp → core/tcp}/index.ts +17 -74
- package/src/core/ward/house.ts +524 -0
- package/src/core/ward/index.ts +7 -0
- package/src/{ward → core/ward}/partition.ts +5 -1
- package/src/{ward → core/ward}/stance.ts +5 -2
- package/src/core/ward/ward.ts +166 -0
- package/src/core.ts +55 -0
- package/src/defaults/dock/index.ts +12 -0
- package/src/defaults/index.ts +10 -0
- package/src/defaults/memory/index.ts +50 -0
- package/src/defaults/tcp/index.ts +89 -0
- package/src/defaults/ward/index.ts +12 -0
- package/src/defaults/web/index.ts +97 -0
- package/src/edge.ts +4 -3
- package/src/index.ts +13 -50
- package/src/kit.ts +15 -0
- package/src/node.ts +4 -3
- package/dist/cli/harbor.d.ts +0 -16
- package/dist/cli/main.js +0 -14
- package/dist/crypto/subtle.d.ts +0 -10
- package/dist/crypto/subtle.js +0 -29
- package/dist/crypto/x25519.js +0 -21
- package/dist/edge/index.d.ts +0 -81
- package/dist/edge/index.js +0 -400
- package/dist/harbor/carrying.d.ts +0 -17
- package/dist/harbor/carrying.js +0 -38
- package/dist/harbor/catalogue.d.ts +0 -28
- package/dist/harbor/catalogue.js +0 -109
- package/dist/harbor/dock.js +0 -236
- package/dist/harbor/harbor.d.ts +0 -45
- package/dist/harbor/harbor.js +0 -347
- package/dist/harbor/index.d.ts +0 -11
- package/dist/harbor/probe.d.ts +0 -18
- package/dist/harbor/probe.js +0 -15
- package/dist/harbor/registry.d.ts +0 -10
- package/dist/harbor/relay.d.ts +0 -15
- package/dist/harbor/relay.js +0 -406
- package/dist/harbor/root-line.d.ts +0 -9
- package/dist/harbor/root-line.js +0 -38
- package/dist/harbor/store.d.ts +0 -13
- package/dist/harbor/store.js +0 -53
- package/dist/http/index.d.ts +0 -4
- package/dist/line/ground.js +0 -9
- package/dist/line/index.d.ts +0 -5
- package/dist/line/index.js +0 -9
- package/dist/line/push.d.ts +0 -7
- package/dist/line/push.js +0 -92
- package/dist/line/web.d.ts +0 -30
- package/dist/node/index.js +0 -236
- package/dist/pointer/bodies.js +0 -80
- package/dist/pointer/index.d.ts +0 -2
- package/dist/proof/index.d.ts +0 -3
- package/dist/proof/law.d.ts +0 -90
- package/dist/proof/law.js +0 -591
- package/dist/tcp/frame.d.ts +0 -25
- package/dist/tcp/frame.js +0 -64
- package/dist/ward/index.d.ts +0 -6
- package/dist/ward/index.js +0 -8
- package/dist/ward/pilot.d.ts +0 -8
- package/dist/ward/pilot.js +0 -50
- package/dist/ward/ward-being.js +0 -82
- package/dist/ward/ward.js +0 -290
- package/src/cli/main.ts +0 -13
- package/src/crypto/subtle.ts +0 -33
- package/src/crypto/x25519.ts +0 -21
- package/src/edge/index.ts +0 -490
- package/src/harbor/carrying.ts +0 -56
- package/src/harbor/catalogue.ts +0 -134
- package/src/harbor/dock.ts +0 -265
- package/src/harbor/harbor.ts +0 -381
- package/src/harbor/index.ts +0 -14
- package/src/harbor/probe.ts +0 -34
- package/src/harbor/relay.ts +0 -418
- package/src/harbor/root-line.ts +0 -39
- package/src/harbor/store.ts +0 -69
- package/src/line/ground.ts +0 -19
- package/src/line/index.ts +0 -9
- package/src/line/push.ts +0 -112
- package/src/node/index.ts +0 -241
- package/src/pointer/bodies.ts +0 -82
- package/src/pointer/index.ts +0 -4
- package/src/proof/law.ts +0 -591
- package/src/ward/index.ts +0 -8
- package/src/ward/pilot.ts +0 -50
- package/src/ward/ward-being.ts +0 -103
- package/src/ward/ward.ts +0 -328
- /package/dist/{cli/main.d.ts → cli.d.ts} +0 -0
- /package/dist/{being → core/being}/being.d.ts +0 -0
- /package/dist/{being → core/being}/digest.d.ts +0 -0
- /package/dist/{being → core/being}/digest.js +0 -0
- /package/dist/{being → core/being}/faculty.d.ts +0 -0
- /package/dist/{being → core/being}/types.d.ts +0 -0
- /package/dist/{being → core/being}/words.d.ts +0 -0
- /package/dist/{being → core/being}/words.js +0 -0
- /package/dist/{cli → core/cli}/edge.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/aes.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/aes.js +0 -0
- /package/dist/{crypto → core/crypto}/bytes.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/bytes.js +0 -0
- /package/dist/{crypto → core/crypto}/ed25519.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/hash.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/hash.js +0 -0
- /package/dist/{crypto → core/crypto}/index.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/index.js +0 -0
- /package/dist/{crypto → core/crypto}/json.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/json.js +0 -0
- /package/dist/{crypto → core/crypto}/mlkem.d.ts +0 -0
- /package/dist/{crypto → core/crypto}/mlkem.js +0 -0
- /package/dist/{crypto → core/crypto}/x25519.d.ts +0 -0
- /package/dist/{folder → core/folder}/index.d.ts +0 -0
- /package/dist/{folder → core/folder}/index.js +0 -0
- /package/dist/{http → core/http}/websocket.d.ts +0 -0
- /package/dist/{http → core/http}/websocket.js +0 -0
- /package/dist/{line → core/line}/answer.js +0 -0
- /package/dist/{line → core/line}/ground.d.ts +0 -0
- /package/dist/{proof → core/proof}/expect.d.ts +0 -0
- /package/dist/{proof → core/proof}/expect.js +0 -0
- /package/dist/{quo → core/quo}/address.d.ts +0 -0
- /package/dist/{quo → core/quo}/address.js +0 -0
- /package/dist/{quo → core/quo}/door.d.ts +0 -0
- /package/dist/{quo → core/quo}/door.js +0 -0
- /package/dist/{quo → core/quo}/index.d.ts +0 -0
- /package/dist/{quo → core/quo}/index.js +0 -0
- /package/dist/{quo → core/quo}/invitation.d.ts +0 -0
- /package/dist/{quo → core/quo}/invitation.js +0 -0
- /package/dist/{quo → core/quo}/keys.d.ts +0 -0
- /package/dist/{quo → core/quo}/keys.js +0 -0
- /package/dist/{quo → core/quo}/payload.d.ts +0 -0
- /package/dist/{quo → core/quo}/payload.js +0 -0
- /package/dist/{quo → core/quo}/relations.d.ts +0 -0
- /package/dist/{quo → core/quo}/relations.js +0 -0
- /package/dist/{quo → core/quo}/reply.d.ts +0 -0
- /package/dist/{quo → core/quo}/reply.js +0 -0
- /package/dist/{quo → core/quo}/seal.d.ts +0 -0
- /package/dist/{quo → core/quo}/seal.js +0 -0
- /package/dist/{quo → core/quo}/standing.d.ts +0 -0
- /package/dist/{quo → core/quo}/standing.js +0 -0
- /package/dist/{ward → core/ward}/allowance.d.ts +0 -0
- /package/dist/{ward → core/ward}/allowance.js +0 -0
- /package/dist/{ward → core/ward}/cells.d.ts +0 -0
- /package/dist/{ward → core/ward}/cells.js +0 -0
- /package/dist/{ward → core/ward}/partition.js +0 -0
- /package/src/{being → core/being}/digest.ts +0 -0
- /package/src/{being → core/being}/words.ts +0 -0
- /package/src/{crypto → core/crypto}/aes.ts +0 -0
- /package/src/{crypto → core/crypto}/bytes.ts +0 -0
- /package/src/{crypto → core/crypto}/hash.ts +0 -0
- /package/src/{crypto → core/crypto}/index.ts +0 -0
- /package/src/{crypto → core/crypto}/json.ts +0 -0
- /package/src/{crypto → core/crypto}/mlkem.ts +0 -0
- /package/src/{folder → core/folder}/index.ts +0 -0
- /package/src/{http → core/http}/websocket.ts +0 -0
- /package/src/{proof → core/proof}/expect.ts +0 -0
- /package/src/{quo → core/quo}/address.ts +0 -0
- /package/src/{quo → core/quo}/door.ts +0 -0
- /package/src/{quo → core/quo}/index.ts +0 -0
- /package/src/{quo → core/quo}/invitation.ts +0 -0
- /package/src/{quo → core/quo}/keys.ts +0 -0
- /package/src/{quo → core/quo}/payload.ts +0 -0
- /package/src/{quo → core/quo}/relations.ts +0 -0
- /package/src/{quo → core/quo}/reply.ts +0 -0
- /package/src/{quo → core/quo}/seal.ts +0 -0
- /package/src/{quo → core/quo}/standing.ts +0 -0
- /package/src/{stand → core/stand}/main.ts +0 -0
- /package/src/{ward → core/ward}/allowance.ts +0 -0
- /package/src/{ward → core/ward}/cells.ts +0 -0
package/dist/harbor/relay.js
DELETED
|
@@ -1,406 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The relay: a harbor nobody dials is reached through a harbor that is,
|
|
3
|
-
// by relations alone. Both sides are kit faculties, opened by the root.
|
|
4
|
-
//
|
|
5
|
-
// On the reached harbor, `org.nervur.relay`:
|
|
6
|
-
//
|
|
7
|
-
// invite { id, wards } a relay client invited under `id`, its
|
|
8
|
-
// notes naming the ward pks it collects for
|
|
9
|
-
// release { id } that client let go, and every box waiting
|
|
10
|
-
// for its wards answered with nothing
|
|
11
|
-
// collect { replies?, wait? } asked by a client: the replies to the boxes
|
|
12
|
-
// it took last, handed to their callers, then
|
|
13
|
-
// the boxes waiting for its wards; with
|
|
14
|
-
// `wait`, it waits for one first
|
|
15
|
-
// bell { endpoint } asked by a client: the push endpoint rung
|
|
16
|
-
// when a box waits for it, or null for none
|
|
17
|
-
// key asked by a client: the key its device
|
|
18
|
-
// subscribes to pushes with
|
|
19
|
-
//
|
|
20
|
-
// A box for a ward a client collects for reaches this harbor on any
|
|
21
|
-
// carrier, and the caller's dial waits for its reply, or for nothing once
|
|
22
|
-
// `RELAY_WAIT` passes. No box is opened here. A box no waiting collect
|
|
23
|
-
// takes rings the client's bell once, through a `Push` faculty the relay
|
|
24
|
-
// lends, until the client collects again.
|
|
25
|
-
//
|
|
26
|
-
// On the harbor nobody dials, `org.nervur.relay-client`:
|
|
27
|
-
//
|
|
28
|
-
// hold { invitation, line?, every? } the relay's invitation taken; a
|
|
29
|
-
// line collects always, `every`
|
|
30
|
-
// rings on a schedule, in ms
|
|
31
|
-
// ring every waiting box collected, handed
|
|
32
|
-
// to this harbor's doors, and the
|
|
33
|
-
// replies returned: a doorbell
|
|
34
|
-
// bell { endpoint } the relay's `bell`, asked
|
|
35
|
-
// key the relay's `key`, asked
|
|
36
|
-
// drop the relay let go
|
|
37
|
-
//
|
|
38
|
-
// Its harbor's `reach` names the relay's address, so every invitation it
|
|
39
|
-
// gives sends callers there. Whatever hears a push on the device asks
|
|
40
|
-
// `ring`.
|
|
41
|
-
import { Faculty, isSilence, isWord, told } from '../being/index.js';
|
|
42
|
-
import { hex, isHex, unhex } from '../crypto/index.js';
|
|
43
|
-
import { readInvitation } from '../quo/index.js';
|
|
44
|
-
import { ownerAsk } from '../ward/index.js';
|
|
45
|
-
import { CarrierFaculty, UNDIALED } from './carrying.js';
|
|
46
|
-
export const RELAY = 'org.nervur.relay';
|
|
47
|
-
export const RELAY_CLIENT = 'org.nervur.relay-client';
|
|
48
|
-
export const PUSH = 'org.nervur.push';
|
|
49
|
-
// How long a box waits for its reply: a caller's allowance, unless it
|
|
50
|
-
// asks for another.
|
|
51
|
-
export const RELAY_WAIT = 30_000;
|
|
52
|
-
// How long a collect with `wait` holds, inside the client's allowance.
|
|
53
|
-
export const RELAY_HOLD = 20_000;
|
|
54
|
-
// How long a line rests after a collect that reached nothing.
|
|
55
|
-
export const RELAY_REST = 1_000;
|
|
56
|
-
// The largest box a relay carries, so the collect answering it stays a
|
|
57
|
-
// box Quo carries.
|
|
58
|
-
export const RELAYED = 262_144;
|
|
59
|
-
// The longest push endpoint a relay keeps.
|
|
60
|
-
const ENDPOINT = 2_048;
|
|
61
|
-
// The most boxes one collect hands over.
|
|
62
|
-
const BATCH = 16;
|
|
63
|
-
const CLIENT = 'relay';
|
|
64
|
-
const PUSHER = 'push';
|
|
65
|
-
// The contract of a ring with no content: `key` answers the key a device
|
|
66
|
-
// subscribes with, and `ring { endpoint }` answers `rung`, `gone` where
|
|
67
|
-
// the push service has let the endpoint go, or an error.
|
|
68
|
-
export class Push extends Faculty {
|
|
69
|
-
static kind = PUSH;
|
|
70
|
-
}
|
|
71
|
-
const text = (v) => typeof v === 'string';
|
|
72
|
-
const wardsOf = (notes) => (Array.isArray(notes?.relay) ? notes.relay.filter(text) : []);
|
|
73
|
-
const collects = (_, notes) => wardsOf(notes).length > 0;
|
|
74
|
-
const clientAsk = (description, input = {}) => ({ description, input: { type: 'object', ...input }, for: collects });
|
|
75
|
-
const readReplies = (v) => v === undefined
|
|
76
|
-
? []
|
|
77
|
-
: Array.isArray(v) && v.every((r) => typeof r === 'object' && r !== null && Number.isInteger(r.n) && (r.box === null || isHex(r.box, (r.box ?? '').length / 2)))
|
|
78
|
-
? v
|
|
79
|
-
: null;
|
|
80
|
-
// An answer, or the error it stands for.
|
|
81
|
-
const answered = (out) => (isSilence(out) ? { error: 'silence' } : isWord(out) ? { error: told(out) } : out);
|
|
82
|
-
export const relayFaculty = (clock) => class Relay extends CarrierFaculty {
|
|
83
|
-
static kind = RELAY;
|
|
84
|
-
static cells = { clients: {}, bells: {} };
|
|
85
|
-
static asks = {
|
|
86
|
-
invite: ownerAsk('a relay client, collecting for the ward pks named', { required: ['id', 'wards'] }),
|
|
87
|
-
release: ownerAsk('a relay client let go', { required: ['id'] }),
|
|
88
|
-
collect: clientAsk('the replies to the boxes taken last, then the boxes waiting'),
|
|
89
|
-
bell: clientAsk('the push endpoint rung when a box waits, or null', { required: ['endpoint'] }),
|
|
90
|
-
key: clientAsk('the key a device subscribes to pushes with'),
|
|
91
|
-
};
|
|
92
|
-
#n = 0;
|
|
93
|
-
#waiting = [];
|
|
94
|
-
#taken = new Map();
|
|
95
|
-
#collectors = new Set();
|
|
96
|
-
// The clients rung since they last collected.
|
|
97
|
-
#rung = new Set();
|
|
98
|
-
#lending;
|
|
99
|
-
accepts() {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
dial() {
|
|
103
|
-
return Promise.resolve(UNDIALED);
|
|
104
|
-
}
|
|
105
|
-
get #clients() {
|
|
106
|
-
return this.cells.clients;
|
|
107
|
-
}
|
|
108
|
-
get #bells() {
|
|
109
|
-
return this.cells.bells;
|
|
110
|
-
}
|
|
111
|
-
relays(pk) {
|
|
112
|
-
return Object.values(this.#clients).some((wards) => wards.includes(pk));
|
|
113
|
-
}
|
|
114
|
-
relay(pk, bytes) {
|
|
115
|
-
if (!this.relays(pk) || bytes.length > RELAYED)
|
|
116
|
-
return Promise.resolve(null);
|
|
117
|
-
return new Promise((resolve) => {
|
|
118
|
-
const wait = clock.wait(RELAY_WAIT);
|
|
119
|
-
const box = { n: ++this.#n, ward: pk, bytes, answer: resolve, cancel: wait.cancel };
|
|
120
|
-
void wait.done.then(() => this.#settle(box, null));
|
|
121
|
-
this.#waiting.push(box);
|
|
122
|
-
let woken = false;
|
|
123
|
-
for (const collector of this.#collectors) {
|
|
124
|
-
if (!collector.wards.includes(pk))
|
|
125
|
-
continue;
|
|
126
|
-
collector.wake();
|
|
127
|
-
woken = true;
|
|
128
|
-
}
|
|
129
|
-
if (woken)
|
|
130
|
-
return;
|
|
131
|
-
for (const [id, wards] of Object.entries(this.#clients)) {
|
|
132
|
-
if (!wards.includes(pk) || !Object.hasOwn(this.#bells, id) || this.#rung.has(id))
|
|
133
|
-
continue;
|
|
134
|
-
this.#rung.add(id);
|
|
135
|
-
void this.#ring(id);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
// Every box answered with nothing, and every collect woken.
|
|
140
|
-
sleep() {
|
|
141
|
-
for (const box of [...this.#waiting, ...this.#taken.values()])
|
|
142
|
-
this.#settle(box, null);
|
|
143
|
-
for (const collector of this.#collectors)
|
|
144
|
-
collector.wake();
|
|
145
|
-
return Promise.resolve();
|
|
146
|
-
}
|
|
147
|
-
async invite(args) {
|
|
148
|
-
const { id, wards } = args;
|
|
149
|
-
if (!text(id) || !Array.isArray(wards) || wards.length === 0 || !wards.every((w) => isHex(w, 64)))
|
|
150
|
-
return { error: 'id is text and wards a list of ward pks' };
|
|
151
|
-
if (Object.hasOwn(this.#clients, id))
|
|
152
|
-
return { error: 'that client is invited' };
|
|
153
|
-
const invitation = await this.stance.occupants.invite(id, { relay: wards });
|
|
154
|
-
if (invitation === null)
|
|
155
|
-
return { error: 'not invited' };
|
|
156
|
-
this.#clients[id] = [...wards];
|
|
157
|
-
return { invitation };
|
|
158
|
-
}
|
|
159
|
-
release(args) {
|
|
160
|
-
if (!text(args.id) || !Object.hasOwn(this.#clients, args.id))
|
|
161
|
-
return { error: 'no such client' };
|
|
162
|
-
this.stance.occupants.remove(args.id);
|
|
163
|
-
delete this.#clients[args.id];
|
|
164
|
-
delete this.#bells[args.id];
|
|
165
|
-
this.#rung.delete(args.id);
|
|
166
|
-
for (const box of [...this.#waiting, ...this.#taken.values()])
|
|
167
|
-
if (!this.relays(box.ward))
|
|
168
|
-
this.#settle(box, null);
|
|
169
|
-
return { released: args.id };
|
|
170
|
-
}
|
|
171
|
-
async collect(args, asker) {
|
|
172
|
-
const replies = readReplies(args.replies);
|
|
173
|
-
if (replies === null)
|
|
174
|
-
return { error: 'replies are a list of { n, box }' };
|
|
175
|
-
const id = asker.id;
|
|
176
|
-
this.#rung.delete(id);
|
|
177
|
-
const replied = new Set(replies.map((r) => r.n));
|
|
178
|
-
for (const { n, box } of replies) {
|
|
179
|
-
const taken = this.#taken.get(n);
|
|
180
|
-
if (taken?.collector === id)
|
|
181
|
-
this.#settle(taken, box === null ? null : unhex(box));
|
|
182
|
-
}
|
|
183
|
-
// A client answers every box it took in its next collect, so a box it
|
|
184
|
-
// left out never reached its doors, and waits again. A door that
|
|
185
|
-
// hears it twice answers the second as repeated.
|
|
186
|
-
for (const taken of [...this.#taken.values()]) {
|
|
187
|
-
if (taken.collector !== id || replied.has(taken.n))
|
|
188
|
-
continue;
|
|
189
|
-
this.#taken.delete(taken.n);
|
|
190
|
-
delete taken.collector;
|
|
191
|
-
this.#waiting.unshift(taken);
|
|
192
|
-
}
|
|
193
|
-
const wards = wardsOf(this.notes(asker));
|
|
194
|
-
if (args.wait === true && !this.#waiting.some((b) => wards.includes(b.ward)))
|
|
195
|
-
await this.#hold(wards);
|
|
196
|
-
const boxes = this.#waiting.filter((b) => wards.includes(b.ward)).slice(0, BATCH);
|
|
197
|
-
for (const box of boxes) {
|
|
198
|
-
this.#waiting.splice(this.#waiting.indexOf(box), 1);
|
|
199
|
-
box.collector = id;
|
|
200
|
-
this.#taken.set(box.n, box);
|
|
201
|
-
}
|
|
202
|
-
return { boxes: boxes.map(({ n, ward, bytes }) => ({ n, ward, box: hex(bytes) })) };
|
|
203
|
-
}
|
|
204
|
-
bell(args, asker) {
|
|
205
|
-
const { endpoint } = args;
|
|
206
|
-
const id = asker.id;
|
|
207
|
-
if (endpoint === null) {
|
|
208
|
-
delete this.#bells[id];
|
|
209
|
-
return { bell: null };
|
|
210
|
-
}
|
|
211
|
-
if (!text(endpoint) || endpoint.length > ENDPOINT || !/^https?:\/\//.test(endpoint))
|
|
212
|
-
return { error: 'endpoint is a web URL, or null' };
|
|
213
|
-
this.#bells[id] = endpoint;
|
|
214
|
-
return { bell: endpoint };
|
|
215
|
-
}
|
|
216
|
-
async key() {
|
|
217
|
-
const push = await this.#push();
|
|
218
|
-
return push ? answered(await push.ask('key')) : { error: 'no push faculty is open' };
|
|
219
|
-
}
|
|
220
|
-
// The client's bell rung. An endpoint the push service calls gone is
|
|
221
|
-
// forgotten, and kept at the relay's next arrival.
|
|
222
|
-
async #ring(id) {
|
|
223
|
-
const push = await this.#push();
|
|
224
|
-
const endpoint = this.#bells[id];
|
|
225
|
-
if (!push || endpoint === undefined)
|
|
226
|
-
return;
|
|
227
|
-
const out = answered(await push.ask('ring', { endpoint }));
|
|
228
|
-
if (out.gone === true && this.#bells[id] === endpoint)
|
|
229
|
-
delete this.#bells[id];
|
|
230
|
-
}
|
|
231
|
-
async #push() {
|
|
232
|
-
if (!this.stance.standings.get(PUSHER)) {
|
|
233
|
-
this.#lending ??= this.stance.lend(Push, PUSHER).finally(() => (this.#lending = undefined));
|
|
234
|
-
await this.#lending;
|
|
235
|
-
}
|
|
236
|
-
return this.stance.standings.get(PUSHER);
|
|
237
|
-
}
|
|
238
|
-
#hold(wards) {
|
|
239
|
-
return new Promise((resolve) => {
|
|
240
|
-
const wait = clock.wait(RELAY_HOLD);
|
|
241
|
-
const collector = {
|
|
242
|
-
wards,
|
|
243
|
-
wake: () => {
|
|
244
|
-
wait.cancel();
|
|
245
|
-
this.#collectors.delete(collector);
|
|
246
|
-
resolve();
|
|
247
|
-
},
|
|
248
|
-
};
|
|
249
|
-
this.#collectors.add(collector);
|
|
250
|
-
void wait.done.then(collector.wake);
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
#settle(box, reply) {
|
|
254
|
-
box.cancel();
|
|
255
|
-
const at = this.#waiting.indexOf(box);
|
|
256
|
-
if (at >= 0)
|
|
257
|
-
this.#waiting.splice(at, 1);
|
|
258
|
-
this.#taken.delete(box.n);
|
|
259
|
-
box.answer(reply);
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
export const relayClient = (ground, clock) => class RelayClient extends CarrierFaculty {
|
|
263
|
-
static kind = RELAY_CLIENT;
|
|
264
|
-
static asks = {
|
|
265
|
-
hold: ownerAsk("a relay's invitation, collected from on a line, a schedule or a ring", { required: ['invitation'] }),
|
|
266
|
-
ring: ownerAsk('every waiting box collected and answered now'),
|
|
267
|
-
bell: ownerAsk('the push endpoint the relay rings, or null', { required: ['endpoint'] }),
|
|
268
|
-
key: ownerAsk('the key this device subscribes to pushes with'),
|
|
269
|
-
drop: ownerAsk('the relay let go'),
|
|
270
|
-
};
|
|
271
|
-
#awake = false;
|
|
272
|
-
#replies = [];
|
|
273
|
-
#turn = Promise.resolve();
|
|
274
|
-
// Ends every rest and schedule when the client sleeps or lets go.
|
|
275
|
-
#stop = () => { };
|
|
276
|
-
accepts() {
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
dial() {
|
|
280
|
-
return Promise.resolve(UNDIALED);
|
|
281
|
-
}
|
|
282
|
-
awake() {
|
|
283
|
-
if (!this.#awake) {
|
|
284
|
-
this.#awake = true;
|
|
285
|
-
this.#start();
|
|
286
|
-
}
|
|
287
|
-
return Promise.resolve();
|
|
288
|
-
}
|
|
289
|
-
sleep() {
|
|
290
|
-
this.#awake = false;
|
|
291
|
-
this.#stop();
|
|
292
|
-
return Promise.resolve();
|
|
293
|
-
}
|
|
294
|
-
async hold(args) {
|
|
295
|
-
const invitation = readInvitation(args.invitation);
|
|
296
|
-
const { line, every } = args;
|
|
297
|
-
if (invitation === null || (line !== undefined && typeof line !== 'boolean') || (every !== undefined && !(Number.isInteger(every) && every > 0))) {
|
|
298
|
-
return { error: 'an invitation, line a boolean and every a positive integer' };
|
|
299
|
-
}
|
|
300
|
-
if (this.stance.standings.get(CLIENT))
|
|
301
|
-
return { error: 'a relay is held' };
|
|
302
|
-
if ((await this.stance.standings.take(CLIENT, invitation)) === null)
|
|
303
|
-
return { error: 'not taken' };
|
|
304
|
-
this.cells.line = line === true;
|
|
305
|
-
if (every !== undefined)
|
|
306
|
-
this.cells.every = every;
|
|
307
|
-
this.#start();
|
|
308
|
-
return { held: invitation.ward };
|
|
309
|
-
}
|
|
310
|
-
async ring() {
|
|
311
|
-
if (!this.stance.standings.get(CLIENT))
|
|
312
|
-
return { error: 'no relay is held' };
|
|
313
|
-
let carried = 0;
|
|
314
|
-
for (;;) {
|
|
315
|
-
const sent = this.#replies.length;
|
|
316
|
-
const got = await this.#collect(false);
|
|
317
|
-
if (got === null)
|
|
318
|
-
return { error: 'the relay was not reached', carried };
|
|
319
|
-
carried += got;
|
|
320
|
-
if (got === 0 && sent === 0)
|
|
321
|
-
return { carried };
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
bell(args) {
|
|
325
|
-
return this.#relay('bell', { endpoint: args.endpoint ?? null });
|
|
326
|
-
}
|
|
327
|
-
key() {
|
|
328
|
-
return this.#relay('key');
|
|
329
|
-
}
|
|
330
|
-
drop() {
|
|
331
|
-
if (!this.stance.standings.remove(CLIENT))
|
|
332
|
-
return { error: 'no relay is held' };
|
|
333
|
-
delete this.cells.line;
|
|
334
|
-
delete this.cells.every;
|
|
335
|
-
this.#stop();
|
|
336
|
-
return { dropped: true };
|
|
337
|
-
}
|
|
338
|
-
async #relay(method, args = {}) {
|
|
339
|
-
const standing = this.stance.standings.get(CLIENT);
|
|
340
|
-
return standing ? answered(await standing.ask(method, args)) : { error: 'no relay is held' };
|
|
341
|
-
}
|
|
342
|
-
#start() {
|
|
343
|
-
if (!this.#awake || !this.stance.standings.get(CLIENT))
|
|
344
|
-
return;
|
|
345
|
-
this.#stop();
|
|
346
|
-
let stopped = false;
|
|
347
|
-
const rests = new Set();
|
|
348
|
-
this.#stop = () => {
|
|
349
|
-
stopped = true;
|
|
350
|
-
for (const end of rests)
|
|
351
|
-
end();
|
|
352
|
-
};
|
|
353
|
-
const rest = (ms) => new Promise((resolve) => {
|
|
354
|
-
const wait = clock.wait(ms);
|
|
355
|
-
const end = () => {
|
|
356
|
-
wait.cancel();
|
|
357
|
-
rests.delete(end);
|
|
358
|
-
resolve();
|
|
359
|
-
};
|
|
360
|
-
rests.add(end);
|
|
361
|
-
void wait.done.then(end);
|
|
362
|
-
});
|
|
363
|
-
const going = () => !stopped && this.stance.standings.get(CLIENT) !== undefined;
|
|
364
|
-
if (this.cells.line === true) {
|
|
365
|
-
void (async () => {
|
|
366
|
-
while (going())
|
|
367
|
-
if ((await this.#collect(true)) === null && going())
|
|
368
|
-
await rest(RELAY_REST);
|
|
369
|
-
})();
|
|
370
|
-
}
|
|
371
|
-
const every = this.cells.every;
|
|
372
|
-
if (every !== undefined) {
|
|
373
|
-
void (async () => {
|
|
374
|
-
for (await rest(every); going(); await rest(every))
|
|
375
|
-
await this.ring();
|
|
376
|
-
})();
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
// One collect: the replies owed go with it, and each box it brings is
|
|
380
|
-
// handed to this harbor's doors. The number of boxes, or null where the
|
|
381
|
-
// relay was not reached.
|
|
382
|
-
// Collects run one after another, so each carries the replies to every
|
|
383
|
-
// box the one before it brought, as the relay counts on.
|
|
384
|
-
#collect(wait) {
|
|
385
|
-
const run = this.#turn.then(() => this.#collectNow(wait));
|
|
386
|
-
this.#turn = run.catch(() => undefined);
|
|
387
|
-
return run;
|
|
388
|
-
}
|
|
389
|
-
async #collectNow(wait) {
|
|
390
|
-
const standing = this.stance.standings.get(CLIENT);
|
|
391
|
-
if (!standing)
|
|
392
|
-
return null;
|
|
393
|
-
const replies = this.#replies.splice(0);
|
|
394
|
-
const out = await standing.ask('collect', { replies, wait });
|
|
395
|
-
const boxes = !isSilence(out) && !isWord(out) && Array.isArray(out.boxes) ? out.boxes : null;
|
|
396
|
-
if (boxes === null) {
|
|
397
|
-
this.#replies.unshift(...replies);
|
|
398
|
-
return null;
|
|
399
|
-
}
|
|
400
|
-
for (const { n, ward, box } of boxes) {
|
|
401
|
-
const reply = text(ward) && text(box) && isHex(box, box.length / 2) ? await ground.arrive(ward, unhex(box)) : null;
|
|
402
|
-
this.#replies.push({ n: n, box: reply === null ? null : hex(reply) });
|
|
403
|
-
}
|
|
404
|
-
return boxes.length;
|
|
405
|
-
}
|
|
406
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type JsonObject } from '../being/index.ts';
|
|
2
|
-
import type { Harbor } from './harbor.ts';
|
|
3
|
-
export type RootRequest = {
|
|
4
|
-
ward?: string;
|
|
5
|
-
method?: string;
|
|
6
|
-
args?: JsonObject;
|
|
7
|
-
};
|
|
8
|
-
export declare const readRootRequest: (value: unknown) => RootRequest | null;
|
|
9
|
-
export declare const rootLine: (harbor: Harbor, value: unknown) => Promise<JsonObject>;
|
package/dist/harbor/root-line.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The root line: one request, one answer, both plain JSON, for whatever
|
|
3
|
-
// carries the root's asks to a harbor in its own process. The command line
|
|
4
|
-
// carries it over a local socket, and an edge route carries it the same way.
|
|
5
|
-
//
|
|
6
|
-
// request { ward?, method?, args? } no ward is the box ward, no
|
|
7
|
-
// method the census
|
|
8
|
-
// answer { answer } what the ward-being said
|
|
9
|
-
// { silence: true } she said nothing
|
|
10
|
-
// { word } a kit word: unreached, late, ...
|
|
11
|
-
// { error } the request was not one, or the
|
|
12
|
-
// ward is none this harbor holds
|
|
13
|
-
import { isSilence, isWord, told } from '../being/index.js';
|
|
14
|
-
const object = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
15
|
-
export const readRootRequest = (value) => {
|
|
16
|
-
if (!object(value))
|
|
17
|
-
return null;
|
|
18
|
-
const { ward, method, args } = value;
|
|
19
|
-
if ((ward !== undefined && typeof ward !== 'string') || (method !== undefined && typeof method !== 'string') || (args !== undefined && !object(args)))
|
|
20
|
-
return null;
|
|
21
|
-
return { ...(ward === undefined ? {} : { ward }), ...(method === undefined ? {} : { method }), ...(args === undefined ? {} : { args }) };
|
|
22
|
-
};
|
|
23
|
-
export const rootLine = async (harbor, value) => {
|
|
24
|
-
const request = readRootRequest(value);
|
|
25
|
-
if (request === null)
|
|
26
|
-
return { error: 'not a root request' };
|
|
27
|
-
const ward = request.ward === undefined ? harbor.box : harbor.ward(request.ward);
|
|
28
|
-
if (ward === undefined) {
|
|
29
|
-
const failed = request.ward === undefined ? undefined : harbor.failures().wards[request.ward];
|
|
30
|
-
return failed === undefined ? { error: 'no such ward' } : { error: 'the ward did not stand', reason: failed };
|
|
31
|
-
}
|
|
32
|
-
const out = await ward.root(request.method, request.args);
|
|
33
|
-
if (isSilence(out))
|
|
34
|
-
return { silence: true };
|
|
35
|
-
if (isWord(out))
|
|
36
|
-
return { word: told(out) };
|
|
37
|
-
return { answer: out };
|
|
38
|
-
};
|
package/dist/harbor/store.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Faculty, type BeingClass } from '../being/index.ts';
|
|
2
|
-
import type { Memory } from '../contract/index.ts';
|
|
3
|
-
export declare const STORE = "org.nervur.store";
|
|
4
|
-
export declare const GROUND_STORE = "org.nervur.ground-store";
|
|
5
|
-
export declare abstract class Store extends Faculty {
|
|
6
|
-
static readonly kind: string;
|
|
7
|
-
abstract read(place: string): Promise<Map<string, Uint8Array>>;
|
|
8
|
-
abstract write(place: string, entries: ReadonlyMap<string, Uint8Array | null>): Promise<void>;
|
|
9
|
-
abstract places(): Promise<string[]>;
|
|
10
|
-
abstract forget(place: string): Promise<void>;
|
|
11
|
-
occupies(_place: string): boolean;
|
|
12
|
-
}
|
|
13
|
-
export declare const groundStore: (memory: Memory) => BeingClass;
|
package/dist/harbor/store.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The store: a faculty that keeps a hosted ward's place, where the root
|
|
3
|
-
// memory does not. It makes the same promise the Memory body makes, lent
|
|
4
|
-
// once the dock stands: sealed entries in places, each keep whole or not
|
|
5
|
-
// at all. The box ward never moves off the root memory, since the store
|
|
6
|
-
// itself stands from the box ward's cells.
|
|
7
|
-
//
|
|
8
|
-
// A ward is the unit a keeper holds: its head, its ward-being 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, whoever keeps them.
|
|
11
|
-
//
|
|
12
|
-
// The kit ships `org.nervur.ground-store` on every ground: places of the
|
|
13
|
-
// terrain's own memory under the faculty's key, so a store stands wherever
|
|
14
|
-
// a harbor does. A store of a cloud, a database or a ledger is a class
|
|
15
|
-
// fulfilling `org.nervur.store`, handed to the catalogue in a module.
|
|
16
|
-
import { Faculty } from '../being/index.js';
|
|
17
|
-
import { hex, utf8 } from '../crypto/index.js';
|
|
18
|
-
export const STORE = 'org.nervur.store';
|
|
19
|
-
export const GROUND_STORE = 'org.nervur.ground-store';
|
|
20
|
-
export class Store extends Faculty {
|
|
21
|
-
static kind = STORE;
|
|
22
|
-
// Whether a place of the root memory is this store's own, so the root's
|
|
23
|
-
// sweep leaves it.
|
|
24
|
-
occupies(_place) {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
// A place of the package is thirty-two hex digits.
|
|
29
|
-
const PLACE = 32;
|
|
30
|
-
// The store over the terrain's memory, made for one harbor. Its places are
|
|
31
|
-
// the package's, behind the hex of the faculty's key, so two stores and the
|
|
32
|
-
// root never meet in one place.
|
|
33
|
-
export const groundStore = (memory) => class GroundStore extends Store {
|
|
34
|
-
static kind = GROUND_STORE;
|
|
35
|
-
get #prefix() {
|
|
36
|
-
return hex(utf8(this.stance.key));
|
|
37
|
-
}
|
|
38
|
-
occupies(place) {
|
|
39
|
-
return place.length === this.#prefix.length + PLACE && place.startsWith(this.#prefix);
|
|
40
|
-
}
|
|
41
|
-
read(place) {
|
|
42
|
-
return memory.read(this.#prefix + place);
|
|
43
|
-
}
|
|
44
|
-
write(place, entries) {
|
|
45
|
-
return memory.write(this.#prefix + place, entries);
|
|
46
|
-
}
|
|
47
|
-
async places() {
|
|
48
|
-
return (await memory.places()).filter((place) => this.occupies(place)).map((place) => place.slice(this.#prefix.length));
|
|
49
|
-
}
|
|
50
|
-
forget(place) {
|
|
51
|
-
return memory.forget(this.#prefix + place);
|
|
52
|
-
}
|
|
53
|
-
};
|
package/dist/http/index.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { Ground, GroundFaculty } from '../harbor/index.ts';
|
|
2
|
-
import { type WebListen, type WebListener } from '../line/index.ts';
|
|
3
|
-
export declare const webServe: (ground: Ground, listen: WebListen) => Promise<WebListener>;
|
|
4
|
-
export declare const webGround: GroundFaculty;
|
package/dist/line/ground.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { HeldLoader, PointerTerrain } from '../pointer/index.js';
|
|
2
|
-
import { webPush } from './push.js';
|
|
3
|
-
import { WEB_OPENING, webFaculty } from './web.js';
|
|
4
|
-
export const NEUTRAL = 'neutral';
|
|
5
|
-
export const neutralGround = {
|
|
6
|
-
name: NEUTRAL,
|
|
7
|
-
fits: () => true,
|
|
8
|
-
terrain: ({ modules = [] }) => new PointerTerrain({ loader: new HeldLoader(modules), faculties: [webFaculty(), webPush], opens: [WEB_OPENING] }),
|
|
9
|
-
};
|
package/dist/line/index.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { ASK, askBody, askFrame, FrameReader, MAX_BODY, NOTHING, nothingBody, nothingFrame, readBody, REPLY, replyBody, replyFrame, TCP, TCP_OPENING, type Frame } from './frame.ts';
|
|
2
|
-
export { answerHeld, answerPost, type HeldSide } from './answer.ts';
|
|
3
|
-
export { NEUTRAL, neutralGround } from './ground.ts';
|
|
4
|
-
export { base64url, PUSH_TTL, pushEndpoint, VAPID_LIFE, WEB_PUSH, webPush } from './push.ts';
|
|
5
|
-
export { MAX_POST, MIN_POST, readPost, WEB, WEB_OPENING, WebDialer, webFaculty, type WebListen, type WebListener, type WebServe } from './web.ts';
|
package/dist/line/index.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The lines Quo is carried on, with no platform under them: the frames
|
|
3
|
-
// both published carriers share, the web carrier on fetch and the
|
|
4
|
-
// WebSocket client, and a ring with no content as Web Push sends it.
|
|
5
|
-
export { ASK, askBody, askFrame, FrameReader, MAX_BODY, NOTHING, nothingBody, nothingFrame, readBody, REPLY, replyBody, replyFrame, TCP, TCP_OPENING } from './frame.js';
|
|
6
|
-
export { answerHeld, answerPost } from './answer.js';
|
|
7
|
-
export { NEUTRAL, neutralGround } from './ground.js';
|
|
8
|
-
export { base64url, PUSH_TTL, pushEndpoint, VAPID_LIFE, WEB_PUSH, webPush } from './push.js';
|
|
9
|
-
export { MAX_POST, MIN_POST, readPost, WEB, WEB_OPENING, WebDialer, webFaculty } from './web.js';
|
package/dist/line/push.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { type GroundFaculty } from '../harbor/index.ts';
|
|
2
|
-
export declare const WEB_PUSH = "org.nervur.web-push";
|
|
3
|
-
export declare const PUSH_TTL = 60;
|
|
4
|
-
export declare const VAPID_LIFE = 43200;
|
|
5
|
-
export declare const base64url: (bytes: Uint8Array) => string;
|
|
6
|
-
export declare const pushEndpoint: (value: unknown) => URL | null;
|
|
7
|
-
export declare const webPush: GroundFaculty;
|
package/dist/line/push.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { concat, utf8 } from '../crypto/index.js';
|
|
2
|
-
import { Push } from '../harbor/index.js';
|
|
3
|
-
import { ownerAsk } from '../ward/index.js';
|
|
4
|
-
export const WEB_PUSH = 'org.nervur.web-push';
|
|
5
|
-
// How long a push service holds a ring for a device, in seconds.
|
|
6
|
-
export const PUSH_TTL = 60;
|
|
7
|
-
// How long a VAPID token stands, in seconds, inside RFC 8292's day.
|
|
8
|
-
export const VAPID_LIFE = 43_200;
|
|
9
|
-
const EC = { name: 'ECDSA', namedCurve: 'P-256' };
|
|
10
|
-
export const base64url = (bytes) => {
|
|
11
|
-
let s = '';
|
|
12
|
-
for (const b of bytes)
|
|
13
|
-
s += String.fromCharCode(b);
|
|
14
|
-
return btoa(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
15
|
-
};
|
|
16
|
-
const unbase64url = (text) => Uint8Array.from(atob(text.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0));
|
|
17
|
-
const local = (host) => host === '127.0.0.1' || host === 'localhost' || host === '[::1]';
|
|
18
|
-
// A push endpoint: an https URL, or plain http to this machine alone.
|
|
19
|
-
export const pushEndpoint = (value) => {
|
|
20
|
-
if (typeof value !== 'string')
|
|
21
|
-
return null;
|
|
22
|
-
try {
|
|
23
|
-
const url = new URL(value);
|
|
24
|
-
return url.protocol === 'https:' || (url.protocol === 'http:' && local(url.hostname)) ? url : null;
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
const isSubject = (value) => typeof value === 'string' && /^(mailto:.+|https:\/\/.+)$/.test(value);
|
|
31
|
-
export const webPush = () => class WebPush extends Push {
|
|
32
|
-
static kind = WEB_PUSH;
|
|
33
|
-
static asks = {
|
|
34
|
-
subject: ownerAsk('the contact a push service reaches, a mailto: or https: URI', { required: ['subject'] }),
|
|
35
|
-
key: { description: 'the key a device subscribes to pushes with', input: { type: 'object' } },
|
|
36
|
-
ring: { description: 'a ring with no content to a push endpoint', input: { type: 'object', required: ['endpoint'] } },
|
|
37
|
-
};
|
|
38
|
-
#drawing;
|
|
39
|
-
subject(args) {
|
|
40
|
-
if (!isSubject(args.subject))
|
|
41
|
-
return { error: 'subject is a mailto: or https: URI' };
|
|
42
|
-
this.cells.subject = args.subject;
|
|
43
|
-
return { subject: args.subject };
|
|
44
|
-
}
|
|
45
|
-
async key() {
|
|
46
|
-
return { key: WebPush.#public(await this.#vapid()) };
|
|
47
|
-
}
|
|
48
|
-
async ring(args) {
|
|
49
|
-
const endpoint = pushEndpoint(args.endpoint);
|
|
50
|
-
if (endpoint === null)
|
|
51
|
-
return { error: 'endpoint is an https URL' };
|
|
52
|
-
const sub = this.cells.subject;
|
|
53
|
-
if (!isSubject(sub))
|
|
54
|
-
return { error: 'no subject is set' };
|
|
55
|
-
const vapid = await this.#vapid();
|
|
56
|
-
const signing = await crypto.subtle.importKey('jwk', { kty: 'EC', crv: 'P-256', ...vapid }, EC, false, ['sign']);
|
|
57
|
-
const part = (value) => base64url(utf8(JSON.stringify(value)));
|
|
58
|
-
const unsigned = `${part({ typ: 'JWT', alg: 'ES256' })}.${part({ aud: endpoint.origin, exp: Math.floor(Date.now() / 1000) + VAPID_LIFE, sub })}`;
|
|
59
|
-
const signature = new Uint8Array(await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, signing, new Uint8Array(utf8(unsigned))));
|
|
60
|
-
let status;
|
|
61
|
-
try {
|
|
62
|
-
const response = await fetch(endpoint, {
|
|
63
|
-
method: 'POST',
|
|
64
|
-
headers: { TTL: String(PUSH_TTL), Urgency: 'high', 'Content-Length': '0', Authorization: `vapid t=${unsigned}.${base64url(signature)}, k=${WebPush.#public(vapid)}` },
|
|
65
|
-
});
|
|
66
|
-
status = response.status;
|
|
67
|
-
await response.body?.cancel();
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
return { error: 'the push service was not reached' };
|
|
71
|
-
}
|
|
72
|
-
if (status === 404 || status === 410)
|
|
73
|
-
return { gone: true };
|
|
74
|
-
return status >= 200 && status < 300 ? { rung: true } : { error: `the push service answered ${String(status)}` };
|
|
75
|
-
}
|
|
76
|
-
static #public({ x, y }) {
|
|
77
|
-
return base64url(concat(Uint8Array.of(4), unbase64url(x), unbase64url(y)));
|
|
78
|
-
}
|
|
79
|
-
#vapid() {
|
|
80
|
-
const kept = this.cells.vapid;
|
|
81
|
-
if (kept)
|
|
82
|
-
return Promise.resolve(kept);
|
|
83
|
-
this.#drawing ??= (async () => {
|
|
84
|
-
const pair = await crypto.subtle.generateKey(EC, true, ['sign']);
|
|
85
|
-
const { d, x, y } = await crypto.subtle.exportKey('jwk', pair.privateKey);
|
|
86
|
-
const vapid = { d: d, x: x, y: y };
|
|
87
|
-
this.cells.vapid = vapid;
|
|
88
|
-
return vapid;
|
|
89
|
-
})();
|
|
90
|
-
return this.#drawing;
|
|
91
|
-
}
|
|
92
|
-
};
|