@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 +20 -0
- package/dist/cli.cjs +40 -31
- package/dist/cli.js +40 -31
- package/dist/index.cjs +528 -65
- package/dist/index.d.cts +85 -1
- package/dist/index.d.ts +85 -1
- package/dist/index.js +524 -64
- package/package.json +6 -2
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-
|
|
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.
|
|
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-
|
|
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-
|
|
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
|
|
1324
|
-
const ownershipProofs = Array.isArray(
|
|
1325
|
-
const
|
|
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 =
|
|
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-
|
|
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") && !
|
|
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-
|
|
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.
|
|
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-
|
|
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-
|
|
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
|
|
1298
|
-
const ownershipProofs = Array.isArray(
|
|
1299
|
-
const
|
|
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 =
|
|
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-
|
|
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") && !
|
|
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 = {
|