@dvmkit/sdk 0.7.0-rc.1 → 0.7.0-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.
- package/README.md +39 -2
- package/dist/{chunk-S3OY533W.js → chunk-2NUFE2PG.js} +47 -5
- package/dist/{chunk-RA2WIX7G.js → chunk-3E4C6W7W.js} +17 -6
- package/dist/{chunk-GY66THYI.js → chunk-53SNRGQQ.js} +372 -153
- package/dist/{chunk-CXCQLOOK.js → chunk-62FI3NJF.js} +42 -107
- package/dist/chunk-6HJEVCVI.js +17 -0
- package/dist/chunk-A262WVYX.js +6 -0
- package/dist/{chunk-IV6Q7NRW.js → chunk-C5RIQWG4.js} +1 -1
- package/dist/{chunk-GAOAYHZA.js → chunk-FBQVOOYF.js} +37 -6
- package/dist/{chunk-Z4ZT5LNT.js → chunk-GEI4MAXE.js} +3 -3
- package/dist/{chunk-OML32F6I.js → chunk-GLIAR7RN.js} +1 -1
- package/dist/{chunk-X7EZ5CLI.js → chunk-HCATFJDD.js} +3 -3
- package/dist/{chunk-BYCEKO65.js → chunk-HPCXF3DV.js} +220 -32
- package/dist/{chunk-6XF3RVVX.js → chunk-IRXIH775.js} +5 -5
- package/dist/{chunk-QR2EF2NI.js → chunk-KCQDXIJU.js} +1 -42
- package/dist/chunk-MDW7ZR7V.js +47 -0
- package/dist/{chunk-KA6VN5FK.js → chunk-MQYM4T66.js} +3 -3
- package/dist/{chunk-P6QON7ER.js → chunk-NV7Z7377.js} +1 -1
- package/dist/{chunk-KMED3H3A.js → chunk-OBBVDKLE.js} +476 -230
- package/dist/{chunk-EQLA4FFY.js → chunk-OHUXCAOM.js} +17 -6
- package/dist/{chunk-FWGWLPXF.js → chunk-PZ5IAWFD.js} +1 -1
- package/dist/{chunk-IXR5RFK7.js → chunk-R3TQSXWT.js} +191 -5
- package/dist/{chunk-VHNPVGSA.js → chunk-T5DIXOLR.js} +3 -3
- package/dist/{chunk-RCM3P2HE.js → chunk-UKD3R2KU.js} +55 -4
- package/dist/chunk-WMGXJQI3.js +120 -0
- package/dist/{chunk-N5RZ5HVB.js → chunk-X6S2CHFM.js} +2 -2
- package/dist/{chunk-ETXDTUJO.js → chunk-ZCNPIILZ.js} +112 -1
- package/dist/{content-retention-DHyLdA6b.d.ts → content-retention-D2K4MKNO.d.ts} +1 -1
- package/dist/{credit-ledger-MCUXYKSJ.js → credit-ledger-MFIIOSZH.js} +4 -4
- package/dist/{credit-menu-DjnkeEUU.d.ts → credit-menu-D2t1-Tf6.d.ts} +13 -6
- package/dist/{fx-zMWFzfrU.d.ts → fx-Ql4nvdbh.d.ts} +10 -3
- package/dist/index.d.ts +5 -5
- package/dist/index.js +248 -16
- package/dist/internal/caller.d.ts +5032 -8272
- package/dist/internal/caller.js +4302 -8084
- package/dist/internal/index.js +1 -1
- package/dist/internal/server.d.ts +7 -7
- package/dist/internal/server.js +30 -31
- package/dist/{job-store-DdLXBpol.d.ts → job-store-DCvJQUX0.d.ts} +1 -1
- package/dist/{lightning-backend-Bw-qtAbt.d.ts → lightning-backend-CY5ML3km.d.ts} +2 -2
- package/dist/{memory-credit-ledger-SBSMGMDX.js → memory-credit-ledger-44NE4PZC.js} +5 -5
- package/dist/{mpp-setup-RF5FXGGV.js → mpp-setup-HRWUBULX.js} +4 -2
- package/dist/{payout-reporter-3Y2U55ZX.js → payout-reporter-7P66T77I.js} +6 -4
- package/dist/{postgres-consumed-credential-store-BUVCAPLS.js → postgres-consumed-credential-store-IDGPFKIL.js} +3 -3
- package/dist/{postgres-job-store-VHLQBJZC.js → postgres-job-store-UKNJ2F6Z.js} +2 -2
- package/dist/{postgres-replay-store-ARZSQ45X.js → postgres-replay-store-PMA4ADXN.js} +2 -2
- package/dist/{pricing-XT2IAPNE.js → pricing-52XJHJ6K.js} +12 -12
- package/dist/{revenue-reporter-MAERPYGK.js → revenue-reporter-HV7RMS54.js} +2 -2
- package/dist/server/index.d.ts +12 -11
- package/dist/server/index.js +47 -48
- package/dist/{step-cache-2MkvenJn.d.ts → step-cache-BOWAn_BH.d.ts} +84 -7
- package/dist/{tempo-charge-store-Q3D7KYMH.js → tempo-charge-store-P2Z4RMU7.js} +2 -2
- package/dist/{tempo-session-store-ZRNCOX7P.js → tempo-session-store-VSP7KLBS.js} +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +7 -6
- package/dist/{usd-DI3d3gTK.d.ts → usd-MAtMp3DB.d.ts} +1 -1
- package/dist/{x402-FT4S4JS4.js → x402-3IQ3HXSG.js} +8 -26
- package/package.json +1 -1
- package/dist/chunk-AT6V3SY7.js +0 -102
- package/dist/chunk-EZXAJ6EI.js +0 -1082
- package/dist/chunk-HCLVYZUZ.js +0 -244
- package/dist/chunk-JEVLNAO3.js +0 -1668
- package/dist/chunk-NFMOPYBA.js +0 -357
- package/dist/chunk-O2OTZ5GP.js +0 -1869
- package/dist/chunk-OFVV37XC.js +0 -57
- package/dist/chunk-SZVXOQ75.js +0 -211
- package/dist/chunk-WBOKPC37.js +0 -795
- package/dist/tempo-lifecycle-GJ77YKVY.js +0 -15
- package/dist/tempo-wallet-X2GGAZ6X.js +0 -40
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
TEMPO_MODERATO_CHAIN_ID,
|
|
3
|
+
TEMPO_MODERATO_RPC,
|
|
4
|
+
advertisedMethods,
|
|
5
|
+
challengeMeta,
|
|
6
|
+
installHostedTempoChargeGuard,
|
|
7
|
+
installHostedTempoCloseGuard,
|
|
8
|
+
isTempoInsufficientFundsError,
|
|
9
|
+
resolveTempoNetwork
|
|
10
|
+
} from "./chunk-R3TQSXWT.js";
|
|
11
|
+
import {
|
|
12
|
+
x402EarnedCeiling
|
|
13
|
+
} from "./chunk-FBQVOOYF.js";
|
|
6
14
|
import {
|
|
7
15
|
createX402FacilitatorAuthHeaders,
|
|
8
16
|
createX402FacilitatorClient,
|
|
17
|
+
paymentFailureStage,
|
|
9
18
|
settleWithFacilitator,
|
|
10
|
-
verifyWithFacilitator
|
|
11
|
-
|
|
19
|
+
verifyWithFacilitator,
|
|
20
|
+
withPaymentDiagnostics,
|
|
21
|
+
withPaymentStage
|
|
22
|
+
} from "./chunk-2NUFE2PG.js";
|
|
12
23
|
import {
|
|
13
24
|
MemoryCreditLedger
|
|
14
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-GLIAR7RN.js";
|
|
15
26
|
import {
|
|
16
27
|
PostgresJobStore
|
|
17
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-OHUXCAOM.js";
|
|
18
29
|
import {
|
|
19
30
|
parseStoreValue
|
|
20
31
|
} from "./chunk-YG7G4DPZ.js";
|
|
@@ -25,7 +36,7 @@ import {
|
|
|
25
36
|
humanizeZodIssues,
|
|
26
37
|
signedRequestInput,
|
|
27
38
|
zodIssuesOf
|
|
28
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-X6S2CHFM.js";
|
|
29
40
|
import {
|
|
30
41
|
MemoryJobStore,
|
|
31
42
|
UNCAPPABLE_ASK_TOTAL,
|
|
@@ -34,7 +45,7 @@ import {
|
|
|
34
45
|
isJobRetentionStore,
|
|
35
46
|
isReceiptIssuingStore,
|
|
36
47
|
isStreamableJobStore
|
|
37
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-C5RIQWG4.js";
|
|
38
49
|
import {
|
|
39
50
|
ContentHoldError,
|
|
40
51
|
JobCancelledError,
|
|
@@ -53,34 +64,28 @@ import {
|
|
|
53
64
|
ADMIN_AUTH_CLOCK_SKEW_SECONDS,
|
|
54
65
|
ADMIN_AUTH_NONCE_TTL_SECONDS,
|
|
55
66
|
ADMIN_STATE_UNAVAILABLE,
|
|
67
|
+
IMPLICIT_CREDIT_TTL_MS,
|
|
68
|
+
JOB_IDENTITY_HEADER,
|
|
56
69
|
TEMPO_SESSION_UPDATED_REASON,
|
|
57
70
|
X402_BATCH_CHANNEL_ABI,
|
|
58
71
|
attestedDvmIdentity,
|
|
59
72
|
buildAdminChallenge,
|
|
60
73
|
checkMintHealth,
|
|
74
|
+
computeResultHash,
|
|
61
75
|
createMonotonicClock,
|
|
76
|
+
formatStaleness,
|
|
62
77
|
getWallet,
|
|
78
|
+
isJobIdentityValue,
|
|
63
79
|
isPublicRequestId,
|
|
64
|
-
isTestMintUrl,
|
|
65
80
|
isX402SettlementReconciliationReason,
|
|
66
|
-
normaliseMintUrl,
|
|
67
81
|
parseTraceparent,
|
|
68
82
|
receiptPubkeyFromSecret,
|
|
69
|
-
toLockPubkey,
|
|
70
|
-
verifyCashuToken,
|
|
71
|
-
verifyChallenge
|
|
72
|
-
} from "./chunk-KMED3H3A.js";
|
|
73
|
-
import {
|
|
74
|
-
IMPLICIT_CREDIT_TTL_MS,
|
|
75
|
-
computeResultHash,
|
|
76
|
-
formatStaleness,
|
|
77
|
-
msatsToUsd,
|
|
78
|
-
msatsToUsdc,
|
|
79
83
|
signDrainReceipt,
|
|
80
84
|
signFundingReceipt,
|
|
81
85
|
signReceipt,
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
toLockPubkey,
|
|
87
|
+
verifyChallenge
|
|
88
|
+
} from "./chunk-OBBVDKLE.js";
|
|
84
89
|
import {
|
|
85
90
|
X402_BATCH_SETTLEMENT_SCHEME,
|
|
86
91
|
X402_DEFAULT_FACILITATOR,
|
|
@@ -93,25 +98,28 @@ import {
|
|
|
93
98
|
encodePaymentRequiredHeader,
|
|
94
99
|
encodeSettleResponseHeader,
|
|
95
100
|
exactEvmAuthorization,
|
|
101
|
+
msatsToUsd,
|
|
102
|
+
msatsToUsdc,
|
|
96
103
|
paymentRequiredV2FromV1,
|
|
97
104
|
resolveRpcOverride,
|
|
105
|
+
usdcToMsats,
|
|
98
106
|
x402NetworkToCaip2
|
|
99
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-62FI3NJF.js";
|
|
100
108
|
import {
|
|
101
109
|
RAIL_REFUNDABLE,
|
|
102
110
|
canonicalRequestPath,
|
|
111
|
+
canonicalize,
|
|
103
112
|
isZodSchema
|
|
104
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-UKD3R2KU.js";
|
|
105
114
|
import {
|
|
106
|
-
|
|
107
|
-
} from "./chunk-
|
|
115
|
+
createConsoleLogger
|
|
116
|
+
} from "./chunk-MDW7ZR7V.js";
|
|
108
117
|
import {
|
|
109
|
-
createConsoleLogger,
|
|
110
118
|
loggers,
|
|
111
119
|
pinDimension,
|
|
112
120
|
withSpan,
|
|
113
121
|
withTraceContext
|
|
114
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-KCQDXIJU.js";
|
|
115
123
|
import {
|
|
116
124
|
StepCache
|
|
117
125
|
} from "./chunk-BQJIFRAZ.js";
|
|
@@ -120,16 +128,15 @@ import {
|
|
|
120
128
|
InvalidCurrencyError,
|
|
121
129
|
UnsupportedCurrencyError,
|
|
122
130
|
createFxFetcher,
|
|
123
|
-
fxRateFor,
|
|
124
|
-
resolveFxSourceFromEnv,
|
|
125
|
-
validateCurrency
|
|
126
|
-
} from "./chunk-BYCEKO65.js";
|
|
127
|
-
import {
|
|
128
131
|
fiatToSatsCeil,
|
|
132
|
+
fxRateFor,
|
|
129
133
|
parseUsdPrice,
|
|
134
|
+
readFxSourceFailure,
|
|
135
|
+
resolveFxSourceFromEnv,
|
|
130
136
|
roundUsd,
|
|
131
|
-
satsToFiat
|
|
132
|
-
|
|
137
|
+
satsToFiat,
|
|
138
|
+
validateCurrency
|
|
139
|
+
} from "./chunk-HPCXF3DV.js";
|
|
133
140
|
import {
|
|
134
141
|
CreditLedger,
|
|
135
142
|
CreditLedgerError,
|
|
@@ -145,30 +152,26 @@ import {
|
|
|
145
152
|
isNonChannelBitcoinRail,
|
|
146
153
|
netOwedSats,
|
|
147
154
|
x402SettlementPending
|
|
148
|
-
} from "./chunk-
|
|
149
|
-
import {
|
|
150
|
-
withSdkInitLock
|
|
151
|
-
} from "./chunk-COYKJRMM.js";
|
|
155
|
+
} from "./chunk-IRXIH775.js";
|
|
152
156
|
import {
|
|
153
157
|
withPostgresRecoveryContext
|
|
154
|
-
} from "./chunk-
|
|
158
|
+
} from "./chunk-NV7Z7377.js";
|
|
155
159
|
import {
|
|
160
|
+
DvmError,
|
|
156
161
|
x402NetworkByCaip2
|
|
157
162
|
} from "./chunk-BPYMEMQX.js";
|
|
158
|
-
import {
|
|
159
|
-
TEMPO_MODERATO_CHAIN_ID,
|
|
160
|
-
TEMPO_MODERATO_RPC,
|
|
161
|
-
advertisedMethods,
|
|
162
|
-
challengeMeta,
|
|
163
|
-
installHostedTempoChargeGuard,
|
|
164
|
-
installHostedTempoCloseGuard,
|
|
165
|
-
isTempoInsufficientFundsError,
|
|
166
|
-
resolveTempoNetwork
|
|
167
|
-
} from "./chunk-IXR5RFK7.js";
|
|
168
163
|
import {
|
|
169
164
|
createDiagnosticCapabilityAuthority,
|
|
170
165
|
diagnosticConsole
|
|
171
|
-
} from "./chunk-
|
|
166
|
+
} from "./chunk-ZCNPIILZ.js";
|
|
167
|
+
import {
|
|
168
|
+
MemoryProcessedPaymentStore,
|
|
169
|
+
PostgresProcessedPaymentStore,
|
|
170
|
+
ProcessedPaymentReplayError
|
|
171
|
+
} from "./chunk-XRLKGCAW.js";
|
|
172
|
+
import {
|
|
173
|
+
withSdkInitLock
|
|
174
|
+
} from "./chunk-COYKJRMM.js";
|
|
172
175
|
|
|
173
176
|
// src/sdk/server/lock-pubkey-store.ts
|
|
174
177
|
async function initLockPubkeyTable(db) {
|
|
@@ -1071,7 +1074,8 @@ async function resolveFxSnapshot(fetcher) {
|
|
|
1071
1074
|
return {
|
|
1072
1075
|
ok: false,
|
|
1073
1076
|
reason: "rate_stale_refused",
|
|
1074
|
-
detail: `snapshot ${err.knownStale.staleDays.toString()}d stale
|
|
1077
|
+
detail: `snapshot ${err.knownStale.staleDays.toString()}d stale`,
|
|
1078
|
+
sourceFailure: readFxSourceFailure(err)
|
|
1075
1079
|
};
|
|
1076
1080
|
}
|
|
1077
1081
|
const cached = fetcher.lastKnown?.();
|
|
@@ -1081,7 +1085,8 @@ async function resolveFxSnapshot(fetcher) {
|
|
|
1081
1085
|
return {
|
|
1082
1086
|
ok: false,
|
|
1083
1087
|
reason: "rate_unavailable",
|
|
1084
|
-
detail: err instanceof Error ? err.message : String(err)
|
|
1088
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
1089
|
+
sourceFailure: err instanceof FxRateUnavailableError ? readFxSourceFailure(err) ?? { category: "unknown" } : { category: "unknown" }
|
|
1085
1090
|
};
|
|
1086
1091
|
}
|
|
1087
1092
|
}
|
|
@@ -1108,7 +1113,10 @@ async function msatsToFiatMicro(args) {
|
|
|
1108
1113
|
// A currency the snapshot never carried is the rate source narrowing, not
|
|
1109
1114
|
// a currency this DVM doesn't speak — `fxRateFor` separates the two.
|
|
1110
1115
|
reason: err instanceof FxRateUnavailableError ? "rate_unavailable" : "unsupported_currency",
|
|
1111
|
-
detail: err instanceof Error ? err.message : String(err)
|
|
1116
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
1117
|
+
...err instanceof FxRateUnavailableError && {
|
|
1118
|
+
sourceFailure: readFxSourceFailure(err) ?? { category: "unknown" }
|
|
1119
|
+
}
|
|
1112
1120
|
};
|
|
1113
1121
|
}
|
|
1114
1122
|
const amountMicro = Math.round(amount * 1e6);
|
|
@@ -1973,9 +1981,10 @@ async function createX402BatchSettlementServer(opts) {
|
|
|
1973
1981
|
throw new Error("x402 batch-settlement payTo must be a 20-byte EVM address");
|
|
1974
1982
|
}
|
|
1975
1983
|
const withdrawDelay = opts.config.withdrawDelay ?? X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS;
|
|
1976
|
-
|
|
1984
|
+
const minimumWithdrawDelay = opts.network === X402_BATCH_SETTLEMENT_NETWORK ? 900 : X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS;
|
|
1985
|
+
if (!Number.isInteger(withdrawDelay) || withdrawDelay < minimumWithdrawDelay) {
|
|
1977
1986
|
throw new Error(
|
|
1978
|
-
`x402 batch-settlement withdrawDelay must be at least ${String(
|
|
1987
|
+
`x402 batch-settlement withdrawDelay must be at least ${String(minimumWithdrawDelay)} seconds`
|
|
1979
1988
|
);
|
|
1980
1989
|
}
|
|
1981
1990
|
if (opts.config.autoSettlement !== false && opts.config.autoSettlement?.selectRefundChannels) {
|
|
@@ -2076,6 +2085,7 @@ async function createX402BatchSettlementServer(opts) {
|
|
|
2076
2085
|
payTo: opts.payTo,
|
|
2077
2086
|
network: opts.network,
|
|
2078
2087
|
storage,
|
|
2088
|
+
earnedNative: opts.earnedNative,
|
|
2079
2089
|
settleIntervalMs: (settlementConfig.settleIntervalSecs ?? X402_BATCH_AUTO_SETTLEMENT.settleIntervalSecs ?? 300) * 1e3,
|
|
2080
2090
|
...postgres ? { listWedgedRefunds: () => listWedgedRefunds(postgres) } : {}
|
|
2081
2091
|
});
|
|
@@ -2830,22 +2840,19 @@ function claimCeilingSelector(earnedNative) {
|
|
|
2830
2840
|
const charged = BigInt(channel.chargedCumulativeAmount);
|
|
2831
2841
|
const claimed = BigInt(channel.totalClaimed);
|
|
2832
2842
|
if (charged <= claimed) continue;
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
earned = await earnedNative(channel.channelId.toLowerCase());
|
|
2836
|
-
} catch (error) {
|
|
2843
|
+
const resolved = await x402EarnedCeiling(channel, earnedNative);
|
|
2844
|
+
if (resolved.kind === "unresolved") {
|
|
2837
2845
|
loggers.x402.warn("x402_claim_ceiling_unresolved", {
|
|
2838
2846
|
"channel.id": channel.channelId,
|
|
2839
|
-
error: error instanceof Error ? error.message : String(error)
|
|
2847
|
+
error: resolved.error instanceof Error ? resolved.error.message : String(resolved.error)
|
|
2840
2848
|
});
|
|
2841
2849
|
continue;
|
|
2842
2850
|
}
|
|
2843
|
-
if (
|
|
2851
|
+
if (resolved.kind === "unbound") {
|
|
2844
2852
|
loggers.x402.warn("x402_claim_ceiling_unbound", { "channel.id": channel.channelId });
|
|
2845
2853
|
continue;
|
|
2846
2854
|
}
|
|
2847
|
-
const
|
|
2848
|
-
const ceiling = wanted < charged ? wanted : charged;
|
|
2855
|
+
const { ceiling } = resolved;
|
|
2849
2856
|
if (ceiling <= claimed) continue;
|
|
2850
2857
|
selected.push({ ...channel, chargedCumulativeAmount: ceiling.toString() });
|
|
2851
2858
|
}
|
|
@@ -3113,6 +3120,10 @@ function decodeBatchPayment(header) {
|
|
|
3113
3120
|
if (!isBatchSettlementDepositPayload2(parsed.payload) && !isBatchSettlementVoucherPayload(parsed.payload) && !isBatchSettlementRefundPayload2(parsed.payload)) {
|
|
3114
3121
|
throw new Error("invalid batch-settlement payload");
|
|
3115
3122
|
}
|
|
3123
|
+
const voucher = parsed.payload.voucher;
|
|
3124
|
+
if (typeof voucher.channelId !== "string" || typeof voucher.maxClaimableAmount !== "string" || typeof voucher.signature !== "string") {
|
|
3125
|
+
throw new Error("invalid batch-settlement voucher");
|
|
3126
|
+
}
|
|
3116
3127
|
return parsed;
|
|
3117
3128
|
}
|
|
3118
3129
|
function batchVoucher(payload) {
|
|
@@ -3161,10 +3172,66 @@ function isRecord(value) {
|
|
|
3161
3172
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
3162
3173
|
}
|
|
3163
3174
|
|
|
3175
|
+
// src/sdk/server/payment-diagnostics.ts
|
|
3176
|
+
import { Errors } from "mppx";
|
|
3177
|
+
function paymentFailureFields(error) {
|
|
3178
|
+
let category = "unknown";
|
|
3179
|
+
try {
|
|
3180
|
+
if (error instanceof ProcessedPaymentReplayError) category = "replay_detected";
|
|
3181
|
+
else if (error instanceof CreditLedgerError) category = "ledger_refused";
|
|
3182
|
+
else if (error instanceof Errors.InvalidChallengeError) category = "invalid_challenge";
|
|
3183
|
+
else if (error instanceof Errors.MalformedCredentialError || error instanceof Errors.InvalidPayloadError) category = "malformed_credential";
|
|
3184
|
+
else if (error instanceof Errors.PaymentExpiredError) category = "payment_expired";
|
|
3185
|
+
else if (error instanceof Errors.VerificationFailedError) category = "verification_failed";
|
|
3186
|
+
else if (error instanceof Errors.PaymentInsufficientError || error instanceof Errors.InsufficientBalanceError) category = "insufficient_funds";
|
|
3187
|
+
else if (error instanceof Errors.InvalidSignatureError) category = "invalid_signature";
|
|
3188
|
+
else if (error instanceof Errors.PaymentMethodUnsupportedError) category = "unsupported_method";
|
|
3189
|
+
} catch {
|
|
3190
|
+
}
|
|
3191
|
+
return { failure_category: category, failure_stage: paymentFailureStage(error) };
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3164
3194
|
// src/sdk/server/payment.ts
|
|
3165
|
-
import { randomBytes, randomUUID as randomUUID2 } from "crypto";
|
|
3195
|
+
import { createHash as createHash4, randomBytes, randomUUID as randomUUID2 } from "crypto";
|
|
3166
3196
|
import { Challenge } from "mppx";
|
|
3167
3197
|
|
|
3198
|
+
// src/lib/cashu/verify.ts
|
|
3199
|
+
import { getTokenMetadata } from "@cashu/cashu-ts";
|
|
3200
|
+
function verifyCashuToken(token, acceptedMints) {
|
|
3201
|
+
let mint, unit, totalMsats;
|
|
3202
|
+
try {
|
|
3203
|
+
const meta = getTokenMetadata(token);
|
|
3204
|
+
mint = meta.mint;
|
|
3205
|
+
unit = meta.unit;
|
|
3206
|
+
totalMsats = meta.amount.toNumber() * 1e3;
|
|
3207
|
+
} catch {
|
|
3208
|
+
throw new DvmError(
|
|
3209
|
+
"cashu_invalid_token",
|
|
3210
|
+
"The Cashu token could not be decoded.",
|
|
3211
|
+
"Ensure the token is a valid cashuA... or cashuB... string."
|
|
3212
|
+
);
|
|
3213
|
+
}
|
|
3214
|
+
const normalised = acceptedMints.map(normaliseMintUrl);
|
|
3215
|
+
if (!normalised.includes(normaliseMintUrl(mint))) {
|
|
3216
|
+
throw new DvmError(
|
|
3217
|
+
"cashu_mint_not_accepted",
|
|
3218
|
+
`Mint ${mint} is not accepted by this provider.`,
|
|
3219
|
+
`Accepted mints: ${acceptedMints.join(", ")}`
|
|
3220
|
+
);
|
|
3221
|
+
}
|
|
3222
|
+
return { mint, totalMsats, unit };
|
|
3223
|
+
}
|
|
3224
|
+
function normaliseMintUrl(url) {
|
|
3225
|
+
try {
|
|
3226
|
+
const u = new URL(url);
|
|
3227
|
+
u.hostname = u.hostname.toLowerCase();
|
|
3228
|
+
u.pathname = u.pathname.replace(/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
3229
|
+
return u.toString().replace(/\/$/, "");
|
|
3230
|
+
} catch {
|
|
3231
|
+
return url.toLowerCase().replace(/\/+$/, "");
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
|
|
3168
3235
|
// src/sdk/server/mpp-units.ts
|
|
3169
3236
|
function decimalsFor(methodName) {
|
|
3170
3237
|
switch (methodName) {
|
|
@@ -3219,6 +3286,22 @@ function methodNativeAmountToDecimal(amount, methodName) {
|
|
|
3219
3286
|
return `${nativeAmount2 / scale}.${(nativeAmount2 % scale).toString().padStart(decimals, "0")}`;
|
|
3220
3287
|
}
|
|
3221
3288
|
|
|
3289
|
+
// src/lib/mints.ts
|
|
3290
|
+
function isTestMintUrl(url) {
|
|
3291
|
+
let host;
|
|
3292
|
+
try {
|
|
3293
|
+
host = new URL(url).hostname.toLowerCase();
|
|
3294
|
+
} catch {
|
|
3295
|
+
return false;
|
|
3296
|
+
}
|
|
3297
|
+
if (host.startsWith("[") && host.endsWith("]")) host = host.slice(1, -1);
|
|
3298
|
+
if (LOOPBACK_HOSTS.has(host)) return true;
|
|
3299
|
+
if (host.endsWith(".localhost")) return true;
|
|
3300
|
+
return TEST_MINT_HOSTS.has(host);
|
|
3301
|
+
}
|
|
3302
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1"]);
|
|
3303
|
+
var TEST_MINT_HOSTS = /* @__PURE__ */ new Set(["testnut.cashu.space", "dvmkit-testmint.fly.dev"]);
|
|
3304
|
+
|
|
3222
3305
|
// src/sdk/server/wallet-accumulator-receive.ts
|
|
3223
3306
|
import {
|
|
3224
3307
|
Amount as Amount2,
|
|
@@ -3468,6 +3551,9 @@ async function issueUpfrontChallenges(mpp, requiredMsats, resourcePath, btcUsdRa
|
|
|
3468
3551
|
);
|
|
3469
3552
|
}
|
|
3470
3553
|
async function verifyUpfrontPayment(opts) {
|
|
3554
|
+
return withPaymentDiagnostics(() => verifyUpfrontPaymentInScope(opts));
|
|
3555
|
+
}
|
|
3556
|
+
async function verifyUpfrontPaymentInScope(opts) {
|
|
3471
3557
|
const {
|
|
3472
3558
|
cashuToken,
|
|
3473
3559
|
requiredMsats,
|
|
@@ -3733,7 +3819,10 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3733
3819
|
);
|
|
3734
3820
|
} catch (err) {
|
|
3735
3821
|
const mapped = mapLedgerCommitError(err, x402Requirements);
|
|
3736
|
-
if (mapped)
|
|
3822
|
+
if (mapped) {
|
|
3823
|
+
logCredentialRejected("x402", "upfront", err);
|
|
3824
|
+
return mapped;
|
|
3825
|
+
}
|
|
3737
3826
|
logCredentialRejected("x402", "upfront", err);
|
|
3738
3827
|
return {
|
|
3739
3828
|
paidMsats: 0,
|
|
@@ -3794,15 +3883,15 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3794
3883
|
x402Requirements
|
|
3795
3884
|
});
|
|
3796
3885
|
}
|
|
3797
|
-
const { verifyX402Payment } = await import("./x402-
|
|
3798
|
-
const receipt = await verifyX402Payment(
|
|
3886
|
+
const { verifyX402Payment } = await import("./x402-3IQ3HXSG.js");
|
|
3887
|
+
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
3799
3888
|
x402Payment,
|
|
3800
3889
|
x402Config,
|
|
3801
3890
|
requiredUsdcMicro,
|
|
3802
3891
|
x402Resource ?? "/v1/job",
|
|
3803
3892
|
rate ?? 0,
|
|
3804
3893
|
x402ExactVersions
|
|
3805
|
-
);
|
|
3894
|
+
));
|
|
3806
3895
|
if (receipt.verified) {
|
|
3807
3896
|
const settledUsdcMicro = receipt.amountUsdcMicro;
|
|
3808
3897
|
const paidMsats = settledUsdcMicro === void 0 ? receipt.amountMsats : x402SettledShare(requiredMsats, Number(requiredUsdcMicro), settledUsdcMicro);
|
|
@@ -3846,7 +3935,10 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3846
3935
|
});
|
|
3847
3936
|
} catch (err) {
|
|
3848
3937
|
const mapped = mapLedgerCommitError(err, x402Requirements, true);
|
|
3849
|
-
if (mapped)
|
|
3938
|
+
if (mapped) {
|
|
3939
|
+
logCredentialRejected("x402", "upfront", err);
|
|
3940
|
+
return mapped;
|
|
3941
|
+
}
|
|
3850
3942
|
throw err;
|
|
3851
3943
|
}
|
|
3852
3944
|
}
|
|
@@ -3954,6 +4046,30 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3954
4046
|
}
|
|
3955
4047
|
const expectedAmount = opts.priceFiat?.currency === "usd" ? fiatMicroToMethodAmount(opts.priceFiat.amountMicro, cred.challenge.method) : msatsToMethodAmount(requiredMsats, cred.challenge.method, rate);
|
|
3956
4048
|
const sessionBasis = mppSessionBasis(cred);
|
|
4049
|
+
const replayRealm = mpp.realm ?? cred.challenge.realm;
|
|
4050
|
+
if (consumedCredentialStore && await withPaymentStage("replay_store", () => consumedCredentialStore.has(replayRealm, cred.challenge.id))) {
|
|
4051
|
+
const mppChallenges = await issueUpfrontChallenges(
|
|
4052
|
+
mpp,
|
|
4053
|
+
requiredMsats,
|
|
4054
|
+
resourcePath ?? "/v1/job",
|
|
4055
|
+
rate,
|
|
4056
|
+
sessionIssuable,
|
|
4057
|
+
opts.fundOnly?.allowOneShotStablecoin,
|
|
4058
|
+
opts.priceFiat
|
|
4059
|
+
);
|
|
4060
|
+
return {
|
|
4061
|
+
paidMsats: 0,
|
|
4062
|
+
receivedProofs: [],
|
|
4063
|
+
error: {
|
|
4064
|
+
body: paymentErrorBody("payment_invalid", {
|
|
4065
|
+
message: "MPP credential already used"
|
|
4066
|
+
}),
|
|
4067
|
+
status: 402,
|
|
4068
|
+
mppChallenges,
|
|
4069
|
+
...x402Requirements && { x402Requirements }
|
|
4070
|
+
}
|
|
4071
|
+
};
|
|
4072
|
+
}
|
|
3957
4073
|
let tempoReceipt;
|
|
3958
4074
|
const broadcast = async () => {
|
|
3959
4075
|
const receipt = await loggers.tempo.span(
|
|
@@ -3963,7 +4079,7 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3963
4079
|
challenge_id: cred.challenge.id,
|
|
3964
4080
|
amount: expectedAmount
|
|
3965
4081
|
},
|
|
3966
|
-
() => mpp.broadcastCredential(mppCredential, {
|
|
4082
|
+
() => withPaymentStage("verifier_broadcast", () => mpp.broadcastCredential(mppCredential, {
|
|
3967
4083
|
request: { amount: expectedAmount },
|
|
3968
4084
|
...opts.hostingAdmissionId && {
|
|
3969
4085
|
hostedPaymentIntent: {
|
|
@@ -3982,7 +4098,8 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3982
4098
|
path: resourcePath ?? "/v1/job",
|
|
3983
4099
|
nonce: challengeMeta(cred.challenge)?.nonce ?? ""
|
|
3984
4100
|
}
|
|
3985
|
-
})
|
|
4101
|
+
})),
|
|
4102
|
+
{ onError: paymentFailureFields }
|
|
3986
4103
|
);
|
|
3987
4104
|
tempoReceipt = receipt;
|
|
3988
4105
|
return receipt;
|
|
@@ -4039,7 +4156,10 @@ async function verifyUpfrontPayment(opts) {
|
|
|
4039
4156
|
credited = accepted.result;
|
|
4040
4157
|
} catch (err) {
|
|
4041
4158
|
const mapped = mapLedgerCommitError(err, x402Requirements, true);
|
|
4042
|
-
if (mapped)
|
|
4159
|
+
if (mapped) {
|
|
4160
|
+
logCredentialRejected("tempo", "upfront", err);
|
|
4161
|
+
return mapped;
|
|
4162
|
+
}
|
|
4043
4163
|
throw err;
|
|
4044
4164
|
}
|
|
4045
4165
|
} else {
|
|
@@ -4067,35 +4187,12 @@ async function verifyUpfrontPayment(opts) {
|
|
|
4067
4187
|
}
|
|
4068
4188
|
};
|
|
4069
4189
|
}
|
|
4070
|
-
if (consumedCredentialStore) {
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
requiredMsats,
|
|
4077
|
-
resourcePath ?? "/v1/job",
|
|
4078
|
-
rate,
|
|
4079
|
-
sessionIssuable,
|
|
4080
|
-
opts.fundOnly?.allowOneShotStablecoin,
|
|
4081
|
-
opts.priceFiat
|
|
4082
|
-
);
|
|
4083
|
-
return {
|
|
4084
|
-
paidMsats: 0,
|
|
4085
|
-
receivedProofs: [],
|
|
4086
|
-
error: {
|
|
4087
|
-
body: paymentErrorBody("payment_invalid", {
|
|
4088
|
-
message: "MPP credential already used"
|
|
4089
|
-
}),
|
|
4090
|
-
status: 402,
|
|
4091
|
-
mppChallenges,
|
|
4092
|
-
...x402Requirements && { x402Requirements }
|
|
4093
|
-
}
|
|
4094
|
-
};
|
|
4095
|
-
}
|
|
4096
|
-
if (!sessionBasis) {
|
|
4097
|
-
await consumedCredentialStore.mark(realm, id, CONSUMED_CREDENTIAL_TTL_MS / 1e3);
|
|
4098
|
-
}
|
|
4190
|
+
if (consumedCredentialStore && !sessionBasis) {
|
|
4191
|
+
await withPaymentStage("replay_store", () => consumedCredentialStore.mark(
|
|
4192
|
+
replayRealm,
|
|
4193
|
+
cred.challenge.id,
|
|
4194
|
+
CONSUMED_CREDENTIAL_TTL_MS / 1e3
|
|
4195
|
+
));
|
|
4099
4196
|
}
|
|
4100
4197
|
if (ledgerCtx) {
|
|
4101
4198
|
try {
|
|
@@ -4109,16 +4206,27 @@ async function verifyUpfrontPayment(opts) {
|
|
|
4109
4206
|
});
|
|
4110
4207
|
} catch (err) {
|
|
4111
4208
|
const mapped = mapLedgerCommitError(err, x402Requirements, true);
|
|
4112
|
-
if (mapped)
|
|
4209
|
+
if (mapped) {
|
|
4210
|
+
logCredentialRejected("tempo", "upfront", err);
|
|
4211
|
+
return mapped;
|
|
4212
|
+
}
|
|
4113
4213
|
throw err;
|
|
4114
4214
|
}
|
|
4115
4215
|
}
|
|
4116
4216
|
if (sessionBasis && consumedCredentialStore) {
|
|
4117
|
-
await consumedCredentialStore.mark(
|
|
4118
|
-
|
|
4217
|
+
await withPaymentStage("replay_store", () => consumedCredentialStore.mark(
|
|
4218
|
+
replayRealm,
|
|
4119
4219
|
cred.challenge.id,
|
|
4120
4220
|
CONSUMED_CREDENTIAL_TTL_MS / 1e3
|
|
4121
|
-
)
|
|
4221
|
+
)).catch((error) => {
|
|
4222
|
+
diagnosticConsole.warn({
|
|
4223
|
+
level: "warn",
|
|
4224
|
+
event: "tempo_replay_mark_failed",
|
|
4225
|
+
phase: "upfront",
|
|
4226
|
+
rail: "tempo",
|
|
4227
|
+
...paymentFailureFields(error)
|
|
4228
|
+
});
|
|
4229
|
+
});
|
|
4122
4230
|
}
|
|
4123
4231
|
if (credited) {
|
|
4124
4232
|
await mpp.completeHostedTempoCharge?.(cred.challenge.id).catch((error) => {
|
|
@@ -4327,6 +4435,22 @@ async function verifyTempoSessionManagementCredential(args) {
|
|
|
4327
4435
|
throw new Error("Hosted Tempo close requires non-mutating credential validation");
|
|
4328
4436
|
}
|
|
4329
4437
|
await args.mpp.validateCredential(credential, verifyOptions);
|
|
4438
|
+
if (args.action === "close") {
|
|
4439
|
+
if (!args.mpp.assertTempoSessionCloseVoucher) {
|
|
4440
|
+
throw new Error("Hosted Tempo close requires stored-channel voucher validation");
|
|
4441
|
+
}
|
|
4442
|
+
const { cumulativeAmount, signature } = credential.payload;
|
|
4443
|
+
if (typeof cumulativeAmount !== "string" || typeof signature !== "string") {
|
|
4444
|
+
throw new Error("Expected a Tempo session close voucher");
|
|
4445
|
+
}
|
|
4446
|
+
await args.mpp.assertTempoSessionCloseVoucher({
|
|
4447
|
+
channelId: payload.channelId,
|
|
4448
|
+
cumulativeAmount: BigInt(cumulativeAmount),
|
|
4449
|
+
signature,
|
|
4450
|
+
descriptor: credential.payload.descriptor,
|
|
4451
|
+
request: credential.challenge.request
|
|
4452
|
+
});
|
|
4453
|
+
}
|
|
4330
4454
|
}
|
|
4331
4455
|
await args.onBound?.();
|
|
4332
4456
|
const receipt = await args.mpp.broadcastCredential(credential, verifyOptions);
|
|
@@ -4687,6 +4811,9 @@ function buildPaymentErrorResponse(body, challenges, x402Requirements, status, x
|
|
|
4687
4811
|
return new Response(JSON.stringify(mergedBody), { status: status ?? 402, headers });
|
|
4688
4812
|
}
|
|
4689
4813
|
async function verifyIncomingPayment(body, opts, snapshot) {
|
|
4814
|
+
return withPaymentDiagnostics(() => verifyIncomingPaymentInScope(body, opts, snapshot));
|
|
4815
|
+
}
|
|
4816
|
+
async function verifyIncomingPaymentInScope(body, opts, snapshot) {
|
|
4690
4817
|
if (body.type !== "payment") return {};
|
|
4691
4818
|
if (body.content.cashu_token) {
|
|
4692
4819
|
if (opts.cashuMode === "p2pk-accumulator" && (opts.accumulatorDb || opts.disposableCashu) && opts.dvmId && opts.lockPubkeys && opts.lockPubkeys.length > 0) {
|
|
@@ -4769,15 +4896,15 @@ async function verifyIncomingPayment(body, opts, snapshot) {
|
|
|
4769
4896
|
snapshot
|
|
4770
4897
|
});
|
|
4771
4898
|
}
|
|
4772
|
-
const { verifyX402Payment } = await import("./x402-
|
|
4773
|
-
const receipt = await verifyX402Payment(
|
|
4899
|
+
const { verifyX402Payment } = await import("./x402-3IQ3HXSG.js");
|
|
4900
|
+
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
4774
4901
|
body.content.x402_payment,
|
|
4775
4902
|
opts.x402Config,
|
|
4776
4903
|
requiredUsdcMicro,
|
|
4777
4904
|
opts.resourcePath ?? "/v1/job",
|
|
4778
4905
|
rate,
|
|
4779
4906
|
opts.x402ExactVersions
|
|
4780
|
-
);
|
|
4907
|
+
));
|
|
4781
4908
|
if (!receipt.verified) {
|
|
4782
4909
|
return {
|
|
4783
4910
|
error: {
|
|
@@ -4826,6 +4953,7 @@ async function verifyIncomingPayment(body, opts, snapshot) {
|
|
|
4826
4953
|
} catch (err) {
|
|
4827
4954
|
const mapped = mapLedgerCommitError(err, void 0, true);
|
|
4828
4955
|
if (mapped?.error) {
|
|
4956
|
+
logCredentialRejected("x402", "mid-job", err);
|
|
4829
4957
|
return { error: { body: mapped.error.body, status: mapped.error.status } };
|
|
4830
4958
|
}
|
|
4831
4959
|
throw err;
|
|
@@ -4933,13 +5061,14 @@ async function verifyIncomingPayment(body, opts, snapshot) {
|
|
|
4933
5061
|
challenge_id: credential.challenge.id,
|
|
4934
5062
|
amount: expectedAmount
|
|
4935
5063
|
},
|
|
4936
|
-
() => mppServer.broadcastCredential(credential, {
|
|
5064
|
+
() => withPaymentStage("verifier_broadcast", () => mppServer.broadcastCredential(credential, {
|
|
4937
5065
|
request: { amount: expectedAmount },
|
|
4938
5066
|
...opts.hostingPaymentSeq !== void 0 && {
|
|
4939
5067
|
hostedPaymentIntent: { jobId: opts.jobId, paymentSeq: opts.hostingPaymentSeq }
|
|
4940
5068
|
},
|
|
4941
5069
|
...expectedMeta && { meta: expectedMeta }
|
|
4942
|
-
})
|
|
5070
|
+
})),
|
|
5071
|
+
{ onError: paymentFailureFields }
|
|
4943
5072
|
);
|
|
4944
5073
|
let credited;
|
|
4945
5074
|
if (ledgerCtx) {
|
|
@@ -4948,6 +5077,7 @@ async function verifyIncomingPayment(body, opts, snapshot) {
|
|
|
4948
5077
|
} catch (err) {
|
|
4949
5078
|
const mapped = mapLedgerCommitError(err, void 0, true);
|
|
4950
5079
|
if (mapped?.error) {
|
|
5080
|
+
logCredentialRejected("tempo", "mid-job", err);
|
|
4951
5081
|
return { error: { body: mapped.error.body, status: mapped.error.status } };
|
|
4952
5082
|
}
|
|
4953
5083
|
throw err;
|
|
@@ -5142,6 +5272,9 @@ function applyPaymentInfoToJob(job, info) {
|
|
|
5142
5272
|
creditPendingPayment(job);
|
|
5143
5273
|
}
|
|
5144
5274
|
async function processIncomingPayment(job, body, opts) {
|
|
5275
|
+
return withPaymentDiagnostics(() => processIncomingPaymentInScope(job, body, opts));
|
|
5276
|
+
}
|
|
5277
|
+
async function processIncomingPaymentInScope(job, body, opts) {
|
|
5145
5278
|
if (body.type !== "payment") return null;
|
|
5146
5279
|
if (body.content.cashu_token) {
|
|
5147
5280
|
if (opts.cashuMode === "p2pk-accumulator" && (opts.accumulatorDb || opts.disposableCashu) && opts.dvmId && opts.lockPubkeys && opts.lockPubkeys.length > 0) {
|
|
@@ -5194,15 +5327,15 @@ async function processIncomingPayment(job, body, opts) {
|
|
|
5194
5327
|
try {
|
|
5195
5328
|
const requiredMsats = job.pendingPaymentMsats ?? 0;
|
|
5196
5329
|
const requiredUsdcMicro = job.pendingX402AmountUsdcMicro !== void 0 ? BigInt(job.pendingX402AmountUsdcMicro) : BigInt(msatsToUsdc(requiredMsats, rate));
|
|
5197
|
-
const { verifyX402Payment } = await import("./x402-
|
|
5198
|
-
const receipt = await verifyX402Payment(
|
|
5330
|
+
const { verifyX402Payment } = await import("./x402-3IQ3HXSG.js");
|
|
5331
|
+
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
5199
5332
|
body.content.x402_payment,
|
|
5200
5333
|
opts.x402Config,
|
|
5201
5334
|
requiredUsdcMicro,
|
|
5202
5335
|
opts.resourcePath ?? "/v1/job",
|
|
5203
5336
|
rate,
|
|
5204
5337
|
opts.x402ExactVersions
|
|
5205
|
-
);
|
|
5338
|
+
));
|
|
5206
5339
|
if (receipt.verified) {
|
|
5207
5340
|
if (job.pendingX402Nonce !== void 0) {
|
|
5208
5341
|
const incomingNonce = decodePayment(body.content.x402_payment).payload.authorization.nonce;
|
|
@@ -5269,13 +5402,14 @@ async function processIncomingPayment(job, body, opts) {
|
|
|
5269
5402
|
challenge_id: credential.challenge.id,
|
|
5270
5403
|
amount: expectedAmount
|
|
5271
5404
|
},
|
|
5272
|
-
() => mppHandle.broadcastCredential(credential, {
|
|
5405
|
+
() => withPaymentStage("verifier_broadcast", () => mppHandle.broadcastCredential(credential, {
|
|
5273
5406
|
request: { amount: expectedAmount },
|
|
5274
5407
|
...opts.hostingPaymentSeq !== void 0 && {
|
|
5275
5408
|
hostedPaymentIntent: { jobId: opts.jobId, paymentSeq: opts.hostingPaymentSeq }
|
|
5276
5409
|
},
|
|
5277
5410
|
...expectedMeta && { meta: expectedMeta }
|
|
5278
|
-
})
|
|
5411
|
+
})),
|
|
5412
|
+
{ onError: paymentFailureFields }
|
|
5279
5413
|
);
|
|
5280
5414
|
if (!job.pendingMppChallengeIds?.includes(credential.challenge.id)) {
|
|
5281
5415
|
return {
|
|
@@ -5581,7 +5715,10 @@ async function resolveTopUpLedgerContext(opts, snapshot, binding) {
|
|
|
5581
5715
|
job_id: opts.jobId,
|
|
5582
5716
|
credit_id: snapshot.creditId,
|
|
5583
5717
|
draw_id: snapshot.drawId,
|
|
5584
|
-
...extra
|
|
5718
|
+
...extra,
|
|
5719
|
+
...typeof opts.jobId === "string" && {
|
|
5720
|
+
job_id_hash: createHash4("sha256").update(opts.jobId, "utf8").digest("hex")
|
|
5721
|
+
}
|
|
5585
5722
|
}
|
|
5586
5723
|
);
|
|
5587
5724
|
};
|
|
@@ -5644,7 +5781,10 @@ async function resolveTopUpLedgerContext(opts, snapshot, binding) {
|
|
|
5644
5781
|
logSkip("denomination_unavailable", {
|
|
5645
5782
|
currency,
|
|
5646
5783
|
cause: denomination.reason,
|
|
5647
|
-
...denomination.
|
|
5784
|
+
...denomination.sourceFailure && {
|
|
5785
|
+
source_failure: denomination.sourceFailure.category,
|
|
5786
|
+
source_status: denomination.sourceFailure.httpStatus
|
|
5787
|
+
}
|
|
5648
5788
|
});
|
|
5649
5789
|
return void 0;
|
|
5650
5790
|
}
|
|
@@ -5793,6 +5933,9 @@ function withDrawBasis(info, ctx, committed) {
|
|
|
5793
5933
|
};
|
|
5794
5934
|
}
|
|
5795
5935
|
async function fundAndDraw(ctx, funding, tx) {
|
|
5936
|
+
return withPaymentStage("funding_ledger", () => fundAndDrawInScope(ctx, funding, tx));
|
|
5937
|
+
}
|
|
5938
|
+
async function fundAndDrawInScope(ctx, funding, tx) {
|
|
5796
5939
|
const env = ctx.creditEnvelope;
|
|
5797
5940
|
const fundedMicro = funding.fundedMicro ?? fundedMicroFor(ctx.priceFiat, funding.paidMsats, ctx.requiredMsats);
|
|
5798
5941
|
const shortMidJob = ctx.midJob === true && funding.paidMsats < ctx.requiredMsats;
|
|
@@ -5831,9 +5974,11 @@ async function fundAndDraw(ctx, funding, tx) {
|
|
|
5831
5974
|
throw new Error("deposit outbox enqueue requires the rail's open transaction and a DVM id");
|
|
5832
5975
|
}
|
|
5833
5976
|
const commitDeposit = async (result, credit) => {
|
|
5977
|
+
const instrument = credit.rail ? storedCreditBinding(credit).instrument : void 0;
|
|
5834
5978
|
const report = {
|
|
5835
5979
|
...deposit,
|
|
5836
|
-
callerPubkey: credit.callerPubkey
|
|
5980
|
+
callerPubkey: credit.callerPubkey,
|
|
5981
|
+
...instrument && { instrument }
|
|
5837
5982
|
};
|
|
5838
5983
|
if (createsDepositLiability && enqueue && tx) {
|
|
5839
5984
|
await enqueue(tx, creditDepositPayload(ctx.dvmId, report));
|
|
@@ -6015,6 +6160,7 @@ function creditDepositPayload(dvmId, funding) {
|
|
|
6015
6160
|
creditCurrency: funding.currency,
|
|
6016
6161
|
fundedAt: funding.fundedAt,
|
|
6017
6162
|
expiryMs: funding.expiryMs,
|
|
6163
|
+
...funding.instrument && { instrument: funding.instrument },
|
|
6018
6164
|
// label a session-funded deposit as one, whether or not the chain
|
|
6019
6165
|
// binding below could be read. `rail: "tempo"` alone does not say — a
|
|
6020
6166
|
// `tempo/charge` one-shot funds a credit with no channel at all — so this is
|
|
@@ -6219,7 +6365,7 @@ async function commitMarkedFunding(ctx, funding, outerTx) {
|
|
|
6219
6365
|
const env = ctx.creditEnvelope;
|
|
6220
6366
|
const creditId = ctx.fundOnly?.creditId ?? ctx.topUp?.creditId ?? env?.creditId ?? implicitCreditId(funding.rail, funding.paymentId);
|
|
6221
6367
|
const drawId = ctx.fundOnly?.fundId ?? ctx.topUp?.drawId ?? env?.drawId ?? funding.paymentId;
|
|
6222
|
-
await store.record({
|
|
6368
|
+
await withPaymentStage("replay_store", () => store.record({
|
|
6223
6369
|
dvmId: ctx.dvmId,
|
|
6224
6370
|
rail: funding.rail,
|
|
6225
6371
|
paymentId: funding.paymentId,
|
|
@@ -6227,10 +6373,10 @@ async function commitMarkedFunding(ctx, funding, outerTx) {
|
|
|
6227
6373
|
drawId,
|
|
6228
6374
|
jobId: ctx.jobId,
|
|
6229
6375
|
tx
|
|
6230
|
-
});
|
|
6376
|
+
}));
|
|
6231
6377
|
return fundAndDraw(ctx, funding, tx);
|
|
6232
6378
|
};
|
|
6233
|
-
return outerTx ? commit(outerTx) : store.withTx(commit);
|
|
6379
|
+
return outerTx ? commit(outerTx) : withPaymentStage("replay_store", () => store.withTx(commit));
|
|
6234
6380
|
}
|
|
6235
6381
|
async function commitMppFunding(ctx, credential, funding) {
|
|
6236
6382
|
const session = mppSessionBasis(credential);
|
|
@@ -6592,15 +6738,14 @@ function x402NotOfferedResult(currency) {
|
|
|
6592
6738
|
error: x402NotOfferedPaymentError(currency)
|
|
6593
6739
|
};
|
|
6594
6740
|
}
|
|
6595
|
-
function logCredentialRejected(rail, phase,
|
|
6741
|
+
function logCredentialRejected(rail, phase, err) {
|
|
6596
6742
|
diagnosticConsole.warn(
|
|
6597
6743
|
{
|
|
6598
6744
|
level: "warn",
|
|
6599
6745
|
event: `${rail}_credential_rejected`,
|
|
6600
6746
|
phase,
|
|
6601
6747
|
rail,
|
|
6602
|
-
|
|
6603
|
-
error_message: void 0
|
|
6748
|
+
...paymentFailureFields(err)
|
|
6604
6749
|
}
|
|
6605
6750
|
);
|
|
6606
6751
|
}
|
|
@@ -9058,7 +9203,7 @@ async function handle(c, opts, action) {
|
|
|
9058
9203
|
}
|
|
9059
9204
|
|
|
9060
9205
|
// src/sdk/server/x402-exact-settlement.ts
|
|
9061
|
-
import { createHash as
|
|
9206
|
+
import { createHash as createHash5 } from "crypto";
|
|
9062
9207
|
var X402ExactSettlementServer = class {
|
|
9063
9208
|
constructor(opts) {
|
|
9064
9209
|
this.opts = opts;
|
|
@@ -9384,7 +9529,7 @@ function settlementMayHaveMoved(response) {
|
|
|
9384
9529
|
return reason.includes("authorization_already_used") || reason.includes("authorization already used") || /facilitator_status_5\d\d/.test(reason);
|
|
9385
9530
|
}
|
|
9386
9531
|
function hash(parts) {
|
|
9387
|
-
return
|
|
9532
|
+
return createHash5("sha256").update(JSON.stringify(parts)).digest("hex");
|
|
9388
9533
|
}
|
|
9389
9534
|
function safeError(err) {
|
|
9390
9535
|
if (err instanceof Error) return err.name;
|
|
@@ -9558,7 +9703,7 @@ var HostingCleanupFence = class {
|
|
|
9558
9703
|
};
|
|
9559
9704
|
|
|
9560
9705
|
// src/sdk/server/hosting-settlement-report-obligations.ts
|
|
9561
|
-
import { createHash as
|
|
9706
|
+
import { createHash as createHash6, randomUUID as randomUUID3 } from "crypto";
|
|
9562
9707
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
9563
9708
|
import { BATCH_SETTLEMENT_ADDRESS as BATCH_SETTLEMENT_ADDRESS3 } from "@x402/evm";
|
|
9564
9709
|
import { computeChannelId as computeChannelId2 } from "@x402/evm/batch-settlement/client";
|
|
@@ -9621,7 +9766,7 @@ var TEMPO_CLOSED_EVENT = TempoSession.Precompile.escrowAbi.find(
|
|
|
9621
9766
|
(item) => item.type === "event" && item.name === "ChannelClosed"
|
|
9622
9767
|
);
|
|
9623
9768
|
function hash2(value) {
|
|
9624
|
-
return
|
|
9769
|
+
return createHash6("sha256").update(JSON.stringify(value)).digest("hex");
|
|
9625
9770
|
}
|
|
9626
9771
|
function hex(value, bytes) {
|
|
9627
9772
|
return typeof value === "string" && new RegExp(`^0x[0-9a-fA-F]{${bytes * 2}}$`).test(value);
|
|
@@ -9948,6 +10093,18 @@ var HostedSettlementReportObligations = class {
|
|
|
9948
10093
|
);
|
|
9949
10094
|
return result.rows[0];
|
|
9950
10095
|
}
|
|
10096
|
+
/** The original close obligation reserved for this drain, while its report is outstanding. */
|
|
10097
|
+
async pendingTempoClose(channelId, drainId) {
|
|
10098
|
+
const result = await this.pool.query(
|
|
10099
|
+
`SELECT id,tx_hash,created_at_ms FROM sdk_hosted_settlement_report_obligations
|
|
10100
|
+
WHERE dvm_id=$1 AND scope=$2 AND rail='tempo' AND operation='close' AND channel_id=$3
|
|
10101
|
+
AND original->>'drainId'=$4 AND state NOT IN ('delivered','no_report')
|
|
10102
|
+
ORDER BY created_at_ms DESC LIMIT 1`,
|
|
10103
|
+
[this.dvmId, this.scope, channelId.toLowerCase(), drainId]
|
|
10104
|
+
);
|
|
10105
|
+
const row = result.rows[0];
|
|
10106
|
+
return row && { id: row.id, txHash: row.tx_hash, reservedAtMs: Number(row.created_at_ms) };
|
|
10107
|
+
}
|
|
9951
10108
|
async submittedIds(rail, operation, txHash, batchId) {
|
|
9952
10109
|
if (!hex(txHash, 32)) throw new Error("Hosted effect has no exact transaction hash");
|
|
9953
10110
|
const result = await this.pool.query(
|
|
@@ -10087,6 +10244,10 @@ var HostedSettlementReportObligations = class {
|
|
|
10087
10244
|
}));
|
|
10088
10245
|
}
|
|
10089
10246
|
async recoverOriginalX402Refunds() {
|
|
10247
|
+
const table = await this.pool.query(
|
|
10248
|
+
"SELECT to_regclass('x402_batch_settlements') IS NOT NULL AS present"
|
|
10249
|
+
);
|
|
10250
|
+
if (!table.rows[0]?.present) return [];
|
|
10090
10251
|
const rows2 = await this.pool.query(
|
|
10091
10252
|
`SELECT obligation.id,settlement.settle_response AS response
|
|
10092
10253
|
FROM sdk_hosted_settlement_report_obligations obligation
|
|
@@ -10524,7 +10685,7 @@ var HostedSettlementReportObligations = class {
|
|
|
10524
10685
|
};
|
|
10525
10686
|
|
|
10526
10687
|
// src/sdk/server/hosting-channel-evidence.ts
|
|
10527
|
-
import { createHash as
|
|
10688
|
+
import { createHash as createHash7 } from "crypto";
|
|
10528
10689
|
import { Session as TempoSession2 } from "mppx/tempo";
|
|
10529
10690
|
import { createPublicClient as createPublicClient5, http as http5 } from "viem";
|
|
10530
10691
|
import { BATCH_SETTLEMENT_ADDRESS as BATCH_SETTLEMENT_ADDRESS4 } from "@x402/evm";
|
|
@@ -10575,7 +10736,7 @@ async function readHostedChannelSnapshot(query) {
|
|
|
10575
10736
|
};
|
|
10576
10737
|
const x402HistoryComplete = await history(names[6]);
|
|
10577
10738
|
const tempoHistoryComplete = await history(names[7]);
|
|
10578
|
-
const digest =
|
|
10739
|
+
const digest = createHash7("sha256").update(JSON.stringify({
|
|
10579
10740
|
present: [...exists].sort(),
|
|
10580
10741
|
x402,
|
|
10581
10742
|
x402Tombstones,
|
|
@@ -11657,7 +11818,8 @@ var HostingControl = class {
|
|
|
11657
11818
|
pendingAdmissionCount: Number(pending.rows[0].pending),
|
|
11658
11819
|
pendingAdmissions: inFlight.rows.map((row) => ({ admissionId: row.id, workId: row.job_id })),
|
|
11659
11820
|
unresolvedAdmissionCount: Number(pending.rows[0].unresolved),
|
|
11660
|
-
unresolvedAdmissions: unresolved.rows.map((row) => ({ admissionId: row.id, jobId: row.job_id }))
|
|
11821
|
+
unresolvedAdmissions: unresolved.rows.map((row) => ({ admissionId: row.id, jobId: row.job_id })),
|
|
11822
|
+
jobIdentityHeader: "v1"
|
|
11661
11823
|
};
|
|
11662
11824
|
}
|
|
11663
11825
|
};
|
|
@@ -11724,9 +11886,9 @@ import { AsyncLocalStorage } from "async_hooks";
|
|
|
11724
11886
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
11725
11887
|
|
|
11726
11888
|
// src/sdk/server/instrumented-kv.ts
|
|
11727
|
-
import { createHash as
|
|
11889
|
+
import { createHash as createHash8 } from "crypto";
|
|
11728
11890
|
function hashKey(key) {
|
|
11729
|
-
return
|
|
11891
|
+
return createHash8("sha256").update(key).digest("hex").slice(0, 16);
|
|
11730
11892
|
}
|
|
11731
11893
|
function instrumentKVStore(inner) {
|
|
11732
11894
|
return {
|
|
@@ -16502,7 +16664,7 @@ function withWallClockDeadline(promise, timeoutMs) {
|
|
|
16502
16664
|
}
|
|
16503
16665
|
|
|
16504
16666
|
// src/sdk/server/app.ts
|
|
16505
|
-
import { createHash as
|
|
16667
|
+
import { createHash as createHash10, randomBytes as randomBytes5, randomUUID as randomUUID6 } from "crypto";
|
|
16506
16668
|
import { Hono } from "hono";
|
|
16507
16669
|
import { getCookie } from "hono/cookie";
|
|
16508
16670
|
import { cors } from "hono/cors";
|
|
@@ -16524,7 +16686,7 @@ import {
|
|
|
16524
16686
|
Amount as Amount3,
|
|
16525
16687
|
CheckStateEnum as CheckStateEnum3,
|
|
16526
16688
|
getP2PKExpectedWitnessPubkeys as getP2PKExpectedWitnessPubkeys2,
|
|
16527
|
-
getTokenMetadata
|
|
16689
|
+
getTokenMetadata as getTokenMetadata2
|
|
16528
16690
|
} from "@cashu/cashu-ts";
|
|
16529
16691
|
function installAdminCreditRoutes(app, opts) {
|
|
16530
16692
|
app.get("/admin/credit/pending-drains", (c) => handlePendingDrains(c, opts));
|
|
@@ -16885,7 +17047,7 @@ async function handleParkDrain(c, opts) {
|
|
|
16885
17047
|
}
|
|
16886
17048
|
let parsed;
|
|
16887
17049
|
try {
|
|
16888
|
-
const meta =
|
|
17050
|
+
const meta = getTokenMetadata2(token);
|
|
16889
17051
|
parsed = {
|
|
16890
17052
|
mint: meta.mint,
|
|
16891
17053
|
faceSats: Amount3.from(meta.amount).toNumber(),
|
|
@@ -19291,7 +19453,7 @@ initSchemaForm();
|
|
|
19291
19453
|
}
|
|
19292
19454
|
|
|
19293
19455
|
// src/sdk/server/request-fingerprint.ts
|
|
19294
|
-
import { createHash as
|
|
19456
|
+
import { createHash as createHash9 } from "crypto";
|
|
19295
19457
|
function requestFingerprint(req, opts) {
|
|
19296
19458
|
const canonical = canonicalize({
|
|
19297
19459
|
capability: req.capability,
|
|
@@ -19299,7 +19461,7 @@ function requestFingerprint(req, opts) {
|
|
|
19299
19461
|
params: req.params ?? {},
|
|
19300
19462
|
data: opts.stripAuthEnvelope ? stripEnvelope(req.data) : req.data
|
|
19301
19463
|
});
|
|
19302
|
-
return
|
|
19464
|
+
return createHash9("sha256").update(canonical).digest("hex");
|
|
19303
19465
|
}
|
|
19304
19466
|
var ENVELOPE_KEYS = /* @__PURE__ */ new Set(["pubkey", "signature", "timestamp", "nonce", "auth_statement"]);
|
|
19305
19467
|
function stripEnvelope(data) {
|
|
@@ -19422,7 +19584,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
19422
19584
|
}
|
|
19423
19585
|
}
|
|
19424
19586
|
if (!opts.onJobCompleted && platformToken && platformUrl && dvmId && opts.db) {
|
|
19425
|
-
const { RevenueReporter } = await import("./revenue-reporter-
|
|
19587
|
+
const { RevenueReporter } = await import("./revenue-reporter-HV7RMS54.js");
|
|
19426
19588
|
const reporter = new RevenueReporter(
|
|
19427
19589
|
opts.db,
|
|
19428
19590
|
platformUrl,
|
|
@@ -19432,7 +19594,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
19432
19594
|
revenueReporter = reporter;
|
|
19433
19595
|
await reporter.init();
|
|
19434
19596
|
reporter.startRetryLoop();
|
|
19435
|
-
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-
|
|
19597
|
+
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-7P66T77I.js");
|
|
19436
19598
|
payoutReporter = new PayoutReporter({
|
|
19437
19599
|
dvmId,
|
|
19438
19600
|
db: opts.db,
|
|
@@ -19717,6 +19879,7 @@ var DVMServer = class {
|
|
|
19717
19879
|
`createDVMServer: this DVM prices in ${JSON.stringify(this.pricingCurrency)} (DVMConfig.currency) but its fx fetcher only quotes [${fxCurrencies.join(", ")}]. Wire a fetcher that carries it \u2014 createFxFetcher({ currencies: [..., ${JSON.stringify(this.pricingCurrency)}] }) \u2014 or price in one of the above.`
|
|
19718
19880
|
);
|
|
19719
19881
|
}
|
|
19882
|
+
assertCapabilityRates(descriptor.capabilities);
|
|
19720
19883
|
if (opts.mintHealthTracker) {
|
|
19721
19884
|
this.mintHealthTracker = opts.mintHealthTracker;
|
|
19722
19885
|
this.ownsMintHealthTracker = false;
|
|
@@ -20297,7 +20460,7 @@ var DVMServer = class {
|
|
|
20297
20460
|
const dvmId = this.opts.dvmId ?? `dev:${this.descriptor.name}`;
|
|
20298
20461
|
return {
|
|
20299
20462
|
dvm_id: dvmId,
|
|
20300
|
-
builder_pubkey:
|
|
20463
|
+
builder_pubkey: createHash10("sha256").update(`dvmkit-dev:${dvmId}`).digest("hex")
|
|
20301
20464
|
};
|
|
20302
20465
|
}
|
|
20303
20466
|
throw new AuthAudienceError();
|
|
@@ -20645,7 +20808,7 @@ var DVMServer = class {
|
|
|
20645
20808
|
const paymentAuthorization = ctx.req.header("Authorization");
|
|
20646
20809
|
const mppArtifact = paymentAuthorization ? (await import("mppx")).Credential.extractPaymentScheme(paymentAuthorization) : void 0;
|
|
20647
20810
|
const attachedPayment = ctx.req.header("X-Cashu") ?? ctx.req.header("PAYMENT-SIGNATURE") ?? ctx.req.header("X-PAYMENT") ?? mppArtifact;
|
|
20648
|
-
const paymentArtifactHash = attachedPayment ?
|
|
20811
|
+
const paymentArtifactHash = attachedPayment ? createHash10("sha256").update(attachedPayment).digest("hex") : void 0;
|
|
20649
20812
|
hostingFundingArtifactHash = paymentArtifactHash;
|
|
20650
20813
|
if (!await control.admit(admissionId, workId, {
|
|
20651
20814
|
creditId,
|
|
@@ -20789,7 +20952,7 @@ var DVMServer = class {
|
|
|
20789
20952
|
// sees only the shortened list cannot tell a DVM that never did
|
|
20790
20953
|
// sessions from one whose observer is down for a minute.
|
|
20791
20954
|
...withheld.length && { withheld },
|
|
20792
|
-
realm: this.opts.mpp.realm,
|
|
20955
|
+
...this.opts.mpp.realm && { realm: this.opts.mpp.realm },
|
|
20793
20956
|
...this.opts.mpp.tempoConfiguration && {
|
|
20794
20957
|
recipient: this.opts.mpp.tempoConfiguration.recipient,
|
|
20795
20958
|
payment_token: this.opts.mpp.tempoConfiguration.paymentToken,
|
|
@@ -20829,17 +20992,20 @@ var DVMServer = class {
|
|
|
20829
20992
|
entry.input_schema = toJSONSchema(cap.input, { io: "input" });
|
|
20830
20993
|
}
|
|
20831
20994
|
if (cap.example !== void 0) entry.example = cap.example;
|
|
20995
|
+
let pricing;
|
|
20832
20996
|
if (cap.onQuote?.schema) {
|
|
20833
20997
|
const qs = cap.onQuote.schema;
|
|
20834
|
-
|
|
20998
|
+
pricing = {
|
|
20835
20999
|
quote: {
|
|
20836
21000
|
schema: isZodSchema(qs) ? toJSONSchema(qs, { io: "input" }) : qs
|
|
20837
21001
|
}
|
|
20838
21002
|
};
|
|
20839
21003
|
} else {
|
|
20840
21004
|
const max = this.jobManager.currentPricingMax(name);
|
|
20841
|
-
if (max)
|
|
21005
|
+
if (max) pricing = { max };
|
|
20842
21006
|
}
|
|
21007
|
+
if (cap.rates) pricing = { ...pricing, rates: cap.rates };
|
|
21008
|
+
if (pricing) entry.pricing = pricing;
|
|
20843
21009
|
out[name] = entry;
|
|
20844
21010
|
}
|
|
20845
21011
|
return out;
|
|
@@ -21351,7 +21517,7 @@ var DVMServer = class {
|
|
|
21351
21517
|
const authorization = c.req.header("Authorization");
|
|
21352
21518
|
const mppArtifact = authorization ? (await import("mppx")).Credential.extractPaymentScheme(authorization) : void 0;
|
|
21353
21519
|
const attachedPayment = c.req.header("X-Cashu") ?? c.req.header("PAYMENT-SIGNATURE") ?? c.req.header("X-PAYMENT") ?? mppArtifact;
|
|
21354
|
-
const hostingPaymentArtifactHash = attachedPayment ?
|
|
21520
|
+
const hostingPaymentArtifactHash = attachedPayment ? createHash10("sha256").update(attachedPayment).digest("hex") : void 0;
|
|
21355
21521
|
if (!resumeOnly && this.opts.hostingControlInstance && hostingPaymentArtifactHash) {
|
|
21356
21522
|
const priorId = await this.opts.hostingControlInstance.acceptedJobByPaymentArtifactHash(
|
|
21357
21523
|
hostingPaymentArtifactHash
|
|
@@ -21649,7 +21815,7 @@ var DVMServer = class {
|
|
|
21649
21815
|
}
|
|
21650
21816
|
const isAnonymous = requesterId === "anonymous" || requesterId === "dev-anonymous";
|
|
21651
21817
|
const jobToken = isAnonymous ? randomBytes5(32).toString("hex") : void 0;
|
|
21652
|
-
const requesterTokenHash = jobToken ?
|
|
21818
|
+
const requesterTokenHash = jobToken ? createHash10("sha256").update(jobToken).digest("hex") : void 0;
|
|
21653
21819
|
const job = jm.createJob(
|
|
21654
21820
|
normalisedBody,
|
|
21655
21821
|
requesterId,
|
|
@@ -22361,7 +22527,7 @@ function isJobOwner(c, job) {
|
|
|
22361
22527
|
if (job.requesterTokenHash) {
|
|
22362
22528
|
const token = c.req.header("X-Job-Token");
|
|
22363
22529
|
if (!token) return false;
|
|
22364
|
-
const provided =
|
|
22530
|
+
const provided = createHash10("sha256").update(token).digest("hex");
|
|
22365
22531
|
return timingSafeEqualHex(provided, job.requesterTokenHash);
|
|
22366
22532
|
}
|
|
22367
22533
|
return c.get("requesterId") === job.requesterId;
|
|
@@ -22379,7 +22545,7 @@ function buildSubmitResponse(c, job, jobToken, contentFields) {
|
|
|
22379
22545
|
else if (job.status === "completed") res.status = "completed";
|
|
22380
22546
|
Object.assign(res, terminalResponseFields(job), contentFields);
|
|
22381
22547
|
removeUnavailableContent(res);
|
|
22382
|
-
return c.json(res, job.status === "completed" ? 200 : 202);
|
|
22548
|
+
return c.json(res, job.status === "completed" ? 200 : 202, jobIdentityHeaders(job.id));
|
|
22383
22549
|
}
|
|
22384
22550
|
function requestRecoveryStore(store) {
|
|
22385
22551
|
return store.findJobByRequestId && store.claimRequestId && store.resumeRequestId && store.releaseRequestIdClaim ? store : void 0;
|
|
@@ -22445,7 +22611,10 @@ function buildRequestResultResponse(c, requestId, job, contentFields) {
|
|
|
22445
22611
|
if (job.paymentTransactionHash) res.transaction_hash = job.paymentTransactionHash;
|
|
22446
22612
|
Object.assign(res, terminalResponseFields(job), contentFields);
|
|
22447
22613
|
removeUnavailableContent(res);
|
|
22448
|
-
return c.json(res, isTerminal(job.status) ? 200 : 202);
|
|
22614
|
+
return c.json(res, isTerminal(job.status) ? 200 : 202, jobIdentityHeaders(job.id));
|
|
22615
|
+
}
|
|
22616
|
+
function jobIdentityHeaders(jobId) {
|
|
22617
|
+
return isJobIdentityValue(jobId) ? { [JOB_IDENTITY_HEADER]: jobId } : {};
|
|
22449
22618
|
}
|
|
22450
22619
|
function requestResultNotFound(c, requestId) {
|
|
22451
22620
|
return c.json(
|
|
@@ -22636,6 +22805,55 @@ function validateMessageContent(type, content, devMode) {
|
|
|
22636
22805
|
}
|
|
22637
22806
|
return null;
|
|
22638
22807
|
}
|
|
22808
|
+
var MAX_RATES = 5;
|
|
22809
|
+
var MAX_RATE_AMOUNT_LENGTH = 12;
|
|
22810
|
+
var MAX_RATE_TEXT_LENGTH = 24;
|
|
22811
|
+
var RATE_AMOUNT_RE = /^\d+(\.\d+)?$/;
|
|
22812
|
+
var RATE_KEYS = /* @__PURE__ */ new Set(["label", "amount", "currency", "per"]);
|
|
22813
|
+
function assertCapabilityRates(capabilities) {
|
|
22814
|
+
for (const [name, cap] of Object.entries(capabilities)) {
|
|
22815
|
+
if (cap.rates === void 0) continue;
|
|
22816
|
+
const refuse = (detail) => {
|
|
22817
|
+
throw new Error(`createDVMServer: capability ${JSON.stringify(name)}: ${detail}`);
|
|
22818
|
+
};
|
|
22819
|
+
const rates = cap.rates;
|
|
22820
|
+
if (!Array.isArray(rates) || rates.length === 0 || rates.length > MAX_RATES) {
|
|
22821
|
+
refuse(`rates must be an array of 1 to ${MAX_RATES} entries`);
|
|
22822
|
+
}
|
|
22823
|
+
if (cap.price === void 0 && cap.onQuote === void 0) {
|
|
22824
|
+
refuse("rates is declared on a free capability; set `price` or `onQuote`, or remove `rates`");
|
|
22825
|
+
}
|
|
22826
|
+
rates.forEach((rate, i) => {
|
|
22827
|
+
const at = `rates[${i}]`;
|
|
22828
|
+
if (typeof rate !== "object" || rate === null || Array.isArray(rate)) {
|
|
22829
|
+
refuse(`${at} must be an object with amount, currency and per`);
|
|
22830
|
+
}
|
|
22831
|
+
const entry = rate;
|
|
22832
|
+
for (const key of Object.keys(entry)) {
|
|
22833
|
+
if (!RATE_KEYS.has(key)) refuse(`${at}.${key} is not a rate field (label, amount, currency, per)`);
|
|
22834
|
+
}
|
|
22835
|
+
const amount = entry.amount;
|
|
22836
|
+
if (typeof amount !== "string" || amount.length > MAX_RATE_AMOUNT_LENGTH || !RATE_AMOUNT_RE.test(amount) || // Above zero without parsing to a float: some digit is non-zero.
|
|
22837
|
+
!/[1-9]/.test(amount)) {
|
|
22838
|
+
refuse(
|
|
22839
|
+
`${at}.amount must be a decimal dollar string above zero of at most ${MAX_RATE_AMOUNT_LENGTH} characters, like "0.00015" (got ${JSON.stringify(amount)})`
|
|
22840
|
+
);
|
|
22841
|
+
}
|
|
22842
|
+
if (entry.currency !== "USD") {
|
|
22843
|
+
refuse(`${at}.currency must be "USD" (got ${JSON.stringify(entry.currency)})`);
|
|
22844
|
+
}
|
|
22845
|
+
assertRateText(entry.per, `${at}.per`, refuse);
|
|
22846
|
+
if (entry.label !== void 0) assertRateText(entry.label, `${at}.label`, refuse);
|
|
22847
|
+
});
|
|
22848
|
+
}
|
|
22849
|
+
}
|
|
22850
|
+
function assertRateText(value, field, refuse) {
|
|
22851
|
+
if (typeof value !== "string" || value.length === 0 || value.length > MAX_RATE_TEXT_LENGTH || value.trim() !== value) {
|
|
22852
|
+
refuse(
|
|
22853
|
+
`${field} must be a string of 1 to ${MAX_RATE_TEXT_LENGTH} characters with no leading or trailing whitespace (got ${JSON.stringify(value)})`
|
|
22854
|
+
);
|
|
22855
|
+
}
|
|
22856
|
+
}
|
|
22639
22857
|
|
|
22640
22858
|
// src/sdk/server/tempo-observer-health.ts
|
|
22641
22859
|
var TEMPO_OBSERVER_HEALTH_REFRESH_TTL_MS = 60 * 1e3;
|
|
@@ -22848,6 +23066,7 @@ export {
|
|
|
22848
23066
|
derivedFundCreditId,
|
|
22849
23067
|
drawSettlementRef,
|
|
22850
23068
|
rateUnavailablePaymentError,
|
|
23069
|
+
isTestMintUrl,
|
|
22851
23070
|
X402_BATCH_SETTLEMENT_NETWORK,
|
|
22852
23071
|
X402_BATCH_SETTLEMENT_MAINNET_NETWORK,
|
|
22853
23072
|
X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS,
|