@piprail/sdk 3.1.0 → 3.1.2
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 +42 -0
- package/dist/index.cjs +20 -3
- package/dist/index.d.cts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +20 -3
- package/dist/{xrpl-5K444RGX.js → xrpl-WIDRV2XY.js} +7 -1
- package/dist/{xrpl-G2FKFXRI.cjs → xrpl-YUGDNI2R.cjs} +7 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,46 @@ 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
|
+
## [3.1.2] — 2026-09-09 — a balance says what it means
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Three descriptions of a balance still said HOLDS after 3.1.0 made it SPENDABLE.** 3.1.0
|
|
12
|
+
changed the drivers to deduct a chain's retained minimum (Solana rent, XRPL/Stellar/Algorand
|
|
13
|
+
reserves) from the native figure, and documented that precisely on `WalletBalance.token` — but
|
|
14
|
+
every layer above it kept the old wording. `PipRailClient.balanceOf`'s TSDoc, the interface it
|
|
15
|
+
implements, and the `piprail_wallet` tool description a MODEL reads all still promised "what you
|
|
16
|
+
hold". They now say what they mean, and name the gap as locked rather than lost.
|
|
17
|
+
|
|
18
|
+
The wording mattered most in the tool description, because an agent comparing its own balance
|
|
19
|
+
against a block explorer sees a smaller number and has to decide whether it is being lied to. On
|
|
20
|
+
a live Stellar account holding 1.5398 XLM with three subentries, `balanceOf` reports 0.0398: the
|
|
21
|
+
1.5 XLM difference is the base reserve. Text only; no behaviour changes.
|
|
22
|
+
|
|
23
|
+
## [3.1.1] — 2026-09-09 — XRPL payments work again
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **A facilitator's payload rejection answered 5xx instead of 402.** Every non-200 from a
|
|
28
|
+
facilitator's `/verify` was treated as a transport failure, so a **400** — a forged or
|
|
29
|
+
malformed authorization — made the gate return a server error. That tells the buyer "our
|
|
30
|
+
fault, try again" about a payment that can never succeed, and shows in the merchant's metrics
|
|
31
|
+
as an outage they do not have. Now only `400`/`422` (the payload is bad, and only the buyer
|
|
32
|
+
can fix it) reject with the facilitator's own reason; `401`/`403` (our credentials),
|
|
33
|
+
`404` (our URL), `429` and `5xx` stay `SettlementError`, because a buyer can do nothing about
|
|
34
|
+
any of them. Found by tampering with a real authorization on Base.
|
|
35
|
+
|
|
36
|
+
- 🔴 **Every XRPL payment failed.** `ledger_current` is documented to return
|
|
37
|
+
`ledger_current_index`, and rippled does, but the public clusters in front of it answer with
|
|
38
|
+
`ledger_index`. Reading only the documented name returned `undefined`, `undefined + 20` became
|
|
39
|
+
`NaN`, and the transaction died in xrpl.js's serializer. Both names are now accepted, and a
|
|
40
|
+
response carrying neither is refused with a message that says nothing was signed.
|
|
41
|
+
|
|
42
|
+
Latent since XRPL shipped and intermittent by nature: it depends on which backend the cluster
|
|
43
|
+
routes to, which is why the same wallet settled all morning and then could not settle at all.
|
|
44
|
+
Caught by a post-release live sweep against the published package — the pre-flight guard added
|
|
45
|
+
in 3.1.0 is what turned an unreadable serializer error into a sentence naming the field.
|
|
46
|
+
|
|
7
47
|
## [3.1.0] — 2026-09-09 — spendable is not held, and a swap refused for no reason
|
|
8
48
|
|
|
9
49
|
### Fixed
|
|
@@ -2642,6 +2682,8 @@ straight into your wallet. The API is small and self-contained.
|
|
|
2642
2682
|
[1.5.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
2643
2683
|
[1.4.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
2644
2684
|
[1.3.1]: https://www.npmjs.com/package/@piprail/sdk
|
|
2685
|
+
[3.1.2]: https://www.npmjs.com/package/@piprail/sdk
|
|
2686
|
+
[3.1.1]: https://www.npmjs.com/package/@piprail/sdk
|
|
2645
2687
|
[3.1.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
2646
2688
|
[3.0.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
2647
2689
|
[1.3.0]: https://www.npmjs.com/package/@piprail/sdk
|
package/dist/index.cjs
CHANGED
|
@@ -2498,7 +2498,7 @@ var loaders = {
|
|
|
2498
2498
|
xrpl: async () => {
|
|
2499
2499
|
let mod;
|
|
2500
2500
|
try {
|
|
2501
|
-
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-
|
|
2501
|
+
mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-YUGDNI2R.cjs")));
|
|
2502
2502
|
} catch (cause) {
|
|
2503
2503
|
throw new (0, _chunk6XTNI2OQcjs.MissingDriverError)(
|
|
2504
2504
|
`XRPL selected, but its package isn't installed. Run: npm install xrpl`,
|
|
@@ -3800,7 +3800,16 @@ var PipRailClient = (_class2 = class {
|
|
|
3800
3800
|
return this.opts.chain;
|
|
3801
3801
|
}
|
|
3802
3802
|
/**
|
|
3803
|
-
* What this wallet actually
|
|
3803
|
+
* What this wallet can actually SPEND, per asset — the balance sheet, not the leash.
|
|
3804
|
+
*
|
|
3805
|
+
* 🔴 For a NATIVE asset this is not always what the chain says the account holds. Solana
|
|
3806
|
+
* (rent exemption), XRPL (base + owner reserve), Stellar (base reserve per subentry) and
|
|
3807
|
+
* Algorand (minimum balance) all require an account to retain a minimum it can never send,
|
|
3808
|
+
* and since 3.1.0 the drivers report that reserve DEDUCTED, because affordability measured
|
|
3809
|
+
* against the raw balance calls a payment affordable right up until the chain refuses it.
|
|
3810
|
+
* Live example: a Stellar account holding 1.5398 XLM with three subentries reports 0.0398,
|
|
3811
|
+
* the 1.5 XLM difference being the reserve. That is the number to spend against; it is not
|
|
3812
|
+
* missing money. `estimateCost()` judges gas against the TRUE balance separately.
|
|
3804
3813
|
*
|
|
3805
3814
|
* `budget()` answers "how much of my allowance is left", a different question and the only
|
|
3806
3815
|
* one an agent could previously ask. An agent that OWNS a wallet has to answer "what do I
|
|
@@ -6238,6 +6247,14 @@ async function settleViaFacilitator(input) {
|
|
|
6238
6247
|
);
|
|
6239
6248
|
}
|
|
6240
6249
|
if (verify.status !== 200) {
|
|
6250
|
+
if (verify.status === 400 || verify.status === 422) {
|
|
6251
|
+
const vr4 = _nullishCoalesce(verify.json, () => ( {}));
|
|
6252
|
+
return {
|
|
6253
|
+
ok: false,
|
|
6254
|
+
error: mapReason(vr4.invalidReason),
|
|
6255
|
+
detail: `Facilitator rejected the payment payload (HTTP ${verify.status})${vr4.invalidReason ? `: ${vr4.invalidReason}` : ""}${vr4.invalidMessage ? ` \u2014 ${vr4.invalidMessage}` : ""}.`
|
|
6256
|
+
};
|
|
6257
|
+
}
|
|
6241
6258
|
throw new (0, _chunk6XTNI2OQcjs.SettlementError)(
|
|
6242
6259
|
`exact settle (facilitator ${base2}): /verify returned HTTP ${verify.status} (transport/auth error).`
|
|
6243
6260
|
);
|
|
@@ -8303,7 +8320,7 @@ function paymentTools(client) {
|
|
|
8303
8320
|
},
|
|
8304
8321
|
{
|
|
8305
8322
|
name: "piprail_wallet",
|
|
8306
|
-
description: "What YOU
|
|
8323
|
+
description: "What YOU can SPEND, and where you get paid \u2014 your balance sheet, which is a different question from piprail_budget (that is how much of your allowance is left). Returns your own address per chain plus the spendable amount of each asset. Use it before deciding to sell, swap or ask to be topped up, and give the address to anyone who needs to send you funds. On some chains a native amount is LOWER than the figure a block explorer shows, because the chain makes an account retain a minimum it can never send (Solana, XRPL, Stellar, Algorand). That gap is locked, not lost, and this number is the one you can actually pay with. A null amount means the read was UNAVAILABLE, not zero: do NOT treat it as being broke. Read-only; moves nothing and needs no approval.",
|
|
8307
8324
|
annotations: {
|
|
8308
8325
|
title: "Your wallet",
|
|
8309
8326
|
readOnlyHint: true,
|
package/dist/index.d.cts
CHANGED
|
@@ -5974,7 +5974,9 @@ interface PayingClient {
|
|
|
5974
5974
|
canAgentSell?(): boolean;
|
|
5975
5975
|
/** The chain this client is configured for — the default an offer is priced on. */
|
|
5976
5976
|
chain?(): ChainSelector;
|
|
5977
|
-
/** What this wallet
|
|
5977
|
+
/** What this wallet can SPEND, per asset — the balance sheet, distinct from the budget
|
|
5978
|
+
* leash. On a chain with a retained minimum (Solana rent, XRPL/Stellar/Algorand
|
|
5979
|
+
* reserves) a native balance reports the reserve DEDUCTED. See {@link WalletBalance}. */
|
|
5978
5980
|
balanceOf?(assets?: readonly string[]): Promise<WalletAssetBalance[]>;
|
|
5979
5981
|
}
|
|
5980
5982
|
/**
|
|
@@ -6214,7 +6216,16 @@ declare class PipRailClient {
|
|
|
6214
6216
|
* defaults to it, so an agent prices on the chain it actually holds funds on. */
|
|
6215
6217
|
chain(): ChainSelector;
|
|
6216
6218
|
/**
|
|
6217
|
-
* What this wallet actually
|
|
6219
|
+
* What this wallet can actually SPEND, per asset — the balance sheet, not the leash.
|
|
6220
|
+
*
|
|
6221
|
+
* 🔴 For a NATIVE asset this is not always what the chain says the account holds. Solana
|
|
6222
|
+
* (rent exemption), XRPL (base + owner reserve), Stellar (base reserve per subentry) and
|
|
6223
|
+
* Algorand (minimum balance) all require an account to retain a minimum it can never send,
|
|
6224
|
+
* and since 3.1.0 the drivers report that reserve DEDUCTED, because affordability measured
|
|
6225
|
+
* against the raw balance calls a payment affordable right up until the chain refuses it.
|
|
6226
|
+
* Live example: a Stellar account holding 1.5398 XLM with three subentries reports 0.0398,
|
|
6227
|
+
* the 1.5 XLM difference being the reserve. That is the number to spend against; it is not
|
|
6228
|
+
* missing money. `estimateCost()` judges gas against the TRUE balance separately.
|
|
6218
6229
|
*
|
|
6219
6230
|
* `budget()` answers "how much of my allowance is left", a different question and the only
|
|
6220
6231
|
* one an agent could previously ask. An agent that OWNS a wallet has to answer "what do I
|
package/dist/index.d.ts
CHANGED
|
@@ -5974,7 +5974,9 @@ interface PayingClient {
|
|
|
5974
5974
|
canAgentSell?(): boolean;
|
|
5975
5975
|
/** The chain this client is configured for — the default an offer is priced on. */
|
|
5976
5976
|
chain?(): ChainSelector;
|
|
5977
|
-
/** What this wallet
|
|
5977
|
+
/** What this wallet can SPEND, per asset — the balance sheet, distinct from the budget
|
|
5978
|
+
* leash. On a chain with a retained minimum (Solana rent, XRPL/Stellar/Algorand
|
|
5979
|
+
* reserves) a native balance reports the reserve DEDUCTED. See {@link WalletBalance}. */
|
|
5978
5980
|
balanceOf?(assets?: readonly string[]): Promise<WalletAssetBalance[]>;
|
|
5979
5981
|
}
|
|
5980
5982
|
/**
|
|
@@ -6214,7 +6216,16 @@ declare class PipRailClient {
|
|
|
6214
6216
|
* defaults to it, so an agent prices on the chain it actually holds funds on. */
|
|
6215
6217
|
chain(): ChainSelector;
|
|
6216
6218
|
/**
|
|
6217
|
-
* What this wallet actually
|
|
6219
|
+
* What this wallet can actually SPEND, per asset — the balance sheet, not the leash.
|
|
6220
|
+
*
|
|
6221
|
+
* 🔴 For a NATIVE asset this is not always what the chain says the account holds. Solana
|
|
6222
|
+
* (rent exemption), XRPL (base + owner reserve), Stellar (base reserve per subentry) and
|
|
6223
|
+
* Algorand (minimum balance) all require an account to retain a minimum it can never send,
|
|
6224
|
+
* and since 3.1.0 the drivers report that reserve DEDUCTED, because affordability measured
|
|
6225
|
+
* against the raw balance calls a payment affordable right up until the chain refuses it.
|
|
6226
|
+
* Live example: a Stellar account holding 1.5398 XLM with three subentries reports 0.0398,
|
|
6227
|
+
* the 1.5 XLM difference being the reserve. That is the number to spend against; it is not
|
|
6228
|
+
* missing money. `estimateCost()` judges gas against the TRUE balance separately.
|
|
6218
6229
|
*
|
|
6219
6230
|
* `budget()` answers "how much of my allowance is left", a different question and the only
|
|
6220
6231
|
* one an agent could previously ask. An agent that OWNS a wallet has to answer "what do I
|
package/dist/index.js
CHANGED
|
@@ -2498,7 +2498,7 @@ var loaders = {
|
|
|
2498
2498
|
xrpl: async () => {
|
|
2499
2499
|
let mod;
|
|
2500
2500
|
try {
|
|
2501
|
-
mod = await import("./xrpl-
|
|
2501
|
+
mod = await import("./xrpl-WIDRV2XY.js");
|
|
2502
2502
|
} catch (cause) {
|
|
2503
2503
|
throw new MissingDriverError(
|
|
2504
2504
|
`XRPL selected, but its package isn't installed. Run: npm install xrpl`,
|
|
@@ -3800,7 +3800,16 @@ var PipRailClient = class {
|
|
|
3800
3800
|
return this.opts.chain;
|
|
3801
3801
|
}
|
|
3802
3802
|
/**
|
|
3803
|
-
* What this wallet actually
|
|
3803
|
+
* What this wallet can actually SPEND, per asset — the balance sheet, not the leash.
|
|
3804
|
+
*
|
|
3805
|
+
* 🔴 For a NATIVE asset this is not always what the chain says the account holds. Solana
|
|
3806
|
+
* (rent exemption), XRPL (base + owner reserve), Stellar (base reserve per subentry) and
|
|
3807
|
+
* Algorand (minimum balance) all require an account to retain a minimum it can never send,
|
|
3808
|
+
* and since 3.1.0 the drivers report that reserve DEDUCTED, because affordability measured
|
|
3809
|
+
* against the raw balance calls a payment affordable right up until the chain refuses it.
|
|
3810
|
+
* Live example: a Stellar account holding 1.5398 XLM with three subentries reports 0.0398,
|
|
3811
|
+
* the 1.5 XLM difference being the reserve. That is the number to spend against; it is not
|
|
3812
|
+
* missing money. `estimateCost()` judges gas against the TRUE balance separately.
|
|
3804
3813
|
*
|
|
3805
3814
|
* `budget()` answers "how much of my allowance is left", a different question and the only
|
|
3806
3815
|
* one an agent could previously ask. An agent that OWNS a wallet has to answer "what do I
|
|
@@ -6238,6 +6247,14 @@ async function settleViaFacilitator(input) {
|
|
|
6238
6247
|
);
|
|
6239
6248
|
}
|
|
6240
6249
|
if (verify.status !== 200) {
|
|
6250
|
+
if (verify.status === 400 || verify.status === 422) {
|
|
6251
|
+
const vr4 = verify.json ?? {};
|
|
6252
|
+
return {
|
|
6253
|
+
ok: false,
|
|
6254
|
+
error: mapReason(vr4.invalidReason),
|
|
6255
|
+
detail: `Facilitator rejected the payment payload (HTTP ${verify.status})${vr4.invalidReason ? `: ${vr4.invalidReason}` : ""}${vr4.invalidMessage ? ` \u2014 ${vr4.invalidMessage}` : ""}.`
|
|
6256
|
+
};
|
|
6257
|
+
}
|
|
6241
6258
|
throw new SettlementError(
|
|
6242
6259
|
`exact settle (facilitator ${base2}): /verify returned HTTP ${verify.status} (transport/auth error).`
|
|
6243
6260
|
);
|
|
@@ -8303,7 +8320,7 @@ function paymentTools(client) {
|
|
|
8303
8320
|
},
|
|
8304
8321
|
{
|
|
8305
8322
|
name: "piprail_wallet",
|
|
8306
|
-
description: "What YOU
|
|
8323
|
+
description: "What YOU can SPEND, and where you get paid \u2014 your balance sheet, which is a different question from piprail_budget (that is how much of your allowance is left). Returns your own address per chain plus the spendable amount of each asset. Use it before deciding to sell, swap or ask to be topped up, and give the address to anyone who needs to send you funds. On some chains a native amount is LOWER than the figure a block explorer shows, because the chain makes an account retain a minimum it can never send (Solana, XRPL, Stellar, Algorand). That gap is locked, not lost, and this number is the one you can actually pay with. A null amount means the read was UNAVAILABLE, not zero: do NOT treat it as being broke. Read-only; moves nothing and needs no approval.",
|
|
8307
8324
|
annotations: {
|
|
8308
8325
|
title: "Your wallet",
|
|
8309
8326
|
readOnlyHint: true,
|
|
@@ -745,7 +745,13 @@ function makeXrplNetwork(preset, rpcUrl) {
|
|
|
745
745
|
},
|
|
746
746
|
async currentLedgerIndex() {
|
|
747
747
|
const r = await rpc("ledger_current", {});
|
|
748
|
-
|
|
748
|
+
const index = r.ledger_current_index ?? r.ledger_index;
|
|
749
|
+
if (typeof index !== "number") {
|
|
750
|
+
throw new Error(
|
|
751
|
+
`XRPL: ledger_current returned neither ledger_current_index nor ledger_index (got ${JSON.stringify(Object.keys(r ?? {}))}). Nothing was signed or submitted.`
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
return index;
|
|
749
755
|
},
|
|
750
756
|
async submit(txBlob) {
|
|
751
757
|
return rpc("submit", { tx_blob: txBlob });
|
|
@@ -745,7 +745,13 @@ function makeXrplNetwork(preset, rpcUrl) {
|
|
|
745
745
|
},
|
|
746
746
|
async currentLedgerIndex() {
|
|
747
747
|
const r = await rpc("ledger_current", {});
|
|
748
|
-
|
|
748
|
+
const index = _nullishCoalesce(r.ledger_current_index, () => ( r.ledger_index));
|
|
749
|
+
if (typeof index !== "number") {
|
|
750
|
+
throw new Error(
|
|
751
|
+
`XRPL: ledger_current returned neither ledger_current_index nor ledger_index (got ${JSON.stringify(Object.keys(_nullishCoalesce(r, () => ( {}))))}). Nothing was signed or submitted.`
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
return index;
|
|
749
755
|
},
|
|
750
756
|
async submit(txBlob) {
|
|
751
757
|
return rpc("submit", { tx_blob: txBlob });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piprail/sdk",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.2",
|
|
4
4
|
"description": "Accept x402 crypto payments across 30 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",
|