@agentcash/discovery 1.1.2 → 1.2.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.js CHANGED
@@ -13834,7 +13834,6 @@ var WellKnownDocSchema = external_exports.object({
13834
13834
  version: external_exports.number().optional(),
13835
13835
  resources: external_exports.array(external_exports.string()).default([]),
13836
13836
  mppResources: external_exports.array(external_exports.string()).optional(),
13837
- // isMmmEnabled
13838
13837
  description: external_exports.string().optional(),
13839
13838
  ownershipProofs: external_exports.array(external_exports.string()).optional(),
13840
13839
  instructions: external_exports.string().optional()
@@ -13944,9 +13943,6 @@ function fetchSafe(url2, init) {
13944
13943
  return ResultAsync.fromPromise(fetch(url2, init), toFetchError);
13945
13944
  }
13946
13945
 
13947
- // src/mmm-enabled.ts
13948
- var isMmmEnabled = () => "1.1.2".includes("-mmm");
13949
-
13950
13946
  // src/core/source/openapi/index.ts
13951
13947
  var OpenApiParsedSchema = OpenApiDocSchema.transform((doc) => {
13952
13948
  const routes = [];
@@ -13956,9 +13952,7 @@ var OpenApiParsedSchema = OpenApiDocSchema.transform((doc) => {
13956
13952
  if (!operation) continue;
13957
13953
  const authMode = inferAuthMode(operation, doc.security, doc.components?.securitySchemes) ?? void 0;
13958
13954
  const p = operation["x-payment-info"];
13959
- const protocols = (p?.protocols ?? []).filter(
13960
- (proto) => proto !== "mpp" || isMmmEnabled()
13961
- );
13955
+ const protocols = (p?.protocols ?? []).filter((proto) => proto.length > 0);
13962
13956
  const pricing = (authMode === "paid" || authMode === "apiKey+paid") && p ? {
13963
13957
  pricingMode: p.pricingMode,
13964
13958
  ...p.price ? { price: p.price } : {},
@@ -14072,6 +14066,7 @@ function checkL2ForOpenAPI(openApi) {
14072
14066
  return {
14073
14067
  ...openApi.info.title ? { title: openApi.info.title } : {},
14074
14068
  ...openApi.info.description ? { description: openApi.info.description } : {},
14069
+ ...openApi.info.version ? { version: openApi.info.version } : {},
14075
14070
  routes,
14076
14071
  source: "openapi"
14077
14072
  };
@@ -14142,7 +14137,13 @@ async function discoverOriginSchema(options) {
14142
14137
  found: true,
14143
14138
  origin,
14144
14139
  source: "openapi",
14145
- ...l22.title ? { info: { title: l22.title, ...l22.description ? { description: l22.description } : {} } } : {},
14140
+ ...l22.title ? {
14141
+ info: {
14142
+ title: l22.title,
14143
+ ...l22.description ? { description: l22.description } : {},
14144
+ ...l22.version ? { version: l22.version } : {}
14145
+ }
14146
+ } : {},
14146
14147
  endpoints: l22.routes
14147
14148
  };
14148
14149
  return withGuidance(base2, l42, guidanceMode);
@@ -14596,7 +14597,7 @@ function detectProtocols(response) {
14596
14597
  }
14597
14598
  const authHeader = response.headers.get("www-authenticate")?.toLowerCase() ?? "";
14598
14599
  if (authHeader.includes("x402")) protocols.add("x402");
14599
- if (isMmmEnabled() && authHeader.includes("mpp")) protocols.add("mpp");
14600
+ if (authHeader.includes("mpp")) protocols.add("mpp");
14600
14601
  return [...protocols];
14601
14602
  }
14602
14603
  function buildProbeUrl(url2, method, inputBody) {
@@ -14676,7 +14677,7 @@ function parseAuthParams(segment) {
14676
14677
  return params;
14677
14678
  }
14678
14679
  function extractPaymentOptions4(wwwAuthenticate) {
14679
- if (!isMmmEnabled() || !wwwAuthenticate) return [];
14680
+ if (!wwwAuthenticate) return [];
14680
14681
  const options = [];
14681
14682
  for (const segment of wwwAuthenticate.split(/,\s*(?=Payment\s)/i)) {
14682
14683
  const stripped = segment.replace(/^Payment\s+/i, "").trim();
@@ -14705,12 +14706,10 @@ function extractPaymentOptions4(wwwAuthenticate) {
14705
14706
  if (!asset || !amount) continue;
14706
14707
  options.push({
14707
14708
  protocol: "mpp",
14708
- // isMmmEnabled
14709
14709
  paymentMethod,
14710
14710
  intent,
14711
14711
  realm,
14712
14712
  network: `tempo:${String(chainId)}`,
14713
- // isMmmEnabled
14714
14713
  asset,
14715
14714
  amount,
14716
14715
  ...decimals != null ? { decimals } : {},
@@ -14838,7 +14837,7 @@ function parseOperationProtocols(operation) {
14838
14837
  const paymentInfo = operation["x-payment-info"];
14839
14838
  if (!isRecord(paymentInfo) || !Array.isArray(paymentInfo.protocols)) return void 0;
14840
14839
  const protocols = paymentInfo.protocols.filter(
14841
- (protocol) => typeof protocol === "string" && protocol.length > 0 && (protocol !== "mpp" || isMmmEnabled())
14840
+ (protocol) => typeof protocol === "string" && protocol.length > 0
14842
14841
  );
14843
14842
  return protocols.length > 0 ? protocols : void 0;
14844
14843
  }
@@ -14869,8 +14868,7 @@ function getL3ForProbe(probe, path, method) {
14869
14868
  const outputSchema = probeResult.paymentRequiredBody ? parseOutputSchema(probeResult.paymentRequiredBody) : void 0;
14870
14869
  const paymentOptions = [
14871
14870
  ...probeResult.paymentRequiredBody ? extractPaymentOptions3(probeResult.paymentRequiredBody) : [],
14872
- ...isMmmEnabled() ? extractPaymentOptions4(probeResult.wwwAuthenticate) : []
14873
- // isMmmEnabled
14871
+ ...extractPaymentOptions4(probeResult.wwwAuthenticate)
14874
14872
  ];
14875
14873
  return {
14876
14874
  source: "probe",
@@ -14879,7 +14877,8 @@ function getL3ForProbe(probe, path, method) {
14879
14877
  ...inputSchema ? { inputSchema } : {},
14880
14878
  ...outputSchema ? { outputSchema } : {},
14881
14879
  ...paymentOptions.length ? { paymentOptions } : {},
14882
- ...probeResult.paymentRequiredBody !== void 0 ? { paymentRequiredBody: probeResult.paymentRequiredBody } : {}
14880
+ ...probeResult.paymentRequiredBody !== void 0 ? { paymentRequiredBody: probeResult.paymentRequiredBody } : {},
14881
+ ...probeResult.wwwAuthenticate ? { wwwAuthenticate: probeResult.wwwAuthenticate } : {}
14883
14882
  };
14884
14883
  }
14885
14884
  async function attachProbePayload(url2, advisories) {
@@ -14914,7 +14913,7 @@ async function checkEndpointSchema(options) {
14914
14913
  const endpoint = new URL(ensureProtocol(options.url));
14915
14914
  const origin = normalizeOrigin(endpoint.origin);
14916
14915
  const path = normalizePath(endpoint.pathname || "/");
14917
- if (options.sampleInputBody !== void 0) {
14916
+ if (options.probe || options.sampleInputBody !== void 0) {
14918
14917
  const probeResult2 = await getProbe(
14919
14918
  endpoint.href,
14920
14919
  options.headers,
@@ -15060,9 +15059,23 @@ var AUDIT_CODES = {
15060
15059
  L3_INPUT_SCHEMA_MISSING: "L3_INPUT_SCHEMA_MISSING",
15061
15060
  L3_AUTH_MODE_MISSING: "L3_AUTH_MODE_MISSING",
15062
15061
  L3_PROTOCOLS_MISSING_ON_PAID: "L3_PROTOCOLS_MISSING_ON_PAID",
15062
+ L3_PAYMENT_OPTIONS_MISSING_ON_PAID: "L3_PAYMENT_OPTIONS_MISSING_ON_PAID",
15063
15063
  // ─── L4 guidance checks ──────────────────────────────────────────────────────
15064
15064
  L4_GUIDANCE_MISSING: "L4_GUIDANCE_MISSING",
15065
- L4_GUIDANCE_TOO_LONG: "L4_GUIDANCE_TOO_LONG"
15065
+ L4_GUIDANCE_TOO_LONG: "L4_GUIDANCE_TOO_LONG",
15066
+ // ─── MPP WWW-Authenticate header checks ──────────────────────────────────────
15067
+ MPP_HEADER_MISSING: "MPP_HEADER_MISSING",
15068
+ MPP_NO_PAYMENT_CHALLENGES: "MPP_NO_PAYMENT_CHALLENGES",
15069
+ MPP_CHALLENGE_ID_MISSING: "MPP_CHALLENGE_ID_MISSING",
15070
+ MPP_CHALLENGE_METHOD_MISSING: "MPP_CHALLENGE_METHOD_MISSING",
15071
+ MPP_CHALLENGE_INTENT_MISSING: "MPP_CHALLENGE_INTENT_MISSING",
15072
+ MPP_CHALLENGE_REALM_MISSING: "MPP_CHALLENGE_REALM_MISSING",
15073
+ MPP_CHALLENGE_EXPIRES_MISSING: "MPP_CHALLENGE_EXPIRES_MISSING",
15074
+ MPP_CHALLENGE_REQUEST_MISSING: "MPP_CHALLENGE_REQUEST_MISSING",
15075
+ MPP_CHALLENGE_REQUEST_INVALID: "MPP_CHALLENGE_REQUEST_INVALID",
15076
+ MPP_CHALLENGE_ASSET_MISSING: "MPP_CHALLENGE_ASSET_MISSING",
15077
+ MPP_CHALLENGE_AMOUNT_MISSING: "MPP_CHALLENGE_AMOUNT_MISSING",
15078
+ MPP_CHALLENGE_RECIPIENT_MISSING: "MPP_CHALLENGE_RECIPIENT_MISSING"
15066
15079
  };
15067
15080
 
15068
15081
  // src/core/protocols/x402/v1/coinbase-schema.ts
@@ -15151,6 +15164,157 @@ function validateWithCoinbaseSchema2(body) {
15151
15164
  });
15152
15165
  }
15153
15166
 
15167
+ // src/audit/warnings/mpp.ts
15168
+ function parseAuthParams2(segment) {
15169
+ const params = {};
15170
+ const re = /(\w+)=(?:"([^"]*)"|'([^']*)')/g;
15171
+ let match;
15172
+ while ((match = re.exec(segment)) !== null) {
15173
+ params[match[1]] = match[2] ?? match[3] ?? "";
15174
+ }
15175
+ return params;
15176
+ }
15177
+ function getWarningsForMppHeader(wwwAuthenticate) {
15178
+ if (!wwwAuthenticate?.trim()) {
15179
+ return [
15180
+ {
15181
+ code: AUDIT_CODES.MPP_HEADER_MISSING,
15182
+ severity: "error",
15183
+ message: "WWW-Authenticate header is absent.",
15184
+ hint: "MPP endpoints must respond to unauthenticated requests with a 402 and a WWW-Authenticate: Payment ... header."
15185
+ }
15186
+ ];
15187
+ }
15188
+ const segments = wwwAuthenticate.split(/,\s*(?=Payment\s)/i).filter((s) => /^Payment\s/i.test(s.trim()));
15189
+ if (segments.length === 0) {
15190
+ return [
15191
+ {
15192
+ code: AUDIT_CODES.MPP_NO_PAYMENT_CHALLENGES,
15193
+ severity: "error",
15194
+ message: "WWW-Authenticate header contains no Payment challenges.",
15195
+ hint: `Add at least one Payment challenge: WWW-Authenticate: Payment method="tempo" intent="charge" realm="..." request='...'`
15196
+ }
15197
+ ];
15198
+ }
15199
+ const warnings = [];
15200
+ for (let i = 0; i < segments.length; i++) {
15201
+ const stripped = segments[i].replace(/^Payment\s+/i, "").trim();
15202
+ const params = parseAuthParams2(stripped);
15203
+ const idx = `WWW-Authenticate[${i}]`;
15204
+ if (!params["id"]) {
15205
+ warnings.push({
15206
+ code: AUDIT_CODES.MPP_CHALLENGE_ID_MISSING,
15207
+ severity: "error",
15208
+ message: `Payment challenge ${i} is missing the id parameter.`,
15209
+ hint: "Set id to a unique challenge identifier so clients can correlate credentials to challenges.",
15210
+ path: `${idx}.id`
15211
+ });
15212
+ }
15213
+ if (!params["method"]) {
15214
+ warnings.push({
15215
+ code: AUDIT_CODES.MPP_CHALLENGE_METHOD_MISSING,
15216
+ severity: "error",
15217
+ message: `Payment challenge ${i} is missing the method parameter.`,
15218
+ hint: 'Set method="tempo" (or your payment method identifier) on the Payment challenge.',
15219
+ path: `${idx}.method`
15220
+ });
15221
+ }
15222
+ if (!params["intent"]) {
15223
+ warnings.push({
15224
+ code: AUDIT_CODES.MPP_CHALLENGE_INTENT_MISSING,
15225
+ severity: "error",
15226
+ message: `Payment challenge ${i} is missing the intent parameter.`,
15227
+ hint: 'Set intent="charge" on the Payment challenge.',
15228
+ path: `${idx}.intent`
15229
+ });
15230
+ }
15231
+ if (!params["realm"]) {
15232
+ warnings.push({
15233
+ code: AUDIT_CODES.MPP_CHALLENGE_REALM_MISSING,
15234
+ severity: "error",
15235
+ message: `Payment challenge ${i} is missing the realm parameter.`,
15236
+ hint: "Set realm to a stable server identifier so clients can associate payment credentials.",
15237
+ path: `${idx}.realm`
15238
+ });
15239
+ }
15240
+ if (!params["expires"]) {
15241
+ warnings.push({
15242
+ code: AUDIT_CODES.MPP_CHALLENGE_EXPIRES_MISSING,
15243
+ severity: "error",
15244
+ message: `Payment challenge ${i} is missing the expires parameter.`,
15245
+ hint: "Set expires to an RFC 3339 timestamp so clients know when the challenge lapses.",
15246
+ path: `${idx}.expires`
15247
+ });
15248
+ }
15249
+ const requestStr = params["request"];
15250
+ if (!requestStr) {
15251
+ warnings.push({
15252
+ code: AUDIT_CODES.MPP_CHALLENGE_REQUEST_MISSING,
15253
+ severity: "error",
15254
+ message: `Payment challenge ${i} is missing the request field.`,
15255
+ hint: `Include a base64url-encoded JSON request field: request=base64url('{"currency":"...","amount":"...","recipient":"..."}')`,
15256
+ path: `${idx}.request`
15257
+ });
15258
+ continue;
15259
+ }
15260
+ let request;
15261
+ try {
15262
+ const decoded = Buffer.from(requestStr, "base64url").toString("utf-8");
15263
+ const parsed = JSON.parse(decoded);
15264
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
15265
+ throw new Error("not an object");
15266
+ }
15267
+ request = parsed;
15268
+ } catch {
15269
+ warnings.push({
15270
+ code: AUDIT_CODES.MPP_CHALLENGE_REQUEST_INVALID,
15271
+ severity: "error",
15272
+ message: `Payment challenge ${i} request field is not valid base64url-encoded JSON.`,
15273
+ hint: "The request value must be a base64url-encoded JCS JSON object.",
15274
+ path: `${idx}.request`
15275
+ });
15276
+ continue;
15277
+ }
15278
+ if (!request["currency"]) {
15279
+ warnings.push({
15280
+ code: AUDIT_CODES.MPP_CHALLENGE_ASSET_MISSING,
15281
+ severity: "error",
15282
+ message: `Payment challenge ${i} is missing currency in the request object.`,
15283
+ hint: "Set currency to a TIP-20 token address (e.g. a USDC contract).",
15284
+ path: `${idx}.request.currency`
15285
+ });
15286
+ }
15287
+ const amount = request["amount"];
15288
+ if (amount === void 0 || amount === null) {
15289
+ warnings.push({
15290
+ code: AUDIT_CODES.MPP_CHALLENGE_AMOUNT_MISSING,
15291
+ severity: "error",
15292
+ message: `Payment challenge ${i} is missing amount in the request object.`,
15293
+ hint: 'Set amount to a raw token-unit string (e.g. "1000000" for 1 USDC with 6 decimals).',
15294
+ path: `${idx}.request.amount`
15295
+ });
15296
+ } else if (typeof amount !== "string" && typeof amount !== "number") {
15297
+ warnings.push({
15298
+ code: AUDIT_CODES.MPP_CHALLENGE_AMOUNT_MISSING,
15299
+ severity: "error",
15300
+ message: `Payment challenge ${i} has an invalid amount type (got ${typeof amount}, expected string or number).`,
15301
+ hint: "Set amount to a raw token-unit string.",
15302
+ path: `${idx}.request.amount`
15303
+ });
15304
+ }
15305
+ if (!request["recipient"]) {
15306
+ warnings.push({
15307
+ code: AUDIT_CODES.MPP_CHALLENGE_RECIPIENT_MISSING,
15308
+ severity: "error",
15309
+ message: `Payment challenge ${i} is missing recipient in the request object.`,
15310
+ hint: "Set recipient to the wallet address that should receive payment.",
15311
+ path: `${idx}.request.recipient`
15312
+ });
15313
+ }
15314
+ }
15315
+ return warnings;
15316
+ }
15317
+
15154
15318
  // src/audit/warnings/l3.ts
15155
15319
  function getWarningsFor402Body(body) {
15156
15320
  if (!isRecord(body)) {
@@ -15280,17 +15444,28 @@ function getWarningsForL3(l3) {
15280
15444
  hint: "Add a requestBody or parameters schema so agents can construct valid payloads."
15281
15445
  });
15282
15446
  }
15283
- if (l3.authMode === "paid" && !l3.protocols?.length) {
15447
+ if (l3.authMode === "paid" && l3.source === "openapi" && !l3.protocols?.length) {
15284
15448
  warnings.push({
15285
15449
  code: AUDIT_CODES.L3_PROTOCOLS_MISSING_ON_PAID,
15286
15450
  severity: "info",
15287
15451
  message: "Paid endpoint does not declare supported payment protocols.",
15288
- hint: "Add x-payment-info.protocols (e.g. ['x402']) to the operation."
15452
+ hint: "Add x-payment-info.protocols (e.g. ['x402', 'mpp']) to the operation."
15453
+ });
15454
+ }
15455
+ if (l3.authMode === "paid" && l3.source === "probe" && !l3.paymentOptions?.length) {
15456
+ warnings.push({
15457
+ code: AUDIT_CODES.L3_PAYMENT_OPTIONS_MISSING_ON_PAID,
15458
+ severity: "warn",
15459
+ message: "Paid endpoint did not return payment options in the 402 response.",
15460
+ hint: "Ensure the 402 response returns a valid payment challenge so clients know how to pay."
15289
15461
  });
15290
15462
  }
15291
15463
  if (l3.paymentRequiredBody !== void 0) {
15292
15464
  warnings.push(...getWarningsFor402Body(l3.paymentRequiredBody));
15293
15465
  }
15466
+ if (l3.wwwAuthenticate !== void 0) {
15467
+ warnings.push(...getWarningsForMppHeader(l3.wwwAuthenticate));
15468
+ }
15294
15469
  return warnings;
15295
15470
  }
15296
15471
 
@@ -15514,6 +15689,7 @@ export {
15514
15689
  getWarningsForL2,
15515
15690
  getWarningsForL3,
15516
15691
  getWarningsForL4,
15692
+ getWarningsForMppHeader,
15517
15693
  getWarningsForOpenAPI,
15518
15694
  getWarningsForWellKnown,
15519
15695
  getWellKnown,
package/dist/schemas.cjs CHANGED
@@ -13856,7 +13856,6 @@ var WellKnownDocSchema = external_exports.object({
13856
13856
  version: external_exports.number().optional(),
13857
13857
  resources: external_exports.array(external_exports.string()).default([]),
13858
13858
  mppResources: external_exports.array(external_exports.string()).optional(),
13859
- // isMmmEnabled
13860
13859
  description: external_exports.string().optional(),
13861
13860
  ownershipProofs: external_exports.array(external_exports.string()).optional(),
13862
13861
  instructions: external_exports.string().optional()
package/dist/schemas.js CHANGED
@@ -13831,7 +13831,6 @@ var WellKnownDocSchema = external_exports.object({
13831
13831
  version: external_exports.number().optional(),
13832
13832
  resources: external_exports.array(external_exports.string()).default([]),
13833
13833
  mppResources: external_exports.array(external_exports.string()).optional(),
13834
- // isMmmEnabled
13835
13834
  description: external_exports.string().optional(),
13836
13835
  ownershipProofs: external_exports.array(external_exports.string()).optional(),
13837
13836
  instructions: external_exports.string().optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentcash/discovery",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Canonical OpenAPI-first discovery runtime for the agentcash ecosystem",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",