@agentokratia/x402-escrow 2.0.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 +159 -0
- package/dist/client/index.cjs +524 -0
- package/dist/client/index.cjs.map +1 -0
- package/dist/client/index.d.cts +51 -0
- package/dist/client/index.d.ts +51 -0
- package/dist/client/index.js +492 -0
- package/dist/client/index.js.map +1 -0
- package/dist/index.cjs +596 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +568 -0
- package/dist/index.js.map +1 -0
- package/dist/server/index.cjs +100 -0
- package/dist/server/index.cjs.map +1 -0
- package/dist/server/index.d.cts +105 -0
- package/dist/server/index.d.ts +105 -0
- package/dist/server/index.js +71 -0
- package/dist/server/index.js.map +1 -0
- package/dist/session-wrapper-Cf7U8ObX.d.cts +372 -0
- package/dist/session-wrapper-Cf7U8ObX.d.ts +372 -0
- package/package.json +74 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { Address, WalletClient } from 'viem';
|
|
2
|
+
import { x402Client } from '@x402/core/client';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* x402 Protocol Types for @agentokratia/x402-escrow
|
|
6
|
+
*
|
|
7
|
+
* Subset of types needed for the escrow scheme.
|
|
8
|
+
*/
|
|
9
|
+
/** Current x402 protocol version */
|
|
10
|
+
declare const X402_VERSION = 2;
|
|
11
|
+
/** Network identifier in CAIP-2 format (e.g., "eip155:8453" for Base) */
|
|
12
|
+
type Network = `${string}:${string}`;
|
|
13
|
+
/**
|
|
14
|
+
* PaymentRequirements - defines a single payment option
|
|
15
|
+
* Base interface that each scheme extends
|
|
16
|
+
*/
|
|
17
|
+
interface PaymentRequirements {
|
|
18
|
+
scheme: string;
|
|
19
|
+
network: Network;
|
|
20
|
+
amount: string;
|
|
21
|
+
asset: string;
|
|
22
|
+
payTo: string;
|
|
23
|
+
maxTimeoutSeconds: number;
|
|
24
|
+
extra: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* x402 Facilitator settle response (JSON body)
|
|
28
|
+
*/
|
|
29
|
+
interface SettleResponse {
|
|
30
|
+
success: boolean;
|
|
31
|
+
errorReason?: string;
|
|
32
|
+
payer?: string;
|
|
33
|
+
transaction: string;
|
|
34
|
+
network: string;
|
|
35
|
+
session?: {
|
|
36
|
+
id: string;
|
|
37
|
+
balance: string;
|
|
38
|
+
token?: string;
|
|
39
|
+
expiresAt?: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Header name constants (x402 v2) */
|
|
43
|
+
declare const X402_HEADERS: {
|
|
44
|
+
/** Server → Client: Payment options (402 response) - base64 JSON */
|
|
45
|
+
readonly PAYMENT_REQUIRED: "PAYMENT-REQUIRED";
|
|
46
|
+
/** Client → Server: Payment payload - base64 JSON */
|
|
47
|
+
readonly PAYMENT_SIGNATURE: "PAYMENT-SIGNATURE";
|
|
48
|
+
/** Server → Client: Settlement result - base64 JSON (includes session data) */
|
|
49
|
+
readonly PAYMENT_RESPONSE: "PAYMENT-RESPONSE";
|
|
50
|
+
};
|
|
51
|
+
/** PAYMENT-RESPONSE header data (all schemes) */
|
|
52
|
+
interface PaymentResponseData {
|
|
53
|
+
success: boolean;
|
|
54
|
+
transaction: string;
|
|
55
|
+
network: string;
|
|
56
|
+
payer?: string;
|
|
57
|
+
receiver?: string;
|
|
58
|
+
errorReason?: string;
|
|
59
|
+
session?: {
|
|
60
|
+
id: string;
|
|
61
|
+
balance: string;
|
|
62
|
+
token?: string;
|
|
63
|
+
expiresAt?: number;
|
|
64
|
+
};
|
|
65
|
+
requirements?: PaymentRequirements;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parse PAYMENT-RESPONSE header.
|
|
69
|
+
*/
|
|
70
|
+
declare function parsePaymentResponseHeader(header: string): PaymentResponseData | null;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Session Storage for x402 Escrow Scheme
|
|
74
|
+
*
|
|
75
|
+
* Provides session persistence with two implementations:
|
|
76
|
+
* - InMemoryStorage: For server-side or ephemeral usage
|
|
77
|
+
* - LocalStorage: For browser persistence across page loads
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
interface StoredSession {
|
|
81
|
+
sessionId: string;
|
|
82
|
+
sessionToken: string;
|
|
83
|
+
network: string;
|
|
84
|
+
payer: Address;
|
|
85
|
+
receiver: Address;
|
|
86
|
+
balance: string;
|
|
87
|
+
authorizationExpiry: number;
|
|
88
|
+
createdAt: number;
|
|
89
|
+
}
|
|
90
|
+
interface SessionStorage {
|
|
91
|
+
get(network: string, receiver: Address): StoredSession | null;
|
|
92
|
+
findBest(network: string, receiver: Address, minAmount: bigint): StoredSession | null;
|
|
93
|
+
set(session: StoredSession): void;
|
|
94
|
+
update(sessionId: string, balance: string): void;
|
|
95
|
+
list(): StoredSession[];
|
|
96
|
+
remove(sessionId: string): void;
|
|
97
|
+
}
|
|
98
|
+
declare abstract class BaseStorage implements SessionStorage {
|
|
99
|
+
protected sessions: Map<string, StoredSession>;
|
|
100
|
+
get(network: string, receiver: Address): StoredSession | null;
|
|
101
|
+
findBest(network: string, receiver: Address, minAmount: bigint): StoredSession | null;
|
|
102
|
+
set(session: StoredSession): void;
|
|
103
|
+
update(sessionId: string, balance: string): void;
|
|
104
|
+
list(): StoredSession[];
|
|
105
|
+
remove(sessionId: string): void;
|
|
106
|
+
/** Override in subclasses for persistence */
|
|
107
|
+
protected onUpdate(): void;
|
|
108
|
+
}
|
|
109
|
+
declare class InMemoryStorage extends BaseStorage {
|
|
110
|
+
}
|
|
111
|
+
declare class BrowserLocalStorage extends BaseStorage {
|
|
112
|
+
private key;
|
|
113
|
+
constructor(key?: string);
|
|
114
|
+
protected onUpdate(): void;
|
|
115
|
+
private load;
|
|
116
|
+
private save;
|
|
117
|
+
}
|
|
118
|
+
declare function createStorage(type: 'memory' | 'localStorage', storageKey?: string): SessionStorage;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Session Manager for x402 Escrow Scheme
|
|
122
|
+
*
|
|
123
|
+
* Handles session lifecycle: lookup, storage, and validation.
|
|
124
|
+
* Uses the SessionStorage interface for persistence.
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
interface SessionManagerOptions {
|
|
128
|
+
/** Storage type: 'memory' (default) or 'localStorage' */
|
|
129
|
+
storage?: 'memory' | 'localStorage';
|
|
130
|
+
/** localStorage key (default: 'x402-sessions') */
|
|
131
|
+
storageKey?: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Manages session lifecycle for the escrow scheme.
|
|
135
|
+
*
|
|
136
|
+
* Responsibilities:
|
|
137
|
+
* - Store sessions from escrow settlement responses
|
|
138
|
+
* - Find best session for a receiver/amount
|
|
139
|
+
* - Update session balances after debits
|
|
140
|
+
* - Validate session expiry
|
|
141
|
+
*/
|
|
142
|
+
declare class SessionManager {
|
|
143
|
+
private readonly storage;
|
|
144
|
+
private readonly network;
|
|
145
|
+
constructor(network: Network, options?: SessionManagerOptions);
|
|
146
|
+
/**
|
|
147
|
+
* Store a session from escrow settlement response.
|
|
148
|
+
*/
|
|
149
|
+
store(session: Omit<StoredSession, 'createdAt'>): void;
|
|
150
|
+
/**
|
|
151
|
+
* Get session for a specific receiver.
|
|
152
|
+
*/
|
|
153
|
+
getForReceiver(receiver: Address): StoredSession | null;
|
|
154
|
+
/**
|
|
155
|
+
* Find best session for receiver with minimum balance.
|
|
156
|
+
*/
|
|
157
|
+
findBest(receiver: Address, minAmount: bigint): StoredSession | null;
|
|
158
|
+
/**
|
|
159
|
+
* Check if valid session exists for receiver.
|
|
160
|
+
*/
|
|
161
|
+
hasValid(receiver: Address, minAmount?: string): boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Update session balance after debit.
|
|
164
|
+
*/
|
|
165
|
+
updateBalance(sessionId: string, newBalance: string): void;
|
|
166
|
+
/**
|
|
167
|
+
* Get all stored sessions.
|
|
168
|
+
*/
|
|
169
|
+
getAll(): StoredSession[];
|
|
170
|
+
/**
|
|
171
|
+
* Remove a specific session.
|
|
172
|
+
*/
|
|
173
|
+
remove(sessionId: string): void;
|
|
174
|
+
/**
|
|
175
|
+
* Clear all sessions.
|
|
176
|
+
*/
|
|
177
|
+
clear(): void;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Escrow Client Scheme (Unified)
|
|
182
|
+
*
|
|
183
|
+
* Thin orchestrator that delegates to:
|
|
184
|
+
* - SessionManager: Session lifecycle management
|
|
185
|
+
* - Signer (eip712.ts): EIP-712 signing for session creation
|
|
186
|
+
*
|
|
187
|
+
* Handles both session CREATION and session USAGE in a single scheme.
|
|
188
|
+
* - First call: Creates session with wallet signature (EIP-712)
|
|
189
|
+
* - Subsequent calls: Uses stored session token (no signature needed)
|
|
190
|
+
*/
|
|
191
|
+
|
|
192
|
+
interface PaymentPayload {
|
|
193
|
+
x402Version: number;
|
|
194
|
+
resource?: {
|
|
195
|
+
url: string;
|
|
196
|
+
description?: string;
|
|
197
|
+
mimeType?: string;
|
|
198
|
+
};
|
|
199
|
+
accepted?: PaymentRequirements;
|
|
200
|
+
payload: Record<string, unknown>;
|
|
201
|
+
extensions?: Record<string, unknown>;
|
|
202
|
+
}
|
|
203
|
+
interface SchemeNetworkClient {
|
|
204
|
+
readonly scheme: string;
|
|
205
|
+
createPaymentPayload(x402Version: number, paymentRequirements: PaymentRequirements): Promise<Pick<PaymentPayload, 'x402Version' | 'payload'>>;
|
|
206
|
+
}
|
|
207
|
+
interface EscrowSchemeOptions {
|
|
208
|
+
/** Session duration in seconds (default: 1 hour) */
|
|
209
|
+
sessionDuration?: number;
|
|
210
|
+
/** Refund window after session expires (default: 24 hours) */
|
|
211
|
+
refundWindow?: number;
|
|
212
|
+
/** Storage type: 'memory' (default) or 'localStorage' */
|
|
213
|
+
storage?: 'memory' | 'localStorage';
|
|
214
|
+
/** localStorage key (default: 'x402-sessions') */
|
|
215
|
+
storageKey?: string;
|
|
216
|
+
/**
|
|
217
|
+
* Custom deposit amount in atomic units (e.g., "10000000" for $10 USDC).
|
|
218
|
+
* Must be between minDeposit and maxDeposit from the 402 response.
|
|
219
|
+
* If not specified, defaults to maxDeposit for maximum flexibility.
|
|
220
|
+
*/
|
|
221
|
+
depositAmount?: string;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Escrow payment scheme for x402 (Unified).
|
|
225
|
+
*
|
|
226
|
+
* Orchestrates:
|
|
227
|
+
* - SessionManager for session lookup and storage
|
|
228
|
+
* - EIP-712 signer for session creation signatures
|
|
229
|
+
*
|
|
230
|
+
* Auto-preference: If a valid session exists for the receiver,
|
|
231
|
+
* it will be used automatically (no wallet interaction required).
|
|
232
|
+
*/
|
|
233
|
+
declare class EscrowScheme implements SchemeNetworkClient {
|
|
234
|
+
readonly scheme = "escrow";
|
|
235
|
+
/** Session manager - use directly for session operations */
|
|
236
|
+
readonly sessions: SessionManager;
|
|
237
|
+
private readonly wallet;
|
|
238
|
+
private readonly chainId;
|
|
239
|
+
readonly network: Network;
|
|
240
|
+
private readonly sessionDuration;
|
|
241
|
+
private readonly refundWindow;
|
|
242
|
+
private readonly customDepositAmount?;
|
|
243
|
+
constructor(walletClient: WalletClient, options?: EscrowSchemeOptions);
|
|
244
|
+
get address(): Address;
|
|
245
|
+
/**
|
|
246
|
+
* Creates payment payload for escrow scheme.
|
|
247
|
+
* Auto-detects whether to create new session or use existing one.
|
|
248
|
+
*/
|
|
249
|
+
createPaymentPayload(x402Version: number, paymentRequirements: PaymentRequirements): Promise<Pick<PaymentPayload, 'x402Version' | 'payload'>>;
|
|
250
|
+
/**
|
|
251
|
+
* Session USAGE payload - uses existing session (no signature).
|
|
252
|
+
*/
|
|
253
|
+
private createUsagePayload;
|
|
254
|
+
/**
|
|
255
|
+
* Session CREATION payload - requires wallet signature.
|
|
256
|
+
*/
|
|
257
|
+
private createCreationPayload;
|
|
258
|
+
private generateSalt;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Session Extraction Wrappers
|
|
263
|
+
*
|
|
264
|
+
* Thin wrappers that extract sessions from x402 responses and store them.
|
|
265
|
+
*
|
|
266
|
+
* @example Simple (recommended)
|
|
267
|
+
* ```typescript
|
|
268
|
+
* const { fetch: escrowFetch, scheme, x402 } = createEscrowFetch(walletClient);
|
|
269
|
+
* const response = await escrowFetch('https://api.example.com/premium');
|
|
270
|
+
*
|
|
271
|
+
* // Add hooks (user has control)
|
|
272
|
+
* x402.onAfterPaymentCreation(async (ctx) => {
|
|
273
|
+
* console.log('Payment created:', ctx.paymentPayload);
|
|
274
|
+
* });
|
|
275
|
+
* ```
|
|
276
|
+
*
|
|
277
|
+
* @example With custom fetch
|
|
278
|
+
* ```typescript
|
|
279
|
+
* const { fetch: escrowFetch } = createEscrowFetch(walletClient, {
|
|
280
|
+
* fetch: ky, // Use ky, undici, node-fetch, etc.
|
|
281
|
+
* });
|
|
282
|
+
* ```
|
|
283
|
+
*
|
|
284
|
+
* @example Fully composable (manual setup)
|
|
285
|
+
* ```typescript
|
|
286
|
+
* const escrowScheme = new EscrowScheme(walletClient);
|
|
287
|
+
* const x402 = new x402Client().register('eip155:84532', escrowScheme);
|
|
288
|
+
* const paidFetch = wrapFetchWithPayment(fetch, x402);
|
|
289
|
+
* const escrowFetch = withSessionExtraction(paidFetch, escrowScheme);
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
|
|
293
|
+
type FetchLike = typeof globalThis.fetch;
|
|
294
|
+
/** Options for createEscrowFetch */
|
|
295
|
+
interface CreateEscrowFetchOptions extends EscrowSchemeOptions {
|
|
296
|
+
/** Custom fetch implementation (default: globalThis.fetch) */
|
|
297
|
+
fetch?: FetchLike;
|
|
298
|
+
}
|
|
299
|
+
/** Result from createEscrowFetch */
|
|
300
|
+
interface EscrowFetchResult {
|
|
301
|
+
/** Fetch function with automatic payment + session handling */
|
|
302
|
+
fetch: FetchLike;
|
|
303
|
+
/** Access to underlying scheme for session management */
|
|
304
|
+
scheme: EscrowScheme;
|
|
305
|
+
/** Access to x402Client for adding hooks (onBeforePaymentCreation, etc.) */
|
|
306
|
+
x402: x402Client;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Creates a fetch function with automatic escrow payment and session handling.
|
|
310
|
+
* This is the simplest way to integrate x402 escrow payments.
|
|
311
|
+
*
|
|
312
|
+
* @example Simple usage
|
|
313
|
+
* ```typescript
|
|
314
|
+
* const { fetch: escrowFetch, scheme, x402 } = createEscrowFetch(walletClient);
|
|
315
|
+
* const response = await escrowFetch('https://api.example.com/premium');
|
|
316
|
+
*
|
|
317
|
+
* // Access sessions
|
|
318
|
+
* scheme.sessions.getAll();
|
|
319
|
+
* scheme.sessions.hasValid(receiverAddress, '10000');
|
|
320
|
+
* ```
|
|
321
|
+
*
|
|
322
|
+
* @example With custom fetch and hooks
|
|
323
|
+
* ```typescript
|
|
324
|
+
* const { fetch: escrowFetch, x402 } = createEscrowFetch(walletClient, {
|
|
325
|
+
* fetch: customFetch, // Use ky, undici, node-fetch, etc.
|
|
326
|
+
* });
|
|
327
|
+
*
|
|
328
|
+
* // Add hooks for user control
|
|
329
|
+
* x402.onBeforePaymentCreation(async (ctx) => {
|
|
330
|
+
* console.log('About to pay:', ctx.paymentRequirements);
|
|
331
|
+
* });
|
|
332
|
+
* ```
|
|
333
|
+
*/
|
|
334
|
+
declare function createEscrowFetch(walletClient: WalletClient, options?: CreateEscrowFetchOptions): EscrowFetchResult;
|
|
335
|
+
/**
|
|
336
|
+
* Wraps a paid fetch to automatically extract and store sessions.
|
|
337
|
+
* Use with wrapFetchWithPayment from @x402/fetch.
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
* ```typescript
|
|
341
|
+
* const escrowScheme = new EscrowScheme(walletClient);
|
|
342
|
+
* const x402 = new x402Client().register('eip155:84532', escrowScheme);
|
|
343
|
+
* const paidFetch = wrapFetchWithPayment(fetch, x402);
|
|
344
|
+
* const escrowFetch = withSessionExtraction(paidFetch, escrowScheme);
|
|
345
|
+
*
|
|
346
|
+
* const response = await escrowFetch('https://api.example.com/premium');
|
|
347
|
+
* // Session automatically stored if present in response
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
declare function withSessionExtraction(paidFetch: FetchLike, escrowScheme: EscrowScheme): FetchLike;
|
|
351
|
+
interface AxiosResponseLike {
|
|
352
|
+
headers: Record<string, string | undefined>;
|
|
353
|
+
[key: string]: unknown;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Returns an Axios response interceptor that extracts and stores sessions.
|
|
357
|
+
* Use with wrapAxiosWithPayment from @x402/axios.
|
|
358
|
+
*
|
|
359
|
+
* @example
|
|
360
|
+
* ```typescript
|
|
361
|
+
* const escrowScheme = new EscrowScheme(walletClient);
|
|
362
|
+
* const x402 = new x402Client().register('eip155:84532', escrowScheme);
|
|
363
|
+
* const paidAxios = wrapAxiosWithPayment(axios.create(), x402);
|
|
364
|
+
* paidAxios.interceptors.response.use(withAxiosSessionExtraction(escrowScheme));
|
|
365
|
+
*
|
|
366
|
+
* const response = await paidAxios.get('https://api.example.com/premium');
|
|
367
|
+
* // Session automatically stored if present in response
|
|
368
|
+
* ```
|
|
369
|
+
*/
|
|
370
|
+
declare function withAxiosSessionExtraction(escrowScheme: EscrowScheme): <T extends AxiosResponseLike>(response: T) => T;
|
|
371
|
+
|
|
372
|
+
export { BrowserLocalStorage as B, type CreateEscrowFetchOptions as C, type EscrowFetchResult as E, InMemoryStorage as I, type PaymentResponseData as P, type StoredSession as S, X402_HEADERS as X, EscrowScheme as a, type EscrowSchemeOptions as b, createEscrowFetch as c, withAxiosSessionExtraction as d, type SettleResponse as e, SessionManager as f, type SessionManagerOptions as g, type SessionStorage as h, createStorage as i, X402_VERSION as j, parsePaymentResponseHeader as p, withSessionExtraction as w };
|