@alleyboss/micropay-solana-x402-paywall 2.3.1 → 3.0.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.
Files changed (72) hide show
  1. package/README.md +85 -139
  2. package/dist/agent/index.cjs +1 -2
  3. package/dist/agent/index.cjs.map +1 -1
  4. package/dist/agent/index.d.cts +11 -2
  5. package/dist/agent/index.d.ts +11 -2
  6. package/dist/agent/index.js +1 -2
  7. package/dist/agent/index.js.map +1 -1
  8. package/dist/client/index.cjs +1 -1
  9. package/dist/client/index.cjs.map +1 -1
  10. package/dist/client/index.d.cts +10 -1
  11. package/dist/client/index.d.ts +10 -1
  12. package/dist/client/index.js +1 -1
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/express/index.cjs +79 -0
  15. package/dist/express/index.cjs.map +1 -0
  16. package/dist/express/index.d.cts +40 -0
  17. package/dist/express/index.d.ts +40 -0
  18. package/dist/express/index.js +76 -0
  19. package/dist/express/index.js.map +1 -0
  20. package/dist/index.cjs +257 -1357
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +6 -12
  23. package/dist/index.d.ts +6 -12
  24. package/dist/index.js +239 -1319
  25. package/dist/index.js.map +1 -1
  26. package/dist/session/index.cjs.map +1 -1
  27. package/dist/session/index.d.cts +1 -1
  28. package/dist/session/index.d.ts +1 -1
  29. package/dist/session/index.js.map +1 -1
  30. package/dist/{session-D2IoWAWV.d.cts → types-BWYQMw03.d.cts} +1 -16
  31. package/dist/{session-D2IoWAWV.d.ts → types-BWYQMw03.d.ts} +1 -16
  32. package/package.json +28 -68
  33. package/dist/client-D-dteoJw.d.cts +0 -63
  34. package/dist/client-DfCIRrNG.d.ts +0 -63
  35. package/dist/memory-Daxkczti.d.cts +0 -29
  36. package/dist/memory-Daxkczti.d.ts +0 -29
  37. package/dist/middleware/index.cjs +0 -273
  38. package/dist/middleware/index.cjs.map +0 -1
  39. package/dist/middleware/index.d.cts +0 -91
  40. package/dist/middleware/index.d.ts +0 -91
  41. package/dist/middleware/index.js +0 -267
  42. package/dist/middleware/index.js.map +0 -1
  43. package/dist/nextjs-BDyOqGAq.d.cts +0 -81
  44. package/dist/nextjs-CbX8_9yK.d.ts +0 -81
  45. package/dist/payment-BGp7eMQl.d.cts +0 -103
  46. package/dist/payment-BGp7eMQl.d.ts +0 -103
  47. package/dist/priority-fees-C-OH4Trr.d.cts +0 -50
  48. package/dist/priority-fees-C-OH4Trr.d.ts +0 -50
  49. package/dist/solana/index.cjs +0 -589
  50. package/dist/solana/index.cjs.map +0 -1
  51. package/dist/solana/index.d.cts +0 -195
  52. package/dist/solana/index.d.ts +0 -195
  53. package/dist/solana/index.js +0 -567
  54. package/dist/solana/index.js.map +0 -1
  55. package/dist/store/index.cjs +0 -99
  56. package/dist/store/index.cjs.map +0 -1
  57. package/dist/store/index.d.cts +0 -38
  58. package/dist/store/index.d.ts +0 -38
  59. package/dist/store/index.js +0 -96
  60. package/dist/store/index.js.map +0 -1
  61. package/dist/utils/index.cjs +0 -68
  62. package/dist/utils/index.cjs.map +0 -1
  63. package/dist/utils/index.d.cts +0 -30
  64. package/dist/utils/index.d.ts +0 -30
  65. package/dist/utils/index.js +0 -65
  66. package/dist/utils/index.js.map +0 -1
  67. package/dist/x402/index.cjs +0 -387
  68. package/dist/x402/index.cjs.map +0 -1
  69. package/dist/x402/index.d.cts +0 -96
  70. package/dist/x402/index.d.ts +0 -96
  71. package/dist/x402/index.js +0 -375
  72. package/dist/x402/index.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,1153 +1,24 @@
1
1
  'use strict';
2
2
 
3
+ var core = require('@x402/core');
4
+ var types = require('@x402/core/types');
5
+ var client = require('@x402/core/client');
6
+ var svm = require('@x402/svm');
3
7
  var web3_js = require('@solana/web3.js');
4
8
  var jose = require('jose');
5
9
  var uuid = require('uuid');
6
10
 
7
- // src/types/payment.ts
8
- var TOKEN_MINTS = {
9
- /** USDC on mainnet */
10
- USDC_MAINNET: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
11
- /** USDC on devnet */
12
- USDC_DEVNET: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
13
- /** USDT on mainnet */
14
- USDT_MAINNET: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"
15
- };
16
- var cachedConnection = null;
17
- var cachedNetwork = null;
18
- var cachedFallbacks = [];
19
- var cachedFallbackEnabled = false;
20
- function buildRpcUrl(config2) {
21
- const { network, rpcUrl, tatumApiKey } = config2;
22
- if (rpcUrl) {
23
- if (rpcUrl.includes("tatum.io") && tatumApiKey && !rpcUrl.includes(tatumApiKey)) {
24
- return rpcUrl.endsWith("/") ? `${rpcUrl}${tatumApiKey}` : `${rpcUrl}/${tatumApiKey}`;
25
- }
26
- return rpcUrl;
27
- }
28
- if (tatumApiKey) {
29
- const baseUrl = network === "mainnet-beta" ? "https://solana-mainnet.gateway.tatum.io" : "https://solana-devnet.gateway.tatum.io";
30
- return `${baseUrl}/${tatumApiKey}`;
31
- }
32
- return web3_js.clusterApiUrl(network);
33
- }
34
- function createConnection(rpcUrl) {
35
- return new web3_js.Connection(rpcUrl, {
36
- commitment: "confirmed",
37
- confirmTransactionInitialTimeout: 6e4
38
- });
39
- }
40
- function getConnection(config2) {
41
- const { network } = config2;
42
- if (cachedConnection && cachedNetwork === network) {
43
- return cachedConnection;
44
- }
45
- const rpcUrl = buildRpcUrl(config2);
46
- cachedConnection = createConnection(rpcUrl);
47
- cachedNetwork = network;
48
- cachedFallbackEnabled = config2.enableFallback ?? false;
49
- cachedFallbacks = [];
50
- if (cachedFallbackEnabled && config2.fallbackRpcUrls?.length) {
51
- cachedFallbacks = config2.fallbackRpcUrls.map(createConnection);
52
- }
53
- return cachedConnection;
54
- }
55
- function getConnectionWithFallback(config2) {
56
- const connection = getConnection(config2);
57
- return {
58
- connection,
59
- fallbacks: cachedFallbacks,
60
- fallbackEnabled: cachedFallbackEnabled
61
- };
62
- }
63
- async function withFallback(config2, operation) {
64
- const { connection, fallbacks, fallbackEnabled } = getConnectionWithFallback(config2);
65
- try {
66
- return await operation(connection);
67
- } catch (error) {
68
- if (!fallbackEnabled || fallbacks.length === 0) {
69
- throw error;
70
- }
71
- if (!isRetryableError(error)) {
72
- throw error;
73
- }
74
- for (let i = 0; i < fallbacks.length; i++) {
75
- try {
76
- return await operation(fallbacks[i]);
77
- } catch (fallbackError) {
78
- if (i === fallbacks.length - 1) {
79
- throw fallbackError;
80
- }
81
- }
82
- }
83
- throw error;
84
- }
85
- }
86
- function isRetryableError(error) {
87
- if (error instanceof Error) {
88
- const message = error.message.toLowerCase();
89
- return message.includes("429") || message.includes("503") || message.includes("502") || message.includes("timeout") || message.includes("econnrefused") || message.includes("enotfound") || message.includes("rate limit");
90
- }
91
- return false;
92
- }
93
- function resetConnection() {
94
- cachedConnection = null;
95
- cachedNetwork = null;
96
- }
97
- function isMainnet(network) {
98
- return network === "mainnet-beta";
99
- }
100
- function toX402Network(network) {
101
- return network === "mainnet-beta" ? "solana-mainnet" : "solana-devnet";
102
- }
103
- var SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;
104
- var WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
105
- function isValidSignature(signature) {
106
- if (!signature || typeof signature !== "string") return false;
107
- return SIGNATURE_REGEX.test(signature);
108
- }
109
- function isValidWalletAddress(address) {
110
- if (!address || typeof address !== "string") return false;
111
- return WALLET_REGEX.test(address);
112
- }
113
- function parseSOLTransfer(transaction, expectedRecipient) {
114
- const instructions = transaction.transaction.message.instructions;
115
- for (const ix of instructions) {
116
- if ("parsed" in ix && ix.program === "system") {
117
- const parsed = ix.parsed;
118
- if (parsed.type === "transfer" && parsed.info.destination === expectedRecipient) {
119
- return {
120
- from: parsed.info.source,
121
- to: parsed.info.destination,
122
- amount: BigInt(parsed.info.lamports)
123
- };
124
- }
125
- }
126
- }
127
- if (transaction.meta?.innerInstructions) {
128
- for (const inner of transaction.meta.innerInstructions) {
129
- for (const ix of inner.instructions) {
130
- if ("parsed" in ix && ix.program === "system") {
131
- const parsed = ix.parsed;
132
- if (parsed.type === "transfer" && parsed.info.destination === expectedRecipient) {
133
- return {
134
- from: parsed.info.source,
135
- to: parsed.info.destination,
136
- amount: BigInt(parsed.info.lamports)
137
- };
138
- }
139
- }
140
- }
141
- }
142
- }
143
- return null;
144
- }
145
- async function verifyPayment(params) {
146
- const {
147
- signature,
148
- expectedRecipient,
149
- expectedAmount,
150
- maxAgeSeconds = 300,
151
- clientConfig,
152
- signatureStore
153
- } = params;
154
- if (!isValidSignature(signature)) {
155
- return { valid: false, confirmed: false, signature, error: "Invalid signature format" };
156
- }
157
- if (!isValidWalletAddress(expectedRecipient)) {
158
- return { valid: false, confirmed: false, signature, error: "Invalid recipient address" };
159
- }
160
- if (expectedAmount <= 0n) {
161
- return { valid: false, confirmed: false, signature, error: "Invalid expected amount" };
162
- }
163
- if (signatureStore) {
164
- const isUsed = await signatureStore.hasBeenUsed(signature);
165
- if (isUsed) {
166
- return { valid: false, confirmed: true, signature, error: "Signature already used" };
167
- }
168
- }
169
- const effectiveMaxAge = Math.min(Math.max(maxAgeSeconds, 60), 3600);
170
- const connection = getConnection(clientConfig);
171
- try {
172
- const transaction = await connection.getParsedTransaction(signature, {
173
- commitment: "confirmed",
174
- maxSupportedTransactionVersion: 0
175
- });
176
- if (!transaction) {
177
- return { valid: false, confirmed: false, signature, error: "Transaction not found" };
178
- }
179
- if (transaction.meta?.err) {
180
- return {
181
- valid: false,
182
- confirmed: true,
183
- signature,
184
- error: "Transaction failed on-chain"
185
- };
186
- }
187
- if (transaction.blockTime) {
188
- const now = Math.floor(Date.now() / 1e3);
189
- if (now - transaction.blockTime > effectiveMaxAge) {
190
- return { valid: false, confirmed: true, signature, error: "Transaction too old" };
191
- }
192
- if (transaction.blockTime > now + 60) {
193
- return { valid: false, confirmed: true, signature, error: "Invalid transaction time" };
194
- }
195
- }
196
- const transferDetails = parseSOLTransfer(transaction, expectedRecipient);
197
- if (!transferDetails) {
198
- return {
199
- valid: false,
200
- confirmed: true,
201
- signature,
202
- error: "No valid SOL transfer to recipient found"
203
- };
204
- }
205
- if (transferDetails.amount < expectedAmount) {
206
- return {
207
- valid: false,
208
- confirmed: true,
209
- signature,
210
- from: transferDetails.from,
211
- to: transferDetails.to,
212
- amount: transferDetails.amount,
213
- error: "Insufficient payment amount"
214
- };
215
- }
216
- return {
217
- valid: true,
218
- confirmed: true,
219
- signature,
220
- from: transferDetails.from,
221
- to: transferDetails.to,
222
- amount: transferDetails.amount,
223
- blockTime: transaction.blockTime ?? void 0,
224
- slot: transaction.slot
225
- };
226
- } catch (error) {
227
- return {
228
- valid: false,
229
- confirmed: false,
230
- signature,
231
- error: "Verification failed"
232
- };
233
- }
234
- }
235
- async function waitForConfirmation(signature, clientConfig) {
236
- if (!isValidSignature(signature)) {
237
- return { confirmed: false, error: "Invalid signature format" };
238
- }
239
- const connection = getConnection(clientConfig);
240
- try {
241
- const confirmation = await connection.confirmTransaction(signature, "confirmed");
242
- if (confirmation.value.err) {
243
- return { confirmed: false, error: "Transaction failed" };
244
- }
245
- return { confirmed: true, slot: confirmation.context?.slot };
246
- } catch {
247
- return { confirmed: false, error: "Confirmation timeout" };
248
- }
249
- }
250
- async function getWalletTransactions(walletAddress, clientConfig, limit = 20) {
251
- if (!isValidWalletAddress(walletAddress)) {
252
- return [];
253
- }
254
- const safeLimit = Math.min(Math.max(limit, 1), 100);
255
- const connection = getConnection(clientConfig);
256
- try {
257
- const pubkey = new web3_js.PublicKey(walletAddress);
258
- const signatures = await connection.getSignaturesForAddress(pubkey, { limit: safeLimit });
259
- return signatures.map((sig) => ({
260
- signature: sig.signature,
261
- blockTime: sig.blockTime ?? void 0,
262
- slot: sig.slot
263
- }));
264
- } catch {
265
- return [];
266
- }
267
- }
268
- function lamportsToSol(lamports) {
269
- return Number(lamports) / web3_js.LAMPORTS_PER_SOL;
270
- }
271
- function solToLamports(sol) {
272
- if (!Number.isFinite(sol) || sol < 0) {
273
- throw new Error("Invalid SOL amount");
274
- }
275
- return BigInt(Math.floor(sol * web3_js.LAMPORTS_PER_SOL));
276
- }
277
- var SIGNATURE_REGEX2 = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;
278
- var WALLET_REGEX2 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
279
- function resolveMintAddress(asset, network) {
280
- if (asset === "native") return null;
281
- if (asset === "usdc") {
282
- return network === "mainnet-beta" ? TOKEN_MINTS.USDC_MAINNET : TOKEN_MINTS.USDC_DEVNET;
283
- }
284
- if (asset === "usdt") {
285
- return TOKEN_MINTS.USDT_MAINNET;
286
- }
287
- if (typeof asset === "object" && "mint" in asset) {
288
- return asset.mint;
289
- }
290
- return null;
291
- }
292
- function getTokenDecimals(asset) {
293
- if (asset === "native") return 9;
294
- if (asset === "usdc" || asset === "usdt") return 6;
295
- if (typeof asset === "object" && "decimals" in asset) {
296
- return asset.decimals ?? 6;
297
- }
298
- return 6;
299
- }
300
- function parseSPLTransfer(transaction, expectedRecipient, expectedMint) {
301
- const instructions = transaction.transaction.message.instructions;
302
- for (const ix of instructions) {
303
- if ("parsed" in ix && (ix.program === "spl-token" || ix.program === "spl-token-2022")) {
304
- const parsed = ix.parsed;
305
- if (parsed.type === "transfer" || parsed.type === "transferChecked") {
306
- const amount = parsed.info.amount || parsed.info.tokenAmount?.amount;
307
- if (amount && parsed.info.destination) {
308
- return {
309
- from: parsed.info.authority || parsed.info.source || "",
310
- to: parsed.info.destination,
311
- amount: BigInt(amount),
312
- mint: parsed.info.mint || expectedMint
313
- };
314
- }
315
- }
316
- }
317
- }
318
- if (transaction.meta?.innerInstructions) {
319
- for (const inner of transaction.meta.innerInstructions) {
320
- for (const ix of inner.instructions) {
321
- if ("parsed" in ix && (ix.program === "spl-token" || ix.program === "spl-token-2022")) {
322
- const parsed = ix.parsed;
323
- if (parsed.type === "transfer" || parsed.type === "transferChecked") {
324
- const amount = parsed.info.amount || parsed.info.tokenAmount?.amount;
325
- if (amount) {
326
- return {
327
- from: parsed.info.authority || parsed.info.source || "",
328
- to: parsed.info.destination || "",
329
- amount: BigInt(amount),
330
- mint: parsed.info.mint || expectedMint
331
- };
332
- }
333
- }
334
- }
335
- }
336
- }
337
- }
338
- if (transaction.meta?.postTokenBalances && transaction.meta?.preTokenBalances) {
339
- const preBalances = transaction.meta.preTokenBalances;
340
- const postBalances = transaction.meta.postTokenBalances;
341
- for (const post of postBalances) {
342
- if (post.mint === expectedMint && post.owner === expectedRecipient) {
343
- const pre = preBalances.find(
344
- (p) => p.accountIndex === post.accountIndex
345
- );
346
- const preAmount = BigInt(pre?.uiTokenAmount?.amount || "0");
347
- const postAmount = BigInt(post.uiTokenAmount?.amount || "0");
348
- const transferred = postAmount - preAmount;
349
- if (transferred > 0n) {
350
- return {
351
- from: "",
352
- // Can't determine from balance changes
353
- to: expectedRecipient,
354
- amount: transferred,
355
- mint: expectedMint
356
- };
357
- }
358
- }
359
- }
360
- }
361
- return null;
362
- }
363
- async function verifySPLPayment(params) {
364
- const {
365
- signature,
366
- expectedRecipient,
367
- expectedAmount,
368
- asset,
369
- clientConfig,
370
- maxAgeSeconds = 300,
371
- signatureStore
372
- } = params;
373
- if (signatureStore) {
374
- const isUsed = await signatureStore.hasBeenUsed(signature);
375
- if (isUsed) {
376
- return { valid: false, confirmed: true, signature, error: "Signature already used" };
377
- }
378
- }
379
- if (!SIGNATURE_REGEX2.test(signature)) {
380
- return { valid: false, confirmed: false, signature, error: "Invalid signature format" };
381
- }
382
- if (!WALLET_REGEX2.test(expectedRecipient)) {
383
- return { valid: false, confirmed: false, signature, error: "Invalid recipient address" };
384
- }
385
- const mintAddress = resolveMintAddress(asset, clientConfig.network);
386
- if (!mintAddress) {
387
- return { valid: false, confirmed: false, signature, error: "Invalid asset configuration" };
388
- }
389
- if (expectedAmount <= 0n) {
390
- return { valid: false, confirmed: false, signature, error: "Invalid expected amount" };
391
- }
392
- const effectiveMaxAge = Math.min(Math.max(maxAgeSeconds, 60), 3600);
393
- const connection = getConnection(clientConfig);
394
- try {
395
- const transaction = await connection.getParsedTransaction(signature, {
396
- commitment: "confirmed",
397
- maxSupportedTransactionVersion: 0
398
- });
399
- if (!transaction) {
400
- return { valid: false, confirmed: false, signature, error: "Transaction not found" };
401
- }
402
- if (transaction.meta?.err) {
403
- return { valid: false, confirmed: true, signature, error: "Transaction failed on-chain" };
404
- }
405
- if (transaction.blockTime) {
406
- const now = Math.floor(Date.now() / 1e3);
407
- if (now - transaction.blockTime > effectiveMaxAge) {
408
- return { valid: false, confirmed: true, signature, error: "Transaction too old" };
409
- }
410
- if (transaction.blockTime > now + 60) {
411
- return { valid: false, confirmed: true, signature, error: "Invalid transaction time" };
412
- }
413
- }
414
- const transfer = parseSPLTransfer(transaction, expectedRecipient, mintAddress);
415
- if (!transfer) {
416
- return {
417
- valid: false,
418
- confirmed: true,
419
- signature,
420
- error: "No valid token transfer to recipient found"
421
- };
422
- }
423
- if (transfer.to) {
424
- try {
425
- const destinationInfo = await connection.getParsedAccountInfo(new web3_js.PublicKey(transfer.to));
426
- const owner = destinationInfo.value?.data?.parsed?.info?.owner;
427
- if (owner && owner !== expectedRecipient) {
428
- return {
429
- valid: false,
430
- confirmed: true,
431
- signature,
432
- error: "Recipient mismatch: Token account not owned by merchant"
433
- };
434
- }
435
- } catch (e) {
436
- return {
437
- valid: false,
438
- confirmed: true,
439
- signature,
440
- error: "Could not verify token account owner"
441
- };
442
- }
443
- }
444
- if (transfer.mint !== mintAddress) {
445
- return {
446
- valid: false,
447
- confirmed: true,
448
- signature,
449
- error: "Token mint mismatch"
450
- };
451
- }
452
- if (transfer.amount < expectedAmount) {
453
- return {
454
- valid: false,
455
- confirmed: true,
456
- signature,
457
- from: transfer.from,
458
- to: transfer.to,
459
- mint: transfer.mint,
460
- amount: transfer.amount,
461
- error: "Insufficient payment amount"
462
- };
463
- }
464
- return {
465
- valid: true,
466
- confirmed: true,
467
- signature,
468
- from: transfer.from,
469
- to: transfer.to,
470
- mint: transfer.mint,
471
- amount: transfer.amount,
472
- blockTime: transaction.blockTime ?? void 0,
473
- slot: transaction.slot
474
- };
475
- } catch {
476
- return { valid: false, confirmed: false, signature, error: "Verification failed" };
477
- }
478
- }
479
- function isNativeAsset(asset) {
480
- return asset === "native";
481
- }
482
- var DEFAULT_COMPUTE_UNITS = 2e5;
483
- var DEFAULT_MICRO_LAMPORTS = 1e3;
484
- function createPriorityFeeInstructions(config2 = {}) {
485
- const { enabled = false, microLamports, computeUnits } = config2;
486
- if (!enabled) {
487
- return [];
488
- }
489
- const instructions = [];
490
- const units = computeUnits ?? DEFAULT_COMPUTE_UNITS;
491
- instructions.push(web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units }));
492
- const price = microLamports ?? DEFAULT_MICRO_LAMPORTS;
493
- instructions.push(web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: price }));
494
- return instructions;
495
- }
496
- async function estimatePriorityFee(connection, accounts = []) {
497
- try {
498
- const fees = await connection.getRecentPrioritizationFees({
499
- lockedWritableAccounts: accounts
500
- });
501
- if (fees.length === 0) {
502
- return DEFAULT_MICRO_LAMPORTS;
503
- }
504
- const sortedFees = fees.map((f) => f.prioritizationFee).filter((f) => f > 0).sort((a, b) => a - b);
505
- if (sortedFees.length === 0) {
506
- return DEFAULT_MICRO_LAMPORTS;
507
- }
508
- const medianIndex = Math.floor(sortedFees.length / 2);
509
- return sortedFees[medianIndex];
510
- } catch {
511
- return DEFAULT_MICRO_LAMPORTS;
512
- }
513
- }
514
- function calculatePriorityFeeCost(microLamportsPerCU, computeUnits) {
515
- return Math.ceil(microLamportsPerCU * computeUnits / 1e6);
516
- }
517
- async function buildVersionedTransaction(config2) {
518
- const {
519
- connection,
520
- payer,
521
- instructions,
522
- lookupTables = [],
523
- priorityFee,
524
- recentBlockhash
525
- } = config2;
526
- const priorityIxs = createPriorityFeeInstructions(priorityFee);
527
- const allInstructions = [...priorityIxs, ...instructions];
528
- let blockhash;
529
- let lastValidBlockHeight;
530
- if (recentBlockhash) {
531
- blockhash = recentBlockhash;
532
- const slot = await connection.getSlot();
533
- lastValidBlockHeight = slot + 150;
534
- } else {
535
- const latestBlockhash = await connection.getLatestBlockhash("confirmed");
536
- blockhash = latestBlockhash.blockhash;
537
- lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
538
- }
539
- const message = new web3_js.TransactionMessage({
540
- payerKey: payer,
541
- recentBlockhash: blockhash,
542
- instructions: allInstructions
543
- }).compileToV0Message(lookupTables);
544
- const transaction = new web3_js.VersionedTransaction(message);
545
- return {
546
- transaction,
547
- blockhash,
548
- lastValidBlockHeight
549
- };
550
- }
551
- async function fetchLookupTables(connection, addresses) {
552
- const tables = [];
553
- for (const address of addresses) {
554
- const result = await connection.getAddressLookupTable(address);
555
- if (result.value) {
556
- tables.push(result.value);
557
- }
558
- }
559
- return tables;
560
- }
561
- function isVersionedTransaction(tx) {
562
- return tx instanceof web3_js.VersionedTransaction;
563
- }
564
- var MAX_ARTICLES_PER_SESSION = 100;
565
- var MIN_SECRET_LENGTH = 32;
566
- function getSecretKey(secret) {
567
- if (!secret || typeof secret !== "string") {
568
- throw new Error("Session secret is required");
569
- }
570
- if (secret.length < MIN_SECRET_LENGTH) {
571
- throw new Error(`Session secret must be at least ${MIN_SECRET_LENGTH} characters`);
572
- }
573
- return new TextEncoder().encode(secret);
574
- }
575
- function validateWalletAddress(address) {
576
- if (!address || typeof address !== "string") return false;
577
- const base58Regex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
578
- return base58Regex.test(address);
579
- }
580
- function validateArticleId(articleId) {
581
- if (!articleId || typeof articleId !== "string") return false;
582
- if (articleId.length > 128) return false;
583
- const safeIdRegex = /^[a-zA-Z0-9_-]+$/;
584
- return safeIdRegex.test(articleId);
585
- }
586
- async function createSession(walletAddress, articleId, config2, siteWide = false) {
587
- if (!validateWalletAddress(walletAddress)) {
588
- throw new Error("Invalid wallet address format");
589
- }
590
- if (!validateArticleId(articleId)) {
591
- throw new Error("Invalid article ID format");
592
- }
593
- if (!config2.durationHours || config2.durationHours <= 0 || config2.durationHours > 720) {
594
- throw new Error("Session duration must be between 1 and 720 hours");
595
- }
596
- const sessionId = uuid.v4();
597
- const now = Math.floor(Date.now() / 1e3);
598
- const expiresAt = now + config2.durationHours * 3600;
599
- const session = {
600
- id: sessionId,
601
- walletAddress,
602
- unlockedArticles: [articleId],
603
- siteWideUnlock: Boolean(siteWide),
604
- createdAt: now,
605
- expiresAt
606
- };
607
- const payload = {
608
- sub: walletAddress,
609
- sid: sessionId,
610
- articles: session.unlockedArticles,
611
- siteWide: session.siteWideUnlock,
612
- iat: now,
613
- exp: expiresAt
614
- };
615
- const token = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(`${config2.durationHours}h`).sign(getSecretKey(config2.secret));
616
- return { token, session };
617
- }
618
- async function validateSession(token, secret) {
619
- if (!token || typeof token !== "string") {
620
- return { valid: false, reason: "Invalid token format" };
621
- }
622
- try {
623
- const { payload } = await jose.jwtVerify(token, getSecretKey(secret));
624
- const sessionPayload = payload;
625
- if (!sessionPayload.sub || !sessionPayload.sid || !sessionPayload.exp) {
626
- return { valid: false, reason: "Malformed session payload" };
627
- }
628
- const now = Math.floor(Date.now() / 1e3);
629
- if (sessionPayload.exp < now) {
630
- return { valid: false, reason: "Session expired" };
631
- }
632
- if (!validateWalletAddress(sessionPayload.sub)) {
633
- return { valid: false, reason: "Invalid session data" };
634
- }
635
- const session = {
636
- id: sessionPayload.sid,
637
- walletAddress: sessionPayload.sub,
638
- unlockedArticles: Array.isArray(sessionPayload.articles) ? sessionPayload.articles : [],
639
- siteWideUnlock: Boolean(sessionPayload.siteWide),
640
- createdAt: sessionPayload.iat ?? 0,
641
- expiresAt: sessionPayload.exp
642
- };
643
- return { valid: true, session };
644
- } catch (error) {
645
- return { valid: false, reason: "Invalid session" };
646
- }
647
- }
648
- async function addArticleToSession(token, articleId, secret) {
649
- if (!validateArticleId(articleId)) {
650
- return null;
651
- }
652
- const validation = await validateSession(token, secret);
653
- if (!validation.valid || !validation.session) {
654
- return null;
655
- }
656
- const session = validation.session;
657
- if (session.unlockedArticles.includes(articleId)) {
658
- return { token, session };
659
- }
660
- if (session.unlockedArticles.length >= MAX_ARTICLES_PER_SESSION) {
661
- return null;
662
- }
663
- const updatedArticles = [...session.unlockedArticles, articleId];
664
- const payload = {
665
- sub: session.walletAddress,
666
- sid: session.id,
667
- articles: updatedArticles,
668
- siteWide: session.siteWideUnlock,
669
- iat: session.createdAt,
670
- exp: session.expiresAt
671
- };
672
- const newToken = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).sign(getSecretKey(secret));
673
- return {
674
- token: newToken,
675
- session: { ...session, unlockedArticles: updatedArticles }
676
- };
677
- }
678
- async function isArticleUnlocked(token, articleId, secret) {
679
- if (!validateArticleId(articleId)) {
680
- return false;
681
- }
682
- const validation = await validateSession(token, secret);
683
- if (!validation.valid || !validation.session) {
684
- return false;
685
- }
686
- if (validation.session.siteWideUnlock) {
687
- return true;
688
- }
689
- return validation.session.unlockedArticles.includes(articleId);
690
- }
691
-
692
- // src/x402/config.ts
693
- var WALLET_REGEX3 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
694
- function sanitizeDisplayString(str, maxLength = 200) {
695
- if (!str || typeof str !== "string") return "";
696
- return str.slice(0, maxLength).replace(/[<>"'&]/g, "");
697
- }
698
- function isValidUrl(url) {
699
- try {
700
- const parsed = new URL(url);
701
- return parsed.protocol === "http:" || parsed.protocol === "https:";
702
- } catch {
703
- return false;
704
- }
705
- }
706
- function buildPaymentRequirement(params) {
707
- if (!WALLET_REGEX3.test(params.creatorWallet)) {
708
- throw new Error("Invalid creator wallet address");
709
- }
710
- if (params.priceInLamports <= 0n) {
711
- throw new Error("Price must be positive");
712
- }
713
- if (!isValidUrl(params.resourceUrl)) {
714
- throw new Error("Invalid resource URL");
715
- }
716
- if (params.network !== "devnet" && params.network !== "mainnet-beta") {
717
- throw new Error("Invalid network");
718
- }
719
- const timeout = params.maxTimeoutSeconds ?? 300;
720
- if (timeout < 60 || timeout > 3600) {
721
- throw new Error("Timeout must be between 60 and 3600 seconds");
722
- }
723
- const x402Network = toX402Network(params.network);
724
- const safeTitle = sanitizeDisplayString(params.articleTitle, 200);
725
- const safeArticleId = sanitizeDisplayString(params.articleId, 128);
726
- return {
727
- scheme: "exact",
728
- network: x402Network,
729
- maxAmountRequired: params.priceInLamports.toString(),
730
- resource: params.resourceUrl,
731
- description: `Unlock: ${safeTitle}`,
732
- mimeType: "text/html",
733
- payTo: params.creatorWallet,
734
- maxTimeoutSeconds: timeout,
735
- asset: "native",
736
- extra: {
737
- name: safeTitle,
738
- articleId: safeArticleId
739
- }
740
- };
741
- }
742
- function encodePaymentRequired(requirement) {
743
- return Buffer.from(JSON.stringify(requirement)).toString("base64");
744
- }
745
- function decodePaymentRequired(encoded) {
746
- if (!encoded || typeof encoded !== "string") {
747
- throw new Error("Invalid encoded requirement");
748
- }
749
- if (encoded.length > 1e4) {
750
- throw new Error("Encoded requirement too large");
751
- }
752
- try {
753
- const decoded = Buffer.from(encoded, "base64").toString("utf-8");
754
- return JSON.parse(decoded);
755
- } catch {
756
- throw new Error("Failed to decode payment requirement");
757
- }
758
- }
759
- var X402_HEADERS = {
760
- PAYMENT_REQUIRED: "X-Payment-Required",
761
- PAYMENT: "X-Payment",
762
- PAYMENT_RESPONSE: "X-Payment-Response"
763
- };
764
- function create402ResponseBody(requirement) {
765
- const assetStr = typeof requirement.asset === "string" ? requirement.asset : requirement.asset.mint;
766
- return {
767
- error: "Payment Required",
768
- message: requirement.description,
769
- price: {
770
- amount: requirement.maxAmountRequired,
771
- asset: assetStr,
772
- network: requirement.network
773
- }
774
- };
775
- }
776
- function create402Headers(requirement) {
777
- const encoded = encodePaymentRequired(requirement);
778
- return {
779
- "Content-Type": "application/json",
780
- [X402_HEADERS.PAYMENT_REQUIRED]: encoded,
781
- "Access-Control-Expose-Headers": X402_HEADERS.PAYMENT_REQUIRED
782
- };
783
- }
784
-
785
- // src/x402/verification.ts
786
- var SIGNATURE_REGEX3 = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;
787
- async function verifyX402Payment(payload, requirement, clientConfig) {
788
- if (!payload || typeof payload !== "object") {
789
- return { valid: false, invalidReason: "Invalid payload" };
790
- }
791
- const signature = payload.payload?.signature;
792
- if (!signature || typeof signature !== "string") {
793
- return { valid: false, invalidReason: "Missing transaction signature" };
794
- }
795
- if (!SIGNATURE_REGEX3.test(signature)) {
796
- return { valid: false, invalidReason: "Invalid signature format" };
797
- }
798
- if (payload.x402Version !== 1) {
799
- return { valid: false, invalidReason: "Unsupported x402 version" };
800
- }
801
- if (payload.scheme !== "exact") {
802
- return { valid: false, invalidReason: "Unsupported payment scheme" };
803
- }
804
- if (payload.network !== requirement.network) {
805
- return {
806
- valid: false,
807
- invalidReason: `Network mismatch: expected ${requirement.network}`
808
- };
809
- }
810
- const walletRegex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
811
- if (!walletRegex.test(requirement.payTo)) {
812
- return { valid: false, invalidReason: "Invalid recipient configuration" };
813
- }
814
- let expectedAmount;
815
- try {
816
- expectedAmount = BigInt(requirement.maxAmountRequired);
817
- if (expectedAmount <= 0n) {
818
- return { valid: false, invalidReason: "Invalid payment amount" };
819
- }
820
- } catch {
821
- return { valid: false, invalidReason: "Invalid payment amount format" };
822
- }
823
- const verification = await verifyPayment({
824
- signature,
825
- expectedRecipient: requirement.payTo,
826
- expectedAmount,
827
- maxAgeSeconds: requirement.maxTimeoutSeconds,
828
- clientConfig
829
- });
830
- if (!verification.valid) {
831
- return {
832
- valid: false,
833
- invalidReason: verification.error || "Transaction verification failed"
834
- };
835
- }
836
- return {
837
- valid: true,
838
- settled: verification.confirmed,
839
- from: verification.from,
840
- transaction: {
841
- signature: verification.signature,
842
- blockTime: verification.blockTime,
843
- slot: verification.slot
844
- }
845
- };
846
- }
847
- function parsePaymentHeader(header) {
848
- if (!header || typeof header !== "string") {
849
- return null;
850
- }
851
- if (header.length > 1e4) {
852
- return null;
853
- }
854
- try {
855
- const decoded = Buffer.from(header, "base64").toString("utf-8");
856
- const parsed = JSON.parse(decoded);
857
- if (!parsed || typeof parsed !== "object") {
858
- return null;
859
- }
860
- return parsed;
861
- } catch {
862
- return null;
863
- }
864
- }
865
- function encodePaymentRequirement(requirement) {
866
- return Buffer.from(JSON.stringify(requirement)).toString("base64");
867
- }
868
- function encodePaymentResponse(response) {
869
- return Buffer.from(JSON.stringify(response)).toString("base64");
870
- }
871
- function create402Response(requirement, body) {
872
- const headers = new Headers({
873
- "Content-Type": "application/json",
874
- "X-Payment-Required": encodePaymentRequirement(requirement)
875
- });
876
- const responseBody = body || {
877
- error: "Payment Required",
878
- message: "This resource requires payment to access",
879
- x402Version: 1,
880
- accepts: [requirement]
881
- };
882
- return new Response(JSON.stringify(responseBody), {
883
- status: 402,
884
- headers
885
- });
886
- }
887
-
888
- // src/store/memory.ts
889
- function createMemoryStore(options = {}) {
890
- const { cleanupInterval = 6e4 } = options;
891
- const store = /* @__PURE__ */ new Map();
892
- const cleanupTimer = setInterval(() => {
893
- const now = Date.now();
894
- for (const [key, record] of store.entries()) {
895
- if (record.expiresAt < now) {
896
- store.delete(key);
897
- }
898
- }
899
- }, cleanupInterval);
900
- return {
901
- async hasBeenUsed(signature) {
902
- const record = store.get(signature);
903
- if (!record) return false;
904
- if (record.expiresAt < Date.now()) {
905
- store.delete(signature);
906
- return false;
907
- }
908
- return true;
909
- },
910
- async markAsUsed(signature, resourceId, expiresAt) {
911
- store.set(signature, {
912
- resourceId,
913
- usedAt: Date.now(),
914
- expiresAt: expiresAt.getTime()
915
- });
916
- },
917
- async getUsage(signature) {
918
- const record = store.get(signature);
919
- if (!record) return null;
920
- if (record.expiresAt < Date.now()) {
921
- store.delete(signature);
922
- return null;
923
- }
924
- return {
925
- signature,
926
- resourceId: record.resourceId,
927
- usedAt: new Date(record.usedAt),
928
- expiresAt: new Date(record.expiresAt),
929
- walletAddress: record.walletAddress
930
- };
931
- },
932
- /** Stop cleanup timer (for graceful shutdown) */
933
- close() {
934
- clearInterval(cleanupTimer);
935
- store.clear();
936
- }
937
- };
938
- }
939
-
940
- // src/store/redis.ts
941
- function createRedisStore(options) {
942
- const { client, keyPrefix = "micropay:sig:" } = options;
943
- const buildKey = (signature) => `${keyPrefix}${signature}`;
944
- return {
945
- async hasBeenUsed(signature) {
946
- const exists = await client.exists(buildKey(signature));
947
- return exists > 0;
948
- },
949
- async markAsUsed(signature, resourceId, expiresAt) {
950
- const key = buildKey(signature);
951
- const ttl = Math.max(1, Math.floor((expiresAt.getTime() - Date.now()) / 1e3));
952
- const record = {
953
- signature,
954
- resourceId,
955
- usedAt: /* @__PURE__ */ new Date(),
956
- expiresAt
957
- };
958
- if (client.setex) {
959
- await client.setex(key, ttl, JSON.stringify(record));
960
- } else {
961
- await client.set(key, JSON.stringify(record), { EX: ttl });
962
- }
963
- },
964
- async getUsage(signature) {
965
- const data = await client.get(buildKey(signature));
966
- if (!data) return null;
967
- try {
968
- const record = JSON.parse(data);
969
- return {
970
- ...record,
971
- usedAt: new Date(record.usedAt),
972
- expiresAt: new Date(record.expiresAt)
973
- };
974
- } catch {
975
- return null;
976
- }
977
- }
978
- };
979
- }
980
-
981
- // src/middleware/nextjs.ts
982
- function matchesProtectedPath(path, patterns) {
983
- for (const pattern of patterns) {
984
- const regexPattern = pattern.replace(/\*\*/g, "{{DOUBLE_STAR}}").replace(/\*/g, "[^/]*").replace(/{{DOUBLE_STAR}}/g, ".*");
985
- const regex = new RegExp(`^${regexPattern}$`);
986
- if (regex.test(path)) {
987
- return true;
988
- }
989
- }
990
- return false;
991
- }
992
- async function checkPaywallAccess(path, sessionToken, config2) {
993
- if (!matchesProtectedPath(path, config2.protectedPaths)) {
994
- return { allowed: true };
995
- }
996
- if (!sessionToken) {
997
- return {
998
- allowed: false,
999
- reason: "No session token",
1000
- requiresPayment: true
1001
- };
1002
- }
1003
- const validation = await validateSession(sessionToken, config2.sessionSecret);
1004
- if (!validation.valid || !validation.session) {
1005
- return {
1006
- allowed: false,
1007
- reason: validation.reason || "Invalid session",
1008
- requiresPayment: true
1009
- };
1010
- }
1011
- return {
1012
- allowed: true,
1013
- session: validation.session
1014
- };
1015
- }
1016
- function createPaywallMiddleware(config2) {
1017
- const { cookieName = "x402_session" } = config2;
1018
- return async function middleware(request) {
1019
- const url = new URL(request.url);
1020
- const path = url.pathname;
1021
- const cookieHeader = request.headers.get("cookie") || "";
1022
- const cookies = Object.fromEntries(
1023
- cookieHeader.split(";").map((c) => {
1024
- const [key, ...vals] = c.trim().split("=");
1025
- return [key, vals.join("=")];
1026
- })
1027
- );
1028
- const sessionToken = cookies[cookieName];
1029
- const result = await checkPaywallAccess(path, sessionToken, config2);
1030
- if (!result.allowed && result.requiresPayment) {
1031
- const headers = {
1032
- "Content-Type": "application/json"
1033
- };
1034
- if (config2.paymentRequirement) {
1035
- const requirement = typeof config2.paymentRequirement === "function" ? config2.paymentRequirement(path) : config2.paymentRequirement;
1036
- headers["X-Payment-Required"] = encodePaymentRequirement(requirement);
1037
- }
1038
- const body = config2.custom402Response ? config2.custom402Response(path) : {
1039
- error: "Payment Required",
1040
- message: "This resource requires payment to access",
1041
- x402Version: 1,
1042
- path
1043
- };
1044
- return new Response(JSON.stringify(body), {
1045
- status: 402,
1046
- headers
1047
- });
1048
- }
1049
- return null;
1050
- };
1051
- }
1052
- function withPaywall(handler, options) {
1053
- const { sessionSecret, cookieName = "x402_session", articleId } = options;
1054
- return async function protectedHandler(request) {
1055
- const cookieHeader = request.headers.get("cookie") || "";
1056
- const cookies = Object.fromEntries(
1057
- cookieHeader.split(";").map((c) => {
1058
- const [key, ...vals] = c.trim().split("=");
1059
- return [key, vals.join("=")];
1060
- })
1061
- );
1062
- const sessionToken = cookies[cookieName];
1063
- if (!sessionToken) {
1064
- return new Response(
1065
- JSON.stringify({ error: "Payment Required", message: "No session token" }),
1066
- { status: 402, headers: { "Content-Type": "application/json" } }
1067
- );
1068
- }
1069
- const validation = await validateSession(sessionToken, sessionSecret);
1070
- if (!validation.valid || !validation.session) {
1071
- return new Response(
1072
- JSON.stringify({ error: "Payment Required", message: validation.reason }),
1073
- { status: 402, headers: { "Content-Type": "application/json" } }
1074
- );
1075
- }
1076
- if (articleId) {
1077
- const { session } = validation;
1078
- const hasAccess = session.siteWideUnlock || session.unlockedArticles.includes(articleId);
1079
- if (!hasAccess) {
1080
- return new Response(
1081
- JSON.stringify({ error: "Payment Required", message: "Article not unlocked" }),
1082
- { status: 402, headers: { "Content-Type": "application/json" } }
1083
- );
1084
- }
1085
- }
1086
- return handler(request, validation.session);
1087
- };
1088
- }
11
+ // src/index.ts
1089
12
 
1090
- // src/utils/retry.ts
1091
- function sleep(ms) {
1092
- return new Promise((resolve) => setTimeout(resolve, ms));
1093
- }
1094
- function calculateDelay(attempt, options) {
1095
- const { baseDelay, maxDelay, jitter } = options;
1096
- let delay = baseDelay * Math.pow(2, attempt);
1097
- delay = Math.min(delay, maxDelay);
1098
- if (jitter) {
1099
- const jitterAmount = delay * 0.25;
1100
- delay += Math.random() * jitterAmount * 2 - jitterAmount;
1101
- }
1102
- return Math.floor(delay);
1103
- }
1104
- async function withRetry(fn, options = {}) {
1105
- const {
1106
- maxAttempts = 3,
1107
- baseDelay = 500,
1108
- maxDelay = 1e4,
1109
- jitter = true,
1110
- retryOn = () => true
1111
- } = options;
1112
- let lastError;
1113
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
1114
- try {
1115
- return await fn();
1116
- } catch (error) {
1117
- lastError = error;
1118
- if (!retryOn(error)) {
1119
- throw error;
1120
- }
1121
- if (attempt < maxAttempts - 1) {
1122
- const delay = calculateDelay(attempt, {
1123
- baseDelay,
1124
- maxDelay,
1125
- jitter
1126
- });
1127
- await sleep(delay);
1128
- }
1129
- }
1130
- }
1131
- throw lastError;
1132
- }
1133
- function isRetryableRPCError(error) {
1134
- if (error instanceof Error) {
1135
- const message = error.message.toLowerCase();
1136
- if (message.includes("429") || message.includes("rate limit")) {
1137
- return true;
1138
- }
1139
- if (message.includes("timeout") || message.includes("econnreset")) {
1140
- return true;
1141
- }
1142
- if (message.includes("503") || message.includes("502") || message.includes("500")) {
1143
- return true;
1144
- }
1145
- if (message.includes("blockhash not found") || message.includes("slot skipped")) {
1146
- return true;
1147
- }
1148
- }
1149
- return false;
1150
- }
13
+ // src/client/types.ts
14
+ var TOKEN_MINTS = {
15
+ /** USDC on mainnet */
16
+ USDC_MAINNET: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
17
+ /** USDC on devnet */
18
+ USDC_DEVNET: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
19
+ /** USDT on mainnet */
20
+ USDT_MAINNET: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"
21
+ };
1151
22
 
1152
23
  // src/client/payment.ts
1153
24
  function buildSolanaPayUrl(params) {
@@ -1198,172 +69,91 @@ function createPaymentFlow(config2) {
1198
69
  /** Generate Solana Pay URL for QR codes */
1199
70
  getSolanaPayUrl: (options = {}) => {
1200
71
  return buildSolanaPayUrl({
1201
- recipient: recipientWallet,
1202
- amount: naturalAmount,
1203
- splToken: mintAddress,
1204
- label: options.label,
1205
- reference: options.reference,
1206
- message: memo
1207
- });
1208
- },
1209
- /** Get the token mint address (undefined for native SOL) */
1210
- getMintAddress: () => mintAddress,
1211
- /** Check if this is a native SOL payment */
1212
- isNativePayment: () => asset === "native",
1213
- /** Get network information */
1214
- getNetworkInfo: () => ({
1215
- network,
1216
- isMainnet: network === "mainnet-beta",
1217
- explorerUrl: network === "mainnet-beta" ? "https://explorer.solana.com" : "https://explorer.solana.com?cluster=devnet"
1218
- }),
1219
- /** Build explorer URL for a transaction */
1220
- getExplorerUrl: (signature) => {
1221
- const baseUrl = "https://explorer.solana.com/tx";
1222
- const cluster = network === "mainnet-beta" ? "" : "?cluster=devnet";
1223
- return `${baseUrl}/${signature}${cluster}`;
1224
- }
1225
- };
1226
- }
1227
- function createPaymentReference() {
1228
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
1229
- return crypto.randomUUID();
1230
- }
1231
- return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
1232
- }
1233
-
1234
- // src/pricing/index.ts
1235
- var cachedPrice = null;
1236
- var config = {};
1237
- var lastProviderIndex = -1;
1238
- function configurePricing(newConfig) {
1239
- config = { ...config, ...newConfig };
1240
- cachedPrice = null;
1241
- }
1242
- var PROVIDERS = [
1243
- {
1244
- name: "coincap",
1245
- url: "https://api.coincap.io/v2/assets/solana",
1246
- parse: (data) => parseFloat(data.data?.priceUsd || "0")
1247
- },
1248
- {
1249
- name: "binance",
1250
- url: "https://api.binance.com/api/v3/ticker/price?symbol=SOLUSDT",
1251
- parse: (data) => parseFloat(data.price || "0")
1252
- },
1253
- {
1254
- name: "coingecko",
1255
- url: "https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd",
1256
- parse: (data) => data.solana?.usd || 0
1257
- },
1258
- {
1259
- name: "kraken",
1260
- url: "https://api.kraken.com/0/public/Ticker?pair=SOLUSD",
1261
- parse: (data) => parseFloat(data.result?.SOLUSD?.c?.[0] || "0")
1262
- }
1263
- ];
1264
- async function fetchFromProvider(provider, timeout) {
1265
- const controller = new AbortController();
1266
- const timeoutId = setTimeout(() => controller.abort(), timeout);
1267
- try {
1268
- const response = await fetch(provider.url, {
1269
- headers: { "Accept": "application/json" },
1270
- signal: controller.signal
1271
- });
1272
- if (!response.ok) {
1273
- throw new Error(`HTTP ${response.status}`);
1274
- }
1275
- const data = await response.json();
1276
- const price = provider.parse(data);
1277
- if (!price || price <= 0) {
1278
- throw new Error("Invalid price");
1279
- }
1280
- return price;
1281
- } finally {
1282
- clearTimeout(timeoutId);
1283
- }
1284
- }
1285
- async function getSolPrice() {
1286
- const cacheTTL = config.cacheTTL ?? 6e4;
1287
- const timeout = config.timeout ?? 5e3;
1288
- if (cachedPrice && Date.now() - cachedPrice.fetchedAt.getTime() < cacheTTL) {
1289
- return cachedPrice;
1290
- }
1291
- if (config.customProvider) {
1292
- try {
1293
- const price = await config.customProvider();
1294
- if (price > 0) {
1295
- cachedPrice = {
1296
- solPrice: price,
1297
- fetchedAt: /* @__PURE__ */ new Date(),
1298
- source: "custom"
1299
- };
1300
- return cachedPrice;
1301
- }
1302
- } catch {
1303
- }
1304
- }
1305
- for (let i = 0; i < PROVIDERS.length; i++) {
1306
- const idx = (lastProviderIndex + 1 + i) % PROVIDERS.length;
1307
- const provider = PROVIDERS[idx];
1308
- try {
1309
- const price = await fetchFromProvider(provider, timeout);
1310
- lastProviderIndex = idx;
1311
- cachedPrice = {
1312
- solPrice: price,
1313
- fetchedAt: /* @__PURE__ */ new Date(),
1314
- source: provider.name
1315
- };
1316
- return cachedPrice;
1317
- } catch {
1318
- continue;
72
+ recipient: recipientWallet,
73
+ amount: naturalAmount,
74
+ splToken: mintAddress,
75
+ label: options.label,
76
+ reference: options.reference,
77
+ message: memo
78
+ });
79
+ },
80
+ /** Get the token mint address (undefined for native SOL) */
81
+ getMintAddress: () => mintAddress,
82
+ /** Check if this is a native SOL payment */
83
+ isNativePayment: () => asset === "native",
84
+ /** Get network information */
85
+ getNetworkInfo: () => ({
86
+ network,
87
+ isMainnet: network === "mainnet-beta",
88
+ explorerUrl: network === "mainnet-beta" ? "https://explorer.solana.com" : "https://explorer.solana.com?cluster=devnet"
89
+ }),
90
+ /** Build explorer URL for a transaction */
91
+ getExplorerUrl: (signature) => {
92
+ const baseUrl = "https://explorer.solana.com/tx";
93
+ const cluster = network === "mainnet-beta" ? "" : "?cluster=devnet";
94
+ return `${baseUrl}/${signature}${cluster}`;
1319
95
  }
1320
- }
1321
- if (cachedPrice) {
1322
- return {
1323
- ...cachedPrice,
1324
- source: `${cachedPrice.source} (stale)`
1325
- };
1326
- }
1327
- throw new Error(
1328
- "Failed to fetch SOL price from all providers. Configure a custom provider or ensure network connectivity."
1329
- );
1330
- }
1331
- async function lamportsToUsd(lamports) {
1332
- const { solPrice } = await getSolPrice();
1333
- const sol = Number(lamports) / 1e9;
1334
- return sol * solPrice;
96
+ };
1335
97
  }
1336
- async function usdToLamports(usd) {
1337
- const { solPrice } = await getSolPrice();
1338
- const sol = usd / solPrice;
1339
- return BigInt(Math.floor(sol * 1e9));
98
+ function createPaymentReference() {
99
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
100
+ return crypto.randomUUID();
101
+ }
102
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
1340
103
  }
1341
- async function formatPriceDisplay(lamports) {
1342
- const { solPrice } = await getSolPrice();
1343
- const sol = Number(lamports) / 1e9;
1344
- const usd = sol * solPrice;
1345
- return `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`;
104
+ var DEFAULT_COMPUTE_UNITS = 2e5;
105
+ var DEFAULT_MICRO_LAMPORTS = 1e3;
106
+ function createPriorityFeeInstructions(config2 = {}) {
107
+ const { enabled = false, microLamports, computeUnits } = config2;
108
+ if (!enabled) {
109
+ return [];
110
+ }
111
+ const instructions = [];
112
+ const units = computeUnits ?? DEFAULT_COMPUTE_UNITS;
113
+ instructions.push(web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units }));
114
+ const price = microLamports ?? DEFAULT_MICRO_LAMPORTS;
115
+ instructions.push(web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: price }));
116
+ return instructions;
1346
117
  }
1347
- function formatPriceSync(lamports, solPrice) {
1348
- const sol = Number(lamports) / 1e9;
1349
- const usd = sol * solPrice;
118
+ async function buildVersionedTransaction(config2) {
119
+ const {
120
+ connection,
121
+ payer,
122
+ instructions,
123
+ priorityFee,
124
+ recentBlockhash
125
+ } = config2;
126
+ const priorityIxs = createPriorityFeeInstructions(priorityFee);
127
+ const allInstructions = [...priorityIxs, ...instructions];
128
+ let blockhash;
129
+ let lastValidBlockHeight;
130
+ if (recentBlockhash) {
131
+ blockhash = recentBlockhash;
132
+ const slot = await connection.getSlot();
133
+ lastValidBlockHeight = slot + 150;
134
+ } else {
135
+ const latestBlockhash = await connection.getLatestBlockhash("confirmed");
136
+ blockhash = latestBlockhash.blockhash;
137
+ lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
138
+ }
139
+ const message = new web3_js.TransactionMessage({
140
+ payerKey: payer,
141
+ recentBlockhash: blockhash,
142
+ instructions: allInstructions
143
+ }).compileToV0Message([]);
144
+ const transaction = new web3_js.VersionedTransaction(message);
1350
145
  return {
1351
- sol,
1352
- usd,
1353
- formatted: `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`
146
+ transaction,
147
+ blockhash,
148
+ lastValidBlockHeight
1354
149
  };
1355
150
  }
1356
- function clearPriceCache() {
1357
- cachedPrice = null;
1358
- lastProviderIndex = -1;
1359
- }
1360
- function getProviders() {
1361
- return PROVIDERS.map((p) => ({ name: p.name, url: p.url }));
1362
- }
1363
- var WALLET_REGEX4 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
1364
- function isValidWalletAddress2(address) {
151
+
152
+ // src/agent/agentPayment.ts
153
+ var WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
154
+ function isValidWalletAddress(address) {
1365
155
  if (!address || typeof address !== "string") return false;
1366
- return WALLET_REGEX4.test(address);
156
+ return WALLET_REGEX.test(address);
1367
157
  }
1368
158
  async function executeAgentPayment(params) {
1369
159
  const {
@@ -1374,7 +164,7 @@ async function executeAgentPayment(params) {
1374
164
  priorityFee,
1375
165
  confirmationTimeout = 6e4
1376
166
  } = params;
1377
- if (!isValidWalletAddress2(recipientAddress)) {
167
+ if (!isValidWalletAddress(recipientAddress)) {
1378
168
  return {
1379
169
  success: false,
1380
170
  error: "Invalid recipient address format"
@@ -1481,23 +271,23 @@ function generateAgentKeypair() {
1481
271
  };
1482
272
  }
1483
273
  var MAX_CREDITS = 1e3;
1484
- var MIN_SECRET_LENGTH2 = 32;
1485
- function getSecretKey2(secret) {
274
+ var MIN_SECRET_LENGTH = 32;
275
+ function getSecretKey(secret) {
1486
276
  if (!secret || typeof secret !== "string") {
1487
277
  throw new Error("Session secret is required");
1488
278
  }
1489
- if (secret.length < MIN_SECRET_LENGTH2) {
1490
- throw new Error(`Session secret must be at least ${MIN_SECRET_LENGTH2} characters`);
279
+ if (secret.length < MIN_SECRET_LENGTH) {
280
+ throw new Error(`Session secret must be at least ${MIN_SECRET_LENGTH} characters`);
1491
281
  }
1492
282
  return new TextEncoder().encode(secret);
1493
283
  }
1494
- function validateWalletAddress2(address) {
284
+ function validateWalletAddress(address) {
1495
285
  if (!address || typeof address !== "string") return false;
1496
286
  const base58Regex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
1497
287
  return base58Regex.test(address);
1498
288
  }
1499
289
  async function createCreditSession(walletAddress, purchaseId, config2) {
1500
- if (!validateWalletAddress2(walletAddress)) {
290
+ if (!validateWalletAddress(walletAddress)) {
1501
291
  throw new Error("Invalid wallet address format");
1502
292
  }
1503
293
  if (config2.initialCredits <= 0 || config2.initialCredits > MAX_CREDITS) {
@@ -1532,7 +322,7 @@ async function createCreditSession(walletAddress, purchaseId, config2) {
1532
322
  iat: now,
1533
323
  exp: expiresAt
1534
324
  };
1535
- const token = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(`${config2.durationHours}h`).sign(getSecretKey2(config2.secret));
325
+ const token = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(`${config2.durationHours}h`).sign(getSecretKey(config2.secret));
1536
326
  return { token, session };
1537
327
  }
1538
328
  async function validateCreditSession(token, secret) {
@@ -1540,7 +330,7 @@ async function validateCreditSession(token, secret) {
1540
330
  return { valid: false, reason: "Invalid token format" };
1541
331
  }
1542
332
  try {
1543
- const { payload } = await jose.jwtVerify(token, getSecretKey2(secret));
333
+ const { payload } = await jose.jwtVerify(token, getSecretKey(secret));
1544
334
  const creditPayload = payload;
1545
335
  if (!creditPayload.sub || !creditPayload.sid || !creditPayload.exp) {
1546
336
  return { valid: false, reason: "Malformed session payload" };
@@ -1552,7 +342,7 @@ async function validateCreditSession(token, secret) {
1552
342
  if (creditPayload.bundleExpiry && creditPayload.bundleExpiry < now) {
1553
343
  return { valid: false, reason: "Bundle expired" };
1554
344
  }
1555
- if (!validateWalletAddress2(creditPayload.sub)) {
345
+ if (!validateWalletAddress(creditPayload.sub)) {
1556
346
  return { valid: false, reason: "Invalid session data" };
1557
347
  }
1558
348
  const session = {
@@ -1603,7 +393,7 @@ async function useCredit(token, secret, creditsToUse = 1) {
1603
393
  iat: session.createdAt,
1604
394
  exp: session.expiresAt
1605
395
  };
1606
- const newToken = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).sign(getSecretKey2(secret));
396
+ const newToken = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).sign(getSecretKey(secret));
1607
397
  return {
1608
398
  success: true,
1609
399
  remainingCredits: newCredits,
@@ -1631,7 +421,7 @@ async function addCredits(token, secret, creditsToAdd) {
1631
421
  iat: session.createdAt,
1632
422
  exp: session.expiresAt
1633
423
  };
1634
- const newToken = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).sign(getSecretKey2(secret));
424
+ const newToken = await new jose.SignJWT(payload).setProtectedHeader({ alg: "HS256" }).sign(getSecretKey(secret));
1635
425
  return {
1636
426
  success: true,
1637
427
  newToken,
@@ -1650,70 +440,180 @@ async function getRemainingCredits(token, secret) {
1650
440
  };
1651
441
  }
1652
442
 
1653
- exports.TOKEN_MINTS = TOKEN_MINTS;
1654
- exports.X402_HEADERS = X402_HEADERS;
1655
- exports.addArticleToSession = addArticleToSession;
443
+ // src/pricing/index.ts
444
+ var cachedPrice = null;
445
+ var config = {};
446
+ var lastProviderIndex = -1;
447
+ function configurePricing(newConfig) {
448
+ config = { ...config, ...newConfig };
449
+ cachedPrice = null;
450
+ }
451
+ var PROVIDERS = [
452
+ {
453
+ name: "coincap",
454
+ url: "https://api.coincap.io/v2/assets/solana",
455
+ parse: (data) => parseFloat(data.data?.priceUsd || "0")
456
+ },
457
+ {
458
+ name: "binance",
459
+ url: "https://api.binance.com/api/v3/ticker/price?symbol=SOLUSDT",
460
+ parse: (data) => parseFloat(data.price || "0")
461
+ },
462
+ {
463
+ name: "coingecko",
464
+ url: "https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd",
465
+ parse: (data) => data.solana?.usd || 0
466
+ },
467
+ {
468
+ name: "kraken",
469
+ url: "https://api.kraken.com/0/public/Ticker?pair=SOLUSD",
470
+ parse: (data) => parseFloat(data.result?.SOLUSD?.c?.[0] || "0")
471
+ }
472
+ ];
473
+ async function fetchFromProvider(provider, timeout) {
474
+ const controller = new AbortController();
475
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
476
+ try {
477
+ const response = await fetch(provider.url, {
478
+ headers: { "Accept": "application/json" },
479
+ signal: controller.signal
480
+ });
481
+ if (!response.ok) {
482
+ throw new Error(`HTTP ${response.status}`);
483
+ }
484
+ const data = await response.json();
485
+ const price = provider.parse(data);
486
+ if (!price || price <= 0) {
487
+ throw new Error("Invalid price");
488
+ }
489
+ return price;
490
+ } finally {
491
+ clearTimeout(timeoutId);
492
+ }
493
+ }
494
+ async function getSolPrice() {
495
+ const cacheTTL = config.cacheTTL ?? 6e4;
496
+ const timeout = config.timeout ?? 5e3;
497
+ if (cachedPrice && Date.now() - cachedPrice.fetchedAt.getTime() < cacheTTL) {
498
+ return cachedPrice;
499
+ }
500
+ if (config.customProvider) {
501
+ try {
502
+ const price = await config.customProvider();
503
+ if (price > 0) {
504
+ cachedPrice = {
505
+ solPrice: price,
506
+ fetchedAt: /* @__PURE__ */ new Date(),
507
+ source: "custom"
508
+ };
509
+ return cachedPrice;
510
+ }
511
+ } catch {
512
+ }
513
+ }
514
+ for (let i = 0; i < PROVIDERS.length; i++) {
515
+ const idx = (lastProviderIndex + 1 + i) % PROVIDERS.length;
516
+ const provider = PROVIDERS[idx];
517
+ try {
518
+ const price = await fetchFromProvider(provider, timeout);
519
+ lastProviderIndex = idx;
520
+ cachedPrice = {
521
+ solPrice: price,
522
+ fetchedAt: /* @__PURE__ */ new Date(),
523
+ source: provider.name
524
+ };
525
+ return cachedPrice;
526
+ } catch {
527
+ continue;
528
+ }
529
+ }
530
+ if (cachedPrice) {
531
+ return {
532
+ ...cachedPrice,
533
+ source: `${cachedPrice.source} (stale)`
534
+ };
535
+ }
536
+ throw new Error(
537
+ "Failed to fetch SOL price from all providers. Configure a custom provider or ensure network connectivity."
538
+ );
539
+ }
540
+ async function lamportsToUsd(lamports) {
541
+ const { solPrice } = await getSolPrice();
542
+ const sol = Number(lamports) / 1e9;
543
+ return sol * solPrice;
544
+ }
545
+ async function usdToLamports(usd) {
546
+ const { solPrice } = await getSolPrice();
547
+ const sol = usd / solPrice;
548
+ return BigInt(Math.floor(sol * 1e9));
549
+ }
550
+ async function formatPriceDisplay(lamports) {
551
+ const { solPrice } = await getSolPrice();
552
+ const sol = Number(lamports) / 1e9;
553
+ const usd = sol * solPrice;
554
+ return `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`;
555
+ }
556
+ function formatPriceSync(lamports, solPrice) {
557
+ const sol = Number(lamports) / 1e9;
558
+ const usd = sol * solPrice;
559
+ return {
560
+ sol,
561
+ usd,
562
+ formatted: `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`
563
+ };
564
+ }
565
+ function clearPriceCache() {
566
+ cachedPrice = null;
567
+ lastProviderIndex = -1;
568
+ }
569
+ function getProviders() {
570
+ return PROVIDERS.map((p) => ({ name: p.name, url: p.url }));
571
+ }
572
+
1656
573
  exports.addCredits = addCredits;
1657
- exports.buildPaymentRequirement = buildPaymentRequirement;
1658
574
  exports.buildSolanaPayUrl = buildSolanaPayUrl;
1659
- exports.buildVersionedTransaction = buildVersionedTransaction;
1660
- exports.calculatePriorityFeeCost = calculatePriorityFeeCost;
1661
- exports.checkPaywallAccess = checkPaywallAccess;
1662
575
  exports.clearPriceCache = clearPriceCache;
1663
576
  exports.configurePricing = configurePricing;
1664
- exports.create402Headers = create402Headers;
1665
- exports.create402Response = create402Response;
1666
- exports.create402ResponseBody = create402ResponseBody;
1667
577
  exports.createCreditSession = createCreditSession;
1668
- exports.createMemoryStore = createMemoryStore;
1669
578
  exports.createPaymentFlow = createPaymentFlow;
1670
579
  exports.createPaymentReference = createPaymentReference;
1671
- exports.createPaywallMiddleware = createPaywallMiddleware;
1672
- exports.createPriorityFeeInstructions = createPriorityFeeInstructions;
1673
- exports.createRedisStore = createRedisStore;
1674
- exports.createSession = createSession;
1675
- exports.decodePaymentRequired = decodePaymentRequired;
1676
- exports.encodePaymentRequired = encodePaymentRequired;
1677
- exports.encodePaymentRequirement = encodePaymentRequirement;
1678
- exports.encodePaymentResponse = encodePaymentResponse;
1679
- exports.estimatePriorityFee = estimatePriorityFee;
1680
580
  exports.executeAgentPayment = executeAgentPayment;
1681
- exports.fetchLookupTables = fetchLookupTables;
1682
581
  exports.formatPriceDisplay = formatPriceDisplay;
1683
582
  exports.formatPriceSync = formatPriceSync;
1684
583
  exports.generateAgentKeypair = generateAgentKeypair;
1685
584
  exports.getAgentBalance = getAgentBalance;
1686
- exports.getConnection = getConnection;
1687
- exports.getConnectionWithFallback = getConnectionWithFallback;
1688
585
  exports.getProviders = getProviders;
1689
586
  exports.getRemainingCredits = getRemainingCredits;
1690
587
  exports.getSolPrice = getSolPrice;
1691
- exports.getTokenDecimals = getTokenDecimals;
1692
- exports.getWalletTransactions = getWalletTransactions;
1693
588
  exports.hasAgentSufficientBalance = hasAgentSufficientBalance;
1694
- exports.isArticleUnlocked = isArticleUnlocked;
1695
- exports.isMainnet = isMainnet;
1696
- exports.isNativeAsset = isNativeAsset;
1697
- exports.isRetryableRPCError = isRetryableRPCError;
1698
- exports.isVersionedTransaction = isVersionedTransaction;
1699
589
  exports.keypairFromBase58 = keypairFromBase58;
1700
- exports.lamportsToSol = lamportsToSol;
1701
590
  exports.lamportsToUsd = lamportsToUsd;
1702
- exports.parsePaymentHeader = parsePaymentHeader;
1703
- exports.resetConnection = resetConnection;
1704
- exports.resolveMintAddress = resolveMintAddress;
1705
- exports.solToLamports = solToLamports;
1706
- exports.toX402Network = toX402Network;
1707
591
  exports.usdToLamports = usdToLamports;
1708
592
  exports.useCredit = useCredit;
1709
593
  exports.validateCreditSession = validateCreditSession;
1710
- exports.validateSession = validateSession;
1711
- exports.verifyPayment = verifyPayment;
1712
- exports.verifySPLPayment = verifySPLPayment;
1713
- exports.verifyX402Payment = verifyX402Payment;
1714
- exports.waitForConfirmation = waitForConfirmation;
1715
- exports.withFallback = withFallback;
1716
- exports.withPaywall = withPaywall;
1717
- exports.withRetry = withRetry;
594
+ Object.keys(core).forEach(function (k) {
595
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
596
+ enumerable: true,
597
+ get: function () { return core[k]; }
598
+ });
599
+ });
600
+ Object.keys(types).forEach(function (k) {
601
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
602
+ enumerable: true,
603
+ get: function () { return types[k]; }
604
+ });
605
+ });
606
+ Object.keys(client).forEach(function (k) {
607
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
608
+ enumerable: true,
609
+ get: function () { return client[k]; }
610
+ });
611
+ });
612
+ Object.keys(svm).forEach(function (k) {
613
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
614
+ enumerable: true,
615
+ get: function () { return svm[k]; }
616
+ });
617
+ });
1718
618
  //# sourceMappingURL=index.cjs.map
1719
619
  //# sourceMappingURL=index.cjs.map