@alleyboss/micropay-solana-x402-paywall 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AlleyBoss
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # @alleyboss/micropay-solana-x402-paywall
2
+
3
+ > Solana micropayments library implementing the x402 protocol for content paywalls.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@alleyboss/micropay-solana-x402-paywall)](https://www.npmjs.com/package/@alleyboss/micropay-solana-x402-paywall)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - 🔐 **x402 Protocol** — HTTP 402 Payment Required standard
11
+ - ⚡ **Solana Native** — Fast, low-cost SOL micropayments
12
+ - 🔑 **JWT Sessions** — Secure unlock tracking
13
+ - 📦 **Framework Agnostic** — Works with Next.js, Express, or any Node.js project
14
+ - 🌳 **Tree-shakeable** — Import only what you need
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @alleyboss/micropay-solana-x402-paywall @solana/web3.js
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### 1. Verify a Payment
25
+
26
+ ```typescript
27
+ import { verifyPayment, type SolanaClientConfig } from '@alleyboss/micropay-solana-x402-paywall';
28
+
29
+ const clientConfig: SolanaClientConfig = {
30
+ network: 'devnet',
31
+ tatumApiKey: 'your-tatum-api-key', // Optional: for better RPC
32
+ };
33
+
34
+ const result = await verifyPayment({
35
+ signature: 'abc123...',
36
+ expectedRecipient: 'CreatorWalletAddress',
37
+ expectedAmount: BigInt(10000000), // 0.01 SOL
38
+ clientConfig,
39
+ });
40
+
41
+ if (result.valid) {
42
+ console.log('Payment verified!', result.from, 'paid', result.amount);
43
+ }
44
+ ```
45
+
46
+ ### 2. Create Session After Payment
47
+
48
+ ```typescript
49
+ import { createSession, validateSession } from '@alleyboss/micropay-solana-x402-paywall';
50
+
51
+ const sessionConfig = {
52
+ durationHours: 24,
53
+ secret: 'your-32-character-minimum-secret-key',
54
+ };
55
+
56
+ // After payment verification
57
+ const { token, session } = await createSession(
58
+ 'UserWalletAddress',
59
+ 'article-123',
60
+ sessionConfig
61
+ );
62
+
63
+ // Later, validate the session
64
+ const validation = await validateSession(token, sessionConfig.secret);
65
+ if (validation.valid) {
66
+ console.log('Session valid until', new Date(validation.session!.expiresAt * 1000));
67
+ }
68
+ ```
69
+
70
+ ### 3. Build x402 Payment Requirement
71
+
72
+ ```typescript
73
+ import { buildPaymentRequirement, create402Headers } from '@alleyboss/micropay-solana-x402-paywall';
74
+
75
+ const requirement = buildPaymentRequirement({
76
+ articleId: 'article-123',
77
+ articleTitle: 'Premium Article',
78
+ priceInLamports: BigInt(10000000),
79
+ creatorWallet: 'CreatorWalletAddress',
80
+ resourceUrl: 'https://example.com/article/123',
81
+ network: 'devnet',
82
+ });
83
+
84
+ // Use in HTTP response
85
+ const headers = create402Headers(requirement);
86
+ ```
87
+
88
+ ## API Reference
89
+
90
+ ### Solana Module
91
+
92
+ ```typescript
93
+ import {
94
+ getConnection,
95
+ verifyPayment,
96
+ waitForConfirmation,
97
+ lamportsToSol,
98
+ solToLamports
99
+ } from '@alleyboss/micropay-solana-x402-paywall/solana';
100
+ ```
101
+
102
+ | Function | Description |
103
+ |----------|-------------|
104
+ | `getConnection(config)` | Get/create Solana RPC connection |
105
+ | `verifyPayment(params)` | Verify on-chain SOL transfer |
106
+ | `waitForConfirmation(sig, config)` | Wait for transaction confirmation |
107
+ | `lamportsToSol(lamports)` | Convert lamports to SOL |
108
+ | `solToLamports(sol)` | Convert SOL to lamports |
109
+
110
+ ### Session Module
111
+
112
+ ```typescript
113
+ import {
114
+ createSession,
115
+ validateSession,
116
+ addArticleToSession,
117
+ isArticleUnlocked
118
+ } from '@alleyboss/micropay-solana-x402-paywall/session';
119
+ ```
120
+
121
+ | Function | Description |
122
+ |----------|-------------|
123
+ | `createSession(wallet, articleId, config)` | Create JWT session token |
124
+ | `validateSession(token, secret)` | Validate and decode session |
125
+ | `addArticleToSession(token, articleId, secret)` | Add article to existing session |
126
+ | `isArticleUnlocked(token, articleId, secret)` | Check if article is unlocked |
127
+
128
+ ### x402 Module
129
+
130
+ ```typescript
131
+ import {
132
+ buildPaymentRequirement,
133
+ verifyX402Payment,
134
+ parsePaymentHeader,
135
+ X402_HEADERS
136
+ } from '@alleyboss/micropay-solana-x402-paywall/x402';
137
+ ```
138
+
139
+ | Function | Description |
140
+ |----------|-------------|
141
+ | `buildPaymentRequirement(params)` | Build x402 payment requirement |
142
+ | `verifyX402Payment(payload, requirement, config)` | Verify x402 payment |
143
+ | `parsePaymentHeader(header)` | Parse base64 payment header |
144
+ | `encodePaymentRequired(requirement)` | Encode requirement for header |
145
+
146
+ ## Next.js Integration Example
147
+
148
+ ```typescript
149
+ // app/api/payment/verify/route.ts
150
+ import {
151
+ verifyX402Payment,
152
+ createSession,
153
+ parsePaymentHeader,
154
+ decodePaymentRequired
155
+ } from '@alleyboss/micropay-solana-x402-paywall';
156
+ import { cookies } from 'next/headers';
157
+
158
+ export async function POST(request: Request) {
159
+ const { signature, articleId } = await request.json();
160
+
161
+ const clientConfig = {
162
+ network: process.env.SOLANA_NETWORK as 'devnet' | 'mainnet-beta',
163
+ tatumApiKey: process.env.TATUM_API_KEY,
164
+ };
165
+
166
+ const sessionConfig = {
167
+ durationHours: 24,
168
+ secret: process.env.SESSION_SECRET!,
169
+ };
170
+
171
+ // Build requirement for the article
172
+ const requirement = buildPaymentRequirement({
173
+ articleId,
174
+ articleTitle: 'Article Title',
175
+ priceInLamports: BigInt(process.env.ARTICLE_PRICE || '10000000'),
176
+ creatorWallet: process.env.CREATOR_WALLET!,
177
+ resourceUrl: `${process.env.SITE_URL}/article/${articleId}`,
178
+ network: clientConfig.network,
179
+ });
180
+
181
+ // Verify payment
182
+ const payload = {
183
+ x402Version: 1,
184
+ scheme: 'exact' as const,
185
+ network: requirement.network,
186
+ payload: { signature },
187
+ };
188
+
189
+ const result = await verifyX402Payment(payload, requirement, clientConfig);
190
+
191
+ if (!result.valid) {
192
+ return Response.json({ error: result.invalidReason }, { status: 400 });
193
+ }
194
+
195
+ // Create session
196
+ const { token } = await createSession(
197
+ result.transaction!.signature,
198
+ articleId,
199
+ sessionConfig
200
+ );
201
+
202
+ // Set cookie
203
+ const cookieStore = await cookies();
204
+ cookieStore.set('x402_session', token, {
205
+ httpOnly: true,
206
+ secure: process.env.NODE_ENV === 'production',
207
+ sameSite: 'strict',
208
+ maxAge: sessionConfig.durationHours * 3600,
209
+ });
210
+
211
+ return Response.json({ success: true });
212
+ }
213
+ ```
214
+
215
+ ## TypeScript Support
216
+
217
+ Full TypeScript support with exported types:
218
+
219
+ ```typescript
220
+ import type {
221
+ PaymentRequirement,
222
+ PaymentPayload,
223
+ VerificationResponse,
224
+ SessionData,
225
+ SessionConfig,
226
+ SolanaClientConfig,
227
+ } from '@alleyboss/micropay-solana-x402-paywall';
228
+ ```
229
+
230
+ ## License
231
+
232
+ MIT © AlleyBoss
@@ -0,0 +1,112 @@
1
+ import { Connection } from '@solana/web3.js';
2
+
3
+ /** x402 network identifiers for Solana */
4
+ type X402Network = 'solana-devnet' | 'solana-mainnet';
5
+ /** Solana network types */
6
+ type SolanaNetwork = 'devnet' | 'mainnet-beta';
7
+ /** Payment requirement for x402 protocol */
8
+ interface PaymentRequirement {
9
+ /** Payment scheme - currently only 'exact' is supported */
10
+ scheme: 'exact';
11
+ /** Network identifier for x402 */
12
+ network: X402Network;
13
+ /** Amount in lamports as string (for JSON serialization) */
14
+ maxAmountRequired: string;
15
+ /** URL of the protected resource */
16
+ resource: string;
17
+ /** Human-readable description */
18
+ description: string;
19
+ /** MIME type of the resource */
20
+ mimeType?: string;
21
+ /** Recipient wallet address */
22
+ payTo: string;
23
+ /** Maximum time in seconds to complete payment */
24
+ maxTimeoutSeconds: number;
25
+ /** Asset type - 'native' for SOL */
26
+ asset: string;
27
+ /** Additional metadata */
28
+ extra?: {
29
+ name?: string;
30
+ [key: string]: unknown;
31
+ };
32
+ }
33
+ /** Payment payload sent by client after transaction */
34
+ interface PaymentPayload {
35
+ /** x402 protocol version */
36
+ x402Version: number;
37
+ /** Payment scheme */
38
+ scheme: 'exact';
39
+ /** Network identifier */
40
+ network: X402Network;
41
+ /** Transaction details */
42
+ payload: {
43
+ /** Transaction signature (base58) */
44
+ signature: string;
45
+ /** Base64 encoded transaction (optional) */
46
+ transaction?: string;
47
+ };
48
+ }
49
+ /** Request to verify a payment */
50
+ interface VerificationRequest {
51
+ paymentPayload: PaymentPayload;
52
+ paymentRequirements: PaymentRequirement;
53
+ }
54
+ /** Response from payment verification */
55
+ interface VerificationResponse {
56
+ /** Whether the payment is valid */
57
+ valid: boolean;
58
+ /** Reason for invalid payment */
59
+ invalidReason?: string;
60
+ /** Whether the transaction is settled on-chain */
61
+ settled?: boolean;
62
+ /** Transaction details */
63
+ transaction?: {
64
+ signature: string;
65
+ blockTime?: number;
66
+ slot?: number;
67
+ };
68
+ }
69
+ /** Payment status for tracking */
70
+ interface PaymentStatus {
71
+ status: 'pending' | 'confirmed' | 'failed' | 'expired';
72
+ signature?: string;
73
+ confirmations?: number;
74
+ error?: string;
75
+ }
76
+ /** Configuration for article pricing */
77
+ interface ArticlePaymentConfig {
78
+ articleId: string;
79
+ priceInLamports: bigint;
80
+ title: string;
81
+ description?: string;
82
+ }
83
+
84
+ /** Configuration for Solana client */
85
+ interface SolanaClientConfig {
86
+ /** Network to connect to */
87
+ network: SolanaNetwork;
88
+ /** Custom RPC URL (optional) */
89
+ rpcUrl?: string;
90
+ /** Tatum.io API key for RPC (optional) */
91
+ tatumApiKey?: string;
92
+ }
93
+ /**
94
+ * Get or create a Solana connection
95
+ * Uses singleton pattern with network-aware caching
96
+ */
97
+ declare function getConnection(config: SolanaClientConfig): Connection;
98
+ /**
99
+ * Reset the cached connection
100
+ * Useful for testing or network switching
101
+ */
102
+ declare function resetConnection(): void;
103
+ /**
104
+ * Check if network is mainnet
105
+ */
106
+ declare function isMainnet(network: SolanaNetwork): boolean;
107
+ /**
108
+ * Convert Solana network to x402 network identifier
109
+ */
110
+ declare function toX402Network(network: SolanaNetwork): 'solana-devnet' | 'solana-mainnet';
111
+
112
+ export { type ArticlePaymentConfig as A, type PaymentRequirement as P, type SolanaNetwork as S, type VerificationRequest as V, type X402Network as X, type PaymentPayload as a, type VerificationResponse as b, type PaymentStatus as c, type SolanaClientConfig as d, getConnection as g, isMainnet as i, resetConnection as r, toX402Network as t };
@@ -0,0 +1,112 @@
1
+ import { Connection } from '@solana/web3.js';
2
+
3
+ /** x402 network identifiers for Solana */
4
+ type X402Network = 'solana-devnet' | 'solana-mainnet';
5
+ /** Solana network types */
6
+ type SolanaNetwork = 'devnet' | 'mainnet-beta';
7
+ /** Payment requirement for x402 protocol */
8
+ interface PaymentRequirement {
9
+ /** Payment scheme - currently only 'exact' is supported */
10
+ scheme: 'exact';
11
+ /** Network identifier for x402 */
12
+ network: X402Network;
13
+ /** Amount in lamports as string (for JSON serialization) */
14
+ maxAmountRequired: string;
15
+ /** URL of the protected resource */
16
+ resource: string;
17
+ /** Human-readable description */
18
+ description: string;
19
+ /** MIME type of the resource */
20
+ mimeType?: string;
21
+ /** Recipient wallet address */
22
+ payTo: string;
23
+ /** Maximum time in seconds to complete payment */
24
+ maxTimeoutSeconds: number;
25
+ /** Asset type - 'native' for SOL */
26
+ asset: string;
27
+ /** Additional metadata */
28
+ extra?: {
29
+ name?: string;
30
+ [key: string]: unknown;
31
+ };
32
+ }
33
+ /** Payment payload sent by client after transaction */
34
+ interface PaymentPayload {
35
+ /** x402 protocol version */
36
+ x402Version: number;
37
+ /** Payment scheme */
38
+ scheme: 'exact';
39
+ /** Network identifier */
40
+ network: X402Network;
41
+ /** Transaction details */
42
+ payload: {
43
+ /** Transaction signature (base58) */
44
+ signature: string;
45
+ /** Base64 encoded transaction (optional) */
46
+ transaction?: string;
47
+ };
48
+ }
49
+ /** Request to verify a payment */
50
+ interface VerificationRequest {
51
+ paymentPayload: PaymentPayload;
52
+ paymentRequirements: PaymentRequirement;
53
+ }
54
+ /** Response from payment verification */
55
+ interface VerificationResponse {
56
+ /** Whether the payment is valid */
57
+ valid: boolean;
58
+ /** Reason for invalid payment */
59
+ invalidReason?: string;
60
+ /** Whether the transaction is settled on-chain */
61
+ settled?: boolean;
62
+ /** Transaction details */
63
+ transaction?: {
64
+ signature: string;
65
+ blockTime?: number;
66
+ slot?: number;
67
+ };
68
+ }
69
+ /** Payment status for tracking */
70
+ interface PaymentStatus {
71
+ status: 'pending' | 'confirmed' | 'failed' | 'expired';
72
+ signature?: string;
73
+ confirmations?: number;
74
+ error?: string;
75
+ }
76
+ /** Configuration for article pricing */
77
+ interface ArticlePaymentConfig {
78
+ articleId: string;
79
+ priceInLamports: bigint;
80
+ title: string;
81
+ description?: string;
82
+ }
83
+
84
+ /** Configuration for Solana client */
85
+ interface SolanaClientConfig {
86
+ /** Network to connect to */
87
+ network: SolanaNetwork;
88
+ /** Custom RPC URL (optional) */
89
+ rpcUrl?: string;
90
+ /** Tatum.io API key for RPC (optional) */
91
+ tatumApiKey?: string;
92
+ }
93
+ /**
94
+ * Get or create a Solana connection
95
+ * Uses singleton pattern with network-aware caching
96
+ */
97
+ declare function getConnection(config: SolanaClientConfig): Connection;
98
+ /**
99
+ * Reset the cached connection
100
+ * Useful for testing or network switching
101
+ */
102
+ declare function resetConnection(): void;
103
+ /**
104
+ * Check if network is mainnet
105
+ */
106
+ declare function isMainnet(network: SolanaNetwork): boolean;
107
+ /**
108
+ * Convert Solana network to x402 network identifier
109
+ */
110
+ declare function toX402Network(network: SolanaNetwork): 'solana-devnet' | 'solana-mainnet';
111
+
112
+ export { type ArticlePaymentConfig as A, type PaymentRequirement as P, type SolanaNetwork as S, type VerificationRequest as V, type X402Network as X, type PaymentPayload as a, type VerificationResponse as b, type PaymentStatus as c, type SolanaClientConfig as d, getConnection as g, isMainnet as i, resetConnection as r, toX402Network as t };
@@ -0,0 +1,71 @@
1
+ /** Session data stored in JWT */
2
+ interface SessionData {
3
+ /** Unique session ID */
4
+ id: string;
5
+ /** Wallet address that paid */
6
+ walletAddress: string;
7
+ /** Array of unlocked article IDs */
8
+ unlockedArticles: string[];
9
+ /** Whether site-wide access is granted */
10
+ siteWideUnlock: boolean;
11
+ /** Unix timestamp of creation */
12
+ createdAt: number;
13
+ /** Unix timestamp of expiration */
14
+ expiresAt: number;
15
+ }
16
+ /** Session configuration options */
17
+ interface SessionConfig {
18
+ /** Session duration in hours */
19
+ durationHours: number;
20
+ /** Secret key for JWT signing (min 32 chars) */
21
+ secret: string;
22
+ }
23
+ /** Result of session validation */
24
+ interface SessionValidation {
25
+ /** Whether the session is valid */
26
+ valid: boolean;
27
+ /** Parsed session data if valid */
28
+ session?: SessionData;
29
+ /** Reason for invalid session */
30
+ reason?: string;
31
+ }
32
+ /** JWT payload structure for sessions */
33
+ interface SessionJWTPayload {
34
+ /** Wallet address (subject) */
35
+ sub: string;
36
+ /** Session ID */
37
+ sid: string;
38
+ /** Unlocked article IDs */
39
+ articles: string[];
40
+ /** Site-wide unlock flag */
41
+ siteWide: boolean;
42
+ /** Issued at timestamp */
43
+ iat: number;
44
+ /** Expiration timestamp */
45
+ exp: number;
46
+ }
47
+
48
+ /**
49
+ * Create a new session after successful payment
50
+ */
51
+ declare function createSession(walletAddress: string, articleId: string, config: SessionConfig, siteWide?: boolean): Promise<{
52
+ token: string;
53
+ session: SessionData;
54
+ }>;
55
+ /**
56
+ * Validate an existing session token
57
+ */
58
+ declare function validateSession(token: string, secret: string): Promise<SessionValidation>;
59
+ /**
60
+ * Add an article to an existing session
61
+ */
62
+ declare function addArticleToSession(token: string, articleId: string, secret: string): Promise<{
63
+ token: string;
64
+ session: SessionData;
65
+ } | null>;
66
+ /**
67
+ * Check if an article is unlocked for a session
68
+ */
69
+ declare function isArticleUnlocked(token: string, articleId: string, secret: string): Promise<boolean>;
70
+
71
+ export { type SessionData as S, type SessionConfig as a, type SessionValidation as b, type SessionJWTPayload as c, createSession as d, addArticleToSession as e, isArticleUnlocked as i, validateSession as v };
@@ -0,0 +1,71 @@
1
+ /** Session data stored in JWT */
2
+ interface SessionData {
3
+ /** Unique session ID */
4
+ id: string;
5
+ /** Wallet address that paid */
6
+ walletAddress: string;
7
+ /** Array of unlocked article IDs */
8
+ unlockedArticles: string[];
9
+ /** Whether site-wide access is granted */
10
+ siteWideUnlock: boolean;
11
+ /** Unix timestamp of creation */
12
+ createdAt: number;
13
+ /** Unix timestamp of expiration */
14
+ expiresAt: number;
15
+ }
16
+ /** Session configuration options */
17
+ interface SessionConfig {
18
+ /** Session duration in hours */
19
+ durationHours: number;
20
+ /** Secret key for JWT signing (min 32 chars) */
21
+ secret: string;
22
+ }
23
+ /** Result of session validation */
24
+ interface SessionValidation {
25
+ /** Whether the session is valid */
26
+ valid: boolean;
27
+ /** Parsed session data if valid */
28
+ session?: SessionData;
29
+ /** Reason for invalid session */
30
+ reason?: string;
31
+ }
32
+ /** JWT payload structure for sessions */
33
+ interface SessionJWTPayload {
34
+ /** Wallet address (subject) */
35
+ sub: string;
36
+ /** Session ID */
37
+ sid: string;
38
+ /** Unlocked article IDs */
39
+ articles: string[];
40
+ /** Site-wide unlock flag */
41
+ siteWide: boolean;
42
+ /** Issued at timestamp */
43
+ iat: number;
44
+ /** Expiration timestamp */
45
+ exp: number;
46
+ }
47
+
48
+ /**
49
+ * Create a new session after successful payment
50
+ */
51
+ declare function createSession(walletAddress: string, articleId: string, config: SessionConfig, siteWide?: boolean): Promise<{
52
+ token: string;
53
+ session: SessionData;
54
+ }>;
55
+ /**
56
+ * Validate an existing session token
57
+ */
58
+ declare function validateSession(token: string, secret: string): Promise<SessionValidation>;
59
+ /**
60
+ * Add an article to an existing session
61
+ */
62
+ declare function addArticleToSession(token: string, articleId: string, secret: string): Promise<{
63
+ token: string;
64
+ session: SessionData;
65
+ } | null>;
66
+ /**
67
+ * Check if an article is unlocked for a session
68
+ */
69
+ declare function isArticleUnlocked(token: string, articleId: string, secret: string): Promise<boolean>;
70
+
71
+ export { type SessionData as S, type SessionConfig as a, type SessionValidation as b, type SessionJWTPayload as c, createSession as d, addArticleToSession as e, isArticleUnlocked as i, validateSession as v };