@alleyboss/micropay-solana-x402-paywall 3.3.15 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -0
- package/dist/agent/index.cjs +432 -0
- package/dist/agent/index.d.cts +77 -1
- package/dist/agent/index.d.ts +77 -1
- package/dist/agent/index.js +433 -2
- package/dist/fetch/index.cjs +421 -0
- package/dist/fetch/index.d.cts +403 -0
- package/dist/fetch/index.d.ts +403 -0
- package/dist/fetch/index.js +402 -0
- package/dist/index.cjs +432 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +432 -1
- package/package.json +27 -3
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { WalletAdapter } from '@solana/wallet-adapter-base';
|
|
2
|
+
import { Keypair, Connection } from '@solana/web3.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @fileoverview Type definitions for x402Fetch
|
|
6
|
+
* @module @alleyboss/micropay-solana-x402-paywall/fetch
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Solana network identifier
|
|
11
|
+
*/
|
|
12
|
+
type SolanaNetwork = 'devnet' | 'mainnet-beta' | 'testnet';
|
|
13
|
+
/**
|
|
14
|
+
* Wallet type - supports both browser wallet adapters and server-side keypairs
|
|
15
|
+
*/
|
|
16
|
+
type WalletLike = WalletAdapter | Keypair;
|
|
17
|
+
/**
|
|
18
|
+
* Payment requirements extracted from 402 response
|
|
19
|
+
*/
|
|
20
|
+
interface PaymentRequirements {
|
|
21
|
+
/** Recipient wallet address */
|
|
22
|
+
readonly payTo: string;
|
|
23
|
+
/** Amount in smallest unit (lamports for SOL) */
|
|
24
|
+
readonly amount: string;
|
|
25
|
+
/** Asset identifier (e.g., 'SOL', 'USDC') */
|
|
26
|
+
readonly asset: string;
|
|
27
|
+
/** Network identifier */
|
|
28
|
+
readonly network: string;
|
|
29
|
+
/** Optional: Human-readable description */
|
|
30
|
+
readonly description?: string;
|
|
31
|
+
/** Optional: Resource identifier */
|
|
32
|
+
readonly resource?: string;
|
|
33
|
+
/** Optional: Maximum age of payment proof in seconds */
|
|
34
|
+
readonly maxAge?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Configuration for createX402Fetch factory
|
|
38
|
+
*/
|
|
39
|
+
interface X402FetchConfig {
|
|
40
|
+
/**
|
|
41
|
+
* Solana wallet - WalletAdapter for browser, Keypair for server/agents
|
|
42
|
+
* @example
|
|
43
|
+
* // Browser
|
|
44
|
+
* { wallet: useWallet() }
|
|
45
|
+
* // Server/Agent
|
|
46
|
+
* { wallet: Keypair.fromSecretKey(...) }
|
|
47
|
+
*/
|
|
48
|
+
readonly wallet: WalletLike;
|
|
49
|
+
/**
|
|
50
|
+
* Solana network to use
|
|
51
|
+
* @default 'mainnet-beta'
|
|
52
|
+
*/
|
|
53
|
+
readonly network?: SolanaNetwork;
|
|
54
|
+
/**
|
|
55
|
+
* Solana RPC connection (optional - will create one if not provided)
|
|
56
|
+
*/
|
|
57
|
+
readonly connection?: Connection;
|
|
58
|
+
/**
|
|
59
|
+
* Custom facilitator URL for verification
|
|
60
|
+
* If not provided, uses built-in verification
|
|
61
|
+
*/
|
|
62
|
+
readonly facilitatorUrl?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Callback when payment is required
|
|
65
|
+
* Return `true` to proceed with payment, `false` to abort
|
|
66
|
+
* If not provided, payment proceeds automatically
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* onPaymentRequired: async (req) => {
|
|
70
|
+
* return confirm(`Pay ${req.amount} ${req.asset}?`);
|
|
71
|
+
* }
|
|
72
|
+
*/
|
|
73
|
+
readonly onPaymentRequired?: PaymentRequiredHook;
|
|
74
|
+
/**
|
|
75
|
+
* Callback after successful payment
|
|
76
|
+
*/
|
|
77
|
+
readonly onPaymentSuccess?: PaymentSuccessHook;
|
|
78
|
+
/**
|
|
79
|
+
* Callback on payment failure
|
|
80
|
+
*/
|
|
81
|
+
readonly onPaymentError?: PaymentErrorHook;
|
|
82
|
+
/**
|
|
83
|
+
* Priority fee configuration for Solana transactions
|
|
84
|
+
*/
|
|
85
|
+
readonly priorityFee?: PriorityFeeConfig;
|
|
86
|
+
/**
|
|
87
|
+
* Maximum retries for transaction confirmation
|
|
88
|
+
* @default 3
|
|
89
|
+
*/
|
|
90
|
+
readonly maxRetries?: number;
|
|
91
|
+
/**
|
|
92
|
+
* Timeout for payment flow in milliseconds
|
|
93
|
+
* @default 30000 (30 seconds)
|
|
94
|
+
*/
|
|
95
|
+
readonly timeout?: number;
|
|
96
|
+
/**
|
|
97
|
+
* Maximum payment amount per request in lamports
|
|
98
|
+
* Prevents wallet drain from malicious 402 responses
|
|
99
|
+
* @default undefined (no limit - USE WITH CAUTION)
|
|
100
|
+
* @example 10_000_000n // Max 0.01 SOL per request
|
|
101
|
+
*/
|
|
102
|
+
readonly maxPaymentPerRequest?: bigint;
|
|
103
|
+
/**
|
|
104
|
+
* Whitelist of allowed recipient addresses
|
|
105
|
+
* Payments to addresses not in this list will be rejected
|
|
106
|
+
* @default undefined (allow all - USE WITH CAUTION)
|
|
107
|
+
* @example ['7fPjN...', 'ABC123...']
|
|
108
|
+
*/
|
|
109
|
+
readonly allowedRecipients?: readonly string[];
|
|
110
|
+
/**
|
|
111
|
+
* Solana commitment level for transaction confirmation
|
|
112
|
+
* - 'processed': Fastest (~100ms), optimistic, may revert
|
|
113
|
+
* - 'confirmed': Balanced (~400ms), supermajority confirmed
|
|
114
|
+
* - 'finalized': Slowest (~30s), irreversible
|
|
115
|
+
* @default 'confirmed'
|
|
116
|
+
*/
|
|
117
|
+
readonly commitment?: 'processed' | 'confirmed' | 'finalized';
|
|
118
|
+
/**
|
|
119
|
+
* Rate limiting configuration to prevent infinite payment loops
|
|
120
|
+
*/
|
|
121
|
+
readonly rateLimit?: RateLimitConfig;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Rate limiting configuration
|
|
125
|
+
*/
|
|
126
|
+
interface RateLimitConfig {
|
|
127
|
+
/**
|
|
128
|
+
* Maximum number of payments allowed within the time window
|
|
129
|
+
* @default 10
|
|
130
|
+
*/
|
|
131
|
+
readonly maxPayments: number;
|
|
132
|
+
/**
|
|
133
|
+
* Time window in milliseconds
|
|
134
|
+
* @default 60000 (1 minute)
|
|
135
|
+
*/
|
|
136
|
+
readonly windowMs: number;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Priority fee configuration
|
|
140
|
+
*/
|
|
141
|
+
interface PriorityFeeConfig {
|
|
142
|
+
/** Enable priority fees */
|
|
143
|
+
readonly enabled: boolean;
|
|
144
|
+
/** Micro-lamports per compute unit */
|
|
145
|
+
readonly microLamports?: number;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Hook called when payment is required
|
|
149
|
+
* @returns Promise<boolean> - true to proceed, false to abort
|
|
150
|
+
*/
|
|
151
|
+
type PaymentRequiredHook = (requirements: PaymentRequirements, url: string) => Promise<boolean> | boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Hook called after successful payment
|
|
154
|
+
*/
|
|
155
|
+
type PaymentSuccessHook = (signature: string, requirements: PaymentRequirements) => void | Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* Hook called on payment error
|
|
158
|
+
*/
|
|
159
|
+
type PaymentErrorHook = (error: Error, requirements?: PaymentRequirements) => void | Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Extended RequestInit with x402-specific options
|
|
162
|
+
*/
|
|
163
|
+
interface X402RequestInit extends RequestInit {
|
|
164
|
+
/**
|
|
165
|
+
* Skip payment flow - useful for checking if resource requires payment
|
|
166
|
+
*/
|
|
167
|
+
readonly skipPayment?: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Custom payment requirements override
|
|
170
|
+
*/
|
|
171
|
+
readonly paymentOverride?: Partial<PaymentRequirements>;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* x402Fetch function signature
|
|
175
|
+
*/
|
|
176
|
+
interface X402FetchFunction {
|
|
177
|
+
/**
|
|
178
|
+
* Fetch with automatic 402 handling
|
|
179
|
+
*
|
|
180
|
+
* @param input - URL or Request object
|
|
181
|
+
* @param init - Extended fetch options
|
|
182
|
+
* @returns Promise<Response>
|
|
183
|
+
* @throws {X402PaymentError} on payment failure
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* const response = await x402Fetch('/api/premium');
|
|
187
|
+
* const data = await response.json();
|
|
188
|
+
*/
|
|
189
|
+
(input: RequestInfo | URL, init?: X402RequestInit): Promise<Response>;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Error codes for X402PaymentError
|
|
193
|
+
*/
|
|
194
|
+
declare const X402ErrorCode: {
|
|
195
|
+
/** User rejected the payment */
|
|
196
|
+
readonly USER_REJECTED: "USER_REJECTED";
|
|
197
|
+
/** Insufficient wallet balance */
|
|
198
|
+
readonly INSUFFICIENT_BALANCE: "INSUFFICIENT_BALANCE";
|
|
199
|
+
/** Transaction failed on-chain */
|
|
200
|
+
readonly TRANSACTION_FAILED: "TRANSACTION_FAILED";
|
|
201
|
+
/** Payment verification failed */
|
|
202
|
+
readonly VERIFICATION_FAILED: "VERIFICATION_FAILED";
|
|
203
|
+
/** Network/RPC error */
|
|
204
|
+
readonly NETWORK_ERROR: "NETWORK_ERROR";
|
|
205
|
+
/** Invalid 402 response format */
|
|
206
|
+
readonly INVALID_402_RESPONSE: "INVALID_402_RESPONSE";
|
|
207
|
+
/** Payment timeout */
|
|
208
|
+
readonly TIMEOUT: "TIMEOUT";
|
|
209
|
+
/** Wallet not connected */
|
|
210
|
+
readonly WALLET_NOT_CONNECTED: "WALLET_NOT_CONNECTED";
|
|
211
|
+
/** Payment amount exceeds maxPaymentPerRequest */
|
|
212
|
+
readonly AMOUNT_EXCEEDS_LIMIT: "AMOUNT_EXCEEDS_LIMIT";
|
|
213
|
+
/** Recipient address not in allowedRecipients whitelist */
|
|
214
|
+
readonly RECIPIENT_NOT_ALLOWED: "RECIPIENT_NOT_ALLOWED";
|
|
215
|
+
/** Rate limit exceeded */
|
|
216
|
+
readonly RATE_LIMIT_EXCEEDED: "RATE_LIMIT_EXCEEDED";
|
|
217
|
+
};
|
|
218
|
+
type X402ErrorCode = (typeof X402ErrorCode)[keyof typeof X402ErrorCode];
|
|
219
|
+
/**
|
|
220
|
+
* Payment result from successful transaction
|
|
221
|
+
*/
|
|
222
|
+
interface PaymentResult {
|
|
223
|
+
/** Transaction signature */
|
|
224
|
+
readonly signature: string;
|
|
225
|
+
/** Amount paid in lamports */
|
|
226
|
+
readonly amountPaid: bigint;
|
|
227
|
+
/** Recipient address */
|
|
228
|
+
readonly recipient: string;
|
|
229
|
+
/** Timestamp of payment */
|
|
230
|
+
readonly timestamp: number;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @fileoverview x402Fetch - Drop-in fetch() replacement with automatic 402 handling
|
|
235
|
+
* @module @alleyboss/micropay-solana-x402-paywall/fetch
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* import { createX402Fetch } from '@alleyboss/micropay-solana-x402-paywall/fetch';
|
|
240
|
+
*
|
|
241
|
+
* const x402Fetch = createX402Fetch({
|
|
242
|
+
* wallet: useWallet(), // or Keypair for server-side
|
|
243
|
+
* network: 'mainnet-beta',
|
|
244
|
+
* });
|
|
245
|
+
*
|
|
246
|
+
* // Use it like fetch() - automatically handles 402 responses
|
|
247
|
+
* const response = await x402Fetch('/api/premium-data');
|
|
248
|
+
* const data = await response.json();
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Parse payment requirements from 402 response headers
|
|
254
|
+
*/
|
|
255
|
+
declare function parse402Response(response: Response): PaymentRequirements;
|
|
256
|
+
/**
|
|
257
|
+
* Build x402 payment proof header
|
|
258
|
+
*/
|
|
259
|
+
declare function buildPaymentHeader(signature: string): string;
|
|
260
|
+
/**
|
|
261
|
+
* Create a configured x402Fetch instance
|
|
262
|
+
*
|
|
263
|
+
* This factory function returns a fetch-like function that automatically
|
|
264
|
+
* handles HTTP 402 responses by executing Solana payments.
|
|
265
|
+
*
|
|
266
|
+
* @param config - Configuration options
|
|
267
|
+
* @returns A fetch function that handles 402 automatically
|
|
268
|
+
*
|
|
269
|
+
* @example Browser (with Wallet Adapter)
|
|
270
|
+
* ```typescript
|
|
271
|
+
* import { useWallet } from '@solana/wallet-adapter-react';
|
|
272
|
+
*
|
|
273
|
+
* function MyComponent() {
|
|
274
|
+
* const wallet = useWallet();
|
|
275
|
+
* const x402Fetch = useMemo(() => createX402Fetch({
|
|
276
|
+
* wallet,
|
|
277
|
+
* network: 'mainnet-beta',
|
|
278
|
+
* onPaymentRequired: async (req) => {
|
|
279
|
+
* return confirm(`Pay ${req.amount} lamports?`);
|
|
280
|
+
* },
|
|
281
|
+
* }), [wallet]);
|
|
282
|
+
*
|
|
283
|
+
* // Use it like fetch
|
|
284
|
+
* const loadData = () => x402Fetch('/api/premium').then(r => r.json());
|
|
285
|
+
* }
|
|
286
|
+
* ```
|
|
287
|
+
*
|
|
288
|
+
* @example Server/Agent (with Keypair)
|
|
289
|
+
* ```typescript
|
|
290
|
+
* import { Keypair } from '@solana/web3.js';
|
|
291
|
+
* import bs58 from 'bs58';
|
|
292
|
+
*
|
|
293
|
+
* const agentKeypair = Keypair.fromSecretKey(
|
|
294
|
+
* bs58.decode(process.env.AGENT_PRIVATE_KEY!)
|
|
295
|
+
* );
|
|
296
|
+
*
|
|
297
|
+
* const x402Fetch = createX402Fetch({
|
|
298
|
+
* wallet: agentKeypair,
|
|
299
|
+
* network: 'mainnet-beta',
|
|
300
|
+
* });
|
|
301
|
+
*
|
|
302
|
+
* // Autonomous payment
|
|
303
|
+
* const response = await x402Fetch('https://api.example.com/data');
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
declare function createX402Fetch(config: X402FetchConfig): X402FetchFunction;
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* @fileoverview Custom error classes for x402Fetch
|
|
310
|
+
* @module @alleyboss/micropay-solana-x402-paywall/fetch
|
|
311
|
+
*/
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Base error for all x402 payment-related errors
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* try {
|
|
318
|
+
* await x402Fetch('/api/premium');
|
|
319
|
+
* } catch (error) {
|
|
320
|
+
* if (error instanceof X402PaymentError) {
|
|
321
|
+
* console.log(error.code); // 'USER_REJECTED'
|
|
322
|
+
* console.log(error.requirements); // { payTo: '...', amount: '...' }
|
|
323
|
+
* }
|
|
324
|
+
* }
|
|
325
|
+
*/
|
|
326
|
+
declare class X402PaymentError extends Error {
|
|
327
|
+
/** Error code for programmatic handling */
|
|
328
|
+
readonly code: X402ErrorCode;
|
|
329
|
+
/** Payment requirements that triggered the error */
|
|
330
|
+
readonly requirements?: PaymentRequirements | undefined;
|
|
331
|
+
/** Original error if this wraps another error */
|
|
332
|
+
readonly cause?: Error | undefined;
|
|
333
|
+
readonly name: "X402PaymentError";
|
|
334
|
+
constructor(message: string,
|
|
335
|
+
/** Error code for programmatic handling */
|
|
336
|
+
code: X402ErrorCode,
|
|
337
|
+
/** Payment requirements that triggered the error */
|
|
338
|
+
requirements?: PaymentRequirements | undefined,
|
|
339
|
+
/** Original error if this wraps another error */
|
|
340
|
+
cause?: Error | undefined);
|
|
341
|
+
/**
|
|
342
|
+
* Check if error is retryable
|
|
343
|
+
*/
|
|
344
|
+
get isRetryable(): boolean;
|
|
345
|
+
/**
|
|
346
|
+
* Convert to JSON-serializable object
|
|
347
|
+
*/
|
|
348
|
+
toJSON(): Record<string, unknown>;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Create error for user rejection
|
|
352
|
+
*/
|
|
353
|
+
declare function userRejectedError(requirements: PaymentRequirements): X402PaymentError;
|
|
354
|
+
/**
|
|
355
|
+
* Create error for insufficient balance
|
|
356
|
+
*/
|
|
357
|
+
declare function insufficientBalanceError(requirements: PaymentRequirements, balance: bigint): X402PaymentError;
|
|
358
|
+
/**
|
|
359
|
+
* Create error for transaction failure
|
|
360
|
+
*/
|
|
361
|
+
declare function transactionFailedError(requirements: PaymentRequirements, cause?: Error): X402PaymentError;
|
|
362
|
+
/**
|
|
363
|
+
* Create error for verification failure
|
|
364
|
+
*/
|
|
365
|
+
declare function verificationFailedError(requirements: PaymentRequirements, reason?: string): X402PaymentError;
|
|
366
|
+
/**
|
|
367
|
+
* Create error for network issues
|
|
368
|
+
*/
|
|
369
|
+
declare function networkError(cause?: Error): X402PaymentError;
|
|
370
|
+
/**
|
|
371
|
+
* Create error for invalid 402 response
|
|
372
|
+
*/
|
|
373
|
+
declare function invalid402ResponseError(details?: string): X402PaymentError;
|
|
374
|
+
/**
|
|
375
|
+
* Create error for timeout
|
|
376
|
+
*/
|
|
377
|
+
declare function timeoutError(requirements?: PaymentRequirements): X402PaymentError;
|
|
378
|
+
/**
|
|
379
|
+
* Create error for wallet not connected
|
|
380
|
+
*/
|
|
381
|
+
declare function walletNotConnectedError(): X402PaymentError;
|
|
382
|
+
/**
|
|
383
|
+
* Create error when payment amount exceeds configured limit
|
|
384
|
+
*/
|
|
385
|
+
declare function amountExceedsLimitError(requirements: PaymentRequirements, limit: bigint): X402PaymentError;
|
|
386
|
+
/**
|
|
387
|
+
* Create error when recipient is not in whitelist
|
|
388
|
+
*/
|
|
389
|
+
declare function recipientNotAllowedError(requirements: PaymentRequirements, recipient: string): X402PaymentError;
|
|
390
|
+
/**
|
|
391
|
+
* Create error when rate limit is exceeded
|
|
392
|
+
*/
|
|
393
|
+
declare function rateLimitExceededError(limit: number, windowMs: number): X402PaymentError;
|
|
394
|
+
/**
|
|
395
|
+
* Check if an error is an X402PaymentError
|
|
396
|
+
*/
|
|
397
|
+
declare function isX402PaymentError(error: unknown): error is X402PaymentError;
|
|
398
|
+
/**
|
|
399
|
+
* Check if error indicates user explicitly rejected
|
|
400
|
+
*/
|
|
401
|
+
declare function isUserRejection(error: unknown): boolean;
|
|
402
|
+
|
|
403
|
+
export { type PaymentErrorHook, type PaymentRequiredHook, type PaymentRequirements, type PaymentResult, type PaymentSuccessHook, type PriorityFeeConfig, type RateLimitConfig, type SolanaNetwork, type WalletLike, X402ErrorCode, type X402FetchConfig, type X402FetchFunction, X402PaymentError, type X402RequestInit, amountExceedsLimitError, buildPaymentHeader, createX402Fetch, insufficientBalanceError, invalid402ResponseError, isUserRejection, isX402PaymentError, networkError, parse402Response as parsePaymentRequirements, rateLimitExceededError, recipientNotAllowedError, timeoutError, transactionFailedError, userRejectedError, verificationFailedError, walletNotConnectedError };
|