@dvmkit/sdk 0.16.0 → 0.16.2

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.
@@ -428,6 +428,14 @@ async function insertAccumulatorRows(db, args) {
428
428
  client.release();
429
429
  }
430
430
  }
431
+ async function hasAccumulatedProof(db, dvmId, secrets) {
432
+ if (secrets.length === 0) return false;
433
+ const { rows: rows2 } = await db.query(
434
+ `SELECT 1 FROM wallet_accumulator WHERE dvm_id = $1 AND proof_secret_hash = ANY($2::text[]) LIMIT 1`,
435
+ [dvmId, secrets.map(hashProofSecret)]
436
+ );
437
+ return rows2.length > 0;
438
+ }
431
439
  async function listPendingBatches(db, dvmId) {
432
440
  const { rows: rows2 } = await db.query(
433
441
  `SELECT id, lock_pubkey, mint_url, proof_keyset_id, proof_secret, proof_c, proof_amount, proof_dleq, received_at, melt_quote_id, t_expire
@@ -3341,7 +3349,11 @@ import {
3341
3349
  Amount as Amount2,
3342
3350
  CheckStateEnum,
3343
3351
  getP2PKExpectedWitnessPubkeys,
3352
+ getSecretData,
3353
+ getSecretKind,
3344
3354
  getTagInt,
3355
+ getTags,
3356
+ parseP2PKSecret,
3345
3357
  verifyDleqIfPresent
3346
3358
  } from "@cashu/cashu-ts";
3347
3359
  function valueCashuFunding(wallet, proofs) {
@@ -3358,6 +3370,91 @@ function valueCashuFunding(wallet, proofs) {
3358
3370
  netMsats: netSats.multiplyBy(1e3).toNumber()
3359
3371
  };
3360
3372
  }
3373
+ var CASHU_MIN_LOCKTIME_SECONDS = 604800;
3374
+ var CASHU_LOCKTIME_RESUME_MARGIN_SECONDS = 86400;
3375
+ var P2PK_TAG_KEYS = /* @__PURE__ */ new Set(["locktime", "refund", "pubkeys", "n_sigs", "sigflag", "n_sigs_refund"]);
3376
+ var SINGLE_VALUE_TAG_KEYS = /* @__PURE__ */ new Set(["locktime", "n_sigs", "sigflag", "n_sigs_refund"]);
3377
+ function assessCashuLock(secret, lockPubkeys, nowSec) {
3378
+ try {
3379
+ parseP2PKSecret(secret);
3380
+ if (getSecretKind(secret) !== "P2PK") throw new Error("not P2PK");
3381
+ } catch {
3382
+ return { kind: "rejected", code: "not_p2pk_locked", message: "Proof secret is not a NUT-11 P2PK secret." };
3383
+ }
3384
+ const dvmKeyFor = (x) => x === void 0 ? void 0 : lockPubkeys.find((pk) => compressedX(pk) === x);
3385
+ const data = getSecretData(secret).data;
3386
+ const dataX = typeof data === "string" ? compressedX(data) : void 0;
3387
+ const lockPubkey = dvmKeyFor(dataX);
3388
+ if (!dataX || !lockPubkey) {
3389
+ return {
3390
+ kind: "rejected",
3391
+ code: "wrong_lock_pubkey",
3392
+ message: "Proof is not locked to one of this DVM's active lock pubkeys, spelled as a 33-byte compressed hex key."
3393
+ };
3394
+ }
3395
+ const notExclusive = (message, locktimeBelowFloor) => ({
3396
+ kind: "rejected",
3397
+ code: "lock_not_exclusive",
3398
+ message,
3399
+ ...locktimeBelowFloor && { locktimeBelowFloor }
3400
+ });
3401
+ try {
3402
+ getP2PKExpectedWitnessPubkeys(secret);
3403
+ } catch (err) {
3404
+ return notExclusive(`Proof carries an unreadable spending condition: ${err instanceof Error ? err.message : String(err)}`);
3405
+ }
3406
+ const tags = /* @__PURE__ */ new Map();
3407
+ for (const tag of getTags(secret)) {
3408
+ if (!Array.isArray(tag) || !tag.every((item) => typeof item === "string")) {
3409
+ return notExclusive("Proof carries a malformed tag.");
3410
+ }
3411
+ const [key, ...values] = tag;
3412
+ if (key === void 0 || !P2PK_TAG_KEYS.has(key)) return notExclusive(`Proof carries the unsupported tag ${JSON.stringify(key)}.`);
3413
+ if (tags.has(key)) return notExclusive(`Proof repeats the ${key} tag.`);
3414
+ if (values.length === 0) return notExclusive(`Proof carries a ${key} tag without a value.`);
3415
+ if (SINGLE_VALUE_TAG_KEYS.has(key) && values.length !== 1) return notExclusive(`Proof's ${key} tag must carry exactly one value.`);
3416
+ tags.set(key, values);
3417
+ }
3418
+ const sigflag = tags.get("sigflag")?.[0];
3419
+ if (sigflag !== void 0 && sigflag !== "SIG_INPUTS") {
3420
+ return notExclusive(`Proof requires sigflag ${sigflag}; this DVM accepts SIG_INPUTS only.`);
3421
+ }
3422
+ const nSigs = tags.get("n_sigs")?.[0];
3423
+ if (nSigs !== void 0 && nSigs !== "1") {
3424
+ return notExclusive(`Proof requires n_sigs=${nSigs}; this DVM accepts a single-signature lock only.`);
3425
+ }
3426
+ const mainX = [dataX];
3427
+ for (const key of tags.get("pubkeys") ?? []) {
3428
+ const x = compressedX(key);
3429
+ if (!x || !dvmKeyFor(x)) return notExclusive("Proof's pubkeys tag names a key other than this DVM's lock pubkeys.");
3430
+ if (mainX.includes(x)) return notExclusive("Proof repeats a key across data and pubkeys.");
3431
+ mainX.push(x);
3432
+ }
3433
+ const refundX = [];
3434
+ for (const key of tags.get("refund") ?? []) {
3435
+ const x = compressedX(key);
3436
+ if (!x) return notExclusive("Proof's refund tag names a key that is not a 33-byte compressed hex key.");
3437
+ if (refundX.includes(x)) return notExclusive("Proof repeats a key in its refund tag.");
3438
+ refundX.push(x);
3439
+ }
3440
+ const nSigsRefund = tags.get("n_sigs_refund")?.[0];
3441
+ if (nSigsRefund !== void 0 && !(/^[1-9][0-9]*$/.test(nSigsRefund) && Number(nSigsRefund) <= refundX.length)) {
3442
+ return notExclusive(`Proof's n_sigs_refund ${nSigsRefund} is not a count between 1 and its number of refund keys.`);
3443
+ }
3444
+ const locktimeValue = tags.get("locktime")?.[0];
3445
+ if (locktimeValue !== void 0) {
3446
+ const locktime = /^(0|[1-9][0-9]*)$/.test(locktimeValue) ? Number(locktimeValue) : NaN;
3447
+ if (!Number.isSafeInteger(locktime)) return notExclusive(`Proof's locktime ${locktimeValue} is not a unix-seconds integer.`);
3448
+ const floor = nowSec + CASHU_MIN_LOCKTIME_SECONDS - CASHU_LOCKTIME_RESUME_MARGIN_SECONDS;
3449
+ if (locktime < floor) {
3450
+ return notExclusive(
3451
+ `Proof locktime ${locktime} is earlier than the accepted floor ${floor} (unix seconds).`,
3452
+ true
3453
+ );
3454
+ }
3455
+ }
3456
+ return { kind: "exclusive", lockPubkey };
3457
+ }
3361
3458
  async function acceptAccumulatorPayment(opts) {
3362
3459
  if (opts.disposable && !opts.mints.every(isTestMintUrl)) {
3363
3460
  throw new Error("Disposable Cashu accepts only known test or loopback mints.");
@@ -3409,41 +3506,26 @@ async function acceptAccumulatorPayment(opts) {
3409
3506
  mintUrl,
3410
3507
  paidMsats: valuation.netMsats
3411
3508
  };
3509
+ const nowSec = Math.floor(Date.now() / 1e3);
3412
3510
  const tExpireMsByIndex = [];
3413
3511
  const matchedLockPubkeyByIndex = [];
3512
+ let belowFloorMessage;
3414
3513
  for (const p of proofs) {
3415
- let allowed;
3416
- try {
3417
- allowed = getP2PKExpectedWitnessPubkeys(p.secret);
3418
- } catch {
3419
- return {
3420
- kind: "rejected",
3421
- code: "not_p2pk_locked",
3422
- message: "Proof secret is not a NUT-11 P2PK secret."
3423
- };
3424
- }
3425
- if (allowed.length === 0) {
3426
- return {
3427
- kind: "rejected",
3428
- code: "not_p2pk_locked",
3429
- message: "Proof is unlocked or the P2PK lock has expired."
3430
- };
3431
- }
3432
- const allowedNormalised = allowed.map(toLockPubkey);
3433
- if (opts.disposable && (allowedNormalised.length !== 1 || (getTagInt(p.secret, "n_sigs") ?? 1) !== 1)) {
3434
- return { kind: "rejected", code: "not_p2pk_locked", message: "Disposable Cashu requires an exclusive single-signature P2PK lock." };
3514
+ const lock = assessCashuLock(p.secret, accepted, nowSec);
3515
+ if (lock.kind === "rejected") {
3516
+ if (!lock.locktimeBelowFloor) return { kind: "rejected", code: lock.code, message: lock.message };
3517
+ belowFloorMessage ??= lock.message;
3518
+ continue;
3435
3519
  }
3436
- const match = accepted.find((pk) => allowedNormalised.includes(pk));
3437
- if (!match) {
3438
- return {
3439
- kind: "rejected",
3440
- code: "wrong_lock_pubkey",
3441
- message: "Proof is not locked to one of this DVM's active lock pubkeys."
3442
- };
3443
- }
3444
- matchedLockPubkeyByIndex.push(match);
3520
+ matchedLockPubkeyByIndex.push(lock.lockPubkey);
3445
3521
  tExpireMsByIndex.push(parseNut11LocktimeMs(p.secret));
3446
3522
  }
3523
+ if (belowFloorMessage) {
3524
+ const secrets = proofs.map((p) => p.secret);
3525
+ const banked = opts.disposable ? await opts.disposable.hasAccepted(secrets) : opts.db ? await hasAccumulatedProof(opts.db, opts.dvmId, secrets) : false;
3526
+ if (banked) return replayRejected();
3527
+ return { kind: "rejected", code: "lock_not_exclusive", message: belowFloorMessage };
3528
+ }
3447
3529
  try {
3448
3530
  const walletProvider = opts.walletProvider ?? getWallet;
3449
3531
  const wallet = await walletProvider(mintUrl);
@@ -3516,13 +3598,7 @@ async function acceptAccumulatorPayment(opts) {
3516
3598
  await insertAccumulatorRows(opts.db, insertArgs);
3517
3599
  }
3518
3600
  } catch (err) {
3519
- if (err instanceof AccumulatorReplayError) {
3520
- return {
3521
- kind: "rejected",
3522
- code: "replay_rejected",
3523
- message: "Proofs or request id already accepted at this DVM."
3524
- };
3525
- }
3601
+ if (err instanceof AccumulatorReplayError) return replayRejected();
3526
3602
  throw err;
3527
3603
  }
3528
3604
  return {
@@ -3534,6 +3610,13 @@ async function acceptAccumulatorPayment(opts) {
3534
3610
  mintUrl
3535
3611
  };
3536
3612
  }
3613
+ function replayRejected() {
3614
+ return {
3615
+ kind: "rejected",
3616
+ code: "replay_rejected",
3617
+ message: "Proofs or request id already accepted at this DVM."
3618
+ };
3619
+ }
3537
3620
  function parseNut11LocktimeMs(secret) {
3538
3621
  try {
3539
3622
  const secs = getTagInt(secret, "locktime");
@@ -3542,6 +3625,9 @@ function parseNut11LocktimeMs(secret) {
3542
3625
  return null;
3543
3626
  }
3544
3627
  }
3628
+ function compressedX(raw) {
3629
+ return /^0[23][0-9a-fA-F]{64}$/.test(raw) ? raw.slice(2).toLowerCase() : void 0;
3630
+ }
3545
3631
 
3546
3632
  // src/sdk/server/payment.ts
3547
3633
  var UPFRONT_CHALLENGE_TTL_MS = 5 * 60 * 1e3;
@@ -4771,6 +4857,11 @@ var PAYMENT_ERROR_COPY = {
4771
4857
  hint: "Re-fetch this service's current lock key from /v1/info and lock a fresh token to it.",
4772
4858
  retryable: false
4773
4859
  },
4860
+ lock_not_exclusive: {
4861
+ display: "The payment token's lock would let a key other than this service's spend it, so it wasn't accepted. Nothing was charged.",
4862
+ hint: "Lock a fresh token with data set to cashu.lock_pubkeys[0] from /v1/info as a 33-byte compressed hex key. Use only the locktime, refund, pubkeys, n_sigs, sigflag and n_sigs_refund tags, each once and with a value: pubkeys may list only other cashu.lock_pubkeys entries, n_sigs must be 1, sigflag SIG_INPUTS, refund keys compressed and distinct, n_sigs_refund at most the number of refund keys, and any locktime at least cashu.min_locktime minus 24 hours in the future.",
4863
+ retryable: false
4864
+ },
4774
4865
  proof_not_unspent: {
4775
4866
  display: "The payment token has already been spent. Nothing was charged.",
4776
4867
  hint: "Those funds are gone; pay with a fresh token.",
@@ -22455,7 +22546,7 @@ var DVMServer = class {
22455
22546
  mints,
22456
22547
  lock_pubkeys: activePubkeySet(active),
22457
22548
  lock_pubkey_grace_seconds: this.graceSeconds(),
22458
- min_locktime: 604800,
22549
+ min_locktime: CASHU_MIN_LOCKTIME_SECONDS,
22459
22550
  canonical_id: this.opts.canonicalDvmId ?? this.opts.dvmId ?? null
22460
22551
  };
22461
22552
  }
@@ -339,6 +339,8 @@ interface PaidJobCompletion {
339
339
  /** Typed transaction boundary; proof ownership and accounting commit together. */
340
340
  interface DisposableCashuCommit {
341
341
  commit(requestId: string, proofs: Proof[], account: (ledger: CreditLedgerLike) => Promise<void>): Promise<void>;
342
+ /** Whether any of these proof secrets has already been committed. */
343
+ hasAccepted(secrets: string[]): Promise<boolean>;
342
344
  }
343
345
 
344
346
  interface CreditExpirySweepOpts {
@@ -1159,7 +1161,7 @@ declare class MemoryProcessedPaymentStore implements ProcessedPaymentStore {
1159
1161
  * so the payment-error builder in `payment.ts` folds them into `PaymentErrorCode`
1160
1162
  * and keeps display/hint/retryable copy in lockstep with this union.
1161
1163
  */
1162
- type AccumulatorRejectionCode = "missing_request_id" | "missing_lock_pubkey" | "not_p2pk_locked" | "wrong_lock_pubkey" | "proof_not_unspent" | "proof_pending" | "replay_rejected" | "mint_unreachable" | "invalid_token";
1164
+ type AccumulatorRejectionCode = "missing_request_id" | "missing_lock_pubkey" | "not_p2pk_locked" | "wrong_lock_pubkey" | "lock_not_exclusive" | "proof_not_unspent" | "proof_pending" | "replay_rejected" | "mint_unreachable" | "invalid_token";
1163
1165
 
1164
1166
  type X402ExactSettlementStatus = "prepared" | "submitting" | "settled" | "local_committed" | "ambiguous" | "rejected" | "complete";
1165
1167
  /** Serializable local economic effect that follows an exact settlement. */
@@ -6,8 +6,8 @@ import { Env, BlankSchema } from 'hono/types';
6
6
  import { Pool } from 'pg';
7
7
  export { Pool } from 'pg';
8
8
  import { g as getWallet } from '../wallet-Dwjs5n_M.js';
9
- import { C as ConsumedCredentialStore, L as LockPubkeyStateLoader } from '../credit-menu-B239nIY5.js';
10
- export { A as AccumulatorPool, a as AppEnv, b as CreditFundingReport, D as DEFAULT_LOCK_PUBKEY_GRACE_SECONDS, F as FiatDenomination, c as FiatDenominationFailure, d as FundOnlyRequest, I as IncomingPaymentOpts, J as JobCancelledError, e as LockPubkeyPool, f as LockPubkeyState, M as MintHealthTracker, P as PAYMENT_PROOF_KEYS, g as PaymentErrorCode, h as PaymentErrorDetail, i as PaymentInfo, j as PostgresTempoChargeStore, R as ReporterBannerOpts, k as ResolvedFx, l as RevenueBootCheckOpts, S as SDKServerOpts, m as ServerJob, n as ShortPayForfeit, T as TempoChannelReport, o as TempoObserverHealth, p as TempoSessionChannelMismatchError, U as UpfrontPaymentOpts, V as VerifiedIncomingPayment, q as VerifyIncomingSnapshot, X as X402BatchChannelObservation, r as X402FacilitatorHealth, s as X402SettlementEvidenceOutcome, t as X402SettlementRepair, u as X402SettlementRepairRefusal, v as X402SettlementRepaired, w as X402WedgedSettlement, x as X402WedgedSettlementPage, y as X402_BATCH_SETTLEMENT_MAINNET_NETWORK, z as abortJob, B as activePubkeySet, E as applyPaymentInfoToJob, G as assertRevenueReporterReady, H as buildPaymentErrorResponse, K as clearAccumulatorForDvm, N as createDVMServer, O as creditDepositPayload, Q as derivedFundCreditId, W as devModeSkipsPaymentVerification, Y as fromJobRecord, Z as fundedMicroFor, _ as hasPaymentProof, $ as hashLockKey, a0 as implicitCreditId, a1 as initLockPubkeyTable, a2 as initWalletAccumulatorTable, a3 as insertAccumulatorRows, a4 as isDerivedCreditId, a5 as isTerminal, a6 as isYieldMessage, a7 as issueUpfrontChallenges, a8 as loadLockPubkeyState, a9 as msatsToFiatMicro, aa as paymentErrorBody, ab as pinAskFiat, ac as priceFiatMicro, ad as processIncomingPayment, ae as providerMessage, af as pruneRetired, ag as repairX402ExactSettlementEffect, ah as resolveFxSnapshot, ai as resolvePriceFiat, aj as revenueReporterBannerState, ak as rotateLockPubkey, al as seedLockPubkeyState, am as toCreditTerms, an as toJobRecord, ao as unknownRouteNotFound, ap as verifyIncomingPayment, aq as verifyTempoSessionManagementCredential, ar as verifyUpfrontPayment, as as x402RequiredUsdcMicro, at as x402SettledShare } from '../credit-menu-B239nIY5.js';
9
+ import { C as ConsumedCredentialStore, L as LockPubkeyStateLoader } from '../credit-menu-BfXaeHgR.js';
10
+ export { A as AccumulatorPool, a as AppEnv, b as CreditFundingReport, D as DEFAULT_LOCK_PUBKEY_GRACE_SECONDS, F as FiatDenomination, c as FiatDenominationFailure, d as FundOnlyRequest, I as IncomingPaymentOpts, J as JobCancelledError, e as LockPubkeyPool, f as LockPubkeyState, M as MintHealthTracker, P as PAYMENT_PROOF_KEYS, g as PaymentErrorCode, h as PaymentErrorDetail, i as PaymentInfo, j as PostgresTempoChargeStore, R as ReporterBannerOpts, k as ResolvedFx, l as RevenueBootCheckOpts, S as SDKServerOpts, m as ServerJob, n as ShortPayForfeit, T as TempoChannelReport, o as TempoObserverHealth, p as TempoSessionChannelMismatchError, U as UpfrontPaymentOpts, V as VerifiedIncomingPayment, q as VerifyIncomingSnapshot, X as X402BatchChannelObservation, r as X402FacilitatorHealth, s as X402SettlementEvidenceOutcome, t as X402SettlementRepair, u as X402SettlementRepairRefusal, v as X402SettlementRepaired, w as X402WedgedSettlement, x as X402WedgedSettlementPage, y as X402_BATCH_SETTLEMENT_MAINNET_NETWORK, z as abortJob, B as activePubkeySet, E as applyPaymentInfoToJob, G as assertRevenueReporterReady, H as buildPaymentErrorResponse, K as clearAccumulatorForDvm, N as createDVMServer, O as creditDepositPayload, Q as derivedFundCreditId, W as devModeSkipsPaymentVerification, Y as fromJobRecord, Z as fundedMicroFor, _ as hasPaymentProof, $ as hashLockKey, a0 as implicitCreditId, a1 as initLockPubkeyTable, a2 as initWalletAccumulatorTable, a3 as insertAccumulatorRows, a4 as isDerivedCreditId, a5 as isTerminal, a6 as isYieldMessage, a7 as issueUpfrontChallenges, a8 as loadLockPubkeyState, a9 as msatsToFiatMicro, aa as paymentErrorBody, ab as pinAskFiat, ac as priceFiatMicro, ad as processIncomingPayment, ae as providerMessage, af as pruneRetired, ag as repairX402ExactSettlementEffect, ah as resolveFxSnapshot, ai as resolvePriceFiat, aj as revenueReporterBannerState, ak as rotateLockPubkey, al as seedLockPubkeyState, am as toCreditTerms, an as toJobRecord, ao as unknownRouteNotFound, ap as verifyIncomingPayment, aq as verifyTempoSessionManagementCredential, ar as verifyUpfrontPayment, as as x402RequiredUsdcMicro, at as x402SettledShare } from '../credit-menu-BfXaeHgR.js';
11
11
  export { O as OutgoingMessage, S as StaleJobReapable, i as isStaleJobReapable } from '../job-store-CA7u1nHV.js';
12
12
  import { z } from 'zod';
13
13
  export { f as LockPubkeyStoreLockPubkey, t as lockPubkeyStoreToLockPubkey } from '../lightning-backend-BOcopzXk.js';
@@ -61,7 +61,7 @@ import {
61
61
  verifyUpfrontPayment,
62
62
  x402RequiredUsdcMicro,
63
63
  x402SettledShare
64
- } from "../chunk-SGSHDMHP.js";
64
+ } from "../chunk-KERFCBT7.js";
65
65
  import "../chunk-XRLKGCAW.js";
66
66
  import {
67
67
  PayoutReporter
@@ -1,8 +1,8 @@
1
1
  import { ag as CashuMode, bR as CreditLedgerQuerier, bS as CreditDrainEnqueue, bT as HostedSettlementReportObligations, R as ResolvedCreditConfig, bU as DVMAuthScheme, B as SignedRequestDomain, bV as CreditLedgerLike, bW as X402RefundSettlementGate, bX as CreditSnapshot, bY as CreditDrawRefundArgs, bZ as CreditDrawRefundResult, b_ as DrawResult, b$ as X402SettlementStatus, c0 as X402UnresolvedRefund, c1 as GrownDrawResult, c2 as DrawResolution, c3 as FundingRecord, c4 as CreditFundingEvidence, c5 as CreditInvoiceRecord, c6 as InvoiceSettlement, c7 as BlockedInvoiceCursor, c8 as InvoiceReconciliation, c9 as InvoiceWriteOff, ca as DrawRecord, cb as StalePendingDrawCursor, cc as TempoCreditLossEvidence, cd as TempoCreditLoss, ce as X402CreditLossEvidence, cf as X402CreditLoss, cg as DrainMethod, ch as DrainRequestResult, ci as BitcoinDepositLiability, bv as FundingLot, cj as CreditDrainRecord, ck as ChannelDrainCursor, cl as DrainWriteOff, cm as DrainTransitionResult, cn as DrainReleaseResult, co as DrainFulfilment, cp as HostingCleanupFence, aA as StepRecord, a2 as JobReceipt, a7 as Message, K as KVStore, G as SignedRequestReplayStore, Z as ZodLike, a as DVMDescriptor } from '../step-cache-BCRHimiY.js';
2
2
  export { cq as CLIENT_COMPATIBILITY_HEADERS, d as CanonicalEnvelope, cr as ClientCompatibility, cs as ClientCompatibilityEnv, ct as ClientCompatibilityGate, cu as ClientCompatibilityRequirement, cv as ClientSemVer, f as CreateSignedRequestVerifierOpts, cw as CreditFundingBasis, cx as CreditInvoiceStatus, cy as CreditLedger, cz as CreditLedgerError, cA as CreditLedgerErrorCode, cB as CreditLedgerErrorDetails, cC as CreditLedgerPool, cD as CreditStatus, cE as DRAIN_DELIVERY_RESERVE_SATS, cF as DVM_PROTOCOL_VERSION, cG as DrainConflictReason, cH as DrawRailValue, cI as DrawStatus, cJ as HostedTempoCloseReportWriteOff, cK as JobCostReportPayload, cL as JobTerminalReportPayload, cM as PostgresX402ChannelStorage, cN as ReplayStoreBackend, cO as RevenueSkippedNoRailPayload, cP as RevenueSkippedNoRailReason, x as SIGNED_REQUEST_AUTH_ID, y as SIGNED_REQUEST_STATEMENT_VERSION, cQ as Secp256k1AuthOpts, z as SignedRequestAudience, E as SignedRequestError, F as SignedRequestFailure, H as SignedRequestSignOpts, M as SignedRequestStatementHeader, N as SignedRequestVerifier, cR as TempoDrainDecision, cS as TempoDrainDecisionArgs, cT as TempoDrainDecisionResult, cU as TempoDrainHoldReason, O as UpfrontPayment, cV as X402ChannelStorageOpts, cW as X402RelayLockHolder, cX as X402RelaySubmissionLock, cY as X402RelaySubmissionLockError, cZ as allocateDrawValue, c_ as clientCompatibilityAttributes, c$ as clientCompatibilityMiddleware, d0 as clientUpgradeRequired, T as createSignedRequestVerifier, d1 as parseClientCapabilities, d2 as parseClientCompatibility, d3 as parseDvmClient, d4 as parseProtocolVersion, d5 as requireClientCompatibility, d6 as retryHostedTempoCloseReport, d7 as secp256k1Auth, d8 as signedRequestInput, W as signedRequestStatementHeader, d9 as writeOffHostedTempoCloseReport } from '../step-cache-BCRHimiY.js';
3
3
  import { Pool } from 'pg';
4
- import { au as CreditMenu, a as AppEnv, U as UpfrontPaymentOpts, i as PaymentInfo, av as ReceiptIssuer, aw as LightningReceive, ax as TempoSettlementReadiness, ay as DVMHostOpts, az as DVMServeResult, L as LockPubkeyStateLoader, C as ConsumedCredentialStore } from '../credit-menu-B239nIY5.js';
5
- export { aA as BuildCreditMenuArgs, aB as BuilderIdentity, aC as CREDIT_ENVELOPE_KEYS, aD as CreateX402BatchSettlementServerOpts, aE as CreditEnvelope, aF as CreditEnvelopeError, aG as CreditFundCommitment, aH as CreditTerms, aI as DEFAULT_INVOICE_TTL_SECONDS, aJ as DVMHost, aK as HostingClosureCommand, aL as HostingClosureEvidence, aM as HostingControlCommand, aN as HostingControlConfig, aO as HostingControlStatus, aP as JobManager, aQ as JobManagerOpts, aR as LightningReceiveConfig, aS as MIN_INVOICE_TTL_SECONDS, aT as MemoryConsumedCredentialStore, aU as MemoryConsumedCredentialStoreOpts, aV as MemoryProcessedPaymentStore, aW as MemoryX402ExactSettlementStore, aX as MountOpts, aY as OwnerDisplay, aZ as PaidJobCompletion, a_ as PaymentMode, a$ as PlatformReporterOpts, b0 as PostgresProcessedPaymentStore, b1 as PostgresX402ExactSettlementStore, b2 as PriceFiat, b3 as ProcessedPaymentQuerier, b4 as ProcessedPaymentRail, b5 as ProcessedPaymentRecord, b6 as ProcessedPaymentReplayError, b7 as ProcessedPaymentStore, b8 as X402BatchAcceptance, b9 as X402BatchFunding, ba as X402BatchRefusal, bb as X402BatchSettlementServer, bc as X402ExactAcceptance, bd as X402ExactIntentConflictError, be as X402ExactSettlementAttempt, bf as X402ExactSettlementChainEvidence, bg as X402ExactSettlementEffect, bh as X402ExactSettlementEvidenceMissingError, bi as X402ExactSettlementEvidenceReader, bj as X402ExactSettlementIntent, bk as X402ExactSettlementNotReadyError, bl as X402ExactSettlementServer, bm as X402ExactSettlementServerOpts, bn as X402ExactSettlementStatus, bo as X402ExactSettlementStore, bp as X402SettlementChainEvidence, bq as X402SettlementEvidenceReader, br as X402SettlementSubmissionError, bs as X402_BATCH_AUTO_SETTLEMENT, bt as X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS, bu as X402_BATCH_SETTLEMENT_NETWORK, bv as attachCreditMenu, bw as buildCreditMenu, bx as createDVMHost, by as createX402BatchSettlementServer, bz as creditEnvelopeIgnoreFields, bA as drawSettlementRef, bB as extractCreditEnvelope, bC as fundingCommitment, bD as selectPrimaryCredit, bE as signHostingClosure, bF as signHostingControl, bG as stripCreditEnvelope, bH as toCreditView } from '../credit-menu-B239nIY5.js';
4
+ import { au as CreditMenu, a as AppEnv, U as UpfrontPaymentOpts, i as PaymentInfo, av as ReceiptIssuer, aw as LightningReceive, ax as TempoSettlementReadiness, ay as DVMHostOpts, az as DVMServeResult, L as LockPubkeyStateLoader, C as ConsumedCredentialStore } from '../credit-menu-BfXaeHgR.js';
5
+ export { aA as BuildCreditMenuArgs, aB as BuilderIdentity, aC as CREDIT_ENVELOPE_KEYS, aD as CreateX402BatchSettlementServerOpts, aE as CreditEnvelope, aF as CreditEnvelopeError, aG as CreditFundCommitment, aH as CreditTerms, aI as DEFAULT_INVOICE_TTL_SECONDS, aJ as DVMHost, aK as HostingClosureCommand, aL as HostingClosureEvidence, aM as HostingControlCommand, aN as HostingControlConfig, aO as HostingControlStatus, aP as JobManager, aQ as JobManagerOpts, aR as LightningReceiveConfig, aS as MIN_INVOICE_TTL_SECONDS, aT as MemoryConsumedCredentialStore, aU as MemoryConsumedCredentialStoreOpts, aV as MemoryProcessedPaymentStore, aW as MemoryX402ExactSettlementStore, aX as MountOpts, aY as OwnerDisplay, aZ as PaidJobCompletion, a_ as PaymentMode, a$ as PlatformReporterOpts, b0 as PostgresProcessedPaymentStore, b1 as PostgresX402ExactSettlementStore, b2 as PriceFiat, b3 as ProcessedPaymentQuerier, b4 as ProcessedPaymentRail, b5 as ProcessedPaymentRecord, b6 as ProcessedPaymentReplayError, b7 as ProcessedPaymentStore, b8 as X402BatchAcceptance, b9 as X402BatchFunding, ba as X402BatchRefusal, bb as X402BatchSettlementServer, bc as X402ExactAcceptance, bd as X402ExactIntentConflictError, be as X402ExactSettlementAttempt, bf as X402ExactSettlementChainEvidence, bg as X402ExactSettlementEffect, bh as X402ExactSettlementEvidenceMissingError, bi as X402ExactSettlementEvidenceReader, bj as X402ExactSettlementIntent, bk as X402ExactSettlementNotReadyError, bl as X402ExactSettlementServer, bm as X402ExactSettlementServerOpts, bn as X402ExactSettlementStatus, bo as X402ExactSettlementStore, bp as X402SettlementChainEvidence, bq as X402SettlementEvidenceReader, br as X402SettlementSubmissionError, bs as X402_BATCH_AUTO_SETTLEMENT, bt as X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS, bu as X402_BATCH_SETTLEMENT_NETWORK, bv as attachCreditMenu, bw as buildCreditMenu, bx as createDVMHost, by as createX402BatchSettlementServer, bz as creditEnvelopeIgnoreFields, bA as drawSettlementRef, bB as extractCreditEnvelope, bC as fundingCommitment, bD as selectPrimaryCredit, bE as signHostingClosure, bF as signHostingControl, bG as stripCreditEnvelope, bH as toCreditView } from '../credit-menu-BfXaeHgR.js';
6
6
  import { Context, Hono } from 'hono';
7
7
  import { z } from 'zod';
8
8
  import { F as FxFetcher } from '../fx-BmvWGISH.js';
@@ -82,7 +82,7 @@ import {
82
82
  toCreditView,
83
83
  unknownRouteNotFound,
84
84
  writeOffHostedTempoCloseReport
85
- } from "../chunk-SGSHDMHP.js";
85
+ } from "../chunk-KERFCBT7.js";
86
86
  import {
87
87
  MemoryProcessedPaymentStore,
88
88
  PostgresProcessedPaymentStore,
@@ -342,6 +342,9 @@ function createDisposableCashuStore() {
342
342
  requests.add(requestId);
343
343
  for (const secret of incoming) secrets.add(secret);
344
344
  });
345
+ },
346
+ hasAccepted(incoming) {
347
+ return exclusive(() => Promise.resolve(incoming.some((secret) => secrets.has(secret))));
345
348
  }
346
349
  }
347
350
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dvmkit/sdk",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "description": "SDK for building Digital Vending Machines: pay-per-use HTTPS services AI agents can find, pay, and call with no account or API key",
5
5
  "author": "DVM Technologies Ltd",
6
6
  "keywords": [
@@ -89,14 +89,14 @@
89
89
  "@scure/bip39": "2.0.1",
90
90
  "@x402/core": "2.21.0",
91
91
  "@x402/evm": "2.21.0",
92
- "hono": "4.13.5",
92
+ "hono": "4.13.14",
93
93
  "jose": "6.2.1",
94
94
  "mppx": "0.8.15",
95
95
  "nostr-tools": "2.23.3",
96
96
  "proper-lockfile": "4.1.2",
97
- "undici": "7.29.1",
97
+ "undici": "7.30.1",
98
98
  "ws": "8.21.0",
99
- "zod": "4.4.3"
99
+ "zod": "4.6.7"
100
100
  },
101
101
  "optionalDependencies": {
102
102
  "pg": "8.20.0",