@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.
- package/dist/card-charge-journal-SKMBEPRM.js +44 -0
- package/dist/{chunk-ALTE7I6C.js → chunk-2WWVI32F.js} +56 -1
- package/dist/{chunk-C65P6MGZ.js → chunk-3DGIRHP2.js} +2 -2
- package/dist/{chunk-6RJAE332.js → chunk-5NMHZIIU.js} +1 -1
- package/dist/{chunk-34H4ZKBM.js → chunk-5YJWAJ4N.js} +1 -1
- package/dist/{chunk-2PN4DKZW.js → chunk-CUWSJQGT.js} +1 -1
- package/dist/{chunk-A6AOE63A.js → chunk-DLRPKEAM.js} +5 -1
- package/dist/{chunk-KRX7VNBG.js → chunk-DY5QIHJA.js} +1 -1
- package/dist/{chunk-RX6FT7XA.js → chunk-EHBUAJ5M.js} +1 -1
- package/dist/{chunk-7RWE6ELV.js → chunk-EQIP6TFD.js} +1 -1
- package/dist/{chunk-OTNHKRHA.js → chunk-GDZXGB43.js} +3 -3
- package/dist/{chunk-5RLNRLLB.js → chunk-HEH7YUGE.js} +1 -1
- package/dist/{chunk-DJRTYBEE.js → chunk-HVZIITWW.js} +27 -4
- package/dist/{chunk-MUMZPUYD.js → chunk-JINZMDNK.js} +1231 -85
- package/dist/{chunk-QTKGFG3I.js → chunk-JMTLK2SZ.js} +1 -1
- package/dist/{chunk-INYFUPXV.js → chunk-L35WYOH2.js} +1 -1
- package/dist/{chunk-MWDUGMN2.js → chunk-LCNRFKP7.js} +2 -2
- package/dist/{chunk-CVN2YNMG.js → chunk-QMKGYIBM.js} +1 -1
- package/dist/{chunk-I5MXADJS.js → chunk-SEIMPHIP.js} +225 -11
- package/dist/{chunk-QCZXKUS2.js → chunk-SQOVLAJ2.js} +1 -1
- package/dist/{chunk-72A4PHLD.js → chunk-UVRBD5GR.js} +1 -1
- package/dist/{chunk-5RGZN6WQ.js → chunk-XB644VN3.js} +1 -1
- package/dist/{chunk-CXRI4N4Y.js → chunk-YNHFJE6U.js} +1 -1
- package/dist/{chunk-LY2JYSJS.js → chunk-ZH5CLGO6.js} +1 -1
- package/dist/{content-retention-COnj0QKi.d.ts → content-retention-DEvY5vjM.d.ts} +1 -1
- package/dist/{credit-ledger-ZCJXJG6R.js → credit-ledger-S76KU53A.js} +11 -3
- package/dist/{credit-menu-DbjmA1vK.d.ts → credit-menu-BA2my6hE.d.ts} +229 -8
- package/dist/{fx-DfzQ0Lge.d.ts → fx-J5oXbv9A.d.ts} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/internal/caller.d.ts +10 -9
- package/dist/internal/caller.js +11 -11
- package/dist/internal/server.d.ts +7 -7
- package/dist/internal/server.js +21 -21
- package/dist/{job-store-p45j28px.d.ts → job-store-CjPnf0dd.d.ts} +1 -1
- package/dist/{lightning-backend-DO7G7VqP.d.ts → lightning-backend-D9Q2KDS-.d.ts} +1 -1
- package/dist/{memory-credit-ledger-N4PZKTT5.js → memory-credit-ledger-5KXHOWB2.js} +4 -4
- package/dist/{mpp-setup-BLIYBORK.js → mpp-setup-3YZMURZL.js} +3 -3
- package/dist/{payout-reporter-5QAHCYIO.js → payout-reporter-KTLBNJJ7.js} +2 -2
- package/dist/{postgres-consumed-credential-store-4PCJEZBD.js → postgres-consumed-credential-store-Y336KNIB.js} +1 -1
- package/dist/{postgres-job-store-QKN5LGAH.js → postgres-job-store-ESEAN7JL.js} +2 -2
- package/dist/{postgres-replay-store-GH5AINQR.js → postgres-replay-store-6SVCZ475.js} +2 -2
- package/dist/{pricing-JJYLTTWK.js → pricing-RP5CGW6I.js} +3 -3
- package/dist/{revenue-reporter-6XARUEG6.js → revenue-reporter-FD3GDQZS.js} +2 -2
- package/dist/server/index.d.ts +20 -11
- package/dist/server/index.js +303 -30
- package/dist/{step-cache-CcCjpZm1.d.ts → step-cache-DXFftnAc.d.ts} +156 -13
- package/dist/{tempo-charge-store-A3CDF7D5.js → tempo-charge-store-SOIRMEFJ.js} +2 -2
- package/dist/{tempo-session-store-XJE6GIXN.js → tempo-session-store-UBDFFHDG.js} +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +6 -6
- package/dist/{usd-BnAFcUai.d.ts → usd-Bc_rva_K.d.ts} +1 -1
- package/dist/{x402-XLFD43RF.js → x402-MFBRORHG.js} +5 -5
- package/package.json +1 -1
- package/dist/{chunk-NUDHO4HV.js → chunk-LABJSMSJ.js} +48 -48
package/dist/server/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PostgresReplayStore
|
|
3
|
-
} from "../chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
92
|
-
import "../chunk-
|
|
95
|
+
import "../chunk-DY5QIHJA.js";
|
|
96
|
+
import "../chunk-3DGIRHP2.js";
|
|
93
97
|
import {
|
|
94
98
|
MemoryCreditLedger
|
|
95
|
-
} from "../chunk-
|
|
99
|
+
} from "../chunk-HVZIITWW.js";
|
|
96
100
|
import {
|
|
97
101
|
PostgresJobStore
|
|
98
|
-
} from "../chunk-
|
|
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-
|
|
109
|
+
} from "../chunk-DLRPKEAM.js";
|
|
105
110
|
import {
|
|
106
111
|
isStreamableJobStore
|
|
107
|
-
} from "../chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
135
|
+
import "../chunk-JMTLK2SZ.js";
|
|
131
136
|
import "../chunk-FUJ36YDV.js";
|
|
132
137
|
import "../chunk-BQJIFRAZ.js";
|
|
133
|
-
import "../chunk-
|
|
134
|
-
import "../chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
168
|
+
} from "../chunk-LCNRFKP7.js";
|
|
163
169
|
import {
|
|
164
170
|
initLoggers
|
|
165
|
-
} from "../chunk-
|
|
171
|
+
} from "../chunk-ZH5CLGO6.js";
|
|
166
172
|
import "../chunk-66HGCPBU.js";
|
|
167
173
|
import {
|
|
168
174
|
diagnosticConsole
|
|
169
|
-
} from "../chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
2110
|
-
|
|
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,
|