@agentcash/discovery 0.1.2 → 0.1.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/README.md CHANGED
@@ -75,6 +75,7 @@ import {
75
75
  auditContextHarness,
76
76
  discover,
77
77
  discoverDetailed,
78
+ validatePaymentRequiredDetailed,
78
79
  type HarnessClientId,
79
80
  } from '@agentcash/discovery';
80
81
 
@@ -96,6 +97,16 @@ const harness = await auditContextHarness({
96
97
  contextWindowTokens: 200000,
97
98
  compatMode: 'on',
98
99
  });
100
+
101
+ const validation = validatePaymentRequiredDetailed(payload, {
102
+ compatMode: 'strict',
103
+ metadata: {
104
+ title: 'Example API',
105
+ description: 'Sample description',
106
+ favicon: 'https://example.com/favicon.ico',
107
+ ogImages: [{ url: 'https://example.com/og.png' }],
108
+ },
109
+ });
99
110
  ```
100
111
 
101
112
  ## MCP Adapter Contract
@@ -144,6 +155,11 @@ Behavior:
144
155
  - `discover(...)` stops at first valid non-empty stage.
145
156
  - `discoverDetailed(...)` runs full waterfall and merges deterministically.
146
157
 
158
+ Validation behavior:
159
+
160
+ - `validatePaymentRequiredDetailed(...)` uses Coinbase `@x402/core` schemas as the structural base gate.
161
+ - Product policy diagnostics (network/schema/metadata) are layered on top with stable issue codes.
162
+
147
163
  ## Compatibility Modes
148
164
 
149
165
  - `on` (default): legacy adapters enabled.
@@ -195,3 +211,7 @@ Output:
195
211
  ## Deeper Docs
196
212
 
197
213
  Architecture and planning artifacts live in `.claude/`.
214
+
215
+ Validation design doc:
216
+
217
+ - `docs/VALIDATION_DIAGNOSTICS_DESIGN_2026-03-03.md`
package/dist/cli.cjs CHANGED
@@ -330,7 +330,7 @@ function actionItems(run, options) {
330
330
  ];
331
331
  }
332
332
  return [
333
- "Publish canonical OpenAPI discovery metadata with x-agentcash extensions",
333
+ "Publish canonical OpenAPI discovery metadata with x-payment-info and security schemes",
334
334
  `Validate migration path: npx @agentcash/discovery ${target} --compat strict -v --probe`,
335
335
  "Keep legacy well-known path only during sunset window"
336
336
  ];
@@ -637,7 +637,7 @@ function renderJson(run, options) {
637
637
  }
638
638
 
639
639
  // src/mmm-enabled.ts
640
- var isMmmEnabled = () => "0.1.2".includes("-mmm");
640
+ var isMmmEnabled = () => "0.1.4".includes("-mmm");
641
641
 
642
642
  // src/core/constants.ts
643
643
  var OPENAPI_PATH_CANDIDATES = ["/openapi.json", "/.well-known/openapi.json"];
@@ -807,7 +807,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
807
807
  "Using /.well-known/x402.instructions as compatibility guidance fallback. Prefer llms.txt.",
808
808
  {
809
809
  stage: "well-known/x402",
810
- hint: "Move guidance to llms.txt and reference via x-agentcash-guidance.llmsTxtUrl."
810
+ hint: "Move guidance to llms.txt and reference via x-discovery.llmsTxtUrl in OpenAPI."
811
811
  }
812
812
  )
813
813
  );
@@ -820,7 +820,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
820
820
  "Using /.well-known/x402.ownershipProofs compatibility field. Prefer OpenAPI provenance extension.",
821
821
  {
822
822
  stage: "well-known/x402",
823
- hint: "Move ownership proofs to x-agentcash-provenance.ownershipProofs in OpenAPI."
823
+ hint: "Move ownership proofs to x-discovery.ownershipProofs in OpenAPI."
824
824
  }
825
825
  )
826
826
  );
@@ -1216,10 +1216,31 @@ function estimateTokenCount(text) {
1216
1216
  return Math.ceil(text.length / 4);
1217
1217
  }
1218
1218
 
1219
- // src/core/openapi.ts
1219
+ // src/core/openapi-utils.ts
1220
1220
  function isRecord3(value) {
1221
1221
  return value !== null && typeof value === "object" && !Array.isArray(value);
1222
1222
  }
1223
+ function hasSecurity(operation, scheme) {
1224
+ const security = operation.security;
1225
+ return Array.isArray(security) && security.some((s) => isRecord3(s) && scheme in s);
1226
+ }
1227
+ function has402Response(operation) {
1228
+ const responses = operation.responses;
1229
+ if (!isRecord3(responses)) return false;
1230
+ return Boolean(responses["402"]);
1231
+ }
1232
+ function inferAuthMode(operation) {
1233
+ if (isRecord3(operation["x-payment-info"])) return "paid";
1234
+ if (has402Response(operation)) {
1235
+ if (hasSecurity(operation, "siwx")) return "siwx";
1236
+ return "paid";
1237
+ }
1238
+ if (hasSecurity(operation, "apiKey")) return "apiKey";
1239
+ if (hasSecurity(operation, "siwx")) return "siwx";
1240
+ return void 0;
1241
+ }
1242
+
1243
+ // src/core/openapi.ts
1223
1244
  function asString(value) {
1224
1245
  return typeof value === "string" && value.length > 0 ? value : void 0;
1225
1246
  }
@@ -1228,11 +1249,6 @@ function parsePriceValue(value) {
1228
1249
  if (typeof value === "number" && Number.isFinite(value)) return String(value);
1229
1250
  return void 0;
1230
1251
  }
1231
- function require402Response(operation) {
1232
- const responses = operation.responses;
1233
- if (!isRecord3(responses)) return false;
1234
- return Boolean(responses["402"]);
1235
- }
1236
1252
  function parseProtocols(paymentInfo) {
1237
1253
  const protocols = paymentInfo.protocols;
1238
1254
  if (!Array.isArray(protocols)) return [];
@@ -1240,15 +1256,6 @@ function parseProtocols(paymentInfo) {
1240
1256
  (entry) => typeof entry === "string" && entry.length > 0
1241
1257
  );
1242
1258
  }
1243
- function parseAuthMode(operation) {
1244
- const auth = operation["x-agentcash-auth"];
1245
- if (!isRecord3(auth)) return void 0;
1246
- const mode = auth.mode;
1247
- if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
1248
- return mode;
1249
- }
1250
- return void 0;
1251
- }
1252
1259
  async function runOpenApiStage(options) {
1253
1260
  const warnings = [];
1254
1261
  const resources = [];
@@ -1320,10 +1327,9 @@ async function runOpenApiStage(options) {
1320
1327
  };
1321
1328
  }
1322
1329
  const paths = document.paths;
1323
- const provenance = isRecord3(document["x-agentcash-provenance"]) ? document["x-agentcash-provenance"] : void 0;
1324
- const ownershipProofs = Array.isArray(provenance?.ownershipProofs) ? provenance.ownershipProofs.filter((entry) => typeof entry === "string") : [];
1325
- const guidance = isRecord3(document["x-agentcash-guidance"]) ? document["x-agentcash-guidance"] : void 0;
1326
- const llmsTxtUrl = asString(guidance?.llmsTxtUrl);
1330
+ const discovery = isRecord3(document["x-discovery"]) ? document["x-discovery"] : void 0;
1331
+ const ownershipProofs = Array.isArray(discovery?.ownershipProofs) ? discovery.ownershipProofs.filter((entry) => typeof entry === "string") : [];
1332
+ const llmsTxtUrl = asString(discovery?.llmsTxtUrl);
1327
1333
  if (ownershipProofs.length > 0) {
1328
1334
  warnings.push(
1329
1335
  warning("OPENAPI_OWNERSHIP_PROOFS_PRESENT", "info", "OpenAPI ownership proofs detected", {
@@ -1368,13 +1374,13 @@ async function runOpenApiStage(options) {
1368
1374
  )
1369
1375
  );
1370
1376
  }
1371
- const authMode = parseAuthMode(operation);
1377
+ const authMode = inferAuthMode(operation);
1372
1378
  if (!authMode) {
1373
1379
  warnings.push(
1374
1380
  warning(
1375
1381
  "OPENAPI_AUTH_MODE_MISSING",
1376
1382
  "error",
1377
- `${method} ${rawPath} missing x-agentcash-auth.mode`,
1383
+ `${method} ${rawPath} missing auth mode (no x-payment-info, 402 response, or security scheme)`,
1378
1384
  {
1379
1385
  stage: "openapi"
1380
1386
  }
@@ -1382,7 +1388,7 @@ async function runOpenApiStage(options) {
1382
1388
  );
1383
1389
  continue;
1384
1390
  }
1385
- if ((authMode === "paid" || authMode === "siwx") && !require402Response(operation)) {
1391
+ if ((authMode === "paid" || authMode === "siwx") && !has402Response(operation)) {
1386
1392
  warnings.push(
1387
1393
  warning(
1388
1394
  "OPENAPI_402_MISSING",
@@ -1961,11 +1967,6 @@ async function runDiscovery({
1961
1967
  }
1962
1968
  }
1963
1969
  }
1964
- if (!stageResult.valid) {
1965
- continue;
1966
- }
1967
- const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
1968
- warnings.push(...mergeWarnings);
1969
1970
  if (includeRaw && stageResult.raw !== void 0) {
1970
1971
  if (stageResult.stage === "openapi" || stageResult.stage === "override") {
1971
1972
  const rawObject = stageResult.raw;
@@ -1985,6 +1986,11 @@ async function runDiscovery({
1985
1986
  rawSources.interopMpp = stageResult.raw;
1986
1987
  }
1987
1988
  }
1989
+ if (!stageResult.valid) {
1990
+ continue;
1991
+ }
1992
+ const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
1993
+ warnings.push(...mergeWarnings);
1988
1994
  if (!detailed) {
1989
1995
  selectedStage = selectedStage ?? stageResult.stage;
1990
1996
  break;
@@ -2025,6 +2031,9 @@ async function runDiscovery({
2025
2031
  };
2026
2032
  }
2027
2033
 
2034
+ // src/validation/payment-required.ts
2035
+ var import_schemas = require("@x402/core/schemas");
2036
+
2028
2037
  // src/harness.ts
2029
2038
  var INTENT_TRIGGERS = ["x402", "mpp", "pay for", "micropayment", "agentic commerce"];
2030
2039
  var CLIENT_PROFILES = {
package/dist/cli.js CHANGED
@@ -304,7 +304,7 @@ function actionItems(run, options) {
304
304
  ];
305
305
  }
306
306
  return [
307
- "Publish canonical OpenAPI discovery metadata with x-agentcash extensions",
307
+ "Publish canonical OpenAPI discovery metadata with x-payment-info and security schemes",
308
308
  `Validate migration path: npx @agentcash/discovery ${target} --compat strict -v --probe`,
309
309
  "Keep legacy well-known path only during sunset window"
310
310
  ];
@@ -611,7 +611,7 @@ function renderJson(run, options) {
611
611
  }
612
612
 
613
613
  // src/mmm-enabled.ts
614
- var isMmmEnabled = () => "0.1.2".includes("-mmm");
614
+ var isMmmEnabled = () => "0.1.4".includes("-mmm");
615
615
 
616
616
  // src/core/constants.ts
617
617
  var OPENAPI_PATH_CANDIDATES = ["/openapi.json", "/.well-known/openapi.json"];
@@ -781,7 +781,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
781
781
  "Using /.well-known/x402.instructions as compatibility guidance fallback. Prefer llms.txt.",
782
782
  {
783
783
  stage: "well-known/x402",
784
- hint: "Move guidance to llms.txt and reference via x-agentcash-guidance.llmsTxtUrl."
784
+ hint: "Move guidance to llms.txt and reference via x-discovery.llmsTxtUrl in OpenAPI."
785
785
  }
786
786
  )
787
787
  );
@@ -794,7 +794,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
794
794
  "Using /.well-known/x402.ownershipProofs compatibility field. Prefer OpenAPI provenance extension.",
795
795
  {
796
796
  stage: "well-known/x402",
797
- hint: "Move ownership proofs to x-agentcash-provenance.ownershipProofs in OpenAPI."
797
+ hint: "Move ownership proofs to x-discovery.ownershipProofs in OpenAPI."
798
798
  }
799
799
  )
800
800
  );
@@ -1190,10 +1190,31 @@ function estimateTokenCount(text) {
1190
1190
  return Math.ceil(text.length / 4);
1191
1191
  }
1192
1192
 
1193
- // src/core/openapi.ts
1193
+ // src/core/openapi-utils.ts
1194
1194
  function isRecord3(value) {
1195
1195
  return value !== null && typeof value === "object" && !Array.isArray(value);
1196
1196
  }
1197
+ function hasSecurity(operation, scheme) {
1198
+ const security = operation.security;
1199
+ return Array.isArray(security) && security.some((s) => isRecord3(s) && scheme in s);
1200
+ }
1201
+ function has402Response(operation) {
1202
+ const responses = operation.responses;
1203
+ if (!isRecord3(responses)) return false;
1204
+ return Boolean(responses["402"]);
1205
+ }
1206
+ function inferAuthMode(operation) {
1207
+ if (isRecord3(operation["x-payment-info"])) return "paid";
1208
+ if (has402Response(operation)) {
1209
+ if (hasSecurity(operation, "siwx")) return "siwx";
1210
+ return "paid";
1211
+ }
1212
+ if (hasSecurity(operation, "apiKey")) return "apiKey";
1213
+ if (hasSecurity(operation, "siwx")) return "siwx";
1214
+ return void 0;
1215
+ }
1216
+
1217
+ // src/core/openapi.ts
1197
1218
  function asString(value) {
1198
1219
  return typeof value === "string" && value.length > 0 ? value : void 0;
1199
1220
  }
@@ -1202,11 +1223,6 @@ function parsePriceValue(value) {
1202
1223
  if (typeof value === "number" && Number.isFinite(value)) return String(value);
1203
1224
  return void 0;
1204
1225
  }
1205
- function require402Response(operation) {
1206
- const responses = operation.responses;
1207
- if (!isRecord3(responses)) return false;
1208
- return Boolean(responses["402"]);
1209
- }
1210
1226
  function parseProtocols(paymentInfo) {
1211
1227
  const protocols = paymentInfo.protocols;
1212
1228
  if (!Array.isArray(protocols)) return [];
@@ -1214,15 +1230,6 @@ function parseProtocols(paymentInfo) {
1214
1230
  (entry) => typeof entry === "string" && entry.length > 0
1215
1231
  );
1216
1232
  }
1217
- function parseAuthMode(operation) {
1218
- const auth = operation["x-agentcash-auth"];
1219
- if (!isRecord3(auth)) return void 0;
1220
- const mode = auth.mode;
1221
- if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
1222
- return mode;
1223
- }
1224
- return void 0;
1225
- }
1226
1233
  async function runOpenApiStage(options) {
1227
1234
  const warnings = [];
1228
1235
  const resources = [];
@@ -1294,10 +1301,9 @@ async function runOpenApiStage(options) {
1294
1301
  };
1295
1302
  }
1296
1303
  const paths = document.paths;
1297
- const provenance = isRecord3(document["x-agentcash-provenance"]) ? document["x-agentcash-provenance"] : void 0;
1298
- const ownershipProofs = Array.isArray(provenance?.ownershipProofs) ? provenance.ownershipProofs.filter((entry) => typeof entry === "string") : [];
1299
- const guidance = isRecord3(document["x-agentcash-guidance"]) ? document["x-agentcash-guidance"] : void 0;
1300
- const llmsTxtUrl = asString(guidance?.llmsTxtUrl);
1304
+ const discovery = isRecord3(document["x-discovery"]) ? document["x-discovery"] : void 0;
1305
+ const ownershipProofs = Array.isArray(discovery?.ownershipProofs) ? discovery.ownershipProofs.filter((entry) => typeof entry === "string") : [];
1306
+ const llmsTxtUrl = asString(discovery?.llmsTxtUrl);
1301
1307
  if (ownershipProofs.length > 0) {
1302
1308
  warnings.push(
1303
1309
  warning("OPENAPI_OWNERSHIP_PROOFS_PRESENT", "info", "OpenAPI ownership proofs detected", {
@@ -1342,13 +1348,13 @@ async function runOpenApiStage(options) {
1342
1348
  )
1343
1349
  );
1344
1350
  }
1345
- const authMode = parseAuthMode(operation);
1351
+ const authMode = inferAuthMode(operation);
1346
1352
  if (!authMode) {
1347
1353
  warnings.push(
1348
1354
  warning(
1349
1355
  "OPENAPI_AUTH_MODE_MISSING",
1350
1356
  "error",
1351
- `${method} ${rawPath} missing x-agentcash-auth.mode`,
1357
+ `${method} ${rawPath} missing auth mode (no x-payment-info, 402 response, or security scheme)`,
1352
1358
  {
1353
1359
  stage: "openapi"
1354
1360
  }
@@ -1356,7 +1362,7 @@ async function runOpenApiStage(options) {
1356
1362
  );
1357
1363
  continue;
1358
1364
  }
1359
- if ((authMode === "paid" || authMode === "siwx") && !require402Response(operation)) {
1365
+ if ((authMode === "paid" || authMode === "siwx") && !has402Response(operation)) {
1360
1366
  warnings.push(
1361
1367
  warning(
1362
1368
  "OPENAPI_402_MISSING",
@@ -1935,11 +1941,6 @@ async function runDiscovery({
1935
1941
  }
1936
1942
  }
1937
1943
  }
1938
- if (!stageResult.valid) {
1939
- continue;
1940
- }
1941
- const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
1942
- warnings.push(...mergeWarnings);
1943
1944
  if (includeRaw && stageResult.raw !== void 0) {
1944
1945
  if (stageResult.stage === "openapi" || stageResult.stage === "override") {
1945
1946
  const rawObject = stageResult.raw;
@@ -1959,6 +1960,11 @@ async function runDiscovery({
1959
1960
  rawSources.interopMpp = stageResult.raw;
1960
1961
  }
1961
1962
  }
1963
+ if (!stageResult.valid) {
1964
+ continue;
1965
+ }
1966
+ const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
1967
+ warnings.push(...mergeWarnings);
1962
1968
  if (!detailed) {
1963
1969
  selectedStage = selectedStage ?? stageResult.stage;
1964
1970
  break;
@@ -1999,6 +2005,9 @@ async function runDiscovery({
1999
2005
  };
2000
2006
  }
2001
2007
 
2008
+ // src/validation/payment-required.ts
2009
+ import { parsePaymentRequired } from "@x402/core/schemas";
2010
+
2002
2011
  // src/harness.ts
2003
2012
  var INTENT_TRIGGERS = ["x402", "mpp", "pay for", "micropayment", "agentic commerce"];
2004
2013
  var CLIENT_PROFILES = {