@dvmkit/sdk 0.1.5-rc.9 → 0.2.1-rc.9
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 +14 -0
- package/dist/{chunk-MLRCSJYX.js → chunk-2D75MNNG.js} +178 -550
- package/dist/{chunk-BIFLRKMO.js → chunk-2KGG5ORW.js} +1 -1
- package/dist/{chunk-27V2ILSR.js → chunk-4A2RAKCW.js} +2 -2
- package/dist/{chunk-5URG56JJ.js → chunk-A4CM2BD3.js} +18 -2
- package/dist/{chunk-L4OYF4DQ.js → chunk-AJNFXR7J.js} +2 -2
- package/dist/{chunk-S3XAHZQY.js → chunk-COYKJRMM.js} +24 -3
- package/dist/{chunk-UP2F5RRT.js → chunk-D7YQYLLM.js} +1 -4
- package/dist/{chunk-CEOAHV2I.js → chunk-FDKRXOZO.js} +0 -5
- package/dist/{chunk-TQWGQCNV.js → chunk-FPOLJRBF.js} +5 -5
- package/dist/{chunk-BTZY7VPH.js → chunk-GAIPXGM3.js} +1 -1
- package/dist/{chunk-SSSZUVWM.js → chunk-JAHRF5X3.js} +89 -39
- package/dist/{chunk-5PBOA25N.js → chunk-JNKQZVZX.js} +472 -617
- package/dist/{chunk-U6M3ATSG.js → chunk-MD3H3BF7.js} +40 -6
- package/dist/{chunk-CGKZDODG.js → chunk-MG67KXU7.js} +0 -5
- package/dist/{chunk-KSQEFVFJ.js → chunk-MMCE7XSR.js} +1 -1
- package/dist/{chunk-JZWELPFH.js → chunk-N5B66UOS.js} +4 -16
- package/dist/{chunk-BIP6G74V.js → chunk-O6D72KYA.js} +10 -10
- package/dist/{chunk-KXCKFIJI.js → chunk-QX52F6IB.js} +1 -1
- package/dist/{chunk-RW5LP57K.js → chunk-SDK6KDJN.js} +0 -1
- package/dist/{chunk-KVEHHC7W.js → chunk-U5VNEALI.js} +24 -13
- package/dist/{chunk-FROTD5XQ.js → chunk-V5ZRATJH.js} +2 -3
- package/dist/{chunk-EVBK675R.js → chunk-VA7GT6C6.js} +31 -37
- package/dist/{chunk-2UUXIIOC.js → chunk-VIVXB4CD.js} +3 -3
- package/dist/{chunk-6BQM7TOW.js → chunk-XMDQOXHO.js} +11 -38
- package/dist/{chunk-DMNLFNTW.js → chunk-XRLKGCAW.js} +2 -2
- package/dist/{chunk-M7LHFJ5K.js → chunk-XZ7LW4S5.js} +2 -3
- package/dist/{chunk-E4EVGPDX.js → chunk-YO56VCTQ.js} +0 -6
- package/dist/{credit-ledger-2DFQHNLB.js → credit-ledger-MHA652TV.js} +2 -2
- package/dist/{credit-menu-enwMbn55.d.ts → credit-menu-kDA9RVzD.d.ts} +524 -1077
- package/dist/{fx-D860pZvP.d.ts → fx-DhyT1Cjh.d.ts} +38 -82
- package/dist/index.d.ts +11 -26
- package/dist/index.js +2 -2
- package/dist/internal/caller.d.ts +644 -2140
- package/dist/internal/caller.js +32 -66
- package/dist/internal/server.d.ts +40 -90
- package/dist/internal/server.js +16 -16
- package/dist/{job-store-BUGqvCfL.d.ts → job-store-D3CcZp_g.d.ts} +73 -66
- package/dist/{lightning-backend-BozcevPZ.d.ts → lightning-backend-BhsyrBLa.d.ts} +19 -41
- package/dist/{memory-credit-ledger-MNUOTQO5.js → memory-credit-ledger-BYBATRN3.js} +3 -3
- package/dist/{mpp-secret-state-WNAQQ6K4.js → mpp-secret-state-B5GCILVH.js} +1 -1
- package/dist/{mpp-setup-4FJD6ZHV.js → mpp-setup-MPP3ST5X.js} +1 -1
- package/dist/{payout-reporter-RG6XNGPI.js → payout-reporter-KEMUXEUO.js} +2 -2
- package/dist/{postgres-consumed-credential-store-VHBT4KEA.js → postgres-consumed-credential-store-6N2V5MJN.js} +2 -2
- package/dist/postgres-job-store-MZZZMS2B.js +7 -0
- package/dist/postgres-kv-store-DXGTKXLU.js +7 -0
- package/dist/{postgres-replay-store-UJXRT6VO.js → postgres-replay-store-ZF4JNZOW.js} +2 -2
- package/dist/{pricing-4CEB34RM.js → pricing-MU5GNUJZ.js} +1 -1
- package/dist/{processed-payment-store-HAA4SFNK.js → processed-payment-store-GKMAWOM3.js} +2 -2
- package/dist/revenue-reporter-O75BGYFK.js +7 -0
- package/dist/server/index.d.ts +47 -159
- package/dist/server/index.js +67 -138
- package/dist/{ssrf-DbFkpDv0.d.ts → ssrf-dMooihtY.d.ts} +1 -2
- package/dist/{step-cache-5dljDqrQ.d.ts → step-cache-v2yhyhSZ.d.ts} +617 -1532
- package/dist/{tempo-charge-store-RIFTALZK.js → tempo-charge-store-SDTUNTKA.js} +2 -2
- package/dist/{tempo-lifecycle-DFIXQ54Q.js → tempo-lifecycle-G5SB4HFC.js} +5 -5
- package/dist/{tempo-session-store-2JNOKJGX.js → tempo-session-store-WF3VZXNF.js} +2 -2
- package/dist/{tempo-wallet-4QKSV65O.js → tempo-wallet-ZFNUDFVO.js} +2 -2
- package/dist/testing/index.d.ts +5 -15
- package/dist/testing/index.js +4 -11
- package/dist/{usd-DoRuAckA.d.ts → usd-Cu9G6xv2.d.ts} +14 -16
- package/dist/{wallet-CJC8lwxx.d.ts → wallet-Dwjs5n_M.d.ts} +1 -1
- package/dist/{x402-5H27DCBE.js → x402-CI6PSHNO.js} +5 -5
- package/package.json +3 -2
- package/dist/postgres-job-store-3RAXMNSY.js +0 -7
- package/dist/postgres-kv-store-JFBDP5IP.js +0 -7
- package/dist/revenue-reporter-ASZ7SHHH.js +0 -7
package/dist/server/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PostgresReplayStore
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-AJNFXR7J.js";
|
|
4
4
|
import {
|
|
5
5
|
PostgresJobStore
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-JAHRF5X3.js";
|
|
7
7
|
import {
|
|
8
8
|
PostgresKVStore
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-V5ZRATJH.js";
|
|
10
10
|
import {
|
|
11
11
|
SSRFError,
|
|
12
12
|
assertSafeUrl,
|
|
@@ -21,10 +21,10 @@ import {
|
|
|
21
21
|
parseNwcUri,
|
|
22
22
|
validateX402Env,
|
|
23
23
|
withNwcPool
|
|
24
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-FDKRXOZO.js";
|
|
25
25
|
import {
|
|
26
26
|
MemoryKVStore
|
|
27
|
-
} from "../chunk-
|
|
27
|
+
} from "../chunk-SDK6KDJN.js";
|
|
28
28
|
import {
|
|
29
29
|
AccumulatorReplayError,
|
|
30
30
|
CLIENT_COMPATIBILITY_HEADERS,
|
|
@@ -78,16 +78,16 @@ import {
|
|
|
78
78
|
stripProtocolEnvelope,
|
|
79
79
|
toCreditView,
|
|
80
80
|
unknownRouteNotFound
|
|
81
|
-
} from "../chunk-
|
|
81
|
+
} from "../chunk-JNKQZVZX.js";
|
|
82
82
|
import {
|
|
83
83
|
MemoryProcessedPaymentStore,
|
|
84
84
|
PostgresProcessedPaymentStore,
|
|
85
85
|
ProcessedPaymentReplayError
|
|
86
|
-
} from "../chunk-
|
|
86
|
+
} from "../chunk-XRLKGCAW.js";
|
|
87
87
|
import "../chunk-BQ2NMWKE.js";
|
|
88
88
|
import {
|
|
89
89
|
MemoryCreditLedger
|
|
90
|
-
} from "../chunk-
|
|
90
|
+
} from "../chunk-U5VNEALI.js";
|
|
91
91
|
import {
|
|
92
92
|
SignedRequestError,
|
|
93
93
|
createDefaultReplayStore,
|
|
@@ -96,12 +96,12 @@ import {
|
|
|
96
96
|
} from "../chunk-H2MEFVH6.js";
|
|
97
97
|
import {
|
|
98
98
|
isStreamableJobStore
|
|
99
|
-
} from "../chunk-
|
|
99
|
+
} from "../chunk-MD3H3BF7.js";
|
|
100
100
|
import {
|
|
101
101
|
generateEphemeralReceiptKey,
|
|
102
102
|
isTestMintUrl,
|
|
103
103
|
receiptPubkeyFromSecret
|
|
104
|
-
} from "../chunk-
|
|
104
|
+
} from "../chunk-QX52F6IB.js";
|
|
105
105
|
import {
|
|
106
106
|
X402_DEFAULT_FACILITATOR,
|
|
107
107
|
X402_DEFAULT_NETWORK,
|
|
@@ -110,7 +110,7 @@ import {
|
|
|
110
110
|
} from "../chunk-Z4BNLUZF.js";
|
|
111
111
|
import {
|
|
112
112
|
IMPLICIT_CREDIT_TTL_MS
|
|
113
|
-
} from "../chunk-
|
|
113
|
+
} from "../chunk-A4CM2BD3.js";
|
|
114
114
|
import {
|
|
115
115
|
resolveRpcOverride
|
|
116
116
|
} from "../chunk-MKI6OVW4.js";
|
|
@@ -121,10 +121,10 @@ import {
|
|
|
121
121
|
} from "../chunk-KXZUCCEY.js";
|
|
122
122
|
import {
|
|
123
123
|
initLoggers
|
|
124
|
-
} from "../chunk-
|
|
124
|
+
} from "../chunk-YO56VCTQ.js";
|
|
125
125
|
import "../chunk-66HGCPBU.js";
|
|
126
126
|
import "../chunk-FUJ36YDV.js";
|
|
127
|
-
import "../chunk-
|
|
127
|
+
import "../chunk-4A2RAKCW.js";
|
|
128
128
|
import "../chunk-AT6V3SY7.js";
|
|
129
129
|
import {
|
|
130
130
|
CreditLedger,
|
|
@@ -133,11 +133,11 @@ import {
|
|
|
133
133
|
PostgresX402ChannelStorage,
|
|
134
134
|
X402RelaySubmissionLockError,
|
|
135
135
|
allocateDrawValue
|
|
136
|
-
} from "../chunk-
|
|
136
|
+
} from "../chunk-2D75MNNG.js";
|
|
137
137
|
import {
|
|
138
138
|
SDK_INIT_ADVISORY_LOCK,
|
|
139
139
|
withSdkInitLock
|
|
140
|
-
} from "../chunk-
|
|
140
|
+
} from "../chunk-COYKJRMM.js";
|
|
141
141
|
import {
|
|
142
142
|
applyRetryToPool
|
|
143
143
|
} from "../chunk-C3MTFLC6.js";
|
|
@@ -147,7 +147,7 @@ import {
|
|
|
147
147
|
TEMPO_SETTLEMENT_DEFAULT_LOW_BALANCE_MICRO,
|
|
148
148
|
TempoSettlementReadiness,
|
|
149
149
|
resolveTempoNetwork
|
|
150
|
-
} from "../chunk-
|
|
150
|
+
} from "../chunk-XZ7LW4S5.js";
|
|
151
151
|
|
|
152
152
|
// src/sdk/server/cashu-env.ts
|
|
153
153
|
async function resolveCashuOptsFromEnv(env, pool, cashuModeHint) {
|
|
@@ -221,6 +221,7 @@ async function resolveCashuOptsFromEnv(env, pool, cashuModeHint) {
|
|
|
221
221
|
error: err instanceof Error ? err.message : String(err)
|
|
222
222
|
})
|
|
223
223
|
);
|
|
224
|
+
if (cashuMode === "p2pk-accumulator") throw err;
|
|
224
225
|
db = void 0;
|
|
225
226
|
}
|
|
226
227
|
}
|
|
@@ -320,7 +321,6 @@ var PlatformLightningRailHealth = class {
|
|
|
320
321
|
lastAttemptAtMs;
|
|
321
322
|
inFlight;
|
|
322
323
|
ceilingLoggedForMs;
|
|
323
|
-
/** Prime the signal during boot without making a menu request wait for it. */
|
|
324
324
|
async refresh() {
|
|
325
325
|
if (this.inFlight) return this.inFlight;
|
|
326
326
|
this.lastAttemptAtMs = this.now();
|
|
@@ -332,7 +332,6 @@ var PlatformLightningRailHealth = class {
|
|
|
332
332
|
this.inFlight = void 0;
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
|
-
/** Answer from cache and begin a non-blocking refresh once it is due. */
|
|
336
335
|
available() {
|
|
337
336
|
const nowMs = this.now();
|
|
338
337
|
if (this.lastAttemptAtMs === void 0 || nowMs - this.lastAttemptAtMs >= this.refreshTtlMs) {
|
|
@@ -463,16 +462,10 @@ var LightningReceive = class _LightningReceive {
|
|
|
463
462
|
permissionRefusal;
|
|
464
463
|
railHealth;
|
|
465
464
|
/**
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
* unreachable.** A wallet outage at boot must not stop a DVM whose other
|
|
471
|
-
* rails are fine — the menu simply omits `lightning` until a later probe
|
|
472
|
-
* succeeds. A connection that can spend, or one that can't state what it can
|
|
473
|
-
* do, is a different thing entirely: it is a standing money risk that no
|
|
474
|
-
* amount of retrying fixes, so it fails the boot loudly with the fix in the
|
|
475
|
-
* message.
|
|
465
|
+
* Return undefined when unconfigured. Permission/URI failures refuse construction with a
|
|
466
|
+
* corrective message; wallet transport failure constructs an unavailable receive leg so
|
|
467
|
+
* other rails can still boot. Recovery must validate method scope before advertising
|
|
468
|
+
* Lightning.
|
|
476
469
|
*/
|
|
477
470
|
static async create(config) {
|
|
478
471
|
const invoiceTtlSeconds = resolveInvoiceTtl(config.invoiceTtlSeconds);
|
|
@@ -528,26 +521,17 @@ var LightningReceive = class _LightningReceive {
|
|
|
528
521
|
);
|
|
529
522
|
}
|
|
530
523
|
/**
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
* Reads the cached observation and never blocks; a stale one kicks off a
|
|
534
|
-
* background refresh and answers with what we last knew. Advertising a rail
|
|
535
|
-
* whose wallet is down would hand the caller an option that 402s on use —
|
|
536
|
-
* the §4 posture is to drop it and let the sale survive on the others.
|
|
524
|
+
* Answer from cached wallet and optional rail-health observations without blocking. A stale
|
|
525
|
+
* wallet observation starts a background refresh.
|
|
537
526
|
*/
|
|
538
527
|
available() {
|
|
539
528
|
if (Date.now() - this.checkedAtMs > HEALTH_TTL_MS) void this.refresh();
|
|
540
529
|
return this.health === "healthy" && (this.railHealth?.available() ?? true);
|
|
541
530
|
}
|
|
542
531
|
/**
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
* signed body — that binding is the internal-review condition-3 commitment on this
|
|
547
|
-
* rail, and it is why no artifact hash rides the request: there is no
|
|
548
|
-
* caller-supplied artifact to hash. A re-poll returns the stored row rather
|
|
549
|
-
* than minting again; a second bolt11 for one `fund_id` would leave two
|
|
550
|
-
* payable invoices against a funding that can only be credited once.
|
|
532
|
+
* Return the stored invoice on retry: two payable bolt11s for one fund ID could charge
|
|
533
|
+
* twice while only one credits. Caller and amount are bound to the recorded credit/funding
|
|
534
|
+
* pair, without a caller-supplied artifact hash.
|
|
551
535
|
*/
|
|
552
536
|
async issue(ledger, args) {
|
|
553
537
|
const existing = await ledger.getInvoice({ creditId: args.creditId, fundId: args.fundId });
|
|
@@ -582,9 +566,8 @@ var LightningReceive = class _LightningReceive {
|
|
|
582
566
|
fundId: args.fundId,
|
|
583
567
|
callerPubkey: args.callerPubkey,
|
|
584
568
|
currency: args.currency,
|
|
585
|
-
//
|
|
586
|
-
//
|
|
587
|
-
// caller was quoted (the internal-review shape).
|
|
569
|
+
// Pin fiat and millisatoshi amounts at issue time; settlement does not reprice them
|
|
570
|
+
// after FX changes.
|
|
588
571
|
amountMicro: args.amountMicro,
|
|
589
572
|
amountMsats: created.amountMsats || args.amountMsats,
|
|
590
573
|
paymentHash: created.paymentHash,
|
|
@@ -593,24 +576,9 @@ var LightningReceive = class _LightningReceive {
|
|
|
593
576
|
});
|
|
594
577
|
}
|
|
595
578
|
/**
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
599
|
-
* `blocked` row implies payment — {@link applyOne} returns above the block
|
|
600
|
-
* classification when the lookup says unpaid — but that is *this fleet's
|
|
601
|
-
* belief, recorded possibly weeks ago*, and the verb it gates mints balance
|
|
602
|
-
* against it. One round trip turns the belief into a fact and recovers the
|
|
603
|
-
* true settlement instant for `settled_at`, which a blocked row never got to
|
|
604
|
-
* write.
|
|
605
|
-
*
|
|
606
|
-
* Unlike {@link settlePending} this **throws**: there is no request whose
|
|
607
|
-
* latency it protects, and crediting on an unverifiable wallet is exactly
|
|
608
|
-
* what it exists to prevent. `NOT_FOUND` is the one exception, and it is not
|
|
609
|
-
* an outage — it is the wallet saying it has never seen this hash, the same
|
|
610
|
-
* reading {@link applyOne} and the caller-side reconcile in `src/lib/nwc.ts`
|
|
611
|
-
* take. It comes back as `known: false` because the operator's repair for it
|
|
612
|
-
* ("you are pointed at a different wallet than the one that minted this")
|
|
613
|
-
* is not the repair for an unpaid invoice, and certainly not for a retry.
|
|
579
|
+
* Re-observe the wallet payment before an operator credits a blocked invoice and recover
|
|
580
|
+
* its settlement instant. Unlike settlePending, lookup failures throw. NOT_FOUND returns
|
|
581
|
+
* known:false, distinguishing the wrong wallet/unknown hash from an unpaid known invoice.
|
|
614
582
|
*/
|
|
615
583
|
async lookupSettlement(paymentHash) {
|
|
616
584
|
try {
|
|
@@ -627,23 +595,12 @@ var LightningReceive = class _LightningReceive {
|
|
|
627
595
|
}
|
|
628
596
|
}
|
|
629
597
|
/**
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
* The pending rows are read locally first, so the common case (nothing
|
|
634
|
-
* outstanding) costs one indexed SELECT and no network at all. Bounded to
|
|
635
|
-
* {@link MAX_SETTLE_CHECKS} invoices on a short deadline, and **never throws
|
|
636
|
-
* into the request**: a wallet failure here means the caller's balance is
|
|
637
|
-
* merely not updated yet, which the ordinary `insufficient_credit` path
|
|
638
|
-
* already states honestly.
|
|
598
|
+
* Read pending invoices locally, then check at most MAX_SETTLE_CHECKS on bounded wallet
|
|
599
|
+
* deadlines. Log failures without throwing into the request.
|
|
639
600
|
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
* the rest of the pass down with it: the next invoice in the window may be
|
|
644
|
-
* the paid one, and it would never be looked up. Only a transport failure
|
|
645
|
-
* ends the pass early, because there the wallet itself is gone and the
|
|
646
|
-
* remaining lookups would just spend the caller's latency confirming it.
|
|
601
|
+
* An invoice-specific failure must not suppress payable siblings; wallet transport failure
|
|
602
|
+
* ends the pass. Deterministic refusals retire that row as blocked for operator repair,
|
|
603
|
+
* while transient failures remain pending.
|
|
647
604
|
*/
|
|
648
605
|
async settlePending(ledger, args) {
|
|
649
606
|
let pending;
|
|
@@ -683,14 +640,6 @@ var LightningReceive = class _LightningReceive {
|
|
|
683
640
|
}
|
|
684
641
|
return settled;
|
|
685
642
|
}
|
|
686
|
-
// ── Internal ───────────────────────────────────────────────────────────
|
|
687
|
-
/**
|
|
688
|
-
* One invoice's settlement check. Returns the applied settlement, or
|
|
689
|
-
* `undefined` when nothing changed (still unpaid, or retired unpaid).
|
|
690
|
-
*
|
|
691
|
-
* Throws whatever the wallet or the ledger threw — classifying that is
|
|
692
|
-
* {@link retireOrLog}'s job, so this stays one invoice's happy path.
|
|
693
|
-
*/
|
|
694
643
|
async applyOne(ledger, backend, invoice, opts) {
|
|
695
644
|
let status;
|
|
696
645
|
try {
|
|
@@ -741,18 +690,9 @@ var LightningReceive = class _LightningReceive {
|
|
|
741
690
|
});
|
|
742
691
|
}
|
|
743
692
|
/**
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
*
|
|
747
|
-
* The split that matters is permanent-versus-transient, because it decides
|
|
748
|
-
* whether the row keeps a slot in the sweep window. A transient failure — the
|
|
749
|
-
* database blinked, the wallet answered oddly — leaves it `pending` and the
|
|
750
|
-
* caller's next request retries it. A **permanent** one means the ledger will
|
|
751
|
-
* refuse this invoice identically forever, so leaving it pending costs a
|
|
752
|
-
* `lookup_invoice` on every subsequent request and, at
|
|
753
|
-
* {@link MAX_SETTLE_CHECKS} of them, fills the window so a genuinely payable
|
|
754
|
-
* invoice behind them is never even looked up. Those get `blocked`, which
|
|
755
|
-
* drops them out of the sweep and hands the operator the payment hash.
|
|
693
|
+
* Retire a deterministic uncreditable payment as blocked so it no longer occupies the
|
|
694
|
+
* bounded sweep window. Transient failures stay pending for a later request; report the
|
|
695
|
+
* payment hash for operator repair.
|
|
756
696
|
*/
|
|
757
697
|
async retireOrLog(ledger, invoice, err) {
|
|
758
698
|
const reason = await this.blockingReason(ledger, invoice, err);
|
|
@@ -785,21 +725,10 @@ var LightningReceive = class _LightningReceive {
|
|
|
785
725
|
);
|
|
786
726
|
}
|
|
787
727
|
/**
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
*
|
|
792
|
-
* has already committed (a `credit_fundings` entry at this
|
|
793
|
-
* `(credit_id, fund_id)`, or a `credits` row whose owner, denomination or
|
|
794
|
-
* rail disagrees with the invoice), or the basis this module rebuilds
|
|
795
|
-
* identically from the invoice row on every pass. None of them is a race.
|
|
796
|
-
*
|
|
797
|
-
* `funding_replayed` is the one that needs a second read to classify.
|
|
798
|
-
* Usually it *is* benign — a concurrent check won the race and the money is
|
|
799
|
-
* credited either way — but the key is `(credit_id, fund_id)` and `fund_id`
|
|
800
|
-
* is **caller-chosen**: reuse it on cashu or x402 after this bolt11 was
|
|
801
|
-
* minted and the row that collided is a different payment entirely, so the
|
|
802
|
-
* sats this invoice received have nowhere to land.
|
|
728
|
+
* Classify funding_replayed by reading the existing funding’s rail. A Lightning row can
|
|
729
|
+
* represent a concurrent applied check; another rail at this caller-chosen key is a
|
|
730
|
+
* different payment, leaving the invoice’s sats uncredited. A failed diagnostic read
|
|
731
|
+
* remains transient, never a guessed permanent refusal.
|
|
803
732
|
*/
|
|
804
733
|
async blockingReason(ledger, invoice, err) {
|
|
805
734
|
if (!(err instanceof CreditLedgerError)) return void 0;
|
|
@@ -835,7 +764,6 @@ var LightningReceive = class _LightningReceive {
|
|
|
835
764
|
throw err;
|
|
836
765
|
}
|
|
837
766
|
}
|
|
838
|
-
/** Record activity without letting it promote an unvalidated connection. */
|
|
839
767
|
noteOperationOk() {
|
|
840
768
|
if (this.health !== "healthy") return;
|
|
841
769
|
this.checkedAtMs = Date.now();
|
|
@@ -1028,7 +956,6 @@ var PostgresTempoSettlementReadinessStore = class {
|
|
|
1028
956
|
address;
|
|
1029
957
|
token;
|
|
1030
958
|
now;
|
|
1031
|
-
/** Create the shared latch table under the SDK-wide boot migration lock. */
|
|
1032
959
|
async init() {
|
|
1033
960
|
await withSdkInitLock(this.pool, async () => {
|
|
1034
961
|
await this.pool.query(`
|
|
@@ -1181,7 +1108,7 @@ function createDVMHost(opts = {}) {
|
|
|
1181
1108
|
const dbRequired = !opts.jobStore && !opts.devMode && !opts.pool;
|
|
1182
1109
|
if (!databaseUrl && dbRequired) {
|
|
1183
1110
|
throw new Error(
|
|
1184
|
-
"createDVMHost requires a Postgres database. Pass `database` opt or set DATABASE_URL env.
|
|
1111
|
+
"createDVMHost requires a Postgres database. Pass `database` opt or set DATABASE_URL env."
|
|
1185
1112
|
);
|
|
1186
1113
|
}
|
|
1187
1114
|
let store = opts.store ?? new MemoryKVStore();
|
|
@@ -1200,13 +1127,13 @@ function createDVMHost(opts = {}) {
|
|
|
1200
1127
|
});
|
|
1201
1128
|
applyRetryToPool(pool, "dvm-host");
|
|
1202
1129
|
pgPool = pool;
|
|
1203
|
-
const { PostgresJobStore: PostgresJobStore2 } = await import("../postgres-job-store-
|
|
1130
|
+
const { PostgresJobStore: PostgresJobStore2 } = await import("../postgres-job-store-MZZZMS2B.js");
|
|
1204
1131
|
const pgJobStore = new PostgresJobStore2(pool);
|
|
1205
1132
|
pendingInits.push(pgJobStore.init(), pgJobStore.initStreaming());
|
|
1206
1133
|
jobStore = pgJobStore;
|
|
1207
1134
|
pgStreamStore = pgJobStore;
|
|
1208
1135
|
if (!opts.store) {
|
|
1209
|
-
const { PostgresKVStore: PostgresKVStore2 } = await import("../postgres-kv-store-
|
|
1136
|
+
const { PostgresKVStore: PostgresKVStore2 } = await import("../postgres-kv-store-DXGTKXLU.js");
|
|
1210
1137
|
const pgKvStore = new PostgresKVStore2(pool);
|
|
1211
1138
|
pendingInits.push(pgKvStore.init());
|
|
1212
1139
|
store = pgKvStore;
|
|
@@ -1238,7 +1165,7 @@ function createDVMHost(opts = {}) {
|
|
|
1238
1165
|
if (testMints.length > 0) {
|
|
1239
1166
|
if (!envFlag(envMaybe.DVMKIT_ALLOW_TEST_MINTS)) {
|
|
1240
1167
|
throw new Error(
|
|
1241
|
-
`[FATAL] Refusing to boot: platform-hosted DVM configured with test mint(s) [${testMints.join(", ")}]. A test/FakeWallet mint settles no real money \u2014 every payment would silently no-op and revenue would read $0. If this is intentional (dev stack, smoke test, or the staging fleet), set DVMKIT_ALLOW_TEST_MINTS=true
|
|
1168
|
+
`[FATAL] Refusing to boot: platform-hosted DVM configured with test mint(s) [${testMints.join(", ")}]. A test/FakeWallet mint settles no real money \u2014 every payment would silently no-op and revenue would read $0. If this is intentional (dev stack, smoke test, or the staging fleet), set DVMKIT_ALLOW_TEST_MINTS=true.`
|
|
1242
1169
|
);
|
|
1243
1170
|
}
|
|
1244
1171
|
console.warn(
|
|
@@ -1246,7 +1173,7 @@ function createDVMHost(opts = {}) {
|
|
|
1246
1173
|
level: "warn",
|
|
1247
1174
|
event: "platform_hosted_test_mint_allowed",
|
|
1248
1175
|
mints: testMints,
|
|
1249
|
-
message: "Platform-hosted DVM booting with test mint(s) because DVMKIT_ALLOW_TEST_MINTS=true \u2014 payments settle no real money.
|
|
1176
|
+
message: "Platform-hosted DVM booting with test mint(s) because DVMKIT_ALLOW_TEST_MINTS=true \u2014 payments settle no real money."
|
|
1250
1177
|
})
|
|
1251
1178
|
);
|
|
1252
1179
|
}
|
|
@@ -1291,11 +1218,11 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1291
1218
|
let tempoChargeBackend = "user-supplied";
|
|
1292
1219
|
const mppTempoRecipient = envMaybe.DVMKIT_TEMPO_RECIPIENT;
|
|
1293
1220
|
if (!mpp && mppTempoRecipient) {
|
|
1294
|
-
const { createMppFromOpts, createDualKeyMppxFromOpts, parseMppMethodsAllowlist } = await import("../mpp-setup-
|
|
1221
|
+
const { createMppFromOpts, createDualKeyMppxFromOpts, parseMppMethodsAllowlist } = await import("../mpp-setup-MPP3ST5X.js");
|
|
1295
1222
|
tempoChargeBackend = pgPool ? "postgres" : "memory";
|
|
1296
1223
|
let tempoCharge;
|
|
1297
1224
|
if (pgPool) {
|
|
1298
|
-
const { PostgresTempoChargeStore } = await import("../tempo-charge-store-
|
|
1225
|
+
const { PostgresTempoChargeStore } = await import("../tempo-charge-store-SDTUNTKA.js");
|
|
1299
1226
|
const chargeStore = new PostgresTempoChargeStore(pgPool);
|
|
1300
1227
|
pendingInits.push(chargeStore.init());
|
|
1301
1228
|
tempoCharge = { store: chargeStore };
|
|
@@ -1314,7 +1241,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1314
1241
|
{ createPublicClient, createWalletClient, erc20Abi, http },
|
|
1315
1242
|
{ tempo: tempoMainnet, tempoModerato }
|
|
1316
1243
|
] = await Promise.all([
|
|
1317
|
-
import("../tempo-session-store-
|
|
1244
|
+
import("../tempo-session-store-WF3VZXNF.js"),
|
|
1318
1245
|
import("viem/accounts"),
|
|
1319
1246
|
import("viem"),
|
|
1320
1247
|
import("viem/chains")
|
|
@@ -1372,7 +1299,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1372
1299
|
chain: selectedChain,
|
|
1373
1300
|
// Trimmed, so a blank DVMKIT_TEMPO_RPC_URL falls back to the
|
|
1374
1301
|
// chain's bundled endpoint rather than becoming the transport
|
|
1375
|
-
// target
|
|
1302
|
+
// target.
|
|
1376
1303
|
transport: http(tempoRpc)
|
|
1377
1304
|
});
|
|
1378
1305
|
},
|
|
@@ -1415,7 +1342,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1415
1342
|
applyMppSecretRotation,
|
|
1416
1343
|
loadMppSecretState,
|
|
1417
1344
|
DEFAULT_ROTATION_WINDOW_MS
|
|
1418
|
-
} = await import("../mpp-secret-state-
|
|
1345
|
+
} = await import("../mpp-secret-state-B5GCILVH.js");
|
|
1419
1346
|
await initMppSecretStateTable(pgPool);
|
|
1420
1347
|
const rotation = await applyMppSecretRotation(
|
|
1421
1348
|
pgPool,
|
|
@@ -1445,7 +1372,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1445
1372
|
}
|
|
1446
1373
|
}
|
|
1447
1374
|
const fxSource = envMaybe.DVMKIT_FX_SOURCE;
|
|
1448
|
-
const { createFxFetcher, resolveFxSourceFromEnv, warmFxSnapshot } = await import("../pricing-
|
|
1375
|
+
const { createFxFetcher, resolveFxSourceFromEnv, warmFxSnapshot } = await import("../pricing-MU5GNUJZ.js");
|
|
1449
1376
|
const fxFetcher = opts.fx ?? createFxFetcher({ source: resolveFxSourceFromEnv(envMaybe) });
|
|
1450
1377
|
const hostRailConfigured = (opts.paymentMethods?.length ?? 0) > 0 || (effectiveMints?.length ?? 0) > 0 || !!x402WithDualServe || !!mpp;
|
|
1451
1378
|
if (mounts.some((entry) => mountNeedsFx(entry, hostRailConfigured))) warmFxSnapshot(fxFetcher);
|
|
@@ -1455,7 +1382,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1455
1382
|
assertReceiptIdentity(envMaybe, opts.builder, receiptKey, cashuOpts.dvmId, opts.devMode);
|
|
1456
1383
|
let sharedPgReplayStore;
|
|
1457
1384
|
if (pgPool) {
|
|
1458
|
-
const { PostgresReplayStore: PostgresReplayStore2 } = await import("../postgres-replay-store-
|
|
1385
|
+
const { PostgresReplayStore: PostgresReplayStore2 } = await import("../postgres-replay-store-ZF4JNZOW.js");
|
|
1459
1386
|
const store2 = new PostgresReplayStore2(pgPool);
|
|
1460
1387
|
pendingInits.push(store2.init());
|
|
1461
1388
|
sharedPgReplayStore = store2;
|
|
@@ -1467,7 +1394,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1467
1394
|
const backend = auth.resolveReplayStore ? auth.resolveReplayStore({ postgresStore: sharedPgReplayStore }) : "user-supplied";
|
|
1468
1395
|
replayStoreSummaries.push({ mount: entry.descriptor.name, backend });
|
|
1469
1396
|
if (backend === "memory" && !opts.devMode) {
|
|
1470
|
-
const msg = `secp256k1Auth on "${entry.descriptor.name}" fell back to the in-memory replay store. Multi-machine deploys MUST use a cross-machine store (e.g. PostgresReplayStore) \u2014 each machine's per-process window otherwise lets an attacker replay a captured signed envelope once per machine via the load balancer. Set DATABASE_URL or pass \`replayStore\` to secp256k1Auth()
|
|
1397
|
+
const msg = `secp256k1Auth on "${entry.descriptor.name}" fell back to the in-memory replay store. Multi-machine deploys MUST use a cross-machine store (e.g. PostgresReplayStore) \u2014 each machine's per-process window otherwise lets an attacker replay a captured signed envelope once per machine via the load balancer. Set DATABASE_URL or pass \`replayStore\` to secp256k1Auth().`;
|
|
1471
1398
|
if (failFast) {
|
|
1472
1399
|
throw new Error(`[FATAL] ${msg}`);
|
|
1473
1400
|
}
|
|
@@ -1483,24 +1410,24 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1483
1410
|
}
|
|
1484
1411
|
let sharedPgConsumedStore;
|
|
1485
1412
|
if (pgPool) {
|
|
1486
|
-
const { PostgresConsumedCredentialStore } = await import("../postgres-consumed-credential-store-
|
|
1413
|
+
const { PostgresConsumedCredentialStore } = await import("../postgres-consumed-credential-store-6N2V5MJN.js");
|
|
1487
1414
|
const consumedStore = new PostgresConsumedCredentialStore(pgPool);
|
|
1488
1415
|
pendingInits.push(consumedStore.init());
|
|
1489
1416
|
sharedPgConsumedStore = consumedStore;
|
|
1490
1417
|
}
|
|
1491
1418
|
if (pgPool) {
|
|
1492
|
-
const { CreditLedger: CreditLedger2 } = await import("../credit-ledger-
|
|
1419
|
+
const { CreditLedger: CreditLedger2 } = await import("../credit-ledger-MHA652TV.js");
|
|
1493
1420
|
const pgLedger = new CreditLedger2(pgPool, tempoSessionStore);
|
|
1494
1421
|
pendingInits.push(pgLedger.init());
|
|
1495
1422
|
creditLedger = pgLedger;
|
|
1496
|
-
const { PostgresProcessedPaymentStore: PostgresProcessedPaymentStore2 } = await import("../processed-payment-store-
|
|
1423
|
+
const { PostgresProcessedPaymentStore: PostgresProcessedPaymentStore2 } = await import("../processed-payment-store-GKMAWOM3.js");
|
|
1497
1424
|
const pgProcessed = new PostgresProcessedPaymentStore2(pgPool);
|
|
1498
1425
|
pendingInits.push(pgProcessed.init());
|
|
1499
1426
|
processedPayments = pgProcessed;
|
|
1500
1427
|
} else {
|
|
1501
|
-
const { MemoryCreditLedger: MemoryCreditLedger2 } = await import("../memory-credit-ledger-
|
|
1428
|
+
const { MemoryCreditLedger: MemoryCreditLedger2 } = await import("../memory-credit-ledger-BYBATRN3.js");
|
|
1502
1429
|
creditLedger = disposableCashu?.ledger ?? new MemoryCreditLedger2();
|
|
1503
|
-
const { MemoryProcessedPaymentStore: MemoryProcessedPaymentStore2 } = await import("../processed-payment-store-
|
|
1430
|
+
const { MemoryProcessedPaymentStore: MemoryProcessedPaymentStore2 } = await import("../processed-payment-store-GKMAWOM3.js");
|
|
1504
1431
|
processedPayments = new MemoryProcessedPaymentStore2();
|
|
1505
1432
|
}
|
|
1506
1433
|
await Promise.all(pendingInits);
|
|
@@ -1509,7 +1436,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1509
1436
|
const checkStoreFallback = (label, event, active, backend, hazardHint) => {
|
|
1510
1437
|
storeSummaries.push({ label, backend });
|
|
1511
1438
|
if (active && backend === "memory" && !opts.devMode) {
|
|
1512
|
-
const msg = `The ${label} store fell back to in-memory. Multi-machine deploys MUST use a cross-machine store (set DATABASE_URL) \u2014 each machine's per-process window otherwise lets an attacker ${hazardHint} once per machine via the load balancer
|
|
1439
|
+
const msg = `The ${label} store fell back to in-memory. Multi-machine deploys MUST use a cross-machine store (set DATABASE_URL) \u2014 each machine's per-process window otherwise lets an attacker ${hazardHint} once per machine via the load balancer.`;
|
|
1513
1440
|
if (failFast) {
|
|
1514
1441
|
throw new Error(`[FATAL] ${msg}`);
|
|
1515
1442
|
}
|
|
@@ -1691,8 +1618,9 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1691
1618
|
replayStores: replayStoreSummaries,
|
|
1692
1619
|
stores: storeSummaries
|
|
1693
1620
|
});
|
|
1694
|
-
return new Promise((resolvePromise) => {
|
|
1621
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
1695
1622
|
const server = honoServe({ fetch: app.fetch, port }, (info) => {
|
|
1623
|
+
server.off("error", rejectPromise);
|
|
1696
1624
|
const url = `http://{authority}`.replace("{authority}", `localhost:${info.port}`);
|
|
1697
1625
|
nodeServer = server;
|
|
1698
1626
|
const portBindMs = Date.now() - bootStart;
|
|
@@ -1708,7 +1636,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1708
1636
|
level: "dvm_boot_phase_timings",
|
|
1709
1637
|
totalMsToPortBind: portBindMs,
|
|
1710
1638
|
phaseMs: deltas
|
|
1711
|
-
//
|
|
1639
|
+
// removed the pre-`listen` `mint_wait` phase: mint health
|
|
1712
1640
|
// is now validated by the runtime tracker after the port binds, so
|
|
1713
1641
|
// `totalMsToPortBind` no longer carries the mint-probe tail.
|
|
1714
1642
|
})
|
|
@@ -1722,6 +1650,7 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1722
1650
|
}
|
|
1723
1651
|
});
|
|
1724
1652
|
});
|
|
1653
|
+
server.once("error", rejectPromise);
|
|
1725
1654
|
});
|
|
1726
1655
|
}
|
|
1727
1656
|
async function serveFn(serveOpts) {
|
|
@@ -2071,7 +2000,7 @@ function secp256k1Auth(opts = {}) {
|
|
|
2071
2000
|
replayStore: null,
|
|
2072
2001
|
driftSeconds,
|
|
2073
2002
|
now,
|
|
2074
|
-
//
|
|
2003
|
+
// the caller signs over the credit envelope, so it has to be in
|
|
2075
2004
|
// the canonical bytes — but it is protocol-level, not capability input, so
|
|
2076
2005
|
// the builder's schema must not have to tolerate it. Resolved once per
|
|
2077
2006
|
// schema, cached with the verifier below.
|
|
@@ -26,7 +26,6 @@ type SSRFResolver = (host: string) => Promise<{
|
|
|
26
26
|
* baseline denylist; extra entries compose with (never replace) the defaults.
|
|
27
27
|
*/
|
|
28
28
|
interface SSRFGuardOpts {
|
|
29
|
-
/** Custom DNS resolver — typically a test stub. */
|
|
30
29
|
resolver?: SSRFResolver;
|
|
31
30
|
/** Additional exact hostnames to deny on top of the defaults (lowercased on input). */
|
|
32
31
|
extraHostnamesExact?: Iterable<string>;
|
|
@@ -61,7 +60,7 @@ interface SSRFGuardOpts {
|
|
|
61
60
|
* link-local IP ranges, the AWS / GCP metadata IP, Fly's `*.internal`
|
|
62
61
|
* service-discovery names, and a small denylist of obviously-internal
|
|
63
62
|
* hostnames. Defence-in-depth — full mitigation belongs at the egress firewall
|
|
64
|
-
* and at fetch-time IP pinning (`createPinnedFetch
|
|
63
|
+
* and at fetch-time IP pinning (`createPinnedFetch`).
|
|
65
64
|
*
|
|
66
65
|
* Throws `SSRFError` with a `reason` discriminator so callers can branch onto
|
|
67
66
|
* their own typed error taxonomy.
|