@cogcoin/client 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +136 -0
  3. package/dist/app-paths.d.ts +38 -0
  4. package/dist/app-paths.js +121 -0
  5. package/dist/art/banner.txt +13 -0
  6. package/dist/art/scroll.txt +13 -0
  7. package/dist/art/train-car.txt +6 -0
  8. package/dist/art/train-smoke.txt +6 -0
  9. package/dist/art/train.txt +6 -0
  10. package/dist/bitcoind/bootstrap/chainstate.d.ts +4 -0
  11. package/dist/bitcoind/bootstrap/chainstate.js +13 -0
  12. package/dist/bitcoind/bootstrap/constants.d.ts +7 -0
  13. package/dist/bitcoind/bootstrap/constants.js +12 -0
  14. package/dist/bitcoind/bootstrap/controller.d.ts +29 -0
  15. package/dist/bitcoind/bootstrap/controller.js +101 -0
  16. package/dist/bitcoind/bootstrap/download.d.ts +2 -0
  17. package/dist/bitcoind/bootstrap/download.js +196 -0
  18. package/dist/bitcoind/bootstrap/headers.d.ts +13 -0
  19. package/dist/bitcoind/bootstrap/headers.js +61 -0
  20. package/dist/bitcoind/bootstrap/paths.d.ts +4 -0
  21. package/dist/bitcoind/bootstrap/paths.js +15 -0
  22. package/dist/bitcoind/bootstrap/snapshot-file.d.ts +7 -0
  23. package/dist/bitcoind/bootstrap/snapshot-file.js +42 -0
  24. package/dist/bitcoind/bootstrap/state.d.ts +40 -0
  25. package/dist/bitcoind/bootstrap/state.js +70 -0
  26. package/dist/bitcoind/bootstrap/types.d.ts +28 -0
  27. package/dist/bitcoind/bootstrap/types.js +1 -0
  28. package/dist/bitcoind/bootstrap.d.ts +8 -0
  29. package/dist/bitcoind/bootstrap.js +7 -0
  30. package/dist/bitcoind/client/factory.d.ts +3 -0
  31. package/dist/bitcoind/client/factory.js +57 -0
  32. package/dist/bitcoind/client/follow-block-times.d.ts +8 -0
  33. package/dist/bitcoind/client/follow-block-times.js +25 -0
  34. package/dist/bitcoind/client/follow-loop.d.ts +10 -0
  35. package/dist/bitcoind/client/follow-loop.js +57 -0
  36. package/dist/bitcoind/client/internal-types.d.ts +63 -0
  37. package/dist/bitcoind/client/internal-types.js +18 -0
  38. package/dist/bitcoind/client/managed-client.d.ts +20 -0
  39. package/dist/bitcoind/client/managed-client.js +197 -0
  40. package/dist/bitcoind/client/rate-tracker.d.ts +2 -0
  41. package/dist/bitcoind/client/rate-tracker.js +24 -0
  42. package/dist/bitcoind/client/sync-engine.d.ts +3 -0
  43. package/dist/bitcoind/client/sync-engine.js +143 -0
  44. package/dist/bitcoind/client.d.ts +1 -0
  45. package/dist/bitcoind/client.js +1 -0
  46. package/dist/bitcoind/errors.d.ts +1 -0
  47. package/dist/bitcoind/errors.js +49 -0
  48. package/dist/bitcoind/index.d.ts +2 -0
  49. package/dist/bitcoind/index.js +1 -0
  50. package/dist/bitcoind/indexer-daemon-main.d.ts +1 -0
  51. package/dist/bitcoind/indexer-daemon-main.js +472 -0
  52. package/dist/bitcoind/indexer-daemon.d.ts +107 -0
  53. package/dist/bitcoind/indexer-daemon.js +391 -0
  54. package/dist/bitcoind/node.d.ts +8 -0
  55. package/dist/bitcoind/node.js +219 -0
  56. package/dist/bitcoind/normalize.d.ts +3 -0
  57. package/dist/bitcoind/normalize.js +47 -0
  58. package/dist/bitcoind/progress/assets.d.ts +10 -0
  59. package/dist/bitcoind/progress/assets.js +90 -0
  60. package/dist/bitcoind/progress/constants.d.ts +48 -0
  61. package/dist/bitcoind/progress/constants.js +53 -0
  62. package/dist/bitcoind/progress/controller.d.ts +28 -0
  63. package/dist/bitcoind/progress/controller.js +188 -0
  64. package/dist/bitcoind/progress/follow-scene.d.ts +40 -0
  65. package/dist/bitcoind/progress/follow-scene.js +367 -0
  66. package/dist/bitcoind/progress/formatting.d.ts +23 -0
  67. package/dist/bitcoind/progress/formatting.js +227 -0
  68. package/dist/bitcoind/progress/quote-scene.d.ts +4 -0
  69. package/dist/bitcoind/progress/quote-scene.js +137 -0
  70. package/dist/bitcoind/progress/train-scene.d.ts +9 -0
  71. package/dist/bitcoind/progress/train-scene.js +92 -0
  72. package/dist/bitcoind/progress/tty-renderer.d.ts +18 -0
  73. package/dist/bitcoind/progress/tty-renderer.js +150 -0
  74. package/dist/bitcoind/progress.d.ts +7 -0
  75. package/dist/bitcoind/progress.js +7 -0
  76. package/dist/bitcoind/quotes.d.ts +24 -0
  77. package/dist/bitcoind/quotes.js +195 -0
  78. package/dist/bitcoind/rpc.d.ts +71 -0
  79. package/dist/bitcoind/rpc.js +322 -0
  80. package/dist/bitcoind/service-paths.d.ts +19 -0
  81. package/dist/bitcoind/service-paths.js +49 -0
  82. package/dist/bitcoind/service.d.ts +40 -0
  83. package/dist/bitcoind/service.js +735 -0
  84. package/dist/bitcoind/testing.d.ts +9 -0
  85. package/dist/bitcoind/testing.js +9 -0
  86. package/dist/bitcoind/types.d.ts +396 -0
  87. package/dist/bitcoind/types.js +3 -0
  88. package/dist/bytes.d.ts +9 -0
  89. package/dist/bytes.js +36 -0
  90. package/dist/cli/commands/follow.d.ts +2 -0
  91. package/dist/cli/commands/follow.js +43 -0
  92. package/dist/cli/commands/mining-admin.d.ts +2 -0
  93. package/dist/cli/commands/mining-admin.js +92 -0
  94. package/dist/cli/commands/mining-read.d.ts +2 -0
  95. package/dist/cli/commands/mining-read.js +173 -0
  96. package/dist/cli/commands/mining-runtime.d.ts +2 -0
  97. package/dist/cli/commands/mining-runtime.js +108 -0
  98. package/dist/cli/commands/status.d.ts +2 -0
  99. package/dist/cli/commands/status.js +31 -0
  100. package/dist/cli/commands/sync.d.ts +2 -0
  101. package/dist/cli/commands/sync.js +52 -0
  102. package/dist/cli/commands/wallet-admin.d.ts +2 -0
  103. package/dist/cli/commands/wallet-admin.js +175 -0
  104. package/dist/cli/commands/wallet-mutation.d.ts +2 -0
  105. package/dist/cli/commands/wallet-mutation.js +681 -0
  106. package/dist/cli/commands/wallet-read.d.ts +2 -0
  107. package/dist/cli/commands/wallet-read.js +265 -0
  108. package/dist/cli/context.d.ts +3 -0
  109. package/dist/cli/context.js +75 -0
  110. package/dist/cli/io.d.ts +3 -0
  111. package/dist/cli/io.js +12 -0
  112. package/dist/cli/mining-format.d.ts +5 -0
  113. package/dist/cli/mining-format.js +156 -0
  114. package/dist/cli/mining-json.d.ts +49 -0
  115. package/dist/cli/mining-json.js +89 -0
  116. package/dist/cli/mutation-command-groups.d.ts +15 -0
  117. package/dist/cli/mutation-command-groups.js +71 -0
  118. package/dist/cli/mutation-json.d.ts +430 -0
  119. package/dist/cli/mutation-json.js +311 -0
  120. package/dist/cli/mutation-resolved-json.d.ts +124 -0
  121. package/dist/cli/mutation-resolved-json.js +129 -0
  122. package/dist/cli/mutation-success.d.ts +20 -0
  123. package/dist/cli/mutation-success.js +47 -0
  124. package/dist/cli/mutation-text-format.d.ts +22 -0
  125. package/dist/cli/mutation-text-format.js +171 -0
  126. package/dist/cli/mutation-text-write.d.ts +13 -0
  127. package/dist/cli/mutation-text-write.js +16 -0
  128. package/dist/cli/output.d.ts +185 -0
  129. package/dist/cli/output.js +1085 -0
  130. package/dist/cli/parse.d.ts +3 -0
  131. package/dist/cli/parse.js +971 -0
  132. package/dist/cli/preview-json.d.ts +416 -0
  133. package/dist/cli/preview-json.js +293 -0
  134. package/dist/cli/prompt.d.ts +3 -0
  135. package/dist/cli/prompt.js +33 -0
  136. package/dist/cli/read-json.d.ts +187 -0
  137. package/dist/cli/read-json.js +675 -0
  138. package/dist/cli/runner.d.ts +2 -0
  139. package/dist/cli/runner.js +129 -0
  140. package/dist/cli/signals.d.ts +3 -0
  141. package/dist/cli/signals.js +63 -0
  142. package/dist/cli/status-format.d.ts +2 -0
  143. package/dist/cli/status-format.js +48 -0
  144. package/dist/cli/types.d.ts +148 -0
  145. package/dist/cli/types.js +2 -0
  146. package/dist/cli/wallet-format.d.ts +29 -0
  147. package/dist/cli/wallet-format.js +637 -0
  148. package/dist/cli/workflow-hints.d.ts +13 -0
  149. package/dist/cli/workflow-hints.js +94 -0
  150. package/dist/cli-runner.d.ts +3 -0
  151. package/dist/cli-runner.js +3 -0
  152. package/dist/cli.d.ts +2 -0
  153. package/dist/cli.js +6 -0
  154. package/dist/client/default-client.d.ts +11 -0
  155. package/dist/client/default-client.js +118 -0
  156. package/dist/client/factory.d.ts +2 -0
  157. package/dist/client/factory.js +15 -0
  158. package/dist/client/initialization.d.ts +6 -0
  159. package/dist/client/initialization.js +30 -0
  160. package/dist/client/persistence.d.ts +5 -0
  161. package/dist/client/persistence.js +28 -0
  162. package/dist/client/store-adapter.d.ts +3 -0
  163. package/dist/client/store-adapter.js +20 -0
  164. package/dist/client.d.ts +2 -0
  165. package/dist/client.js +2 -0
  166. package/dist/index.d.ts +2 -0
  167. package/dist/index.js +1 -0
  168. package/dist/passive-status.d.ts +36 -0
  169. package/dist/passive-status.js +100 -0
  170. package/dist/sqlite/better-sqlite3.d.ts +26 -0
  171. package/dist/sqlite/better-sqlite3.js +4 -0
  172. package/dist/sqlite/checkpoints.d.ts +11 -0
  173. package/dist/sqlite/checkpoints.js +27 -0
  174. package/dist/sqlite/driver.d.ts +17 -0
  175. package/dist/sqlite/driver.js +98 -0
  176. package/dist/sqlite/index.d.ts +4 -0
  177. package/dist/sqlite/index.js +9 -0
  178. package/dist/sqlite/migrate.d.ts +2 -0
  179. package/dist/sqlite/migrate.js +37 -0
  180. package/dist/sqlite/store.d.ts +3 -0
  181. package/dist/sqlite/store.js +122 -0
  182. package/dist/sqlite/tip-meta.d.ts +26 -0
  183. package/dist/sqlite/tip-meta.js +97 -0
  184. package/dist/sqlite/types.d.ts +10 -0
  185. package/dist/sqlite/types.js +1 -0
  186. package/dist/types.d.ts +55 -0
  187. package/dist/types.js +1 -0
  188. package/dist/wallet/archive.d.ts +4 -0
  189. package/dist/wallet/archive.js +39 -0
  190. package/dist/wallet/cogop/constants.d.ts +32 -0
  191. package/dist/wallet/cogop/constants.js +32 -0
  192. package/dist/wallet/cogop/index.d.ts +32 -0
  193. package/dist/wallet/cogop/index.js +213 -0
  194. package/dist/wallet/cogop/numeric.d.ts +3 -0
  195. package/dist/wallet/cogop/numeric.js +24 -0
  196. package/dist/wallet/cogop/scriptpubkey.d.ts +2 -0
  197. package/dist/wallet/cogop/scriptpubkey.js +13 -0
  198. package/dist/wallet/cogop/validate-name.d.ts +2 -0
  199. package/dist/wallet/cogop/validate-name.js +18 -0
  200. package/dist/wallet/fs/atomic.d.ts +6 -0
  201. package/dist/wallet/fs/atomic.js +46 -0
  202. package/dist/wallet/fs/lock.d.ts +19 -0
  203. package/dist/wallet/fs/lock.js +61 -0
  204. package/dist/wallet/fs/status-file.d.ts +1 -0
  205. package/dist/wallet/fs/status-file.js +4 -0
  206. package/dist/wallet/lifecycle.d.ts +193 -0
  207. package/dist/wallet/lifecycle.js +1475 -0
  208. package/dist/wallet/material.d.ts +45 -0
  209. package/dist/wallet/material.js +118 -0
  210. package/dist/wallet/mining/config.d.ts +18 -0
  211. package/dist/wallet/mining/config.js +44 -0
  212. package/dist/wallet/mining/constants.d.ts +24 -0
  213. package/dist/wallet/mining/constants.js +24 -0
  214. package/dist/wallet/mining/control.d.ts +53 -0
  215. package/dist/wallet/mining/control.js +758 -0
  216. package/dist/wallet/mining/coordination.d.ts +40 -0
  217. package/dist/wallet/mining/coordination.js +121 -0
  218. package/dist/wallet/mining/hook-protocol.d.ts +47 -0
  219. package/dist/wallet/mining/hook-protocol.js +161 -0
  220. package/dist/wallet/mining/hook-runner.d.ts +1 -0
  221. package/dist/wallet/mining/hook-runner.js +52 -0
  222. package/dist/wallet/mining/hooks.d.ts +38 -0
  223. package/dist/wallet/mining/hooks.js +520 -0
  224. package/dist/wallet/mining/index.d.ts +8 -0
  225. package/dist/wallet/mining/index.js +6 -0
  226. package/dist/wallet/mining/runner.d.ts +155 -0
  227. package/dist/wallet/mining/runner.js +2574 -0
  228. package/dist/wallet/mining/runtime-artifacts.d.ts +17 -0
  229. package/dist/wallet/mining/runtime-artifacts.js +166 -0
  230. package/dist/wallet/mining/sentences.d.ts +23 -0
  231. package/dist/wallet/mining/sentences.js +281 -0
  232. package/dist/wallet/mining/state.d.ts +9 -0
  233. package/dist/wallet/mining/state.js +75 -0
  234. package/dist/wallet/mining/types.d.ts +141 -0
  235. package/dist/wallet/mining/types.js +1 -0
  236. package/dist/wallet/mining/visualizer.d.ts +19 -0
  237. package/dist/wallet/mining/visualizer.js +134 -0
  238. package/dist/wallet/mining/worker-main.d.ts +1 -0
  239. package/dist/wallet/mining/worker-main.js +17 -0
  240. package/dist/wallet/read/context.d.ts +20 -0
  241. package/dist/wallet/read/context.js +532 -0
  242. package/dist/wallet/read/filter.d.ts +9 -0
  243. package/dist/wallet/read/filter.js +42 -0
  244. package/dist/wallet/read/index.d.ts +4 -0
  245. package/dist/wallet/read/index.js +3 -0
  246. package/dist/wallet/read/project.d.ts +11 -0
  247. package/dist/wallet/read/project.js +300 -0
  248. package/dist/wallet/read/types.d.ts +144 -0
  249. package/dist/wallet/read/types.js +1 -0
  250. package/dist/wallet/runtime.d.ts +26 -0
  251. package/dist/wallet/runtime.js +28 -0
  252. package/dist/wallet/state/crypto.d.ts +31 -0
  253. package/dist/wallet/state/crypto.js +127 -0
  254. package/dist/wallet/state/provider.d.ts +37 -0
  255. package/dist/wallet/state/provider.js +312 -0
  256. package/dist/wallet/state/session.d.ts +12 -0
  257. package/dist/wallet/state/session.js +23 -0
  258. package/dist/wallet/state/storage.d.ts +19 -0
  259. package/dist/wallet/state/storage.js +55 -0
  260. package/dist/wallet/tx/anchor.d.ts +40 -0
  261. package/dist/wallet/tx/anchor.js +1210 -0
  262. package/dist/wallet/tx/cog.d.ts +92 -0
  263. package/dist/wallet/tx/cog.js +1055 -0
  264. package/dist/wallet/tx/common.d.ts +89 -0
  265. package/dist/wallet/tx/common.js +156 -0
  266. package/dist/wallet/tx/confirm.d.ts +15 -0
  267. package/dist/wallet/tx/confirm.js +24 -0
  268. package/dist/wallet/tx/domain-admin.d.ts +105 -0
  269. package/dist/wallet/tx/domain-admin.js +869 -0
  270. package/dist/wallet/tx/domain-market.d.ts +112 -0
  271. package/dist/wallet/tx/domain-market.js +1365 -0
  272. package/dist/wallet/tx/field.d.ts +101 -0
  273. package/dist/wallet/tx/field.js +1853 -0
  274. package/dist/wallet/tx/identity-selector.d.ts +12 -0
  275. package/dist/wallet/tx/identity-selector.js +52 -0
  276. package/dist/wallet/tx/index.d.ts +7 -0
  277. package/dist/wallet/tx/index.js +7 -0
  278. package/dist/wallet/tx/journal.d.ts +5 -0
  279. package/dist/wallet/tx/journal.js +31 -0
  280. package/dist/wallet/tx/register.d.ts +68 -0
  281. package/dist/wallet/tx/register.js +952 -0
  282. package/dist/wallet/tx/reputation.d.ts +72 -0
  283. package/dist/wallet/tx/reputation.js +693 -0
  284. package/dist/wallet/tx/targets.d.ts +7 -0
  285. package/dist/wallet/tx/targets.js +122 -0
  286. package/dist/wallet/types.d.ts +249 -0
  287. package/dist/wallet/types.js +1 -0
  288. package/dist/writing_quotes.json +1654 -0
  289. package/package.json +78 -0
@@ -0,0 +1,37 @@
1
+ export interface LinuxSecretToolResult {
2
+ stdout: string;
3
+ stderr: string;
4
+ exitCode: number | null;
5
+ signal: NodeJS.Signals | null;
6
+ }
7
+ export interface LinuxSecretToolInvocationOptions {
8
+ stdin?: string;
9
+ }
10
+ export type LinuxSecretToolRunner = (args: readonly string[], options?: LinuxSecretToolInvocationOptions) => Promise<LinuxSecretToolResult>;
11
+ export interface DefaultWalletSecretProviderFactoryOptions {
12
+ platform?: NodeJS.Platform;
13
+ linuxSecretToolRunner?: LinuxSecretToolRunner;
14
+ }
15
+ export interface WalletSecretReference {
16
+ kind: string;
17
+ keyId: string;
18
+ }
19
+ export interface WalletSecretProvider {
20
+ readonly kind: string;
21
+ loadSecret(keyId: string): Promise<Uint8Array>;
22
+ storeSecret(keyId: string, secret: Uint8Array): Promise<void>;
23
+ deleteSecret(keyId: string): Promise<void>;
24
+ }
25
+ export declare function createWalletSecretReference(walletRootId: string): WalletSecretReference;
26
+ export declare class MemoryWalletSecretProvider implements WalletSecretProvider {
27
+ #private;
28
+ readonly kind = "memory-test";
29
+ loadSecret(keyId: string): Promise<Uint8Array>;
30
+ storeSecret(keyId: string, secret: Uint8Array): Promise<void>;
31
+ deleteSecret(keyId: string): Promise<void>;
32
+ }
33
+ export declare function createDefaultWalletSecretProvider(): WalletSecretProvider;
34
+ export declare function createDefaultWalletSecretProviderForTesting(options?: DefaultWalletSecretProviderFactoryOptions): WalletSecretProvider;
35
+ export declare function createLazyDefaultWalletSecretProvider(): WalletSecretProvider;
36
+ export declare function createMemoryWalletSecretProviderForTesting(): WalletSecretProvider;
37
+ export declare function createWalletRootId(): string;
@@ -0,0 +1,312 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { execFile, spawn } from "node:child_process";
3
+ import { mkdir, readFile, rm } from "node:fs/promises";
4
+ import { dirname, join } from "node:path";
5
+ import { promisify } from "node:util";
6
+ import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
7
+ import { writeFileAtomic } from "../fs/atomic.js";
8
+ const execFileAsync = promisify(execFile);
9
+ const KEYCHAIN_SERVICE_NAME = "org.cogcoin.wallet";
10
+ const LINUX_SECRET_TOOL_ATTRIBUTE_APPLICATION = "application";
11
+ const LINUX_SECRET_TOOL_ATTRIBUTE_KIND = "secret-kind";
12
+ const LINUX_SECRET_TOOL_ATTRIBUTE_KEY_ID = "key-id";
13
+ const LINUX_SECRET_TOOL_SECRET_KIND = "wallet-secret";
14
+ export function createWalletSecretReference(walletRootId) {
15
+ return {
16
+ kind: "wallet-state-key",
17
+ keyId: `wallet-state:${walletRootId}`,
18
+ };
19
+ }
20
+ function bytesToBase64(secret) {
21
+ return Buffer.from(secret).toString("base64");
22
+ }
23
+ function base64ToBytes(secret) {
24
+ return new Uint8Array(Buffer.from(secret, "base64"));
25
+ }
26
+ function createLinuxSecretToolAttributes(keyId) {
27
+ return [
28
+ LINUX_SECRET_TOOL_ATTRIBUTE_APPLICATION,
29
+ KEYCHAIN_SERVICE_NAME,
30
+ LINUX_SECRET_TOOL_ATTRIBUTE_KIND,
31
+ LINUX_SECRET_TOOL_SECRET_KIND,
32
+ LINUX_SECRET_TOOL_ATTRIBUTE_KEY_ID,
33
+ keyId,
34
+ ];
35
+ }
36
+ function createLinuxSecretToolError(message, cause) {
37
+ return cause === undefined ? new Error(message) : new Error(message, { cause });
38
+ }
39
+ function isLinuxSecretServiceUnavailableMessage(stderr) {
40
+ const normalized = stderr.trim().toLowerCase();
41
+ if (normalized.length === 0) {
42
+ return false;
43
+ }
44
+ return normalized.includes("secret service")
45
+ || normalized.includes("org.freedesktop.secrets")
46
+ || normalized.includes("dbus")
47
+ || normalized.includes("d-bus")
48
+ || normalized.includes("cannot autolaunch")
49
+ || normalized.includes("no such secret collection")
50
+ || normalized.includes("collection is locked")
51
+ || normalized.includes("prompt dismissed")
52
+ || normalized.includes("not available");
53
+ }
54
+ function isLinuxSecretToolMissingSecretMessage(stderr) {
55
+ const normalized = stderr.trim().toLowerCase();
56
+ if (normalized.length === 0) {
57
+ return true;
58
+ }
59
+ return normalized.includes("no matching")
60
+ || normalized.includes("not found")
61
+ || normalized.includes("does not exist")
62
+ || normalized.includes("no such item")
63
+ || normalized.includes("no secret");
64
+ }
65
+ async function runLinuxSecretTool(args, options = {}) {
66
+ return await new Promise((resolve, reject) => {
67
+ const child = spawn("secret-tool", [...args], {
68
+ stdio: ["pipe", "pipe", "pipe"],
69
+ });
70
+ let stdout = "";
71
+ let stderr = "";
72
+ child.once("error", reject);
73
+ child.stdout.setEncoding("utf8");
74
+ child.stderr.setEncoding("utf8");
75
+ child.stdout.on("data", (chunk) => {
76
+ stdout += chunk;
77
+ });
78
+ child.stderr.on("data", (chunk) => {
79
+ stderr += chunk;
80
+ });
81
+ child.once("close", (exitCode, signal) => {
82
+ resolve({
83
+ stdout,
84
+ stderr,
85
+ exitCode,
86
+ signal,
87
+ });
88
+ });
89
+ child.stdin.on("error", (error) => {
90
+ if ("code" in error && error.code === "EPIPE") {
91
+ return;
92
+ }
93
+ reject(error);
94
+ });
95
+ child.stdin.end(options.stdin ?? undefined, "utf8");
96
+ });
97
+ }
98
+ export class MemoryWalletSecretProvider {
99
+ kind = "memory-test";
100
+ #values = new Map();
101
+ async loadSecret(keyId) {
102
+ const secret = this.#values.get(keyId);
103
+ if (secret === undefined) {
104
+ throw new Error(`wallet_secret_missing_${keyId}`);
105
+ }
106
+ return new Uint8Array(secret);
107
+ }
108
+ async storeSecret(keyId, secret) {
109
+ this.#values.set(keyId, new Uint8Array(secret));
110
+ }
111
+ async deleteSecret(keyId) {
112
+ this.#values.delete(keyId);
113
+ }
114
+ }
115
+ class MacOsKeychainWalletSecretProvider {
116
+ kind = "macos-keychain";
117
+ async loadSecret(keyId) {
118
+ try {
119
+ const { stdout } = await execFileAsync("security", [
120
+ "find-generic-password",
121
+ "-a",
122
+ keyId,
123
+ "-s",
124
+ KEYCHAIN_SERVICE_NAME,
125
+ "-w",
126
+ ]);
127
+ return base64ToBytes(stdout.trim());
128
+ }
129
+ catch (error) {
130
+ throw new Error(`wallet_secret_missing_${keyId}`, { cause: error });
131
+ }
132
+ }
133
+ async storeSecret(keyId, secret) {
134
+ await execFileAsync("security", [
135
+ "add-generic-password",
136
+ "-a",
137
+ keyId,
138
+ "-s",
139
+ KEYCHAIN_SERVICE_NAME,
140
+ "-w",
141
+ bytesToBase64(secret),
142
+ "-U",
143
+ ]);
144
+ }
145
+ async deleteSecret(keyId) {
146
+ await execFileAsync("security", [
147
+ "delete-generic-password",
148
+ "-a",
149
+ keyId,
150
+ "-s",
151
+ KEYCHAIN_SERVICE_NAME,
152
+ ]).catch(() => undefined);
153
+ }
154
+ }
155
+ class LinuxSecretToolWalletSecretProvider {
156
+ kind = "linux-secret-service";
157
+ #runner;
158
+ constructor(runner = runLinuxSecretTool) {
159
+ this.#runner = runner;
160
+ }
161
+ async #invoke(options) {
162
+ try {
163
+ const result = await this.#runner(options.args, {
164
+ stdin: options.stdin,
165
+ });
166
+ if (result.exitCode === 0) {
167
+ return result;
168
+ }
169
+ if (isLinuxSecretServiceUnavailableMessage(result.stderr)) {
170
+ throw createLinuxSecretToolError("wallet_secret_provider_linux_secret_service_unavailable");
171
+ }
172
+ if ((options.operation === "load" || options.ignoreMissing)
173
+ && isLinuxSecretToolMissingSecretMessage(result.stderr)) {
174
+ throw createLinuxSecretToolError(`wallet_secret_missing_${options.keyId}`);
175
+ }
176
+ throw createLinuxSecretToolError("wallet_secret_provider_linux_runtime_error");
177
+ }
178
+ catch (error) {
179
+ if (error instanceof Error
180
+ && (error.message === "wallet_secret_provider_linux_secret_tool_missing"
181
+ || error.message === "wallet_secret_provider_linux_secret_service_unavailable"
182
+ || error.message === "wallet_secret_provider_linux_runtime_error"
183
+ || error.message === `wallet_secret_missing_${options.keyId}`)) {
184
+ throw error;
185
+ }
186
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
187
+ throw createLinuxSecretToolError("wallet_secret_provider_linux_secret_tool_missing", error);
188
+ }
189
+ throw createLinuxSecretToolError("wallet_secret_provider_linux_runtime_error", error);
190
+ }
191
+ }
192
+ async loadSecret(keyId) {
193
+ const result = await this.#invoke({
194
+ args: ["lookup", ...createLinuxSecretToolAttributes(keyId)],
195
+ keyId,
196
+ operation: "load",
197
+ });
198
+ return base64ToBytes(result.stdout.trim());
199
+ }
200
+ async storeSecret(keyId, secret) {
201
+ await this.#invoke({
202
+ args: [
203
+ "store",
204
+ "--label",
205
+ `Cogcoin wallet secret (${keyId})`,
206
+ ...createLinuxSecretToolAttributes(keyId),
207
+ ],
208
+ keyId,
209
+ operation: "store",
210
+ stdin: bytesToBase64(secret),
211
+ });
212
+ }
213
+ async deleteSecret(keyId) {
214
+ try {
215
+ await this.#invoke({
216
+ args: ["clear", ...createLinuxSecretToolAttributes(keyId)],
217
+ keyId,
218
+ operation: "delete",
219
+ ignoreMissing: true,
220
+ });
221
+ }
222
+ catch (error) {
223
+ if (error instanceof Error && error.message === `wallet_secret_missing_${keyId}`) {
224
+ return;
225
+ }
226
+ throw error;
227
+ }
228
+ }
229
+ }
230
+ class WindowsDpapiWalletSecretProvider {
231
+ kind = "windows-dpapi";
232
+ #directoryPath;
233
+ constructor(directoryPath) {
234
+ this.#directoryPath = directoryPath;
235
+ }
236
+ #resolveSecretPath(keyId) {
237
+ const fileId = keyId.replace(/[^a-zA-Z0-9._-]+/g, "-");
238
+ return join(this.#directoryPath, `${fileId}.dpapi`);
239
+ }
240
+ async loadSecret(keyId) {
241
+ const secretPath = this.#resolveSecretPath(keyId);
242
+ const encoded = await readFile(secretPath, "utf8");
243
+ const { stdout } = await execFileAsync("powershell.exe", [
244
+ "-NoProfile",
245
+ "-NonInteractive",
246
+ "-Command",
247
+ "$data=[Convert]::FromBase64String($args[0]);$value=[System.Security.Cryptography.ProtectedData]::Unprotect($data,$null,[System.Security.Cryptography.DataProtectionScope]::CurrentUser);[Console]::Out.Write([Convert]::ToBase64String($value));",
248
+ encoded.trim(),
249
+ ]);
250
+ return base64ToBytes(stdout.trim());
251
+ }
252
+ async storeSecret(keyId, secret) {
253
+ const secretPath = this.#resolveSecretPath(keyId);
254
+ await mkdir(dirname(secretPath), { recursive: true });
255
+ const { stdout } = await execFileAsync("powershell.exe", [
256
+ "-NoProfile",
257
+ "-NonInteractive",
258
+ "-Command",
259
+ "$data=[Convert]::FromBase64String($args[0]);$value=[System.Security.Cryptography.ProtectedData]::Protect($data,$null,[System.Security.Cryptography.DataProtectionScope]::CurrentUser);[Console]::Out.Write([Convert]::ToBase64String($value));",
260
+ bytesToBase64(secret),
261
+ ]);
262
+ await writeFileAtomic(secretPath, `${stdout.trim()}\n`, { mode: 0o600 });
263
+ }
264
+ async deleteSecret(keyId) {
265
+ await rm(this.#resolveSecretPath(keyId), { force: true }).catch(() => undefined);
266
+ }
267
+ }
268
+ function createWalletSecretProviderForPlatform(platform, options = {}) {
269
+ if (platform === "darwin") {
270
+ return new MacOsKeychainWalletSecretProvider();
271
+ }
272
+ if (platform === "win32") {
273
+ return new WindowsDpapiWalletSecretProvider(join(resolveWalletRuntimePathsForTesting().stateRoot, "secrets"));
274
+ }
275
+ if (platform === "linux") {
276
+ return new LinuxSecretToolWalletSecretProvider(options.linuxSecretToolRunner);
277
+ }
278
+ throw new Error(`wallet_secret_provider_unsupported_${platform}`);
279
+ }
280
+ export function createDefaultWalletSecretProvider() {
281
+ return createWalletSecretProviderForPlatform(process.platform);
282
+ }
283
+ export function createDefaultWalletSecretProviderForTesting(options = {}) {
284
+ return createWalletSecretProviderForPlatform(options.platform ?? process.platform, options);
285
+ }
286
+ export function createLazyDefaultWalletSecretProvider() {
287
+ let resolved = null;
288
+ const getResolved = () => {
289
+ resolved ??= createDefaultWalletSecretProvider();
290
+ return resolved;
291
+ };
292
+ return {
293
+ get kind() {
294
+ return resolved?.kind ?? "lazy-default";
295
+ },
296
+ async loadSecret(keyId) {
297
+ return getResolved().loadSecret(keyId);
298
+ },
299
+ async storeSecret(keyId, secret) {
300
+ await getResolved().storeSecret(keyId, secret);
301
+ },
302
+ async deleteSecret(keyId) {
303
+ await getResolved().deleteSecret(keyId);
304
+ },
305
+ };
306
+ }
307
+ export function createMemoryWalletSecretProviderForTesting() {
308
+ return new MemoryWalletSecretProvider();
309
+ }
310
+ export function createWalletRootId() {
311
+ return `wallet-${randomUUID().replaceAll("-", "")}`;
312
+ }
@@ -0,0 +1,12 @@
1
+ import type { UnlockSessionStateV1 } from "../types.js";
2
+ import type { WalletSecretProvider, WalletSecretReference } from "./provider.js";
3
+ export type UnlockSessionSaveAccess = Uint8Array | string | {
4
+ provider: WalletSecretProvider;
5
+ secretReference: WalletSecretReference;
6
+ };
7
+ export type UnlockSessionLoadAccess = Uint8Array | string | {
8
+ provider: WalletSecretProvider;
9
+ };
10
+ export declare function saveUnlockSession(sessionPath: string, session: UnlockSessionStateV1, access: UnlockSessionSaveAccess): Promise<void>;
11
+ export declare function loadUnlockSession(sessionPath: string, access: UnlockSessionLoadAccess): Promise<UnlockSessionStateV1>;
12
+ export declare function clearUnlockSession(sessionPath: string): Promise<void>;
@@ -0,0 +1,23 @@
1
+ import { readFile, rm } from "node:fs/promises";
2
+ import { writeJsonFileAtomic } from "../fs/atomic.js";
3
+ import { decryptJsonWithPassphrase, decryptJsonWithSecretProvider, encryptJsonWithPassphrase, encryptJsonWithSecretProvider, } from "./crypto.js";
4
+ export async function saveUnlockSession(sessionPath, session, access) {
5
+ const envelope = typeof access === "string" || access instanceof Uint8Array
6
+ ? await encryptJsonWithPassphrase(session, access, {
7
+ format: "cogcoin-wallet-unlock-session",
8
+ })
9
+ : await encryptJsonWithSecretProvider(session, access.provider, access.secretReference, {
10
+ format: "cogcoin-wallet-unlock-session",
11
+ });
12
+ await writeJsonFileAtomic(sessionPath, envelope, { mode: 0o600 });
13
+ }
14
+ export async function loadUnlockSession(sessionPath, access) {
15
+ const raw = await readFile(sessionPath, "utf8");
16
+ const envelope = JSON.parse(raw);
17
+ return typeof access === "string" || access instanceof Uint8Array
18
+ ? decryptJsonWithPassphrase(envelope, access)
19
+ : decryptJsonWithSecretProvider(envelope, access.provider);
20
+ }
21
+ export async function clearUnlockSession(sessionPath) {
22
+ await rm(sessionPath, { force: true });
23
+ }
@@ -0,0 +1,19 @@
1
+ import type { WalletStateV1 } from "../types.js";
2
+ import type { WalletSecretProvider, WalletSecretReference } from "./provider.js";
3
+ export interface WalletStateStoragePaths {
4
+ primaryPath: string;
5
+ backupPath: string;
6
+ }
7
+ export interface LoadedWalletState {
8
+ source: "primary" | "backup";
9
+ state: WalletStateV1;
10
+ }
11
+ export type WalletStateSaveAccess = Uint8Array | string | {
12
+ provider: WalletSecretProvider;
13
+ secretReference: WalletSecretReference;
14
+ };
15
+ export type WalletStateLoadAccess = Uint8Array | string | {
16
+ provider: WalletSecretProvider;
17
+ };
18
+ export declare function saveWalletState(paths: WalletStateStoragePaths, state: WalletStateV1, access: WalletStateSaveAccess): Promise<void>;
19
+ export declare function loadWalletState(paths: WalletStateStoragePaths, access: WalletStateLoadAccess): Promise<LoadedWalletState>;
@@ -0,0 +1,55 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { writeJsonFileAtomic } from "../fs/atomic.js";
3
+ import { decryptJsonWithPassphrase, decryptJsonWithSecretProvider, encryptJsonWithPassphrase, encryptJsonWithSecretProvider, } from "./crypto.js";
4
+ async function readEnvelope(path) {
5
+ const raw = await readFile(path, "utf8");
6
+ return JSON.parse(raw);
7
+ }
8
+ export async function saveWalletState(paths, state, access) {
9
+ let previousPrimary = null;
10
+ try {
11
+ previousPrimary = await readEnvelope(paths.primaryPath);
12
+ }
13
+ catch (error) {
14
+ if (error instanceof SyntaxError) {
15
+ previousPrimary = null;
16
+ }
17
+ else if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
18
+ throw error;
19
+ }
20
+ }
21
+ const envelope = typeof access === "string" || access instanceof Uint8Array
22
+ ? await encryptJsonWithPassphrase(state, access, {
23
+ format: "cogcoin-local-wallet-state",
24
+ })
25
+ : await encryptJsonWithSecretProvider(state, access.provider, access.secretReference, {
26
+ format: "cogcoin-local-wallet-state",
27
+ });
28
+ await writeJsonFileAtomic(paths.primaryPath, envelope, { mode: 0o600 });
29
+ if (previousPrimary !== null) {
30
+ await writeJsonFileAtomic(paths.backupPath, previousPrimary, { mode: 0o600 });
31
+ }
32
+ }
33
+ export async function loadWalletState(paths, access) {
34
+ try {
35
+ return {
36
+ source: "primary",
37
+ state: typeof access === "string" || access instanceof Uint8Array
38
+ ? await decryptJsonWithPassphrase(await readEnvelope(paths.primaryPath), access)
39
+ : await decryptJsonWithSecretProvider(await readEnvelope(paths.primaryPath), access.provider),
40
+ };
41
+ }
42
+ catch (primaryError) {
43
+ try {
44
+ return {
45
+ source: "backup",
46
+ state: typeof access === "string" || access instanceof Uint8Array
47
+ ? await decryptJsonWithPassphrase(await readEnvelope(paths.backupPath), access)
48
+ : await decryptJsonWithSecretProvider(await readEnvelope(paths.backupPath), access.provider),
49
+ };
50
+ }
51
+ catch {
52
+ throw primaryError;
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,40 @@
1
+ import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
2
+ import { createRpcClient } from "../../bitcoind/node.js";
3
+ import type { RpcTransaction } from "../../bitcoind/types.js";
4
+ import type { WalletPrompter } from "../lifecycle.js";
5
+ import { type WalletRuntimePaths } from "../runtime.js";
6
+ import { type WalletSecretProvider } from "../state/provider.js";
7
+ import { openWalletReadContext } from "../read/index.js";
8
+ import { type WalletMutationRpcClient } from "./common.js";
9
+ interface WalletAnchorRpcClient extends WalletMutationRpcClient {
10
+ getBlockchainInfo(): Promise<{
11
+ blocks: number;
12
+ }>;
13
+ sendRawTransaction(hex: string): Promise<string>;
14
+ getRawMempool(): Promise<string[]>;
15
+ getRawTransaction(txid: string, verbose?: boolean): Promise<RpcTransaction>;
16
+ }
17
+ export interface AnchorDomainOptions {
18
+ domainName: string;
19
+ foundingMessageText?: string | null;
20
+ dataDir: string;
21
+ databasePath: string;
22
+ provider?: WalletSecretProvider;
23
+ prompter: WalletPrompter;
24
+ nowUnixMs?: number;
25
+ paths?: WalletRuntimePaths;
26
+ openReadContext?: typeof openWalletReadContext;
27
+ attachService?: typeof attachOrStartManagedBitcoindService;
28
+ rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletAnchorRpcClient;
29
+ }
30
+ export interface AnchorDomainResult {
31
+ domainName: string;
32
+ txid: string;
33
+ tx1Txid: string;
34
+ tx2Txid: string;
35
+ dedicatedIndex: number;
36
+ status: "live" | "confirmed";
37
+ reusedExisting: boolean;
38
+ }
39
+ export declare function anchorDomain(options: AnchorDomainOptions): Promise<AnchorDomainResult>;
40
+ export {};