@dvmkit/sdk 0.1.3-rc.7 → 0.1.4-rc.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.
@@ -125,6 +125,7 @@ var ListenChannel = class {
125
125
 
126
126
  // src/sdk/server/postgres-job-store.ts
127
127
  var JOB_MESSAGES_CHANNEL = "job_messages";
128
+ var JOB_DVM_ID = /* @__PURE__ */ Symbol("jobDvmId");
128
129
  var PostgresJobStore = class {
129
130
  pool;
130
131
  listenChannel = null;
@@ -177,6 +178,18 @@ var PostgresJobStore = class {
177
178
  ALTER TABLE jobs ADD COLUMN IF NOT EXISTS native_amount DOUBLE PRECISION;
178
179
  ALTER TABLE jobs ADD COLUMN IF NOT EXISTS native_asset TEXT;
179
180
  ALTER TABLE jobs ADD COLUMN IF NOT EXISTS cashu_flow TEXT;
181
+ -- internal-review: what the job cost the BUILDER to serve, declared by the
182
+ -- handler through ctx.cost(). NULL is "unreported", deliberately
183
+ -- distinguishable from a declared zero.
184
+ ALTER TABLE jobs ADD COLUMN IF NOT EXISTS cost_amount_micro BIGINT;
185
+ ALTER TABLE jobs ADD COLUMN IF NOT EXISTS cost_currency TEXT;
186
+ ALTER TABLE jobs ADD COLUMN IF NOT EXISTS cost_revision BIGINT;
187
+ -- Cost-only reports are queued after the terminal row lands. Keep the
188
+ -- owning DVM and the last durably-enqueued revision on that row so a
189
+ -- restarted (or sibling) process can close that crash window without
190
+ -- replaying another mount's jobs.
191
+ ALTER TABLE jobs ADD COLUMN IF NOT EXISTS dvm_id TEXT;
192
+ ALTER TABLE jobs ADD COLUMN IF NOT EXISTS cost_reported_revision BIGINT;
180
193
  ALTER TABLE jobs ADD COLUMN IF NOT EXISTS required_msats BIGINT;
181
194
  -- next_seq is intentionally absent from isolate_jobs (platform/db.ts).
182
195
  -- It powers StreamableJobStore cross-machine seq allocation; isolate
@@ -245,6 +258,10 @@ var PostgresJobStore = class {
245
258
  CREATE INDEX IF NOT EXISTS idx_jobs_retention
246
259
  ON jobs (last_activity_at, id)
247
260
  WHERE redacted_at IS NULL AND status IN ('completed', 'failed', 'cancelled');
261
+ CREATE INDEX IF NOT EXISTS idx_jobs_pending_cost_report
262
+ ON jobs (dvm_id, id)
263
+ WHERE cost_revision IS NOT NULL
264
+ AND status IN ('completed', 'failed', 'cancelled');
248
265
  -- internal-review: the idempotent-replay lookup. payment_tx_hash carries the
249
266
  -- caller's X-Cashu-Request-Id on the accumulator path, so a retried paid
250
267
  -- submit finds the job its payment already created.
@@ -413,18 +430,32 @@ var PostgresJobStore = class {
413
430
  held.client.release();
414
431
  }
415
432
  async save(record) {
433
+ await this.saveRecord(record, record[JOB_DVM_ID]);
434
+ }
435
+ /** Persist a job while retaining its mount identity for cost-report recovery. */
436
+ async saveForDvm(record, dvmId) {
437
+ const scoped = record;
438
+ scoped[JOB_DVM_ID] = dvmId;
439
+ try {
440
+ await this.save(scoped);
441
+ } finally {
442
+ delete scoped[JOB_DVM_ID];
443
+ }
444
+ }
445
+ async saveRecord(record, dvmId) {
416
446
  const { rowCount } = await this.pool.query(
417
447
  `INSERT INTO jobs (
418
448
  id, tags, capability, input, params, requester_id, status, summary,
419
449
  messages, seq, paid_msats, payment_mint, payment_rail,
420
450
  payment_tx_hash, payment_transaction_hash, native_amount, native_asset, cashu_flow,
451
+ cost_amount_micro, cost_currency, cost_revision,
421
452
  received_proofs, pending_payment_msats, pending_mpp_challenge_ids,
422
453
  pending_x402_nonce, pending_x402_amount_usdc_micro, required_msats, step_cache, state, created_at,
423
454
  last_activity_at, next_seq, requester_token_hash, requester_token,
424
455
  request_fingerprint, requester_pubkey, request_id, credit_id, draw_id,
425
456
  pending_payment_fiat_micro, pending_payment_fiat_currency, auth_request_path,
426
- funding_receipt, funding_credit
427
- ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41)
457
+ funding_receipt, funding_credit, dvm_id
458
+ ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41,$42,$43,$44,$45)
428
459
  ON CONFLICT (id) DO UPDATE SET
429
460
  status = EXCLUDED.status,
430
461
  summary = EXCLUDED.summary,
@@ -440,6 +471,29 @@ var PostgresJobStore = class {
440
471
  native_amount = EXCLUDED.native_amount,
441
472
  native_asset = EXCLUDED.native_asset,
442
473
  cashu_flow = EXCLUDED.cashu_flow,
474
+ -- Cost declarations are revisioned because a terminal snapshot can be
475
+ -- re-saved by a different machine. Never let a stale persisted prefix
476
+ -- replace the handler owner's later cumulative declaration; a higher
477
+ -- revision with NULL amount/currency is an intentional invalidation.
478
+ cost_amount_micro = CASE
479
+ WHEN EXCLUDED.cost_revision IS NOT NULL
480
+ AND (jobs.cost_revision IS NULL OR EXCLUDED.cost_revision >= jobs.cost_revision)
481
+ THEN EXCLUDED.cost_amount_micro
482
+ ELSE jobs.cost_amount_micro
483
+ END,
484
+ cost_currency = CASE
485
+ WHEN EXCLUDED.cost_revision IS NOT NULL
486
+ AND (jobs.cost_revision IS NULL OR EXCLUDED.cost_revision >= jobs.cost_revision)
487
+ THEN EXCLUDED.cost_currency
488
+ ELSE jobs.cost_currency
489
+ END,
490
+ cost_revision = CASE
491
+ WHEN EXCLUDED.cost_revision IS NOT NULL
492
+ AND (jobs.cost_revision IS NULL OR EXCLUDED.cost_revision >= jobs.cost_revision)
493
+ THEN EXCLUDED.cost_revision
494
+ ELSE jobs.cost_revision
495
+ END,
496
+ dvm_id = COALESCE(jobs.dvm_id, EXCLUDED.dvm_id),
443
497
  received_proofs = EXCLUDED.received_proofs,
444
498
  pending_mpp_challenge_ids = EXCLUDED.pending_mpp_challenge_ids,
445
499
  pending_x402_nonce = EXCLUDED.pending_x402_nonce,
@@ -478,6 +532,9 @@ var PostgresJobStore = class {
478
532
  record.nativeAmount ?? null,
479
533
  record.nativeAsset ?? null,
480
534
  record.cashuFlow ?? null,
535
+ record.costAmountMicro ?? null,
536
+ record.costCurrency ?? null,
537
+ record.costRevision ?? null,
481
538
  JSON.stringify(record.receivedProofs),
482
539
  record.pendingPaymentMsats ?? null,
483
540
  record.pendingMppChallengeIds ? JSON.stringify(record.pendingMppChallengeIds) : null,
@@ -513,7 +570,8 @@ var PostgresJobStore = class {
513
570
  // whose live gate accepted this proof.
514
571
  record.authRequestPath ?? null,
515
572
  record.fundingReceipt ? JSON.stringify(record.fundingReceipt) : null,
516
- record.fundingCredit ? JSON.stringify(record.fundingCredit) : null
573
+ record.fundingCredit ? JSON.stringify(record.fundingCredit) : null,
574
+ dvmId ?? null
517
575
  ]
518
576
  );
519
577
  if (rowCount === 0) {
@@ -530,6 +588,38 @@ var PostgresJobStore = class {
530
588
  await this.pool.query("DELETE FROM job_messages WHERE job_id = $1", [record.id]).catch(() => void 0);
531
589
  }
532
590
  }
591
+ /**
592
+ * Read terminal zero-revenue jobs whose latest declared-cost revision has
593
+ * not yet reached the durable reporter outbox.
594
+ */
595
+ async listUnreportedTerminalCosts(args) {
596
+ const { rows } = await this.pool.query(
597
+ `SELECT *
598
+ FROM jobs
599
+ WHERE dvm_id = $1
600
+ AND cost_revision IS NOT NULL
601
+ AND (cost_reported_revision IS NULL OR cost_reported_revision < cost_revision)
602
+ AND (
603
+ status IN ('failed', 'cancelled')
604
+ OR (status = 'completed' AND paid_msats = 0)
605
+ )
606
+ AND ($2::text IS NULL OR id > $2)
607
+ ORDER BY id
608
+ LIMIT $3`,
609
+ [args.dvmId, args.afterJobId ?? null, args.limit]
610
+ );
611
+ return rows.map(rowToRecord);
612
+ }
613
+ /** Mark one revision only after its report has reached durable enqueue. */
614
+ async markTerminalCostReported(jobId, costRevision) {
615
+ const { rowCount } = await this.pool.query(
616
+ `UPDATE jobs
617
+ SET cost_reported_revision = GREATEST(COALESCE(cost_reported_revision, -1), $2)
618
+ WHERE id = $1 AND cost_revision = $2`,
619
+ [jobId, costRevision]
620
+ );
621
+ return rowCount === 1;
622
+ }
533
623
  async delete(id) {
534
624
  await this.pool.query("DELETE FROM jobs WHERE id = $1", [id]);
535
625
  await this.pool.query("DELETE FROM job_messages WHERE job_id = $1", [id]).catch(() => void 0);
@@ -1203,6 +1293,9 @@ function rowToRecord(row) {
1203
1293
  nativeAmount: row.native_amount,
1204
1294
  nativeAsset: row.native_asset,
1205
1295
  cashuFlow: row.cashu_flow,
1296
+ costAmountMicro: row.cost_amount_micro == null ? void 0 : Number(row.cost_amount_micro),
1297
+ costCurrency: row.cost_currency ?? void 0,
1298
+ costRevision: row.cost_revision == null ? void 0 : Number(row.cost_revision),
1206
1299
  creditId: row.credit_id ?? void 0,
1207
1300
  drawId: row.draw_id ?? void 0,
1208
1301
  fundingReceipt: row.funding_receipt ?? void 0,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  StepCache,
3
3
  loggers
4
- } from "./chunk-YDIYXGYL.js";
4
+ } from "./chunk-E4EVGPDX.js";
5
5
  import {
6
6
  redactUrl
7
7
  } from "./chunk-FUJ36YDV.js";
@@ -33,6 +33,9 @@ function toJobRecord(job) {
33
33
  nativeAmount: job.nativeAmount,
34
34
  nativeAsset: job.nativeAsset,
35
35
  cashuFlow: job.cashuFlow,
36
+ costAmountMicro: job.costAmountMicro,
37
+ costCurrency: job.costCurrency,
38
+ costRevision: job.costRevision,
36
39
  creditId: job.creditId,
37
40
  drawId: job.drawId,
38
41
  fundingReceipt: job.fundingReceipt,
@@ -76,6 +79,9 @@ function fromJobRecord(record) {
76
79
  nativeAmount: record.nativeAmount,
77
80
  nativeAsset: record.nativeAsset,
78
81
  cashuFlow: record.cashuFlow,
82
+ costAmountMicro: record.costAmountMicro,
83
+ costCurrency: record.costCurrency,
84
+ costRevision: record.costRevision,
79
85
  creditId: record.creditId,
80
86
  drawId: record.drawId,
81
87
  fundingReceipt: record.fundingReceipt,
@@ -162,7 +162,7 @@ var LOCK_FILE = `${WALLET_FILE}.lock`;
162
162
  var DEFAULT_LOCK_STALE_MS = 3e4;
163
163
  var DEFAULT_LOCK_RETRIES = 30;
164
164
  var DEFAULT_LOCK_RETRY_INTERVAL_MS = 1e3;
165
- var WALLET_VERSION = 8;
165
+ var WALLET_VERSION = 9;
166
166
  var RECENT_SPENDS_CAP = 10;
167
167
  var DEFAULT_AGENT_MINT_URL = "https://mint.coinos.io";
168
168
  function loadAgentWallet() {
@@ -187,37 +187,54 @@ function loadAgentWallet() {
187
187
  }
188
188
  const version = parsed.version;
189
189
  if (version === 1) {
190
- return migrateV7ToV8(
191
- migrateV6ToV7(migrateV5ToV6(migrateV4ToV5(migrateV1ToV4(parsed))))
190
+ return migrateV8ToV9(
191
+ migrateV7ToV8(
192
+ migrateV6ToV7(
193
+ migrateV5ToV6(migrateV4ToV5(migrateV1ToV4(parsed)))
194
+ )
195
+ )
192
196
  );
193
197
  }
194
198
  if (version === 2) {
195
- return migrateV7ToV8(
196
- migrateV6ToV7(
197
- migrateV5ToV6(
198
- migrateV4ToV5(migrateV3ToV4(migrateV2ToV3(parsed)))
199
+ return migrateV8ToV9(
200
+ migrateV7ToV8(
201
+ migrateV6ToV7(
202
+ migrateV5ToV6(
203
+ migrateV4ToV5(migrateV3ToV4(migrateV2ToV3(parsed)))
204
+ )
199
205
  )
200
206
  )
201
207
  );
202
208
  }
203
209
  if (version === 3) {
204
- return migrateV7ToV8(
205
- migrateV6ToV7(migrateV5ToV6(migrateV4ToV5(migrateV3ToV4(parsed))))
210
+ return migrateV8ToV9(
211
+ migrateV7ToV8(
212
+ migrateV6ToV7(
213
+ migrateV5ToV6(migrateV4ToV5(migrateV3ToV4(parsed)))
214
+ )
215
+ )
206
216
  );
207
217
  }
208
218
  if (version === 4) {
209
- return migrateV7ToV8(
210
- migrateV6ToV7(migrateV5ToV6(migrateV4ToV5(parsed)))
219
+ return migrateV8ToV9(
220
+ migrateV7ToV8(
221
+ migrateV6ToV7(migrateV5ToV6(migrateV4ToV5(parsed)))
222
+ )
211
223
  );
212
224
  }
213
225
  if (version === 5) {
214
- return migrateV7ToV8(migrateV6ToV7(migrateV5ToV6(parsed)));
226
+ return migrateV8ToV9(
227
+ migrateV7ToV8(migrateV6ToV7(migrateV5ToV6(parsed)))
228
+ );
215
229
  }
216
230
  if (version === 6) {
217
- return migrateV7ToV8(migrateV6ToV7(parsed));
231
+ return migrateV8ToV9(migrateV7ToV8(migrateV6ToV7(parsed)));
218
232
  }
219
233
  if (version === 7) {
220
- return migrateV7ToV8(parsed);
234
+ return migrateV8ToV9(migrateV7ToV8(parsed));
235
+ }
236
+ if (version === 8) {
237
+ return migrateV8ToV9(parsed);
221
238
  }
222
239
  if (version !== WALLET_VERSION) {
223
240
  throw new DvmError(
@@ -366,6 +383,22 @@ function migrateV6ToV7(parsed) {
366
383
  };
367
384
  }
368
385
  function migrateV7ToV8(parsed) {
386
+ return {
387
+ version: 8,
388
+ lock_privkey: String(parsed.lock_privkey),
389
+ lock_pubkey: String(parsed.lock_pubkey),
390
+ mnemonic_fingerprint: typeof parsed.mnemonic_fingerprint === "string" ? parsed.mnemonic_fingerprint : null,
391
+ mints: Array.isArray(parsed.mints) ? parsed.mints : [],
392
+ proofs: Array.isArray(parsed.proofs) ? parsed.proofs : [],
393
+ nut13_counters: isCounterMap(parsed.nut13_counters) ? parsed.nut13_counters : {},
394
+ pending_mints: Array.isArray(parsed.pending_mints) ? parsed.pending_mints : [],
395
+ pending_melts: Array.isArray(parsed.pending_melts) ? parsed.pending_melts : [],
396
+ pending_submissions: Array.isArray(parsed.pending_submissions) ? parsed.pending_submissions : [],
397
+ recent_spends: Array.isArray(parsed.recent_spends) ? parsed.recent_spends : [],
398
+ created_at: typeof parsed.created_at === "string" ? parsed.created_at : (/* @__PURE__ */ new Date()).toISOString()
399
+ };
400
+ }
401
+ function migrateV8ToV9(parsed) {
369
402
  return {
370
403
  version: WALLET_VERSION,
371
404
  lock_privkey: String(parsed.lock_privkey),
@@ -1,9 +1,9 @@
1
1
  import { Hono, Context } from 'hono';
2
2
  import { Pool } from 'pg';
3
- import { a0 as Message, ag as FundingMethod, W as FundingReceipt, bN as CreditSnapshot, X as JobReceipt, S as SDKJobContext, av as StepCache, u as ResponseContent, P as PaymentContent, a1 as MessageType, bi as X402Receipt, aD as X402Config, bh as X402ExactVersionSupport, cQ as X402SettlementIntent, ap as PaymentRequirementsV2, c0 as CreditLedgerQuerier, cR as X402SettlementCursor, bP as X402SettlementStatus, cS as X402SettlementWriteOff, bM as X402RefundSettlementGate, cT as X402FacilitatorAuth, cU as X402BatchSettlementConfig, cw as PostgresX402ChannelStorage, cV as X402PayoutObserver, bq as MppxServer, aa as CashuMode, bL as CreditLedgerLike, cW as CreditDepositEnqueue, cX as X402SettlementReconciliationReason, an as PaymentRequirements, $ as MppxCredential, o as PaymentMethod, bl as CreditDepositPayload, bO as DrawResult, cm as CreditLedgerError, a5 as ReceiptCredit, ad as DrainReceiptEvent, ac as DrainReceipt, K as KVStore, y as SignedRequestAudience, cY as CreditDrawReleaseEnqueue, cy as RevenueSkippedNoRailPayload, Z as ZodLike, a as DVMDescriptor, bU as CreditInvoiceRecord, bV as InvoiceSettlement, cg as ClientCompatibilityGate, ce as ClientCompatibility, bt as PayoutReporter, R as ResolvedCreditConfig, g as CreditView } from './step-cache-3cT4Shk0.js';
4
- import { b as FxRateSnapshot, F as FxFetcher } from './fx-BF_SG2i0.js';
5
- import { g as LockPubkey, f as CheckMintHealthOptions, b as LightningBackend, A as AttestationPayload } from './lightning-backend-C04nH94l.js';
6
- import { T as TopUpCapUnenforcedReason, A as AppendOutgoingOptions, J as JobRecord, b as JobStore } from './job-store-Bn23V3QU.js';
3
+ import { a1 as Message, ah as FundingMethod, X as FundingReceipt, bO as CreditSnapshot, Y as JobReceipt, S as SDKJobContext, aw as StepCache, u as ResponseContent, P as PaymentContent, a2 as MessageType, bj as X402Receipt, aE as X402Config, bi as X402ExactVersionSupport, cS as X402SettlementIntent, aq as PaymentRequirementsV2, c1 as CreditLedgerQuerier, cT as X402SettlementCursor, bQ as X402SettlementStatus, cU as X402SettlementWriteOff, bN as X402RefundSettlementGate, cV as X402FacilitatorAuth, cW as X402BatchSettlementConfig, cy as PostgresX402ChannelStorage, cX as X402PayoutObserver, br as MppxServer, ab as CashuMode, bM as CreditLedgerLike, cY as CreditDepositEnqueue, cZ as X402SettlementReconciliationReason, ao as PaymentRequirements, a0 as MppxCredential, o as PaymentMethod, bm as CreditDepositPayload, bP as DrawResult, cn as CreditLedgerError, a6 as ReceiptCredit, ae as DrainReceiptEvent, ad as DrainReceipt, K as KVStore, y as SignedRequestAudience, c_ as CreditDrawReleaseEnqueue, cx as JobCostReportPayload, cA as RevenueSkippedNoRailPayload, Z as ZodLike, a as DVMDescriptor, bV as CreditInvoiceRecord, bW as InvoiceSettlement, ch as ClientCompatibilityGate, cf as ClientCompatibility, bu as PayoutReporter, R as ResolvedCreditConfig, g as CreditView } from './step-cache-BLPZNizw.js';
4
+ import { b as FxRateSnapshot, F as FxFetcher } from './fx-C6dl2LVI.js';
5
+ import { g as LockPubkey, f as CheckMintHealthOptions, b as LightningBackend, A as AttestationPayload } from './lightning-backend-Ci1nogk_.js';
6
+ import { T as TopUpCapUnenforcedReason, A as AppendOutgoingOptions, J as JobRecord, b as JobStore } from './job-store-DHnW4Cg_.js';
7
7
  import { ProofLike, SerializedDLEQ } from '@cashu/cashu-ts';
8
8
  import { Challenge } from 'mppx';
9
9
  import { SettleResponse, SupportedResponse } from '@x402/core/types';
@@ -239,6 +239,25 @@ interface ServerJob {
239
239
  nativeAsset?: "sats" | "usdc" | "usdc.e" | "usd-cents";
240
240
  /** Cashu flow discriminator written into `revenue_events.metadata.cashu_flow` (internal-review). */
241
241
  cashuFlow?: "p2pk_accumulator";
242
+ /**
243
+ * What this job cost the **builder** to serve, in 1e-6 of
244
+ * {@link ServerJob.costCurrency} — the running total the handler declared
245
+ * through `ctx.cost()` (internal-review). Absent until a handler declares
246
+ * something; absent is "unreported", which is not the same fact as a
247
+ * declared zero and is reported differently.
248
+ *
249
+ * Persisted on the row rather than held in the context because the report
250
+ * has to survive a crash between the job finishing and the report landing:
251
+ * the terminal funnel writes this row before it books, and Postgres cost
252
+ * reconciliation retries any revision whose durable-enqueue marker still
253
+ * lags. Never netted against `paidMsats` or the draw — the builder's cost
254
+ * and the caller's payment are two questions.
255
+ */
256
+ costAmountMicro?: number;
257
+ /** Currency {@link ServerJob.costAmountMicro} is 1e-6 of (lowercase ISO-4217). */
258
+ costCurrency?: string;
259
+ /** Number of `ctx.cost()` declarations incorporated into the current cost state. */
260
+ costRevision?: number;
242
261
  /** Credit the upfront payment funded/drew (internal-review). See `JobRecord.creditId`. */
243
262
  creditId?: string;
244
263
  /** The draw placed for this job on `creditId` (internal-review). */
@@ -2702,6 +2721,8 @@ interface JobManagerOpts {
2702
2721
  onJobCompleted?: (info: {
2703
2722
  dvmId: string;
2704
2723
  jobId: string;
2724
+ /** Dispatched capability. Omitted only for legacy persisted jobs that predate dispatch. */
2725
+ capability?: string;
2705
2726
  paidMsats: number;
2706
2727
  paymentMint?: string;
2707
2728
  rail: string;
@@ -2709,6 +2730,10 @@ interface JobManagerOpts {
2709
2730
  nativeAmount?: number;
2710
2731
  nativeAsset?: string;
2711
2732
  cashuFlow?: string;
2733
+ cost?: {
2734
+ amountMicro: number;
2735
+ currency: string;
2736
+ };
2712
2737
  creditId?: string;
2713
2738
  drawId?: string;
2714
2739
  drawAmountMicro?: number;
@@ -2717,6 +2742,13 @@ interface JobManagerOpts {
2717
2742
  fundingRef?: string;
2718
2743
  kind?: string;
2719
2744
  }) => void | Promise<void>;
2745
+ /**
2746
+ * Callback fired when a terminal job declared a builder cost but emitted no
2747
+ * revenue report (internal-review). Container-runtime DVMs use the reporter's
2748
+ * durable `job-cost` outbox path. The receiver de-duplicates by DVM + job,
2749
+ * independently of the rail-keyed revenue ledger.
2750
+ */
2751
+ onJobCost?: (info: JobCostReportPayload) => void | Promise<void>;
2720
2752
  /**
2721
2753
  * Callback fired when the stale-job reaper force-fails a *paid* job — its
2722
2754
  * pending credit draw is released rather than settled, because only a
@@ -2895,6 +2927,8 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
2895
2927
  private readonly jobStore;
2896
2928
  private readonly idleTimers;
2897
2929
  private readonly cleanupTimers;
2930
+ /** Cost revisions held only by a terminal handler owner until its durable merge succeeds. */
2931
+ private readonly terminalCostHandoffRetryTimers;
2898
2932
  /** Per-job NOTIFY unsubscribe handles for the durable-status watch (internal-review). */
2899
2933
  private readonly statusWatchers;
2900
2934
  /** Job ids whose durable-status re-read is in flight — coalesces notify storms (internal-review). */
@@ -2918,6 +2952,7 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
2918
2952
  private staleSweepTimer?;
2919
2953
  private heartbeatTimer?;
2920
2954
  private orphanDrawSweepTimer?;
2955
+ private terminalCostRecoveryTimer?;
2921
2956
  private jobRetentionSweepTimer?;
2922
2957
  private jobRetentionBootTimer?;
2923
2958
  /** This manager holds {@link ORPHAN_SWEEP_CLAIMS} for its ledger. */
@@ -2935,6 +2970,8 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
2935
2970
  private readonly monotonicNowMs;
2936
2971
  private sweepInFlight;
2937
2972
  private orphanSweepInFlight;
2973
+ private terminalCostRecoveryInFlight;
2974
+ private terminalCostRecoveryResumeAfter?;
2938
2975
  private jobRetentionSweepInFlight;
2939
2976
  private heartbeatInFlight;
2940
2977
  /**
@@ -3086,6 +3123,16 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3086
3123
  * stores' terminal-sticky `save`, which keeps the row itself correct).
3087
3124
  */
3088
3125
  private adoptDurableTerminal;
3126
+ /**
3127
+ * Persist an adopted terminal cost, retaining the in-memory revision for a
3128
+ * later retry when the durable store is transiently unavailable.
3129
+ */
3130
+ private tryPersistAdoptedTerminalCost;
3131
+ /** Retry outside the status watcher, which correctly stops once the job is terminal. */
3132
+ private scheduleTerminalCostHandoffRetry;
3133
+ private retryTerminalCostHandoff;
3134
+ /** Durably merge a terminal handler owner's latest cost before reporting it. */
3135
+ private persistAdoptedTerminalCost;
3089
3136
  /**
3090
3137
  * Watch the durable status of a locally-active job (internal-review).
3091
3138
  *
@@ -3645,8 +3692,27 @@ declare class JobManager<State, InputSchema extends ZodLike | undefined> {
3645
3692
  * from whatever the caller happened to have in hand.
3646
3693
  */
3647
3694
  issueReceiptForStoredJob(jobId: string): Promise<JobReceipt | undefined>;
3695
+ /**
3696
+ * Finish accounting for a terminal written directly to the store — the
3697
+ * stale reaper and a cancel handled on a different machine (internal-review).
3698
+ */
3699
+ finalizeStoredTerminal(jobId: string): Promise<JobReceipt | undefined>;
3648
3700
  /** Handle job reaching terminal state (completed, failed, cancelled). */
3649
3701
  private handleJobTerminal;
3702
+ /**
3703
+ * Re-enqueue terminal cost-only rows left between the job commit and outbox
3704
+ * insert. The marker advances only after `onJobCost` resolves, which for the
3705
+ * SDK reporter means the local durable insert has committed; a crash after
3706
+ * that insert but before the marker can duplicate a payload, but the
3707
+ * revisioned platform contract makes that replay harmless.
3708
+ */
3709
+ recoverTerminalCosts(): Promise<{
3710
+ examined: number;
3711
+ queued: number;
3712
+ complete: boolean;
3713
+ }>;
3714
+ /** Report the latest declared-cost state only when no revenue event carried it. */
3715
+ private reportJobCost;
3650
3716
  /**
3651
3717
  * Report a completed paid job's revenue (internal-review, re-keyed by internal-review).
3652
3718
  * Fire-and-forget — the `RevenueReporter` owns persistence and retry.
@@ -4435,6 +4501,12 @@ interface SDKServerOpts {
4435
4501
  * tests and advanced integrations only.
4436
4502
  */
4437
4503
  onJobCompleted?: JobManagerOpts["onJobCompleted"];
4504
+ /**
4505
+ * Advanced override for a declared cost on a terminal job that emitted no
4506
+ * revenue report (internal-review). Auto-wired to the reporter's durable
4507
+ * job-cost path; intended for tests and advanced integrations only.
4508
+ */
4509
+ onJobCost?: JobManagerOpts["onJobCost"];
4438
4510
  /**
4439
4511
  * Advanced override: callback fired when the stale-job reaper force-fails a
4440
4512
  * *paid* job (internal-review). Auto-wired to the `RevenueReporter`'s paid-job-death
@@ -1,4 +1,4 @@
1
- import { C as Currency } from './step-cache-3cT4Shk0.js';
1
+ import { C as Currency } from './step-cache-BLPZNizw.js';
2
2
 
3
3
  /**
4
4
  * Quote-time fx snapshot. Embedded in scribe's `lockedQuote` for within-job
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { C as Currency, Z as ZodLike, D as DVMConfig, a as DVMDescriptor } from './step-cache-3cT4Shk0.js';
2
- export { A as ApprovalContent, b as ArtifactContent, c as CancelContent, d as CanonicalEnvelope, e as CreateSignedRequestVerifierOpts, f as CreditConfig, g as CreditView, h as DEFAULT_CREDIT_MAX, i as DEFAULT_CREDIT_MIN, j as DEFAULT_CREDIT_TTL_SECONDS, k as DEFAULT_JOB_RETENTION_DAYS, l as DVMRouteContext, I as IncomingMessage, m as InputType, n as InvalidCurrencyError, K as KVStore, L as Logger, P as PaymentContent, o as PaymentMethod, p as PriceValue, q as ProgressContent, r as PromptOpts, Q as QuoteConfig, s as QuoteContext, t as QuoteResult, R as ResolvedCreditConfig, u as ResponseContent, S as SDKJobContext, v as SDKPaymentRequestOpts, w as SIGNED_REQUEST_AUTH_ID, x as SIGNED_REQUEST_STATEMENT_VERSION, y as SignedRequestAudience, z as SignedRequestDomain, B as SignedRequestError, E as SignedRequestFailure, F as SignedRequestReplayStore, G as SignedRequestSignOpts, H as SignedRequestStatementHeader, J as SignedRequestVerifier, U as UnsupportedCurrencyError, M as createSignedRequestVerifier, N as isZodSchema, O as signedRequestStatementHeader, T as validateCurrency } from './step-cache-3cT4Shk0.js';
3
- export { C as CreateFxFetcherOpts, D as DEFAULT_FX_CURRENCIES, a as DEFAULT_FX_RATE_SOURCE, F as FxFetcher, b as FxRateSnapshot, c as FxRateUnavailableError, P as PlatformFxSource, d as createFxFetcher, f as fxRateFor, r as resolveFxSourceFromEnv } from './fx-BF_SG2i0.js';
4
- export { I as InvalidFxRateError, f as fiatToSatsCeil, a as formatFiat, b as formatUsd, r as roundUsd, s as satsToFiat } from './usd-BnuXoFl5.js';
5
- export { J as JobRecord, a as JobStatus, b as JobStore } from './job-store-Bn23V3QU.js';
1
+ import { C as Currency, Z as ZodLike, D as DVMConfig, a as DVMDescriptor } from './step-cache-BLPZNizw.js';
2
+ export { A as ApprovalContent, b as ArtifactContent, c as CancelContent, d as CanonicalEnvelope, e as CreateSignedRequestVerifierOpts, f as CreditConfig, g as CreditView, h as DEFAULT_CREDIT_MAX, i as DEFAULT_CREDIT_MIN, j as DEFAULT_CREDIT_TTL_SECONDS, k as DEFAULT_JOB_RETENTION_DAYS, l as DVMRouteContext, I as IncomingMessage, m as InputType, n as InvalidCurrencyError, J as JobCost, K as KVStore, L as Logger, P as PaymentContent, o as PaymentMethod, p as PriceValue, q as ProgressContent, r as PromptOpts, Q as QuoteConfig, s as QuoteContext, t as QuoteResult, R as ResolvedCreditConfig, u as ResponseContent, S as SDKJobContext, v as SDKPaymentRequestOpts, w as SIGNED_REQUEST_AUTH_ID, x as SIGNED_REQUEST_STATEMENT_VERSION, y as SignedRequestAudience, z as SignedRequestDomain, B as SignedRequestError, E as SignedRequestFailure, F as SignedRequestReplayStore, G as SignedRequestSignOpts, H as SignedRequestStatementHeader, M as SignedRequestVerifier, U as UnsupportedCurrencyError, N as createSignedRequestVerifier, O as isZodSchema, T as signedRequestStatementHeader, V as validateCurrency } from './step-cache-BLPZNizw.js';
3
+ export { C as CreateFxFetcherOpts, D as DEFAULT_FX_CURRENCIES, a as DEFAULT_FX_RATE_SOURCE, F as FxFetcher, b as FxRateSnapshot, c as FxRateUnavailableError, P as PlatformFxSource, d as createFxFetcher, f as fxRateFor, r as resolveFxSourceFromEnv } from './fx-C6dl2LVI.js';
4
+ export { I as InvalidFxRateError, f as fiatToSatsCeil, a as formatFiat, b as formatUsd, r as roundUsd, s as satsToFiat } from './usd-BgOfZlk6.js';
5
+ export { J as JobRecord, a as JobStatus, b as JobStore } from './job-store-DHnW4Cg_.js';
6
6
  export { P as PinnedFetch, S as SSRFError, a as SSRFGuardOpts, b as SSRFReason, c as SSRFResolver, d as assertSafeUrl, e as createPinnedFetch } from './ssrf-DbFkpDv0.js';
7
7
  export { z } from 'zod';
8
8
  import 'hono';
@@ -1,16 +1,16 @@
1
- import { L as LightningTransactionListOptions, a as LightningTransactionSnapshot, b as LightningBackend, c as LightningPayment, d as LightningWalletInfo, C as CreatedInvoice, I as InvoiceStatus, M as MintAmountBounds, e as MintHealthCheckResult } from '../lightning-backend-C04nH94l.js';
2
- export { A as AttestationPayload, B as BuilderIdentityKeypair, f as CheckMintHealthOptions, g as LockPubkey, h as amountBoundsVerdict, i as assertNutSupport, j as buildAttestation, k as canSwap, l as checkMintHealth, m as generateIdentity, n as hashCapabilities, o as loadIdentitySecret, s as signAttestation, t as toLockPubkey, v as verifyAttestation, w as writeIdentity } from '../lightning-backend-C04nH94l.js';
1
+ import { L as LightningTransactionListOptions, a as LightningTransactionSnapshot, b as LightningBackend, c as LightningPayment, d as LightningWalletInfo, C as CreatedInvoice, I as InvoiceStatus, M as MintAmountBounds, e as MintHealthCheckResult } from '../lightning-backend-Ci1nogk_.js';
2
+ export { A as AttestationPayload, B as BuilderIdentityKeypair, f as CheckMintHealthOptions, g as LockPubkey, h as amountBoundsVerdict, i as assertNutSupport, j as buildAttestation, k as canSwap, l as checkMintHealth, m as generateIdentity, n as hashCapabilities, o as loadIdentitySecret, s as signAttestation, t as toLockPubkey, v as verifyAttestation, w as writeIdentity } from '../lightning-backend-Ci1nogk_.js';
3
3
  import { ProofLike, MeltQuoteBolt11Response, Proof, Wallet, SerializedDLEQ, MintQuoteBolt11Response, MintQuoteState, MintPreview, OutputDataLike, CounterSource, CounterRange } from '@cashu/cashu-ts';
4
4
  export { g as getWallet } from '../wallet-CJC8lwxx.js';
5
- import { V as JsonValue, z as SignedRequestDomain, H as SignedRequestStatementHeader, W as FundingReceipt, X as JobReceipt$1, y as SignedRequestAudience, Y as PaymentRequired, _ as X402Version, $ as MppxCredential, a0 as Message, a1 as MessageType, a2 as MppxChallenge, a3 as X402_BATCH_SETTLEMENT_SCHEME, a4 as X402_EXACT_SCHEME, a5 as ReceiptCredit, C as Currency, a6 as X402Wallet, L as Logger$1, K as KVStore, a7 as ResourceInfo } from '../step-cache-3cT4Shk0.js';
6
- export { a8 as BuildPaymentRequirementsOpts, a9 as CapabilityDescriptor, aa as CashuMode, ab as CompleteContent, ac as DrainReceipt, ad as DrainReceiptEvent, ae as ExactEvmPayload, af as ExactEvmPayloadAuthorization, ag as FundingMethod, ah as MessageFrom, ai as PaymentPayload, aj as PaymentPayloadV1, ak as PaymentPayloadV2, al as PaymentRequestContent, am as PaymentRequiredV2, an as PaymentRequirements, ao as PaymentRequirementsV1, ap as PaymentRequirementsV2, aq as PromptContent, ar as RAIL_REFUNDABLE, as as ReceiptOutcome, at as ReceiptPayment, au as SettleResponse, av as StepCache, aw as StepRecord, ax as TextContent, ay as UnsignedDrainReceipt, az as UnsignedFundingReceipt, aA as UnsignedJobReceipt, aB as VerifyResponse, aC as WorkingContent, aD as X402Config, aE as X402ResponseBody, aF as X402SelfRelayRpcFailureReason, aG as X402_DEFAULT_NETWORK, aH as X402_V1_VERSION, aI as X402_VERSION, aJ as buildPaymentRequiredV2, aK as buildPaymentRequirements, aL as caip2ToX402Network, aM as canonicalRequestPath, aN as canonicaliseForSigning, aO as canonicalize, aP as chainIdFromCaip2, aQ as computeResultHash, aR as decodePayment, aS as decodePaymentRequiredHeader, aT as encodePayment, aU as encodePaymentRequiredHeader, aV as encodeSettleResponseHeader, aW as exactEvmAuthorization, aX as isArtifactMessage, aY as isCancelMessage, aZ as isCompleteMessage, a_ as isDrainReceipt, a$ as isFundingReceipt, b0 as isPaymentRequestMessage, b1 as isPromptMessage, b2 as isSignedJobReceipt, b3 as isTextMessage, b4 as isWorkingMessage, b5 as paymentRequiredV2FromV1, b6 as signDrainReceipt, b7 as signFundingReceipt, b8 as signReceipt, b9 as usdcContractByCaip2, ba as usdcContractFor, bb as usdcDomainNameFor, bc as usdcDomainVersionFor, bd as verifyDrainReceipt, be as verifyFundingReceipt, bf as verifyReceipt, bg as x402NetworkToCaip2 } from '../step-cache-3cT4Shk0.js';
5
+ import { W as JsonValue, z as SignedRequestDomain, H as SignedRequestStatementHeader, X as FundingReceipt, Y as JobReceipt$1, y as SignedRequestAudience, _ as PaymentRequired, $ as X402Version, a0 as MppxCredential, a1 as Message, a2 as MessageType, a3 as MppxChallenge, a4 as X402_BATCH_SETTLEMENT_SCHEME, a5 as X402_EXACT_SCHEME, a6 as ReceiptCredit, C as Currency, a7 as X402Wallet, L as Logger$1, K as KVStore, a8 as ResourceInfo } from '../step-cache-BLPZNizw.js';
6
+ export { a9 as BuildPaymentRequirementsOpts, aa as CapabilityDescriptor, ab as CashuMode, ac as CompleteContent, ad as DrainReceipt, ae as DrainReceiptEvent, af as ExactEvmPayload, ag as ExactEvmPayloadAuthorization, ah as FundingMethod, ai as MessageFrom, aj as PaymentPayload, ak as PaymentPayloadV1, al as PaymentPayloadV2, am as PaymentRequestContent, an as PaymentRequiredV2, ao as PaymentRequirements, ap as PaymentRequirementsV1, aq as PaymentRequirementsV2, ar as PromptContent, as as RAIL_REFUNDABLE, at as ReceiptOutcome, au as ReceiptPayment, av as SettleResponse, aw as StepCache, ax as StepRecord, ay as TextContent, az as UnsignedDrainReceipt, aA as UnsignedFundingReceipt, aB as UnsignedJobReceipt, aC as VerifyResponse, aD as WorkingContent, aE as X402Config, aF as X402ResponseBody, aG as X402SelfRelayRpcFailureReason, aH as X402_DEFAULT_NETWORK, aI as X402_V1_VERSION, aJ as X402_VERSION, aK as buildPaymentRequiredV2, aL as buildPaymentRequirements, aM as caip2ToX402Network, aN as canonicalRequestPath, aO as canonicaliseForSigning, aP as canonicalize, aQ as chainIdFromCaip2, aR as computeResultHash, aS as decodePayment, aT as decodePaymentRequiredHeader, aU as encodePayment, aV as encodePaymentRequiredHeader, aW as encodeSettleResponseHeader, aX as exactEvmAuthorization, aY as isArtifactMessage, aZ as isCancelMessage, a_ as isCompleteMessage, a$ as isDrainReceipt, b0 as isFundingReceipt, b1 as isPaymentRequestMessage, b2 as isPromptMessage, b3 as isSignedJobReceipt, b4 as isTextMessage, b5 as isWorkingMessage, b6 as paymentRequiredV2FromV1, b7 as signDrainReceipt, b8 as signFundingReceipt, b9 as signReceipt, ba as usdcContractByCaip2, bb as usdcContractFor, bc as usdcDomainNameFor, bd as usdcDomainVersionFor, be as verifyDrainReceipt, bf as verifyFundingReceipt, bg as verifyReceipt, bh as x402NetworkToCaip2 } from '../step-cache-BLPZNizw.js';
7
7
  import { SimplePool } from 'nostr-tools/pool';
8
8
  import { Session } from 'mppx/tempo';
9
9
  import { Pool } from 'pg';
10
10
  import { PaymentRequired as PaymentRequired$1 } from '@x402/core/types';
11
11
  import { ClientChannelStorage, BatchSettlementClientContext, BatchSettlementEvmScheme } from '@x402/evm/batch-settlement/client';
12
- export { e as FX_CACHE_TTL_MS, g as FX_RETRY_COUNT, w as warmFxSnapshot } from '../fx-BF_SG2i0.js';
13
- export { c as InvalidUsdPriceError, p as parseUsdPrice } from '../usd-BnuXoFl5.js';
12
+ export { e as FX_CACHE_TTL_MS, g as FX_RETRY_COUNT, w as warmFxSnapshot } from '../fx-C6dl2LVI.js';
13
+ export { c as InvalidUsdPriceError, p as parseUsdPrice } from '../usd-BgOfZlk6.js';
14
14
  import 'hono';
15
15
  import 'mppx';
16
16
  import '@x402/core/server';
@@ -5888,7 +5888,7 @@ interface SmartDenominationOptions {
5888
5888
  declare function computeSmartDenominations(amountSats: number, opts?: SmartDenominationOptions): number[];
5889
5889
 
5890
5890
  /** Current on-disk wallet schema version. Bumping requires a migration path. */
5891
- declare const WALLET_VERSION: 8;
5891
+ declare const WALLET_VERSION: 9;
5892
5892
  /** Cap on the number of recent-spends entries persisted to the wallet. */
5893
5893
  declare const RECENT_SPENDS_CAP = 10;
5894
5894
  /**
@@ -6026,6 +6026,8 @@ interface PendingMint {
6026
6026
  amount_sats: number;
6027
6027
  /** ISO-8601 timestamp of the original `createMintQuote` call. */
6028
6028
  requested_at: string;
6029
+ /** Quote expiry as unix seconds, when the mint supplied one. */
6030
+ expires_at?: number;
6029
6031
  /** Pre-built blinded outputs, present only between `prepareMint` and `completeMint`. */
6030
6032
  minting?: PendingMintMintingState;
6031
6033
  }
@@ -6350,27 +6352,29 @@ interface AgentWallet {
6350
6352
  }
6351
6353
  /**
6352
6354
  * Read `~/.dvm/wallet.json` and return the parsed wallet. Returns `null` if
6353
- * the file does not exist. Migrates older wallets in-memory to v8:
6354
- * - v1 → v8: rejects populated proofs/pending_mints (the v1 shape predated
6355
+ * the file does not exist. Migrates older wallets in-memory to v9:
6356
+ * - v1 → v9: rejects populated proofs/pending_mints (the v1 shape predated
6355
6357
  * the fund flow and is expected to be empty); fresh recent_spends,
6356
6358
  * pending_submissions, nut13_counters; `mnemonic_fingerprint: null`.
6357
- * - v2 → v8: preserves all v2 fields, adds empty recent_spends,
6359
+ * - v2 → v9: preserves all v2 fields, adds empty recent_spends,
6358
6360
  * pending_submissions, nut13_counters.
6359
- * - v3 → v8: renames recovery_pubkey/recovery_privkey → lock_pubkey/lock_privkey;
6361
+ * - v3 → v9: renames recovery_pubkey/recovery_privkey → lock_pubkey/lock_privkey;
6360
6362
  * adds empty pending_submissions, nut13_counters.
6361
- * - v4 → v8: adds empty pending_submissions (internal-review), nut13_counters
6363
+ * - v4 → v9: adds empty pending_submissions (internal-review), nut13_counters
6362
6364
  * (internal-review).
6363
- * - v5 → v8: adds empty nut13_counters and a null mnemonic_fingerprint
6365
+ * - v5 → v9: adds empty nut13_counters and a null mnemonic_fingerprint
6364
6366
  * (internal-review). A v5 wallet inherits NUT-13 inactive — `getWallet` will
6365
6367
  * stay in degraded mode until the user runs `dvm wallet restore
6366
6368
  * <mnemonic>` to re-attach the sibling `~/.dvm/wallet.mnemonic`.
6367
- * - v6 → v8: pass-through for the v7 step (internal-review). Existing proofs are
6369
+ * - v6 → v9: pass-through for the v7 step (internal-review). Existing proofs are
6368
6370
  * free-balance, so `reserved_for` and `t_expire` remain unset;
6369
6371
  * `dvm wallet reserve` populates them on new pre-fund proofs.
6370
- * - v7 → v8: adds empty pending_melts (internal-review). No wallet predating the
6372
+ * - v7 → v9: adds empty pending_melts (internal-review). No wallet predating the
6371
6373
  * cash-out verb can have a melt in flight, so an empty list is exact.
6374
+ * - v8 → v9: preserves pending mints without `expires_at`; the recovery sweep
6375
+ * applies its bounded legacy fallback to those entries.
6372
6376
  * Throws `DvmError("wallet_unknown_version", ...)` for files written by a
6373
- * newer CLI so we never silently corrupt a future schema by treating it as v8.
6377
+ * newer CLI so we never silently corrupt a future schema by treating it as v9.
6374
6378
  */
6375
6379
  declare function loadAgentWallet(): AgentWallet | null;
6376
6380
  /**
@@ -9257,6 +9261,10 @@ interface MeltSweepOptions {
9257
9261
  abandonAfterMs?: number;
9258
9262
  /** Override `getWallet`. */
9259
9263
  getWalletForMint?: (mintUrl: string) => Promise<Wallet>;
9264
+ /** Maximum time spent retrying one transient quote-status read. Default 10 seconds. */
9265
+ quoteRetryTimeoutMs?: number;
9266
+ /** Sleep override for quote-status retry tests. */
9267
+ sleep?: (ms: number) => Promise<void>;
9260
9268
  }
9261
9269
  /**
9262
9270
  * Reconcile every entry in `wallet.pending_melts[]` against its mint and
@@ -9557,10 +9565,14 @@ interface SweepResult {
9557
9565
  interface SweepOptions {
9558
9566
  /** Override `Date.now`. */
9559
9567
  now?: () => number;
9560
- /** Override `fundTimeoutMs`. */
9568
+ /** Override the bounded fallback for legacy entries without a quote expiry. */
9561
9569
  expirationMs?: number;
9562
9570
  /** Override `getWallet`. */
9563
9571
  getWalletForMint?: (mintUrl: string) => Promise<Wallet>;
9572
+ /** Maximum time spent retrying one transient quote-status read. Default 10 seconds. */
9573
+ quoteRetryTimeoutMs?: number;
9574
+ /** Sleep override for quote-status retry tests. */
9575
+ sleep?: (ms: number) => Promise<void>;
9564
9576
  }
9565
9577
  /**
9566
9578
  * Reconcile every entry in `wallet.pending_mints[]` against its mint and