@dvmkit/sdk 0.1.0-rc.2 → 0.1.0-rc.3
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 +10 -2
- package/dist/{revenue-reporter-GB4WKLDC.js → chunk-2ABMGUDS.js} +1 -0
- package/dist/chunk-5SO7ZVOH.js +375 -0
- package/dist/chunk-66HGCPBU.js +25 -0
- package/dist/{chunk-KQAJVVZT.js → chunk-AZBXSXQT.js} +27 -287
- package/dist/chunk-C2DC4FKR.js +21424 -0
- package/dist/{chunk-H25M54MI.js → chunk-C3MTFLC6.js} +16 -0
- package/dist/{chunk-OJ5WFIB2.js → chunk-EXHBXA4U.js} +1 -1
- package/dist/chunk-FT7IM66W.js +1557 -0
- package/dist/{chunk-KXWROQGK.js → chunk-FUJ36YDV.js} +1 -24
- package/dist/{tempo-charge-store-6GJEMNUU.js → chunk-JZWELPFH.js} +1 -0
- package/dist/{chunk-365P52XQ.js → chunk-LWUR4CGG.js} +2 -1
- package/dist/chunk-RHP3BRTH.js +1090 -0
- package/dist/{tempo-session-store-FTEEGZXA.js → chunk-RU7SXHLO.js} +2 -1
- package/dist/{chunk-7IH5SG2A.js → chunk-TKA6ZP4M.js} +62 -41
- package/dist/chunk-TVI4V7GF.js +283 -0
- package/dist/{payout-reporter-4TNWRS5F.js → chunk-X3IKFWJA.js} +3 -2
- package/dist/{chunk-DCNT4PJS.js → chunk-XY5Y5REG.js} +6 -258
- package/dist/chunk-XYTSDAPH.js +232 -0
- package/dist/chunk-YD3TZNXV.js +1042 -0
- package/dist/{credit-ledger-RO4FGSHG.js → credit-ledger-ED6JXKVD.js} +2 -2
- package/dist/credit-menu-DONAtGVf.d.ts +5076 -0
- package/dist/{ssrf-DZi-xJyn.d.ts → fx-Bq4cvn16.d.ts} +37 -119
- package/dist/index.d.ts +8 -66
- package/dist/index.js +11 -219
- package/dist/internal/index.d.ts +5745 -0
- package/dist/internal/index.js +6379 -0
- package/dist/{job-store-6gR4pZRP.d.ts → job-store-m2pYmvbr.d.ts} +1493 -12
- package/dist/{memory-credit-ledger-I2G64DDK.js → memory-credit-ledger-XJ5VQEVP.js} +3 -3
- package/dist/payout-reporter-3UB5WRCV.js +13 -0
- package/dist/revenue-reporter-JIKUPXOK.js +7 -0
- package/dist/server/index.d.ts +14 -3590
- package/dist/server/index.js +309 -20796
- package/dist/ssrf-DbFkpDv0.d.ts +118 -0
- package/dist/tempo-charge-store-RIFTALZK.js +8 -0
- package/dist/tempo-session-store-DALMRIWN.js +11 -0
- package/dist/testing/index.d.ts +3 -2
- package/dist/testing/index.js +3 -2
- package/dist/usd-DjVAPMlf.d.ts +97 -0
- package/dist/x402-5EVIUSEP.js +81 -0
- package/package.json +6 -2
- package/dist/x402-35VLYFKZ.js +0 -1272
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ProofLike } from '@cashu/cashu-ts';
|
|
2
|
-
import { Challenge, Credential, Method, Receipt } from 'mppx';
|
|
3
|
-
import {
|
|
4
|
-
import { FacilitatorClient } from '@x402/core/server';
|
|
2
|
+
import { Challenge, Credential, Store, Method, Receipt } from 'mppx';
|
|
3
|
+
import { FacilitatorClient, FacilitatorConfig } from '@x402/core/server';
|
|
5
4
|
import { AuthorizerSigner, ChannelStorage, AutoSettlementConfig, Channel, ChannelUpdateResult } from '@x402/evm/batch-settlement/server';
|
|
5
|
+
import { MiddlewareHandler, Context, Hono } from 'hono';
|
|
6
|
+
import { Account, Client, Hex } from 'viem';
|
|
6
7
|
import { Pool, PoolClient } from 'pg';
|
|
7
|
-
import { PaymentPayload, PaymentRequirements, SettleResponse } from '@x402/core/types';
|
|
8
|
+
import { PaymentPayload as PaymentPayload$1, PaymentRequirements as PaymentRequirements$1, SettleResponse as SettleResponse$1 } from '@x402/core/types';
|
|
8
9
|
import { z } from 'zod';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -78,6 +79,8 @@ interface X402SelfRelayConfig {
|
|
|
78
79
|
/** Advanced RPC-health hook; platform-hosted DVMs receive an automatic reporter. */
|
|
79
80
|
onRpcHealth?: (observation: X402SelfRelayRpcHealthObservation) => void | Promise<void>;
|
|
80
81
|
}
|
|
82
|
+
/** Caller-visible reasons an ambiguous x402 settlement could not be reconciled. */
|
|
83
|
+
type X402SettlementReconciliationReason = "settlement_not_on_chain" | "chain_unreachable" | "settlement_unbookmarked" | "facilitator_channel_state_unavailable";
|
|
81
84
|
/** Builder-facing configuration for reusable x402 batch-settlement channels. */
|
|
82
85
|
interface X402BatchSettlementConfig {
|
|
83
86
|
/** Receiver-authorizer signer used when the facilitator advertises none. */
|
|
@@ -142,6 +145,13 @@ interface X402ExactVersionSupport {
|
|
|
142
145
|
v1: boolean;
|
|
143
146
|
v2: boolean;
|
|
144
147
|
}
|
|
148
|
+
/** Client-side x402 wallet — EVM key pair for signing payments. */
|
|
149
|
+
interface X402Wallet {
|
|
150
|
+
privateKey: string;
|
|
151
|
+
address: string;
|
|
152
|
+
/** CAIP-2 chain id this wallet pays on. */
|
|
153
|
+
network: string;
|
|
154
|
+
}
|
|
145
155
|
/** Server-side receipt from verifying an x402 payment. */
|
|
146
156
|
interface X402Receipt {
|
|
147
157
|
verified: boolean;
|
|
@@ -181,6 +191,50 @@ interface X402Receipt {
|
|
|
181
191
|
|
|
182
192
|
/** Current x402 protocol version preferred by dvmkit clients and servers. */
|
|
183
193
|
declare const X402_VERSION = 2;
|
|
194
|
+
/** Legacy x402 protocol version retained during the dual-serve window. */
|
|
195
|
+
declare const X402_V1_VERSION = 1;
|
|
196
|
+
/** x402 protocol versions supported by dvmkit's hand-rolled exact codec. */
|
|
197
|
+
type X402Version = typeof X402_V1_VERSION | typeof X402_VERSION;
|
|
198
|
+
/**
|
|
199
|
+
* Chain a caller's x402 wallet reads when it was connected without an explicit
|
|
200
|
+
* `--network`. Single source of truth for the default: the wallet loader, the
|
|
201
|
+
* connect output and the asset resolver all read it from here (internal-review).
|
|
202
|
+
*/
|
|
203
|
+
declare const X402_DEFAULT_NETWORK = "eip155:8453";
|
|
204
|
+
/**
|
|
205
|
+
* Scheme name of the per-call rail — one signed authorization settling one
|
|
206
|
+
* resource. Shared with the credit funding menu's `x402.schemes` block, which
|
|
207
|
+
* has to name the same string the requirement carries (internal-review).
|
|
208
|
+
*/
|
|
209
|
+
declare const X402_EXACT_SCHEME = "exact";
|
|
210
|
+
/**
|
|
211
|
+
* Scheme name of the reusable v2 channel rail. Single source of truth: the
|
|
212
|
+
* facilitator probe, the requirement the server builds, the header dispatch,
|
|
213
|
+
* the caller's requirement selection, and the credit menu's `x402.schemes`
|
|
214
|
+
* block all read it from here — the menu advertises exactly what the challenge
|
|
215
|
+
* will carry, so a rename cannot leave one of them advertising a flavour the
|
|
216
|
+
* others no longer speak (internal-review).
|
|
217
|
+
*/
|
|
218
|
+
declare const X402_BATCH_SETTLEMENT_SCHEME = "batch-settlement";
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* x402-spec PaymentRequirements — the shape advertised on a 402 response's
|
|
222
|
+
* `accepts` array, mirrored from the facilitator's `PaymentRequirementsSchema`
|
|
223
|
+
* (see `x402/types/index.d.ts` in the published `x402` package).
|
|
224
|
+
*/
|
|
225
|
+
interface PaymentRequirementsV1 {
|
|
226
|
+
scheme: string;
|
|
227
|
+
network: string;
|
|
228
|
+
maxAmountRequired: string;
|
|
229
|
+
resource: string;
|
|
230
|
+
description: string;
|
|
231
|
+
mimeType: string;
|
|
232
|
+
payTo: string;
|
|
233
|
+
asset: string;
|
|
234
|
+
maxTimeoutSeconds: number;
|
|
235
|
+
outputSchema?: Record<string, unknown>;
|
|
236
|
+
extra?: Record<string, unknown>;
|
|
237
|
+
}
|
|
184
238
|
/** x402 v2 resource metadata echoed by a paying client. */
|
|
185
239
|
interface ResourceInfo {
|
|
186
240
|
url: string;
|
|
@@ -204,6 +258,73 @@ interface PaymentRequirementsV2 {
|
|
|
204
258
|
*/
|
|
205
259
|
extra?: Record<string, unknown> | null;
|
|
206
260
|
}
|
|
261
|
+
/** Legacy alias retained for server internals that carry the v1 body requirements. */
|
|
262
|
+
type PaymentRequirements = PaymentRequirementsV1;
|
|
263
|
+
/**
|
|
264
|
+
* EIP-3009 `TransferWithAuthorization` parameters that the client signs and
|
|
265
|
+
* the facilitator submits on settlement.
|
|
266
|
+
*/
|
|
267
|
+
interface ExactEvmPayloadAuthorization {
|
|
268
|
+
from: string;
|
|
269
|
+
to: string;
|
|
270
|
+
value: string;
|
|
271
|
+
validAfter: string;
|
|
272
|
+
validBefore: string;
|
|
273
|
+
nonce: string;
|
|
274
|
+
}
|
|
275
|
+
/** Signed EIP-3009 transfer authorization (the `payload` of a PaymentPayload). */
|
|
276
|
+
interface ExactEvmPayload {
|
|
277
|
+
signature: string;
|
|
278
|
+
authorization: ExactEvmPayloadAuthorization;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* x402-spec PaymentPayload — the JSON shape carried inside the `X-PAYMENT`
|
|
282
|
+
* header (base64-encoded). `payload` is scheme-specific; alpha only supports
|
|
283
|
+
* `scheme: "exact"` against an EVM network.
|
|
284
|
+
*/
|
|
285
|
+
interface PaymentPayloadV1 {
|
|
286
|
+
x402Version: typeof X402_V1_VERSION;
|
|
287
|
+
scheme: "exact";
|
|
288
|
+
network: string;
|
|
289
|
+
payload: ExactEvmPayload;
|
|
290
|
+
}
|
|
291
|
+
/** x402 v2 payment payload carried in `PAYMENT-SIGNATURE`. */
|
|
292
|
+
interface PaymentPayloadV2 {
|
|
293
|
+
x402Version: typeof X402_VERSION;
|
|
294
|
+
resource?: ResourceInfo;
|
|
295
|
+
accepted: PaymentRequirementsV2;
|
|
296
|
+
payload: ExactEvmPayload;
|
|
297
|
+
extensions?: Record<string, unknown>;
|
|
298
|
+
}
|
|
299
|
+
/** Exact EVM payment payload accepted by the dual-version codec. */
|
|
300
|
+
type PaymentPayload = PaymentPayloadV1 | PaymentPayloadV2;
|
|
301
|
+
/** Facilitator `/verify` response. */
|
|
302
|
+
interface VerifyResponse {
|
|
303
|
+
isValid: boolean;
|
|
304
|
+
invalidReason?: string;
|
|
305
|
+
payer?: string;
|
|
306
|
+
}
|
|
307
|
+
/** Facilitator `/settle` response — what we base64 into `X-PAYMENT-RESPONSE`. */
|
|
308
|
+
interface SettleResponse {
|
|
309
|
+
success: boolean;
|
|
310
|
+
errorReason?: string;
|
|
311
|
+
payer?: string;
|
|
312
|
+
transaction?: string;
|
|
313
|
+
network?: string;
|
|
314
|
+
amount?: string;
|
|
315
|
+
extensions?: Record<string, unknown>;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Body envelope used to carry x402 PaymentRequirements on a 402 response.
|
|
319
|
+
* The x402 spec puts requirements in the JSON body under `accepts`; the
|
|
320
|
+
* `WWW-Authenticate: Payment` header carries the MPP method advertisements
|
|
321
|
+
* separately, so the two protocols don't fight for the same header slot.
|
|
322
|
+
*/
|
|
323
|
+
interface X402ResponseBody {
|
|
324
|
+
x402Version: typeof X402_V1_VERSION;
|
|
325
|
+
accepts: PaymentRequirementsV1[];
|
|
326
|
+
error?: string;
|
|
327
|
+
}
|
|
207
328
|
/** x402 v2 payment-required declaration encoded into `PAYMENT-REQUIRED`. */
|
|
208
329
|
interface PaymentRequiredV2 {
|
|
209
330
|
x402Version: typeof X402_VERSION;
|
|
@@ -212,6 +333,101 @@ interface PaymentRequiredV2 {
|
|
|
212
333
|
accepts: PaymentRequirementsV2[];
|
|
213
334
|
extensions?: Record<string, unknown>;
|
|
214
335
|
}
|
|
336
|
+
/** Either challenge shape understood by dvmkit callers. */
|
|
337
|
+
type PaymentRequired = X402ResponseBody | PaymentRequiredV2;
|
|
338
|
+
/** Inputs for `buildPaymentRequirements`. */
|
|
339
|
+
interface BuildPaymentRequirementsOpts {
|
|
340
|
+
x402Config: X402Config;
|
|
341
|
+
requiredUsdcMicro: bigint;
|
|
342
|
+
resource: string;
|
|
343
|
+
description?: string;
|
|
344
|
+
mimeType?: string;
|
|
345
|
+
version?: X402Version;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Build a single x402 `PaymentRequirements` entry from the DVM's `X402Config`,
|
|
349
|
+
* the resolved per-call USDC amount, and the live request's resource URL.
|
|
350
|
+
* The resource string is bound into the EIP-3009 `extra` field on signing in
|
|
351
|
+
* the reference clients, so it must match exactly between the 402 response
|
|
352
|
+
* and the retry payload — pass the request URL the client will retry against.
|
|
353
|
+
*/
|
|
354
|
+
declare function buildPaymentRequirements(opts: BuildPaymentRequirementsOpts & {
|
|
355
|
+
version: typeof X402_V1_VERSION;
|
|
356
|
+
}): PaymentRequirementsV1;
|
|
357
|
+
declare function buildPaymentRequirements(opts: (BuildPaymentRequirementsOpts & {
|
|
358
|
+
version: typeof X402_VERSION;
|
|
359
|
+
}) | (BuildPaymentRequirementsOpts & {
|
|
360
|
+
version?: undefined;
|
|
361
|
+
})): PaymentRequirementsV2;
|
|
362
|
+
/** Build the canonical x402 v2 declaration for a `PAYMENT-REQUIRED` header. */
|
|
363
|
+
declare function buildPaymentRequiredV2(opts: Omit<BuildPaymentRequirementsOpts, "version"> & {
|
|
364
|
+
error?: string;
|
|
365
|
+
}): PaymentRequiredV2;
|
|
366
|
+
/** Convert the server's legacy body requirements into the parallel v2 declaration. */
|
|
367
|
+
declare function paymentRequiredV2FromV1(requirements: PaymentRequirementsV1[], error?: string): PaymentRequiredV2;
|
|
368
|
+
/**
|
|
369
|
+
* Translate a CAIP-2 chain id (`eip155:8453`) to the x402-spec network slug
|
|
370
|
+
* (`base`). Operators configure DVMs in CAIP-2 because it's the lingua-franca
|
|
371
|
+
* across our other rails; the x402 facilitator API only accepts named slugs.
|
|
372
|
+
* Unknown CAIP-2 ids fall through to the original string so non-EVM rails
|
|
373
|
+
* (Solana mainnet, etc.) can also be plumbed once supported.
|
|
374
|
+
*/
|
|
375
|
+
declare function caip2ToX402Network(network: string): string;
|
|
376
|
+
/** Translate a legacy x402 network slug back to its CAIP-2 chain id. */
|
|
377
|
+
declare function x402NetworkToCaip2(network: string): string;
|
|
378
|
+
/** EIP-712 chain id derived from a CAIP-2 chain id. */
|
|
379
|
+
declare function chainIdFromCaip2(network: string): number;
|
|
380
|
+
/** USDC contract address for a network slug (post-translation). */
|
|
381
|
+
declare function usdcContractFor(networkSlug: string): `0x${string}` | undefined;
|
|
382
|
+
/**
|
|
383
|
+
* USDC contract address for a CAIP-2 chain id (e.g. `eip155:8453`). Resolves
|
|
384
|
+
* via {@link caip2ToX402Network} so the one network table is the source of
|
|
385
|
+
* truth — keeps callers that hold the CAIP-2 form (CLI wallet) in lockstep
|
|
386
|
+
* with the SDK 402-builder which already speaks x402 slugs.
|
|
387
|
+
*/
|
|
388
|
+
declare function usdcContractByCaip2(caip2: string): `0x${string}` | undefined;
|
|
389
|
+
/** USDC EIP-712 domain `name` for a network slug. */
|
|
390
|
+
declare function usdcDomainNameFor(networkSlug: string): string | undefined;
|
|
391
|
+
/** USDC EIP-712 domain `version` for a network slug. */
|
|
392
|
+
declare function usdcDomainVersionFor(networkSlug: string): string | undefined;
|
|
393
|
+
/**
|
|
394
|
+
* Decode a base64-encoded `X-PAYMENT` header into a structured `PaymentPayload`.
|
|
395
|
+
* Throws on malformed input rather than silently returning a partial — the
|
|
396
|
+
* server treats decode failures as `payment_invalid` per the spec.
|
|
397
|
+
*/
|
|
398
|
+
declare function decodePayment(header: string): PaymentPayload;
|
|
399
|
+
/**
|
|
400
|
+
* Encode a `PaymentPayload` for transport in the `X-PAYMENT` header. JSON
|
|
401
|
+
* serialization uses string-typed integer fields (the spec encodes uint256
|
|
402
|
+
* values as decimal strings, so `bigint` must already be stringified by the
|
|
403
|
+
* caller).
|
|
404
|
+
*/
|
|
405
|
+
declare function encodePayment(payload: PaymentPayload): string;
|
|
406
|
+
/** Encode a v2 `PaymentRequired` declaration for the HTTP response header. */
|
|
407
|
+
declare function encodePaymentRequiredHeader(required: PaymentRequiredV2): string;
|
|
408
|
+
/** Decode and structurally validate a v2 `PAYMENT-REQUIRED` header. */
|
|
409
|
+
declare function decodePaymentRequiredHeader(header: string): PaymentRequiredV2;
|
|
410
|
+
/** Read the exact EIP-3009 authorization carried by either protocol version. */
|
|
411
|
+
declare function exactEvmAuthorization(payload: PaymentPayload): ExactEvmPayloadAuthorization;
|
|
412
|
+
/**
|
|
413
|
+
* Encode a `SettleResponse` for the `X-PAYMENT-RESPONSE` header that the
|
|
414
|
+
* server emits on a 2xx after a successful settlement (internal-review, per the
|
|
415
|
+
* x402 spec).
|
|
416
|
+
*/
|
|
417
|
+
declare function encodeSettleResponseHeader(response: SettleResponse): string;
|
|
418
|
+
/**
|
|
419
|
+
* POST a verify request to the facilitator. Returns the parsed `VerifyResponse`
|
|
420
|
+
* or a structured-failure shape when the facilitator rejects the call (network
|
|
421
|
+
* error, non-2xx, or `isValid: false`).
|
|
422
|
+
*/
|
|
423
|
+
declare function verifyWithFacilitator(payload: PaymentPayload, requirements: PaymentRequirementsV1 | PaymentRequirementsV2, config?: Pick<X402Config, "facilitator" | "facilitatorAuth">, createAuthHeaders?: FacilitatorConfig["createAuthHeaders"] | undefined): Promise<VerifyResponse>;
|
|
424
|
+
/**
|
|
425
|
+
* POST a settle request to the facilitator. The facilitator broadcasts the
|
|
426
|
+
* EIP-3009 `transferWithAuthorization` and returns the on-chain tx hash on
|
|
427
|
+
* success; the dvmkit DVM mirrors that into `X-PAYMENT-RESPONSE` for the
|
|
428
|
+
* client and into `revenue_events.tx_hash` for the platform ledger.
|
|
429
|
+
*/
|
|
430
|
+
declare function settleWithFacilitator(payload: PaymentPayload, requirements: PaymentRequirementsV1 | PaymentRequirementsV2, config?: Pick<X402Config, "facilitator" | "facilitatorAuth">, createAuthHeaders?: FacilitatorConfig["createAuthHeaders"] | undefined): Promise<SettleResponse>;
|
|
215
431
|
|
|
216
432
|
/** Identifies which side of the conversation sent a message. */
|
|
217
433
|
type MessageFrom = "requester" | "provider";
|
|
@@ -419,6 +635,16 @@ type Message = (MessageBase & {
|
|
|
419
635
|
type: "progress";
|
|
420
636
|
content: ProgressContent;
|
|
421
637
|
});
|
|
638
|
+
/** Type guard: message contains an artifact. */
|
|
639
|
+
declare function isArtifactMessage(msg: Message): msg is MessageBase & {
|
|
640
|
+
type: "artifact";
|
|
641
|
+
content: ArtifactContent;
|
|
642
|
+
};
|
|
643
|
+
/** Type guard: message is a payment request. */
|
|
644
|
+
declare function isPaymentRequestMessage(msg: Message): msg is MessageBase & {
|
|
645
|
+
type: "payment-request";
|
|
646
|
+
content: PaymentRequestContent;
|
|
647
|
+
};
|
|
422
648
|
|
|
423
649
|
/** Auth identifier advertised by DVMs using audience-bound caller proofs. */
|
|
424
650
|
declare const SIGNED_REQUEST_AUTH_ID: "secp256k1-schnorr-v2";
|
|
@@ -514,6 +740,42 @@ declare const requireClientCompatibility: ClientCompatibilityGate;
|
|
|
514
740
|
/** Render the normal structured HTTP 426 compatibility error. */
|
|
515
741
|
declare function clientUpgradeRequired(c: Context, compatibility: ClientCompatibility, requirement: ClientCompatibilityRequirement): Response;
|
|
516
742
|
|
|
743
|
+
/**
|
|
744
|
+
* Canonical JSON serialisation used for secp256k1+BIP-340 Schnorr request
|
|
745
|
+
* signing in cast (internal-review).
|
|
746
|
+
*
|
|
747
|
+
* Single source of truth for both the cast DVM's verifier (internal-review) and the
|
|
748
|
+
* client signing helper (internal-review). The same function on both sides guarantees
|
|
749
|
+
* that what the client signs is byte-identical to what the server hashes.
|
|
750
|
+
*
|
|
751
|
+
* Algorithm: recursively sort object keys lexicographically (UTF-16 code-unit
|
|
752
|
+
* order — JavaScript's default), then JSON.stringify with no whitespace.
|
|
753
|
+
* Arrays preserve order. Numbers, strings, booleans, null pass through as
|
|
754
|
+
* `JSON.stringify` formats them. Values of `undefined` or functions are
|
|
755
|
+
* forbidden (we throw rather than silently drop, since both sides must agree).
|
|
756
|
+
*/
|
|
757
|
+
/** Any JSON-serialisable value accepted by `canonicalize`. */
|
|
758
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
759
|
+
[key: string]: JsonValue;
|
|
760
|
+
};
|
|
761
|
+
/**
|
|
762
|
+
* Serialise `value` to its canonical JSON form (sorted keys, no whitespace).
|
|
763
|
+
*
|
|
764
|
+
* `undefined` properties on objects are silently omitted (mirroring
|
|
765
|
+
* `JSON.stringify`), so callers don't need to explicitly delete optional fields
|
|
766
|
+
* that weren't set. Throws `TypeError` for unsupported scalar types (functions,
|
|
767
|
+
* symbols, non-finite numbers). The caller is responsible for stripping fields
|
|
768
|
+
* that shouldn't appear in the signed payload (e.g. `signature` itself).
|
|
769
|
+
*/
|
|
770
|
+
declare function canonicalize(value: JsonValue): string;
|
|
771
|
+
/**
|
|
772
|
+
* Canonicalise `value` and return the UTF-8 bytes the signer should produce a
|
|
773
|
+
* signature over. Both the cast client signer (`signAddEpisode`) and the
|
|
774
|
+
* server verifier (`verifyCanonicalSignedRequest`) call this — sharing the function
|
|
775
|
+
* guarantees byte-identical input on both sides.
|
|
776
|
+
*/
|
|
777
|
+
declare function canonicaliseForSigning(value: JsonValue): Uint8Array;
|
|
778
|
+
|
|
517
779
|
/** Terminal outcome a receipt attests. Mirrors the SDK's terminal job statuses. */
|
|
518
780
|
type ReceiptOutcome = "completed" | "failed" | "cancelled";
|
|
519
781
|
/** What the caller paid for the job, as persisted on the job record. */
|
|
@@ -611,6 +873,8 @@ interface JobReceipt {
|
|
|
611
873
|
*/
|
|
612
874
|
credit?: ReceiptCredit;
|
|
613
875
|
}
|
|
876
|
+
/** A receipt before signing — every field but the signature itself. */
|
|
877
|
+
type UnsignedJobReceipt = Omit<JobReceipt, "signature">;
|
|
614
878
|
/** Reclaim lifecycle event a {@link DrainReceipt} attests (internal-review, spec §5). */
|
|
615
879
|
type DrainReceiptEvent = "requested" | "parked" | "picked_up" | "sent" | "released";
|
|
616
880
|
/**
|
|
@@ -665,6 +929,8 @@ interface DrainReceipt {
|
|
|
665
929
|
/** BIP-340 Schnorr signature over the canonical receipt minus `signature`. */
|
|
666
930
|
signature: string;
|
|
667
931
|
}
|
|
932
|
+
/** A drain receipt before signing — every field but the signature itself. */
|
|
933
|
+
type UnsignedDrainReceipt = Omit<DrainReceipt, "signature">;
|
|
668
934
|
/**
|
|
669
935
|
* A DVM-signed proof that one payment funded a prepaid credit (internal-review).
|
|
670
936
|
* The balance and sequence are the values fixed when the funding committed;
|
|
@@ -698,6 +964,94 @@ interface FundingReceipt {
|
|
|
698
964
|
/** BIP-340 Schnorr signature over the canonical receipt minus `signature`. */
|
|
699
965
|
signature: string;
|
|
700
966
|
}
|
|
967
|
+
/** A funding receipt before signing. */
|
|
968
|
+
type UnsignedFundingReceipt = Omit<FundingReceipt, "signature">;
|
|
969
|
+
/**
|
|
970
|
+
* Hash the delivered result so a receipt binds to *what* was returned, not
|
|
971
|
+
* just that something was.
|
|
972
|
+
*
|
|
973
|
+
* `sha256(canonicalize({ summary, artifact_hashes }))`, where each artifact
|
|
974
|
+
* hash is `sha256(canonicalize(artifactContent))` in emission order (`[]`
|
|
975
|
+
* when the job emitted none). Hashing the artifact *content object* rather
|
|
976
|
+
* than trusting `content.sha256` — which is optional and which `ctx.artifact`
|
|
977
|
+
* never fills in — keeps the hash recomputable by any consumer from exactly
|
|
978
|
+
* the messages it received.
|
|
979
|
+
*
|
|
980
|
+
* **Pass `summary` only for a `completed` job.** On `failed`/`cancelled` the
|
|
981
|
+
* SDK's durable terminal writes the terminal *reason* into the job's summary
|
|
982
|
+
* column, so a verifier recomputing a non-completed receipt must pass
|
|
983
|
+
* `undefined` here and read the reason off `receipt.reason` instead. The
|
|
984
|
+
* issuer does the same (`resultHashFor` in `sdk/server/receipt-issuer.ts`).
|
|
985
|
+
*/
|
|
986
|
+
declare function computeResultHash(summary: string | undefined, artifactContents: JsonValue[]): string;
|
|
987
|
+
/**
|
|
988
|
+
* Sign an unsigned receipt with the DVM's receipt secret, returning the
|
|
989
|
+
* complete receipt. Signs `canonicaliseForSigning(receipt)` — the same
|
|
990
|
+
* sorted-key canonical JSON the caller-auth envelope and the builder
|
|
991
|
+
* attestation use, so {@link verifyReceipt} is symmetric with
|
|
992
|
+
* `verifyCanonicalSignedRequest`. There is no second canonicalisation.
|
|
993
|
+
*/
|
|
994
|
+
declare function signReceipt(unsigned: UnsignedJobReceipt, secretHex: string): JobReceipt;
|
|
995
|
+
/**
|
|
996
|
+
* Verify a receipt's self-consistency: the BIP-340 signature over the
|
|
997
|
+
* canonical payload (minus `signature`) under the receipt's own
|
|
998
|
+
* `receipt_pubkey`. Returns `false` rather than throwing on malformed input.
|
|
999
|
+
*
|
|
1000
|
+
* This is only the inner link. A consumer that wants provenance must also
|
|
1001
|
+
* check `receipt_pubkey` against `/v1/info#builder`'s attested
|
|
1002
|
+
* `receipt_pubkey` and verify that attestation under the builder pubkey
|
|
1003
|
+
* (`verifyAttestation` in `builder-identity.ts`).
|
|
1004
|
+
*/
|
|
1005
|
+
declare function verifyReceipt(receipt: JobReceipt): boolean;
|
|
1006
|
+
/**
|
|
1007
|
+
* Structural guard on a receipt that arrived from outside this process — off a
|
|
1008
|
+
* `/v1/job` response, or back out of the hand-editable `~/.dvm/receipts.jsonl`.
|
|
1009
|
+
*
|
|
1010
|
+
* Checks only that the load-bearing fields are the right *kind* of thing; it
|
|
1011
|
+
* deliberately does not judge the receipt. A well-formed receipt whose
|
|
1012
|
+
* signature doesn't hold is `invalid` and the caller must see it said so. A
|
|
1013
|
+
* body missing one of these fields is a different animal: consumers dereference
|
|
1014
|
+
* them unconditionally (`receiptDisplay`'s `paid.msats`, the attestation link's
|
|
1015
|
+
* `receipt_pubkey`), so an unguarded one throws `TypeError` and surfaces as an
|
|
1016
|
+
* `internal` exit — and it could never have verified anyway, since the
|
|
1017
|
+
* signature covers the whole canonical body. Refusing it costs no proof.
|
|
1018
|
+
*
|
|
1019
|
+
* One guard for both directions on purpose: what can't come in over the wire
|
|
1020
|
+
* must not be able to come back out of the file.
|
|
1021
|
+
*
|
|
1022
|
+
* Release coupling: adding or requiring a field here changes both the SDK's
|
|
1023
|
+
* emitted wire shape and the caller CLI's accepted shape. Name the first-party
|
|
1024
|
+
* fleet redeploy as a prerequisite in the release note before publishing the
|
|
1025
|
+
* stricter caller; see `public compatibility guide`.
|
|
1026
|
+
*/
|
|
1027
|
+
declare function isSignedJobReceipt(value: unknown): value is JobReceipt;
|
|
1028
|
+
/** Sign an unsigned drain receipt — same canonicalisation as {@link signReceipt}. */
|
|
1029
|
+
declare function signDrainReceipt(unsigned: UnsignedDrainReceipt, secretHex: string): DrainReceipt;
|
|
1030
|
+
/** Sign an unsigned funding receipt using the common receipt canonicalisation. */
|
|
1031
|
+
declare function signFundingReceipt(unsigned: UnsignedFundingReceipt, secretHex: string): FundingReceipt;
|
|
1032
|
+
/** Structural guard for a funding receipt received over the wire or from disk. */
|
|
1033
|
+
declare function isFundingReceipt(value: unknown): value is FundingReceipt;
|
|
1034
|
+
/** Verify a funding receipt's inner BIP-340 signature. */
|
|
1035
|
+
declare function verifyFundingReceipt(receipt: FundingReceipt): boolean;
|
|
1036
|
+
/**
|
|
1037
|
+
* Structural guard on a drain receipt from outside this process — off a
|
|
1038
|
+
* `/v1/credit` drain response, or back out of `~/.dvm/credits.json`.
|
|
1039
|
+
*
|
|
1040
|
+
* Same contract and same reasoning as {@link isSignedJobReceipt}: both homes
|
|
1041
|
+
* type these `unknown[]` because neither the wire nor a hand-editable file is
|
|
1042
|
+
* evidence of shape, and the chain walk dereferences `receipt_pubkey`
|
|
1043
|
+
* unconditionally. A body missing one of these fields could never have carried
|
|
1044
|
+
* a valid signature anyway, so refusing it costs no proof.
|
|
1045
|
+
* Required-field changes follow the fleet-before-caller release note linked
|
|
1046
|
+
* from {@link isSignedJobReceipt}.
|
|
1047
|
+
*/
|
|
1048
|
+
declare function isDrainReceipt(value: unknown): value is DrainReceipt;
|
|
1049
|
+
/**
|
|
1050
|
+
* Verify a drain receipt's self-consistency, mirroring {@link verifyReceipt}
|
|
1051
|
+
* — the same provenance caveat applies: check `receipt_pubkey` against the
|
|
1052
|
+
* DVM's attested `receipt_pubkey` for the outer link.
|
|
1053
|
+
*/
|
|
1054
|
+
declare function verifyDrainReceipt(receipt: DrainReceipt): boolean;
|
|
701
1055
|
|
|
702
1056
|
/**
|
|
703
1057
|
* Funding lots: the in-kind basis of a non-channel Bitcoin credit (internal-review).
|
|
@@ -734,6 +1088,8 @@ interface FundingReceipt {
|
|
|
734
1088
|
declare const NON_CHANNEL_BITCOIN_RAILS: readonly ["cashu", "lightning"];
|
|
735
1089
|
/** A rail whose unused credit is a sats deposit the provider owes back. */
|
|
736
1090
|
type NonChannelBitcoinRail = (typeof NON_CHANNEL_BITCOIN_RAILS)[number];
|
|
1091
|
+
/** True when `rail` funds a credit with sats the provider holds and owes back. */
|
|
1092
|
+
declare function isNonChannelBitcoinRail(rail: string | null | undefined): rail is NonChannelBitcoinRail;
|
|
737
1093
|
/**
|
|
738
1094
|
* One funding event's deposit: the sats that arrived and the credit micro they
|
|
739
1095
|
* bought, with however much of that micro is still unspent.
|
|
@@ -760,6 +1116,71 @@ interface FundingLot {
|
|
|
760
1116
|
fundingRef: string | null;
|
|
761
1117
|
createdAt: number;
|
|
762
1118
|
}
|
|
1119
|
+
/** One lot's share of a depletion, and what that share is worth in kind. */
|
|
1120
|
+
interface LotDebit {
|
|
1121
|
+
lotId: string;
|
|
1122
|
+
/** Credit micro taken out of this lot. */
|
|
1123
|
+
micro: number;
|
|
1124
|
+
/** Sats that micro is worth at this lot's own funding rate, floored. */
|
|
1125
|
+
sats: number;
|
|
1126
|
+
}
|
|
1127
|
+
/** What a FIFO depletion took, and what it could not cover. */
|
|
1128
|
+
interface LotDepletion {
|
|
1129
|
+
debits: LotDebit[];
|
|
1130
|
+
/** In-kind value of everything taken — the reclaim obligation. */
|
|
1131
|
+
satsOwed: number;
|
|
1132
|
+
/** Micro the lots could not cover. Non-zero means the credit's lots are short. */
|
|
1133
|
+
uncoveredMicro: number;
|
|
1134
|
+
/** Of the micro taken, how much came out of a lot carrying a real sats basis. */
|
|
1135
|
+
backedMicro: number;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Take `amountMicro` out of `lots`, oldest first, and price what was taken at
|
|
1139
|
+
* each lot's own rate.
|
|
1140
|
+
*
|
|
1141
|
+
* FIFO rather than pro rata across the pool, so a top-up taken at a different
|
|
1142
|
+
* rate is reclaimed at *that* rate once the earlier deposit is spent. A
|
|
1143
|
+
* fraction of a satoshi cannot be handed back, so the conversion floors and
|
|
1144
|
+
* the dust stays with the provider rather than being rounded into a payout the
|
|
1145
|
+
* deposit does not cover.
|
|
1146
|
+
*
|
|
1147
|
+
* A slice is priced as the **decrement in the lot's own obligation** —
|
|
1148
|
+
* `lotSats(before) - lotSats(after)` — rather than by flooring the slice on
|
|
1149
|
+
* its own. The two agree whenever a lot is taken whole, which is every
|
|
1150
|
+
* ordinary reclaim; they diverge once a lot is drawn down in pieces, and there
|
|
1151
|
+
* the independent floor loses up to a satoshi *per piece*, permanently. That
|
|
1152
|
+
* matters since internal-review, where each settling draw is priced through here: the
|
|
1153
|
+
* slices have to telescope, or a lot spent over many jobs pays out less than
|
|
1154
|
+
* it took in and the residue is exactly the unattributable one this was meant
|
|
1155
|
+
* to remove. It also makes {@link lotOwedSats} exact rather than conservative
|
|
1156
|
+
* — the remaining obligation is precisely what future depletions will pay.
|
|
1157
|
+
*
|
|
1158
|
+
* `lots` must already be in FIFO order ({@link fifoOrder}).
|
|
1159
|
+
*/
|
|
1160
|
+
declare function depleteLots(lots: FundingLot[], amountMicro: number): LotDepletion;
|
|
1161
|
+
/**
|
|
1162
|
+
* What a settling draw's fiat debit was worth in kind, in millisatoshis
|
|
1163
|
+
* (internal-review) — `null` where the lots cannot price it.
|
|
1164
|
+
*
|
|
1165
|
+
* This is the single sats authority for a non-channel Bitcoin credit. The
|
|
1166
|
+
* settle already depletes the lots the draw consumed, so the figure costs no
|
|
1167
|
+
* extra read: it is `depletion.satsOwed` in the ledger's own msat unit, and
|
|
1168
|
+
* stamping it on `credit_draws.draw_msats` is what makes
|
|
1169
|
+
* `Σ settled draw sats + reclaim sats == Σ sats funded` close per credit.
|
|
1170
|
+
*
|
|
1171
|
+
* `null` follows {@link isInKindDepletion} exactly, so a settle and a reclaim
|
|
1172
|
+
* fall back together: lots short of the balance, or covering lots with no sats
|
|
1173
|
+
* basis, keep the pooled pro-rata figure rather than blending a lot rate with
|
|
1174
|
+
* a blended one. Mixed coverage counts as unpriceable for the same reason it
|
|
1175
|
+
* does on the reclaim.
|
|
1176
|
+
*/
|
|
1177
|
+
declare function inKindDrawMsats(depletion: LotDepletion, amountMicro: number): number | null;
|
|
1178
|
+
/**
|
|
1179
|
+
* What these lots owe in kind if every remaining micro were reclaimed now —
|
|
1180
|
+
* the deposit-liability figure, and the floor the hub must never be swept
|
|
1181
|
+
* below.
|
|
1182
|
+
*/
|
|
1183
|
+
declare function lotOwedSats(lots: FundingLot[]): number;
|
|
763
1184
|
/**
|
|
764
1185
|
* Sats held back from every non-channel Bitcoin reclaim to pay for handing it
|
|
765
1186
|
* over (internal-review).
|
|
@@ -782,7 +1203,502 @@ interface FundingLot {
|
|
|
782
1203
|
* rule the per-lot flooring already follows.
|
|
783
1204
|
*/
|
|
784
1205
|
declare const DRAIN_DELIVERY_RESERVE_SATS = 8;
|
|
1206
|
+
/**
|
|
1207
|
+
* The figure a reclaim publishes: its in-kind gross less
|
|
1208
|
+
* {@link DRAIN_DELIVERY_RESERVE_SATS}, floored at zero.
|
|
1209
|
+
*
|
|
1210
|
+
* Zero is a refusal rather than a payout — a balance worth no more than what
|
|
1211
|
+
* it costs to send is `drain_below_dust`, since parking a zero-value token
|
|
1212
|
+
* would hold the servicer's queue open forever.
|
|
1213
|
+
*/
|
|
1214
|
+
declare function netOwedSats(grossSats: number): number;
|
|
1215
|
+
/**
|
|
1216
|
+
* The order lots deplete in: oldest first, `lotId` breaking a tie.
|
|
1217
|
+
*
|
|
1218
|
+
* A tiebreak is not decoration — lot ids are surrogates rather than a
|
|
1219
|
+
* per-credit sequence (`fund` takes no credit lock, so two concurrent
|
|
1220
|
+
* fundings cannot cooperate on a counter), and two fundings can land on the
|
|
1221
|
+
* same millisecond. Without it the FIFO order is whatever the planner
|
|
1222
|
+
* returned, and a reclaim's figure would depend on it.
|
|
1223
|
+
*/
|
|
1224
|
+
declare function fifoOrder(left: FundingLot, right: FundingLot): number;
|
|
1225
|
+
/**
|
|
1226
|
+
* Whether a depletion may be settled in kind, or has to fall back to pricing
|
|
1227
|
+
* the fiat balance at a live rate.
|
|
1228
|
+
*
|
|
1229
|
+
* Both failure modes are real and neither is the caller's fault: a credit's
|
|
1230
|
+
* lots can be short (a coverage hole the boot backfill is meant to close), and
|
|
1231
|
+
* a credit funded before internal-review recorded a rail basis at all has lots whose
|
|
1232
|
+
* `satsFunded` is 0 — pricing *that* in kind would answer "we owe you nothing"
|
|
1233
|
+
* for a deposit we plainly hold. Mixed coverage is treated as unbacked too:
|
|
1234
|
+
* blending a lot rate with a live rate produces a figure neither basis
|
|
1235
|
+
* supports.
|
|
1236
|
+
*/
|
|
1237
|
+
declare function isInKindDepletion(depletion: LotDepletion, amountMicro: number): boolean;
|
|
1238
|
+
|
|
1239
|
+
/** The rails a payout lands on. Lightning never pays out: credits fund straight into the receive wallet. */
|
|
1240
|
+
type PayoutRail = "cashu" | "x402" | "tempo";
|
|
1241
|
+
/**
|
|
1242
|
+
* What gathered the payments into one transfer: a cashu accumulator melt, an
|
|
1243
|
+
* x402 batch settle to `pay_to`, a Tempo channel's cooperative close, or a
|
|
1244
|
+
* Tempo channel's scheduled / manual settlement to the recipient.
|
|
1245
|
+
*/
|
|
1246
|
+
type PayoutKind = "melt" | "batch" | "close" | "settle";
|
|
1247
|
+
/** Which repair verb completed a stuck movement. Only `tempo_close_reconciled` is produced here today. */
|
|
1248
|
+
type PayoutRepairKind = "x402_settlement_reconciled" | "lightning_invoice_reconciled" | "tempo_close_reconciled";
|
|
1249
|
+
/**
|
|
1250
|
+
* JSON wire shape POSTed to the platform's `/_internal/payout` endpoint —
|
|
1251
|
+
* one landed movement into the builder's custody. Idempotent platform-side
|
|
1252
|
+
* on `(dvmId, payoutId)`, so the durable retry loop can redeliver freely; a
|
|
1253
|
+
* `repaired` redelivery of an id that already landed upgrades that row rather
|
|
1254
|
+
* than adding a second.
|
|
1255
|
+
*/
|
|
1256
|
+
interface PayoutReportPayload {
|
|
1257
|
+
/** Required. Platform DVM record ID (`dvms.id`); must match the bearer token's DVM. */
|
|
1258
|
+
dvmId: string;
|
|
1259
|
+
/** Required. The DVM's own id for the movement — `cashu:melt:<quote>`, `x402:batch:<uuid>`, `tempo:<tx>`. */
|
|
1260
|
+
payoutId: string;
|
|
1261
|
+
rail: PayoutRail;
|
|
1262
|
+
kind: PayoutKind;
|
|
1263
|
+
/** Required. Rail-native atomic units: sats, or USDC micro. Always > 0. */
|
|
1264
|
+
nativeAmount: number;
|
|
1265
|
+
/** Required. `sats` for cashu, `usdc` for the stablecoin rails. */
|
|
1266
|
+
nativeAsset: "sats" | "usdc";
|
|
1267
|
+
/** Where it landed; `null` for a melt, whose Lightning destination the platform never records. */
|
|
1268
|
+
recipient: string | null;
|
|
1269
|
+
/** Mechanism references — mint, melt quote, tx hash, batch id, voucher count, channel id. Description material, never arithmetic. */
|
|
1270
|
+
refs: Record<string, unknown>;
|
|
1271
|
+
/** Required. When the money landed (epoch ms). */
|
|
1272
|
+
landedAt: number;
|
|
1273
|
+
/** Set when a repair verb completed this movement. */
|
|
1274
|
+
repaired?: boolean;
|
|
1275
|
+
/** Required iff `repaired`. */
|
|
1276
|
+
repairKind?: PayoutRepairKind;
|
|
1277
|
+
}
|
|
1278
|
+
/** A stuck movement inside a pending snapshot. */
|
|
1279
|
+
interface PayoutWedge {
|
|
1280
|
+
id: string;
|
|
1281
|
+
/**
|
|
1282
|
+
* `settle`: an x402 batch whose transfer keeps failing (auto-retried).
|
|
1283
|
+
* `refund`: an x402 cooperative refund wedged between chain and ledger —
|
|
1284
|
+
* caller money, not in the pool. `close`: a Tempo close wedged the same way.
|
|
1285
|
+
* `melt`: cashu rows whose builder-side melt failed.
|
|
1286
|
+
*/
|
|
1287
|
+
kind: "settle" | "refund" | "close" | "melt";
|
|
1288
|
+
/** Epoch ms the wedge was first observed. */
|
|
1289
|
+
since: number;
|
|
1290
|
+
/** Retry count where the retry is automatic, else null. */
|
|
1291
|
+
attempts: number | null;
|
|
1292
|
+
/** Epoch ms of the next automatic retry, else null. */
|
|
1293
|
+
nextRetry: number | null;
|
|
1294
|
+
lastError: string | null;
|
|
1295
|
+
/** Rail-native amount held up, when known. */
|
|
1296
|
+
native?: number;
|
|
1297
|
+
}
|
|
1298
|
+
/** One pool inside a rail's pending figure — a mint, a batch, a channel. */
|
|
1299
|
+
interface PayoutPool {
|
|
1300
|
+
id: string;
|
|
1301
|
+
native: number;
|
|
1302
|
+
label?: string;
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* JSON wire shape POSTed to the platform's `/_internal/payout-pending`
|
|
1306
|
+
* endpoint — one rail's snapshot of money still moving toward the builder,
|
|
1307
|
+
* replaced on each report. Best-effort: a lost one is superseded by the next
|
|
1308
|
+
* tick, so it rides no durable queue.
|
|
1309
|
+
*/
|
|
1310
|
+
interface PayoutPendingPayload {
|
|
1311
|
+
dvmId: string;
|
|
1312
|
+
rail: PayoutRail;
|
|
1313
|
+
/** Everything on this rail still moving toward the builder, in atomic units. */
|
|
1314
|
+
poolNative: number;
|
|
1315
|
+
nativeAsset: "sats" | "usdc";
|
|
1316
|
+
/** How many pools the figure is made of. */
|
|
1317
|
+
items: number;
|
|
1318
|
+
pools: PayoutPool[];
|
|
1319
|
+
wedged: PayoutWedge[];
|
|
1320
|
+
/** This DVM's clock when the snapshot was taken (epoch ms). */
|
|
1321
|
+
snapshotAt: number;
|
|
1322
|
+
}
|
|
1323
|
+
/** The delivery seam — implemented by `RevenueReporter`, stubbed in tests. */
|
|
1324
|
+
interface PayoutTransport {
|
|
1325
|
+
/**
|
|
1326
|
+
* Queue a payout through the caller's open transaction, so the row and the
|
|
1327
|
+
* fact it reports commit or roll back together; without `tx` it is queued on
|
|
1328
|
+
* its own. Durable once committed — the retry loop delivers it, or
|
|
1329
|
+
* {@link PayoutTransport.drainPending} when a caller wants it now.
|
|
1330
|
+
*/
|
|
1331
|
+
enqueuePayout(payload: PayoutReportPayload, tx?: RevenueReporterQuerier): Promise<void>;
|
|
1332
|
+
/** Queue a payout on its own and try to deliver it at once. */
|
|
1333
|
+
reportPayout(payload: PayoutReportPayload): Promise<void>;
|
|
1334
|
+
/** Best-effort: one POST, replaced by the next snapshot. */
|
|
1335
|
+
reportPayoutPending(payload: PayoutPendingPayload): Promise<void>;
|
|
1336
|
+
/** Deliver what is queued now rather than on the next retry tick. */
|
|
1337
|
+
drainPending?(): Promise<void>;
|
|
1338
|
+
}
|
|
1339
|
+
/**
|
|
1340
|
+
* A money-path hook whose report must commit with the fact it describes.
|
|
1341
|
+
* `enqueue` runs inside the caller's transaction, and a throw rolls the fact
|
|
1342
|
+
* back with it — the drain report's own discipline (internal-review): a call the
|
|
1343
|
+
* caller has to repeat costs a round trip, where a landed movement with no
|
|
1344
|
+
* row understates paid-out forever. `committed` runs once that transaction
|
|
1345
|
+
* has committed, for the delivery and the snapshot that must not read
|
|
1346
|
+
* uncommitted state.
|
|
1347
|
+
*/
|
|
1348
|
+
interface TransactionalPayoutHook<E> {
|
|
1349
|
+
enqueue(event: E, tx: RevenueReporterQuerier): Promise<void>;
|
|
1350
|
+
committed(): void;
|
|
1351
|
+
}
|
|
1352
|
+
/** What `/admin/cashu/mark-melted` knows once the rows are marked. */
|
|
1353
|
+
interface CashuMeltCompleted {
|
|
1354
|
+
rows: {
|
|
1355
|
+
id: string;
|
|
1356
|
+
mintUrl: string;
|
|
1357
|
+
proofAmount: number;
|
|
1358
|
+
}[];
|
|
1359
|
+
meltQuoteId: string;
|
|
1360
|
+
paymentPreimage: string;
|
|
1361
|
+
}
|
|
1362
|
+
/** What mppx reports after a Tempo channel settlement or close confirmed on chain. */
|
|
1363
|
+
interface TempoSessionSettled {
|
|
1364
|
+
txHash: string;
|
|
1365
|
+
channelId: string;
|
|
1366
|
+
trigger: "settle" | "close" | "scheduled";
|
|
1367
|
+
/** Cumulative amount settled to the payee on this channel, atomic units. */
|
|
1368
|
+
amount: bigint;
|
|
1369
|
+
/** Newly settled to the payee by this transaction, atomic units. */
|
|
1370
|
+
delta: bigint;
|
|
1371
|
+
}
|
|
1372
|
+
/** What `reconcile-tempo-drain` re-read from the close receipt it booked against. */
|
|
1373
|
+
interface TempoCloseReconciled {
|
|
1374
|
+
channelId: string;
|
|
1375
|
+
txHash: string;
|
|
1376
|
+
/** Captured by the payee — this DVM — per the receipt, atomic units as a decimal string. */
|
|
1377
|
+
settledToPayee: string;
|
|
1378
|
+
}
|
|
1379
|
+
/** The channel view the tracker sums claims over. */
|
|
1380
|
+
interface X402TrackedChannel {
|
|
1381
|
+
channelId: string;
|
|
1382
|
+
chargedCumulativeAmount: string;
|
|
1383
|
+
totalClaimed: string;
|
|
1384
|
+
}
|
|
1385
|
+
/** A refund settlement wedged between chain and ledger (internal-review), for the wedge list. */
|
|
1386
|
+
interface X402WedgedRefund {
|
|
1387
|
+
settlementId: string;
|
|
1388
|
+
/** Epoch ms the settlement was first prepared. */
|
|
1389
|
+
createdAt: number;
|
|
1390
|
+
native?: number;
|
|
1391
|
+
}
|
|
1392
|
+
/** What the batch-settlement server hands the tracker once it knows its scope. */
|
|
1393
|
+
interface X402PayoutContext {
|
|
1394
|
+
/** `${network}|${payTo}|${token}` — the scope the settle-pending marker is keyed on. */
|
|
1395
|
+
scope: string;
|
|
1396
|
+
payTo: string;
|
|
1397
|
+
network: string;
|
|
1398
|
+
storage: {
|
|
1399
|
+
list(): Promise<X402TrackedChannel[]>;
|
|
1400
|
+
};
|
|
1401
|
+
/** The scheduler's settle cadence — what a wedge's `nextRetry` is derived from. */
|
|
1402
|
+
settleIntervalMs: number;
|
|
1403
|
+
listWedgedRefunds?: () => Promise<X402WedgedRefund[]>;
|
|
1404
|
+
}
|
|
1405
|
+
/** The two manager verbs the tracker wraps. */
|
|
1406
|
+
interface X402TrackedManager {
|
|
1407
|
+
claim(...args: never[]): Promise<{
|
|
1408
|
+
vouchers: number;
|
|
1409
|
+
transaction: string;
|
|
1410
|
+
}[]>;
|
|
1411
|
+
settle(): Promise<{
|
|
1412
|
+
transaction: string;
|
|
1413
|
+
}>;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* The batch-settlement server's view of the reporter: attach once with the
|
|
1417
|
+
* scope, then route every claim and settle through the tracked manager so
|
|
1418
|
+
* the open batch is kept and the settle emits the payout.
|
|
1419
|
+
*/
|
|
1420
|
+
interface X402PayoutObserver {
|
|
1421
|
+
attach(ctx: X402PayoutContext): void;
|
|
1422
|
+
trackManager<M extends X402TrackedManager>(manager: M): M;
|
|
1423
|
+
/** A settle that landed outside the tracked manager — the manual claim-and-settle's own retry loop. */
|
|
1424
|
+
recordSettle(transaction: string): Promise<void>;
|
|
1425
|
+
/** A settle attempt that failed outside the tracked manager. One call per attempt a builder would count as one. */
|
|
1426
|
+
recordSettleFailure(error: unknown): Promise<void>;
|
|
1427
|
+
}
|
|
1428
|
+
/** The Tempo readers the host attaches after mounting. */
|
|
1429
|
+
interface TempoPayoutReader {
|
|
1430
|
+
/** The recipient address every Tempo payout names. */
|
|
1431
|
+
recipient?: string;
|
|
1432
|
+
/** CAIP-2 network for the refs, when known. */
|
|
1433
|
+
network?: string;
|
|
1434
|
+
listActive?: (limit: number, cursor?: {
|
|
1435
|
+
updatedAt: number;
|
|
1436
|
+
key: string;
|
|
1437
|
+
}) => Promise<{
|
|
1438
|
+
key: string;
|
|
1439
|
+
state: Record<string, unknown>;
|
|
1440
|
+
updatedAt: number;
|
|
1441
|
+
}[]>;
|
|
1442
|
+
listChannelDrains?: (args: {
|
|
1443
|
+
limit: number;
|
|
1444
|
+
after?: ChannelDrainCursor;
|
|
1445
|
+
createdBeforeMs: number;
|
|
1446
|
+
rail: "tempo";
|
|
1447
|
+
}) => Promise<CreditDrainRecord[]>;
|
|
1448
|
+
}
|
|
1449
|
+
/**
|
|
1450
|
+
* The claims gathered since the last settle — the batch the next settle pays
|
|
1451
|
+
* out. Durable across machines because claims run under the fleet lock on
|
|
1452
|
+
* whichever machine won the tick, and the settle that finally moves the money
|
|
1453
|
+
* may run on another: an in-process figure would report a partial amount
|
|
1454
|
+
* after any restart in between.
|
|
1455
|
+
*/
|
|
1456
|
+
interface X402OpenBatch {
|
|
1457
|
+
scope: string;
|
|
1458
|
+
batchId: string;
|
|
1459
|
+
claimedNative: bigint;
|
|
1460
|
+
voucherCount: number;
|
|
1461
|
+
claims: number;
|
|
1462
|
+
openedAt: number;
|
|
1463
|
+
attempts: number;
|
|
1464
|
+
firstFailedAt: number | null;
|
|
1465
|
+
lastError: string | null;
|
|
1466
|
+
nextRetryAt: number | null;
|
|
1467
|
+
}
|
|
1468
|
+
/** Where the open batch lives — Postgres beside the settlement rows, or memory in dev. */
|
|
1469
|
+
interface X402BatchStore {
|
|
1470
|
+
get(scope: string): Promise<X402OpenBatch | undefined>;
|
|
1471
|
+
put(batch: X402OpenBatch): Promise<void>;
|
|
1472
|
+
delete(scope: string): Promise<void>;
|
|
1473
|
+
/**
|
|
1474
|
+
* Close the open batch and run `enqueue` in the same transaction, so the
|
|
1475
|
+
* payout row is queued exactly when the batch is gone and never otherwise:
|
|
1476
|
+
* a settle can never lose its payout, because a failed enqueue leaves the
|
|
1477
|
+
* batch open for the next settle to report in full. `false` when the batch
|
|
1478
|
+
* under `scope` is no longer `batchId` — a sibling settled it first — in
|
|
1479
|
+
* which case nothing is queued.
|
|
1480
|
+
*/
|
|
1481
|
+
settle(scope: string, batchId: string, enqueue: (tx?: RevenueReporterQuerier) => Promise<void>): Promise<boolean>;
|
|
1482
|
+
}
|
|
1483
|
+
/** Construction options for {@link PayoutReporter}. */
|
|
1484
|
+
interface PayoutReporterOpts {
|
|
1485
|
+
/** Platform DVM record ID, bound into every report. */
|
|
1486
|
+
dvmId: string;
|
|
1487
|
+
transport: PayoutTransport;
|
|
1488
|
+
/**
|
|
1489
|
+
* The SDK's Postgres. Reads the cashu accumulator for the pending pool and
|
|
1490
|
+
* holds the open x402 batch; without it the batch lives in memory (dev) and
|
|
1491
|
+
* no cashu snapshot is taken.
|
|
1492
|
+
*/
|
|
1493
|
+
db?: Pool;
|
|
1494
|
+
/**
|
|
1495
|
+
* Whether this DVM runs the cashu accumulator. The cashu snapshot reads
|
|
1496
|
+
* `wallet_accumulator`, which only that mode creates — on any other DVM the
|
|
1497
|
+
* read would fail every tick and warn about a rail it does not carry.
|
|
1498
|
+
*/
|
|
1499
|
+
cashu?: boolean;
|
|
1500
|
+
/** Override the batch store (tests); defaults to Postgres on `db`, memory without. */
|
|
1501
|
+
batchStore?: X402BatchStore;
|
|
1502
|
+
/** Snapshot cadence, ms. Default 5 minutes. */
|
|
1503
|
+
snapshotIntervalMs?: number;
|
|
1504
|
+
/** Override for the current time (tests). */
|
|
1505
|
+
now?: () => number;
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Builds the payout and pending reports from the SDK's money paths and hands
|
|
1509
|
+
* them to the transport.
|
|
1510
|
+
*
|
|
1511
|
+
* Two entry points are transactional: `cashuMelted` and `tempoCloseReconciled`
|
|
1512
|
+
* queue their row inside the caller's transaction and throw when they cannot,
|
|
1513
|
+
* so the melt or the reconciled close rolls back with its missing report rather
|
|
1514
|
+
* than landing without one. The x402 settle and the pending snapshots are
|
|
1515
|
+
* fail-safe instead: a report that cannot be built or queued there is logged and
|
|
1516
|
+
* picked up on the next tick, never thrown into the settle that produced it.
|
|
1517
|
+
*/
|
|
1518
|
+
declare class PayoutReporter implements PayoutTransport {
|
|
1519
|
+
private readonly dvmId;
|
|
1520
|
+
private readonly transport;
|
|
1521
|
+
private readonly db?;
|
|
1522
|
+
private readonly cashu;
|
|
1523
|
+
private readonly batches;
|
|
1524
|
+
private readonly ownsBatchStore;
|
|
1525
|
+
private readonly intervalMs;
|
|
1526
|
+
private readonly now;
|
|
1527
|
+
private x402?;
|
|
1528
|
+
private tempo?;
|
|
1529
|
+
private timer;
|
|
1530
|
+
private warmup;
|
|
1531
|
+
constructor(opts: PayoutReporterOpts);
|
|
1532
|
+
/** Boot DDL for the durable batch store, when this reporter owns one. */
|
|
1533
|
+
init(): Promise<void>;
|
|
1534
|
+
/**
|
|
1535
|
+
* Start the snapshot loop. Unref'd, so it never keeps a scale-to-zero
|
|
1536
|
+
* machine awake; a first snapshot runs shortly after boot so a fresh process
|
|
1537
|
+
* reports without waiting a whole interval.
|
|
1538
|
+
*/
|
|
1539
|
+
start(): void;
|
|
1540
|
+
stop(): void;
|
|
1541
|
+
enqueuePayout(payload: PayoutReportPayload, tx?: RevenueReporterQuerier): Promise<void>;
|
|
1542
|
+
reportPayout(payload: PayoutReportPayload): Promise<void>;
|
|
1543
|
+
reportPayoutPending(payload: PayoutPendingPayload): Promise<void>;
|
|
1544
|
+
/** Deliver what is queued now; a transport without the seam waits for its retry loop. */
|
|
1545
|
+
flush(): Promise<void>;
|
|
1546
|
+
/** The hook `mark-melted` runs inside its transaction: the mark and its payout commit together. */
|
|
1547
|
+
meltHook(): TransactionalPayoutHook<CashuMeltCompleted>;
|
|
1548
|
+
/**
|
|
1549
|
+
* A melt completed: the accumulator rows are SPENT at the mint and the
|
|
1550
|
+
* Lightning payment reached the builder's destination. One payout per mint
|
|
1551
|
+
* in the call — a `mark-melted` normally names one, since a melt quote
|
|
1552
|
+
* belongs to one mint. The amount is the face value melted; the mint's fee
|
|
1553
|
+
* and the Lightning amount received are builder-machine facts this DVM does
|
|
1554
|
+
* not see.
|
|
1555
|
+
*
|
|
1556
|
+
* Queued through `tx` when the caller is inside the transaction that marks
|
|
1557
|
+
* the rows, and a failure is thrown rather than swallowed so that mark rolls
|
|
1558
|
+
* back with it — see {@link TransactionalPayoutHook}. Without `tx` the rows
|
|
1559
|
+
* are queued on their own and delivered at once.
|
|
1560
|
+
*/
|
|
1561
|
+
cashuMelted(event: CashuMeltCompleted, tx?: RevenueReporterQuerier): Promise<void>;
|
|
1562
|
+
/** The host attaches the session store and ledger readers once they exist. */
|
|
1563
|
+
attachTempo(reader: TempoPayoutReader): void;
|
|
1564
|
+
/**
|
|
1565
|
+
* A Tempo channel settled or closed on chain. `delta` is what this
|
|
1566
|
+
* transaction newly paid the recipient; a transaction that paid nothing new
|
|
1567
|
+
* (a close of a fully settled channel) is no payout.
|
|
1568
|
+
*/
|
|
1569
|
+
tempoSettled(event: TempoSessionSettled): Promise<void>;
|
|
1570
|
+
/** The hook `reconcile-tempo-drain` runs inside its transaction: the booking and its payout commit together. */
|
|
1571
|
+
tempoRepairHook(): TransactionalPayoutHook<TempoCloseReconciled>;
|
|
1572
|
+
/**
|
|
1573
|
+
* The operator repaired a wedged cooperative close (internal-review). The close's
|
|
1574
|
+
* payee side landed on chain when the close did; if the live hook reported
|
|
1575
|
+
* it, this upgrades that row to `repair`, otherwise it is the row. The
|
|
1576
|
+
* figure is the receipt's payee total for the channel.
|
|
1577
|
+
*
|
|
1578
|
+
* Queued through `tx` when the caller is inside the transaction that books
|
|
1579
|
+
* the drain, and thrown rather than swallowed so that booking rolls back
|
|
1580
|
+
* with it — see {@link TransactionalPayoutHook}.
|
|
1581
|
+
*/
|
|
1582
|
+
tempoCloseReconciled(event: TempoCloseReconciled, tx?: RevenueReporterQuerier): Promise<void>;
|
|
1583
|
+
/** The observer the batch-settlement server attaches to and routes its manager through. */
|
|
1584
|
+
x402Observer(): X402PayoutObserver;
|
|
1585
|
+
/**
|
|
1586
|
+
* Wrap the upstream channel manager so every claim grows the open batch and
|
|
1587
|
+
* every settle closes it. The claim delta is read off storage rather than
|
|
1588
|
+
* off upstream's result, which carries only a voucher count; under the
|
|
1589
|
+
* fleet lock the before/after read is consistent. A channel the claim
|
|
1590
|
+
* removed on its way through — a refund's claim-then-delete (internal-review) —
|
|
1591
|
+
* moved whatever it still owed before it went, and that value reaches
|
|
1592
|
+
* `pay_to` in this batch too, so it counts at its pre-claim figure.
|
|
1593
|
+
*/
|
|
1594
|
+
private trackX402Manager;
|
|
1595
|
+
private recordX402Claim;
|
|
1596
|
+
private recordX402Settle;
|
|
1597
|
+
private recordX402SettleFailure;
|
|
1598
|
+
/** Every rail this reporter can read, each on its own failure boundary. */
|
|
1599
|
+
snapshot(): Promise<void>;
|
|
1600
|
+
/**
|
|
1601
|
+
* Cashu: every unmelted proof in the accumulator, per mint. Rows whose
|
|
1602
|
+
* builder-side melt failed are still in the pool (they are still at the
|
|
1603
|
+
* mint) and listed as wedged until `restart-failed` clears them.
|
|
1604
|
+
*/
|
|
1605
|
+
snapshotCashu(): Promise<void>;
|
|
1606
|
+
/**
|
|
1607
|
+
* x402: the open batch (claimed, not yet transferred) plus every channel's
|
|
1608
|
+
* unclaimed voucher value; wedged when the settle keeps failing, and the
|
|
1609
|
+
* refund settlements stuck between chain and ledger beside it.
|
|
1610
|
+
*/
|
|
1611
|
+
snapshotX402(): Promise<void>;
|
|
1612
|
+
/**
|
|
1613
|
+
* Tempo: each active channel's spent-but-unsettled balance — earned, not
|
|
1614
|
+
* yet paid to the recipient — and the cooperative closes wedged between
|
|
1615
|
+
* chain and ledger (internal-review), aged past the same floor the repair queue
|
|
1616
|
+
* uses so an in-flight close is not reported as stuck.
|
|
1617
|
+
*/
|
|
1618
|
+
snapshotTempo(): Promise<void>;
|
|
1619
|
+
}
|
|
785
1620
|
|
|
1621
|
+
/**
|
|
1622
|
+
* JSON wire shape POSTed to the platform's `/_internal/job-revenue` endpoint
|
|
1623
|
+
* and stored in `pending_revenue_reports.payload` for durable retry.
|
|
1624
|
+
*
|
|
1625
|
+
* The platform-side consumer is `OnJobCompleted`, implemented by
|
|
1626
|
+
* `createRevenueCallback`. Keep the two shapes in sync: the SDK and platform
|
|
1627
|
+
* deploy in lockstep, and any
|
|
1628
|
+
* backwards-incompatible field change requires a coordinated release. No `version`
|
|
1629
|
+
* field is included pre-launch because there are no external container-runtime
|
|
1630
|
+
* consumers yet; add one once the first third-party builder ships a container-runtime
|
|
1631
|
+
* DVM (trigger condition: external builder onboarded via `dvmctl deploy --container`).
|
|
1632
|
+
*/
|
|
1633
|
+
interface RevenueReportPayload {
|
|
1634
|
+
/** Required. Platform DVM record ID (`dvms.id`). Identifies which DVM earned the revenue. */
|
|
1635
|
+
dvmId: string;
|
|
1636
|
+
/** Required. Job identifier used by the platform to de-duplicate revenue rows and link to the job record. */
|
|
1637
|
+
jobId: string;
|
|
1638
|
+
/** Required. Total amount paid by the caller in millisatoshis, across all credits that satisfied the job. */
|
|
1639
|
+
paidMsats: number;
|
|
1640
|
+
/** Optional. Cashu mint URL from which the payment tokens were issued. Set only for the `cashu` rail; omitted for all other rails. */
|
|
1641
|
+
paymentMint?: string;
|
|
1642
|
+
/**
|
|
1643
|
+
* Required. Payment rail identifier (`"cashu"`, `"tempo"`, `"x402"`, `"stripe"`).
|
|
1644
|
+
* Mirrors `PaymentMethod` on the platform; carried as a plain string over the wire
|
|
1645
|
+
* so the SDK has no platform-type dependency.
|
|
1646
|
+
*/
|
|
1647
|
+
rail: string;
|
|
1648
|
+
/**
|
|
1649
|
+
* Optional. Settlement reference for the credit: EVM tx hash for `x402`, credential
|
|
1650
|
+
* challenge ID for `tempo`, `X-Cashu-Request-Id` UUID for `cashu`. Required by the
|
|
1651
|
+
* platform revenue ledger for `tempo`/`x402` rails (recordJobRevenue throws without it);
|
|
1652
|
+
* nullable for `cashu`.
|
|
1653
|
+
*/
|
|
1654
|
+
paymentTxHash?: string;
|
|
1655
|
+
/**
|
|
1656
|
+
* Optional. Rail-native payment amount in atomic units: satoshis for `tempo`, USDC
|
|
1657
|
+
* microunits for `x402`, USD cents for `stripe`. Omitted for `cashu` (platform derives
|
|
1658
|
+
* `paidMsats / 1000`). Must be set together with `nativeAsset`.
|
|
1659
|
+
*/
|
|
1660
|
+
nativeAmount?: number;
|
|
1661
|
+
/**
|
|
1662
|
+
* Optional. Asset tag paired with `nativeAmount`: `"sats"`, `"usdc"`, `"usdc.e"`, or
|
|
1663
|
+
* `"usd-cents"`. Both fields must be present for the platform to write a non-cashu
|
|
1664
|
+
* revenue row.
|
|
1665
|
+
*/
|
|
1666
|
+
nativeAsset?: string;
|
|
1667
|
+
/**
|
|
1668
|
+
* Optional. Cashu flow discriminator. Set to `"p2pk_accumulator"` when the cashu
|
|
1669
|
+
* accumulator path (internal-review) satisfied the job; omitted for legacy cashu. Written into
|
|
1670
|
+
* `revenue_events.metadata.cashu_flow` by the platform so ops can split per-call cashu
|
|
1671
|
+
* rows by source.
|
|
1672
|
+
*/
|
|
1673
|
+
cashuFlow?: string;
|
|
1674
|
+
/**
|
|
1675
|
+
* Optional. Credit this job's payment drew against (internal-review). Present on
|
|
1676
|
+
* every job a ledger-backed payment satisfied; its presence is what tells
|
|
1677
|
+
* the platform the row is a **draw-keyed** revenue event rather than a
|
|
1678
|
+
* pre-credits per-call one.
|
|
1679
|
+
*/
|
|
1680
|
+
creditId?: string;
|
|
1681
|
+
/** Optional. The draw this job settled — one draw, one revenue row. */
|
|
1682
|
+
drawId?: string;
|
|
1683
|
+
/** Optional. The draw's fiat amount, 1e-6 of `creditCurrency`. The exact liability offset. */
|
|
1684
|
+
drawAmountMicro?: number;
|
|
1685
|
+
/** Optional. Currency the credit is denominated in (lowercase ISO, e.g. `usd`). */
|
|
1686
|
+
creditCurrency?: string;
|
|
1687
|
+
/**
|
|
1688
|
+
* Optional. Settlement instant (epoch ms) — draws are revenue *when they
|
|
1689
|
+
* settle*, so this dates the row. Omitted for pre-credits rows, which the
|
|
1690
|
+
* platform dates at record time as before.
|
|
1691
|
+
*/
|
|
1692
|
+
settledAt?: number;
|
|
1693
|
+
/** Optional. The funding's own rail reference, for reconciling a draw back to its deposit. */
|
|
1694
|
+
fundingRef?: string;
|
|
1695
|
+
/**
|
|
1696
|
+
* Optional. Revenue class when this row is not ordinary service revenue.
|
|
1697
|
+
* `short_pay_forfeit` marks money kept from an underpayment that bought no
|
|
1698
|
+
* job (internal-review operator ruling) so analytics can exclude it.
|
|
1699
|
+
*/
|
|
1700
|
+
kind?: string;
|
|
1701
|
+
}
|
|
786
1702
|
/**
|
|
787
1703
|
* JSON wire shape POSTed to the platform's `/_internal/credit-deposit`
|
|
788
1704
|
* endpoint (internal-review). A funding event is a **deposit** — a liability until
|
|
@@ -1015,6 +1931,36 @@ interface CreditExpiryReleasePayload {
|
|
|
1015
1931
|
* between the two overstates or understates committed value forever.
|
|
1016
1932
|
*/
|
|
1017
1933
|
type CreditExpiryReleaseEnqueue = (tx: RevenueReporterQuerier, payload: CreditExpiryReleasePayload) => Promise<void>;
|
|
1934
|
+
/**
|
|
1935
|
+
* JSON wire shape POSTed to the platform's `/_internal/paid-job-death` endpoint
|
|
1936
|
+
* (internal-review) when the stale-job reaper force-fails a *paid* job — its pending
|
|
1937
|
+
* credit draw is released rather than settled, so the caller's payment is back
|
|
1938
|
+
* on their credit balance and reclaimable by drain. The platform resolves fiat
|
|
1939
|
+
* + owner and sends an ambient notice via the shared alert sink. Unlike
|
|
1940
|
+
* {@link RevenueReportPayload} this carries no durable-retry semantics: the
|
|
1941
|
+
* reaper's `stale_job_failed` structured log is the durable backstop, so a lost
|
|
1942
|
+
* report degrades to log-only rather than blocking the sweep.
|
|
1943
|
+
*/
|
|
1944
|
+
interface PaidJobDeathPayload {
|
|
1945
|
+
/** Required. Platform DVM record ID (`dvms.id`). Bound to the authenticating token. */
|
|
1946
|
+
dvmId: string;
|
|
1947
|
+
/** Required. Job identifier the reaper force-failed. */
|
|
1948
|
+
jobId: string;
|
|
1949
|
+
/** Required. Capability the job dispatched to (e.g. `"add-episode"`). */
|
|
1950
|
+
capability: string;
|
|
1951
|
+
/** Required. Amount of the released credit draw in millisatoshis. */
|
|
1952
|
+
paidMsats: number;
|
|
1953
|
+
/** Required. Payment rail of the credit draw (`"cashu"` / `"tempo"` / `"x402"`). */
|
|
1954
|
+
rail: string;
|
|
1955
|
+
/** Required. Terminal reason the reaper set: dead worker vs never-terminal idle. */
|
|
1956
|
+
reason: string;
|
|
1957
|
+
/** Optional. Rail-native released amount, paired with `nativeAsset`. */
|
|
1958
|
+
nativeAmount?: number;
|
|
1959
|
+
/** Optional. Asset tag for `nativeAmount` (`"sats"` / `"usdc"` / …). */
|
|
1960
|
+
nativeAsset?: string;
|
|
1961
|
+
/** Optional. Cashu mint URL the credit draw's tokens were issued from. */
|
|
1962
|
+
paymentMint?: string;
|
|
1963
|
+
}
|
|
1018
1964
|
/** Distinct causes for a settled credit draw that could not book revenue. */
|
|
1019
1965
|
type RevenueSkippedNoRailReason = "credit_rail_null" | "credit_rail_unrecognized" | "job_rail_missing" | "ledger_not_configured";
|
|
1020
1966
|
/**
|
|
@@ -1044,6 +1990,210 @@ interface RevenueSkippedNoRailPayload {
|
|
|
1044
1990
|
/** Required classification of why the revenue rail was unavailable. */
|
|
1045
1991
|
reason: RevenueSkippedNoRailReason;
|
|
1046
1992
|
}
|
|
1993
|
+
/** Gas-balance observation POSTed by a platform-hosted x402 self-relay. */
|
|
1994
|
+
interface X402SelfRelayGasBalancePayload {
|
|
1995
|
+
/** Platform DVM record ID, bound to the authenticating platform token. */
|
|
1996
|
+
dvmId: string;
|
|
1997
|
+
/** Dedicated relay EOA whose Base ETH balance was read. */
|
|
1998
|
+
address: `0x${string}`;
|
|
1999
|
+
/** CAIP-2 Base network identifier. */
|
|
2000
|
+
network: string;
|
|
2001
|
+
/** Current native balance as a decimal wei string. */
|
|
2002
|
+
balanceWei: string;
|
|
2003
|
+
/** Configured paging floor as a decimal wei string. */
|
|
2004
|
+
lowBalanceWei: string;
|
|
2005
|
+
/** Millisecond timestamp at which the DVM read the balance. */
|
|
2006
|
+
checkedAt: number;
|
|
2007
|
+
}
|
|
2008
|
+
/** RPC-health transition POSTed by a platform-hosted x402 self-relay. */
|
|
2009
|
+
type X402SelfRelayRpcHealthPayload = {
|
|
2010
|
+
/** Platform DVM record ID, bound to the authenticating platform token. */
|
|
2011
|
+
dvmId: string;
|
|
2012
|
+
/** Dedicated relay EOA identifying the affected self-relay. */
|
|
2013
|
+
address: `0x${string}`;
|
|
2014
|
+
/** CAIP-2 Base network identifier. */
|
|
2015
|
+
network: string;
|
|
2016
|
+
/** Healthy transition clears an open RPC page. */
|
|
2017
|
+
status: "healthy";
|
|
2018
|
+
/** Millisecond timestamp at which the DVM observed the transition. */
|
|
2019
|
+
checkedAt: number;
|
|
2020
|
+
} | {
|
|
2021
|
+
/** Platform DVM record ID, bound to the authenticating platform token. */
|
|
2022
|
+
dvmId: string;
|
|
2023
|
+
/** Dedicated relay EOA identifying the affected self-relay. */
|
|
2024
|
+
address: `0x${string}`;
|
|
2025
|
+
/** CAIP-2 Base network identifier. */
|
|
2026
|
+
network: string;
|
|
2027
|
+
/** Failed transition opens or refreshes an RPC page. */
|
|
2028
|
+
status: "failed";
|
|
2029
|
+
/** Redacted failure class; never the provider error or endpoint URL. */
|
|
2030
|
+
reason: X402SelfRelayRpcFailureReason;
|
|
2031
|
+
/** Millisecond timestamp at which the DVM observed the transition. */
|
|
2032
|
+
checkedAt: number;
|
|
2033
|
+
};
|
|
2034
|
+
/** Configured Tempo operator fee-token balance POSTed by a hosted DVM. */
|
|
2035
|
+
interface TempoSettlementBalancePayload {
|
|
2036
|
+
dvmId: string;
|
|
2037
|
+
address: `0x${string}`;
|
|
2038
|
+
network: string;
|
|
2039
|
+
token: `0x${string}`;
|
|
2040
|
+
balanceMicro: string;
|
|
2041
|
+
lowBalanceMicro: string;
|
|
2042
|
+
checkedAt: number;
|
|
2043
|
+
ready: boolean;
|
|
2044
|
+
}
|
|
2045
|
+
/** Redacted Tempo operator fee-funding rejection POSTed by a hosted DVM. */
|
|
2046
|
+
interface TempoSettlementFailurePayload {
|
|
2047
|
+
dvmId: string;
|
|
2048
|
+
address: `0x${string}`;
|
|
2049
|
+
network: string;
|
|
2050
|
+
token: `0x${string}`;
|
|
2051
|
+
operation: "settle" | "close";
|
|
2052
|
+
errorClass: "InsufficientFundsError";
|
|
2053
|
+
checkedAt: number;
|
|
2054
|
+
balanceMicro?: string;
|
|
2055
|
+
channelId?: string;
|
|
2056
|
+
creditId?: string;
|
|
2057
|
+
drainId?: string;
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Durable revenue reporter for container-runtime DVMs (internal-review).
|
|
2061
|
+
*
|
|
2062
|
+
* On job completion the SDK calls `report()`, which persists the payload to
|
|
2063
|
+
* a local Postgres table and attempts an immediate POST to the platform.
|
|
2064
|
+
* A background retry loop picks up un-acked rows with exponential backoff.
|
|
2065
|
+
*/
|
|
2066
|
+
declare class RevenueReporter {
|
|
2067
|
+
private readonly db;
|
|
2068
|
+
private readonly platformUrl;
|
|
2069
|
+
private readonly platformToken;
|
|
2070
|
+
private retryTimer;
|
|
2071
|
+
private static readonly RETRY_INTERVAL_MS;
|
|
2072
|
+
private static readonly MAX_BACKOFF_MS;
|
|
2073
|
+
private static readonly ABANDON_AFTER_MS;
|
|
2074
|
+
constructor(db: Pool, platformUrl: string, platformToken: string);
|
|
2075
|
+
/** Create the pending-reports table (idempotent). */
|
|
2076
|
+
init(): Promise<void>;
|
|
2077
|
+
/** The boot DDL itself — always runs under {@link withSdkInitLock} (internal-review). */
|
|
2078
|
+
private createTables;
|
|
2079
|
+
/** Persist a revenue report and attempt immediate delivery. */
|
|
2080
|
+
report(payload: RevenueReportPayload): Promise<void>;
|
|
2081
|
+
/**
|
|
2082
|
+
* Join a credit deposit to the caller-owned rail transaction.
|
|
2083
|
+
*
|
|
2084
|
+
* This method performs no network I/O: it only writes the reporter-owned
|
|
2085
|
+
* durable queue row through `tx`. The retry drain delivers the row after the
|
|
2086
|
+
* rail transaction commits, including after a process restart.
|
|
2087
|
+
*/
|
|
2088
|
+
enqueueDeposit(tx: RevenueReporterQuerier, payload: CreditDepositPayload): Promise<void>;
|
|
2089
|
+
/** Join a released draw to the transaction that made the hold terminal. */
|
|
2090
|
+
enqueueCreditDrawRelease(tx: RevenueReporterQuerier, payload: CreditDrawReleasePayload): Promise<void>;
|
|
2091
|
+
/**
|
|
2092
|
+
* Join a credit drain to the transaction that made it terminal (internal-review).
|
|
2093
|
+
*
|
|
2094
|
+
* Same discipline as {@link enqueueDeposit} and the same reason: no network
|
|
2095
|
+
* I/O here, only the durable queue row, written through `tx` so the report
|
|
2096
|
+
* and the status CAS commit or roll back together. A drain whose row was
|
|
2097
|
+
* lost between the two would overstate outstanding liability forever —
|
|
2098
|
+
* the mirror image of a lost deposit.
|
|
2099
|
+
*
|
|
2100
|
+
* Named for the payload rather than the verb because `drain` already means
|
|
2101
|
+
* "flush the queue" in this class (see {@link drainPending}).
|
|
2102
|
+
*/
|
|
2103
|
+
enqueueCreditDrain(tx: RevenueReporterQuerier, payload: CreditDrainPayload): Promise<void>;
|
|
2104
|
+
/**
|
|
2105
|
+
* Join a payout to the transaction that commits the movement it reports
|
|
2106
|
+
* (internal-review) — the batch close, the accumulator mark, the drain booking.
|
|
2107
|
+
* No network I/O, only the durable queue row through `tx`, the discipline
|
|
2108
|
+
* {@link enqueueCreditDrain} set and for the same reason: the money has
|
|
2109
|
+
* already moved on a rail this ledger does not own, so the platform row is
|
|
2110
|
+
* the only record the builder's dashboard has of it, and a row lost between
|
|
2111
|
+
* the fact and the queue would understate "paid out" forever. Without `tx`
|
|
2112
|
+
* the row is queued on the pool, for callers with no fact of their own to
|
|
2113
|
+
* commit. Idempotent on `(dvmId, payoutId)` platform-side, so the retry
|
|
2114
|
+
* loop redelivers freely.
|
|
2115
|
+
*/
|
|
2116
|
+
enqueuePayout(payload: PayoutReportPayload, tx?: RevenueReporterQuerier): Promise<void>;
|
|
2117
|
+
/**
|
|
2118
|
+
* Report one landed payout on its own and try to deliver it at once — the
|
|
2119
|
+
* live Tempo settlement, which has no dvmkit transaction to join. Durable
|
|
2120
|
+
* like {@link report}.
|
|
2121
|
+
*/
|
|
2122
|
+
reportPayout(payload: PayoutReportPayload): Promise<void>;
|
|
2123
|
+
/**
|
|
2124
|
+
* Report one rail's pending-pool snapshot (internal-review). Best-effort and
|
|
2125
|
+
* fire-and-forget, deliberately unlike {@link reportPayout}: a snapshot is
|
|
2126
|
+
* replaced by the next tick, so queueing a stale one behind an outage would
|
|
2127
|
+
* only deliver figures the platform already has newer ones for.
|
|
2128
|
+
*/
|
|
2129
|
+
reportPayoutPending(payload: PayoutPendingPayload): Promise<void>;
|
|
2130
|
+
/**
|
|
2131
|
+
* Join a credit-expiry release — or the revival that reverses one — to the
|
|
2132
|
+
* transaction that made it true (internal-review).
|
|
2133
|
+
*
|
|
2134
|
+
* Same discipline as {@link enqueueCreditDrain}: no network I/O, only the
|
|
2135
|
+
* durable queue row written through `tx`. A release whose row was lost after
|
|
2136
|
+
* the sweep committed would understate committed value forever; a lost
|
|
2137
|
+
* reversal would overstate it, which is the worse direction — the builder
|
|
2138
|
+
* would see money as theirs that a revived credit can still buy work with.
|
|
2139
|
+
*/
|
|
2140
|
+
enqueueCreditExpiryRelease(tx: RevenueReporterQuerier, payload: CreditExpiryReleasePayload): Promise<void>;
|
|
2141
|
+
/**
|
|
2142
|
+
* Report a reaper-force-failed paid job to the platform (internal-review) so the
|
|
2143
|
+
* operator receives an ambient notice that a DVM died or wedged mid-job.
|
|
2144
|
+
* Best-effort and fire-and-forget: unlike {@link report} there is no local
|
|
2145
|
+
* durable queue — a non-2xx or transport failure is structured-logged
|
|
2146
|
+
* (`paid_job_death_report_failed`) and dropped, since the reaper's own
|
|
2147
|
+
* `stale_job_failed` log is the durable record and a failed *alert* must never
|
|
2148
|
+
* wedge the sweep.
|
|
2149
|
+
*/
|
|
2150
|
+
reportPaidJobDeath(payload: PaidJobDeathPayload): Promise<void>;
|
|
2151
|
+
/**
|
|
2152
|
+
* Report a settled draw whose revenue event was skipped (internal-review).
|
|
2153
|
+
* Best-effort and fire-and-forget: the SDK's structured
|
|
2154
|
+
* `revenue_skipped_no_rail` log is the durable backstop, so a failed notice
|
|
2155
|
+
* must never wedge terminal handling or the orphan-draw reconciler.
|
|
2156
|
+
*/
|
|
2157
|
+
reportRevenueSkippedNoRail(payload: RevenueSkippedNoRailPayload): Promise<void>;
|
|
2158
|
+
/** Report the self-relay's Base gas gauge for platform-side paging and recovery. */
|
|
2159
|
+
reportX402SelfRelayGasBalance(payload: X402SelfRelayGasBalancePayload): Promise<void>;
|
|
2160
|
+
/** Report redacted self-relay RPC health for platform-side paging and recovery. */
|
|
2161
|
+
reportX402SelfRelayRpcHealth(payload: X402SelfRelayRpcHealthPayload): Promise<void>;
|
|
2162
|
+
/** Report the Tempo operator's fee-token gauge for paging and recovery. */
|
|
2163
|
+
reportTempoSettlementBalance(payload: TempoSettlementBalancePayload): Promise<void>;
|
|
2164
|
+
/** Report a redacted operator fee rejection immediately. */
|
|
2165
|
+
reportTempoSettlementFailure(payload: TempoSettlementFailurePayload): Promise<void>;
|
|
2166
|
+
private postTempoSettlementReadiness;
|
|
2167
|
+
/** Start the background retry loop. */
|
|
2168
|
+
startRetryLoop(): void;
|
|
2169
|
+
/** Stop the background retry loop. */
|
|
2170
|
+
stop(): void;
|
|
2171
|
+
/**
|
|
2172
|
+
* Operator-facing queue snapshot: distinguishes the live retry queue from
|
|
2173
|
+
* terminal (stale) rows and breaks the latter down by classification reason
|
|
2174
|
+
* (`token_rotated`, `client_error:<status>`, `abandoned`). Lets monitoring tell
|
|
2175
|
+
* transient backlog apart from permanently-failed rows.
|
|
2176
|
+
*/
|
|
2177
|
+
getQueueStats(): Promise<{
|
|
2178
|
+
liveRetry: number;
|
|
2179
|
+
stale: number;
|
|
2180
|
+
byReason: Record<string, number>;
|
|
2181
|
+
}>;
|
|
2182
|
+
/**
|
|
2183
|
+
* Deliver one bounded batch from the durable queue.
|
|
2184
|
+
*
|
|
2185
|
+
* Public so startup/recovery tests and operator tooling can drive the same
|
|
2186
|
+
* drain the background timer uses without reaching into private state.
|
|
2187
|
+
*/
|
|
2188
|
+
drainPending(): Promise<void>;
|
|
2189
|
+
/** Durably queue one report of either kind, then try it once immediately. */
|
|
2190
|
+
private enqueue;
|
|
2191
|
+
/** Insert one pending report through either the pool or an open transaction. */
|
|
2192
|
+
private insertPending;
|
|
2193
|
+
private attemptDelivery;
|
|
2194
|
+
/** Mark a pending row terminal (stale) with a classification reason. */
|
|
2195
|
+
private markStale;
|
|
2196
|
+
}
|
|
1047
2197
|
|
|
1048
2198
|
/** Query surface shared by the pool and an open Postgres transaction. */
|
|
1049
2199
|
type X402ChannelQuerier = Pick<Pool, "query">;
|
|
@@ -1063,8 +2213,8 @@ interface X402SettlementIntent {
|
|
|
1063
2213
|
operation: "fund" | "refund";
|
|
1064
2214
|
effectId: string;
|
|
1065
2215
|
paymentId: string;
|
|
1066
|
-
payload: PaymentPayload;
|
|
1067
|
-
requirements: PaymentRequirements;
|
|
2216
|
+
payload: PaymentPayload$1;
|
|
2217
|
+
requirements: PaymentRequirements$1;
|
|
1068
2218
|
channelBefore: Channel;
|
|
1069
2219
|
/**
|
|
1070
2220
|
* The channel as it stood when the settlement was handed to the facilitator —
|
|
@@ -1083,7 +2233,7 @@ interface X402SettlementIntent {
|
|
|
1083
2233
|
submissionBlock?: string;
|
|
1084
2234
|
pendingId?: string;
|
|
1085
2235
|
status: X402SettlementStatus;
|
|
1086
|
-
response?: SettleResponse;
|
|
2236
|
+
response?: SettleResponse$1;
|
|
1087
2237
|
/** Epoch ms the row was first prepared. */
|
|
1088
2238
|
createdAt: number;
|
|
1089
2239
|
/** Epoch ms of the last status write — what the repair queue ages against. */
|
|
@@ -1350,7 +2500,7 @@ declare class PostgresX402ChannelStorage implements ChannelStorage {
|
|
|
1350
2500
|
* reversed. On the live path the columns are already `NULL` and this is a
|
|
1351
2501
|
* no-op.
|
|
1352
2502
|
*/
|
|
1353
|
-
recordSettlementResponse(settlementId: string, response: SettleResponse): Promise<void>;
|
|
2503
|
+
recordSettlementResponse(settlementId: string, response: SettleResponse$1): Promise<void>;
|
|
1354
2504
|
/**
|
|
1355
2505
|
* Mark the external settlement and ledger effect complete in the active transaction.
|
|
1356
2506
|
*
|
|
@@ -1437,15 +2587,15 @@ declare class PostgresX402ChannelStorage implements ChannelStorage {
|
|
|
1437
2587
|
|
|
1438
2588
|
/** Durable channel seam used to compose a settled draw with consumed Tempo value. */
|
|
1439
2589
|
interface TempoSessionSettlementStore {
|
|
1440
|
-
withDrawPlacement<value>(channelId: string, operation: (tx: CreditLedgerQuerier, lifecycle: TempoSessionLifecycle) => Promise<value>, tx?: CreditLedgerQuerier): Promise<value>;
|
|
1441
|
-
withTerminalConsumption<value>(channelId: string, operation: (tx: CreditLedgerQuerier, lifecycle: TempoSessionLifecycle) => Promise<{
|
|
2590
|
+
withDrawPlacement<value>(channelId: string, operation: (tx: CreditLedgerQuerier, lifecycle: TempoSessionLifecycle$1) => Promise<value>, tx?: CreditLedgerQuerier): Promise<value>;
|
|
2591
|
+
withTerminalConsumption<value>(channelId: string, operation: (tx: CreditLedgerQuerier, lifecycle: TempoSessionLifecycle$1) => Promise<{
|
|
1442
2592
|
value: value;
|
|
1443
2593
|
amount: bigint;
|
|
1444
2594
|
consume: boolean;
|
|
1445
2595
|
}>): Promise<value>;
|
|
1446
2596
|
}
|
|
1447
2597
|
/** Tempo channel state read while holding its durable row lock. */
|
|
1448
|
-
interface TempoSessionLifecycle {
|
|
2598
|
+
interface TempoSessionLifecycle$1 {
|
|
1449
2599
|
finalized: boolean;
|
|
1450
2600
|
closeRequestedAt: bigint;
|
|
1451
2601
|
spent: bigint;
|
|
@@ -3504,6 +4654,17 @@ declare class CreditLedgerError extends Error {
|
|
|
3504
4654
|
constructor(code: CreditLedgerErrorCode, message: string, details?: CreditLedgerErrorDetails, opts?: ErrorOptions);
|
|
3505
4655
|
}
|
|
3506
4656
|
|
|
4657
|
+
/** One durable Tempo session-channel row exposed to reconciliation workers. */
|
|
4658
|
+
interface TempoSessionRow {
|
|
4659
|
+
key: string;
|
|
4660
|
+
state: Record<string, unknown>;
|
|
4661
|
+
updatedAt: number;
|
|
4662
|
+
}
|
|
4663
|
+
/** Cursor for stable pagination over active Tempo session channels. */
|
|
4664
|
+
interface TempoSessionCursor {
|
|
4665
|
+
updatedAt: number;
|
|
4666
|
+
key: string;
|
|
4667
|
+
}
|
|
3507
4668
|
/** Durable state joining a credit drain to its cooperative channel close. */
|
|
3508
4669
|
interface TempoSessionCloseRecord {
|
|
3509
4670
|
channelId: string;
|
|
@@ -3521,7 +4682,212 @@ type TempoSessionCloseForecastResolution<value> = {
|
|
|
3521
4682
|
} | {
|
|
3522
4683
|
outcome: "missing";
|
|
3523
4684
|
};
|
|
4685
|
+
/** The voucher increment observed while holding the channel row lock. */
|
|
4686
|
+
interface TempoVoucherDelta {
|
|
4687
|
+
key: string;
|
|
4688
|
+
cumulativeAmount: bigint;
|
|
4689
|
+
priorCumulativeAmount: bigint;
|
|
4690
|
+
delta: bigint;
|
|
4691
|
+
}
|
|
4692
|
+
/** Result of a ledger resolution composed with terminal channel consumption. */
|
|
4693
|
+
interface TempoSessionConsumption<value> {
|
|
4694
|
+
value: value;
|
|
4695
|
+
amount: bigint;
|
|
4696
|
+
consume: boolean;
|
|
4697
|
+
}
|
|
4698
|
+
/** Channel lifecycle fields exposed while its row lock is held. */
|
|
4699
|
+
interface TempoSessionLifecycle {
|
|
4700
|
+
finalized: boolean;
|
|
4701
|
+
closeRequestedAt: bigint;
|
|
4702
|
+
spent: bigint;
|
|
4703
|
+
settledOnChain: bigint;
|
|
4704
|
+
highestVoucherAmount: bigint;
|
|
4705
|
+
}
|
|
4706
|
+
/**
|
|
4707
|
+
* Postgres implementation of mppx's atomic channel store.
|
|
4708
|
+
*
|
|
4709
|
+
* Every mutation takes an advisory transaction lock keyed by the channel
|
|
4710
|
+
* before locking its row with `FOR UPDATE`, applies mppx's synchronous
|
|
4711
|
+
* transition exactly once, and commits before returning. The advisory lock
|
|
4712
|
+
* covers a channel's first write, when there is no row for `FOR UPDATE` to
|
|
4713
|
+
* lock. Together these are the cross-machine linearization point for voucher,
|
|
4714
|
+
* top-up, spend, and close state; mppx's process-local fallback is
|
|
4715
|
+
* intentionally never used in a durable SDK host.
|
|
4716
|
+
*
|
|
4717
|
+
* Lock order remains channel before credit: mutation paths take the advisory
|
|
4718
|
+
* lock and then the row lock, while terminal consumption requires an existing
|
|
4719
|
+
* row and starts there. Both own the channel lock before the ledger takes its
|
|
4720
|
+
* parent-credit lock through the same client.
|
|
4721
|
+
*
|
|
4722
|
+
* {@link withVoucherAcceptance} acquires its pooled client **lazily**, on the
|
|
4723
|
+
* first store mutation rather than up front (internal-review). Its `operation` is
|
|
4724
|
+
* mppx's credential verification, which does the chain work before it touches
|
|
4725
|
+
* the store: an `open` submits the escrow transaction and awaits its receipt,
|
|
4726
|
+
* a `voucher` reads channel state over public RPC. Holding a connection across
|
|
4727
|
+
* that starves everything else on the shared host pool — `/v1/job`, the job
|
|
4728
|
+
* store, KV, the credit ledger, the replay store — and exposes the open
|
|
4729
|
+
* transaction to `idle_in_transaction_session_timeout`. This is the same shape
|
|
4730
|
+
* internal-review removed from the x402 settlement path. Laziness costs nothing in
|
|
4731
|
+
* atomicity: the `FOR UPDATE` row lock was always taken at the first mutation,
|
|
4732
|
+
* never at `BEGIN`, so the critical section is unchanged — only the
|
|
4733
|
+
* connection-holding window shrinks to the database work it actually covers.
|
|
4734
|
+
*/
|
|
4735
|
+
declare class PostgresTempoSessionStore implements Store.AtomicStore {
|
|
4736
|
+
private readonly pool;
|
|
4737
|
+
private readonly acceptance;
|
|
4738
|
+
constructor(pool: Pool);
|
|
4739
|
+
/** Create the channel table under the SDK-wide migration lock. */
|
|
4740
|
+
init(): Promise<void>;
|
|
4741
|
+
/** Read one channel snapshot. */
|
|
4742
|
+
get(key: string): Promise<unknown>;
|
|
4743
|
+
/** Replace one channel snapshot. Used by mppx only for non-RMW maintenance. */
|
|
4744
|
+
put(key: string, value: unknown): Promise<void>;
|
|
4745
|
+
/** Delete one channel snapshot. */
|
|
4746
|
+
delete(key: string): Promise<void>;
|
|
4747
|
+
/** Atomic read-modify-write using a row lock shared by every SDK replica. */
|
|
4748
|
+
update<result>(key: string, fn: (current: unknown) => Store.Change<unknown, result>): Promise<result>;
|
|
4749
|
+
/** Compose voucher acceptance and its ledger mutation under the channel-row lock. */
|
|
4750
|
+
withVoucherAcceptance<value, result>(voucher: {
|
|
4751
|
+
channelId: string;
|
|
4752
|
+
cumulativeAmount: bigint;
|
|
4753
|
+
}, commit: (tx: PoolClient, voucher: TempoVoucherDelta) => Promise<result>, operation: () => Promise<value>): Promise<{
|
|
4754
|
+
value: value;
|
|
4755
|
+
result: result | undefined;
|
|
4756
|
+
}>;
|
|
4757
|
+
/**
|
|
4758
|
+
* Check out the acceptance transaction's client, opening it on first demand.
|
|
4759
|
+
*
|
|
4760
|
+
* An operation that never mutates the store therefore never takes a
|
|
4761
|
+
* connection and never opens an empty transaction — the caller sees the same
|
|
4762
|
+
* `result: undefined` it saw before, because nothing committed either way.
|
|
4763
|
+
*
|
|
4764
|
+
* The in-flight checkout is memoized, not just its result: mppx awaits each
|
|
4765
|
+
* store call today, but two concurrent first mutations would otherwise open
|
|
4766
|
+
* two transactions and leak the one nobody keeps a handle to.
|
|
4767
|
+
*/
|
|
4768
|
+
private acceptanceClient;
|
|
4769
|
+
/** Serialize a credit draw with the channel lifecycle that authorizes it. */
|
|
4770
|
+
withDrawPlacement<value>(channelId: string, operation: (tx: CreditLedgerQuerier, lifecycle: TempoSessionLifecycle) => Promise<value>, tx?: CreditLedgerQuerier): Promise<value>;
|
|
4771
|
+
private withLockedLifecycle;
|
|
4772
|
+
/**
|
|
4773
|
+
* Compose a terminal ledger resolution with the channel's consumed value.
|
|
4774
|
+
*
|
|
4775
|
+
* Voucher acceptance records spending authority; only a successful job
|
|
4776
|
+
* consumes it. Holding the channel row while the callback locks and settles
|
|
4777
|
+
* the credit keeps that distinction atomic across machines and preserves the
|
|
4778
|
+
* shared channel -> credit lock order.
|
|
4779
|
+
*/
|
|
4780
|
+
withTerminalConsumption<value>(channelId: string, operation: (tx: PoolClient, lifecycle: TempoSessionLifecycle) => Promise<TempoSessionConsumption<value>>): Promise<value>;
|
|
4781
|
+
/** Retire lost backing while holding the channel row ahead of every credit lock. */
|
|
4782
|
+
withFinalizedCreditLoss<value>(channelId: string, operation: (tx: PoolClient, lifecycle: TempoSessionLifecycle) => Promise<value>): Promise<value>;
|
|
4783
|
+
/** Page active channel snapshots for the close/settlement watcher. */
|
|
4784
|
+
listActive(limit?: number, cursor?: TempoSessionCursor): Promise<TempoSessionRow[]>;
|
|
4785
|
+
/** Persist a drain's close intent before its credential is broadcast. */
|
|
4786
|
+
beginClose(channelId: string, drainId: string): Promise<TempoSessionCloseRecord>;
|
|
4787
|
+
/** Reserve a close intent and run its ledger debit in the same transaction. */
|
|
4788
|
+
withCloseIntent<value>(channelId: string, drainId: string, operation: (tx: PoolClient) => Promise<value>): Promise<value>;
|
|
4789
|
+
/**
|
|
4790
|
+
* Resolve a reserved close's forecast under the intent row lock.
|
|
4791
|
+
*
|
|
4792
|
+
* `proceed` opens the broadcast gate. `release` deletes the intent and runs
|
|
4793
|
+
* the ledger restore in the same transaction, but only while the gate is
|
|
4794
|
+
* still pending. A concurrent proceed wins by returning `proceed` to the
|
|
4795
|
+
* releaser, which must not restore value that may already be broadcasting.
|
|
4796
|
+
*/
|
|
4797
|
+
resolveCloseForecast<value>(channelId: string, drainId: string, decision: TempoSessionCloseForecastDecision, operation?: (tx: PoolClient) => Promise<value>): Promise<TempoSessionCloseForecastResolution<value>>;
|
|
4798
|
+
/** Delete a matching close intent and release its ledger debit atomically. */
|
|
4799
|
+
releaseCloseIntent<value>(channelId: string, drainId: string, operation: (tx: PoolClient) => Promise<value>): Promise<value>;
|
|
4800
|
+
/** Read a persisted cooperative-close intent or confirmed result. */
|
|
4801
|
+
getClose(channelId: string): Promise<TempoSessionCloseRecord | null>;
|
|
4802
|
+
/** Persist proof that a cooperative close reached terminal chain state. */
|
|
4803
|
+
confirmClose(channelId: string, drainId: string, reference: string): Promise<TempoSessionCloseRecord>;
|
|
4804
|
+
private runCloseIntentTransaction;
|
|
4805
|
+
private transaction;
|
|
4806
|
+
private writeCloseIntent;
|
|
4807
|
+
private updateInTransaction;
|
|
4808
|
+
}
|
|
3524
4809
|
|
|
4810
|
+
/**
|
|
4811
|
+
* Options for assembling an Mppx server handle from explicit recipient strings
|
|
4812
|
+
* and the surrounding environment. The SDK boundary owns env reads so DVM
|
|
4813
|
+
* authors only think in terms of "set DVMKIT_TEMPO_RECIPIENT /
|
|
4814
|
+
* DVMKIT_TEMPO_SECRET_KEY in your DVM env" — same pattern as the existing
|
|
4815
|
+
* payment-rail inputs.
|
|
4816
|
+
*/
|
|
4817
|
+
interface MppOpts {
|
|
4818
|
+
/**
|
|
4819
|
+
* Tempo recipient (0x-prefixed 40-char hex address). When set, registers
|
|
4820
|
+
* `tempo/charge`. Currency defaults to USDC on Tempo mainnet; override via
|
|
4821
|
+
* the `DVMKIT_TEMPO_CURRENCY` env var for testnet/devnet deployments.
|
|
4822
|
+
*/
|
|
4823
|
+
tempoRecipient?: string;
|
|
4824
|
+
/**
|
|
4825
|
+
* Server realm for advertising on `/v1/info`. Default resolution lives in
|
|
4826
|
+
* mppx (env vars `MPP_REALM`, `FLY_APP_NAME`, `VERCEL_URL`, request URL,
|
|
4827
|
+
* `"MPP Payment"`).
|
|
4828
|
+
*/
|
|
4829
|
+
realm?: string;
|
|
4830
|
+
/**
|
|
4831
|
+
* When set, only register MPP methods whose name appears in this list, even
|
|
4832
|
+
* if the per-rail env var (`DVMKIT_TEMPO_RECIPIENT`) is configured
|
|
4833
|
+
* (internal-review). Lets operators temporarily disable a rail without unsetting
|
|
4834
|
+
* other knobs. Empty/undefined falls back to "register everything that has
|
|
4835
|
+
* a configured recipient".
|
|
4836
|
+
*/
|
|
4837
|
+
methodsAllowlist?: string[];
|
|
4838
|
+
/**
|
|
4839
|
+
* Durable replay protection for the one-shot `tempo/charge` method
|
|
4840
|
+
* (internal-review). Omit and mppx falls back to `Store.memory()`, whose consumed
|
|
4841
|
+
* transaction hashes are per-process — invisible to sibling machines and lost
|
|
4842
|
+
* on restart. Pass a cross-machine store (`PostgresTempoChargeStore`) on any
|
|
4843
|
+
* multi-instance deploy.
|
|
4844
|
+
*
|
|
4845
|
+
* The same store also backs mppx's fee-sponsor budget and, because mppx
|
|
4846
|
+
* enables proof-credential replay protection only when a store is supplied,
|
|
4847
|
+
* turns that guard on as a side effect.
|
|
4848
|
+
*/
|
|
4849
|
+
tempoCharge?: {
|
|
4850
|
+
store: Store.AtomicStore;
|
|
4851
|
+
};
|
|
4852
|
+
/**
|
|
4853
|
+
* Durable TIP-1034 session support. Omit to keep the existing one-shot
|
|
4854
|
+
* `tempo/charge` method only. The account must be able to submit settlement
|
|
4855
|
+
* transactions as the channel payee/operator; an address-only client is not
|
|
4856
|
+
* sufficient.
|
|
4857
|
+
*/
|
|
4858
|
+
tempoSession?: {
|
|
4859
|
+
store: Store.AtomicStore;
|
|
4860
|
+
account: Account;
|
|
4861
|
+
getClient?: (parameters: {
|
|
4862
|
+
chainId?: number;
|
|
4863
|
+
}) => Client | Promise<Client>;
|
|
4864
|
+
chainId?: number;
|
|
4865
|
+
settlementSchedule?: {
|
|
4866
|
+
units?: number;
|
|
4867
|
+
amount?: string | bigint;
|
|
4868
|
+
intervalMs?: number;
|
|
4869
|
+
/**
|
|
4870
|
+
* How long a settlement holds its in-flight lease (internal-review). Defaults to
|
|
4871
|
+
* {@link TEMPO_SETTLEMENT_LEASE_MS}, which documents the receipt-timeout
|
|
4872
|
+
* floor an override has to stay above.
|
|
4873
|
+
*/
|
|
4874
|
+
leaseMs?: number;
|
|
4875
|
+
};
|
|
4876
|
+
beforeSessionSettlement?: () => string | undefined | Promise<string | undefined>;
|
|
4877
|
+
onSessionSettlement?: (context: {
|
|
4878
|
+
txHash: `0x${string}`;
|
|
4879
|
+
channelId: `0x${string}`;
|
|
4880
|
+
trigger: "settle" | "close" | "scheduled";
|
|
4881
|
+
amount: bigint;
|
|
4882
|
+
delta: bigint;
|
|
4883
|
+
recoveryVersion?: string;
|
|
4884
|
+
}) => void | Promise<void>;
|
|
4885
|
+
onInsufficientFunds?: (context: {
|
|
4886
|
+
operation: "settle";
|
|
4887
|
+
channelId: string;
|
|
4888
|
+
}) => void | Promise<void>;
|
|
4889
|
+
};
|
|
4890
|
+
}
|
|
3525
4891
|
/**
|
|
3526
4892
|
* Loose runtime view of an `Mppx.create(...)` handle. mppx's full generic
|
|
3527
4893
|
* typing is precise but propagates badly through layers — the SDK boundary
|
|
@@ -3724,6 +5090,36 @@ interface TempoSessionDrainState {
|
|
|
3724
5090
|
deposit: bigint;
|
|
3725
5091
|
finalized: boolean;
|
|
3726
5092
|
}
|
|
5093
|
+
/**
|
|
5094
|
+
* Attach the typed `issueChallenge` dispatcher to a freshly-created mppx
|
|
5095
|
+
* handle. Production builds via `createMppFromOpts`; tests build via
|
|
5096
|
+
* `Mppx.create(...)` directly and use `wrapMppx` to satisfy the SDK boundary.
|
|
5097
|
+
*
|
|
5098
|
+
* Accepts `unknown` because mppx's `Mppx<methods, transport>` generic doesn't
|
|
5099
|
+
* collapse cleanly through `ReturnType<typeof Mppx.create>` — the default
|
|
5100
|
+
* pins `methods: readonly []` and rejects any concrete method tuple. We cast
|
|
5101
|
+
* inside the wrapper instead of leaking the generic onto every caller.
|
|
5102
|
+
*/
|
|
5103
|
+
declare function wrapMppx(mppx: unknown): MppxServer;
|
|
5104
|
+
interface TempoSessionChainOps {
|
|
5105
|
+
getChannelStatesBatch(client: Client, channelIds: readonly Hex[], escrowContract: `0x${string}`): Promise<{
|
|
5106
|
+
settled: bigint;
|
|
5107
|
+
deposit: bigint;
|
|
5108
|
+
closeRequestedAt: number;
|
|
5109
|
+
}[]>;
|
|
5110
|
+
settle(store: Store.AtomicStore, client: Client, channelId: Hex, options: {
|
|
5111
|
+
account: Account;
|
|
5112
|
+
escrowContract: `0x${string}`;
|
|
5113
|
+
feeToken: `0x${string}`;
|
|
5114
|
+
onSessionSettlement?: NonNullable<MppOpts["tempoSession"]>["onSessionSettlement"];
|
|
5115
|
+
}): Promise<Hex>;
|
|
5116
|
+
readChannelClose(client: Client, channelId: Hex, txHash: Hex): Promise<TempoChannelCloseAmounts>;
|
|
5117
|
+
}
|
|
5118
|
+
declare function attachTempoSessionRuntime(mppx: MppxServer, config: MppOpts["tempoSession"], chainOpOverrides?: Partial<TempoSessionChainOps>): MppxServer;
|
|
5119
|
+
/** Test-only seams for deterministic watcher coverage without a live Tempo RPC. */
|
|
5120
|
+
declare const _testing: {
|
|
5121
|
+
attachTempoSessionRuntime: typeof attachTempoSessionRuntime;
|
|
5122
|
+
};
|
|
3727
5123
|
|
|
3728
5124
|
/** Envelope fields the verifier validates around the signed payload. */
|
|
3729
5125
|
interface CanonicalEnvelope {
|
|
@@ -3835,6 +5231,28 @@ interface SignedRequestVerifier<T> {
|
|
|
3835
5231
|
}
|
|
3836
5232
|
/** Failure mode taxonomy returned from `verify()`. */
|
|
3837
5233
|
type SignedRequestFailure = "schema_invalid" | "timestamp_drift" | "signature_invalid" | "replay_detected";
|
|
5234
|
+
/**
|
|
5235
|
+
* The four fields every signed-request envelope carries around the payload,
|
|
5236
|
+
* with the runtime type each must have once the schema has parsed.
|
|
5237
|
+
*
|
|
5238
|
+
* The single definition of "which part of a schema failure is the envelope's":
|
|
5239
|
+
* the post-parse shape check in `parse()` iterates it, and `authErrorBody`'s
|
|
5240
|
+
* internal-review classifier reads its keys to decide whether a `schema_invalid` throw
|
|
5241
|
+
* is the caller's *input* being wrong (disclosable: the schema is public on
|
|
5242
|
+
* `/v1/info`) or their *signing* being wrong (folded into `signature_invalid`,
|
|
5243
|
+
* one answer for every key and signature failure). `satisfies` pins it to
|
|
5244
|
+
* {@link CanonicalEnvelope}, so a fifth envelope field can't be added to the
|
|
5245
|
+
* type without both readers picking it up.
|
|
5246
|
+
*/
|
|
5247
|
+
declare const SIGNED_ENVELOPE_TYPES: {
|
|
5248
|
+
readonly pubkey: "string";
|
|
5249
|
+
readonly signature: "string";
|
|
5250
|
+
readonly timestamp: "number";
|
|
5251
|
+
readonly nonce: "string";
|
|
5252
|
+
readonly auth_statement: "object";
|
|
5253
|
+
};
|
|
5254
|
+
/** The envelope field names — {@link SIGNED_ENVELOPE_TYPES}' keys. */
|
|
5255
|
+
declare const SIGNED_ENVELOPE_FIELDS: readonly (keyof CanonicalEnvelope)[];
|
|
3838
5256
|
/** Structured error from `verify()` — `sub_reason` is the failure kind. */
|
|
3839
5257
|
declare class SignedRequestError extends Error {
|
|
3840
5258
|
readonly sub_reason: SignedRequestFailure;
|
|
@@ -3900,6 +5318,23 @@ declare function signedRequestInput(body: {
|
|
|
3900
5318
|
input?: string;
|
|
3901
5319
|
data?: unknown;
|
|
3902
5320
|
}): unknown;
|
|
5321
|
+
/**
|
|
5322
|
+
* Build the bounded in-memory FIFO replay store used as the default when no
|
|
5323
|
+
* cross-machine `SignedRequestReplayStore` is supplied. 10-minute retention
|
|
5324
|
+
* window, 100k entry cap, per-process. Exported so `secp256k1Auth(...)` can
|
|
5325
|
+
* pre-build one and share it across every per-schema verifier plus its own
|
|
5326
|
+
* `recordReplay` path (internal-review).
|
|
5327
|
+
*
|
|
5328
|
+
* When the cap is hit after the time-expired sweep, fresh inserts are
|
|
5329
|
+
* **rejected** (return `true` — treated as replay at the wire) rather than
|
|
5330
|
+
* silently evicting an in-window entry. Silent eviction would flush a
|
|
5331
|
+
* still-valid nonce back to "unseen" and let an attacker who can drive cap
|
|
5332
|
+
* pressure replay it (internal-review). A rate-limited structured warning fires so
|
|
5333
|
+
* operators see saturation in `fly logs`; reaching cap means in-memory has
|
|
5334
|
+
* been pushed past where it's safe and the deploy should move to
|
|
5335
|
+
* `PostgresReplayStore`.
|
|
5336
|
+
*/
|
|
5337
|
+
declare function createDefaultReplayStore(): SignedRequestReplayStore;
|
|
3903
5338
|
|
|
3904
5339
|
/**
|
|
3905
5340
|
* A DVM-level auth scheme, declared on `DVMDescriptor.auth`. Authentication
|
|
@@ -4383,6 +5818,35 @@ type PaymentMethod = "cashu" | "x402" | "tempo";
|
|
|
4383
5818
|
* stops that dead rail from reappearing every time the funding menu grows.
|
|
4384
5819
|
*/
|
|
4385
5820
|
type FundingMethod = PaymentMethod | "lightning";
|
|
5821
|
+
/**
|
|
5822
|
+
* Whether a failed job on a given rail can return the caller's funds (internal-review).
|
|
5823
|
+
*
|
|
5824
|
+
* **No rail refunds on `ctx.fail`, and no code behind the idea any more.** Under
|
|
5825
|
+
* the P2PK-accumulator Cashu path — the only Cashu path post-internal-review/internal-review —
|
|
5826
|
+
* `verifyAccumulatorReceipt` commits the caller's proofs straight into
|
|
5827
|
+
* `wallet_accumulator` and leaves `job.receivedProofs` empty; every producer in
|
|
5828
|
+
* `payment.ts` returns `[]`. The `ctx.fail(err, { refund: true })` branch that
|
|
5829
|
+
* used to send proofs back gated on those held proofs, so it had been an
|
|
5830
|
+
* unreachable no-op for as long as the accumulator has been the commit boundary,
|
|
5831
|
+
* and internal-review deleted it. This fail-closed posture was locked by internal-review
|
|
5832
|
+
* (Decision C) and pinned by internal-review. mpp (Tempo) and x402 credentials are
|
|
5833
|
+
* single-use, final-settlement — no SDK-managed reversal path either.
|
|
5834
|
+
*
|
|
5835
|
+
* **This is a rail-level question, and since internal-review it is no longer the whole
|
|
5836
|
+
* story.** A failed job never debits: the draw is a hold the terminal funnel
|
|
5837
|
+
* releases (`JobManager.resolveCreditDraw`), so the value stays on the caller's
|
|
5838
|
+
* credit. What this flag reports is narrower and still true — no rail hands
|
|
5839
|
+
* value backwards — and reclaiming a released balance runs through the
|
|
5840
|
+
* internal-review `drain` op, which exists only on a DVM that advertises credit.
|
|
5841
|
+
*
|
|
5842
|
+
* `{ refund: true }` survives as a **caller-fault annotation only** — first-party
|
|
5843
|
+
* handlers tag which errors were the caller's doing, and `sdk/testing`'s
|
|
5844
|
+
* `createTestContext` exposes it — and it is not a hook waiting to be re-wired.
|
|
5845
|
+
* internal-review, the accumulator-debit rewrite that would have flipped `cashu` back to
|
|
5846
|
+
* `true`, was cancelled as superseded: the ledger is where reclaim lives now.
|
|
5847
|
+
* x402 refund parity remains a deferred internal-review exploration.
|
|
5848
|
+
*/
|
|
5849
|
+
declare const RAIL_REFUNDABLE: Record<PaymentMethod, boolean>;
|
|
4386
5850
|
/**
|
|
4387
5851
|
* Cashu receive mode for builder DVMs (internal-review).
|
|
4388
5852
|
*
|
|
@@ -5346,5 +6810,22 @@ interface OutgoingMessage {
|
|
|
5346
6810
|
* that calls the member it's missing.
|
|
5347
6811
|
*/
|
|
5348
6812
|
declare function isStreamableJobStore(store: JobStore): store is StreamableJobStore;
|
|
6813
|
+
/**
|
|
6814
|
+
* The stale-job reaper surface (internal-review) — the two methods a sweeper needs to
|
|
6815
|
+
* find and atomically reap worker-stranded jobs. A strict subset of
|
|
6816
|
+
* `StreamableJobStore`: `MemoryJobStore` and `PostgresJobStore` satisfy it via
|
|
6817
|
+
* the full streamable interface, and the platform's `IsolateJobStore` (a plain
|
|
6818
|
+
* single-machine `JobStore`, not streamable) implements just these two so the
|
|
6819
|
+
* `IsolateJobManager` reaper can sweep the `isolate_jobs` table without taking
|
|
6820
|
+
* on the streaming/LISTEN machinery it doesn't need.
|
|
6821
|
+
*/
|
|
6822
|
+
interface StaleJobReapable {
|
|
6823
|
+
/** See {@link StreamableJobStore.findStaleJobs}. */
|
|
6824
|
+
findStaleJobs(processingThresholdMs: number, awaitingThresholdMs: number, limit: number, capabilities: string[] | null): Promise<JobRecord[]>;
|
|
6825
|
+
/** See {@link StreamableJobStore.cancelStaleJob}. */
|
|
6826
|
+
cancelStaleJob(jobId: string, expectedActivityBefore: number, reason: string, terminalStatus: "failed" | "cancelled"): Promise<boolean>;
|
|
6827
|
+
}
|
|
6828
|
+
/** Runtime type guard for StaleJobReapable. */
|
|
6829
|
+
declare function isStaleJobReapable(store: JobStore): store is JobStore & StaleJobReapable;
|
|
5349
6830
|
|
|
5350
|
-
export { type
|
|
6831
|
+
export { type PaymentRequired as $, type ApprovalContent as A, type SignedRequestDomain as B, type Currency as C, type DVMConfig as D, SignedRequestError as E, type SignedRequestFailure as F, type SignedRequestReplayStore as G, type SignedRequestSignOpts as H, type IncomingMessage as I, type JobRecord as J, type KVStore as K, type Logger as L, type SignedRequestStatementHeader as M, type SignedRequestVerifier as N, createSignedRequestVerifier as O, type PaymentContent as P, type QuoteConfig as Q, type ResolvedCreditConfig as R, type SDKJobContext as S, isZodSchema as T, UnsupportedCurrencyError as U, signedRequestStatementHeader as V, validateCurrency as W, type JsonValue as X, type FundingReceipt as Y, type ZodLike as Z, type JobReceipt as _, type DVMDescriptor as a, caip2ToX402Network as a$, type X402Version as a0, type MppxCredential as a1, type Message as a2, type MessageType as a3, type MppxChallenge as a4, X402_BATCH_SETTLEMENT_SCHEME as a5, X402_EXACT_SCHEME as a6, type X402Wallet as a7, type X402Config as a8, type X402ExactVersionSupport as a9, PayoutReporter as aA, PostgresTempoSessionStore as aB, RAIL_REFUNDABLE as aC, type ReceiptCredit as aD, type ReceiptOutcome as aE, type ReceiptPayment as aF, type ResourceInfo as aG, RevenueReporter as aH, SIGNED_ENVELOPE_FIELDS as aI, SIGNED_ENVELOPE_TYPES as aJ, type SettleResponse as aK, type StaleJobReapable as aL, StepCache as aM, type StepRecord as aN, type UnsignedDrainReceipt as aO, type UnsignedFundingReceipt as aP, type UnsignedJobReceipt as aQ, type VerifyResponse as aR, type X402ResponseBody as aS, type X402SelfRelayRpcFailureReason as aT, type X402TrackedChannel as aU, X402_DEFAULT_NETWORK as aV, X402_V1_VERSION as aW, X402_VERSION as aX, _testing as aY, buildPaymentRequiredV2 as aZ, buildPaymentRequirements as a_, type X402Receipt as aa, type TransactionalPayoutHook as ab, type CashuMeltCompleted as ac, type BuildPaymentRequirementsOpts as ad, type CapabilityDescriptor as ae, type CashuMode as af, type CreditDepositPayload as ag, type DrainReceipt as ah, type DrainReceiptEvent as ai, type ExactEvmPayload as aj, type ExactEvmPayloadAuthorization as ak, type FundingLot as al, type FundingMethod as am, type LotDebit as an, type LotDepletion as ao, type MppxServer as ap, NON_CHANNEL_BITCOIN_RAILS as aq, type NonChannelBitcoinRail as ar, type OutgoingMessage as as, type PaymentPayload as at, type PaymentPayloadV1 as au, type PaymentPayloadV2 as av, type PaymentRequiredV2 as aw, type PaymentRequirements as ax, type PaymentRequirementsV1 as ay, type PaymentRequirementsV2 as az, type ArtifactContent as b, type DrainRequestResult as b$, canonicaliseForSigning as b0, canonicalize as b1, chainIdFromCaip2 as b2, computeResultHash as b3, createDefaultReplayStore as b4, decodePayment as b5, decodePaymentRequiredHeader as b6, depleteLots as b7, encodePayment as b8, encodePaymentRequiredHeader as b9, verifyWithFacilitator as bA, wrapMppx as bB, x402NetworkToCaip2 as bC, type CreditDrainEnqueue as bD, type DVMAuthScheme as bE, type CreditLedgerLike as bF, type X402RefundSettlementGate as bG, type CreditSnapshot as bH, type DrawResult as bI, type X402SettlementStatus as bJ, type X402UnresolvedRefund as bK, type GrownDrawResult as bL, type DrawResolution as bM, type FundingRecord as bN, type CreditInvoiceRecord as bO, type InvoiceSettlement as bP, type BlockedInvoiceCursor as bQ, type InvoiceReconciliation as bR, type InvoiceWriteOff as bS, type DrawRecord as bT, type StalePendingDrawCursor as bU, type TempoCreditLossEvidence as bV, type CreditLedgerQuerier as bW, type TempoCreditLoss as bX, type X402CreditLossEvidence as bY, type X402CreditLoss as bZ, type DrainMethod as b_, encodeSettleResponseHeader as ba, exactEvmAuthorization as bb, fifoOrder as bc, inKindDrawMsats as bd, isArtifactMessage as be, isDrainReceipt as bf, isFundingReceipt as bg, isInKindDepletion as bh, isNonChannelBitcoinRail as bi, isPaymentRequestMessage as bj, isSignedJobReceipt as bk, isStaleJobReapable as bl, lotOwedSats as bm, netOwedSats as bn, paymentRequiredV2FromV1 as bo, settleWithFacilitator as bp, signDrainReceipt as bq, signFundingReceipt as br, signReceipt as bs, usdcContractByCaip2 as bt, usdcContractFor as bu, usdcDomainNameFor as bv, usdcDomainVersionFor as bw, verifyDrainReceipt as bx, verifyFundingReceipt as by, verifyReceipt as bz, type CancelContent as c, type X402SettlementReconciliationReason as c$, type BitcoinDepositLiability as c0, type CreditDrainRecord as c1, type ChannelDrainCursor as c2, type DrainWriteOff as c3, type DrainReleaseResult as c4, type DrainFulfilment as c5, type DrainTransitionResult as c6, type StreamableJobStore as c7, type ReceiptIssuingStore as c8, type RequestIdClaim as c9, type RevenueSkippedNoRailPayload as cA, type RevenueSkippedNoRailReason as cB, type Secp256k1AuthOpts as cC, type X402ChannelStorageOpts as cD, type X402RelayLockHolder as cE, type X402RelaySubmissionLock as cF, X402RelaySubmissionLockError as cG, allocateDrawValue as cH, clientCompatibilityAttributes as cI, clientCompatibilityMiddleware as cJ, clientUpgradeRequired as cK, isStreamableJobStore as cL, parseClientCapabilities as cM, parseClientCompatibility as cN, parseDvmClient as cO, parseProtocolVersion as cP, requireClientCompatibility as cQ, secp256k1Auth as cR, signedRequestInput as cS, type CreditDepositEnqueue as cT, type TopUpCapUnenforcedReason as cU, type X402SettlementIntent as cV, type X402SettlementCursor as cW, type X402SettlementWriteOff as cX, type X402FacilitatorAuth as cY, type X402BatchSettlementConfig as cZ, type X402PayoutObserver as c_, type RequestIdClaimResult as ca, type AppendOutgoingOptions as cb, type PaymentCreditDelta as cc, type VerifyAndCreditResult as cd, type JobCounters as ce, CLIENT_COMPATIBILITY_HEADERS as cf, type ClientCompatibility as cg, type ClientCompatibilityEnv as ch, type ClientCompatibilityGate as ci, type ClientCompatibilityRequirement as cj, type ClientSemVer as ck, type CreditFundingBasis as cl, type CreditInvoiceStatus as cm, CreditLedger as cn, CreditLedgerError as co, type CreditLedgerErrorCode as cp, type CreditLedgerErrorDetails as cq, type CreditLedgerPool as cr, type CreditStatus as cs, DRAIN_DELIVERY_RESERVE_SATS as ct, DVM_PROTOCOL_VERSION as cu, type DrainConflictReason as cv, type DrawRailValue as cw, type DrawStatus as cx, PostgresX402ChannelStorage as cy, type ReplayStoreBackend as cz, type CanonicalEnvelope as d, type CreditDrawReleaseEnqueue as d0, type CreateSignedRequestVerifierOpts as e, type CreditConfig as f, type CreditView as g, DEFAULT_CREDIT_MAX as h, DEFAULT_CREDIT_MIN as i, DEFAULT_CREDIT_TTL_SECONDS as j, type DVMRouteContext as k, type InputType as l, InvalidCurrencyError as m, type JobStatus as n, type JobStore as o, type PaymentMethod as p, type PriceValue as q, type ProgressContent as r, type PromptOpts as s, type QuoteContext as t, type QuoteResult as u, type ResponseContent as v, type SDKPaymentRequestOpts as w, SIGNED_REQUEST_AUTH_ID as x, SIGNED_REQUEST_STATEMENT_VERSION as y, type SignedRequestAudience as z };
|