@agentcash/discovery 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -78,6 +78,15 @@ interface OpenApiSource {
78
78
  guidance?: string;
79
79
  fetchedUrl: string;
80
80
  }
81
+ /** Returned when the spec was fetched successfully but failed schema validation. */
82
+ interface OpenApiParseFailure {
83
+ parseFailure: true;
84
+ fetchedUrl: string;
85
+ issues: Array<{
86
+ path: (string | number | symbol)[];
87
+ message: string;
88
+ }>;
89
+ }
81
90
  interface OpenApiRoute {
82
91
  path: string;
83
92
  method: HttpMethod;
@@ -89,12 +98,18 @@ interface OpenApiRoute {
89
98
  interface WellKnownSource {
90
99
  raw: Record<string, unknown>;
91
100
  routes: WellKnownRoute[];
101
+ title?: string;
102
+ description?: string;
92
103
  instructions?: string;
93
104
  fetchedUrl: string;
105
+ /** Which well-known document(s) this source was built from. */
106
+ protocol: 'x402' | 'mpp' | 'x402+mpp';
94
107
  }
95
108
  interface WellKnownRoute {
96
109
  path: string;
97
110
  method: HttpMethod;
111
+ /** Raw price hint from the well-known document (e.g. MPP `payment.amount`). */
112
+ price?: string;
98
113
  }
99
114
  interface ProbeResult {
100
115
  path: string;
@@ -111,7 +126,7 @@ interface L2Result {
111
126
  description?: string;
112
127
  version?: string;
113
128
  routes: L2Route[];
114
- source: 'openapi' | 'well-known/x402' | null;
129
+ source: 'openapi' | 'well-known/x402' | 'well-known/mpp' | 'well-known/x402+mpp' | null;
115
130
  }
116
131
  interface L2Route {
117
132
  path: string;
@@ -145,7 +160,7 @@ interface L3Result {
145
160
  }
146
161
  interface L4Result {
147
162
  guidance: string;
148
- source: 'openapi' | 'well-known/x402';
163
+ source: 'openapi' | 'well-known/x402' | 'well-known/mpp' | 'well-known/x402+mpp';
149
164
  }
150
165
 
151
166
  declare enum GuidanceMode {
@@ -182,6 +197,8 @@ interface DiscoverOriginSchemaSuccess {
182
197
  guidanceTokens?: number;
183
198
  /** Guidance text. Included when short enough (auto mode) or guidance='always'. */
184
199
  guidance?: string;
200
+ /** Ownership proof strings collected from the discovery document, if any. */
201
+ ownershipProofs?: string[];
185
202
  }
186
203
  interface DiscoverOriginSchemaNotFound {
187
204
  found: false;
@@ -239,10 +256,23 @@ interface FetchError {
239
256
  message: string;
240
257
  }
241
258
 
242
- declare function getOpenAPI(origin: string, headers?: Record<string, string>, signal?: AbortSignal, specificationOverrideUrl?: string): ResultAsync<OpenApiSource | null, FetchError>;
259
+ declare function getOpenAPI(origin: string, headers?: Record<string, string>, signal?: AbortSignal, specificationOverrideUrl?: string): ResultAsync<OpenApiSource | OpenApiParseFailure | null, FetchError>;
243
260
 
261
+ /**
262
+ * Fetches both `/.well-known/x402` and `/.well-known/mpp` in parallel and merges results.
263
+ *
264
+ * In practice these are mutually exclusive, but if both exist their routes are combined
265
+ * (deduplicated by method+path). x402 wins on instruction/fetchedUrl conflicts.
266
+ *
267
+ * Individual leg failures are treated as "not found" for that leg so valid data from
268
+ * the other is never suppressed. Returns Err(FetchError) only when both legs hard-fail.
269
+ */
244
270
  declare function getWellKnown(origin: string, headers?: Record<string, string>, signal?: AbortSignal): ResultAsync<WellKnownSource | null, FetchError>;
245
271
 
272
+ declare function getX402WellKnown(origin: string, headers?: Record<string, string>, signal?: AbortSignal): ResultAsync<WellKnownSource | null, FetchError>;
273
+
274
+ declare function getMppWellKnown(origin: string, headers?: Record<string, string>, signal?: AbortSignal): ResultAsync<WellKnownSource | null, FetchError>;
275
+
246
276
  declare function getProbe(url: string, headers?: Record<string, string>, signal?: AbortSignal, inputBody?: Record<string, unknown>): ResultAsync<ProbeResult[], FetchError>;
247
277
 
248
278
  declare function checkL2ForOpenAPI(openApi: OpenApiSource): L2Result;
@@ -354,6 +384,7 @@ declare function validatePaymentRequiredDetailed(payload: unknown, options?: Val
354
384
  declare const AUDIT_CODES: {
355
385
  readonly OPENAPI_NOT_FOUND: "OPENAPI_NOT_FOUND";
356
386
  readonly WELLKNOWN_NOT_FOUND: "WELLKNOWN_NOT_FOUND";
387
+ readonly OPENAPI_PARSE_ERROR: "OPENAPI_PARSE_ERROR";
357
388
  readonly OPENAPI_NO_ROUTES: "OPENAPI_NO_ROUTES";
358
389
  readonly L2_NO_ROUTES: "L2_NO_ROUTES";
359
390
  readonly L2_ROUTE_COUNT_HIGH: "L2_ROUTE_COUNT_HIGH";
@@ -394,7 +425,9 @@ interface AuditWarning {
394
425
  path?: string;
395
426
  }
396
427
 
397
- declare function getWarningsForOpenAPI(openApi: OpenApiSource | null): AuditWarning[];
428
+ /** Type guard: true when the value is a parse-failure sentinel (spec fetched but invalid). */
429
+ declare function isOpenApiParseFailure(value: OpenApiSource | OpenApiParseFailure | null): value is OpenApiParseFailure;
430
+ declare function getWarningsForOpenAPI(openApi: OpenApiSource | OpenApiParseFailure | null): AuditWarning[];
398
431
  declare function getWarningsForWellKnown(wellKnown: WellKnownSource | null): AuditWarning[];
399
432
 
400
433
  declare function getWarningsForL2(l2: L2Result): AuditWarning[];
@@ -424,4 +457,4 @@ declare function getWarningsForL4(l4: L4Result | null): AuditWarning[];
424
457
  */
425
458
  declare function getWarningsForMppHeader(wwwAuthenticate: string | null | undefined): AuditWarning[];
426
459
 
427
- export { AUDIT_CODES, type AuditCode, type AuditSeverity, type AuditWarning, type AuthMode, type CheckEndpointNotFound, type CheckEndpointOptions, type CheckEndpointResult, type CheckEndpointSuccess, type DiscoverOriginSchemaNotFound, type DiscoverOriginSchemaOptions, type DiscoverOriginSchemaResult, type DiscoverOriginSchemaSuccess, type EndpointMethodAdvisory, GuidanceMode, type HttpMethod, type L2Result, type L2Route, type L3Result, type L4Result, type MetadataPreview, type MppPaymentOption, type NormalizedAccept, type NormalizedPaymentRequired, type OpenApiRoute, type OpenApiSource, type PaymentOption, type PricingMode, type ProbeResult, type TrustTier, VALIDATION_CODES, type ValidatePaymentRequiredDetailedResult, type ValidatePaymentRequiredOptions, type ValidationIssue, type ValidationSeverity, type ValidationStage, type ValidationSummary, type WellKnownRoute, type WellKnownSource, type X402PaymentOption, type X402V1PaymentOption, type X402V2PaymentOption, attachProbePayload, checkEndpointSchema, checkL2ForOpenAPI, checkL2ForWellknown, checkL4ForOpenAPI, checkL4ForWellknown, discoverOriginSchema, evaluateMetadataCompleteness, getL3, getL3ForOpenAPI, getL3ForProbe, getOpenAPI, getProbe, getWarningsFor402Body, getWarningsForL2, getWarningsForL3, getWarningsForL4, getWarningsForMppHeader, getWarningsForOpenAPI, getWarningsForWellKnown, getWellKnown, validatePaymentRequiredDetailed };
460
+ export { AUDIT_CODES, type AuditCode, type AuditSeverity, type AuditWarning, type AuthMode, type CheckEndpointNotFound, type CheckEndpointOptions, type CheckEndpointResult, type CheckEndpointSuccess, type DiscoverOriginSchemaNotFound, type DiscoverOriginSchemaOptions, type DiscoverOriginSchemaResult, type DiscoverOriginSchemaSuccess, type EndpointMethodAdvisory, GuidanceMode, type HttpMethod, type L2Result, type L2Route, type L3Result, type L4Result, type MetadataPreview, type MppPaymentOption, type NormalizedAccept, type NormalizedPaymentRequired, type OpenApiParseFailure, type OpenApiRoute, type OpenApiSource, type PaymentOption, type PricingMode, type ProbeResult, type TrustTier, VALIDATION_CODES, type ValidatePaymentRequiredDetailedResult, type ValidatePaymentRequiredOptions, type ValidationIssue, type ValidationSeverity, type ValidationStage, type ValidationSummary, type WellKnownRoute, type WellKnownSource, type X402PaymentOption, type X402V1PaymentOption, type X402V2PaymentOption, attachProbePayload, checkEndpointSchema, checkL2ForOpenAPI, checkL2ForWellknown, checkL4ForOpenAPI, checkL4ForWellknown, discoverOriginSchema, evaluateMetadataCompleteness, getL3, getL3ForOpenAPI, getL3ForProbe, getMppWellKnown, getOpenAPI, getProbe, getWarningsFor402Body, getWarningsForL2, getWarningsForL3, getWarningsForL4, getWarningsForMppHeader, getWarningsForOpenAPI, getWarningsForWellKnown, getWellKnown, getX402WellKnown, isOpenApiParseFailure, validatePaymentRequiredDetailed };
package/dist/index.js CHANGED
@@ -13842,7 +13842,8 @@ var WellKnownParsedSchema = external_exports.object({
13842
13842
  routes: external_exports.array(
13843
13843
  external_exports.object({
13844
13844
  path: external_exports.string(),
13845
- method: external_exports.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE"])
13845
+ method: external_exports.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE"]),
13846
+ price: external_exports.string().optional()
13846
13847
  })
13847
13848
  ),
13848
13849
  instructions: external_exports.string().optional()
@@ -13935,9 +13936,9 @@ function toAbsoluteUrl(origin, value) {
13935
13936
 
13936
13937
  // src/core/source/fetch.ts
13937
13938
  import { ResultAsync } from "neverthrow";
13938
- function toFetchError(err) {
13939
- const cause = err instanceof DOMException && (err.name === "TimeoutError" || err.name === "AbortError") ? "timeout" : "network";
13940
- return { cause, message: String(err) };
13939
+ function toFetchError(err2) {
13940
+ const cause = err2 instanceof DOMException && (err2.name === "TimeoutError" || err2.name === "AbortError") ? "timeout" : "network";
13941
+ return { cause, message: String(err2) };
13941
13942
  }
13942
13943
  function fetchSafe(url2, init) {
13943
13944
  return ResultAsync.fromPromise(fetch(url2, init), toFetchError);
@@ -13984,7 +13985,13 @@ async function parseBody(response, url2) {
13984
13985
  try {
13985
13986
  const payload = await response.json();
13986
13987
  const parsed = OpenApiParsedSchema.safeParse(payload);
13987
- if (!parsed.success) return null;
13988
+ if (!parsed.success) {
13989
+ return {
13990
+ parseFailure: true,
13991
+ fetchedUrl: url2,
13992
+ issues: parsed.error.issues.map((i) => ({ path: i.path, message: i.message }))
13993
+ };
13994
+ }
13988
13995
  return { raw: payload, ...parsed.data, fetchedUrl: url2 };
13989
13996
  } catch {
13990
13997
  return null;
@@ -14003,6 +14010,9 @@ function getOpenAPI(origin, headers, signal, specificationOverrideUrl) {
14003
14010
  }
14004
14011
 
14005
14012
  // src/core/source/wellknown/index.ts
14013
+ import { ok, err, ResultAsync as ResultAsync5 } from "neverthrow";
14014
+
14015
+ // src/core/source/wellknown/x402.ts
14006
14016
  import { okAsync as okAsync2, ResultAsync as ResultAsync3 } from "neverthrow";
14007
14017
  function toWellKnownParsed(origin, doc) {
14008
14018
  const routes = doc.resources.flatMap((entry) => {
@@ -14029,12 +14039,17 @@ async function parseBody2(response, origin, url2) {
14029
14039
  if (!doc.success) return null;
14030
14040
  const parsed = WellKnownParsedSchema.safeParse(toWellKnownParsed(origin, doc.data));
14031
14041
  if (!parsed.success) return null;
14032
- return { raw: payload, ...parsed.data, fetchedUrl: url2 };
14042
+ return {
14043
+ raw: payload,
14044
+ ...parsed.data,
14045
+ protocol: "x402",
14046
+ fetchedUrl: url2
14047
+ };
14033
14048
  } catch {
14034
14049
  return null;
14035
14050
  }
14036
14051
  }
14037
- function getWellKnown(origin, headers, signal) {
14052
+ function getX402WellKnown(origin, headers, signal) {
14038
14053
  const url2 = `${origin}/.well-known/x402`;
14039
14054
  return fetchSafe(url2, {
14040
14055
  method: "GET",
@@ -14046,6 +14061,127 @@ function getWellKnown(origin, headers, signal) {
14046
14061
  });
14047
14062
  }
14048
14063
 
14064
+ // src/core/source/wellknown/mpp.ts
14065
+ import { okAsync as okAsync3, ResultAsync as ResultAsync4 } from "neverthrow";
14066
+ var MppEndpointSchema = external_exports.object({
14067
+ method: external_exports.string(),
14068
+ path: external_exports.string(),
14069
+ description: external_exports.string().optional(),
14070
+ payment: external_exports.object({
14071
+ intent: external_exports.string().optional(),
14072
+ method: external_exports.string().optional(),
14073
+ amount: external_exports.string().optional(),
14074
+ currency: external_exports.string().optional()
14075
+ }).optional()
14076
+ });
14077
+ var MppWellKnownDocSchema = external_exports.object({
14078
+ version: external_exports.number().optional(),
14079
+ name: external_exports.string().optional(),
14080
+ description: external_exports.string().optional(),
14081
+ categories: external_exports.array(external_exports.string()).optional(),
14082
+ methods: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
14083
+ endpoints: external_exports.array(MppEndpointSchema).default([]),
14084
+ docs: external_exports.object({
14085
+ homepage: external_exports.string().optional(),
14086
+ apiReference: external_exports.string().optional()
14087
+ }).optional()
14088
+ });
14089
+ var MPP_DECIMALS = 6;
14090
+ function formatMppAmount(raw) {
14091
+ if (!raw) return void 0;
14092
+ const n = Number(raw);
14093
+ if (!Number.isFinite(n)) return void 0;
14094
+ return `$${(n / 10 ** MPP_DECIMALS).toFixed(MPP_DECIMALS)}`;
14095
+ }
14096
+ function toWellKnownParsed2(doc) {
14097
+ const routes = doc.endpoints.flatMap((entry) => {
14098
+ const method = parseMethod(entry.method);
14099
+ if (!method) return [];
14100
+ const path = normalizePath(entry.path);
14101
+ if (!path) return [];
14102
+ const price = formatMppAmount(entry.payment?.amount);
14103
+ return [{ path, method, ...price ? { price } : {} }];
14104
+ });
14105
+ return {
14106
+ routes,
14107
+ ...doc.description ? { instructions: doc.description } : {}
14108
+ };
14109
+ }
14110
+ async function parseBody3(response, url2) {
14111
+ try {
14112
+ const payload = await response.json();
14113
+ const doc = MppWellKnownDocSchema.safeParse(payload);
14114
+ if (!doc.success) return null;
14115
+ const parsed = WellKnownParsedSchema.safeParse(toWellKnownParsed2(doc.data));
14116
+ if (!parsed.success) return null;
14117
+ return {
14118
+ raw: payload,
14119
+ ...parsed.data,
14120
+ ...doc.data.name ? { title: doc.data.name } : {},
14121
+ ...doc.data.description ? { description: doc.data.description } : {},
14122
+ protocol: "mpp",
14123
+ fetchedUrl: url2
14124
+ };
14125
+ } catch {
14126
+ return null;
14127
+ }
14128
+ }
14129
+ function getMppWellKnown(origin, headers, signal) {
14130
+ const url2 = `${origin}/.well-known/mpp`;
14131
+ return fetchSafe(url2, {
14132
+ method: "GET",
14133
+ headers: { Accept: "application/json", ...headers },
14134
+ signal
14135
+ }).andThen((response) => {
14136
+ if (!response.ok) return okAsync3(null);
14137
+ return ResultAsync4.fromSafePromise(parseBody3(response, url2));
14138
+ });
14139
+ }
14140
+
14141
+ // src/core/source/wellknown/index.ts
14142
+ function mergeError(a, b) {
14143
+ return {
14144
+ cause: a.cause === "network" || b.cause === "network" ? "network" : "timeout",
14145
+ message: `x402: ${a.message} | mpp: ${b.message}`
14146
+ };
14147
+ }
14148
+ function merge2(x402, mpp) {
14149
+ const seen = /* @__PURE__ */ new Set();
14150
+ const routes = [...x402.routes, ...mpp.routes].filter((r) => {
14151
+ const key = `${r.method} ${r.path}`;
14152
+ if (seen.has(key)) return false;
14153
+ seen.add(key);
14154
+ return true;
14155
+ });
14156
+ return {
14157
+ raw: { ...mpp.raw, ...x402.raw },
14158
+ routes,
14159
+ protocol: "x402+mpp",
14160
+ // Prefer x402 instructions; fall back to mpp
14161
+ ...x402.instructions || mpp.instructions ? { instructions: x402.instructions ?? mpp.instructions } : {},
14162
+ fetchedUrl: x402.fetchedUrl
14163
+ };
14164
+ }
14165
+ function getWellKnown(origin, headers, signal) {
14166
+ return new ResultAsync5(
14167
+ Promise.all([
14168
+ getX402WellKnown(origin, headers, signal),
14169
+ getMppWellKnown(origin, headers, signal)
14170
+ ]).then(([x402Result, mppResult]) => {
14171
+ const x402 = x402Result.isOk() ? x402Result.value : null;
14172
+ const mpp = mppResult.isOk() ? mppResult.value : null;
14173
+ if (x402 && mpp) return ok(merge2(x402, mpp));
14174
+ if (x402) return ok(x402);
14175
+ if (mpp) return ok(mpp);
14176
+ if (x402Result.isErr() && mppResult.isErr())
14177
+ return err(mergeError(x402Result.error, mppResult.error));
14178
+ if (x402Result.isErr()) return err(x402Result.error);
14179
+ if (mppResult.isErr()) return err(mppResult.error);
14180
+ return ok(null);
14181
+ })
14182
+ );
14183
+ }
14184
+
14049
14185
  // src/core/layers/l2.ts
14050
14186
  function formatPrice(pricing) {
14051
14187
  if (pricing.pricingMode === "fixed") return `$${pricing.price}`;
@@ -14071,15 +14207,27 @@ function checkL2ForOpenAPI(openApi) {
14071
14207
  source: "openapi"
14072
14208
  };
14073
14209
  }
14210
+ var WELL_KNOWN_PROTOCOLS = {
14211
+ x402: ["x402"],
14212
+ mpp: ["mpp"],
14213
+ "x402+mpp": ["x402", "mpp"]
14214
+ };
14074
14215
  function checkL2ForWellknown(wellKnown) {
14216
+ const protocols = WELL_KNOWN_PROTOCOLS[wellKnown.protocol];
14075
14217
  const routes = wellKnown.routes.map((route) => ({
14076
14218
  path: route.path,
14077
14219
  method: route.method,
14078
14220
  summary: `${route.method} ${route.path}`,
14079
14221
  authMode: "paid",
14080
- protocols: ["x402"]
14222
+ protocols,
14223
+ ...route.price ? { price: route.price } : {}
14081
14224
  }));
14082
- return { routes, source: "well-known/x402" };
14225
+ return {
14226
+ ...wellKnown.title ? { title: wellKnown.title } : {},
14227
+ ...wellKnown.description ? { description: wellKnown.description } : {},
14228
+ routes,
14229
+ source: `well-known/${wellKnown.protocol}`
14230
+ };
14083
14231
  }
14084
14232
 
14085
14233
  // src/core/layers/l4.ts
@@ -14091,7 +14239,7 @@ function checkL4ForOpenAPI(openApi) {
14091
14239
  }
14092
14240
  function checkL4ForWellknown(wellKnown) {
14093
14241
  if (wellKnown.instructions) {
14094
- return { guidance: wellKnown.instructions, source: "well-known/x402" };
14242
+ return { guidance: wellKnown.instructions, source: `well-known/${wellKnown.protocol}` };
14095
14243
  }
14096
14244
  return null;
14097
14245
  }
@@ -14109,8 +14257,41 @@ var GuidanceMode = /* @__PURE__ */ ((GuidanceMode2) => {
14109
14257
  return GuidanceMode2;
14110
14258
  })(GuidanceMode || {});
14111
14259
 
14260
+ // src/core/types/sources.ts
14261
+ function isOpenApiSource(raw) {
14262
+ return raw !== null && !("parseFailure" in raw);
14263
+ }
14264
+
14112
14265
  // src/runtime/discover.ts
14113
14266
  var GUIDANCE_AUTO_INCLUDE_MAX_TOKENS_LENGTH = 1e3;
14267
+ function extractFromWellknown(raw) {
14268
+ if (Array.isArray(raw["ownershipProofs"])) {
14269
+ const proofs = raw["ownershipProofs"].filter(
14270
+ (p) => typeof p === "string"
14271
+ );
14272
+ if (proofs.length > 0) return proofs;
14273
+ }
14274
+ return void 0;
14275
+ }
14276
+ function extractFromOpenapi(raw) {
14277
+ const xDiscovery = raw["x-discovery"];
14278
+ if (xDiscovery && typeof xDiscovery === "object" && !Array.isArray(xDiscovery)) {
14279
+ const proofs = xDiscovery["ownershipProofs"];
14280
+ if (Array.isArray(proofs)) {
14281
+ const filtered = proofs.filter((p) => typeof p === "string");
14282
+ if (filtered.length > 0) return filtered;
14283
+ }
14284
+ }
14285
+ const legacy = raw["x-agentcash-provenance"];
14286
+ if (legacy && typeof legacy === "object" && !Array.isArray(legacy)) {
14287
+ const proofs = legacy["ownershipProofs"];
14288
+ if (Array.isArray(proofs)) {
14289
+ const filtered = proofs.filter((p) => typeof p === "string");
14290
+ if (filtered.length > 0) return filtered;
14291
+ }
14292
+ }
14293
+ return void 0;
14294
+ }
14114
14295
  function withGuidance(base, l4, guidanceMode) {
14115
14296
  if (guidanceMode === "never" /* Never */) return { ...base, guidanceAvailable: !!l4 };
14116
14297
  if (!l4) return { ...base, guidanceAvailable: false };
@@ -14129,10 +14310,12 @@ async function discoverOriginSchema(options) {
14129
14310
  options.signal,
14130
14311
  options.specificationOverrideUrl
14131
14312
  );
14132
- const openApi = openApiResult.isOk() ? openApiResult.value : null;
14313
+ const openApiRaw = openApiResult.isOk() ? openApiResult.value : null;
14314
+ const openApi = isOpenApiSource(openApiRaw) ? openApiRaw : null;
14133
14315
  if (openApi) {
14134
14316
  const l22 = checkL2ForOpenAPI(openApi);
14135
14317
  const l42 = checkL4ForOpenAPI(openApi);
14318
+ const ownershipProofs2 = extractFromOpenapi(openApi.raw);
14136
14319
  const base2 = {
14137
14320
  found: true,
14138
14321
  origin,
@@ -14144,7 +14327,8 @@ async function discoverOriginSchema(options) {
14144
14327
  ...l22.version ? { version: l22.version } : {}
14145
14328
  }
14146
14329
  } : {},
14147
- endpoints: l22.routes
14330
+ endpoints: l22.routes,
14331
+ ...ownershipProofs2 ? { ownershipProofs: ownershipProofs2 } : {}
14148
14332
  };
14149
14333
  return withGuidance(base2, l42, guidanceMode);
14150
14334
  }
@@ -14161,17 +14345,25 @@ async function discoverOriginSchema(options) {
14161
14345
  if (!wellKnown) return { found: false, origin, cause: "not_found" };
14162
14346
  const l2 = checkL2ForWellknown(wellKnown);
14163
14347
  const l4 = checkL4ForWellknown(wellKnown);
14348
+ const ownershipProofs = extractFromWellknown(wellKnown.raw);
14164
14349
  const base = {
14165
14350
  found: true,
14166
14351
  origin,
14167
- source: "well-known/x402",
14168
- endpoints: l2.routes
14352
+ source: l2.source,
14353
+ ...l2.title ? {
14354
+ info: {
14355
+ title: l2.title,
14356
+ ...l2.description ? { description: l2.description } : {}
14357
+ }
14358
+ } : {},
14359
+ endpoints: l2.routes,
14360
+ ...ownershipProofs ? { ownershipProofs } : {}
14169
14361
  };
14170
14362
  return withGuidance(base, l4, guidanceMode);
14171
14363
  }
14172
14364
 
14173
14365
  // src/core/source/probe/index.ts
14174
- import { ResultAsync as ResultAsync4 } from "neverthrow";
14366
+ import { ResultAsync as ResultAsync6 } from "neverthrow";
14175
14367
 
14176
14368
  // src/core/protocols/x402/v1/schema.ts
14177
14369
  function extractSchemas(accepts) {
@@ -14621,8 +14813,8 @@ function probeMethod(url2, method, path, headers, signal, inputBody) {
14621
14813
  ...hasBody ? { body: JSON.stringify(inputBody) } : {},
14622
14814
  signal
14623
14815
  }).andThen((response) => {
14624
- if (!isUsableStatus(response.status)) return ResultAsync4.fromSafePromise(Promise.resolve(null));
14625
- return ResultAsync4.fromSafePromise(
14816
+ if (!isUsableStatus(response.status)) return ResultAsync6.fromSafePromise(Promise.resolve(null));
14817
+ return ResultAsync6.fromSafePromise(
14626
14818
  (async () => {
14627
14819
  let authHint = response.status === 402 ? "paid" : "unprotected";
14628
14820
  let paymentRequiredBody;
@@ -14653,7 +14845,7 @@ function probeMethod(url2, method, path, headers, signal, inputBody) {
14653
14845
  }
14654
14846
  function getProbe(url2, headers, signal, inputBody) {
14655
14847
  const path = normalizePath(new URL(url2).pathname || "/");
14656
- return ResultAsync4.fromSafePromise(
14848
+ return ResultAsync6.fromSafePromise(
14657
14849
  Promise.all(
14658
14850
  [...HTTP_METHODS].map(
14659
14851
  (method) => probeMethod(url2, method, path, headers, signal, inputBody).match(
@@ -14666,6 +14858,20 @@ function getProbe(url2, headers, signal, inputBody) {
14666
14858
  }
14667
14859
 
14668
14860
  // src/core/protocols/mpp/index.ts
14861
+ import { Result } from "neverthrow";
14862
+ function parseBase64Json(encoded) {
14863
+ return Result.fromThrowable(
14864
+ () => {
14865
+ const decoded = typeof Buffer !== "undefined" ? Buffer.from(encoded, "base64").toString("utf8") : atob(encoded);
14866
+ const parsed = JSON.parse(decoded);
14867
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
14868
+ throw new Error("not an object");
14869
+ }
14870
+ return parsed;
14871
+ },
14872
+ (e) => e
14873
+ )();
14874
+ }
14669
14875
  var TEMPO_DEFAULT_CHAIN_ID = 4217;
14670
14876
  function parseAuthParams(segment) {
14671
14877
  const params = {};
@@ -14688,14 +14894,9 @@ function extractPaymentOptions4(wwwAuthenticate) {
14688
14894
  const description = params["description"];
14689
14895
  const requestStr = params["request"];
14690
14896
  if (!paymentMethod || !intent || !realm || !requestStr) continue;
14691
- let request;
14692
- try {
14693
- const parsed = JSON.parse(requestStr);
14694
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
14695
- request = parsed;
14696
- } catch {
14697
- continue;
14698
- }
14897
+ const requestResult = parseBase64Json(requestStr);
14898
+ if (requestResult.isErr()) continue;
14899
+ const request = requestResult.value;
14699
14900
  const asset = typeof request["currency"] === "string" ? request["currency"] : void 0;
14700
14901
  const amountRaw = request["amount"];
14701
14902
  const amount = typeof amountRaw === "string" ? amountRaw : typeof amountRaw === "number" ? String(amountRaw) : void 0;
@@ -14934,7 +15135,8 @@ async function checkEndpointSchema(options) {
14934
15135
  return { found: false, origin, path, cause: "not_found" };
14935
15136
  }
14936
15137
  const openApiResult = await getOpenAPI(origin, options.headers, options.signal);
14937
- const openApi = openApiResult.isOk() ? openApiResult.value : null;
15138
+ const openApiRaw = openApiResult.isOk() ? openApiResult.value : null;
15139
+ const openApi = isOpenApiSource(openApiRaw) ? openApiRaw : null;
14938
15140
  if (openApi) {
14939
15141
  const advisories2 = getAdvisoriesForOpenAPI(openApi, path);
14940
15142
  if (advisories2.length > 0) return { found: true, origin, path, advisories: advisories2 };
@@ -15045,6 +15247,7 @@ var AUDIT_CODES = {
15045
15247
  OPENAPI_NOT_FOUND: "OPENAPI_NOT_FOUND",
15046
15248
  WELLKNOWN_NOT_FOUND: "WELLKNOWN_NOT_FOUND",
15047
15249
  // ─── OpenAPI quality ─────────────────────────────────────────────────────────
15250
+ OPENAPI_PARSE_ERROR: "OPENAPI_PARSE_ERROR",
15048
15251
  OPENAPI_NO_ROUTES: "OPENAPI_NO_ROUTES",
15049
15252
  // ─── L2 route-list checks ────────────────────────────────────────────────────
15050
15253
  L2_NO_ROUTES: "L2_NO_ROUTES",
@@ -15532,6 +15735,9 @@ function validatePaymentRequiredDetailed(payload, options = {}) {
15532
15735
  }
15533
15736
 
15534
15737
  // src/audit/warnings/sources.ts
15738
+ function isOpenApiParseFailure(value) {
15739
+ return value !== null && "parseFailure" in value;
15740
+ }
15535
15741
  function getWarningsForOpenAPI(openApi) {
15536
15742
  if (openApi === null) {
15537
15743
  return [
@@ -15543,6 +15749,18 @@ function getWarningsForOpenAPI(openApi) {
15543
15749
  }
15544
15750
  ];
15545
15751
  }
15752
+ if (isOpenApiParseFailure(openApi)) {
15753
+ const details = openApi.issues.map((i) => ` ${i.path.map(String).join(".")}: ${i.message}`).join("\n");
15754
+ return [
15755
+ {
15756
+ code: AUDIT_CODES.OPENAPI_PARSE_ERROR,
15757
+ severity: "warn",
15758
+ message: `OpenAPI spec found at ${openApi.fetchedUrl} but failed schema validation:
15759
+ ${details}`,
15760
+ hint: "Fix the schema issues above so discovery can read the spec."
15761
+ }
15762
+ ];
15763
+ }
15546
15764
  const warnings = [];
15547
15765
  if (openApi.routes.length === 0) {
15548
15766
  warnings.push({
@@ -15683,6 +15901,7 @@ export {
15683
15901
  getL3,
15684
15902
  getL3ForOpenAPI,
15685
15903
  getL3ForProbe,
15904
+ getMppWellKnown,
15686
15905
  getOpenAPI,
15687
15906
  getProbe,
15688
15907
  getWarningsFor402Body,
@@ -15693,5 +15912,7 @@ export {
15693
15912
  getWarningsForOpenAPI,
15694
15913
  getWarningsForWellKnown,
15695
15914
  getWellKnown,
15915
+ getX402WellKnown,
15916
+ isOpenApiParseFailure,
15696
15917
  validatePaymentRequiredDetailed
15697
15918
  };
package/dist/schemas.cjs CHANGED
@@ -13864,7 +13864,8 @@ var WellKnownParsedSchema = external_exports.object({
13864
13864
  routes: external_exports.array(
13865
13865
  external_exports.object({
13866
13866
  path: external_exports.string(),
13867
- method: external_exports.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE"])
13867
+ method: external_exports.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE"]),
13868
+ price: external_exports.string().optional()
13868
13869
  })
13869
13870
  ),
13870
13871
  instructions: external_exports.string().optional()
@@ -517,6 +517,7 @@ declare const WellKnownParsedSchema: z.ZodObject<{
517
517
  OPTIONS: "OPTIONS";
518
518
  TRACE: "TRACE";
519
519
  }>;
520
+ price: z.ZodOptional<z.ZodString>;
520
521
  }, z.core.$strip>>;
521
522
  instructions: z.ZodOptional<z.ZodString>;
522
523
  }, z.core.$strip>;
package/dist/schemas.d.ts CHANGED
@@ -517,6 +517,7 @@ declare const WellKnownParsedSchema: z.ZodObject<{
517
517
  OPTIONS: "OPTIONS";
518
518
  TRACE: "TRACE";
519
519
  }>;
520
+ price: z.ZodOptional<z.ZodString>;
520
521
  }, z.core.$strip>>;
521
522
  instructions: z.ZodOptional<z.ZodString>;
522
523
  }, z.core.$strip>;
package/dist/schemas.js CHANGED
@@ -13839,7 +13839,8 @@ var WellKnownParsedSchema = external_exports.object({
13839
13839
  routes: external_exports.array(
13840
13840
  external_exports.object({
13841
13841
  path: external_exports.string(),
13842
- method: external_exports.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE"])
13842
+ method: external_exports.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "TRACE"]),
13843
+ price: external_exports.string().optional()
13843
13844
  })
13844
13845
  ),
13845
13846
  instructions: external_exports.string().optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentcash/discovery",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Canonical OpenAPI-first discovery runtime for the agentcash ecosystem",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",