@dcasegr/skein 0.0.0-stage → 0.1.2
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 +525 -2
- package/bin/skein-host.js +22 -0
- package/bin/skein.js +8 -0
- package/dist/client/admin-cli.d.ts +10 -0
- package/dist/client/admin-cli.js +370 -0
- package/dist/client/admin.d.ts +139 -0
- package/dist/client/admin.js +256 -0
- package/dist/client/bundle.d.ts +9 -0
- package/dist/client/bundle.js +34 -0
- package/dist/client/cli.d.ts +44 -0
- package/dist/client/cli.js +306 -0
- package/dist/client/client.d.ts +161 -0
- package/dist/client/client.js +237 -0
- package/dist/client/config.d.ts +18 -0
- package/dist/client/config.js +31 -0
- package/dist/client/conversation.d.ts +62 -0
- package/dist/client/conversation.js +113 -0
- package/dist/client/raw.d.ts +94 -0
- package/dist/client/raw.js +154 -0
- package/dist/client/target.d.ts +34 -0
- package/dist/client/target.js +158 -0
- package/dist/dev/cli.d.ts +8 -0
- package/dist/dev/cli.js +248 -0
- package/dist/dev/scan.d.ts +15 -0
- package/dist/dev/scan.js +173 -0
- package/dist/envelope-cbor.d.ts +110 -0
- package/dist/envelope-cbor.js +160 -0
- package/dist/envelope.d.ts +38 -0
- package/dist/envelope.js +101 -0
- package/dist/host/arc.d.ts +131 -0
- package/dist/host/arc.js +425 -0
- package/dist/host/billing.d.ts +102 -0
- package/dist/host/billing.js +167 -0
- package/dist/host/boot.d.ts +246 -0
- package/dist/host/boot.js +643 -0
- package/dist/host/cli.d.ts +57 -0
- package/dist/host/cli.js +1253 -0
- package/dist/host/clock.d.ts +3 -0
- package/dist/host/clock.js +8 -0
- package/dist/host/control.d.ts +45 -0
- package/dist/host/control.js +170 -0
- package/dist/host/cron.d.ts +99 -0
- package/dist/host/cron.js +196 -0
- package/dist/host/deliver.d.ts +53 -0
- package/dist/host/deliver.js +251 -0
- package/dist/host/deploy.d.ts +29 -0
- package/dist/host/deploy.js +55 -0
- package/dist/host/door-answer.d.ts +24 -0
- package/dist/host/door-answer.js +21 -0
- package/dist/host/events.d.ts +89 -0
- package/dist/host/events.js +222 -0
- package/dist/host/fake-arcade.d.ts +40 -0
- package/dist/host/fake-arcade.js +149 -0
- package/dist/host/fake-discovery.d.ts +4 -0
- package/dist/host/fake-discovery.js +58 -0
- package/dist/host/feeds.d.ts +127 -0
- package/dist/host/feeds.js +422 -0
- package/dist/host/frontdoor.d.ts +92 -0
- package/dist/host/frontdoor.js +172 -0
- package/dist/host/genesis.d.ts +259 -0
- package/dist/host/genesis.js +353 -0
- package/dist/host/handles.d.ts +40 -0
- package/dist/host/handles.js +88 -0
- package/dist/host/hostenv.d.ts +30 -0
- package/dist/host/hostenv.js +83 -0
- package/dist/host/image-chain.d.ts +127 -0
- package/dist/host/image-chain.js +440 -0
- package/dist/host/install.d.ts +22 -0
- package/dist/host/install.js +139 -0
- package/dist/host/instances.d.ts +227 -0
- package/dist/host/instances.js +430 -0
- package/dist/host/kernel.d.ts +246 -0
- package/dist/host/kernel.js +603 -0
- package/dist/host/liveness.d.ts +65 -0
- package/dist/host/liveness.js +155 -0
- package/dist/host/manifest.d.ts +160 -0
- package/dist/host/manifest.js +597 -0
- package/dist/host/p2p.d.ts +337 -0
- package/dist/host/p2p.js +1002 -0
- package/dist/host/packet.d.ts +121 -0
- package/dist/host/packet.js +562 -0
- package/dist/host/plan.d.ts +154 -0
- package/dist/host/plan.js +418 -0
- package/dist/host/providers.d.ts +238 -0
- package/dist/host/providers.js +565 -0
- package/dist/host/roster.d.ts +72 -0
- package/dist/host/roster.js +172 -0
- package/dist/host/router.d.ts +782 -0
- package/dist/host/router.js +2411 -0
- package/dist/host/signer.d.ts +49 -0
- package/dist/host/signer.js +167 -0
- package/dist/host/store-sqlite.d.ts +39 -0
- package/dist/host/store-sqlite.js +170 -0
- package/dist/host/stores.d.ts +43 -0
- package/dist/host/stores.js +342 -0
- package/dist/host/sync.d.ts +121 -0
- package/dist/host/sync.js +467 -0
- package/dist/host/testbeef.d.ts +21 -0
- package/dist/host/testbeef.js +37 -0
- package/dist/host/testhost.d.ts +149 -0
- package/dist/host/testhost.js +211 -0
- package/dist/host/vcdiff.d.ts +9 -0
- package/dist/host/vcdiff.js +210 -0
- package/dist/host/wasm-kernel.d.ts +87 -0
- package/dist/host/wasm-kernel.js +296 -0
- package/dist/host/wasm-worker.d.ts +1 -0
- package/dist/host/wasm-worker.js +186 -0
- package/dist/peers/cron.d.ts +33 -0
- package/dist/peers/cron.js +75 -0
- package/dist/peers/infer-main.d.ts +2 -0
- package/dist/peers/infer-main.js +74 -0
- package/dist/peers/infer.d.ts +163 -0
- package/dist/peers/infer.js +367 -0
- package/dist/runtime/beef.d.ts +28 -0
- package/dist/runtime/beef.js +107 -0
- package/dist/runtime/bitcoin.d.ts +36 -0
- package/dist/runtime/bitcoin.js +141 -0
- package/dist/runtime/cid.d.ts +14 -0
- package/dist/runtime/cid.js +51 -0
- package/dist/runtime/dispatch.d.ts +92 -0
- package/dist/runtime/dispatch.js +142 -0
- package/dist/runtime/envelope.d.ts +60 -0
- package/dist/runtime/envelope.js +101 -0
- package/dist/runtime/heads.d.ts +25 -0
- package/dist/runtime/heads.js +37 -0
- package/dist/runtime/identity.d.ts +28 -0
- package/dist/runtime/identity.js +67 -0
- package/dist/runtime/index-store.d.ts +152 -0
- package/dist/runtime/index-store.js +715 -0
- package/dist/runtime/log.d.ts +62 -0
- package/dist/runtime/log.js +104 -0
- package/dist/runtime/programs.d.ts +30 -0
- package/dist/runtime/programs.js +61 -0
- package/dist/runtime/records.d.ts +135 -0
- package/dist/runtime/records.js +149 -0
- package/dist/runtime/sqlite.d.ts +33 -0
- package/dist/runtime/sqlite.js +604 -0
- package/dist/runtime/store.d.ts +141 -0
- package/dist/runtime/store.js +24 -0
- package/dist/runtime/syscalls.d.ts +9 -0
- package/dist/runtime/syscalls.js +41 -0
- package/dist/runtime/tree.d.ts +60 -0
- package/dist/runtime/tree.js +196 -0
- package/dist/runtime/types.d.ts +100 -0
- package/dist/runtime/types.js +7 -0
- package/dist/testapps.d.ts +101 -0
- package/dist/testapps.js +275 -0
- package/dist/testkit.d.ts +25 -0
- package/dist/testkit.js +48 -0
- package/dist/wallet.d.ts +35 -0
- package/dist/wallet.js +87 -0
- package/images/README.md +68 -0
- package/images/default/README.md +38 -0
- package/images/default/bin/frontdoor.cid +1 -0
- package/images/default/bin/frontdoor.json +5 -0
- package/images/default/bin/messagebox.cid +1 -0
- package/images/default/bin/messagebox.json +8 -0
- package/images/default/bin/wallet.cid +1 -0
- package/images/default/bin/wallet.json +14 -0
- package/images/default/etc/config.json +1 -0
- package/images/default/etc/dispatch.json +82 -0
- package/images/host/etc/apps.json +8 -0
- package/kernel-zig/README.md +1247 -0
- package/kernel-zig/web/client.js +65 -0
- package/kernel-zig/web/kernel.d.ts +59 -0
- package/kernel-zig/web/kernel.js +329 -0
- package/kernel-zig/web/store.js +67 -0
- package/kernel-zig/web/worker.js +79 -0
- package/kernel-zig/zig-out/web/skein-kernel.wasm +0 -0
- package/package.json +77 -4
- package/wasm/README.md +35 -0
- package/wasm/frontdoor.wasm +0 -0
- package/wasm/messagebox.wasm +0 -0
- package/wasm/resolve.wasm +0 -0
- package/wasm/wallet.wasm +0 -0
- package/wasm/wire-probe.wasm +0 -0
|
@@ -0,0 +1,782 @@
|
|
|
1
|
+
import { type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
|
2
|
+
import { PrivateKey, ProtoWallet, type WalletInterface } from "@bsv/sdk";
|
|
3
|
+
import { CID } from "multiformats/cid";
|
|
4
|
+
import type { Stamp } from "../runtime/syscalls.ts";
|
|
5
|
+
import { Broadcaster, type ArcConfig } from "./arc.ts";
|
|
6
|
+
import { Feeds, type FeedSpec } from "./feeds.ts";
|
|
7
|
+
import { Cron } from "./cron.ts";
|
|
8
|
+
import { type DispatchRow } from "../runtime/dispatch.ts";
|
|
9
|
+
import { type BootSource, type Booted } from "./boot.ts";
|
|
10
|
+
import { ImageChain } from "./image-chain.ts";
|
|
11
|
+
import { OverlaySync } from "./sync.ts";
|
|
12
|
+
import { type AddressSeed, type DispatchSpec, type Genesis2Config, type Libp2pSpec } from "./genesis.ts";
|
|
13
|
+
import { HANDLE, type HostDb, type InstanceRow } from "./instances.ts";
|
|
14
|
+
import { type KernelSurface } from "./kernel.ts";
|
|
15
|
+
import { type Live } from "./liveness.ts";
|
|
16
|
+
import { EventStreams } from "./events.ts";
|
|
17
|
+
import { P2PHost, type Beacon, type InboundAnswer, type InboundCall, type P2PHostConfig, type Subscription } from "./p2p.ts";
|
|
18
|
+
import { Providers, type HttpRequest, type HttpResponse, type MailRecord, type ProviderName } from "./providers.ts";
|
|
19
|
+
import { Deliverer } from "./deliver.ts";
|
|
20
|
+
import { type BillingConfig, type BillingView } from "./billing.ts";
|
|
21
|
+
type Named = {
|
|
22
|
+
handle: string;
|
|
23
|
+
domain: string;
|
|
24
|
+
};
|
|
25
|
+
export interface RouterOptions {
|
|
26
|
+
db: HostDb;
|
|
27
|
+
/** Each row's signer: the wallet its kernel's `wallet` import is answered from. */
|
|
28
|
+
walletFor(row: InstanceRow): Promise<WalletInterface> | WalletInterface;
|
|
29
|
+
/** A new agent's genesis: its owner (required to write one), the inference peer, their names. */
|
|
30
|
+
owner?: string;
|
|
31
|
+
infer?: string;
|
|
32
|
+
ownerHandle?: Named;
|
|
33
|
+
inferHandle?: Named;
|
|
34
|
+
fuelPerStep?: string;
|
|
35
|
+
/** A new genesis's extra routes — boxes (a box and its handler) and routes of any transport (#143: no sender) — and defaults (over DEFAULTS), e.g. the wallet's (#29). */
|
|
36
|
+
genesis?: {
|
|
37
|
+
subscriptions?: Array<{
|
|
38
|
+
box: string;
|
|
39
|
+
handler: CID;
|
|
40
|
+
}>;
|
|
41
|
+
defaults?: Record<string, string>;
|
|
42
|
+
feeds?: FeedSpec[];
|
|
43
|
+
libp2p?: Libp2pSpec;
|
|
44
|
+
dispatch?: DispatchSpec[];
|
|
45
|
+
};
|
|
46
|
+
/** The router-held feeds' limits (feeds.ts); the backoff is the broadcaster's subscription's too. */
|
|
47
|
+
feeds?: {
|
|
48
|
+
maxQueue?: number;
|
|
49
|
+
backoff?: {
|
|
50
|
+
min: number;
|
|
51
|
+
max: number;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
/** The host's headers feed (#102, SKEIN_HEADERS_URL): an SSE stream of block headers every enabled instance whose dispatch table takes events in box `chain` is subscribed to. */
|
|
55
|
+
headersFeed?: string;
|
|
56
|
+
/** The host's Arcade (#58, #65, arc.ts): where the broadcast events go, the status subscription, the `status` provider. Absent: no broadcaster (a broadcast event is dropped). */
|
|
57
|
+
arc?: ArcConfig;
|
|
58
|
+
/** Tests: how the broadcaster reaches Arcade. */
|
|
59
|
+
arcFetch?: typeof fetch;
|
|
60
|
+
/** The broadcaster's queue: how soon a broadcast Arcade did not take is posted again (ms, doubling; default 1 000 → 300 000). */
|
|
61
|
+
arcRetry?: {
|
|
62
|
+
min: number;
|
|
63
|
+
max: number;
|
|
64
|
+
};
|
|
65
|
+
/** The HTTP proxy's network (#70, the `fetch` provider) for URLs that are not this host's; default: SKEIN_HTTP=fetch performs them (fetchHttp), else refused. */
|
|
66
|
+
http?(req: HttpRequest): Promise<HttpResponse>;
|
|
67
|
+
/** Stop a kernel this long after its last call (ms); 0: never (the default: instances are not stopped until resource contention appears). */
|
|
68
|
+
idleMs?: number;
|
|
69
|
+
/** How long a synchronous client waits on its request's thread (#66) before 503 + Retry-After (ms); default SKEIN_ANSWER_WAIT_MS, else two minutes. */
|
|
70
|
+
answerWaitMs?: number;
|
|
71
|
+
/** Where a new mailbox instance's store goes: <home>/instances/<handle>/runtime.db. */
|
|
72
|
+
home?: string;
|
|
73
|
+
/** SKEIN_STORE (#96): the host's LMDB environment (a directory); a new instance's store is then its set there (host.db `lmdb:<dir>`, the set its handle). Unset: a file, <home>/instances/<handle>/runtime.db. */
|
|
74
|
+
lmdbStore?: string;
|
|
75
|
+
/**
|
|
76
|
+
* SKEIN_STORE_ROCKSDB (#158): the host's RocksDB database (a directory), run by one
|
|
77
|
+
* `skein-kernel host` process this router starts (KernelHost): a new instance's store is its set
|
|
78
|
+
* there (host.db `rocksdb:<dir>`, the set its handle). Over `lmdbStore`.
|
|
79
|
+
*/
|
|
80
|
+
rocksStore?: string;
|
|
81
|
+
/**
|
|
82
|
+
* SKEIN_STORE_SQLITE (the settled split, 2026-10-31): the host's one SQLite database (a file); a
|
|
83
|
+
* new instance's store is then its set there (host.db `sqlite:<path>`, the set its handle), run by
|
|
84
|
+
* the wasm kernel this process loads (wasm-kernel.ts). Over `rocksStore` and `lmdbStore`.
|
|
85
|
+
*/
|
|
86
|
+
sqliteStore?: string;
|
|
87
|
+
/** An instance's origin, `{handle}` and `{port}` filled in; default http://{handle}.localhost:{port}. */
|
|
88
|
+
instanceOrigin?: string;
|
|
89
|
+
/** This host's own origin (the manifest, a genesis's resolveOrigin); default http://127.0.0.1:{port}. */
|
|
90
|
+
origin?: string;
|
|
91
|
+
/** The port it serves on, for origins named before it listens (a boot, `skein-host add`); listening sets it. */
|
|
92
|
+
port?: number;
|
|
93
|
+
/** The owner's messagebox URL for a new agent's genesis; default the owner's mailbox instance here, if there is one. */
|
|
94
|
+
ownerMessagebox?: string;
|
|
95
|
+
/** The network the whole host runs on (SKEIN_NETWORK): every genesis it makes has it as `defaults.walletNetwork`. */
|
|
96
|
+
network?: string;
|
|
97
|
+
/** How often the fuel ledger is written (ms); default 5000. */
|
|
98
|
+
ledgerMs?: number;
|
|
99
|
+
/** Tests: the clock entries are stamped with (and ticks fall due by: cron.ts). */
|
|
100
|
+
now?: () => Stamp;
|
|
101
|
+
/** The cron provider's clock (#69, cron.ts): false — this router sends no ticks (a one-shot command's router is no clock; it still keeps a schedule a step asks for, in host.db). Default true. */
|
|
102
|
+
cron?: boolean;
|
|
103
|
+
/** Lines, by source: an instance's handle, or "router". */
|
|
104
|
+
log?(source: string, line: string): void;
|
|
105
|
+
/** Kernel process settings. */
|
|
106
|
+
kernel?: {
|
|
107
|
+
command?: string;
|
|
108
|
+
env?: Record<string, string | undefined>;
|
|
109
|
+
};
|
|
110
|
+
/** The libp2p host (#51, p2p.ts): its host-wide settings (default: loopback TCP + WS, no DHT, no mDNS). */
|
|
111
|
+
libp2p?: P2PHostConfig;
|
|
112
|
+
/** An instance's libp2p peer key (signer.ts peerKey). Absent: no libp2p host; the kernels' `libp2p` is refused. */
|
|
113
|
+
peerKeyFor?(handle: string): PrivateKey;
|
|
114
|
+
/**
|
|
115
|
+
* A provider's key (#70, signer.ts providerKey: the HTTP proxy `fetch`, the
|
|
116
|
+
* `waker`, `cron`, `libp2p`, `status`), which each new genesis's address
|
|
117
|
+
* book names. Absent: keys of this router's own, made fresh (a test's; a
|
|
118
|
+
* restarted router would not be the providers its instances know).
|
|
119
|
+
*/
|
|
120
|
+
providerKeyFor?(name: ProviderName): PrivateKey;
|
|
121
|
+
/**
|
|
122
|
+
* Tests: the host's own origin's BRC-169 requests (DISCOVERY) answered
|
|
123
|
+
* when the host has no host skein — a fixture resolver over host.db
|
|
124
|
+
* (testhost.ts). A host's are always the host skein's.
|
|
125
|
+
*/
|
|
126
|
+
discovery?(req: RouterRequest, url: URL): Promise<RouterResponse | undefined>;
|
|
127
|
+
/** How often the libp2p host redials bootstrap peers and runs topic rendezvous (ms); default 30 000. */
|
|
128
|
+
libp2pDiscoveryMs?: number;
|
|
129
|
+
/** #130: what this host bills (billing.ts; `skein-host run`: billingConfig over the environment). Absent: it bills no one. */
|
|
130
|
+
billing?: BillingConfig;
|
|
131
|
+
/**
|
|
132
|
+
* #160, #162: a one-key host's shared key's wallet (signer.ts Signer.oneKey). With it, an instance the
|
|
133
|
+
* host creates (createInstance) with no forwarded claim is claimed by the host itself: the claim
|
|
134
|
+
* message signed by this key (its owner), appended as a forwarded claim is. Absent (a master-key
|
|
135
|
+
* host): a create needs the owner's own signed claim, as before.
|
|
136
|
+
*/
|
|
137
|
+
claimer?: WalletInterface;
|
|
138
|
+
/**
|
|
139
|
+
* #162, SKEIN_MANAGER_FOR (host env): the instances besides the host skein the instance manager
|
|
140
|
+
* takes messages from — the manager in their address book at birth, as in the host skein's (not the
|
|
141
|
+
* certifier). No other instance reaches it.
|
|
142
|
+
*/
|
|
143
|
+
managerFor?: string[];
|
|
144
|
+
/** SKEIN_ROOT_INSTANCE: the instance served at `/` of any hostname that is no instance's (the standalone's one app at localhost:<port>/). */
|
|
145
|
+
rootInstance?: string;
|
|
146
|
+
/** #162, SKEIN_IMAGES_DIR (default $SKEIN_HOME/images): the images a create names by name, a directory each (the layout `skein-host add --image <dir>` takes). */
|
|
147
|
+
imagesDir?: string;
|
|
148
|
+
/**
|
|
149
|
+
* #164: an application host's wiring (providers.ts `appEvent`): an emitted event whose name no
|
|
150
|
+
* stock wiring takes, from `handle`, handed over after its step's commit. Absent: logged as ignored.
|
|
151
|
+
*/
|
|
152
|
+
appEvent?(handle: string, record: Record<string, unknown>): void;
|
|
153
|
+
}
|
|
154
|
+
interface Loaded {
|
|
155
|
+
row: InstanceRow;
|
|
156
|
+
kernel: KernelSurface;
|
|
157
|
+
identity: string;
|
|
158
|
+
wallet: WalletInterface;
|
|
159
|
+
/** The genesis (its `libp2p`), and the dispatch table's tip as the libp2p node last followed it (#72, #77). */
|
|
160
|
+
genesis: Record<string, unknown>;
|
|
161
|
+
dispatchTip?: string;
|
|
162
|
+
/** The dispatch table as last read (syncDispatch). */
|
|
163
|
+
rows?: DispatchRow[];
|
|
164
|
+
/** The apps' subscriptions (#119): folded from the log at hydrate, then followed live. */
|
|
165
|
+
subs: Subscription[];
|
|
166
|
+
/** The apps' beacons (#126): folded from the log at hydrate, then followed live; an uninstalled app's (no row left) dropped. */
|
|
167
|
+
beacons: Beacon[];
|
|
168
|
+
/** The apps' liveness (#138): folded from the log at hydrate, then followed live; an uninstalled app's (no row left) dropped. */
|
|
169
|
+
live: Live[];
|
|
170
|
+
}
|
|
171
|
+
/** A request as the router takes it: the full URL (its host is the Host header's), lower-cased headers, the body. */
|
|
172
|
+
export interface RouterRequest {
|
|
173
|
+
method: string;
|
|
174
|
+
url: string;
|
|
175
|
+
headers: Record<string, string>;
|
|
176
|
+
body: Uint8Array; /** The instance whose `http` this is (none for a socket's). */
|
|
177
|
+
from?: string;
|
|
178
|
+
}
|
|
179
|
+
export interface RouterResponse {
|
|
180
|
+
status: number;
|
|
181
|
+
headers: Record<string, string>;
|
|
182
|
+
body: Uint8Array;
|
|
183
|
+
}
|
|
184
|
+
export { HANDLE };
|
|
185
|
+
/** Handles no instance may take on this host (H3), besides the router origin's own first label (Router.reserved): `id` (the router's own in production) and `host` (the host skein's). */
|
|
186
|
+
export declare const RESERVED_HANDLES: Set<string>;
|
|
187
|
+
/** The registration signature (#113: the onboarding app checks it): [2, "skein register"], key ID the username, counterparty anyone, over `register <username>@<domain>`. */
|
|
188
|
+
export declare const REGISTER_PROTOCOL: [2, string];
|
|
189
|
+
/** The onboarding app (shruggr/skein-onboard, #90, #113): the host skein's app that serves BRC-169 on the host's own origin. */
|
|
190
|
+
export declare const ONBOARD_APP = "onboard";
|
|
191
|
+
/**
|
|
192
|
+
* The host's own origin's BRC-169 requests (#113) → the host skein's routes
|
|
193
|
+
* (the onboarding app's, under /onboard/): method + path → route.
|
|
194
|
+
*/
|
|
195
|
+
export declare const DISCOVERY: Record<string, string>;
|
|
196
|
+
/** The paymail PKI (`GET /bsvalias/id/<handle>[@<domain>]`) → the app's prefix row `/onboard/bsvalias/id/…`. */
|
|
197
|
+
export declare const PAYMAIL_PREFIX = "/bsvalias/id/";
|
|
198
|
+
/** The BRC-169 domain a host name stands for: a dev router at a loopback address answers for `localhost`. */
|
|
199
|
+
export declare const domainOf: (hostname: string) => string;
|
|
200
|
+
/**
|
|
201
|
+
* The BRC-169 domain of this host (H4): its public origin's host name
|
|
202
|
+
* (SKEIN_ROUTER_ORIGIN, default the loopback: `localhost`). What a created
|
|
203
|
+
* instance, a claim and a mailbox instance record when nothing names one,
|
|
204
|
+
* and what /.well-known/skein-host answers.
|
|
205
|
+
*/
|
|
206
|
+
export declare const hostDomain: (origin: string) => string;
|
|
207
|
+
/**
|
|
208
|
+
* SKEIN_HTTP=fetch: the HTTP proxy's requests (#70, the `fetch` provider)
|
|
209
|
+
* performed for real; `timeoutMs` (default 30 000) bounds the whole exchange,
|
|
210
|
+
* `maxBytes` (#91) the response body: reading stops past it, and the request
|
|
211
|
+
* fails.
|
|
212
|
+
*/
|
|
213
|
+
export declare function fetchHttp(req: HttpRequest): Promise<HttpResponse>;
|
|
214
|
+
/**
|
|
215
|
+
* The warning for an agent whose genesis names no owner messagebox
|
|
216
|
+
* (`defaults.ownerMessagebox`): its sends to the owner — every answer to him —
|
|
217
|
+
* fail, since nothing else tells it where his mailbox is. Undefined if it names one.
|
|
218
|
+
*/
|
|
219
|
+
export declare function noOwnerMessagebox(genesis: Record<string, unknown> | null | undefined): string | undefined;
|
|
220
|
+
export declare class Router {
|
|
221
|
+
readonly o: RouterOptions;
|
|
222
|
+
readonly feeds: Feeds;
|
|
223
|
+
/** The cron provider's schedules (#69). */
|
|
224
|
+
readonly cron: Cron;
|
|
225
|
+
/** The host's broadcaster (#58, #65): present when the host has an Arcade. */
|
|
226
|
+
readonly arc?: Broadcaster;
|
|
227
|
+
/** The libp2p host (#51): one node per instance whose genesis declares libp2p. */
|
|
228
|
+
readonly p2p?: P2PHost;
|
|
229
|
+
/** shruggr/skein#150: overlay sync over the libp2p node (sync.ts). */
|
|
230
|
+
readonly sync?: OverlaySync;
|
|
231
|
+
/** The host's providers (#70): what carries the instances' messages out. */
|
|
232
|
+
readonly providers: Providers;
|
|
233
|
+
/** #148: the pages' subscriptions to their apps' emitted events (GET /<app>/.events), per instance. */
|
|
234
|
+
readonly events: EventStreams;
|
|
235
|
+
/** The certifier (#100, #113): signs the BRC-169 handle certificates, for the host skein's onboarding app (the `certifier` provider). */
|
|
236
|
+
readonly certifier: ProtoWallet;
|
|
237
|
+
/** #157: the `deliver` intention's carrier (BRC-103/104, the sessions the host keeps). */
|
|
238
|
+
readonly deliverer: Deliverer;
|
|
239
|
+
readonly loaded: Map<string, Loaded>;
|
|
240
|
+
private loading;
|
|
241
|
+
/** #156: the host chain record each running instance was last sent (a `chain` event), by handle; cleared at each start. */
|
|
242
|
+
private sentChain;
|
|
243
|
+
/** Rows being created (#90): hydrated before their hostname is published (disabled until claimed). */
|
|
244
|
+
private unpublished;
|
|
245
|
+
private queues;
|
|
246
|
+
/** The libp2p nodes following their dispatch tables (#72: syncDispatch after a settle). */
|
|
247
|
+
private syncing;
|
|
248
|
+
private idleTimer?;
|
|
249
|
+
private ledgerTimer?;
|
|
250
|
+
/** The fuel of calls not yet written to the ledger: instance\0caller\0op → {calls, fuel}. */
|
|
251
|
+
private owed;
|
|
252
|
+
private stopped;
|
|
253
|
+
private closing?;
|
|
254
|
+
/** Settles when the router starts shutting down: every client still waiting on a thread is answered 503 (#66). */
|
|
255
|
+
private stopping;
|
|
256
|
+
private stopNow;
|
|
257
|
+
/** Requests being forwarded (their clients held on a thread). */
|
|
258
|
+
private inflight;
|
|
259
|
+
servers: Server[];
|
|
260
|
+
port: number;
|
|
261
|
+
/** The control socket (control.ts), while this router listens on one. */
|
|
262
|
+
private control?;
|
|
263
|
+
/** The default image (#89), with its chain part (#132): what createInstance boots a new skein from. */
|
|
264
|
+
readonly image: ImageChain;
|
|
265
|
+
/** #130: each billed instance as last read (its host row's terms, the kernel's billing state), and what this host metered since its last tick. */
|
|
266
|
+
private views;
|
|
267
|
+
private periods;
|
|
268
|
+
/** Instances a tick is on its way to; and those sent their first (billing starts with it) since this router started: the timer sends it again. */
|
|
269
|
+
private ticking;
|
|
270
|
+
private firstTicks;
|
|
271
|
+
private tickTimer?;
|
|
272
|
+
/** The host's provider keys (its billing key among them, #130). */
|
|
273
|
+
private readonly providerKey;
|
|
274
|
+
/** The one-process kernels this router holds (#158), by database directory. */
|
|
275
|
+
private kernelHosts;
|
|
276
|
+
private wasmHosts;
|
|
277
|
+
/** The wasm kernel's host over the SQLite database at `db` (the settled split): its machines, its host chain. */
|
|
278
|
+
private wasmHost;
|
|
279
|
+
/** The `skein-kernel host` process for the RocksDB database at `dir` (#158), started on first use. */
|
|
280
|
+
private kernelHost;
|
|
281
|
+
constructor(o: RouterOptions);
|
|
282
|
+
private say;
|
|
283
|
+
private now;
|
|
284
|
+
/** The router's clock, as entries are stamped. */
|
|
285
|
+
nowStamp(): Stamp;
|
|
286
|
+
/** This host's own origin. */
|
|
287
|
+
origin(): string;
|
|
288
|
+
/**
|
|
289
|
+
* The first label of the router's own origin, when its host name is a
|
|
290
|
+
* name (`id` for id.skein.nexus), else undefined: no instance may take it,
|
|
291
|
+
* so a request to the router's origin never reaches an instance (H3).
|
|
292
|
+
*/
|
|
293
|
+
ownLabel(): string | undefined;
|
|
294
|
+
/** Whether `handle` is reserved on this host: `id`, `host` (RESERVED_HANDLES), or the router origin's own first label. */
|
|
295
|
+
reserved(handle: string): boolean;
|
|
296
|
+
/**
|
|
297
|
+
* The router's own label as an instance (2026-10-28, one public name): allowed only when the operator names
|
|
298
|
+
* that handle in SKEIN_MANAGER_FOR (managerFor) — the Open Exchange's config instance at the host's own
|
|
299
|
+
* origin. Its hostname then serves the instance; the router keeps /.well-known/skein-host, /skeins and
|
|
300
|
+
* /arc/callback there. Any other row named like the router's origin still never takes its requests.
|
|
301
|
+
*/
|
|
302
|
+
ownLabelInstance(handle: string): boolean;
|
|
303
|
+
/** This host's BRC-169 domain: its origin's host name (hostDomain). */
|
|
304
|
+
domain(): string;
|
|
305
|
+
/** An instance's origin: where its front door is, what BRC-169 publishes as its messagebox. */
|
|
306
|
+
originOf(handle: string): string;
|
|
307
|
+
/** Hydrate every enabled row once (recovery at hydrate time: what a waiting thread awaits is handed to the providers again), then let them idle out. */
|
|
308
|
+
start(): Promise<void>;
|
|
309
|
+
/**
|
|
310
|
+
* Stop everything this router started (#61), once: the providers' (the
|
|
311
|
+
* waker's, the cron provider's), the idle reaper's and the ledger's timers
|
|
312
|
+
* (the owed fuel written first), its
|
|
313
|
+
* servers and their connections, the control socket (its file removed), the header feeds' and the broadcaster's
|
|
314
|
+
* SSE clients, the libp2p nodes, and every kernel process it spawned — one
|
|
315
|
+
* still hydrating included. Afterwards nothing of it keeps the process
|
|
316
|
+
* alive: `skein-host run`'s shutdown and every one-shot command that builds
|
|
317
|
+
* a router (`add --boot/--packet`) end with it.
|
|
318
|
+
*/
|
|
319
|
+
close(): Promise<void>;
|
|
320
|
+
/** The same as `close()`. */
|
|
321
|
+
stop(): Promise<void>;
|
|
322
|
+
/**
|
|
323
|
+
* Listen on the control socket at `path` ($SKEIN_HOME/host.sock for
|
|
324
|
+
* `skein-host run`; mode 0600, no HTTP route): `skein-host event` sends its
|
|
325
|
+
* event here while this router runs, and it reaches the instance as a tick
|
|
326
|
+
* due now (cronEvent). Removed by `close()`.
|
|
327
|
+
*/
|
|
328
|
+
listenControl(path: string): Promise<void>;
|
|
329
|
+
private shutdown;
|
|
330
|
+
/**
|
|
331
|
+
* `skein-host event` (#69): a message from the cron provider into `box`, as
|
|
332
|
+
* a tick due now would be — {...event, kind: event.kind ?? "cron", due:
|
|
333
|
+
* now}, signed by the provider and appended as a `local` request; the
|
|
334
|
+
* instance takes it by its subscription to the box (from the cron provider,
|
|
335
|
+
* or from anyone). The entry's CID.
|
|
336
|
+
*/
|
|
337
|
+
cronEvent(handle: string, box: string, event: Record<string, unknown>): Promise<CID>;
|
|
338
|
+
/**
|
|
339
|
+
* A plain entry (#29, #65): a self-validating event from the host's wiring
|
|
340
|
+
* (a header feed, the broadcaster's proof), admitted into the instance in
|
|
341
|
+
* `box` with its record beside the entry (#164: the kernel puts it — after
|
|
342
|
+
* the door, when `box`'s event route names kernel.beef: its BEEFs decoded
|
|
343
|
+
* and checked, the bytes never stored; a BUMP that does not check, or no
|
|
344
|
+
* BEEF, is turned away: DoorAnswered, thrown, nothing written). The kernel
|
|
345
|
+
* routes it by its `subject` to the thread awaiting that record, else to
|
|
346
|
+
* `box`'s event route.
|
|
347
|
+
*/
|
|
348
|
+
admitEvent(handle: string, box: string, event: Record<string, unknown>): Promise<CID>;
|
|
349
|
+
/**
|
|
350
|
+
* #157: a `deliver` intention from `handle`, carried (deliver.ts: BRC-103/104 with the instance's
|
|
351
|
+
* key) and its answer admitted in box `deliver` — it stands on its own at the door (the server's
|
|
352
|
+
* signature). No answer: nothing admitted, the thread rests (offered again at its next start).
|
|
353
|
+
*/
|
|
354
|
+
deliver(handle: string, id: CID, rec: Record<string, unknown>): Promise<boolean>;
|
|
355
|
+
/**
|
|
356
|
+
* A message for an instance (#70): a provider's signed answer, a forwarded
|
|
357
|
+
* claim, or the loopback's own emit, appended as received — a `local`
|
|
358
|
+
* request entry, {kind: "message", message, body}; the front door checks it
|
|
359
|
+
* (the signature, or for the loopback the record in the store) and routes
|
|
360
|
+
* it. Nobody waits on it.
|
|
361
|
+
*/
|
|
362
|
+
appendLocal(handle: string, pkg: Record<string, unknown>): Promise<CID>;
|
|
363
|
+
/**
|
|
364
|
+
* #142: a message signed outside the host (the client `skein`, with the operator's key), delivered on
|
|
365
|
+
* the host machine over the control socket: its mail record (dag-cbor) and body, appended as a `local`
|
|
366
|
+
* request (appendLocal — the path a forwarded claim takes). The front door checks the signature and
|
|
367
|
+
* admits it by the dispatch table as it would any signed message; this waits for its verdict and
|
|
368
|
+
* throws on a refusal. The host signs nothing. The entry.
|
|
369
|
+
*/
|
|
370
|
+
messageLocal(handle: string, messageBytes: Uint8Array, body: Uint8Array): Promise<CID>;
|
|
371
|
+
/** Sign `data` with `handle`'s signer: [2, "metanet handles envelope"] / `send` / anyone — an intention request's signature (providers.ts), a beacon's beat (p2p.ts beaconFrame). */
|
|
372
|
+
private signAs;
|
|
373
|
+
/**
|
|
374
|
+
* An inbound libp2p message or stream frame (#51, #68): appended as
|
|
375
|
+
* received (the message with its signature; the frame), and the verdict
|
|
376
|
+
* — or the frame's answer — read off the thread the front door is stepped
|
|
377
|
+
* on, once it comes to rest (#66). The front door verifies, routes, and
|
|
378
|
+
* admits what an accept carries (the message's `p2p` event first); a
|
|
379
|
+
* redelivered message it accepted before is `ignore`. Its thread failing,
|
|
380
|
+
* or not answering within the wait, is `ignore` (no penalty). A frame a
|
|
381
|
+
* route's filter answers at the door (a read, #143: nothing written) is
|
|
382
|
+
* answered with the filter's body (#154: the overlay's sync protocol).
|
|
383
|
+
*/
|
|
384
|
+
p2pInbound(handle: string, call: InboundCall): Promise<InboundAnswer>;
|
|
385
|
+
/** Until nothing is queued and every loaded kernel has processed what it was given (tests, corpus). */
|
|
386
|
+
settled(): Promise<void>;
|
|
387
|
+
/**
|
|
388
|
+
* Run `f` after everything else queued for this instance: the host's own admissions (events from its
|
|
389
|
+
* wiring, `local` messages: the waker's, the providers', the loopback, a forwarded claim) reach the
|
|
390
|
+
* kernel in the order the host made them, each after its hydrate and `closed` check, and `settled`
|
|
391
|
+
* waits on them. Not the log's order: the kernel assigns every entry's place (#163), so HTTP and
|
|
392
|
+
* libp2p arrivals, which do not queue here, need no queue.
|
|
393
|
+
*/
|
|
394
|
+
serial<T>(handle: string, f: () => Promise<T>): Promise<T>;
|
|
395
|
+
/**
|
|
396
|
+
* The network the host chain is on: SKEIN_NETWORK (`network`), else the genesis defaults'
|
|
397
|
+
* `walletNetwork` (a test host's), else the kernel's default (main).
|
|
398
|
+
*/
|
|
399
|
+
chainNetwork(): string | undefined;
|
|
400
|
+
/** The kernels' environment: the configured one, and the host chain's network (#156). */
|
|
401
|
+
private kernelEnv;
|
|
402
|
+
/**
|
|
403
|
+
* A run of headers from a feed for `handle` (#156): into the host chain — the one kernel
|
|
404
|
+
* process's for a RocksDB set (an instance not running is not hydrated for it: it gets the
|
|
405
|
+
* chain at its next start), the instance's own serve kernel's otherwise — then, when the
|
|
406
|
+
* record changed for it, the `chain` event.
|
|
407
|
+
*/
|
|
408
|
+
chainHeaders(handle: string, box: string, raws: Uint8Array[]): Promise<void>;
|
|
409
|
+
/** The `chain` event (#156) for `handle` in `box`, unless it was sent that record already since its start. */
|
|
410
|
+
private chainEvent;
|
|
411
|
+
/**
|
|
412
|
+
* Fresh-host bootstrap (#156): the host chain empty and the instance's tree (its head `main`,
|
|
413
|
+
* an image's) carrying `chain/headers`: those imported into the host chain before the
|
|
414
|
+
* instance's first event. A tree with none, or a host chain with a tip: nothing.
|
|
415
|
+
*/
|
|
416
|
+
private chainBootstrap;
|
|
417
|
+
/** At start (and once an app takes box `chain` — an install): the host chain's current record, as the `chain` event. */
|
|
418
|
+
private chainBirth;
|
|
419
|
+
/** The instance's kernel, started (and its genesis written) if it is not loaded. */
|
|
420
|
+
hydrate(handle: string): Promise<Loaded>;
|
|
421
|
+
private load;
|
|
422
|
+
/**
|
|
423
|
+
* Whether a stopped instance's route table routes an entry in `box` — an event, or (given a
|
|
424
|
+
* sender) a message: the kernel's rule (#77, #143: dispatch.zig forMail/forEvent, by the box
|
|
425
|
+
* alone; who may run the function is the gate's, when it is routed). Read from its store file,
|
|
426
|
+
* read-only, with no kernel.
|
|
427
|
+
*/
|
|
428
|
+
subscribes(handle: string, box: string, sender?: string): Promise<boolean>;
|
|
429
|
+
/**
|
|
430
|
+
* Boot a row's empty store from a system tree or a checkpoint (issue #4,
|
|
431
|
+
* boot.ts) before its first hydration; the row's identity is its signer's.
|
|
432
|
+
*/
|
|
433
|
+
bootRow(handle: string, src: BootSource, o?: {
|
|
434
|
+
image?: boolean;
|
|
435
|
+
manager?: boolean;
|
|
436
|
+
owner?: string;
|
|
437
|
+
appConfig?: Genesis2Config["appConfig"];
|
|
438
|
+
}): Promise<Booted>;
|
|
439
|
+
/** The owner's messagebox: configured, else its mailbox instance here. */
|
|
440
|
+
ownerMessagebox(): string | undefined;
|
|
441
|
+
/**
|
|
442
|
+
* A new agent's address book seed (#70): this host's providers — the HTTP
|
|
443
|
+
* proxy, the waker, the cron provider (#69), the libp2p node (when it runs
|
|
444
|
+
* one), the status provider (#65, when it has an Arcade) — and the owner's
|
|
445
|
+
* mailbox, when it knows it.
|
|
446
|
+
*/
|
|
447
|
+
addressSeed(handle?: string): AddressSeed[];
|
|
448
|
+
/**
|
|
449
|
+
* What this host brings to an image's genesis (#89): only its own facts —
|
|
450
|
+
* the instance's identity, handle and domain, its providers in the address
|
|
451
|
+
* book, where its domain resolves, the host's defaults. No owner, no
|
|
452
|
+
* owner's mailbox, no inference peer, no names: the image is the same for
|
|
453
|
+
* everyone, and the owner is the claim's sender (#127). `manager`
|
|
454
|
+
* (#90, #113): the host skein's — the instance manager and the certifier
|
|
455
|
+
* in its address book too (no other instance's book names them).
|
|
456
|
+
*/
|
|
457
|
+
imageConfig(row: Pick<InstanceRow, "handle" | "domain">, identity: string, o?: {
|
|
458
|
+
manager?: boolean;
|
|
459
|
+
}): Genesis2Config;
|
|
460
|
+
/** #162: whether SKEIN_MANAGER_FOR names `handle` (the instance manager in its address book, its messages taken). */
|
|
461
|
+
managerFor(handle: string): boolean;
|
|
462
|
+
/**
|
|
463
|
+
* #162: the image a create names, as a boot source — the built-in `default` (this host's, with its
|
|
464
|
+
* chain part), or a directory `<imagesDir>/<name>` (SKEIN_IMAGES_DIR, default $SKEIN_HOME/images;
|
|
465
|
+
* the layout `skein-host add --image <dir>` takes: with no bin/ merged over the default image as
|
|
466
|
+
* images/host is, with bin/ a complete image). Its path resolved first (a link to an app repository's
|
|
467
|
+
* image/ reads `..` beside the repository's image, not beside the link).
|
|
468
|
+
*/
|
|
469
|
+
private namedImage;
|
|
470
|
+
/** #162: an image by name: its directory under imagesDir (resolved), or undefined. */
|
|
471
|
+
private imageDir;
|
|
472
|
+
/** Whether `owner` holds root on the instance (#143: the head `grants`): claimed by that key. */
|
|
473
|
+
private claimedBy;
|
|
474
|
+
/**
|
|
475
|
+
* A new instance from an image, owned by `owner` (#90: the instance
|
|
476
|
+
* manager's `create`; `skein-host init` for the host skein). In this order:
|
|
477
|
+
* the row, disabled (no hostname: nothing reaches it); its identity
|
|
478
|
+
* derived (the signer's, key ID = the handle) and its store booted from the
|
|
479
|
+
* image (only `default`, the default image, so far); its kernel started
|
|
480
|
+
* unpublished; `claim` (#127) — the owner's own signed claim, a message in
|
|
481
|
+
* box `claim` naming no recipient (it was signed before the instance
|
|
482
|
+
* existed), with its body — forwarded into it as a `local` request, its
|
|
483
|
+
* first entry after the genesis: the front door checks the signature, and
|
|
484
|
+
* the kernel takes the owner from the signer (the owner's admin rows
|
|
485
|
+
* written, the claim row removed); only then (`publish`, default true) the
|
|
486
|
+
* row enabled, which publishes its hostname. No request can reach the claim
|
|
487
|
+
* row first. The host signs nothing for the owner. With no `claim` (a bare
|
|
488
|
+
* image: `skein-host init`), the instance keeps its claim row, from anyone:
|
|
489
|
+
* the first sender of a claim owns it. `host`: the host skein — the
|
|
490
|
+
* instance manager and the certifier in its address book, and recorded as
|
|
491
|
+
* the host skein (host.db). `domain`: the handle's domain, recorded with
|
|
492
|
+
* the row (default `localhost`). A refusal throws (a bad or taken handle, a
|
|
493
|
+
* bad key, another image, a claim not `owner`'s or refused: the row is left
|
|
494
|
+
* disabled, its store kept for a look).
|
|
495
|
+
*
|
|
496
|
+
* `owned` (#164): a non-host image instance born owned as the host skein
|
|
497
|
+
* is — its genesis's `root` is `owner`, no claim (none taken, none made:
|
|
498
|
+
* the image's claim route is not seeded), no instance manager or
|
|
499
|
+
* certifier in its address book (those stay the host skein's and
|
|
500
|
+
* SKEIN_MANAGER_FOR's).
|
|
501
|
+
*
|
|
502
|
+
* Image `mailbox` (#113): a mailbox instance for `owner` — the front door
|
|
503
|
+
* and the messagebox, its owner in its genesis (no claim) — published at
|
|
504
|
+
* once (`publish`). The same owner and handle again: the same answer (it
|
|
505
|
+
* exists, enabled again if it was not, at `domain` if given); a key with
|
|
506
|
+
* another mailbox here is refused. One creation path: the manager's `create` (the onboarding app's
|
|
507
|
+
* registrations) and `skein-host add --mailbox` both come here.
|
|
508
|
+
*/
|
|
509
|
+
createInstance(handle: string, owner: string, o?: {
|
|
510
|
+
image?: string;
|
|
511
|
+
host?: boolean;
|
|
512
|
+
owned?: boolean;
|
|
513
|
+
publish?: boolean;
|
|
514
|
+
domain?: string;
|
|
515
|
+
claim?: SignedClaim | unknown;
|
|
516
|
+
needsClaim?: boolean;
|
|
517
|
+
appConfig?: Genesis2Config["appConfig"];
|
|
518
|
+
topics?: string[];
|
|
519
|
+
}): Promise<{
|
|
520
|
+
handle: string;
|
|
521
|
+
identity: string;
|
|
522
|
+
url: string;
|
|
523
|
+
}>;
|
|
524
|
+
/** host.db's `store` for a new instance (#96): its set in the host's LMDB environment (SKEIN_STORE), else its own file. */
|
|
525
|
+
private newStore;
|
|
526
|
+
/** createInstance's image `mailbox` (#113). */
|
|
527
|
+
private createMailbox;
|
|
528
|
+
/**
|
|
529
|
+
* The instance manager's work (#90; providers.ts `manager`): a message from
|
|
530
|
+
* the host skein in box `create`, `start` or `stop` → the answer body. A
|
|
531
|
+
* refusal throws (the provider answers {error}).
|
|
532
|
+
*/
|
|
533
|
+
private manage;
|
|
534
|
+
/**
|
|
535
|
+
* A create's `beef` (skein-amm#4): the Atomic BEEF handed into the new instance's receive row
|
|
536
|
+
* (/skein/overlay/beef/1.0.0) exactly as a catch-up's fetched BEEF is (sync.ts `deliver`), from the
|
|
537
|
+
* host's own peer, and the answer → {verdict, reason?}. No topic is named here: the instance's engine
|
|
538
|
+
* judges it under the topics its config declares. Turned away at the door (unmined, a bad BUMP): reported,
|
|
539
|
+
* not retried; the instance stays created.
|
|
540
|
+
*/
|
|
541
|
+
private deliverBeef;
|
|
542
|
+
/** What this host brings to a new instance's genesis (boot.ts): the owner and its messagebox, the inference peer, their names, the host's defaults. */
|
|
543
|
+
genesisConfig(row: Pick<InstanceRow, "handle" | "domain"> & Partial<Pick<InstanceRow, "kind" | "owner">>, identity: string, code?: boolean): Genesis2Config;
|
|
544
|
+
/**
|
|
545
|
+
* The kernel counts as busy until it has processed what was just admitted
|
|
546
|
+
* (its `idle` answers after the drain); then the libp2p node and the host's
|
|
547
|
+
* headers feed follow the dispatch table (#72, #77, #102).
|
|
548
|
+
*/
|
|
549
|
+
private settle;
|
|
550
|
+
/**
|
|
551
|
+
* What the host does by the instance's dispatch table (#72, #77, #102):
|
|
552
|
+
* read the table (the kernel's `dispatch` frame); when its chain's tip
|
|
553
|
+
* moved since it was last followed (or `first`), the host's headers feed
|
|
554
|
+
* subscribes or unsubscribes it (followHeaders), and its libp2p node is
|
|
555
|
+
* declared again as its genesis and the table ask (p2p.ts libp2pConfig) —
|
|
556
|
+
* started, reconfigured (topics subscribed and unsubscribed, protocols
|
|
557
|
+
* handled and unhandled) or stopped. A failure is logged, not fatal.
|
|
558
|
+
*/
|
|
559
|
+
private syncDispatch;
|
|
560
|
+
/** The instance's libp2p node declared as its genesis, its table and its apps' subscriptions (#119) ask. */
|
|
561
|
+
private declareP2P;
|
|
562
|
+
/** #138: the apps' liveness, folded from the instance's log (liveness.ts livenessOf), the store file read-only. */
|
|
563
|
+
private readLiveness;
|
|
564
|
+
/** #126: the apps' beacons, folded from the instance's log (p2p.ts beaconsOf), the store file read-only. */
|
|
565
|
+
private foldBeacons;
|
|
566
|
+
/**
|
|
567
|
+
* #119: the apps' subscriptions, folded from the instance's log — the
|
|
568
|
+
* libp2p node's recovery at hydrate, by reading (p2p.ts subscriptionsOf;
|
|
569
|
+
* the store file opened read-only beside the kernel, as `subscribes` reads it).
|
|
570
|
+
*/
|
|
571
|
+
private foldSubscriptions;
|
|
572
|
+
/**
|
|
573
|
+
* A `subscribe` / `unsubscribe` event from `handle` (#119, after its step's
|
|
574
|
+
* commit; the kernel checked it as it was emitted): the subscriptions
|
|
575
|
+
* change and the node is declared again — the topic subscribed, or left
|
|
576
|
+
* when no subscription, row or genesis topic takes it any more. Which app's
|
|
577
|
+
* program runs for a message on it is the kernel's (the subscription). An
|
|
578
|
+
* instance still loading reads the event from its log at hydrate; it is
|
|
579
|
+
* applied after that too (the same result).
|
|
580
|
+
*/
|
|
581
|
+
private topicEvent;
|
|
582
|
+
/**
|
|
583
|
+
* A `liveness` / `unliveness` event from `handle` (#138, after its step's commit; the kernel
|
|
584
|
+
* checked its shape as it was emitted): the liveness changes and the node's liveness tool follows
|
|
585
|
+
* it (P2PHost.liveness) — the topic subscribed without admitting its messages, or left. An instance
|
|
586
|
+
* still loading reads it from its log.
|
|
587
|
+
*/
|
|
588
|
+
private livenessEvent;
|
|
589
|
+
/**
|
|
590
|
+
* GET /<app>/.live/<topic> at an instance's origin (#138): the liveness tool's set for the app's
|
|
591
|
+
* liveness on the topic, served by the host — no program, no entry, nothing logged; metered as a
|
|
592
|
+
* read (bytes served). 404 when the app keeps no liveness for the topic (or the host has no libp2p).
|
|
593
|
+
*/
|
|
594
|
+
private liveRead;
|
|
595
|
+
/**
|
|
596
|
+
* GET /<app>/.events at an instance's origin (#148, events.ts): the app's emitted events of the
|
|
597
|
+
* asked name and topics as a Server-Sent Events stream — the backlog folded from the log, then each
|
|
598
|
+
* as it is handed over — held open until the client goes, the app is uninstalled or the instance
|
|
599
|
+
* stops. The host's own (no program, no entry, nothing logged); each message metered as a read.
|
|
600
|
+
*/
|
|
601
|
+
private eventStream;
|
|
602
|
+
/** How long a peer that beat on a topic is remembered without beating again (ms): 30 days (David to review). */
|
|
603
|
+
static readonly PEER_KEEP_MS: number;
|
|
604
|
+
/**
|
|
605
|
+
* A beat kept from `peer` on `liveTopic` at `handle` (the settled sync design): when an overlay app
|
|
606
|
+
* of the instance beats on that topic, the peer and its addresses (the node's peer store) upserted
|
|
607
|
+
* into host.db `topic_peers`, keyed by the overlay topic. What a restart asks first.
|
|
608
|
+
*/
|
|
609
|
+
private rememberPeer;
|
|
610
|
+
/**
|
|
611
|
+
* At a start (hydrate): for each overlay topic the instance beats on, the peers host.db remembers
|
|
612
|
+
* (rows older than PEER_KEEP_MS pruned first) dialled, a few at a time, failures dropped silently;
|
|
613
|
+
* each that answers asked at once — the locator and the tail (sync.ts `reconnect`) — without waiting
|
|
614
|
+
* for a beat.
|
|
615
|
+
*/
|
|
616
|
+
private askKnownPeers;
|
|
617
|
+
/**
|
|
618
|
+
* shruggr/skein#154: our own overlay's read, for the sync's puller (its locator and what it lacks) —
|
|
619
|
+
* the engine's function `fn` (`anchors`, `admitted`) by a kernel call (the `call` op; nothing
|
|
620
|
+
* appended, nothing logged), not through the app's http table, which an app need not publish. The
|
|
621
|
+
* program is the app record's engine (its role `overlay`); the argument is what a read route's
|
|
622
|
+
* filter is handed (docs/APPS.md "Filters": the route handler contract's fields), `match` naming the
|
|
623
|
+
* app, so the engine reads its configuration from the app record as it does for its read routes.
|
|
624
|
+
* Its answer is the read route's `{status, type, body}`: the body's JSON, or a throw on another status.
|
|
625
|
+
*/
|
|
626
|
+
private overlayRead;
|
|
627
|
+
/**
|
|
628
|
+
* A `beacon` / `unbeacon` event from `handle` (#126, after its step's commit;
|
|
629
|
+
* the kernel checked its shape as it was emitted): the beacons change and
|
|
630
|
+
* the node beats them (P2PHost.beacons) — started if a beacon needs it; the
|
|
631
|
+
* topic is not subscribed. An instance still loading reads it from its log.
|
|
632
|
+
*/
|
|
633
|
+
private beaconEvent;
|
|
634
|
+
/**
|
|
635
|
+
* The host's headers feed (#102) for an instance whose dispatch table is
|
|
636
|
+
* `rows`: subscribed (box `chain`) while it is enabled and a row takes
|
|
637
|
+
* events in box `chain` by name (the chain app's `event` row; dispatch.zig
|
|
638
|
+
* forEvent) — a catch-all `*` row (a mailbox instance's) is not one —
|
|
639
|
+
* else not. One line when that changes.
|
|
640
|
+
*/
|
|
641
|
+
private followHeaders;
|
|
642
|
+
/** Follow the host's headers feed for an instance whose status changed (#102): its table read again. */
|
|
643
|
+
private refollowHeaders;
|
|
644
|
+
/**
|
|
645
|
+
* The waker answers every wake-me due by this router's clock, and the cron
|
|
646
|
+
* provider sends every tick due (#69) — what their timers do in real time,
|
|
647
|
+
* for a clock that is not (a script clock: tests, the corpus).
|
|
648
|
+
*/
|
|
649
|
+
wake(): Promise<void>;
|
|
650
|
+
/** An instance's next wake (ms), if any (the host page): the waker's earliest, or its next tick (#69). */
|
|
651
|
+
nextWake(handle: string): number | undefined;
|
|
652
|
+
/** Stop kernels idle for `ms` with nothing queued. Their deadlines and sleeps stay with the waker, their schedules with the cron provider. */
|
|
653
|
+
private reap;
|
|
654
|
+
private charge;
|
|
655
|
+
/** Write what calls cost since the last flush (host.db, never the log). */
|
|
656
|
+
flushLedger(): void;
|
|
657
|
+
/** Why this host forwards nothing to `handle` (undefined: it forwards as usual). */
|
|
658
|
+
closed(handle: string): string | undefined;
|
|
659
|
+
/** A billed instance as this host last read it (#130). */
|
|
660
|
+
billingView(handle: string): BillingView | undefined;
|
|
661
|
+
/** A line of this host's log for `handle`'s period (#130): a request it served, a read call it made. */
|
|
662
|
+
private meter;
|
|
663
|
+
/**
|
|
664
|
+
* Read the instance's billing (#130): its host row's terms (the dispatch table) and its kernel's
|
|
665
|
+
* billing state (the head `billing`), checked against what this host supports. A skein with a host
|
|
666
|
+
* row this host has not ticked yet is ticked now; one whose unreported amounts would take its tally
|
|
667
|
+
* to its allocation, early. When it went asleep (and woke) goes to host.db (the grace).
|
|
668
|
+
*/
|
|
669
|
+
private syncBilling;
|
|
670
|
+
/** Tick every billed instance this router holds (the timer, every tickMs). */
|
|
671
|
+
private tickAll;
|
|
672
|
+
/**
|
|
673
|
+
* The host's tick to `handle` (#130 decided 4): signed by its billing key, in the host row's box —
|
|
674
|
+
* {kind: "tick", at, allowance, fuel, served, log} — the period since its last tick closed, its log
|
|
675
|
+
* record kept (host.db billing_ticks: `log` is that record's CID). Not to an instance the gate
|
|
676
|
+
* holds (asleep, other terms), nor twice at once. The tick's entry, or undefined.
|
|
677
|
+
*/
|
|
678
|
+
billingTick(handle: string): Promise<CID | undefined>;
|
|
679
|
+
/**
|
|
680
|
+
* A `payment` event from `handle` (#130 decided 6: its pay step's, the kernel lets no other step
|
|
681
|
+
* emit one): this host is the payee. Its wiring: the payment kept (host.db billing_payments, with
|
|
682
|
+
* whether its output pays the key the BRC-29 remittance derives from this host's billing key) and
|
|
683
|
+
* broadcast (its Arcade, once).
|
|
684
|
+
*/
|
|
685
|
+
private payment;
|
|
686
|
+
/**
|
|
687
|
+
* Reclaim an instance (#130 decided 9; `skein-host reclaim`): its kernel stopped, its row and its
|
|
688
|
+
* billing removed, its store deleted. The host's call to make, after the grace; nothing here makes
|
|
689
|
+
* it on its own. Not the host skein.
|
|
690
|
+
*/
|
|
691
|
+
reclaim(handle: string): Promise<void>;
|
|
692
|
+
/** Whether a URL is this host's own (answered in process: no DNS, no socket). */
|
|
693
|
+
isLocal(url: string): boolean;
|
|
694
|
+
/** Which instance a URL is for: `/@<handle>` (stripped for the routes), or a `<handle>.` host name. */
|
|
695
|
+
target(url: URL): {
|
|
696
|
+
handle: string;
|
|
697
|
+
route: string;
|
|
698
|
+
} | undefined;
|
|
699
|
+
/**
|
|
700
|
+
* The HTTP proxy's request (#70, the `fetch` provider): this host's own URLs in
|
|
701
|
+
* process, the rest as configured. A delivery (`POST …/sendMessage`, from
|
|
702
|
+
* instance `from`) is logged in one line: where it went, how, and the result.
|
|
703
|
+
*/
|
|
704
|
+
http(req: HttpRequest, from?: string): Promise<HttpResponse>;
|
|
705
|
+
/** One request, whoever made it: a socket's, or an instance's own http. */
|
|
706
|
+
dispatch(req: RouterRequest): Promise<RouterResponse>;
|
|
707
|
+
/**
|
|
708
|
+
* #161, #137: an overlay request at the bare host — POST /submit (the topics its X-Topics names: a
|
|
709
|
+
* comma list or a JSON array, as the overlay reads it) or POST /lookup (its JSON body's `service`,
|
|
710
|
+
* and a `topic` beside it or in its query) — routed to the instance that serves the names:
|
|
711
|
+
*
|
|
712
|
+
* - a token's name, `tm_color_<id>` / `ls_color_<id>` whose `<id>` is an enabled path-only
|
|
713
|
+
* instance here: that instance (#161, the handle naming convention; checked first);
|
|
714
|
+
* - any other name (`tm_color`, `ls_color`, …): the enabled instance whose `topics` (the
|
|
715
|
+
* names the instance manager's create or start named, host.db) contain it. Whether the instance
|
|
716
|
+
* has run yet does not matter. Two instances taking the same name: a problem (400, "N instances
|
|
717
|
+
* here take <name>").
|
|
718
|
+
*
|
|
719
|
+
* Every name that maps must map to the same instance (else a problem: 400); a name mapping to no
|
|
720
|
+
* instance here beside one that does is a problem too. Nothing maps: no handle (the hostname's
|
|
721
|
+
* instance, or the bare host, as before).
|
|
722
|
+
*/
|
|
723
|
+
overlayTarget(path: "/submit" | "/lookup", req: RouterRequest): {
|
|
724
|
+
handle?: string;
|
|
725
|
+
} | {
|
|
726
|
+
problem: string;
|
|
727
|
+
};
|
|
728
|
+
/**
|
|
729
|
+
* GET /skeins?key=<hex> at the host's own origin: the skeins on this host whose head `grants`
|
|
730
|
+
* (#143) names `key` among root's holders — each enabled agent row's store file read read-only,
|
|
731
|
+
* no kernel — as JSON [{handle, identity, url}]. A key's skeins are the host's to say (no token
|
|
732
|
+
* in a wallet tracks them). Unsigned, anyone; mailbox instances are not listed.
|
|
733
|
+
*/
|
|
734
|
+
private skeinsHeldBy;
|
|
735
|
+
/**
|
|
736
|
+
* GET /.well-known/skein at an instance's origin (its hostname, `/@<handle>/`, or the root instance's
|
|
737
|
+
* hostname): `{handle, identity, origin, claimed}` — `claimed` whether its head `grants` names a root
|
|
738
|
+
* holder (an image instance nobody has claimed: false). Read from its store read-only, no kernel, as
|
|
739
|
+
* /skeins does. Unsigned, anyone; 404 for no instance. "Am I root" is /skeins?key=<identity>.
|
|
740
|
+
*/
|
|
741
|
+
private instanceCard;
|
|
742
|
+
/** The keys an instance's head `grants` names root (#143), its store read read-only; none when it has no store yet. */
|
|
743
|
+
private rootsOf;
|
|
744
|
+
/** A forwarded request, held among the in-flight ones (shutdown answers them 503). */
|
|
745
|
+
private held;
|
|
746
|
+
/**
|
|
747
|
+
* The handle domain (#113): the host skein's onboarding app's
|
|
748
|
+
* `config.onboard.domain` (the app record, a kernel read), the one setting
|
|
749
|
+
* every handle here is at. With no host skein or no app: this router's
|
|
750
|
+
* origin's host name as a domain.
|
|
751
|
+
*/
|
|
752
|
+
handleDomain(): Promise<string>;
|
|
753
|
+
/** Arcade's webhook (#58, arc.ts); 404 when the host has no Arcade. */
|
|
754
|
+
private arcRequest;
|
|
755
|
+
/**
|
|
756
|
+
* A request for an instance (#68, #66): appended as received, and the
|
|
757
|
+
* client's connection held until the thread it launched comes to rest —
|
|
758
|
+
* then its answer, signed on the session inside. Past `answerWaitMs`, or
|
|
759
|
+
* when the router shuts down, 503 + Retry-After (the thread goes on). A
|
|
760
|
+
* read's call fuel (the explorer's) is charged to the ledger.
|
|
761
|
+
*/
|
|
762
|
+
private forward;
|
|
763
|
+
/** The HTTP handler: CORS, then dispatch. */
|
|
764
|
+
handler(): (req: IncomingMessage, res: ServerResponse) => void;
|
|
765
|
+
/**
|
|
766
|
+
* Listen on `port` (0: any) at each of `hosts` (default the IPv4 and IPv6
|
|
767
|
+
* loopbacks: `<handle>.localhost` resolves to either).
|
|
768
|
+
*/
|
|
769
|
+
listen(port: number, hosts?: string | string[]): Promise<Server>;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* The owner's signed claim (#127): a message in box `claim`, signed by the
|
|
773
|
+
* owner (BRC-169's signing, counterparty anyone) and naming no recipient — it
|
|
774
|
+
* was signed before the instance it claims existed — with its body (dag-cbor
|
|
775
|
+
* bytes). The host forwards it as it is (Router.createInstance).
|
|
776
|
+
*/
|
|
777
|
+
export interface SignedClaim {
|
|
778
|
+
message: Omit<MailRecord, "recipient"> & {
|
|
779
|
+
recipient?: undefined;
|
|
780
|
+
};
|
|
781
|
+
body: Uint8Array;
|
|
782
|
+
}
|