x402-sessions 0.1.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/LICENSE +21 -0
- package/README.md +337 -0
- package/dist/client.d.ts +15 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +178 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/scheme-server.d.ts +42 -0
- package/dist/scheme-server.d.ts.map +1 -0
- package/dist/scheme-server.js +71 -0
- package/dist/scheme-server.js.map +1 -0
- package/dist/stellar.d.ts +31 -0
- package/dist/stellar.d.ts.map +1 -0
- package/dist/stellar.js +102 -0
- package/dist/stellar.js.map +1 -0
- package/dist/types.d.ts +126 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 madhav
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# x402-sessions
|
|
2
|
+
|
|
3
|
+
**Sign once, settle many times — session-based x402 payments on Stellar.**
|
|
4
|
+
|
|
5
|
+
A tiny TypeScript SDK that turns a single Stellar Asset Contract (SAC) `approve` into an unlimited stream of x402 micropayments. Pay $1 upfront, then every API call automatically settles $0.10 on-chain via `transfer_from`. No per-call wallet popup. No off-chain bookkeeping tricks. The cap and expiry are enforced on-chain by the SAC itself.
|
|
6
|
+
|
|
7
|
+
> Classic x402 = 1 request, 1 signature, 1 settlement.
|
|
8
|
+
> **x402-sessions = 1 signature, N settlements.**
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
If you're building an AI agent, a dapp game, a pay-per-inference API, or anything where a user makes many small payments in a row, classic x402 becomes friction theatre — one wallet popup per request. Thirdweb built a session model for EVM using Permit2 + off-chain facilitator bookkeeping. This package is the Stellar-native equivalent, and it's arguably simpler *and* stronger:
|
|
13
|
+
|
|
14
|
+
- **On-chain enforcement of the cap** via SEP-41 `approve`. Not a facilitator-side ledger hack.
|
|
15
|
+
- **Zero escrow.** Unused allowance stays in the user's wallet. No refund dance when a session expires.
|
|
16
|
+
- **Works with existing x402 infra.** Registers as a new scheme (`session`) alongside Coinbase's `exact`. Drop-in on the resource-server side via `@x402/core`'s `x402ResourceServer.register()`.
|
|
17
|
+
- **Tiny wire format.** The retry `PaymentPayload.payload` is just `{ sessionId }`.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install x402-sessions @stellar/stellar-sdk
|
|
23
|
+
# if you're also building the resource-server side:
|
|
24
|
+
npm install @x402/core @x402/next
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Peer deps: `@stellar/stellar-sdk ^14 || ^15`, `@x402/core ^2.8.0` (optional — only if you use the server-side scheme plugin).
|
|
28
|
+
|
|
29
|
+
You also need a running **x402-sessions facilitator** — a small service that verifies sessions and performs the on-chain `transfer_from`. A reference implementation (Express + better-sqlite3 + `@stellar/stellar-sdk`) ships alongside this package. Self-host it or point your clients at one you trust.
|
|
30
|
+
|
|
31
|
+
## 30-second quickstart
|
|
32
|
+
|
|
33
|
+
### 1. Client side (Node)
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { Keypair } from "@stellar/stellar-sdk";
|
|
37
|
+
import { createSession } from "x402-sessions";
|
|
38
|
+
|
|
39
|
+
const session = await createSession({
|
|
40
|
+
signer: Keypair.fromSecret(process.env.USER_SECRET!),
|
|
41
|
+
facilitatorUrl: "http://localhost:4021",
|
|
42
|
+
network: "stellar:testnet",
|
|
43
|
+
asset: "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA", // USDC testnet SAC
|
|
44
|
+
spendingCap: "1.00", // $1 total
|
|
45
|
+
expiresIn: 3600, // 1 hour
|
|
46
|
+
recipient: "GBWYMS7R...", // your resource server's wallet
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// session.fetch is a drop-in fetch that transparently pays per call.
|
|
50
|
+
for (let i = 0; i < 10; i++) {
|
|
51
|
+
const res = await session.fetch("https://yourapi.example/inference");
|
|
52
|
+
console.log(await res.json()); // each call settles $0.10 on-chain
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Under the hood `createSession` signs and submits **one** SAC `approve(user, facilitator, cap, expiration_ledger)` tx, registers the approval with the facilitator, and returns a `SessionHandle` whose `fetch()` method transparently handles 402 responses.
|
|
57
|
+
|
|
58
|
+
### 2. Client side (browser with Freighter)
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { signTransaction, requestAccess } from "@stellar/freighter-api";
|
|
62
|
+
import { createSession } from "x402-sessions";
|
|
63
|
+
|
|
64
|
+
const { address } = await requestAccess();
|
|
65
|
+
|
|
66
|
+
const session = await createSession({
|
|
67
|
+
signer: {
|
|
68
|
+
publicKey: () => address,
|
|
69
|
+
signTransaction: async (xdr, opts) => {
|
|
70
|
+
const r = await signTransaction(xdr, {
|
|
71
|
+
networkPassphrase: opts?.networkPassphrase,
|
|
72
|
+
address,
|
|
73
|
+
});
|
|
74
|
+
if (r.error) throw new Error(r.error.message ?? "sign failed");
|
|
75
|
+
return r.signedTxXdr;
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
facilitatorUrl: "http://localhost:4021",
|
|
79
|
+
network: "stellar:testnet",
|
|
80
|
+
asset: process.env.NEXT_PUBLIC_USDC_SAC_ID!,
|
|
81
|
+
spendingCap: "1.00",
|
|
82
|
+
expiresIn: 3600,
|
|
83
|
+
recipient: process.env.NEXT_PUBLIC_RECIPIENT!,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Use it anywhere you'd use fetch()
|
|
87
|
+
await session.fetch("/api/chat", {
|
|
88
|
+
method: "POST",
|
|
89
|
+
body: JSON.stringify({ prompt: "hi" }),
|
|
90
|
+
headers: { "Content-Type": "application/json" },
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Any signer with `publicKey()` + either `sign(tx)` (Node `Keypair`) or `signTransaction(xdr, opts)` (browser wallet adapter) works.
|
|
95
|
+
|
|
96
|
+
### 3. Resource-server side (Next.js + `@x402/next`)
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { paymentProxy, x402ResourceServer } from "@x402/next";
|
|
100
|
+
import { HTTPFacilitatorClient } from "@x402/core/server";
|
|
101
|
+
import { SessionStellarScheme } from "x402-sessions";
|
|
102
|
+
|
|
103
|
+
const facilitator = new HTTPFacilitatorClient({
|
|
104
|
+
url: process.env.SESSION_FACILITATOR_URL ?? "http://localhost:4021",
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const server = new x402ResourceServer(facilitator).register(
|
|
108
|
+
"stellar:testnet",
|
|
109
|
+
new SessionStellarScheme({
|
|
110
|
+
assetContractId: "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
|
|
111
|
+
facilitatorUrl: process.env.SESSION_FACILITATOR_URL,
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
export const handler = paymentProxy(
|
|
116
|
+
{
|
|
117
|
+
"/api/chat": {
|
|
118
|
+
accepts: [
|
|
119
|
+
{
|
|
120
|
+
scheme: "session" as const,
|
|
121
|
+
price: "0.10",
|
|
122
|
+
network: "stellar:testnet",
|
|
123
|
+
payTo: process.env.SERVER_STELLAR_ADDRESS!,
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
description: "AI chat, settled per message via session",
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
server,
|
|
130
|
+
);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
That's it. Any request to `/api/chat` without a session payload gets a 402. With one, it passes through and $0.10 settles on-chain.
|
|
134
|
+
|
|
135
|
+
## How it works
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
┌──────────────┐ ┌───────────────┐
|
|
139
|
+
│ user wallet │──1. approve(facilitator, $1, 1h) ─────▶│ USDC SAC │
|
|
140
|
+
│ (Freighter) │ │ (on-chain) │
|
|
141
|
+
└──────┬───────┘ └───────▲───────┘
|
|
142
|
+
│ │
|
|
143
|
+
│ 2. POST /sessions {approvalTxHash, cap, …} │
|
|
144
|
+
▼ │
|
|
145
|
+
┌──────────────┐ 3. sessionId │
|
|
146
|
+
│ x402-sessions│◀─────────────────┐ │
|
|
147
|
+
│ facilitator │ │ │
|
|
148
|
+
│ (HTTP) │ │ │
|
|
149
|
+
└──────┬───────┘ │ │
|
|
150
|
+
│ │ │
|
|
151
|
+
│ │ │
|
|
152
|
+
│ 4. POST /api/chat (per call) │
|
|
153
|
+
│ ┌──────────────┴───────────────┐ │
|
|
154
|
+
│ │ │ │
|
|
155
|
+
│ │ ┌──────────────┐ │ │
|
|
156
|
+
│ └──────▶│ resource │ │ │
|
|
157
|
+
│ │ server │ │ │
|
|
158
|
+
│ │ (@x402/next) │ │ │
|
|
159
|
+
│ └──────┬───────┘ │ │
|
|
160
|
+
│ │ │ │
|
|
161
|
+
│◀── 5. /verify ────────── │ │ │
|
|
162
|
+
│ /settle │
|
|
163
|
+
│──── 6. transfer_from(facilitator, user, server, $0.10) ─▶
|
|
164
|
+
│ │
|
|
165
|
+
│ 7. ok + reply │
|
|
166
|
+
│ └──────────────▶ user │
|
|
167
|
+
└──── decrement session (sqlite) ─────────────────────────┘
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
1. User signs **one** on-chain `approve(spender=facilitator, amount=cap, expiration_ledger)`.
|
|
171
|
+
2. SDK registers the approval with the facilitator (`POST /sessions`).
|
|
172
|
+
3. Facilitator verifies on-chain allowance via `allowance()`, stores the session, returns a `sessionId`.
|
|
173
|
+
4. User hits protected endpoint with `session.fetch(...)`. SDK handles the 402 dance automatically:
|
|
174
|
+
- Reads the `PAYMENT-REQUIRED` header (x402 v2)
|
|
175
|
+
- Builds a payment payload `{ sessionId }`
|
|
176
|
+
- Retries with `PAYMENT-SIGNATURE` header
|
|
177
|
+
5. Resource server's `x402ResourceServer` calls facilitator `/verify` then `/settle`.
|
|
178
|
+
6. Facilitator runs `transfer_from(spender, from, to, amount)` on-chain. The SAC itself enforces the cap and expiry.
|
|
179
|
+
7. Response flows back to the user. Spent counter decrements.
|
|
180
|
+
|
|
181
|
+
## API reference
|
|
182
|
+
|
|
183
|
+
### `createSession(options)`
|
|
184
|
+
|
|
185
|
+
Signs + submits the on-chain `approve`, registers the session with the facilitator, and returns a `SessionHandle`.
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
function createSession(opts: CreateSessionOptions): Promise<SessionHandle>
|
|
189
|
+
|
|
190
|
+
interface CreateSessionOptions {
|
|
191
|
+
signer: ClientSigner; // Keypair or browser wallet adapter
|
|
192
|
+
facilitatorUrl: string; // e.g. "http://localhost:4021"
|
|
193
|
+
network?: "stellar:testnet" | "stellar:pubnet"; // default testnet
|
|
194
|
+
asset: string; // SAC contract id (C...)
|
|
195
|
+
spendingCap: string; // human units, e.g. "1.00"
|
|
196
|
+
decimals?: number; // default 7 (USDC)
|
|
197
|
+
expiresIn: number; // seconds; converted to ledger count
|
|
198
|
+
recipient: string; // payTo address (G...)
|
|
199
|
+
sorobanRpcUrl?: string; // override default
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
interface SessionHandle {
|
|
203
|
+
sessionId: string;
|
|
204
|
+
user: string;
|
|
205
|
+
spender: string;
|
|
206
|
+
asset: string;
|
|
207
|
+
recipient: string;
|
|
208
|
+
cap: string; // base units (stroops for 7-dec USDC)
|
|
209
|
+
spent: string; // base units
|
|
210
|
+
expirationLedger: number;
|
|
211
|
+
network: Network;
|
|
212
|
+
facilitatorUrl: string;
|
|
213
|
+
fetch: typeof fetch; // auto-paying fetch
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### `wrapFetch(sessionId)`
|
|
218
|
+
|
|
219
|
+
Lower-level helper. Returns a `fetch`-compatible function that, on receiving a 402, reads the `PAYMENT-REQUIRED` header, builds a `PaymentPayload` with the given `sessionId`, and retries with `PAYMENT-SIGNATURE`. Use this if you want to manage the session handle yourself (e.g. persist it across pages).
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
function wrapFetch(sessionId: string): typeof fetch
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### `SessionStellarScheme`
|
|
226
|
+
|
|
227
|
+
Resource-server plugin for `@x402/core`'s `x402ResourceServer.register()`. Advertises the `session` scheme, parses prices, and enriches 402 responses with facilitator metadata.
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
class SessionStellarScheme {
|
|
231
|
+
constructor(config: {
|
|
232
|
+
assetContractId: string; // SAC contract id
|
|
233
|
+
decimals?: number; // default 7
|
|
234
|
+
facilitatorUrl?: string; // exposed to clients in 402.extra
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Structurally compatible with `@x402/core`'s `SchemeNetworkServer` interface. (It doesn't `implements` literally, to avoid an `@x402/core/types` module-resolution requirement — your TypeScript will happily pass it to `register(network, new SessionStellarScheme(...))` via structural typing.)
|
|
240
|
+
|
|
241
|
+
### `ClientSigner`
|
|
242
|
+
|
|
243
|
+
Minimal signer interface. A `Keypair` from `@stellar/stellar-sdk` satisfies it natively (via its `sign(Buffer)` method). For browser wallets, provide the `signTransaction` shape.
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
interface ClientSigner {
|
|
247
|
+
publicKey(): string;
|
|
248
|
+
sign?(data: Buffer): Buffer;
|
|
249
|
+
signTransaction?(
|
|
250
|
+
xdr: string,
|
|
251
|
+
opts?: { networkPassphrase: string },
|
|
252
|
+
): Promise<string>;
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Helpers
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
import {
|
|
260
|
+
decimalToBaseUnits, // "1.50" + 7 decimals -> 15000000n
|
|
261
|
+
defaultRpcUrlFor, // network -> public Soroban RPC URL
|
|
262
|
+
networkPassphraseFor, // network -> stellar-sdk Networks constant
|
|
263
|
+
} from "x402-sessions";
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Wire format (session scheme)
|
|
267
|
+
|
|
268
|
+
- **Scheme:** `"session"`
|
|
269
|
+
- **Network:** `"stellar:testnet"` | `"stellar:pubnet"`
|
|
270
|
+
- **`PaymentPayload.payload`** (the scheme-specific slot): `{ sessionId: string }`
|
|
271
|
+
- **Facilitator HTTP surface** (added to the standard x402 triplet):
|
|
272
|
+
- `GET /supported` — standard x402
|
|
273
|
+
- `POST /verify` — standard x402
|
|
274
|
+
- `POST /settle` — standard x402
|
|
275
|
+
- `POST /sessions` — **new**: register a session from a signed approval tx hash
|
|
276
|
+
- `GET /sessions/:id` — **new**: inspect remaining cap / spent / expiry
|
|
277
|
+
|
|
278
|
+
## Trust model
|
|
279
|
+
|
|
280
|
+
| Limit | Enforced by | Hardness |
|
|
281
|
+
|---|---|---|
|
|
282
|
+
| **Total cap** (e.g. $1) | SAC `approve` + `transfer_from` reverts past cap | **On-chain** |
|
|
283
|
+
| **Expiry** (ledger) | `expiration_ledger` parameter in SAC `approve` | **On-chain** |
|
|
284
|
+
| **Per-call price** (e.g. $0.10) | Facilitator `/settle` refuses amounts > policy | Off-chain (trust your facilitator) |
|
|
285
|
+
| **Recipient binding** | Facilitator only pays the pre-registered `recipient` | Off-chain |
|
|
286
|
+
| **Session reuse control** | Facilitator sqlite bookkeeping | Off-chain |
|
|
287
|
+
| **Unused balance handling** | Funds never escrowed — they stay in the user's wallet | **Native** |
|
|
288
|
+
|
|
289
|
+
In short: on-chain handles the money-safety invariants (total and expiry). Off-chain handles the application policy (per-call price, recipient, bookkeeping). This is the same trust model as thirdweb's session x402 on EVM, except the cap enforcement is *strictly better* because ours is on-chain.
|
|
290
|
+
|
|
291
|
+
If you need on-chain per-call policy enforcement (e.g. "no more than $0.10 per call, no matter what"), upgrade to a Soroban custom account / smart wallet with a policy-signer session key — out of scope for this package.
|
|
292
|
+
|
|
293
|
+
## No refund dance
|
|
294
|
+
|
|
295
|
+
Because `approve` is a *permission*, not an escrow, tokens never leave the user's wallet until `transfer_from` is called:
|
|
296
|
+
|
|
297
|
+
| Scenario | What happens |
|
|
298
|
+
|---|---|
|
|
299
|
+
| Session expires unused | Still in user's wallet. Allowance becomes unusable. No refund call. |
|
|
300
|
+
| Session partially used | The untouched portion never moved. No refund call. |
|
|
301
|
+
| User wants to end early | Optional: sign `approve(..., amount=0)` to revoke. Not required — expiry handles it. |
|
|
302
|
+
|
|
303
|
+
Compare this to escrow-based session models where you must explicitly claim refunds.
|
|
304
|
+
|
|
305
|
+
## Security notes
|
|
306
|
+
|
|
307
|
+
- Treat the `sessionId` as a **bearer token** — anyone who steals it can spend the full cap to the pre-registered recipient. Keep it in memory or secure storage; don't log it.
|
|
308
|
+
- The recipient is bound at session creation. A stolen sessionId cannot redirect funds.
|
|
309
|
+
- Worst-case: an attacker drains the whole cap to *your* game server. User loses up to `cap`; funds still end up where they were meant to go.
|
|
310
|
+
- For higher-trust scenarios, use a smaller cap per session and rotate often.
|
|
311
|
+
|
|
312
|
+
## FAQ
|
|
313
|
+
|
|
314
|
+
**Q: Is this the same as Coinbase x402's `upto` scheme?**
|
|
315
|
+
A: No — `upto` is a canonical Coinbase-authored scheme that's currently EVM-only and enforces single-use authorizations. This is a **new scheme** called `session`, Stellar-native, built on SAC `approve`.
|
|
316
|
+
|
|
317
|
+
**Q: Is this the same as thirdweb's session x402?**
|
|
318
|
+
A: Same *model* (sign once, settle many), different *mechanism*. Thirdweb uses Uniswap Permit2 on EVM with facilitator-side bookkeeping. This package uses Stellar SAC `approve`/`transfer_from` with on-chain bookkeeping. No EIP-7702 involved on either side.
|
|
319
|
+
|
|
320
|
+
**Q: Can I use it with real Circle USDC on Stellar?**
|
|
321
|
+
A: Yes — the SAC contract ID for Circle testnet USDC is `CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA`, and pubnet is `CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75`. Any SEP-41 token works — native XLM SAC, Circle USDC, or your own issued asset.
|
|
322
|
+
|
|
323
|
+
**Q: What if on-chain `transfer_from` fails after the facilitator debits sqlite?**
|
|
324
|
+
A: The reference facilitator rolls back the sqlite debit automatically and returns `success: false, errorReason: "onchain_transfer_failed"` in the `payment-response` header.
|
|
325
|
+
|
|
326
|
+
**Q: Can I reuse a session across multiple resource servers?**
|
|
327
|
+
A: Only if the `recipient` matches. The facilitator binds a session to exactly one recipient at creation time.
|
|
328
|
+
|
|
329
|
+
**Q: What happens if the session cap runs out mid-request?**
|
|
330
|
+
A: Facilitator `/verify` returns `invalidReason: "cap_exceeded"`. The client sees a 402 with the reason in the `payment-response` header; the resource is not served and no on-chain tx is submitted.
|
|
331
|
+
|
|
332
|
+
**Q: Can I use the browser `fetch` directly, without `wrapFetch`?**
|
|
333
|
+
A: Yes — just handle the 402 yourself. Read the `PAYMENT-REQUIRED` response header (base64 JSON), find the `scheme: "session"` accept, build a `PaymentPayload` with `{ payload: { sessionId } }`, base64-encode it, and retry with a `PAYMENT-SIGNATURE` header.
|
|
334
|
+
|
|
335
|
+
## License
|
|
336
|
+
|
|
337
|
+
MIT © madhav
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CreateSessionOptions, SessionHandle } from "./types";
|
|
2
|
+
export declare function createSession(opts: CreateSessionOptions): Promise<SessionHandle>;
|
|
3
|
+
/**
|
|
4
|
+
* Returns a fetch-compatible function that, on a 402 response, decodes the
|
|
5
|
+
* `PAYMENT-REQUIRED` response header (x402 v2), finds a `scheme: "session"`
|
|
6
|
+
* accept entry, and retries with `PAYMENT-SIGNATURE` (plus `X-PAYMENT` as a
|
|
7
|
+
* fallback for older servers).
|
|
8
|
+
*
|
|
9
|
+
* The x402 v2 wire format (per @x402/core):
|
|
10
|
+
* - Server 402 puts PaymentRequired JSON in `PAYMENT-REQUIRED` header (base64).
|
|
11
|
+
* The body is empty `{}`.
|
|
12
|
+
* - Client retries with PaymentPayload JSON in `PAYMENT-SIGNATURE` header (base64).
|
|
13
|
+
*/
|
|
14
|
+
export declare function wrapFetch(sessionId: string): typeof fetch;
|
|
15
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,oBAAoB,EAMpB,aAAa,EAEd,MAAM,SAAS,CAAC;AAKjB,wBAAsB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CA8DtF;AAgCD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,KAAK,CAuDzD"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// createSession() — the main client-facing API.
|
|
3
|
+
//
|
|
4
|
+
// Flow:
|
|
5
|
+
// 1. GET {facilitatorUrl}/supported to learn the facilitator's spender address.
|
|
6
|
+
// 2. Sign & submit SAC approve(user, spender, cap, expiration_ledger) on-chain.
|
|
7
|
+
// 3. POST /sessions to register the approval. Returns a sessionId.
|
|
8
|
+
// 4. Return a SessionHandle with a wrapFetch() that auto-handles 402 responses.
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createSession = createSession;
|
|
11
|
+
exports.wrapFetch = wrapFetch;
|
|
12
|
+
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
13
|
+
const stellar_1 = require("./stellar");
|
|
14
|
+
const DEFAULT_DECIMALS = 7;
|
|
15
|
+
const DEFAULT_NETWORK = "stellar:testnet";
|
|
16
|
+
async function createSession(opts) {
|
|
17
|
+
const network = opts.network ?? DEFAULT_NETWORK;
|
|
18
|
+
const decimals = opts.decimals ?? DEFAULT_DECIMALS;
|
|
19
|
+
const rpcUrl = opts.sorobanRpcUrl ?? (0, stellar_1.defaultRpcUrlFor)(network);
|
|
20
|
+
// 1. Fetch facilitator's /supported to discover spender address and scheme config.
|
|
21
|
+
const supported = await fetchSupported(opts.facilitatorUrl);
|
|
22
|
+
const kind = supported.kinds.find((k) => k.scheme === "session" && k.network === network);
|
|
23
|
+
if (!kind) {
|
|
24
|
+
throw new Error(`facilitator ${opts.facilitatorUrl} does not advertise scheme=session network=${network}`);
|
|
25
|
+
}
|
|
26
|
+
const spender = kind.extra?.spender ?? supported.signers["stellar:*"]?.[0];
|
|
27
|
+
if (!spender) {
|
|
28
|
+
throw new Error(`facilitator /supported did not include a spender address; got: ${JSON.stringify(supported)}`);
|
|
29
|
+
}
|
|
30
|
+
// 2. Compute expiration ledger from expiresIn seconds.
|
|
31
|
+
const server = new stellar_sdk_1.rpc.Server(rpcUrl, { allowHttp: rpcUrl.startsWith("http://") });
|
|
32
|
+
const expirationLedger = await (0, stellar_1.computeExpirationLedger)(server, opts.expiresIn);
|
|
33
|
+
// 3. Sign & submit SAC approve on-chain.
|
|
34
|
+
const capBaseUnits = (0, stellar_1.decimalToBaseUnits)(opts.spendingCap, decimals);
|
|
35
|
+
const { txHash } = await (0, stellar_1.approveSAC)({
|
|
36
|
+
signer: opts.signer,
|
|
37
|
+
assetContractId: opts.asset,
|
|
38
|
+
spender,
|
|
39
|
+
amount: capBaseUnits,
|
|
40
|
+
expirationLedger,
|
|
41
|
+
network,
|
|
42
|
+
sorobanRpcUrl: rpcUrl,
|
|
43
|
+
});
|
|
44
|
+
// 4. Register the session with the facilitator.
|
|
45
|
+
const createReq = {
|
|
46
|
+
approvalTxHash: txHash,
|
|
47
|
+
user: opts.signer.publicKey(),
|
|
48
|
+
asset: opts.asset,
|
|
49
|
+
recipient: opts.recipient,
|
|
50
|
+
cap: capBaseUnits.toString(),
|
|
51
|
+
expirationLedger,
|
|
52
|
+
network,
|
|
53
|
+
};
|
|
54
|
+
const created = await postSession(opts.facilitatorUrl, createReq);
|
|
55
|
+
// 5. Build the session handle with wrapped fetch.
|
|
56
|
+
return {
|
|
57
|
+
sessionId: created.sessionId,
|
|
58
|
+
user: created.user,
|
|
59
|
+
spender: created.spender,
|
|
60
|
+
asset: created.asset,
|
|
61
|
+
recipient: created.recipient,
|
|
62
|
+
cap: created.cap,
|
|
63
|
+
spent: created.spent,
|
|
64
|
+
expirationLedger: created.expirationLedger,
|
|
65
|
+
network: created.network,
|
|
66
|
+
facilitatorUrl: opts.facilitatorUrl,
|
|
67
|
+
fetch: wrapFetch(created.sessionId),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function fetchSupported(facilitatorUrl) {
|
|
71
|
+
const res = await fetch(joinUrl(facilitatorUrl, "/supported"));
|
|
72
|
+
if (!res.ok)
|
|
73
|
+
throw new Error(`facilitator /supported returned ${res.status}`);
|
|
74
|
+
return (await res.json());
|
|
75
|
+
}
|
|
76
|
+
async function postSession(facilitatorUrl, body) {
|
|
77
|
+
const res = await fetch(joinUrl(facilitatorUrl, "/sessions"), {
|
|
78
|
+
method: "POST",
|
|
79
|
+
headers: { "Content-Type": "application/json" },
|
|
80
|
+
body: JSON.stringify(body),
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok) {
|
|
83
|
+
const text = await res.text();
|
|
84
|
+
throw new Error(`facilitator /sessions ${res.status}: ${text}`);
|
|
85
|
+
}
|
|
86
|
+
return (await res.json());
|
|
87
|
+
}
|
|
88
|
+
function joinUrl(base, path) {
|
|
89
|
+
return base.replace(/\/+$/, "") + (path.startsWith("/") ? path : `/${path}`);
|
|
90
|
+
}
|
|
91
|
+
// --------------------------------------------------------------------------
|
|
92
|
+
// wrapFetch: automatically handles 402 responses by attaching the session payload
|
|
93
|
+
// --------------------------------------------------------------------------
|
|
94
|
+
/**
|
|
95
|
+
* Returns a fetch-compatible function that, on a 402 response, decodes the
|
|
96
|
+
* `PAYMENT-REQUIRED` response header (x402 v2), finds a `scheme: "session"`
|
|
97
|
+
* accept entry, and retries with `PAYMENT-SIGNATURE` (plus `X-PAYMENT` as a
|
|
98
|
+
* fallback for older servers).
|
|
99
|
+
*
|
|
100
|
+
* The x402 v2 wire format (per @x402/core):
|
|
101
|
+
* - Server 402 puts PaymentRequired JSON in `PAYMENT-REQUIRED` header (base64).
|
|
102
|
+
* The body is empty `{}`.
|
|
103
|
+
* - Client retries with PaymentPayload JSON in `PAYMENT-SIGNATURE` header (base64).
|
|
104
|
+
*/
|
|
105
|
+
function wrapFetch(sessionId) {
|
|
106
|
+
return async (input, init = {}) => {
|
|
107
|
+
const first = await fetch(input, init);
|
|
108
|
+
if (first.status !== 402)
|
|
109
|
+
return first;
|
|
110
|
+
// Try v2 header-based discovery first, then v1 body-based.
|
|
111
|
+
let required = null;
|
|
112
|
+
const headerValue = first.headers.get("payment-required") ??
|
|
113
|
+
first.headers.get("PAYMENT-REQUIRED") ??
|
|
114
|
+
first.headers.get("x-payment-required");
|
|
115
|
+
if (headerValue) {
|
|
116
|
+
try {
|
|
117
|
+
required = base64DecodeJson(headerValue);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
/* fall through */
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (!required) {
|
|
124
|
+
try {
|
|
125
|
+
const body = (await first.clone().json());
|
|
126
|
+
if (body && Array.isArray(body.accepts))
|
|
127
|
+
required = body;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
/* fall through */
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (!required)
|
|
134
|
+
return first;
|
|
135
|
+
const sessionAccept = (required.accepts ?? []).find((a) => a.scheme === "session");
|
|
136
|
+
if (!sessionAccept)
|
|
137
|
+
return first;
|
|
138
|
+
const paymentPayload = {
|
|
139
|
+
x402Version: required.x402Version ?? 2,
|
|
140
|
+
accepted: sessionAccept,
|
|
141
|
+
payload: { sessionId },
|
|
142
|
+
};
|
|
143
|
+
const encoded = base64EncodeJson(paymentPayload);
|
|
144
|
+
const retryInit = {
|
|
145
|
+
...init,
|
|
146
|
+
headers: {
|
|
147
|
+
...init.headers,
|
|
148
|
+
// v2 canonical name
|
|
149
|
+
"PAYMENT-SIGNATURE": encoded,
|
|
150
|
+
// v1 fallback — harmless if server ignores it
|
|
151
|
+
"X-PAYMENT": encoded,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
return fetch(input, retryInit);
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function base64EncodeJson(obj) {
|
|
158
|
+
const json = JSON.stringify(obj);
|
|
159
|
+
if (typeof Buffer !== "undefined")
|
|
160
|
+
return Buffer.from(json, "utf-8").toString("base64");
|
|
161
|
+
// Browser fallback
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
|
+
const g = globalThis;
|
|
164
|
+
return g.btoa(unescape(encodeURIComponent(json)));
|
|
165
|
+
}
|
|
166
|
+
function base64DecodeJson(b64) {
|
|
167
|
+
let json;
|
|
168
|
+
if (typeof Buffer !== "undefined") {
|
|
169
|
+
json = Buffer.from(b64, "base64").toString("utf-8");
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
173
|
+
const g = globalThis;
|
|
174
|
+
json = decodeURIComponent(escape(g.atob(b64)));
|
|
175
|
+
}
|
|
176
|
+
return JSON.parse(json);
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { createSession, wrapFetch } from "./client";
|
|
2
|
+
export { SessionStellarScheme } from "./scheme-server";
|
|
3
|
+
export type { ClientSigner, CreateSessionOptions, CreateSessionRequest, CreateSessionResponse, Network, PaymentPayload, PaymentRequired, PaymentRequirements, SessionHandle, SessionPaymentPayloadBody, SupportedResponse, } from "./types";
|
|
4
|
+
export { decimalToBaseUnits, defaultRpcUrlFor, networkPassphraseFor } from "./stellar";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,OAAO,EACP,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,yBAAyB,EACzB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// x402-sessions
|
|
3
|
+
// Sign once, settle many times — session-based x402 payments on Stellar.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.networkPassphraseFor = exports.defaultRpcUrlFor = exports.decimalToBaseUnits = exports.SessionStellarScheme = exports.wrapFetch = exports.createSession = void 0;
|
|
6
|
+
var client_1 = require("./client");
|
|
7
|
+
Object.defineProperty(exports, "createSession", { enumerable: true, get: function () { return client_1.createSession; } });
|
|
8
|
+
Object.defineProperty(exports, "wrapFetch", { enumerable: true, get: function () { return client_1.wrapFetch; } });
|
|
9
|
+
var scheme_server_1 = require("./scheme-server");
|
|
10
|
+
Object.defineProperty(exports, "SessionStellarScheme", { enumerable: true, get: function () { return scheme_server_1.SessionStellarScheme; } });
|
|
11
|
+
var stellar_1 = require("./stellar");
|
|
12
|
+
Object.defineProperty(exports, "decimalToBaseUnits", { enumerable: true, get: function () { return stellar_1.decimalToBaseUnits; } });
|
|
13
|
+
Object.defineProperty(exports, "defaultRpcUrlFor", { enumerable: true, get: function () { return stellar_1.defaultRpcUrlFor; } });
|
|
14
|
+
Object.defineProperty(exports, "networkPassphraseFor", { enumerable: true, get: function () { return stellar_1.networkPassphraseFor; } });
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,gBAAgB;AAChB,yEAAyE;;;AAEzE,mCAAoD;AAA3C,uGAAA,aAAa,OAAA;AAAE,mGAAA,SAAS,OAAA;AACjC,iDAAuD;AAA9C,qHAAA,oBAAoB,OAAA;AAc7B,qCAAuF;AAA9E,6GAAA,kBAAkB,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAAE,+GAAA,oBAAoB,OAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Network, PaymentRequirements } from "./types";
|
|
2
|
+
type AssetAmount = {
|
|
3
|
+
asset: string;
|
|
4
|
+
amount: string;
|
|
5
|
+
extra?: Record<string, unknown>;
|
|
6
|
+
};
|
|
7
|
+
type Price = string | number | AssetAmount;
|
|
8
|
+
export type SessionSchemeConfig = {
|
|
9
|
+
/** SAC contract id of the payment token (e.g. USDC). */
|
|
10
|
+
assetContractId: string;
|
|
11
|
+
/** Token decimals. Default 7 (USDC on Stellar). */
|
|
12
|
+
decimals?: number;
|
|
13
|
+
/** Facilitator base URL — embedded into /402 extras so clients can find the sessions endpoint. */
|
|
14
|
+
facilitatorUrl?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Resource-server plugin for the `session` scheme on Stellar.
|
|
18
|
+
*
|
|
19
|
+
* Usage (in your proxy.ts):
|
|
20
|
+
*
|
|
21
|
+
* import { SessionStellarScheme } from "x402-sessions/scheme-server";
|
|
22
|
+
*
|
|
23
|
+
* const server = new x402ResourceServer(facilitatorClient)
|
|
24
|
+
* .register("stellar:testnet", new SessionStellarScheme({
|
|
25
|
+
* assetContractId: "CBIELTK6...",
|
|
26
|
+
* facilitatorUrl: "http://localhost:4021",
|
|
27
|
+
* }));
|
|
28
|
+
*/
|
|
29
|
+
export declare class SessionStellarScheme {
|
|
30
|
+
readonly scheme: "session";
|
|
31
|
+
private readonly config;
|
|
32
|
+
constructor(config: SessionSchemeConfig);
|
|
33
|
+
parsePrice(price: Price, _network: Network): Promise<AssetAmount>;
|
|
34
|
+
enhancePaymentRequirements(paymentRequirements: PaymentRequirements, supportedKind: {
|
|
35
|
+
x402Version: number;
|
|
36
|
+
scheme: string;
|
|
37
|
+
network: Network;
|
|
38
|
+
extra?: Record<string, unknown>;
|
|
39
|
+
}, _facilitatorExtensions: string[]): Promise<PaymentRequirements>;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=scheme-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheme-server.d.ts","sourceRoot":"","sources":["../src/scheme-server.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE5D,KAAK,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AACtF,KAAK,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3C,MAAM,MAAM,mBAAmB,GAAG;IAChC,wDAAwD;IACxD,eAAe,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAYF;;;;;;;;;;;;GAYG;AAMH,qBAAa,oBAAoB;IAC/B,QAAQ,CAAC,MAAM,EAAG,SAAS,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwE;gBAEnF,MAAM,EAAE,mBAAmB;IAKjC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;IAQjE,0BAA0B,CAC9B,mBAAmB,EAAE,mBAAmB,EACxC,aAAa,EAAE;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACjC,EAED,sBAAsB,EAAE,MAAM,EAAE,GAC/B,OAAO,CAAC,mBAAmB,CAAC;CAUhC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SessionStellarScheme — resource-server plugin.
|
|
3
|
+
//
|
|
4
|
+
// Implements @x402/core's SchemeNetworkServer interface so it can be registered
|
|
5
|
+
// with `x402ResourceServer.register(network, new SessionStellarScheme())`.
|
|
6
|
+
//
|
|
7
|
+
// Responsibilities:
|
|
8
|
+
// - parsePrice(): convert "1.00" (decimal USD-ish) to { asset, amount } base units.
|
|
9
|
+
// - enhancePaymentRequirements(): add scheme-specific extras (facilitator spender,
|
|
10
|
+
// sessions endpoint URL) to the 402 response so the client SDK knows where to
|
|
11
|
+
// create a session.
|
|
12
|
+
//
|
|
13
|
+
// The actual verify/settle happen on the HTTP facilitator (our Express service),
|
|
14
|
+
// which x402's HTTPFacilitatorClient talks to.
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.SessionStellarScheme = void 0;
|
|
17
|
+
const DEFAULT_DECIMALS = 7;
|
|
18
|
+
function decimalToBaseUnits(amount, decimals) {
|
|
19
|
+
const s = typeof amount === "number" ? amount.toString() : amount;
|
|
20
|
+
if (!/^\d+(\.\d+)?$/.test(s))
|
|
21
|
+
throw new Error(`invalid decimal amount: ${s}`);
|
|
22
|
+
const [whole, frac = ""] = s.split(".");
|
|
23
|
+
const padded = (frac + "0".repeat(decimals)).slice(0, decimals);
|
|
24
|
+
return (BigInt(whole) * 10n ** BigInt(decimals) + BigInt(padded || "0")).toString();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resource-server plugin for the `session` scheme on Stellar.
|
|
28
|
+
*
|
|
29
|
+
* Usage (in your proxy.ts):
|
|
30
|
+
*
|
|
31
|
+
* import { SessionStellarScheme } from "x402-sessions/scheme-server";
|
|
32
|
+
*
|
|
33
|
+
* const server = new x402ResourceServer(facilitatorClient)
|
|
34
|
+
* .register("stellar:testnet", new SessionStellarScheme({
|
|
35
|
+
* assetContractId: "CBIELTK6...",
|
|
36
|
+
* facilitatorUrl: "http://localhost:4021",
|
|
37
|
+
* }));
|
|
38
|
+
*/
|
|
39
|
+
// NOTE: We intentionally do NOT `implements SchemeNetworkServer` here — @x402/core
|
|
40
|
+
// uses an exports map that requires node16+ module resolution, which would force
|
|
41
|
+
// us to emit ESM or use .js extensions. Instead, this class is structurally
|
|
42
|
+
// compatible with SchemeNetworkServer. TypeScript's duck typing means consumers
|
|
43
|
+
// can pass `new SessionStellarScheme(...)` directly to `x402ResourceServer.register(network, ...)`.
|
|
44
|
+
class SessionStellarScheme {
|
|
45
|
+
constructor(config) {
|
|
46
|
+
this.scheme = "session";
|
|
47
|
+
this.config = { decimals: DEFAULT_DECIMALS, ...config };
|
|
48
|
+
}
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
50
|
+
async parsePrice(price, _network) {
|
|
51
|
+
if (typeof price === "object" && "asset" in price && "amount" in price) {
|
|
52
|
+
return price;
|
|
53
|
+
}
|
|
54
|
+
const amount = decimalToBaseUnits(price, this.config.decimals);
|
|
55
|
+
return { asset: this.config.assetContractId, amount };
|
|
56
|
+
}
|
|
57
|
+
async enhancePaymentRequirements(paymentRequirements, supportedKind,
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
59
|
+
_facilitatorExtensions) {
|
|
60
|
+
const mergedExtra = {
|
|
61
|
+
...paymentRequirements.extra,
|
|
62
|
+
...(supportedKind.extra ?? {}),
|
|
63
|
+
};
|
|
64
|
+
if (this.config.facilitatorUrl && !mergedExtra.facilitatorUrl) {
|
|
65
|
+
mergedExtra.facilitatorUrl = this.config.facilitatorUrl;
|
|
66
|
+
}
|
|
67
|
+
return { ...paymentRequirements, extra: mergedExtra };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.SessionStellarScheme = SessionStellarScheme;
|
|
71
|
+
//# sourceMappingURL=scheme-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheme-server.js","sourceRoot":"","sources":["../src/scheme-server.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,EAAE;AACF,gFAAgF;AAChF,2EAA2E;AAC3E,EAAE;AACF,oBAAoB;AACpB,sFAAsF;AACtF,qFAAqF;AACrF,kFAAkF;AAClF,wBAAwB;AACxB,EAAE;AACF,iFAAiF;AACjF,+CAA+C;;;AAgB/C,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B,SAAS,kBAAkB,CAAC,MAAuB,EAAE,QAAgB;IACnE,MAAM,CAAC,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAClE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,EAAE,CAAC,CAAC;IAC9E,MAAM,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAChE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AACtF,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,mFAAmF;AACnF,iFAAiF;AACjF,4EAA4E;AAC5E,gFAAgF;AAChF,oGAAoG;AACpG,MAAa,oBAAoB;IAI/B,YAAY,MAA2B;QAH9B,WAAM,GAAG,SAAkB,CAAC;QAInC,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM,EAAE,CAAC;IAC1D,CAAC;IAED,6DAA6D;IAC7D,KAAK,CAAC,UAAU,CAAC,KAAY,EAAE,QAAiB;QAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;YACvE,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAwB,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClF,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,0BAA0B,CAC9B,mBAAwC,EACxC,aAKC;IACD,6DAA6D;IAC7D,sBAAgC;QAEhC,MAAM,WAAW,GAA4B;YAC3C,GAAG,mBAAmB,CAAC,KAAK;YAC5B,GAAG,CAAC,aAAa,CAAC,KAAK,IAAI,EAAE,CAAC;SAC/B,CAAC;QACF,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC;YAC9D,WAAW,CAAC,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;QAC1D,CAAC;QACD,OAAO,EAAE,GAAG,mBAAmB,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IACxD,CAAC;CACF;AArCD,oDAqCC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { rpc } from "@stellar/stellar-sdk";
|
|
2
|
+
import type { ClientSigner, Network } from "./types";
|
|
3
|
+
export declare function networkPassphraseFor(network: Network): string;
|
|
4
|
+
export declare function defaultRpcUrlFor(network: Network): string;
|
|
5
|
+
export declare function computeExpirationLedger(server: rpc.Server, expiresInSeconds: number): Promise<number>;
|
|
6
|
+
/**
|
|
7
|
+
* Convert a decimal-string amount (e.g. "1.00") to base-unit bigint given decimals.
|
|
8
|
+
* Supports simple decimal form only; rejects scientific notation.
|
|
9
|
+
*/
|
|
10
|
+
export declare function decimalToBaseUnits(amount: string, decimals: number): bigint;
|
|
11
|
+
/**
|
|
12
|
+
* Build and submit a SAC `approve(from, spender, amount, expiration_ledger)` transaction.
|
|
13
|
+
*
|
|
14
|
+
* Returns the tx hash on success.
|
|
15
|
+
*
|
|
16
|
+
* Signing: if the signer exposes `signTransaction(xdr, { networkPassphrase })` (browser
|
|
17
|
+
* wallet adapter shape), we use that path. Otherwise we expect a `Keypair` (Node) and
|
|
18
|
+
* call `tx.sign(kp)` directly.
|
|
19
|
+
*/
|
|
20
|
+
export declare function approveSAC(args: {
|
|
21
|
+
signer: ClientSigner;
|
|
22
|
+
assetContractId: string;
|
|
23
|
+
spender: string;
|
|
24
|
+
amount: bigint;
|
|
25
|
+
expirationLedger: number;
|
|
26
|
+
network: Network;
|
|
27
|
+
sorobanRpcUrl?: string;
|
|
28
|
+
}): Promise<{
|
|
29
|
+
txHash: string;
|
|
30
|
+
}>;
|
|
31
|
+
//# sourceMappingURL=stellar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stellar.d.ts","sourceRoot":"","sources":["../src/stellar.ts"],"names":[],"mappings":"AAMA,OAAO,EASL,GAAG,EAEJ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAYrD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAE7D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAIzD;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,GAAG,CAAC,MAAM,EAClB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO3E;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,MAAM,EAAE,YAAY,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA4D9B"}
|
package/dist/stellar.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Client-side Stellar/Soroban helpers for the SDK:
|
|
3
|
+
// - build & submit SAC `approve(from, spender, amount, expiration_ledger)`
|
|
4
|
+
// - fetch the current ledger sequence (to compute expiration_ledger from expiresIn seconds)
|
|
5
|
+
//
|
|
6
|
+
// Imports stellar-sdk as a peer dep — users bring their own version.
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.networkPassphraseFor = networkPassphraseFor;
|
|
9
|
+
exports.defaultRpcUrlFor = defaultRpcUrlFor;
|
|
10
|
+
exports.computeExpirationLedger = computeExpirationLedger;
|
|
11
|
+
exports.decimalToBaseUnits = decimalToBaseUnits;
|
|
12
|
+
exports.approveSAC = approveSAC;
|
|
13
|
+
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
14
|
+
const LEDGER_SECONDS = 5;
|
|
15
|
+
function toI128(amount) {
|
|
16
|
+
return (0, stellar_sdk_1.nativeToScVal)(typeof amount === "string" ? BigInt(amount) : amount, { type: "i128" });
|
|
17
|
+
}
|
|
18
|
+
function addrToScVal(addr) {
|
|
19
|
+
return stellar_sdk_1.Address.fromString(addr).toScVal();
|
|
20
|
+
}
|
|
21
|
+
function networkPassphraseFor(network) {
|
|
22
|
+
return network === "stellar:pubnet" ? stellar_sdk_1.Networks.PUBLIC : stellar_sdk_1.Networks.TESTNET;
|
|
23
|
+
}
|
|
24
|
+
function defaultRpcUrlFor(network) {
|
|
25
|
+
return network === "stellar:pubnet"
|
|
26
|
+
? "https://soroban-rpc.mainnet.stellar.gateway.fm"
|
|
27
|
+
: "https://soroban-testnet.stellar.org";
|
|
28
|
+
}
|
|
29
|
+
async function computeExpirationLedger(server, expiresInSeconds) {
|
|
30
|
+
const latest = await server.getLatestLedger();
|
|
31
|
+
return latest.sequence + Math.ceil(expiresInSeconds / LEDGER_SECONDS);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Convert a decimal-string amount (e.g. "1.00") to base-unit bigint given decimals.
|
|
35
|
+
* Supports simple decimal form only; rejects scientific notation.
|
|
36
|
+
*/
|
|
37
|
+
function decimalToBaseUnits(amount, decimals) {
|
|
38
|
+
if (!/^\d+(\.\d+)?$/.test(amount)) {
|
|
39
|
+
throw new Error(`invalid decimal amount: ${amount}`);
|
|
40
|
+
}
|
|
41
|
+
const [whole, frac = ""] = amount.split(".");
|
|
42
|
+
const padded = (frac + "0".repeat(decimals)).slice(0, decimals);
|
|
43
|
+
return BigInt(whole) * 10n ** BigInt(decimals) + BigInt(padded || "0");
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build and submit a SAC `approve(from, spender, amount, expiration_ledger)` transaction.
|
|
47
|
+
*
|
|
48
|
+
* Returns the tx hash on success.
|
|
49
|
+
*
|
|
50
|
+
* Signing: if the signer exposes `signTransaction(xdr, { networkPassphrase })` (browser
|
|
51
|
+
* wallet adapter shape), we use that path. Otherwise we expect a `Keypair` (Node) and
|
|
52
|
+
* call `tx.sign(kp)` directly.
|
|
53
|
+
*/
|
|
54
|
+
async function approveSAC(args) {
|
|
55
|
+
const rpcUrl = args.sorobanRpcUrl ?? defaultRpcUrlFor(args.network);
|
|
56
|
+
const server = new stellar_sdk_1.rpc.Server(rpcUrl, { allowHttp: rpcUrl.startsWith("http://") });
|
|
57
|
+
const passphrase = networkPassphraseFor(args.network);
|
|
58
|
+
const from = args.signer.publicKey();
|
|
59
|
+
const sourceAccount = await server.getAccount(from);
|
|
60
|
+
const contract = new stellar_sdk_1.Contract(args.assetContractId);
|
|
61
|
+
const tx = new stellar_sdk_1.TransactionBuilder(sourceAccount, {
|
|
62
|
+
fee: stellar_sdk_1.BASE_FEE,
|
|
63
|
+
networkPassphrase: passphrase,
|
|
64
|
+
})
|
|
65
|
+
.addOperation(contract.call("approve", addrToScVal(from), addrToScVal(args.spender), toI128(args.amount), (0, stellar_sdk_1.nativeToScVal)(args.expirationLedger, { type: "u32" })))
|
|
66
|
+
.setTimeout(60)
|
|
67
|
+
.build();
|
|
68
|
+
const prepared = await server.prepareTransaction(tx);
|
|
69
|
+
// --- signing paths ---
|
|
70
|
+
let signedXdr;
|
|
71
|
+
if (args.signer.signTransaction) {
|
|
72
|
+
const xdrStr = prepared.toXDR();
|
|
73
|
+
signedXdr = await args.signer.signTransaction(xdrStr, { networkPassphrase: passphrase });
|
|
74
|
+
}
|
|
75
|
+
else if (args.signer.sign) {
|
|
76
|
+
prepared.sign(args.signer);
|
|
77
|
+
signedXdr = prepared.toXDR();
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
throw new Error("signer must expose either sign() or signTransaction()");
|
|
81
|
+
}
|
|
82
|
+
// Reconstruct signed tx for submission.
|
|
83
|
+
const signedTx = stellar_sdk_1.TransactionBuilder.fromXDR(signedXdr, passphrase);
|
|
84
|
+
const sent = await server.sendTransaction(signedTx);
|
|
85
|
+
if (sent.status === "ERROR") {
|
|
86
|
+
throw new Error(`approve send failed: ${JSON.stringify(sent.errorResult)}`);
|
|
87
|
+
}
|
|
88
|
+
// Poll for confirmation.
|
|
89
|
+
const deadline = Date.now() + 30000;
|
|
90
|
+
while (Date.now() < deadline) {
|
|
91
|
+
const r = await server.getTransaction(sent.hash);
|
|
92
|
+
if (r.status === stellar_sdk_1.rpc.Api.GetTransactionStatus.SUCCESS) {
|
|
93
|
+
return { txHash: sent.hash };
|
|
94
|
+
}
|
|
95
|
+
if (r.status === stellar_sdk_1.rpc.Api.GetTransactionStatus.FAILED) {
|
|
96
|
+
throw new Error(`approve tx failed: ${JSON.stringify(r)}`);
|
|
97
|
+
}
|
|
98
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`approve tx ${sent.hash} timed out`);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=stellar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stellar.js","sourceRoot":"","sources":["../src/stellar.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export type Network = `${string}:${string}`;
|
|
2
|
+
export type PaymentRequirements = {
|
|
3
|
+
scheme: string;
|
|
4
|
+
network: Network;
|
|
5
|
+
asset: string;
|
|
6
|
+
amount: string;
|
|
7
|
+
payTo: string;
|
|
8
|
+
maxTimeoutSeconds: number;
|
|
9
|
+
extra: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
export type SessionPaymentPayloadBody = {
|
|
12
|
+
sessionId: string;
|
|
13
|
+
};
|
|
14
|
+
export type PaymentPayload = {
|
|
15
|
+
x402Version: number;
|
|
16
|
+
accepted: PaymentRequirements;
|
|
17
|
+
payload: SessionPaymentPayloadBody;
|
|
18
|
+
resource?: {
|
|
19
|
+
url: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
mimeType?: string;
|
|
22
|
+
};
|
|
23
|
+
extensions?: Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
export type PaymentRequired = {
|
|
26
|
+
x402Version: number;
|
|
27
|
+
error?: string;
|
|
28
|
+
resource: {
|
|
29
|
+
url: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
mimeType?: string;
|
|
32
|
+
};
|
|
33
|
+
accepts: PaymentRequirements[];
|
|
34
|
+
extensions?: Record<string, unknown>;
|
|
35
|
+
};
|
|
36
|
+
export type CreateSessionOptions = {
|
|
37
|
+
/** Facilitator HTTP base URL, e.g. http://localhost:4021 */
|
|
38
|
+
facilitatorUrl: string;
|
|
39
|
+
/** Stellar network identifier. Default: "stellar:testnet" */
|
|
40
|
+
network?: Network;
|
|
41
|
+
/** SAC contract id of the payment token (e.g. USDC). */
|
|
42
|
+
asset: string;
|
|
43
|
+
/**
|
|
44
|
+
* Spending cap in human units (e.g. "1.00" for 1 USDC).
|
|
45
|
+
* Will be converted to base units using `decimals`.
|
|
46
|
+
*/
|
|
47
|
+
spendingCap: string;
|
|
48
|
+
/** Token decimals. USDC on Stellar = 7. Default: 7 */
|
|
49
|
+
decimals?: number;
|
|
50
|
+
/** How long the session is valid, in seconds. Converted to ledgers (~5s/ledger). */
|
|
51
|
+
expiresIn: number;
|
|
52
|
+
/** Address where settled funds go (resource server wallet). */
|
|
53
|
+
recipient: string;
|
|
54
|
+
/**
|
|
55
|
+
* Signer used to sign & submit the SAC approve transaction.
|
|
56
|
+
* For Node: a `Keypair` from @stellar/stellar-sdk.
|
|
57
|
+
* For browser: implement the `ClientSigner` interface below.
|
|
58
|
+
*/
|
|
59
|
+
signer: ClientSigner;
|
|
60
|
+
/** Optional custom Soroban RPC URL. Defaults to testnet public RPC. */
|
|
61
|
+
sorobanRpcUrl?: string;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Minimal signer interface the SDK needs from a wallet.
|
|
65
|
+
* A @stellar/stellar-sdk `Keypair` satisfies this directly.
|
|
66
|
+
* For browser wallets (Freighter, etc.), provide an adapter.
|
|
67
|
+
*/
|
|
68
|
+
export interface ClientSigner {
|
|
69
|
+
/** The G... public key of this signer. */
|
|
70
|
+
publicKey(): string;
|
|
71
|
+
/** Sign a tx hash (raw 32-byte buffer). Used by the stellar-sdk internal tx.sign flow. */
|
|
72
|
+
sign?(data: Buffer): Buffer;
|
|
73
|
+
/**
|
|
74
|
+
* Alternative: sign a built Transaction's XDR string and return the signed XDR.
|
|
75
|
+
* Use this form for browser wallet adapters like Freighter that expose
|
|
76
|
+
* `signTransaction(xdr): Promise<xdr>`.
|
|
77
|
+
*/
|
|
78
|
+
signTransaction?(xdr: string, opts?: {
|
|
79
|
+
networkPassphrase: string;
|
|
80
|
+
}): Promise<string>;
|
|
81
|
+
}
|
|
82
|
+
export type SessionHandle = {
|
|
83
|
+
sessionId: string;
|
|
84
|
+
user: string;
|
|
85
|
+
spender: string;
|
|
86
|
+
asset: string;
|
|
87
|
+
recipient: string;
|
|
88
|
+
cap: string;
|
|
89
|
+
spent: string;
|
|
90
|
+
expirationLedger: number;
|
|
91
|
+
network: Network;
|
|
92
|
+
facilitatorUrl: string;
|
|
93
|
+
/** Fetch wrapper that auto-adds X-PAYMENT session header on 402 responses. */
|
|
94
|
+
fetch: typeof fetch;
|
|
95
|
+
};
|
|
96
|
+
export type CreateSessionRequest = {
|
|
97
|
+
approvalTxHash: string;
|
|
98
|
+
user: string;
|
|
99
|
+
asset: string;
|
|
100
|
+
recipient: string;
|
|
101
|
+
cap: string;
|
|
102
|
+
expirationLedger: number;
|
|
103
|
+
network: Network;
|
|
104
|
+
};
|
|
105
|
+
export type CreateSessionResponse = {
|
|
106
|
+
sessionId: string;
|
|
107
|
+
user: string;
|
|
108
|
+
spender: string;
|
|
109
|
+
asset: string;
|
|
110
|
+
recipient: string;
|
|
111
|
+
cap: string;
|
|
112
|
+
spent: string;
|
|
113
|
+
expirationLedger: number;
|
|
114
|
+
network: Network;
|
|
115
|
+
};
|
|
116
|
+
export type SupportedResponse = {
|
|
117
|
+
kinds: Array<{
|
|
118
|
+
x402Version: number;
|
|
119
|
+
scheme: string;
|
|
120
|
+
network: Network;
|
|
121
|
+
extra?: Record<string, unknown>;
|
|
122
|
+
}>;
|
|
123
|
+
extensions: string[];
|
|
124
|
+
signers: Record<string, string[]>;
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,mFAAmF;AACnF,mEAAmE"}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "x402-sessions",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Sign once, settle many times — session-based x402 payments on Stellar. One on-chain SAC approve unlocks unlimited micropayments via transfer_from until the cap or expiry is reached. No per-request wallet popup.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "madhav",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"sideEffects": false,
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./client": {
|
|
21
|
+
"types": "./dist/client.d.ts",
|
|
22
|
+
"default": "./dist/client.js"
|
|
23
|
+
},
|
|
24
|
+
"./scheme": {
|
|
25
|
+
"types": "./dist/scheme-server.d.ts",
|
|
26
|
+
"default": "./dist/scheme-server.js"
|
|
27
|
+
},
|
|
28
|
+
"./stellar": {
|
|
29
|
+
"types": "./dist/stellar.d.ts",
|
|
30
|
+
"default": "./dist/stellar.js"
|
|
31
|
+
},
|
|
32
|
+
"./package.json": "./package.json"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.json",
|
|
36
|
+
"dev": "tsc -p tsconfig.json --watch",
|
|
37
|
+
"clean": "rm -rf dist",
|
|
38
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"x402",
|
|
42
|
+
"stellar",
|
|
43
|
+
"soroban",
|
|
44
|
+
"payments",
|
|
45
|
+
"micropayments",
|
|
46
|
+
"session",
|
|
47
|
+
"pay-per-call",
|
|
48
|
+
"sac",
|
|
49
|
+
"usdc",
|
|
50
|
+
"sign-once",
|
|
51
|
+
"settle-many",
|
|
52
|
+
"agentic-payments"
|
|
53
|
+
],
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@stellar/stellar-sdk": "^14.0.0 || ^15.0.0",
|
|
56
|
+
"@x402/core": "^2.8.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependenciesMeta": {
|
|
59
|
+
"@x402/core": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@stellar/stellar-sdk": "^15.0.1",
|
|
65
|
+
"@types/node": "^22",
|
|
66
|
+
"@x402/core": "^2.8.0",
|
|
67
|
+
"typescript": "^5.5.0"
|
|
68
|
+
},
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=18"
|
|
71
|
+
},
|
|
72
|
+
"publishConfig": {
|
|
73
|
+
"access": "public"
|
|
74
|
+
}
|
|
75
|
+
}
|