@dexterai/x402 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/index.d.cts +4 -4
- package/dist/adapters/index.d.ts +4 -4
- package/dist/client/index.cjs +182 -4
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +23 -5
- package/dist/client/index.d.ts +23 -5
- package/dist/client/index.js +182 -4
- package/dist/client/index.js.map +1 -1
- package/dist/{evm-ZDwQi4QL.d.ts → evm-71SZ7cjW.d.ts} +2 -2
- package/dist/{evm-BaoETN1Y.d.cts → evm-BYjwU6ZW.d.cts} +2 -2
- package/dist/react/index.cjs +323 -3
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +108 -4
- package/dist/react/index.d.ts +108 -4
- package/dist/react/index.js +322 -3
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +253 -2
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +101 -3
- package/dist/server/index.d.ts +101 -3
- package/dist/server/index.js +240 -0
- package/dist/server/index.js.map +1 -1
- package/dist/{types-CQGDK_7X.d.cts → types--r7urkVI.d.cts} +1 -1
- package/dist/{types-DNx7-QUN.d.ts → types-BtpD4ULe.d.ts} +1 -1
- package/dist/{types-B7T6dZ-y.d.cts → types-CcVAaoro.d.cts} +64 -2
- package/dist/{types-B7T6dZ-y.d.ts → types-CcVAaoro.d.ts} +64 -2
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/{x402-client-COrn-FQk.d.ts → x402-client-BxQWcK2Z.d.ts} +8 -1
- package/dist/{x402-client-DHmpVhEK.d.cts → x402-client-Dcm2FQ9f.d.cts} +8 -1
- package/package.json +1 -1
package/dist/server/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
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
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/server/index.ts
|
|
@@ -48,6 +58,7 @@ __export(server_exports, {
|
|
|
48
58
|
getTextModels: () => getTextModels,
|
|
49
59
|
isValidModel: () => isValidModel,
|
|
50
60
|
isValidModelId: () => isValidModelId,
|
|
61
|
+
x402AccessPass: () => x402AccessPass,
|
|
51
62
|
x402Middleware: () => x402Middleware
|
|
52
63
|
});
|
|
53
64
|
module.exports = __toCommonJS(server_exports);
|
|
@@ -411,6 +422,245 @@ function x402Middleware(config) {
|
|
|
411
422
|
};
|
|
412
423
|
}
|
|
413
424
|
|
|
425
|
+
// src/server/access-pass.ts
|
|
426
|
+
var import_crypto = __toESM(require("crypto"), 1);
|
|
427
|
+
var DURATION_REGEX = /^(\d+)(m|h|d|w)$/;
|
|
428
|
+
function parseTierDuration(tierId) {
|
|
429
|
+
const match = tierId.match(DURATION_REGEX);
|
|
430
|
+
if (!match) return null;
|
|
431
|
+
const value = parseInt(match[1], 10);
|
|
432
|
+
const unit = match[2];
|
|
433
|
+
switch (unit) {
|
|
434
|
+
case "m":
|
|
435
|
+
return value * 60;
|
|
436
|
+
case "h":
|
|
437
|
+
return value * 3600;
|
|
438
|
+
case "d":
|
|
439
|
+
return value * 86400;
|
|
440
|
+
case "w":
|
|
441
|
+
return value * 604800;
|
|
442
|
+
default:
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
function formatDuration(seconds) {
|
|
447
|
+
if (seconds >= 604800 && seconds % 604800 === 0) return `${seconds / 604800} week${seconds / 604800 > 1 ? "s" : ""}`;
|
|
448
|
+
if (seconds >= 86400 && seconds % 86400 === 0) return `${seconds / 86400} day${seconds / 86400 > 1 ? "s" : ""}`;
|
|
449
|
+
if (seconds >= 3600 && seconds % 3600 === 0) return `${seconds / 3600} hour${seconds / 3600 > 1 ? "s" : ""}`;
|
|
450
|
+
if (seconds >= 60 && seconds % 60 === 0) return `${seconds / 60} minute${seconds / 60 > 1 ? "s" : ""}`;
|
|
451
|
+
return `${seconds} second${seconds > 1 ? "s" : ""}`;
|
|
452
|
+
}
|
|
453
|
+
function signJwt(payload, secret) {
|
|
454
|
+
const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url");
|
|
455
|
+
const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
456
|
+
const sig = import_crypto.default.createHmac("sha256", secret).update(`${header}.${body}`).digest("base64url");
|
|
457
|
+
return `${header}.${body}.${sig}`;
|
|
458
|
+
}
|
|
459
|
+
function verifyJwt(token, secret) {
|
|
460
|
+
try {
|
|
461
|
+
const parts = token.split(".");
|
|
462
|
+
if (parts.length !== 3) return null;
|
|
463
|
+
const [header, body, sig] = parts;
|
|
464
|
+
const expected = import_crypto.default.createHmac("sha256", secret).update(`${header}.${body}`).digest("base64url");
|
|
465
|
+
if (sig !== expected) return null;
|
|
466
|
+
const payload = JSON.parse(Buffer.from(body, "base64url").toString());
|
|
467
|
+
if (payload.exp && Date.now() / 1e3 > payload.exp) return null;
|
|
468
|
+
if (payload.sub !== "x402-access-pass") return null;
|
|
469
|
+
return payload;
|
|
470
|
+
} catch {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
var DEFAULT_NETWORK2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
475
|
+
var USDC_DECIMALS2 = 6;
|
|
476
|
+
function x402AccessPass(config) {
|
|
477
|
+
const {
|
|
478
|
+
payTo,
|
|
479
|
+
network = DEFAULT_NETWORK2,
|
|
480
|
+
asset,
|
|
481
|
+
facilitatorUrl,
|
|
482
|
+
tiers: tierPrices,
|
|
483
|
+
ratePerHour,
|
|
484
|
+
secret = import_crypto.default.randomBytes(32),
|
|
485
|
+
issuer = "x402-access-pass",
|
|
486
|
+
verbose = false,
|
|
487
|
+
description
|
|
488
|
+
} = config;
|
|
489
|
+
if (!tierPrices && !ratePerHour) {
|
|
490
|
+
throw new Error("x402AccessPass: at least one of `tiers` or `ratePerHour` is required");
|
|
491
|
+
}
|
|
492
|
+
const log = verbose ? console.log.bind(console, "[x402:access-pass]") : () => {
|
|
493
|
+
};
|
|
494
|
+
const decimals = asset?.decimals ?? USDC_DECIMALS2;
|
|
495
|
+
const builtTiers = [];
|
|
496
|
+
if (tierPrices) {
|
|
497
|
+
for (const [id, price] of Object.entries(tierPrices)) {
|
|
498
|
+
const seconds = parseTierDuration(id);
|
|
499
|
+
if (!seconds) {
|
|
500
|
+
console.warn(`x402AccessPass: skipping tier "${id}" \u2014 unrecognized duration format (use 5m, 1h, 24h, 7d)`);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
builtTiers.push({
|
|
504
|
+
id,
|
|
505
|
+
label: formatDuration(seconds),
|
|
506
|
+
seconds,
|
|
507
|
+
price,
|
|
508
|
+
priceAtomic: toAtomicUnits(parseFloat(price), decimals)
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
builtTiers.sort((a, b) => a.seconds - b.seconds);
|
|
512
|
+
}
|
|
513
|
+
const server = createX402Server({
|
|
514
|
+
payTo,
|
|
515
|
+
network,
|
|
516
|
+
asset,
|
|
517
|
+
facilitatorUrl
|
|
518
|
+
});
|
|
519
|
+
const passInfo = {
|
|
520
|
+
tiers: builtTiers.length > 0 ? builtTiers : void 0,
|
|
521
|
+
ratePerHour: ratePerHour || void 0,
|
|
522
|
+
issuer
|
|
523
|
+
};
|
|
524
|
+
const passInfoEncoded = btoa(JSON.stringify(passInfo));
|
|
525
|
+
function calculateCustomPrice(durationSeconds) {
|
|
526
|
+
if (!ratePerHour) {
|
|
527
|
+
throw new Error("Custom durations not supported \u2014 no ratePerHour configured");
|
|
528
|
+
}
|
|
529
|
+
const hours = durationSeconds / 3600;
|
|
530
|
+
const price = (parseFloat(ratePerHour) * hours).toFixed(decimals > 4 ? 4 : 2);
|
|
531
|
+
return { price, priceAtomic: toAtomicUnits(parseFloat(price), decimals) };
|
|
532
|
+
}
|
|
533
|
+
function resolvePricing(req) {
|
|
534
|
+
const tierParam = req.query.tier;
|
|
535
|
+
const durationParam = req.query.duration;
|
|
536
|
+
if (tierParam) {
|
|
537
|
+
const found = builtTiers.find((t) => t.id === tierParam);
|
|
538
|
+
if (found) {
|
|
539
|
+
return { tier: found.id, seconds: found.seconds, price: found.price, priceAtomic: found.priceAtomic, label: found.label };
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (durationParam) {
|
|
543
|
+
const seconds = parseInt(durationParam, 10);
|
|
544
|
+
if (seconds > 0 && ratePerHour) {
|
|
545
|
+
const pricing2 = calculateCustomPrice(seconds);
|
|
546
|
+
return { tier: "custom", seconds, ...pricing2, label: formatDuration(seconds) };
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (builtTiers.length > 0) {
|
|
550
|
+
const t = builtTiers[0];
|
|
551
|
+
return { tier: t.id, seconds: t.seconds, price: t.price, priceAtomic: t.priceAtomic, label: t.label };
|
|
552
|
+
}
|
|
553
|
+
const pricing = calculateCustomPrice(3600);
|
|
554
|
+
return { tier: "custom", seconds: 3600, ...pricing, label: "1 hour" };
|
|
555
|
+
}
|
|
556
|
+
return async (req, res, next) => {
|
|
557
|
+
try {
|
|
558
|
+
const auth = req.headers.authorization;
|
|
559
|
+
if (auth?.startsWith("Bearer ")) {
|
|
560
|
+
const claims = verifyJwt(auth.slice(7), secret);
|
|
561
|
+
if (claims) {
|
|
562
|
+
log("Valid access pass:", claims.tier, "| expires:", new Date(claims.exp * 1e3).toISOString());
|
|
563
|
+
req.accessPass = {
|
|
564
|
+
tier: claims.tier,
|
|
565
|
+
duration: claims.duration,
|
|
566
|
+
expiresAt: new Date(claims.exp * 1e3).toISOString(),
|
|
567
|
+
payer: claims.payer,
|
|
568
|
+
network: claims.network
|
|
569
|
+
};
|
|
570
|
+
return next();
|
|
571
|
+
}
|
|
572
|
+
log("Invalid or expired access pass token");
|
|
573
|
+
}
|
|
574
|
+
const paymentSignature = req.headers["payment-signature"];
|
|
575
|
+
if (paymentSignature) {
|
|
576
|
+
log("Payment signature received, verifying for pass purchase...");
|
|
577
|
+
const verifyResult = await server.verifyPayment(paymentSignature);
|
|
578
|
+
if (!verifyResult.isValid) {
|
|
579
|
+
log("Payment verification failed:", verifyResult.invalidReason);
|
|
580
|
+
res.status(402).json({ error: "Payment verification failed", reason: verifyResult.invalidReason });
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
const settleResult = await server.settlePayment(paymentSignature);
|
|
584
|
+
if (!settleResult.success) {
|
|
585
|
+
log("Payment settlement failed:", settleResult.errorReason);
|
|
586
|
+
res.status(402).json({ error: "Payment settlement failed", reason: settleResult.errorReason });
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
log("Payment settled:", settleResult.transaction);
|
|
590
|
+
const pricing2 = resolvePricing(req);
|
|
591
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
592
|
+
const claims = {
|
|
593
|
+
sub: "x402-access-pass",
|
|
594
|
+
tier: pricing2.tier,
|
|
595
|
+
duration: pricing2.seconds,
|
|
596
|
+
iat: now,
|
|
597
|
+
exp: now + pricing2.seconds,
|
|
598
|
+
payer: verifyResult.payer ?? "",
|
|
599
|
+
network,
|
|
600
|
+
iss: issuer
|
|
601
|
+
};
|
|
602
|
+
const jwt = signJwt(claims, secret);
|
|
603
|
+
req.x402 = {
|
|
604
|
+
transaction: settleResult.transaction,
|
|
605
|
+
payer: verifyResult.payer ?? "",
|
|
606
|
+
network
|
|
607
|
+
};
|
|
608
|
+
const paymentResponseData = {
|
|
609
|
+
success: true,
|
|
610
|
+
transaction: settleResult.transaction,
|
|
611
|
+
network,
|
|
612
|
+
payer: verifyResult.payer ?? ""
|
|
613
|
+
};
|
|
614
|
+
res.setHeader("PAYMENT-RESPONSE", btoa(JSON.stringify(paymentResponseData)));
|
|
615
|
+
res.setHeader("ACCESS-PASS", jwt);
|
|
616
|
+
res.json({
|
|
617
|
+
accessPass: {
|
|
618
|
+
token: jwt,
|
|
619
|
+
tier: pricing2.tier,
|
|
620
|
+
duration: pricing2.label,
|
|
621
|
+
durationSeconds: pricing2.seconds,
|
|
622
|
+
expiresAt: new Date((now + pricing2.seconds) * 1e3).toISOString(),
|
|
623
|
+
usage: "Include on subsequent requests as: Authorization: Bearer <token>"
|
|
624
|
+
},
|
|
625
|
+
transaction: settleResult.transaction,
|
|
626
|
+
payer: verifyResult.payer
|
|
627
|
+
});
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
log("No access pass or payment, returning 402");
|
|
631
|
+
const pricing = resolvePricing(req);
|
|
632
|
+
const amountAtomic = pricing.priceAtomic;
|
|
633
|
+
const resourceUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
|
|
634
|
+
const requirements = await server.buildRequirements({
|
|
635
|
+
amountAtomic,
|
|
636
|
+
resourceUrl,
|
|
637
|
+
description: description || `Access pass: ${pricing.label}`,
|
|
638
|
+
mimeType: "application/json"
|
|
639
|
+
});
|
|
640
|
+
const encoded = server.encodeRequirements(requirements);
|
|
641
|
+
res.setHeader("PAYMENT-REQUIRED", encoded);
|
|
642
|
+
res.setHeader("X-ACCESS-PASS-TIERS", passInfoEncoded);
|
|
643
|
+
res.status(402).json({
|
|
644
|
+
error: "Access pass required",
|
|
645
|
+
message: "Purchase an access pass to unlock unlimited API access for a time window.",
|
|
646
|
+
accepts: requirements.accepts,
|
|
647
|
+
resource: requirements.resource,
|
|
648
|
+
accessPass: {
|
|
649
|
+
tiers: builtTiers.length > 0 ? builtTiers : void 0,
|
|
650
|
+
ratePerHour: ratePerHour || void 0,
|
|
651
|
+
usage: "Add ?tier=<id> or ?duration=<seconds> to your payment request to choose a pass duration."
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
} catch (error) {
|
|
655
|
+
log("Access pass middleware error:", error);
|
|
656
|
+
res.status(500).json({
|
|
657
|
+
error: "Payment processing error",
|
|
658
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
|
|
414
664
|
// src/server/dynamic-pricing.ts
|
|
415
665
|
function simpleHash(str) {
|
|
416
666
|
let hash = 2166136261;
|
|
@@ -494,7 +744,7 @@ function formatPricing(config) {
|
|
|
494
744
|
}
|
|
495
745
|
|
|
496
746
|
// src/server/token-pricing.ts
|
|
497
|
-
var
|
|
747
|
+
var import_crypto2 = require("crypto");
|
|
498
748
|
var import_tiktoken = require("tiktoken");
|
|
499
749
|
|
|
500
750
|
// src/server/model-registry.ts
|
|
@@ -1092,7 +1342,7 @@ function countTokens(text, model = DEFAULT_MODEL) {
|
|
|
1092
1342
|
}
|
|
1093
1343
|
function generateQuoteHash(prompt, model, rate, tokens) {
|
|
1094
1344
|
const configString = JSON.stringify({ model, rate, tokens });
|
|
1095
|
-
return (0,
|
|
1345
|
+
return (0, import_crypto2.createHash)("sha256").update(prompt + configString).digest("hex").slice(0, 16);
|
|
1096
1346
|
}
|
|
1097
1347
|
function createTokenPricing(config = {}) {
|
|
1098
1348
|
const model = config.model ?? DEFAULT_MODEL;
|
|
@@ -1211,6 +1461,7 @@ function formatTokenPricing(model = DEFAULT_MODEL) {
|
|
|
1211
1461
|
getTextModels,
|
|
1212
1462
|
isValidModel,
|
|
1213
1463
|
isValidModelId,
|
|
1464
|
+
x402AccessPass,
|
|
1214
1465
|
x402Middleware
|
|
1215
1466
|
});
|
|
1216
1467
|
//# sourceMappingURL=index.cjs.map
|