@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,17 @@
1
+ import type { MiningEventRecord, MiningRuntimeStatusV1 } from "./types.js";
2
+ export declare function resolveRotatedMiningEventsPath(eventsPath: string): string;
3
+ export declare function loadMiningRuntimeStatus(statusPath: string): Promise<MiningRuntimeStatusV1 | null>;
4
+ export declare function saveMiningRuntimeStatus(statusPath: string, snapshot: MiningRuntimeStatusV1): Promise<void>;
5
+ export declare function appendMiningEvent(eventsPath: string, event: MiningEventRecord): Promise<void>;
6
+ export declare function readMiningEvents(options: {
7
+ eventsPath: string;
8
+ limit?: number | null;
9
+ all?: boolean;
10
+ }): Promise<MiningEventRecord[]>;
11
+ export declare function getLastMiningEventTimestamp(eventsPath: string): Promise<number | null>;
12
+ export declare function followMiningEvents(options: {
13
+ eventsPath: string;
14
+ intervalMs?: number;
15
+ signal?: AbortSignal;
16
+ onEvent: (event: MiningEventRecord) => void;
17
+ }): Promise<void>;
@@ -0,0 +1,166 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, open, readFile, rename, rm, stat } from "node:fs/promises";
3
+ import { dirname } from "node:path";
4
+ import { writeRuntimeStatusFile } from "../fs/status-file.js";
5
+ import { normalizeMiningFamilyStatus, normalizeMiningPublishState } from "./state.js";
6
+ const MAX_EVENT_LOG_BYTES = 10 * 1024 * 1024;
7
+ const MAX_EVENT_LOG_ROTATIONS = 4;
8
+ export function resolveRotatedMiningEventsPath(eventsPath) {
9
+ return `${eventsPath}.1`;
10
+ }
11
+ function resolveIndexedRotatedMiningEventsPath(eventsPath, index) {
12
+ return `${eventsPath}.${index}`;
13
+ }
14
+ export async function loadMiningRuntimeStatus(statusPath) {
15
+ try {
16
+ const raw = await readFile(statusPath, "utf8");
17
+ const parsed = JSON.parse(raw);
18
+ return {
19
+ ...parsed,
20
+ miningState: normalizeMiningFamilyStatus(parsed.miningState),
21
+ currentPublishState: normalizeMiningPublishState(parsed.currentPublishState),
22
+ indexerReorgDepth: parsed.indexerReorgDepth ?? null,
23
+ sameDomainCompetitorSuppressed: parsed.sameDomainCompetitorSuppressed ?? null,
24
+ dedupedCompetitorDomainCount: parsed.dedupedCompetitorDomainCount ?? null,
25
+ competitivenessGateIndeterminate: parsed.competitivenessGateIndeterminate ?? null,
26
+ mempoolSequenceCacheStatus: parsed.mempoolSequenceCacheStatus ?? null,
27
+ };
28
+ }
29
+ catch (error) {
30
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
31
+ return null;
32
+ }
33
+ throw error;
34
+ }
35
+ }
36
+ export async function saveMiningRuntimeStatus(statusPath, snapshot) {
37
+ await writeRuntimeStatusFile(statusPath, snapshot);
38
+ }
39
+ async function rotateMiningEventsIfNeeded(eventsPath, nextEntryBytes) {
40
+ try {
41
+ const current = await stat(eventsPath);
42
+ if ((current.size + nextEntryBytes) <= MAX_EVENT_LOG_BYTES) {
43
+ return;
44
+ }
45
+ for (let index = MAX_EVENT_LOG_ROTATIONS; index >= 1; index -= 1) {
46
+ const sourcePath = index === 1
47
+ ? eventsPath
48
+ : resolveIndexedRotatedMiningEventsPath(eventsPath, index - 1);
49
+ const destinationPath = resolveIndexedRotatedMiningEventsPath(eventsPath, index);
50
+ if (index === MAX_EVENT_LOG_ROTATIONS) {
51
+ await rm(destinationPath, { force: true }).catch(() => undefined);
52
+ }
53
+ try {
54
+ await rename(sourcePath, destinationPath);
55
+ }
56
+ catch (error) {
57
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
58
+ continue;
59
+ }
60
+ throw error;
61
+ }
62
+ }
63
+ }
64
+ catch (error) {
65
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
66
+ return;
67
+ }
68
+ throw error;
69
+ }
70
+ }
71
+ export async function appendMiningEvent(eventsPath, event) {
72
+ const serialized = `${JSON.stringify(event)}\n`;
73
+ await mkdir(dirname(eventsPath), { recursive: true });
74
+ await rotateMiningEventsIfNeeded(eventsPath, Buffer.byteLength(serialized));
75
+ const handle = await open(eventsPath, "a", 0o600);
76
+ try {
77
+ await handle.writeFile(serialized, { encoding: "utf8" });
78
+ await handle.sync();
79
+ }
80
+ finally {
81
+ await handle.close();
82
+ }
83
+ }
84
+ function parseMiningEventLines(raw) {
85
+ const hasTrailingNewline = raw.endsWith("\n");
86
+ const lines = raw.split("\n");
87
+ const completeLines = hasTrailingNewline ? lines.slice(0, -1) : lines.slice(0, -1);
88
+ const events = [];
89
+ for (const line of completeLines) {
90
+ const trimmed = line.trim();
91
+ if (trimmed.length === 0) {
92
+ continue;
93
+ }
94
+ try {
95
+ events.push(JSON.parse(trimmed));
96
+ }
97
+ catch {
98
+ continue;
99
+ }
100
+ }
101
+ return events;
102
+ }
103
+ async function readEventFile(path) {
104
+ try {
105
+ const raw = await readFile(path, "utf8");
106
+ return parseMiningEventLines(raw);
107
+ }
108
+ catch (error) {
109
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
110
+ return [];
111
+ }
112
+ throw error;
113
+ }
114
+ }
115
+ export async function readMiningEvents(options) {
116
+ const paths = [];
117
+ for (let index = MAX_EVENT_LOG_ROTATIONS; index >= 1; index -= 1) {
118
+ paths.push(resolveIndexedRotatedMiningEventsPath(options.eventsPath, index));
119
+ }
120
+ paths.push(options.eventsPath);
121
+ const chunks = await Promise.all(paths.map((path) => readEventFile(path)));
122
+ const events = chunks.flat();
123
+ if (options.all) {
124
+ return events;
125
+ }
126
+ const limit = options.limit ?? 50;
127
+ return events.slice(Math.max(0, events.length - limit));
128
+ }
129
+ export async function getLastMiningEventTimestamp(eventsPath) {
130
+ const events = await readMiningEvents({
131
+ eventsPath,
132
+ limit: 1,
133
+ });
134
+ return events.length === 0 ? null : events[0].timestampUnixMs;
135
+ }
136
+ export async function followMiningEvents(options) {
137
+ const seen = new Set();
138
+ const recordEvents = async () => {
139
+ const events = await readMiningEvents({
140
+ eventsPath: options.eventsPath,
141
+ all: true,
142
+ });
143
+ for (const event of events) {
144
+ const digest = createHash("sha256").update(JSON.stringify(event)).digest("hex");
145
+ if (seen.has(digest)) {
146
+ continue;
147
+ }
148
+ seen.add(digest);
149
+ options.onEvent(event);
150
+ }
151
+ };
152
+ await recordEvents();
153
+ while (!options.signal?.aborted) {
154
+ await new Promise((resolve) => {
155
+ const timeout = setTimeout(resolve, options.intervalMs ?? 250);
156
+ options.signal?.addEventListener("abort", () => {
157
+ clearTimeout(timeout);
158
+ resolve(undefined);
159
+ }, { once: true });
160
+ });
161
+ if (options.signal?.aborted) {
162
+ return;
163
+ }
164
+ await recordEvents();
165
+ }
166
+ }
@@ -0,0 +1,23 @@
1
+ import type { GenerateSentencesHookCandidateV1, GenerateSentencesHookRequestV1 } from "./hook-protocol.js";
2
+ import type { WalletRuntimePaths } from "../runtime.js";
3
+ import type { HookClientStateRecord } from "../types.js";
4
+ import type { WalletSecretProvider } from "../state/provider.js";
5
+ export type MiningSentenceGenerationRequest = GenerateSentencesHookRequestV1;
6
+ export type MiningSentenceGenerationCandidate = GenerateSentencesHookCandidateV1;
7
+ export interface MiningSentenceSourceOptions {
8
+ paths: WalletRuntimePaths;
9
+ provider: WalletSecretProvider;
10
+ hookState: HookClientStateRecord | null;
11
+ signal?: AbortSignal;
12
+ fetchImpl?: typeof fetch;
13
+ }
14
+ declare class MiningProviderRequestError extends Error {
15
+ readonly providerState: "unavailable" | "rate-limited" | "auth-error";
16
+ constructor(providerState: "unavailable" | "rate-limited" | "auth-error", message: string);
17
+ }
18
+ export declare function generateMiningSentences(request: MiningSentenceGenerationRequest, options: MiningSentenceSourceOptions): Promise<{
19
+ hookMode: "builtin" | "custom";
20
+ candidates: GenerateSentencesHookCandidateV1[];
21
+ providerState: "ready" | "n/a";
22
+ }>;
23
+ export { MiningProviderRequestError, };
@@ -0,0 +1,281 @@
1
+ import { loadClientConfig } from "./config.js";
2
+ import { inspectMiningHookState, runGenerateSentencesHookRequest } from "./hooks.js";
3
+ import { MINING_BUILTIN_TIMEOUT_MS, } from "./constants.js";
4
+ import { normalizeHookResponse, parseStrictJsonValue, stripMarkdownCodeFence, } from "./hook-protocol.js";
5
+ class MiningProviderRequestError extends Error {
6
+ providerState;
7
+ constructor(providerState, message) {
8
+ super(message);
9
+ this.name = "MiningProviderRequestError";
10
+ this.providerState = providerState;
11
+ }
12
+ }
13
+ function buildSystemPrompt(extraPrompt) {
14
+ const lines = [
15
+ "You are helping generate candidate Cogcoin mining sentences.",
16
+ "Return only JSON matching the requested response schema.",
17
+ "Every sentence must be a single natural-language sentence.",
18
+ "Do not add commentary, markdown, or code fences.",
19
+ "Do not invent domain IDs or request IDs.",
20
+ ];
21
+ if (extraPrompt !== null && extraPrompt.trim().length > 0) {
22
+ lines.push(`Extra instruction: ${extraPrompt.trim()}`);
23
+ }
24
+ return lines.join("\n");
25
+ }
26
+ function buildUserPrompt(request) {
27
+ return [
28
+ "Return a JSON object with:",
29
+ `- schemaVersion: 1`,
30
+ `- requestId: ${request.requestId}`,
31
+ "- candidates: [{ domainId, sentence }]",
32
+ "Use only domain IDs from rootDomains.",
33
+ `Keep each sentence within ${request.limits.maxCandidateSentenceUtf8Bytes} UTF-8 bytes after trimming.`,
34
+ "Mining request JSON:",
35
+ JSON.stringify(request, null, 2),
36
+ ].join("\n");
37
+ }
38
+ function annotateProviderCandidates(options) {
39
+ return options.candidates.map((candidate) => ({
40
+ ...candidate,
41
+ attribution: candidate.attribution ?? {
42
+ provider: options.provider,
43
+ model: options.model,
44
+ promptLabel: "built-in",
45
+ },
46
+ }));
47
+ }
48
+ function parseProviderJsonResponse(options) {
49
+ const response = parseStrictJsonValue(stripMarkdownCodeFence(options.raw), `${options.providerLabel} returned invalid JSON.`);
50
+ try {
51
+ return normalizeHookResponse({
52
+ request: options.request,
53
+ response,
54
+ }).candidates;
55
+ }
56
+ catch (error) {
57
+ throw new Error(error instanceof Error
58
+ ? error.message.replace(/^Custom mining hook /, `${options.providerLabel} `)
59
+ : `${options.providerLabel} returned an invalid response.`);
60
+ }
61
+ }
62
+ function createProviderSignal(signal, timeoutMs) {
63
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
64
+ return signal === undefined ? timeoutSignal : AbortSignal.any([signal, timeoutSignal]);
65
+ }
66
+ async function requestBuiltInSentences(options) {
67
+ const fetchImpl = options.fetchImpl ?? fetch;
68
+ const providerSignal = createProviderSignal(options.signal, Math.min(MINING_BUILTIN_TIMEOUT_MS, options.request.limits.timeoutMs));
69
+ try {
70
+ if (options.provider === "openai") {
71
+ const model = options.modelOverride ?? "gpt-5.4-mini";
72
+ const response = await fetchImpl("https://api.openai.com/v1/responses", {
73
+ method: "POST",
74
+ headers: {
75
+ authorization: `Bearer ${options.apiKey}`,
76
+ "content-type": "application/json",
77
+ },
78
+ body: JSON.stringify({
79
+ model,
80
+ input: [
81
+ {
82
+ role: "system",
83
+ content: buildSystemPrompt(options.extraPrompt),
84
+ },
85
+ {
86
+ role: "user",
87
+ content: buildUserPrompt(options.request),
88
+ },
89
+ ],
90
+ }),
91
+ signal: providerSignal,
92
+ });
93
+ if (response.status === 401 || response.status === 403) {
94
+ throw new MiningProviderRequestError("auth-error", "The built-in OpenAI mining provider rejected the configured API key.");
95
+ }
96
+ if (response.status === 429) {
97
+ throw new MiningProviderRequestError("rate-limited", "The built-in OpenAI mining provider is rate limited.");
98
+ }
99
+ if (!response.ok) {
100
+ throw new MiningProviderRequestError("unavailable", `The built-in OpenAI mining provider returned HTTP ${response.status}.`);
101
+ }
102
+ return annotateProviderCandidates({
103
+ candidates: parseProviderJsonResponse({
104
+ raw: extractOpenAiText(await response.json()),
105
+ request: options.request,
106
+ providerLabel: "The built-in OpenAI mining provider",
107
+ }),
108
+ provider: options.provider,
109
+ model,
110
+ });
111
+ }
112
+ const model = options.modelOverride ?? "claude-sonnet-4-20250514";
113
+ const response = await fetchImpl("https://api.anthropic.com/v1/messages", {
114
+ method: "POST",
115
+ headers: {
116
+ "x-api-key": options.apiKey,
117
+ "anthropic-version": "2023-06-01",
118
+ "content-type": "application/json",
119
+ },
120
+ body: JSON.stringify({
121
+ model,
122
+ max_tokens: 1_200,
123
+ system: buildSystemPrompt(options.extraPrompt),
124
+ messages: [
125
+ {
126
+ role: "user",
127
+ content: buildUserPrompt(options.request),
128
+ },
129
+ ],
130
+ }),
131
+ signal: providerSignal,
132
+ });
133
+ if (response.status === 401 || response.status === 403) {
134
+ throw new MiningProviderRequestError("auth-error", "The built-in Anthropic mining provider rejected the configured API key.");
135
+ }
136
+ if (response.status === 429) {
137
+ throw new MiningProviderRequestError("rate-limited", "The built-in Anthropic mining provider is rate limited.");
138
+ }
139
+ if (!response.ok) {
140
+ throw new MiningProviderRequestError("unavailable", `The built-in Anthropic mining provider returned HTTP ${response.status}.`);
141
+ }
142
+ return annotateProviderCandidates({
143
+ candidates: parseProviderJsonResponse({
144
+ raw: extractAnthropicText(await response.json()),
145
+ request: options.request,
146
+ providerLabel: "The built-in Anthropic mining provider",
147
+ }),
148
+ provider: options.provider,
149
+ model,
150
+ });
151
+ }
152
+ catch (error) {
153
+ if (error instanceof MiningProviderRequestError) {
154
+ throw error;
155
+ }
156
+ if (error instanceof Error && error.name === "AbortError") {
157
+ throw new MiningProviderRequestError("unavailable", "Mining sentence generation was aborted.");
158
+ }
159
+ throw new MiningProviderRequestError("unavailable", error instanceof Error ? error.message : String(error));
160
+ }
161
+ }
162
+ function extractOpenAiText(payload) {
163
+ if (payload !== null && typeof payload === "object") {
164
+ const outputText = payload.output_text;
165
+ if (typeof outputText === "string" && outputText.trim().length > 0) {
166
+ return outputText;
167
+ }
168
+ const output = payload.output;
169
+ if (Array.isArray(output)) {
170
+ const collected = [];
171
+ for (const item of output) {
172
+ if (item === null || typeof item !== "object") {
173
+ continue;
174
+ }
175
+ const content = item.content;
176
+ if (!Array.isArray(content)) {
177
+ continue;
178
+ }
179
+ for (const part of content) {
180
+ if (part !== null && typeof part === "object") {
181
+ const text = part.text;
182
+ if (typeof text === "string" && text.trim().length > 0) {
183
+ collected.push(text);
184
+ }
185
+ }
186
+ }
187
+ }
188
+ if (collected.length > 0) {
189
+ return collected.join("\n");
190
+ }
191
+ }
192
+ }
193
+ throw new Error("The built-in OpenAI mining provider returned an empty response.");
194
+ }
195
+ function extractAnthropicText(payload) {
196
+ if (payload !== null && typeof payload === "object") {
197
+ const content = payload.content;
198
+ if (Array.isArray(content)) {
199
+ const parts = content
200
+ .flatMap((entry) => {
201
+ if (entry !== null && typeof entry === "object") {
202
+ const text = entry.text;
203
+ return typeof text === "string" && text.trim().length > 0 ? [text] : [];
204
+ }
205
+ return [];
206
+ });
207
+ if (parts.length > 0) {
208
+ return parts.join("\n");
209
+ }
210
+ }
211
+ }
212
+ throw new Error("The built-in Anthropic mining provider returned an empty response.");
213
+ }
214
+ async function requestCustomHookSentences(options) {
215
+ const inspection = await inspectMiningHookState({
216
+ hookRootPath: options.paths.hooksMiningDir,
217
+ entrypointPath: options.paths.hooksMiningEntrypointPath,
218
+ packagePath: options.paths.hooksMiningPackageJsonPath,
219
+ localState: options.hookState,
220
+ verify: false,
221
+ nowUnixMs: Date.now(),
222
+ });
223
+ if (inspection.mode !== "custom") {
224
+ throw new Error("Custom mining hooks are not enabled.");
225
+ }
226
+ if (inspection.cooldownActive) {
227
+ throw new Error("Custom mining hook is cooling down after repeated failures. Wait for the cooldown to expire or rerun `cogcoin hooks enable mining`.");
228
+ }
229
+ if (inspection.operatorValidationState === "failed"
230
+ || inspection.operatorValidationState === "stale"
231
+ || inspection.operatorValidationState === "never") {
232
+ throw new Error("Custom mining hook validation is stale or failed. Rerun `cogcoin hooks enable mining`.");
233
+ }
234
+ if (inspection.trustStatus !== "trusted") {
235
+ throw new Error(inspection.trustMessage ?? "Custom mining hook trust checks failed.");
236
+ }
237
+ return runGenerateSentencesHookRequest({
238
+ hookRootPath: options.paths.hooksMiningDir,
239
+ entrypointPath: options.paths.hooksMiningEntrypointPath,
240
+ request: options.request,
241
+ signal: options.signal,
242
+ timeoutMs: options.request.limits.timeoutMs,
243
+ }).then((result) => result.candidates);
244
+ }
245
+ export async function generateMiningSentences(request, options) {
246
+ const hookMode = options.hookState?.mode === "custom" ? "custom" : "builtin";
247
+ if (hookMode === "custom") {
248
+ return {
249
+ hookMode,
250
+ candidates: await requestCustomHookSentences({
251
+ paths: options.paths,
252
+ hookState: options.hookState,
253
+ request,
254
+ signal: options.signal,
255
+ }),
256
+ providerState: "n/a",
257
+ };
258
+ }
259
+ const config = await loadClientConfig({
260
+ path: options.paths.clientConfigPath,
261
+ provider: options.provider,
262
+ });
263
+ const builtIn = config?.mining.builtIn ?? null;
264
+ if (builtIn === null) {
265
+ throw new MiningProviderRequestError("unavailable", "Mining is not configured. Run `cogcoin mine setup`.");
266
+ }
267
+ return {
268
+ hookMode,
269
+ candidates: await requestBuiltInSentences({
270
+ provider: builtIn.provider,
271
+ apiKey: builtIn.apiKey,
272
+ modelOverride: builtIn.modelOverride,
273
+ extraPrompt: builtIn.extraPrompt ?? request.extraPrompt,
274
+ request,
275
+ fetchImpl: options.fetchImpl,
276
+ signal: options.signal,
277
+ }),
278
+ providerState: "ready",
279
+ };
280
+ }
281
+ export { MiningProviderRequestError, };
@@ -0,0 +1,9 @@
1
+ import type { MiningStateRecord } from "../types.js";
2
+ export type MiningFamilyStatus = MiningStateRecord["state"];
3
+ export type MiningPublishState = MiningStateRecord["currentPublishState"];
4
+ export declare function normalizeMiningFamilyStatus(raw: string | null | undefined): MiningFamilyStatus;
5
+ export declare function normalizeMiningPublishState(raw: string | null | undefined): MiningPublishState;
6
+ export declare function normalizeMiningStateRecord(state: MiningStateRecord): MiningStateRecord;
7
+ export declare function clearMiningFamilyState(state: MiningStateRecord): MiningStateRecord;
8
+ export declare function miningFamilyMayStillExist(state: MiningStateRecord): boolean;
9
+ export declare function miningFamilyIsInMempool(state: MiningStateRecord): boolean;
@@ -0,0 +1,75 @@
1
+ export function normalizeMiningFamilyStatus(raw) {
2
+ switch (raw) {
3
+ case "live":
4
+ case "paused":
5
+ case "paused-stale":
6
+ case "repair-required":
7
+ return raw;
8
+ case "waiting-bitcoin-network":
9
+ case "waiting-indexer":
10
+ case "waiting-provider":
11
+ case "resuming":
12
+ return "paused";
13
+ case "idle":
14
+ default:
15
+ return "idle";
16
+ }
17
+ }
18
+ export function normalizeMiningPublishState(raw) {
19
+ switch (raw) {
20
+ case "broadcasting":
21
+ case "broadcast-unknown":
22
+ case "in-mempool":
23
+ return raw;
24
+ case "live":
25
+ return "in-mempool";
26
+ case "draft":
27
+ case "idle":
28
+ case "none":
29
+ default:
30
+ return "none";
31
+ }
32
+ }
33
+ export function normalizeMiningStateRecord(state) {
34
+ return {
35
+ ...state,
36
+ state: normalizeMiningFamilyStatus(state.state),
37
+ currentPublishState: normalizeMiningPublishState(state.currentPublishState),
38
+ };
39
+ }
40
+ export function clearMiningFamilyState(state) {
41
+ return {
42
+ ...normalizeMiningStateRecord(state),
43
+ state: "idle",
44
+ pauseReason: null,
45
+ currentPublishState: "none",
46
+ currentDomain: null,
47
+ currentDomainId: null,
48
+ currentDomainIndex: null,
49
+ currentSenderScriptPubKeyHex: null,
50
+ currentTxid: null,
51
+ currentWtxid: null,
52
+ currentFeeRateSatVb: null,
53
+ currentAbsoluteFeeSats: null,
54
+ currentScore: null,
55
+ currentSentence: null,
56
+ currentEncodedSentenceBytesHex: null,
57
+ currentBip39WordIndices: null,
58
+ currentBlendSeedHex: null,
59
+ currentBlockTargetHeight: null,
60
+ currentReferencedBlockHashDisplay: null,
61
+ currentIntentFingerprintHex: null,
62
+ liveMiningFamilyInMempool: false,
63
+ currentPublishDecision: null,
64
+ replacementCount: 0,
65
+ sharedMiningConflictOutpoint: null,
66
+ };
67
+ }
68
+ export function miningFamilyMayStillExist(state) {
69
+ const normalized = normalizeMiningStateRecord(state);
70
+ return normalized.currentTxid !== null
71
+ && normalized.currentPublishState !== "none";
72
+ }
73
+ export function miningFamilyIsInMempool(state) {
74
+ return normalizeMiningStateRecord(state).currentPublishState === "in-mempool";
75
+ }