@dvmkit/sdk 0.3.0-rc.9 → 0.3.2-rc.10

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 (49) hide show
  1. package/dist/{chunk-MD3H3BF7.js → chunk-2A33VHYM.js} +1 -1
  2. package/dist/{chunk-AJNFXR7J.js → chunk-3KYLYVY4.js} +4 -1
  3. package/dist/{chunk-YO56VCTQ.js → chunk-BWGRKGKG.js} +190 -75
  4. package/dist/{chunk-MMCE7XSR.js → chunk-C2AGARLM.js} +1 -13
  5. package/dist/chunk-D42FMCLJ.js +1423 -0
  6. package/dist/{chunk-QX52F6IB.js → chunk-DSVGYW3B.js} +7 -4
  7. package/dist/{chunk-LTAIBLS2.js → chunk-HNIKSOI2.js} +524 -408
  8. package/dist/{chunk-4A2RAKCW.js → chunk-IBDDIG4K.js} +7 -3
  9. package/dist/{chunk-D7YQYLLM.js → chunk-J7PW2U6P.js} +1 -1
  10. package/dist/{chunk-FDKRXOZO.js → chunk-KL4C3LQV.js} +57 -49
  11. package/dist/{chunk-VA7GT6C6.js → chunk-LHN75BTX.js} +56 -53
  12. package/dist/{chunk-C3MTFLC6.js → chunk-M4RSKQAV.js} +14 -12
  13. package/dist/{chunk-U5VNEALI.js → chunk-PPHE7XUU.js} +1 -1
  14. package/dist/{chunk-GAIPXGM3.js → chunk-SP42AI5T.js} +1 -1
  15. package/dist/{chunk-N5B66UOS.js → chunk-U2EYIPFX.js} +4 -1
  16. package/dist/{chunk-H2MEFVH6.js → chunk-UQCK5VMA.js} +7 -4
  17. package/dist/{chunk-XMDQOXHO.js → chunk-Y7JZLO5J.js} +4 -1
  18. package/dist/{chunk-HHTL3ZFT.js → chunk-YEO5GW7U.js} +16 -13
  19. package/dist/{chunk-O6D72KYA.js → chunk-YRDA7EWN.js} +1 -1
  20. package/dist/{chunk-VIVXB4CD.js → chunk-YYQG4R7T.js} +1 -1
  21. package/dist/{chunk-FPOLJRBF.js → chunk-Z3EHBW2G.js} +2 -2
  22. package/dist/{chunk-2D75MNNG.js → chunk-ZHTUITDW.js} +8 -5
  23. package/dist/{chunk-XZ7LW4S5.js → chunk-ZUTI56L7.js} +20 -16
  24. package/dist/{credit-ledger-MHA652TV.js → credit-ledger-4CCHRJE2.js} +3 -2
  25. package/dist/{credit-menu-BlCL7gZx.d.ts → credit-menu-0-UtJ3hh.d.ts} +5 -1
  26. package/dist/index.js +4 -3
  27. package/dist/internal/caller.d.ts +38 -3
  28. package/dist/internal/caller.js +59 -19
  29. package/dist/internal/index.js +1 -1
  30. package/dist/internal/server.d.ts +2 -2
  31. package/dist/internal/server.js +16 -15
  32. package/dist/memory-credit-ledger-TERNM5T6.js +10 -0
  33. package/dist/{mpp-setup-MPP3ST5X.js → mpp-setup-OQ4OV7A5.js} +2 -1
  34. package/dist/{payout-reporter-KEMUXEUO.js → payout-reporter-TQ3YIFLZ.js} +2 -1
  35. package/dist/{postgres-consumed-credential-store-6N2V5MJN.js → postgres-consumed-credential-store-LFQNC7LD.js} +4 -1
  36. package/dist/{postgres-job-store-VE2JRUEC.js → postgres-job-store-FGOJ7UIX.js} +2 -1
  37. package/dist/{postgres-replay-store-ZF4JNZOW.js → postgres-replay-store-DFQSXPCG.js} +2 -1
  38. package/dist/{pricing-MU5GNUJZ.js → pricing-UJAPJLOM.js} +2 -1
  39. package/dist/{revenue-reporter-O75BGYFK.js → revenue-reporter-VN4WYN74.js} +2 -1
  40. package/dist/server/index.d.ts +3 -3
  41. package/dist/server/index.js +112 -112
  42. package/dist/{tempo-charge-store-SDTUNTKA.js → tempo-charge-store-EA66LSVJ.js} +2 -1
  43. package/dist/{tempo-lifecycle-G5SB4HFC.js → tempo-lifecycle-TJ62A7UX.js} +3 -3
  44. package/dist/{tempo-session-store-WF3VZXNF.js → tempo-session-store-65NA77KJ.js} +3 -2
  45. package/dist/{tempo-wallet-ZFNUDFVO.js → tempo-wallet-RCGBBAJH.js} +1 -1
  46. package/dist/testing/index.js +4 -3
  47. package/dist/{x402-CI6PSHNO.js → x402-S47Q77UE.js} +2 -2
  48. package/package.json +2 -2
  49. package/dist/memory-credit-ledger-BYBATRN3.js +0 -9
@@ -10,10 +10,10 @@ import {
10
10
  } from "./chunk-BQ2NMWKE.js";
11
11
  import {
12
12
  MemoryCreditLedger
13
- } from "./chunk-U5VNEALI.js";
13
+ } from "./chunk-PPHE7XUU.js";
14
14
  import {
15
15
  PostgresJobStore
16
- } from "./chunk-HHTL3ZFT.js";
16
+ } from "./chunk-YEO5GW7U.js";
17
17
  import {
18
18
  SIGNED_ENVELOPE_FIELDS,
19
19
  SignedRequestError,
@@ -21,7 +21,7 @@ import {
21
21
  humanizeZodIssues,
22
22
  signedRequestInput,
23
23
  zodIssuesOf
24
- } from "./chunk-H2MEFVH6.js";
24
+ } from "./chunk-UQCK5VMA.js";
25
25
  import {
26
26
  JobCancelledError,
27
27
  MemoryJobStore,
@@ -38,7 +38,7 @@ import {
38
38
  localMessage,
39
39
  providerMessage,
40
40
  toJobRecord
41
- } from "./chunk-MD3H3BF7.js";
41
+ } from "./chunk-2A33VHYM.js";
42
42
  import {
43
43
  ADMIN_AUTH_CLOCK_SKEW_SECONDS,
44
44
  ADMIN_AUTH_NONCE_TTL_SECONDS,
@@ -63,7 +63,7 @@ import {
63
63
  toLockPubkey,
64
64
  verifyCashuToken,
65
65
  verifyChallenge
66
- } from "./chunk-QX52F6IB.js";
66
+ } from "./chunk-DSVGYW3B.js";
67
67
  import {
68
68
  X402_BATCH_SETTLEMENT_SCHEME,
69
69
  X402_DEFAULT_FACILITATOR,
@@ -103,7 +103,7 @@ import {
103
103
  pinDimension,
104
104
  withSpan,
105
105
  withTraceContext
106
- } from "./chunk-YO56VCTQ.js";
106
+ } from "./chunk-BWGRKGKG.js";
107
107
  import {
108
108
  FxRateUnavailableError,
109
109
  InvalidCurrencyError,
@@ -112,7 +112,7 @@ import {
112
112
  fxRateFor,
113
113
  resolveFxSourceFromEnv,
114
114
  validateCurrency
115
- } from "./chunk-4A2RAKCW.js";
115
+ } from "./chunk-IBDDIG4K.js";
116
116
  import {
117
117
  fiatToSatsCeil,
118
118
  parseUsdPrice,
@@ -133,18 +133,22 @@ import {
133
133
  isNonChannelBitcoinRail,
134
134
  netOwedSats,
135
135
  x402SettlementPending
136
- } from "./chunk-2D75MNNG.js";
136
+ } from "./chunk-ZHTUITDW.js";
137
137
  import {
138
138
  withSdkInitLock
139
139
  } from "./chunk-COYKJRMM.js";
140
140
  import {
141
141
  withPostgresRecoveryContext
142
- } from "./chunk-C3MTFLC6.js";
142
+ } from "./chunk-M4RSKQAV.js";
143
143
  import {
144
144
  advertisedMethods,
145
145
  challengeMeta,
146
146
  isTempoInsufficientFundsError
147
- } from "./chunk-XZ7LW4S5.js";
147
+ } from "./chunk-ZUTI56L7.js";
148
+ import {
149
+ createDiagnosticCapabilityAuthority,
150
+ diagnosticConsole
151
+ } from "./chunk-D42FMCLJ.js";
148
152
 
149
153
  // src/sdk/server/lock-pubkey-store.ts
150
154
  async function initLockPubkeyTable(db) {
@@ -1010,7 +1014,7 @@ var warned = /* @__PURE__ */ new Set();
1010
1014
  function warnOnce(event, message) {
1011
1015
  if (warned.has(event)) return;
1012
1016
  warned.add(event);
1013
- console.warn(JSON.stringify({ level: "warn", event, message }));
1017
+ diagnosticConsole.warn({ level: "warn", event, message });
1014
1018
  }
1015
1019
 
1016
1020
  // src/sdk/server/funding.ts
@@ -1198,26 +1202,26 @@ function usableCachedRate(fx) {
1198
1202
  function warnStaleRate(cachedAt) {
1199
1203
  if (staleEpisode) return;
1200
1204
  staleEpisode = true;
1201
- console.warn(
1202
- JSON.stringify({
1205
+ diagnosticConsole.warn(
1206
+ {
1203
1207
  level: "btc_rate_stale_fallback",
1204
- message: "BTC/USD rate provider unreachable \u2014 pricing off the last rate this process saw. Amounts may have drifted.",
1208
+ message: void 0,
1205
1209
  cached_at: new Date(cachedAt).toISOString(),
1206
1210
  age: formatStaleness(cachedAt)
1207
- })
1211
+ }
1208
1212
  );
1209
1213
  }
1210
1214
  function warnKnownStaleRefusal(knownStale) {
1211
1215
  if (staleRefusalEpisode) return;
1212
1216
  staleRefusalEpisode = true;
1213
- console.warn(
1214
- JSON.stringify({
1217
+ diagnosticConsole.warn(
1218
+ {
1215
1219
  level: "btc_rate_stale_refused",
1216
- message: "Platform refused a known-stale FX snapshot \u2014 refusing to price x402/mppx off it rather than degrading to the last-known rate.",
1220
+ message: void 0,
1217
1221
  stale_days: knownStale.staleDays,
1218
1222
  stale_source: knownStale.staleSource,
1219
1223
  threshold_days: knownStale.thresholdDays
1220
- })
1224
+ }
1221
1225
  );
1222
1226
  }
1223
1227
  function rateStaleRefused(knownStale) {
@@ -1332,15 +1336,15 @@ function createX402SelfRelay(opts) {
1332
1336
  lowBalanceWei,
1333
1337
  checkedAt
1334
1338
  };
1335
- console.info(
1336
- JSON.stringify({
1339
+ diagnosticConsole.info(
1340
+ {
1337
1341
  level: "info",
1338
1342
  event: "x402_self_relay_gas_balance",
1339
1343
  address: observation.address,
1340
1344
  network: observation.network,
1341
1345
  balance_wei: observation.balanceWei.toString(),
1342
1346
  low_balance_wei: observation.lowBalanceWei.toString()
1343
- })
1347
+ }
1344
1348
  );
1345
1349
  await Promise.all([
1346
1350
  opts.config.onBalance?.(observation),
@@ -1417,8 +1421,8 @@ function createSubmissionLock(lock, network, address) {
1417
1421
  };
1418
1422
  }
1419
1423
  function logSubmissionLockTimeout(error) {
1420
- console.warn(
1421
- JSON.stringify({
1424
+ diagnosticConsole.warn(
1425
+ {
1422
1426
  level: "warn",
1423
1427
  event: "x402_self_relay_submission_lock_timeout",
1424
1428
  lock_key: error.lockKey,
@@ -1430,16 +1434,16 @@ function logSubmissionLockTimeout(error) {
1430
1434
  ...error.holder.state ? { holder_state: error.holder.state } : {},
1431
1435
  ...error.holder.heldSeconds !== void 0 ? { holder_held_seconds: error.holder.heldSeconds } : {}
1432
1436
  } : {}
1433
- })
1437
+ }
1434
1438
  );
1435
1439
  }
1436
- function logBalanceFailure(error) {
1437
- console.warn(
1438
- JSON.stringify({
1440
+ function logBalanceFailure(_error) {
1441
+ diagnosticConsole.warn(
1442
+ {
1439
1443
  level: "warn",
1440
1444
  event: "x402_self_relay_gas_balance_failed",
1441
- error_name: error instanceof Error ? error.name : "unknown"
1442
- })
1445
+ error_name: void 0
1446
+ }
1443
1447
  );
1444
1448
  }
1445
1449
  function classifyX402SelfRelayRpcFailure(error) {
@@ -1470,24 +1474,24 @@ async function reportRpcFailure(config, address, network, reason, checkedAt = Da
1470
1474
  reason,
1471
1475
  checkedAt
1472
1476
  };
1473
- console.warn(
1474
- JSON.stringify({
1477
+ diagnosticConsole.warn(
1478
+ {
1475
1479
  level: "warn",
1476
1480
  event: "x402_self_relay_rpc_failed",
1477
1481
  address,
1478
1482
  network,
1479
1483
  reason
1480
- })
1484
+ }
1481
1485
  );
1482
1486
  await Promise.resolve(config.onRpcHealth?.(observation)).catch(() => {
1483
- console.warn(
1484
- JSON.stringify({
1487
+ diagnosticConsole.warn(
1488
+ {
1485
1489
  level: "warn",
1486
1490
  event: "x402_self_relay_rpc_health_report_failed",
1487
1491
  address,
1488
1492
  network,
1489
1493
  reason
1490
- })
1494
+ }
1491
1495
  );
1492
1496
  });
1493
1497
  }
@@ -1749,7 +1753,7 @@ function createX402FleetSettlementScheduler(opts) {
1749
1753
  });
1750
1754
  const report = (error) => {
1751
1755
  if (config.onError) config.onError(error);
1752
- else console.error("x402 batch-settlement scheduler failed", error);
1756
+ else diagnosticConsole.error("x402 batch-settlement scheduler failed", error);
1753
1757
  };
1754
1758
  const runClaim = async () => {
1755
1759
  const results = await manager.claim({
@@ -1896,13 +1900,13 @@ async function createX402BatchSettlementServer(opts) {
1896
1900
  const selfRelayActive = selfRelayEnabled && !opts.config.facilitatorClient;
1897
1901
  const relayLockOwner = selfRelayActive ? postgres ?? (opts.db ? new PostgresX402ChannelStorage(opts.db) : void 0) : void 0;
1898
1902
  if (selfRelayActive && !relayLockOwner && !opts.allowInMemory) {
1899
- console.warn(
1900
- JSON.stringify({
1903
+ diagnosticConsole.warn(
1904
+ {
1901
1905
  level: "warn",
1902
1906
  event: "x402_self_relay_unserialized",
1903
1907
  network: opts.network,
1904
1908
  detail: "no database for the fleet-wide submission lock; this relay's gas EOA is serialized in-process only"
1905
- })
1909
+ }
1906
1910
  );
1907
1911
  }
1908
1912
  const selfRelay = opts.config.selfRelay && selfRelayActive ? createX402SelfRelay({
@@ -2278,15 +2282,15 @@ async function createX402BatchSettlementServer(opts) {
2278
2282
  const settlement = await resource.settlePayment(payload, matched);
2279
2283
  if (!settlement.success) {
2280
2284
  const operatorErrorMessage = selfRelayEnabled ? void 0 : settlement.errorMessage;
2281
- console.warn(
2282
- JSON.stringify({
2285
+ diagnosticConsole.warn(
2286
+ {
2283
2287
  level: "warn",
2284
2288
  event: "x402_settlement_submission_failed",
2285
2289
  network: settlement.network,
2286
2290
  settlement_id: intent?.settlementId,
2287
2291
  error_reason: settlement.errorReason,
2288
- ...operatorErrorMessage ? { error_message: operatorErrorMessage } : {}
2289
- })
2292
+ ...operatorErrorMessage ? { error_message: void 0 } : {}
2293
+ }
2290
2294
  );
2291
2295
  throw new X402SettlementSubmissionError(
2292
2296
  settlement.errorReason ?? "batch_settlement_failed",
@@ -2329,7 +2333,7 @@ async function createX402BatchSettlementServer(opts) {
2329
2333
  if (postgres) await postgres.withFleetSettlementLock(claim);
2330
2334
  else await claim();
2331
2335
  } catch (error) {
2332
- console.error("x402 batch-settlement withdrawal claim failed", error);
2336
+ diagnosticConsole.error("x402 batch-settlement withdrawal claim failed", error);
2333
2337
  } finally {
2334
2338
  await restoreReservation(storage, funding.channelId, pendingId, channelBeforeVerify);
2335
2339
  }
@@ -3651,7 +3655,7 @@ async function verifyUpfrontPayment(opts) {
3651
3655
  x402Requirements
3652
3656
  });
3653
3657
  }
3654
- const { verifyX402Payment } = await import("./x402-CI6PSHNO.js");
3658
+ const { verifyX402Payment } = await import("./x402-S47Q77UE.js");
3655
3659
  const receipt = await verifyX402Payment(
3656
3660
  x402Payment,
3657
3661
  x402Config,
@@ -3764,16 +3768,16 @@ async function verifyUpfrontPayment(opts) {
3764
3768
  const channelId = mppSessionChannelId(cred);
3765
3769
  const known = channelId ? await mpp.getTempoSessionBinding?.(channelId).catch(() => null) : null;
3766
3770
  if (!known) {
3767
- console.warn(
3768
- JSON.stringify({
3771
+ diagnosticConsole.warn(
3772
+ {
3769
3773
  level: "warn",
3770
3774
  event: "tempo_session_open_refused",
3771
- message: sessionUnavailable.message,
3775
+ message: void 0,
3772
3776
  channel_id: channelId,
3773
3777
  // True means the credit is bound to some *other* channel — a
3774
3778
  // stale client, not a caller trying to open a fresh one.
3775
3779
  credit_channel_bound: sessionIssuable
3776
- })
3780
+ }
3777
3781
  );
3778
3782
  return {
3779
3783
  paidMsats: 0,
@@ -4585,7 +4589,7 @@ async function verifyIncomingPayment(body, opts, snapshot) {
4585
4589
  snapshot
4586
4590
  });
4587
4591
  }
4588
- const { verifyX402Payment } = await import("./x402-CI6PSHNO.js");
4592
+ const { verifyX402Payment } = await import("./x402-S47Q77UE.js");
4589
4593
  const receipt = await verifyX402Payment(
4590
4594
  body.content.x402_payment,
4591
4595
  opts.x402Config,
@@ -5002,7 +5006,7 @@ async function processIncomingPayment(job, body, opts) {
5002
5006
  try {
5003
5007
  const requiredMsats = job.pendingPaymentMsats ?? 0;
5004
5008
  const requiredUsdcMicro = job.pendingX402AmountUsdcMicro !== void 0 ? BigInt(job.pendingX402AmountUsdcMicro) : BigInt(msatsToUsdc(requiredMsats, rate));
5005
- const { verifyX402Payment } = await import("./x402-CI6PSHNO.js");
5009
+ const { verifyX402Payment } = await import("./x402-S47Q77UE.js");
5006
5010
  const receipt = await verifyX402Payment(
5007
5011
  body.content.x402_payment,
5008
5012
  opts.x402Config,
@@ -5373,8 +5377,8 @@ async function resolveTopUpLedgerContext(opts, snapshot, binding) {
5373
5377
  if (askSatisfied && !(snapshot.creditId && snapshot.drawId)) return void 0;
5374
5378
  const dvmId = opts.dvmId ?? "";
5375
5379
  const logTopUp = (event, extra) => {
5376
- console.warn(
5377
- JSON.stringify({
5380
+ diagnosticConsole.warn(
5381
+ {
5378
5382
  level: "warn",
5379
5383
  event,
5380
5384
  rail,
@@ -5382,7 +5386,7 @@ async function resolveTopUpLedgerContext(opts, snapshot, binding) {
5382
5386
  credit_id: snapshot.creditId,
5383
5387
  draw_id: snapshot.drawId,
5384
5388
  ...extra
5385
- })
5389
+ }
5386
5390
  );
5387
5391
  };
5388
5392
  const logSkip = (reason, extra) => {
@@ -6326,25 +6330,25 @@ function oneShotCreditRefusal(instrument) {
6326
6330
  );
6327
6331
  }
6328
6332
  function logCreditRejected(reason, creditId, extra) {
6329
- console.warn(
6330
- JSON.stringify({
6333
+ diagnosticConsole.warn(
6334
+ {
6331
6335
  level: "warn",
6332
6336
  event: "credit_rejected",
6333
6337
  reason,
6334
6338
  credit_id: creditId,
6335
6339
  ...extra
6336
- })
6340
+ }
6337
6341
  );
6338
6342
  }
6339
6343
  function logTempoBindingUnavailable(args) {
6340
- console.warn(
6341
- JSON.stringify({
6344
+ diagnosticConsole.warn(
6345
+ {
6342
6346
  level: "warn",
6343
6347
  event: "tempo_channel_binding_unavailable",
6344
6348
  channel_id: args.channelId,
6345
6349
  credit_id: args.creditId,
6346
6350
  dvm_id: args.dvmId
6347
- })
6351
+ }
6348
6352
  );
6349
6353
  }
6350
6354
  async function resolveRateOrNull(fetcher) {
@@ -6372,16 +6376,16 @@ function x402NotOfferedResult(currency) {
6372
6376
  error: x402NotOfferedPaymentError(currency)
6373
6377
  };
6374
6378
  }
6375
- function logCredentialRejected(rail, phase, err) {
6376
- console.warn(
6377
- JSON.stringify({
6379
+ function logCredentialRejected(rail, phase, _err) {
6380
+ diagnosticConsole.warn(
6381
+ {
6378
6382
  level: "warn",
6379
6383
  event: `${rail}_credential_rejected`,
6380
6384
  phase,
6381
6385
  rail,
6382
- error_name: err instanceof Error ? err.name : void 0,
6383
- error_message: err instanceof Error ? err.message : String(err)
6384
- })
6386
+ error_name: void 0,
6387
+ error_message: void 0
6388
+ }
6385
6389
  );
6386
6390
  }
6387
6391
 
@@ -7978,14 +7982,14 @@ async function lightningIssue(c, deps, args) {
7978
7982
  }
7979
7983
  });
7980
7984
  }
7981
- console.warn(
7982
- JSON.stringify({
7985
+ diagnosticConsole.warn(
7986
+ {
7983
7987
  level: "warn",
7984
7988
  event: "lightning_invoice_issue_failed",
7985
7989
  credit_id: args.creditId,
7986
7990
  fund_id: args.fundId,
7987
- error: err instanceof Error ? err.message : String(err)
7988
- })
7991
+ error: void 0
7992
+ }
7989
7993
  );
7990
7994
  return lightningUnavailable(c, args.menu);
7991
7995
  }
@@ -8238,15 +8242,15 @@ async function replayedFunding(c, deps, args) {
8238
8242
  });
8239
8243
  }
8240
8244
  function creditFundingUnrecorded(c, args) {
8241
- console.warn(
8242
- JSON.stringify({
8245
+ diagnosticConsole.warn(
8246
+ {
8243
8247
  level: "warn",
8244
8248
  event: "credit_funding_unrecorded",
8245
8249
  credit_id: args.creditId,
8246
8250
  fund_id: args.fundId,
8247
8251
  requested_micro: args.requestedMicro,
8248
8252
  ...args.invoiceStatus ? { invoice_status: args.invoiceStatus } : {}
8249
- })
8253
+ }
8250
8254
  );
8251
8255
  return c.json(
8252
8256
  {
@@ -8431,17 +8435,17 @@ async function loadAdminLockPubkeyState(c, opts) {
8431
8435
  return { state: await opts.getLockPubkeyState() };
8432
8436
  } catch (error) {
8433
8437
  const errorCode = safeErrorCode(error);
8434
- console.error(
8435
- JSON.stringify({
8438
+ diagnosticConsole.error(
8439
+ {
8436
8440
  level: "error",
8437
8441
  event: "admin_lock_state_unavailable",
8438
- message: "Admin authentication state could not be loaded; the request failed closed.",
8442
+ message: void 0,
8439
8443
  dvm_id: opts.dvmId,
8440
8444
  method: c.req.method,
8441
8445
  route: c.req.path,
8442
8446
  error_kind: error instanceof Error ? "Error" : typeof error,
8443
8447
  ...errorCode ? { error_code: errorCode } : {}
8444
- })
8448
+ }
8445
8449
  );
8446
8450
  return {
8447
8451
  response: c.json(
@@ -9089,7 +9093,17 @@ function safeError(err) {
9089
9093
  // src/sdk/server/hosting-control.ts
9090
9094
  import { createHmac, timingSafeEqual } from "crypto";
9091
9095
  function signHostingControl(secret, command) {
9092
- return createHmac("sha256", secret).update(JSON.stringify([
9096
+ const signed = command.version === 2 ? [
9097
+ "dvmkit-hosting-v2",
9098
+ command.action,
9099
+ command.scope,
9100
+ command.dvmId,
9101
+ command.generation ?? null,
9102
+ command.leaseExpiresAtMs ?? null,
9103
+ command.deadlineMs ?? null,
9104
+ command.timestampMs,
9105
+ command.nonce
9106
+ ] : [
9093
9107
  "dvmkit-hosting-v1",
9094
9108
  command.action,
9095
9109
  command.scope,
@@ -9098,7 +9112,8 @@ function signHostingControl(secret, command) {
9098
9112
  command.deadlineMs ?? null,
9099
9113
  command.timestampMs,
9100
9114
  command.nonce
9101
- ])).digest("hex");
9115
+ ];
9116
+ return createHmac("sha256", secret).update(JSON.stringify(signed)).digest("hex");
9102
9117
  }
9103
9118
  var HostingControl = class {
9104
9119
  constructor(pool, dvmId, config) {
@@ -9117,7 +9132,7 @@ var HostingControl = class {
9117
9132
  await this.pool.query(`
9118
9133
  CREATE TABLE IF NOT EXISTS sdk_hosting_control (
9119
9134
  dvm_id TEXT NOT NULL, scope TEXT NOT NULL, state TEXT NOT NULL,
9120
- generation BIGINT NOT NULL, deadline_ms BIGINT,
9135
+ generation BIGINT NOT NULL, deadline_ms BIGINT, lease_expires_at_ms BIGINT,
9121
9136
  PRIMARY KEY (dvm_id, scope)
9122
9137
  );
9123
9138
  CREATE TABLE IF NOT EXISTS sdk_hosting_nonces (
@@ -9135,6 +9150,7 @@ var HostingControl = class {
9135
9150
  ALTER TABLE sdk_hosting_admissions ADD COLUMN IF NOT EXISTS credit_id TEXT;
9136
9151
  ALTER TABLE sdk_hosting_admissions ADD COLUMN IF NOT EXISTS fund_id TEXT;
9137
9152
  ALTER TABLE sdk_hosting_admissions ADD COLUMN IF NOT EXISTS payment_artifact_hash TEXT;
9153
+ ALTER TABLE sdk_hosting_control ADD COLUMN IF NOT EXISTS lease_expires_at_ms BIGINT;
9138
9154
  CREATE INDEX IF NOT EXISTS sdk_hosting_admissions_pending
9139
9155
  ON sdk_hosting_admissions (dvm_id, scope) WHERE outcome = 'pending';
9140
9156
  CREATE INDEX IF NOT EXISTS sdk_hosting_admissions_unresolved
@@ -9148,13 +9164,31 @@ var HostingControl = class {
9148
9164
  `);
9149
9165
  await this.pool.query(
9150
9166
  `INSERT INTO sdk_hosting_control (dvm_id, scope, state, generation)
9151
- VALUES ($1, $2, 'accepting', 0) ON CONFLICT DO NOTHING`,
9167
+ VALUES ($1, $2, 'draining', 0) ON CONFLICT DO NOTHING`,
9152
9168
  [this.dvmId, this.config.scope]
9153
9169
  );
9170
+ const client = await this.pool.connect();
9171
+ try {
9172
+ await client.query("BEGIN");
9173
+ const migrated = await client.query(
9174
+ `UPDATE sdk_hosting_control SET state='draining',
9175
+ deadline_ms=FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint + 3600000
9176
+ WHERE dvm_id=$1 AND scope=$2 AND state='accepting' AND lease_expires_at_ms IS NULL
9177
+ RETURNING deadline_ms`,
9178
+ [this.dvmId, this.config.scope]
9179
+ );
9180
+ if (migrated.rows[0]) await this.pinAdmissionDeadlines(client, Number(migrated.rows[0].deadline_ms));
9181
+ await client.query("COMMIT");
9182
+ } catch (error) {
9183
+ await client.query("ROLLBACK").catch(() => void 0);
9184
+ throw error;
9185
+ } finally {
9186
+ client.release();
9187
+ }
9154
9188
  });
9155
9189
  }
9156
9190
  async authorize(command, signature) {
9157
- if (command.scope !== this.config.scope || command.dvmId !== this.dvmId || !Number.isSafeInteger(command.timestampMs) || Math.abs(Date.now() - command.timestampMs) > 3e5 || typeof command.nonce !== "string" || !/^[A-Za-z0-9_-]{16,128}$/.test(command.nonce) || !signature || !/^[0-9a-f]{64}$/i.test(signature)) return false;
9191
+ if (command.version !== void 0 && command.version !== 2 || command.version === 2 && command.action !== "resume" || command.version === void 0 && command.leaseExpiresAtMs !== void 0 || command.scope !== this.config.scope || command.dvmId !== this.dvmId || !Number.isSafeInteger(command.timestampMs) || Math.abs(Date.now() - command.timestampMs) > 3e5 || typeof command.nonce !== "string" || !/^[A-Za-z0-9_-]{16,128}$/.test(command.nonce) || !signature || !/^[0-9a-f]{64}$/i.test(signature)) return false;
9158
9192
  const actual = Buffer.from(signature, "hex");
9159
9193
  const expected = Buffer.from(signHostingControl(this.config.secret, command), "hex");
9160
9194
  if (!timingSafeEqual(actual, expected)) return false;
@@ -9171,11 +9205,14 @@ var HostingControl = class {
9171
9205
  try {
9172
9206
  await client.query("BEGIN");
9173
9207
  const { rows } = await client.query(
9174
- `SELECT state FROM sdk_hosting_control WHERE dvm_id=$1 AND scope=$2 FOR UPDATE`,
9208
+ `SELECT state, lease_expires_at_ms, deadline_ms FROM sdk_hosting_control WHERE dvm_id=$1 AND scope=$2 FOR UPDATE`,
9175
9209
  [this.dvmId, this.config.scope]
9176
9210
  );
9177
- if (rows[0]?.state !== "accepting") {
9178
- await client.query("ROLLBACK");
9211
+ const now = await this.databaseNow(client);
9212
+ const current = rows[0];
9213
+ if (current) await this.expireIfNeeded(client, current, now);
9214
+ if (current?.state !== "accepting" || current.lease_expires_at_ms === null || Number(current.lease_expires_at_ms) <= now) {
9215
+ await client.query("COMMIT");
9179
9216
  return false;
9180
9217
  }
9181
9218
  await client.query(
@@ -9187,7 +9224,7 @@ var HostingControl = class {
9187
9224
  this.dvmId,
9188
9225
  this.config.scope,
9189
9226
  jobId,
9190
- Date.now(),
9227
+ now,
9191
9228
  details?.creditId ?? null,
9192
9229
  details?.fundId ?? null,
9193
9230
  details?.paymentArtifactHash ?? null
@@ -9228,26 +9265,70 @@ var HostingControl = class {
9228
9265
  }
9229
9266
  async jobDeadline(jobId) {
9230
9267
  const { rows } = await this.pool.query(
9231
- `SELECT MAX(drain_deadline_ms)::text AS drain_deadline_ms
9268
+ `SELECT MIN(drain_deadline_ms)::text AS drain_deadline_ms
9232
9269
  FROM sdk_hosting_admissions WHERE dvm_id=$1 AND scope=$2 AND job_id=$3`,
9233
9270
  [this.dvmId, this.config.scope, jobId]
9234
9271
  );
9235
9272
  return rows[0]?.drain_deadline_ms === null || !rows[0] ? null : Number(rows[0].drain_deadline_ms);
9236
9273
  }
9274
+ async dispatchDeadlineReached(jobId) {
9275
+ const { rows } = await this.pool.query(
9276
+ `SELECT EXISTS (
9277
+ SELECT 1 FROM sdk_hosting_admissions
9278
+ WHERE dvm_id=$1 AND scope=$2 AND job_id=$3
9279
+ AND drain_deadline_ms <= FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint
9280
+ ) OR EXISTS (
9281
+ SELECT 1 FROM sdk_hosting_control
9282
+ WHERE dvm_id=$1 AND scope=$2 AND state='draining'
9283
+ AND deadline_ms <= FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint
9284
+ ) AS reached`,
9285
+ [this.dvmId, this.config.scope, jobId]
9286
+ );
9287
+ return rows[0]?.reached ?? false;
9288
+ }
9289
+ async databaseNow(client) {
9290
+ const { rows } = await client.query(
9291
+ `SELECT FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint AS now_ms`
9292
+ );
9293
+ return Number(rows[0].now_ms);
9294
+ }
9295
+ async pinAdmissionDeadlines(client, deadlineMs) {
9296
+ await client.query(
9297
+ `UPDATE sdk_hosting_admissions SET drain_deadline_ms=
9298
+ CASE WHEN drain_deadline_ms IS NULL THEN $3 ELSE LEAST(drain_deadline_ms, $3) END
9299
+ WHERE dvm_id=$1 AND scope=$2 AND outcome <> 'failed'`,
9300
+ [this.dvmId, this.config.scope, deadlineMs]
9301
+ );
9302
+ }
9303
+ async expireIfNeeded(client, row, now) {
9304
+ if (row.state !== "accepting" || row.lease_expires_at_ms !== null && Number(row.lease_expires_at_ms) > now) return;
9305
+ const deadline = row.deadline_ms === null ? now + 36e5 : Number(row.deadline_ms);
9306
+ await client.query(
9307
+ `UPDATE sdk_hosting_control SET state='draining', deadline_ms=$3
9308
+ WHERE dvm_id=$1 AND scope=$2`,
9309
+ [this.dvmId, this.config.scope, deadline]
9310
+ );
9311
+ row.state = "draining";
9312
+ row.deadline_ms = String(deadline);
9313
+ await this.pinAdmissionDeadlines(client, deadline);
9314
+ }
9237
9315
  async transition(command) {
9238
- if (command.action !== "drain" && command.action !== "resume" || !Number.isSafeInteger(command.generation) || command.generation < 1 || command.action === "drain" && !Number.isSafeInteger(command.deadlineMs) || command.action === "resume" && command.deadlineMs !== void 0) return "conflict";
9316
+ if (command.action !== "drain" && command.action !== "resume" || !Number.isSafeInteger(command.generation) || command.generation < 1 || command.action === "drain" && (command.version !== void 0 || !Number.isSafeInteger(command.deadlineMs) || command.leaseExpiresAtMs !== void 0) || command.action === "resume" && (command.version !== 2 || !Number.isSafeInteger(command.leaseExpiresAtMs) || !Number.isSafeInteger(command.deadlineMs))) return "conflict";
9239
9317
  const client = await this.pool.connect();
9240
9318
  try {
9241
9319
  await client.query("BEGIN");
9242
9320
  const { rows } = await client.query(
9243
- `SELECT state, generation, deadline_ms FROM sdk_hosting_control
9321
+ `SELECT state, generation, deadline_ms, lease_expires_at_ms FROM sdk_hosting_control
9244
9322
  WHERE dvm_id=$1 AND scope=$2 FOR UPDATE`,
9245
9323
  [this.dvmId, this.config.scope]
9246
9324
  );
9247
9325
  const prior = rows[0];
9326
+ if (!prior) throw new Error("Hosting control was not initialized");
9327
+ const now = await this.databaseNow(client);
9328
+ await this.expireIfNeeded(client, prior, now);
9248
9329
  const generation = Number(prior.generation);
9249
9330
  const nextState = command.action === "drain" ? "draining" : "accepting";
9250
- if (command.generation === generation && prior.state === nextState && Number(prior.deadline_ms ?? 0) === (command.deadlineMs ?? 0)) {
9331
+ if (command.generation === generation && prior.state === nextState && Number(prior.deadline_ms ?? 0) === (command.deadlineMs ?? 0) && (command.action !== "resume" || Number(prior.lease_expires_at_ms ?? 0) === command.leaseExpiresAtMs)) {
9251
9332
  await client.query("COMMIT");
9252
9333
  return "ok";
9253
9334
  }
@@ -9255,21 +9336,29 @@ var HostingControl = class {
9255
9336
  await client.query("ROLLBACK");
9256
9337
  return "conflict";
9257
9338
  }
9258
- if (command.action === "drain" && (command.deadlineMs <= Date.now() || command.deadlineMs > Date.now() + 864e5)) {
9339
+ if (command.action === "drain" && (command.deadlineMs <= now || command.deadlineMs > now + 864e5)) {
9340
+ await client.query("ROLLBACK");
9341
+ return "conflict";
9342
+ }
9343
+ if (command.action === "resume" && (command.leaseExpiresAtMs <= now || command.leaseExpiresAtMs > now + 36e5 || command.deadlineMs <= command.leaseExpiresAtMs || command.deadlineMs > command.leaseExpiresAtMs + 36e5)) {
9259
9344
  await client.query("ROLLBACK");
9260
9345
  return "conflict";
9261
9346
  }
9262
9347
  await client.query(
9263
- `UPDATE sdk_hosting_control SET state=$3, generation=$4, deadline_ms=$5
9348
+ `UPDATE sdk_hosting_control SET state=$3, generation=$4, deadline_ms=$5,
9349
+ lease_expires_at_ms=$6
9264
9350
  WHERE dvm_id=$1 AND scope=$2`,
9265
- [this.dvmId, this.config.scope, nextState, command.generation, command.deadlineMs ?? null]
9351
+ [
9352
+ this.dvmId,
9353
+ this.config.scope,
9354
+ nextState,
9355
+ command.generation,
9356
+ command.deadlineMs ?? null,
9357
+ command.action === "resume" ? command.leaseExpiresAtMs : null
9358
+ ]
9266
9359
  );
9267
9360
  if (command.action === "drain") {
9268
- await client.query(
9269
- `UPDATE sdk_hosting_admissions SET drain_deadline_ms=$3
9270
- WHERE dvm_id=$1 AND scope=$2 AND outcome='pending'`,
9271
- [this.dvmId, this.config.scope, command.deadlineMs]
9272
- );
9361
+ await this.pinAdmissionDeadlines(client, command.deadlineMs);
9273
9362
  }
9274
9363
  await client.query("COMMIT");
9275
9364
  return "ok";
@@ -9281,6 +9370,22 @@ var HostingControl = class {
9281
9370
  }
9282
9371
  }
9283
9372
  async status() {
9373
+ const client = await this.pool.connect();
9374
+ try {
9375
+ await client.query("BEGIN");
9376
+ const locked = await client.query(
9377
+ `SELECT state, deadline_ms, lease_expires_at_ms FROM sdk_hosting_control
9378
+ WHERE dvm_id=$1 AND scope=$2 FOR UPDATE`,
9379
+ [this.dvmId, this.config.scope]
9380
+ );
9381
+ if (locked.rows[0]) await this.expireIfNeeded(client, locked.rows[0], await this.databaseNow(client));
9382
+ await client.query("COMMIT");
9383
+ } catch (error) {
9384
+ await client.query("ROLLBACK").catch(() => void 0);
9385
+ throw error;
9386
+ } finally {
9387
+ client.release();
9388
+ }
9284
9389
  await this.pool.query(
9285
9390
  `UPDATE sdk_hosting_admissions a SET outcome='accepted'
9286
9391
  WHERE a.dvm_id=$1 AND a.scope=$2 AND a.outcome='pending'
@@ -9300,7 +9405,7 @@ var HostingControl = class {
9300
9405
  [this.dvmId, this.config.scope]
9301
9406
  );
9302
9407
  const { rows } = await this.pool.query(
9303
- `SELECT state, generation, deadline_ms FROM sdk_hosting_control WHERE dvm_id=$1 AND scope=$2`,
9408
+ `SELECT state, generation, deadline_ms, lease_expires_at_ms FROM sdk_hosting_control WHERE dvm_id=$1 AND scope=$2`,
9304
9409
  [this.dvmId, this.config.scope]
9305
9410
  );
9306
9411
  const active = await this.pool.query(
@@ -9339,6 +9444,7 @@ var HostingControl = class {
9339
9444
  state: rows[0].state,
9340
9445
  generation: Number(rows[0].generation),
9341
9446
  deadlineMs: rows[0].deadline_ms === null ? null : Number(rows[0].deadline_ms),
9447
+ leaseExpiresAtMs: rows[0].lease_expires_at_ms === null ? null : Number(rows[0].lease_expires_at_ms),
9342
9448
  activeJobIds: active.rows.map((row) => row.id),
9343
9449
  unownedActiveJobIds: unowned.rows.map((row) => row.id),
9344
9450
  pendingAdmissionCount: Number(pending.rows[0].pending),
@@ -10121,13 +10227,13 @@ function startAccumulatorMonitor(opts) {
10121
10227
  lockKey,
10122
10228
  graceSeconds: opts.lockPubkeyGraceSeconds ?? DEFAULT_LOCK_PUBKEY_GRACE_SECONDS
10123
10229
  });
10124
- } catch (err) {
10125
- console.error(
10126
- JSON.stringify({
10230
+ } catch (_err) {
10231
+ diagnosticConsole.error(
10232
+ {
10127
10233
  level: "wallet_accumulator_tick_error",
10128
10234
  dvmId: opts.dvmId,
10129
- error: err instanceof Error ? err.message : String(err)
10130
- })
10235
+ error: void 0
10236
+ }
10131
10237
  );
10132
10238
  } finally {
10133
10239
  inFlight = null;
@@ -10163,13 +10269,13 @@ async function runTick(opts) {
10163
10269
  try {
10164
10270
  await pruneRetired(client, opts.dvmId, opts.graceSeconds * 1e3, opts.now());
10165
10271
  activeState = await opts.getLockPubkeyState();
10166
- } catch (err) {
10167
- console.error(
10168
- JSON.stringify({
10272
+ } catch (_err) {
10273
+ diagnosticConsole.error(
10274
+ {
10169
10275
  level: "wallet_accumulator_lock_pubkey_prune_failed",
10170
10276
  dvmId: opts.dvmId,
10171
- error: err instanceof Error ? err.message : String(err)
10172
- })
10277
+ error: void 0
10278
+ }
10173
10279
  );
10174
10280
  }
10175
10281
  }
@@ -10213,8 +10319,8 @@ async function emitExpiryEvents(opts, db, activeState) {
10213
10319
  }
10214
10320
  }
10215
10321
  function emitRetiredLockPubkey(dvmId, batch, retiredAtMs) {
10216
- console.log(
10217
- JSON.stringify({
10322
+ diagnosticConsole.log(
10323
+ {
10218
10324
  level: "wallet_accumulator_batch_retired_lock_pubkey",
10219
10325
  dvmId,
10220
10326
  mintUrl: batch.mintUrl,
@@ -10222,24 +10328,24 @@ function emitRetiredLockPubkey(dvmId, batch, retiredAtMs) {
10222
10328
  retiredAtMs,
10223
10329
  totalSats: batch.totalSats,
10224
10330
  rowIds: batch.rowIds
10225
- })
10331
+ }
10226
10332
  );
10227
10333
  }
10228
10334
  function emitOrphanBatch(dvmId, batch) {
10229
- console.log(
10230
- JSON.stringify({
10335
+ diagnosticConsole.log(
10336
+ {
10231
10337
  level: "wallet_accumulator_batch_orphan_lock_pubkey",
10232
10338
  dvmId,
10233
10339
  mintUrl: batch.mintUrl,
10234
10340
  lockPubkey: batch.lockPubkey,
10235
10341
  totalSats: batch.totalSats,
10236
10342
  rowIds: batch.rowIds
10237
- })
10343
+ }
10238
10344
  );
10239
10345
  }
10240
10346
  function emitExpired(dvmId, batch, tExpiredAgoMs) {
10241
- console.log(
10242
- JSON.stringify({
10347
+ diagnosticConsole.log(
10348
+ {
10243
10349
  level: "wallet_accumulator_batch_expired",
10244
10350
  dvmId,
10245
10351
  mintUrl: batch.mintUrl,
@@ -10247,12 +10353,12 @@ function emitExpired(dvmId, batch, tExpiredAgoMs) {
10247
10353
  totalSats: batch.totalSats,
10248
10354
  rowIds: batch.rowIds,
10249
10355
  tExpiredAgoMs
10250
- })
10356
+ }
10251
10357
  );
10252
10358
  }
10253
10359
  function emitExpiringSoon(dvmId, batch, timeToExpireMs) {
10254
- console.log(
10255
- JSON.stringify({
10360
+ diagnosticConsole.log(
10361
+ {
10256
10362
  level: "wallet_accumulator_batch_expiring_soon",
10257
10363
  dvmId,
10258
10364
  mintUrl: batch.mintUrl,
@@ -10260,7 +10366,7 @@ function emitExpiringSoon(dvmId, batch, timeToExpireMs) {
10260
10366
  totalSats: batch.totalSats,
10261
10367
  rowIds: batch.rowIds,
10262
10368
  timeToExpireMs
10263
- })
10369
+ }
10264
10370
  );
10265
10371
  }
10266
10372
  async function reapExpiredKeysetRows(opts, db) {
@@ -10281,15 +10387,15 @@ async function reapExpiredKeysetRows(opts, db) {
10281
10387
  [opts.dvmId, mint_url, proof_keyset_id]
10282
10388
  );
10283
10389
  if ((rowCount ?? 0) > 0) {
10284
- console.log(
10285
- JSON.stringify({
10390
+ diagnosticConsole.log(
10391
+ {
10286
10392
  level: "wallet_accumulator_reaped_expired_keyset",
10287
10393
  dvmId: opts.dvmId,
10288
10394
  mintUrl: mint_url,
10289
10395
  keysetId: proof_keyset_id,
10290
10396
  finalExpiry,
10291
10397
  rowCount
10292
- })
10398
+ }
10293
10399
  );
10294
10400
  }
10295
10401
  }
@@ -10403,12 +10509,12 @@ var JobManager = class {
10403
10509
  );
10404
10510
  }
10405
10511
  if (opts.receiptIssuer && !isReceiptIssuingStore(this.jobStore)) {
10406
- console.warn(
10407
- JSON.stringify({
10512
+ diagnosticConsole.warn(
10513
+ {
10408
10514
  level: "warn",
10409
10515
  event: "receipts_disabled_store_unsupported",
10410
- message: "DVMKIT_RECEIPT_KEY is set but the configured jobStore does not implement ReceiptIssuingStore (claimReceiptSeq / saveReceipt), so no receipts will be issued and /v1/info will not advertise them. Use PostgresJobStore, MemoryJobStore, or implement both methods."
10411
- })
10516
+ message: void 0
10517
+ }
10412
10518
  );
10413
10519
  }
10414
10520
  if (opts.cashuMode === "p2pk-accumulator" && opts.db && opts.dvmId) {
@@ -10417,12 +10523,12 @@ var JobManager = class {
10417
10523
  pool: opts.db,
10418
10524
  dvmId: opts.dvmId
10419
10525
  });
10420
- } catch (err) {
10421
- console.error(
10422
- JSON.stringify({
10526
+ } catch (_err) {
10527
+ diagnosticConsole.error(
10528
+ {
10423
10529
  level: "wallet_accumulator_monitor_start_failed",
10424
- error: err instanceof Error ? err.message : String(err)
10425
- })
10530
+ error: void 0
10531
+ }
10426
10532
  );
10427
10533
  }
10428
10534
  }
@@ -10438,24 +10544,24 @@ var JobManager = class {
10438
10544
  );
10439
10545
  const intervalMs = opts.staleJobSweepIntervalMs ?? Math.min(6e4, Math.max(15e3, Math.floor(tightest / 4)));
10440
10546
  this.staleSweepTimer = setInterval(() => {
10441
- void this.sweepStaleJobs().catch((err) => {
10442
- console.error(
10443
- JSON.stringify({
10547
+ void this.sweepStaleJobs().catch((_err) => {
10548
+ diagnosticConsole.error(
10549
+ {
10444
10550
  level: "stale_job_sweep_failed",
10445
- error: err instanceof Error ? err.message : String(err)
10446
- })
10551
+ error: void 0
10552
+ }
10447
10553
  );
10448
10554
  });
10449
10555
  }, intervalMs);
10450
10556
  this.staleSweepTimer.unref();
10451
10557
  if (this.processingWatchdogMs > 0 && this.heartbeatIntervalMs > 0) {
10452
10558
  this.heartbeatTimer = setInterval(() => {
10453
- void this.heartbeatActiveJobs().catch((err) => {
10454
- console.error(
10455
- JSON.stringify({
10559
+ void this.heartbeatActiveJobs().catch((_err) => {
10560
+ diagnosticConsole.error(
10561
+ {
10456
10562
  level: "job_heartbeat_failed",
10457
- error: err instanceof Error ? err.message : String(err)
10458
- })
10563
+ error: void 0
10564
+ }
10459
10565
  );
10460
10566
  });
10461
10567
  }, this.heartbeatIntervalMs);
@@ -10469,12 +10575,12 @@ var JobManager = class {
10469
10575
  ORPHAN_SWEEP_CLAIMS.add(opts.creditLedger);
10470
10576
  this.orphanSweepClaimed = true;
10471
10577
  this.orphanDrawSweepTimer = setInterval(() => {
10472
- void this.sweepOrphanDraws().catch((err) => {
10473
- console.error(
10474
- JSON.stringify({
10578
+ void this.sweepOrphanDraws().catch((_err) => {
10579
+ diagnosticConsole.error(
10580
+ {
10475
10581
  level: "orphan_draw_sweep_failed",
10476
- error: err instanceof Error ? err.message : String(err)
10477
- })
10582
+ error: void 0
10583
+ }
10478
10584
  );
10479
10585
  });
10480
10586
  }, orphanIntervalMs);
@@ -10482,13 +10588,13 @@ var JobManager = class {
10482
10588
  }
10483
10589
  if (descriptor.jobRetentionDays > 0) {
10484
10590
  if (!isJobRetentionStore(this.jobStore)) {
10485
- console.warn(
10486
- JSON.stringify({
10591
+ diagnosticConsole.warn(
10592
+ {
10487
10593
  level: "warn",
10488
10594
  event: "job_retention_store_unsupported",
10489
10595
  dvm: descriptor.name,
10490
10596
  retentionDays: descriptor.jobRetentionDays
10491
- })
10597
+ }
10492
10598
  );
10493
10599
  } else {
10494
10600
  const pass = () => {
@@ -10508,12 +10614,12 @@ var JobManager = class {
10508
10614
  }
10509
10615
  if (opts.dvmId && (opts.onJobCost || opts.onJobTerminal) && isTerminalCostRecoveryStore(this.jobStore)) {
10510
10616
  this.terminalCostRecoveryTimer = setInterval(() => {
10511
- void this.recoverTerminalCosts().catch((err) => {
10512
- console.error(
10513
- JSON.stringify({
10617
+ void this.recoverTerminalCosts().catch((_err) => {
10618
+ diagnosticConsole.error(
10619
+ {
10514
10620
  level: "terminal_cost_recovery_failed",
10515
- error: err instanceof Error ? err.message : String(err)
10516
- })
10621
+ error: void 0
10622
+ }
10517
10623
  );
10518
10624
  });
10519
10625
  }, TERMINAL_COST_RECOVERY_INTERVAL_MS);
@@ -10885,13 +10991,13 @@ var JobManager = class {
10885
10991
  if (!counters || !isTerminal(counters.status) || counters.status === job.status) return false;
10886
10992
  const durable = await this.jobStore.get(job.id);
10887
10993
  if (!durable) return false;
10888
- console.warn(
10889
- JSON.stringify({
10994
+ diagnosticConsole.warn(
10995
+ {
10890
10996
  level: "job_terminal_elsewhere",
10891
10997
  jobId: job.id,
10892
10998
  durableStatus: durable.status,
10893
10999
  localStatus: job.status
10894
- })
11000
+ }
10895
11001
  );
10896
11002
  job.status = durable.status;
10897
11003
  job.summary = durable.summary;
@@ -10915,7 +11021,7 @@ var JobManager = class {
10915
11021
  const ctx = job.sdkCtx;
10916
11022
  const onCancel = cap.onCancel;
10917
11023
  void Promise.resolve(onCancel(ctx, { reason })).catch((err) => {
10918
- console.error(`[${job.id}] onCancel hook failed after cross-machine cancel:`, err);
11024
+ diagnosticConsole.error(`[${job.id}] onCancel hook failed after cross-machine cancel:`, err);
10919
11025
  });
10920
11026
  }
10921
11027
  this.clearIdleTimer(job.id);
@@ -10940,20 +11046,20 @@ var JobManager = class {
10940
11046
  }
10941
11047
  }
10942
11048
  /** Retry outside the status watcher, which correctly stops once the job is terminal. */
10943
- scheduleTerminalCostHandoffRetry(job, attempt, err) {
11049
+ scheduleTerminalCostHandoffRetry(job, attempt, _err) {
10944
11050
  if (this.terminalCostHandoffRetryTimers.has(job.id)) return;
10945
11051
  const delayMs = Math.min(
10946
11052
  TERMINAL_COST_HANDOFF_RETRY_INITIAL_MS * 2 ** Math.min(attempt - 1, 8),
10947
11053
  TERMINAL_COST_HANDOFF_RETRY_MAX_MS
10948
11054
  );
10949
- console.error(
10950
- JSON.stringify({
11055
+ diagnosticConsole.error(
11056
+ {
10951
11057
  level: "terminal_cost_handoff_retry_scheduled",
10952
11058
  jobId: job.id,
10953
11059
  attempt,
10954
11060
  delayMs,
10955
- error: err instanceof Error ? err.message : String(err)
10956
- })
11061
+ error: void 0
11062
+ }
10957
11063
  );
10958
11064
  const timer = setTimeout(() => {
10959
11065
  this.terminalCostHandoffRetryTimers.delete(job.id);
@@ -11024,13 +11130,13 @@ var JobManager = class {
11024
11130
  return;
11025
11131
  }
11026
11132
  this.statusWatchers.set(jobId, unsubscribe);
11027
- }).catch((err) => {
11028
- console.error(
11029
- JSON.stringify({
11133
+ }).catch((_err) => {
11134
+ diagnosticConsole.error(
11135
+ {
11030
11136
  level: "job_status_watch_subscribe_failed",
11031
11137
  jobId,
11032
- error: err instanceof Error ? err.message : String(err)
11033
- })
11138
+ error: void 0
11139
+ }
11034
11140
  );
11035
11141
  this.statusWatchers.delete(jobId);
11036
11142
  });
@@ -11067,13 +11173,13 @@ var JobManager = class {
11067
11173
  if (isTerminal(job.status)) return;
11068
11174
  if (await this.adoptDurableTerminal(job)) return;
11069
11175
  } while (this.statusChecksQueued.has(job.id));
11070
- } catch (err) {
11071
- console.error(
11072
- JSON.stringify({
11176
+ } catch (_err) {
11177
+ diagnosticConsole.error(
11178
+ {
11073
11179
  level: "job_status_watch_check_failed",
11074
11180
  jobId: job.id,
11075
- error: err instanceof Error ? err.message : String(err)
11076
- })
11181
+ error: void 0
11182
+ }
11077
11183
  );
11078
11184
  } finally {
11079
11185
  this.statusChecksInFlight.delete(job.id);
@@ -11115,9 +11221,9 @@ var JobManager = class {
11115
11221
  content: msg.content
11116
11222
  },
11117
11223
  opts
11118
- ).catch((err) => {
11119
- console.error(
11120
- JSON.stringify({
11224
+ ).catch((_err) => {
11225
+ diagnosticConsole.error(
11226
+ {
11121
11227
  level: "job_message_append_failed",
11122
11228
  jobId,
11123
11229
  // In-memory counter, NOT the authoritative DB-allocated seq:
@@ -11125,9 +11231,9 @@ var JobManager = class {
11125
11231
  // RETURNING` inside the transaction that just failed, so no DB
11126
11232
  // seq was assigned for this message.
11127
11233
  localSeq: msg.seq,
11128
- note: "localSeq is the in-process counter; the DB-allocated seq was never assigned (append rolled back)",
11129
- error: err instanceof Error ? err.message : String(err)
11130
- })
11234
+ note: void 0,
11235
+ error: void 0
11236
+ }
11131
11237
  );
11132
11238
  })
11133
11239
  );
@@ -11267,8 +11373,8 @@ var JobManager = class {
11267
11373
  if (claimed) {
11268
11374
  swept++;
11269
11375
  await this.finalizeStoredTerminal(record.id);
11270
- console.warn(
11271
- JSON.stringify({
11376
+ diagnosticConsole.warn(
11377
+ {
11272
11378
  level: awaiting ? "stale_job_cancelled" : "stale_job_failed",
11273
11379
  jobId: record.id,
11274
11380
  capability: record.capability,
@@ -11286,7 +11392,7 @@ var JobManager = class {
11286
11392
  skewMs: skewMs > 0 ? skewMs : void 0,
11287
11393
  paidMsats: record.paidMsats,
11288
11394
  paymentRail: record.paymentRail
11289
- })
11395
+ }
11290
11396
  );
11291
11397
  if (record.paidMsats > 0 && record.paymentRail && this.opts.onPaidJobDeath) {
11292
11398
  try {
@@ -11303,10 +11409,10 @@ var JobManager = class {
11303
11409
  paymentMint: record.paymentMint
11304
11410
  })
11305
11411
  ).catch((err) => {
11306
- console.error(`[${record.id}] paid-job-death report failed:`, err);
11412
+ diagnosticConsole.error(`[${record.id}] paid-job-death report failed:`, err);
11307
11413
  });
11308
11414
  } catch (err) {
11309
- console.error(`[${record.id}] paid-job-death report failed:`, err);
11415
+ diagnosticConsole.error(`[${record.id}] paid-job-death report failed:`, err);
11310
11416
  }
11311
11417
  }
11312
11418
  const active = this._activeJobs.get(record.id);
@@ -11319,15 +11425,15 @@ var JobManager = class {
11319
11425
  }
11320
11426
  }
11321
11427
  if (skewMs > 0) {
11322
- console.warn(
11323
- JSON.stringify({
11428
+ diagnosticConsole.warn(
11429
+ {
11324
11430
  level: "stale_job_sweep_clock_skew",
11325
11431
  skewMs,
11326
11432
  processingCompensatedMs: this.processingWatchdogMs > 0 ? processingCompensationMs : void 0,
11327
11433
  awaitingCompensatedMs: this.staleJobTimeoutMs > 0 ? awaitingCompensationMs : void 0,
11328
11434
  examined: stale.length,
11329
11435
  swept
11330
- })
11436
+ }
11331
11437
  );
11332
11438
  }
11333
11439
  return { swept };
@@ -11420,13 +11526,13 @@ var JobManager = class {
11420
11526
  } catch (err) {
11421
11527
  const failure = err instanceof Error ? err : new Error(String(err));
11422
11528
  failures.push(failure);
11423
- console.error(
11424
- JSON.stringify({
11529
+ diagnosticConsole.error(
11530
+ {
11425
11531
  level: "error",
11426
11532
  event: "job_retention_candidate_failed",
11427
11533
  jobId: record.id,
11428
- error: failure.message
11429
- })
11534
+ error: void 0
11535
+ }
11430
11536
  );
11431
11537
  }
11432
11538
  }
@@ -11440,8 +11546,8 @@ var JobManager = class {
11440
11546
  throw new AggregateError(failures, `${failures.length} job retention candidate(s) failed`);
11441
11547
  }
11442
11548
  this.jobRetentionResumeFrom = complete ? void 0 : cursor;
11443
- console.log(
11444
- JSON.stringify({
11549
+ diagnosticConsole.log(
11550
+ {
11445
11551
  level: "info",
11446
11552
  event: "job_retention_swept",
11447
11553
  retentionDays: this.descriptor.jobRetentionDays,
@@ -11449,7 +11555,7 @@ var JobManager = class {
11449
11555
  examined,
11450
11556
  redacted,
11451
11557
  complete
11452
- })
11558
+ }
11453
11559
  );
11454
11560
  if (complete) {
11455
11561
  await this.notifyJobRetentionRecovered({ examined, redacted });
@@ -11458,15 +11564,15 @@ var JobManager = class {
11458
11564
  } catch (err) {
11459
11565
  this.jobRetentionResumeFrom = void 0;
11460
11566
  const error = err instanceof Error ? err.message : String(err);
11461
- console.error(
11462
- JSON.stringify({
11567
+ diagnosticConsole.error(
11568
+ {
11463
11569
  level: "error",
11464
11570
  event: "job_retention_sweep_failed",
11465
11571
  retentionDays: this.descriptor.jobRetentionDays,
11466
11572
  examined,
11467
11573
  redacted,
11468
11574
  error
11469
- })
11575
+ }
11470
11576
  );
11471
11577
  await this.notifyJobRetentionFailed(error);
11472
11578
  throw err;
@@ -11510,13 +11616,13 @@ var JobManager = class {
11510
11616
  retentionDays: this.descriptor.jobRetentionDays,
11511
11617
  error
11512
11618
  });
11513
- } catch (callbackError) {
11514
- console.error(
11515
- JSON.stringify({
11619
+ } catch (_callbackError) {
11620
+ diagnosticConsole.error(
11621
+ {
11516
11622
  level: "error",
11517
11623
  event: "job_retention_alert_failed",
11518
- error: callbackError instanceof Error ? callbackError.message : String(callbackError)
11519
- })
11624
+ error: void 0
11625
+ }
11520
11626
  );
11521
11627
  }
11522
11628
  }
@@ -11530,13 +11636,13 @@ var JobManager = class {
11530
11636
  retentionDays: this.descriptor.jobRetentionDays,
11531
11637
  ...result
11532
11638
  });
11533
- } catch (callbackError) {
11534
- console.error(
11535
- JSON.stringify({
11639
+ } catch (_callbackError) {
11640
+ diagnosticConsole.error(
11641
+ {
11536
11642
  level: "error",
11537
11643
  event: "job_retention_recovery_alert_failed",
11538
- error: callbackError instanceof Error ? callbackError.message : String(callbackError)
11539
- })
11644
+ error: void 0
11645
+ }
11540
11646
  );
11541
11647
  }
11542
11648
  }
@@ -11629,8 +11735,8 @@ var JobManager = class {
11629
11735
  this.drawResolutionArgs(draw.creditId, draw.drawId)
11630
11736
  );
11631
11737
  if (!resolution.replayed) released++;
11632
- console.warn(
11633
- JSON.stringify({
11738
+ diagnosticConsole.warn(
11739
+ {
11634
11740
  level: "orphan_draw_released",
11635
11741
  creditId: draw.creditId,
11636
11742
  drawId: draw.drawId,
@@ -11641,18 +11747,18 @@ var JobManager = class {
11641
11747
  reason,
11642
11748
  replayed: resolution.replayed,
11643
11749
  availableMicro: resolution.availableMicro
11644
- })
11750
+ }
11645
11751
  );
11646
11752
  } catch (err) {
11647
- console.warn(
11648
- JSON.stringify({
11753
+ diagnosticConsole.warn(
11754
+ {
11649
11755
  level: "orphan_draw_release_failed",
11650
11756
  creditId: draw.creditId,
11651
11757
  drawId: draw.drawId,
11652
11758
  jobId: draw.jobId,
11653
11759
  code: err instanceof CreditLedgerError ? err.code : void 0,
11654
- error: err instanceof Error ? err.message : String(err)
11655
- })
11760
+ error: void 0
11761
+ }
11656
11762
  );
11657
11763
  }
11658
11764
  }
@@ -11669,8 +11775,8 @@ var JobManager = class {
11669
11775
  }
11670
11776
  }
11671
11777
  this.orphanSweepResumeFrom = cursor;
11672
- console.warn(
11673
- JSON.stringify({
11778
+ diagnosticConsole.warn(
11779
+ {
11674
11780
  level: "orphan_draw_sweep_truncated",
11675
11781
  examined,
11676
11782
  skipped,
@@ -11679,7 +11785,7 @@ var JobManager = class {
11679
11785
  reconciled,
11680
11786
  maxPages: ORPHAN_DRAW_SWEEP_MAX_PAGES,
11681
11787
  resumeAfterCreatedAt: cursor?.createdAt
11682
- })
11788
+ }
11683
11789
  );
11684
11790
  return { released, reconciled };
11685
11791
  } finally {
@@ -11732,8 +11838,8 @@ var JobManager = class {
11732
11838
  }
11733
11839
  }
11734
11840
  const clockSkewMs = nowMs - Date.now();
11735
- console.warn(
11736
- JSON.stringify({
11841
+ diagnosticConsole.warn(
11842
+ {
11737
11843
  level: "orphan_draw_sweep_no_progress",
11738
11844
  examined: tally.examined,
11739
11845
  skipped: tally.skipped,
@@ -11745,7 +11851,7 @@ var JobManager = class {
11745
11851
  oldestPendingAgeMs,
11746
11852
  clockSkewMs: clockSkewMs > 0 ? clockSkewMs : void 0,
11747
11853
  probeError
11748
- })
11854
+ }
11749
11855
  );
11750
11856
  }
11751
11857
  /**
@@ -11786,8 +11892,8 @@ var JobManager = class {
11786
11892
  try {
11787
11893
  const resolution = settle ? await ledger.settle(args) : await ledger.release(args);
11788
11894
  const booked = settle && !resolution.replayed ? await this.bookRevenue(record) : false;
11789
- console.warn(
11790
- JSON.stringify({
11895
+ diagnosticConsole.warn(
11896
+ {
11791
11897
  level: "credit_draw_reconciled",
11792
11898
  creditId: draw.creditId,
11793
11899
  drawId: draw.drawId,
@@ -11801,20 +11907,20 @@ var JobManager = class {
11801
11907
  replayed: resolution.replayed,
11802
11908
  availableMicro: resolution.availableMicro,
11803
11909
  booked
11804
- })
11910
+ }
11805
11911
  );
11806
11912
  return !resolution.replayed;
11807
11913
  } catch (err) {
11808
- console.warn(
11809
- JSON.stringify({
11914
+ diagnosticConsole.warn(
11915
+ {
11810
11916
  level: "credit_draw_reconcile_failed",
11811
11917
  creditId: draw.creditId,
11812
11918
  drawId: draw.drawId,
11813
11919
  jobId: draw.jobId,
11814
11920
  jobStatus: record.status,
11815
11921
  code: err instanceof CreditLedgerError ? err.code : void 0,
11816
- error: err instanceof Error ? err.message : String(err)
11817
- })
11922
+ error: void 0
11923
+ }
11818
11924
  );
11819
11925
  return false;
11820
11926
  }
@@ -11962,13 +12068,13 @@ var JobManager = class {
11962
12068
  domain
11963
12069
  );
11964
12070
  } catch (err) {
11965
- console.warn(
11966
- JSON.stringify({
12071
+ diagnosticConsole.warn(
12072
+ {
11967
12073
  level: "auth_reverify_failed",
11968
12074
  jobId: record.id,
11969
12075
  capability: record.capability,
11970
12076
  sub_reason: err instanceof SignedRequestError ? err.sub_reason : "unknown"
11971
- })
12077
+ }
11972
12078
  );
11973
12079
  throw err;
11974
12080
  }
@@ -12123,8 +12229,8 @@ var JobManager = class {
12123
12229
  job.drawId = result.drawId;
12124
12230
  if (info.creditId && result.creditId !== info.creditId) {
12125
12231
  unappliedCredit = this.unappliedCredit(info.funding, info.creditId, "unbound");
12126
- console.warn(
12127
- JSON.stringify({
12232
+ diagnosticConsole.warn(
12233
+ {
12128
12234
  level: "warn",
12129
12235
  event: "credit_topup_unbound",
12130
12236
  job_id: job.id,
@@ -12132,7 +12238,7 @@ var JobManager = class {
12132
12238
  draw_id: info.drawId,
12133
12239
  bound_credit_id: result.creditId,
12134
12240
  bound_draw_id: result.drawId
12135
- })
12241
+ }
12136
12242
  );
12137
12243
  }
12138
12244
  } else {
@@ -12167,8 +12273,8 @@ var JobManager = class {
12167
12273
  unappliedCredit = this.unappliedCredit(info.funding, info.funding?.creditId, "over_ask", {
12168
12274
  creditedMicro: info.unappliedMicro
12169
12275
  });
12170
- console.warn(
12171
- JSON.stringify({
12276
+ diagnosticConsole.warn(
12277
+ {
12172
12278
  level: "warn",
12173
12279
  event: "credit_topup_over_ask",
12174
12280
  job_id: job.id,
@@ -12176,7 +12282,7 @@ var JobManager = class {
12176
12282
  draw_id: info.drawId,
12177
12283
  unapplied_micro: info.unappliedMicro,
12178
12284
  funded_micro: info.funding?.amountMicro
12179
- })
12285
+ }
12180
12286
  );
12181
12287
  }
12182
12288
  this.reportCreditDeposit(info.funding);
@@ -12226,15 +12332,15 @@ var JobManager = class {
12226
12332
  } catch (err) {
12227
12333
  lastErr = err;
12228
12334
  if (attempt === CREDIT_INBOUND_ATTEMPTS) break;
12229
- console.warn(
12230
- JSON.stringify({
12335
+ diagnosticConsole.warn(
12336
+ {
12231
12337
  level: "warn",
12232
12338
  event: "credit_job_row_retry",
12233
12339
  job_id: jobId,
12234
12340
  seq,
12235
12341
  attempt,
12236
- error: errText(err)
12237
- })
12342
+ error: void 0
12343
+ }
12238
12344
  );
12239
12345
  await new Promise((resolve) => setTimeout(resolve, CREDIT_INBOUND_BACKOFF_MS * attempt));
12240
12346
  }
@@ -12253,16 +12359,16 @@ var JobManager = class {
12253
12359
  }
12254
12360
  }
12255
12361
  if (landed) {
12256
- console.warn(
12257
- JSON.stringify({
12362
+ diagnosticConsole.warn(
12363
+ {
12258
12364
  level: "warn",
12259
12365
  event: "credit_job_row_recovered",
12260
12366
  job_id: jobId,
12261
12367
  seq,
12262
12368
  credit_id: landed.creditId,
12263
12369
  draw_id: landed.drawId,
12264
- error: errText(lastErr)
12265
- })
12370
+ error: void 0
12371
+ }
12266
12372
  );
12267
12373
  return landed;
12268
12374
  }
@@ -12303,8 +12409,8 @@ var JobManager = class {
12303
12409
  const funding = info.funding;
12304
12410
  const readErr = err instanceof CreditInboundExhaustedError ? err.readError : void 0;
12305
12411
  const rowChecked = err instanceof CreditInboundExhaustedError && readErr === void 0;
12306
- console.error(
12307
- JSON.stringify({
12412
+ diagnosticConsole.error(
12413
+ {
12308
12414
  level: "error",
12309
12415
  event: "credit_job_row_unwritten",
12310
12416
  job_id: job.id,
@@ -12313,13 +12419,13 @@ var JobManager = class {
12313
12419
  paid_msats: info.paidMsats,
12314
12420
  credit_id: funding?.creditId ?? info.creditId,
12315
12421
  draw_id: info.drawId,
12316
- error: errText(err),
12422
+ error: void 0,
12317
12423
  // `false` means the job row's credit state is unknown, not that it is
12318
12424
  // clean — the difference between a payment that provably didn't land and
12319
12425
  // one nobody could ask about.
12320
12426
  row_checked: rowChecked,
12321
12427
  ...readErr !== void 0 && { read_error: errText(readErr) }
12322
- })
12428
+ }
12323
12429
  );
12324
12430
  if (isStreamableJobStore(this.jobStore)) {
12325
12431
  await this.jobStore.markInboundFailed(job.id, inboundSeq, "payment_unapplied").catch(() => void 0);
@@ -12366,7 +12472,7 @@ var JobManager = class {
12366
12472
  if (!funding || !onCreditFunded || !this.opts.dvmId) return;
12367
12473
  Promise.resolve(onCreditFunded(creditDepositPayload(this.opts.dvmId, funding))).catch(
12368
12474
  (err) => {
12369
- console.error(`[${funding.creditId}] Deposit reporting failed:`, err);
12475
+ diagnosticConsole.error(`[${funding.creditId}] Deposit reporting failed:`, err);
12370
12476
  }
12371
12477
  );
12372
12478
  }
@@ -12465,8 +12571,8 @@ var JobManager = class {
12465
12571
  }
12466
12572
  /** Internal: structured warn for the one path that can't price a drawn job's pool. */
12467
12573
  warnDrawPool(job, reason, error) {
12468
- console.warn(
12469
- JSON.stringify({
12574
+ diagnosticConsole.warn(
12575
+ {
12470
12576
  level: "warn",
12471
12577
  event: "draw_pool_unpriced",
12472
12578
  reason,
@@ -12474,7 +12580,7 @@ var JobManager = class {
12474
12580
  creditId: job.creditId,
12475
12581
  drawId: job.drawId,
12476
12582
  ...error !== void 0 && { error }
12477
- })
12583
+ }
12478
12584
  );
12479
12585
  }
12480
12586
  /**
@@ -12501,7 +12607,7 @@ var JobManager = class {
12501
12607
  try {
12502
12608
  await callback({ jobId: record.id, rail, amountMicro: draw.amountMicro, currency, testFunds });
12503
12609
  } catch (error) {
12504
- console.error(`[${record.id}] Paid completion observer failed:`, error);
12610
+ diagnosticConsole.error(`[${record.id}] Paid completion observer failed:`, error);
12505
12611
  }
12506
12612
  }
12507
12613
  async issueReceipt(record) {
@@ -12513,17 +12619,17 @@ var JobManager = class {
12513
12619
  let credit;
12514
12620
  try {
12515
12621
  credit = await this.resolveCreditDraw(record);
12516
- } catch (err) {
12517
- console.error(
12518
- JSON.stringify({
12622
+ } catch (_err) {
12623
+ diagnosticConsole.error(
12624
+ {
12519
12625
  level: "error",
12520
12626
  event: "credit_resolve_failed",
12521
12627
  jobId: record.id,
12522
12628
  creditId: record.creditId,
12523
12629
  drawId: record.drawId,
12524
12630
  status: record.status,
12525
- error: err instanceof Error ? err.message : String(err)
12526
- })
12631
+ error: void 0
12632
+ }
12527
12633
  );
12528
12634
  return void 0;
12529
12635
  }
@@ -12540,15 +12646,15 @@ var JobManager = class {
12540
12646
  const saved = await store.saveReceipt(record.id, receipt) ?? receipt;
12541
12647
  await this.observePaidCompletion(record);
12542
12648
  return saved;
12543
- } catch (err) {
12544
- console.error(
12545
- JSON.stringify({
12649
+ } catch (_err) {
12650
+ diagnosticConsole.error(
12651
+ {
12546
12652
  level: "error",
12547
12653
  event: "receipt_issue_failed",
12548
12654
  jobId: record.id,
12549
12655
  status: record.status,
12550
- error: err instanceof Error ? err.message : String(err)
12551
- })
12656
+ error: void 0
12657
+ }
12552
12658
  );
12553
12659
  return void 0;
12554
12660
  }
@@ -12590,8 +12696,8 @@ var JobManager = class {
12590
12696
  if (err instanceof CreditLedgerError && err.code === "invalid_draw_state") {
12591
12697
  const rec = await ledger.getDraw(args);
12592
12698
  if (!rec) return void 0;
12593
- console.warn(
12594
- JSON.stringify({
12699
+ diagnosticConsole.warn(
12700
+ {
12595
12701
  level: "warn",
12596
12702
  event: "credit_resolve_state_mismatch",
12597
12703
  jobId: record.id,
@@ -12599,7 +12705,7 @@ var JobManager = class {
12599
12705
  drawId: record.drawId,
12600
12706
  jobStatus: record.status,
12601
12707
  drawStatus: rec.status
12602
- })
12708
+ }
12603
12709
  );
12604
12710
  return {
12605
12711
  credit_id: rec.creditId,
@@ -12727,7 +12833,7 @@ var JobManager = class {
12727
12833
  await this.jobStore.markTerminalReported(jobId);
12728
12834
  }
12729
12835
  } catch (error) {
12730
- console.error(`[${jobId}] Terminal reporting failed:`, error);
12836
+ diagnosticConsole.error(`[${jobId}] Terminal reporting failed:`, error);
12731
12837
  }
12732
12838
  }
12733
12839
  terminalReportRecoveryCursor;
@@ -12787,28 +12893,28 @@ var JobManager = class {
12787
12893
  if (candidates.length < TERMINAL_COST_RECOVERY_BATCH) {
12788
12894
  this.terminalCostRecoveryResumeAfter = void 0;
12789
12895
  if (examined > 0) {
12790
- console.log(
12791
- JSON.stringify({
12896
+ diagnosticConsole.log(
12897
+ {
12792
12898
  level: "info",
12793
12899
  event: "terminal_cost_recovery_complete",
12794
12900
  dvmId,
12795
12901
  examined,
12796
12902
  queued
12797
- })
12903
+ }
12798
12904
  );
12799
12905
  }
12800
12906
  return { examined, queued, complete: true };
12801
12907
  }
12802
12908
  }
12803
12909
  this.terminalCostRecoveryResumeAfter = cursor;
12804
- console.warn(
12805
- JSON.stringify({
12910
+ diagnosticConsole.warn(
12911
+ {
12806
12912
  level: "terminal_cost_recovery_truncated",
12807
12913
  dvmId,
12808
12914
  examined,
12809
12915
  queued,
12810
12916
  resumeAfterJobId: cursor
12811
- })
12917
+ }
12812
12918
  );
12813
12919
  return { examined, queued, complete: false };
12814
12920
  } finally {
@@ -12840,7 +12946,7 @@ var JobManager = class {
12840
12946
  }
12841
12947
  }
12842
12948
  } catch (err) {
12843
- console.error(`[${job.id}] Job cost reporting failed:`, err);
12949
+ diagnosticConsole.error(`[${job.id}] Job cost reporting failed:`, err);
12844
12950
  return false;
12845
12951
  }
12846
12952
  return true;
@@ -12901,15 +13007,15 @@ var JobManager = class {
12901
13007
  const args = { creditId: job.creditId, drawId: job.drawId };
12902
13008
  const draw = await this.opts.creditLedger.getDraw(args).catch(() => void 0);
12903
13009
  if (draw?.status !== "settled") {
12904
- console.warn(
12905
- JSON.stringify({
13010
+ diagnosticConsole.warn(
13011
+ {
12906
13012
  level: "warn",
12907
13013
  event: "revenue_skipped_unsettled_draw",
12908
13014
  jobId: job.id,
12909
13015
  creditId: job.creditId,
12910
13016
  drawId: job.drawId,
12911
13017
  drawStatus: draw?.status ?? "missing"
12912
- })
13018
+ }
12913
13019
  );
12914
13020
  return false;
12915
13021
  }
@@ -12933,8 +13039,8 @@ var JobManager = class {
12933
13039
  if (job.creditId && job.drawId) {
12934
13040
  const creditCurrency = typeof credit.creditCurrency === "string" ? credit.creditCurrency : void 0;
12935
13041
  const reason = creditRail === void 0 ? "ledger_not_configured" : creditRail === null ? "credit_rail_null" : isFundingRail(creditRail) ? "job_rail_missing" : "credit_rail_unrecognized";
12936
- console.warn(
12937
- JSON.stringify({
13042
+ diagnosticConsole.warn(
13043
+ {
12938
13044
  level: "warn",
12939
13045
  event: "revenue_skipped_no_rail",
12940
13046
  jobId: job.id,
@@ -12956,7 +13062,7 @@ var JobManager = class {
12956
13062
  // database one, and the only arm where the debit is reported on
12957
13063
  // the job row's word rather than the ledger's.
12958
13064
  reason
12959
- })
13065
+ }
12960
13066
  );
12961
13067
  if (onRevenueSkippedNoRail) {
12962
13068
  Promise.resolve(
@@ -12972,7 +13078,7 @@ var JobManager = class {
12972
13078
  reason
12973
13079
  })
12974
13080
  ).catch((err) => {
12975
- console.error(`[${job.id}] Revenue skip alert reporting failed:`, err);
13081
+ diagnosticConsole.error(`[${job.id}] Revenue skip alert reporting failed:`, err);
12976
13082
  });
12977
13083
  }
12978
13084
  }
@@ -13001,7 +13107,7 @@ var JobManager = class {
13001
13107
  ...credit
13002
13108
  })
13003
13109
  ).catch((err) => {
13004
- console.error(`[${job.id}] Revenue reporting failed:`, err);
13110
+ diagnosticConsole.error(`[${job.id}] Revenue reporting failed:`, err);
13005
13111
  });
13006
13112
  return true;
13007
13113
  }
@@ -13274,14 +13380,14 @@ var MintHealthTracker = class {
13274
13380
  };
13275
13381
  this.state.set(key, next);
13276
13382
  if (previous.sick) {
13277
- console.log(
13278
- JSON.stringify({
13383
+ diagnosticConsole.log(
13384
+ {
13279
13385
  level: "cashu_mint_runtime_recovered",
13280
13386
  mintUrl,
13281
13387
  latencyMs: result.latencyMs,
13282
13388
  version: result.version,
13283
13389
  observedAt: this.nowFn()
13284
- })
13390
+ }
13285
13391
  );
13286
13392
  }
13287
13393
  return;
@@ -13298,21 +13404,19 @@ var MintHealthTracker = class {
13298
13404
  errorCode: nutIncompatible ? "nut_support_missing" : result.error?.code
13299
13405
  });
13300
13406
  if (!previous.sick && sick) {
13301
- console.log(
13302
- JSON.stringify(
13303
- nutIncompatible ? {
13304
- level: "cashu_mint_nut_incompatible",
13305
- mintUrl,
13306
- version: result.version,
13307
- observedAt: this.nowFn()
13308
- } : {
13309
- level: "cashu_mint_runtime_sick",
13310
- mintUrl,
13311
- consecutiveFailures,
13312
- error: result.error,
13313
- observedAt: this.nowFn()
13314
- }
13315
- )
13407
+ diagnosticConsole.log(
13408
+ nutIncompatible ? {
13409
+ level: "cashu_mint_nut_incompatible",
13410
+ mintUrl,
13411
+ version: result.version,
13412
+ observedAt: this.nowFn()
13413
+ } : {
13414
+ level: "cashu_mint_runtime_sick",
13415
+ mintUrl,
13416
+ consecutiveFailures,
13417
+ error: void 0,
13418
+ observedAt: this.nowFn()
13419
+ }
13316
13420
  );
13317
13421
  }
13318
13422
  }
@@ -13327,8 +13431,8 @@ var MintHealthTracker = class {
13327
13431
  errorCode: s.errorCode
13328
13432
  }));
13329
13433
  const healthy = mints.filter((m) => m.probeOk).length;
13330
- console.log(
13331
- JSON.stringify({
13434
+ diagnosticConsole.log(
13435
+ {
13332
13436
  level: healthy === 0 && mints.length > 0 ? "warn" : "cashu_mint_boot_health",
13333
13437
  event: "cashu_mint_boot_health",
13334
13438
  healthyMints: healthy,
@@ -13336,7 +13440,7 @@ var MintHealthTracker = class {
13336
13440
  allUnhealthy: healthy === 0 && mints.length > 0,
13337
13441
  mints,
13338
13442
  observedAt: this.nowFn()
13339
- })
13443
+ }
13340
13444
  );
13341
13445
  }
13342
13446
  };
@@ -14015,16 +14119,16 @@ var X402FacilitatorHealth = class {
14015
14119
  if (ageMs >= this.maxStalenessMs) {
14016
14120
  if (this.ceilingLoggedForMs !== observedAtMs) {
14017
14121
  this.ceilingLoggedForMs = observedAtMs;
14018
- console.warn(
14019
- JSON.stringify({
14122
+ diagnosticConsole.warn(
14123
+ {
14020
14124
  level: "warn",
14021
14125
  event: "x402_facilitator_staleness_ceiling",
14022
14126
  facilitator: this.facilitator,
14023
14127
  network: this.network,
14024
14128
  age_ms: ageMs,
14025
14129
  staleness_ceiling_ms: this.maxStalenessMs,
14026
- message: "x402 removed from the payment menu because the facilitator capability observation is too old."
14027
- })
14130
+ message: void 0
14131
+ }
14028
14132
  );
14029
14133
  }
14030
14134
  return unavailableSupport(
@@ -14050,17 +14154,17 @@ var X402FacilitatorHealth = class {
14050
14154
  const { support } = read;
14051
14155
  if (support.reason === "probe_failed") {
14052
14156
  const observedAtMs = this.observation?.observedAtMs ?? this.startedAtMs;
14053
- console.warn(
14054
- JSON.stringify({
14157
+ diagnosticConsole.warn(
14158
+ {
14055
14159
  level: "warn",
14056
14160
  event: "x402_facilitator_fallback",
14057
14161
  facilitator: support.facilitator,
14058
14162
  network: support.network,
14059
- error: support.error,
14163
+ error: void 0,
14060
14164
  age_ms: Math.max(0, this.now() - observedAtMs),
14061
14165
  staleness_ceiling_ms: this.maxStalenessMs,
14062
- message: "Facilitator capability probe failed; x402 keeps its last exact support until the staleness ceiling."
14063
- })
14166
+ message: void 0
14167
+ }
14064
14168
  );
14065
14169
  return;
14066
14170
  }
@@ -14068,19 +14172,19 @@ var X402FacilitatorHealth = class {
14068
14172
  this.lastSupportedResponse = read.response;
14069
14173
  this.ceilingLoggedForMs = void 0;
14070
14174
  if (!support.available) {
14071
- console.warn(
14072
- JSON.stringify({
14175
+ diagnosticConsole.warn(
14176
+ {
14073
14177
  level: "warn",
14074
14178
  event: "x402_facilitator_unavailable",
14075
14179
  facilitator: support.facilitator,
14076
14180
  network: support.network,
14077
14181
  reason: support.reason,
14078
- message: "Exact x402 is unavailable because the configured facilitator advertises no supported exact generation on this network. Configured batch settlement is evaluated separately; other rails are unaffected."
14079
- })
14182
+ message: void 0
14183
+ }
14080
14184
  );
14081
14185
  } else if (!support.exact.v1 || !support.exact.v2 || this.config.batchSettlement && !support.batchSettlement) {
14082
- console.warn(
14083
- JSON.stringify({
14186
+ diagnosticConsole.warn(
14187
+ {
14084
14188
  level: "warn",
14085
14189
  event: "x402_facilitator_capability_degraded",
14086
14190
  facilitator: support.facilitator,
@@ -14088,8 +14192,8 @@ var X402FacilitatorHealth = class {
14088
14192
  exact_v1: support.exact.v1,
14089
14193
  exact_v2: support.exact.v2,
14090
14194
  batch_settlement: support.batchSettlement,
14091
- message: "x402 is serving only the protocol generations and channel scheme advertised by the facilitator."
14092
- })
14195
+ message: void 0
14196
+ }
14093
14197
  );
14094
14198
  }
14095
14199
  }
@@ -14968,11 +15072,11 @@ async function handleWriteOffInvoice(c, opts) {
14968
15072
  );
14969
15073
  }
14970
15074
  if (outcome.written) {
14971
- console.warn(
14972
- JSON.stringify({
15075
+ diagnosticConsole.warn(
15076
+ {
14973
15077
  level: "warn",
14974
15078
  event: "lightning_invoice_written_off",
14975
- message: "An operator closed a blocked Lightning funding invoice without crediting it. The received sats stay in the wallet and no caller balance was created for them.",
15079
+ message: void 0,
14976
15080
  payment_hash: written.paymentHash,
14977
15081
  credit_id: written.creditId,
14978
15082
  fund_id: written.fundId,
@@ -14980,8 +15084,8 @@ async function handleWriteOffInvoice(c, opts) {
14980
15084
  amount_msats: written.amountMsats,
14981
15085
  amount_micro: written.amountMicro,
14982
15086
  currency: written.currency,
14983
- note: written.writeOffNote
14984
- })
15087
+ note: void 0
15088
+ }
14985
15089
  );
14986
15090
  }
14987
15091
  return c.json({
@@ -15161,19 +15265,19 @@ async function handleWriteOffX402(c, opts) {
15161
15265
  if ("refusal" in outcome) return x402RefusalResponse(c, outcome);
15162
15266
  if (outcome.written) {
15163
15267
  const credit = await opts.ledger.getCreditByX402Channel(outcome.intent.channelId);
15164
- console.warn(
15165
- JSON.stringify({
15268
+ diagnosticConsole.warn(
15269
+ {
15166
15270
  level: "warn",
15167
15271
  event: "x402_settlement_written_off",
15168
- message: "An operator closed a wedged x402 settlement without booking it. If the refund did reach the chain, the caller's credit balance is still on this ledger and is reclaimable with a fresh drain id.",
15272
+ message: void 0,
15169
15273
  settlement_id: outcome.intent.settlementId,
15170
15274
  channel_id: outcome.intent.channelId,
15171
15275
  operation: outcome.intent.operation,
15172
15276
  effect_id: outcome.intent.effectId,
15173
15277
  credit_id: credit?.creditId ?? null,
15174
15278
  settled_amount: outcome.intent.response?.amount ?? null,
15175
- note: outcome.intent.writeOffNote
15176
- })
15279
+ note: void 0
15280
+ }
15177
15281
  );
15178
15282
  }
15179
15283
  return c.json({
@@ -15352,19 +15456,19 @@ async function handleWriteOffTempo(c, opts) {
15352
15456
  return tempoNotWedgedRefusal(c, parsed, outcome.drain.status);
15353
15457
  }
15354
15458
  if (outcome.written) {
15355
- console.warn(
15356
- JSON.stringify({
15459
+ diagnosticConsole.warn(
15460
+ {
15357
15461
  level: "warn",
15358
15462
  event: "tempo_drain_written_off",
15359
- message: "An operator closed a wedged Tempo cooperative close without booking it. The caller's on-chain refund landed short of the balance this ledger extinguished; that difference is not expressible in any dvmkit row and must be made good out of band.",
15463
+ message: void 0,
15360
15464
  credit_id: outcome.drain.creditId,
15361
15465
  drain_id: outcome.drain.drainId,
15362
15466
  channel_id: outcome.drain.channelId,
15363
15467
  amount_micro: outcome.drain.amountMicro,
15364
15468
  amount_native: outcome.drain.drainedNative,
15365
15469
  currency: outcome.drain.currency,
15366
- note: outcome.drain.writeOffNote
15367
- })
15470
+ note: void 0
15471
+ }
15368
15472
  );
15369
15473
  }
15370
15474
  return c.json({
@@ -15998,19 +16102,19 @@ function startCreditExpirySweep(ledger, opts = {}) {
15998
16102
  if (stopped) return;
15999
16103
  void runOnce().then(({ released }) => {
16000
16104
  if (released.length === 0) return;
16001
- console.log(
16002
- JSON.stringify({
16105
+ diagnosticConsole.log(
16106
+ {
16003
16107
  level: "credit_expiry_released",
16004
16108
  count: released.length,
16005
16109
  credits: released.map((r) => r.creditId)
16006
- })
16110
+ }
16007
16111
  );
16008
- }).catch((err) => {
16009
- console.error(
16010
- JSON.stringify({
16112
+ }).catch((_err) => {
16113
+ diagnosticConsole.error(
16114
+ {
16011
16115
  level: "credit_expiry_sweep_failed",
16012
- error: err instanceof Error ? err.message : String(err)
16013
- })
16116
+ error: void 0
16117
+ }
16014
16118
  );
16015
16119
  });
16016
16120
  };
@@ -16992,7 +17096,7 @@ function assertRevenueReporterReady(opts) {
16992
17096
  const missing = Object.entries(pieces).filter(([, v]) => !v).map(([k]) => k);
16993
17097
  if (missing.length === 0) return;
16994
17098
  const msg = `[FATAL] Platform-hosted DVM with incomplete revenue-reporter wiring. DVMKIT_PLATFORM_URL is set but missing: ${missing.join(", ")}. Either complete the configuration or unset DVMKIT_PLATFORM_URL to opt out.`;
16995
- console.error(msg);
17099
+ diagnosticConsole.error(msg);
16996
17100
  throw new Error(msg);
16997
17101
  }
16998
17102
  function revenueReporterBannerState(s) {
@@ -17048,11 +17152,11 @@ async function createDVMServer(descriptor, opts) {
17048
17152
  })();
17049
17153
  try {
17050
17154
  if (opts.env.DVMKIT_CASHU_MINTS && opts.cashuMode === void 0) {
17051
- console.warn(
17052
- JSON.stringify({
17155
+ diagnosticConsole.warn(
17156
+ {
17053
17157
  level: "cashu_opts_env_ignored",
17054
- message: "DVMKIT_CASHU_MINTS is set in env but cashuMode opt is undefined \u2014 cashu is NOT active. Pass cashuMode, lockPubkey, and db via createDVMHost to enable it."
17055
- })
17158
+ message: void 0
17159
+ }
17056
17160
  );
17057
17161
  }
17058
17162
  const envMaybe = opts.env;
@@ -17060,12 +17164,12 @@ async function createDVMServer(descriptor, opts) {
17060
17164
  const platformUrl = opts.platformUrl ?? envMaybe.DVMKIT_PLATFORM_URL;
17061
17165
  const dvmId = opts.dvmId;
17062
17166
  if (!opts.onJobCompleted && platformToken && platformUrl && dvmId && opts.db) {
17063
- const { RevenueReporter } = await import("./revenue-reporter-O75BGYFK.js");
17167
+ const { RevenueReporter } = await import("./revenue-reporter-VN4WYN74.js");
17064
17168
  const reporter = new RevenueReporter(opts.db, platformUrl, platformToken);
17065
17169
  revenueReporter = reporter;
17066
17170
  await reporter.init();
17067
17171
  reporter.startRetryLoop();
17068
- const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-KEMUXEUO.js");
17172
+ const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-TQ3YIFLZ.js");
17069
17173
  payoutReporter = new PayoutReporter({
17070
17174
  dvmId,
17071
17175
  db: opts.db,
@@ -17292,8 +17396,12 @@ var DVMServer = class {
17292
17396
  /** Withdraws this mount's Tempo session capability from the poll. */
17293
17397
  undeclareSessionCapability;
17294
17398
  hostingSweepTimer;
17399
+ diagnosticCapabilityAuthority;
17295
17400
  constructor(descriptor, opts) {
17296
17401
  this.descriptor = descriptor;
17402
+ this.diagnosticCapabilityAuthority = createDiagnosticCapabilityAuthority(
17403
+ Object.keys(descriptor.capabilities)
17404
+ );
17297
17405
  this.pricingCurrency = descriptor.currency ?? "usd";
17298
17406
  this.opts = opts;
17299
17407
  this.publicOrigin = resolvePublicOrigin(opts.env.DVMKIT_PUBLIC_URL);
@@ -17378,12 +17486,12 @@ var DVMServer = class {
17378
17486
  if (opts.hostingControlInstance) {
17379
17487
  this.hostingSweepTimer = setInterval(() => {
17380
17488
  void this.sweepHostingDeadline().catch((error) => {
17381
- console.error("Hosting deadline sweep failed:", error);
17489
+ diagnosticConsole.error("Hosting deadline sweep failed:", error);
17382
17490
  });
17383
17491
  }, 1e3);
17384
17492
  this.hostingSweepTimer.unref();
17385
17493
  void this.sweepHostingDeadline().catch((error) => {
17386
- console.error("Hosting deadline sweep failed:", error);
17494
+ diagnosticConsole.error("Hosting deadline sweep failed:", error);
17387
17495
  });
17388
17496
  }
17389
17497
  if (this.ownsMintHealthTracker) this.mintHealthTracker?.start();
@@ -17432,12 +17540,10 @@ var DVMServer = class {
17432
17540
  const control = this.opts.hostingControlInstance;
17433
17541
  if (!control) return;
17434
17542
  const status = await control.status();
17435
- if (status.state !== "draining" || status.deadlineMs === null || Date.now() < status.deadlineMs)
17436
- return;
17437
17543
  const store = this.jobManager.store;
17438
17544
  if (!(store instanceof PostgresJobStore)) return;
17439
17545
  for (const jobId of status.activeJobIds) {
17440
- if (await store.cancelJobForHosting(jobId, "Hosting drain deadline reached")) {
17546
+ if (await control.dispatchDeadlineReached(jobId) && await store.cancelJobForHosting(jobId, "Hosting drain deadline reached")) {
17441
17547
  await this.jobManager.finalizeStoredTerminal(jobId);
17442
17548
  }
17443
17549
  }
@@ -17466,7 +17572,6 @@ var DVMServer = class {
17466
17572
  }
17467
17573
  registerRoutes() {
17468
17574
  const dvmSlug = this.descriptor.name;
17469
- const builderPubkey = this.opts.builder?.pubkey;
17470
17575
  this.app.use("*", async (c, next) => {
17471
17576
  const raw = c.req.header("traceparent");
17472
17577
  const parsed = raw ? parseTraceparent(raw) : null;
@@ -17475,12 +17580,12 @@ var DVMServer = class {
17475
17580
  spanId: parsed ? parsed.parentSpanId : null,
17476
17581
  dimensions: {},
17477
17582
  service: `isolate-${dvmSlug}`,
17478
- flags: parsed?.flags ?? 1
17583
+ flags: parsed?.flags ?? 1,
17584
+ diagnosticCapabilityAuthority: this.diagnosticCapabilityAuthority
17479
17585
  };
17480
17586
  return withTraceContext(traceCtx, async () => {
17481
17587
  if (this.opts.dvmId) pinDimension("dvm_id", this.opts.dvmId);
17482
17588
  pinDimension("dvm_slug", dvmSlug);
17483
- if (builderPubkey) pinDimension("builder_id", builderPubkey);
17484
17589
  await next();
17485
17590
  });
17486
17591
  });
@@ -17689,21 +17794,21 @@ var DVMServer = class {
17689
17794
  this.tempoSweepInFlight = true;
17690
17795
  void sweep().then((result) => {
17691
17796
  if (result.settled > 0 || result.closeRequested > 0 || result.inFlight > 0) {
17692
- console.info(
17693
- JSON.stringify({
17797
+ diagnosticConsole.info(
17798
+ {
17694
17799
  level: "tempo_routine_sweep",
17695
17800
  dvm_id: this.opts.dvmId,
17696
17801
  ...result
17697
- })
17802
+ }
17698
17803
  );
17699
17804
  }
17700
- }).catch((err) => {
17701
- console.warn(
17702
- JSON.stringify({
17805
+ }).catch((_err) => {
17806
+ diagnosticConsole.warn(
17807
+ {
17703
17808
  level: "tempo_routine_sweep_failed",
17704
17809
  dvm_id: this.opts.dvmId,
17705
- error: err instanceof Error ? err.message : String(err)
17706
- })
17810
+ error: void 0
17811
+ }
17707
17812
  );
17708
17813
  }).finally(() => {
17709
17814
  this.tempoSweepInFlight = false;
@@ -17795,8 +17900,8 @@ var DVMServer = class {
17795
17900
  getBinding: (channelId) => recoverPostgres(channelId, () => getBinding(channelId)),
17796
17901
  settle: (channelId) => recoverPostgres(channelId, () => settle(channelId))
17797
17902
  });
17798
- console.info(
17799
- JSON.stringify({
17903
+ diagnosticConsole.info(
17904
+ {
17800
17905
  level: "tempo_close_event",
17801
17906
  dvm_id: this.opts.dvmId,
17802
17907
  chain_id: locator.chainId,
@@ -17806,10 +17911,10 @@ var DVMServer = class {
17806
17911
  outcome: result.outcome.outcome,
17807
17912
  channel_id: result.outcome.channelId,
17808
17913
  ...result.outcome.outcome === "retryable_failure" && {
17809
- error: result.outcome.error.slice(0, 500)
17914
+ error: void 0
17810
17915
  }
17811
17916
  } : { outcome: result.status, reason: result.reason }
17812
- })
17917
+ }
17813
17918
  );
17814
17919
  return c.json(
17815
17920
  result.status === "ok" ? { status: "ok", ...serializeTempoSettlementOutcome(result.outcome) } : {
@@ -18516,11 +18621,11 @@ var DVMServer = class {
18516
18621
  return c.json(res2);
18517
18622
  } catch (err) {
18518
18623
  if (err instanceof InvalidQuoteResultError) {
18519
- console.error("invalid QuoteResult from onQuote:", err);
18624
+ diagnosticConsole.error("invalid QuoteResult from onQuote:", err);
18520
18625
  return c.json({ error: { code: err.code, message: err.message } }, 500);
18521
18626
  }
18522
18627
  if (err instanceof QuoteCurrencyMismatchError) {
18523
- console.error("quote currency mismatch:", err);
18628
+ diagnosticConsole.error("quote currency mismatch:", err);
18524
18629
  return c.json({ error: { code: err.code, message: err.message } }, 500);
18525
18630
  }
18526
18631
  if (err instanceof InvalidCurrencyError) {
@@ -18531,7 +18636,7 @@ var DVMServer = class {
18531
18636
  const structured = pickStructuredError(err);
18532
18637
  if (structured) return c.json({ error: structured }, 400);
18533
18638
  const message = err instanceof Error ? err.message : String(err);
18534
- console.error("quote handler failed:", err);
18639
+ diagnosticConsole.error("quote handler failed:", err);
18535
18640
  return c.json({ error: { code: "internal", message } }, 500);
18536
18641
  }
18537
18642
  }
@@ -18965,14 +19070,25 @@ var DVMServer = class {
18965
19070
  payment = recoveredPayment;
18966
19071
  resumedAcceptedPayment = true;
18967
19072
  }
18968
- let priceMsats = resumeOnly ? payment.paidMsats || void 0 : await this.jobManager.currentPriceMsats(capabilityName);
19073
+ const skipPayment = devModeSkipsPaymentVerification(this.opts);
19074
+ let priceMsats = resumeOnly ? payment.paidMsats || void 0 : void 0;
19075
+ if (!resumeOnly && !skipPayment) {
19076
+ try {
19077
+ priceMsats = await this.jobManager.currentPriceMsats(capabilityName);
19078
+ } catch (err) {
19079
+ const fxErr = pickFxRateUnavailable(err);
19080
+ if (fxErr) return c.json({ error: fxErr }, 503);
19081
+ throw err;
19082
+ }
19083
+ }
18969
19084
  let dynamicUpfront;
18970
- if (!resumeOnly && priceMsats === void 0 && cap.onQuote) {
19085
+ if (!resumeOnly && cap.price === void 0 && priceMsats === void 0 && cap.onQuote) {
18971
19086
  const dyn = await this.computeDynamicPrice(
18972
19087
  cap.onQuote,
18973
19088
  parsedInput,
18974
19089
  normalisedBody,
18975
- authPubkey
19090
+ authPubkey,
19091
+ skipPayment
18976
19092
  );
18977
19093
  if (dyn.error) return c.json(dyn.error.body, dyn.error.status);
18978
19094
  priceMsats = dyn.priceMsats;
@@ -19004,7 +19120,6 @@ var DVMServer = class {
19004
19120
  }
19005
19121
  }
19006
19122
  }
19007
- const skipPayment = devModeSkipsPaymentVerification(this.opts);
19008
19123
  if (!skipPayment && !resumedAcceptedPayment) {
19009
19124
  const railOpts = await this.railVerifyOpts(c);
19010
19125
  hostingPaymentMayHaveLanded = Boolean(
@@ -19193,10 +19308,8 @@ var DVMServer = class {
19193
19308
  await this.opts.hostingControlInstance.finishAdmission(hostingAdmissionId, "accepted", jobId);
19194
19309
  hostingAdmissionAccepted = true;
19195
19310
  }
19196
- const reservedDrainDeadline = this.opts.hostingControlInstance ? await this.opts.hostingControlInstance.jobDeadline(jobId) : null;
19197
- const hostingStatus = await this.opts.hostingControlInstance?.status();
19198
- const currentDrainDeadline = hostingStatus?.state === "draining" ? hostingStatus.deadlineMs : null;
19199
- if (reservedDrainDeadline !== null && Date.now() >= reservedDrainDeadline || currentDrainDeadline !== null && currentDrainDeadline !== void 0 && Date.now() >= currentDrainDeadline) {
19311
+ await this.opts.hostingControlInstance?.status();
19312
+ if (this.opts.hostingControlInstance && await this.opts.hostingControlInstance.dispatchDeadlineReached(jobId)) {
19200
19313
  const store = jm.store;
19201
19314
  if (store instanceof PostgresJobStore && await store.cancelJobForHosting(jobId, "Hosting drain deadline reached")) {
19202
19315
  await jm.finalizeStoredTerminal(jobId);
@@ -19247,7 +19360,7 @@ var DVMServer = class {
19247
19360
  if (!funding || !onCreditFunded || !this.opts.dvmId) return;
19248
19361
  Promise.resolve(onCreditFunded(creditDepositPayload(this.opts.dvmId, funding))).catch(
19249
19362
  (err) => {
19250
- console.error(`[${funding.creditId}] Deposit reporting failed:`, err);
19363
+ diagnosticConsole.error(`[${funding.creditId}] Deposit reporting failed:`, err);
19251
19364
  }
19252
19365
  );
19253
19366
  }
@@ -19278,7 +19391,7 @@ var DVMServer = class {
19278
19391
  kind: "short_pay_forfeit"
19279
19392
  })
19280
19393
  ).catch((err) => {
19281
- console.error(`[${forfeit.paymentId}] Short-pay forfeit reporting failed:`, err);
19394
+ diagnosticConsole.error(`[${forfeit.paymentId}] Short-pay forfeit reporting failed:`, err);
19282
19395
  });
19283
19396
  }
19284
19397
  /**
@@ -19294,13 +19407,13 @@ var DVMServer = class {
19294
19407
  const pubkeyMatches = this.descriptor.auth === void 0 || prior.requesterPubkey !== void 0 && prior.requesterPubkey === opts.callerPubkey;
19295
19408
  const requesterMatches = prior.requesterId === c.get("requesterId");
19296
19409
  if (!bodyMatches || !pubkeyMatches || !requesterMatches) {
19297
- console.warn(
19298
- JSON.stringify({
19410
+ diagnosticConsole.warn(
19411
+ {
19299
19412
  level: "paid_submit_replay_refused",
19300
19413
  jobId: prior.id,
19301
19414
  requestId: opts.requestId,
19302
19415
  reason: !bodyMatches ? "fingerprint_mismatch" : !pubkeyMatches ? "pubkey_mismatch" : "requester_mismatch"
19303
- })
19416
+ }
19304
19417
  );
19305
19418
  return void 0;
19306
19419
  }
@@ -19323,14 +19436,14 @@ var DVMServer = class {
19323
19436
  }
19324
19437
  const prior = jobId ? await this.jobManager.store.get(jobId) : void 0;
19325
19438
  if (!prior) {
19326
- console.warn(
19327
- JSON.stringify({
19439
+ diagnosticConsole.warn(
19440
+ {
19328
19441
  level: "drawn_job_recovery_refused",
19329
19442
  creditId: opts.creditId,
19330
19443
  drawId: opts.drawId,
19331
19444
  jobId,
19332
19445
  reason: "job_not_found"
19333
- })
19446
+ }
19334
19447
  );
19335
19448
  return void 0;
19336
19449
  }
@@ -19338,14 +19451,14 @@ var DVMServer = class {
19338
19451
  const pubkeyMatches = prior.requesterPubkey !== void 0 && prior.requesterPubkey === opts.callerPubkey;
19339
19452
  const requesterMatches = prior.requesterId === c.get("requesterId");
19340
19453
  if (!bodyMatches || !pubkeyMatches || !requesterMatches) {
19341
- console.warn(
19342
- JSON.stringify({
19454
+ diagnosticConsole.warn(
19455
+ {
19343
19456
  level: "paid_submit_replay_refused",
19344
19457
  jobId: prior.id,
19345
19458
  creditId: opts.creditId,
19346
19459
  drawId: opts.drawId,
19347
19460
  reason: !bodyMatches ? "fingerprint_mismatch" : !pubkeyMatches ? "pubkey_mismatch" : "requester_mismatch"
19348
- })
19461
+ }
19349
19462
  );
19350
19463
  return void 0;
19351
19464
  }
@@ -19368,15 +19481,15 @@ var DVMServer = class {
19368
19481
  });
19369
19482
  if (!marker) continue;
19370
19483
  if (marker.jobId !== opts.jobId) {
19371
- console.warn(
19372
- JSON.stringify({
19484
+ diagnosticConsole.warn(
19485
+ {
19373
19486
  level: "request_acceptance_recovery_refused",
19374
19487
  rail,
19375
19488
  paymentId: opts.paymentId,
19376
19489
  expectedJobId: opts.jobId,
19377
19490
  recordedJobId: marker.jobId,
19378
19491
  reason: "job_id_mismatch"
19379
- })
19492
+ }
19380
19493
  );
19381
19494
  return void 0;
19382
19495
  }
@@ -19407,14 +19520,14 @@ var DVMServer = class {
19407
19520
  paymentId: opts.paymentId
19408
19521
  });
19409
19522
  if (payment) {
19410
- console.warn(
19411
- JSON.stringify({
19523
+ diagnosticConsole.warn(
19524
+ {
19412
19525
  level: "request_acceptance_recovered",
19413
19526
  jobId: opts.expectedJobId,
19414
19527
  creditId: opts.creditId,
19415
19528
  drawId: opts.drawId,
19416
19529
  rail: payment.paymentRail
19417
- })
19530
+ }
19418
19531
  );
19419
19532
  }
19420
19533
  return payment;
@@ -19422,9 +19535,9 @@ var DVMServer = class {
19422
19535
  /**
19423
19536
  * Recompute dynamic upfront pricing from parsed job input, applying the quote
19424
19537
  * schema separately. Refuse invalid input/results, currency mismatch or missing
19425
- * FX rather than running without a price (400/500/503 as classified below).
19538
+ * FX when payment needs a price (400/500/503 as classified below).
19426
19539
  */
19427
- async computeDynamicPrice(onQuote, parsedInput, body, callerPubkey) {
19540
+ async computeDynamicPrice(onQuote, parsedInput, body, callerPubkey, skipRateConversion = false) {
19428
19541
  let data = parsedInput;
19429
19542
  if (isZodSchema(onQuote.schema)) {
19430
19543
  const parsed = onQuote.schema.safeParse(parsedInput);
@@ -19456,6 +19569,9 @@ var DVMServer = class {
19456
19569
  if (!supported.includes(upfrontCurrency)) {
19457
19570
  throw new UnsupportedCurrencyError(upfrontCurrency, supported);
19458
19571
  }
19572
+ if (skipRateConversion) {
19573
+ return { upfront: { amount: validated.upfront.amount, currency: upfrontCurrency } };
19574
+ }
19459
19575
  const fx = await this.fxFetcher.fetch();
19460
19576
  const priceMsats = fiatToSatsCeil(validated.upfront.amount, fxRateFor(fx, upfrontCurrency)) * 1e3;
19461
19577
  return {
@@ -19472,7 +19588,7 @@ var DVMServer = class {
19472
19588
  };
19473
19589
  }
19474
19590
  if (err instanceof QuoteCurrencyMismatchError) {
19475
- console.error("quote currency mismatch:", err);
19591
+ diagnosticConsole.error("quote currency mismatch:", err);
19476
19592
  return {
19477
19593
  error: { body: { error: err.code, message: err.message }, status: 500 }
19478
19594
  };
@@ -20234,13 +20350,13 @@ var PlatformTempoObserverHealth = class {
20234
20350
  withhold(reason) {
20235
20351
  if (!this.withheldLogged) {
20236
20352
  this.withheldLogged = true;
20237
- console.warn(
20238
- JSON.stringify({
20353
+ diagnosticConsole.warn(
20354
+ {
20239
20355
  level: "warn",
20240
20356
  event: "tempo_session_withheld",
20241
- message: "Tempo session funding withheld: the platform's close observer is not confirmed healthy. tempo/charge is unaffected.",
20357
+ message: void 0,
20242
20358
  reason
20243
- })
20359
+ }
20244
20360
  );
20245
20361
  }
20246
20362
  return false;