@dexterai/x402 3.0.1 → 3.1.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.
@@ -1,744 +1,4 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/server/index.ts
31
- var server_exports = {};
32
- __export(server_exports, {
33
- BASE_MAINNET_NETWORK: () => BASE_MAINNET_NETWORK,
34
- DEXTER_FACILITATOR_URL: () => DEXTER_FACILITATOR_URL,
35
- FacilitatorClient: () => FacilitatorClient,
36
- MODEL_PRICING: () => MODEL_PRICING,
37
- MODEL_PRICING_MAP: () => MODEL_PRICING_MAP,
38
- MODEL_REGISTRY: () => MODEL_REGISTRY,
39
- SOLANA_MAINNET_NETWORK: () => SOLANA_MAINNET_NETWORK,
40
- SPONSORED_ACCESS_EXTENSION_KEY: () => import_x402_ads_types.SPONSORED_ACCESS_EXTENSION_KEY,
41
- USDC_BASE: () => USDC_BASE,
42
- USDC_MINT: () => USDC_MINT,
43
- countTokens: () => countTokens,
44
- createDynamicPricing: () => createDynamicPricing,
45
- createTokenPricing: () => createTokenPricing,
46
- createX402Server: () => createX402Server,
47
- escapeHtml: () => escapeHtml,
48
- estimateCost: () => estimateCost,
49
- findModel: () => findModel,
50
- formatModelPricing: () => formatModelPricing,
51
- formatPricing: () => formatPricing,
52
- formatTokenPricing: () => formatTokenPricing,
53
- getActiveModels: () => getActiveModels,
54
- getAvailableModelIds: () => getAvailableModelIds,
55
- getAvailableModels: () => getAvailableModels,
56
- getCheapestModel: () => getCheapestModel,
57
- getModel: () => getModel,
58
- getModelsByFamily: () => getModelsByFamily,
59
- getModelsByTier: () => getModelsByTier,
60
- getTextModels: () => getTextModels,
61
- isValidModel: () => isValidModel,
62
- isValidModelId: () => isValidModelId,
63
- stripePayTo: () => stripePayTo,
64
- x402AccessPass: () => x402AccessPass,
65
- x402BrowserSupport: () => x402BrowserSupport,
66
- x402Middleware: () => x402Middleware
67
- });
68
- module.exports = __toCommonJS(server_exports);
69
-
70
- // src/types.ts
71
- var SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
72
- var BASE_MAINNET_NETWORK = "eip155:8453";
73
- var USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
74
- var USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
75
- var DEXTER_FACILITATOR_URL = "https://x402.dexter.cash";
76
-
77
- // src/utils.ts
78
- function toAtomicUnits(amount, decimals) {
79
- const multiplier = Math.pow(10, decimals);
80
- return Math.floor(amount * multiplier).toString();
81
- }
82
- function isSolanaNetwork(network) {
83
- return network.startsWith("solana:") || network === "solana";
84
- }
85
- function safeBase64Encode(str) {
86
- if (typeof Buffer !== "undefined") {
87
- return Buffer.from(str, "utf-8").toString("base64");
88
- }
89
- const bytes = new TextEncoder().encode(str);
90
- let binary = "";
91
- for (let i = 0; i < bytes.length; i++) {
92
- binary += String.fromCharCode(bytes[i]);
93
- }
94
- return btoa(binary);
95
- }
96
- function safeBase64Decode(encoded) {
97
- if (typeof Buffer !== "undefined") {
98
- return Buffer.from(encoded, "base64").toString("utf-8");
99
- }
100
- const binary = atob(encoded);
101
- const bytes = new Uint8Array(binary.length);
102
- for (let i = 0; i < binary.length; i++) {
103
- bytes[i] = binary.charCodeAt(i);
104
- }
105
- return new TextDecoder().decode(bytes);
106
- }
107
- function encodeBase64Json(obj) {
108
- return safeBase64Encode(JSON.stringify(obj));
109
- }
110
- function decodeBase64Json(encoded) {
111
- return JSON.parse(safeBase64Decode(encoded));
112
- }
113
-
114
- // src/server/facilitator-client.ts
115
- function isRetryable(error) {
116
- if (error instanceof TypeError) return true;
117
- if (error && typeof error === "object" && "status" in error) {
118
- const status = error.status;
119
- return status >= 500 && status < 600;
120
- }
121
- return false;
122
- }
123
- var HttpError = class extends Error {
124
- status;
125
- body;
126
- constructor(status, body) {
127
- super(`HTTP ${status}`);
128
- this.status = status;
129
- this.body = body;
130
- }
131
- };
132
- var FacilitatorClient = class {
133
- facilitatorUrl;
134
- cachedSupported = null;
135
- cacheTime = 0;
136
- CACHE_TTL_MS = 6e4;
137
- timeoutMs;
138
- maxRetries;
139
- retryBaseMs;
140
- constructor(facilitatorUrl = DEXTER_FACILITATOR_URL, config) {
141
- this.facilitatorUrl = facilitatorUrl.replace(/\/$/, "");
142
- this.timeoutMs = config?.timeoutMs ?? 1e4;
143
- this.maxRetries = config?.maxRetries ?? 3;
144
- this.retryBaseMs = config?.retryBaseMs ?? 500;
145
- }
146
- async fetchWithTimeout(url, init) {
147
- const controller = new AbortController();
148
- const timer = setTimeout(() => controller.abort(), this.timeoutMs);
149
- try {
150
- return await fetch(url, { ...init, signal: controller.signal });
151
- } finally {
152
- clearTimeout(timer);
153
- }
154
- }
155
- async fetchWithRetry(url, init) {
156
- let lastError;
157
- for (let attempt = 0; attempt < this.maxRetries; attempt++) {
158
- try {
159
- const response = await this.fetchWithTimeout(url, init);
160
- if (!response.ok && response.status >= 500) {
161
- throw new HttpError(response.status, await response.text());
162
- }
163
- return response;
164
- } catch (error) {
165
- lastError = error;
166
- if (attempt < this.maxRetries - 1 && isRetryable(error)) {
167
- const delay = this.retryBaseMs * Math.pow(2, attempt);
168
- await new Promise((r) => setTimeout(r, delay));
169
- continue;
170
- }
171
- throw error;
172
- }
173
- }
174
- throw lastError;
175
- }
176
- /**
177
- * Get supported payment kinds from the facilitator.
178
- * Results are cached for 1 minute to reduce network calls.
179
- */
180
- async getSupported() {
181
- const now = Date.now();
182
- if (this.cachedSupported && now - this.cacheTime < this.CACHE_TTL_MS) {
183
- return this.cachedSupported;
184
- }
185
- const response = await this.fetchWithTimeout(`${this.facilitatorUrl}/supported`);
186
- if (!response.ok) {
187
- throw new Error(`Facilitator /supported returned ${response.status}`);
188
- }
189
- this.cachedSupported = await response.json();
190
- this.cacheTime = now;
191
- return this.cachedSupported;
192
- }
193
- /**
194
- * Get the fee payer address for a specific network
195
- */
196
- async getFeePayer(network) {
197
- const supported = await this.getSupported();
198
- const kind = supported.kinds.find(
199
- (k) => k.x402Version === 2 && (k.scheme === "exact" || k.scheme === "exact-approval") && k.network === network
200
- );
201
- if (!kind) {
202
- throw new Error(
203
- `Facilitator does not support network "${network}" with a recognized scheme`
204
- );
205
- }
206
- return kind.extra?.feePayer;
207
- }
208
- /**
209
- * Get extra data for a network (feePayer, decimals, EIP-712 data, etc.)
210
- */
211
- async getNetworkExtra(network) {
212
- const supported = await this.getSupported();
213
- const kind = supported.kinds.find(
214
- (k) => k.x402Version === 2 && (k.scheme === "exact" || k.scheme === "exact-approval") && k.network === network
215
- );
216
- return kind?.extra;
217
- }
218
- /**
219
- * Verify a payment with the facilitator.
220
- * Retries on 5xx and network errors with exponential backoff.
221
- */
222
- async verifyPayment(paymentSignatureHeader, requirements) {
223
- try {
224
- const paymentPayload = decodeBase64Json(paymentSignatureHeader);
225
- const response = await this.fetchWithRetry(`${this.facilitatorUrl}/verify`, {
226
- method: "POST",
227
- headers: { "Content-Type": "application/json" },
228
- body: JSON.stringify({
229
- x402Version: 2,
230
- paymentPayload,
231
- paymentRequirements: requirements
232
- })
233
- });
234
- if (!response.ok) {
235
- return {
236
- isValid: false,
237
- invalidReason: `facilitator_error_${response.status}`
238
- };
239
- }
240
- return await response.json();
241
- } catch (error) {
242
- const reason = error instanceof HttpError ? `facilitator_error_${error.status}` : error instanceof Error && error.name === "AbortError" ? "facilitator_timeout" : error instanceof Error ? error.message : "unexpected_verify_error";
243
- return { isValid: false, invalidReason: reason };
244
- }
245
- }
246
- /**
247
- * Settle a payment with the facilitator.
248
- * Retries on 5xx and network errors with exponential backoff.
249
- */
250
- async settlePayment(paymentSignatureHeader, requirements) {
251
- try {
252
- const paymentPayload = decodeBase64Json(paymentSignatureHeader);
253
- const response = await this.fetchWithRetry(`${this.facilitatorUrl}/settle`, {
254
- method: "POST",
255
- headers: { "Content-Type": "application/json" },
256
- body: JSON.stringify({
257
- x402Version: 2,
258
- paymentPayload,
259
- paymentRequirements: requirements
260
- })
261
- });
262
- if (!response.ok) {
263
- return {
264
- success: false,
265
- network: requirements.network,
266
- errorReason: `facilitator_error_${response.status}`
267
- };
268
- }
269
- const result = await response.json();
270
- return { ...result, network: requirements.network };
271
- } catch (error) {
272
- const reason = error instanceof HttpError ? `facilitator_error_${error.status}` : error instanceof Error && error.name === "AbortError" ? "facilitator_timeout" : error instanceof Error ? error.message : "unexpected_settle_error";
273
- return {
274
- success: false,
275
- network: requirements.network,
276
- errorReason: reason
277
- };
278
- }
279
- }
280
- };
281
-
282
- // src/server/x402-server.ts
283
- function extractAmountFromHeader(paymentSignatureHeader) {
284
- try {
285
- const decoded = decodeBase64Json(paymentSignatureHeader);
286
- return decoded?.accepted?.amount ?? decoded?.accepted?.maxAmountRequired;
287
- } catch {
288
- return void 0;
289
- }
290
- }
291
- function createX402Server(config) {
292
- const {
293
- payTo,
294
- facilitatorUrl = DEXTER_FACILITATOR_URL,
295
- network = SOLANA_MAINNET_NETWORK,
296
- asset = { address: USDC_MINT, decimals: 6 },
297
- defaultTimeoutSeconds = 60
298
- } = config;
299
- const facilitator = new FacilitatorClient(facilitatorUrl);
300
- let cachedExtra = null;
301
- const requirementsCache = /* @__PURE__ */ new Map();
302
- const CACHE_PRUNE_INTERVAL = 3e4;
303
- let lastPrune = Date.now();
304
- function cacheRequirements(accept) {
305
- const ttl = (accept.maxTimeoutSeconds || defaultTimeoutSeconds) * 1e3;
306
- requirementsCache.set(accept.payTo, { accept, expiresAt: Date.now() + ttl });
307
- if (Date.now() - lastPrune > CACHE_PRUNE_INTERVAL) {
308
- const now = Date.now();
309
- for (const [key, entry] of requirementsCache) {
310
- if (entry.expiresAt < now) requirementsCache.delete(key);
311
- }
312
- lastPrune = now;
313
- }
314
- }
315
- function getCachedRequirements(address) {
316
- const entry = requirementsCache.get(address);
317
- if (!entry) return void 0;
318
- if (entry.expiresAt < Date.now()) {
319
- requirementsCache.delete(address);
320
- return void 0;
321
- }
322
- return entry.accept;
323
- }
324
- async function resolvePayTo(context) {
325
- if (typeof payTo === "string") return payTo;
326
- return payTo(context || {});
327
- }
328
- async function getNetworkExtra() {
329
- if (!cachedExtra) {
330
- cachedExtra = await facilitator.getNetworkExtra(network);
331
- }
332
- const isSvm = isSolanaNetwork(network);
333
- if (isSvm && !cachedExtra?.feePayer) {
334
- throw new Error(`Facilitator does not provide feePayer for network "${network}"`);
335
- }
336
- return {
337
- ...cachedExtra?.feePayer ? { feePayer: cachedExtra.feePayer } : {},
338
- decimals: cachedExtra?.decimals ?? asset.decimals,
339
- name: cachedExtra?.name,
340
- version: cachedExtra?.version
341
- };
342
- }
343
- async function buildPaymentAccept(resolvedPayTo, options) {
344
- const {
345
- amountAtomic,
346
- timeoutSeconds = defaultTimeoutSeconds
347
- } = options;
348
- const extra = await getNetworkExtra();
349
- const accept = {
350
- scheme: "exact",
351
- network,
352
- amount: amountAtomic,
353
- maxAmountRequired: amountAtomic,
354
- asset: asset.address,
355
- payTo: resolvedPayTo,
356
- maxTimeoutSeconds: timeoutSeconds,
357
- extra
358
- };
359
- cacheRequirements(accept);
360
- return accept;
361
- }
362
- async function getPaymentAccept(options) {
363
- const address = await resolvePayTo({
364
- amountAtomic: options.amountAtomic,
365
- resourceUrl: options.resourceUrl
366
- });
367
- return buildPaymentAccept(address, options);
368
- }
369
- async function buildRequirements(options) {
370
- const {
371
- resourceUrl,
372
- description,
373
- mimeType = "application/json"
374
- } = options;
375
- const resource = {
376
- url: resourceUrl,
377
- description,
378
- mimeType
379
- };
380
- const accept = await getPaymentAccept(options);
381
- return {
382
- x402Version: 2,
383
- resource,
384
- accepts: [accept],
385
- error: "Payment required"
386
- };
387
- }
388
- function encodeRequirements(requirements) {
389
- return encodeBase64Json(requirements);
390
- }
391
- function create402Response(requirements) {
392
- return {
393
- status: 402,
394
- headers: {
395
- "PAYMENT-REQUIRED": encodeRequirements(requirements)
396
- },
397
- body: {}
398
- };
399
- }
400
- async function verifyPayment(paymentSignatureHeader, requirements) {
401
- if (!requirements) {
402
- const address = await resolvePayTo({ paymentHeader: paymentSignatureHeader });
403
- requirements = getCachedRequirements(address);
404
- if (!requirements) {
405
- requirements = await buildPaymentAccept(address, {
406
- amountAtomic: extractAmountFromHeader(paymentSignatureHeader) ?? "0",
407
- resourceUrl: ""
408
- });
409
- }
410
- }
411
- return facilitator.verifyPayment(paymentSignatureHeader, requirements);
412
- }
413
- async function settlePayment(paymentSignatureHeader, requirements) {
414
- if (!requirements) {
415
- const address = await resolvePayTo({ paymentHeader: paymentSignatureHeader });
416
- requirements = getCachedRequirements(address);
417
- if (!requirements) {
418
- requirements = await buildPaymentAccept(address, {
419
- amountAtomic: extractAmountFromHeader(paymentSignatureHeader) ?? "0",
420
- resourceUrl: ""
421
- });
422
- }
423
- }
424
- return facilitator.settlePayment(paymentSignatureHeader, requirements);
425
- }
426
- return {
427
- buildRequirements,
428
- encodeRequirements,
429
- create402Response,
430
- verifyPayment,
431
- settlePayment,
432
- getPaymentAccept,
433
- network,
434
- facilitator
435
- };
436
- }
437
-
438
- // src/server/stripe-payto.ts
439
- var stripeProviderNetworks = /* @__PURE__ */ new WeakMap();
440
- function getStripeProviderNetwork(provider) {
441
- return stripeProviderNetworks.get(provider);
442
- }
443
- var STRIPE_NETWORK_KEYS = {
444
- "base": "base",
445
- "base-sepolia": "base_sepolia"
446
- };
447
- var CAIP2_NETWORKS = {
448
- "base": "eip155:8453",
449
- "base-sepolia": "eip155:84532"
450
- };
451
- var USDC_DECIMALS = 6;
452
- function stripePayTo(secretKeyOrConfig) {
453
- const config = typeof secretKeyOrConfig === "string" ? { secretKey: secretKeyOrConfig } : secretKeyOrConfig;
454
- const networkName = config.network ?? "base";
455
- const stripeNetworkKey = STRIPE_NETWORK_KEYS[networkName] ?? "base";
456
- const caip2Network = CAIP2_NETWORKS[networkName] ?? "eip155:8453";
457
- const apiVersion = config.apiVersion ?? "2026-01-28.clover";
458
- let stripeClient = null;
459
- async function getStripe() {
460
- if (stripeClient) return stripeClient;
461
- try {
462
- const { default: Stripe } = await import("stripe");
463
- stripeClient = new Stripe(config.secretKey, {
464
- apiVersion,
465
- appInfo: {
466
- name: "@dexterai/x402",
467
- url: "https://dexter.cash/sdk"
468
- }
469
- });
470
- return stripeClient;
471
- } catch {
472
- throw new Error(
473
- 'The "stripe" package is required for stripePayTo(). Install it with: npm install stripe'
474
- );
475
- }
476
- }
477
- const provider = async (context) => {
478
- if (context.paymentHeader) {
479
- try {
480
- const decoded = JSON.parse(
481
- Buffer.from(context.paymentHeader, "base64").toString()
482
- );
483
- const toAddress = decoded.payload?.authorization?.to;
484
- if (toAddress && typeof toAddress === "string") {
485
- return toAddress;
486
- }
487
- const acceptedPayTo = decoded.accepted?.payTo;
488
- if (acceptedPayTo && typeof acceptedPayTo === "string") {
489
- return acceptedPayTo;
490
- }
491
- } catch {
492
- }
493
- throw new Error(
494
- "Could not extract deposit address from payment header. Ensure the client is sending a valid x402 PAYMENT-SIGNATURE."
495
- );
496
- }
497
- const stripe = await getStripe();
498
- const amountAtomic = context.amountAtomic ? parseInt(context.amountAtomic, 10) : 1e4;
499
- const amountInCents = Math.max(1, Math.round(amountAtomic / Math.pow(10, USDC_DECIMALS - 2)));
500
- const paymentIntent = await stripe.paymentIntents.create({
501
- amount: amountInCents,
502
- currency: "usd",
503
- payment_method_types: ["crypto"],
504
- payment_method_data: { type: "crypto" },
505
- payment_method_options: {
506
- crypto: { mode: "custom" }
507
- },
508
- confirm: true
509
- });
510
- const nextAction = paymentIntent.next_action;
511
- if (!nextAction?.crypto_collect_deposit_details) {
512
- throw new Error(
513
- "Stripe PaymentIntent did not return crypto deposit details. Ensure your Stripe account has crypto payins enabled: https://support.stripe.com/questions/get-started-with-pay-with-crypto"
514
- );
515
- }
516
- const depositDetails = nextAction.crypto_collect_deposit_details;
517
- const payToAddress = depositDetails.deposit_addresses?.[stripeNetworkKey]?.address;
518
- if (!payToAddress) {
519
- throw new Error(
520
- `No deposit address found for network "${stripeNetworkKey}". Available networks: ${Object.keys(depositDetails.deposit_addresses || {}).join(", ")}`
521
- );
522
- }
523
- return payToAddress;
524
- };
525
- provider._x402Defaults = {
526
- network: caip2Network,
527
- facilitatorUrl: "https://x402.dexter.cash"
528
- };
529
- stripeProviderNetworks.set(provider, caip2Network);
530
- return provider;
531
- }
532
-
533
- // src/server/middleware.ts
534
- var DEFAULT_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
535
- var USDC_DECIMALS2 = 6;
536
- function resolvePayToForNetwork(payTo, network) {
537
- if (typeof payTo === "string" || typeof payTo === "function") return payTo;
538
- if (network in payTo) return payTo[network];
539
- const prefix = network.split(":")[0];
540
- const globKey = `${prefix}:*`;
541
- if (globKey in payTo) return payTo[globKey];
542
- if ("*" in payTo) return payTo["*"];
543
- throw new Error(`No payTo configured for network "${network}"`);
544
- }
545
- function x402Middleware(config) {
546
- const {
547
- payTo,
548
- amount,
549
- asset,
550
- description,
551
- resourceUrl: staticResourceUrl,
552
- mimeType,
553
- timeoutSeconds,
554
- verbose = false,
555
- getResourceUrl,
556
- getAmount,
557
- getDescription
558
- } = config;
559
- const log = verbose ? console.log.bind(console, "[x402:middleware]") : () => {
560
- };
561
- const singleProviderDefaults = typeof payTo === "function" ? payTo._x402Defaults : void 0;
562
- const facilitatorUrl = config.facilitatorUrl ?? singleProviderDefaults?.facilitatorUrl;
563
- const configuredNetworks = (() => {
564
- if (config.network) {
565
- return Array.isArray(config.network) ? config.network : [config.network];
566
- }
567
- if (singleProviderDefaults?.network) return [singleProviderDefaults.network];
568
- return [DEFAULT_NETWORK];
569
- })();
570
- const servers = /* @__PURE__ */ new Map();
571
- for (const net of configuredNetworks) {
572
- const netPayTo = resolvePayToForNetwork(payTo, net);
573
- if (typeof netPayTo === "function") {
574
- const stripeNet = getStripeProviderNetwork(netPayTo);
575
- if (stripeNet && net !== stripeNet) {
576
- throw new Error(
577
- `stripePayTo is configured for "${stripeNet}" but middleware includes network "${net}". Stripe only supports Base deposit addresses. Use a static payTo for other chains.`
578
- );
579
- }
580
- }
581
- servers.set(net, createX402Server({
582
- payTo: netPayTo,
583
- network: net,
584
- asset,
585
- facilitatorUrl,
586
- defaultTimeoutSeconds: timeoutSeconds
587
- }));
588
- }
589
- const primaryServer = servers.get(configuredNetworks[0]);
590
- return async (req, res, next) => {
591
- try {
592
- const paymentSignature = req.headers["payment-signature"];
593
- if (!paymentSignature) {
594
- log("No payment signature, returning 402");
595
- const resourceUrl = getResourceUrl?.(req) ?? staticResourceUrl ?? `${req.protocol}://${req.get("host")}${req.originalUrl}`;
596
- const requestAmount = getAmount?.(req) ?? amount;
597
- const requestDescription = getDescription?.(req) ?? description;
598
- const decimals = asset?.decimals ?? USDC_DECIMALS2;
599
- const amountAtomic = toAtomicUnits(parseFloat(requestAmount), decimals);
600
- const requirementsOptions = {
601
- amountAtomic,
602
- resourceUrl,
603
- description: requestDescription,
604
- mimeType,
605
- timeoutSeconds
606
- };
607
- const allAccepts = [];
608
- let requirements = null;
609
- for (const [, srv] of servers) {
610
- try {
611
- const reqs = await srv.buildRequirements(requirementsOptions);
612
- allAccepts.push(...reqs.accepts);
613
- if (!requirements) requirements = reqs;
614
- } catch (e) {
615
- log("Failed to build requirements for a network:", e);
616
- }
617
- }
618
- if (!requirements || allAccepts.length === 0) {
619
- res.status(500).json({ error: "Failed to build payment requirements" });
620
- return;
621
- }
622
- requirements = { ...requirements, accepts: allAccepts };
623
- const encoded = primaryServer.encodeRequirements(requirements);
624
- res.setHeader("PAYMENT-REQUIRED", encoded);
625
- res.status(402).json({
626
- error: "Payment required",
627
- accepts: requirements.accepts,
628
- resource: requirements.resource
629
- });
630
- return;
631
- }
632
- log("Payment signature received, verifying...");
633
- let targetServer = primaryServer;
634
- try {
635
- const decoded = JSON.parse(Buffer.from(paymentSignature, "base64").toString());
636
- const paymentNetwork = decoded?.accepted?.network;
637
- if (paymentNetwork && servers.has(paymentNetwork)) {
638
- targetServer = servers.get(paymentNetwork);
639
- }
640
- } catch {
641
- }
642
- const verifyResult = await targetServer.verifyPayment(paymentSignature);
643
- if (!verifyResult.isValid) {
644
- log("Payment verification failed:", verifyResult.invalidReason);
645
- if (config.onVerifyFailed) {
646
- try {
647
- await config.onVerifyFailed({
648
- reason: verifyResult.invalidReason,
649
- resourceUrl: `${req.protocol}://${req.get("host")}${req.originalUrl}`
650
- });
651
- } catch {
652
- }
653
- }
654
- res.status(402).json({
655
- error: "Payment verification failed",
656
- reason: verifyResult.invalidReason
657
- });
658
- return;
659
- }
660
- log("Payment verified, settling...");
661
- const settleResult = await targetServer.settlePayment(paymentSignature);
662
- if (!settleResult.success) {
663
- log("Payment settlement failed:", settleResult.errorReason);
664
- res.status(402).json({
665
- error: "Payment settlement failed",
666
- reason: settleResult.errorReason
667
- });
668
- return;
669
- }
670
- log("Payment settled:", settleResult.transaction);
671
- const settledNetwork = settleResult.network || configuredNetworks[0];
672
- if (config.onSettlement) {
673
- try {
674
- await config.onSettlement({
675
- transaction: settleResult.transaction,
676
- network: settledNetwork,
677
- payer: verifyResult.payer ?? "",
678
- resourceUrl: `${req.protocol}://${req.get("host")}${req.originalUrl}`
679
- });
680
- } catch {
681
- }
682
- }
683
- req.x402 = {
684
- transaction: settleResult.transaction,
685
- payer: verifyResult.payer ?? "",
686
- network: settledNetwork
687
- };
688
- const paymentResponseData = {
689
- success: true,
690
- transaction: settleResult.transaction,
691
- network: settledNetwork,
692
- payer: verifyResult.payer ?? ""
693
- };
694
- if (settleResult.extensions) {
695
- paymentResponseData.extensions = settleResult.extensions;
696
- }
697
- res.setHeader("PAYMENT-RESPONSE", encodeBase64Json(paymentResponseData));
698
- if (config.sponsoredAccess && settleResult.extensions?.["sponsored-access"]) {
699
- const extData = settleResult.extensions["sponsored-access"];
700
- const recs = extData?.info?.recommendations ?? extData?.recommendations;
701
- if (recs && recs.length > 0) {
702
- log("Injecting sponsored-access recommendations into response");
703
- if (typeof config.sponsoredAccess === "object" && config.sponsoredAccess.onMatch) {
704
- try {
705
- config.sponsoredAccess.onMatch(recs, {
706
- transaction: settleResult.transaction,
707
- network: settledNetwork,
708
- payer: verifyResult.payer ?? ""
709
- });
710
- } catch {
711
- }
712
- }
713
- const originalJson = res.json.bind(res);
714
- res.json = function patchedJson(body) {
715
- if (typeof config.sponsoredAccess === "object" && config.sponsoredAccess.inject) {
716
- return originalJson(config.sponsoredAccess.inject(body, recs));
717
- }
718
- if (body && typeof body === "object" && !Array.isArray(body)) {
719
- return originalJson({ _x402_sponsored: recs, ...body });
720
- }
721
- return originalJson(body);
722
- };
723
- }
724
- }
725
- next();
726
- } catch (error) {
727
- log("Middleware error:", error);
728
- res.status(500).json({
729
- error: "Payment processing error"
730
- });
731
- }
732
- };
733
- }
734
-
735
- // src/server/browser-support.ts
736
- function escapeHtml(s) {
737
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
738
- }
739
- var USDC_ICON_SVG = `<svg width="18" height="18" viewBox="0 0 2000 2000" xmlns="http://www.w3.org/2000/svg"><path d="M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z" fill="#2775ca"/><path d="M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z" fill="#fff"/><path d="M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zM1229.17 295.83c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z" fill="#fff"/></svg>`;
740
- var DEXTER_CREST_SVG = `<svg width="36" height="36" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg"><g><path fill="#F2681A" d="m324.93,313.11c-115.5,0-231,0-350,0l350,0z"/><path fill="#FDFAF5" d="m230.43,50.62c1.1.85 2.19 1.7 3.32 2.57 6.02 4.8 11.77 9.88 17.46 15.07.92.84.92.84 1.86 1.69 1.82 1.69 3.59 3.42 5.35 5.16.61.56 1.22 1.13 1.84 1.71 5.66 5.76 6.18 10.43 6.13 18.3.02 1.16.04 2.32.06 3.52.06 3.83.06 7.65.07 11.48.02 2.68.05 5.35.08 8.03.05 5.6.09 11.21.1 16.81.02 7.15.09 14.31.17 21.46.06 5.53.1 11.05.13 16.58.02 2.64.04 5.27.07 7.91.18 17.58.12 32.82-11.24 47.32-7.35 7.27-16.54 12.06-25.42 17.22-1.97 1.16-3.94 2.33-5.91 3.49-7.16 4.24-14.34 8.44-21.53 12.62-4.8 2.79-9.59 5.6-14.38 8.42-1.25.73-2.5 1.47-3.79 2.23-2.32 1.36-4.64 2.73-6.96 4.1-27.47 16.09-27.47 16.09-42.16 12.93-8.06-2.28-14.94-5.82-22.16-10.02-1.17-.67-2.34-1.34-3.54-2.04-24.55-14.25-43.58-27.03-51.9-55.58-1.07-4.58-1.54-8.92-1.52-13.61.28-9.5.28-9.5-3.3-17.97-1.81-1.49-3.68-2.92-5.59-4.28-9.19-7.06-12.7-20.03-14.18-31.06-.54-5.77-.55-11.56-.6-17.35-.03-1.32-.07-2.63-.1-3.99-.01-1.26-.02-2.53-.03-3.83-.02-1.15-.03-2.29-.05-3.47.72-4.02 1.94-5.36 5.21-7.74 2.89-.53 2.89-.53 6.07-.46 1.71.02 1.71.02 3.46.05 1.19.04 2.37.08 3.59.12 1.2.02 2.41.04 3.65.06 2.97.05 5.93.13 8.9.23.14-1.35.29-2.7.43-4.08.63-5 1.78-9.74 3.14-14.58.22-.79.43-1.59.66-2.4.53-1.92 1.06-3.84 1.6-5.76-1.55-.45-1.55-.45-3.13-.9-9.52-3.52-17.1-10.95-21.37-20.1-3.81-9.26-3.87-20.34-.29-29.68 6.49-13.99 16.36-23.23 30.66-29.01 49.81-17.69 115.79 8.35 155.13 38.85z"/><path fill="#F2671A" d="m142.93,22.62c.86.19 1.73.39 2.62.59 36.12 8.21 68.79 24.98 95.38 50.75 1.02.98 2.03 1.97 3.08 2.98 10.84 10.66 10.84 10.66 11.05 14.62-2.06 3.55-5.44 4.18-9.17 5.3-.79.25-1.59.49-2.41.75-28.13 8.43-60.95 6.37-87.13-7.16-.86-.49-1.71-.97-2.6-1.48-7.37-4.05-12.59-3.36-20.59-1.54-22.76 4-48.47 1.53-68.69-9.74-4.88-3.88-8.23-8.29-10.21-14.22-.93-10.38-.67-18.44 5.83-26.83 19.57-23.38 55.99-20.36 82.83-14z"/><path fill="#F16619" d="m44.93,129.12c27.36-.03 54.72-.05 82.08-.06 12.7-.01 25.41-.01 38.11-.03 11.07-.01 22.14-.02 33.2-.02 5.86 0 11.73-.01 17.59-.01 5.51-.01 11.03-.01 16.54-.01 2.03 0 4.06 0 6.09-.01 2.76-.01 5.52 0 8.28 0 .81 0 1.63-.01 2.47-.01 5.51.02 5.51.02 6.81 1.32.22 3.43.22 3.43 0 7-2.75 2.75-3.42 2.66-7.15 2.82-1.41.07-1.41.07-2.85.14-1.47.05-1.47.05-2.98.11-1.49.07-1.49.07-3 .14-2.45.11-4.9.21-7.35.3-.2 1.3-.4 2.59-.6 3.93-2.57 16.08-5.93 29.89-18.89 40.86-10.35 7.28-21.87 8.49-34.17 7.71-13.11-2.33-22.52-9.19-30.33-19.83-4.49-7.64-4.8-17.05-5.83-25.67-4.24.39-8.47.77-12.83 1.17-.28 1.84-.28 1.84-.56 3.71-2.32 14.39-5.63 23.35-16.95 33.11-2.32 1.67-2.32 1.67-4.65 1.67 4 4.67 9.06 6.59 14.87 8.24 3.79 1.09 3.79 1.09 6.12 3.43-.65 5.31-.65 5.31-2.33 7-8.42-.27-15.13-2.29-22.17-7-1.09-1.21-2.17-2.43-3.25-3.65-2.72-2.81-4.45-3.84-8.36-4.16-1.67-.02-3.34-.02-5.01.01-1.77-.04-3.54-.09-5.3-.15-1.27-.04-1.27-.04-2.56-.08-9.26-.54-17.6-4.56-24.51-10.64-9.58-11.11-11.03-22.56-10.72-36.82.02-1.4.03-2.8.05-4.24.04-3.42.1-6.85.17-10.27z"/><path fill="#F26117" d="m172.68,203.08c7.27.09 13.23 1.97 18.87 6.65 2.88 3.07 3.86 5.12 4.25 9.32-.12 1.01-.24 2.02-.36 3.06-2.55.95-2.55.95-5.83 1.17-3.28-2.84-3.28-2.84-5.83-5.83-.36.58-.71 1.16-1.08 1.75-7.6 11.29-20.06 17.74-33.05 21.09-20.36 3.1-36.81-1.66-53.37-13.73-2.33-2.11-2.33-2.11-4.67-5.61.42-3.45.99-4.49 3.5-7 4.07.37 5.95 2.13 8.75 4.96 9.81 8.93 22.53 11.87 35.51 11.69 11.74-1.05 22.38-5.85 31.57-13.15 2.06-2.45 2.06-2.45 3.5-4.67-1.66.07-1.66.07-3.35.15-3.65-.15-3.65-.15-5.98-2.48.75-6.18 1.46-7.19 7.58-7.36z"/></g></svg>`;
741
- var DEXTER_STYLES = `
1
+ "use strict";var We=Object.create;var Q=Object.defineProperty;var ze=Object.getOwnPropertyDescriptor;var Le=Object.getOwnPropertyNames;var Ve=Object.getPrototypeOf,je=Object.prototype.hasOwnProperty;var Ge=(e,t)=>{for(var n in t)Q(e,n,{get:t[n],enumerable:!0})},ue=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Le(t))!je.call(e,i)&&i!==n&&Q(e,i,{get:()=>t[i],enumerable:!(r=ze(t,i))||r.enumerable});return e};var ae=(e,t,n)=>(n=e!=null?We(Ve(e)):{},ue(t||!e||!e.__esModule?Q(n,"default",{value:e,enumerable:!0}):n,e)),He=e=>ue(Q({},"__esModule",{value:!0}),e);var ht={};Ge(ht,{BASE_MAINNET_NETWORK:()=>ce,DEXTER_FACILITATOR_URL:()=>L,FacilitatorClient:()=>V,MODEL_PRICING:()=>I,MODEL_PRICING_MAP:()=>ne,MODEL_REGISTRY:()=>N,SOLANA_MAINNET_NETWORK:()=>G,SPONSORED_ACCESS_EXTENSION_KEY:()=>Fe.SPONSORED_ACCESS_EXTENSION_KEY,USDC_BASE:()=>de,USDC_MINT:()=>Z,countTokens:()=>se,createDynamicPricing:()=>we,createTokenPricing:()=>De,createX402Server:()=>j,escapeHtml:()=>O,estimateCost:()=>Oe,findModel:()=>ke,formatModelPricing:()=>Ne,formatPricing:()=>Te,formatTokenPricing:()=>qe,getActiveModels:()=>Ee,getAvailableModelIds:()=>Se,getAvailableModels:()=>Be,getCheapestModel:()=>Ce,getModel:()=>re,getModelsByFamily:()=>ve,getModelsByTier:()=>Me,getTextModels:()=>_e,isValidModel:()=>$e,isValidModelId:()=>Ae,stripePayTo:()=>ye,x402AccessPass:()=>Pe,x402BrowserSupport:()=>he,x402Middleware:()=>xe});module.exports=He(ht);var G="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",ce="eip155:8453";var Z="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",de="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",L="https://x402.dexter.cash";function H(e,t){let n=Math.pow(10,t);return Math.floor(e*n).toString()}function le(e){return e.startsWith("solana:")||e==="solana"}function Ke(e){if(typeof Buffer<"u")return Buffer.from(e,"utf-8").toString("base64");let t=new TextEncoder().encode(e),n="";for(let r=0;r<t.length;r++)n+=String.fromCharCode(t[r]);return btoa(n)}function Xe(e){if(typeof Buffer<"u")return Buffer.from(e,"base64").toString("utf-8");let t=atob(e),n=new Uint8Array(t.length);for(let r=0;r<t.length;r++)n[r]=t.charCodeAt(r);return new TextDecoder().decode(n)}function F(e){return Ke(JSON.stringify(e))}function K(e){return JSON.parse(Xe(e))}function Je(e){if(e instanceof TypeError)return!0;if(e&&typeof e=="object"&&"status"in e){let t=e.status;return t>=500&&t<600}return!1}var X=class extends Error{status;body;constructor(t,n){super(`HTTP ${t}`),this.status=t,this.body=n}},V=class{facilitatorUrl;cachedSupported=null;cacheTime=0;CACHE_TTL_MS=6e4;timeoutMs;maxRetries;retryBaseMs;constructor(t=L,n){this.facilitatorUrl=t.replace(/\/$/,""),this.timeoutMs=n?.timeoutMs??1e4,this.maxRetries=n?.maxRetries??3,this.retryBaseMs=n?.retryBaseMs??500}async fetchWithTimeout(t,n){let r=new AbortController,i=setTimeout(()=>r.abort(),this.timeoutMs);try{return await fetch(t,{...n,signal:r.signal})}finally{clearTimeout(i)}}async fetchWithRetry(t,n){let r;for(let i=0;i<this.maxRetries;i++)try{let c=await this.fetchWithTimeout(t,n);if(!c.ok&&c.status>=500)throw new X(c.status,await c.text());return c}catch(c){if(r=c,i<this.maxRetries-1&&Je(c)){let d=this.retryBaseMs*Math.pow(2,i);await new Promise(g=>setTimeout(g,d));continue}throw c}throw r}async getSupported(){let t=Date.now();if(this.cachedSupported&&t-this.cacheTime<this.CACHE_TTL_MS)return this.cachedSupported;let n=await this.fetchWithTimeout(`${this.facilitatorUrl}/supported`);if(!n.ok)throw new Error(`Facilitator /supported returned ${n.status}`);return this.cachedSupported=await n.json(),this.cacheTime=t,this.cachedSupported}async getFeePayer(t){let r=(await this.getSupported()).kinds.find(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval")&&i.network===t);if(!r)throw new Error(`Facilitator does not support network "${t}" with a recognized scheme`);return r.extra?.feePayer}async getNetworkExtra(t){return(await this.getSupported()).kinds.find(i=>i.x402Version===2&&(i.scheme==="exact"||i.scheme==="exact-approval")&&i.network===t)?.extra}async verifyPayment(t,n){try{let r=K(t),i=await this.fetchWithRetry(`${this.facilitatorUrl}/verify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:r,paymentRequirements:n})});return i.ok?await i.json():{isValid:!1,invalidReason:`facilitator_error_${i.status}`}}catch(r){return{isValid:!1,invalidReason:r instanceof X?`facilitator_error_${r.status}`:r instanceof Error&&r.name==="AbortError"?"facilitator_timeout":r instanceof Error?r.message:"unexpected_verify_error"}}}async settlePayment(t,n){try{let r=K(t),i=await this.fetchWithRetry(`${this.facilitatorUrl}/settle`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({x402Version:2,paymentPayload:r,paymentRequirements:n})});return i.ok?{...await i.json(),network:n.network}:{success:!1,network:n.network,errorReason:`facilitator_error_${i.status}`}}catch(r){let i=r instanceof X?`facilitator_error_${r.status}`:r instanceof Error&&r.name==="AbortError"?"facilitator_timeout":r instanceof Error?r.message:"unexpected_settle_error";return{success:!1,network:n.network,errorReason:i}}}};function me(e){try{let t=K(e);return t?.accepted?.amount??t?.accepted?.maxAmountRequired}catch{return}}function j(e){let{payTo:t,facilitatorUrl:n=L,network:r=G,asset:i={address:Z,decimals:6},defaultTimeoutSeconds:c=60}=e,d=new V(n),g=null,P=new Map,w=3e4,k=Date.now();function A(a){let p=(a.maxTimeoutSeconds||c)*1e3;if(P.set(a.payTo,{accept:a,expiresAt:Date.now()+p}),Date.now()-k>w){let s=Date.now();for(let[R,_]of P)_.expiresAt<s&&P.delete(R);k=s}}function o(a){let p=P.get(a);if(p){if(p.expiresAt<Date.now()){P.delete(a);return}return p.accept}}async function x(a){return typeof t=="string"?t:t(a||{})}async function f(){if(g||(g=await d.getNetworkExtra(r)),le(r)&&!g?.feePayer)throw new Error(`Facilitator does not provide feePayer for network "${r}"`);return{...g?.feePayer?{feePayer:g.feePayer}:{},decimals:g?.decimals??i.decimals,name:g?.name,version:g?.version}}async function m(a,p){let{amountAtomic:s,timeoutSeconds:R=c}=p,_=await f(),E={scheme:"exact",network:r,amount:s,maxAmountRequired:s,asset:i.address,payTo:a,maxTimeoutSeconds:R,extra:_};return A(E),E}async function y(a){let p=await x({amountAtomic:a.amountAtomic,resourceUrl:a.resourceUrl});return m(p,a)}async function S(a){let{resourceUrl:p,description:s,mimeType:R="application/json"}=a,_={url:p,description:s,mimeType:R},E=await y(a);return{x402Version:2,resource:_,accepts:[E],error:"Payment required"}}function u(a){return F(a)}function h(a){return{status:402,headers:{"PAYMENT-REQUIRED":u(a)},body:{}}}async function l(a,p){if(!p){let s=await x({paymentHeader:a});p=o(s),p||(p=await m(s,{amountAtomic:me(a)??"0",resourceUrl:""}))}return d.verifyPayment(a,p)}async function b(a,p){if(!p){let s=await x({paymentHeader:a});p=o(s),p||(p=await m(s,{amountAtomic:me(a)??"0",resourceUrl:""}))}return d.settlePayment(a,p)}return{buildRequirements:S,encodeRequirements:u,create402Response:h,verifyPayment:l,settlePayment:b,getPaymentAccept:y,network:r,facilitator:d}}var fe=new WeakMap;function ge(e){return fe.get(e)}var Ye={base:"base","base-sepolia":"base_sepolia"},Qe={base:"eip155:8453","base-sepolia":"eip155:84532"},Ze=6;function ye(e){let t=typeof e=="string"?{secretKey:e}:e,n=t.network??"base",r=Ye[n]??"base",i=Qe[n]??"eip155:8453",c=t.apiVersion??"2026-01-28.clover",d=null;async function g(){if(d)return d;try{let{default:w}=await import("stripe");return d=new w(t.secretKey,{apiVersion:c,appInfo:{name:"@dexterai/x402",url:"https://dexter.cash/sdk"}}),d}catch{throw new Error('The "stripe" package is required for stripePayTo(). Install it with: npm install stripe')}}let P=async w=>{if(w.paymentHeader){try{let S=JSON.parse(Buffer.from(w.paymentHeader,"base64").toString()),u=S.payload?.authorization?.to;if(u&&typeof u=="string")return u;let h=S.accepted?.payTo;if(h&&typeof h=="string")return h}catch{}throw new Error("Could not extract deposit address from payment header. Ensure the client is sending a valid x402 PAYMENT-SIGNATURE.")}let k=await g(),A=w.amountAtomic?parseInt(w.amountAtomic,10):1e4,o=Math.max(1,Math.round(A/Math.pow(10,Ze-2))),f=(await k.paymentIntents.create({amount:o,currency:"usd",payment_method_types:["crypto"],payment_method_data:{type:"crypto"},payment_method_options:{crypto:{mode:"custom"}},confirm:!0})).next_action;if(!f?.crypto_collect_deposit_details)throw new Error("Stripe PaymentIntent did not return crypto deposit details. Ensure your Stripe account has crypto payins enabled: https://support.stripe.com/questions/get-started-with-pay-with-crypto");let m=f.crypto_collect_deposit_details,y=m.deposit_addresses?.[r]?.address;if(!y)throw new Error(`No deposit address found for network "${r}". Available networks: ${Object.keys(m.deposit_addresses||{}).join(", ")}`);return y};return P._x402Defaults={network:i,facilitatorUrl:"https://x402.dexter.cash"},fe.set(P,i),P}var et="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",tt=6;function rt(e,t){if(typeof e=="string"||typeof e=="function")return e;if(t in e)return e[t];let r=`${t.split(":")[0]}:*`;if(r in e)return e[r];if("*"in e)return e["*"];throw new Error(`No payTo configured for network "${t}"`)}function xe(e){let{payTo:t,amount:n,asset:r,description:i,resourceUrl:c,mimeType:d,timeoutSeconds:g,verbose:P=!1,getResourceUrl:w,getAmount:k,getDescription:A}=e,o=P?console.log.bind(console,"[x402:middleware]"):()=>{},x=typeof t=="function"?t._x402Defaults:void 0,f=e.facilitatorUrl??x?.facilitatorUrl,m=e.network?Array.isArray(e.network)?e.network:[e.network]:x?.network?[x.network]:[et],y=new Map;for(let u of m){let h=rt(t,u);if(typeof h=="function"){let l=ge(h);if(l&&u!==l)throw new Error(`stripePayTo is configured for "${l}" but middleware includes network "${u}". Stripe only supports Base deposit addresses. Use a static payTo for other chains.`)}y.set(u,j({payTo:h,network:u,asset:r,facilitatorUrl:f,defaultTimeoutSeconds:g}))}let S=y.get(m[0]);return async(u,h,l)=>{try{let b=u.headers["payment-signature"];if(!b){o("No payment signature, returning 402");let E=w?.(u)??c??`${u.protocol}://${u.get("host")}${u.originalUrl}`,M=k?.(u)??n,$=A?.(u)??i,T=r?.decimals??tt,U={amountAtomic:H(parseFloat(M),T),resourceUrl:E,description:$,mimeType:d,timeoutSeconds:g},q=[],C=null;for(let[,oe]of y)try{let Y=await oe.buildRequirements(U);q.push(...Y.accepts),C||(C=Y)}catch(Y){o("Failed to build requirements for a network:",Y)}if(!C||q.length===0){h.status(500).json({error:"Failed to build payment requirements"});return}C={...C,accepts:q};let J=S.encodeRequirements(C);h.setHeader("PAYMENT-REQUIRED",J),h.status(402).json({error:"Payment required",accepts:C.accepts,resource:C.resource});return}o("Payment signature received, verifying...");let a=S;try{let M=JSON.parse(Buffer.from(b,"base64").toString())?.accepted?.network;M&&y.has(M)&&(a=y.get(M))}catch{}let p=await a.verifyPayment(b);if(!p.isValid){if(o("Payment verification failed:",p.invalidReason),e.onVerifyFailed)try{await e.onVerifyFailed({reason:p.invalidReason,resourceUrl:`${u.protocol}://${u.get("host")}${u.originalUrl}`})}catch{}h.status(402).json({error:"Payment verification failed",reason:p.invalidReason});return}o("Payment verified, settling...");let s=await a.settlePayment(b);if(!s.success){o("Payment settlement failed:",s.errorReason),h.status(402).json({error:"Payment settlement failed",reason:s.errorReason});return}o("Payment settled:",s.transaction);let R=s.network||m[0];if(e.onSettlement)try{await e.onSettlement({transaction:s.transaction,network:R,payer:p.payer??"",resourceUrl:`${u.protocol}://${u.get("host")}${u.originalUrl}`})}catch{}u.x402={transaction:s.transaction,payer:p.payer??"",network:R};let _={success:!0,transaction:s.transaction,network:R,payer:p.payer??""};if(s.extensions&&(_.extensions=s.extensions),h.setHeader("PAYMENT-RESPONSE",F(_)),e.sponsoredAccess&&s.extensions?.["sponsored-access"]){let E=s.extensions["sponsored-access"],M=E?.info?.recommendations??E?.recommendations;if(M&&M.length>0){if(o("Injecting sponsored-access recommendations into response"),typeof e.sponsoredAccess=="object"&&e.sponsoredAccess.onMatch)try{e.sponsoredAccess.onMatch(M,{transaction:s.transaction,network:R,payer:p.payer??""})}catch{}let $=h.json.bind(h);h.json=function(v){return typeof e.sponsoredAccess=="object"&&e.sponsoredAccess.inject?$(e.sponsoredAccess.inject(v,M)):v&&typeof v=="object"&&!Array.isArray(v)?$({_x402_sponsored:M,...v}):$(v)}}}l()}catch(b){o("Middleware error:",b),h.status(500).json({error:"Payment processing error"})}}}function O(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}var nt='<svg width="18" height="18" viewBox="0 0 2000 2000" xmlns="http://www.w3.org/2000/svg"><path d="M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z" fill="#2775ca"/><path d="M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z" fill="#fff"/><path d="M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zM1229.17 295.83c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z" fill="#fff"/></svg>',it='<svg width="36" height="36" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg"><g><path fill="#F2681A" d="m324.93,313.11c-115.5,0-231,0-350,0l350,0z"/><path fill="#FDFAF5" d="m230.43,50.62c1.1.85 2.19 1.7 3.32 2.57 6.02 4.8 11.77 9.88 17.46 15.07.92.84.92.84 1.86 1.69 1.82 1.69 3.59 3.42 5.35 5.16.61.56 1.22 1.13 1.84 1.71 5.66 5.76 6.18 10.43 6.13 18.3.02 1.16.04 2.32.06 3.52.06 3.83.06 7.65.07 11.48.02 2.68.05 5.35.08 8.03.05 5.6.09 11.21.1 16.81.02 7.15.09 14.31.17 21.46.06 5.53.1 11.05.13 16.58.02 2.64.04 5.27.07 7.91.18 17.58.12 32.82-11.24 47.32-7.35 7.27-16.54 12.06-25.42 17.22-1.97 1.16-3.94 2.33-5.91 3.49-7.16 4.24-14.34 8.44-21.53 12.62-4.8 2.79-9.59 5.6-14.38 8.42-1.25.73-2.5 1.47-3.79 2.23-2.32 1.36-4.64 2.73-6.96 4.1-27.47 16.09-27.47 16.09-42.16 12.93-8.06-2.28-14.94-5.82-22.16-10.02-1.17-.67-2.34-1.34-3.54-2.04-24.55-14.25-43.58-27.03-51.9-55.58-1.07-4.58-1.54-8.92-1.52-13.61.28-9.5.28-9.5-3.3-17.97-1.81-1.49-3.68-2.92-5.59-4.28-9.19-7.06-12.7-20.03-14.18-31.06-.54-5.77-.55-11.56-.6-17.35-.03-1.32-.07-2.63-.1-3.99-.01-1.26-.02-2.53-.03-3.83-.02-1.15-.03-2.29-.05-3.47.72-4.02 1.94-5.36 5.21-7.74 2.89-.53 2.89-.53 6.07-.46 1.71.02 1.71.02 3.46.05 1.19.04 2.37.08 3.59.12 1.2.02 2.41.04 3.65.06 2.97.05 5.93.13 8.9.23.14-1.35.29-2.7.43-4.08.63-5 1.78-9.74 3.14-14.58.22-.79.43-1.59.66-2.4.53-1.92 1.06-3.84 1.6-5.76-1.55-.45-1.55-.45-3.13-.9-9.52-3.52-17.1-10.95-21.37-20.1-3.81-9.26-3.87-20.34-.29-29.68 6.49-13.99 16.36-23.23 30.66-29.01 49.81-17.69 115.79 8.35 155.13 38.85z"/><path fill="#F2671A" d="m142.93,22.62c.86.19 1.73.39 2.62.59 36.12 8.21 68.79 24.98 95.38 50.75 1.02.98 2.03 1.97 3.08 2.98 10.84 10.66 10.84 10.66 11.05 14.62-2.06 3.55-5.44 4.18-9.17 5.3-.79.25-1.59.49-2.41.75-28.13 8.43-60.95 6.37-87.13-7.16-.86-.49-1.71-.97-2.6-1.48-7.37-4.05-12.59-3.36-20.59-1.54-22.76 4-48.47 1.53-68.69-9.74-4.88-3.88-8.23-8.29-10.21-14.22-.93-10.38-.67-18.44 5.83-26.83 19.57-23.38 55.99-20.36 82.83-14z"/><path fill="#F16619" d="m44.93,129.12c27.36-.03 54.72-.05 82.08-.06 12.7-.01 25.41-.01 38.11-.03 11.07-.01 22.14-.02 33.2-.02 5.86 0 11.73-.01 17.59-.01 5.51-.01 11.03-.01 16.54-.01 2.03 0 4.06 0 6.09-.01 2.76-.01 5.52 0 8.28 0 .81 0 1.63-.01 2.47-.01 5.51.02 5.51.02 6.81 1.32.22 3.43.22 3.43 0 7-2.75 2.75-3.42 2.66-7.15 2.82-1.41.07-1.41.07-2.85.14-1.47.05-1.47.05-2.98.11-1.49.07-1.49.07-3 .14-2.45.11-4.9.21-7.35.3-.2 1.3-.4 2.59-.6 3.93-2.57 16.08-5.93 29.89-18.89 40.86-10.35 7.28-21.87 8.49-34.17 7.71-13.11-2.33-22.52-9.19-30.33-19.83-4.49-7.64-4.8-17.05-5.83-25.67-4.24.39-8.47.77-12.83 1.17-.28 1.84-.28 1.84-.56 3.71-2.32 14.39-5.63 23.35-16.95 33.11-2.32 1.67-2.32 1.67-4.65 1.67 4 4.67 9.06 6.59 14.87 8.24 3.79 1.09 3.79 1.09 6.12 3.43-.65 5.31-.65 5.31-2.33 7-8.42-.27-15.13-2.29-22.17-7-1.09-1.21-2.17-2.43-3.25-3.65-2.72-2.81-4.45-3.84-8.36-4.16-1.67-.02-3.34-.02-5.01.01-1.77-.04-3.54-.09-5.3-.15-1.27-.04-1.27-.04-2.56-.08-9.26-.54-17.6-4.56-24.51-10.64-9.58-11.11-11.03-22.56-10.72-36.82.02-1.4.03-2.8.05-4.24.04-3.42.1-6.85.17-10.27z"/><path fill="#F26117" d="m172.68,203.08c7.27.09 13.23 1.97 18.87 6.65 2.88 3.07 3.86 5.12 4.25 9.32-.12 1.01-.24 2.02-.36 3.06-2.55.95-2.55.95-5.83 1.17-3.28-2.84-3.28-2.84-5.83-5.83-.36.58-.71 1.16-1.08 1.75-7.6 11.29-20.06 17.74-33.05 21.09-20.36 3.1-36.81-1.66-53.37-13.73-2.33-2.11-2.33-2.11-4.67-5.61.42-3.45.99-4.49 3.5-7 4.07.37 5.95 2.13 8.75 4.96 9.81 8.93 22.53 11.87 35.51 11.69 11.74-1.05 22.38-5.85 31.57-13.15 2.06-2.45 2.06-2.45 3.5-4.67-1.66.07-1.66.07-3.35.15-3.65-.15-3.65-.15-5.98-2.48.75-6.18 1.46-7.19 7.58-7.36z"/></g></svg>',st=`
742
2
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Orbitron:wght@500;700&display=swap');
743
3
  *{margin:0;padding:0;box-sizing:border-box}
744
4
  body{font-family:'Inter',system-ui,-apple-system,sans-serif;background:#0a0a0a;color:#e2e8f0;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:1rem}
@@ -760,8 +20,7 @@ h1{font-family:'Orbitron',sans-serif;font-size:1.15rem;font-weight:700;color:#f1
760
20
  .footer a{color:#525252;text-decoration:none}
761
21
  .footer a:hover{color:#737373}
762
22
  .sep{width:3px;height:3px;border-radius:50%;background:#333}
763
- `;
764
- var PAY_BUTTON_STYLES = `
23
+ `,ot=`
765
24
  .pay-section{margin:1.25rem 0}
766
25
  .pay-btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;background:linear-gradient(135deg,#F26B1A,#D13F00);color:#fff;border:none;padding:.65rem 2rem;border-radius:6px;font-family:'Inter',sans-serif;font-size:.95rem;font-weight:600;cursor:pointer;transition:opacity .15s,transform .1s;min-width:180px}
767
26
  .pay-btn:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}
@@ -777,8 +36,7 @@ var PAY_BUTTON_STYLES = `
777
36
  .result-box{background:rgba(34,197,94,.06);border:1px solid rgba(34,197,94,.15);border-radius:6px;padding:.75rem;margin-top:.75rem;text-align:left;font-size:.78rem;max-height:200px;overflow:auto}
778
37
  .result-box pre{color:#94a3b8;font-family:'SF Mono',Monaco,Consolas,monospace;white-space:pre-wrap;word-break:break-all}
779
38
  .no-wallet{font-size:.82rem;color:#737373;margin:1rem 0}
780
- `;
781
- var PAY_SCRIPT = `
39
+ `,at=`
782
40
  <script type="module">
783
41
  // Payment data is embedded in #x402-data attributes
784
42
  const dataEl = document.getElementById('x402-data');
@@ -975,48 +233,27 @@ if (btn) {
975
233
  });
976
234
  }
977
235
  </script>
978
- `;
979
- function generatePaywallHtml(paymentRequiredHeader, requestUrl, method, config, rpcUrl, requestBody) {
980
- let price = "?";
981
- let description = "This resource requires payment";
982
- let network = "";
983
- try {
984
- const decoded = JSON.parse(Buffer.from(paymentRequiredHeader, "base64").toString());
985
- const accept = decoded.accepts?.[0];
986
- if (accept) {
987
- const amount = accept.amount ?? accept.maxAmountRequired ?? "0";
988
- const decimals = accept.extra?.decimals || 6;
989
- price = (Number(amount) / Math.pow(10, decimals)).toFixed(decimals > 4 ? 4 : 2);
990
- network = accept.network || "";
991
- }
992
- if (decoded.resource?.description) {
993
- description = decoded.resource.description;
994
- }
995
- } catch {
996
- }
997
- const chainName = network.includes("solana") ? "Solana" : network.includes("eip155") ? "Base" : "";
998
- const endpointSection = config.showEndpoint ? `<div class="endpoint"><code>${escapeHtml(method)} ${escapeHtml(requestUrl)}</code></div>` : "";
999
- return `<!DOCTYPE html>
236
+ `;function ct(e,t,n,r,i,c){let d="?",g="This resource requires payment",P="";try{let A=JSON.parse(Buffer.from(e,"base64").toString()),o=A.accepts?.[0];if(o){let x=o.amount??o.maxAmountRequired??"0",f=o.extra?.decimals||6;d=(Number(x)/Math.pow(10,f)).toFixed(f>4?4:2),P=o.network||""}A.resource?.description&&(g=A.resource.description)}catch{}let w=P.includes("solana")?"Solana":P.includes("eip155")?"Base":"",k=r.showEndpoint?`<div class="endpoint"><code>${O(n)} ${O(t)}</code></div>`:"";return`<!DOCTYPE html>
1000
237
  <html lang="en">
1001
238
  <head>
1002
239
  <meta charset="utf-8">
1003
240
  <meta name="viewport" content="width=device-width,initial-scale=1">
1004
- <title>${escapeHtml(config.title)} \u2014 ${escapeHtml(price)} USDC</title>
1005
- <style>${DEXTER_STYLES}${PAY_BUTTON_STYLES}</style>
241
+ <title>${O(r.title)} \u2014 ${O(d)} USDC</title>
242
+ <style>${st}${ot}</style>
1006
243
  </head>
1007
244
  <body>
1008
245
  <div class="card">
1009
- <div class="crest">${DEXTER_CREST_SVG}</div>
1010
- <h1>${escapeHtml(config.title)}</h1>
1011
- <p class="desc">${escapeHtml(description)}</p>
1012
- <div class="price">${USDC_ICON_SVG}<span id="price-value">${escapeHtml(price)}</span></div>
1013
- <div class="chain">${escapeHtml(chainName)}${chainName ? " network" : ""}</div>
1014
- ${endpointSection}
246
+ <div class="crest">${it}</div>
247
+ <h1>${O(r.title)}</h1>
248
+ <p class="desc">${O(g)}</p>
249
+ <div class="price">${nt}<span id="price-value">${O(d)}</span></div>
250
+ <div class="chain">${O(w)}${w?" network":""}</div>
251
+ ${k}
1015
252
 
1016
253
  <div id="pay-section" class="pay-section" style="display:none">
1017
- <button id="pay-btn" class="pay-btn">Pay ${price}</button>
254
+ <button id="pay-btn" class="pay-btn">Pay ${d}</button>
1018
255
  <div id="pay-status" class="pay-status"></div>
1019
- <div class="pay-alt">or use <a href="${config.sdkUrl}">x402 SDK</a> for programmatic access</div>
256
+ <div class="pay-alt">or use <a href="${r.sdkUrl}">x402 SDK</a> for programmatic access</div>
1020
257
  </div>
1021
258
 
1022
259
  <div id="no-wallet" class="no-wallet" style="display:none">
@@ -1024,7 +261,7 @@ function generatePaywallHtml(paymentRequiredHeader, requestUrl, method, config,
1024
261
  <strong>Access this endpoint:</strong><br><br>
1025
262
  Use any x402-compatible client or a browser with a Solana wallet extension (Phantom, Solflare, Backpack).<br><br>
1026
263
  <code>npm install @dexterai/x402</code><br><br>
1027
- <a href="${config.sdkUrl}">x402 SDK docs &rarr;</a>
264
+ <a href="${r.sdkUrl}">x402 SDK docs &rarr;</a>
1028
265
  </div>
1029
266
  </div>
1030
267
 
@@ -1036,1129 +273,14 @@ function generatePaywallHtml(paymentRequiredHeader, requestUrl, method, config,
1036
273
  </div>
1037
274
 
1038
275
  <div id="x402-data" style="display:none"
1039
- data-requirements="${paymentRequiredHeader}"
1040
- data-method="${method}"
1041
- data-url="${requestUrl}"
1042
- data-rpc="${rpcUrl}"
1043
- data-body="${requestBody ? Buffer.from(requestBody).toString("base64") : ""}"
276
+ data-requirements="${e}"
277
+ data-method="${n}"
278
+ data-url="${t}"
279
+ data-rpc="${i}"
280
+ data-body="${c?Buffer.from(c).toString("base64"):""}"
1044
281
  ></div>
1045
- ${PAY_SCRIPT}
282
+ ${at}
1046
283
  </body>
1047
- </html>`;
1048
- }
1049
- function x402BrowserSupport(config = {}) {
1050
- const resolvedConfig = {
1051
- title: config.title ?? "Payment Required",
1052
- branding: config.branding ?? 'Powered by <a href="https://docs.dexter.cash/docs/sdk/">Dexter x402</a>',
1053
- sdkUrl: config.sdkUrl ?? "https://docs.dexter.cash/docs/sdk/",
1054
- showEndpoint: config.showEndpoint ?? true
1055
- };
1056
- const rpcUrl = config.rpcUrl ?? "https://api.dexter.cash/api/solana/rpc";
1057
- return (req, res, next) => {
1058
- const originalJson = res.json.bind(res);
1059
- res.json = function(body) {
1060
- if (res.statusCode === 402 && req.accepts("html") && !req.headers["payment-signature"]) {
1061
- const paymentRequired = res.getHeader("PAYMENT-REQUIRED") || res.getHeader("payment-required");
1062
- if (paymentRequired && typeof paymentRequired === "string") {
1063
- let bodyStr;
1064
- if (req.body && typeof req.body === "object" && Object.keys(req.body).length > 0) {
1065
- try {
1066
- bodyStr = JSON.stringify(req.body);
1067
- } catch {
1068
- }
1069
- }
1070
- const html = generatePaywallHtml(
1071
- paymentRequired,
1072
- req.originalUrl,
1073
- req.method,
1074
- resolvedConfig,
1075
- rpcUrl,
1076
- bodyStr
1077
- );
1078
- res.setHeader("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; connect-src *; img-src data:; frame-ancestors 'none'");
1079
- res.setHeader("X-Content-Type-Options", "nosniff");
1080
- res.status(402).type("html").send(html);
1081
- return res;
1082
- }
1083
- }
1084
- return originalJson(body);
1085
- };
1086
- next();
1087
- };
1088
- }
1089
-
1090
- // src/server/access-pass.ts
1091
- var import_crypto = __toESM(require("crypto"), 1);
1092
- var DURATION_REGEX = /^(\d+)(m|h|d|w)$/;
1093
- function parseTierDuration(tierId) {
1094
- const match = tierId.match(DURATION_REGEX);
1095
- if (!match) return null;
1096
- const value = parseInt(match[1], 10);
1097
- const unit = match[2];
1098
- switch (unit) {
1099
- case "m":
1100
- return value * 60;
1101
- case "h":
1102
- return value * 3600;
1103
- case "d":
1104
- return value * 86400;
1105
- case "w":
1106
- return value * 604800;
1107
- default:
1108
- return null;
1109
- }
1110
- }
1111
- function formatDuration(seconds) {
1112
- if (seconds >= 604800 && seconds % 604800 === 0) return `${seconds / 604800} week${seconds / 604800 > 1 ? "s" : ""}`;
1113
- if (seconds >= 86400 && seconds % 86400 === 0) return `${seconds / 86400} day${seconds / 86400 > 1 ? "s" : ""}`;
1114
- if (seconds >= 3600 && seconds % 3600 === 0) return `${seconds / 3600} hour${seconds / 3600 > 1 ? "s" : ""}`;
1115
- if (seconds >= 60 && seconds % 60 === 0) return `${seconds / 60} minute${seconds / 60 > 1 ? "s" : ""}`;
1116
- return `${seconds} second${seconds > 1 ? "s" : ""}`;
1117
- }
1118
- function signJwt(payload, secret) {
1119
- const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url");
1120
- const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
1121
- const sig = import_crypto.default.createHmac("sha256", secret).update(`${header}.${body}`).digest("base64url");
1122
- return `${header}.${body}.${sig}`;
1123
- }
1124
- function verifyJwt(token, secret) {
1125
- try {
1126
- const parts = token.split(".");
1127
- if (parts.length !== 3) return null;
1128
- const [header, body, sig] = parts;
1129
- const expected = import_crypto.default.createHmac("sha256", secret).update(`${header}.${body}`).digest("base64url");
1130
- if (sig !== expected) return null;
1131
- const payload = JSON.parse(Buffer.from(body, "base64url").toString());
1132
- if (payload.exp && Date.now() / 1e3 > payload.exp) return null;
1133
- if (payload.sub !== "x402-access-pass") return null;
1134
- return payload;
1135
- } catch {
1136
- return null;
1137
- }
1138
- }
1139
- var DEFAULT_NETWORK2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
1140
- var USDC_DECIMALS3 = 6;
1141
- function x402AccessPass(config) {
1142
- const {
1143
- payTo,
1144
- network = DEFAULT_NETWORK2,
1145
- asset,
1146
- facilitatorUrl,
1147
- tiers: tierPrices,
1148
- ratePerHour,
1149
- secret: explicitSecret,
1150
- issuer = "x402-access-pass",
1151
- verbose = false,
1152
- description
1153
- } = config;
1154
- const secret = explicitSecret ?? import_crypto.default.randomBytes(32);
1155
- if (!explicitSecret) {
1156
- console.warn("[x402:access-pass] No secret provided \u2014 access passes will be invalidated on server restart. Set `secret` for production use.");
1157
- }
1158
- if (!tierPrices && !ratePerHour) {
1159
- throw new Error("x402AccessPass: at least one of `tiers` or `ratePerHour` is required");
1160
- }
1161
- const log = verbose ? console.log.bind(console, "[x402:access-pass]") : () => {
1162
- };
1163
- const decimals = asset?.decimals ?? USDC_DECIMALS3;
1164
- const builtTiers = [];
1165
- if (tierPrices) {
1166
- for (const [id, price] of Object.entries(tierPrices)) {
1167
- const seconds = parseTierDuration(id);
1168
- if (!seconds) {
1169
- console.warn(`x402AccessPass: skipping tier "${id}" \u2014 unrecognized duration format (use 5m, 1h, 24h, 7d)`);
1170
- continue;
1171
- }
1172
- builtTiers.push({
1173
- id,
1174
- label: formatDuration(seconds),
1175
- seconds,
1176
- price,
1177
- priceAtomic: toAtomicUnits(parseFloat(price), decimals)
1178
- });
1179
- }
1180
- builtTiers.sort((a, b) => a.seconds - b.seconds);
1181
- }
1182
- const server = createX402Server({
1183
- payTo,
1184
- network,
1185
- asset,
1186
- facilitatorUrl
1187
- });
1188
- const passInfo = {
1189
- tiers: builtTiers.length > 0 ? builtTiers : void 0,
1190
- ratePerHour: ratePerHour || void 0,
1191
- issuer
1192
- };
1193
- const passInfoEncoded = encodeBase64Json(passInfo);
1194
- function calculateCustomPrice(durationSeconds) {
1195
- if (!ratePerHour) {
1196
- throw new Error("Custom durations not supported \u2014 no ratePerHour configured");
1197
- }
1198
- const hours = durationSeconds / 3600;
1199
- const price = (parseFloat(ratePerHour) * hours).toFixed(decimals > 4 ? 4 : 2);
1200
- return { price, priceAtomic: toAtomicUnits(parseFloat(price), decimals) };
1201
- }
1202
- function resolvePricing(req) {
1203
- const tierParam = req.query.tier;
1204
- const durationParam = req.query.duration;
1205
- if (tierParam) {
1206
- const found = builtTiers.find((t) => t.id === tierParam);
1207
- if (found) {
1208
- return { tier: found.id, seconds: found.seconds, price: found.price, priceAtomic: found.priceAtomic, label: found.label };
1209
- }
1210
- }
1211
- if (durationParam) {
1212
- const seconds = parseInt(durationParam, 10);
1213
- if (seconds > 0 && ratePerHour) {
1214
- const pricing2 = calculateCustomPrice(seconds);
1215
- return { tier: "custom", seconds, ...pricing2, label: formatDuration(seconds) };
1216
- }
1217
- }
1218
- if (builtTiers.length > 0) {
1219
- const t = builtTiers[0];
1220
- return { tier: t.id, seconds: t.seconds, price: t.price, priceAtomic: t.priceAtomic, label: t.label };
1221
- }
1222
- const pricing = calculateCustomPrice(3600);
1223
- return { tier: "custom", seconds: 3600, ...pricing, label: "1 hour" };
1224
- }
1225
- return async (req, res, next) => {
1226
- try {
1227
- const auth = req.headers.authorization;
1228
- if (auth?.startsWith("Bearer ")) {
1229
- const claims = verifyJwt(auth.slice(7), secret);
1230
- if (claims) {
1231
- log("Valid access pass:", claims.tier, "| expires:", new Date(claims.exp * 1e3).toISOString());
1232
- req.accessPass = {
1233
- tier: claims.tier,
1234
- duration: claims.duration,
1235
- expiresAt: new Date(claims.exp * 1e3).toISOString(),
1236
- payer: claims.payer,
1237
- network: claims.network
1238
- };
1239
- return next();
1240
- }
1241
- log("Invalid or expired access pass token");
1242
- }
1243
- const paymentSignature = req.headers["payment-signature"];
1244
- if (paymentSignature) {
1245
- log("Payment signature received, verifying for pass purchase...");
1246
- const verifyResult = await server.verifyPayment(paymentSignature);
1247
- if (!verifyResult.isValid) {
1248
- log("Payment verification failed:", verifyResult.invalidReason);
1249
- res.status(402).json({ error: "Payment verification failed", reason: verifyResult.invalidReason });
1250
- return;
1251
- }
1252
- const settleResult = await server.settlePayment(paymentSignature);
1253
- if (!settleResult.success) {
1254
- log("Payment settlement failed:", settleResult.errorReason);
1255
- res.status(402).json({ error: "Payment settlement failed", reason: settleResult.errorReason });
1256
- return;
1257
- }
1258
- log("Payment settled:", settleResult.transaction);
1259
- const pricing2 = resolvePricing(req);
1260
- const now = Math.floor(Date.now() / 1e3);
1261
- const claims = {
1262
- sub: "x402-access-pass",
1263
- tier: pricing2.tier,
1264
- duration: pricing2.seconds,
1265
- iat: now,
1266
- exp: now + pricing2.seconds,
1267
- payer: verifyResult.payer ?? "",
1268
- network,
1269
- iss: issuer
1270
- };
1271
- const jwt = signJwt(claims, secret);
1272
- req.x402 = {
1273
- transaction: settleResult.transaction,
1274
- payer: verifyResult.payer ?? "",
1275
- network
1276
- };
1277
- const paymentResponseData = {
1278
- success: true,
1279
- transaction: settleResult.transaction,
1280
- network,
1281
- payer: verifyResult.payer ?? ""
1282
- };
1283
- res.setHeader("PAYMENT-RESPONSE", encodeBase64Json(paymentResponseData));
1284
- res.setHeader("ACCESS-PASS", jwt);
1285
- res.json({
1286
- accessPass: {
1287
- token: jwt,
1288
- tier: pricing2.tier,
1289
- duration: pricing2.label,
1290
- durationSeconds: pricing2.seconds,
1291
- expiresAt: new Date((now + pricing2.seconds) * 1e3).toISOString(),
1292
- usage: "Include on subsequent requests as: Authorization: Bearer <token>"
1293
- },
1294
- transaction: settleResult.transaction,
1295
- payer: verifyResult.payer
1296
- });
1297
- return;
1298
- }
1299
- log("No access pass or payment, returning 402");
1300
- const pricing = resolvePricing(req);
1301
- const amountAtomic = pricing.priceAtomic;
1302
- const resourceUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
1303
- const requirements = await server.buildRequirements({
1304
- amountAtomic,
1305
- resourceUrl,
1306
- description: description || `Access pass: ${pricing.label}`,
1307
- mimeType: "application/json"
1308
- });
1309
- const encoded = server.encodeRequirements(requirements);
1310
- res.setHeader("PAYMENT-REQUIRED", encoded);
1311
- res.setHeader("X-ACCESS-PASS-TIERS", passInfoEncoded);
1312
- res.status(402).json({
1313
- error: "Access pass required",
1314
- message: "Purchase an access pass to unlock unlimited API access for a time window.",
1315
- accepts: requirements.accepts,
1316
- resource: requirements.resource,
1317
- accessPass: {
1318
- tiers: builtTiers.length > 0 ? builtTiers : void 0,
1319
- ratePerHour: ratePerHour || void 0,
1320
- usage: "Add ?tier=<id> or ?duration=<seconds> to your payment request to choose a pass duration."
1321
- }
1322
- });
1323
- } catch (error) {
1324
- log("Access pass middleware error:", error);
1325
- res.status(500).json({
1326
- error: "Payment processing error",
1327
- message: error instanceof Error ? error.message : "Unknown error"
1328
- });
1329
- }
1330
- };
1331
- }
1332
-
1333
- // src/server/dynamic-pricing.ts
1334
- var import_crypto2 = require("crypto");
1335
- var QUOTE_MAX_AGE_SECONDS = 300;
1336
- function createDynamicPricing(config) {
1337
- const fullConfig = {
1338
- unitSize: config.unitSize,
1339
- ratePerUnit: config.ratePerUnit,
1340
- minUsd: config.minUsd ?? 0.01,
1341
- maxUsd: config.maxUsd ?? Infinity,
1342
- roundingMode: config.roundingMode ?? "ceil",
1343
- decimals: config.decimals ?? 6
1344
- };
1345
- const { unitSize, ratePerUnit, minUsd, maxUsd, roundingMode, decimals } = fullConfig;
1346
- if (unitSize <= 0) throw new Error("unitSize must be positive");
1347
- if (ratePerUnit <= 0) throw new Error("ratePerUnit must be positive");
1348
- if (minUsd < 0) throw new Error("minUsd cannot be negative");
1349
- if (maxUsd < minUsd) throw new Error("maxUsd must be >= minUsd");
1350
- const hmacSecret = (0, import_crypto2.randomBytes)(32);
1351
- function signQuote(input, timestamp) {
1352
- const configStr = JSON.stringify({
1353
- unitSize,
1354
- ratePerUnit,
1355
- minUsd,
1356
- maxUsd: maxUsd === Infinity ? "none" : maxUsd,
1357
- roundingMode
1358
- });
1359
- const data = `${input}|${configStr}|${timestamp}`;
1360
- return (0, import_crypto2.createHmac)("sha256", hmacSecret).update(data).digest("hex").slice(0, 16);
1361
- }
1362
- function calculate(input) {
1363
- const inputLength = input.length;
1364
- const rawUnits = inputLength / unitSize;
1365
- let units;
1366
- switch (roundingMode) {
1367
- case "ceil":
1368
- units = Math.ceil(rawUnits);
1369
- break;
1370
- case "floor":
1371
- units = Math.floor(rawUnits);
1372
- break;
1373
- case "round":
1374
- units = Math.round(rawUnits);
1375
- break;
1376
- }
1377
- if (inputLength > 0 && units === 0) {
1378
- units = 1;
1379
- }
1380
- let usdAmount = units * ratePerUnit;
1381
- usdAmount = Math.max(minUsd, usdAmount);
1382
- usdAmount = Math.min(maxUsd, usdAmount);
1383
- const multiplier = Math.pow(10, decimals);
1384
- const amountAtomic = Math.floor(usdAmount * multiplier).toString();
1385
- const timestamp = Math.floor(Date.now() / 1e3);
1386
- const mac = signQuote(input, timestamp);
1387
- const quoteHash = `${timestamp}.${mac}`;
1388
- return {
1389
- amountAtomic,
1390
- usdAmount,
1391
- quoteHash,
1392
- units,
1393
- inputLength
1394
- };
1395
- }
1396
- function validateQuote(input, quoteHash) {
1397
- if (!quoteHash) return false;
1398
- const dotIndex = quoteHash.indexOf(".");
1399
- if (dotIndex === -1) return false;
1400
- const timestamp = parseInt(quoteHash.slice(0, dotIndex), 10);
1401
- const mac = quoteHash.slice(dotIndex + 1);
1402
- if (isNaN(timestamp) || !mac) return false;
1403
- const age = Math.floor(Date.now() / 1e3) - timestamp;
1404
- if (age < 0 || age > QUOTE_MAX_AGE_SECONDS) return false;
1405
- const expectedMac = signQuote(input, timestamp);
1406
- if (mac.length !== expectedMac.length) return false;
1407
- let mismatch = 0;
1408
- for (let i = 0; i < mac.length; i++) {
1409
- mismatch |= mac.charCodeAt(i) ^ expectedMac.charCodeAt(i);
1410
- }
1411
- return mismatch === 0;
1412
- }
1413
- return {
1414
- calculate,
1415
- validateQuote,
1416
- config: fullConfig
1417
- };
1418
- }
1419
- function formatPricing(config) {
1420
- const rate = config.ratePerUnit.toFixed(2);
1421
- const units = config.unitSize.toLocaleString();
1422
- return `from $${rate} per ${units} chars`;
1423
- }
1424
-
1425
- // src/server/token-pricing.ts
1426
- var import_crypto3 = require("crypto");
1427
-
1428
- // src/server/model-registry.ts
1429
- var STANDARD_PARAMS = {
1430
- usesMaxCompletionTokens: false,
1431
- supportsTemperature: true,
1432
- supportsTopP: true,
1433
- supportsFrequencyPenalty: true,
1434
- supportsPresencePenalty: true,
1435
- supportsReasoningEffort: false,
1436
- supportsStreaming: true,
1437
- supportsSystemMessage: true,
1438
- supportsTools: true,
1439
- supportsStructuredOutput: true
1440
- };
1441
- var GPT5_PARAMS = {
1442
- usesMaxCompletionTokens: true,
1443
- // GPT-5 requires this!
1444
- supportsTemperature: false,
1445
- // Only default (1) is supported
1446
- supportsTopP: false,
1447
- // Likely same restriction
1448
- supportsFrequencyPenalty: false,
1449
- supportsPresencePenalty: false,
1450
- supportsReasoningEffort: false,
1451
- supportsStreaming: true,
1452
- supportsSystemMessage: true,
1453
- supportsTools: true,
1454
- supportsStructuredOutput: true
1455
- };
1456
- var REASONING_PARAMS = {
1457
- usesMaxCompletionTokens: true,
1458
- supportsTemperature: false,
1459
- // Fixed at 1
1460
- supportsTopP: false,
1461
- supportsFrequencyPenalty: false,
1462
- supportsPresencePenalty: false,
1463
- supportsReasoningEffort: true,
1464
- supportsStreaming: true,
1465
- supportsSystemMessage: true,
1466
- // Developer message
1467
- supportsTools: true,
1468
- supportsStructuredOutput: true
1469
- };
1470
- var PRO_REASONING_PARAMS = {
1471
- ...REASONING_PARAMS,
1472
- supportsStreaming: false
1473
- // Pro models may not stream
1474
- };
1475
- var MODEL_REGISTRY = [
1476
- // =========================================================================
1477
- // FAST TIER - Cheapest, fastest, good for simple tasks
1478
- // =========================================================================
1479
- {
1480
- id: "gpt-4o-mini",
1481
- displayName: "GPT-4o Mini",
1482
- family: "gpt-4o",
1483
- tier: "fast",
1484
- capabilityRank: 3,
1485
- modalities: ["text", "vision"],
1486
- apiType: "chat",
1487
- pricing: { input: 0.15, output: 0.6, cached: 0.075 },
1488
- contextWindow: 128e3,
1489
- defaultMaxOutput: 4096,
1490
- maxOutputTokens: 16384,
1491
- parameters: STANDARD_PARAMS,
1492
- deprecated: false,
1493
- description: "Fast, affordable small model with vision support"
1494
- },
1495
- {
1496
- id: "gpt-4.1-nano",
1497
- displayName: "GPT-4.1 Nano",
1498
- family: "gpt-4.1",
1499
- tier: "fast",
1500
- capabilityRank: 2,
1501
- modalities: ["text"],
1502
- apiType: "chat",
1503
- pricing: { input: 0.1, output: 0.4, cached: 0.025 },
1504
- contextWindow: 128e3,
1505
- defaultMaxOutput: 4096,
1506
- maxOutputTokens: 32768,
1507
- parameters: STANDARD_PARAMS,
1508
- deprecated: false,
1509
- description: "Smallest 4.1 model, very fast and cheap"
1510
- },
1511
- {
1512
- id: "gpt-4.1-mini",
1513
- displayName: "GPT-4.1 Mini",
1514
- family: "gpt-4.1",
1515
- tier: "fast",
1516
- capabilityRank: 4,
1517
- modalities: ["text"],
1518
- apiType: "chat",
1519
- pricing: { input: 0.4, output: 1.6, cached: 0.1 },
1520
- contextWindow: 128e3,
1521
- defaultMaxOutput: 4096,
1522
- maxOutputTokens: 32768,
1523
- parameters: STANDARD_PARAMS,
1524
- deprecated: false,
1525
- description: "Balanced 4.1 model, good price/performance"
1526
- },
1527
- {
1528
- id: "gpt-5-nano",
1529
- displayName: "GPT-5 Nano",
1530
- family: "gpt-5",
1531
- tier: "fast",
1532
- capabilityRank: 1,
1533
- modalities: ["text"],
1534
- apiType: "chat",
1535
- pricing: { input: 0.05, output: 0.4, cached: 5e-3 },
1536
- contextWindow: 128e3,
1537
- defaultMaxOutput: 4096,
1538
- maxOutputTokens: 16384,
1539
- parameters: GPT5_PARAMS,
1540
- deprecated: false,
1541
- description: "Cheapest GPT-5 variant, extremely fast"
1542
- },
1543
- {
1544
- id: "gpt-5-mini",
1545
- displayName: "GPT-5 Mini",
1546
- family: "gpt-5",
1547
- tier: "fast",
1548
- capabilityRank: 5,
1549
- modalities: ["text"],
1550
- apiType: "chat",
1551
- pricing: { input: 0.25, output: 2, cached: 0.025 },
1552
- contextWindow: 128e3,
1553
- defaultMaxOutput: 8192,
1554
- maxOutputTokens: 32768,
1555
- parameters: GPT5_PARAMS,
1556
- deprecated: false,
1557
- description: "Small but capable GPT-5, great value"
1558
- },
1559
- // =========================================================================
1560
- // STANDARD TIER - Balanced price/performance
1561
- // =========================================================================
1562
- {
1563
- id: "gpt-4o",
1564
- displayName: "GPT-4o",
1565
- family: "gpt-4o",
1566
- tier: "standard",
1567
- capabilityRank: 5,
1568
- modalities: ["text", "vision"],
1569
- apiType: "chat",
1570
- pricing: { input: 2.5, output: 10, cached: 1.25 },
1571
- contextWindow: 128e3,
1572
- defaultMaxOutput: 4096,
1573
- maxOutputTokens: 16384,
1574
- parameters: STANDARD_PARAMS,
1575
- deprecated: false,
1576
- description: "Flagship multimodal model with vision"
1577
- },
1578
- {
1579
- id: "gpt-4.1",
1580
- displayName: "GPT-4.1",
1581
- family: "gpt-4.1",
1582
- tier: "standard",
1583
- capabilityRank: 6,
1584
- modalities: ["text"],
1585
- apiType: "chat",
1586
- pricing: { input: 2, output: 8, cached: 0.5 },
1587
- contextWindow: 1e6,
1588
- // 1M context!
1589
- defaultMaxOutput: 8192,
1590
- maxOutputTokens: 32768,
1591
- parameters: STANDARD_PARAMS,
1592
- deprecated: false,
1593
- description: "Long context specialist, 1M token window"
1594
- },
1595
- {
1596
- id: "gpt-5",
1597
- displayName: "GPT-5",
1598
- family: "gpt-5",
1599
- tier: "standard",
1600
- capabilityRank: 7,
1601
- modalities: ["text"],
1602
- apiType: "chat",
1603
- pricing: { input: 1.25, output: 10, cached: 0.125 },
1604
- contextWindow: 128e3,
1605
- defaultMaxOutput: 8192,
1606
- maxOutputTokens: 32768,
1607
- parameters: GPT5_PARAMS,
1608
- deprecated: false,
1609
- description: "Base GPT-5, excellent all-around"
1610
- },
1611
- {
1612
- id: "gpt-5.1",
1613
- displayName: "GPT-5.1",
1614
- family: "gpt-5",
1615
- tier: "standard",
1616
- capabilityRank: 8,
1617
- modalities: ["text"],
1618
- apiType: "chat",
1619
- pricing: { input: 1.25, output: 10, cached: 0.125 },
1620
- contextWindow: 128e3,
1621
- defaultMaxOutput: 8192,
1622
- maxOutputTokens: 32768,
1623
- parameters: GPT5_PARAMS,
1624
- deprecated: false,
1625
- description: "Improved GPT-5 with better instruction following"
1626
- },
1627
- {
1628
- id: "gpt-5.2",
1629
- displayName: "GPT-5.2",
1630
- family: "gpt-5",
1631
- tier: "standard",
1632
- capabilityRank: 9,
1633
- modalities: ["text"],
1634
- apiType: "chat",
1635
- pricing: { input: 1.75, output: 14, cached: 0.175 },
1636
- contextWindow: 128e3,
1637
- defaultMaxOutput: 8192,
1638
- maxOutputTokens: 32768,
1639
- parameters: GPT5_PARAMS,
1640
- deprecated: false,
1641
- description: "Latest GPT-5, most capable standard model"
1642
- },
1643
- // =========================================================================
1644
- // REASONING TIER - Chain-of-thought reasoning (o-series)
1645
- // =========================================================================
1646
- {
1647
- id: "o1-mini",
1648
- displayName: "o1 Mini",
1649
- family: "o1",
1650
- tier: "reasoning",
1651
- capabilityRank: 3,
1652
- modalities: ["text"],
1653
- apiType: "chat",
1654
- pricing: { input: 1.1, output: 4.4, cached: 0.55 },
1655
- contextWindow: 128e3,
1656
- defaultMaxOutput: 16384,
1657
- maxOutputTokens: 65536,
1658
- parameters: REASONING_PARAMS,
1659
- deprecated: false,
1660
- description: "Fast reasoning model, good for math/code"
1661
- },
1662
- {
1663
- id: "o3-mini",
1664
- displayName: "o3 Mini",
1665
- family: "o3",
1666
- tier: "reasoning",
1667
- capabilityRank: 4,
1668
- modalities: ["text"],
1669
- apiType: "chat",
1670
- pricing: { input: 1.1, output: 4.4, cached: 0.55 },
1671
- contextWindow: 128e3,
1672
- defaultMaxOutput: 16384,
1673
- maxOutputTokens: 65536,
1674
- parameters: REASONING_PARAMS,
1675
- deprecated: false,
1676
- description: "Improved mini reasoner with better efficiency"
1677
- },
1678
- {
1679
- id: "o4-mini",
1680
- displayName: "o4 Mini",
1681
- family: "o4",
1682
- tier: "reasoning",
1683
- capabilityRank: 5,
1684
- modalities: ["text"],
1685
- apiType: "chat",
1686
- pricing: { input: 1.1, output: 4.4, cached: 0.275 },
1687
- contextWindow: 128e3,
1688
- defaultMaxOutput: 16384,
1689
- maxOutputTokens: 65536,
1690
- parameters: REASONING_PARAMS,
1691
- deprecated: false,
1692
- description: "Latest mini reasoner, best reasoning per dollar"
1693
- },
1694
- {
1695
- id: "o3",
1696
- displayName: "o3",
1697
- family: "o3",
1698
- tier: "reasoning",
1699
- capabilityRank: 7,
1700
- modalities: ["text"],
1701
- apiType: "chat",
1702
- pricing: { input: 2, output: 8, cached: 0.5 },
1703
- contextWindow: 2e5,
1704
- defaultMaxOutput: 32768,
1705
- maxOutputTokens: 1e5,
1706
- parameters: REASONING_PARAMS,
1707
- deprecated: false,
1708
- description: "Full o3 reasoning model, excellent for complex problems"
1709
- },
1710
- {
1711
- id: "o1",
1712
- displayName: "o1",
1713
- family: "o1",
1714
- tier: "reasoning",
1715
- capabilityRank: 8,
1716
- modalities: ["text"],
1717
- apiType: "chat",
1718
- pricing: { input: 15, output: 60, cached: 7.5 },
1719
- contextWindow: 2e5,
1720
- defaultMaxOutput: 32768,
1721
- maxOutputTokens: 1e5,
1722
- parameters: REASONING_PARAMS,
1723
- deprecated: false,
1724
- description: "Original full reasoning model, very capable"
1725
- },
1726
- // =========================================================================
1727
- // PREMIUM TIER - Most capable, expensive
1728
- // =========================================================================
1729
- {
1730
- id: "gpt-5-pro",
1731
- displayName: "GPT-5 Pro",
1732
- family: "gpt-5",
1733
- tier: "premium",
1734
- capabilityRank: 7,
1735
- modalities: ["text"],
1736
- apiType: "chat",
1737
- pricing: { input: 15, output: 120 },
1738
- contextWindow: 128e3,
1739
- defaultMaxOutput: 16384,
1740
- maxOutputTokens: 32768,
1741
- parameters: GPT5_PARAMS,
1742
- deprecated: false,
1743
- description: "Enhanced GPT-5 for demanding tasks"
1744
- },
1745
- {
1746
- id: "gpt-5.2-pro",
1747
- displayName: "GPT-5.2 Pro",
1748
- family: "gpt-5",
1749
- tier: "premium",
1750
- capabilityRank: 8,
1751
- modalities: ["text"],
1752
- apiType: "chat",
1753
- pricing: { input: 21, output: 168 },
1754
- contextWindow: 128e3,
1755
- defaultMaxOutput: 16384,
1756
- maxOutputTokens: 32768,
1757
- parameters: GPT5_PARAMS,
1758
- deprecated: false,
1759
- description: "Most capable standard model available"
1760
- },
1761
- {
1762
- id: "o3-pro",
1763
- displayName: "o3 Pro",
1764
- family: "o3",
1765
- tier: "premium",
1766
- capabilityRank: 9,
1767
- modalities: ["text"],
1768
- apiType: "chat",
1769
- pricing: { input: 20, output: 80 },
1770
- contextWindow: 2e5,
1771
- defaultMaxOutput: 32768,
1772
- maxOutputTokens: 1e5,
1773
- parameters: PRO_REASONING_PARAMS,
1774
- deprecated: false,
1775
- description: "Premium o3 with extended thinking time"
1776
- },
1777
- {
1778
- id: "o1-pro",
1779
- displayName: "o1 Pro",
1780
- family: "o1",
1781
- tier: "premium",
1782
- capabilityRank: 10,
1783
- modalities: ["text"],
1784
- apiType: "chat",
1785
- pricing: { input: 150, output: 600 },
1786
- contextWindow: 2e5,
1787
- defaultMaxOutput: 32768,
1788
- maxOutputTokens: 1e5,
1789
- parameters: PRO_REASONING_PARAMS,
1790
- deprecated: false,
1791
- description: "Most capable reasoning model, extended compute"
1792
- },
1793
- // =========================================================================
1794
- // SPECIALIZED TIER - Special purpose models
1795
- // =========================================================================
1796
- {
1797
- id: "o3-deep-research",
1798
- displayName: "o3 Deep Research",
1799
- family: "o3",
1800
- tier: "specialized",
1801
- capabilityRank: 8,
1802
- modalities: ["text"],
1803
- apiType: "responses",
1804
- pricing: { input: 10, output: 40, cached: 2.5 },
1805
- contextWindow: 2e5,
1806
- defaultMaxOutput: 32768,
1807
- maxOutputTokens: 1e5,
1808
- parameters: {
1809
- ...REASONING_PARAMS,
1810
- supportsStreaming: false
1811
- },
1812
- deprecated: false,
1813
- description: "Extended research sessions with web access"
1814
- },
1815
- {
1816
- id: "o4-mini-deep-research",
1817
- displayName: "o4 Mini Deep Research",
1818
- family: "o4",
1819
- tier: "specialized",
1820
- capabilityRank: 6,
1821
- modalities: ["text"],
1822
- apiType: "responses",
1823
- pricing: { input: 2, output: 8, cached: 0.5 },
1824
- contextWindow: 128e3,
1825
- defaultMaxOutput: 16384,
1826
- maxOutputTokens: 65536,
1827
- parameters: {
1828
- ...REASONING_PARAMS,
1829
- supportsStreaming: false
1830
- },
1831
- deprecated: false,
1832
- description: "Affordable deep research with o4 mini"
1833
- },
1834
- {
1835
- id: "computer-use-preview",
1836
- displayName: "Computer Use Preview",
1837
- family: "computer-use",
1838
- tier: "specialized",
1839
- capabilityRank: 5,
1840
- modalities: ["text", "vision"],
1841
- apiType: "responses",
1842
- pricing: { input: 3, output: 12 },
1843
- contextWindow: 128e3,
1844
- defaultMaxOutput: 4096,
1845
- maxOutputTokens: 16384,
1846
- parameters: {
1847
- ...STANDARD_PARAMS,
1848
- supportsReasoningEffort: false
1849
- },
1850
- deprecated: false,
1851
- description: "Can control computer interfaces via screenshots"
1852
- },
1853
- // =========================================================================
1854
- // REALTIME TIER - Real-time audio/video
1855
- // =========================================================================
1856
- {
1857
- id: "gpt-realtime",
1858
- displayName: "GPT Realtime",
1859
- family: "gpt-realtime",
1860
- tier: "specialized",
1861
- capabilityRank: 7,
1862
- modalities: ["text", "audio", "realtime"],
1863
- apiType: "chat",
1864
- pricing: { input: 4, output: 16, cached: 0.4 },
1865
- contextWindow: 128e3,
1866
- defaultMaxOutput: 4096,
1867
- maxOutputTokens: 4096,
1868
- parameters: {
1869
- ...STANDARD_PARAMS,
1870
- supportsReasoningEffort: false
1871
- },
1872
- deprecated: false,
1873
- description: "Real-time audio conversation model"
1874
- },
1875
- {
1876
- id: "gpt-realtime-mini",
1877
- displayName: "GPT Realtime Mini",
1878
- family: "gpt-realtime",
1879
- tier: "specialized",
1880
- capabilityRank: 4,
1881
- modalities: ["text", "audio", "realtime"],
1882
- apiType: "chat",
1883
- pricing: { input: 0.6, output: 2.4, cached: 0.06 },
1884
- contextWindow: 128e3,
1885
- defaultMaxOutput: 4096,
1886
- maxOutputTokens: 4096,
1887
- parameters: {
1888
- ...STANDARD_PARAMS,
1889
- supportsReasoningEffort: false
1890
- },
1891
- deprecated: false,
1892
- description: "Affordable real-time audio model"
1893
- },
1894
- // =========================================================================
1895
- // LEGACY MODELS - Still available but older
1896
- // =========================================================================
1897
- {
1898
- id: "gpt-4o-2024-05-13",
1899
- displayName: "GPT-4o (May 2024)",
1900
- family: "gpt-4o",
1901
- tier: "standard",
1902
- capabilityRank: 4,
1903
- modalities: ["text", "vision"],
1904
- apiType: "chat",
1905
- pricing: { input: 5, output: 15 },
1906
- contextWindow: 128e3,
1907
- defaultMaxOutput: 4096,
1908
- maxOutputTokens: 4096,
1909
- parameters: STANDARD_PARAMS,
1910
- deprecated: true,
1911
- description: "Original GPT-4o snapshot, use gpt-4o instead"
1912
- }
1913
- ];
1914
- var MODEL_MAP = new Map(
1915
- MODEL_REGISTRY.map((m) => [m.id, m])
1916
- );
1917
- function getModel(modelId) {
1918
- const model = MODEL_MAP.get(modelId);
1919
- if (!model) {
1920
- throw new Error(`Unknown model: ${modelId}. Use getAvailableModelIds() to see valid options.`);
1921
- }
1922
- return model;
1923
- }
1924
- function findModel(modelId) {
1925
- return MODEL_MAP.get(modelId);
1926
- }
1927
- function isValidModelId(modelId) {
1928
- return MODEL_MAP.has(modelId);
1929
- }
1930
- function getAvailableModelIds() {
1931
- return MODEL_REGISTRY.map((m) => m.id);
1932
- }
1933
- function getModelsByTier(tier) {
1934
- return MODEL_REGISTRY.filter((m) => m.tier === tier && !m.deprecated).sort((a, b) => a.capabilityRank - b.capabilityRank);
1935
- }
1936
- function getModelsByFamily(family) {
1937
- return MODEL_REGISTRY.filter((m) => m.family === family).sort((a, b) => a.capabilityRank - b.capabilityRank);
1938
- }
1939
- function getActiveModels() {
1940
- const tierOrder = {
1941
- fast: 1,
1942
- standard: 2,
1943
- reasoning: 3,
1944
- premium: 4,
1945
- specialized: 5
1946
- };
1947
- return MODEL_REGISTRY.filter((m) => !m.deprecated).sort((a, b) => {
1948
- const tierDiff = tierOrder[a.tier] - tierOrder[b.tier];
1949
- if (tierDiff !== 0) return tierDiff;
1950
- return a.capabilityRank - b.capabilityRank;
1951
- });
1952
- }
1953
- function getTextModels() {
1954
- return MODEL_REGISTRY.filter(
1955
- (m) => !m.deprecated && m.modalities.includes("text") && !m.modalities.includes("realtime") && m.apiType !== "responses"
1956
- // Standard chat API
1957
- ).sort((a, b) => {
1958
- const tierOrder = {
1959
- fast: 1,
1960
- standard: 2,
1961
- reasoning: 3,
1962
- premium: 4,
1963
- specialized: 5
1964
- };
1965
- const tierDiff = tierOrder[a.tier] - tierOrder[b.tier];
1966
- if (tierDiff !== 0) return tierDiff;
1967
- return a.capabilityRank - b.capabilityRank;
1968
- });
1969
- }
1970
- function getCheapestModel(minTier = "fast") {
1971
- const tierOrder = {
1972
- fast: 1,
1973
- standard: 2,
1974
- reasoning: 3,
1975
- premium: 4,
1976
- specialized: 5
1977
- };
1978
- const minTierNum = tierOrder[minTier];
1979
- const candidates = MODEL_REGISTRY.filter((m) => !m.deprecated && tierOrder[m.tier] >= minTierNum).sort((a, b) => a.pricing.input - b.pricing.input);
1980
- return candidates[0];
1981
- }
1982
- function estimateCost(modelId, inputTokens, outputTokens, useCached = false) {
1983
- const model = getModel(modelId);
1984
- const inputCost = useCached && model.pricing.cached ? inputTokens / 1e6 * model.pricing.cached : inputTokens / 1e6 * model.pricing.input;
1985
- const outputCost = outputTokens / 1e6 * model.pricing.output;
1986
- return inputCost + outputCost;
1987
- }
1988
- function formatModelPricing(modelId) {
1989
- const model = getModel(modelId);
1990
- return `$${model.pricing.input.toFixed(2)} in / $${model.pricing.output.toFixed(2)} out per 1M tokens`;
1991
- }
1992
- var MODEL_PRICING_MAP = Object.fromEntries(
1993
- MODEL_REGISTRY.map((m) => [m.id, {
1994
- input: m.pricing.input,
1995
- output: m.pricing.output,
1996
- cached: m.pricing.cached,
1997
- maxTokens: m.defaultMaxOutput,
1998
- tier: m.tier
1999
- }])
2000
- );
2001
-
2002
- // src/server/token-pricing.ts
2003
- var _tiktoken = null;
2004
- async function loadTiktoken() {
2005
- if (_tiktoken) return _tiktoken;
2006
- try {
2007
- _tiktoken = await import("tiktoken");
2008
- return _tiktoken;
2009
- } catch {
2010
- throw new Error(
2011
- 'Token pricing requires the "tiktoken" package. Install with: npm install tiktoken'
2012
- );
2013
- }
2014
- }
2015
- var MODEL_PRICING = MODEL_PRICING_MAP;
2016
- var DEFAULT_MODEL = "gpt-4o-mini";
2017
- async function getEncodingForModel(model) {
2018
- const tiktoken = await loadTiktoken();
2019
- try {
2020
- return tiktoken.encoding_for_model(model);
2021
- } catch {
2022
- return tiktoken.get_encoding("cl100k_base");
2023
- }
2024
- }
2025
- async function countTokens(text, model = DEFAULT_MODEL) {
2026
- const encoding = await getEncodingForModel(model);
2027
- try {
2028
- const tokens = encoding.encode(text);
2029
- return tokens.length;
2030
- } finally {
2031
- encoding.free();
2032
- }
2033
- }
2034
- function generateQuoteHash(prompt, model, rate, tokens) {
2035
- const configString = JSON.stringify({ model, rate, tokens });
2036
- return (0, import_crypto3.createHash)("sha256").update(prompt + configString).digest("hex").slice(0, 16);
2037
- }
2038
- function createTokenPricing(config = {}) {
2039
- const model = config.model ?? DEFAULT_MODEL;
2040
- const builtInPricing = MODEL_PRICING[model];
2041
- const modelInfo = {
2042
- input: config.inputRate ?? builtInPricing?.input ?? MODEL_PRICING[DEFAULT_MODEL].input,
2043
- output: config.outputRate ?? builtInPricing?.output ?? MODEL_PRICING[DEFAULT_MODEL].output,
2044
- maxTokens: config.maxTokens ?? builtInPricing?.maxTokens ?? 4096,
2045
- tier: config.tier ?? builtInPricing?.tier ?? "custom"
2046
- };
2047
- const customTokenizer = config.tokenizer;
2048
- const fullConfig = {
2049
- model,
2050
- inputRate: modelInfo.input,
2051
- outputRate: modelInfo.output,
2052
- maxTokens: modelInfo.maxTokens,
2053
- tier: modelInfo.tier,
2054
- tokenizer: customTokenizer ?? ((text) => countTokens(text, model)),
2055
- minUsd: config.minUsd ?? 1e-3,
2056
- maxUsd: config.maxUsd ?? 50,
2057
- decimals: config.decimals ?? 6
2058
- };
2059
- const { minUsd, maxUsd, decimals } = fullConfig;
2060
- async function countTokensInternal(input) {
2061
- if (customTokenizer) {
2062
- return customTokenizer(input);
2063
- }
2064
- return countTokens(input, model);
2065
- }
2066
- async function calculate(input, systemPrompt) {
2067
- const fullInput = systemPrompt ? `${systemPrompt}
2068
-
2069
- ${input}` : input;
2070
- const inputTokens = await countTokensInternal(fullInput);
2071
- let usdAmount = inputTokens / 1e6 * modelInfo.input;
2072
- usdAmount = Math.max(usdAmount, minUsd);
2073
- usdAmount = Math.min(usdAmount, maxUsd);
2074
- const multiplier = Math.pow(10, decimals);
2075
- const amountAtomic = Math.floor(usdAmount * multiplier).toString();
2076
- const quoteHash = generateQuoteHash(input, model, modelInfo.input, inputTokens);
2077
- return {
2078
- amountAtomic,
2079
- usdAmount,
2080
- inputTokens,
2081
- model,
2082
- tier: modelInfo.tier,
2083
- inputRatePerMillion: modelInfo.input,
2084
- outputRatePerMillion: modelInfo.output,
2085
- maxOutputTokens: modelInfo.maxTokens,
2086
- quoteHash
2087
- };
2088
- }
2089
- async function validateQuote(input, quoteHash) {
2090
- if (!quoteHash) return false;
2091
- const inputTokens = await countTokensInternal(input);
2092
- const expectedHash = generateQuoteHash(input, model, modelInfo.input, inputTokens);
2093
- return expectedHash === quoteHash;
2094
- }
2095
- return {
2096
- calculate,
2097
- validateQuote,
2098
- countTokens: countTokensInternal,
2099
- config: fullConfig,
2100
- modelInfo
2101
- };
2102
- }
2103
- function getAvailableModels() {
2104
- return Object.entries(MODEL_PRICING).map(([model, pricing]) => ({
2105
- model,
2106
- inputRate: pricing.input,
2107
- outputRate: pricing.output,
2108
- maxTokens: pricing.maxTokens,
2109
- tier: pricing.tier
2110
- })).sort((a, b) => {
2111
- const tierOrder = { fast: 0, standard: 1, reasoning: 2, premium: 3 };
2112
- const tierDiff = tierOrder[a.tier] - tierOrder[b.tier];
2113
- if (tierDiff !== 0) return tierDiff;
2114
- return a.inputRate - b.inputRate;
2115
- });
2116
- }
2117
- function isValidModel(model) {
2118
- return model in MODEL_PRICING;
2119
- }
2120
- function formatTokenPricing(model = DEFAULT_MODEL) {
2121
- const pricing = MODEL_PRICING[model] ?? MODEL_PRICING[DEFAULT_MODEL];
2122
- const actualModel = MODEL_PRICING[model] ? model : DEFAULT_MODEL;
2123
- return `$${pricing.input.toFixed(2)} per 1M tokens (${actualModel})`;
2124
- }
284
+ </html>`}function he(e={}){let t={title:e.title??"Payment Required",branding:e.branding??'Powered by <a href="https://docs.dexter.cash/docs/sdk/">Dexter x402</a>',sdkUrl:e.sdkUrl??"https://docs.dexter.cash/docs/sdk/",showEndpoint:e.showEndpoint??!0},n=e.rpcUrl??"https://api.dexter.cash/api/solana/rpc";return(r,i,c)=>{let d=i.json.bind(i);i.json=function(g){if(i.statusCode===402&&r.accepts("html")&&!r.headers["payment-signature"]){let P=i.getHeader("PAYMENT-REQUIRED")||i.getHeader("payment-required");if(P&&typeof P=="string"){let w;if(r.body&&typeof r.body=="object"&&Object.keys(r.body).length>0)try{w=JSON.stringify(r.body)}catch{}let k=ct(P,r.originalUrl,r.method,t,n,w);return i.setHeader("Content-Security-Policy","default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; connect-src *; img-src data:; frame-ancestors 'none'"),i.setHeader("X-Content-Type-Options","nosniff"),i.status(402).type("html").send(k),i}}return d(g)},c()}}var ee=ae(require("crypto"),1),pt=/^(\d+)(m|h|d|w)$/;function ut(e){let t=e.match(pt);if(!t)return null;let n=parseInt(t[1],10);switch(t[2]){case"m":return n*60;case"h":return n*3600;case"d":return n*86400;case"w":return n*604800;default:return null}}function be(e){return e>=604800&&e%604800===0?`${e/604800} week${e/604800>1?"s":""}`:e>=86400&&e%86400===0?`${e/86400} day${e/86400>1?"s":""}`:e>=3600&&e%3600===0?`${e/3600} hour${e/3600>1?"s":""}`:e>=60&&e%60===0?`${e/60} minute${e/60>1?"s":""}`:`${e} second${e>1?"s":""}`}function dt(e,t){let n=Buffer.from(JSON.stringify({alg:"HS256",typ:"JWT"})).toString("base64url"),r=Buffer.from(JSON.stringify(e)).toString("base64url"),i=ee.default.createHmac("sha256",t).update(`${n}.${r}`).digest("base64url");return`${n}.${r}.${i}`}function lt(e,t){try{let n=e.split(".");if(n.length!==3)return null;let[r,i,c]=n,d=ee.default.createHmac("sha256",t).update(`${r}.${i}`).digest("base64url");if(c!==d)return null;let g=JSON.parse(Buffer.from(i,"base64url").toString());return g.exp&&Date.now()/1e3>g.exp||g.sub!=="x402-access-pass"?null:g}catch{return null}}var mt="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",ft=6;function Pe(e){let{payTo:t,network:n=mt,asset:r,facilitatorUrl:i,tiers:c,ratePerHour:d,secret:g,issuer:P="x402-access-pass",verbose:w=!1,description:k}=e,A=g??ee.default.randomBytes(32);if(g||console.warn("[x402:access-pass] No secret provided \u2014 access passes will be invalidated on server restart. Set `secret` for production use."),!c&&!d)throw new Error("x402AccessPass: at least one of `tiers` or `ratePerHour` is required");let o=w?console.log.bind(console,"[x402:access-pass]"):()=>{},x=r?.decimals??ft,f=[];if(c){for(let[l,b]of Object.entries(c)){let a=ut(l);if(!a){console.warn(`x402AccessPass: skipping tier "${l}" \u2014 unrecognized duration format (use 5m, 1h, 24h, 7d)`);continue}f.push({id:l,label:be(a),seconds:a,price:b,priceAtomic:H(parseFloat(b),x)})}f.sort((l,b)=>l.seconds-b.seconds)}let m=j({payTo:t,network:n,asset:r,facilitatorUrl:i}),y={tiers:f.length>0?f:void 0,ratePerHour:d||void 0,issuer:P},S=F(y);function u(l){if(!d)throw new Error("Custom durations not supported \u2014 no ratePerHour configured");let b=l/3600,a=(parseFloat(d)*b).toFixed(x>4?4:2);return{price:a,priceAtomic:H(parseFloat(a),x)}}function h(l){let b=l.query.tier,a=l.query.duration;if(b){let s=f.find(R=>R.id===b);if(s)return{tier:s.id,seconds:s.seconds,price:s.price,priceAtomic:s.priceAtomic,label:s.label}}if(a){let s=parseInt(a,10);if(s>0&&d){let R=u(s);return{tier:"custom",seconds:s,...R,label:be(s)}}}if(f.length>0){let s=f[0];return{tier:s.id,seconds:s.seconds,price:s.price,priceAtomic:s.priceAtomic,label:s.label}}return{tier:"custom",seconds:3600,...u(3600),label:"1 hour"}}return async(l,b,a)=>{try{let p=l.headers.authorization;if(p?.startsWith("Bearer ")){let T=lt(p.slice(7),A);if(T)return o("Valid access pass:",T.tier,"| expires:",new Date(T.exp*1e3).toISOString()),l.accessPass={tier:T.tier,duration:T.duration,expiresAt:new Date(T.exp*1e3).toISOString(),payer:T.payer,network:T.network},a();o("Invalid or expired access pass token")}let s=l.headers["payment-signature"];if(s){o("Payment signature received, verifying for pass purchase...");let T=await m.verifyPayment(s);if(!T.isValid){o("Payment verification failed:",T.invalidReason),b.status(402).json({error:"Payment verification failed",reason:T.invalidReason});return}let v=await m.settlePayment(s);if(!v.success){o("Payment settlement failed:",v.errorReason),b.status(402).json({error:"Payment settlement failed",reason:v.errorReason});return}o("Payment settled:",v.transaction);let U=h(l),q=Math.floor(Date.now()/1e3),C={sub:"x402-access-pass",tier:U.tier,duration:U.seconds,iat:q,exp:q+U.seconds,payer:T.payer??"",network:n,iss:P},J=dt(C,A);l.x402={transaction:v.transaction,payer:T.payer??"",network:n};let oe={success:!0,transaction:v.transaction,network:n,payer:T.payer??""};b.setHeader("PAYMENT-RESPONSE",F(oe)),b.setHeader("ACCESS-PASS",J),b.json({accessPass:{token:J,tier:U.tier,duration:U.label,durationSeconds:U.seconds,expiresAt:new Date((q+U.seconds)*1e3).toISOString(),usage:"Include on subsequent requests as: Authorization: Bearer <token>"},transaction:v.transaction,payer:T.payer});return}o("No access pass or payment, returning 402");let R=h(l),_=R.priceAtomic,E=`${l.protocol}://${l.get("host")}${l.originalUrl}`,M=await m.buildRequirements({amountAtomic:_,resourceUrl:E,description:k||`Access pass: ${R.label}`,mimeType:"application/json"}),$=m.encodeRequirements(M);b.setHeader("PAYMENT-REQUIRED",$),b.setHeader("X-ACCESS-PASS-TIERS",S),b.status(402).json({error:"Access pass required",message:"Purchase an access pass to unlock unlimited API access for a time window.",accepts:M.accepts,resource:M.resource,accessPass:{tiers:f.length>0?f:void 0,ratePerHour:d||void 0,usage:"Add ?tier=<id> or ?duration=<seconds> to your payment request to choose a pass duration."}})}catch(p){o("Access pass middleware error:",p),b.status(500).json({error:"Payment processing error",message:p instanceof Error?p.message:"Unknown error"})}}}var te=require("crypto"),gt=300;function we(e){let t={unitSize:e.unitSize,ratePerUnit:e.ratePerUnit,minUsd:e.minUsd??.01,maxUsd:e.maxUsd??1/0,roundingMode:e.roundingMode??"ceil",decimals:e.decimals??6},{unitSize:n,ratePerUnit:r,minUsd:i,maxUsd:c,roundingMode:d,decimals:g}=t;if(n<=0)throw new Error("unitSize must be positive");if(r<=0)throw new Error("ratePerUnit must be positive");if(i<0)throw new Error("minUsd cannot be negative");if(c<i)throw new Error("maxUsd must be >= minUsd");let P=(0,te.randomBytes)(32);function w(o,x){let f=JSON.stringify({unitSize:n,ratePerUnit:r,minUsd:i,maxUsd:c===1/0?"none":c,roundingMode:d}),m=`${o}|${f}|${x}`;return(0,te.createHmac)("sha256",P).update(m).digest("hex").slice(0,16)}function k(o){let x=o.length,f=x/n,m;switch(d){case"ceil":m=Math.ceil(f);break;case"floor":m=Math.floor(f);break;case"round":m=Math.round(f);break}x>0&&m===0&&(m=1);let y=m*r;y=Math.max(i,y),y=Math.min(c,y);let S=Math.pow(10,g),u=Math.floor(y*S).toString(),h=Math.floor(Date.now()/1e3),l=w(o,h),b=`${h}.${l}`;return{amountAtomic:u,usdAmount:y,quoteHash:b,units:m,inputLength:x}}function A(o,x){if(!x)return!1;let f=x.indexOf(".");if(f===-1)return!1;let m=parseInt(x.slice(0,f),10),y=x.slice(f+1);if(isNaN(m)||!y)return!1;let S=Math.floor(Date.now()/1e3)-m;if(S<0||S>gt)return!1;let u=w(o,m);if(y.length!==u.length)return!1;let h=0;for(let l=0;l<y.length;l++)h|=y.charCodeAt(l)^u.charCodeAt(l);return h===0}return{calculate:k,validateQuote:A,config:t}}function Te(e){let t=e.ratePerUnit.toFixed(2),n=e.unitSize.toLocaleString();return`from $${t} per ${n} chars`}var Ue=require("crypto");var D={usesMaxCompletionTokens:!1,supportsTemperature:!0,supportsTopP:!0,supportsFrequencyPenalty:!0,supportsPresencePenalty:!0,supportsReasoningEffort:!1,supportsStreaming:!0,supportsSystemMessage:!0,supportsTools:!0,supportsStructuredOutput:!0},W={usesMaxCompletionTokens:!0,supportsTemperature:!1,supportsTopP:!1,supportsFrequencyPenalty:!1,supportsPresencePenalty:!1,supportsReasoningEffort:!1,supportsStreaming:!0,supportsSystemMessage:!0,supportsTools:!0,supportsStructuredOutput:!0},B={usesMaxCompletionTokens:!0,supportsTemperature:!1,supportsTopP:!1,supportsFrequencyPenalty:!1,supportsPresencePenalty:!1,supportsReasoningEffort:!0,supportsStreaming:!0,supportsSystemMessage:!0,supportsTools:!0,supportsStructuredOutput:!0},Re={...B,supportsStreaming:!1},N=[{id:"gpt-4o-mini",displayName:"GPT-4o Mini",family:"gpt-4o",tier:"fast",capabilityRank:3,modalities:["text","vision"],apiType:"chat",pricing:{input:.15,output:.6,cached:.075},contextWindow:128e3,defaultMaxOutput:4096,maxOutputTokens:16384,parameters:D,deprecated:!1,description:"Fast, affordable small model with vision support"},{id:"gpt-4.1-nano",displayName:"GPT-4.1 Nano",family:"gpt-4.1",tier:"fast",capabilityRank:2,modalities:["text"],apiType:"chat",pricing:{input:.1,output:.4,cached:.025},contextWindow:128e3,defaultMaxOutput:4096,maxOutputTokens:32768,parameters:D,deprecated:!1,description:"Smallest 4.1 model, very fast and cheap"},{id:"gpt-4.1-mini",displayName:"GPT-4.1 Mini",family:"gpt-4.1",tier:"fast",capabilityRank:4,modalities:["text"],apiType:"chat",pricing:{input:.4,output:1.6,cached:.1},contextWindow:128e3,defaultMaxOutput:4096,maxOutputTokens:32768,parameters:D,deprecated:!1,description:"Balanced 4.1 model, good price/performance"},{id:"gpt-5-nano",displayName:"GPT-5 Nano",family:"gpt-5",tier:"fast",capabilityRank:1,modalities:["text"],apiType:"chat",pricing:{input:.05,output:.4,cached:.005},contextWindow:128e3,defaultMaxOutput:4096,maxOutputTokens:16384,parameters:W,deprecated:!1,description:"Cheapest GPT-5 variant, extremely fast"},{id:"gpt-5-mini",displayName:"GPT-5 Mini",family:"gpt-5",tier:"fast",capabilityRank:5,modalities:["text"],apiType:"chat",pricing:{input:.25,output:2,cached:.025},contextWindow:128e3,defaultMaxOutput:8192,maxOutputTokens:32768,parameters:W,deprecated:!1,description:"Small but capable GPT-5, great value"},{id:"gpt-4o",displayName:"GPT-4o",family:"gpt-4o",tier:"standard",capabilityRank:5,modalities:["text","vision"],apiType:"chat",pricing:{input:2.5,output:10,cached:1.25},contextWindow:128e3,defaultMaxOutput:4096,maxOutputTokens:16384,parameters:D,deprecated:!1,description:"Flagship multimodal model with vision"},{id:"gpt-4.1",displayName:"GPT-4.1",family:"gpt-4.1",tier:"standard",capabilityRank:6,modalities:["text"],apiType:"chat",pricing:{input:2,output:8,cached:.5},contextWindow:1e6,defaultMaxOutput:8192,maxOutputTokens:32768,parameters:D,deprecated:!1,description:"Long context specialist, 1M token window"},{id:"gpt-5",displayName:"GPT-5",family:"gpt-5",tier:"standard",capabilityRank:7,modalities:["text"],apiType:"chat",pricing:{input:1.25,output:10,cached:.125},contextWindow:128e3,defaultMaxOutput:8192,maxOutputTokens:32768,parameters:W,deprecated:!1,description:"Base GPT-5, excellent all-around"},{id:"gpt-5.1",displayName:"GPT-5.1",family:"gpt-5",tier:"standard",capabilityRank:8,modalities:["text"],apiType:"chat",pricing:{input:1.25,output:10,cached:.125},contextWindow:128e3,defaultMaxOutput:8192,maxOutputTokens:32768,parameters:W,deprecated:!1,description:"Improved GPT-5 with better instruction following"},{id:"gpt-5.2",displayName:"GPT-5.2",family:"gpt-5",tier:"standard",capabilityRank:9,modalities:["text"],apiType:"chat",pricing:{input:1.75,output:14,cached:.175},contextWindow:128e3,defaultMaxOutput:8192,maxOutputTokens:32768,parameters:W,deprecated:!1,description:"Latest GPT-5, most capable standard model"},{id:"o1-mini",displayName:"o1 Mini",family:"o1",tier:"reasoning",capabilityRank:3,modalities:["text"],apiType:"chat",pricing:{input:1.1,output:4.4,cached:.55},contextWindow:128e3,defaultMaxOutput:16384,maxOutputTokens:65536,parameters:B,deprecated:!1,description:"Fast reasoning model, good for math/code"},{id:"o3-mini",displayName:"o3 Mini",family:"o3",tier:"reasoning",capabilityRank:4,modalities:["text"],apiType:"chat",pricing:{input:1.1,output:4.4,cached:.55},contextWindow:128e3,defaultMaxOutput:16384,maxOutputTokens:65536,parameters:B,deprecated:!1,description:"Improved mini reasoner with better efficiency"},{id:"o4-mini",displayName:"o4 Mini",family:"o4",tier:"reasoning",capabilityRank:5,modalities:["text"],apiType:"chat",pricing:{input:1.1,output:4.4,cached:.275},contextWindow:128e3,defaultMaxOutput:16384,maxOutputTokens:65536,parameters:B,deprecated:!1,description:"Latest mini reasoner, best reasoning per dollar"},{id:"o3",displayName:"o3",family:"o3",tier:"reasoning",capabilityRank:7,modalities:["text"],apiType:"chat",pricing:{input:2,output:8,cached:.5},contextWindow:2e5,defaultMaxOutput:32768,maxOutputTokens:1e5,parameters:B,deprecated:!1,description:"Full o3 reasoning model, excellent for complex problems"},{id:"o1",displayName:"o1",family:"o1",tier:"reasoning",capabilityRank:8,modalities:["text"],apiType:"chat",pricing:{input:15,output:60,cached:7.5},contextWindow:2e5,defaultMaxOutput:32768,maxOutputTokens:1e5,parameters:B,deprecated:!1,description:"Original full reasoning model, very capable"},{id:"gpt-5-pro",displayName:"GPT-5 Pro",family:"gpt-5",tier:"premium",capabilityRank:7,modalities:["text"],apiType:"chat",pricing:{input:15,output:120},contextWindow:128e3,defaultMaxOutput:16384,maxOutputTokens:32768,parameters:W,deprecated:!1,description:"Enhanced GPT-5 for demanding tasks"},{id:"gpt-5.2-pro",displayName:"GPT-5.2 Pro",family:"gpt-5",tier:"premium",capabilityRank:8,modalities:["text"],apiType:"chat",pricing:{input:21,output:168},contextWindow:128e3,defaultMaxOutput:16384,maxOutputTokens:32768,parameters:W,deprecated:!1,description:"Most capable standard model available"},{id:"o3-pro",displayName:"o3 Pro",family:"o3",tier:"premium",capabilityRank:9,modalities:["text"],apiType:"chat",pricing:{input:20,output:80},contextWindow:2e5,defaultMaxOutput:32768,maxOutputTokens:1e5,parameters:Re,deprecated:!1,description:"Premium o3 with extended thinking time"},{id:"o1-pro",displayName:"o1 Pro",family:"o1",tier:"premium",capabilityRank:10,modalities:["text"],apiType:"chat",pricing:{input:150,output:600},contextWindow:2e5,defaultMaxOutput:32768,maxOutputTokens:1e5,parameters:Re,deprecated:!1,description:"Most capable reasoning model, extended compute"},{id:"o3-deep-research",displayName:"o3 Deep Research",family:"o3",tier:"specialized",capabilityRank:8,modalities:["text"],apiType:"responses",pricing:{input:10,output:40,cached:2.5},contextWindow:2e5,defaultMaxOutput:32768,maxOutputTokens:1e5,parameters:{...B,supportsStreaming:!1},deprecated:!1,description:"Extended research sessions with web access"},{id:"o4-mini-deep-research",displayName:"o4 Mini Deep Research",family:"o4",tier:"specialized",capabilityRank:6,modalities:["text"],apiType:"responses",pricing:{input:2,output:8,cached:.5},contextWindow:128e3,defaultMaxOutput:16384,maxOutputTokens:65536,parameters:{...B,supportsStreaming:!1},deprecated:!1,description:"Affordable deep research with o4 mini"},{id:"computer-use-preview",displayName:"Computer Use Preview",family:"computer-use",tier:"specialized",capabilityRank:5,modalities:["text","vision"],apiType:"responses",pricing:{input:3,output:12},contextWindow:128e3,defaultMaxOutput:4096,maxOutputTokens:16384,parameters:{...D,supportsReasoningEffort:!1},deprecated:!1,description:"Can control computer interfaces via screenshots"},{id:"gpt-realtime",displayName:"GPT Realtime",family:"gpt-realtime",tier:"specialized",capabilityRank:7,modalities:["text","audio","realtime"],apiType:"chat",pricing:{input:4,output:16,cached:.4},contextWindow:128e3,defaultMaxOutput:4096,maxOutputTokens:4096,parameters:{...D,supportsReasoningEffort:!1},deprecated:!1,description:"Real-time audio conversation model"},{id:"gpt-realtime-mini",displayName:"GPT Realtime Mini",family:"gpt-realtime",tier:"specialized",capabilityRank:4,modalities:["text","audio","realtime"],apiType:"chat",pricing:{input:.6,output:2.4,cached:.06},contextWindow:128e3,defaultMaxOutput:4096,maxOutputTokens:4096,parameters:{...D,supportsReasoningEffort:!1},deprecated:!1,description:"Affordable real-time audio model"},{id:"gpt-4o-2024-05-13",displayName:"GPT-4o (May 2024)",family:"gpt-4o",tier:"standard",capabilityRank:4,modalities:["text","vision"],apiType:"chat",pricing:{input:5,output:15},contextWindow:128e3,defaultMaxOutput:4096,maxOutputTokens:4096,parameters:D,deprecated:!0,description:"Original GPT-4o snapshot, use gpt-4o instead"}],pe=new Map(N.map(e=>[e.id,e]));function re(e){let t=pe.get(e);if(!t)throw new Error(`Unknown model: ${e}. Use getAvailableModelIds() to see valid options.`);return t}function ke(e){return pe.get(e)}function Ae(e){return pe.has(e)}function Se(){return N.map(e=>e.id)}function Me(e){return N.filter(t=>t.tier===e&&!t.deprecated).sort((t,n)=>t.capabilityRank-n.capabilityRank)}function ve(e){return N.filter(t=>t.family===e).sort((t,n)=>t.capabilityRank-n.capabilityRank)}function Ee(){let e={fast:1,standard:2,reasoning:3,premium:4,specialized:5};return N.filter(t=>!t.deprecated).sort((t,n)=>{let r=e[t.tier]-e[n.tier];return r!==0?r:t.capabilityRank-n.capabilityRank})}function _e(){return N.filter(e=>!e.deprecated&&e.modalities.includes("text")&&!e.modalities.includes("realtime")&&e.apiType!=="responses").sort((e,t)=>{let n={fast:1,standard:2,reasoning:3,premium:4,specialized:5},r=n[e.tier]-n[t.tier];return r!==0?r:e.capabilityRank-t.capabilityRank})}function Ce(e="fast"){let t={fast:1,standard:2,reasoning:3,premium:4,specialized:5},n=t[e];return N.filter(i=>!i.deprecated&&t[i.tier]>=n).sort((i,c)=>i.pricing.input-c.pricing.input)[0]}function Oe(e,t,n,r=!1){let i=re(e),c=r&&i.pricing.cached?t/1e6*i.pricing.cached:t/1e6*i.pricing.input,d=n/1e6*i.pricing.output;return c+d}function Ne(e){let t=re(e);return`$${t.pricing.input.toFixed(2)} in / $${t.pricing.output.toFixed(2)} out per 1M tokens`}var ne=Object.fromEntries(N.map(e=>[e.id,{input:e.pricing.input,output:e.pricing.output,cached:e.pricing.cached,maxTokens:e.defaultMaxOutput,tier:e.tier}]));var ie=null;async function yt(){if(ie)return ie;try{return ie=await import("tiktoken"),ie}catch{throw new Error('Token pricing requires the "tiktoken" package. Install with: npm install tiktoken')}}var I=ne,z="gpt-4o-mini";async function xt(e){let t=await yt();try{return t.encoding_for_model(e)}catch{return t.get_encoding("cl100k_base")}}async function se(e,t=z){let n=await xt(t);try{return n.encode(e).length}finally{n.free()}}function Ie(e,t,n,r){let i=JSON.stringify({model:t,rate:n,tokens:r});return(0,Ue.createHash)("sha256").update(e+i).digest("hex").slice(0,16)}function De(e={}){let t=e.model??z,n=I[t],r={input:e.inputRate??n?.input??I[z].input,output:e.outputRate??n?.output??I[z].output,maxTokens:e.maxTokens??n?.maxTokens??4096,tier:e.tier??n?.tier??"custom"},i=e.tokenizer,c={model:t,inputRate:r.input,outputRate:r.output,maxTokens:r.maxTokens,tier:r.tier,tokenizer:i??(o=>se(o,t)),minUsd:e.minUsd??.001,maxUsd:e.maxUsd??50,decimals:e.decimals??6},{minUsd:d,maxUsd:g,decimals:P}=c;async function w(o){return i?i(o):se(o,t)}async function k(o,x){let f=x?`${x}
2125
285
 
2126
- // src/server/index.ts
2127
- var import_x402_ads_types = require("@dexterai/x402-ads-types");
2128
- // Annotate the CommonJS export names for ESM import in node:
2129
- 0 && (module.exports = {
2130
- BASE_MAINNET_NETWORK,
2131
- DEXTER_FACILITATOR_URL,
2132
- FacilitatorClient,
2133
- MODEL_PRICING,
2134
- MODEL_PRICING_MAP,
2135
- MODEL_REGISTRY,
2136
- SOLANA_MAINNET_NETWORK,
2137
- SPONSORED_ACCESS_EXTENSION_KEY,
2138
- USDC_BASE,
2139
- USDC_MINT,
2140
- countTokens,
2141
- createDynamicPricing,
2142
- createTokenPricing,
2143
- createX402Server,
2144
- escapeHtml,
2145
- estimateCost,
2146
- findModel,
2147
- formatModelPricing,
2148
- formatPricing,
2149
- formatTokenPricing,
2150
- getActiveModels,
2151
- getAvailableModelIds,
2152
- getAvailableModels,
2153
- getCheapestModel,
2154
- getModel,
2155
- getModelsByFamily,
2156
- getModelsByTier,
2157
- getTextModels,
2158
- isValidModel,
2159
- isValidModelId,
2160
- stripePayTo,
2161
- x402AccessPass,
2162
- x402BrowserSupport,
2163
- x402Middleware
2164
- });
286
+ ${o}`:o,m=await w(f),y=m/1e6*r.input;y=Math.max(y,d),y=Math.min(y,g);let S=Math.pow(10,P),u=Math.floor(y*S).toString(),h=Ie(o,t,r.input,m);return{amountAtomic:u,usdAmount:y,inputTokens:m,model:t,tier:r.tier,inputRatePerMillion:r.input,outputRatePerMillion:r.output,maxOutputTokens:r.maxTokens,quoteHash:h}}async function A(o,x){if(!x)return!1;let f=await w(o);return Ie(o,t,r.input,f)===x}return{calculate:k,validateQuote:A,countTokens:w,config:c,modelInfo:r}}function Be(){return Object.entries(I).map(([e,t])=>({model:e,inputRate:t.input,outputRate:t.output,maxTokens:t.maxTokens,tier:t.tier})).sort((e,t)=>{let n={fast:0,standard:1,reasoning:2,premium:3},r=n[e.tier]-n[t.tier];return r!==0?r:e.inputRate-t.inputRate})}function $e(e){return e in I}function qe(e=z){let t=I[e]??I[z],n=I[e]?e:z;return`$${t.input.toFixed(2)} per 1M tokens (${n})`}var Fe=require("@dexterai/x402-ads-types");0&&(module.exports={BASE_MAINNET_NETWORK,DEXTER_FACILITATOR_URL,FacilitatorClient,MODEL_PRICING,MODEL_PRICING_MAP,MODEL_REGISTRY,SOLANA_MAINNET_NETWORK,SPONSORED_ACCESS_EXTENSION_KEY,USDC_BASE,USDC_MINT,countTokens,createDynamicPricing,createTokenPricing,createX402Server,escapeHtml,estimateCost,findModel,formatModelPricing,formatPricing,formatTokenPricing,getActiveModels,getAvailableModelIds,getAvailableModels,getCheapestModel,getModel,getModelsByFamily,getModelsByTier,getTextModels,isValidModel,isValidModelId,stripePayTo,x402AccessPass,x402BrowserSupport,x402Middleware});