@cogcoin/client 1.2.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@cogcoin/client`
2
2
 
3
- `@cogcoin/client@1.2.2` is the reference Cogcoin client package for applications that want a local wallet, durable SQLite-backed state, and a managed Bitcoin Core integration around `@cogcoin/indexer`. It publishes the reusable client APIs, the SQLite adapter, the managed `bitcoind` integration, and the first-party `cogcoin` CLI in one package.
3
+ `@cogcoin/client@1.2.3` is the reference Cogcoin client package for applications that want a local wallet, durable SQLite-backed state, and a managed Bitcoin Core integration around `@cogcoin/indexer`. It publishes the reusable client APIs, the SQLite adapter, the managed `bitcoind` integration, and the first-party `cogcoin` CLI in one package.
4
4
 
5
5
  Use Node 22 or newer.
6
6
 
@@ -4,7 +4,7 @@ import { persistWalletCoinControlStateIfNeeded } from "../coin-control.js";
4
4
  import { createWalletSecretReference } from "../state/provider.js";
5
5
  import { recreateManagedCoreWalletReplica, verifyManagedCoreWalletReplica } from "./managed-core.js";
6
6
  import { pathExists } from "./context.js";
7
- import { clearManagedBitcoindArtifacts, isManagedBitcoindRpcUnavailableError, mapBitcoindCompatibilityToRepairIssue, mapBitcoindRepairHealth, waitForProcessExit, } from "./repair-runtime.js";
7
+ import { clearManagedBitcoindArtifactsForDataDir, isManagedBitcoindRpcUnavailableError, mapBitcoindCompatibilityToRepairIssue, mapBitcoindRepairHealth, waitForProcessExit, } from "./repair-runtime.js";
8
8
  export async function repairManagedBitcoindStage(options) {
9
9
  let state = options.state;
10
10
  let repairStateNeedsPersist = options.repairStateNeedsPersist;
@@ -40,7 +40,7 @@ export async function repairManagedBitcoindStage(options) {
40
40
  if (initialBitcoindProbe.compatibility !== "rawtx-zmq-missing") {
41
41
  throw new Error("managed_bitcoind_process_id_unavailable");
42
42
  }
43
- await clearManagedBitcoindArtifacts(options.servicePaths);
43
+ await clearManagedBitcoindArtifactsForDataDir(options.servicePaths, options.context.dataDir);
44
44
  bitcoindServiceAction = "restarted-missing-rawtx-zmq";
45
45
  }
46
46
  else {
@@ -53,7 +53,7 @@ export async function repairManagedBitcoindStage(options) {
53
53
  }
54
54
  }
55
55
  await waitForProcessExit(processId, 15_000, "managed_bitcoind_stop_timeout");
56
- await clearManagedBitcoindArtifacts(options.servicePaths);
56
+ await clearManagedBitcoindArtifactsForDataDir(options.servicePaths, options.context.dataDir);
57
57
  bitcoindServiceAction = initialBitcoindProbe.compatibility === "rawtx-zmq-missing"
58
58
  ? "restarted-missing-rawtx-zmq"
59
59
  : "stopped-incompatible-service";
@@ -68,7 +68,7 @@ export async function repairManagedBitcoindStage(options) {
68
68
  options.servicePaths.bitcoindWalletStatusPath,
69
69
  ].map(pathExists));
70
70
  if (hasStaleArtifacts.some(Boolean)) {
71
- await clearManagedBitcoindArtifacts(options.servicePaths);
71
+ await clearManagedBitcoindArtifactsForDataDir(options.servicePaths, options.context.dataDir);
72
72
  bitcoindServiceAction = "cleared-stale-artifacts";
73
73
  }
74
74
  }
@@ -161,7 +161,7 @@ export async function repairManagedBitcoindStage(options) {
161
161
  dataDir: options.context.dataDir,
162
162
  });
163
163
  try {
164
- await clearManagedBitcoindArtifacts(options.servicePaths);
164
+ await clearManagedBitcoindArtifactsForDataDir(options.servicePaths, options.context.dataDir);
165
165
  }
166
166
  finally {
167
167
  await retryLock.release();
@@ -33,5 +33,6 @@ export declare function isManagedBitcoindRpcUnavailableError(error: unknown): bo
33
33
  export declare function waitForProcessExit(pid: number, timeoutMs?: number, errorCode?: string): Promise<void>;
34
34
  export declare function clearIndexerDaemonArtifacts(servicePaths: ReturnType<typeof resolveManagedServicePaths>): Promise<void>;
35
35
  export declare function clearManagedBitcoindArtifacts(servicePaths: ReturnType<typeof resolveManagedServicePaths>): Promise<void>;
36
+ export declare function clearManagedBitcoindArtifactsForDataDir(servicePaths: ReturnType<typeof resolveManagedServicePaths>, dataDir: string): Promise<void>;
36
37
  export declare function stopRecordedManagedProcess(pid: number | null, errorCode: string): Promise<void>;
37
38
  export declare function clearOrphanedRepairLocks(lockPaths: readonly string[]): Promise<void>;
@@ -1,5 +1,5 @@
1
- import { access, constants, mkdir, readFile, rm } from "node:fs/promises";
2
- import { dirname } from "node:path";
1
+ import { access, constants, mkdir, readdir, readFile, rm } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
3
  import { attachOrStartIndexerDaemon, probeIndexerDaemon, readSnapshotWithRetry, } from "../../bitcoind/indexer-daemon.js";
4
4
  import { probeManagedBitcoindService } from "../../bitcoind/service.js";
5
5
  import { resolveManagedServicePaths } from "../../bitcoind/service-paths.js";
@@ -184,11 +184,62 @@ export async function clearIndexerDaemonArtifacts(servicePaths) {
184
184
  await rm(servicePaths.indexerDaemonSocketPath, { force: true }).catch(() => undefined);
185
185
  }
186
186
  export async function clearManagedBitcoindArtifacts(servicePaths) {
187
- await rm(servicePaths.bitcoindStatusPath, { force: true }).catch(() => undefined);
188
- await rm(servicePaths.bitcoindPidPath, { force: true }).catch(() => undefined);
189
- await rm(servicePaths.bitcoindReadyPath, { force: true }).catch(() => undefined);
190
- await rm(servicePaths.bitcoindRuntimeConfigPath, { force: true }).catch(() => undefined);
191
- await rm(servicePaths.bitcoindWalletStatusPath, { force: true }).catch(() => undefined);
187
+ await clearManagedBitcoindArtifactRoot(servicePaths.walletRuntimeRoot);
188
+ }
189
+ async function readManagedBitcoindStatusAtRoot(serviceRoot) {
190
+ try {
191
+ return JSON.parse(await readFile(join(serviceRoot, "bitcoind-status.json"), "utf8"));
192
+ }
193
+ catch {
194
+ return null;
195
+ }
196
+ }
197
+ async function clearManagedBitcoindArtifactRoot(serviceRoot) {
198
+ await rm(join(serviceRoot, "bitcoind-status.json"), { force: true }).catch(() => undefined);
199
+ await rm(join(serviceRoot, "bitcoind.pid"), { force: true }).catch(() => undefined);
200
+ await rm(join(serviceRoot, "bitcoind.ready"), { force: true }).catch(() => undefined);
201
+ await rm(join(serviceRoot, "bitcoind-config.json"), { force: true }).catch(() => undefined);
202
+ await rm(join(serviceRoot, "bitcoind-wallet.json"), { force: true }).catch(() => undefined);
203
+ }
204
+ async function stopManagedBitcoindPid(pid) {
205
+ if (pid === null || !await isProcessAlive(pid)) {
206
+ return;
207
+ }
208
+ try {
209
+ process.kill(pid, "SIGTERM");
210
+ }
211
+ catch (error) {
212
+ if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) {
213
+ throw error;
214
+ }
215
+ }
216
+ await waitForProcessExit(pid, 15_000, "managed_bitcoind_stop_timeout");
217
+ }
218
+ export async function clearManagedBitcoindArtifactsForDataDir(servicePaths, dataDir) {
219
+ const serviceRoots = new Set([servicePaths.walletRuntimeRoot]);
220
+ const runtimeEntries = await readdir(servicePaths.runtimeRoot, { withFileTypes: true }).catch((error) => {
221
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
222
+ return [];
223
+ }
224
+ throw error;
225
+ });
226
+ for (const entry of runtimeEntries) {
227
+ if (!entry.isDirectory()) {
228
+ continue;
229
+ }
230
+ const serviceRoot = join(servicePaths.runtimeRoot, entry.name);
231
+ const status = await readManagedBitcoindStatusAtRoot(serviceRoot);
232
+ if (status?.dataDir === dataDir) {
233
+ serviceRoots.add(serviceRoot);
234
+ }
235
+ }
236
+ for (const serviceRoot of serviceRoots) {
237
+ const status = await readManagedBitcoindStatusAtRoot(serviceRoot);
238
+ if (status?.dataDir === dataDir) {
239
+ await stopManagedBitcoindPid(status.processId);
240
+ }
241
+ await clearManagedBitcoindArtifactRoot(serviceRoot);
242
+ }
192
243
  }
193
244
  export async function stopRecordedManagedProcess(pid, errorCode) {
194
245
  if (pid === null || !await isProcessAlive(pid)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cogcoin/client",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Store-backed Cogcoin client with wallet flows, SQLite persistence, and managed Bitcoin Core integration.",
5
5
  "license": "MIT",
6
6
  "type": "module",