@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.
Files changed (176) hide show
  1. package/README.md +525 -2
  2. package/bin/skein-host.js +22 -0
  3. package/bin/skein.js +8 -0
  4. package/dist/client/admin-cli.d.ts +10 -0
  5. package/dist/client/admin-cli.js +370 -0
  6. package/dist/client/admin.d.ts +139 -0
  7. package/dist/client/admin.js +256 -0
  8. package/dist/client/bundle.d.ts +9 -0
  9. package/dist/client/bundle.js +34 -0
  10. package/dist/client/cli.d.ts +44 -0
  11. package/dist/client/cli.js +306 -0
  12. package/dist/client/client.d.ts +161 -0
  13. package/dist/client/client.js +237 -0
  14. package/dist/client/config.d.ts +18 -0
  15. package/dist/client/config.js +31 -0
  16. package/dist/client/conversation.d.ts +62 -0
  17. package/dist/client/conversation.js +113 -0
  18. package/dist/client/raw.d.ts +94 -0
  19. package/dist/client/raw.js +154 -0
  20. package/dist/client/target.d.ts +34 -0
  21. package/dist/client/target.js +158 -0
  22. package/dist/dev/cli.d.ts +8 -0
  23. package/dist/dev/cli.js +248 -0
  24. package/dist/dev/scan.d.ts +15 -0
  25. package/dist/dev/scan.js +173 -0
  26. package/dist/envelope-cbor.d.ts +110 -0
  27. package/dist/envelope-cbor.js +160 -0
  28. package/dist/envelope.d.ts +38 -0
  29. package/dist/envelope.js +101 -0
  30. package/dist/host/arc.d.ts +131 -0
  31. package/dist/host/arc.js +425 -0
  32. package/dist/host/billing.d.ts +102 -0
  33. package/dist/host/billing.js +167 -0
  34. package/dist/host/boot.d.ts +246 -0
  35. package/dist/host/boot.js +643 -0
  36. package/dist/host/cli.d.ts +57 -0
  37. package/dist/host/cli.js +1253 -0
  38. package/dist/host/clock.d.ts +3 -0
  39. package/dist/host/clock.js +8 -0
  40. package/dist/host/control.d.ts +45 -0
  41. package/dist/host/control.js +170 -0
  42. package/dist/host/cron.d.ts +99 -0
  43. package/dist/host/cron.js +196 -0
  44. package/dist/host/deliver.d.ts +53 -0
  45. package/dist/host/deliver.js +251 -0
  46. package/dist/host/deploy.d.ts +29 -0
  47. package/dist/host/deploy.js +55 -0
  48. package/dist/host/door-answer.d.ts +24 -0
  49. package/dist/host/door-answer.js +21 -0
  50. package/dist/host/events.d.ts +89 -0
  51. package/dist/host/events.js +222 -0
  52. package/dist/host/fake-arcade.d.ts +40 -0
  53. package/dist/host/fake-arcade.js +149 -0
  54. package/dist/host/fake-discovery.d.ts +4 -0
  55. package/dist/host/fake-discovery.js +58 -0
  56. package/dist/host/feeds.d.ts +127 -0
  57. package/dist/host/feeds.js +422 -0
  58. package/dist/host/frontdoor.d.ts +92 -0
  59. package/dist/host/frontdoor.js +172 -0
  60. package/dist/host/genesis.d.ts +259 -0
  61. package/dist/host/genesis.js +353 -0
  62. package/dist/host/handles.d.ts +40 -0
  63. package/dist/host/handles.js +88 -0
  64. package/dist/host/hostenv.d.ts +30 -0
  65. package/dist/host/hostenv.js +83 -0
  66. package/dist/host/image-chain.d.ts +127 -0
  67. package/dist/host/image-chain.js +440 -0
  68. package/dist/host/install.d.ts +22 -0
  69. package/dist/host/install.js +139 -0
  70. package/dist/host/instances.d.ts +227 -0
  71. package/dist/host/instances.js +430 -0
  72. package/dist/host/kernel.d.ts +246 -0
  73. package/dist/host/kernel.js +603 -0
  74. package/dist/host/liveness.d.ts +65 -0
  75. package/dist/host/liveness.js +155 -0
  76. package/dist/host/manifest.d.ts +160 -0
  77. package/dist/host/manifest.js +597 -0
  78. package/dist/host/p2p.d.ts +337 -0
  79. package/dist/host/p2p.js +1002 -0
  80. package/dist/host/packet.d.ts +121 -0
  81. package/dist/host/packet.js +562 -0
  82. package/dist/host/plan.d.ts +154 -0
  83. package/dist/host/plan.js +418 -0
  84. package/dist/host/providers.d.ts +238 -0
  85. package/dist/host/providers.js +565 -0
  86. package/dist/host/roster.d.ts +72 -0
  87. package/dist/host/roster.js +172 -0
  88. package/dist/host/router.d.ts +782 -0
  89. package/dist/host/router.js +2411 -0
  90. package/dist/host/signer.d.ts +49 -0
  91. package/dist/host/signer.js +167 -0
  92. package/dist/host/store-sqlite.d.ts +39 -0
  93. package/dist/host/store-sqlite.js +170 -0
  94. package/dist/host/stores.d.ts +43 -0
  95. package/dist/host/stores.js +342 -0
  96. package/dist/host/sync.d.ts +121 -0
  97. package/dist/host/sync.js +467 -0
  98. package/dist/host/testbeef.d.ts +21 -0
  99. package/dist/host/testbeef.js +37 -0
  100. package/dist/host/testhost.d.ts +149 -0
  101. package/dist/host/testhost.js +211 -0
  102. package/dist/host/vcdiff.d.ts +9 -0
  103. package/dist/host/vcdiff.js +210 -0
  104. package/dist/host/wasm-kernel.d.ts +87 -0
  105. package/dist/host/wasm-kernel.js +296 -0
  106. package/dist/host/wasm-worker.d.ts +1 -0
  107. package/dist/host/wasm-worker.js +186 -0
  108. package/dist/peers/cron.d.ts +33 -0
  109. package/dist/peers/cron.js +75 -0
  110. package/dist/peers/infer-main.d.ts +2 -0
  111. package/dist/peers/infer-main.js +74 -0
  112. package/dist/peers/infer.d.ts +163 -0
  113. package/dist/peers/infer.js +367 -0
  114. package/dist/runtime/beef.d.ts +28 -0
  115. package/dist/runtime/beef.js +107 -0
  116. package/dist/runtime/bitcoin.d.ts +36 -0
  117. package/dist/runtime/bitcoin.js +141 -0
  118. package/dist/runtime/cid.d.ts +14 -0
  119. package/dist/runtime/cid.js +51 -0
  120. package/dist/runtime/dispatch.d.ts +92 -0
  121. package/dist/runtime/dispatch.js +142 -0
  122. package/dist/runtime/envelope.d.ts +60 -0
  123. package/dist/runtime/envelope.js +101 -0
  124. package/dist/runtime/heads.d.ts +25 -0
  125. package/dist/runtime/heads.js +37 -0
  126. package/dist/runtime/identity.d.ts +28 -0
  127. package/dist/runtime/identity.js +67 -0
  128. package/dist/runtime/index-store.d.ts +152 -0
  129. package/dist/runtime/index-store.js +715 -0
  130. package/dist/runtime/log.d.ts +62 -0
  131. package/dist/runtime/log.js +104 -0
  132. package/dist/runtime/programs.d.ts +30 -0
  133. package/dist/runtime/programs.js +61 -0
  134. package/dist/runtime/records.d.ts +135 -0
  135. package/dist/runtime/records.js +149 -0
  136. package/dist/runtime/sqlite.d.ts +33 -0
  137. package/dist/runtime/sqlite.js +604 -0
  138. package/dist/runtime/store.d.ts +141 -0
  139. package/dist/runtime/store.js +24 -0
  140. package/dist/runtime/syscalls.d.ts +9 -0
  141. package/dist/runtime/syscalls.js +41 -0
  142. package/dist/runtime/tree.d.ts +60 -0
  143. package/dist/runtime/tree.js +196 -0
  144. package/dist/runtime/types.d.ts +100 -0
  145. package/dist/runtime/types.js +7 -0
  146. package/dist/testapps.d.ts +101 -0
  147. package/dist/testapps.js +275 -0
  148. package/dist/testkit.d.ts +25 -0
  149. package/dist/testkit.js +48 -0
  150. package/dist/wallet.d.ts +35 -0
  151. package/dist/wallet.js +87 -0
  152. package/images/README.md +68 -0
  153. package/images/default/README.md +38 -0
  154. package/images/default/bin/frontdoor.cid +1 -0
  155. package/images/default/bin/frontdoor.json +5 -0
  156. package/images/default/bin/messagebox.cid +1 -0
  157. package/images/default/bin/messagebox.json +8 -0
  158. package/images/default/bin/wallet.cid +1 -0
  159. package/images/default/bin/wallet.json +14 -0
  160. package/images/default/etc/config.json +1 -0
  161. package/images/default/etc/dispatch.json +82 -0
  162. package/images/host/etc/apps.json +8 -0
  163. package/kernel-zig/README.md +1247 -0
  164. package/kernel-zig/web/client.js +65 -0
  165. package/kernel-zig/web/kernel.d.ts +59 -0
  166. package/kernel-zig/web/kernel.js +329 -0
  167. package/kernel-zig/web/store.js +67 -0
  168. package/kernel-zig/web/worker.js +79 -0
  169. package/kernel-zig/zig-out/web/skein-kernel.wasm +0 -0
  170. package/package.json +77 -4
  171. package/wasm/README.md +35 -0
  172. package/wasm/frontdoor.wasm +0 -0
  173. package/wasm/messagebox.wasm +0 -0
  174. package/wasm/resolve.wasm +0 -0
  175. package/wasm/wallet.wasm +0 -0
  176. 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
+ }