@dexterai/x402 1.4.0 → 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/README.md +1 -1
- 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 +263 -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 +250 -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);
|
|
@@ -137,6 +148,7 @@ var FacilitatorClient = class {
|
|
|
137
148
|
try {
|
|
138
149
|
const paymentPayload = decodeBase64Json(paymentSignatureHeader);
|
|
139
150
|
const verifyPayload = {
|
|
151
|
+
x402Version: 2,
|
|
140
152
|
paymentPayload,
|
|
141
153
|
paymentRequirements: requirements
|
|
142
154
|
};
|
|
@@ -175,6 +187,7 @@ var FacilitatorClient = class {
|
|
|
175
187
|
try {
|
|
176
188
|
const paymentPayload = decodeBase64Json(paymentSignatureHeader);
|
|
177
189
|
const settlePayload = {
|
|
190
|
+
x402Version: 2,
|
|
178
191
|
paymentPayload,
|
|
179
192
|
paymentRequirements: requirements
|
|
180
193
|
};
|
|
@@ -245,6 +258,7 @@ function createX402Server(config) {
|
|
|
245
258
|
return {
|
|
246
259
|
scheme: "exact",
|
|
247
260
|
network,
|
|
261
|
+
amount: amountAtomic,
|
|
248
262
|
maxAmountRequired: amountAtomic,
|
|
249
263
|
asset: asset.address,
|
|
250
264
|
payTo,
|
|
@@ -390,6 +404,13 @@ function x402Middleware(config) {
|
|
|
390
404
|
payer: verifyResult.payer ?? "",
|
|
391
405
|
network
|
|
392
406
|
};
|
|
407
|
+
const paymentResponseData = {
|
|
408
|
+
success: true,
|
|
409
|
+
transaction: settleResult.transaction,
|
|
410
|
+
network,
|
|
411
|
+
payer: verifyResult.payer ?? ""
|
|
412
|
+
};
|
|
413
|
+
res.setHeader("PAYMENT-RESPONSE", btoa(JSON.stringify(paymentResponseData)));
|
|
393
414
|
next();
|
|
394
415
|
} catch (error) {
|
|
395
416
|
log("Middleware error:", error);
|
|
@@ -401,6 +422,245 @@ function x402Middleware(config) {
|
|
|
401
422
|
};
|
|
402
423
|
}
|
|
403
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
|
+
|
|
404
664
|
// src/server/dynamic-pricing.ts
|
|
405
665
|
function simpleHash(str) {
|
|
406
666
|
let hash = 2166136261;
|
|
@@ -484,7 +744,7 @@ function formatPricing(config) {
|
|
|
484
744
|
}
|
|
485
745
|
|
|
486
746
|
// src/server/token-pricing.ts
|
|
487
|
-
var
|
|
747
|
+
var import_crypto2 = require("crypto");
|
|
488
748
|
var import_tiktoken = require("tiktoken");
|
|
489
749
|
|
|
490
750
|
// src/server/model-registry.ts
|
|
@@ -1082,7 +1342,7 @@ function countTokens(text, model = DEFAULT_MODEL) {
|
|
|
1082
1342
|
}
|
|
1083
1343
|
function generateQuoteHash(prompt, model, rate, tokens) {
|
|
1084
1344
|
const configString = JSON.stringify({ model, rate, tokens });
|
|
1085
|
-
return (0,
|
|
1345
|
+
return (0, import_crypto2.createHash)("sha256").update(prompt + configString).digest("hex").slice(0, 16);
|
|
1086
1346
|
}
|
|
1087
1347
|
function createTokenPricing(config = {}) {
|
|
1088
1348
|
const model = config.model ?? DEFAULT_MODEL;
|
|
@@ -1201,6 +1461,7 @@ function formatTokenPricing(model = DEFAULT_MODEL) {
|
|
|
1201
1461
|
getTextModels,
|
|
1202
1462
|
isValidModel,
|
|
1203
1463
|
isValidModelId,
|
|
1464
|
+
x402AccessPass,
|
|
1204
1465
|
x402Middleware
|
|
1205
1466
|
});
|
|
1206
1467
|
//# sourceMappingURL=index.cjs.map
|