@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,49 @@
1
+ import { PrivateKey, type WalletInterface, type WalletProtocol } from "@bsv/sdk";
2
+ export declare const INSTANCE_PROTOCOL: WalletProtocol;
3
+ export declare const PROVIDER_PROTOCOL: WalletProtocol;
4
+ /** The master secret: SKEIN_MASTER_KEY, else the file (created if absent). */
5
+ export declare function masterKey(vars: Record<string, string | undefined>, home: string): PrivateKey;
6
+ /** One-key mode (#160): the provisioned key's settings — SKEIN_KEY (hex) or SKEIN_KEY_FILE — if either is set. */
7
+ export declare function oneKeySetting(vars: Record<string, string | undefined>): boolean;
8
+ /**
9
+ * The one key (#160): SKEIN_KEY (hex), else the file SKEIN_KEY_FILE names, read and never made (the
10
+ * host is provisioned with it). Refused together with SKEIN_MASTER_KEY or SKEIN_MASTER_KEY_FILE.
11
+ */
12
+ export declare function oneKey(vars: Record<string, string | undefined>): PrivateKey;
13
+ /** The host's signer by its settings (#160): one-key mode when SKEIN_KEY / SKEIN_KEY_FILE is set, else the master key's (made if absent). */
14
+ export declare function signerOf(vars: Record<string, string | undefined>, home: string): Signer;
15
+ export declare class Signer {
16
+ private readonly deriver;
17
+ private readonly wallets;
18
+ readonly master: PrivateKey;
19
+ /** One-key mode (#160): the key every instance signs with (Signer.oneKey); undefined: the master's derivation per instance. */
20
+ readonly shared?: PrivateKey;
21
+ constructor(master: PrivateKey, shared?: boolean);
22
+ /** One-key mode (#160): every instance's key is `key` itself; providers and the certifier derive from it as from a master. */
23
+ static oneKey(key: PrivateKey): Signer;
24
+ /** An instance's root key: BRC-42 child of the master, key ID = the instance id. One-key mode: the key, for every id. */
25
+ instanceKey(id: string): PrivateKey;
26
+ /**
27
+ * An instance's libp2p peer key (#51, #129): a BRC-42 child of the
28
+ * instance's root key (instanceKey), protocol [2, "skein instance"], key ID
29
+ * `libp2p:<handle>`, counterparty self — the key whose public half the
30
+ * instance's signer answers for getPublicKey with those arguments. Not the
31
+ * root itself. Its peer ID is the identity multihash of the compressed key
32
+ * (p2p.ts peerIdOf).
33
+ */
34
+ peerKey(id: string): PrivateKey;
35
+ /** The instance's identity key (hex): what `skein-host add` records. */
36
+ identity(id: string): string;
37
+ /** The instance's signer: a ProtoWallet over its root key (a WalletInterface whose actions reject). */
38
+ wallet(id: string): WalletInterface;
39
+ /**
40
+ * A provider's key (#70: the HTTP proxy, the waker, the libp2p node, the
41
+ * broadcaster — providers.ts): a BRC-42 child of the master under
42
+ * PROVIDER_PROTOCOL, key ID = the provider's name. The same identity for
43
+ * every instance on this host; each genesis's address book names it. How a
44
+ * host obtains provider keys is its own business: this is this host's way.
45
+ */
46
+ providerKey(name: string): PrivateKey;
47
+ /** The certifier key (#100): BRC-169's trust anchor, providerKey("certifier"). */
48
+ certifierKey(): PrivateKey;
49
+ }
@@ -0,0 +1,167 @@
1
+ // The signer (#18, #29): one master secret held by the router, and
2
+ // per instance a root key derived from it with BRC-42/43 — protocol
3
+ // [2, "skein instance"], key ID = the instance id (its handle), counterparty
4
+ // self — behind a ProtoWallet: getPublicKey, createSignature, encrypt,
5
+ // decrypt, createHmac (and their verify halves), no storage, no actions. The
6
+ // instance's identity key is that child's public key; provisioning an
7
+ // instance is picking an id. The router answers the kernel's `wallet` import
8
+ // from it in process (kernel.ts); the router has no identity of its own. Its
9
+ // libp2p host (#51, #129) signs as a child of the INSTANCE's root key: [2,
10
+ // "skein instance"], key ID `libp2p:<handle>`, counterparty self (peerKey) —
11
+ // exactly what the instance's program gets when it asks its signer for that
12
+ // public key, so a program knows its own peer ID. The master is only how this
13
+ // host hands each instance its root. Its providers (#70: the HTTP proxy,
14
+ // the waker, the libp2p node, the broadcaster — providers.ts) are third
15
+ // children, one per provider for the whole host: [2, "skein provider"], key
16
+ // ID = the provider's name (providerKey). The host's BRC-169 certifier key
17
+ // (#100: the manifest's `metanet.trust.publicKey`, the signer of the handle
18
+ // certificates — handles.ts) is the same derivation, key ID `certifier`: not
19
+ // a provider — it takes no messages, and no address book names it.
20
+ //
21
+ // Custody (dev): the secret is a file, `$SKEIN_HOME/master.key` (64 hex
22
+ // digits, mode 0600), made on first use; `SKEIN_MASTER_KEY` (hex) overrides
23
+ // it, `SKEIN_MASTER_KEY_FILE` names another file. KMS/hardware later, behind
24
+ // the same calls.
25
+ //
26
+ // One-key mode (#160): a host provisioned with ONE private key —
27
+ // `SKEIN_KEY_FILE` (a file, 64 hex digits, read and never made: the host is
28
+ // provisioned) or `SKEIN_KEY` (hex); never together with the master key
29
+ // settings. Its signer (Signer.oneKey) answers for every instance with that
30
+ // key directly: instanceKey(id) is the key for every id, so every instance's
31
+ // identity is its public key and its wallet one ProtoWallet over it. The
32
+ // peer key is the key's child [2, "skein instance"], key ID `libp2p`,
33
+ // counterparty self — the same for every id — and a program's
34
+ // getPublicKey([2, "skein instance"], `libp2p:<handle>`, self) is answered
35
+ // with that child: the lookup is by handle as it is in master-key mode, the
36
+ // derivation rule ignores the handle (David, 2026-10-28: "all derive the same
37
+ // way"). The providers' keys and the certifier key are derived from the key
38
+ // as they are from the master. signerOf picks the mode.
39
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
40
+ import { dirname, join } from "node:path";
41
+ import { KeyDeriver, PrivateKey, ProtoWallet } from "@bsv/sdk";
42
+ import { ephemeralWallet, keyWallet } from "../wallet.js";
43
+ export const INSTANCE_PROTOCOL = [2, "skein instance"];
44
+ export const PROVIDER_PROTOCOL = [2, "skein provider"];
45
+ /** The master secret: SKEIN_MASTER_KEY, else the file (created if absent). */
46
+ export function masterKey(vars, home) {
47
+ if (vars.SKEIN_MASTER_KEY)
48
+ return PrivateKey.fromHex(vars.SKEIN_MASTER_KEY.trim());
49
+ const file = vars.SKEIN_MASTER_KEY_FILE || join(home, "master.key");
50
+ if (!existsSync(file)) {
51
+ mkdirSync(dirname(file), { recursive: true });
52
+ writeFileSync(file, `${PrivateKey.fromRandom().toHex().padStart(64, "0")}\n`, { mode: 0o600, flag: "wx" });
53
+ }
54
+ return PrivateKey.fromHex(readFileSync(file, "utf8").trim());
55
+ }
56
+ /** One-key mode (#160): the provisioned key's settings — SKEIN_KEY (hex) or SKEIN_KEY_FILE — if either is set. */
57
+ export function oneKeySetting(vars) {
58
+ return !!(vars.SKEIN_KEY || vars.SKEIN_KEY_FILE);
59
+ }
60
+ /**
61
+ * The one key (#160): SKEIN_KEY (hex), else the file SKEIN_KEY_FILE names, read and never made (the
62
+ * host is provisioned with it). Refused together with SKEIN_MASTER_KEY or SKEIN_MASTER_KEY_FILE.
63
+ */
64
+ export function oneKey(vars) {
65
+ if (vars.SKEIN_MASTER_KEY || vars.SKEIN_MASTER_KEY_FILE)
66
+ throw new Error("SKEIN_KEY / SKEIN_KEY_FILE (one key for every instance) and SKEIN_MASTER_KEY / SKEIN_MASTER_KEY_FILE (a key derived per instance) are two modes: set one");
67
+ if (vars.SKEIN_KEY && vars.SKEIN_KEY_FILE)
68
+ throw new Error("SKEIN_KEY and SKEIN_KEY_FILE: set one");
69
+ if (vars.SKEIN_KEY)
70
+ return PrivateKey.fromHex(vars.SKEIN_KEY.trim());
71
+ const file = vars.SKEIN_KEY_FILE;
72
+ if (!existsSync(file))
73
+ throw new Error(`SKEIN_KEY_FILE ${file}: no such file (a one-key host is provisioned with its key: it is never made here)`);
74
+ return PrivateKey.fromHex(readFileSync(file, "utf8").trim());
75
+ }
76
+ /** The host's signer by its settings (#160): one-key mode when SKEIN_KEY / SKEIN_KEY_FILE is set, else the master key's (made if absent). */
77
+ export function signerOf(vars, home) {
78
+ return oneKeySetting(vars) ? Signer.oneKey(oneKey(vars)) : new Signer(masterKey(vars, home));
79
+ }
80
+ /** Whether a getPublicKey asks for an instance's peer key by handle: [2, "skein instance"], key ID `libp2p:<handle>`, counterparty self. */
81
+ function peerLookup(args) {
82
+ if (args.identityKey || !args.protocolID || typeof args.keyID !== "string" || !args.keyID.startsWith("libp2p:"))
83
+ return false;
84
+ const [level, name] = args.protocolID;
85
+ return level === INSTANCE_PROTOCOL[0] && typeof name === "string" && name.trim().toLowerCase() === INSTANCE_PROTOCOL[1] && (args.counterparty === undefined || args.counterparty === "self");
86
+ }
87
+ /**
88
+ * The one-key host's signer wallet (#160): a ProtoWallet over the key whose getPublicKey for an
89
+ * instance's peer key by handle ([2, "skein instance"], `libp2p:<handle>`, self) answers the one peer
90
+ * key (Signer.peerKey: key ID `libp2p`), whatever the handle. Everything else is the ProtoWallet's.
91
+ */
92
+ class OneKeyWallet extends ProtoWallet {
93
+ peer;
94
+ constructor(key, peer) {
95
+ super(key);
96
+ this.peer = peer.toPublicKey().toString();
97
+ }
98
+ async getPublicKey(args) {
99
+ if (peerLookup(args))
100
+ return { publicKey: this.peer };
101
+ return await super.getPublicKey(args);
102
+ }
103
+ }
104
+ export class Signer {
105
+ deriver;
106
+ wallets = new Map();
107
+ master;
108
+ /** One-key mode (#160): the key every instance signs with (Signer.oneKey); undefined: the master's derivation per instance. */
109
+ shared;
110
+ constructor(master, shared = false) {
111
+ this.master = master;
112
+ this.deriver = new KeyDeriver(master);
113
+ if (shared)
114
+ this.shared = master;
115
+ }
116
+ /** One-key mode (#160): every instance's key is `key` itself; providers and the certifier derive from it as from a master. */
117
+ static oneKey(key) {
118
+ return new Signer(key, true);
119
+ }
120
+ /** An instance's root key: BRC-42 child of the master, key ID = the instance id. One-key mode: the key, for every id. */
121
+ instanceKey(id) {
122
+ if (this.shared)
123
+ return this.shared;
124
+ return this.deriver.derivePrivateKey(INSTANCE_PROTOCOL, id, "self");
125
+ }
126
+ /**
127
+ * An instance's libp2p peer key (#51, #129): a BRC-42 child of the
128
+ * instance's root key (instanceKey), protocol [2, "skein instance"], key ID
129
+ * `libp2p:<handle>`, counterparty self — the key whose public half the
130
+ * instance's signer answers for getPublicKey with those arguments. Not the
131
+ * root itself. Its peer ID is the identity multihash of the compressed key
132
+ * (p2p.ts peerIdOf).
133
+ */
134
+ peerKey(id) {
135
+ // #160: one-key mode — the key's child, key ID `libp2p`, the same for every id (the handle is ignored).
136
+ if (this.shared)
137
+ return this.deriver.derivePrivateKey(INSTANCE_PROTOCOL, "libp2p", "self");
138
+ return new KeyDeriver(this.instanceKey(id)).derivePrivateKey(INSTANCE_PROTOCOL, `libp2p:${id}`, "self");
139
+ }
140
+ /** The instance's identity key (hex): what `skein-host add` records. */
141
+ identity(id) {
142
+ return this.instanceKey(id).toPublicKey().toString();
143
+ }
144
+ /** The instance's signer: a ProtoWallet over its root key (a WalletInterface whose actions reject). */
145
+ wallet(id) {
146
+ // #160: one-key mode — one wallet for every instance, its peer-key lookup answered by OneKeyWallet.
147
+ const k = this.shared ? "" : id;
148
+ let w = this.wallets.get(k);
149
+ if (!w)
150
+ this.wallets.set(k, (w = this.shared ? keyWallet(this.shared, new OneKeyWallet(this.shared, this.peerKey(id))) : ephemeralWallet(this.instanceKey(id))));
151
+ return w;
152
+ }
153
+ /**
154
+ * A provider's key (#70: the HTTP proxy, the waker, the libp2p node, the
155
+ * broadcaster — providers.ts): a BRC-42 child of the master under
156
+ * PROVIDER_PROTOCOL, key ID = the provider's name. The same identity for
157
+ * every instance on this host; each genesis's address book names it. How a
158
+ * host obtains provider keys is its own business: this is this host's way.
159
+ */
160
+ providerKey(name) {
161
+ return this.deriver.derivePrivateKey(PROVIDER_PROTOCOL, name, "self");
162
+ }
163
+ /** The certifier key (#100): BRC-169's trust anchor, providerKey("certifier"). */
164
+ certifierKey() {
165
+ return this.providerKey("certifier");
166
+ }
167
+ }
@@ -0,0 +1,39 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ /** Open (and make) the host's database: the three tables, WAL. */
3
+ export declare function openHostDb(path: string, o?: {
4
+ readOnly?: boolean;
5
+ }): DatabaseSync;
6
+ /**
7
+ * One set of the host's database as the shim's store: an instance's (with the chain exception), or
8
+ * the host chain's (`set` = host/chain). `readOnly`: a replay's source.
9
+ */
10
+ export declare class SqliteSetStore {
11
+ readonly db: DatabaseSync;
12
+ readonly set: string;
13
+ readonly readOnly: boolean;
14
+ private tx;
15
+ private q;
16
+ constructor(db: DatabaseSync, set: string, o?: {
17
+ readOnly?: boolean;
18
+ });
19
+ private args;
20
+ getBlock(cid: Uint8Array): Uint8Array | undefined;
21
+ hasBlock(cid: Uint8Array): boolean;
22
+ putBlock(cid: Uint8Array, bytes: Uint8Array): boolean;
23
+ getPointer(name: string): Uint8Array | undefined;
24
+ setPointer(name: string, cid: Uint8Array): boolean;
25
+ begin(): void;
26
+ commit(): boolean;
27
+ rollback(): void;
28
+ /** Every block the set holds (a replay's source: the raw modules first; a checkpoint's extras). */
29
+ entries(): Generator<[Uint8Array, Uint8Array]>;
30
+ }
31
+ /** Whether the set has committed a state (its index's `state` pointer). */
32
+ export declare function setHasState(db: DatabaseSync, set: string): boolean;
33
+ /**
34
+ * A set as a native kernel's store file (kernel-zig/src/sqlite_store.zig: `blocks(cid, bytes)`,
35
+ * `pointers(name, cid)`): the set's blocks and those of `host/chain` (what it reads through the
36
+ * chain exception), its pointers — what `skein-kernel replay` takes (the two kernels agree:
37
+ * requirement 1's proof). `out` must not exist.
38
+ */
39
+ export declare function exportSet(dbPath: string, set: string, out: string): void;
@@ -0,0 +1,170 @@
1
+ // The host's store (the settled split, 2026-10-31): ONE SQLite database for the
2
+ // whole host (node's built-in `node:sqlite`, synchronous), every instance a
3
+ // SET of it — the store interface of the wasm kernel's shim (kernel-zig/web/
4
+ // kernel.js MemoryStore: getBlock/hasBlock/putBlock/getPointer/setPointer/
5
+ // begin/commit/rollback), so the machine asks for a record by CID, writes
6
+ // under its heads, and never knows where it lives (requirement 5).
7
+ //
8
+ // blocks(cid BLOB PRIMARY KEY, bytes BLOB) each block once for the host
9
+ // members(set TEXT, cid BLOB, PRIMARY KEY(set, cid)) what each set holds
10
+ // pointers(set TEXT, name TEXT, cid BLOB, PRIMARY KEY(set, name))
11
+ //
12
+ // An instance's view: a read answers when the CID is in its own set OR in the
13
+ // `host/chain` set (the chain exception, decided 2026-10-27: the host's header
14
+ // chain is the one shared read); a write goes to its own set. The `host/chain`
15
+ // set is written only by the host's chain holder (a view with no chain
16
+ // exception of its own). A batch (begin … commit) is one SQLite transaction at
17
+ // commit: reads see the batch, rollback drops it. Every worker opens its own
18
+ // connection (WAL; a writer waits on SQLite's lock, `busy_timeout`, for
19
+ // another worker's commit).
20
+ //
21
+ // host.db's `store` for such an instance: `sqlite:<db path>` (the set: its
22
+ // handle); its spec `sqlite:<db path>#<set>` (index-store.ts).
23
+ import { mkdirSync } from "node:fs";
24
+ import { dirname } from "node:path";
25
+ import { DatabaseSync } from "node:sqlite";
26
+ import { CHAIN_SET } from "../runtime/index-store.js";
27
+ const key = (b) => Buffer.from(b.buffer, b.byteOffset, b.byteLength).toString("latin1");
28
+ /** Open (and make) the host's database: the three tables, WAL. */
29
+ export function openHostDb(path, o = {}) {
30
+ if (!o.readOnly)
31
+ mkdirSync(dirname(path), { recursive: true });
32
+ const db = new DatabaseSync(path, o.readOnly ? { readOnly: true } : {});
33
+ db.exec("PRAGMA busy_timeout = 60000");
34
+ if (!o.readOnly) {
35
+ db.exec("PRAGMA journal_mode = WAL");
36
+ db.exec("PRAGMA synchronous = NORMAL");
37
+ db.exec(`CREATE TABLE IF NOT EXISTS blocks (cid BLOB PRIMARY KEY, bytes BLOB NOT NULL) WITHOUT ROWID;
38
+ CREATE TABLE IF NOT EXISTS members ("set" TEXT NOT NULL, cid BLOB NOT NULL, PRIMARY KEY ("set", cid)) WITHOUT ROWID;
39
+ CREATE TABLE IF NOT EXISTS pointers ("set" TEXT NOT NULL, name TEXT NOT NULL, cid BLOB NOT NULL, PRIMARY KEY ("set", name)) WITHOUT ROWID;`);
40
+ }
41
+ return db;
42
+ }
43
+ /**
44
+ * One set of the host's database as the shim's store: an instance's (with the chain exception), or
45
+ * the host chain's (`set` = host/chain). `readOnly`: a replay's source.
46
+ */
47
+ export class SqliteSetStore {
48
+ db;
49
+ set;
50
+ readOnly;
51
+ tx = null;
52
+ q;
53
+ constructor(db, set, o = {}) {
54
+ this.db = db;
55
+ this.set = set;
56
+ this.readOnly = !!o.readOnly;
57
+ const sets = set === CHAIN_SET ? 'm."set" = ?1' : '(m."set" = ?1 OR m."set" = ?2)';
58
+ this.q = {
59
+ get: db.prepare(`SELECT b.bytes FROM members m JOIN blocks b ON b.cid = m.cid WHERE m.cid = ?3 AND ${sets} LIMIT 1`),
60
+ has: db.prepare(`SELECT 1 FROM members m WHERE m.cid = ?3 AND ${sets} LIMIT 1`),
61
+ putBlock: db.prepare("INSERT OR IGNORE INTO blocks (cid, bytes) VALUES (?, ?)"),
62
+ putMember: db.prepare(`INSERT OR IGNORE INTO members ("set", cid) VALUES (?, ?)`),
63
+ ptr: db.prepare(`SELECT cid FROM pointers WHERE "set" = ? AND name = ?`),
64
+ setPtr: db.prepare(`INSERT INTO pointers ("set", name, cid) VALUES (?, ?, ?) ON CONFLICT ("set", name) DO UPDATE SET cid = excluded.cid`),
65
+ };
66
+ }
67
+ args(cid) { return [this.set, CHAIN_SET, cid]; }
68
+ getBlock(cid) {
69
+ const t = this.tx?.blocks.get(key(cid));
70
+ if (t)
71
+ return t[1];
72
+ const r = this.q.get.get(...this.args(cid));
73
+ return r ? new Uint8Array(r.bytes) : undefined;
74
+ }
75
+ hasBlock(cid) {
76
+ if (this.tx?.blocks.has(key(cid)))
77
+ return true;
78
+ return this.q.has.get(...this.args(cid)) !== undefined;
79
+ }
80
+ putBlock(cid, bytes) {
81
+ if (this.readOnly)
82
+ return false;
83
+ if (this.tx) {
84
+ this.tx.blocks.set(key(cid), [cid, bytes]);
85
+ return true;
86
+ }
87
+ this.q.putBlock.run(cid, bytes);
88
+ this.q.putMember.run(this.set, cid);
89
+ return true;
90
+ }
91
+ getPointer(name) {
92
+ if (this.tx?.pointers.has(name))
93
+ return this.tx.pointers.get(name);
94
+ const r = this.q.ptr.get(this.set, name);
95
+ return r ? new Uint8Array(r.cid) : undefined;
96
+ }
97
+ setPointer(name, cid) {
98
+ if (this.readOnly)
99
+ return false;
100
+ if (this.tx) {
101
+ this.tx.pointers.set(name, cid);
102
+ return true;
103
+ }
104
+ this.q.setPtr.run(this.set, name, cid);
105
+ return true;
106
+ }
107
+ begin() { this.tx = { blocks: new Map(), pointers: new Map() }; }
108
+ commit() {
109
+ const t = this.tx;
110
+ this.tx = null;
111
+ if (!t || (t.blocks.size === 0 && t.pointers.size === 0))
112
+ return true;
113
+ this.db.exec("BEGIN IMMEDIATE");
114
+ try {
115
+ for (const [cid, bytes] of t.blocks.values()) {
116
+ this.q.putBlock.run(cid, bytes);
117
+ this.q.putMember.run(this.set, cid);
118
+ }
119
+ for (const [name, cid] of t.pointers)
120
+ this.q.setPtr.run(this.set, name, cid);
121
+ this.db.exec("COMMIT");
122
+ }
123
+ catch (e) {
124
+ this.db.exec("ROLLBACK");
125
+ throw e;
126
+ }
127
+ return true;
128
+ }
129
+ rollback() { this.tx = null; }
130
+ /** Every block the set holds (a replay's source: the raw modules first; a checkpoint's extras). */
131
+ *entries() {
132
+ for (const r of this.db.prepare(`SELECT m.cid, b.bytes FROM members m JOIN blocks b ON b.cid = m.cid WHERE m."set" = ?`).iterate(this.set))
133
+ yield [new Uint8Array(r.cid), new Uint8Array(r.bytes)];
134
+ }
135
+ }
136
+ /** Whether the set has committed a state (its index's `state` pointer). */
137
+ export function setHasState(db, set) {
138
+ try {
139
+ return db.prepare(`SELECT 1 FROM pointers WHERE "set" = ? AND name = 'state'`).get(set) !== undefined;
140
+ }
141
+ catch {
142
+ return false;
143
+ }
144
+ }
145
+ /**
146
+ * A set as a native kernel's store file (kernel-zig/src/sqlite_store.zig: `blocks(cid, bytes)`,
147
+ * `pointers(name, cid)`): the set's blocks and those of `host/chain` (what it reads through the
148
+ * chain exception), its pointers — what `skein-kernel replay` takes (the two kernels agree:
149
+ * requirement 1's proof). `out` must not exist.
150
+ */
151
+ export function exportSet(dbPath, set, out) {
152
+ const src = new DatabaseSync(dbPath, { readOnly: true });
153
+ const dst = new DatabaseSync(out);
154
+ try {
155
+ dst.exec(`CREATE TABLE blocks (cid BLOB PRIMARY KEY, bytes BLOB NOT NULL) WITHOUT ROWID;
156
+ CREATE TABLE pointers (name TEXT PRIMARY KEY, cid BLOB NOT NULL) WITHOUT ROWID;`);
157
+ const put = dst.prepare("INSERT OR IGNORE INTO blocks (cid, bytes) VALUES (?, ?)");
158
+ dst.exec("BEGIN");
159
+ for (const r of src.prepare(`SELECT b.cid, b.bytes FROM members m JOIN blocks b ON b.cid = m.cid WHERE m."set" = ? OR m."set" = ?`).iterate(set, CHAIN_SET))
160
+ put.run(r.cid, r.bytes);
161
+ const ptr = dst.prepare("INSERT INTO pointers (name, cid) VALUES (?, ?)");
162
+ for (const r of src.prepare(`SELECT name, cid FROM pointers WHERE "set" = ?`).all(set))
163
+ ptr.run(r.name, r.cid);
164
+ dst.exec("COMMIT");
165
+ }
166
+ finally {
167
+ src.close();
168
+ dst.close();
169
+ }
170
+ }
@@ -0,0 +1,43 @@
1
+ import { type CID } from "../runtime/cid.ts";
2
+ import { type IndexStore } from "../runtime/index-store.ts";
3
+ import type { SqliteStore } from "../runtime/sqlite.ts";
4
+ /** A store, whichever backend: a file (index-store.ts openStoreFile), or an LMDB set, read only. */
5
+ export declare function openStoreFile(spec: string, o?: {
6
+ readOnly?: boolean;
7
+ }): SqliteStore;
8
+ /** Whether a store is there to read: the file; for an LMDB set, its state pointer (the kernel has committed). */
9
+ export declare function storeExists(spec: string): boolean;
10
+ /**
11
+ * A set of an LMDB environment through the index (#96), read only: the same reader as a SQLite
12
+ * file's, with the kernel's gate — a block is there if the set holds it, or the chain's set does
13
+ * (#133); one only another set holds is absent. Each state read takes a fresh snapshot.
14
+ */
15
+ export declare function openLmdbStore(dir: string, set: string): IndexStore;
16
+ /**
17
+ * A set of the host's SQLite database (the settled split), read only, through the index: the same
18
+ * reader as a file's, with the gate the wasm host's store keeps (store-sqlite.ts) — a block is there
19
+ * if the set holds it, or the `host/chain` set does. Its own read-only connection, closed with it.
20
+ */
21
+ export declare function openSqliteSetStore(path: string, set: string): IndexStore;
22
+ /** The host chain as it stands (#156): its record's CID, tip height and hash; undefined when empty. */
23
+ export type HostChain = {
24
+ root: CID;
25
+ height: number;
26
+ hash: string;
27
+ };
28
+ /**
29
+ * The host chain a store sees (#156): a RocksDB database's (the kernel process's `chain` frame over
30
+ * its host-read socket), or a SQLite file's or an LMDB set's own (a serve instance's: the pointer
31
+ * `host/chain` and the record it names, read directly).
32
+ */
33
+ export declare function readHostChain(spec: string): HostChain | undefined;
34
+ /** Every block a store holds (a SQLite file's `blocks`; an LMDB set's members), for a checkpoint's extras. */
35
+ export declare function storeBlocks(spec: string): Generator<{
36
+ cid: CID;
37
+ bytes: Uint8Array;
38
+ }>;
39
+ /**
40
+ * A set of the one-process kernel's RocksDB database (#158), read only, through the kernel: blocks by
41
+ * CID through the set's gate (what the instance holds), the state pointer read on every state read.
42
+ */
43
+ export declare function openRocksStore(dir: string, set: string): IndexStore;