@alleyboss/micropay-solana-x402-paywall 1.0.1 → 2.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 (62) hide show
  1. package/README.md +100 -167
  2. package/dist/client/index.cjs +99 -0
  3. package/dist/client/index.cjs.map +1 -0
  4. package/dist/client/index.d.cts +112 -0
  5. package/dist/client/index.d.ts +112 -0
  6. package/dist/client/index.js +95 -0
  7. package/dist/client/index.js.map +1 -0
  8. package/dist/client-CSZHI8o8.d.ts +32 -0
  9. package/dist/client-vRr48m2x.d.cts +32 -0
  10. package/dist/index.cjs +696 -15
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +11 -3
  13. package/dist/index.d.ts +11 -3
  14. package/dist/index.js +674 -16
  15. package/dist/index.js.map +1 -1
  16. package/dist/memory-Daxkczti.d.cts +29 -0
  17. package/dist/memory-Daxkczti.d.ts +29 -0
  18. package/dist/middleware/index.cjs +261 -0
  19. package/dist/middleware/index.cjs.map +1 -0
  20. package/dist/middleware/index.d.cts +90 -0
  21. package/dist/middleware/index.d.ts +90 -0
  22. package/dist/middleware/index.js +255 -0
  23. package/dist/middleware/index.js.map +1 -0
  24. package/dist/nextjs-BK0pVb9Y.d.ts +78 -0
  25. package/dist/nextjs-Bm272Jkj.d.cts +78 -0
  26. package/dist/{client-kfCr7G-P.d.cts → payment-CTxdtqmc.d.cts} +23 -34
  27. package/dist/{client-kfCr7G-P.d.ts → payment-CTxdtqmc.d.ts} +23 -34
  28. package/dist/pricing/index.cjs +142 -0
  29. package/dist/pricing/index.cjs.map +1 -0
  30. package/dist/pricing/index.d.cts +111 -0
  31. package/dist/pricing/index.d.ts +111 -0
  32. package/dist/pricing/index.js +133 -0
  33. package/dist/pricing/index.js.map +1 -0
  34. package/dist/session/index.d.cts +29 -1
  35. package/dist/session/index.d.ts +29 -1
  36. package/dist/{index-uxMb72hH.d.cts → session-D2IoWAWV.d.cts} +1 -27
  37. package/dist/{index-uxMb72hH.d.ts → session-D2IoWAWV.d.ts} +1 -27
  38. package/dist/solana/index.cjs +193 -0
  39. package/dist/solana/index.cjs.map +1 -1
  40. package/dist/solana/index.d.cts +60 -3
  41. package/dist/solana/index.d.ts +60 -3
  42. package/dist/solana/index.js +190 -1
  43. package/dist/solana/index.js.map +1 -1
  44. package/dist/store/index.cjs +99 -0
  45. package/dist/store/index.cjs.map +1 -0
  46. package/dist/store/index.d.cts +38 -0
  47. package/dist/store/index.d.ts +38 -0
  48. package/dist/store/index.js +96 -0
  49. package/dist/store/index.js.map +1 -0
  50. package/dist/utils/index.cjs +68 -0
  51. package/dist/utils/index.cjs.map +1 -0
  52. package/dist/utils/index.d.cts +30 -0
  53. package/dist/utils/index.d.ts +30 -0
  54. package/dist/utils/index.js +65 -0
  55. package/dist/utils/index.js.map +1 -0
  56. package/dist/x402/index.cjs +2 -1
  57. package/dist/x402/index.cjs.map +1 -1
  58. package/dist/x402/index.d.cts +2 -1
  59. package/dist/x402/index.d.ts +2 -1
  60. package/dist/x402/index.js +2 -1
  61. package/dist/x402/index.js.map +1 -1
  62. package/package.json +56 -3
@@ -0,0 +1,68 @@
1
+ 'use strict';
2
+
3
+ // src/utils/retry.ts
4
+ function sleep(ms) {
5
+ return new Promise((resolve) => setTimeout(resolve, ms));
6
+ }
7
+ function calculateDelay(attempt, options) {
8
+ const { baseDelay, maxDelay, jitter } = options;
9
+ let delay = baseDelay * Math.pow(2, attempt);
10
+ delay = Math.min(delay, maxDelay);
11
+ if (jitter) {
12
+ const jitterAmount = delay * 0.25;
13
+ delay += Math.random() * jitterAmount * 2 - jitterAmount;
14
+ }
15
+ return Math.floor(delay);
16
+ }
17
+ async function withRetry(fn, options = {}) {
18
+ const {
19
+ maxAttempts = 3,
20
+ baseDelay = 500,
21
+ maxDelay = 1e4,
22
+ jitter = true,
23
+ retryOn = () => true
24
+ } = options;
25
+ let lastError;
26
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
27
+ try {
28
+ return await fn();
29
+ } catch (error) {
30
+ lastError = error;
31
+ if (!retryOn(error)) {
32
+ throw error;
33
+ }
34
+ if (attempt < maxAttempts - 1) {
35
+ const delay = calculateDelay(attempt, {
36
+ baseDelay,
37
+ maxDelay,
38
+ jitter
39
+ });
40
+ await sleep(delay);
41
+ }
42
+ }
43
+ }
44
+ throw lastError;
45
+ }
46
+ function isRetryableRPCError(error) {
47
+ if (error instanceof Error) {
48
+ const message = error.message.toLowerCase();
49
+ if (message.includes("429") || message.includes("rate limit")) {
50
+ return true;
51
+ }
52
+ if (message.includes("timeout") || message.includes("econnreset")) {
53
+ return true;
54
+ }
55
+ if (message.includes("503") || message.includes("502") || message.includes("500")) {
56
+ return true;
57
+ }
58
+ if (message.includes("blockhash not found") || message.includes("slot skipped")) {
59
+ return true;
60
+ }
61
+ }
62
+ return false;
63
+ }
64
+
65
+ exports.isRetryableRPCError = isRetryableRPCError;
66
+ exports.withRetry = withRetry;
67
+ //# sourceMappingURL=index.cjs.map
68
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/retry.ts"],"names":[],"mappings":";;;AAmBA,SAAS,MAAM,EAAA,EAA2B;AACtC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAKA,SAAS,cAAA,CAAe,SAAiB,OAAA,EAA0D;AAC/F,EAAA,MAAM,EAAE,SAAA,EAAW,QAAA,EAAU,MAAA,EAAO,GAAI,OAAA;AAGxC,EAAA,IAAI,KAAA,GAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,GAAG,OAAO,CAAA;AAG3C,EAAA,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,QAAQ,CAAA;AAGhC,EAAA,IAAI,MAAA,EAAQ;AACR,IAAA,MAAM,eAAe,KAAA,GAAQ,IAAA;AAC7B,IAAA,KAAA,IAAU,IAAA,CAAK,MAAA,EAAO,GAAI,YAAA,GAAe,CAAA,GAAK,YAAA;AAAA,EAClD;AAEA,EAAA,OAAO,IAAA,CAAK,MAAM,KAAK,CAAA;AAC3B;AAaA,eAAsB,SAAA,CAClB,EAAA,EACA,OAAA,GAAwB,EAAC,EACf;AACV,EAAA,MAAM;AAAA,IACF,WAAA,GAAc,CAAA;AAAA,IACd,SAAA,GAAY,GAAA;AAAA,IACZ,QAAA,GAAW,GAAA;AAAA,IACX,MAAA,GAAS,IAAA;AAAA,IACT,UAAU,MAAM;AAAA,GACpB,GAAI,OAAA;AAEJ,EAAA,IAAI,SAAA;AAEJ,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,GAAU,WAAA,EAAa,OAAA,EAAA,EAAW;AACpD,IAAA,IAAI;AACA,MAAA,OAAO,MAAM,EAAA,EAAG;AAAA,IACpB,SAAS,KAAA,EAAO;AACZ,MAAA,SAAA,GAAY,KAAA;AAGZ,MAAA,IAAI,CAAC,OAAA,CAAQ,KAAK,CAAA,EAAG;AACjB,QAAA,MAAM,KAAA;AAAA,MACV;AAGA,MAAA,IAAI,OAAA,GAAU,cAAc,CAAA,EAAG;AAC3B,QAAA,MAAM,KAAA,GAAQ,eAAe,OAAA,EAAS;AAAA,UAElC,SAAA;AAAA,UACA,QAAA;AAAA,UACA;AAAA,SACH,CAAA;AACD,QAAA,MAAM,MAAM,KAAK,CAAA;AAAA,MACrB;AAAA,IACJ;AAAA,EACJ;AAEA,EAAA,MAAM,SAAA;AACV;AAKO,SAAS,oBAAoB,KAAA,EAAyB;AACzD,EAAA,IAAI,iBAAiB,KAAA,EAAO;AACxB,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,WAAA,EAAY;AAG1C,IAAA,IAAI,QAAQ,QAAA,CAAS,KAAK,KAAK,OAAA,CAAQ,QAAA,CAAS,YAAY,CAAA,EAAG;AAC3D,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,QAAQ,QAAA,CAAS,SAAS,KAAK,OAAA,CAAQ,QAAA,CAAS,YAAY,CAAA,EAAG;AAC/D,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,IAAK,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,IAAK,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,EAAG;AAC/E,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,QAAQ,QAAA,CAAS,qBAAqB,KAAK,OAAA,CAAQ,QAAA,CAAS,cAAc,CAAA,EAAG;AAC7E,MAAA,OAAO,IAAA;AAAA,IACX;AAAA,EACJ;AAEA,EAAA,OAAO,KAAA;AACX","file":"index.cjs","sourcesContent":["// Utility functions\n// Retry logic with exponential backoff for RPC resilience\n\nexport interface RetryOptions {\n /** Maximum number of attempts */\n maxAttempts?: number;\n /** Base delay in milliseconds */\n baseDelay?: number;\n /** Maximum delay in milliseconds */\n maxDelay?: number;\n /** Whether to add jitter to delay */\n jitter?: boolean;\n /** Errors to retry on (default: all) */\n retryOn?: (error: unknown) => boolean;\n}\n\n/**\n * Sleep for a given duration\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay with exponential backoff and optional jitter\n */\nfunction calculateDelay(attempt: number, options: Required<Omit<RetryOptions, 'retryOn'>>): number {\n const { baseDelay, maxDelay, jitter } = options;\n\n // Exponential backoff: baseDelay * 2^attempt\n let delay = baseDelay * Math.pow(2, attempt);\n\n // Cap at maxDelay\n delay = Math.min(delay, maxDelay);\n\n // Add jitter (±25%)\n if (jitter) {\n const jitterAmount = delay * 0.25;\n delay += (Math.random() * jitterAmount * 2) - jitterAmount;\n }\n\n return Math.floor(delay);\n}\n\n/**\n * Execute a function with retry logic and exponential backoff\n * \n * @example\n * ```typescript\n * const result = await withRetry(\n * () => connection.getBalance(publicKey),\n * { maxAttempts: 3, baseDelay: 500 }\n * );\n * ```\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {}\n): Promise<T> {\n const {\n maxAttempts = 3,\n baseDelay = 500,\n maxDelay = 10000,\n jitter = true,\n retryOn = () => true,\n } = options;\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n\n // Check if we should retry this error\n if (!retryOn(error)) {\n throw error;\n }\n\n // Don't sleep after the last attempt\n if (attempt < maxAttempts - 1) {\n const delay = calculateDelay(attempt, {\n maxAttempts,\n baseDelay,\n maxDelay,\n jitter\n });\n await sleep(delay);\n }\n }\n }\n\n throw lastError;\n}\n\n/**\n * Check if error is a transient RPC error that should be retried\n */\nexport function isRetryableRPCError(error: unknown): boolean {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n // Rate limiting\n if (message.includes('429') || message.includes('rate limit')) {\n return true;\n }\n\n // Network errors\n if (message.includes('timeout') || message.includes('econnreset')) {\n return true;\n }\n\n // Server errors\n if (message.includes('503') || message.includes('502') || message.includes('500')) {\n return true;\n }\n\n // Solana-specific transient errors\n if (message.includes('blockhash not found') || message.includes('slot skipped')) {\n return true;\n }\n }\n\n return false;\n}\n"]}
@@ -0,0 +1,30 @@
1
+ interface RetryOptions {
2
+ /** Maximum number of attempts */
3
+ maxAttempts?: number;
4
+ /** Base delay in milliseconds */
5
+ baseDelay?: number;
6
+ /** Maximum delay in milliseconds */
7
+ maxDelay?: number;
8
+ /** Whether to add jitter to delay */
9
+ jitter?: boolean;
10
+ /** Errors to retry on (default: all) */
11
+ retryOn?: (error: unknown) => boolean;
12
+ }
13
+ /**
14
+ * Execute a function with retry logic and exponential backoff
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const result = await withRetry(
19
+ * () => connection.getBalance(publicKey),
20
+ * { maxAttempts: 3, baseDelay: 500 }
21
+ * );
22
+ * ```
23
+ */
24
+ declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
25
+ /**
26
+ * Check if error is a transient RPC error that should be retried
27
+ */
28
+ declare function isRetryableRPCError(error: unknown): boolean;
29
+
30
+ export { type RetryOptions, isRetryableRPCError, withRetry };
@@ -0,0 +1,30 @@
1
+ interface RetryOptions {
2
+ /** Maximum number of attempts */
3
+ maxAttempts?: number;
4
+ /** Base delay in milliseconds */
5
+ baseDelay?: number;
6
+ /** Maximum delay in milliseconds */
7
+ maxDelay?: number;
8
+ /** Whether to add jitter to delay */
9
+ jitter?: boolean;
10
+ /** Errors to retry on (default: all) */
11
+ retryOn?: (error: unknown) => boolean;
12
+ }
13
+ /**
14
+ * Execute a function with retry logic and exponential backoff
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const result = await withRetry(
19
+ * () => connection.getBalance(publicKey),
20
+ * { maxAttempts: 3, baseDelay: 500 }
21
+ * );
22
+ * ```
23
+ */
24
+ declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
25
+ /**
26
+ * Check if error is a transient RPC error that should be retried
27
+ */
28
+ declare function isRetryableRPCError(error: unknown): boolean;
29
+
30
+ export { type RetryOptions, isRetryableRPCError, withRetry };
@@ -0,0 +1,65 @@
1
+ // src/utils/retry.ts
2
+ function sleep(ms) {
3
+ return new Promise((resolve) => setTimeout(resolve, ms));
4
+ }
5
+ function calculateDelay(attempt, options) {
6
+ const { baseDelay, maxDelay, jitter } = options;
7
+ let delay = baseDelay * Math.pow(2, attempt);
8
+ delay = Math.min(delay, maxDelay);
9
+ if (jitter) {
10
+ const jitterAmount = delay * 0.25;
11
+ delay += Math.random() * jitterAmount * 2 - jitterAmount;
12
+ }
13
+ return Math.floor(delay);
14
+ }
15
+ async function withRetry(fn, options = {}) {
16
+ const {
17
+ maxAttempts = 3,
18
+ baseDelay = 500,
19
+ maxDelay = 1e4,
20
+ jitter = true,
21
+ retryOn = () => true
22
+ } = options;
23
+ let lastError;
24
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
25
+ try {
26
+ return await fn();
27
+ } catch (error) {
28
+ lastError = error;
29
+ if (!retryOn(error)) {
30
+ throw error;
31
+ }
32
+ if (attempt < maxAttempts - 1) {
33
+ const delay = calculateDelay(attempt, {
34
+ baseDelay,
35
+ maxDelay,
36
+ jitter
37
+ });
38
+ await sleep(delay);
39
+ }
40
+ }
41
+ }
42
+ throw lastError;
43
+ }
44
+ function isRetryableRPCError(error) {
45
+ if (error instanceof Error) {
46
+ const message = error.message.toLowerCase();
47
+ if (message.includes("429") || message.includes("rate limit")) {
48
+ return true;
49
+ }
50
+ if (message.includes("timeout") || message.includes("econnreset")) {
51
+ return true;
52
+ }
53
+ if (message.includes("503") || message.includes("502") || message.includes("500")) {
54
+ return true;
55
+ }
56
+ if (message.includes("blockhash not found") || message.includes("slot skipped")) {
57
+ return true;
58
+ }
59
+ }
60
+ return false;
61
+ }
62
+
63
+ export { isRetryableRPCError, withRetry };
64
+ //# sourceMappingURL=index.js.map
65
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/retry.ts"],"names":[],"mappings":";AAmBA,SAAS,MAAM,EAAA,EAA2B;AACtC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAKA,SAAS,cAAA,CAAe,SAAiB,OAAA,EAA0D;AAC/F,EAAA,MAAM,EAAE,SAAA,EAAW,QAAA,EAAU,MAAA,EAAO,GAAI,OAAA;AAGxC,EAAA,IAAI,KAAA,GAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,GAAG,OAAO,CAAA;AAG3C,EAAA,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,QAAQ,CAAA;AAGhC,EAAA,IAAI,MAAA,EAAQ;AACR,IAAA,MAAM,eAAe,KAAA,GAAQ,IAAA;AAC7B,IAAA,KAAA,IAAU,IAAA,CAAK,MAAA,EAAO,GAAI,YAAA,GAAe,CAAA,GAAK,YAAA;AAAA,EAClD;AAEA,EAAA,OAAO,IAAA,CAAK,MAAM,KAAK,CAAA;AAC3B;AAaA,eAAsB,SAAA,CAClB,EAAA,EACA,OAAA,GAAwB,EAAC,EACf;AACV,EAAA,MAAM;AAAA,IACF,WAAA,GAAc,CAAA;AAAA,IACd,SAAA,GAAY,GAAA;AAAA,IACZ,QAAA,GAAW,GAAA;AAAA,IACX,MAAA,GAAS,IAAA;AAAA,IACT,UAAU,MAAM;AAAA,GACpB,GAAI,OAAA;AAEJ,EAAA,IAAI,SAAA;AAEJ,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,GAAU,WAAA,EAAa,OAAA,EAAA,EAAW;AACpD,IAAA,IAAI;AACA,MAAA,OAAO,MAAM,EAAA,EAAG;AAAA,IACpB,SAAS,KAAA,EAAO;AACZ,MAAA,SAAA,GAAY,KAAA;AAGZ,MAAA,IAAI,CAAC,OAAA,CAAQ,KAAK,CAAA,EAAG;AACjB,QAAA,MAAM,KAAA;AAAA,MACV;AAGA,MAAA,IAAI,OAAA,GAAU,cAAc,CAAA,EAAG;AAC3B,QAAA,MAAM,KAAA,GAAQ,eAAe,OAAA,EAAS;AAAA,UAElC,SAAA;AAAA,UACA,QAAA;AAAA,UACA;AAAA,SACH,CAAA;AACD,QAAA,MAAM,MAAM,KAAK,CAAA;AAAA,MACrB;AAAA,IACJ;AAAA,EACJ;AAEA,EAAA,MAAM,SAAA;AACV;AAKO,SAAS,oBAAoB,KAAA,EAAyB;AACzD,EAAA,IAAI,iBAAiB,KAAA,EAAO;AACxB,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,WAAA,EAAY;AAG1C,IAAA,IAAI,QAAQ,QAAA,CAAS,KAAK,KAAK,OAAA,CAAQ,QAAA,CAAS,YAAY,CAAA,EAAG;AAC3D,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,QAAQ,QAAA,CAAS,SAAS,KAAK,OAAA,CAAQ,QAAA,CAAS,YAAY,CAAA,EAAG;AAC/D,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,IAAK,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,IAAK,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,EAAG;AAC/E,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,QAAQ,QAAA,CAAS,qBAAqB,KAAK,OAAA,CAAQ,QAAA,CAAS,cAAc,CAAA,EAAG;AAC7E,MAAA,OAAO,IAAA;AAAA,IACX;AAAA,EACJ;AAEA,EAAA,OAAO,KAAA;AACX","file":"index.js","sourcesContent":["// Utility functions\n// Retry logic with exponential backoff for RPC resilience\n\nexport interface RetryOptions {\n /** Maximum number of attempts */\n maxAttempts?: number;\n /** Base delay in milliseconds */\n baseDelay?: number;\n /** Maximum delay in milliseconds */\n maxDelay?: number;\n /** Whether to add jitter to delay */\n jitter?: boolean;\n /** Errors to retry on (default: all) */\n retryOn?: (error: unknown) => boolean;\n}\n\n/**\n * Sleep for a given duration\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay with exponential backoff and optional jitter\n */\nfunction calculateDelay(attempt: number, options: Required<Omit<RetryOptions, 'retryOn'>>): number {\n const { baseDelay, maxDelay, jitter } = options;\n\n // Exponential backoff: baseDelay * 2^attempt\n let delay = baseDelay * Math.pow(2, attempt);\n\n // Cap at maxDelay\n delay = Math.min(delay, maxDelay);\n\n // Add jitter (±25%)\n if (jitter) {\n const jitterAmount = delay * 0.25;\n delay += (Math.random() * jitterAmount * 2) - jitterAmount;\n }\n\n return Math.floor(delay);\n}\n\n/**\n * Execute a function with retry logic and exponential backoff\n * \n * @example\n * ```typescript\n * const result = await withRetry(\n * () => connection.getBalance(publicKey),\n * { maxAttempts: 3, baseDelay: 500 }\n * );\n * ```\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {}\n): Promise<T> {\n const {\n maxAttempts = 3,\n baseDelay = 500,\n maxDelay = 10000,\n jitter = true,\n retryOn = () => true,\n } = options;\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n\n // Check if we should retry this error\n if (!retryOn(error)) {\n throw error;\n }\n\n // Don't sleep after the last attempt\n if (attempt < maxAttempts - 1) {\n const delay = calculateDelay(attempt, {\n maxAttempts,\n baseDelay,\n maxDelay,\n jitter\n });\n await sleep(delay);\n }\n }\n }\n\n throw lastError;\n}\n\n/**\n * Check if error is a transient RPC error that should be retried\n */\nexport function isRetryableRPCError(error: unknown): boolean {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n // Rate limiting\n if (message.includes('429') || message.includes('rate limit')) {\n return true;\n }\n\n // Network errors\n if (message.includes('timeout') || message.includes('econnreset')) {\n return true;\n }\n\n // Server errors\n if (message.includes('503') || message.includes('502') || message.includes('500')) {\n return true;\n }\n\n // Solana-specific transient errors\n if (message.includes('blockhash not found') || message.includes('slot skipped')) {\n return true;\n }\n }\n\n return false;\n}\n"]}
@@ -234,12 +234,13 @@ var X402_HEADERS = {
234
234
  PAYMENT_RESPONSE: "X-Payment-Response"
235
235
  };
236
236
  function create402ResponseBody(requirement) {
237
+ const assetStr = typeof requirement.asset === "string" ? requirement.asset : requirement.asset.mint;
237
238
  return {
238
239
  error: "Payment Required",
239
240
  message: requirement.description,
240
241
  price: {
241
242
  amount: requirement.maxAmountRequired,
242
- asset: requirement.asset,
243
+ asset: assetStr,
243
244
  network: requirement.network
244
245
  }
245
246
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/solana/client.ts","../../src/solana/verification.ts","../../src/x402/config.ts","../../src/x402/verification.ts"],"names":["clusterApiUrl","Connection","WALLET_REGEX","SIGNATURE_REGEX"],"mappings":"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","file":"index.cjs","sourcesContent":["// Solana RPC client with multi-provider support\nimport { Connection, clusterApiUrl, type Cluster } from '@solana/web3.js';\nimport type { SolanaNetwork } from '../types';\n\n/** Configuration for Solana client */\nexport interface SolanaClientConfig {\n /** Network to connect to */\n network: SolanaNetwork;\n /** Custom RPC URL (optional) */\n rpcUrl?: string;\n /** Tatum.io API key for RPC (optional) */\n tatumApiKey?: string;\n}\n\n// Singleton state\nlet cachedConnection: Connection | null = null;\nlet cachedNetwork: SolanaNetwork | null = null;\n\n/**\n * Build RPC URL based on configuration priority:\n * 1. Custom RPC URL\n * 2. Tatum.io with API key\n * 3. Public RPC (rate limited)\n */\nfunction buildRpcUrl(config: SolanaClientConfig): string {\n const { network, rpcUrl, tatumApiKey } = config;\n\n if (rpcUrl) {\n // If Tatum URL without key, append key if available\n if (rpcUrl.includes('tatum.io') && tatumApiKey && !rpcUrl.includes(tatumApiKey)) {\n return rpcUrl.endsWith('/') ? `${rpcUrl}${tatumApiKey}` : `${rpcUrl}/${tatumApiKey}`;\n }\n return rpcUrl;\n }\n\n if (tatumApiKey) {\n const baseUrl = network === 'mainnet-beta'\n ? 'https://solana-mainnet.gateway.tatum.io'\n : 'https://solana-devnet.gateway.tatum.io';\n return `${baseUrl}/${tatumApiKey}`;\n }\n\n // Fallback to public RPC\n return clusterApiUrl(network as Cluster);\n}\n\n/**\n * Get or create a Solana connection\n * Uses singleton pattern with network-aware caching\n */\nexport function getConnection(config: SolanaClientConfig): Connection {\n const { network } = config;\n\n // Return cached if same network\n if (cachedConnection && cachedNetwork === network) {\n return cachedConnection;\n }\n\n const rpcUrl = buildRpcUrl(config);\n\n cachedConnection = new Connection(rpcUrl, {\n commitment: 'confirmed',\n confirmTransactionInitialTimeout: 60000,\n });\n cachedNetwork = network;\n\n return cachedConnection;\n}\n\n/**\n * Reset the cached connection\n * Useful for testing or network switching\n */\nexport function resetConnection(): void {\n cachedConnection = null;\n cachedNetwork = null;\n}\n\n/**\n * Check if network is mainnet\n */\nexport function isMainnet(network: SolanaNetwork): boolean {\n return network === 'mainnet-beta';\n}\n\n/**\n * Convert Solana network to x402 network identifier\n */\nexport function toX402Network(network: SolanaNetwork): 'solana-devnet' | 'solana-mainnet' {\n return network === 'mainnet-beta' ? 'solana-mainnet' : 'solana-devnet';\n}\n","// Transaction verification for SOL payments\n// SECURITY: On-chain verification, signature validation, replay protection\nimport { PublicKey, LAMPORTS_PER_SOL, type ParsedTransactionWithMeta } from '@solana/web3.js';\nimport { getConnection, type SolanaClientConfig } from './client';\n\n/** Result of transaction verification */\nexport interface TransactionVerificationResult {\n /** Whether the transaction is valid for the payment */\n valid: boolean;\n /** Whether the transaction is confirmed on-chain */\n confirmed: boolean;\n /** Transaction signature */\n signature: string;\n /** Sender wallet address */\n from?: string;\n /** Recipient wallet address */\n to?: string;\n /** Amount transferred in lamports */\n amount?: bigint;\n /** Block time (Unix timestamp) */\n blockTime?: number;\n /** Slot number */\n slot?: number;\n /** Error message if verification failed */\n error?: string;\n}\n\n/** Parameters for verifying a payment */\nexport interface VerifyPaymentParams {\n /** Transaction signature to verify */\n signature: string;\n /** Expected recipient wallet address */\n expectedRecipient: string;\n /** Expected amount in lamports */\n expectedAmount: bigint;\n /** Maximum age of transaction in seconds (default: 300) */\n maxAgeSeconds?: number;\n /** Solana client configuration */\n clientConfig: SolanaClientConfig;\n}\n\n// Signature validation regex (base58, 87-88 chars)\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\n\n// Wallet address validation regex\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/**\n * Validate transaction signature format\n * SECURITY: Prevents malformed signatures from reaching RPC\n */\nfunction isValidSignature(signature: string): boolean {\n if (!signature || typeof signature !== 'string') return false;\n return SIGNATURE_REGEX.test(signature);\n}\n\n/**\n * Validate wallet address format\n * SECURITY: Ensures valid base58 address\n */\nfunction isValidWalletAddress(address: string): boolean {\n if (!address || typeof address !== 'string') return false;\n return WALLET_REGEX.test(address);\n}\n\n/**\n * Parse SOL transfer details from a transaction\n */\nfunction parseSOLTransfer(\n transaction: ParsedTransactionWithMeta,\n expectedRecipient: string\n): { from: string; to: string; amount: bigint } | null {\n const instructions = transaction.transaction.message.instructions;\n\n // Check main instructions\n for (const ix of instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n\n // Check inner instructions\n if (transaction.meta?.innerInstructions) {\n for (const inner of transaction.meta.innerInstructions) {\n for (const ix of inner.instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Verify a SOL transfer transaction\n * SECURITY: Full on-chain verification with amount/recipient/age checks\n */\nexport async function verifyPayment(\n params: VerifyPaymentParams\n): Promise<TransactionVerificationResult> {\n const {\n signature,\n expectedRecipient,\n expectedAmount,\n maxAgeSeconds = 300,\n clientConfig\n } = params;\n\n // SECURITY: Validate signature format before RPC call\n if (!isValidSignature(signature)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid signature format' };\n }\n\n // SECURITY: Validate recipient address format\n if (!isValidWalletAddress(expectedRecipient)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid recipient address' };\n }\n\n // SECURITY: Validate expected amount is positive\n if (expectedAmount <= 0n) {\n return { valid: false, confirmed: false, signature, error: 'Invalid expected amount' };\n }\n\n // SECURITY: Enforce reasonable max age (prevent replay with very old transactions)\n const effectiveMaxAge = Math.min(Math.max(maxAgeSeconds, 60), 3600); // 1 min to 1 hour\n\n const connection = getConnection(clientConfig);\n\n try {\n const transaction = await connection.getParsedTransaction(signature, {\n commitment: 'confirmed',\n maxSupportedTransactionVersion: 0,\n });\n\n if (!transaction) {\n return { valid: false, confirmed: false, signature, error: 'Transaction not found' };\n }\n\n // Check for transaction errors\n if (transaction.meta?.err) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'Transaction failed on-chain',\n };\n }\n\n // SECURITY: Validate transaction age (replay protection)\n if (transaction.blockTime) {\n const now = Math.floor(Date.now() / 1000);\n if (now - transaction.blockTime > effectiveMaxAge) {\n return { valid: false, confirmed: true, signature, error: 'Transaction too old' };\n }\n // Also reject future-dated transactions (clock skew attack)\n if (transaction.blockTime > now + 60) {\n return { valid: false, confirmed: true, signature, error: 'Invalid transaction time' };\n }\n }\n\n // Parse transfer details\n const transferDetails = parseSOLTransfer(transaction, expectedRecipient);\n\n if (!transferDetails) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'No valid SOL transfer to recipient found',\n };\n }\n\n // SECURITY: Validate amount (must meet or exceed expected)\n if (transferDetails.amount < expectedAmount) {\n return {\n valid: false,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n error: 'Insufficient payment amount',\n };\n }\n\n return {\n valid: true,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n blockTime: transaction.blockTime ?? undefined,\n slot: transaction.slot,\n };\n } catch (error) {\n // SECURITY: Don't expose internal error details\n return {\n valid: false,\n confirmed: false,\n signature,\n error: 'Verification failed',\n };\n }\n}\n\n/**\n * Wait for transaction confirmation\n */\nexport async function waitForConfirmation(\n signature: string,\n clientConfig: SolanaClientConfig\n): Promise<{ confirmed: boolean; slot?: number; error?: string }> {\n if (!isValidSignature(signature)) {\n return { confirmed: false, error: 'Invalid signature format' };\n }\n\n const connection = getConnection(clientConfig);\n\n try {\n const confirmation = await connection.confirmTransaction(signature, 'confirmed');\n\n if (confirmation.value.err) {\n return { confirmed: false, error: 'Transaction failed' };\n }\n\n return { confirmed: true, slot: confirmation.context?.slot };\n } catch {\n return { confirmed: false, error: 'Confirmation timeout' };\n }\n}\n\n/**\n * Get recent transactions for a wallet\n */\nexport async function getWalletTransactions(\n walletAddress: string,\n clientConfig: SolanaClientConfig,\n limit: number = 20\n): Promise<Array<{ signature: string; blockTime?: number; slot: number }>> {\n if (!isValidWalletAddress(walletAddress)) {\n return [];\n }\n\n // SECURITY: Cap limit to prevent abuse\n const safeLimit = Math.min(Math.max(limit, 1), 100);\n\n const connection = getConnection(clientConfig);\n\n try {\n const pubkey = new PublicKey(walletAddress);\n const signatures = await connection.getSignaturesForAddress(pubkey, { limit: safeLimit });\n return signatures.map((sig) => ({\n signature: sig.signature,\n blockTime: sig.blockTime ?? undefined,\n slot: sig.slot,\n }));\n } catch {\n return [];\n }\n}\n\n/**\n * Convert lamports to SOL\n */\nexport function lamportsToSol(lamports: bigint | number): number {\n return Number(lamports) / LAMPORTS_PER_SOL;\n}\n\n/**\n * Convert SOL to lamports\n */\nexport function solToLamports(sol: number): bigint {\n if (!Number.isFinite(sol) || sol < 0) {\n throw new Error('Invalid SOL amount');\n }\n return BigInt(Math.floor(sol * LAMPORTS_PER_SOL));\n}\n","// x402 payment configuration and helpers\n// SECURITY: Input sanitization for payment requirements\nimport type { PaymentRequirement, X402Network, SolanaNetwork } from '../types';\nimport { toX402Network } from '../solana';\n\n// Wallet address validation regex\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/** Parameters for building a payment requirement */\nexport interface BuildPaymentParams {\n /** Unique article identifier */\n articleId: string;\n /** Article title for display */\n articleTitle: string;\n /** Price in lamports */\n priceInLamports: bigint;\n /** Creator wallet address */\n creatorWallet: string;\n /** Full URL of the protected resource */\n resourceUrl: string;\n /** Solana network */\n network: SolanaNetwork;\n /** Max time to complete payment (default: 300s) */\n maxTimeoutSeconds?: number;\n}\n\n/**\n * Sanitize string for safe display (prevent XSS in UIs)\n */\nfunction sanitizeDisplayString(str: string, maxLength: number = 200): string {\n if (!str || typeof str !== 'string') return '';\n return str.slice(0, maxLength).replace(/[<>\"'&]/g, '');\n}\n\n/**\n * Validate URL format\n */\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/**\n * Build a payment requirement for an article\n * SECURITY: Validates all inputs before building requirement\n */\nexport function buildPaymentRequirement(params: BuildPaymentParams): PaymentRequirement {\n // Validate wallet address\n if (!WALLET_REGEX.test(params.creatorWallet)) {\n throw new Error('Invalid creator wallet address');\n }\n\n // Validate price\n if (params.priceInLamports <= 0n) {\n throw new Error('Price must be positive');\n }\n\n // Validate URL\n if (!isValidUrl(params.resourceUrl)) {\n throw new Error('Invalid resource URL');\n }\n\n // Validate network\n if (params.network !== 'devnet' && params.network !== 'mainnet-beta') {\n throw new Error('Invalid network');\n }\n\n // Validate timeout\n const timeout = params.maxTimeoutSeconds ?? 300;\n if (timeout < 60 || timeout > 3600) {\n throw new Error('Timeout must be between 60 and 3600 seconds');\n }\n\n const x402Network = toX402Network(params.network);\n\n // Sanitize display strings\n const safeTitle = sanitizeDisplayString(params.articleTitle, 200);\n const safeArticleId = sanitizeDisplayString(params.articleId, 128);\n\n return {\n scheme: 'exact',\n network: x402Network,\n maxAmountRequired: params.priceInLamports.toString(),\n resource: params.resourceUrl,\n description: `Unlock: ${safeTitle}`,\n mimeType: 'text/html',\n payTo: params.creatorWallet,\n maxTimeoutSeconds: timeout,\n asset: 'native',\n extra: {\n name: safeTitle,\n articleId: safeArticleId,\n },\n };\n}\n\n/**\n * Encode payment requirement for x402 header\n */\nexport function encodePaymentRequired(requirement: PaymentRequirement): string {\n return Buffer.from(JSON.stringify(requirement)).toString('base64');\n}\n\n/**\n * Decode payment requirement from x402 header\n * SECURITY: Safe parsing with size limit\n */\nexport function decodePaymentRequired(encoded: string): PaymentRequirement {\n if (!encoded || typeof encoded !== 'string') {\n throw new Error('Invalid encoded requirement');\n }\n\n // SECURITY: Limit size to prevent DoS\n if (encoded.length > 10000) {\n throw new Error('Encoded requirement too large');\n }\n\n try {\n const decoded = Buffer.from(encoded, 'base64').toString('utf-8');\n return JSON.parse(decoded);\n } catch {\n throw new Error('Failed to decode payment requirement');\n }\n}\n\n/**\n * x402 response header names\n */\nexport const X402_HEADERS = {\n PAYMENT_REQUIRED: 'X-Payment-Required',\n PAYMENT: 'X-Payment',\n PAYMENT_RESPONSE: 'X-Payment-Response',\n} as const;\n\n/**\n * Create 402 Payment Required response body\n */\nexport function create402ResponseBody(requirement: PaymentRequirement): {\n error: string;\n message: string;\n price: { amount: string; asset: string; network: X402Network };\n} {\n return {\n error: 'Payment Required',\n message: requirement.description,\n price: {\n amount: requirement.maxAmountRequired,\n asset: requirement.asset,\n network: requirement.network,\n },\n };\n}\n\n/**\n * Create headers for 402 response\n */\nexport function create402Headers(requirement: PaymentRequirement): Record<string, string> {\n const encoded = encodePaymentRequired(requirement);\n return {\n 'Content-Type': 'application/json',\n [X402_HEADERS.PAYMENT_REQUIRED]: encoded,\n 'Access-Control-Expose-Headers': X402_HEADERS.PAYMENT_REQUIRED,\n };\n}\n","// x402 payment verification service\n// SECURITY: Input validation, network verification, on-chain settlement check\nimport { verifyPayment, type SolanaClientConfig } from '../solana';\nimport type { PaymentPayload, PaymentRequirement, VerificationResponse } from '../types';\n\n// Signature validation regex (base58, 87-88 chars)\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\n\n/**\n * Verify a payment payload against requirements\n * SECURITY: Full validation chain - format, network, on-chain\n */\nexport async function verifyX402Payment(\n payload: PaymentPayload,\n requirement: PaymentRequirement,\n clientConfig: SolanaClientConfig\n): Promise<VerificationResponse> {\n // SECURITY: Validate payload exists\n if (!payload || typeof payload !== 'object') {\n return { valid: false, invalidReason: 'Invalid payload' };\n }\n\n // SECURITY: Validate signature exists and format\n const signature = payload.payload?.signature;\n if (!signature || typeof signature !== 'string') {\n return { valid: false, invalidReason: 'Missing transaction signature' };\n }\n if (!SIGNATURE_REGEX.test(signature)) {\n return { valid: false, invalidReason: 'Invalid signature format' };\n }\n\n // SECURITY: Validate x402 version\n if (payload.x402Version !== 1) {\n return { valid: false, invalidReason: 'Unsupported x402 version' };\n }\n\n // SECURITY: Validate scheme\n if (payload.scheme !== 'exact') {\n return { valid: false, invalidReason: 'Unsupported payment scheme' };\n }\n\n // SECURITY: Validate network matches exactly\n if (payload.network !== requirement.network) {\n return {\n valid: false,\n invalidReason: `Network mismatch: expected ${requirement.network}`,\n };\n }\n\n // SECURITY: Validate requirement has valid payTo address\n const walletRegex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n if (!walletRegex.test(requirement.payTo)) {\n return { valid: false, invalidReason: 'Invalid recipient configuration' };\n }\n\n // SECURITY: Validate amount is positive\n let expectedAmount: bigint;\n try {\n expectedAmount = BigInt(requirement.maxAmountRequired);\n if (expectedAmount <= 0n) {\n return { valid: false, invalidReason: 'Invalid payment amount' };\n }\n } catch {\n return { valid: false, invalidReason: 'Invalid payment amount format' };\n }\n\n // Verify on-chain\n const verification = await verifyPayment({\n signature,\n expectedRecipient: requirement.payTo,\n expectedAmount,\n maxAgeSeconds: requirement.maxTimeoutSeconds,\n clientConfig,\n });\n\n if (!verification.valid) {\n return {\n valid: false,\n invalidReason: verification.error || 'Transaction verification failed',\n };\n }\n\n return {\n valid: true,\n settled: verification.confirmed,\n transaction: {\n signature: verification.signature,\n blockTime: verification.blockTime,\n slot: verification.slot,\n },\n };\n}\n\n/**\n * Parse payment payload from x402 header\n * SECURITY: Safe JSON parsing with try-catch\n */\nexport function parsePaymentHeader(header: string): PaymentPayload | null {\n if (!header || typeof header !== 'string') {\n return null;\n }\n\n // SECURITY: Limit header size to prevent DoS\n if (header.length > 10000) {\n return null;\n }\n\n try {\n const decoded = Buffer.from(header, 'base64').toString('utf-8');\n const parsed = JSON.parse(decoded);\n\n // Basic structure validation\n if (!parsed || typeof parsed !== 'object') {\n return null;\n }\n\n return parsed as PaymentPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Encode payment response for header\n */\nexport function encodePaymentResponse(response: VerificationResponse): string {\n return Buffer.from(JSON.stringify(response)).toString('base64');\n}\n"]}
1
+ {"version":3,"sources":["../../src/solana/client.ts","../../src/solana/verification.ts","../../src/x402/config.ts","../../src/x402/verification.ts"],"names":["clusterApiUrl","Connection","WALLET_REGEX","SIGNATURE_REGEX"],"mappings":"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","file":"index.cjs","sourcesContent":["// Solana RPC client with multi-provider support\nimport { Connection, clusterApiUrl, type Cluster } from '@solana/web3.js';\nimport type { SolanaNetwork } from '../types';\n\n/** Configuration for Solana client */\nexport interface SolanaClientConfig {\n /** Network to connect to */\n network: SolanaNetwork;\n /** Custom RPC URL (optional) */\n rpcUrl?: string;\n /** Tatum.io API key for RPC (optional) */\n tatumApiKey?: string;\n}\n\n// Singleton state\nlet cachedConnection: Connection | null = null;\nlet cachedNetwork: SolanaNetwork | null = null;\n\n/**\n * Build RPC URL based on configuration priority:\n * 1. Custom RPC URL\n * 2. Tatum.io with API key\n * 3. Public RPC (rate limited)\n */\nfunction buildRpcUrl(config: SolanaClientConfig): string {\n const { network, rpcUrl, tatumApiKey } = config;\n\n if (rpcUrl) {\n // If Tatum URL without key, append key if available\n if (rpcUrl.includes('tatum.io') && tatumApiKey && !rpcUrl.includes(tatumApiKey)) {\n return rpcUrl.endsWith('/') ? `${rpcUrl}${tatumApiKey}` : `${rpcUrl}/${tatumApiKey}`;\n }\n return rpcUrl;\n }\n\n if (tatumApiKey) {\n const baseUrl = network === 'mainnet-beta'\n ? 'https://solana-mainnet.gateway.tatum.io'\n : 'https://solana-devnet.gateway.tatum.io';\n return `${baseUrl}/${tatumApiKey}`;\n }\n\n // Fallback to public RPC\n return clusterApiUrl(network as Cluster);\n}\n\n/**\n * Get or create a Solana connection\n * Uses singleton pattern with network-aware caching\n */\nexport function getConnection(config: SolanaClientConfig): Connection {\n const { network } = config;\n\n // Return cached if same network\n if (cachedConnection && cachedNetwork === network) {\n return cachedConnection;\n }\n\n const rpcUrl = buildRpcUrl(config);\n\n cachedConnection = new Connection(rpcUrl, {\n commitment: 'confirmed',\n confirmTransactionInitialTimeout: 60000,\n });\n cachedNetwork = network;\n\n return cachedConnection;\n}\n\n/**\n * Reset the cached connection\n * Useful for testing or network switching\n */\nexport function resetConnection(): void {\n cachedConnection = null;\n cachedNetwork = null;\n}\n\n/**\n * Check if network is mainnet\n */\nexport function isMainnet(network: SolanaNetwork): boolean {\n return network === 'mainnet-beta';\n}\n\n/**\n * Convert Solana network to x402 network identifier\n */\nexport function toX402Network(network: SolanaNetwork): 'solana-devnet' | 'solana-mainnet' {\n return network === 'mainnet-beta' ? 'solana-mainnet' : 'solana-devnet';\n}\n","// Transaction verification for SOL payments\n// SECURITY: On-chain verification, signature validation, replay protection\nimport { PublicKey, LAMPORTS_PER_SOL, type ParsedTransactionWithMeta } from '@solana/web3.js';\nimport { getConnection, type SolanaClientConfig } from './client';\n\n/** Result of transaction verification */\nexport interface TransactionVerificationResult {\n /** Whether the transaction is valid for the payment */\n valid: boolean;\n /** Whether the transaction is confirmed on-chain */\n confirmed: boolean;\n /** Transaction signature */\n signature: string;\n /** Sender wallet address */\n from?: string;\n /** Recipient wallet address */\n to?: string;\n /** Amount transferred in lamports */\n amount?: bigint;\n /** Block time (Unix timestamp) */\n blockTime?: number;\n /** Slot number */\n slot?: number;\n /** Error message if verification failed */\n error?: string;\n}\n\n/** Parameters for verifying a payment */\nexport interface VerifyPaymentParams {\n /** Transaction signature to verify */\n signature: string;\n /** Expected recipient wallet address */\n expectedRecipient: string;\n /** Expected amount in lamports */\n expectedAmount: bigint;\n /** Maximum age of transaction in seconds (default: 300) */\n maxAgeSeconds?: number;\n /** Solana client configuration */\n clientConfig: SolanaClientConfig;\n}\n\n// Signature validation regex (base58, 87-88 chars)\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\n\n// Wallet address validation regex\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/**\n * Validate transaction signature format\n * SECURITY: Prevents malformed signatures from reaching RPC\n */\nfunction isValidSignature(signature: string): boolean {\n if (!signature || typeof signature !== 'string') return false;\n return SIGNATURE_REGEX.test(signature);\n}\n\n/**\n * Validate wallet address format\n * SECURITY: Ensures valid base58 address\n */\nfunction isValidWalletAddress(address: string): boolean {\n if (!address || typeof address !== 'string') return false;\n return WALLET_REGEX.test(address);\n}\n\n/**\n * Parse SOL transfer details from a transaction\n */\nfunction parseSOLTransfer(\n transaction: ParsedTransactionWithMeta,\n expectedRecipient: string\n): { from: string; to: string; amount: bigint } | null {\n const instructions = transaction.transaction.message.instructions;\n\n // Check main instructions\n for (const ix of instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n\n // Check inner instructions\n if (transaction.meta?.innerInstructions) {\n for (const inner of transaction.meta.innerInstructions) {\n for (const ix of inner.instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Verify a SOL transfer transaction\n * SECURITY: Full on-chain verification with amount/recipient/age checks\n */\nexport async function verifyPayment(\n params: VerifyPaymentParams\n): Promise<TransactionVerificationResult> {\n const {\n signature,\n expectedRecipient,\n expectedAmount,\n maxAgeSeconds = 300,\n clientConfig\n } = params;\n\n // SECURITY: Validate signature format before RPC call\n if (!isValidSignature(signature)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid signature format' };\n }\n\n // SECURITY: Validate recipient address format\n if (!isValidWalletAddress(expectedRecipient)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid recipient address' };\n }\n\n // SECURITY: Validate expected amount is positive\n if (expectedAmount <= 0n) {\n return { valid: false, confirmed: false, signature, error: 'Invalid expected amount' };\n }\n\n // SECURITY: Enforce reasonable max age (prevent replay with very old transactions)\n const effectiveMaxAge = Math.min(Math.max(maxAgeSeconds, 60), 3600); // 1 min to 1 hour\n\n const connection = getConnection(clientConfig);\n\n try {\n const transaction = await connection.getParsedTransaction(signature, {\n commitment: 'confirmed',\n maxSupportedTransactionVersion: 0,\n });\n\n if (!transaction) {\n return { valid: false, confirmed: false, signature, error: 'Transaction not found' };\n }\n\n // Check for transaction errors\n if (transaction.meta?.err) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'Transaction failed on-chain',\n };\n }\n\n // SECURITY: Validate transaction age (replay protection)\n if (transaction.blockTime) {\n const now = Math.floor(Date.now() / 1000);\n if (now - transaction.blockTime > effectiveMaxAge) {\n return { valid: false, confirmed: true, signature, error: 'Transaction too old' };\n }\n // Also reject future-dated transactions (clock skew attack)\n if (transaction.blockTime > now + 60) {\n return { valid: false, confirmed: true, signature, error: 'Invalid transaction time' };\n }\n }\n\n // Parse transfer details\n const transferDetails = parseSOLTransfer(transaction, expectedRecipient);\n\n if (!transferDetails) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'No valid SOL transfer to recipient found',\n };\n }\n\n // SECURITY: Validate amount (must meet or exceed expected)\n if (transferDetails.amount < expectedAmount) {\n return {\n valid: false,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n error: 'Insufficient payment amount',\n };\n }\n\n return {\n valid: true,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n blockTime: transaction.blockTime ?? undefined,\n slot: transaction.slot,\n };\n } catch (error) {\n // SECURITY: Don't expose internal error details\n return {\n valid: false,\n confirmed: false,\n signature,\n error: 'Verification failed',\n };\n }\n}\n\n/**\n * Wait for transaction confirmation\n */\nexport async function waitForConfirmation(\n signature: string,\n clientConfig: SolanaClientConfig\n): Promise<{ confirmed: boolean; slot?: number; error?: string }> {\n if (!isValidSignature(signature)) {\n return { confirmed: false, error: 'Invalid signature format' };\n }\n\n const connection = getConnection(clientConfig);\n\n try {\n const confirmation = await connection.confirmTransaction(signature, 'confirmed');\n\n if (confirmation.value.err) {\n return { confirmed: false, error: 'Transaction failed' };\n }\n\n return { confirmed: true, slot: confirmation.context?.slot };\n } catch {\n return { confirmed: false, error: 'Confirmation timeout' };\n }\n}\n\n/**\n * Get recent transactions for a wallet\n */\nexport async function getWalletTransactions(\n walletAddress: string,\n clientConfig: SolanaClientConfig,\n limit: number = 20\n): Promise<Array<{ signature: string; blockTime?: number; slot: number }>> {\n if (!isValidWalletAddress(walletAddress)) {\n return [];\n }\n\n // SECURITY: Cap limit to prevent abuse\n const safeLimit = Math.min(Math.max(limit, 1), 100);\n\n const connection = getConnection(clientConfig);\n\n try {\n const pubkey = new PublicKey(walletAddress);\n const signatures = await connection.getSignaturesForAddress(pubkey, { limit: safeLimit });\n return signatures.map((sig) => ({\n signature: sig.signature,\n blockTime: sig.blockTime ?? undefined,\n slot: sig.slot,\n }));\n } catch {\n return [];\n }\n}\n\n/**\n * Convert lamports to SOL\n */\nexport function lamportsToSol(lamports: bigint | number): number {\n return Number(lamports) / LAMPORTS_PER_SOL;\n}\n\n/**\n * Convert SOL to lamports\n */\nexport function solToLamports(sol: number): bigint {\n if (!Number.isFinite(sol) || sol < 0) {\n throw new Error('Invalid SOL amount');\n }\n return BigInt(Math.floor(sol * LAMPORTS_PER_SOL));\n}\n","// x402 payment configuration and helpers\n// SECURITY: Input sanitization for payment requirements\nimport type { PaymentRequirement, X402Network, SolanaNetwork } from '../types';\nimport { toX402Network } from '../solana';\n\n// Wallet address validation regex\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/** Parameters for building a payment requirement */\nexport interface BuildPaymentParams {\n /** Unique article identifier */\n articleId: string;\n /** Article title for display */\n articleTitle: string;\n /** Price in lamports */\n priceInLamports: bigint;\n /** Creator wallet address */\n creatorWallet: string;\n /** Full URL of the protected resource */\n resourceUrl: string;\n /** Solana network */\n network: SolanaNetwork;\n /** Max time to complete payment (default: 300s) */\n maxTimeoutSeconds?: number;\n}\n\n/**\n * Sanitize string for safe display (prevent XSS in UIs)\n */\nfunction sanitizeDisplayString(str: string, maxLength: number = 200): string {\n if (!str || typeof str !== 'string') return '';\n return str.slice(0, maxLength).replace(/[<>\"'&]/g, '');\n}\n\n/**\n * Validate URL format\n */\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/**\n * Build a payment requirement for an article\n * SECURITY: Validates all inputs before building requirement\n */\nexport function buildPaymentRequirement(params: BuildPaymentParams): PaymentRequirement {\n // Validate wallet address\n if (!WALLET_REGEX.test(params.creatorWallet)) {\n throw new Error('Invalid creator wallet address');\n }\n\n // Validate price\n if (params.priceInLamports <= 0n) {\n throw new Error('Price must be positive');\n }\n\n // Validate URL\n if (!isValidUrl(params.resourceUrl)) {\n throw new Error('Invalid resource URL');\n }\n\n // Validate network\n if (params.network !== 'devnet' && params.network !== 'mainnet-beta') {\n throw new Error('Invalid network');\n }\n\n // Validate timeout\n const timeout = params.maxTimeoutSeconds ?? 300;\n if (timeout < 60 || timeout > 3600) {\n throw new Error('Timeout must be between 60 and 3600 seconds');\n }\n\n const x402Network = toX402Network(params.network);\n\n // Sanitize display strings\n const safeTitle = sanitizeDisplayString(params.articleTitle, 200);\n const safeArticleId = sanitizeDisplayString(params.articleId, 128);\n\n return {\n scheme: 'exact',\n network: x402Network,\n maxAmountRequired: params.priceInLamports.toString(),\n resource: params.resourceUrl,\n description: `Unlock: ${safeTitle}`,\n mimeType: 'text/html',\n payTo: params.creatorWallet,\n maxTimeoutSeconds: timeout,\n asset: 'native',\n extra: {\n name: safeTitle,\n articleId: safeArticleId,\n },\n };\n}\n\n/**\n * Encode payment requirement for x402 header\n */\nexport function encodePaymentRequired(requirement: PaymentRequirement): string {\n return Buffer.from(JSON.stringify(requirement)).toString('base64');\n}\n\n/**\n * Decode payment requirement from x402 header\n * SECURITY: Safe parsing with size limit\n */\nexport function decodePaymentRequired(encoded: string): PaymentRequirement {\n if (!encoded || typeof encoded !== 'string') {\n throw new Error('Invalid encoded requirement');\n }\n\n // SECURITY: Limit size to prevent DoS\n if (encoded.length > 10000) {\n throw new Error('Encoded requirement too large');\n }\n\n try {\n const decoded = Buffer.from(encoded, 'base64').toString('utf-8');\n return JSON.parse(decoded);\n } catch {\n throw new Error('Failed to decode payment requirement');\n }\n}\n\n/**\n * x402 response header names\n */\nexport const X402_HEADERS = {\n PAYMENT_REQUIRED: 'X-Payment-Required',\n PAYMENT: 'X-Payment',\n PAYMENT_RESPONSE: 'X-Payment-Response',\n} as const;\n\n/**\n * Create 402 Payment Required response body\n */\nexport function create402ResponseBody(requirement: PaymentRequirement): {\n error: string;\n message: string;\n price: { amount: string; asset: string; network: X402Network };\n} {\n // Convert asset to string for JSON serialization\n const assetStr = typeof requirement.asset === 'string'\n ? requirement.asset\n : requirement.asset.mint;\n\n return {\n error: 'Payment Required',\n message: requirement.description,\n price: {\n amount: requirement.maxAmountRequired,\n asset: assetStr,\n network: requirement.network,\n },\n };\n}\n\n/**\n * Create headers for 402 response\n */\nexport function create402Headers(requirement: PaymentRequirement): Record<string, string> {\n const encoded = encodePaymentRequired(requirement);\n return {\n 'Content-Type': 'application/json',\n [X402_HEADERS.PAYMENT_REQUIRED]: encoded,\n 'Access-Control-Expose-Headers': X402_HEADERS.PAYMENT_REQUIRED,\n };\n}\n","// x402 payment verification service\n// SECURITY: Input validation, network verification, on-chain settlement check\nimport { verifyPayment, type SolanaClientConfig } from '../solana';\nimport type { PaymentPayload, PaymentRequirement, VerificationResponse } from '../types';\n\n// Signature validation regex (base58, 87-88 chars)\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\n\n/**\n * Verify a payment payload against requirements\n * SECURITY: Full validation chain - format, network, on-chain\n */\nexport async function verifyX402Payment(\n payload: PaymentPayload,\n requirement: PaymentRequirement,\n clientConfig: SolanaClientConfig\n): Promise<VerificationResponse> {\n // SECURITY: Validate payload exists\n if (!payload || typeof payload !== 'object') {\n return { valid: false, invalidReason: 'Invalid payload' };\n }\n\n // SECURITY: Validate signature exists and format\n const signature = payload.payload?.signature;\n if (!signature || typeof signature !== 'string') {\n return { valid: false, invalidReason: 'Missing transaction signature' };\n }\n if (!SIGNATURE_REGEX.test(signature)) {\n return { valid: false, invalidReason: 'Invalid signature format' };\n }\n\n // SECURITY: Validate x402 version\n if (payload.x402Version !== 1) {\n return { valid: false, invalidReason: 'Unsupported x402 version' };\n }\n\n // SECURITY: Validate scheme\n if (payload.scheme !== 'exact') {\n return { valid: false, invalidReason: 'Unsupported payment scheme' };\n }\n\n // SECURITY: Validate network matches exactly\n if (payload.network !== requirement.network) {\n return {\n valid: false,\n invalidReason: `Network mismatch: expected ${requirement.network}`,\n };\n }\n\n // SECURITY: Validate requirement has valid payTo address\n const walletRegex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n if (!walletRegex.test(requirement.payTo)) {\n return { valid: false, invalidReason: 'Invalid recipient configuration' };\n }\n\n // SECURITY: Validate amount is positive\n let expectedAmount: bigint;\n try {\n expectedAmount = BigInt(requirement.maxAmountRequired);\n if (expectedAmount <= 0n) {\n return { valid: false, invalidReason: 'Invalid payment amount' };\n }\n } catch {\n return { valid: false, invalidReason: 'Invalid payment amount format' };\n }\n\n // Verify on-chain\n const verification = await verifyPayment({\n signature,\n expectedRecipient: requirement.payTo,\n expectedAmount,\n maxAgeSeconds: requirement.maxTimeoutSeconds,\n clientConfig,\n });\n\n if (!verification.valid) {\n return {\n valid: false,\n invalidReason: verification.error || 'Transaction verification failed',\n };\n }\n\n return {\n valid: true,\n settled: verification.confirmed,\n transaction: {\n signature: verification.signature,\n blockTime: verification.blockTime,\n slot: verification.slot,\n },\n };\n}\n\n/**\n * Parse payment payload from x402 header\n * SECURITY: Safe JSON parsing with try-catch\n */\nexport function parsePaymentHeader(header: string): PaymentPayload | null {\n if (!header || typeof header !== 'string') {\n return null;\n }\n\n // SECURITY: Limit header size to prevent DoS\n if (header.length > 10000) {\n return null;\n }\n\n try {\n const decoded = Buffer.from(header, 'base64').toString('utf-8');\n const parsed = JSON.parse(decoded);\n\n // Basic structure validation\n if (!parsed || typeof parsed !== 'object') {\n return null;\n }\n\n return parsed as PaymentPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Encode payment response for header\n */\nexport function encodePaymentResponse(response: VerificationResponse): string {\n return Buffer.from(JSON.stringify(response)).toString('base64');\n}\n"]}
@@ -1,4 +1,5 @@
1
- import { S as SolanaNetwork, P as PaymentRequirement, X as X402Network, a as PaymentPayload, d as SolanaClientConfig, b as VerificationResponse } from '../client-kfCr7G-P.cjs';
1
+ import { S as SolanaNetwork, P as PaymentRequirement, X as X402Network, a as PaymentPayload, b as VerificationResponse } from '../payment-CTxdtqmc.cjs';
2
+ import { S as SolanaClientConfig } from '../client-vRr48m2x.cjs';
2
3
  import '@solana/web3.js';
3
4
 
4
5
  /** Parameters for building a payment requirement */
@@ -1,4 +1,5 @@
1
- import { S as SolanaNetwork, P as PaymentRequirement, X as X402Network, a as PaymentPayload, d as SolanaClientConfig, b as VerificationResponse } from '../client-kfCr7G-P.js';
1
+ import { S as SolanaNetwork, P as PaymentRequirement, X as X402Network, a as PaymentPayload, b as VerificationResponse } from '../payment-CTxdtqmc.js';
2
+ import { S as SolanaClientConfig } from '../client-CSZHI8o8.js';
2
3
  import '@solana/web3.js';
3
4
 
4
5
  /** Parameters for building a payment requirement */
@@ -232,12 +232,13 @@ var X402_HEADERS = {
232
232
  PAYMENT_RESPONSE: "X-Payment-Response"
233
233
  };
234
234
  function create402ResponseBody(requirement) {
235
+ const assetStr = typeof requirement.asset === "string" ? requirement.asset : requirement.asset.mint;
235
236
  return {
236
237
  error: "Payment Required",
237
238
  message: requirement.description,
238
239
  price: {
239
240
  amount: requirement.maxAmountRequired,
240
- asset: requirement.asset,
241
+ asset: assetStr,
241
242
  network: requirement.network
242
243
  }
243
244
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/solana/client.ts","../../src/solana/verification.ts","../../src/x402/config.ts","../../src/x402/verification.ts"],"names":["WALLET_REGEX","SIGNATURE_REGEX"],"mappings":"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","file":"index.js","sourcesContent":["// Solana RPC client with multi-provider support\nimport { Connection, clusterApiUrl, type Cluster } from '@solana/web3.js';\nimport type { SolanaNetwork } from '../types';\n\n/** Configuration for Solana client */\nexport interface SolanaClientConfig {\n /** Network to connect to */\n network: SolanaNetwork;\n /** Custom RPC URL (optional) */\n rpcUrl?: string;\n /** Tatum.io API key for RPC (optional) */\n tatumApiKey?: string;\n}\n\n// Singleton state\nlet cachedConnection: Connection | null = null;\nlet cachedNetwork: SolanaNetwork | null = null;\n\n/**\n * Build RPC URL based on configuration priority:\n * 1. Custom RPC URL\n * 2. Tatum.io with API key\n * 3. Public RPC (rate limited)\n */\nfunction buildRpcUrl(config: SolanaClientConfig): string {\n const { network, rpcUrl, tatumApiKey } = config;\n\n if (rpcUrl) {\n // If Tatum URL without key, append key if available\n if (rpcUrl.includes('tatum.io') && tatumApiKey && !rpcUrl.includes(tatumApiKey)) {\n return rpcUrl.endsWith('/') ? `${rpcUrl}${tatumApiKey}` : `${rpcUrl}/${tatumApiKey}`;\n }\n return rpcUrl;\n }\n\n if (tatumApiKey) {\n const baseUrl = network === 'mainnet-beta'\n ? 'https://solana-mainnet.gateway.tatum.io'\n : 'https://solana-devnet.gateway.tatum.io';\n return `${baseUrl}/${tatumApiKey}`;\n }\n\n // Fallback to public RPC\n return clusterApiUrl(network as Cluster);\n}\n\n/**\n * Get or create a Solana connection\n * Uses singleton pattern with network-aware caching\n */\nexport function getConnection(config: SolanaClientConfig): Connection {\n const { network } = config;\n\n // Return cached if same network\n if (cachedConnection && cachedNetwork === network) {\n return cachedConnection;\n }\n\n const rpcUrl = buildRpcUrl(config);\n\n cachedConnection = new Connection(rpcUrl, {\n commitment: 'confirmed',\n confirmTransactionInitialTimeout: 60000,\n });\n cachedNetwork = network;\n\n return cachedConnection;\n}\n\n/**\n * Reset the cached connection\n * Useful for testing or network switching\n */\nexport function resetConnection(): void {\n cachedConnection = null;\n cachedNetwork = null;\n}\n\n/**\n * Check if network is mainnet\n */\nexport function isMainnet(network: SolanaNetwork): boolean {\n return network === 'mainnet-beta';\n}\n\n/**\n * Convert Solana network to x402 network identifier\n */\nexport function toX402Network(network: SolanaNetwork): 'solana-devnet' | 'solana-mainnet' {\n return network === 'mainnet-beta' ? 'solana-mainnet' : 'solana-devnet';\n}\n","// Transaction verification for SOL payments\n// SECURITY: On-chain verification, signature validation, replay protection\nimport { PublicKey, LAMPORTS_PER_SOL, type ParsedTransactionWithMeta } from '@solana/web3.js';\nimport { getConnection, type SolanaClientConfig } from './client';\n\n/** Result of transaction verification */\nexport interface TransactionVerificationResult {\n /** Whether the transaction is valid for the payment */\n valid: boolean;\n /** Whether the transaction is confirmed on-chain */\n confirmed: boolean;\n /** Transaction signature */\n signature: string;\n /** Sender wallet address */\n from?: string;\n /** Recipient wallet address */\n to?: string;\n /** Amount transferred in lamports */\n amount?: bigint;\n /** Block time (Unix timestamp) */\n blockTime?: number;\n /** Slot number */\n slot?: number;\n /** Error message if verification failed */\n error?: string;\n}\n\n/** Parameters for verifying a payment */\nexport interface VerifyPaymentParams {\n /** Transaction signature to verify */\n signature: string;\n /** Expected recipient wallet address */\n expectedRecipient: string;\n /** Expected amount in lamports */\n expectedAmount: bigint;\n /** Maximum age of transaction in seconds (default: 300) */\n maxAgeSeconds?: number;\n /** Solana client configuration */\n clientConfig: SolanaClientConfig;\n}\n\n// Signature validation regex (base58, 87-88 chars)\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\n\n// Wallet address validation regex\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/**\n * Validate transaction signature format\n * SECURITY: Prevents malformed signatures from reaching RPC\n */\nfunction isValidSignature(signature: string): boolean {\n if (!signature || typeof signature !== 'string') return false;\n return SIGNATURE_REGEX.test(signature);\n}\n\n/**\n * Validate wallet address format\n * SECURITY: Ensures valid base58 address\n */\nfunction isValidWalletAddress(address: string): boolean {\n if (!address || typeof address !== 'string') return false;\n return WALLET_REGEX.test(address);\n}\n\n/**\n * Parse SOL transfer details from a transaction\n */\nfunction parseSOLTransfer(\n transaction: ParsedTransactionWithMeta,\n expectedRecipient: string\n): { from: string; to: string; amount: bigint } | null {\n const instructions = transaction.transaction.message.instructions;\n\n // Check main instructions\n for (const ix of instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n\n // Check inner instructions\n if (transaction.meta?.innerInstructions) {\n for (const inner of transaction.meta.innerInstructions) {\n for (const ix of inner.instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Verify a SOL transfer transaction\n * SECURITY: Full on-chain verification with amount/recipient/age checks\n */\nexport async function verifyPayment(\n params: VerifyPaymentParams\n): Promise<TransactionVerificationResult> {\n const {\n signature,\n expectedRecipient,\n expectedAmount,\n maxAgeSeconds = 300,\n clientConfig\n } = params;\n\n // SECURITY: Validate signature format before RPC call\n if (!isValidSignature(signature)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid signature format' };\n }\n\n // SECURITY: Validate recipient address format\n if (!isValidWalletAddress(expectedRecipient)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid recipient address' };\n }\n\n // SECURITY: Validate expected amount is positive\n if (expectedAmount <= 0n) {\n return { valid: false, confirmed: false, signature, error: 'Invalid expected amount' };\n }\n\n // SECURITY: Enforce reasonable max age (prevent replay with very old transactions)\n const effectiveMaxAge = Math.min(Math.max(maxAgeSeconds, 60), 3600); // 1 min to 1 hour\n\n const connection = getConnection(clientConfig);\n\n try {\n const transaction = await connection.getParsedTransaction(signature, {\n commitment: 'confirmed',\n maxSupportedTransactionVersion: 0,\n });\n\n if (!transaction) {\n return { valid: false, confirmed: false, signature, error: 'Transaction not found' };\n }\n\n // Check for transaction errors\n if (transaction.meta?.err) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'Transaction failed on-chain',\n };\n }\n\n // SECURITY: Validate transaction age (replay protection)\n if (transaction.blockTime) {\n const now = Math.floor(Date.now() / 1000);\n if (now - transaction.blockTime > effectiveMaxAge) {\n return { valid: false, confirmed: true, signature, error: 'Transaction too old' };\n }\n // Also reject future-dated transactions (clock skew attack)\n if (transaction.blockTime > now + 60) {\n return { valid: false, confirmed: true, signature, error: 'Invalid transaction time' };\n }\n }\n\n // Parse transfer details\n const transferDetails = parseSOLTransfer(transaction, expectedRecipient);\n\n if (!transferDetails) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'No valid SOL transfer to recipient found',\n };\n }\n\n // SECURITY: Validate amount (must meet or exceed expected)\n if (transferDetails.amount < expectedAmount) {\n return {\n valid: false,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n error: 'Insufficient payment amount',\n };\n }\n\n return {\n valid: true,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n blockTime: transaction.blockTime ?? undefined,\n slot: transaction.slot,\n };\n } catch (error) {\n // SECURITY: Don't expose internal error details\n return {\n valid: false,\n confirmed: false,\n signature,\n error: 'Verification failed',\n };\n }\n}\n\n/**\n * Wait for transaction confirmation\n */\nexport async function waitForConfirmation(\n signature: string,\n clientConfig: SolanaClientConfig\n): Promise<{ confirmed: boolean; slot?: number; error?: string }> {\n if (!isValidSignature(signature)) {\n return { confirmed: false, error: 'Invalid signature format' };\n }\n\n const connection = getConnection(clientConfig);\n\n try {\n const confirmation = await connection.confirmTransaction(signature, 'confirmed');\n\n if (confirmation.value.err) {\n return { confirmed: false, error: 'Transaction failed' };\n }\n\n return { confirmed: true, slot: confirmation.context?.slot };\n } catch {\n return { confirmed: false, error: 'Confirmation timeout' };\n }\n}\n\n/**\n * Get recent transactions for a wallet\n */\nexport async function getWalletTransactions(\n walletAddress: string,\n clientConfig: SolanaClientConfig,\n limit: number = 20\n): Promise<Array<{ signature: string; blockTime?: number; slot: number }>> {\n if (!isValidWalletAddress(walletAddress)) {\n return [];\n }\n\n // SECURITY: Cap limit to prevent abuse\n const safeLimit = Math.min(Math.max(limit, 1), 100);\n\n const connection = getConnection(clientConfig);\n\n try {\n const pubkey = new PublicKey(walletAddress);\n const signatures = await connection.getSignaturesForAddress(pubkey, { limit: safeLimit });\n return signatures.map((sig) => ({\n signature: sig.signature,\n blockTime: sig.blockTime ?? undefined,\n slot: sig.slot,\n }));\n } catch {\n return [];\n }\n}\n\n/**\n * Convert lamports to SOL\n */\nexport function lamportsToSol(lamports: bigint | number): number {\n return Number(lamports) / LAMPORTS_PER_SOL;\n}\n\n/**\n * Convert SOL to lamports\n */\nexport function solToLamports(sol: number): bigint {\n if (!Number.isFinite(sol) || sol < 0) {\n throw new Error('Invalid SOL amount');\n }\n return BigInt(Math.floor(sol * LAMPORTS_PER_SOL));\n}\n","// x402 payment configuration and helpers\n// SECURITY: Input sanitization for payment requirements\nimport type { PaymentRequirement, X402Network, SolanaNetwork } from '../types';\nimport { toX402Network } from '../solana';\n\n// Wallet address validation regex\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/** Parameters for building a payment requirement */\nexport interface BuildPaymentParams {\n /** Unique article identifier */\n articleId: string;\n /** Article title for display */\n articleTitle: string;\n /** Price in lamports */\n priceInLamports: bigint;\n /** Creator wallet address */\n creatorWallet: string;\n /** Full URL of the protected resource */\n resourceUrl: string;\n /** Solana network */\n network: SolanaNetwork;\n /** Max time to complete payment (default: 300s) */\n maxTimeoutSeconds?: number;\n}\n\n/**\n * Sanitize string for safe display (prevent XSS in UIs)\n */\nfunction sanitizeDisplayString(str: string, maxLength: number = 200): string {\n if (!str || typeof str !== 'string') return '';\n return str.slice(0, maxLength).replace(/[<>\"'&]/g, '');\n}\n\n/**\n * Validate URL format\n */\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/**\n * Build a payment requirement for an article\n * SECURITY: Validates all inputs before building requirement\n */\nexport function buildPaymentRequirement(params: BuildPaymentParams): PaymentRequirement {\n // Validate wallet address\n if (!WALLET_REGEX.test(params.creatorWallet)) {\n throw new Error('Invalid creator wallet address');\n }\n\n // Validate price\n if (params.priceInLamports <= 0n) {\n throw new Error('Price must be positive');\n }\n\n // Validate URL\n if (!isValidUrl(params.resourceUrl)) {\n throw new Error('Invalid resource URL');\n }\n\n // Validate network\n if (params.network !== 'devnet' && params.network !== 'mainnet-beta') {\n throw new Error('Invalid network');\n }\n\n // Validate timeout\n const timeout = params.maxTimeoutSeconds ?? 300;\n if (timeout < 60 || timeout > 3600) {\n throw new Error('Timeout must be between 60 and 3600 seconds');\n }\n\n const x402Network = toX402Network(params.network);\n\n // Sanitize display strings\n const safeTitle = sanitizeDisplayString(params.articleTitle, 200);\n const safeArticleId = sanitizeDisplayString(params.articleId, 128);\n\n return {\n scheme: 'exact',\n network: x402Network,\n maxAmountRequired: params.priceInLamports.toString(),\n resource: params.resourceUrl,\n description: `Unlock: ${safeTitle}`,\n mimeType: 'text/html',\n payTo: params.creatorWallet,\n maxTimeoutSeconds: timeout,\n asset: 'native',\n extra: {\n name: safeTitle,\n articleId: safeArticleId,\n },\n };\n}\n\n/**\n * Encode payment requirement for x402 header\n */\nexport function encodePaymentRequired(requirement: PaymentRequirement): string {\n return Buffer.from(JSON.stringify(requirement)).toString('base64');\n}\n\n/**\n * Decode payment requirement from x402 header\n * SECURITY: Safe parsing with size limit\n */\nexport function decodePaymentRequired(encoded: string): PaymentRequirement {\n if (!encoded || typeof encoded !== 'string') {\n throw new Error('Invalid encoded requirement');\n }\n\n // SECURITY: Limit size to prevent DoS\n if (encoded.length > 10000) {\n throw new Error('Encoded requirement too large');\n }\n\n try {\n const decoded = Buffer.from(encoded, 'base64').toString('utf-8');\n return JSON.parse(decoded);\n } catch {\n throw new Error('Failed to decode payment requirement');\n }\n}\n\n/**\n * x402 response header names\n */\nexport const X402_HEADERS = {\n PAYMENT_REQUIRED: 'X-Payment-Required',\n PAYMENT: 'X-Payment',\n PAYMENT_RESPONSE: 'X-Payment-Response',\n} as const;\n\n/**\n * Create 402 Payment Required response body\n */\nexport function create402ResponseBody(requirement: PaymentRequirement): {\n error: string;\n message: string;\n price: { amount: string; asset: string; network: X402Network };\n} {\n return {\n error: 'Payment Required',\n message: requirement.description,\n price: {\n amount: requirement.maxAmountRequired,\n asset: requirement.asset,\n network: requirement.network,\n },\n };\n}\n\n/**\n * Create headers for 402 response\n */\nexport function create402Headers(requirement: PaymentRequirement): Record<string, string> {\n const encoded = encodePaymentRequired(requirement);\n return {\n 'Content-Type': 'application/json',\n [X402_HEADERS.PAYMENT_REQUIRED]: encoded,\n 'Access-Control-Expose-Headers': X402_HEADERS.PAYMENT_REQUIRED,\n };\n}\n","// x402 payment verification service\n// SECURITY: Input validation, network verification, on-chain settlement check\nimport { verifyPayment, type SolanaClientConfig } from '../solana';\nimport type { PaymentPayload, PaymentRequirement, VerificationResponse } from '../types';\n\n// Signature validation regex (base58, 87-88 chars)\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\n\n/**\n * Verify a payment payload against requirements\n * SECURITY: Full validation chain - format, network, on-chain\n */\nexport async function verifyX402Payment(\n payload: PaymentPayload,\n requirement: PaymentRequirement,\n clientConfig: SolanaClientConfig\n): Promise<VerificationResponse> {\n // SECURITY: Validate payload exists\n if (!payload || typeof payload !== 'object') {\n return { valid: false, invalidReason: 'Invalid payload' };\n }\n\n // SECURITY: Validate signature exists and format\n const signature = payload.payload?.signature;\n if (!signature || typeof signature !== 'string') {\n return { valid: false, invalidReason: 'Missing transaction signature' };\n }\n if (!SIGNATURE_REGEX.test(signature)) {\n return { valid: false, invalidReason: 'Invalid signature format' };\n }\n\n // SECURITY: Validate x402 version\n if (payload.x402Version !== 1) {\n return { valid: false, invalidReason: 'Unsupported x402 version' };\n }\n\n // SECURITY: Validate scheme\n if (payload.scheme !== 'exact') {\n return { valid: false, invalidReason: 'Unsupported payment scheme' };\n }\n\n // SECURITY: Validate network matches exactly\n if (payload.network !== requirement.network) {\n return {\n valid: false,\n invalidReason: `Network mismatch: expected ${requirement.network}`,\n };\n }\n\n // SECURITY: Validate requirement has valid payTo address\n const walletRegex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n if (!walletRegex.test(requirement.payTo)) {\n return { valid: false, invalidReason: 'Invalid recipient configuration' };\n }\n\n // SECURITY: Validate amount is positive\n let expectedAmount: bigint;\n try {\n expectedAmount = BigInt(requirement.maxAmountRequired);\n if (expectedAmount <= 0n) {\n return { valid: false, invalidReason: 'Invalid payment amount' };\n }\n } catch {\n return { valid: false, invalidReason: 'Invalid payment amount format' };\n }\n\n // Verify on-chain\n const verification = await verifyPayment({\n signature,\n expectedRecipient: requirement.payTo,\n expectedAmount,\n maxAgeSeconds: requirement.maxTimeoutSeconds,\n clientConfig,\n });\n\n if (!verification.valid) {\n return {\n valid: false,\n invalidReason: verification.error || 'Transaction verification failed',\n };\n }\n\n return {\n valid: true,\n settled: verification.confirmed,\n transaction: {\n signature: verification.signature,\n blockTime: verification.blockTime,\n slot: verification.slot,\n },\n };\n}\n\n/**\n * Parse payment payload from x402 header\n * SECURITY: Safe JSON parsing with try-catch\n */\nexport function parsePaymentHeader(header: string): PaymentPayload | null {\n if (!header || typeof header !== 'string') {\n return null;\n }\n\n // SECURITY: Limit header size to prevent DoS\n if (header.length > 10000) {\n return null;\n }\n\n try {\n const decoded = Buffer.from(header, 'base64').toString('utf-8');\n const parsed = JSON.parse(decoded);\n\n // Basic structure validation\n if (!parsed || typeof parsed !== 'object') {\n return null;\n }\n\n return parsed as PaymentPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Encode payment response for header\n */\nexport function encodePaymentResponse(response: VerificationResponse): string {\n return Buffer.from(JSON.stringify(response)).toString('base64');\n}\n"]}
1
+ {"version":3,"sources":["../../src/solana/client.ts","../../src/solana/verification.ts","../../src/x402/config.ts","../../src/x402/verification.ts"],"names":["WALLET_REGEX","SIGNATURE_REGEX"],"mappings":"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","file":"index.js","sourcesContent":["// Solana RPC client with multi-provider support\nimport { Connection, clusterApiUrl, type Cluster } from '@solana/web3.js';\nimport type { SolanaNetwork } from '../types';\n\n/** Configuration for Solana client */\nexport interface SolanaClientConfig {\n /** Network to connect to */\n network: SolanaNetwork;\n /** Custom RPC URL (optional) */\n rpcUrl?: string;\n /** Tatum.io API key for RPC (optional) */\n tatumApiKey?: string;\n}\n\n// Singleton state\nlet cachedConnection: Connection | null = null;\nlet cachedNetwork: SolanaNetwork | null = null;\n\n/**\n * Build RPC URL based on configuration priority:\n * 1. Custom RPC URL\n * 2. Tatum.io with API key\n * 3. Public RPC (rate limited)\n */\nfunction buildRpcUrl(config: SolanaClientConfig): string {\n const { network, rpcUrl, tatumApiKey } = config;\n\n if (rpcUrl) {\n // If Tatum URL without key, append key if available\n if (rpcUrl.includes('tatum.io') && tatumApiKey && !rpcUrl.includes(tatumApiKey)) {\n return rpcUrl.endsWith('/') ? `${rpcUrl}${tatumApiKey}` : `${rpcUrl}/${tatumApiKey}`;\n }\n return rpcUrl;\n }\n\n if (tatumApiKey) {\n const baseUrl = network === 'mainnet-beta'\n ? 'https://solana-mainnet.gateway.tatum.io'\n : 'https://solana-devnet.gateway.tatum.io';\n return `${baseUrl}/${tatumApiKey}`;\n }\n\n // Fallback to public RPC\n return clusterApiUrl(network as Cluster);\n}\n\n/**\n * Get or create a Solana connection\n * Uses singleton pattern with network-aware caching\n */\nexport function getConnection(config: SolanaClientConfig): Connection {\n const { network } = config;\n\n // Return cached if same network\n if (cachedConnection && cachedNetwork === network) {\n return cachedConnection;\n }\n\n const rpcUrl = buildRpcUrl(config);\n\n cachedConnection = new Connection(rpcUrl, {\n commitment: 'confirmed',\n confirmTransactionInitialTimeout: 60000,\n });\n cachedNetwork = network;\n\n return cachedConnection;\n}\n\n/**\n * Reset the cached connection\n * Useful for testing or network switching\n */\nexport function resetConnection(): void {\n cachedConnection = null;\n cachedNetwork = null;\n}\n\n/**\n * Check if network is mainnet\n */\nexport function isMainnet(network: SolanaNetwork): boolean {\n return network === 'mainnet-beta';\n}\n\n/**\n * Convert Solana network to x402 network identifier\n */\nexport function toX402Network(network: SolanaNetwork): 'solana-devnet' | 'solana-mainnet' {\n return network === 'mainnet-beta' ? 'solana-mainnet' : 'solana-devnet';\n}\n","// Transaction verification for SOL payments\n// SECURITY: On-chain verification, signature validation, replay protection\nimport { PublicKey, LAMPORTS_PER_SOL, type ParsedTransactionWithMeta } from '@solana/web3.js';\nimport { getConnection, type SolanaClientConfig } from './client';\n\n/** Result of transaction verification */\nexport interface TransactionVerificationResult {\n /** Whether the transaction is valid for the payment */\n valid: boolean;\n /** Whether the transaction is confirmed on-chain */\n confirmed: boolean;\n /** Transaction signature */\n signature: string;\n /** Sender wallet address */\n from?: string;\n /** Recipient wallet address */\n to?: string;\n /** Amount transferred in lamports */\n amount?: bigint;\n /** Block time (Unix timestamp) */\n blockTime?: number;\n /** Slot number */\n slot?: number;\n /** Error message if verification failed */\n error?: string;\n}\n\n/** Parameters for verifying a payment */\nexport interface VerifyPaymentParams {\n /** Transaction signature to verify */\n signature: string;\n /** Expected recipient wallet address */\n expectedRecipient: string;\n /** Expected amount in lamports */\n expectedAmount: bigint;\n /** Maximum age of transaction in seconds (default: 300) */\n maxAgeSeconds?: number;\n /** Solana client configuration */\n clientConfig: SolanaClientConfig;\n}\n\n// Signature validation regex (base58, 87-88 chars)\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\n\n// Wallet address validation regex\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/**\n * Validate transaction signature format\n * SECURITY: Prevents malformed signatures from reaching RPC\n */\nfunction isValidSignature(signature: string): boolean {\n if (!signature || typeof signature !== 'string') return false;\n return SIGNATURE_REGEX.test(signature);\n}\n\n/**\n * Validate wallet address format\n * SECURITY: Ensures valid base58 address\n */\nfunction isValidWalletAddress(address: string): boolean {\n if (!address || typeof address !== 'string') return false;\n return WALLET_REGEX.test(address);\n}\n\n/**\n * Parse SOL transfer details from a transaction\n */\nfunction parseSOLTransfer(\n transaction: ParsedTransactionWithMeta,\n expectedRecipient: string\n): { from: string; to: string; amount: bigint } | null {\n const instructions = transaction.transaction.message.instructions;\n\n // Check main instructions\n for (const ix of instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n\n // Check inner instructions\n if (transaction.meta?.innerInstructions) {\n for (const inner of transaction.meta.innerInstructions) {\n for (const ix of inner.instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Verify a SOL transfer transaction\n * SECURITY: Full on-chain verification with amount/recipient/age checks\n */\nexport async function verifyPayment(\n params: VerifyPaymentParams\n): Promise<TransactionVerificationResult> {\n const {\n signature,\n expectedRecipient,\n expectedAmount,\n maxAgeSeconds = 300,\n clientConfig\n } = params;\n\n // SECURITY: Validate signature format before RPC call\n if (!isValidSignature(signature)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid signature format' };\n }\n\n // SECURITY: Validate recipient address format\n if (!isValidWalletAddress(expectedRecipient)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid recipient address' };\n }\n\n // SECURITY: Validate expected amount is positive\n if (expectedAmount <= 0n) {\n return { valid: false, confirmed: false, signature, error: 'Invalid expected amount' };\n }\n\n // SECURITY: Enforce reasonable max age (prevent replay with very old transactions)\n const effectiveMaxAge = Math.min(Math.max(maxAgeSeconds, 60), 3600); // 1 min to 1 hour\n\n const connection = getConnection(clientConfig);\n\n try {\n const transaction = await connection.getParsedTransaction(signature, {\n commitment: 'confirmed',\n maxSupportedTransactionVersion: 0,\n });\n\n if (!transaction) {\n return { valid: false, confirmed: false, signature, error: 'Transaction not found' };\n }\n\n // Check for transaction errors\n if (transaction.meta?.err) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'Transaction failed on-chain',\n };\n }\n\n // SECURITY: Validate transaction age (replay protection)\n if (transaction.blockTime) {\n const now = Math.floor(Date.now() / 1000);\n if (now - transaction.blockTime > effectiveMaxAge) {\n return { valid: false, confirmed: true, signature, error: 'Transaction too old' };\n }\n // Also reject future-dated transactions (clock skew attack)\n if (transaction.blockTime > now + 60) {\n return { valid: false, confirmed: true, signature, error: 'Invalid transaction time' };\n }\n }\n\n // Parse transfer details\n const transferDetails = parseSOLTransfer(transaction, expectedRecipient);\n\n if (!transferDetails) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'No valid SOL transfer to recipient found',\n };\n }\n\n // SECURITY: Validate amount (must meet or exceed expected)\n if (transferDetails.amount < expectedAmount) {\n return {\n valid: false,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n error: 'Insufficient payment amount',\n };\n }\n\n return {\n valid: true,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n blockTime: transaction.blockTime ?? undefined,\n slot: transaction.slot,\n };\n } catch (error) {\n // SECURITY: Don't expose internal error details\n return {\n valid: false,\n confirmed: false,\n signature,\n error: 'Verification failed',\n };\n }\n}\n\n/**\n * Wait for transaction confirmation\n */\nexport async function waitForConfirmation(\n signature: string,\n clientConfig: SolanaClientConfig\n): Promise<{ confirmed: boolean; slot?: number; error?: string }> {\n if (!isValidSignature(signature)) {\n return { confirmed: false, error: 'Invalid signature format' };\n }\n\n const connection = getConnection(clientConfig);\n\n try {\n const confirmation = await connection.confirmTransaction(signature, 'confirmed');\n\n if (confirmation.value.err) {\n return { confirmed: false, error: 'Transaction failed' };\n }\n\n return { confirmed: true, slot: confirmation.context?.slot };\n } catch {\n return { confirmed: false, error: 'Confirmation timeout' };\n }\n}\n\n/**\n * Get recent transactions for a wallet\n */\nexport async function getWalletTransactions(\n walletAddress: string,\n clientConfig: SolanaClientConfig,\n limit: number = 20\n): Promise<Array<{ signature: string; blockTime?: number; slot: number }>> {\n if (!isValidWalletAddress(walletAddress)) {\n return [];\n }\n\n // SECURITY: Cap limit to prevent abuse\n const safeLimit = Math.min(Math.max(limit, 1), 100);\n\n const connection = getConnection(clientConfig);\n\n try {\n const pubkey = new PublicKey(walletAddress);\n const signatures = await connection.getSignaturesForAddress(pubkey, { limit: safeLimit });\n return signatures.map((sig) => ({\n signature: sig.signature,\n blockTime: sig.blockTime ?? undefined,\n slot: sig.slot,\n }));\n } catch {\n return [];\n }\n}\n\n/**\n * Convert lamports to SOL\n */\nexport function lamportsToSol(lamports: bigint | number): number {\n return Number(lamports) / LAMPORTS_PER_SOL;\n}\n\n/**\n * Convert SOL to lamports\n */\nexport function solToLamports(sol: number): bigint {\n if (!Number.isFinite(sol) || sol < 0) {\n throw new Error('Invalid SOL amount');\n }\n return BigInt(Math.floor(sol * LAMPORTS_PER_SOL));\n}\n","// x402 payment configuration and helpers\n// SECURITY: Input sanitization for payment requirements\nimport type { PaymentRequirement, X402Network, SolanaNetwork } from '../types';\nimport { toX402Network } from '../solana';\n\n// Wallet address validation regex\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/** Parameters for building a payment requirement */\nexport interface BuildPaymentParams {\n /** Unique article identifier */\n articleId: string;\n /** Article title for display */\n articleTitle: string;\n /** Price in lamports */\n priceInLamports: bigint;\n /** Creator wallet address */\n creatorWallet: string;\n /** Full URL of the protected resource */\n resourceUrl: string;\n /** Solana network */\n network: SolanaNetwork;\n /** Max time to complete payment (default: 300s) */\n maxTimeoutSeconds?: number;\n}\n\n/**\n * Sanitize string for safe display (prevent XSS in UIs)\n */\nfunction sanitizeDisplayString(str: string, maxLength: number = 200): string {\n if (!str || typeof str !== 'string') return '';\n return str.slice(0, maxLength).replace(/[<>\"'&]/g, '');\n}\n\n/**\n * Validate URL format\n */\nfunction isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/**\n * Build a payment requirement for an article\n * SECURITY: Validates all inputs before building requirement\n */\nexport function buildPaymentRequirement(params: BuildPaymentParams): PaymentRequirement {\n // Validate wallet address\n if (!WALLET_REGEX.test(params.creatorWallet)) {\n throw new Error('Invalid creator wallet address');\n }\n\n // Validate price\n if (params.priceInLamports <= 0n) {\n throw new Error('Price must be positive');\n }\n\n // Validate URL\n if (!isValidUrl(params.resourceUrl)) {\n throw new Error('Invalid resource URL');\n }\n\n // Validate network\n if (params.network !== 'devnet' && params.network !== 'mainnet-beta') {\n throw new Error('Invalid network');\n }\n\n // Validate timeout\n const timeout = params.maxTimeoutSeconds ?? 300;\n if (timeout < 60 || timeout > 3600) {\n throw new Error('Timeout must be between 60 and 3600 seconds');\n }\n\n const x402Network = toX402Network(params.network);\n\n // Sanitize display strings\n const safeTitle = sanitizeDisplayString(params.articleTitle, 200);\n const safeArticleId = sanitizeDisplayString(params.articleId, 128);\n\n return {\n scheme: 'exact',\n network: x402Network,\n maxAmountRequired: params.priceInLamports.toString(),\n resource: params.resourceUrl,\n description: `Unlock: ${safeTitle}`,\n mimeType: 'text/html',\n payTo: params.creatorWallet,\n maxTimeoutSeconds: timeout,\n asset: 'native',\n extra: {\n name: safeTitle,\n articleId: safeArticleId,\n },\n };\n}\n\n/**\n * Encode payment requirement for x402 header\n */\nexport function encodePaymentRequired(requirement: PaymentRequirement): string {\n return Buffer.from(JSON.stringify(requirement)).toString('base64');\n}\n\n/**\n * Decode payment requirement from x402 header\n * SECURITY: Safe parsing with size limit\n */\nexport function decodePaymentRequired(encoded: string): PaymentRequirement {\n if (!encoded || typeof encoded !== 'string') {\n throw new Error('Invalid encoded requirement');\n }\n\n // SECURITY: Limit size to prevent DoS\n if (encoded.length > 10000) {\n throw new Error('Encoded requirement too large');\n }\n\n try {\n const decoded = Buffer.from(encoded, 'base64').toString('utf-8');\n return JSON.parse(decoded);\n } catch {\n throw new Error('Failed to decode payment requirement');\n }\n}\n\n/**\n * x402 response header names\n */\nexport const X402_HEADERS = {\n PAYMENT_REQUIRED: 'X-Payment-Required',\n PAYMENT: 'X-Payment',\n PAYMENT_RESPONSE: 'X-Payment-Response',\n} as const;\n\n/**\n * Create 402 Payment Required response body\n */\nexport function create402ResponseBody(requirement: PaymentRequirement): {\n error: string;\n message: string;\n price: { amount: string; asset: string; network: X402Network };\n} {\n // Convert asset to string for JSON serialization\n const assetStr = typeof requirement.asset === 'string'\n ? requirement.asset\n : requirement.asset.mint;\n\n return {\n error: 'Payment Required',\n message: requirement.description,\n price: {\n amount: requirement.maxAmountRequired,\n asset: assetStr,\n network: requirement.network,\n },\n };\n}\n\n/**\n * Create headers for 402 response\n */\nexport function create402Headers(requirement: PaymentRequirement): Record<string, string> {\n const encoded = encodePaymentRequired(requirement);\n return {\n 'Content-Type': 'application/json',\n [X402_HEADERS.PAYMENT_REQUIRED]: encoded,\n 'Access-Control-Expose-Headers': X402_HEADERS.PAYMENT_REQUIRED,\n };\n}\n","// x402 payment verification service\n// SECURITY: Input validation, network verification, on-chain settlement check\nimport { verifyPayment, type SolanaClientConfig } from '../solana';\nimport type { PaymentPayload, PaymentRequirement, VerificationResponse } from '../types';\n\n// Signature validation regex (base58, 87-88 chars)\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\n\n/**\n * Verify a payment payload against requirements\n * SECURITY: Full validation chain - format, network, on-chain\n */\nexport async function verifyX402Payment(\n payload: PaymentPayload,\n requirement: PaymentRequirement,\n clientConfig: SolanaClientConfig\n): Promise<VerificationResponse> {\n // SECURITY: Validate payload exists\n if (!payload || typeof payload !== 'object') {\n return { valid: false, invalidReason: 'Invalid payload' };\n }\n\n // SECURITY: Validate signature exists and format\n const signature = payload.payload?.signature;\n if (!signature || typeof signature !== 'string') {\n return { valid: false, invalidReason: 'Missing transaction signature' };\n }\n if (!SIGNATURE_REGEX.test(signature)) {\n return { valid: false, invalidReason: 'Invalid signature format' };\n }\n\n // SECURITY: Validate x402 version\n if (payload.x402Version !== 1) {\n return { valid: false, invalidReason: 'Unsupported x402 version' };\n }\n\n // SECURITY: Validate scheme\n if (payload.scheme !== 'exact') {\n return { valid: false, invalidReason: 'Unsupported payment scheme' };\n }\n\n // SECURITY: Validate network matches exactly\n if (payload.network !== requirement.network) {\n return {\n valid: false,\n invalidReason: `Network mismatch: expected ${requirement.network}`,\n };\n }\n\n // SECURITY: Validate requirement has valid payTo address\n const walletRegex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n if (!walletRegex.test(requirement.payTo)) {\n return { valid: false, invalidReason: 'Invalid recipient configuration' };\n }\n\n // SECURITY: Validate amount is positive\n let expectedAmount: bigint;\n try {\n expectedAmount = BigInt(requirement.maxAmountRequired);\n if (expectedAmount <= 0n) {\n return { valid: false, invalidReason: 'Invalid payment amount' };\n }\n } catch {\n return { valid: false, invalidReason: 'Invalid payment amount format' };\n }\n\n // Verify on-chain\n const verification = await verifyPayment({\n signature,\n expectedRecipient: requirement.payTo,\n expectedAmount,\n maxAgeSeconds: requirement.maxTimeoutSeconds,\n clientConfig,\n });\n\n if (!verification.valid) {\n return {\n valid: false,\n invalidReason: verification.error || 'Transaction verification failed',\n };\n }\n\n return {\n valid: true,\n settled: verification.confirmed,\n transaction: {\n signature: verification.signature,\n blockTime: verification.blockTime,\n slot: verification.slot,\n },\n };\n}\n\n/**\n * Parse payment payload from x402 header\n * SECURITY: Safe JSON parsing with try-catch\n */\nexport function parsePaymentHeader(header: string): PaymentPayload | null {\n if (!header || typeof header !== 'string') {\n return null;\n }\n\n // SECURITY: Limit header size to prevent DoS\n if (header.length > 10000) {\n return null;\n }\n\n try {\n const decoded = Buffer.from(header, 'base64').toString('utf-8');\n const parsed = JSON.parse(decoded);\n\n // Basic structure validation\n if (!parsed || typeof parsed !== 'object') {\n return null;\n }\n\n return parsed as PaymentPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Encode payment response for header\n */\nexport function encodePaymentResponse(response: VerificationResponse): string {\n return Buffer.from(JSON.stringify(response)).toString('base64');\n}\n"]}