@piprail/sdk 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +1 -1
- package/dist/index.cjs +56 -22
- package/dist/index.d.cts +62 -10
- package/dist/index.d.ts +62 -10
- package/dist/index.js +50 -16
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,39 @@ All notable changes to `@piprail/sdk` are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
5
5
|
versions follow [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [2.7.0] — 2026-06-19 — symmetric payment notifications (`onFailed`: both sides notified on success AND failure)
|
|
8
|
+
|
|
9
|
+
Additive and backward-compatible — defaults and the zero-config 402 stay byte-identical; omit the new
|
|
10
|
+
options and behaviour is unchanged.
|
|
11
|
+
|
|
12
|
+
- **New merchant hook `onFailed(failure)`** on `createPaymentGate` / `requirePayment` — the mirror of
|
|
13
|
+
`onPaid`. It fires whenever a SUBMITTED proof is rejected (a `kind:'invalid'` verdict: wrong amount,
|
|
14
|
+
expired, replayed, unknown asset, …), so the merchant is notified of a failure exactly as the buyer's
|
|
15
|
+
client already is. The new `FailedPayment` it receives carries the SAME machine `code` (a
|
|
16
|
+
`VerifyErrorCode`) the buyer gets — one consistent reason on both sides.
|
|
17
|
+
- **`onFailedError(error, failure)`** and **`awaitOnFailed`** mirror `onPaidError` / `awaitOnPaid`: the
|
|
18
|
+
hook is fully isolated (a sync throw or async rejection routes to `onFailedError` — it can never break
|
|
19
|
+
the request or escape as an unhandledRejection), and `awaitOnFailed` runs it before the 402 returns.
|
|
20
|
+
- **Exported `FailedPayment` type** — `{ code, detail, transient }`. The `transient` flag is `true` for
|
|
21
|
+
`tx_not_found` / `insufficient_confirmations` (the proof may still be settling and the buyer's client
|
|
22
|
+
auto-retries — alert on `!transient` to avoid false alarms on RPC lag), `false` for a definitive
|
|
23
|
+
rejection (wrong amount, expired, replayed, bad signature, …). Nothing is hidden — every rejected
|
|
24
|
+
attempt still fires `onFailed`.
|
|
25
|
+
- **Buyer side:** the `payment-failed` client event now also carries structured `code` / `detail` (the
|
|
26
|
+
server's parsed reason) alongside the existing human `reason`. It now ALSO fires on a **pre-send
|
|
27
|
+
decline** (policy / `onBeforePay` / no settleable rail) — previously those only threw — so a consumer
|
|
28
|
+
watching `onEvent` learns of EVERY failure, not just server rejections (the typed throw is unchanged).
|
|
29
|
+
- **Fires only on a real rejection** — not on a normal first-request `challenge` (no proof yet), and not
|
|
30
|
+
on a transient/settlement error that throws (an RPC blip, or a 5xx `SettlementError`): those aren't
|
|
31
|
+
payment verdicts. A failure the merchant never receives a request for (insufficient funds, policy
|
|
32
|
+
decline, abandonment) reaches only the buyer — a backendless gate is passive by design.
|
|
33
|
+
- **Examples + tests:** a complete `examples/payment-system/` reference (merchant + buyer — both sides,
|
|
34
|
+
success + failure → a SQLite ledger with a free `/ledger` dashboard); `onFailed` added to the Express +
|
|
35
|
+
Next.js examples. Coverage spans every `VerifyErrorCode`, both rails, the `requirePayment` middleware,
|
|
36
|
+
the `transient` flag, concurrency, replay-after-success, that a thrown `SettlementError`/transient error
|
|
37
|
+
does NOT fire `onFailed`, buyer declines, and a full client↔gate HTTP loop proving both sides receive
|
|
38
|
+
the same `code`.
|
|
39
|
+
|
|
7
40
|
## [2.6.0] — 2026-06-18 — keyless-gasless `exact` on 7 more EVM mainnets (6 → 13 chains)
|
|
8
41
|
|
|
9
42
|
Additive and backward-compatible — defaults and the zero-config 402 stay byte-identical; this only
|
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ app.get('/report',
|
|
|
24
24
|
)
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
That route now costs **0.05 USDC on Base**, paid straight to your wallet. One parameter picks the chain. → [Accepting payments](https://docs.piprail.com/accepting-payments/require-payment-and-gate/)
|
|
27
|
+
That route now costs **0.05 USDC on Base**, paid straight to your wallet. One parameter picks the chain. Add `onPaid` / `onFailed` to be notified the moment a payment settles or is rejected — both carry the same reason, and the buyer's client is notified too. → [Accepting payments](https://docs.piprail.com/accepting-payments/require-payment-and-gate/)
|
|
28
28
|
|
|
29
29
|
## Let an agent pay for it
|
|
30
30
|
|
package/dist/index.cjs
CHANGED
|
@@ -3212,7 +3212,9 @@ var PipRailClient = (_class2 = class {
|
|
|
3212
3212
|
if (autoRoute) {
|
|
3213
3213
|
const plan = await this.planFromChallenge(net, wallet, challenge, url, schemes);
|
|
3214
3214
|
if (!plan.best) {
|
|
3215
|
-
|
|
3215
|
+
const reason = _nullishCoalesce(plan.fundingHint, () => ( "No rail is settleable for this payment."));
|
|
3216
|
+
this.safeEmit({ kind: "payment-failed", reason });
|
|
3217
|
+
throw new (0, _chunkJG6KRAW6cjs.PaymentDeclinedError)(reason);
|
|
3216
3218
|
}
|
|
3217
3219
|
accept = plan.best.accept;
|
|
3218
3220
|
quote = plan.best.quote;
|
|
@@ -3502,10 +3504,10 @@ var PipRailClient = (_class2 = class {
|
|
|
3502
3504
|
* TERMINAL expiry/approval decline it must not retry) without parsing prose. */
|
|
3503
3505
|
async authorize(quote) {
|
|
3504
3506
|
if (!quote.withinPolicy) {
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
);
|
|
3507
|
+
const reason = `Payment refused by policy: ${_nullishCoalesce(quote.policyReason, () => ( "not allowed"))}`;
|
|
3508
|
+
const reasonCode = reasonCodeForPolicy(quote.policyCode);
|
|
3509
|
+
this.safeEmit({ kind: "payment-failed", reason, code: reasonCode });
|
|
3510
|
+
throw new (0, _chunkJG6KRAW6cjs.PaymentDeclinedError)(reason, { reasonCode });
|
|
3509
3511
|
}
|
|
3510
3512
|
const hook = this.opts.onBeforePay;
|
|
3511
3513
|
if (!hook) return;
|
|
@@ -3513,16 +3515,14 @@ var PipRailClient = (_class2 = class {
|
|
|
3513
3515
|
try {
|
|
3514
3516
|
approved = await hook(quote);
|
|
3515
3517
|
} catch (err) {
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
});
|
|
3518
|
+
const reason = "onBeforePay threw \u2014 refusing to pay.";
|
|
3519
|
+
this.safeEmit({ kind: "payment-failed", reason, code: "APPROVAL" });
|
|
3520
|
+
throw new (0, _chunkJG6KRAW6cjs.PaymentDeclinedError)(reason, { cause: err, reasonCode: "APPROVAL" });
|
|
3520
3521
|
}
|
|
3521
3522
|
if (!approved) {
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
);
|
|
3523
|
+
const reason = `onBeforePay declined ${quote.amountFormatted} ${_nullishCoalesce(quote.symbol, () => ( ""))}`.trimEnd() + ` on ${quote.network}.`;
|
|
3524
|
+
this.safeEmit({ kind: "payment-failed", reason, code: "APPROVAL" });
|
|
3525
|
+
throw new (0, _chunkJG6KRAW6cjs.PaymentDeclinedError)(reason, { reasonCode: "APPROVAL" });
|
|
3526
3526
|
}
|
|
3527
3527
|
}
|
|
3528
3528
|
/** Record a settled payment in the ledger (true decimals for the running total). */
|
|
@@ -3617,7 +3617,8 @@ var PipRailClient = (_class2 = class {
|
|
|
3617
3617
|
const unconfirmedNote = confirmed ? "" : " (broadcast but NOT locally confirmed \u2014 it may still have settled on-chain)";
|
|
3618
3618
|
this.safeEmit({
|
|
3619
3619
|
kind: "payment-failed",
|
|
3620
|
-
reason: `server returned 402 after broadcasting payment ${ref}${unconfirmedNote} (${why})
|
|
3620
|
+
reason: `server returned 402 after broadcasting payment ${ref}${unconfirmedNote} (${why})`,
|
|
3621
|
+
...lastReason ? { code: lastReason.error, detail: lastReason.detail } : {}
|
|
3621
3622
|
});
|
|
3622
3623
|
throw new (0, _chunkJG6KRAW6cjs.MaxRetriesExceededError)(
|
|
3623
3624
|
`Server still returned 402 after ${attempts} attempt(s) with on-chain proof ref=${ref}${unconfirmedNote}. Last server rejection: ${why}. Re-verify or re-submit ref=${ref} before retrying \u2014 never re-pay (it would double-spend).`,
|
|
@@ -3652,7 +3653,7 @@ var PipRailClient = (_class2 = class {
|
|
|
3652
3653
|
const headers = new Headers(_optionalChain([init, 'optionalAccess', _49 => _49.headers]));
|
|
3653
3654
|
headers.set(HEADER_SIGNATURE, buildExactSignatureHeader({ accepted, payload }));
|
|
3654
3655
|
const rejectDefinitive = (why2) => {
|
|
3655
|
-
this.safeEmit({ kind: "payment-failed", reason: `exact: facilitator rejected nonce=${nonce} (${why2})
|
|
3656
|
+
this.safeEmit({ kind: "payment-failed", reason: `exact: facilitator rejected nonce=${nonce} (${why2})`, code: why2 });
|
|
3656
3657
|
throw new (0, _chunkJG6KRAW6cjs.MaxRetriesExceededError)(
|
|
3657
3658
|
`exact: the facilitator rejected the payment (${why2}). Fix the cause, then re-present the SAME signed authorization (nonce=${nonce}) \u2014 do NOT re-sign a fresh nonce. ref=${nonce}.`,
|
|
3658
3659
|
{ ref: nonce }
|
|
@@ -3707,7 +3708,8 @@ var PipRailClient = (_class2 = class {
|
|
|
3707
3708
|
const why = lastReason ? `${lastReason.error}${lastReason.detail ? ` \u2014 ${lastReason.detail}` : ""}` : "server gave no reason";
|
|
3708
3709
|
this.safeEmit({
|
|
3709
3710
|
kind: "payment-failed",
|
|
3710
|
-
reason: `exact: 402 after submitting authorization nonce=${nonce} (${why})
|
|
3711
|
+
reason: `exact: 402 after submitting authorization nonce=${nonce} (${why})`,
|
|
3712
|
+
...lastReason ? { code: lastReason.error, detail: lastReason.detail } : {}
|
|
3711
3713
|
});
|
|
3712
3714
|
throw new (0, _chunkJG6KRAW6cjs.MaxRetriesExceededError)(
|
|
3713
3715
|
`exact: server still returned 402 after submitting the signed authorization (nonce=${nonce}). Last rejection: ${why}. Re-present the SAME authorization \u2014 do NOT re-sign a fresh nonce; verify authorizationState(${payerFrom}, ${nonce}) first. ref=${nonce}.`,
|
|
@@ -5260,6 +5262,7 @@ function normaliseExactOption(exact) {
|
|
|
5260
5262
|
if (exact === true) return { settle: "keyless" };
|
|
5261
5263
|
return exact;
|
|
5262
5264
|
}
|
|
5265
|
+
var TRANSIENT_VERIFY_CODES = /* @__PURE__ */ new Set(["tx_not_found", "insufficient_confirmations"]);
|
|
5263
5266
|
function createPaymentGate(options) {
|
|
5264
5267
|
const minConfirmations = _nullishCoalesce(options.minConfirmations, () => ( 1));
|
|
5265
5268
|
const maxTimeoutSeconds = _nullishCoalesce(options.maxTimeoutSeconds, () => ( 600));
|
|
@@ -5544,6 +5547,32 @@ function createPaymentGate(options) {
|
|
|
5544
5547
|
if (options.awaitOnPaid) await fireOnPaid(paid);
|
|
5545
5548
|
else void fireOnPaid(paid);
|
|
5546
5549
|
}
|
|
5550
|
+
function reportOnFailedError(error, failure) {
|
|
5551
|
+
if (!options.onFailedError) return;
|
|
5552
|
+
try {
|
|
5553
|
+
options.onFailedError(error, failure);
|
|
5554
|
+
} catch (e38) {
|
|
5555
|
+
}
|
|
5556
|
+
}
|
|
5557
|
+
function fireOnFailed(failure) {
|
|
5558
|
+
if (!options.onFailed) return;
|
|
5559
|
+
let outcome;
|
|
5560
|
+
try {
|
|
5561
|
+
outcome = options.onFailed(failure);
|
|
5562
|
+
} catch (err) {
|
|
5563
|
+
reportOnFailedError(err, failure);
|
|
5564
|
+
return;
|
|
5565
|
+
}
|
|
5566
|
+
if (outcome != null && typeof outcome.then === "function") {
|
|
5567
|
+
return Promise.resolve(outcome).catch((err) => reportOnFailedError(err, failure));
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
async function deliverOnFailed(result) {
|
|
5571
|
+
const code = result.error;
|
|
5572
|
+
const failure = { code, detail: result.detail, transient: TRANSIENT_VERIFY_CODES.has(code) };
|
|
5573
|
+
if (options.awaitOnFailed) await fireOnFailed(failure);
|
|
5574
|
+
else void fireOnFailed(failure);
|
|
5575
|
+
}
|
|
5547
5576
|
async function describe(resourceUrl = "") {
|
|
5548
5577
|
const specs = await ready();
|
|
5549
5578
|
const accepts = [];
|
|
@@ -5622,28 +5651,28 @@ function createPaymentGate(options) {
|
|
|
5622
5651
|
nonce = [exact.payload.transaction, exact.payload.senderAuth].map((t) => {
|
|
5623
5652
|
try {
|
|
5624
5653
|
return Buffer.from(t, "base64").toString("base64");
|
|
5625
|
-
} catch (
|
|
5654
|
+
} catch (e39) {
|
|
5626
5655
|
return t;
|
|
5627
5656
|
}
|
|
5628
5657
|
}).join("|");
|
|
5629
5658
|
} else if ("transaction" in exact.payload) {
|
|
5630
5659
|
try {
|
|
5631
5660
|
nonce = Buffer.from(exact.payload.transaction, "base64").toString("base64");
|
|
5632
|
-
} catch (
|
|
5661
|
+
} catch (e40) {
|
|
5633
5662
|
nonce = exact.payload.transaction;
|
|
5634
5663
|
}
|
|
5635
5664
|
} else if ("paymentGroup" in exact.payload) {
|
|
5636
5665
|
nonce = exact.payload.paymentGroup.map((t) => {
|
|
5637
5666
|
try {
|
|
5638
5667
|
return Buffer.from(t, "base64").toString("base64");
|
|
5639
|
-
} catch (
|
|
5668
|
+
} catch (e41) {
|
|
5640
5669
|
return t;
|
|
5641
5670
|
}
|
|
5642
5671
|
}).join("|");
|
|
5643
5672
|
} else if ("signedDelegateAction" in exact.payload) {
|
|
5644
5673
|
try {
|
|
5645
5674
|
nonce = Buffer.from(exact.payload.signedDelegateAction, "base64").toString("base64");
|
|
5646
|
-
} catch (
|
|
5675
|
+
} catch (e42) {
|
|
5647
5676
|
nonce = exact.payload.signedDelegateAction;
|
|
5648
5677
|
}
|
|
5649
5678
|
} else if ("permit2Authorization" in exact.payload) {
|
|
@@ -5707,6 +5736,11 @@ function createPaymentGate(options) {
|
|
|
5707
5736
|
return { kind: "paid", receipt: result.receipt, receiptHeader: buildReceiptHeader(result.receipt) };
|
|
5708
5737
|
}
|
|
5709
5738
|
async function verify(paymentSignature) {
|
|
5739
|
+
const result = await resolveVerdict(paymentSignature);
|
|
5740
|
+
if (result.kind === "invalid") await deliverOnFailed(result);
|
|
5741
|
+
return result;
|
|
5742
|
+
}
|
|
5743
|
+
async function resolveVerdict(paymentSignature) {
|
|
5710
5744
|
const raw = normaliseHeader(paymentSignature);
|
|
5711
5745
|
if (!raw) return asChallenge();
|
|
5712
5746
|
const sig = parseSignatureHeader(raw);
|
|
@@ -5784,7 +5818,7 @@ async function signBody(secret, body) {
|
|
|
5784
5818
|
const sig = await subtle.sign("HMAC", key, enc.encode(body));
|
|
5785
5819
|
const hex = Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
5786
5820
|
return `sha256=${hex}`;
|
|
5787
|
-
} catch (
|
|
5821
|
+
} catch (e43) {
|
|
5788
5822
|
return null;
|
|
5789
5823
|
}
|
|
5790
5824
|
}
|
|
@@ -5845,7 +5879,7 @@ async function deliverReceipt(receipt, options) {
|
|
|
5845
5879
|
const willRetry = !ok && retryable && attempt < maxAttempts;
|
|
5846
5880
|
try {
|
|
5847
5881
|
_optionalChain([onAttempt, 'optionalCall', _91 => _91({ attempt, ok, ...status !== void 0 ? { status } : {}, ...error ? { error } : {}, willRetry })]);
|
|
5848
|
-
} catch (
|
|
5882
|
+
} catch (e44) {
|
|
5849
5883
|
}
|
|
5850
5884
|
if (ok) return { delivered: true, attempts: attempt, status };
|
|
5851
5885
|
if (!willRetry) {
|
package/dist/index.d.cts
CHANGED
|
@@ -5044,6 +5044,14 @@ type PipRailEvent = {
|
|
|
5044
5044
|
} | {
|
|
5045
5045
|
kind: 'payment-failed';
|
|
5046
5046
|
reason: string;
|
|
5047
|
+
/** A machine-readable failure code when one is known. For a SERVER rejection it's the SAME
|
|
5048
|
+
* code the merchant's `onFailed` hook receives (a canonical {@link VerifyErrorCode} from a
|
|
5049
|
+
* PipRail gate, or a foreign facilitator's reason string); for a pre-send client DECLINE
|
|
5050
|
+
* (policy / budget / approval) it's that decline reason (e.g. `'BUDGET'`, `'APPROVAL'`).
|
|
5051
|
+
* Absent when no structured code was given. */
|
|
5052
|
+
code?: string;
|
|
5053
|
+
/** Human-readable detail, when present (e.g. `"Paid 40000, required 500000."`). */
|
|
5054
|
+
detail?: string;
|
|
5047
5055
|
};
|
|
5048
5056
|
/**
|
|
5049
5057
|
* Wallet for the chosen chain family. **One field, every chain: `{ key }`** — the
|
|
@@ -6463,6 +6471,28 @@ interface ExactRailOption {
|
|
|
6463
6471
|
* "just works". Force `'eip3009'` or `'permit2'` to pin one. Ignored on Solana (always SVM). */
|
|
6464
6472
|
method?: 'eip3009' | 'permit2' | 'auto';
|
|
6465
6473
|
}
|
|
6474
|
+
/**
|
|
6475
|
+
* The merchant-side mirror of {@link PaidReceipt}: what an {@link RequirePaymentOptions.onFailed}
|
|
6476
|
+
* hook receives when a SUBMITTED payment proof is REJECTED. It carries the SAME machine-readable
|
|
6477
|
+
* `code` the buyer's client is given for that rejection, so both sides are notified of one
|
|
6478
|
+
* consistent reason. (A rejection has no settlement, so — unlike a receipt — there is no tx hash
|
|
6479
|
+
* or settled amount to report.)
|
|
6480
|
+
*/
|
|
6481
|
+
interface FailedPayment {
|
|
6482
|
+
/** The canonical rejection reason — the same {@link VerifyErrorCode} surfaced to the buyer
|
|
6483
|
+
* (e.g. `amount_too_low`, `payment_expired`, `tx_already_used`, `transfer_not_found`). */
|
|
6484
|
+
code: VerifyErrorCode;
|
|
6485
|
+
/** Human-readable detail, e.g. `"Paid 40000, required 500000."`. */
|
|
6486
|
+
detail: string;
|
|
6487
|
+
/**
|
|
6488
|
+
* `true` for a **transient** rejection (`tx_not_found` / `insufficient_confirmations`): the proof
|
|
6489
|
+
* may still be settling and the buyer's client **retries automatically** — you'll get `onPaid` if
|
|
6490
|
+
* it then succeeds. `false` for a **definitive** rejection the buyer must fix (wrong amount,
|
|
6491
|
+
* expired, replayed, bad signature, wrong recipient). Alert on `!transient` to avoid false alarms
|
|
6492
|
+
* on normal RPC lag; nothing is hidden — every rejected attempt still fires `onFailed`.
|
|
6493
|
+
*/
|
|
6494
|
+
transient: boolean;
|
|
6495
|
+
}
|
|
6466
6496
|
interface RequirePaymentOptions {
|
|
6467
6497
|
/**
|
|
6468
6498
|
* Single-chain form: which chain to accept payment on. EVM ('bnb'|'base'|…),
|
|
@@ -6535,6 +6565,37 @@ interface RequirePaymentOptions {
|
|
|
6535
6565
|
* via `onPaidError`; it never turns a settled payment into a 402.
|
|
6536
6566
|
*/
|
|
6537
6567
|
awaitOnPaid?: boolean;
|
|
6568
|
+
/**
|
|
6569
|
+
* The merchant-side mirror of `onPaid`: fired when a SUBMITTED payment proof is REJECTED — a
|
|
6570
|
+
* `kind:'invalid'` verdict (wrong amount, expired, replayed, unknown asset, …). Receives a
|
|
6571
|
+
* {@link FailedPayment} carrying the SAME machine `code` the buyer's client is given, so the
|
|
6572
|
+
* merchant and the buyer are notified of the same failure with the same reason.
|
|
6573
|
+
*
|
|
6574
|
+
* Fires ONLY on a rejected attempt — NOT on a normal first-request 402 `challenge` (no proof
|
|
6575
|
+
* yet), and NOT on a transient/settlement error that throws (an RPC blip, or a 5xx
|
|
6576
|
+
* `SettlementError`): those aren't payment verdicts. Like `onPaid`, it may be **sync or async**
|
|
6577
|
+
* and is fully isolated — a throw OR a rejected promise is caught and routed to `onFailedError`,
|
|
6578
|
+
* so it can never break the request or crash the process. Fire-and-forget by default; set
|
|
6579
|
+
* `awaitOnFailed` to run it before the 402 is returned.
|
|
6580
|
+
*
|
|
6581
|
+
* NOTE: a failure the merchant never receives a request for — the buyer can't afford it, an
|
|
6582
|
+
* `onBeforePay`/`policy` declines it, or the buyer abandons before paying — cannot reach a
|
|
6583
|
+
* backendless gate (only the buyer's client sees it). `onFailed` covers every rejection that
|
|
6584
|
+
* DOES reach the gate.
|
|
6585
|
+
*/
|
|
6586
|
+
onFailed?: (failure: FailedPayment) => void | Promise<void>;
|
|
6587
|
+
/**
|
|
6588
|
+
* Observe a failure inside `onFailed` (sync throw or async rejection) — the mirror of
|
|
6589
|
+
* `onPaidError`. Without it, a throwing `onFailed` is swallowed silently. Its own throws are
|
|
6590
|
+
* also swallowed (it can never break a request).
|
|
6591
|
+
*/
|
|
6592
|
+
onFailedError?: (error: unknown, failure: FailedPayment) => void;
|
|
6593
|
+
/**
|
|
6594
|
+
* Await `onFailed` before the 402 rejection is returned (mirror of `awaitOnPaid`), so
|
|
6595
|
+
* "failure recorded" is guaranteed before the caller is told. Default `false` (fire-and-forget).
|
|
6596
|
+
* A rejection inside the hook is still isolated via `onFailedError`.
|
|
6597
|
+
*/
|
|
6598
|
+
awaitOnFailed?: boolean;
|
|
6538
6599
|
/**
|
|
6539
6600
|
* ALSO advertise a standard x402 `exact` rail so any standard x402 client can pay this
|
|
6540
6601
|
* gate — opt-in, EVM (EIP-3009/Permit2) + Solana (SVM). See {@link ExactRailOption}.
|
|
@@ -6639,15 +6700,6 @@ interface PaymentGate {
|
|
|
6639
6700
|
*/
|
|
6640
6701
|
landingPage(challenge: X402Challenge): string;
|
|
6641
6702
|
}
|
|
6642
|
-
/**
|
|
6643
|
-
* Framework-agnostic core. Build one gate per gated resource and reuse it
|
|
6644
|
-
* — its in-memory used-tx set is what stops the same proof being redeemed
|
|
6645
|
-
* twice. Wrap it for Express with `requirePayment`, or call it directly
|
|
6646
|
-
* from Hono / Fastify / Adonis / Workers / etc.
|
|
6647
|
-
*
|
|
6648
|
-
* The chain's driver is resolved lazily on first `challenge()`/`verify()`,
|
|
6649
|
-
* which is what lets Solana (and future families) auto-mount with no setup.
|
|
6650
|
-
*/
|
|
6651
6703
|
declare function createPaymentGate(options: RequirePaymentOptions): PaymentGate;
|
|
6652
6704
|
interface ExpressLikeRequest {
|
|
6653
6705
|
headers: Record<string, string | string[] | undefined>;
|
|
@@ -7527,4 +7579,4 @@ declare const PERMIT2_WITNESS_TYPES: {
|
|
|
7527
7579
|
*/
|
|
7528
7580
|
declare function renderLandingPage(sd: SelfDescription): string;
|
|
7529
7581
|
|
|
7530
|
-
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, BRAND, type BazaarExtension, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ChallengeTriage, type ChallengeVerdict, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DeclineReasonCode, type DeliverAttempt, type DeliverReceiptOptions, type DeliverResult, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoveryDescriptor, type DiscoverySigner, type DiscoverySort, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactPaymentPayloadAny, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, type FacilitatorSupportedKind, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, KNOWN_FACILITATORS, type KnownFacilitator, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, MultiChainPayer, type MultiChainPayerOptions, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, PERMIT2_ADDRESS, PERMIT2_PROXY_CHAIN_IDS, PERMIT2_WITNESS_TYPES, PIPRAIL_AGENT_GUIDE, POWERED_BY, type PaidReceipt, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, type PayingClient, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, type PaymentScheme, PaymentTimeoutError, type Permit2Authorization, type Permit2PaymentPayload, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, type PolicyDenyCode, REGISTER_ATTRIBUTION, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SelfDescribeEndpoint, type SelfDescribeRail, type SelfDescription, type SessionBudget, type SettleOutcome, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendRemaining, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, UnsupportedSchemeError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, WalletRequiredError, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, X402_EXACT_PERMIT2_PROXY, type XrplToken, agentGuide, appendAttribution, appendKeywords, buildBazaarExtension, buildChallengeHeader, buildEndpointInfo, buildExactAuthorization, buildExactSignatureHeader, buildOpenApi, buildReceiptHeader, buildSelfDescription, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, classifyChallenge, createPaymentGate, decorateOutcome, deliverReceipt, describeChallenge, discoveryHeaders, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, explainDecline, facilitatorCoverage, fetchAcross, firstKeylessFacilitator, formatSpendReport, getDirectoryInfo, isPermit2ProxyChain, knownFacilitatorsFor, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseFacilitatorSupported, parseReceipt, parseSettleResponse, parseSignatureHeader, paymentTools, pickAccept, planAcross, rankResources, readExactDomain, register402Index, registerDriver, registerX402Scan, renderLandingPage, requirePayment, resolveChain, scoreResource, searchOpenIndexes, settleViaFacilitator, summarizePlan, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
|
|
7582
|
+
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, BRAND, type BazaarExtension, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ChallengeTriage, type ChallengeVerdict, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DeclineReasonCode, type DeliverAttempt, type DeliverReceiptOptions, type DeliverResult, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoveryDescriptor, type DiscoverySigner, type DiscoverySort, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactPaymentPayloadAny, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, type FacilitatorSupportedKind, type FailedPayment, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, KNOWN_FACILITATORS, type KnownFacilitator, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, MultiChainPayer, type MultiChainPayerOptions, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, PERMIT2_ADDRESS, PERMIT2_PROXY_CHAIN_IDS, PERMIT2_WITNESS_TYPES, PIPRAIL_AGENT_GUIDE, POWERED_BY, type PaidReceipt, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, type PayingClient, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, type PaymentScheme, PaymentTimeoutError, type Permit2Authorization, type Permit2PaymentPayload, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, type PolicyDenyCode, REGISTER_ATTRIBUTION, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SelfDescribeEndpoint, type SelfDescribeRail, type SelfDescription, type SessionBudget, type SettleOutcome, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendRemaining, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, UnsupportedSchemeError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, WalletRequiredError, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, X402_EXACT_PERMIT2_PROXY, type XrplToken, agentGuide, appendAttribution, appendKeywords, buildBazaarExtension, buildChallengeHeader, buildEndpointInfo, buildExactAuthorization, buildExactSignatureHeader, buildOpenApi, buildReceiptHeader, buildSelfDescription, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, classifyChallenge, createPaymentGate, decorateOutcome, deliverReceipt, describeChallenge, discoveryHeaders, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, explainDecline, facilitatorCoverage, fetchAcross, firstKeylessFacilitator, formatSpendReport, getDirectoryInfo, isPermit2ProxyChain, knownFacilitatorsFor, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseFacilitatorSupported, parseReceipt, parseSettleResponse, parseSignatureHeader, paymentTools, pickAccept, planAcross, rankResources, readExactDomain, register402Index, registerDriver, registerX402Scan, renderLandingPage, requirePayment, resolveChain, scoreResource, searchOpenIndexes, settleViaFacilitator, summarizePlan, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
|
package/dist/index.d.ts
CHANGED
|
@@ -5044,6 +5044,14 @@ type PipRailEvent = {
|
|
|
5044
5044
|
} | {
|
|
5045
5045
|
kind: 'payment-failed';
|
|
5046
5046
|
reason: string;
|
|
5047
|
+
/** A machine-readable failure code when one is known. For a SERVER rejection it's the SAME
|
|
5048
|
+
* code the merchant's `onFailed` hook receives (a canonical {@link VerifyErrorCode} from a
|
|
5049
|
+
* PipRail gate, or a foreign facilitator's reason string); for a pre-send client DECLINE
|
|
5050
|
+
* (policy / budget / approval) it's that decline reason (e.g. `'BUDGET'`, `'APPROVAL'`).
|
|
5051
|
+
* Absent when no structured code was given. */
|
|
5052
|
+
code?: string;
|
|
5053
|
+
/** Human-readable detail, when present (e.g. `"Paid 40000, required 500000."`). */
|
|
5054
|
+
detail?: string;
|
|
5047
5055
|
};
|
|
5048
5056
|
/**
|
|
5049
5057
|
* Wallet for the chosen chain family. **One field, every chain: `{ key }`** — the
|
|
@@ -6463,6 +6471,28 @@ interface ExactRailOption {
|
|
|
6463
6471
|
* "just works". Force `'eip3009'` or `'permit2'` to pin one. Ignored on Solana (always SVM). */
|
|
6464
6472
|
method?: 'eip3009' | 'permit2' | 'auto';
|
|
6465
6473
|
}
|
|
6474
|
+
/**
|
|
6475
|
+
* The merchant-side mirror of {@link PaidReceipt}: what an {@link RequirePaymentOptions.onFailed}
|
|
6476
|
+
* hook receives when a SUBMITTED payment proof is REJECTED. It carries the SAME machine-readable
|
|
6477
|
+
* `code` the buyer's client is given for that rejection, so both sides are notified of one
|
|
6478
|
+
* consistent reason. (A rejection has no settlement, so — unlike a receipt — there is no tx hash
|
|
6479
|
+
* or settled amount to report.)
|
|
6480
|
+
*/
|
|
6481
|
+
interface FailedPayment {
|
|
6482
|
+
/** The canonical rejection reason — the same {@link VerifyErrorCode} surfaced to the buyer
|
|
6483
|
+
* (e.g. `amount_too_low`, `payment_expired`, `tx_already_used`, `transfer_not_found`). */
|
|
6484
|
+
code: VerifyErrorCode;
|
|
6485
|
+
/** Human-readable detail, e.g. `"Paid 40000, required 500000."`. */
|
|
6486
|
+
detail: string;
|
|
6487
|
+
/**
|
|
6488
|
+
* `true` for a **transient** rejection (`tx_not_found` / `insufficient_confirmations`): the proof
|
|
6489
|
+
* may still be settling and the buyer's client **retries automatically** — you'll get `onPaid` if
|
|
6490
|
+
* it then succeeds. `false` for a **definitive** rejection the buyer must fix (wrong amount,
|
|
6491
|
+
* expired, replayed, bad signature, wrong recipient). Alert on `!transient` to avoid false alarms
|
|
6492
|
+
* on normal RPC lag; nothing is hidden — every rejected attempt still fires `onFailed`.
|
|
6493
|
+
*/
|
|
6494
|
+
transient: boolean;
|
|
6495
|
+
}
|
|
6466
6496
|
interface RequirePaymentOptions {
|
|
6467
6497
|
/**
|
|
6468
6498
|
* Single-chain form: which chain to accept payment on. EVM ('bnb'|'base'|…),
|
|
@@ -6535,6 +6565,37 @@ interface RequirePaymentOptions {
|
|
|
6535
6565
|
* via `onPaidError`; it never turns a settled payment into a 402.
|
|
6536
6566
|
*/
|
|
6537
6567
|
awaitOnPaid?: boolean;
|
|
6568
|
+
/**
|
|
6569
|
+
* The merchant-side mirror of `onPaid`: fired when a SUBMITTED payment proof is REJECTED — a
|
|
6570
|
+
* `kind:'invalid'` verdict (wrong amount, expired, replayed, unknown asset, …). Receives a
|
|
6571
|
+
* {@link FailedPayment} carrying the SAME machine `code` the buyer's client is given, so the
|
|
6572
|
+
* merchant and the buyer are notified of the same failure with the same reason.
|
|
6573
|
+
*
|
|
6574
|
+
* Fires ONLY on a rejected attempt — NOT on a normal first-request 402 `challenge` (no proof
|
|
6575
|
+
* yet), and NOT on a transient/settlement error that throws (an RPC blip, or a 5xx
|
|
6576
|
+
* `SettlementError`): those aren't payment verdicts. Like `onPaid`, it may be **sync or async**
|
|
6577
|
+
* and is fully isolated — a throw OR a rejected promise is caught and routed to `onFailedError`,
|
|
6578
|
+
* so it can never break the request or crash the process. Fire-and-forget by default; set
|
|
6579
|
+
* `awaitOnFailed` to run it before the 402 is returned.
|
|
6580
|
+
*
|
|
6581
|
+
* NOTE: a failure the merchant never receives a request for — the buyer can't afford it, an
|
|
6582
|
+
* `onBeforePay`/`policy` declines it, or the buyer abandons before paying — cannot reach a
|
|
6583
|
+
* backendless gate (only the buyer's client sees it). `onFailed` covers every rejection that
|
|
6584
|
+
* DOES reach the gate.
|
|
6585
|
+
*/
|
|
6586
|
+
onFailed?: (failure: FailedPayment) => void | Promise<void>;
|
|
6587
|
+
/**
|
|
6588
|
+
* Observe a failure inside `onFailed` (sync throw or async rejection) — the mirror of
|
|
6589
|
+
* `onPaidError`. Without it, a throwing `onFailed` is swallowed silently. Its own throws are
|
|
6590
|
+
* also swallowed (it can never break a request).
|
|
6591
|
+
*/
|
|
6592
|
+
onFailedError?: (error: unknown, failure: FailedPayment) => void;
|
|
6593
|
+
/**
|
|
6594
|
+
* Await `onFailed` before the 402 rejection is returned (mirror of `awaitOnPaid`), so
|
|
6595
|
+
* "failure recorded" is guaranteed before the caller is told. Default `false` (fire-and-forget).
|
|
6596
|
+
* A rejection inside the hook is still isolated via `onFailedError`.
|
|
6597
|
+
*/
|
|
6598
|
+
awaitOnFailed?: boolean;
|
|
6538
6599
|
/**
|
|
6539
6600
|
* ALSO advertise a standard x402 `exact` rail so any standard x402 client can pay this
|
|
6540
6601
|
* gate — opt-in, EVM (EIP-3009/Permit2) + Solana (SVM). See {@link ExactRailOption}.
|
|
@@ -6639,15 +6700,6 @@ interface PaymentGate {
|
|
|
6639
6700
|
*/
|
|
6640
6701
|
landingPage(challenge: X402Challenge): string;
|
|
6641
6702
|
}
|
|
6642
|
-
/**
|
|
6643
|
-
* Framework-agnostic core. Build one gate per gated resource and reuse it
|
|
6644
|
-
* — its in-memory used-tx set is what stops the same proof being redeemed
|
|
6645
|
-
* twice. Wrap it for Express with `requirePayment`, or call it directly
|
|
6646
|
-
* from Hono / Fastify / Adonis / Workers / etc.
|
|
6647
|
-
*
|
|
6648
|
-
* The chain's driver is resolved lazily on first `challenge()`/`verify()`,
|
|
6649
|
-
* which is what lets Solana (and future families) auto-mount with no setup.
|
|
6650
|
-
*/
|
|
6651
6703
|
declare function createPaymentGate(options: RequirePaymentOptions): PaymentGate;
|
|
6652
6704
|
interface ExpressLikeRequest {
|
|
6653
6705
|
headers: Record<string, string | string[] | undefined>;
|
|
@@ -7527,4 +7579,4 @@ declare const PERMIT2_WITNESS_TYPES: {
|
|
|
7527
7579
|
*/
|
|
7528
7580
|
declare function renderLandingPage(sd: SelfDescription): string;
|
|
7529
7581
|
|
|
7530
|
-
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, BRAND, type BazaarExtension, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ChallengeTriage, type ChallengeVerdict, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DeclineReasonCode, type DeliverAttempt, type DeliverReceiptOptions, type DeliverResult, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoveryDescriptor, type DiscoverySigner, type DiscoverySort, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactPaymentPayloadAny, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, type FacilitatorSupportedKind, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, KNOWN_FACILITATORS, type KnownFacilitator, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, MultiChainPayer, type MultiChainPayerOptions, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, PERMIT2_ADDRESS, PERMIT2_PROXY_CHAIN_IDS, PERMIT2_WITNESS_TYPES, PIPRAIL_AGENT_GUIDE, POWERED_BY, type PaidReceipt, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, type PayingClient, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, type PaymentScheme, PaymentTimeoutError, type Permit2Authorization, type Permit2PaymentPayload, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, type PolicyDenyCode, REGISTER_ATTRIBUTION, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SelfDescribeEndpoint, type SelfDescribeRail, type SelfDescription, type SessionBudget, type SettleOutcome, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendRemaining, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, UnsupportedSchemeError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, WalletRequiredError, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, X402_EXACT_PERMIT2_PROXY, type XrplToken, agentGuide, appendAttribution, appendKeywords, buildBazaarExtension, buildChallengeHeader, buildEndpointInfo, buildExactAuthorization, buildExactSignatureHeader, buildOpenApi, buildReceiptHeader, buildSelfDescription, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, classifyChallenge, createPaymentGate, decorateOutcome, deliverReceipt, describeChallenge, discoveryHeaders, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, explainDecline, facilitatorCoverage, fetchAcross, firstKeylessFacilitator, formatSpendReport, getDirectoryInfo, isPermit2ProxyChain, knownFacilitatorsFor, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseFacilitatorSupported, parseReceipt, parseSettleResponse, parseSignatureHeader, paymentTools, pickAccept, planAcross, rankResources, readExactDomain, register402Index, registerDriver, registerX402Scan, renderLandingPage, requirePayment, resolveChain, scoreResource, searchOpenIndexes, settleViaFacilitator, summarizePlan, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
|
|
7582
|
+
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, BRAND, type BazaarExtension, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ChallengeTriage, type ChallengeVerdict, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DeclineReasonCode, type DeliverAttempt, type DeliverReceiptOptions, type DeliverResult, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoveryDescriptor, type DiscoverySigner, type DiscoverySort, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactPaymentPayloadAny, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, type FacilitatorSupportedKind, type FailedPayment, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, KNOWN_FACILITATORS, type KnownFacilitator, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, MultiChainPayer, type MultiChainPayerOptions, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, PERMIT2_ADDRESS, PERMIT2_PROXY_CHAIN_IDS, PERMIT2_WITNESS_TYPES, PIPRAIL_AGENT_GUIDE, POWERED_BY, type PaidReceipt, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, type PayingClient, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, type PaymentScheme, PaymentTimeoutError, type Permit2Authorization, type Permit2PaymentPayload, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, type PolicyDenyCode, REGISTER_ATTRIBUTION, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SelfDescribeEndpoint, type SelfDescribeRail, type SelfDescription, type SessionBudget, type SettleOutcome, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendRemaining, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, UnsupportedSchemeError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, WalletRequiredError, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, X402_EXACT_PERMIT2_PROXY, type XrplToken, agentGuide, appendAttribution, appendKeywords, buildBazaarExtension, buildChallengeHeader, buildEndpointInfo, buildExactAuthorization, buildExactSignatureHeader, buildOpenApi, buildReceiptHeader, buildSelfDescription, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, classifyChallenge, createPaymentGate, decorateOutcome, deliverReceipt, describeChallenge, discoveryHeaders, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, explainDecline, facilitatorCoverage, fetchAcross, firstKeylessFacilitator, formatSpendReport, getDirectoryInfo, isPermit2ProxyChain, knownFacilitatorsFor, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseFacilitatorSupported, parseReceipt, parseSettleResponse, parseSignatureHeader, paymentTools, pickAccept, planAcross, rankResources, readExactDomain, register402Index, registerDriver, registerX402Scan, renderLandingPage, requirePayment, resolveChain, scoreResource, searchOpenIndexes, settleViaFacilitator, summarizePlan, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
|
package/dist/index.js
CHANGED
|
@@ -3212,7 +3212,9 @@ var PipRailClient = class {
|
|
|
3212
3212
|
if (autoRoute) {
|
|
3213
3213
|
const plan = await this.planFromChallenge(net, wallet, challenge, url, schemes);
|
|
3214
3214
|
if (!plan.best) {
|
|
3215
|
-
|
|
3215
|
+
const reason = plan.fundingHint ?? "No rail is settleable for this payment.";
|
|
3216
|
+
this.safeEmit({ kind: "payment-failed", reason });
|
|
3217
|
+
throw new PaymentDeclinedError(reason);
|
|
3216
3218
|
}
|
|
3217
3219
|
accept = plan.best.accept;
|
|
3218
3220
|
quote = plan.best.quote;
|
|
@@ -3502,10 +3504,10 @@ var PipRailClient = class {
|
|
|
3502
3504
|
* TERMINAL expiry/approval decline it must not retry) without parsing prose. */
|
|
3503
3505
|
async authorize(quote) {
|
|
3504
3506
|
if (!quote.withinPolicy) {
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
);
|
|
3507
|
+
const reason = `Payment refused by policy: ${quote.policyReason ?? "not allowed"}`;
|
|
3508
|
+
const reasonCode = reasonCodeForPolicy(quote.policyCode);
|
|
3509
|
+
this.safeEmit({ kind: "payment-failed", reason, code: reasonCode });
|
|
3510
|
+
throw new PaymentDeclinedError(reason, { reasonCode });
|
|
3509
3511
|
}
|
|
3510
3512
|
const hook = this.opts.onBeforePay;
|
|
3511
3513
|
if (!hook) return;
|
|
@@ -3513,16 +3515,14 @@ var PipRailClient = class {
|
|
|
3513
3515
|
try {
|
|
3514
3516
|
approved = await hook(quote);
|
|
3515
3517
|
} catch (err) {
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
});
|
|
3518
|
+
const reason = "onBeforePay threw \u2014 refusing to pay.";
|
|
3519
|
+
this.safeEmit({ kind: "payment-failed", reason, code: "APPROVAL" });
|
|
3520
|
+
throw new PaymentDeclinedError(reason, { cause: err, reasonCode: "APPROVAL" });
|
|
3520
3521
|
}
|
|
3521
3522
|
if (!approved) {
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
);
|
|
3523
|
+
const reason = `onBeforePay declined ${quote.amountFormatted} ${quote.symbol ?? ""}`.trimEnd() + ` on ${quote.network}.`;
|
|
3524
|
+
this.safeEmit({ kind: "payment-failed", reason, code: "APPROVAL" });
|
|
3525
|
+
throw new PaymentDeclinedError(reason, { reasonCode: "APPROVAL" });
|
|
3526
3526
|
}
|
|
3527
3527
|
}
|
|
3528
3528
|
/** Record a settled payment in the ledger (true decimals for the running total). */
|
|
@@ -3617,7 +3617,8 @@ var PipRailClient = class {
|
|
|
3617
3617
|
const unconfirmedNote = confirmed ? "" : " (broadcast but NOT locally confirmed \u2014 it may still have settled on-chain)";
|
|
3618
3618
|
this.safeEmit({
|
|
3619
3619
|
kind: "payment-failed",
|
|
3620
|
-
reason: `server returned 402 after broadcasting payment ${ref}${unconfirmedNote} (${why})
|
|
3620
|
+
reason: `server returned 402 after broadcasting payment ${ref}${unconfirmedNote} (${why})`,
|
|
3621
|
+
...lastReason ? { code: lastReason.error, detail: lastReason.detail } : {}
|
|
3621
3622
|
});
|
|
3622
3623
|
throw new MaxRetriesExceededError(
|
|
3623
3624
|
`Server still returned 402 after ${attempts} attempt(s) with on-chain proof ref=${ref}${unconfirmedNote}. Last server rejection: ${why}. Re-verify or re-submit ref=${ref} before retrying \u2014 never re-pay (it would double-spend).`,
|
|
@@ -3652,7 +3653,7 @@ var PipRailClient = class {
|
|
|
3652
3653
|
const headers = new Headers(init?.headers);
|
|
3653
3654
|
headers.set(HEADER_SIGNATURE, buildExactSignatureHeader({ accepted, payload }));
|
|
3654
3655
|
const rejectDefinitive = (why2) => {
|
|
3655
|
-
this.safeEmit({ kind: "payment-failed", reason: `exact: facilitator rejected nonce=${nonce} (${why2})
|
|
3656
|
+
this.safeEmit({ kind: "payment-failed", reason: `exact: facilitator rejected nonce=${nonce} (${why2})`, code: why2 });
|
|
3656
3657
|
throw new MaxRetriesExceededError(
|
|
3657
3658
|
`exact: the facilitator rejected the payment (${why2}). Fix the cause, then re-present the SAME signed authorization (nonce=${nonce}) \u2014 do NOT re-sign a fresh nonce. ref=${nonce}.`,
|
|
3658
3659
|
{ ref: nonce }
|
|
@@ -3707,7 +3708,8 @@ var PipRailClient = class {
|
|
|
3707
3708
|
const why = lastReason ? `${lastReason.error}${lastReason.detail ? ` \u2014 ${lastReason.detail}` : ""}` : "server gave no reason";
|
|
3708
3709
|
this.safeEmit({
|
|
3709
3710
|
kind: "payment-failed",
|
|
3710
|
-
reason: `exact: 402 after submitting authorization nonce=${nonce} (${why})
|
|
3711
|
+
reason: `exact: 402 after submitting authorization nonce=${nonce} (${why})`,
|
|
3712
|
+
...lastReason ? { code: lastReason.error, detail: lastReason.detail } : {}
|
|
3711
3713
|
});
|
|
3712
3714
|
throw new MaxRetriesExceededError(
|
|
3713
3715
|
`exact: server still returned 402 after submitting the signed authorization (nonce=${nonce}). Last rejection: ${why}. Re-present the SAME authorization \u2014 do NOT re-sign a fresh nonce; verify authorizationState(${payerFrom}, ${nonce}) first. ref=${nonce}.`,
|
|
@@ -5260,6 +5262,7 @@ function normaliseExactOption(exact) {
|
|
|
5260
5262
|
if (exact === true) return { settle: "keyless" };
|
|
5261
5263
|
return exact;
|
|
5262
5264
|
}
|
|
5265
|
+
var TRANSIENT_VERIFY_CODES = /* @__PURE__ */ new Set(["tx_not_found", "insufficient_confirmations"]);
|
|
5263
5266
|
function createPaymentGate(options) {
|
|
5264
5267
|
const minConfirmations = options.minConfirmations ?? 1;
|
|
5265
5268
|
const maxTimeoutSeconds = options.maxTimeoutSeconds ?? 600;
|
|
@@ -5544,6 +5547,32 @@ function createPaymentGate(options) {
|
|
|
5544
5547
|
if (options.awaitOnPaid) await fireOnPaid(paid);
|
|
5545
5548
|
else void fireOnPaid(paid);
|
|
5546
5549
|
}
|
|
5550
|
+
function reportOnFailedError(error, failure) {
|
|
5551
|
+
if (!options.onFailedError) return;
|
|
5552
|
+
try {
|
|
5553
|
+
options.onFailedError(error, failure);
|
|
5554
|
+
} catch {
|
|
5555
|
+
}
|
|
5556
|
+
}
|
|
5557
|
+
function fireOnFailed(failure) {
|
|
5558
|
+
if (!options.onFailed) return;
|
|
5559
|
+
let outcome;
|
|
5560
|
+
try {
|
|
5561
|
+
outcome = options.onFailed(failure);
|
|
5562
|
+
} catch (err) {
|
|
5563
|
+
reportOnFailedError(err, failure);
|
|
5564
|
+
return;
|
|
5565
|
+
}
|
|
5566
|
+
if (outcome != null && typeof outcome.then === "function") {
|
|
5567
|
+
return Promise.resolve(outcome).catch((err) => reportOnFailedError(err, failure));
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
async function deliverOnFailed(result) {
|
|
5571
|
+
const code = result.error;
|
|
5572
|
+
const failure = { code, detail: result.detail, transient: TRANSIENT_VERIFY_CODES.has(code) };
|
|
5573
|
+
if (options.awaitOnFailed) await fireOnFailed(failure);
|
|
5574
|
+
else void fireOnFailed(failure);
|
|
5575
|
+
}
|
|
5547
5576
|
async function describe(resourceUrl = "") {
|
|
5548
5577
|
const specs = await ready();
|
|
5549
5578
|
const accepts = [];
|
|
@@ -5707,6 +5736,11 @@ function createPaymentGate(options) {
|
|
|
5707
5736
|
return { kind: "paid", receipt: result.receipt, receiptHeader: buildReceiptHeader(result.receipt) };
|
|
5708
5737
|
}
|
|
5709
5738
|
async function verify(paymentSignature) {
|
|
5739
|
+
const result = await resolveVerdict(paymentSignature);
|
|
5740
|
+
if (result.kind === "invalid") await deliverOnFailed(result);
|
|
5741
|
+
return result;
|
|
5742
|
+
}
|
|
5743
|
+
async function resolveVerdict(paymentSignature) {
|
|
5710
5744
|
const raw = normaliseHeader(paymentSignature);
|
|
5711
5745
|
if (!raw) return asChallenge();
|
|
5712
5746
|
const sig = parseSignatureHeader(raw);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piprail/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Accept x402 crypto payments across 29 chains — every major EVM chain plus Solana, TON, Tron, NEAR, Sui, Aptos, Algorand, Stellar & XRPL — in a couple of lines. No backend, no database, no fee; payments settle straight to your wallet.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|