@x402/extensions 2.7.0 → 2.9.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 +27 -22
- package/dist/cjs/bazaar/index.d.ts +1 -1
- package/dist/cjs/bazaar/index.js +139 -9
- package/dist/cjs/bazaar/index.js.map +1 -1
- package/dist/cjs/{index-CtOzXcjN.d.ts → index-DihVrF7v.d.ts} +49 -9
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +143 -12
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/sign-in-with-x/index.d.ts +7 -1
- package/dist/cjs/sign-in-with-x/index.js +4 -3
- package/dist/cjs/sign-in-with-x/index.js.map +1 -1
- package/dist/esm/bazaar/index.d.mts +1 -1
- package/dist/esm/bazaar/index.mjs +5 -1
- package/dist/esm/{chunk-QVNCC7CH.mjs → chunk-5UYCX7A7.mjs} +5 -4
- package/dist/esm/{chunk-QVNCC7CH.mjs.map → chunk-5UYCX7A7.mjs.map} +1 -1
- package/dist/esm/{chunk-ANAQVNUK.mjs → chunk-V4MBUZVP.mjs} +138 -10
- package/dist/esm/chunk-V4MBUZVP.mjs.map +1 -0
- package/dist/esm/{index-CtOzXcjN.d.mts → index-DihVrF7v.d.mts} +49 -9
- package/dist/esm/index.d.mts +1 -1
- package/dist/esm/index.mjs +6 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/sign-in-with-x/index.d.mts +7 -1
- package/dist/esm/sign-in-with-x/index.mjs +1 -1
- package/package.json +4 -4
- package/dist/esm/chunk-ANAQVNUK.mjs.map +0 -1
package/dist/cjs/index.js
CHANGED
|
@@ -124,6 +124,7 @@ __export(src_exports, {
|
|
|
124
124
|
isQueryExtensionConfig: () => isQueryExtensionConfig,
|
|
125
125
|
isSolanaSigner: () => isSolanaSigner,
|
|
126
126
|
isValidPaymentId: () => isValidPaymentId,
|
|
127
|
+
isValidRouteTemplate: () => isValidRouteTemplate,
|
|
127
128
|
parseSIWxHeader: () => parseSIWxHeader,
|
|
128
129
|
paymentIdentifierResourceServerExtension: () => paymentIdentifierResourceServerExtension,
|
|
129
130
|
paymentIdentifierSchema: () => paymentIdentifierSchema,
|
|
@@ -140,6 +141,7 @@ __export(src_exports, {
|
|
|
140
141
|
validateErc20ApprovalGasSponsoringInfo: () => validateErc20ApprovalGasSponsoringInfo,
|
|
141
142
|
validatePaymentIdentifier: () => validatePaymentIdentifier,
|
|
142
143
|
validatePaymentIdentifierRequirement: () => validatePaymentIdentifierRequirement,
|
|
144
|
+
validateRouteTemplate: () => validateRouteTemplate,
|
|
143
145
|
validateSIWxMessage: () => validateSIWxMessage,
|
|
144
146
|
verifyEVMSignature: () => verifyEVMSignature,
|
|
145
147
|
verifyOfferSignatureEIP712: () => verifyOfferSignatureEIP712,
|
|
@@ -175,6 +177,8 @@ function createQueryDiscoveryExtension({
|
|
|
175
177
|
method,
|
|
176
178
|
input = {},
|
|
177
179
|
inputSchema = { properties: {} },
|
|
180
|
+
pathParams,
|
|
181
|
+
pathParamsSchema,
|
|
178
182
|
output
|
|
179
183
|
}) {
|
|
180
184
|
return {
|
|
@@ -182,7 +186,8 @@ function createQueryDiscoveryExtension({
|
|
|
182
186
|
input: {
|
|
183
187
|
type: "http",
|
|
184
188
|
...method ? { method } : {},
|
|
185
|
-
...input ? { queryParams: input } : {}
|
|
189
|
+
...input ? { queryParams: input } : {},
|
|
190
|
+
...pathParams ? { pathParams } : {}
|
|
186
191
|
},
|
|
187
192
|
...output?.example ? {
|
|
188
193
|
output: {
|
|
@@ -211,9 +216,18 @@ function createQueryDiscoveryExtension({
|
|
|
211
216
|
type: "object",
|
|
212
217
|
...typeof inputSchema === "object" ? inputSchema : {}
|
|
213
218
|
}
|
|
219
|
+
} : {},
|
|
220
|
+
...pathParamsSchema ? {
|
|
221
|
+
pathParams: {
|
|
222
|
+
type: "object",
|
|
223
|
+
...typeof pathParamsSchema === "object" ? pathParamsSchema : {}
|
|
224
|
+
}
|
|
214
225
|
} : {}
|
|
215
226
|
},
|
|
216
|
-
required: ["type"],
|
|
227
|
+
required: ["type", "method"],
|
|
228
|
+
// pathParams are not declared here at schema build time --
|
|
229
|
+
// the server extension's enrichDeclaration adds them to both info and schema
|
|
230
|
+
// atomically at request time, keeping data and schema consistent.
|
|
217
231
|
additionalProperties: false
|
|
218
232
|
},
|
|
219
233
|
...output?.example ? {
|
|
@@ -240,6 +254,8 @@ function createBodyDiscoveryExtension({
|
|
|
240
254
|
method,
|
|
241
255
|
input = {},
|
|
242
256
|
inputSchema = { properties: {} },
|
|
257
|
+
pathParams,
|
|
258
|
+
pathParamsSchema,
|
|
243
259
|
bodyType,
|
|
244
260
|
output
|
|
245
261
|
}) {
|
|
@@ -249,7 +265,8 @@ function createBodyDiscoveryExtension({
|
|
|
249
265
|
type: "http",
|
|
250
266
|
...method ? { method } : {},
|
|
251
267
|
bodyType,
|
|
252
|
-
body: input
|
|
268
|
+
body: input,
|
|
269
|
+
...pathParams ? { pathParams } : {}
|
|
253
270
|
},
|
|
254
271
|
...output?.example ? {
|
|
255
272
|
output: {
|
|
@@ -277,9 +294,18 @@ function createBodyDiscoveryExtension({
|
|
|
277
294
|
type: "string",
|
|
278
295
|
enum: ["json", "form-data", "text"]
|
|
279
296
|
},
|
|
280
|
-
body: inputSchema
|
|
297
|
+
body: inputSchema,
|
|
298
|
+
...pathParamsSchema ? {
|
|
299
|
+
pathParams: {
|
|
300
|
+
type: "object",
|
|
301
|
+
...typeof pathParamsSchema === "object" ? pathParamsSchema : {}
|
|
302
|
+
}
|
|
303
|
+
} : {}
|
|
281
304
|
},
|
|
282
|
-
required: ["type", "bodyType", "body"],
|
|
305
|
+
required: ["type", "method", "bodyType", "body"],
|
|
306
|
+
// pathParams are not declared here at schema build time --
|
|
307
|
+
// the server extension's enrichDeclaration adds them to both info and schema
|
|
308
|
+
// atomically at request time, keeping data and schema consistent.
|
|
283
309
|
additionalProperties: false
|
|
284
310
|
},
|
|
285
311
|
...output?.example ? {
|
|
@@ -400,9 +426,57 @@ function declareDiscoveryExtension(config) {
|
|
|
400
426
|
}
|
|
401
427
|
|
|
402
428
|
// src/bazaar/server.ts
|
|
429
|
+
var BRACKET_PARAM_REGEX = /\[([^\]]+)\]/;
|
|
430
|
+
var BRACKET_PARAM_REGEX_ALL = /\[([^\]]+)\]/g;
|
|
431
|
+
var COLON_PARAM_REGEX = /:([a-zA-Z_][a-zA-Z0-9_]*)/;
|
|
403
432
|
function isHTTPRequestContext(ctx) {
|
|
404
433
|
return ctx !== null && typeof ctx === "object" && "method" in ctx && "adapter" in ctx;
|
|
405
434
|
}
|
|
435
|
+
function normalizeWildcardPattern(pattern) {
|
|
436
|
+
if (!pattern.includes("*")) {
|
|
437
|
+
return pattern;
|
|
438
|
+
}
|
|
439
|
+
let counter = 0;
|
|
440
|
+
return pattern.split("/").map((seg) => {
|
|
441
|
+
if (seg === "*") {
|
|
442
|
+
counter++;
|
|
443
|
+
return `:var${counter}`;
|
|
444
|
+
}
|
|
445
|
+
return seg;
|
|
446
|
+
}).join("/");
|
|
447
|
+
}
|
|
448
|
+
function extractDynamicRouteInfo(routePattern, urlPath) {
|
|
449
|
+
const hasBracket = BRACKET_PARAM_REGEX.test(routePattern);
|
|
450
|
+
const hasColon = COLON_PARAM_REGEX.test(routePattern);
|
|
451
|
+
if (!hasBracket && !hasColon) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
const normalizedPattern = hasBracket ? routePattern.replace(BRACKET_PARAM_REGEX_ALL, ":$1") : routePattern;
|
|
455
|
+
const pathParams = extractPathParams(normalizedPattern, urlPath, false);
|
|
456
|
+
return { routeTemplate: normalizedPattern, pathParams };
|
|
457
|
+
}
|
|
458
|
+
function extractPathParams(routePattern, urlPath, isBracket) {
|
|
459
|
+
const paramNames = [];
|
|
460
|
+
const splitRegex = isBracket ? BRACKET_PARAM_REGEX : COLON_PARAM_REGEX;
|
|
461
|
+
const parts = routePattern.split(splitRegex);
|
|
462
|
+
const regexParts = [];
|
|
463
|
+
parts.forEach((part, i) => {
|
|
464
|
+
if (i % 2 === 0) {
|
|
465
|
+
regexParts.push(part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
466
|
+
} else {
|
|
467
|
+
paramNames.push(part);
|
|
468
|
+
regexParts.push("([^/]+)");
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
const regex = new RegExp(`^${regexParts.join("")}$`);
|
|
472
|
+
const match = urlPath.match(regex);
|
|
473
|
+
if (!match) return {};
|
|
474
|
+
const result = {};
|
|
475
|
+
paramNames.forEach((name, idx) => {
|
|
476
|
+
result[name] = match[idx + 1];
|
|
477
|
+
});
|
|
478
|
+
return result;
|
|
479
|
+
}
|
|
406
480
|
var bazaarResourceServerExtension = {
|
|
407
481
|
key: BAZAAR.key,
|
|
408
482
|
enrichDeclaration: (declaration, transportContext) => {
|
|
@@ -422,7 +496,7 @@ var bazaarResourceServerExtension = {
|
|
|
422
496
|
enum: [method]
|
|
423
497
|
}
|
|
424
498
|
};
|
|
425
|
-
|
|
499
|
+
const enrichedResult = {
|
|
426
500
|
...extension,
|
|
427
501
|
info: {
|
|
428
502
|
...extension.info || {},
|
|
@@ -446,6 +520,37 @@ var bazaarResourceServerExtension = {
|
|
|
446
520
|
}
|
|
447
521
|
}
|
|
448
522
|
};
|
|
523
|
+
const rawRoutePattern = transportContext.routePattern;
|
|
524
|
+
const routePattern = rawRoutePattern ? normalizeWildcardPattern(rawRoutePattern) : void 0;
|
|
525
|
+
const dynamicRoute = routePattern ? extractDynamicRouteInfo(routePattern, transportContext.adapter.getPath()) : null;
|
|
526
|
+
if (dynamicRoute) {
|
|
527
|
+
const inputSchemaProps = enrichedResult.schema?.properties?.input?.properties || {};
|
|
528
|
+
const hasPathParamsInSchema = "pathParams" in inputSchemaProps;
|
|
529
|
+
return {
|
|
530
|
+
...enrichedResult,
|
|
531
|
+
routeTemplate: dynamicRoute.routeTemplate,
|
|
532
|
+
info: {
|
|
533
|
+
...enrichedResult.info,
|
|
534
|
+
input: { ...enrichedResult.info.input, pathParams: dynamicRoute.pathParams }
|
|
535
|
+
},
|
|
536
|
+
...!hasPathParamsInSchema ? {
|
|
537
|
+
schema: {
|
|
538
|
+
...enrichedResult.schema,
|
|
539
|
+
properties: {
|
|
540
|
+
...enrichedResult.schema?.properties,
|
|
541
|
+
input: {
|
|
542
|
+
...enrichedResult.schema?.properties?.input,
|
|
543
|
+
properties: {
|
|
544
|
+
...inputSchemaProps,
|
|
545
|
+
pathParams: { type: "object" }
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
} : {}
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
return enrichedResult;
|
|
449
554
|
}
|
|
450
555
|
};
|
|
451
556
|
|
|
@@ -567,6 +672,23 @@ function extractResourceMetadataV1(paymentRequirements) {
|
|
|
567
672
|
}
|
|
568
673
|
|
|
569
674
|
// src/bazaar/facilitator.ts
|
|
675
|
+
var ROUTE_TEMPLATE_REGEX = /^\/[a-zA-Z0-9_/:.\-~%]+$/;
|
|
676
|
+
function isValidRouteTemplate(value) {
|
|
677
|
+
if (!value) return false;
|
|
678
|
+
if (!ROUTE_TEMPLATE_REGEX.test(value)) return false;
|
|
679
|
+
let decoded;
|
|
680
|
+
try {
|
|
681
|
+
decoded = decodeURIComponent(value);
|
|
682
|
+
} catch {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
if (decoded.includes("..")) return false;
|
|
686
|
+
if (decoded.includes("://")) return false;
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
function validateRouteTemplate(value) {
|
|
690
|
+
return isValidRouteTemplate(value) ? value : void 0;
|
|
691
|
+
}
|
|
570
692
|
function validateDiscoveryExtension(extension) {
|
|
571
693
|
try {
|
|
572
694
|
const ajv = new import__.default({ strict: false, allErrors: true });
|
|
@@ -592,12 +714,18 @@ function validateDiscoveryExtension(extension) {
|
|
|
592
714
|
function extractDiscoveryInfo(paymentPayload, paymentRequirements, validate = true) {
|
|
593
715
|
let discoveryInfo = null;
|
|
594
716
|
let resourceUrl;
|
|
717
|
+
let routeTemplate;
|
|
595
718
|
if (paymentPayload.x402Version === 2) {
|
|
596
719
|
resourceUrl = paymentPayload.resource?.url ?? "";
|
|
597
720
|
if (paymentPayload.extensions) {
|
|
598
721
|
const bazaarExtension = paymentPayload.extensions[BAZAAR.key];
|
|
599
722
|
if (bazaarExtension && typeof bazaarExtension === "object") {
|
|
600
723
|
try {
|
|
724
|
+
const rawExt = bazaarExtension;
|
|
725
|
+
const rawTemplate = typeof rawExt.routeTemplate === "string" ? rawExt.routeTemplate : void 0;
|
|
726
|
+
if (isValidRouteTemplate(rawTemplate)) {
|
|
727
|
+
routeTemplate = rawTemplate;
|
|
728
|
+
}
|
|
601
729
|
const extension = bazaarExtension;
|
|
602
730
|
if (validate) {
|
|
603
731
|
const result = validateDiscoveryExtension(extension);
|
|
@@ -627,7 +755,7 @@ function extractDiscoveryInfo(paymentPayload, paymentRequirements, validate = tr
|
|
|
627
755
|
return null;
|
|
628
756
|
}
|
|
629
757
|
const url = new URL(resourceUrl);
|
|
630
|
-
const
|
|
758
|
+
const canonicalUrl = routeTemplate ? `${url.origin}${routeTemplate}` : `${url.origin}${url.pathname}`;
|
|
631
759
|
let description;
|
|
632
760
|
let mimeType;
|
|
633
761
|
if (paymentPayload.x402Version === 2) {
|
|
@@ -639,7 +767,7 @@ function extractDiscoveryInfo(paymentPayload, paymentRequirements, validate = tr
|
|
|
639
767
|
mimeType = requirementsV1.mimeType;
|
|
640
768
|
}
|
|
641
769
|
const base = {
|
|
642
|
-
resourceUrl:
|
|
770
|
+
resourceUrl: canonicalUrl,
|
|
643
771
|
description,
|
|
644
772
|
mimeType,
|
|
645
773
|
x402Version: paymentPayload.x402Version,
|
|
@@ -648,7 +776,7 @@ function extractDiscoveryInfo(paymentPayload, paymentRequirements, validate = tr
|
|
|
648
776
|
if (discoveryInfo.input.type === "mcp") {
|
|
649
777
|
return { ...base, toolName: discoveryInfo.input.toolName };
|
|
650
778
|
}
|
|
651
|
-
return { ...base, method: discoveryInfo.input.method };
|
|
779
|
+
return { ...base, routeTemplate, method: discoveryInfo.input.method };
|
|
652
780
|
}
|
|
653
781
|
function extractDiscoveryInfoFromExtension(extension, validate = true) {
|
|
654
782
|
if (validate) {
|
|
@@ -1386,7 +1514,7 @@ function createSIWxRequestHook(options) {
|
|
|
1386
1514
|
"SIWxStorage nonce tracking requires both hasUsedNonce and recordNonce to be implemented"
|
|
1387
1515
|
);
|
|
1388
1516
|
}
|
|
1389
|
-
return async (context) => {
|
|
1517
|
+
return async (context, routeConfig) => {
|
|
1390
1518
|
const header = context.adapter.getHeader(SIGN_IN_WITH_X) || context.adapter.getHeader(SIGN_IN_WITH_X.toLowerCase());
|
|
1391
1519
|
if (!header) return;
|
|
1392
1520
|
try {
|
|
@@ -1409,8 +1537,9 @@ function createSIWxRequestHook(options) {
|
|
|
1409
1537
|
return;
|
|
1410
1538
|
}
|
|
1411
1539
|
}
|
|
1412
|
-
const
|
|
1413
|
-
|
|
1540
|
+
const isAuthOnly = Array.isArray(routeConfig?.accepts) && routeConfig.accepts.length === 0;
|
|
1541
|
+
const shouldGrant = isAuthOnly || await storage.hasPaid(context.path, verification.address);
|
|
1542
|
+
if (shouldGrant) {
|
|
1414
1543
|
if (storage.recordNonce) {
|
|
1415
1544
|
await storage.recordNonce(payload.nonce);
|
|
1416
1545
|
}
|
|
@@ -2713,6 +2842,7 @@ function validateErc20ApprovalGasSponsoringInfo(info) {
|
|
|
2713
2842
|
isQueryExtensionConfig,
|
|
2714
2843
|
isSolanaSigner,
|
|
2715
2844
|
isValidPaymentId,
|
|
2845
|
+
isValidRouteTemplate,
|
|
2716
2846
|
parseSIWxHeader,
|
|
2717
2847
|
paymentIdentifierResourceServerExtension,
|
|
2718
2848
|
paymentIdentifierSchema,
|
|
@@ -2729,6 +2859,7 @@ function validateErc20ApprovalGasSponsoringInfo(info) {
|
|
|
2729
2859
|
validateErc20ApprovalGasSponsoringInfo,
|
|
2730
2860
|
validatePaymentIdentifier,
|
|
2731
2861
|
validatePaymentIdentifierRequirement,
|
|
2862
|
+
validateRouteTemplate,
|
|
2732
2863
|
validateSIWxMessage,
|
|
2733
2864
|
verifyEVMSignature,
|
|
2734
2865
|
verifyOfferSignatureEIP712,
|