@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/index.cjs
CHANGED
|
@@ -13847,8 +13847,8 @@ var FixedPriceSchema = external_exports.object({
|
|
|
13847
13847
|
var DynamicPriceSchema = external_exports.object({
|
|
13848
13848
|
currency: Iso4217Schema,
|
|
13849
13849
|
mode: external_exports.literal("dynamic"),
|
|
13850
|
-
min: external_exports.string(),
|
|
13851
|
-
max: external_exports.string()
|
|
13850
|
+
min: external_exports.string().optional(),
|
|
13851
|
+
max: external_exports.string().optional()
|
|
13852
13852
|
});
|
|
13853
13853
|
var PriceSchema = external_exports.union([FixedPriceSchema, DynamicPriceSchema]);
|
|
13854
13854
|
var X402ProtocolSchema = external_exports.object({
|
|
@@ -13947,7 +13947,12 @@ function normalizeLegacy(raw) {
|
|
|
13947
13947
|
function formatPrice(price) {
|
|
13948
13948
|
const sym = price.currency ?? "USD";
|
|
13949
13949
|
if (price.mode === "fixed") return `${price.amount} ${sym}`;
|
|
13950
|
-
|
|
13950
|
+
if (price.min !== void 0 && price.max !== void 0) {
|
|
13951
|
+
return `${price.min}-${price.max} ${sym}`;
|
|
13952
|
+
}
|
|
13953
|
+
if (price.min !== void 0) return `>=${price.min} ${sym}`;
|
|
13954
|
+
if (price.max !== void 0) return `<=${price.max} ${sym}`;
|
|
13955
|
+
return `dynamic ${sym}`;
|
|
13951
13956
|
}
|
|
13952
13957
|
function extractProtocolNames(protocols) {
|
|
13953
13958
|
return protocols.map((p) => {
|
|
@@ -13999,10 +14004,13 @@ var OpenApiOperationSchema = external_exports.object({
|
|
|
13999
14004
|
description: external_exports.string().optional(),
|
|
14000
14005
|
tags: external_exports.array(external_exports.string()).optional(),
|
|
14001
14006
|
security: external_exports.array(external_exports.record(external_exports.string(), external_exports.array(external_exports.string()))).optional(),
|
|
14007
|
+
// `in` / `name` are spec-required, but a single malformed parameter must not
|
|
14008
|
+
// abort the whole spec — keep them optional so discovery is resilient to
|
|
14009
|
+
// non-conformant OpenAPI documents in the wild.
|
|
14002
14010
|
parameters: external_exports.array(
|
|
14003
14011
|
external_exports.object({
|
|
14004
|
-
in: external_exports.string(),
|
|
14005
|
-
name: external_exports.string(),
|
|
14012
|
+
in: external_exports.string().optional(),
|
|
14013
|
+
name: external_exports.string().optional(),
|
|
14006
14014
|
schema: external_exports.unknown().optional(),
|
|
14007
14015
|
required: external_exports.boolean().optional()
|
|
14008
14016
|
})
|
|
@@ -14012,7 +14020,8 @@ var OpenApiOperationSchema = external_exports.object({
|
|
|
14012
14020
|
content: external_exports.record(external_exports.string(), external_exports.object({ schema: external_exports.unknown().optional() }))
|
|
14013
14021
|
}).optional(),
|
|
14014
14022
|
responses: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
14015
|
-
|
|
14023
|
+
// Permissive: vendor extension shape is validated at runtime, never at parse time.
|
|
14024
|
+
"x-payment-info": external_exports.unknown().optional()
|
|
14016
14025
|
});
|
|
14017
14026
|
var OpenApiPathItemSchema = external_exports.object({
|
|
14018
14027
|
get: OpenApiOperationSchema.optional(),
|
|
@@ -14156,20 +14165,27 @@ function fetchSafe(url2, init) {
|
|
|
14156
14165
|
}
|
|
14157
14166
|
|
|
14158
14167
|
// src/core/source/openapi/index.ts
|
|
14159
|
-
function
|
|
14160
|
-
|
|
14161
|
-
|
|
14168
|
+
function toRecord(raw) {
|
|
14169
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return void 0;
|
|
14170
|
+
return raw;
|
|
14171
|
+
}
|
|
14172
|
+
function resolvePricingHint(raw) {
|
|
14173
|
+
const record2 = toRecord(raw);
|
|
14174
|
+
if (!record2) return void 0;
|
|
14175
|
+
const info = resolvePaymentInfo(record2);
|
|
14162
14176
|
if (!info) return void 0;
|
|
14163
14177
|
return {
|
|
14164
14178
|
pricingMode: info.price.mode,
|
|
14165
14179
|
...info.price.mode === "fixed" ? { price: info.price.amount } : {},
|
|
14166
|
-
...info.price.mode === "dynamic"
|
|
14180
|
+
...info.price.mode === "dynamic" && info.price.min !== void 0 ? { minPrice: info.price.min } : {},
|
|
14181
|
+
...info.price.mode === "dynamic" && info.price.max !== void 0 ? { maxPrice: info.price.max } : {},
|
|
14167
14182
|
...info.price.currency ? { currency: info.price.currency } : {}
|
|
14168
14183
|
};
|
|
14169
14184
|
}
|
|
14170
|
-
function resolveProtocols(
|
|
14171
|
-
const
|
|
14172
|
-
|
|
14185
|
+
function resolveProtocols(raw) {
|
|
14186
|
+
const record2 = toRecord(raw);
|
|
14187
|
+
if (!record2) return [];
|
|
14188
|
+
const info = resolvePaymentInfo(record2);
|
|
14173
14189
|
if (!info) return [];
|
|
14174
14190
|
return extractProtocolNames(info.protocols);
|
|
14175
14191
|
}
|
|
@@ -14182,8 +14198,8 @@ var OpenApiParsedSchema = OpenApiDocSchema.transform((doc) => {
|
|
|
14182
14198
|
if (!operation) continue;
|
|
14183
14199
|
const authMode = inferAuthMode(operation, doc.security, doc.components?.securitySchemes) ?? void 0;
|
|
14184
14200
|
const p = operation["x-payment-info"];
|
|
14185
|
-
const protocols = resolveProtocols(p
|
|
14186
|
-
const pricing = (authMode === "paid" || authMode === "apiKey+paid") && p ? resolvePricingHint(p) : void 0;
|
|
14201
|
+
const protocols = resolveProtocols(p);
|
|
14202
|
+
const pricing = (authMode === "paid" || authMode === "apiKey+paid") && p !== void 0 ? resolvePricingHint(p) : void 0;
|
|
14187
14203
|
const summary = operation.summary ?? operation.description;
|
|
14188
14204
|
routes.push({
|
|
14189
14205
|
path: normalizePath(serverBasePath + rawPath),
|
|
@@ -14424,28 +14440,29 @@ function getWellKnown(origin, headers, signal) {
|
|
|
14424
14440
|
// src/core/layers/l2.ts
|
|
14425
14441
|
function formatPrice2(pricing) {
|
|
14426
14442
|
const sym = pricing.currency ?? "USD";
|
|
14427
|
-
if (pricing.pricingMode === "fixed") return `${pricing.price} ${sym}`;
|
|
14443
|
+
if (pricing.pricingMode === "fixed" && pricing.price) return `${pricing.price} ${sym}`;
|
|
14428
14444
|
if (pricing.pricingMode === "dynamic") {
|
|
14429
14445
|
if (pricing.minPrice && pricing.maxPrice)
|
|
14430
14446
|
return `${pricing.minPrice}-${pricing.maxPrice} ${sym}`;
|
|
14431
14447
|
if (pricing.maxPrice) return `up to ${pricing.maxPrice} ${sym}`;
|
|
14432
|
-
return
|
|
14448
|
+
if (pricing.minPrice) return `from ${pricing.minPrice} ${sym}`;
|
|
14433
14449
|
}
|
|
14434
|
-
return
|
|
14450
|
+
return void 0;
|
|
14435
14451
|
}
|
|
14436
14452
|
function checkL2ForOpenAPI(openApi) {
|
|
14437
|
-
const routes = openApi.routes.map((route) =>
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
|
|
14443
|
-
|
|
14444
|
-
|
|
14445
|
-
...route.pricing
|
|
14446
|
-
|
|
14447
|
-
|
|
14448
|
-
|
|
14453
|
+
const routes = openApi.routes.map((route) => {
|
|
14454
|
+
const priceHint = route.pricing ? formatPrice2(route.pricing) : void 0;
|
|
14455
|
+
return {
|
|
14456
|
+
path: route.path,
|
|
14457
|
+
method: route.method,
|
|
14458
|
+
summary: route.summary ?? `${route.method} ${route.path}`,
|
|
14459
|
+
...route.authMode ? { authMode: route.authMode } : {},
|
|
14460
|
+
...priceHint ? { price: priceHint } : {},
|
|
14461
|
+
...route.pricing?.pricingMode ? { pricingMode: route.pricing.pricingMode } : {},
|
|
14462
|
+
...route.pricing?.currency ? { currency: route.pricing.currency } : {},
|
|
14463
|
+
...route.protocols?.length ? { protocols: route.protocols } : {}
|
|
14464
|
+
};
|
|
14465
|
+
});
|
|
14449
14466
|
return {
|
|
14450
14467
|
...openApi.info.title ? { title: openApi.info.title } : {},
|
|
14451
14468
|
...openApi.info.description ? { description: openApi.info.description } : {},
|
|
@@ -15502,9 +15519,12 @@ var AUDIT_CODES = {
|
|
|
15502
15519
|
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
15503
15520
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
15504
15521
|
L2_PRICING_MODE_UNKNOWN: "L2_PRICING_MODE_UNKNOWN",
|
|
15522
|
+
L2_DYNAMIC_PRICE_INCOMPLETE: "L2_DYNAMIC_PRICE_INCOMPLETE",
|
|
15505
15523
|
L2_CURRENCY_INVALID: "L2_CURRENCY_INVALID",
|
|
15506
15524
|
L2_PAYMENT_INFO_LEGACY: "L2_PAYMENT_INFO_LEGACY",
|
|
15507
15525
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
15526
|
+
L2_X402_MALFORMED: "L2_X402_MALFORMED",
|
|
15527
|
+
L2_MPP_MALFORMED: "L2_MPP_MALFORMED",
|
|
15508
15528
|
// ─── L3 endpoint advisory checks ─────────────────────────────────────────────
|
|
15509
15529
|
L3_NOT_FOUND: "L3_NOT_FOUND",
|
|
15510
15530
|
L3_INPUT_SCHEMA_MISSING: "L3_INPUT_SCHEMA_MISSING",
|
|
@@ -16006,6 +16026,54 @@ function hasLegacyPaymentInfo(raw) {
|
|
|
16006
16026
|
}
|
|
16007
16027
|
return false;
|
|
16008
16028
|
}
|
|
16029
|
+
function hasImproperMppTag(raw) {
|
|
16030
|
+
const paths = raw.paths;
|
|
16031
|
+
if (typeof paths !== "object" || paths === null) return false;
|
|
16032
|
+
for (const pathItem of Object.values(paths)) {
|
|
16033
|
+
if (typeof pathItem !== "object" || pathItem === null) continue;
|
|
16034
|
+
for (const method of HTTP_METHODS2) {
|
|
16035
|
+
const operation = pathItem[method];
|
|
16036
|
+
if (typeof operation !== "object" || operation === null) continue;
|
|
16037
|
+
const pi = operation["x-payment-info"];
|
|
16038
|
+
if (typeof pi !== "object" || pi === null) continue;
|
|
16039
|
+
const protocols = pi.protocols;
|
|
16040
|
+
if (!Array.isArray(protocols)) continue;
|
|
16041
|
+
for (const entry of protocols) {
|
|
16042
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
16043
|
+
if (!("mpp" in entry)) continue;
|
|
16044
|
+
const mpp = entry.mpp;
|
|
16045
|
+
if (typeof mpp !== "object" || mpp === null) return true;
|
|
16046
|
+
const mppObj = mpp;
|
|
16047
|
+
if (typeof mppObj.method !== "string" || mppObj.method.length === 0) return true;
|
|
16048
|
+
if (typeof mppObj.intent !== "string" || mppObj.intent.length === 0) return true;
|
|
16049
|
+
if (typeof mppObj.currency !== "string" || mppObj.currency.length === 0) return true;
|
|
16050
|
+
}
|
|
16051
|
+
}
|
|
16052
|
+
}
|
|
16053
|
+
return false;
|
|
16054
|
+
}
|
|
16055
|
+
function hasImproperX402Tag(raw) {
|
|
16056
|
+
const paths = raw.paths;
|
|
16057
|
+
if (typeof paths !== "object" || paths === null) return false;
|
|
16058
|
+
for (const pathItem of Object.values(paths)) {
|
|
16059
|
+
if (typeof pathItem !== "object" || pathItem === null) continue;
|
|
16060
|
+
for (const method of HTTP_METHODS2) {
|
|
16061
|
+
const operation = pathItem[method];
|
|
16062
|
+
if (typeof operation !== "object" || operation === null) continue;
|
|
16063
|
+
const pi = operation["x-payment-info"];
|
|
16064
|
+
if (typeof pi !== "object" || pi === null) continue;
|
|
16065
|
+
const protocols = pi.protocols;
|
|
16066
|
+
if (!Array.isArray(protocols)) continue;
|
|
16067
|
+
for (const entry of protocols) {
|
|
16068
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
16069
|
+
if (!("x402" in entry)) continue;
|
|
16070
|
+
const x402 = entry.x402;
|
|
16071
|
+
if (typeof x402 !== "object" || x402 === null || Array.isArray(x402)) return true;
|
|
16072
|
+
}
|
|
16073
|
+
}
|
|
16074
|
+
}
|
|
16075
|
+
return false;
|
|
16076
|
+
}
|
|
16009
16077
|
function getWarningsForOpenAPI(openApi) {
|
|
16010
16078
|
if (openApi === null) {
|
|
16011
16079
|
return [
|
|
@@ -16047,6 +16115,22 @@ ${details}`,
|
|
|
16047
16115
|
hint: "Migrate to the structured format: { price: { mode, amount, currency }, protocols: [{ x402: {} }] }."
|
|
16048
16116
|
});
|
|
16049
16117
|
}
|
|
16118
|
+
if (hasImproperX402Tag(openApi.raw)) {
|
|
16119
|
+
warnings.push({
|
|
16120
|
+
code: AUDIT_CODES.L2_X402_MALFORMED,
|
|
16121
|
+
severity: "warn",
|
|
16122
|
+
message: "One or more operations have a malformed x402 protocol entry.",
|
|
16123
|
+
hint: "Canonical shape: { x402: { ...optional config } }."
|
|
16124
|
+
});
|
|
16125
|
+
}
|
|
16126
|
+
if (hasImproperMppTag(openApi.raw)) {
|
|
16127
|
+
warnings.push({
|
|
16128
|
+
code: AUDIT_CODES.L2_MPP_MALFORMED,
|
|
16129
|
+
severity: "warn",
|
|
16130
|
+
message: "One or more operations have a malformed mpp protocol entry.",
|
|
16131
|
+
hint: "Canonical shape: { mpp: { method: string, intent: string, currency: string } }."
|
|
16132
|
+
});
|
|
16133
|
+
}
|
|
16050
16134
|
return warnings;
|
|
16051
16135
|
}
|
|
16052
16136
|
function getWarningsForWellKnown(wellKnown) {
|
|
@@ -16124,7 +16208,15 @@ function getWarningsForL2(l2) {
|
|
|
16124
16208
|
});
|
|
16125
16209
|
}
|
|
16126
16210
|
if (route.authMode === "paid") {
|
|
16127
|
-
if (!route.price) {
|
|
16211
|
+
if (route.pricingMode === "dynamic" && !route.price) {
|
|
16212
|
+
warnings.push({
|
|
16213
|
+
code: AUDIT_CODES.L2_DYNAMIC_PRICE_INCOMPLETE,
|
|
16214
|
+
severity: "warn",
|
|
16215
|
+
message: `Paid route ${loc} declares dynamic pricing but no min/max bounds.`,
|
|
16216
|
+
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.",
|
|
16217
|
+
path: route.path
|
|
16218
|
+
});
|
|
16219
|
+
} else if (!route.price) {
|
|
16128
16220
|
warnings.push({
|
|
16129
16221
|
code: AUDIT_CODES.L2_PRICE_MISSING_ON_PAID,
|
|
16130
16222
|
severity: "warn",
|
package/dist/index.d.cts
CHANGED
|
@@ -392,8 +392,8 @@ declare const FixedPriceSchema: z.ZodObject<{
|
|
|
392
392
|
declare const DynamicPriceSchema: z.ZodObject<{
|
|
393
393
|
currency: z.ZodOptional<z.ZodString>;
|
|
394
394
|
mode: z.ZodLiteral<"dynamic">;
|
|
395
|
-
min: z.ZodString
|
|
396
|
-
max: z.ZodString
|
|
395
|
+
min: z.ZodOptional<z.ZodString>;
|
|
396
|
+
max: z.ZodOptional<z.ZodString>;
|
|
397
397
|
}, z.core.$strip>;
|
|
398
398
|
declare const PriceSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
399
399
|
currency: z.ZodOptional<z.ZodString>;
|
|
@@ -402,8 +402,8 @@ declare const PriceSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
402
402
|
}, z.core.$strip>, z.ZodObject<{
|
|
403
403
|
currency: z.ZodOptional<z.ZodString>;
|
|
404
404
|
mode: z.ZodLiteral<"dynamic">;
|
|
405
|
-
min: z.ZodString
|
|
406
|
-
max: z.ZodString
|
|
405
|
+
min: z.ZodOptional<z.ZodString>;
|
|
406
|
+
max: z.ZodOptional<z.ZodString>;
|
|
407
407
|
}, z.core.$strip>]>;
|
|
408
408
|
declare const X402ProtocolSchema: z.ZodObject<{
|
|
409
409
|
x402: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
@@ -424,8 +424,8 @@ declare const PaymentInfoSchema: z.ZodObject<{
|
|
|
424
424
|
}, z.core.$strip>, z.ZodObject<{
|
|
425
425
|
currency: z.ZodOptional<z.ZodString>;
|
|
426
426
|
mode: z.ZodLiteral<"dynamic">;
|
|
427
|
-
min: z.ZodString
|
|
428
|
-
max: z.ZodString
|
|
427
|
+
min: z.ZodOptional<z.ZodString>;
|
|
428
|
+
max: z.ZodOptional<z.ZodString>;
|
|
429
429
|
}, z.core.$strip>]>;
|
|
430
430
|
protocols: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
431
431
|
}, z.core.$strip>;
|
|
@@ -448,9 +448,12 @@ declare const AUDIT_CODES: {
|
|
|
448
448
|
readonly L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES";
|
|
449
449
|
readonly L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID";
|
|
450
450
|
readonly L2_PRICING_MODE_UNKNOWN: "L2_PRICING_MODE_UNKNOWN";
|
|
451
|
+
readonly L2_DYNAMIC_PRICE_INCOMPLETE: "L2_DYNAMIC_PRICE_INCOMPLETE";
|
|
451
452
|
readonly L2_CURRENCY_INVALID: "L2_CURRENCY_INVALID";
|
|
452
453
|
readonly L2_PAYMENT_INFO_LEGACY: "L2_PAYMENT_INFO_LEGACY";
|
|
453
454
|
readonly L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID";
|
|
455
|
+
readonly L2_X402_MALFORMED: "L2_X402_MALFORMED";
|
|
456
|
+
readonly L2_MPP_MALFORMED: "L2_MPP_MALFORMED";
|
|
454
457
|
readonly L3_NOT_FOUND: "L3_NOT_FOUND";
|
|
455
458
|
readonly L3_INPUT_SCHEMA_MISSING: "L3_INPUT_SCHEMA_MISSING";
|
|
456
459
|
readonly L3_AUTH_MODE_MISSING: "L3_AUTH_MODE_MISSING";
|
package/dist/index.d.ts
CHANGED
|
@@ -392,8 +392,8 @@ declare const FixedPriceSchema: z.ZodObject<{
|
|
|
392
392
|
declare const DynamicPriceSchema: z.ZodObject<{
|
|
393
393
|
currency: z.ZodOptional<z.ZodString>;
|
|
394
394
|
mode: z.ZodLiteral<"dynamic">;
|
|
395
|
-
min: z.ZodString
|
|
396
|
-
max: z.ZodString
|
|
395
|
+
min: z.ZodOptional<z.ZodString>;
|
|
396
|
+
max: z.ZodOptional<z.ZodString>;
|
|
397
397
|
}, z.core.$strip>;
|
|
398
398
|
declare const PriceSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
399
399
|
currency: z.ZodOptional<z.ZodString>;
|
|
@@ -402,8 +402,8 @@ declare const PriceSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
402
402
|
}, z.core.$strip>, z.ZodObject<{
|
|
403
403
|
currency: z.ZodOptional<z.ZodString>;
|
|
404
404
|
mode: z.ZodLiteral<"dynamic">;
|
|
405
|
-
min: z.ZodString
|
|
406
|
-
max: z.ZodString
|
|
405
|
+
min: z.ZodOptional<z.ZodString>;
|
|
406
|
+
max: z.ZodOptional<z.ZodString>;
|
|
407
407
|
}, z.core.$strip>]>;
|
|
408
408
|
declare const X402ProtocolSchema: z.ZodObject<{
|
|
409
409
|
x402: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
@@ -424,8 +424,8 @@ declare const PaymentInfoSchema: z.ZodObject<{
|
|
|
424
424
|
}, z.core.$strip>, z.ZodObject<{
|
|
425
425
|
currency: z.ZodOptional<z.ZodString>;
|
|
426
426
|
mode: z.ZodLiteral<"dynamic">;
|
|
427
|
-
min: z.ZodString
|
|
428
|
-
max: z.ZodString
|
|
427
|
+
min: z.ZodOptional<z.ZodString>;
|
|
428
|
+
max: z.ZodOptional<z.ZodString>;
|
|
429
429
|
}, z.core.$strip>]>;
|
|
430
430
|
protocols: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
431
431
|
}, z.core.$strip>;
|
|
@@ -448,9 +448,12 @@ declare const AUDIT_CODES: {
|
|
|
448
448
|
readonly L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES";
|
|
449
449
|
readonly L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID";
|
|
450
450
|
readonly L2_PRICING_MODE_UNKNOWN: "L2_PRICING_MODE_UNKNOWN";
|
|
451
|
+
readonly L2_DYNAMIC_PRICE_INCOMPLETE: "L2_DYNAMIC_PRICE_INCOMPLETE";
|
|
451
452
|
readonly L2_CURRENCY_INVALID: "L2_CURRENCY_INVALID";
|
|
452
453
|
readonly L2_PAYMENT_INFO_LEGACY: "L2_PAYMENT_INFO_LEGACY";
|
|
453
454
|
readonly L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID";
|
|
455
|
+
readonly L2_X402_MALFORMED: "L2_X402_MALFORMED";
|
|
456
|
+
readonly L2_MPP_MALFORMED: "L2_MPP_MALFORMED";
|
|
454
457
|
readonly L3_NOT_FOUND: "L3_NOT_FOUND";
|
|
455
458
|
readonly L3_INPUT_SCHEMA_MISSING: "L3_INPUT_SCHEMA_MISSING";
|
|
456
459
|
readonly L3_AUTH_MODE_MISSING: "L3_AUTH_MODE_MISSING";
|
package/dist/index.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 } : {},
|
|
@@ -15440,9 +15457,12 @@ var AUDIT_CODES = {
|
|
|
15440
15457
|
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
15441
15458
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
15442
15459
|
L2_PRICING_MODE_UNKNOWN: "L2_PRICING_MODE_UNKNOWN",
|
|
15460
|
+
L2_DYNAMIC_PRICE_INCOMPLETE: "L2_DYNAMIC_PRICE_INCOMPLETE",
|
|
15443
15461
|
L2_CURRENCY_INVALID: "L2_CURRENCY_INVALID",
|
|
15444
15462
|
L2_PAYMENT_INFO_LEGACY: "L2_PAYMENT_INFO_LEGACY",
|
|
15445
15463
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
15464
|
+
L2_X402_MALFORMED: "L2_X402_MALFORMED",
|
|
15465
|
+
L2_MPP_MALFORMED: "L2_MPP_MALFORMED",
|
|
15446
15466
|
// ─── L3 endpoint advisory checks ─────────────────────────────────────────────
|
|
15447
15467
|
L3_NOT_FOUND: "L3_NOT_FOUND",
|
|
15448
15468
|
L3_INPUT_SCHEMA_MISSING: "L3_INPUT_SCHEMA_MISSING",
|
|
@@ -15944,6 +15964,54 @@ function hasLegacyPaymentInfo(raw) {
|
|
|
15944
15964
|
}
|
|
15945
15965
|
return false;
|
|
15946
15966
|
}
|
|
15967
|
+
function hasImproperMppTag(raw) {
|
|
15968
|
+
const paths = raw.paths;
|
|
15969
|
+
if (typeof paths !== "object" || paths === null) return false;
|
|
15970
|
+
for (const pathItem of Object.values(paths)) {
|
|
15971
|
+
if (typeof pathItem !== "object" || pathItem === null) continue;
|
|
15972
|
+
for (const method of HTTP_METHODS2) {
|
|
15973
|
+
const operation = pathItem[method];
|
|
15974
|
+
if (typeof operation !== "object" || operation === null) continue;
|
|
15975
|
+
const pi = operation["x-payment-info"];
|
|
15976
|
+
if (typeof pi !== "object" || pi === null) continue;
|
|
15977
|
+
const protocols = pi.protocols;
|
|
15978
|
+
if (!Array.isArray(protocols)) continue;
|
|
15979
|
+
for (const entry of protocols) {
|
|
15980
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
15981
|
+
if (!("mpp" in entry)) continue;
|
|
15982
|
+
const mpp = entry.mpp;
|
|
15983
|
+
if (typeof mpp !== "object" || mpp === null) return true;
|
|
15984
|
+
const mppObj = mpp;
|
|
15985
|
+
if (typeof mppObj.method !== "string" || mppObj.method.length === 0) return true;
|
|
15986
|
+
if (typeof mppObj.intent !== "string" || mppObj.intent.length === 0) return true;
|
|
15987
|
+
if (typeof mppObj.currency !== "string" || mppObj.currency.length === 0) return true;
|
|
15988
|
+
}
|
|
15989
|
+
}
|
|
15990
|
+
}
|
|
15991
|
+
return false;
|
|
15992
|
+
}
|
|
15993
|
+
function hasImproperX402Tag(raw) {
|
|
15994
|
+
const paths = raw.paths;
|
|
15995
|
+
if (typeof paths !== "object" || paths === null) return false;
|
|
15996
|
+
for (const pathItem of Object.values(paths)) {
|
|
15997
|
+
if (typeof pathItem !== "object" || pathItem === null) continue;
|
|
15998
|
+
for (const method of HTTP_METHODS2) {
|
|
15999
|
+
const operation = pathItem[method];
|
|
16000
|
+
if (typeof operation !== "object" || operation === null) continue;
|
|
16001
|
+
const pi = operation["x-payment-info"];
|
|
16002
|
+
if (typeof pi !== "object" || pi === null) continue;
|
|
16003
|
+
const protocols = pi.protocols;
|
|
16004
|
+
if (!Array.isArray(protocols)) continue;
|
|
16005
|
+
for (const entry of protocols) {
|
|
16006
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
16007
|
+
if (!("x402" in entry)) continue;
|
|
16008
|
+
const x402 = entry.x402;
|
|
16009
|
+
if (typeof x402 !== "object" || x402 === null || Array.isArray(x402)) return true;
|
|
16010
|
+
}
|
|
16011
|
+
}
|
|
16012
|
+
}
|
|
16013
|
+
return false;
|
|
16014
|
+
}
|
|
15947
16015
|
function getWarningsForOpenAPI(openApi) {
|
|
15948
16016
|
if (openApi === null) {
|
|
15949
16017
|
return [
|
|
@@ -15985,6 +16053,22 @@ ${details}`,
|
|
|
15985
16053
|
hint: "Migrate to the structured format: { price: { mode, amount, currency }, protocols: [{ x402: {} }] }."
|
|
15986
16054
|
});
|
|
15987
16055
|
}
|
|
16056
|
+
if (hasImproperX402Tag(openApi.raw)) {
|
|
16057
|
+
warnings.push({
|
|
16058
|
+
code: AUDIT_CODES.L2_X402_MALFORMED,
|
|
16059
|
+
severity: "warn",
|
|
16060
|
+
message: "One or more operations have a malformed x402 protocol entry.",
|
|
16061
|
+
hint: "Canonical shape: { x402: { ...optional config } }."
|
|
16062
|
+
});
|
|
16063
|
+
}
|
|
16064
|
+
if (hasImproperMppTag(openApi.raw)) {
|
|
16065
|
+
warnings.push({
|
|
16066
|
+
code: AUDIT_CODES.L2_MPP_MALFORMED,
|
|
16067
|
+
severity: "warn",
|
|
16068
|
+
message: "One or more operations have a malformed mpp protocol entry.",
|
|
16069
|
+
hint: "Canonical shape: { mpp: { method: string, intent: string, currency: string } }."
|
|
16070
|
+
});
|
|
16071
|
+
}
|
|
15988
16072
|
return warnings;
|
|
15989
16073
|
}
|
|
15990
16074
|
function getWarningsForWellKnown(wellKnown) {
|
|
@@ -16062,7 +16146,15 @@ function getWarningsForL2(l2) {
|
|
|
16062
16146
|
});
|
|
16063
16147
|
}
|
|
16064
16148
|
if (route.authMode === "paid") {
|
|
16065
|
-
if (!route.price) {
|
|
16149
|
+
if (route.pricingMode === "dynamic" && !route.price) {
|
|
16150
|
+
warnings.push({
|
|
16151
|
+
code: AUDIT_CODES.L2_DYNAMIC_PRICE_INCOMPLETE,
|
|
16152
|
+
severity: "warn",
|
|
16153
|
+
message: `Paid route ${loc} declares dynamic pricing but no min/max bounds.`,
|
|
16154
|
+
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.",
|
|
16155
|
+
path: route.path
|
|
16156
|
+
});
|
|
16157
|
+
} else if (!route.price) {
|
|
16066
16158
|
warnings.push({
|
|
16067
16159
|
code: AUDIT_CODES.L2_PRICE_MISSING_ON_PAID,
|
|
16068
16160
|
severity: "warn",
|
package/dist/schemas.cjs
CHANGED
|
@@ -13809,8 +13809,8 @@ var FixedPriceSchema = external_exports.object({
|
|
|
13809
13809
|
var DynamicPriceSchema = external_exports.object({
|
|
13810
13810
|
currency: Iso4217Schema,
|
|
13811
13811
|
mode: external_exports.literal("dynamic"),
|
|
13812
|
-
min: external_exports.string(),
|
|
13813
|
-
max: external_exports.string()
|
|
13812
|
+
min: external_exports.string().optional(),
|
|
13813
|
+
max: external_exports.string().optional()
|
|
13814
13814
|
});
|
|
13815
13815
|
var PriceSchema = external_exports.union([FixedPriceSchema, DynamicPriceSchema]);
|
|
13816
13816
|
var X402ProtocolSchema = external_exports.object({
|
|
@@ -13857,10 +13857,13 @@ var OpenApiOperationSchema = external_exports.object({
|
|
|
13857
13857
|
description: external_exports.string().optional(),
|
|
13858
13858
|
tags: external_exports.array(external_exports.string()).optional(),
|
|
13859
13859
|
security: external_exports.array(external_exports.record(external_exports.string(), external_exports.array(external_exports.string()))).optional(),
|
|
13860
|
+
// `in` / `name` are spec-required, but a single malformed parameter must not
|
|
13861
|
+
// abort the whole spec — keep them optional so discovery is resilient to
|
|
13862
|
+
// non-conformant OpenAPI documents in the wild.
|
|
13860
13863
|
parameters: external_exports.array(
|
|
13861
13864
|
external_exports.object({
|
|
13862
|
-
in: external_exports.string(),
|
|
13863
|
-
name: external_exports.string(),
|
|
13865
|
+
in: external_exports.string().optional(),
|
|
13866
|
+
name: external_exports.string().optional(),
|
|
13864
13867
|
schema: external_exports.unknown().optional(),
|
|
13865
13868
|
required: external_exports.boolean().optional()
|
|
13866
13869
|
})
|
|
@@ -13870,7 +13873,8 @@ var OpenApiOperationSchema = external_exports.object({
|
|
|
13870
13873
|
content: external_exports.record(external_exports.string(), external_exports.object({ schema: external_exports.unknown().optional() }))
|
|
13871
13874
|
}).optional(),
|
|
13872
13875
|
responses: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
13873
|
-
|
|
13876
|
+
// Permissive: vendor extension shape is validated at runtime, never at parse time.
|
|
13877
|
+
"x-payment-info": external_exports.unknown().optional()
|
|
13874
13878
|
});
|
|
13875
13879
|
var OpenApiPathItemSchema = external_exports.object({
|
|
13876
13880
|
get: OpenApiOperationSchema.optional(),
|