@alleyboss/micropay-solana-x402-paywall 3.2.2 → 3.3.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/README.md +30 -0
- package/dist/agent/index.cjs +2 -2
- package/dist/agent/index.d.cts +1 -1
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +2 -2
- package/dist/client/index.cjs +220 -0
- package/dist/client/index.d.cts +101 -1
- package/dist/client/index.d.ts +101 -1
- package/dist/client/index.js +218 -2
- package/dist/index.cjs +278 -154
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +276 -156
- package/dist/next/index.cjs +58 -23
- package/dist/next/index.js +58 -23
- package/dist/pricing/index.cjs +54 -38
- package/dist/pricing/index.d.cts +8 -9
- package/dist/pricing/index.d.ts +8 -9
- package/dist/pricing/index.js +54 -38
- package/package.json +1 -1
package/dist/next/index.js
CHANGED
|
@@ -68,6 +68,10 @@ var LocalSvmFacilitator = class {
|
|
|
68
68
|
getSigners(_network) {
|
|
69
69
|
return [];
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Enable debug logging (disable in production)
|
|
73
|
+
*/
|
|
74
|
+
debug = process.env.NODE_ENV === "development";
|
|
71
75
|
/**
|
|
72
76
|
* Verify a payment on-chain
|
|
73
77
|
*/
|
|
@@ -80,57 +84,89 @@ var LocalSvmFacilitator = class {
|
|
|
80
84
|
const payTo = requirements.payTo;
|
|
81
85
|
const amountVal = requirements.amount || requirements.maxAmountRequired || "0";
|
|
82
86
|
const requiredAmount = BigInt(amountVal);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const tx = await this.
|
|
87
|
-
maxSupportedTransactionVersion: 0,
|
|
88
|
-
commitment: "confirmed"
|
|
89
|
-
});
|
|
87
|
+
if (this.debug) {
|
|
88
|
+
console.log(`[LocalSvmFacilitator] Verifying tx: ${signature.slice(0, 8)}...`);
|
|
89
|
+
}
|
|
90
|
+
const tx = await this.fetchTransactionWithRetry(signature, 3);
|
|
90
91
|
if (!tx) {
|
|
91
|
-
console.error("[LocalSvmFacilitator] Transaction not found or not confirmed");
|
|
92
92
|
return { isValid: false, invalidReason: "Transaction not found or not confirmed" };
|
|
93
93
|
}
|
|
94
|
-
console.log("[LocalSvmFacilitator] Transaction found. Parsing instructions...");
|
|
95
94
|
const instructions = tx.transaction.message.instructions;
|
|
96
95
|
let paidAmount = 0n;
|
|
97
96
|
let payer = void 0;
|
|
98
97
|
for (const ix of instructions) {
|
|
99
98
|
if ("program" in ix && ix.program === "system") {
|
|
100
99
|
const parsed = ix.parsed;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
if (parsed?.type === "transfer" && parsed.info?.destination === payTo) {
|
|
101
|
+
paidAmount += BigInt(parsed.info.lamports);
|
|
102
|
+
if (!payer) payer = parsed.info.source;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if ("program" in ix && (ix.program === "spl-token" || ix.program === "spl-token-2022")) {
|
|
106
|
+
const parsed = ix.parsed;
|
|
107
|
+
if (parsed?.type === "transferChecked" || parsed?.type === "transfer") {
|
|
108
|
+
if (this.debug) {
|
|
109
|
+
console.log(`[LocalSvmFacilitator] Found SPL transfer`);
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
|
-
console.log(`[LocalSvmFacilitator] Total Paid Correctly: ${paidAmount}`);
|
|
113
114
|
if (paidAmount >= requiredAmount) {
|
|
114
|
-
|
|
115
|
+
if (this.debug) {
|
|
116
|
+
console.log(`[LocalSvmFacilitator] Verification SUCCESS for tx: ${signature.slice(0, 8)}...`);
|
|
117
|
+
}
|
|
115
118
|
return {
|
|
116
119
|
isValid: true,
|
|
117
120
|
payer: payer || tx.transaction.message.accountKeys[0].pubkey.toBase58()
|
|
118
121
|
};
|
|
119
122
|
}
|
|
120
|
-
console.error(`[LocalSvmFacilitator] Verification FAILED. Paid: ${paidAmount}, Required: ${requiredAmount}`);
|
|
121
123
|
return {
|
|
122
124
|
isValid: false,
|
|
123
|
-
invalidReason:
|
|
125
|
+
invalidReason: "Insufficient payment amount",
|
|
124
126
|
payer
|
|
125
127
|
};
|
|
126
128
|
} catch (error) {
|
|
127
|
-
|
|
129
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
130
|
+
if (this.debug) {
|
|
131
|
+
console.error("[LocalSvmFacilitator] Verify error:", errorMessage);
|
|
132
|
+
}
|
|
128
133
|
throw new VerifyError(500, {
|
|
129
134
|
isValid: false,
|
|
130
|
-
invalidReason:
|
|
135
|
+
invalidReason: errorMessage
|
|
131
136
|
});
|
|
132
137
|
}
|
|
133
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Fetch transaction with exponential backoff retry
|
|
141
|
+
*/
|
|
142
|
+
async fetchTransactionWithRetry(signature, maxRetries = 3) {
|
|
143
|
+
let lastError;
|
|
144
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
145
|
+
try {
|
|
146
|
+
const tx = await this.connection.getParsedTransaction(signature, {
|
|
147
|
+
maxSupportedTransactionVersion: 0,
|
|
148
|
+
commitment: "confirmed"
|
|
149
|
+
});
|
|
150
|
+
if (tx) return tx;
|
|
151
|
+
if (attempt < maxRetries - 1) {
|
|
152
|
+
await this.sleep(Math.pow(2, attempt) * 1e3);
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
lastError = error instanceof Error ? error : new Error("RPC error");
|
|
156
|
+
if (attempt < maxRetries - 1) {
|
|
157
|
+
await this.sleep(Math.pow(2, attempt) * 1e3);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (lastError) throw lastError;
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Sleep helper
|
|
166
|
+
*/
|
|
167
|
+
sleep(ms) {
|
|
168
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
169
|
+
}
|
|
134
170
|
/**
|
|
135
171
|
* Settle a payment (not applicable for direct chain verification, usually)
|
|
136
172
|
* But we must implement it. For 'exact', settlement is just verification + finality.
|
|
@@ -176,7 +212,6 @@ function createX402Middleware(config) {
|
|
|
176
212
|
network: config.network === "mainnet-beta" ? "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" : "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
|
|
177
213
|
}
|
|
178
214
|
};
|
|
179
|
-
console.log("[createX402Middleware] Final Config:", JSON.stringify(finalConfig));
|
|
180
215
|
return withX402$1(handler, finalConfig, server);
|
|
181
216
|
};
|
|
182
217
|
}
|
package/dist/pricing/index.cjs
CHANGED
|
@@ -6,12 +6,10 @@ function lamportsToSol(lamports) {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
// src/pricing/index.ts
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var lastProviderIndex = -1;
|
|
9
|
+
var priceCache = null;
|
|
10
|
+
var currentConfig = {};
|
|
12
11
|
function configurePricing(newConfig) {
|
|
13
|
-
|
|
14
|
-
cachedPrice = null;
|
|
12
|
+
currentConfig = { ...currentConfig, ...newConfig };
|
|
15
13
|
}
|
|
16
14
|
var PROVIDERS = [
|
|
17
15
|
{
|
|
@@ -51,56 +49,75 @@ async function fetchFromProvider(provider, timeout) {
|
|
|
51
49
|
if (!price || price <= 0) {
|
|
52
50
|
throw new Error("Invalid price");
|
|
53
51
|
}
|
|
54
|
-
return price;
|
|
52
|
+
return { price, source: provider.name };
|
|
55
53
|
} finally {
|
|
56
54
|
clearTimeout(timeoutId);
|
|
57
55
|
}
|
|
58
56
|
}
|
|
57
|
+
async function fetchPriceParallel(timeout) {
|
|
58
|
+
const promises = PROVIDERS.map(
|
|
59
|
+
(provider) => fetchFromProvider(provider, timeout).catch(() => null)
|
|
60
|
+
);
|
|
61
|
+
const results = await Promise.all(promises);
|
|
62
|
+
const validResult = results.find((r) => r !== null);
|
|
63
|
+
if (validResult) {
|
|
64
|
+
return validResult;
|
|
65
|
+
}
|
|
66
|
+
throw new Error("All providers failed");
|
|
67
|
+
}
|
|
68
|
+
async function fetchPriceSequential(timeout) {
|
|
69
|
+
for (const provider of PROVIDERS) {
|
|
70
|
+
try {
|
|
71
|
+
return await fetchFromProvider(provider, timeout);
|
|
72
|
+
} catch {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
throw new Error("All providers failed");
|
|
77
|
+
}
|
|
59
78
|
async function getSolPrice() {
|
|
60
|
-
const cacheTTL =
|
|
61
|
-
const timeout =
|
|
62
|
-
|
|
63
|
-
|
|
79
|
+
const cacheTTL = currentConfig.cacheTTL ?? 6e4;
|
|
80
|
+
const timeout = currentConfig.timeout ?? 3e3;
|
|
81
|
+
const useParallel = currentConfig.parallelFetch ?? true;
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
if (priceCache && now - priceCache.timestamp < cacheTTL) {
|
|
84
|
+
return priceCache.data;
|
|
64
85
|
}
|
|
65
|
-
if (
|
|
86
|
+
if (currentConfig.customProvider) {
|
|
66
87
|
try {
|
|
67
|
-
const price = await
|
|
88
|
+
const price = await currentConfig.customProvider();
|
|
68
89
|
if (price > 0) {
|
|
69
|
-
|
|
90
|
+
const data = {
|
|
70
91
|
solPrice: price,
|
|
71
92
|
fetchedAt: /* @__PURE__ */ new Date(),
|
|
72
93
|
source: "custom"
|
|
73
94
|
};
|
|
74
|
-
|
|
95
|
+
priceCache = { data, timestamp: now };
|
|
96
|
+
return data;
|
|
75
97
|
}
|
|
76
98
|
} catch {
|
|
77
99
|
}
|
|
78
100
|
}
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
101
|
+
try {
|
|
102
|
+
const result = useParallel ? await fetchPriceParallel(timeout) : await fetchPriceSequential(timeout);
|
|
103
|
+
const data = {
|
|
104
|
+
solPrice: result.price,
|
|
105
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
106
|
+
source: result.source
|
|
107
|
+
};
|
|
108
|
+
priceCache = { data, timestamp: now };
|
|
109
|
+
return data;
|
|
110
|
+
} catch {
|
|
111
|
+
if (priceCache) {
|
|
112
|
+
return {
|
|
113
|
+
...priceCache.data,
|
|
114
|
+
source: `${priceCache.data.source} (stale)`
|
|
89
115
|
};
|
|
90
|
-
return cachedPrice;
|
|
91
|
-
} catch {
|
|
92
|
-
continue;
|
|
93
116
|
}
|
|
117
|
+
throw new Error(
|
|
118
|
+
"Failed to fetch SOL price from all providers. Configure a custom provider or ensure network connectivity."
|
|
119
|
+
);
|
|
94
120
|
}
|
|
95
|
-
if (cachedPrice) {
|
|
96
|
-
return {
|
|
97
|
-
...cachedPrice,
|
|
98
|
-
source: `${cachedPrice.source} (stale)`
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
throw new Error(
|
|
102
|
-
"Failed to fetch SOL price from all providers. Configure a custom provider or ensure network connectivity."
|
|
103
|
-
);
|
|
104
121
|
}
|
|
105
122
|
async function lamportsToUsd(lamports) {
|
|
106
123
|
const { solPrice } = await getSolPrice();
|
|
@@ -128,8 +145,7 @@ function formatPriceSync(lamports, solPrice) {
|
|
|
128
145
|
};
|
|
129
146
|
}
|
|
130
147
|
function clearPriceCache() {
|
|
131
|
-
|
|
132
|
-
lastProviderIndex = -1;
|
|
148
|
+
priceCache = null;
|
|
133
149
|
}
|
|
134
150
|
function getProviders() {
|
|
135
151
|
return PROVIDERS.map((p) => ({ name: p.name, url: p.url }));
|
package/dist/pricing/index.d.cts
CHANGED
|
@@ -23,8 +23,10 @@ interface PriceConfig {
|
|
|
23
23
|
customProvider?: CustomPriceProvider;
|
|
24
24
|
/** Cache TTL in milliseconds (default: 60000) */
|
|
25
25
|
cacheTTL?: number;
|
|
26
|
-
/** Request timeout in milliseconds (default:
|
|
26
|
+
/** Request timeout in milliseconds (default: 3000) */
|
|
27
27
|
timeout?: number;
|
|
28
|
+
/** Use parallel fetching (default: true, faster but more network calls) */
|
|
29
|
+
parallelFetch?: boolean;
|
|
28
30
|
}
|
|
29
31
|
/**
|
|
30
32
|
* Configure price fetching
|
|
@@ -39,19 +41,16 @@ interface PriceConfig {
|
|
|
39
41
|
* },
|
|
40
42
|
* });
|
|
41
43
|
*
|
|
42
|
-
* // Or
|
|
43
|
-
* configurePricing({ cacheTTL: 30000 });
|
|
44
|
+
* // Or adjust settings
|
|
45
|
+
* configurePricing({ cacheTTL: 30000, parallelFetch: true });
|
|
44
46
|
* ```
|
|
45
47
|
*/
|
|
46
48
|
declare function configurePricing(newConfig: PriceConfig): void;
|
|
47
49
|
/**
|
|
48
|
-
* Get SOL price with multi-provider
|
|
50
|
+
* Get SOL price with multi-provider support
|
|
49
51
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* 2. Binance (backup #1)
|
|
53
|
-
* 3. CoinGecko (backup #2)
|
|
54
|
-
* 4. Kraken (backup #3)
|
|
52
|
+
* Default behavior: Parallel fetch (all providers race, fastest wins)
|
|
53
|
+
* This is faster and more reliable in serverless environments.
|
|
55
54
|
*
|
|
56
55
|
* @example
|
|
57
56
|
* ```typescript
|
package/dist/pricing/index.d.ts
CHANGED
|
@@ -23,8 +23,10 @@ interface PriceConfig {
|
|
|
23
23
|
customProvider?: CustomPriceProvider;
|
|
24
24
|
/** Cache TTL in milliseconds (default: 60000) */
|
|
25
25
|
cacheTTL?: number;
|
|
26
|
-
/** Request timeout in milliseconds (default:
|
|
26
|
+
/** Request timeout in milliseconds (default: 3000) */
|
|
27
27
|
timeout?: number;
|
|
28
|
+
/** Use parallel fetching (default: true, faster but more network calls) */
|
|
29
|
+
parallelFetch?: boolean;
|
|
28
30
|
}
|
|
29
31
|
/**
|
|
30
32
|
* Configure price fetching
|
|
@@ -39,19 +41,16 @@ interface PriceConfig {
|
|
|
39
41
|
* },
|
|
40
42
|
* });
|
|
41
43
|
*
|
|
42
|
-
* // Or
|
|
43
|
-
* configurePricing({ cacheTTL: 30000 });
|
|
44
|
+
* // Or adjust settings
|
|
45
|
+
* configurePricing({ cacheTTL: 30000, parallelFetch: true });
|
|
44
46
|
* ```
|
|
45
47
|
*/
|
|
46
48
|
declare function configurePricing(newConfig: PriceConfig): void;
|
|
47
49
|
/**
|
|
48
|
-
* Get SOL price with multi-provider
|
|
50
|
+
* Get SOL price with multi-provider support
|
|
49
51
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* 2. Binance (backup #1)
|
|
53
|
-
* 3. CoinGecko (backup #2)
|
|
54
|
-
* 4. Kraken (backup #3)
|
|
52
|
+
* Default behavior: Parallel fetch (all providers race, fastest wins)
|
|
53
|
+
* This is faster and more reliable in serverless environments.
|
|
55
54
|
*
|
|
56
55
|
* @example
|
|
57
56
|
* ```typescript
|
package/dist/pricing/index.js
CHANGED
|
@@ -4,12 +4,10 @@ function lamportsToSol(lamports) {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
// src/pricing/index.ts
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var lastProviderIndex = -1;
|
|
7
|
+
var priceCache = null;
|
|
8
|
+
var currentConfig = {};
|
|
10
9
|
function configurePricing(newConfig) {
|
|
11
|
-
|
|
12
|
-
cachedPrice = null;
|
|
10
|
+
currentConfig = { ...currentConfig, ...newConfig };
|
|
13
11
|
}
|
|
14
12
|
var PROVIDERS = [
|
|
15
13
|
{
|
|
@@ -49,56 +47,75 @@ async function fetchFromProvider(provider, timeout) {
|
|
|
49
47
|
if (!price || price <= 0) {
|
|
50
48
|
throw new Error("Invalid price");
|
|
51
49
|
}
|
|
52
|
-
return price;
|
|
50
|
+
return { price, source: provider.name };
|
|
53
51
|
} finally {
|
|
54
52
|
clearTimeout(timeoutId);
|
|
55
53
|
}
|
|
56
54
|
}
|
|
55
|
+
async function fetchPriceParallel(timeout) {
|
|
56
|
+
const promises = PROVIDERS.map(
|
|
57
|
+
(provider) => fetchFromProvider(provider, timeout).catch(() => null)
|
|
58
|
+
);
|
|
59
|
+
const results = await Promise.all(promises);
|
|
60
|
+
const validResult = results.find((r) => r !== null);
|
|
61
|
+
if (validResult) {
|
|
62
|
+
return validResult;
|
|
63
|
+
}
|
|
64
|
+
throw new Error("All providers failed");
|
|
65
|
+
}
|
|
66
|
+
async function fetchPriceSequential(timeout) {
|
|
67
|
+
for (const provider of PROVIDERS) {
|
|
68
|
+
try {
|
|
69
|
+
return await fetchFromProvider(provider, timeout);
|
|
70
|
+
} catch {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
throw new Error("All providers failed");
|
|
75
|
+
}
|
|
57
76
|
async function getSolPrice() {
|
|
58
|
-
const cacheTTL =
|
|
59
|
-
const timeout =
|
|
60
|
-
|
|
61
|
-
|
|
77
|
+
const cacheTTL = currentConfig.cacheTTL ?? 6e4;
|
|
78
|
+
const timeout = currentConfig.timeout ?? 3e3;
|
|
79
|
+
const useParallel = currentConfig.parallelFetch ?? true;
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
if (priceCache && now - priceCache.timestamp < cacheTTL) {
|
|
82
|
+
return priceCache.data;
|
|
62
83
|
}
|
|
63
|
-
if (
|
|
84
|
+
if (currentConfig.customProvider) {
|
|
64
85
|
try {
|
|
65
|
-
const price = await
|
|
86
|
+
const price = await currentConfig.customProvider();
|
|
66
87
|
if (price > 0) {
|
|
67
|
-
|
|
88
|
+
const data = {
|
|
68
89
|
solPrice: price,
|
|
69
90
|
fetchedAt: /* @__PURE__ */ new Date(),
|
|
70
91
|
source: "custom"
|
|
71
92
|
};
|
|
72
|
-
|
|
93
|
+
priceCache = { data, timestamp: now };
|
|
94
|
+
return data;
|
|
73
95
|
}
|
|
74
96
|
} catch {
|
|
75
97
|
}
|
|
76
98
|
}
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
99
|
+
try {
|
|
100
|
+
const result = useParallel ? await fetchPriceParallel(timeout) : await fetchPriceSequential(timeout);
|
|
101
|
+
const data = {
|
|
102
|
+
solPrice: result.price,
|
|
103
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
104
|
+
source: result.source
|
|
105
|
+
};
|
|
106
|
+
priceCache = { data, timestamp: now };
|
|
107
|
+
return data;
|
|
108
|
+
} catch {
|
|
109
|
+
if (priceCache) {
|
|
110
|
+
return {
|
|
111
|
+
...priceCache.data,
|
|
112
|
+
source: `${priceCache.data.source} (stale)`
|
|
87
113
|
};
|
|
88
|
-
return cachedPrice;
|
|
89
|
-
} catch {
|
|
90
|
-
continue;
|
|
91
114
|
}
|
|
115
|
+
throw new Error(
|
|
116
|
+
"Failed to fetch SOL price from all providers. Configure a custom provider or ensure network connectivity."
|
|
117
|
+
);
|
|
92
118
|
}
|
|
93
|
-
if (cachedPrice) {
|
|
94
|
-
return {
|
|
95
|
-
...cachedPrice,
|
|
96
|
-
source: `${cachedPrice.source} (stale)`
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
throw new Error(
|
|
100
|
-
"Failed to fetch SOL price from all providers. Configure a custom provider or ensure network connectivity."
|
|
101
|
-
);
|
|
102
119
|
}
|
|
103
120
|
async function lamportsToUsd(lamports) {
|
|
104
121
|
const { solPrice } = await getSolPrice();
|
|
@@ -126,8 +143,7 @@ function formatPriceSync(lamports, solPrice) {
|
|
|
126
143
|
};
|
|
127
144
|
}
|
|
128
145
|
function clearPriceCache() {
|
|
129
|
-
|
|
130
|
-
lastProviderIndex = -1;
|
|
146
|
+
priceCache = null;
|
|
131
147
|
}
|
|
132
148
|
function getProviders() {
|
|
133
149
|
return PROVIDERS.map((p) => ({ name: p.name, url: p.url }));
|
package/package.json
CHANGED