@dvmkit/sdk 0.10.0 → 0.11.0-rc.1
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/{chunk-3Q6FTZDB.js → chunk-3YFFZLW7.js} +2 -2
- package/dist/{chunk-YOSZIWC3.js → chunk-55DVLBCD.js} +135 -8
- package/dist/{chunk-VMHYGKWT.js → chunk-566CFXGU.js} +9 -1
- package/dist/chunk-5H7P3ORL.js +92 -0
- package/dist/{chunk-3R7NQA3Z.js → chunk-7KQLPVV7.js} +1 -1
- package/dist/{chunk-QNKK7SPY.js → chunk-AIQGF52I.js} +350 -71
- package/dist/{chunk-JNECYURT.js → chunk-D4FFS3IS.js} +1 -1
- package/dist/{chunk-VTHYQCDB.js → chunk-E7ZBCT5U.js} +1 -1
- package/dist/{chunk-MMGSYMIC.js → chunk-EP7OVWI5.js} +1 -1
- package/dist/{chunk-LDIPVPKI.js → chunk-FFRTAQUW.js} +1 -1
- package/dist/chunk-H3GGFEE5.js +57 -0
- package/dist/{chunk-M3T5JYDJ.js → chunk-HNXMWHLU.js} +1 -1
- package/dist/{chunk-Y6DO5WSO.js → chunk-HQPQ4PFI.js} +43 -21
- package/dist/{chunk-UKD3R2KU.js → chunk-HW2UCOOC.js} +4 -55
- package/dist/{chunk-FFXXGCVG.js → chunk-ITRSITFP.js} +1 -1
- package/dist/{chunk-MU3IE434.js → chunk-JLT2YIBS.js} +267 -52
- package/dist/{chunk-STJBBVNL.js → chunk-K2ZNIQZP.js} +458 -69
- package/dist/{chunk-KFCEXCZM.js → chunk-KJZVTWMX.js} +1 -1
- package/dist/{chunk-W3VGCNG6.js → chunk-LDKV4UHI.js} +1 -1
- package/dist/{chunk-AJ6UHXUA.js → chunk-M4NFYEEY.js} +1 -1
- package/dist/{chunk-MB6R4XPZ.js → chunk-NS2OMIU7.js} +15 -3
- package/dist/{chunk-VUGEEMLT.js → chunk-RPUFWIT4.js} +11 -89
- package/dist/{chunk-EWZFANHJ.js → chunk-VWIMQ5H5.js} +1 -1
- package/dist/{chunk-2XQLL6N6.js → chunk-WFCVS6QB.js} +2 -2
- package/dist/{chunk-QGNXYVBO.js → chunk-Z4FOPROB.js} +17 -0
- package/dist/{content-retention-CrILCNxk.d.ts → content-retention-ySTD1wwZ.d.ts} +1 -1
- package/dist/{credit-ledger-4PZNAMDT.js → credit-ledger-4CBYLSLY.js} +6 -3
- package/dist/{credit-menu-VwX_6KM7.d.ts → credit-menu-BYySnZBk.d.ts} +6 -4
- package/dist/{fx-BM5h4o5S.d.ts → fx-DVTNs9q1.d.ts} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +6 -5
- package/dist/internal/caller.d.ts +6 -6
- package/dist/internal/caller.js +26 -22
- package/dist/internal/server.d.ts +7 -7
- package/dist/internal/server.js +24 -22
- package/dist/{job-store-92v8e1LQ.d.ts → job-store-DRwXCJDI.d.ts} +1 -1
- package/dist/{lightning-backend-9oky_wJi.d.ts → lightning-backend-BX5YvjnM.d.ts} +1 -1
- package/dist/memory-credit-ledger-DKCN7FY2.js +14 -0
- package/dist/{mpp-setup-FURD45LI.js → mpp-setup-JU3MT7QX.js} +3 -3
- package/dist/{payout-reporter-HVJ6WUF3.js → payout-reporter-NXWQVKXW.js} +2 -2
- package/dist/{postgres-consumed-credential-store-WO6OCFXZ.js → postgres-consumed-credential-store-WXJLM6J7.js} +1 -1
- package/dist/{postgres-job-store-FSRUPYH2.js → postgres-job-store-WIIVRZPD.js} +2 -2
- package/dist/{postgres-replay-store-XXJSA457.js → postgres-replay-store-QJ4FG6AR.js} +2 -2
- package/dist/{pricing-X4XU5HXY.js → pricing-KCLENT2C.js} +3 -3
- package/dist/{revenue-reporter-EV3K5L6B.js → revenue-reporter-HD4GMXGD.js} +2 -2
- package/dist/server/index.d.ts +29 -12
- package/dist/server/index.js +31 -29
- package/dist/{step-cache--7yA5Ihr.d.ts → step-cache-d-VKen4K.d.ts} +147 -13
- package/dist/{tempo-charge-store-5JOIYUIH.js → tempo-charge-store-7LTUAQHQ.js} +2 -2
- package/dist/{tempo-session-store-S6QMLQUA.js → tempo-session-store-LYAIDR2B.js} +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +6 -6
- package/dist/{usd-C7lvLvLk.d.ts → usd-DSroMJ--.d.ts} +1 -1
- package/dist/{x402-EN5LSOVM.js → x402-RUJ4LUKF.js} +3 -3
- package/package.json +1 -1
- package/recipes/postgres/financial-export-v1.sql +19 -5
- package/dist/memory-credit-ledger-RP7DT5IY.js +0 -11
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-XRLKGCAW.js";
|
|
6
6
|
import {
|
|
7
7
|
x402EarnedCeiling
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ITRSITFP.js";
|
|
9
9
|
import {
|
|
10
10
|
createX402FacilitatorAuthHeaders,
|
|
11
11
|
createX402FacilitatorClient,
|
|
@@ -14,16 +14,13 @@ import {
|
|
|
14
14
|
verifyWithFacilitator,
|
|
15
15
|
withPaymentDiagnostics,
|
|
16
16
|
withPaymentStage
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-E7ZBCT5U.js";
|
|
18
18
|
import {
|
|
19
19
|
MemoryCreditLedger
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-55DVLBCD.js";
|
|
21
21
|
import {
|
|
22
22
|
PostgresJobStore
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import {
|
|
25
|
-
parseStoreValue
|
|
26
|
-
} from "./chunk-YG7G4DPZ.js";
|
|
23
|
+
} from "./chunk-HQPQ4PFI.js";
|
|
27
24
|
import {
|
|
28
25
|
SIGNED_ENVELOPE_FIELDS,
|
|
29
26
|
SignedRequestError,
|
|
@@ -31,7 +28,7 @@ import {
|
|
|
31
28
|
humanizeZodIssues,
|
|
32
29
|
signedRequestInput,
|
|
33
30
|
zodIssuesOf
|
|
34
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-WFCVS6QB.js";
|
|
35
32
|
import {
|
|
36
33
|
MemoryJobStore,
|
|
37
34
|
UNCAPPABLE_ASK_TOTAL,
|
|
@@ -40,7 +37,7 @@ import {
|
|
|
40
37
|
isJobRetentionStore,
|
|
41
38
|
isReceiptIssuingStore,
|
|
42
39
|
isStreamableJobStore
|
|
43
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-KJZVTWMX.js";
|
|
44
41
|
import {
|
|
45
42
|
ContentHoldError,
|
|
46
43
|
JobCancelledError,
|
|
@@ -66,7 +63,6 @@ import {
|
|
|
66
63
|
attestedDvmIdentity,
|
|
67
64
|
buildAdminChallenge,
|
|
68
65
|
checkMintHealth,
|
|
69
|
-
computeResultHash,
|
|
70
66
|
createMonotonicClock,
|
|
71
67
|
formatStaleness,
|
|
72
68
|
getWallet,
|
|
@@ -75,12 +71,9 @@ import {
|
|
|
75
71
|
isX402SettlementReconciliationReason,
|
|
76
72
|
parseTraceparent,
|
|
77
73
|
receiptPubkeyFromSecret,
|
|
78
|
-
signDrainReceipt,
|
|
79
|
-
signFundingReceipt,
|
|
80
|
-
signReceipt,
|
|
81
74
|
toLockPubkey,
|
|
82
75
|
verifyChallenge
|
|
83
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-RPUFWIT4.js";
|
|
84
77
|
import {
|
|
85
78
|
X402_BATCH_SETTLEMENT_SCHEME,
|
|
86
79
|
X402_DEFAULT_FACILITATOR,
|
|
@@ -103,12 +96,11 @@ import {
|
|
|
103
96
|
import {
|
|
104
97
|
RAIL_REFUNDABLE,
|
|
105
98
|
canonicalRequestPath,
|
|
106
|
-
canonicalize,
|
|
107
99
|
isZodSchema
|
|
108
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-HW2UCOOC.js";
|
|
109
101
|
import {
|
|
110
102
|
createConsoleLogger
|
|
111
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-7KQLPVV7.js";
|
|
112
104
|
import {
|
|
113
105
|
StepCache
|
|
114
106
|
} from "./chunk-BQJIFRAZ.js";
|
|
@@ -125,7 +117,7 @@ import {
|
|
|
125
117
|
roundUsd,
|
|
126
118
|
satsToFiat,
|
|
127
119
|
validateCurrency
|
|
128
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-LDKV4UHI.js";
|
|
129
121
|
import {
|
|
130
122
|
CreditLedger,
|
|
131
123
|
CreditLedgerError,
|
|
@@ -141,17 +133,29 @@ import {
|
|
|
141
133
|
isNonChannelBitcoinRail,
|
|
142
134
|
netOwedSats,
|
|
143
135
|
x402SettlementPending
|
|
144
|
-
} from "./chunk-
|
|
136
|
+
} from "./chunk-K2ZNIQZP.js";
|
|
137
|
+
import {
|
|
138
|
+
parseStoreValue
|
|
139
|
+
} from "./chunk-YG7G4DPZ.js";
|
|
145
140
|
import {
|
|
146
141
|
withSdkInitLock
|
|
147
142
|
} from "./chunk-COYKJRMM.js";
|
|
143
|
+
import {
|
|
144
|
+
computeResultHash,
|
|
145
|
+
signDrainReceipt,
|
|
146
|
+
signFundingReceipt,
|
|
147
|
+
signReceipt
|
|
148
|
+
} from "./chunk-5H7P3ORL.js";
|
|
148
149
|
import {
|
|
149
150
|
withPostgresRecoveryContext
|
|
150
|
-
} from "./chunk-
|
|
151
|
+
} from "./chunk-EP7OVWI5.js";
|
|
151
152
|
import {
|
|
152
153
|
DvmError,
|
|
153
154
|
x402NetworkByCaip2
|
|
154
155
|
} from "./chunk-BPYMEMQX.js";
|
|
156
|
+
import {
|
|
157
|
+
canonicalize
|
|
158
|
+
} from "./chunk-H3GGFEE5.js";
|
|
155
159
|
import {
|
|
156
160
|
TEMPO_MODERATO_CHAIN_ID,
|
|
157
161
|
TEMPO_MODERATO_RPC,
|
|
@@ -162,17 +166,17 @@ import {
|
|
|
162
166
|
installHostedTempoCloseGuard,
|
|
163
167
|
isTempoInsufficientFundsError,
|
|
164
168
|
resolveTempoNetwork
|
|
165
|
-
} from "./chunk-
|
|
169
|
+
} from "./chunk-JLT2YIBS.js";
|
|
166
170
|
import {
|
|
167
171
|
loggers,
|
|
168
172
|
pinDimension,
|
|
169
173
|
withSpan,
|
|
170
174
|
withTraceContext
|
|
171
|
-
} from "./chunk-
|
|
175
|
+
} from "./chunk-HNXMWHLU.js";
|
|
172
176
|
import {
|
|
173
177
|
createDiagnosticCapabilityAuthority,
|
|
174
178
|
diagnosticConsole
|
|
175
|
-
} from "./chunk-
|
|
179
|
+
} from "./chunk-Z4FOPROB.js";
|
|
176
180
|
|
|
177
181
|
// src/sdk/server/lock-pubkey-store.ts
|
|
178
182
|
async function initLockPubkeyTable(db) {
|
|
@@ -3884,7 +3888,7 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
3884
3888
|
x402Requirements
|
|
3885
3889
|
});
|
|
3886
3890
|
}
|
|
3887
|
-
const { verifyX402Payment } = await import("./x402-
|
|
3891
|
+
const { verifyX402Payment } = await import("./x402-RUJ4LUKF.js");
|
|
3888
3892
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
3889
3893
|
x402Payment,
|
|
3890
3894
|
x402Config,
|
|
@@ -4908,7 +4912,7 @@ async function verifyIncomingPaymentInScope(body, opts, snapshot) {
|
|
|
4908
4912
|
snapshot
|
|
4909
4913
|
});
|
|
4910
4914
|
}
|
|
4911
|
-
const { verifyX402Payment } = await import("./x402-
|
|
4915
|
+
const { verifyX402Payment } = await import("./x402-RUJ4LUKF.js");
|
|
4912
4916
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
4913
4917
|
body.content.x402_payment,
|
|
4914
4918
|
opts.x402Config,
|
|
@@ -5339,7 +5343,7 @@ async function processIncomingPaymentInScope(job, body, opts) {
|
|
|
5339
5343
|
try {
|
|
5340
5344
|
const requiredMsats = job.pendingPaymentMsats ?? 0;
|
|
5341
5345
|
const requiredUsdcMicro = job.pendingX402AmountUsdcMicro !== void 0 ? BigInt(job.pendingX402AmountUsdcMicro) : BigInt(msatsToUsdc(requiredMsats, rate));
|
|
5342
|
-
const { verifyX402Payment } = await import("./x402-
|
|
5346
|
+
const { verifyX402Payment } = await import("./x402-RUJ4LUKF.js");
|
|
5343
5347
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
5344
5348
|
body.content.x402_payment,
|
|
5345
5349
|
opts.x402Config,
|
|
@@ -6943,13 +6947,37 @@ async function fundingReceiptFor(ledger, issuer, funding) {
|
|
|
6943
6947
|
|
|
6944
6948
|
// src/sdk/server/tempo-drain-leg.ts
|
|
6945
6949
|
async function completeTempoChannelDrain(args) {
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6950
|
+
if (!args.tx && args.refundedNative !== void 0 && /^\d{1,78}$/.test(String(args.refundedNative))) {
|
|
6951
|
+
try {
|
|
6952
|
+
if (args.finalization?.outcome === "payer_exit" || args.finalization?.outcome === "payer_exit_unbacked") {
|
|
6953
|
+
if (BigInt(args.refundedNative) > 0n) await args.deps.ledger.recordTempoDrainPayment?.({ creditId: args.creditId, drainId: args.drainId });
|
|
6954
|
+
} else {
|
|
6955
|
+
await args.deps.ledger.recordTempoDrainRefund?.({ creditId: args.creditId, drainId: args.drainId, refundedNative: args.refundedNative });
|
|
6956
|
+
}
|
|
6957
|
+
} catch (error) {
|
|
6958
|
+
loggers.tempo.warn("tempo_drain_refund_evidence_write_failed", {});
|
|
6959
|
+
throw error;
|
|
6960
|
+
}
|
|
6961
|
+
}
|
|
6962
|
+
let settlementEvidence;
|
|
6963
|
+
try {
|
|
6964
|
+
settlementEvidence = refundFloorEvidence({
|
|
6965
|
+
rail: "tempo",
|
|
6966
|
+
refundedNative: args.refundedNative,
|
|
6967
|
+
debitedNative: args.debitedNative,
|
|
6968
|
+
creditId: args.creditId,
|
|
6969
|
+
drainId: args.drainId
|
|
6970
|
+
});
|
|
6971
|
+
} catch (error) {
|
|
6972
|
+
if (error instanceof DrainRefundFloorError && !args.tx) {
|
|
6973
|
+
try {
|
|
6974
|
+
await args.deps.ledger.recordTempoDrainHold?.({ creditId: args.creditId, drainId: args.drainId, reason: "refund_short" });
|
|
6975
|
+
} catch {
|
|
6976
|
+
loggers.tempo.warn("tempo_drain_hold_reason_write_failed", {});
|
|
6977
|
+
}
|
|
6978
|
+
}
|
|
6979
|
+
throw error;
|
|
6980
|
+
}
|
|
6953
6981
|
return commitTerminalDrain(
|
|
6954
6982
|
args.deps.drainReport,
|
|
6955
6983
|
async (innerTx) => {
|
|
@@ -7690,6 +7718,11 @@ async function recoverTempoDrain(deps, mpp, record, channelId) {
|
|
|
7690
7718
|
}
|
|
7691
7719
|
if (!result) return null;
|
|
7692
7720
|
if (!/^0x[0-9a-fA-F]{64}$/.test(result)) {
|
|
7721
|
+
try {
|
|
7722
|
+
await deps.ledger.recordTempoDrainHold?.({ creditId: record.creditId, drainId: record.drainId, reason: "close_evidence_missing" });
|
|
7723
|
+
} catch {
|
|
7724
|
+
loggers.tempo.warn("tempo_drain_hold_reason_write_failed", { amount_micro: record.amountMicro });
|
|
7725
|
+
}
|
|
7693
7726
|
loggers.tempo.warn("tempo_session_drain_refund_unproven", {
|
|
7694
7727
|
channel_id: channelId,
|
|
7695
7728
|
credit_id: record.creditId,
|
|
@@ -10130,6 +10163,7 @@ var HostedSettlementReportObligations = class {
|
|
|
10130
10163
|
FROM sdk_hosted_settlement_report_obligations target
|
|
10131
10164
|
WHERE target.dvm_id=$1 AND target.scope=$2 AND target.rail='tempo' AND target.operation='close'
|
|
10132
10165
|
AND target.state IN ('unmatched','no_report')
|
|
10166
|
+
AND ($7::text IS NULL OR target.channel_id=$7)
|
|
10133
10167
|
)
|
|
10134
10168
|
SELECT * FROM candidates
|
|
10135
10169
|
WHERE ($6::boolean OR (state='unmatched' AND (retryable OR write_off_allowed)))
|
|
@@ -10141,7 +10175,8 @@ var HostedSettlementReportObligations = class {
|
|
|
10141
10175
|
args.limit,
|
|
10142
10176
|
args.after?.createdAtMs ?? null,
|
|
10143
10177
|
args.after?.obligationId ?? null,
|
|
10144
|
-
args.all ?? false
|
|
10178
|
+
args.all ?? false,
|
|
10179
|
+
args.channelId ?? null
|
|
10145
10180
|
]
|
|
10146
10181
|
);
|
|
10147
10182
|
return result.rows.map((row) => ({
|
|
@@ -12725,22 +12760,17 @@ function buildContext(job, opts) {
|
|
|
12725
12760
|
};
|
|
12726
12761
|
const doResolve = async (pc) => {
|
|
12727
12762
|
if (resolved) return;
|
|
12763
|
+
if (job.pendingPayment?.resolve === doResolve) {
|
|
12764
|
+
job.status = job.pendingPrompts.size > 0 ? "awaiting-input" : "processing";
|
|
12765
|
+
const persist = opts.onPaymentResume ?? opts.onYield;
|
|
12766
|
+
if (job.status === "awaiting-input" && persist) await persist();
|
|
12767
|
+
if (resolved) return;
|
|
12768
|
+
job.pendingPayment = null;
|
|
12769
|
+
}
|
|
12728
12770
|
resolved = true;
|
|
12729
12771
|
cleanup();
|
|
12730
12772
|
creditedToHandlerMsats += amountMsats;
|
|
12731
12773
|
creditedToHandlerMicro += pendingFiat?.amountMicro ?? 0;
|
|
12732
|
-
if (job.pendingPayment?.resolve === doResolve) {
|
|
12733
|
-
job.pendingPayment = null;
|
|
12734
|
-
job.status = job.pendingPrompts.size > 0 ? "awaiting-input" : "processing";
|
|
12735
|
-
if (job.status === "awaiting-input" && opts.onYield) {
|
|
12736
|
-
try {
|
|
12737
|
-
await opts.onYield();
|
|
12738
|
-
} catch (err) {
|
|
12739
|
-
reject(err);
|
|
12740
|
-
return;
|
|
12741
|
-
}
|
|
12742
|
-
}
|
|
12743
|
-
}
|
|
12744
12774
|
resolve(pc);
|
|
12745
12775
|
};
|
|
12746
12776
|
const doReject = (err) => {
|
|
@@ -13266,6 +13296,9 @@ var JobManager = class {
|
|
|
13266
13296
|
// A prompt response and a payment NOTIFY must not mistake each other for a
|
|
13267
13297
|
// different machine's successful claim.
|
|
13268
13298
|
inputResumeTails = /* @__PURE__ */ new WeakMap();
|
|
13299
|
+
// A failed partial-wait snapshot leaves our durable claim in processing.
|
|
13300
|
+
// Retain its continuation so a later input can finish it without a new claim.
|
|
13301
|
+
claimedPaymentResumes = /* @__PURE__ */ new WeakMap();
|
|
13269
13302
|
sessionId = randomBytes4(3).toString("hex");
|
|
13270
13303
|
nextJobId = 1;
|
|
13271
13304
|
accumulatorMonitor;
|
|
@@ -13672,7 +13705,10 @@ var JobManager = class {
|
|
|
13672
13705
|
}
|
|
13673
13706
|
async queueInputResume(job, resume) {
|
|
13674
13707
|
const previous = this.inputResumeTails.get(job) ?? Promise.resolve();
|
|
13675
|
-
const next = previous.catch(() => void 0).then(
|
|
13708
|
+
const next = previous.catch(() => void 0).then(async () => {
|
|
13709
|
+
await this.claimedPaymentResumes.get(job)?.();
|
|
13710
|
+
return resume();
|
|
13711
|
+
});
|
|
13676
13712
|
this.inputResumeTails.set(job, next);
|
|
13677
13713
|
try {
|
|
13678
13714
|
return await next;
|
|
@@ -13684,6 +13720,19 @@ var JobManager = class {
|
|
|
13684
13720
|
await job.messageAppenderTail;
|
|
13685
13721
|
return isStreamableJobStore(this.jobStore) ? this.jobStore.claimForProcessing(job.id) : true;
|
|
13686
13722
|
}
|
|
13723
|
+
async resumeClaimedPayment(job, resume) {
|
|
13724
|
+
const retry = async () => {
|
|
13725
|
+
try {
|
|
13726
|
+
if (!isTerminal(job.status) && !await this.adoptDurableTerminal(job)) await resume();
|
|
13727
|
+
this.claimedPaymentResumes.delete(job);
|
|
13728
|
+
} catch (error) {
|
|
13729
|
+
if (!(error instanceof JobSnapshotPersistenceError)) this.claimedPaymentResumes.delete(job);
|
|
13730
|
+
throw error;
|
|
13731
|
+
}
|
|
13732
|
+
};
|
|
13733
|
+
this.claimedPaymentResumes.set(job, retry);
|
|
13734
|
+
await retry();
|
|
13735
|
+
}
|
|
13687
13736
|
async dispatchMessageNow(job, type, content) {
|
|
13688
13737
|
const ctx = job.sdkCtx;
|
|
13689
13738
|
const cap = this.getCapability(job.capability);
|
|
@@ -13712,10 +13761,13 @@ var JobManager = class {
|
|
|
13712
13761
|
return;
|
|
13713
13762
|
}
|
|
13714
13763
|
if (job.pendingPayment !== pp || isTerminal(job.status)) return;
|
|
13715
|
-
job
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13764
|
+
await this.resumeClaimedPayment(job, async () => {
|
|
13765
|
+
job.status = job.pendingPrompts.size > 0 ? "awaiting-input" : "processing";
|
|
13766
|
+
if (job.status === "awaiting-input") await retryJobSnapshot(() => this.persistJob(job));
|
|
13767
|
+
if (job.pendingPayment !== pp || isTerminal(job.status)) return;
|
|
13768
|
+
job.pendingPayment = null;
|
|
13769
|
+
await pp.resolve(pc);
|
|
13770
|
+
});
|
|
13719
13771
|
} else if (cap?.onPayment && ctx) {
|
|
13720
13772
|
await cap.onPayment(ctx, pc);
|
|
13721
13773
|
}
|
|
@@ -13768,10 +13820,14 @@ var JobManager = class {
|
|
|
13768
13820
|
record.seq = Math.max(record.seq, highSeq);
|
|
13769
13821
|
}
|
|
13770
13822
|
}
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13823
|
+
try {
|
|
13824
|
+
if (this.opts.dvmId && isTerminalCostRecoveryStore(this.jobStore)) {
|
|
13825
|
+
await this.jobStore.saveForDvm(record, this.opts.dvmId);
|
|
13826
|
+
} else {
|
|
13827
|
+
await this.jobStore.save(record);
|
|
13828
|
+
}
|
|
13829
|
+
} catch (error) {
|
|
13830
|
+
throw new JobSnapshotPersistenceError(error);
|
|
13775
13831
|
}
|
|
13776
13832
|
const saved = await this.jobStore.get(job.id);
|
|
13777
13833
|
if (saved) {
|
|
@@ -15311,6 +15367,7 @@ var JobManager = class {
|
|
|
15311
15367
|
fxFetcher: this.opts.fxFetcher,
|
|
15312
15368
|
onTerminal: () => this.handleJobTerminal(job),
|
|
15313
15369
|
onYield: () => this.persistJob(job),
|
|
15370
|
+
onPaymentResume: () => retryJobSnapshot(() => this.persistJob(job)),
|
|
15314
15371
|
subscribeNotifications: isStreamableJobStore(jobStore) ? (cb) => jobStore.subscribeNotifications(job.id, cb) : void 0,
|
|
15315
15372
|
getCounters: isStreamableJobStore(jobStore) ? () => jobStore.getCounters(job.id) : void 0,
|
|
15316
15373
|
drawPool: this.opts.creditLedger ? () => this.resolveDrawPool(job) : void 0,
|
|
@@ -15321,7 +15378,9 @@ var JobManager = class {
|
|
|
15321
15378
|
if (!pending || job.pendingPayment !== pending || isTerminal(job.status)) return false;
|
|
15322
15379
|
if (!await this.claimLocalInput(job)) return false;
|
|
15323
15380
|
if (job.pendingPayment !== pending || isTerminal(job.status)) return false;
|
|
15324
|
-
await
|
|
15381
|
+
await this.resumeClaimedPayment(job, async () => {
|
|
15382
|
+
await resume?.();
|
|
15383
|
+
});
|
|
15325
15384
|
return true;
|
|
15326
15385
|
});
|
|
15327
15386
|
} : void 0,
|
|
@@ -16082,6 +16141,23 @@ function resolvePricingMax(raw) {
|
|
|
16082
16141
|
if (raw === void 0) return void 0;
|
|
16083
16142
|
return { amount: roundUsd(parseUsdPrice(raw, "price")), currency: "usd" };
|
|
16084
16143
|
}
|
|
16144
|
+
var JobSnapshotPersistenceError = class extends Error {
|
|
16145
|
+
constructor(cause) {
|
|
16146
|
+
super("Job snapshot could not be persisted", { cause });
|
|
16147
|
+
this.name = "JobSnapshotPersistenceError";
|
|
16148
|
+
}
|
|
16149
|
+
};
|
|
16150
|
+
async function retryJobSnapshot(persist) {
|
|
16151
|
+
for (let attempt = 0; ; attempt++) {
|
|
16152
|
+
try {
|
|
16153
|
+
await persist();
|
|
16154
|
+
return;
|
|
16155
|
+
} catch (error) {
|
|
16156
|
+
if (!(error instanceof JobSnapshotPersistenceError) || attempt >= 2) throw error;
|
|
16157
|
+
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
|
|
16158
|
+
}
|
|
16159
|
+
}
|
|
16160
|
+
}
|
|
16085
16161
|
|
|
16086
16162
|
// src/sdk/server/mint-health-tracker.ts
|
|
16087
16163
|
var DEFAULT_TICK_INTERVAL_MS2 = 5 * 60 * 1e3;
|
|
@@ -17129,6 +17205,8 @@ function shortSha(sha) {
|
|
|
17129
17205
|
}
|
|
17130
17206
|
|
|
17131
17207
|
// src/sdk/server/admin-credit.ts
|
|
17208
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
17209
|
+
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
17132
17210
|
import {
|
|
17133
17211
|
Amount as Amount3,
|
|
17134
17212
|
CheckStateEnum as CheckStateEnum3,
|
|
@@ -17136,6 +17214,7 @@ import {
|
|
|
17136
17214
|
getTokenMetadata as getTokenMetadata2
|
|
17137
17215
|
} from "@cashu/cashu-ts";
|
|
17138
17216
|
function installAdminCreditRoutes(app, opts) {
|
|
17217
|
+
app.post("/admin/credit/refund-draw", (c) => handleRefundDraw(c, opts));
|
|
17139
17218
|
app.get("/admin/credit/pending-drains", (c) => handlePendingDrains(c, opts));
|
|
17140
17219
|
app.get("/admin/credit/bitcoin-liability", (c) => handleBitcoinLiability(c, opts));
|
|
17141
17220
|
app.post("/admin/credit/park-drain", (c) => handleParkDrain(c, opts));
|
|
@@ -17156,9 +17235,68 @@ function installAdminCreditRoutes(app, opts) {
|
|
|
17156
17235
|
app.post("/admin/credit/write-off-tempo-close-report", (c) => handleTempoCloseReportAction(c, opts, "write-off"));
|
|
17157
17236
|
app.get("/admin/credit/tempo-drains", (c) => handleTempoDrains(c, opts));
|
|
17158
17237
|
app.get("/admin/credit/tempo-losses", (c) => handleTempoLosses(c, opts));
|
|
17238
|
+
app.post("/admin/credit/book-tempo-drain", (c) => handleTempoDrainDecision(c, opts, "book_refunded"));
|
|
17239
|
+
app.post("/admin/credit/release-tempo-drain", (c) => handleTempoDrainDecision(c, opts, "release"));
|
|
17159
17240
|
app.post("/admin/credit/reconcile-tempo-drain", (c) => handleReconcileTempo(c, opts));
|
|
17160
17241
|
app.post("/admin/credit/write-off-tempo-drain", (c) => handleWriteOffTempo(c, opts));
|
|
17161
17242
|
}
|
|
17243
|
+
async function handleRefundDraw(c, opts) {
|
|
17244
|
+
const auth = await requireAuth(c, opts);
|
|
17245
|
+
if ("response" in auth) return auth.response;
|
|
17246
|
+
const body = await c.req.json().catch(() => null);
|
|
17247
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
17248
|
+
return c.json({ error: "invalid_body", message: "Request body must be a JSON object." }, 400);
|
|
17249
|
+
}
|
|
17250
|
+
const value = body;
|
|
17251
|
+
const nonempty = (item) => typeof item === "string" && item.length > 0;
|
|
17252
|
+
const byJob = nonempty(value.jobId) && value.creditId === void 0 && value.drawId === void 0;
|
|
17253
|
+
const byDraw = value.jobId === void 0 && nonempty(value.creditId) && nonempty(value.drawId);
|
|
17254
|
+
if (!byJob && !byDraw || !nonempty(value.refundId) || value.amountMicro !== void 0 && (typeof value.amountMicro !== "number" || !Number.isSafeInteger(value.amountMicro) || value.amountMicro <= 0) || value.reason !== void 0 && (typeof value.reason !== "string" || value.reason.length > 280)) {
|
|
17255
|
+
return c.json({ error: "invalid_body", message: "Provide jobId or creditId + drawId, refundId, an optional positive safe integer amountMicro, and an optional reason of at most 280 characters." }, 400);
|
|
17256
|
+
}
|
|
17257
|
+
if (!opts.ledger.durable || !opts.enqueueCreditDrawRefund) {
|
|
17258
|
+
return c.json({ error: "credit_refund_unavailable", hint: "Configure the persistent credit store and platform refund reporter, then retry with the original refund ID." }, 503);
|
|
17259
|
+
}
|
|
17260
|
+
try {
|
|
17261
|
+
const result = await opts.ledger.refundDraw({
|
|
17262
|
+
...byJob ? { jobId: value.jobId } : { creditId: value.creditId, drawId: value.drawId },
|
|
17263
|
+
refundId: value.refundId,
|
|
17264
|
+
...value.amountMicro === void 0 ? {} : { amountMicro: value.amountMicro },
|
|
17265
|
+
...value.reason === void 0 ? {} : { reason: value.reason },
|
|
17266
|
+
outbox: { dvmId: opts.dvmId, enqueue: opts.enqueueCreditDrawRefund },
|
|
17267
|
+
...opts.receiptIssuer ? { trustedReceiptPubkey: opts.receiptIssuer.pubkey } : {},
|
|
17268
|
+
...opts.now ? { nowMs: opts.now() } : {}
|
|
17269
|
+
});
|
|
17270
|
+
return c.json({
|
|
17271
|
+
status: "refunded",
|
|
17272
|
+
refund_id: result.refundId,
|
|
17273
|
+
credit_id: result.creditId,
|
|
17274
|
+
draw_id: result.drawId,
|
|
17275
|
+
job_id: result.jobId,
|
|
17276
|
+
amount_micro: result.amountMicro,
|
|
17277
|
+
currency: result.currency,
|
|
17278
|
+
ledger_seq: result.ledgerSeq,
|
|
17279
|
+
refunded_at: result.refundedAt,
|
|
17280
|
+
balance_after_micro: result.balanceAfterMicro,
|
|
17281
|
+
replayed: result.replayed
|
|
17282
|
+
});
|
|
17283
|
+
} catch (error) {
|
|
17284
|
+
if (!(error instanceof CreditLedgerError)) throw error;
|
|
17285
|
+
const hints = {
|
|
17286
|
+
draw_not_found: "Check the job ID or credit/draw IDs. If they are correct, this DVM may lack trusted ownership evidence; ask an operator to inspect that evidence. Retrying alone cannot establish ownership.",
|
|
17287
|
+
draw_not_completed: "Wait for the job to complete. Failed or cancelled jobs release their pending hold automatically.",
|
|
17288
|
+
refund_exceeds_draw: "Refund no more than the remaining unrefunded charge. Omit amountMicro to refund that remainder.",
|
|
17289
|
+
credit_not_open: "The original credit is closed or expired. Ask an operator to inspect the original payment before arranging a refund.",
|
|
17290
|
+
credit_refund_channel_unsupported: "This channel returns unused collateral through its normal exit. Ask an operator about refunding completed spending.",
|
|
17291
|
+
credit_refund_basis_unavailable: "The original payment value cannot be proven automatically. Ask an operator to inspect independent original-payment evidence before arranging a repair. Retrying alone cannot establish that evidence.",
|
|
17292
|
+
credit_refund_state_unavailable: "The original credit reopening order cannot be proven automatically. Ask an operator to inspect independent funding and drain evidence before arranging a repair. Retrying alone cannot establish that evidence.",
|
|
17293
|
+
refund_conflict: "Repeat the original arguments, or deliberately choose a new refund ID for a different refund."
|
|
17294
|
+
};
|
|
17295
|
+
const hint = hints[error.code];
|
|
17296
|
+
if (!hint) throw error;
|
|
17297
|
+
return c.json({ error: error.code, hint }, error.code === "draw_not_found" ? 404 : error.code === "refund_conflict" ? 409 : 422);
|
|
17298
|
+
}
|
|
17299
|
+
}
|
|
17162
17300
|
async function handleX402ExactSettlements(c, opts) {
|
|
17163
17301
|
const auth = await requireAuth(c, opts);
|
|
17164
17302
|
if ("response" in auth) return auth.response;
|
|
@@ -17277,6 +17415,9 @@ async function handleTempoLosses(c, opts) {
|
|
|
17277
17415
|
currency: loss.currency,
|
|
17278
17416
|
former_balance_micro: loss.formerBalanceMicro,
|
|
17279
17417
|
settled_on_chain_native: loss.settledOnChainNative.toString(),
|
|
17418
|
+
refunded_to_payer_native: loss.refundedToPayerNative?.toString() ?? null,
|
|
17419
|
+
loss_native: loss.lossNative?.toString() ?? null,
|
|
17420
|
+
loss_basis: loss.lossBasis ?? null,
|
|
17280
17421
|
highest_voucher_native: loss.highestVoucherNative.toString(),
|
|
17281
17422
|
consumed_service_micro: loss.consumedServiceMicro,
|
|
17282
17423
|
consumed_native: loss.consumedNative.toString(),
|
|
@@ -18263,13 +18404,18 @@ async function handleTempoDrains(c, opts) {
|
|
|
18263
18404
|
...after ? { after } : {},
|
|
18264
18405
|
createdBeforeMs: nowMs - minAge,
|
|
18265
18406
|
rail: "tempo",
|
|
18266
|
-
includeResolved: c.req.query("include_resolved") === "true"
|
|
18407
|
+
includeResolved: c.req.query("include_resolved") === "true",
|
|
18408
|
+
includeWrittenOff: true
|
|
18267
18409
|
});
|
|
18268
18410
|
const wantsEvidence = c.req.query("evidence") !== "false";
|
|
18269
18411
|
const rows2 = [];
|
|
18270
18412
|
for (const drain of drains) {
|
|
18271
18413
|
const evidence = wantsEvidence && drain.channelId ? await classifyTempoCloseEvidence(rail.rail, drain.channelId) : void 0;
|
|
18272
|
-
|
|
18414
|
+
const closeReports = drain.channelId && opts.hostedSettlementReports ? await opts.hostedSettlementReports.store.listTempoCloseReports({ limit: 50, all: true, channelId: drain.channelId }) : [];
|
|
18415
|
+
rows2.push({
|
|
18416
|
+
...tempoDrainBody(drain, evidence),
|
|
18417
|
+
close_reports: closeReports.map((row) => ({ obligation_id: row.id, status: row.status, written_off: row.writtenOff }))
|
|
18418
|
+
});
|
|
18273
18419
|
}
|
|
18274
18420
|
const last = drains.length === limit ? drains[drains.length - 1] : void 0;
|
|
18275
18421
|
return c.json({
|
|
@@ -18283,6 +18429,90 @@ async function handleTempoDrains(c, opts) {
|
|
|
18283
18429
|
} : {}
|
|
18284
18430
|
});
|
|
18285
18431
|
}
|
|
18432
|
+
async function handleTempoDrainDecision(c, opts, decision) {
|
|
18433
|
+
const auth = await requireAuth(c, opts);
|
|
18434
|
+
if ("response" in auth) return auth.response;
|
|
18435
|
+
const body = await c.req.json().catch(() => null);
|
|
18436
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
18437
|
+
return c.json({ error: "invalid_body", message: "Request body must be a JSON object." }, 400);
|
|
18438
|
+
}
|
|
18439
|
+
const value = body;
|
|
18440
|
+
const text = (item, max) => typeof item === "string" && item.trim().length > 0 && item.trim().length <= max;
|
|
18441
|
+
if (Object.keys(value).some((key) => !["credit_id", "drain_id", "reason", "evidence"].includes(key)) || typeof value.credit_id !== "string" || value.credit_id.length === 0 || typeof value.drain_id !== "string" || value.drain_id.length === 0 || !text(value.reason, 2e3) || value.evidence !== void 0 && !text(value.evidence, 4e3)) {
|
|
18442
|
+
return c.json({ error: "invalid_body", message: "Provide credit_id, drain_id, a reason of 1\u20132000 characters, and optional evidence of 1\u20134000 characters." }, 400);
|
|
18443
|
+
}
|
|
18444
|
+
if (!opts.ledger.durable || !opts.ledger.decideTempoDrain) {
|
|
18445
|
+
return c.json({ error: "tempo_drain_decision_unavailable", message: "A durable Tempo decision store is required." }, 503);
|
|
18446
|
+
}
|
|
18447
|
+
const args = {
|
|
18448
|
+
creditId: value.credit_id,
|
|
18449
|
+
drainId: value.drain_id,
|
|
18450
|
+
decision,
|
|
18451
|
+
reason: value.reason.trim(),
|
|
18452
|
+
...value.evidence === void 0 ? {} : { evidence: value.evidence.trim() },
|
|
18453
|
+
nowMs: opts.now ? opts.now() : Date.now()
|
|
18454
|
+
};
|
|
18455
|
+
if (decision === "book_refunded" && opts.requireDrainReport && !opts.enqueueCreditDrain) {
|
|
18456
|
+
const existing = await opts.ledger.getDrain(args);
|
|
18457
|
+
if (existing && !existing.operatorDecision && (existing.status === "pending" || existing.status === "exit_required")) {
|
|
18458
|
+
return c.json({ error: "tempo_drain_decision_unavailable", message: "Hosted booking requires a transactional drain reporter. Restore its configuration, then retry the original decision." }, 503);
|
|
18459
|
+
}
|
|
18460
|
+
}
|
|
18461
|
+
const client = await opts.db.connect();
|
|
18462
|
+
let result;
|
|
18463
|
+
try {
|
|
18464
|
+
await client.query("BEGIN");
|
|
18465
|
+
let decided;
|
|
18466
|
+
const transition = async () => {
|
|
18467
|
+
decided = await opts.ledger.decideTempoDrain({ ...args, tx: client });
|
|
18468
|
+
return decided;
|
|
18469
|
+
};
|
|
18470
|
+
if (decision === "book_refunded") {
|
|
18471
|
+
await commitTerminalDrain({ db: opts.db, dvmId: opts.dvmId, enqueueCreditDrain: opts.enqueueCreditDrain }, transition, client);
|
|
18472
|
+
} else {
|
|
18473
|
+
await transition();
|
|
18474
|
+
}
|
|
18475
|
+
result = decided;
|
|
18476
|
+
await client.query("COMMIT");
|
|
18477
|
+
} catch (error) {
|
|
18478
|
+
await client.query("ROLLBACK").catch(() => void 0);
|
|
18479
|
+
if (error instanceof CreditLedgerError) {
|
|
18480
|
+
return c.json(
|
|
18481
|
+
{ error: error.code, message: error.message },
|
|
18482
|
+
error.code === "drain_not_found" || error.code === "credit_not_found" ? 404 : ["drain_decision_conflict", "tempo_drain_close_pending", "tempo_drain_refund_paid", "tempo_drain_refund_unknown"].includes(error.code) ? 409 : 422
|
|
18483
|
+
);
|
|
18484
|
+
}
|
|
18485
|
+
throw error;
|
|
18486
|
+
} finally {
|
|
18487
|
+
client.release();
|
|
18488
|
+
}
|
|
18489
|
+
if (!result.replayed) {
|
|
18490
|
+
diagnosticConsole.warn({
|
|
18491
|
+
dataset: "tempo",
|
|
18492
|
+
event: decision === "book_refunded" ? "tempo_drain_booked_as_refunded" : "tempo_drain_released",
|
|
18493
|
+
credit_id: result.drain.creditId,
|
|
18494
|
+
drain_id: result.drain.drainId,
|
|
18495
|
+
channel_id: result.drain.channelId,
|
|
18496
|
+
drain_reference: `sha256:${bytesToHex(sha256(new TextEncoder().encode(JSON.stringify([result.drain.creditId, result.drain.drainId]))))}`,
|
|
18497
|
+
amount_micro: result.drain.amountMicro,
|
|
18498
|
+
amount_native: result.drain.drainedNative?.toString() ?? null,
|
|
18499
|
+
currency: result.drain.currency
|
|
18500
|
+
});
|
|
18501
|
+
}
|
|
18502
|
+
return c.json({
|
|
18503
|
+
status: result.drain.status,
|
|
18504
|
+
credit_id: result.drain.creditId,
|
|
18505
|
+
drain_id: result.drain.drainId,
|
|
18506
|
+
channel_id: result.drain.channelId,
|
|
18507
|
+
amount_micro: result.drain.amountMicro,
|
|
18508
|
+
amount_native: result.drain.drainedNative,
|
|
18509
|
+
currency: result.drain.currency,
|
|
18510
|
+
decision: result.drain.operatorDecision,
|
|
18511
|
+
balance_micro: result.credit.balanceMicro,
|
|
18512
|
+
spendable_micro: result.spendableMicro,
|
|
18513
|
+
replayed: result.replayed
|
|
18514
|
+
});
|
|
18515
|
+
}
|
|
18286
18516
|
async function handleReconcileTempo(c, opts) {
|
|
18287
18517
|
const auth = await requireAuth(c, opts);
|
|
18288
18518
|
if ("response" in auth) return auth.response;
|
|
@@ -18296,6 +18526,12 @@ async function handleReconcileTempo(c, opts) {
|
|
|
18296
18526
|
if (record.status === "sent") return tempoReconciledBody(c, record, channelId, true);
|
|
18297
18527
|
const evidence = await classifyTempoCloseEvidence(rail.rail, channelId);
|
|
18298
18528
|
if (evidence.chain !== "found") return tempoEvidenceRefusal(c, evidence);
|
|
18529
|
+
try {
|
|
18530
|
+
await opts.ledger.recordTempoDrainRefund?.({ creditId: record.creditId, drainId: record.drainId, refundedNative: evidence.refundedToPayer });
|
|
18531
|
+
} catch (error) {
|
|
18532
|
+
diagnosticConsole.warn({ dataset: "tempo", event: "tempo_drain_refund_evidence_write_failed", amount_micro: record.amountMicro });
|
|
18533
|
+
throw error;
|
|
18534
|
+
}
|
|
18299
18535
|
const client = await opts.db.connect();
|
|
18300
18536
|
let booked;
|
|
18301
18537
|
try {
|
|
@@ -18784,6 +19020,10 @@ function tempoDrainBody(drain, evidence) {
|
|
|
18784
19020
|
created_at: drain.createdAt,
|
|
18785
19021
|
write_off_note: drain.writeOffNote,
|
|
18786
19022
|
written_off_at: drain.writtenOffAt,
|
|
19023
|
+
decision: drain.operatorDecision ?? null,
|
|
19024
|
+
proven_refund_native: drain.provenRefundNative ?? null,
|
|
19025
|
+
refund_payment_proven: drain.refundPaymentProven ?? false,
|
|
19026
|
+
held_reason: drain.status === "pending" || drain.status === "exit_required" ? drain.holdReason ?? (evidence?.chain === "found" && drain.drainedNative !== null && BigInt(evidence.refundedToPayer) < BigInt(drain.drainedNative) ? "refund_short" : drain.status === "exit_required" ? "exit_required" : "refund_unproven") : null,
|
|
18787
19027
|
...evidence ? { chain: evidence } : {}
|
|
18788
19028
|
};
|
|
18789
19029
|
}
|
|
@@ -20129,7 +20369,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
20129
20369
|
}
|
|
20130
20370
|
}
|
|
20131
20371
|
if (!opts.onJobCompleted && platformToken && platformUrl && dvmId && opts.db) {
|
|
20132
|
-
const { RevenueReporter } = await import("./revenue-reporter-
|
|
20372
|
+
const { RevenueReporter } = await import("./revenue-reporter-HD4GMXGD.js");
|
|
20133
20373
|
const reporter = new RevenueReporter(
|
|
20134
20374
|
opts.db,
|
|
20135
20375
|
platformUrl,
|
|
@@ -20139,7 +20379,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
20139
20379
|
revenueReporter = reporter;
|
|
20140
20380
|
await reporter.init();
|
|
20141
20381
|
reporter.startRetryLoop();
|
|
20142
|
-
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-
|
|
20382
|
+
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-NXWQVKXW.js");
|
|
20143
20383
|
payoutReporter = new PayoutReporter({
|
|
20144
20384
|
dvmId,
|
|
20145
20385
|
db: opts.db,
|
|
@@ -20167,6 +20407,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
20167
20407
|
const effectiveOnRevenueSkippedNoRail = opts.onRevenueSkippedNoRail ?? (activeRevenueReporter ? (info) => activeRevenueReporter.reportRevenueSkippedNoRail(info) : void 0);
|
|
20168
20408
|
const enqueueCreditDeposit = !opts.onCreditFunded && activeRevenueReporter ? activeRevenueReporter.enqueueDeposit.bind(activeRevenueReporter) : void 0;
|
|
20169
20409
|
const enqueueCreditDrain = activeRevenueReporter ? activeRevenueReporter.enqueueCreditDrain.bind(activeRevenueReporter) : void 0;
|
|
20410
|
+
const enqueueCreditDrawRefund = activeRevenueReporter ? activeRevenueReporter.enqueueCreditDrawRefund.bind(activeRevenueReporter) : void 0;
|
|
20170
20411
|
const enqueueCreditDrawRelease = activeRevenueReporter ? activeRevenueReporter.enqueueCreditDrawRelease.bind(activeRevenueReporter) : void 0;
|
|
20171
20412
|
unsubscribeTempoSettlementReadiness = opts.tempoSettlementReadiness?.subscribe({
|
|
20172
20413
|
onBalance: (observation) => activeRevenueReporter && dvmId ? activeRevenueReporter.reportTempoSettlementBalance({
|
|
@@ -20322,6 +20563,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
20322
20563
|
} : void 0;
|
|
20323
20564
|
server = new DVMServer(descriptor, {
|
|
20324
20565
|
...opts,
|
|
20566
|
+
platformUrl,
|
|
20325
20567
|
hostingControlInstance: hostingControl,
|
|
20326
20568
|
hostedSettlementReports,
|
|
20327
20569
|
hostingClosureSupport,
|
|
@@ -20336,6 +20578,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
20336
20578
|
enqueueCreditDeposit,
|
|
20337
20579
|
enqueueCreditDrain,
|
|
20338
20580
|
enqueueCreditDrawRelease,
|
|
20581
|
+
enqueueCreditDrawRefund,
|
|
20339
20582
|
x402BatchSettlement,
|
|
20340
20583
|
x402BatchSettlementFactory,
|
|
20341
20584
|
x402ExactSettlement,
|
|
@@ -20791,8 +21034,10 @@ var DVMServer = class {
|
|
|
20791
21034
|
receiptIssuer: this.receiptIssuer,
|
|
20792
21035
|
creditTtlMs: () => this.creditTtlMs(),
|
|
20793
21036
|
creditCurrency: () => this.creditCurrency(),
|
|
21037
|
+
enqueueCreditDrawRefund: this.opts.enqueueCreditDrawRefund,
|
|
20794
21038
|
enqueueCreditDeposit: this.opts.enqueueCreditDeposit,
|
|
20795
21039
|
enqueueCreditDrain: this.opts.enqueueCreditDrain,
|
|
21040
|
+
requireDrainReport: !!this.opts.platformUrl,
|
|
20796
21041
|
lightningReceive: this.opts.lightningReceive,
|
|
20797
21042
|
// x402 repair queue rides the same surface, and resolves
|
|
20798
21043
|
// the rail the same lazy way the verify path does — constructing the
|
|
@@ -22927,8 +23172,14 @@ var DVMServer = class {
|
|
|
22927
23172
|
await jm.markInboundVerified(activeJob.id, inboundSeq2);
|
|
22928
23173
|
}
|
|
22929
23174
|
jm.startIdleTimer(activeJob);
|
|
22930
|
-
|
|
22931
|
-
|
|
23175
|
+
try {
|
|
23176
|
+
await jm.dispatchMessage(activeJob, body2.type, body2.content);
|
|
23177
|
+
await this.persistMessageSnapshot(jm, activeJob, body2.type);
|
|
23178
|
+
} catch (error) {
|
|
23179
|
+
const response = this.postPaymentSnapshotFailure(c, error, activeJob, body2.type, inboundSeq2, unappliedCredit2);
|
|
23180
|
+
if (response) return response;
|
|
23181
|
+
throw error;
|
|
23182
|
+
}
|
|
22932
23183
|
const lastMsg2 = activeJob.messages[activeJob.messages.length - 1];
|
|
22933
23184
|
return c.json({ seq: lastMsg2.seq, ...unappliedCredit2 && { credit: unappliedCredit2 } }, 201);
|
|
22934
23185
|
}
|
|
@@ -23011,20 +23262,48 @@ var DVMServer = class {
|
|
|
23011
23262
|
return c.json({ seq: lastMsg2.seq, ...creditBlock }, 201);
|
|
23012
23263
|
}
|
|
23013
23264
|
jm.startIdleTimer(job);
|
|
23014
|
-
|
|
23015
|
-
|
|
23016
|
-
|
|
23265
|
+
try {
|
|
23266
|
+
if (isStreamableJobStore(jm.store)) {
|
|
23267
|
+
const store = jm.store;
|
|
23268
|
+
const lockResult = await store.tryReactivationLock(job.id, async () => {
|
|
23269
|
+
await this.runReactivation(jm, job, body, record.status);
|
|
23270
|
+
});
|
|
23271
|
+
if (!lockResult.acquired) {
|
|
23272
|
+
this.teardownReactivationScaffold(jm, job);
|
|
23273
|
+
}
|
|
23274
|
+
} else {
|
|
23017
23275
|
await this.runReactivation(jm, job, body, record.status);
|
|
23018
|
-
});
|
|
23019
|
-
if (!lockResult.acquired) {
|
|
23020
|
-
this.teardownReactivationScaffold(jm, job);
|
|
23021
23276
|
}
|
|
23022
|
-
}
|
|
23023
|
-
|
|
23277
|
+
} catch (error) {
|
|
23278
|
+
const response = this.postPaymentSnapshotFailure(c, error, job, body.type, inboundSeq, unappliedCredit);
|
|
23279
|
+
if (response) return response;
|
|
23280
|
+
throw error;
|
|
23024
23281
|
}
|
|
23025
23282
|
const lastMsg = job.messages[job.messages.length - 1];
|
|
23026
23283
|
return c.json({ seq: lastMsg.seq, ...creditBlock }, 201);
|
|
23027
23284
|
}
|
|
23285
|
+
async persistMessageSnapshot(jm, job, type) {
|
|
23286
|
+
if (type === "payment") {
|
|
23287
|
+
await retryJobSnapshot(() => jm.persistJob(job));
|
|
23288
|
+
} else {
|
|
23289
|
+
await jm.persistJob(job);
|
|
23290
|
+
}
|
|
23291
|
+
}
|
|
23292
|
+
postPaymentSnapshotFailure(c, error, job, type, inboundSeq, unappliedCredit) {
|
|
23293
|
+
if (!(error instanceof JobSnapshotPersistenceError) || type !== "payment" || inboundSeq === null || !isStreamableJobStore(this.jobManager.store)) return void 0;
|
|
23294
|
+
diagnosticConsole.error({ level: "job_snapshot_unavailable", job_id: job.id, seq: inboundSeq });
|
|
23295
|
+
return c.json({
|
|
23296
|
+
error: "job_snapshot_unavailable",
|
|
23297
|
+
message: "Payment was recorded but the job snapshot could not be persisted.",
|
|
23298
|
+
display: "Your payment was recorded. The service could not save the latest job progress.",
|
|
23299
|
+
hint: "Do not send another payment. Read the job status and messages; if the worker stopped, resume with a non-payment message.",
|
|
23300
|
+
retryable: false,
|
|
23301
|
+
payment_status: "recorded",
|
|
23302
|
+
job_id: job.id,
|
|
23303
|
+
seq: inboundSeq,
|
|
23304
|
+
...unappliedCredit && { credit: unappliedCredit }
|
|
23305
|
+
}, 503);
|
|
23306
|
+
}
|
|
23028
23307
|
/**
|
|
23029
23308
|
* Run the handler or dispatch the inbound after Tx B + Tx C have already
|
|
23030
23309
|
* committed the credit. Status decides the behaviour: `awaiting-input`
|
|
@@ -23050,7 +23329,7 @@ var DVMServer = class {
|
|
|
23050
23329
|
});
|
|
23051
23330
|
} else {
|
|
23052
23331
|
await jm.dispatchMessage(job, body.type, body.content);
|
|
23053
|
-
await
|
|
23332
|
+
await this.persistMessageSnapshot(jm, job, body.type);
|
|
23054
23333
|
}
|
|
23055
23334
|
}
|
|
23056
23335
|
/**
|