@agentcash/discovery 1.6.1 → 1.6.3
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/cli.cjs +123 -31
- package/dist/cli.js +123 -31
- package/dist/index.cjs +123 -31
- package/dist/index.d.cts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.js +123 -31
- package/dist/schemas.cjs +9 -5
- package/dist/schemas.d.cts +55 -446
- package/dist/schemas.d.ts +55 -446
- package/dist/schemas.js +9 -5
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -13815,8 +13815,8 @@ var FixedPriceSchema = external_exports.object({
|
|
|
13815
13815
|
var DynamicPriceSchema = external_exports.object({
|
|
13816
13816
|
currency: Iso4217Schema,
|
|
13817
13817
|
mode: external_exports.literal("dynamic"),
|
|
13818
|
-
min: external_exports.string(),
|
|
13819
|
-
max: external_exports.string()
|
|
13818
|
+
min: external_exports.string().optional(),
|
|
13819
|
+
max: external_exports.string().optional()
|
|
13820
13820
|
});
|
|
13821
13821
|
var PriceSchema = external_exports.union([FixedPriceSchema, DynamicPriceSchema]);
|
|
13822
13822
|
var X402ProtocolSchema = external_exports.object({
|
|
@@ -13915,7 +13915,12 @@ function normalizeLegacy(raw) {
|
|
|
13915
13915
|
function formatPrice(price) {
|
|
13916
13916
|
const sym = price.currency ?? "USD";
|
|
13917
13917
|
if (price.mode === "fixed") return `${price.amount} ${sym}`;
|
|
13918
|
-
|
|
13918
|
+
if (price.min !== void 0 && price.max !== void 0) {
|
|
13919
|
+
return `${price.min}-${price.max} ${sym}`;
|
|
13920
|
+
}
|
|
13921
|
+
if (price.min !== void 0) return `>=${price.min} ${sym}`;
|
|
13922
|
+
if (price.max !== void 0) return `<=${price.max} ${sym}`;
|
|
13923
|
+
return `dynamic ${sym}`;
|
|
13919
13924
|
}
|
|
13920
13925
|
function extractProtocolNames(protocols) {
|
|
13921
13926
|
return protocols.map((p) => {
|
|
@@ -13967,10 +13972,13 @@ var OpenApiOperationSchema = external_exports.object({
|
|
|
13967
13972
|
description: external_exports.string().optional(),
|
|
13968
13973
|
tags: external_exports.array(external_exports.string()).optional(),
|
|
13969
13974
|
security: external_exports.array(external_exports.record(external_exports.string(), external_exports.array(external_exports.string()))).optional(),
|
|
13975
|
+
// `in` / `name` are spec-required, but a single malformed parameter must not
|
|
13976
|
+
// abort the whole spec — keep them optional so discovery is resilient to
|
|
13977
|
+
// non-conformant OpenAPI documents in the wild.
|
|
13970
13978
|
parameters: external_exports.array(
|
|
13971
13979
|
external_exports.object({
|
|
13972
|
-
in: external_exports.string(),
|
|
13973
|
-
name: external_exports.string(),
|
|
13980
|
+
in: external_exports.string().optional(),
|
|
13981
|
+
name: external_exports.string().optional(),
|
|
13974
13982
|
schema: external_exports.unknown().optional(),
|
|
13975
13983
|
required: external_exports.boolean().optional()
|
|
13976
13984
|
})
|
|
@@ -13980,7 +13988,8 @@ var OpenApiOperationSchema = external_exports.object({
|
|
|
13980
13988
|
content: external_exports.record(external_exports.string(), external_exports.object({ schema: external_exports.unknown().optional() }))
|
|
13981
13989
|
}).optional(),
|
|
13982
13990
|
responses: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
13983
|
-
|
|
13991
|
+
// Permissive: vendor extension shape is validated at runtime, never at parse time.
|
|
13992
|
+
"x-payment-info": external_exports.unknown().optional()
|
|
13984
13993
|
});
|
|
13985
13994
|
var OpenApiPathItemSchema = external_exports.object({
|
|
13986
13995
|
get: OpenApiOperationSchema.optional(),
|
|
@@ -14124,20 +14133,27 @@ function fetchSafe(url2, init) {
|
|
|
14124
14133
|
}
|
|
14125
14134
|
|
|
14126
14135
|
// src/core/source/openapi/index.ts
|
|
14127
|
-
function
|
|
14128
|
-
|
|
14129
|
-
|
|
14136
|
+
function toRecord(raw) {
|
|
14137
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
|
|
14138
|
+
return raw;
|
|
14139
|
+
}
|
|
14140
|
+
function resolvePricingHint(raw) {
|
|
14141
|
+
const record2 = toRecord(raw);
|
|
14142
|
+
if (!record2) return void 0;
|
|
14143
|
+
const info = resolvePaymentInfo(record2);
|
|
14130
14144
|
if (!info) return void 0;
|
|
14131
14145
|
return {
|
|
14132
14146
|
pricingMode: info.price.mode,
|
|
14133
14147
|
...info.price.mode === "fixed" ? { price: info.price.amount } : {},
|
|
14134
|
-
...info.price.mode === "dynamic"
|
|
14148
|
+
...info.price.mode === "dynamic" && info.price.min !== void 0 ? { minPrice: info.price.min } : {},
|
|
14149
|
+
...info.price.mode === "dynamic" && info.price.max !== void 0 ? { maxPrice: info.price.max } : {},
|
|
14135
14150
|
...info.price.currency ? { currency: info.price.currency } : {}
|
|
14136
14151
|
};
|
|
14137
14152
|
}
|
|
14138
|
-
function resolveProtocols(
|
|
14139
|
-
const
|
|
14140
|
-
|
|
14153
|
+
function resolveProtocols(raw) {
|
|
14154
|
+
const record2 = toRecord(raw);
|
|
14155
|
+
if (!record2) return [];
|
|
14156
|
+
const info = resolvePaymentInfo(record2);
|
|
14141
14157
|
if (!info) return [];
|
|
14142
14158
|
return extractProtocolNames(info.protocols);
|
|
14143
14159
|
}
|
|
@@ -14150,8 +14166,8 @@ var OpenApiParsedSchema = OpenApiDocSchema.transform((doc) => {
|
|
|
14150
14166
|
if (!operation) continue;
|
|
14151
14167
|
const authMode = inferAuthMode(operation, doc.security, doc.components?.securitySchemes) ?? void 0;
|
|
14152
14168
|
const p = operation["x-payment-info"];
|
|
14153
|
-
const protocols = resolveProtocols(p
|
|
14154
|
-
const pricing = (authMode === "paid" || authMode === "apiKey+paid") && p ? resolvePricingHint(p) : void 0;
|
|
14169
|
+
const protocols = resolveProtocols(p);
|
|
14170
|
+
const pricing = (authMode === "paid" || authMode === "apiKey+paid") && p !== void 0 ? resolvePricingHint(p) : void 0;
|
|
14155
14171
|
const summary = operation.summary ?? operation.description;
|
|
14156
14172
|
routes.push({
|
|
14157
14173
|
path: normalizePath(serverBasePath + rawPath),
|
|
@@ -14392,28 +14408,29 @@ function getWellKnown(origin, headers, signal) {
|
|
|
14392
14408
|
// src/core/layers/l2.ts
|
|
14393
14409
|
function formatPrice2(pricing) {
|
|
14394
14410
|
const sym = pricing.currency ?? "USD";
|
|
14395
|
-
if (pricing.pricingMode === "fixed") return `${pricing.price} ${sym}`;
|
|
14411
|
+
if (pricing.pricingMode === "fixed" && pricing.price) return `${pricing.price} ${sym}`;
|
|
14396
14412
|
if (pricing.pricingMode === "dynamic") {
|
|
14397
14413
|
if (pricing.minPrice && pricing.maxPrice)
|
|
14398
14414
|
return `${pricing.minPrice}-${pricing.maxPrice} ${sym}`;
|
|
14399
14415
|
if (pricing.maxPrice) return `up to ${pricing.maxPrice} ${sym}`;
|
|
14400
|
-
return
|
|
14416
|
+
if (pricing.minPrice) return `from ${pricing.minPrice} ${sym}`;
|
|
14401
14417
|
}
|
|
14402
|
-
return
|
|
14418
|
+
return void 0;
|
|
14403
14419
|
}
|
|
14404
14420
|
function checkL2ForOpenAPI(openApi) {
|
|
14405
|
-
const routes = openApi.routes.map((route) =>
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
...route.pricing
|
|
14414
|
-
|
|
14415
|
-
|
|
14416
|
-
|
|
14421
|
+
const routes = openApi.routes.map((route) => {
|
|
14422
|
+
const priceHint = route.pricing ? formatPrice2(route.pricing) : void 0;
|
|
14423
|
+
return {
|
|
14424
|
+
path: route.path,
|
|
14425
|
+
method: route.method,
|
|
14426
|
+
summary: route.summary ?? `${route.method} ${route.path}`,
|
|
14427
|
+
...route.authMode ? { authMode: route.authMode } : {},
|
|
14428
|
+
...priceHint ? { price: priceHint } : {},
|
|
14429
|
+
...route.pricing?.pricingMode ? { pricingMode: route.pricing.pricingMode } : {},
|
|
14430
|
+
...route.pricing?.currency ? { currency: route.pricing.currency } : {},
|
|
14431
|
+
...route.protocols?.length ? { protocols: route.protocols } : {}
|
|
14432
|
+
};
|
|
14433
|
+
});
|
|
14417
14434
|
return {
|
|
14418
14435
|
...openApi.info.title ? { title: openApi.info.title } : {},
|
|
14419
14436
|
...openApi.info.description ? { description: openApi.info.description } : {},
|
|
@@ -14474,9 +14491,12 @@ var AUDIT_CODES = {
|
|
|
14474
14491
|
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
14475
14492
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
14476
14493
|
L2_PRICING_MODE_UNKNOWN: "L2_PRICING_MODE_UNKNOWN",
|
|
14494
|
+
L2_DYNAMIC_PRICE_INCOMPLETE: "L2_DYNAMIC_PRICE_INCOMPLETE",
|
|
14477
14495
|
L2_CURRENCY_INVALID: "L2_CURRENCY_INVALID",
|
|
14478
14496
|
L2_PAYMENT_INFO_LEGACY: "L2_PAYMENT_INFO_LEGACY",
|
|
14479
14497
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
14498
|
+
L2_X402_MALFORMED: "L2_X402_MALFORMED",
|
|
14499
|
+
L2_MPP_MALFORMED: "L2_MPP_MALFORMED",
|
|
14480
14500
|
// ─── L3 endpoint advisory checks ─────────────────────────────────────────────
|
|
14481
14501
|
L3_NOT_FOUND: "L3_NOT_FOUND",
|
|
14482
14502
|
L3_INPUT_SCHEMA_MISSING: "L3_INPUT_SCHEMA_MISSING",
|
|
@@ -14525,6 +14545,54 @@ function hasLegacyPaymentInfo(raw) {
|
|
|
14525
14545
|
}
|
|
14526
14546
|
return false;
|
|
14527
14547
|
}
|
|
14548
|
+
function hasImproperMppTag(raw) {
|
|
14549
|
+
const paths = raw.paths;
|
|
14550
|
+
if (typeof paths !== "object" || paths === null) return false;
|
|
14551
|
+
for (const pathItem of Object.values(paths)) {
|
|
14552
|
+
if (typeof pathItem !== "object" || pathItem === null) continue;
|
|
14553
|
+
for (const method of HTTP_METHODS2) {
|
|
14554
|
+
const operation = pathItem[method];
|
|
14555
|
+
if (typeof operation !== "object" || operation === null) continue;
|
|
14556
|
+
const pi = operation["x-payment-info"];
|
|
14557
|
+
if (typeof pi !== "object" || pi === null) continue;
|
|
14558
|
+
const protocols = pi.protocols;
|
|
14559
|
+
if (!Array.isArray(protocols)) continue;
|
|
14560
|
+
for (const entry of protocols) {
|
|
14561
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
14562
|
+
if (!("mpp" in entry)) continue;
|
|
14563
|
+
const mpp = entry.mpp;
|
|
14564
|
+
if (typeof mpp !== "object" || mpp === null) return true;
|
|
14565
|
+
const mppObj = mpp;
|
|
14566
|
+
if (typeof mppObj.method !== "string" || mppObj.method.length === 0) return true;
|
|
14567
|
+
if (typeof mppObj.intent !== "string" || mppObj.intent.length === 0) return true;
|
|
14568
|
+
if (typeof mppObj.currency !== "string" || mppObj.currency.length === 0) return true;
|
|
14569
|
+
}
|
|
14570
|
+
}
|
|
14571
|
+
}
|
|
14572
|
+
return false;
|
|
14573
|
+
}
|
|
14574
|
+
function hasImproperX402Tag(raw) {
|
|
14575
|
+
const paths = raw.paths;
|
|
14576
|
+
if (typeof paths !== "object" || paths === null) return false;
|
|
14577
|
+
for (const pathItem of Object.values(paths)) {
|
|
14578
|
+
if (typeof pathItem !== "object" || pathItem === null) continue;
|
|
14579
|
+
for (const method of HTTP_METHODS2) {
|
|
14580
|
+
const operation = pathItem[method];
|
|
14581
|
+
if (typeof operation !== "object" || operation === null) continue;
|
|
14582
|
+
const pi = operation["x-payment-info"];
|
|
14583
|
+
if (typeof pi !== "object" || pi === null) continue;
|
|
14584
|
+
const protocols = pi.protocols;
|
|
14585
|
+
if (!Array.isArray(protocols)) continue;
|
|
14586
|
+
for (const entry of protocols) {
|
|
14587
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
14588
|
+
if (!("x402" in entry)) continue;
|
|
14589
|
+
const x402 = entry.x402;
|
|
14590
|
+
if (typeof x402 !== "object" || x402 === null || Array.isArray(x402)) return true;
|
|
14591
|
+
}
|
|
14592
|
+
}
|
|
14593
|
+
}
|
|
14594
|
+
return false;
|
|
14595
|
+
}
|
|
14528
14596
|
function getWarningsForOpenAPI(openApi) {
|
|
14529
14597
|
if (openApi === null) {
|
|
14530
14598
|
return [
|
|
@@ -14566,6 +14634,22 @@ ${details}`,
|
|
|
14566
14634
|
hint: "Migrate to the structured format: { price: { mode, amount, currency }, protocols: [{ x402: {} }] }."
|
|
14567
14635
|
});
|
|
14568
14636
|
}
|
|
14637
|
+
if (hasImproperX402Tag(openApi.raw)) {
|
|
14638
|
+
warnings.push({
|
|
14639
|
+
code: AUDIT_CODES.L2_X402_MALFORMED,
|
|
14640
|
+
severity: "warn",
|
|
14641
|
+
message: "One or more operations have a malformed x402 protocol entry.",
|
|
14642
|
+
hint: "Canonical shape: { x402: { ...optional config } }."
|
|
14643
|
+
});
|
|
14644
|
+
}
|
|
14645
|
+
if (hasImproperMppTag(openApi.raw)) {
|
|
14646
|
+
warnings.push({
|
|
14647
|
+
code: AUDIT_CODES.L2_MPP_MALFORMED,
|
|
14648
|
+
severity: "warn",
|
|
14649
|
+
message: "One or more operations have a malformed mpp protocol entry.",
|
|
14650
|
+
hint: "Canonical shape: { mpp: { method: string, intent: string, currency: string } }."
|
|
14651
|
+
});
|
|
14652
|
+
}
|
|
14569
14653
|
return warnings;
|
|
14570
14654
|
}
|
|
14571
14655
|
function getWarningsForWellKnown(wellKnown) {
|
|
@@ -14643,7 +14727,15 @@ function getWarningsForL2(l2) {
|
|
|
14643
14727
|
});
|
|
14644
14728
|
}
|
|
14645
14729
|
if (route.authMode === "paid") {
|
|
14646
|
-
if (!route.price) {
|
|
14730
|
+
if (route.pricingMode === "dynamic" && !route.price) {
|
|
14731
|
+
warnings.push({
|
|
14732
|
+
code: AUDIT_CODES.L2_DYNAMIC_PRICE_INCOMPLETE,
|
|
14733
|
+
severity: "warn",
|
|
14734
|
+
message: `Paid route ${loc} declares dynamic pricing but no min/max bounds.`,
|
|
14735
|
+
hint: "Add x-payment-info.price.min and .price.max so agents can budget before calling. Without bounds, agents have no safe upper limit to pre-authorize.",
|
|
14736
|
+
path: route.path
|
|
14737
|
+
});
|
|
14738
|
+
} else if (!route.price) {
|
|
14647
14739
|
warnings.push({
|
|
14648
14740
|
code: AUDIT_CODES.L2_PRICE_MISSING_ON_PAID,
|
|
14649
14741
|
severity: "warn",
|
package/dist/cli.js
CHANGED
|
@@ -13785,8 +13785,8 @@ var FixedPriceSchema = external_exports.object({
|
|
|
13785
13785
|
var DynamicPriceSchema = external_exports.object({
|
|
13786
13786
|
currency: Iso4217Schema,
|
|
13787
13787
|
mode: external_exports.literal("dynamic"),
|
|
13788
|
-
min: external_exports.string(),
|
|
13789
|
-
max: external_exports.string()
|
|
13788
|
+
min: external_exports.string().optional(),
|
|
13789
|
+
max: external_exports.string().optional()
|
|
13790
13790
|
});
|
|
13791
13791
|
var PriceSchema = external_exports.union([FixedPriceSchema, DynamicPriceSchema]);
|
|
13792
13792
|
var X402ProtocolSchema = external_exports.object({
|
|
@@ -13885,7 +13885,12 @@ function normalizeLegacy(raw) {
|
|
|
13885
13885
|
function formatPrice(price) {
|
|
13886
13886
|
const sym = price.currency ?? "USD";
|
|
13887
13887
|
if (price.mode === "fixed") return `${price.amount} ${sym}`;
|
|
13888
|
-
|
|
13888
|
+
if (price.min !== void 0 && price.max !== void 0) {
|
|
13889
|
+
return `${price.min}-${price.max} ${sym}`;
|
|
13890
|
+
}
|
|
13891
|
+
if (price.min !== void 0) return `>=${price.min} ${sym}`;
|
|
13892
|
+
if (price.max !== void 0) return `<=${price.max} ${sym}`;
|
|
13893
|
+
return `dynamic ${sym}`;
|
|
13889
13894
|
}
|
|
13890
13895
|
function extractProtocolNames(protocols) {
|
|
13891
13896
|
return protocols.map((p) => {
|
|
@@ -13937,10 +13942,13 @@ var OpenApiOperationSchema = external_exports.object({
|
|
|
13937
13942
|
description: external_exports.string().optional(),
|
|
13938
13943
|
tags: external_exports.array(external_exports.string()).optional(),
|
|
13939
13944
|
security: external_exports.array(external_exports.record(external_exports.string(), external_exports.array(external_exports.string()))).optional(),
|
|
13945
|
+
// `in` / `name` are spec-required, but a single malformed parameter must not
|
|
13946
|
+
// abort the whole spec — keep them optional so discovery is resilient to
|
|
13947
|
+
// non-conformant OpenAPI documents in the wild.
|
|
13940
13948
|
parameters: external_exports.array(
|
|
13941
13949
|
external_exports.object({
|
|
13942
|
-
in: external_exports.string(),
|
|
13943
|
-
name: external_exports.string(),
|
|
13950
|
+
in: external_exports.string().optional(),
|
|
13951
|
+
name: external_exports.string().optional(),
|
|
13944
13952
|
schema: external_exports.unknown().optional(),
|
|
13945
13953
|
required: external_exports.boolean().optional()
|
|
13946
13954
|
})
|
|
@@ -13950,7 +13958,8 @@ var OpenApiOperationSchema = external_exports.object({
|
|
|
13950
13958
|
content: external_exports.record(external_exports.string(), external_exports.object({ schema: external_exports.unknown().optional() }))
|
|
13951
13959
|
}).optional(),
|
|
13952
13960
|
responses: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
13953
|
-
|
|
13961
|
+
// Permissive: vendor extension shape is validated at runtime, never at parse time.
|
|
13962
|
+
"x-payment-info": external_exports.unknown().optional()
|
|
13954
13963
|
});
|
|
13955
13964
|
var OpenApiPathItemSchema = external_exports.object({
|
|
13956
13965
|
get: OpenApiOperationSchema.optional(),
|
|
@@ -14094,20 +14103,27 @@ function fetchSafe(url2, init) {
|
|
|
14094
14103
|
}
|
|
14095
14104
|
|
|
14096
14105
|
// src/core/source/openapi/index.ts
|
|
14097
|
-
function
|
|
14098
|
-
|
|
14099
|
-
|
|
14106
|
+
function toRecord(raw) {
|
|
14107
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
|
|
14108
|
+
return raw;
|
|
14109
|
+
}
|
|
14110
|
+
function resolvePricingHint(raw) {
|
|
14111
|
+
const record2 = toRecord(raw);
|
|
14112
|
+
if (!record2) return void 0;
|
|
14113
|
+
const info = resolvePaymentInfo(record2);
|
|
14100
14114
|
if (!info) return void 0;
|
|
14101
14115
|
return {
|
|
14102
14116
|
pricingMode: info.price.mode,
|
|
14103
14117
|
...info.price.mode === "fixed" ? { price: info.price.amount } : {},
|
|
14104
|
-
...info.price.mode === "dynamic"
|
|
14118
|
+
...info.price.mode === "dynamic" && info.price.min !== void 0 ? { minPrice: info.price.min } : {},
|
|
14119
|
+
...info.price.mode === "dynamic" && info.price.max !== void 0 ? { maxPrice: info.price.max } : {},
|
|
14105
14120
|
...info.price.currency ? { currency: info.price.currency } : {}
|
|
14106
14121
|
};
|
|
14107
14122
|
}
|
|
14108
|
-
function resolveProtocols(
|
|
14109
|
-
const
|
|
14110
|
-
|
|
14123
|
+
function resolveProtocols(raw) {
|
|
14124
|
+
const record2 = toRecord(raw);
|
|
14125
|
+
if (!record2) return [];
|
|
14126
|
+
const info = resolvePaymentInfo(record2);
|
|
14111
14127
|
if (!info) return [];
|
|
14112
14128
|
return extractProtocolNames(info.protocols);
|
|
14113
14129
|
}
|
|
@@ -14120,8 +14136,8 @@ var OpenApiParsedSchema = OpenApiDocSchema.transform((doc) => {
|
|
|
14120
14136
|
if (!operation) continue;
|
|
14121
14137
|
const authMode = inferAuthMode(operation, doc.security, doc.components?.securitySchemes) ?? void 0;
|
|
14122
14138
|
const p = operation["x-payment-info"];
|
|
14123
|
-
const protocols = resolveProtocols(p
|
|
14124
|
-
const pricing = (authMode === "paid" || authMode === "apiKey+paid") && p ? resolvePricingHint(p) : void 0;
|
|
14139
|
+
const protocols = resolveProtocols(p);
|
|
14140
|
+
const pricing = (authMode === "paid" || authMode === "apiKey+paid") && p !== void 0 ? resolvePricingHint(p) : void 0;
|
|
14125
14141
|
const summary = operation.summary ?? operation.description;
|
|
14126
14142
|
routes.push({
|
|
14127
14143
|
path: normalizePath(serverBasePath + rawPath),
|
|
@@ -14362,28 +14378,29 @@ function getWellKnown(origin, headers, signal) {
|
|
|
14362
14378
|
// src/core/layers/l2.ts
|
|
14363
14379
|
function formatPrice2(pricing) {
|
|
14364
14380
|
const sym = pricing.currency ?? "USD";
|
|
14365
|
-
if (pricing.pricingMode === "fixed") return `${pricing.price} ${sym}`;
|
|
14381
|
+
if (pricing.pricingMode === "fixed" && pricing.price) return `${pricing.price} ${sym}`;
|
|
14366
14382
|
if (pricing.pricingMode === "dynamic") {
|
|
14367
14383
|
if (pricing.minPrice && pricing.maxPrice)
|
|
14368
14384
|
return `${pricing.minPrice}-${pricing.maxPrice} ${sym}`;
|
|
14369
14385
|
if (pricing.maxPrice) return `up to ${pricing.maxPrice} ${sym}`;
|
|
14370
|
-
return
|
|
14386
|
+
if (pricing.minPrice) return `from ${pricing.minPrice} ${sym}`;
|
|
14371
14387
|
}
|
|
14372
|
-
return
|
|
14388
|
+
return void 0;
|
|
14373
14389
|
}
|
|
14374
14390
|
function checkL2ForOpenAPI(openApi) {
|
|
14375
|
-
const routes = openApi.routes.map((route) =>
|
|
14376
|
-
|
|
14377
|
-
|
|
14378
|
-
|
|
14379
|
-
|
|
14380
|
-
|
|
14381
|
-
|
|
14382
|
-
|
|
14383
|
-
...route.pricing
|
|
14384
|
-
|
|
14385
|
-
|
|
14386
|
-
|
|
14391
|
+
const routes = openApi.routes.map((route) => {
|
|
14392
|
+
const priceHint = route.pricing ? formatPrice2(route.pricing) : void 0;
|
|
14393
|
+
return {
|
|
14394
|
+
path: route.path,
|
|
14395
|
+
method: route.method,
|
|
14396
|
+
summary: route.summary ?? `${route.method} ${route.path}`,
|
|
14397
|
+
...route.authMode ? { authMode: route.authMode } : {},
|
|
14398
|
+
...priceHint ? { price: priceHint } : {},
|
|
14399
|
+
...route.pricing?.pricingMode ? { pricingMode: route.pricing.pricingMode } : {},
|
|
14400
|
+
...route.pricing?.currency ? { currency: route.pricing.currency } : {},
|
|
14401
|
+
...route.protocols?.length ? { protocols: route.protocols } : {}
|
|
14402
|
+
};
|
|
14403
|
+
});
|
|
14387
14404
|
return {
|
|
14388
14405
|
...openApi.info.title ? { title: openApi.info.title } : {},
|
|
14389
14406
|
...openApi.info.description ? { description: openApi.info.description } : {},
|
|
@@ -14444,9 +14461,12 @@ var AUDIT_CODES = {
|
|
|
14444
14461
|
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
14445
14462
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
14446
14463
|
L2_PRICING_MODE_UNKNOWN: "L2_PRICING_MODE_UNKNOWN",
|
|
14464
|
+
L2_DYNAMIC_PRICE_INCOMPLETE: "L2_DYNAMIC_PRICE_INCOMPLETE",
|
|
14447
14465
|
L2_CURRENCY_INVALID: "L2_CURRENCY_INVALID",
|
|
14448
14466
|
L2_PAYMENT_INFO_LEGACY: "L2_PAYMENT_INFO_LEGACY",
|
|
14449
14467
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
14468
|
+
L2_X402_MALFORMED: "L2_X402_MALFORMED",
|
|
14469
|
+
L2_MPP_MALFORMED: "L2_MPP_MALFORMED",
|
|
14450
14470
|
// ─── L3 endpoint advisory checks ─────────────────────────────────────────────
|
|
14451
14471
|
L3_NOT_FOUND: "L3_NOT_FOUND",
|
|
14452
14472
|
L3_INPUT_SCHEMA_MISSING: "L3_INPUT_SCHEMA_MISSING",
|
|
@@ -14495,6 +14515,54 @@ function hasLegacyPaymentInfo(raw) {
|
|
|
14495
14515
|
}
|
|
14496
14516
|
return false;
|
|
14497
14517
|
}
|
|
14518
|
+
function hasImproperMppTag(raw) {
|
|
14519
|
+
const paths = raw.paths;
|
|
14520
|
+
if (typeof paths !== "object" || paths === null) return false;
|
|
14521
|
+
for (const pathItem of Object.values(paths)) {
|
|
14522
|
+
if (typeof pathItem !== "object" || pathItem === null) continue;
|
|
14523
|
+
for (const method of HTTP_METHODS2) {
|
|
14524
|
+
const operation = pathItem[method];
|
|
14525
|
+
if (typeof operation !== "object" || operation === null) continue;
|
|
14526
|
+
const pi = operation["x-payment-info"];
|
|
14527
|
+
if (typeof pi !== "object" || pi === null) continue;
|
|
14528
|
+
const protocols = pi.protocols;
|
|
14529
|
+
if (!Array.isArray(protocols)) continue;
|
|
14530
|
+
for (const entry of protocols) {
|
|
14531
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
14532
|
+
if (!("mpp" in entry)) continue;
|
|
14533
|
+
const mpp = entry.mpp;
|
|
14534
|
+
if (typeof mpp !== "object" || mpp === null) return true;
|
|
14535
|
+
const mppObj = mpp;
|
|
14536
|
+
if (typeof mppObj.method !== "string" || mppObj.method.length === 0) return true;
|
|
14537
|
+
if (typeof mppObj.intent !== "string" || mppObj.intent.length === 0) return true;
|
|
14538
|
+
if (typeof mppObj.currency !== "string" || mppObj.currency.length === 0) return true;
|
|
14539
|
+
}
|
|
14540
|
+
}
|
|
14541
|
+
}
|
|
14542
|
+
return false;
|
|
14543
|
+
}
|
|
14544
|
+
function hasImproperX402Tag(raw) {
|
|
14545
|
+
const paths = raw.paths;
|
|
14546
|
+
if (typeof paths !== "object" || paths === null) return false;
|
|
14547
|
+
for (const pathItem of Object.values(paths)) {
|
|
14548
|
+
if (typeof pathItem !== "object" || pathItem === null) continue;
|
|
14549
|
+
for (const method of HTTP_METHODS2) {
|
|
14550
|
+
const operation = pathItem[method];
|
|
14551
|
+
if (typeof operation !== "object" || operation === null) continue;
|
|
14552
|
+
const pi = operation["x-payment-info"];
|
|
14553
|
+
if (typeof pi !== "object" || pi === null) continue;
|
|
14554
|
+
const protocols = pi.protocols;
|
|
14555
|
+
if (!Array.isArray(protocols)) continue;
|
|
14556
|
+
for (const entry of protocols) {
|
|
14557
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
14558
|
+
if (!("x402" in entry)) continue;
|
|
14559
|
+
const x402 = entry.x402;
|
|
14560
|
+
if (typeof x402 !== "object" || x402 === null || Array.isArray(x402)) return true;
|
|
14561
|
+
}
|
|
14562
|
+
}
|
|
14563
|
+
}
|
|
14564
|
+
return false;
|
|
14565
|
+
}
|
|
14498
14566
|
function getWarningsForOpenAPI(openApi) {
|
|
14499
14567
|
if (openApi === null) {
|
|
14500
14568
|
return [
|
|
@@ -14536,6 +14604,22 @@ ${details}`,
|
|
|
14536
14604
|
hint: "Migrate to the structured format: { price: { mode, amount, currency }, protocols: [{ x402: {} }] }."
|
|
14537
14605
|
});
|
|
14538
14606
|
}
|
|
14607
|
+
if (hasImproperX402Tag(openApi.raw)) {
|
|
14608
|
+
warnings.push({
|
|
14609
|
+
code: AUDIT_CODES.L2_X402_MALFORMED,
|
|
14610
|
+
severity: "warn",
|
|
14611
|
+
message: "One or more operations have a malformed x402 protocol entry.",
|
|
14612
|
+
hint: "Canonical shape: { x402: { ...optional config } }."
|
|
14613
|
+
});
|
|
14614
|
+
}
|
|
14615
|
+
if (hasImproperMppTag(openApi.raw)) {
|
|
14616
|
+
warnings.push({
|
|
14617
|
+
code: AUDIT_CODES.L2_MPP_MALFORMED,
|
|
14618
|
+
severity: "warn",
|
|
14619
|
+
message: "One or more operations have a malformed mpp protocol entry.",
|
|
14620
|
+
hint: "Canonical shape: { mpp: { method: string, intent: string, currency: string } }."
|
|
14621
|
+
});
|
|
14622
|
+
}
|
|
14539
14623
|
return warnings;
|
|
14540
14624
|
}
|
|
14541
14625
|
function getWarningsForWellKnown(wellKnown) {
|
|
@@ -14613,7 +14697,15 @@ function getWarningsForL2(l2) {
|
|
|
14613
14697
|
});
|
|
14614
14698
|
}
|
|
14615
14699
|
if (route.authMode === "paid") {
|
|
14616
|
-
if (!route.price) {
|
|
14700
|
+
if (route.pricingMode === "dynamic" && !route.price) {
|
|
14701
|
+
warnings.push({
|
|
14702
|
+
code: AUDIT_CODES.L2_DYNAMIC_PRICE_INCOMPLETE,
|
|
14703
|
+
severity: "warn",
|
|
14704
|
+
message: `Paid route ${loc} declares dynamic pricing but no min/max bounds.`,
|
|
14705
|
+
hint: "Add x-payment-info.price.min and .price.max so agents can budget before calling. Without bounds, agents have no safe upper limit to pre-authorize.",
|
|
14706
|
+
path: route.path
|
|
14707
|
+
});
|
|
14708
|
+
} else if (!route.price) {
|
|
14617
14709
|
warnings.push({
|
|
14618
14710
|
code: AUDIT_CODES.L2_PRICE_MISSING_ON_PAID,
|
|
14619
14711
|
severity: "warn",
|