@cogcoin/client 1.1.5 → 1.1.7

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 (132) hide show
  1. package/README.md +2 -2
  2. package/dist/bitcoind/indexer-daemon.d.ts +3 -7
  3. package/dist/bitcoind/indexer-daemon.js +39 -204
  4. package/dist/bitcoind/managed-runtime/bitcoind-policy.d.ts +16 -0
  5. package/dist/bitcoind/managed-runtime/bitcoind-policy.js +177 -0
  6. package/dist/bitcoind/managed-runtime/bitcoind-runtime.d.ts +20 -0
  7. package/dist/bitcoind/managed-runtime/bitcoind-runtime.js +74 -0
  8. package/dist/bitcoind/managed-runtime/bitcoind-status.d.ts +11 -0
  9. package/dist/bitcoind/managed-runtime/bitcoind-status.js +44 -0
  10. package/dist/bitcoind/managed-runtime/indexer-policy.d.ts +34 -0
  11. package/dist/bitcoind/managed-runtime/indexer-policy.js +200 -0
  12. package/dist/bitcoind/managed-runtime/indexer-runtime.d.ts +15 -0
  13. package/dist/bitcoind/managed-runtime/indexer-runtime.js +82 -0
  14. package/dist/bitcoind/managed-runtime/status.d.ts +11 -0
  15. package/dist/bitcoind/managed-runtime/status.js +59 -0
  16. package/dist/bitcoind/managed-runtime/types.d.ts +77 -0
  17. package/dist/bitcoind/node.d.ts +2 -2
  18. package/dist/bitcoind/node.js +2 -2
  19. package/dist/bitcoind/rpc.d.ts +2 -1
  20. package/dist/bitcoind/rpc.js +53 -3
  21. package/dist/bitcoind/service.d.ts +2 -7
  22. package/dist/bitcoind/service.js +79 -207
  23. package/dist/cli/command-registry.d.ts +1 -1
  24. package/dist/cli/command-registry.js +2 -64
  25. package/dist/cli/commands/client-admin.js +3 -18
  26. package/dist/cli/commands/mining-runtime.js +4 -60
  27. package/dist/cli/commands/wallet-admin.js +6 -6
  28. package/dist/cli/context.js +1 -3
  29. package/dist/cli/mining-json.d.ts +1 -22
  30. package/dist/cli/mining-json.js +0 -23
  31. package/dist/cli/output.js +16 -2
  32. package/dist/cli/parse.js +0 -2
  33. package/dist/cli/preview-json.d.ts +1 -22
  34. package/dist/cli/preview-json.js +0 -19
  35. package/dist/cli/types.d.ts +1 -3
  36. package/dist/cli/wallet-format.js +1 -1
  37. package/dist/cli/workflow-hints.d.ts +1 -2
  38. package/dist/cli/workflow-hints.js +5 -8
  39. package/dist/wallet/lifecycle/access.d.ts +5 -0
  40. package/dist/wallet/lifecycle/access.js +79 -0
  41. package/dist/wallet/lifecycle/context.d.ts +26 -0
  42. package/dist/wallet/lifecycle/context.js +57 -0
  43. package/dist/wallet/lifecycle/managed-core.d.ts +1 -9
  44. package/dist/wallet/lifecycle/managed-core.js +3 -63
  45. package/dist/wallet/lifecycle/repair-bitcoind.d.ts +10 -0
  46. package/dist/wallet/lifecycle/repair-bitcoind.js +142 -0
  47. package/dist/wallet/lifecycle/repair-indexer.d.ts +8 -0
  48. package/dist/wallet/lifecycle/repair-indexer.js +117 -0
  49. package/dist/wallet/lifecycle/repair-mining.d.ts +1 -5
  50. package/dist/wallet/lifecycle/repair-mining.js +5 -39
  51. package/dist/wallet/lifecycle/repair.d.ts +2 -4
  52. package/dist/wallet/lifecycle/repair.js +74 -318
  53. package/dist/wallet/lifecycle/setup-prompts.d.ts +7 -0
  54. package/dist/wallet/lifecycle/setup-prompts.js +88 -0
  55. package/dist/wallet/lifecycle/setup-state.d.ts +26 -0
  56. package/dist/wallet/lifecycle/setup-state.js +159 -0
  57. package/dist/wallet/lifecycle/setup.d.ts +3 -4
  58. package/dist/wallet/lifecycle/setup.js +47 -351
  59. package/dist/wallet/lifecycle/types.d.ts +33 -5
  60. package/dist/wallet/managed-core-wallet.d.ts +2 -0
  61. package/dist/wallet/managed-core-wallet.js +27 -1
  62. package/dist/wallet/mining/candidate.d.ts +1 -0
  63. package/dist/wallet/mining/candidate.js +38 -6
  64. package/dist/wallet/mining/competitiveness.d.ts +1 -0
  65. package/dist/wallet/mining/competitiveness.js +6 -0
  66. package/dist/wallet/mining/cycle.d.ts +2 -0
  67. package/dist/wallet/mining/cycle.js +14 -4
  68. package/dist/wallet/mining/engine-types.d.ts +1 -0
  69. package/dist/wallet/mining/index.d.ts +1 -1
  70. package/dist/wallet/mining/index.js +1 -1
  71. package/dist/wallet/mining/publish.d.ts +3 -0
  72. package/dist/wallet/mining/publish.js +78 -6
  73. package/dist/wallet/mining/runner.d.ts +0 -32
  74. package/dist/wallet/mining/runner.js +59 -104
  75. package/dist/wallet/mining/stop.d.ts +7 -0
  76. package/dist/wallet/mining/stop.js +23 -0
  77. package/dist/wallet/mining/supervisor.d.ts +2 -36
  78. package/dist/wallet/mining/supervisor.js +139 -246
  79. package/dist/wallet/read/context.d.ts +1 -5
  80. package/dist/wallet/read/context.js +20 -379
  81. package/dist/wallet/read/managed-services.d.ts +33 -0
  82. package/dist/wallet/read/managed-services.js +222 -0
  83. package/dist/wallet/state/client-password/bootstrap.d.ts +2 -0
  84. package/dist/wallet/state/client-password/bootstrap.js +3 -0
  85. package/dist/wallet/state/client-password/context.d.ts +10 -0
  86. package/dist/wallet/state/client-password/context.js +46 -0
  87. package/dist/wallet/state/client-password/crypto.d.ts +34 -0
  88. package/dist/wallet/state/client-password/crypto.js +117 -0
  89. package/dist/wallet/state/client-password/files.d.ts +10 -0
  90. package/dist/wallet/state/client-password/files.js +109 -0
  91. package/dist/wallet/state/client-password/legacy-cleanup.d.ts +11 -0
  92. package/dist/wallet/state/client-password/legacy-cleanup.js +338 -0
  93. package/dist/wallet/state/client-password/messages.d.ts +3 -0
  94. package/dist/wallet/state/client-password/messages.js +9 -0
  95. package/dist/wallet/state/client-password/migration.d.ts +4 -0
  96. package/dist/wallet/state/client-password/migration.js +32 -0
  97. package/dist/wallet/state/client-password/prompts.d.ts +12 -0
  98. package/dist/wallet/state/client-password/prompts.js +79 -0
  99. package/dist/wallet/state/client-password/protected-secrets.d.ts +13 -0
  100. package/dist/wallet/state/client-password/protected-secrets.js +90 -0
  101. package/dist/wallet/state/client-password/readiness.d.ts +4 -0
  102. package/dist/wallet/state/client-password/readiness.js +48 -0
  103. package/dist/wallet/state/client-password/references.d.ts +1 -0
  104. package/dist/wallet/state/client-password/references.js +56 -0
  105. package/dist/wallet/state/client-password/rotation.d.ts +6 -0
  106. package/dist/wallet/state/client-password/rotation.js +98 -0
  107. package/dist/wallet/state/client-password/session-policy.d.ts +6 -0
  108. package/dist/wallet/state/client-password/session-policy.js +28 -0
  109. package/dist/wallet/state/client-password/session.d.ts +19 -0
  110. package/dist/wallet/state/client-password/session.js +170 -0
  111. package/dist/wallet/state/client-password/setup.d.ts +8 -0
  112. package/dist/wallet/state/client-password/setup.js +49 -0
  113. package/dist/wallet/state/client-password/types.d.ts +82 -0
  114. package/dist/wallet/state/client-password/types.js +5 -0
  115. package/dist/wallet/state/client-password.d.ts +7 -38
  116. package/dist/wallet/state/client-password.js +52 -937
  117. package/dist/wallet/tx/anchor.js +123 -216
  118. package/dist/wallet/tx/cog.js +294 -489
  119. package/dist/wallet/tx/common.d.ts +2 -0
  120. package/dist/wallet/tx/common.js +2 -0
  121. package/dist/wallet/tx/domain-admin.js +111 -220
  122. package/dist/wallet/tx/domain-market.js +401 -681
  123. package/dist/wallet/tx/executor.d.ts +176 -0
  124. package/dist/wallet/tx/executor.js +302 -0
  125. package/dist/wallet/tx/field.js +109 -215
  126. package/dist/wallet/tx/register.js +158 -269
  127. package/dist/wallet/tx/reputation.js +120 -227
  128. package/package.json +1 -1
  129. package/dist/wallet/mining/worker-main.js +0 -17
  130. package/dist/wallet/state/client-password-agent.d.ts +0 -1
  131. package/dist/wallet/state/client-password-agent.js +0 -211
  132. /package/dist/{wallet/mining/worker-main.d.ts → bitcoind/managed-runtime/types.js} +0 -0
@@ -1,13 +1,10 @@
1
1
  import { access, constants } from "node:fs/promises";
2
- import { deserializeIndexerState, loadBundledGenesisParameters } from "@cogcoin/indexer";
3
2
  import { readPackageVersionFromDisk } from "../../package-version.js";
4
- import { attachOrStartIndexerDaemon, INDEXER_DAEMON_BACKGROUND_FOLLOW_RECOVERY_FAILED, probeIndexerDaemon, readObservedIndexerDaemonStatus, readSnapshotWithRetry, } from "../../bitcoind/indexer-daemon.js";
3
+ import { readSnapshotWithRetry, } from "../../bitcoind/indexer-daemon.js";
5
4
  import { createRpcClient } from "../../bitcoind/node.js";
6
5
  import { UNINITIALIZED_WALLET_ROOT_ID } from "../../bitcoind/service-paths.js";
7
- import { attachOrStartManagedBitcoindService, probeManagedBitcoindService, } from "../../bitcoind/service.js";
8
- import { resolveCogcoinProcessingStartHeight } from "../../bitcoind/processing-start-height.js";
6
+ import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
9
7
  import {} from "../../bitcoind/types.js";
10
- import { verifyManagedCoreWalletReplica, } from "../lifecycle.js";
11
8
  import { normalizeWalletStateRecord, persistWalletCoinControlStateIfNeeded } from "../coin-control.js";
12
9
  import { persistNormalizedWalletDescriptorStateIfNeeded } from "../descriptor-normalization.js";
13
10
  import { inspectMiningControlPlane } from "../mining/index.js";
@@ -17,12 +14,9 @@ import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
17
14
  import { extractWalletRootIdHintFromWalletStateEnvelope, loadRawWalletStateEnvelope, loadWalletState, } from "../state/storage.js";
18
15
  import { createDefaultWalletSecretProvider, createWalletSecretReference, inspectClientPasswordSetupReadiness, } from "../state/provider.js";
19
16
  import { describeClientPasswordLockedMessage, describeClientPasswordMigrationMessage, describeClientPasswordSetupMessage, } from "../state/client-password.js";
17
+ import { openManagedWalletReadServiceBundle } from "./managed-services.js";
20
18
  import { createWalletReadModel } from "./project.js";
21
19
  const DEFAULT_SERVICE_START_TIMEOUT_MS = 10_000;
22
- const STALE_HEARTBEAT_THRESHOLD_MS = 15_000;
23
- const TOLERATED_NODE_HEADER_LEAD_BLOCKS = 2;
24
- const TOLERATED_NODE_HEADER_LEAD_MESSAGE = "Bitcoin headers can briefly lead validated blocks; a short 1-2 block lead is normal and is being tolerated.";
25
- const NODE_CATCHING_UP_MESSAGE = "Bitcoin Core is still catching up to headers.";
26
20
  function btcAmountToSats(value) {
27
21
  return BigInt(Math.round(value * 100_000_000));
28
22
  }
@@ -222,279 +216,6 @@ async function inspectWalletLocalState(options = {}) {
222
216
  };
223
217
  }
224
218
  }
225
- function mapIndexerStartupError(message) {
226
- switch (message) {
227
- case "indexer_daemon_start_timeout":
228
- return {
229
- health: "starting",
230
- message: "Indexer daemon is still starting.",
231
- };
232
- case "indexer_daemon_service_version_mismatch":
233
- return {
234
- health: "service-version-mismatch",
235
- message: "The live indexer daemon is running an incompatible service API version.",
236
- };
237
- case "indexer_daemon_schema_mismatch":
238
- return {
239
- health: "schema-mismatch",
240
- message: "The live indexer daemon is using an incompatible sqlite schema.",
241
- };
242
- case "indexer_daemon_wallet_root_mismatch":
243
- return {
244
- health: "wallet-root-mismatch",
245
- message: "The live indexer daemon belongs to a different wallet root.",
246
- };
247
- case "indexer_daemon_protocol_error":
248
- return {
249
- health: "unavailable",
250
- message: "The live indexer daemon socket responded with an invalid or incomplete protocol exchange.",
251
- };
252
- case INDEXER_DAEMON_BACKGROUND_FOLLOW_RECOVERY_FAILED:
253
- return {
254
- health: "failed",
255
- message: "The managed indexer daemon could not recover automatic background follow.",
256
- };
257
- default:
258
- return {
259
- health: "unavailable",
260
- message,
261
- };
262
- }
263
- }
264
- function mapBitcoindStartupError(message) {
265
- switch (message) {
266
- case "managed_bitcoind_service_start_timeout":
267
- return {
268
- health: "starting",
269
- status: null,
270
- message: "Managed bitcoind service is still starting.",
271
- };
272
- case "managed_bitcoind_service_version_mismatch":
273
- return {
274
- health: "service-version-mismatch",
275
- status: null,
276
- message: "The live managed bitcoind service is running an incompatible service version.",
277
- };
278
- case "managed_bitcoind_wallet_root_mismatch":
279
- return {
280
- health: "wallet-root-mismatch",
281
- status: null,
282
- message: "The live managed bitcoind service belongs to a different wallet root.",
283
- };
284
- case "managed_bitcoind_runtime_mismatch":
285
- return {
286
- health: "runtime-mismatch",
287
- status: null,
288
- message: "The live managed bitcoind service runtime does not match this wallet's expected data directory or chain.",
289
- };
290
- case "managed_bitcoind_protocol_error":
291
- return {
292
- health: "unavailable",
293
- status: null,
294
- message: "The managed bitcoind runtime artifacts are invalid or incomplete.",
295
- };
296
- default:
297
- return {
298
- health: "unavailable",
299
- status: null,
300
- message,
301
- };
302
- }
303
- }
304
- function deriveBitcoindHealth(options) {
305
- if (options.startupError !== null) {
306
- const mapped = mapBitcoindStartupError(options.startupError);
307
- return {
308
- ...mapped,
309
- status: options.status,
310
- };
311
- }
312
- if (options.status === null) {
313
- return {
314
- health: "unavailable",
315
- status: null,
316
- message: "Managed bitcoind service is unavailable.",
317
- };
318
- }
319
- if (options.status.state === "starting") {
320
- return {
321
- health: "starting",
322
- status: options.status,
323
- message: options.status.lastError ?? "Managed bitcoind service is still starting.",
324
- };
325
- }
326
- if (options.status.state === "failed") {
327
- return {
328
- health: "failed",
329
- status: options.status,
330
- message: options.status.lastError ?? "Managed bitcoind service refresh failed.",
331
- };
332
- }
333
- const proofStatus = options.nodeStatus?.walletReplica?.proofStatus;
334
- if (proofStatus === "missing") {
335
- return {
336
- health: "replica-missing",
337
- status: options.status,
338
- message: options.nodeStatus?.walletReplicaMessage ?? "Managed Core wallet replica is missing.",
339
- };
340
- }
341
- if (proofStatus === "mismatch") {
342
- return {
343
- health: "replica-mismatch",
344
- status: options.status,
345
- message: options.nodeStatus?.walletReplicaMessage ?? "Managed Core wallet replica does not match trusted wallet state.",
346
- };
347
- }
348
- return {
349
- health: "ready",
350
- status: options.status,
351
- message: options.nodeStatus?.walletReplicaMessage ?? options.status.lastError,
352
- };
353
- }
354
- function deriveNodeHealth(status, bitcoindHealth) {
355
- if (bitcoindHealth !== "ready" || status === null || !status.ready) {
356
- return {
357
- health: "catching-up",
358
- message: NODE_CATCHING_UP_MESSAGE,
359
- };
360
- }
361
- const headerLead = status.nodeBestHeight !== null && status.nodeHeaderHeight !== null
362
- ? status.nodeHeaderHeight - status.nodeBestHeight
363
- : null;
364
- if (headerLead !== null && headerLead > 0) {
365
- if (headerLead <= TOLERATED_NODE_HEADER_LEAD_BLOCKS) {
366
- return {
367
- health: "synced",
368
- message: TOLERATED_NODE_HEADER_LEAD_MESSAGE,
369
- };
370
- }
371
- return {
372
- health: "catching-up",
373
- message: NODE_CATCHING_UP_MESSAGE,
374
- };
375
- }
376
- return {
377
- health: "synced",
378
- message: null,
379
- };
380
- }
381
- export function deriveNodeHealthForTesting(status, bitcoindHealth) {
382
- return deriveNodeHealth(status, bitcoindHealth);
383
- }
384
- function deriveIndexerHealth(options) {
385
- const daemonStatus = options.source === "lease"
386
- ? options.daemonStatus
387
- : options.observedStatus ?? options.daemonStatus;
388
- const snapshotTip = options.snapshot?.tip ?? null;
389
- const daemonInstanceId = options.snapshot?.daemonInstanceId ?? daemonStatus?.daemonInstanceId ?? null;
390
- const snapshotSeq = options.snapshot?.snapshotSeq ?? daemonStatus?.snapshotSeq ?? null;
391
- const openedAtUnixMs = options.snapshot?.openedAtUnixMs ?? null;
392
- const source = daemonStatus === null && options.snapshot === null ? "none" : options.source;
393
- const createResult = (health, message) => ({
394
- health,
395
- status: daemonStatus,
396
- message,
397
- snapshotTip,
398
- source,
399
- daemonInstanceId,
400
- snapshotSeq,
401
- openedAtUnixMs,
402
- });
403
- if (options.startupError !== null) {
404
- const mapped = mapIndexerStartupError(options.startupError);
405
- return createResult(mapped.health, mapped.message);
406
- }
407
- if (daemonStatus === null) {
408
- return createResult("unavailable", "Indexer daemon is unavailable.");
409
- }
410
- if ((options.now - daemonStatus.heartbeatAtUnixMs) > STALE_HEARTBEAT_THRESHOLD_MS) {
411
- return createResult("stale-heartbeat", "Indexer daemon heartbeat is stale.");
412
- }
413
- if (daemonStatus.state === "schema-mismatch") {
414
- return createResult("schema-mismatch", daemonStatus.lastError ?? "Indexer daemon sqlite schema is incompatible.");
415
- }
416
- if (daemonStatus.state === "failed") {
417
- return createResult("failed", daemonStatus.lastError ?? "Indexer daemon refresh failed.");
418
- }
419
- if (daemonStatus.state === "service-version-mismatch") {
420
- return createResult("service-version-mismatch", "Indexer daemon service API is incompatible.");
421
- }
422
- if (options.snapshot === null) {
423
- if (daemonStatus.state === "reorging") {
424
- return createResult("reorging", "Indexer daemon is replaying a reorg and refreshing the coherent snapshot.");
425
- }
426
- return createResult(daemonStatus.state === "catching-up" ? "catching-up" : "starting", "Indexer snapshot is not ready yet.");
427
- }
428
- if (daemonStatus.state === "catching-up") {
429
- return createResult("catching-up", "Indexer daemon is still catching up to the managed Bitcoin tip.");
430
- }
431
- if (daemonStatus.state === "reorging") {
432
- return createResult("reorging", "Indexer daemon is replaying a reorg and refreshing the coherent snapshot.");
433
- }
434
- return createResult("synced", null);
435
- }
436
- async function attachNodeStatus(options) {
437
- try {
438
- const probe = await probeManagedBitcoindService({
439
- dataDir: options.dataDir,
440
- chain: "main",
441
- startHeight: 0,
442
- walletRootId: options.walletRootId,
443
- startupTimeoutMs: options.startupTimeoutMs,
444
- });
445
- if (probe.compatibility !== "compatible" && probe.compatibility !== "unreachable") {
446
- return {
447
- handle: null,
448
- rpc: null,
449
- status: null,
450
- observedStatus: probe.status,
451
- error: probe.error,
452
- };
453
- }
454
- const genesis = await loadBundledGenesisParameters();
455
- const handle = await attachOrStartManagedBitcoindService({
456
- dataDir: options.dataDir,
457
- chain: "main",
458
- startHeight: resolveCogcoinProcessingStartHeight(genesis),
459
- walletRootId: options.walletRootId,
460
- startupTimeoutMs: options.startupTimeoutMs,
461
- });
462
- const rpc = createRpcClient(handle.rpc);
463
- const [chainInfo, serviceStatus] = await Promise.all([
464
- rpc.getBlockchainInfo(),
465
- handle.refreshServiceStatus?.(),
466
- ]);
467
- const status = {
468
- ready: true,
469
- chain: chainInfo.chain,
470
- pid: handle.pid,
471
- walletRootId: handle.walletRootId ?? null,
472
- nodeBestHeight: chainInfo.blocks,
473
- nodeBestHashHex: chainInfo.bestblockhash,
474
- nodeHeaderHeight: chainInfo.headers,
475
- serviceUpdatedAtUnixMs: serviceStatus?.updatedAtUnixMs ?? null,
476
- serviceStatus: serviceStatus ?? null,
477
- walletReplica: serviceStatus?.walletReplica ?? null,
478
- walletReplicaMessage: serviceStatus?.walletReplica?.message ?? null,
479
- };
480
- return {
481
- handle,
482
- rpc,
483
- status,
484
- observedStatus: serviceStatus ?? null,
485
- error: null,
486
- };
487
- }
488
- catch (error) {
489
- return {
490
- handle: null,
491
- rpc: null,
492
- status: null,
493
- observedStatus: null,
494
- error: error instanceof Error ? error.message : String(error),
495
- };
496
- }
497
- }
498
219
  async function readFundingSpendableSats(options) {
499
220
  if (options.state === null || options.rpc === null) {
500
221
  return null;
@@ -524,105 +245,26 @@ export async function openWalletReadContext(options) {
524
245
  paths: options.paths,
525
246
  });
526
247
  const walletRootId = localState.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID;
527
- const node = await attachNodeStatus({
248
+ const managedServices = await openManagedWalletReadServiceBundle({
528
249
  dataDir: options.dataDir,
250
+ databasePath: options.databasePath,
529
251
  walletRootId,
252
+ localState,
530
253
  startupTimeoutMs,
531
- });
532
- if (localState.state !== null && node.status !== null) {
533
- const verifiedReplica = await verifyManagedCoreWalletReplica(localState.state, options.dataDir, {
534
- nodeHandle: node.handle ?? undefined,
535
- });
536
- node.status = {
537
- ...node.status,
538
- walletReplica: verifiedReplica,
539
- walletReplicaMessage: verifiedReplica.message ?? null,
540
- };
541
- }
542
- const bitcoind = deriveBitcoindHealth({
543
- status: node.observedStatus,
544
- nodeStatus: node.status,
545
- startupError: node.error,
546
- });
547
- const nodeDerived = deriveNodeHealth(node.status, bitcoind.health);
548
- let daemonClient = null;
549
- let daemonStatus = null;
550
- let observedDaemonStatus = null;
551
- let snapshot = null;
552
- let indexerSource = "none";
553
- let daemonError = null;
554
- try {
555
- const probe = await probeIndexerDaemon({
556
- dataDir: options.dataDir,
557
- walletRootId,
558
- });
559
- if (probe.compatibility === "compatible" || probe.compatibility === "unreachable") {
560
- await probe.client?.close().catch(() => undefined);
561
- daemonClient = await attachOrStartIndexerDaemon({
562
- dataDir: options.dataDir,
563
- databasePath: options.databasePath,
564
- walletRootId,
565
- startupTimeoutMs,
566
- ensureBackgroundFollow: true,
567
- expectedBinaryVersion: expectedIndexerBinaryVersion,
568
- });
569
- }
570
- else {
571
- observedDaemonStatus = probe.status;
572
- indexerSource = probe.status === null ? "none" : "probe";
573
- daemonError = probe.error;
574
- }
575
- if (daemonClient !== null) {
576
- const lease = await readSnapshotWithRetry(daemonClient, walletRootId);
577
- daemonStatus = lease.status;
578
- observedDaemonStatus = lease.status;
579
- snapshot = {
580
- tip: lease.payload.tip,
581
- state: deserializeIndexerState(Buffer.from(lease.payload.stateBase64, "base64")),
582
- source: "lease",
583
- daemonInstanceId: lease.payload.daemonInstanceId,
584
- snapshotSeq: lease.payload.snapshotSeq,
585
- openedAtUnixMs: lease.payload.openedAtUnixMs,
586
- };
587
- indexerSource = "lease";
588
- }
589
- }
590
- catch (error) {
591
- daemonError = error instanceof Error ? error.message : String(error);
592
- if (daemonError === INDEXER_DAEMON_BACKGROUND_FOLLOW_RECOVERY_FAILED) {
593
- await daemonClient?.close().catch(() => undefined);
594
- await node.handle?.stop().catch(() => undefined);
595
- throw error;
596
- }
597
- if (observedDaemonStatus === null) {
598
- observedDaemonStatus = await readObservedIndexerDaemonStatus({
599
- dataDir: options.dataDir,
600
- walletRootId,
601
- }).catch(() => null);
602
- if (observedDaemonStatus !== null) {
603
- indexerSource = "status-file";
604
- }
605
- }
606
- }
607
- const indexer = deriveIndexerHealth({
608
- daemonStatus,
609
- observedStatus: observedDaemonStatus,
610
- snapshot,
611
- source: indexerSource,
254
+ expectedIndexerBinaryVersion,
612
255
  now,
613
- startupError: daemonError,
614
256
  });
615
257
  const fundingSpendableSats = await readFundingSpendableSats({
616
258
  state: localState.state,
617
- rpc: node.rpc,
259
+ rpc: managedServices.node.rpc,
618
260
  });
619
261
  const mining = await inspectMiningControlPlane({
620
262
  provider: options.secretProvider,
621
263
  localState,
622
- bitcoind,
623
- nodeStatus: node.status,
624
- nodeHealth: nodeDerived.health,
625
- indexer,
264
+ bitcoind: managedServices.bitcoind,
265
+ nodeStatus: managedServices.node.status,
266
+ nodeHealth: managedServices.nodeHealth,
267
+ indexer: managedServices.indexer,
626
268
  nowUnixMs: now,
627
269
  paths: options.paths,
628
270
  });
@@ -630,20 +272,19 @@ export async function openWalletReadContext(options) {
630
272
  dataDir: options.dataDir,
631
273
  databasePath: options.databasePath,
632
274
  localState,
633
- bitcoind,
634
- nodeStatus: node.status,
635
- nodeHealth: nodeDerived.health,
636
- nodeMessage: nodeDerived.message,
637
- indexer,
638
- snapshot,
275
+ bitcoind: managedServices.bitcoind,
276
+ nodeStatus: managedServices.node.status,
277
+ nodeHealth: managedServices.nodeHealth,
278
+ nodeMessage: managedServices.nodeMessage,
279
+ indexer: managedServices.indexer,
280
+ snapshot: managedServices.snapshot,
639
281
  model: localState.state === null
640
282
  ? null
641
- : createWalletReadModel(localState.state, snapshot),
283
+ : createWalletReadModel(localState.state, managedServices.snapshot),
642
284
  fundingSpendableSats,
643
285
  mining,
644
286
  async close() {
645
- await daemonClient?.close().catch(() => undefined);
646
- await node.handle?.stop().catch(() => undefined);
287
+ await managedServices.close();
647
288
  },
648
289
  };
649
290
  }
@@ -0,0 +1,33 @@
1
+ import { loadBundledGenesisParameters } from "@cogcoin/indexer";
2
+ import { attachOrStartIndexerDaemon, probeIndexerDaemon, readObservedIndexerDaemonStatus, readSnapshotWithRetry, type IndexerDaemonClient } from "../../bitcoind/indexer-daemon.js";
3
+ import type { ManagedWalletReadServiceBundle } from "../../bitcoind/managed-runtime/types.js";
4
+ import { createRpcClient } from "../../bitcoind/node.js";
5
+ import { attachOrStartManagedBitcoindService, probeManagedBitcoindService } from "../../bitcoind/service.js";
6
+ import type { ManagedBitcoindNodeHandle } from "../../bitcoind/types.js";
7
+ import { verifyManagedCoreWalletReplica } from "../lifecycle.js";
8
+ import type { WalletBitcoindStatus, WalletLocalStateStatus, WalletNodeStatus, WalletServiceHealth } from "./types.js";
9
+ type ManagedWalletReadServiceDeps = {
10
+ loadBundledGenesisParameters: typeof loadBundledGenesisParameters;
11
+ probeManagedBitcoindService: typeof probeManagedBitcoindService;
12
+ attachOrStartManagedBitcoindService: typeof attachOrStartManagedBitcoindService;
13
+ createRpcClient: typeof createRpcClient;
14
+ verifyManagedCoreWalletReplica: typeof verifyManagedCoreWalletReplica;
15
+ probeIndexerDaemon: typeof probeIndexerDaemon;
16
+ attachOrStartIndexerDaemon: typeof attachOrStartIndexerDaemon;
17
+ readSnapshotWithRetry: typeof readSnapshotWithRetry;
18
+ readObservedIndexerDaemonStatus: typeof readObservedIndexerDaemonStatus;
19
+ };
20
+ export declare function deriveNodeHealthForTesting(status: WalletNodeStatus | null, bitcoindHealth: WalletBitcoindStatus["health"]): {
21
+ health: WalletServiceHealth;
22
+ message: string | null;
23
+ };
24
+ export declare function openManagedWalletReadServiceBundle(options: {
25
+ dataDir: string;
26
+ databasePath: string;
27
+ walletRootId: string;
28
+ localState: WalletLocalStateStatus;
29
+ startupTimeoutMs: number;
30
+ expectedIndexerBinaryVersion: string | null;
31
+ now: number;
32
+ }, dependencies?: ManagedWalletReadServiceDeps): Promise<ManagedWalletReadServiceBundle<ManagedBitcoindNodeHandle, ReturnType<typeof createRpcClient>, IndexerDaemonClient>>;
33
+ export {};