@agentcash/discovery 1.6.2 → 1.6.4
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 +94 -42
- package/dist/cli.js +90 -38
- package/dist/index.cjs +102 -50
- package/dist/index.d.cts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +90 -38
- 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 } : {},
|
|
@@ -14610,7 +14627,7 @@ async function discoverOriginSchema(options) {
|
|
|
14610
14627
|
}
|
|
14611
14628
|
|
|
14612
14629
|
// src/core/source/probe/index.ts
|
|
14613
|
-
var
|
|
14630
|
+
var import_neverthrow7 = require("neverthrow");
|
|
14614
14631
|
|
|
14615
14632
|
// src/core/protocols/x402/v1/schema.ts
|
|
14616
14633
|
function extractSchemas(accepts) {
|
|
@@ -15014,11 +15031,36 @@ async function parsePaymentRequiredBody(response) {
|
|
|
15014
15031
|
return payload;
|
|
15015
15032
|
}
|
|
15016
15033
|
|
|
15034
|
+
// src/core/lib/base64.ts
|
|
15035
|
+
var import_neverthrow6 = require("neverthrow");
|
|
15036
|
+
function safeBase64DecodeUtf8(encoded) {
|
|
15037
|
+
return import_neverthrow6.Result.fromThrowable(
|
|
15038
|
+
() => {
|
|
15039
|
+
if (typeof Buffer !== "undefined") {
|
|
15040
|
+
return Buffer.from(encoded, "base64").toString("utf8");
|
|
15041
|
+
}
|
|
15042
|
+
const binaryString = atob(encoded);
|
|
15043
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
15044
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
15045
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
15046
|
+
}
|
|
15047
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
15048
|
+
},
|
|
15049
|
+
(e) => e instanceof Error ? e : new Error(String(e))
|
|
15050
|
+
)();
|
|
15051
|
+
}
|
|
15052
|
+
|
|
15017
15053
|
// src/core/protocols/x402/v2/parse-payment-required.ts
|
|
15018
15054
|
function parsePaymentRequiredBody2(headerValue) {
|
|
15019
|
-
const
|
|
15020
|
-
if (
|
|
15021
|
-
|
|
15055
|
+
const decoded = safeBase64DecodeUtf8(headerValue);
|
|
15056
|
+
if (decoded.isErr()) return null;
|
|
15057
|
+
try {
|
|
15058
|
+
const payload = JSON.parse(decoded.value);
|
|
15059
|
+
if (!isRecord(payload) || payload.x402Version !== 2) return null;
|
|
15060
|
+
return payload;
|
|
15061
|
+
} catch {
|
|
15062
|
+
return null;
|
|
15063
|
+
}
|
|
15022
15064
|
}
|
|
15023
15065
|
|
|
15024
15066
|
// src/core/source/probe/index.ts
|
|
@@ -15060,8 +15102,8 @@ function probeMethod(url2, method, path, headers, signal, inputBody) {
|
|
|
15060
15102
|
...hasBody ? { body: JSON.stringify(inputBody) } : {},
|
|
15061
15103
|
signal
|
|
15062
15104
|
}).andThen((response) => {
|
|
15063
|
-
if (!isUsableStatus(response.status)) return
|
|
15064
|
-
return
|
|
15105
|
+
if (!isUsableStatus(response.status)) return import_neverthrow7.ResultAsync.fromSafePromise(Promise.resolve(null));
|
|
15106
|
+
return import_neverthrow7.ResultAsync.fromSafePromise(
|
|
15065
15107
|
(async () => {
|
|
15066
15108
|
let authHint = response.status === 402 ? "paid" : "unprotected";
|
|
15067
15109
|
let paymentRequiredBody;
|
|
@@ -15092,7 +15134,7 @@ function probeMethod(url2, method, path, headers, signal, inputBody) {
|
|
|
15092
15134
|
}
|
|
15093
15135
|
function getProbe(url2, headers, signal, inputBody) {
|
|
15094
15136
|
const path = normalizePath(new URL(url2).pathname || "/");
|
|
15095
|
-
return
|
|
15137
|
+
return import_neverthrow7.ResultAsync.fromSafePromise(
|
|
15096
15138
|
Promise.all(
|
|
15097
15139
|
[...HTTP_METHODS].map(
|
|
15098
15140
|
(method) => probeMethod(url2, method, path, headers, signal, inputBody).match(
|
|
@@ -15105,12 +15147,13 @@ function getProbe(url2, headers, signal, inputBody) {
|
|
|
15105
15147
|
}
|
|
15106
15148
|
|
|
15107
15149
|
// src/core/protocols/mpp/index.ts
|
|
15108
|
-
var
|
|
15150
|
+
var import_neverthrow8 = require("neverthrow");
|
|
15109
15151
|
function parseBase64Json(encoded) {
|
|
15110
|
-
return
|
|
15152
|
+
return import_neverthrow8.Result.fromThrowable(
|
|
15111
15153
|
() => {
|
|
15112
|
-
const decoded =
|
|
15113
|
-
|
|
15154
|
+
const decoded = safeBase64DecodeUtf8(encoded);
|
|
15155
|
+
if (decoded.isErr()) throw decoded.error;
|
|
15156
|
+
const parsed = JSON.parse(decoded.value);
|
|
15114
15157
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
15115
15158
|
throw new Error("not an object");
|
|
15116
15159
|
}
|
|
@@ -15502,6 +15545,7 @@ var AUDIT_CODES = {
|
|
|
15502
15545
|
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
15503
15546
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
15504
15547
|
L2_PRICING_MODE_UNKNOWN: "L2_PRICING_MODE_UNKNOWN",
|
|
15548
|
+
L2_DYNAMIC_PRICE_INCOMPLETE: "L2_DYNAMIC_PRICE_INCOMPLETE",
|
|
15505
15549
|
L2_CURRENCY_INVALID: "L2_CURRENCY_INVALID",
|
|
15506
15550
|
L2_PAYMENT_INFO_LEGACY: "L2_PAYMENT_INFO_LEGACY",
|
|
15507
15551
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
@@ -16190,7 +16234,15 @@ function getWarningsForL2(l2) {
|
|
|
16190
16234
|
});
|
|
16191
16235
|
}
|
|
16192
16236
|
if (route.authMode === "paid") {
|
|
16193
|
-
if (!route.price) {
|
|
16237
|
+
if (route.pricingMode === "dynamic" && !route.price) {
|
|
16238
|
+
warnings.push({
|
|
16239
|
+
code: AUDIT_CODES.L2_DYNAMIC_PRICE_INCOMPLETE,
|
|
16240
|
+
severity: "warn",
|
|
16241
|
+
message: `Paid route ${loc} declares dynamic pricing but no min/max bounds.`,
|
|
16242
|
+
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.",
|
|
16243
|
+
path: route.path
|
|
16244
|
+
});
|
|
16245
|
+
} else if (!route.price) {
|
|
16194
16246
|
warnings.push({
|
|
16195
16247
|
code: AUDIT_CODES.L2_PRICE_MISSING_ON_PAID,
|
|
16196
16248
|
severity: "warn",
|
|
@@ -16240,7 +16292,7 @@ function getWarningsForL4(l4) {
|
|
|
16240
16292
|
}
|
|
16241
16293
|
|
|
16242
16294
|
// src/audit/warnings/favicon.ts
|
|
16243
|
-
var
|
|
16295
|
+
var import_neverthrow9 = require("neverthrow");
|
|
16244
16296
|
var COMMON_PATHS = ["/favicon.ico", "/favicon.png", "/favicon.svg"];
|
|
16245
16297
|
var TIMEOUT = AbortSignal.timeout(5e3);
|
|
16246
16298
|
function isImage(res) {
|
|
@@ -16248,12 +16300,12 @@ function isImage(res) {
|
|
|
16248
16300
|
}
|
|
16249
16301
|
function checkUrl(url2) {
|
|
16250
16302
|
return fetchSafe(url2, { method: "HEAD", signal: TIMEOUT }).andThen((res) => {
|
|
16251
|
-
if (res.ok) return (0,
|
|
16303
|
+
if (res.ok) return (0, import_neverthrow9.okAsync)(isImage(res));
|
|
16252
16304
|
if (res.status === 405 || res.status === 403) {
|
|
16253
16305
|
return fetchSafe(url2, { signal: TIMEOUT }).map((getRes) => getRes.ok && isImage(getRes));
|
|
16254
16306
|
}
|
|
16255
|
-
return (0,
|
|
16256
|
-
}).orElse(() => (0,
|
|
16307
|
+
return (0, import_neverthrow9.okAsync)(false);
|
|
16308
|
+
}).orElse(() => (0, import_neverthrow9.okAsync)(false));
|
|
16257
16309
|
}
|
|
16258
16310
|
function resolveHref(href, origin) {
|
|
16259
16311
|
if (href.startsWith("//")) return `https:${href}`;
|
|
@@ -16282,15 +16334,15 @@ function extractIconHrefs(html, origin) {
|
|
|
16282
16334
|
function getHtmlIconHrefs(origin) {
|
|
16283
16335
|
return fetchSafe(origin, { signal: TIMEOUT }).andThen((res) => {
|
|
16284
16336
|
if (!res.ok || !(res.headers.get("content-type") ?? "").includes("text/html"))
|
|
16285
|
-
return (0,
|
|
16286
|
-
return
|
|
16287
|
-
}).map((html) => html ? extractIconHrefs(html, origin) : []).orElse(() => (0,
|
|
16337
|
+
return (0, import_neverthrow9.okAsync)("");
|
|
16338
|
+
return import_neverthrow9.ResultAsync.fromSafePromise(res.text());
|
|
16339
|
+
}).map((html) => html ? extractIconHrefs(html, origin) : []).orElse(() => (0, import_neverthrow9.okAsync)([]));
|
|
16288
16340
|
}
|
|
16289
16341
|
function checkFavicon(origin) {
|
|
16290
16342
|
const normalizedOrigin = origin.replace(/\/$/, "");
|
|
16291
16343
|
return getHtmlIconHrefs(normalizedOrigin).andThen((hrefs) => {
|
|
16292
16344
|
const candidates = [...hrefs, ...COMMON_PATHS.map((p) => `${normalizedOrigin}${p}`)];
|
|
16293
|
-
return
|
|
16345
|
+
return import_neverthrow9.ResultAsync.fromSafePromise(
|
|
16294
16346
|
Promise.all(candidates.map((url2) => checkUrl(url2).then((r) => r.isOk() && r.value))).then(
|
|
16295
16347
|
(results) => results.some(Boolean)
|
|
16296
16348
|
)
|
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,6 +448,7 @@ 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";
|
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,6 +448,7 @@ 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";
|
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 } : {},
|
|
@@ -14952,11 +14969,36 @@ async function parsePaymentRequiredBody(response) {
|
|
|
14952
14969
|
return payload;
|
|
14953
14970
|
}
|
|
14954
14971
|
|
|
14972
|
+
// src/core/lib/base64.ts
|
|
14973
|
+
import { Result as Result2 } from "neverthrow";
|
|
14974
|
+
function safeBase64DecodeUtf8(encoded) {
|
|
14975
|
+
return Result2.fromThrowable(
|
|
14976
|
+
() => {
|
|
14977
|
+
if (typeof Buffer !== "undefined") {
|
|
14978
|
+
return Buffer.from(encoded, "base64").toString("utf8");
|
|
14979
|
+
}
|
|
14980
|
+
const binaryString = atob(encoded);
|
|
14981
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
14982
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
14983
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
14984
|
+
}
|
|
14985
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
14986
|
+
},
|
|
14987
|
+
(e) => e instanceof Error ? e : new Error(String(e))
|
|
14988
|
+
)();
|
|
14989
|
+
}
|
|
14990
|
+
|
|
14955
14991
|
// src/core/protocols/x402/v2/parse-payment-required.ts
|
|
14956
14992
|
function parsePaymentRequiredBody2(headerValue) {
|
|
14957
|
-
const
|
|
14958
|
-
if (
|
|
14959
|
-
|
|
14993
|
+
const decoded = safeBase64DecodeUtf8(headerValue);
|
|
14994
|
+
if (decoded.isErr()) return null;
|
|
14995
|
+
try {
|
|
14996
|
+
const payload = JSON.parse(decoded.value);
|
|
14997
|
+
if (!isRecord(payload) || payload.x402Version !== 2) return null;
|
|
14998
|
+
return payload;
|
|
14999
|
+
} catch {
|
|
15000
|
+
return null;
|
|
15001
|
+
}
|
|
14960
15002
|
}
|
|
14961
15003
|
|
|
14962
15004
|
// src/core/source/probe/index.ts
|
|
@@ -15043,12 +15085,13 @@ function getProbe(url2, headers, signal, inputBody) {
|
|
|
15043
15085
|
}
|
|
15044
15086
|
|
|
15045
15087
|
// src/core/protocols/mpp/index.ts
|
|
15046
|
-
import { Result as
|
|
15088
|
+
import { Result as Result3 } from "neverthrow";
|
|
15047
15089
|
function parseBase64Json(encoded) {
|
|
15048
|
-
return
|
|
15090
|
+
return Result3.fromThrowable(
|
|
15049
15091
|
() => {
|
|
15050
|
-
const decoded =
|
|
15051
|
-
|
|
15092
|
+
const decoded = safeBase64DecodeUtf8(encoded);
|
|
15093
|
+
if (decoded.isErr()) throw decoded.error;
|
|
15094
|
+
const parsed = JSON.parse(decoded.value);
|
|
15052
15095
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
15053
15096
|
throw new Error("not an object");
|
|
15054
15097
|
}
|
|
@@ -15440,6 +15483,7 @@ var AUDIT_CODES = {
|
|
|
15440
15483
|
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
15441
15484
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
15442
15485
|
L2_PRICING_MODE_UNKNOWN: "L2_PRICING_MODE_UNKNOWN",
|
|
15486
|
+
L2_DYNAMIC_PRICE_INCOMPLETE: "L2_DYNAMIC_PRICE_INCOMPLETE",
|
|
15443
15487
|
L2_CURRENCY_INVALID: "L2_CURRENCY_INVALID",
|
|
15444
15488
|
L2_PAYMENT_INFO_LEGACY: "L2_PAYMENT_INFO_LEGACY",
|
|
15445
15489
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
@@ -16128,7 +16172,15 @@ function getWarningsForL2(l2) {
|
|
|
16128
16172
|
});
|
|
16129
16173
|
}
|
|
16130
16174
|
if (route.authMode === "paid") {
|
|
16131
|
-
if (!route.price) {
|
|
16175
|
+
if (route.pricingMode === "dynamic" && !route.price) {
|
|
16176
|
+
warnings.push({
|
|
16177
|
+
code: AUDIT_CODES.L2_DYNAMIC_PRICE_INCOMPLETE,
|
|
16178
|
+
severity: "warn",
|
|
16179
|
+
message: `Paid route ${loc} declares dynamic pricing but no min/max bounds.`,
|
|
16180
|
+
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.",
|
|
16181
|
+
path: route.path
|
|
16182
|
+
});
|
|
16183
|
+
} else if (!route.price) {
|
|
16132
16184
|
warnings.push({
|
|
16133
16185
|
code: AUDIT_CODES.L2_PRICE_MISSING_ON_PAID,
|
|
16134
16186
|
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(),
|