@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/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
- return `${price.min}-${price.max} ${sym}`;
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
- "x-payment-info": OpenApiPaymentInfoSchema.optional()
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 resolvePricingHint(p) {
14160
- const raw = p;
14161
- const info = resolvePaymentInfo(raw);
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" ? { minPrice: info.price.min, maxPrice: info.price.max } : {},
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(p) {
14171
- const raw = p;
14172
- const info = resolvePaymentInfo(raw);
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 "dynamic";
14448
+ if (pricing.minPrice) return `from ${pricing.minPrice} ${sym}`;
14433
14449
  }
14434
- return `unknown pricing mode: ${pricing.pricingMode}`;
14450
+ return void 0;
14435
14451
  }
14436
14452
  function checkL2ForOpenAPI(openApi) {
14437
- const routes = openApi.routes.map((route) => ({
14438
- path: route.path,
14439
- method: route.method,
14440
- summary: route.summary ?? `${route.method} ${route.path}`,
14441
- ...route.authMode ? { authMode: route.authMode } : {},
14442
- ...route.pricing ? {
14443
- price: formatPrice2(route.pricing),
14444
- pricingMode: route.pricing.pricingMode,
14445
- ...route.pricing.currency ? { currency: route.pricing.currency } : {}
14446
- } : {},
14447
- ...route.protocols?.length ? { protocols: route.protocols } : {}
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 import_neverthrow6 = require("neverthrow");
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 payload = JSON.parse(atob(headerValue));
15020
- if (!isRecord(payload) || payload.x402Version !== 2) return null;
15021
- return payload;
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 import_neverthrow6.ResultAsync.fromSafePromise(Promise.resolve(null));
15064
- return import_neverthrow6.ResultAsync.fromSafePromise(
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 import_neverthrow6.ResultAsync.fromSafePromise(
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 import_neverthrow7 = require("neverthrow");
15150
+ var import_neverthrow8 = require("neverthrow");
15109
15151
  function parseBase64Json(encoded) {
15110
- return import_neverthrow7.Result.fromThrowable(
15152
+ return import_neverthrow8.Result.fromThrowable(
15111
15153
  () => {
15112
- const decoded = typeof Buffer !== "undefined" ? Buffer.from(encoded, "base64").toString("utf8") : atob(encoded);
15113
- const parsed = JSON.parse(decoded);
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 import_neverthrow8 = require("neverthrow");
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, import_neverthrow8.okAsync)(isImage(res));
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, import_neverthrow8.okAsync)(false);
16256
- }).orElse(() => (0, import_neverthrow8.okAsync)(false));
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, import_neverthrow8.okAsync)("");
16286
- return import_neverthrow8.ResultAsync.fromSafePromise(res.text());
16287
- }).map((html) => html ? extractIconHrefs(html, origin) : []).orElse(() => (0, import_neverthrow8.okAsync)([]));
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 import_neverthrow8.ResultAsync.fromSafePromise(
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
- return `${price.min}-${price.max} ${sym}`;
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
- "x-payment-info": OpenApiPaymentInfoSchema.optional()
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 resolvePricingHint(p) {
14098
- const raw = p;
14099
- const info = resolvePaymentInfo(raw);
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" ? { minPrice: info.price.min, maxPrice: info.price.max } : {},
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(p) {
14109
- const raw = p;
14110
- const info = resolvePaymentInfo(raw);
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 "dynamic";
14386
+ if (pricing.minPrice) return `from ${pricing.minPrice} ${sym}`;
14371
14387
  }
14372
- return `unknown pricing mode: ${pricing.pricingMode}`;
14388
+ return void 0;
14373
14389
  }
14374
14390
  function checkL2ForOpenAPI(openApi) {
14375
- const routes = openApi.routes.map((route) => ({
14376
- path: route.path,
14377
- method: route.method,
14378
- summary: route.summary ?? `${route.method} ${route.path}`,
14379
- ...route.authMode ? { authMode: route.authMode } : {},
14380
- ...route.pricing ? {
14381
- price: formatPrice2(route.pricing),
14382
- pricingMode: route.pricing.pricingMode,
14383
- ...route.pricing.currency ? { currency: route.pricing.currency } : {}
14384
- } : {},
14385
- ...route.protocols?.length ? { protocols: route.protocols } : {}
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 payload = JSON.parse(atob(headerValue));
14958
- if (!isRecord(payload) || payload.x402Version !== 2) return null;
14959
- return payload;
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 Result2 } from "neverthrow";
15088
+ import { Result as Result3 } from "neverthrow";
15047
15089
  function parseBase64Json(encoded) {
15048
- return Result2.fromThrowable(
15090
+ return Result3.fromThrowable(
15049
15091
  () => {
15050
- const decoded = typeof Buffer !== "undefined" ? Buffer.from(encoded, "base64").toString("utf8") : atob(encoded);
15051
- const parsed = JSON.parse(decoded);
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
- "x-payment-info": OpenApiPaymentInfoSchema.optional()
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(),