@dvmkit/sdk 0.21.1 → 0.22.0

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 (55) hide show
  1. package/dist/card-charge-journal-SKMBEPRM.js +44 -0
  2. package/dist/{chunk-ALTE7I6C.js → chunk-2WWVI32F.js} +56 -1
  3. package/dist/{chunk-C65P6MGZ.js → chunk-3DGIRHP2.js} +2 -2
  4. package/dist/{chunk-6RJAE332.js → chunk-5NMHZIIU.js} +1 -1
  5. package/dist/{chunk-34H4ZKBM.js → chunk-5YJWAJ4N.js} +1 -1
  6. package/dist/{chunk-2PN4DKZW.js → chunk-CUWSJQGT.js} +1 -1
  7. package/dist/{chunk-A6AOE63A.js → chunk-DLRPKEAM.js} +5 -1
  8. package/dist/{chunk-KRX7VNBG.js → chunk-DY5QIHJA.js} +1 -1
  9. package/dist/{chunk-RX6FT7XA.js → chunk-EHBUAJ5M.js} +1 -1
  10. package/dist/{chunk-7RWE6ELV.js → chunk-EQIP6TFD.js} +1 -1
  11. package/dist/{chunk-OTNHKRHA.js → chunk-GDZXGB43.js} +3 -3
  12. package/dist/{chunk-5RLNRLLB.js → chunk-HEH7YUGE.js} +1 -1
  13. package/dist/{chunk-DJRTYBEE.js → chunk-HVZIITWW.js} +27 -4
  14. package/dist/{chunk-MUMZPUYD.js → chunk-JINZMDNK.js} +1231 -85
  15. package/dist/{chunk-QTKGFG3I.js → chunk-JMTLK2SZ.js} +1 -1
  16. package/dist/{chunk-INYFUPXV.js → chunk-L35WYOH2.js} +1 -1
  17. package/dist/{chunk-MWDUGMN2.js → chunk-LCNRFKP7.js} +2 -2
  18. package/dist/{chunk-CVN2YNMG.js → chunk-QMKGYIBM.js} +1 -1
  19. package/dist/{chunk-I5MXADJS.js → chunk-SEIMPHIP.js} +225 -11
  20. package/dist/{chunk-QCZXKUS2.js → chunk-SQOVLAJ2.js} +1 -1
  21. package/dist/{chunk-72A4PHLD.js → chunk-UVRBD5GR.js} +1 -1
  22. package/dist/{chunk-5RGZN6WQ.js → chunk-XB644VN3.js} +1 -1
  23. package/dist/{chunk-CXRI4N4Y.js → chunk-YNHFJE6U.js} +1 -1
  24. package/dist/{chunk-LY2JYSJS.js → chunk-ZH5CLGO6.js} +1 -1
  25. package/dist/{content-retention-COnj0QKi.d.ts → content-retention-DEvY5vjM.d.ts} +1 -1
  26. package/dist/{credit-ledger-ZCJXJG6R.js → credit-ledger-S76KU53A.js} +11 -3
  27. package/dist/{credit-menu-DbjmA1vK.d.ts → credit-menu-BA2my6hE.d.ts} +229 -8
  28. package/dist/{fx-DfzQ0Lge.d.ts → fx-J5oXbv9A.d.ts} +1 -1
  29. package/dist/index.d.ts +5 -5
  30. package/dist/index.js +4 -4
  31. package/dist/internal/caller.d.ts +10 -9
  32. package/dist/internal/caller.js +11 -11
  33. package/dist/internal/server.d.ts +7 -7
  34. package/dist/internal/server.js +21 -21
  35. package/dist/{job-store-p45j28px.d.ts → job-store-CjPnf0dd.d.ts} +1 -1
  36. package/dist/{lightning-backend-DO7G7VqP.d.ts → lightning-backend-D9Q2KDS-.d.ts} +1 -1
  37. package/dist/{memory-credit-ledger-N4PZKTT5.js → memory-credit-ledger-5KXHOWB2.js} +4 -4
  38. package/dist/{mpp-setup-BLIYBORK.js → mpp-setup-3YZMURZL.js} +3 -3
  39. package/dist/{payout-reporter-5QAHCYIO.js → payout-reporter-KTLBNJJ7.js} +2 -2
  40. package/dist/{postgres-consumed-credential-store-4PCJEZBD.js → postgres-consumed-credential-store-Y336KNIB.js} +1 -1
  41. package/dist/{postgres-job-store-QKN5LGAH.js → postgres-job-store-ESEAN7JL.js} +2 -2
  42. package/dist/{postgres-replay-store-GH5AINQR.js → postgres-replay-store-6SVCZ475.js} +2 -2
  43. package/dist/{pricing-JJYLTTWK.js → pricing-RP5CGW6I.js} +3 -3
  44. package/dist/{revenue-reporter-6XARUEG6.js → revenue-reporter-FD3GDQZS.js} +2 -2
  45. package/dist/server/index.d.ts +20 -11
  46. package/dist/server/index.js +303 -30
  47. package/dist/{step-cache-CcCjpZm1.d.ts → step-cache-DXFftnAc.d.ts} +156 -13
  48. package/dist/{tempo-charge-store-A3CDF7D5.js → tempo-charge-store-SOIRMEFJ.js} +2 -2
  49. package/dist/{tempo-session-store-XJE6GIXN.js → tempo-session-store-UBDFFHDG.js} +3 -3
  50. package/dist/testing/index.d.ts +3 -3
  51. package/dist/testing/index.js +6 -6
  52. package/dist/{usd-BnAFcUai.d.ts → usd-Bc_rva_K.d.ts} +1 -1
  53. package/dist/{x402-XLFD43RF.js → x402-MFBRORHG.js} +5 -5
  54. package/package.json +1 -1
  55. package/dist/{chunk-NUDHO4HV.js → chunk-LABJSMSJ.js} +48 -48
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PostgresReplayStore
3
- } from "../chunk-5RLNRLLB.js";
3
+ } from "../chunk-HEH7YUGE.js";
4
4
  import {
5
5
  PostgresKVStore
6
6
  } from "../chunk-V5ZRATJH.js";
@@ -18,7 +18,7 @@ import {
18
18
  parseNwcUri,
19
19
  validateX402Env,
20
20
  withNwcPool
21
- } from "../chunk-2PN4DKZW.js";
21
+ } from "../chunk-CUWSJQGT.js";
22
22
  import {
23
23
  MemoryKVStore
24
24
  } from "../chunk-SDK6KDJN.js";
@@ -36,6 +36,7 @@ import {
36
36
  MemoryX402ExactSettlementStore,
37
37
  PostgresX402ExactSettlementStore,
38
38
  REQUEST_ID_FIELD,
39
+ STRIPE_CREDIT_MIN_MICRO,
39
40
  X402ExactIntentConflictError,
40
41
  X402ExactSettlementEvidenceMissingError,
41
42
  X402ExactSettlementNotReadyError,
@@ -47,16 +48,19 @@ import {
47
48
  X402_BATCH_SETTLEMENT_NETWORK,
48
49
  attachCreditMenu,
49
50
  buildCreditMenu,
51
+ callerInputIssues,
50
52
  clientCompatibilityAttributes,
51
53
  clientCompatibilityMiddleware,
52
54
  clientUpgradeRequired,
53
55
  createDVMServer,
54
56
  createPlatformTempoObserverHealth,
57
+ createStripeRefundApi,
55
58
  createX402BatchSettlementServer,
56
59
  creditEnvelopeIgnoreFields,
57
60
  devModeSkipsPaymentVerification,
58
61
  drawSettlementRef,
59
62
  extractCreditEnvelope,
63
+ fiatMicroToMethodAmount,
60
64
  fundingCommitment,
61
65
  handleCreditRequest,
62
66
  hasInvalidRequestId,
@@ -82,29 +86,30 @@ import {
82
86
  toCreditView,
83
87
  unknownRouteNotFound,
84
88
  writeOffHostedTempoCloseReport
85
- } from "../chunk-MUMZPUYD.js";
89
+ } from "../chunk-JINZMDNK.js";
86
90
  import {
87
91
  MemoryProcessedPaymentStore,
88
92
  PostgresProcessedPaymentStore,
89
93
  ProcessedPaymentReplayError
90
94
  } from "../chunk-XRLKGCAW.js";
91
- import "../chunk-KRX7VNBG.js";
92
- import "../chunk-C65P6MGZ.js";
95
+ import "../chunk-DY5QIHJA.js";
96
+ import "../chunk-3DGIRHP2.js";
93
97
  import {
94
98
  MemoryCreditLedger
95
- } from "../chunk-DJRTYBEE.js";
99
+ } from "../chunk-HVZIITWW.js";
96
100
  import {
97
101
  PostgresJobStore
98
- } from "../chunk-QCZXKUS2.js";
102
+ } from "../chunk-SQOVLAJ2.js";
99
103
  import {
100
104
  SignedRequestError,
105
+ carriesSignedEnvelope,
101
106
  createDefaultReplayStore,
102
107
  createSignedRequestVerifier,
103
108
  signedRequestInput
104
- } from "../chunk-A6AOE63A.js";
109
+ } from "../chunk-DLRPKEAM.js";
105
110
  import {
106
111
  isStreamableJobStore
107
- } from "../chunk-6RJAE332.js";
112
+ } from "../chunk-5NMHZIIU.js";
108
113
  import {
109
114
  ContentHoldError,
110
115
  baselineContentExpiry,
@@ -115,23 +120,23 @@ import {
115
120
  IMPLICIT_CREDIT_TTL_MS,
116
121
  generateEphemeralReceiptKey,
117
122
  receiptPubkeyFromSecret
118
- } from "../chunk-7RWE6ELV.js";
123
+ } from "../chunk-EQIP6TFD.js";
119
124
  import {
120
125
  X402_DEFAULT_FACILITATOR,
121
126
  X402_DEFAULT_NETWORK,
122
127
  resolveRpcOverride,
123
128
  x402NetworkToCaip2
124
- } from "../chunk-NUDHO4HV.js";
129
+ } from "../chunk-LABJSMSJ.js";
125
130
  import {
126
131
  SIGNED_REQUEST_AUTH_ID,
127
132
  SIGNED_REQUEST_STATEMENT_VERSION,
128
133
  signedRequestStatementHeader
129
134
  } from "../chunk-SXL44PL5.js";
130
- import "../chunk-QTKGFG3I.js";
135
+ import "../chunk-JMTLK2SZ.js";
131
136
  import "../chunk-FUJ36YDV.js";
132
137
  import "../chunk-BQJIFRAZ.js";
133
- import "../chunk-RX6FT7XA.js";
134
- import "../chunk-72A4PHLD.js";
138
+ import "../chunk-EHBUAJ5M.js";
139
+ import "../chunk-UVRBD5GR.js";
135
140
  import {
136
141
  CreditLedger,
137
142
  CreditLedgerError,
@@ -139,7 +144,7 @@ import {
139
144
  PostgresX402ChannelStorage,
140
145
  X402RelaySubmissionLockError,
141
146
  allocateDrawValue
142
- } from "../chunk-I5MXADJS.js";
147
+ } from "../chunk-SEIMPHIP.js";
143
148
  import "../chunk-YG7G4DPZ.js";
144
149
  import {
145
150
  SDK_INIT_ADVISORY_LOCK,
@@ -148,25 +153,26 @@ import {
148
153
  import "../chunk-5UC7TOQC.js";
149
154
  import {
150
155
  applyRetryToPool
151
- } from "../chunk-INYFUPXV.js";
156
+ } from "../chunk-L35WYOH2.js";
152
157
  import {
153
158
  assertSupportedX402Network
154
159
  } from "../chunk-BPYMEMQX.js";
155
160
  import "../chunk-H3GGFEE5.js";
156
161
  import {
162
+ MPPX_HMAC_MISMATCH_REASON,
157
163
  TEMPO_MODERATO_CHAIN_ID,
158
164
  TEMPO_MODERATO_RPC,
159
165
  TEMPO_SETTLEMENT_DEFAULT_LOW_BALANCE_MICRO,
160
166
  TempoSettlementReadiness,
161
167
  resolveTempoNetwork
162
- } from "../chunk-MWDUGMN2.js";
168
+ } from "../chunk-LCNRFKP7.js";
163
169
  import {
164
170
  initLoggers
165
- } from "../chunk-LY2JYSJS.js";
171
+ } from "../chunk-ZH5CLGO6.js";
166
172
  import "../chunk-66HGCPBU.js";
167
173
  import {
168
174
  diagnosticConsole
169
- } from "../chunk-ALTE7I6C.js";
175
+ } from "../chunk-2WWVI32F.js";
170
176
 
171
177
  // src/sdk/server/cashu-env.ts
172
178
  async function resolveCashuOptsFromEnv(env, pool, cashuModeHint) {
@@ -284,6 +290,243 @@ function safeInteger(value) {
284
290
  return number;
285
291
  }
286
292
 
293
+ // src/sdk/server/stripe-credit.ts
294
+ import { randomBytes } from "crypto";
295
+ import { Credential, Errors as MppxErrors, PaymentRequest } from "mppx";
296
+ import { Mppx } from "mppx/server";
297
+ import { charge as stripeCharge } from "mppx/stripe/server";
298
+ function stripeCreditConfigFromEnv(env) {
299
+ const secretKey = env.DVMKIT_STRIPE_SECRET_KEY?.trim();
300
+ const networkId = env.DVMKIT_STRIPE_NETWORK_ID?.trim();
301
+ if (!secretKey && !networkId) return void 0;
302
+ if (!secretKey) {
303
+ throw new Error(
304
+ "DVMKIT_STRIPE_NETWORK_ID is set but DVMKIT_STRIPE_SECRET_KEY is not. Card credit needs both."
305
+ );
306
+ }
307
+ if (!networkId) {
308
+ throw new Error(
309
+ "DVMKIT_STRIPE_SECRET_KEY is set but DVMKIT_STRIPE_NETWORK_ID is not. Card credit needs both: the network id is your Stripe profile id (profile_\u2026)."
310
+ );
311
+ }
312
+ const hmacSecret = env.DVMKIT_TEMPO_SECRET_KEY;
313
+ if (!hmacSecret) {
314
+ throw new Error(
315
+ "Card credit requires DVMKIT_TEMPO_SECRET_KEY: it binds MPP challenges for both Tempo and card credit. Generate one with 'openssl rand -hex 32'."
316
+ );
317
+ }
318
+ return { secretKey, networkId, hmacSecret };
319
+ }
320
+ function createStripeCreditRail(opts) {
321
+ const apiBase = opts.apiBase ?? "https://api.stripe.com";
322
+ const fetchImpl = opts.fetch ?? fetch;
323
+ const build = (client, secretKey) => Mppx.create({
324
+ methods: [
325
+ stripeCharge({
326
+ client,
327
+ networkId: opts.networkId,
328
+ paymentMethodTypes: ["card"],
329
+ currency: "usd",
330
+ decimals: 2
331
+ })
332
+ ],
333
+ secretKey
334
+ });
335
+ const issuer = build(unusedClient, opts.hmacSecret);
336
+ return {
337
+ networkId: opts.networkId,
338
+ refunds: createStripeRefundApi({ secretKey: opts.secretKey, apiBase, fetch: fetchImpl }),
339
+ ...opts.chargeJournal && { chargeJournal: opts.chargeJournal },
340
+ async issueChallenge({ amountMicro, resourcePath, expires }) {
341
+ return issuer.challenge.stripe.charge({
342
+ amount: fiatMicroToMethodAmount(amountMicro, "stripe"),
343
+ expires,
344
+ meta: { path: resourcePath, nonce: randomBytes(16).toString("hex") }
345
+ });
346
+ },
347
+ async charge(serialized, { amountMicro, resourcePath }) {
348
+ let credential;
349
+ try {
350
+ credential = Credential.deserialize(serialized);
351
+ } catch {
352
+ return invalidCredential("the credential is not a well-formed MPP credential");
353
+ }
354
+ if (credential.challenge.method !== "stripe" || credential.challenge.intent !== "charge") {
355
+ return invalidCredential("the credential is not for a stripe charge challenge");
356
+ }
357
+ const attempt = {};
358
+ const journal = opts.chargeJournal;
359
+ const beforeCharge = journal ? async () => {
360
+ try {
361
+ await journal.record(credential.challenge.id);
362
+ } catch (err) {
363
+ attempt.journalFailed = true;
364
+ diagnosticConsole.warn({ event: "card_charge_journal_failed" });
365
+ throw err;
366
+ }
367
+ } : void 0;
368
+ const amount = fiatMicroToMethodAmount(amountMicro, "stripe");
369
+ const broadcast = (secretKey) => build(fetchClient({ apiBase, secretKey: opts.secretKey, fetchImpl, attempt, beforeCharge }), secretKey).broadcastCredential(serialized, {
370
+ request: { amount },
371
+ meta: { path: resourcePath, nonce: readNonce(credential.challenge) }
372
+ });
373
+ try {
374
+ let receipt;
375
+ try {
376
+ receipt = await broadcast(opts.hmacSecret);
377
+ } catch (err) {
378
+ const previous = !attempt.called && isHmacMismatch(err) ? await opts.previousHmacSecret?.() : void 0;
379
+ if (!previous) throw err;
380
+ receipt = await broadcast(previous);
381
+ }
382
+ if (!attempt.paymentIntentId || receipt.reference !== attempt.paymentIntentId) {
383
+ return {
384
+ ok: false,
385
+ reason: "indeterminate",
386
+ message: "the charge succeeded without a PaymentIntent this server observed"
387
+ };
388
+ }
389
+ if (attempt.amount !== amountMicro / 1e4 || attempt.currency !== "usd") {
390
+ return {
391
+ ok: false,
392
+ reason: "mismatch",
393
+ message: "the PaymentIntent's amount or currency is not this top-up's",
394
+ paymentIntentId: attempt.paymentIntentId
395
+ };
396
+ }
397
+ return { ok: true, paymentIntentId: attempt.paymentIntentId, replayed: attempt.replayed === true };
398
+ } catch (err) {
399
+ if (attempt.journalFailed) {
400
+ return {
401
+ ok: false,
402
+ reason: "unavailable",
403
+ message: "the charge attempt could not be recorded, so this request did not charge the card"
404
+ };
405
+ }
406
+ if (!attempt.called) return invalidCredential(credentialFailure(err));
407
+ const stripeError = attempt.failure?.codes;
408
+ const known = {
409
+ ...stripeError && { stripeError },
410
+ ...attempt.paymentIntentId && { paymentIntentId: attempt.paymentIntentId }
411
+ };
412
+ if (stripeError?.type === "card_error") {
413
+ return { ok: false, reason: "declined", message: "the card was declined", ...known };
414
+ }
415
+ if (attempt.failure?.status === 400 && stripeError?.type === "invalid_request_error") {
416
+ return {
417
+ ok: false,
418
+ reason: "token_unusable",
419
+ message: "Stripe refused the shared payment token; nothing was charged",
420
+ ...known
421
+ };
422
+ }
423
+ if (attempt.status === "requires_action") {
424
+ return {
425
+ ok: false,
426
+ reason: "requires_action",
427
+ message: "the card requires an authentication step",
428
+ ...known
429
+ };
430
+ }
431
+ return {
432
+ ok: false,
433
+ reason: "indeterminate",
434
+ message: attempt.failure ? `Stripe answered HTTP ${attempt.failure.status} without confirming the charge` : attempt.status ? `the PaymentIntent is ${attempt.status}, not succeeded` : "Stripe could not be reached or its answer was lost",
435
+ ...known
436
+ };
437
+ }
438
+ }
439
+ };
440
+ }
441
+ var unusedClient = {
442
+ paymentIntents: {
443
+ create() {
444
+ return Promise.reject(new Error("the challenge issuer never charges"));
445
+ }
446
+ }
447
+ };
448
+ function fetchClient(args) {
449
+ return {
450
+ paymentIntents: {
451
+ async create(params, options) {
452
+ await args.beforeCharge?.();
453
+ args.attempt.called = true;
454
+ const response = await args.fetchImpl(`${args.apiBase}/v1/payment_intents`, {
455
+ method: "POST",
456
+ headers: {
457
+ Authorization: `Basic ${Buffer.from(`${args.secretKey}:`).toString("base64")}`,
458
+ "Content-Type": "application/x-www-form-urlencoded",
459
+ ...options.idempotencyKey && { "Idempotency-Key": options.idempotencyKey },
460
+ ...options.apiVersion && { "Stripe-Version": options.apiVersion },
461
+ ...options.stripeAccount && { "Stripe-Account": options.stripeAccount }
462
+ },
463
+ body: formEncode(params)
464
+ });
465
+ const body = await response.json().catch(() => ({}));
466
+ if (!response.ok) {
467
+ const enumField = (value) => typeof value === "string" && /^[a-z0-9_]{1,64}$/.test(value) ? value : void 0;
468
+ const type = enumField(body.error?.type);
469
+ const code = enumField(body.error?.code);
470
+ const declineCode = enumField(body.error?.decline_code);
471
+ args.attempt.failure = {
472
+ status: response.status,
473
+ codes: { ...type && { type }, ...code && { code }, ...declineCode && { declineCode } }
474
+ };
475
+ const intent = body.error?.payment_intent?.id;
476
+ if (typeof intent === "string" && /^pi_[A-Za-z0-9]+$/.test(intent)) {
477
+ args.attempt.paymentIntentId = intent;
478
+ }
479
+ throw new Error(`Stripe answered HTTP ${response.status}`);
480
+ }
481
+ if (typeof body.id !== "string" || typeof body.status !== "string") {
482
+ throw new Error("Stripe returned a PaymentIntent without an id or status");
483
+ }
484
+ args.attempt.paymentIntentId = body.id;
485
+ args.attempt.status = body.status;
486
+ if (typeof body.amount === "number") args.attempt.amount = body.amount;
487
+ if (typeof body.currency === "string") args.attempt.currency = body.currency;
488
+ args.attempt.replayed = response.headers.get("idempotent-replayed") === "true";
489
+ return { id: body.id, status: body.status };
490
+ }
491
+ }
492
+ };
493
+ }
494
+ function formEncode(params) {
495
+ const out = new URLSearchParams();
496
+ const visit = (key, value) => {
497
+ if (value === void 0 || value === null) return;
498
+ if (Array.isArray(value)) {
499
+ value.forEach((item, index) => visit(`${key}[${index}]`, item));
500
+ } else if (typeof value === "object") {
501
+ for (const [child, nested] of Object.entries(value)) visit(`${key}[${child}]`, nested);
502
+ } else {
503
+ out.set(key, String(value));
504
+ }
505
+ };
506
+ for (const [key, value] of Object.entries(params)) visit(key, value);
507
+ return out;
508
+ }
509
+ function readNonce(challenge) {
510
+ let meta;
511
+ try {
512
+ meta = challenge.opaque ? PaymentRequest.deserialize(challenge.opaque) : challenge.meta;
513
+ } catch {
514
+ return "";
515
+ }
516
+ return typeof meta?.nonce === "string" ? meta.nonce : "";
517
+ }
518
+ function invalidCredential(message) {
519
+ return { ok: false, reason: "invalid_credential", message };
520
+ }
521
+ function credentialFailure(err) {
522
+ if (isHmacMismatch(err)) return "the challenge was not issued by this server";
523
+ if (err instanceof MppxErrors.PaymentExpiredError) return "the challenge has expired";
524
+ return "the credential does not match this top-up's challenge";
525
+ }
526
+ function isHmacMismatch(err) {
527
+ return err instanceof MppxErrors.InvalidChallengeError && err.message.includes(MPPX_HMAC_MISMATCH_REASON);
528
+ }
529
+
287
530
  // src/sdk/server/payment-mode.ts
288
531
  function resolvePaymentMode(opts) {
289
532
  const active = (rail, configured, ready) => ({
@@ -1193,7 +1436,7 @@ function createDVMHost(opts = {}) {
1193
1436
  });
1194
1437
  applyRetryToPool(pool, "dvm-host");
1195
1438
  pgPool = pool;
1196
- const { PostgresJobStore: PostgresJobStore2 } = await import("../postgres-job-store-QKN5LGAH.js");
1439
+ const { PostgresJobStore: PostgresJobStore2 } = await import("../postgres-job-store-ESEAN7JL.js");
1197
1440
  const pgJobStore = new PostgresJobStore2(pool);
1198
1441
  pendingInits.push(pgJobStore.init(), pgJobStore.initStreaming());
1199
1442
  jobStore = pgJobStore;
@@ -1281,16 +1524,18 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
1281
1524
  const tempoObserverHealth = createPlatformTempoObserverHealth(envMaybe);
1282
1525
  void tempoObserverHealth?.refresh();
1283
1526
  const receiptKey = envMaybe.DVMKIT_RECEIPT_KEY ?? (opts.devMode ? generateEphemeralReceiptKey().secret : void 0);
1527
+ let stripeCredit = opts.stripeCredit;
1528
+ const stripeCreditConfig = stripeCredit ? void 0 : stripeCreditConfigFromEnv(envMaybe);
1284
1529
  let mpp = opts.mpp;
1285
1530
  let mppSecretState = null;
1286
1531
  let tempoChargeBackend = "user-supplied";
1287
1532
  const mppTempoRecipient = envMaybe.DVMKIT_TEMPO_RECIPIENT;
1288
1533
  if (!mpp && mppTempoRecipient) {
1289
- const { createMppFromOpts, createDualKeyMppxFromOpts, parseMppMethodsAllowlist } = await import("../mpp-setup-BLIYBORK.js");
1534
+ const { createMppFromOpts, createDualKeyMppxFromOpts, parseMppMethodsAllowlist } = await import("../mpp-setup-3YZMURZL.js");
1290
1535
  tempoChargeBackend = pgPool ? "postgres" : "memory";
1291
1536
  let tempoCharge;
1292
1537
  if (pgPool) {
1293
- const { PostgresTempoChargeStore } = await import("../tempo-charge-store-A3CDF7D5.js");
1538
+ const { PostgresTempoChargeStore } = await import("../tempo-charge-store-SOIRMEFJ.js");
1294
1539
  const chargeStore = new PostgresTempoChargeStore(pgPool);
1295
1540
  tempoChargeStore = chargeStore;
1296
1541
  pendingInits.push(chargeStore.init());
@@ -1310,7 +1555,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
1310
1555
  { createPublicClient, createWalletClient, erc20Abi, http },
1311
1556
  { tempo: tempoMainnet, tempoModerato }
1312
1557
  ] = await Promise.all([
1313
- import("../tempo-session-store-XJE6GIXN.js"),
1558
+ import("../tempo-session-store-UBDFFHDG.js"),
1314
1559
  import("viem/accounts"),
1315
1560
  import("viem"),
1316
1561
  import("viem/chains")
@@ -1462,8 +1707,22 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
1462
1707
  mpp = createMppFromOpts(mppOpts, env);
1463
1708
  }
1464
1709
  }
1710
+ if (stripeCreditConfig) {
1711
+ let previousHmacSecret;
1712
+ if (pgPool) {
1713
+ const { initMppSecretStateTable, applyMppSecretRotation, loadMppSecretState, DEFAULT_ROTATION_WINDOW_MS } = await import("../mpp-secret-state-B5GCILVH.js");
1714
+ if (!mppSecretState) {
1715
+ await initMppSecretStateTable(pgPool);
1716
+ mppSecretState = (await applyMppSecretRotation(pgPool, stripeCreditConfig.hmacSecret, DEFAULT_ROTATION_WINDOW_MS)).state;
1717
+ }
1718
+ const localPool = pgPool;
1719
+ previousHmacSecret = async () => (await loadMppSecretState(localPool))?.previous?.secret;
1720
+ }
1721
+ const chargeJournal = pgPool ? await (await import("../card-charge-journal-SKMBEPRM.js")).createPostgresCardChargeJournal(pgPool) : void 0;
1722
+ stripeCredit = createStripeCreditRail({ ...stripeCreditConfig, previousHmacSecret, chargeJournal });
1723
+ }
1465
1724
  const fxSource = envMaybe.DVMKIT_FX_SOURCE;
1466
- const { createFxFetcher, resolveFxSourceFromEnv, warmFxSnapshot } = await import("../pricing-JJYLTTWK.js");
1725
+ const { createFxFetcher, resolveFxSourceFromEnv, warmFxSnapshot } = await import("../pricing-RP5CGW6I.js");
1467
1726
  const fxFetcher = opts.fx ?? createFxFetcher({ source: resolveFxSourceFromEnv(envMaybe) });
1468
1727
  const hostRailConfigured = (opts.paymentMethods?.length ?? 0) > 0 || (effectiveMints?.length ?? 0) > 0 || !!x402WithDualServe || !!mpp;
1469
1728
  if (mounts.some((entry) => mountNeedsFx(entry, hostRailConfigured))) warmFxSnapshot(fxFetcher);
@@ -1473,7 +1732,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
1473
1732
  assertReceiptIdentity(envMaybe, opts.builder, receiptKey, cashuOpts.dvmId, opts.devMode);
1474
1733
  let sharedPgReplayStore;
1475
1734
  if (pgPool) {
1476
- const { PostgresReplayStore: PostgresReplayStore2 } = await import("../postgres-replay-store-GH5AINQR.js");
1735
+ const { PostgresReplayStore: PostgresReplayStore2 } = await import("../postgres-replay-store-6SVCZ475.js");
1477
1736
  const store2 = new PostgresReplayStore2(pgPool);
1478
1737
  pendingInits.push(store2.init());
1479
1738
  sharedPgReplayStore = store2;
@@ -1501,13 +1760,13 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
1501
1760
  }
1502
1761
  let sharedPgConsumedStore;
1503
1762
  if (pgPool) {
1504
- const { PostgresConsumedCredentialStore } = await import("../postgres-consumed-credential-store-4PCJEZBD.js");
1763
+ const { PostgresConsumedCredentialStore } = await import("../postgres-consumed-credential-store-Y336KNIB.js");
1505
1764
  const consumedStore = new PostgresConsumedCredentialStore(pgPool);
1506
1765
  pendingInits.push(consumedStore.init());
1507
1766
  sharedPgConsumedStore = consumedStore;
1508
1767
  }
1509
1768
  if (pgPool) {
1510
- const { CreditLedger: CreditLedger2 } = await import("../credit-ledger-ZCJXJG6R.js");
1769
+ const { CreditLedger: CreditLedger2 } = await import("../credit-ledger-S76KU53A.js");
1511
1770
  const pgLedger = new CreditLedger2(pgPool, tempoSessionStore);
1512
1771
  pendingInits.push(pgLedger.init());
1513
1772
  creditLedger = pgLedger;
@@ -1516,7 +1775,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
1516
1775
  pendingInits.push(pgProcessed.init());
1517
1776
  processedPayments = pgProcessed;
1518
1777
  } else {
1519
- const { MemoryCreditLedger: MemoryCreditLedger2 } = await import("../memory-credit-ledger-N4PZKTT5.js");
1778
+ const { MemoryCreditLedger: MemoryCreditLedger2 } = await import("../memory-credit-ledger-5KXHOWB2.js");
1520
1779
  creditLedger = disposableCashu?.ledger ?? new MemoryCreditLedger2();
1521
1780
  const { MemoryProcessedPaymentStore: MemoryProcessedPaymentStore2 } = await import("../processed-payment-store-GKMAWOM3.js");
1522
1781
  processedPayments = new MemoryProcessedPaymentStore2();
@@ -1631,6 +1890,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
1631
1890
  x402: descX402WithDualServe,
1632
1891
  x402FacilitatorHealth: descX402Health,
1633
1892
  mpp: descMpp,
1893
+ stripeCredit,
1634
1894
  consumedCredentialStore: opts.consumedCredentialStore ?? sharedPgConsumedStore,
1635
1895
  adminCashuNonceStore: sharedPgConsumedStore,
1636
1896
  cashuMode: cashuOpts.cashuMode,
@@ -1704,6 +1964,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
1704
1964
  x402: bootX402,
1705
1965
  x402Support: bootX402Support,
1706
1966
  lightningReceive,
1967
+ stripeCredit,
1707
1968
  fxSource,
1708
1969
  hasPlatformToken: !!platformToken,
1709
1970
  hasDvmId: !!cashuOpts.dvmId,
@@ -2028,6 +2289,9 @@ function logBootSummary(s) {
2028
2289
  diagnosticConsole.log(
2029
2290
  ` LN receive: ${s.lightningReceive ? `receive-only NWC (${s.lightningReceive.available() ? "reachable" : "unreachable \u2014 omitted from the funding menu"})` : "(unconfigured)"}`
2030
2291
  );
2292
+ diagnosticConsole.log(
2293
+ ` Card credit: ${s.stripeCredit ? `stripe (network ${s.stripeCredit.networkId})` : "(unconfigured)"}`
2294
+ );
2031
2295
  diagnosticConsole.log(
2032
2296
  ` Platform rep.: ${revenueReporterBannerState({
2033
2297
  platformUrl: s.platformUrl,
@@ -2106,8 +2370,15 @@ function secp256k1Auth(opts = {}) {
2106
2370
  id: SIGNED_REQUEST_AUTH_ID,
2107
2371
  allowUnsignedPaid: opts.allowUnsignedPaid === true,
2108
2372
  checkAuth(schema, input, domain) {
2109
- const envelope = getVerifier(schema).checkAuth(input, domain);
2110
- return { pubkey: envelope.pubkey, envelope };
2373
+ try {
2374
+ const envelope = getVerifier(schema).checkAuth(input, domain);
2375
+ return { pubkey: envelope.pubkey, envelope };
2376
+ } catch (err) {
2377
+ if (err instanceof SignedRequestError && err.sub_reason === "schema_invalid" && !carriesSignedEnvelope(input) && callerInputIssues(err.issues).length === 0) {
2378
+ throw new SignedRequestError("signed request required", "signature_required");
2379
+ }
2380
+ throw err;
2381
+ }
2111
2382
  },
2112
2383
  recheckSignature(schema, input, domain) {
2113
2384
  getVerifier(schema).verifySignature(input, domain);
@@ -2172,6 +2443,7 @@ export {
2172
2443
  SIGNED_REQUEST_AUTH_ID,
2173
2444
  SIGNED_REQUEST_STATEMENT_VERSION,
2174
2445
  SSRFError,
2446
+ STRIPE_CREDIT_MIN_MICRO,
2175
2447
  SignedRequestError,
2176
2448
  X402ExactIntentConflictError,
2177
2449
  X402ExactSettlementEvidenceMissingError,
@@ -2194,6 +2466,7 @@ export {
2194
2466
  createDVMHost,
2195
2467
  createPinnedFetch,
2196
2468
  createSignedRequestVerifier,
2469
+ createStripeCreditRail,
2197
2470
  createX402BatchSettlementServer,
2198
2471
  creditEnvelopeIgnoreFields,
2199
2472
  drawSettlementRef,