@agentcash/discovery 0.1.3 → 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/dist/cli.cjs +37 -31
- package/dist/cli.js +37 -31
- package/dist/index.cjs +55 -63
- package/dist/index.js +55 -63
- package/package.json +5 -2
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;
|
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;
|
package/dist/index.cjs
CHANGED
|
@@ -54,7 +54,7 @@ var STRICT_ESCALATION_CODES = [
|
|
|
54
54
|
];
|
|
55
55
|
|
|
56
56
|
// src/mmm-enabled.ts
|
|
57
|
-
var isMmmEnabled = () => "0.1.
|
|
57
|
+
var isMmmEnabled = () => "0.1.4".includes("-mmm");
|
|
58
58
|
|
|
59
59
|
// src/core/constants.ts
|
|
60
60
|
var OPENAPI_PATH_CANDIDATES = ["/openapi.json", "/.well-known/openapi.json"];
|
|
@@ -224,7 +224,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
|
|
|
224
224
|
"Using /.well-known/x402.instructions as compatibility guidance fallback. Prefer llms.txt.",
|
|
225
225
|
{
|
|
226
226
|
stage: "well-known/x402",
|
|
227
|
-
hint: "Move guidance to llms.txt and reference via x-
|
|
227
|
+
hint: "Move guidance to llms.txt and reference via x-discovery.llmsTxtUrl in OpenAPI."
|
|
228
228
|
}
|
|
229
229
|
)
|
|
230
230
|
);
|
|
@@ -237,7 +237,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
|
|
|
237
237
|
"Using /.well-known/x402.ownershipProofs compatibility field. Prefer OpenAPI provenance extension.",
|
|
238
238
|
{
|
|
239
239
|
stage: "well-known/x402",
|
|
240
|
-
hint: "Move ownership proofs to x-
|
|
240
|
+
hint: "Move ownership proofs to x-discovery.ownershipProofs in OpenAPI."
|
|
241
241
|
}
|
|
242
242
|
)
|
|
243
243
|
);
|
|
@@ -633,10 +633,31 @@ function estimateTokenCount(text) {
|
|
|
633
633
|
return Math.ceil(text.length / 4);
|
|
634
634
|
}
|
|
635
635
|
|
|
636
|
-
// src/core/openapi.ts
|
|
636
|
+
// src/core/openapi-utils.ts
|
|
637
637
|
function isRecord3(value) {
|
|
638
638
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
639
639
|
}
|
|
640
|
+
function hasSecurity(operation, scheme) {
|
|
641
|
+
const security = operation.security;
|
|
642
|
+
return Array.isArray(security) && security.some((s) => isRecord3(s) && scheme in s);
|
|
643
|
+
}
|
|
644
|
+
function has402Response(operation) {
|
|
645
|
+
const responses = operation.responses;
|
|
646
|
+
if (!isRecord3(responses)) return false;
|
|
647
|
+
return Boolean(responses["402"]);
|
|
648
|
+
}
|
|
649
|
+
function inferAuthMode(operation) {
|
|
650
|
+
if (isRecord3(operation["x-payment-info"])) return "paid";
|
|
651
|
+
if (has402Response(operation)) {
|
|
652
|
+
if (hasSecurity(operation, "siwx")) return "siwx";
|
|
653
|
+
return "paid";
|
|
654
|
+
}
|
|
655
|
+
if (hasSecurity(operation, "apiKey")) return "apiKey";
|
|
656
|
+
if (hasSecurity(operation, "siwx")) return "siwx";
|
|
657
|
+
return void 0;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/core/openapi.ts
|
|
640
661
|
function asString(value) {
|
|
641
662
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
642
663
|
}
|
|
@@ -645,11 +666,6 @@ function parsePriceValue(value) {
|
|
|
645
666
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
646
667
|
return void 0;
|
|
647
668
|
}
|
|
648
|
-
function require402Response(operation) {
|
|
649
|
-
const responses = operation.responses;
|
|
650
|
-
if (!isRecord3(responses)) return false;
|
|
651
|
-
return Boolean(responses["402"]);
|
|
652
|
-
}
|
|
653
669
|
function parseProtocols(paymentInfo) {
|
|
654
670
|
const protocols = paymentInfo.protocols;
|
|
655
671
|
if (!Array.isArray(protocols)) return [];
|
|
@@ -657,15 +673,6 @@ function parseProtocols(paymentInfo) {
|
|
|
657
673
|
(entry) => typeof entry === "string" && entry.length > 0
|
|
658
674
|
);
|
|
659
675
|
}
|
|
660
|
-
function parseAuthMode(operation) {
|
|
661
|
-
const auth = operation["x-agentcash-auth"];
|
|
662
|
-
if (!isRecord3(auth)) return void 0;
|
|
663
|
-
const mode = auth.mode;
|
|
664
|
-
if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
|
|
665
|
-
return mode;
|
|
666
|
-
}
|
|
667
|
-
return void 0;
|
|
668
|
-
}
|
|
669
676
|
async function runOpenApiStage(options) {
|
|
670
677
|
const warnings = [];
|
|
671
678
|
const resources = [];
|
|
@@ -737,10 +744,9 @@ async function runOpenApiStage(options) {
|
|
|
737
744
|
};
|
|
738
745
|
}
|
|
739
746
|
const paths = document.paths;
|
|
740
|
-
const
|
|
741
|
-
const ownershipProofs = Array.isArray(
|
|
742
|
-
const
|
|
743
|
-
const llmsTxtUrl = asString(guidance?.llmsTxtUrl);
|
|
747
|
+
const discovery = isRecord3(document["x-discovery"]) ? document["x-discovery"] : void 0;
|
|
748
|
+
const ownershipProofs = Array.isArray(discovery?.ownershipProofs) ? discovery.ownershipProofs.filter((entry) => typeof entry === "string") : [];
|
|
749
|
+
const llmsTxtUrl = asString(discovery?.llmsTxtUrl);
|
|
744
750
|
if (ownershipProofs.length > 0) {
|
|
745
751
|
warnings.push(
|
|
746
752
|
warning("OPENAPI_OWNERSHIP_PROOFS_PRESENT", "info", "OpenAPI ownership proofs detected", {
|
|
@@ -785,13 +791,13 @@ async function runOpenApiStage(options) {
|
|
|
785
791
|
)
|
|
786
792
|
);
|
|
787
793
|
}
|
|
788
|
-
const authMode =
|
|
794
|
+
const authMode = inferAuthMode(operation);
|
|
789
795
|
if (!authMode) {
|
|
790
796
|
warnings.push(
|
|
791
797
|
warning(
|
|
792
798
|
"OPENAPI_AUTH_MODE_MISSING",
|
|
793
799
|
"error",
|
|
794
|
-
`${method} ${rawPath} missing x-
|
|
800
|
+
`${method} ${rawPath} missing auth mode (no x-payment-info, 402 response, or security scheme)`,
|
|
795
801
|
{
|
|
796
802
|
stage: "openapi"
|
|
797
803
|
}
|
|
@@ -799,7 +805,7 @@ async function runOpenApiStage(options) {
|
|
|
799
805
|
);
|
|
800
806
|
continue;
|
|
801
807
|
}
|
|
802
|
-
if ((authMode === "paid" || authMode === "siwx") && !
|
|
808
|
+
if ((authMode === "paid" || authMode === "siwx") && !has402Response(operation)) {
|
|
803
809
|
warnings.push(
|
|
804
810
|
warning(
|
|
805
811
|
"OPENAPI_402_MISSING",
|
|
@@ -1378,11 +1384,6 @@ async function runDiscovery({
|
|
|
1378
1384
|
}
|
|
1379
1385
|
}
|
|
1380
1386
|
}
|
|
1381
|
-
if (!stageResult.valid) {
|
|
1382
|
-
continue;
|
|
1383
|
-
}
|
|
1384
|
-
const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
|
|
1385
|
-
warnings.push(...mergeWarnings);
|
|
1386
1387
|
if (includeRaw && stageResult.raw !== void 0) {
|
|
1387
1388
|
if (stageResult.stage === "openapi" || stageResult.stage === "override") {
|
|
1388
1389
|
const rawObject = stageResult.raw;
|
|
@@ -1402,6 +1403,11 @@ async function runDiscovery({
|
|
|
1402
1403
|
rawSources.interopMpp = stageResult.raw;
|
|
1403
1404
|
}
|
|
1404
1405
|
}
|
|
1406
|
+
if (!stageResult.valid) {
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
|
|
1410
|
+
warnings.push(...mergeWarnings);
|
|
1405
1411
|
if (!detailed) {
|
|
1406
1412
|
selectedStage = selectedStage ?? stageResult.stage;
|
|
1407
1413
|
break;
|
|
@@ -1919,9 +1925,6 @@ var OPENAPI_METHODS = [
|
|
|
1919
1925
|
"OPTIONS",
|
|
1920
1926
|
"TRACE"
|
|
1921
1927
|
];
|
|
1922
|
-
function isRecord5(value) {
|
|
1923
|
-
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
1924
|
-
}
|
|
1925
1928
|
function toFiniteNumber(value) {
|
|
1926
1929
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1927
1930
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
@@ -1979,7 +1982,7 @@ function inferFailureCause(warnings) {
|
|
|
1979
1982
|
return { cause: "not_found" };
|
|
1980
1983
|
}
|
|
1981
1984
|
function getOpenApiInfo(document) {
|
|
1982
|
-
if (!
|
|
1985
|
+
if (!isRecord3(document) || !isRecord3(document.info)) return void 0;
|
|
1983
1986
|
if (typeof document.info.title !== "string") return void 0;
|
|
1984
1987
|
return {
|
|
1985
1988
|
title: document.info.title,
|
|
@@ -2022,15 +2025,15 @@ async function resolveGuidance(options) {
|
|
|
2022
2025
|
};
|
|
2023
2026
|
}
|
|
2024
2027
|
function extractPathsDocument(document) {
|
|
2025
|
-
if (!
|
|
2026
|
-
if (!
|
|
2028
|
+
if (!isRecord3(document)) return void 0;
|
|
2029
|
+
if (!isRecord3(document.paths)) return void 0;
|
|
2027
2030
|
return document.paths;
|
|
2028
2031
|
}
|
|
2029
2032
|
function findMatchingOpenApiPath(paths, targetPath) {
|
|
2030
2033
|
const exact = paths[targetPath];
|
|
2031
|
-
if (
|
|
2034
|
+
if (isRecord3(exact)) return { matchedPath: targetPath, pathItem: exact };
|
|
2032
2035
|
for (const [specPath, entry] of Object.entries(paths)) {
|
|
2033
|
-
if (!
|
|
2036
|
+
if (!isRecord3(entry)) continue;
|
|
2034
2037
|
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
2035
2038
|
const regex = new RegExp(`^${pattern}$`);
|
|
2036
2039
|
if (regex.test(targetPath)) {
|
|
@@ -2046,11 +2049,11 @@ function resolveRef(document, ref, seen) {
|
|
|
2046
2049
|
const parts = ref.slice(2).split("/");
|
|
2047
2050
|
let current = document;
|
|
2048
2051
|
for (const part of parts) {
|
|
2049
|
-
if (!
|
|
2052
|
+
if (!isRecord3(current)) return void 0;
|
|
2050
2053
|
current = current[part];
|
|
2051
2054
|
if (current === void 0) return void 0;
|
|
2052
2055
|
}
|
|
2053
|
-
if (
|
|
2056
|
+
if (isRecord3(current)) return resolveRefs(document, current, seen);
|
|
2054
2057
|
return current;
|
|
2055
2058
|
}
|
|
2056
2059
|
function resolveRefs(document, obj, seen, depth = 0) {
|
|
@@ -2059,20 +2062,20 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
2059
2062
|
for (const [key, value] of Object.entries(obj)) {
|
|
2060
2063
|
if (key === "$ref" && typeof value === "string") {
|
|
2061
2064
|
const deref = resolveRef(document, value, seen);
|
|
2062
|
-
if (
|
|
2065
|
+
if (isRecord3(deref)) {
|
|
2063
2066
|
Object.assign(resolved, deref);
|
|
2064
2067
|
} else {
|
|
2065
2068
|
resolved[key] = value;
|
|
2066
2069
|
}
|
|
2067
2070
|
continue;
|
|
2068
2071
|
}
|
|
2069
|
-
if (
|
|
2072
|
+
if (isRecord3(value)) {
|
|
2070
2073
|
resolved[key] = resolveRefs(document, value, seen, depth + 1);
|
|
2071
2074
|
continue;
|
|
2072
2075
|
}
|
|
2073
2076
|
if (Array.isArray(value)) {
|
|
2074
2077
|
resolved[key] = value.map(
|
|
2075
|
-
(item) =>
|
|
2078
|
+
(item) => isRecord3(item) ? resolveRefs(document, item, seen, depth + 1) : item
|
|
2076
2079
|
);
|
|
2077
2080
|
continue;
|
|
2078
2081
|
}
|
|
@@ -2082,15 +2085,15 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
2082
2085
|
}
|
|
2083
2086
|
function extractRequestBodySchema(operationSchema) {
|
|
2084
2087
|
const requestBody = operationSchema.requestBody;
|
|
2085
|
-
if (!
|
|
2088
|
+
if (!isRecord3(requestBody)) return void 0;
|
|
2086
2089
|
const content = requestBody.content;
|
|
2087
|
-
if (!
|
|
2090
|
+
if (!isRecord3(content)) return void 0;
|
|
2088
2091
|
const jsonMediaType = content["application/json"];
|
|
2089
|
-
if (
|
|
2092
|
+
if (isRecord3(jsonMediaType) && isRecord3(jsonMediaType.schema)) {
|
|
2090
2093
|
return jsonMediaType.schema;
|
|
2091
2094
|
}
|
|
2092
2095
|
for (const mediaType of Object.values(content)) {
|
|
2093
|
-
if (
|
|
2096
|
+
if (isRecord3(mediaType) && isRecord3(mediaType.schema)) {
|
|
2094
2097
|
return mediaType.schema;
|
|
2095
2098
|
}
|
|
2096
2099
|
}
|
|
@@ -2099,7 +2102,7 @@ function extractRequestBodySchema(operationSchema) {
|
|
|
2099
2102
|
function extractParameters(operationSchema) {
|
|
2100
2103
|
const params = operationSchema.parameters;
|
|
2101
2104
|
if (!Array.isArray(params)) return [];
|
|
2102
|
-
return params.filter((value) =>
|
|
2105
|
+
return params.filter((value) => isRecord3(value));
|
|
2103
2106
|
}
|
|
2104
2107
|
function extractInputSchema(operationSchema) {
|
|
2105
2108
|
const requestBody = extractRequestBodySchema(operationSchema);
|
|
@@ -2113,7 +2116,7 @@ function extractInputSchema(operationSchema) {
|
|
|
2113
2116
|
}
|
|
2114
2117
|
function parseOperationPrice(operation) {
|
|
2115
2118
|
const paymentInfo = operation["x-payment-info"];
|
|
2116
|
-
if (!
|
|
2119
|
+
if (!isRecord3(paymentInfo)) return void 0;
|
|
2117
2120
|
const fixed = toFiniteNumber(paymentInfo.price);
|
|
2118
2121
|
if (fixed != null) return `$${String(fixed)}`;
|
|
2119
2122
|
const min = toFiniteNumber(paymentInfo.minPrice);
|
|
@@ -2123,23 +2126,12 @@ function parseOperationPrice(operation) {
|
|
|
2123
2126
|
}
|
|
2124
2127
|
function parseOperationProtocols(operation) {
|
|
2125
2128
|
const paymentInfo = operation["x-payment-info"];
|
|
2126
|
-
if (!
|
|
2129
|
+
if (!isRecord3(paymentInfo) || !Array.isArray(paymentInfo.protocols)) return void 0;
|
|
2127
2130
|
const protocols = paymentInfo.protocols.filter(
|
|
2128
2131
|
(protocol) => typeof protocol === "string" && protocol.length > 0
|
|
2129
2132
|
);
|
|
2130
2133
|
return protocols.length > 0 ? protocols : void 0;
|
|
2131
2134
|
}
|
|
2132
|
-
function parseOperationAuthMode(operation) {
|
|
2133
|
-
const authExtension = operation["x-agentcash-auth"];
|
|
2134
|
-
if (isRecord5(authExtension)) {
|
|
2135
|
-
const mode = authExtension.mode;
|
|
2136
|
-
if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
|
|
2137
|
-
return mode;
|
|
2138
|
-
}
|
|
2139
|
-
}
|
|
2140
|
-
if (isRecord5(operation["x-payment-info"])) return "paid";
|
|
2141
|
-
return void 0;
|
|
2142
|
-
}
|
|
2143
2135
|
function createResourceMap(result) {
|
|
2144
2136
|
const map = /* @__PURE__ */ new Map();
|
|
2145
2137
|
for (const resource of result.resources) {
|
|
@@ -2231,7 +2223,7 @@ async function inspectEndpointForMcp(options) {
|
|
|
2231
2223
|
if (matched) {
|
|
2232
2224
|
for (const candidate of OPENAPI_METHODS) {
|
|
2233
2225
|
const operation = matched.pathItem[candidate.toLowerCase()];
|
|
2234
|
-
if (!
|
|
2226
|
+
if (!isRecord3(operation) || !isRecord3(document)) continue;
|
|
2235
2227
|
specMethods.push(candidate);
|
|
2236
2228
|
const resolvedOperation = resolveRefs(document, operation, /* @__PURE__ */ new Set());
|
|
2237
2229
|
const resource = resourceMap.get(toResourceKey(origin, candidate, matched.matchedPath));
|
|
@@ -2239,7 +2231,7 @@ async function inspectEndpointForMcp(options) {
|
|
|
2239
2231
|
const operationSummary = typeof resolvedOperation.summary === "string" ? resolvedOperation.summary : typeof resolvedOperation.description === "string" ? resolvedOperation.description : void 0;
|
|
2240
2232
|
const operationPrice = parseOperationPrice(resolvedOperation);
|
|
2241
2233
|
const operationProtocols = parseOperationProtocols(resolvedOperation);
|
|
2242
|
-
const operationAuthMode =
|
|
2234
|
+
const operationAuthMode = inferAuthMode(resolvedOperation) ?? "unprotected";
|
|
2243
2235
|
const inputSchema = extractInputSchema(resolvedOperation);
|
|
2244
2236
|
advisories[candidate] = {
|
|
2245
2237
|
method: candidate,
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ var STRICT_ESCALATION_CODES = [
|
|
|
12
12
|
];
|
|
13
13
|
|
|
14
14
|
// src/mmm-enabled.ts
|
|
15
|
-
var isMmmEnabled = () => "0.1.
|
|
15
|
+
var isMmmEnabled = () => "0.1.4".includes("-mmm");
|
|
16
16
|
|
|
17
17
|
// src/core/constants.ts
|
|
18
18
|
var OPENAPI_PATH_CANDIDATES = ["/openapi.json", "/.well-known/openapi.json"];
|
|
@@ -182,7 +182,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
|
|
|
182
182
|
"Using /.well-known/x402.instructions as compatibility guidance fallback. Prefer llms.txt.",
|
|
183
183
|
{
|
|
184
184
|
stage: "well-known/x402",
|
|
185
|
-
hint: "Move guidance to llms.txt and reference via x-
|
|
185
|
+
hint: "Move guidance to llms.txt and reference via x-discovery.llmsTxtUrl in OpenAPI."
|
|
186
186
|
}
|
|
187
187
|
)
|
|
188
188
|
);
|
|
@@ -195,7 +195,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
|
|
|
195
195
|
"Using /.well-known/x402.ownershipProofs compatibility field. Prefer OpenAPI provenance extension.",
|
|
196
196
|
{
|
|
197
197
|
stage: "well-known/x402",
|
|
198
|
-
hint: "Move ownership proofs to x-
|
|
198
|
+
hint: "Move ownership proofs to x-discovery.ownershipProofs in OpenAPI."
|
|
199
199
|
}
|
|
200
200
|
)
|
|
201
201
|
);
|
|
@@ -591,10 +591,31 @@ function estimateTokenCount(text) {
|
|
|
591
591
|
return Math.ceil(text.length / 4);
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
-
// src/core/openapi.ts
|
|
594
|
+
// src/core/openapi-utils.ts
|
|
595
595
|
function isRecord3(value) {
|
|
596
596
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
597
597
|
}
|
|
598
|
+
function hasSecurity(operation, scheme) {
|
|
599
|
+
const security = operation.security;
|
|
600
|
+
return Array.isArray(security) && security.some((s) => isRecord3(s) && scheme in s);
|
|
601
|
+
}
|
|
602
|
+
function has402Response(operation) {
|
|
603
|
+
const responses = operation.responses;
|
|
604
|
+
if (!isRecord3(responses)) return false;
|
|
605
|
+
return Boolean(responses["402"]);
|
|
606
|
+
}
|
|
607
|
+
function inferAuthMode(operation) {
|
|
608
|
+
if (isRecord3(operation["x-payment-info"])) return "paid";
|
|
609
|
+
if (has402Response(operation)) {
|
|
610
|
+
if (hasSecurity(operation, "siwx")) return "siwx";
|
|
611
|
+
return "paid";
|
|
612
|
+
}
|
|
613
|
+
if (hasSecurity(operation, "apiKey")) return "apiKey";
|
|
614
|
+
if (hasSecurity(operation, "siwx")) return "siwx";
|
|
615
|
+
return void 0;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// src/core/openapi.ts
|
|
598
619
|
function asString(value) {
|
|
599
620
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
600
621
|
}
|
|
@@ -603,11 +624,6 @@ function parsePriceValue(value) {
|
|
|
603
624
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
604
625
|
return void 0;
|
|
605
626
|
}
|
|
606
|
-
function require402Response(operation) {
|
|
607
|
-
const responses = operation.responses;
|
|
608
|
-
if (!isRecord3(responses)) return false;
|
|
609
|
-
return Boolean(responses["402"]);
|
|
610
|
-
}
|
|
611
627
|
function parseProtocols(paymentInfo) {
|
|
612
628
|
const protocols = paymentInfo.protocols;
|
|
613
629
|
if (!Array.isArray(protocols)) return [];
|
|
@@ -615,15 +631,6 @@ function parseProtocols(paymentInfo) {
|
|
|
615
631
|
(entry) => typeof entry === "string" && entry.length > 0
|
|
616
632
|
);
|
|
617
633
|
}
|
|
618
|
-
function parseAuthMode(operation) {
|
|
619
|
-
const auth = operation["x-agentcash-auth"];
|
|
620
|
-
if (!isRecord3(auth)) return void 0;
|
|
621
|
-
const mode = auth.mode;
|
|
622
|
-
if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
|
|
623
|
-
return mode;
|
|
624
|
-
}
|
|
625
|
-
return void 0;
|
|
626
|
-
}
|
|
627
634
|
async function runOpenApiStage(options) {
|
|
628
635
|
const warnings = [];
|
|
629
636
|
const resources = [];
|
|
@@ -695,10 +702,9 @@ async function runOpenApiStage(options) {
|
|
|
695
702
|
};
|
|
696
703
|
}
|
|
697
704
|
const paths = document.paths;
|
|
698
|
-
const
|
|
699
|
-
const ownershipProofs = Array.isArray(
|
|
700
|
-
const
|
|
701
|
-
const llmsTxtUrl = asString(guidance?.llmsTxtUrl);
|
|
705
|
+
const discovery = isRecord3(document["x-discovery"]) ? document["x-discovery"] : void 0;
|
|
706
|
+
const ownershipProofs = Array.isArray(discovery?.ownershipProofs) ? discovery.ownershipProofs.filter((entry) => typeof entry === "string") : [];
|
|
707
|
+
const llmsTxtUrl = asString(discovery?.llmsTxtUrl);
|
|
702
708
|
if (ownershipProofs.length > 0) {
|
|
703
709
|
warnings.push(
|
|
704
710
|
warning("OPENAPI_OWNERSHIP_PROOFS_PRESENT", "info", "OpenAPI ownership proofs detected", {
|
|
@@ -743,13 +749,13 @@ async function runOpenApiStage(options) {
|
|
|
743
749
|
)
|
|
744
750
|
);
|
|
745
751
|
}
|
|
746
|
-
const authMode =
|
|
752
|
+
const authMode = inferAuthMode(operation);
|
|
747
753
|
if (!authMode) {
|
|
748
754
|
warnings.push(
|
|
749
755
|
warning(
|
|
750
756
|
"OPENAPI_AUTH_MODE_MISSING",
|
|
751
757
|
"error",
|
|
752
|
-
`${method} ${rawPath} missing x-
|
|
758
|
+
`${method} ${rawPath} missing auth mode (no x-payment-info, 402 response, or security scheme)`,
|
|
753
759
|
{
|
|
754
760
|
stage: "openapi"
|
|
755
761
|
}
|
|
@@ -757,7 +763,7 @@ async function runOpenApiStage(options) {
|
|
|
757
763
|
);
|
|
758
764
|
continue;
|
|
759
765
|
}
|
|
760
|
-
if ((authMode === "paid" || authMode === "siwx") && !
|
|
766
|
+
if ((authMode === "paid" || authMode === "siwx") && !has402Response(operation)) {
|
|
761
767
|
warnings.push(
|
|
762
768
|
warning(
|
|
763
769
|
"OPENAPI_402_MISSING",
|
|
@@ -1336,11 +1342,6 @@ async function runDiscovery({
|
|
|
1336
1342
|
}
|
|
1337
1343
|
}
|
|
1338
1344
|
}
|
|
1339
|
-
if (!stageResult.valid) {
|
|
1340
|
-
continue;
|
|
1341
|
-
}
|
|
1342
|
-
const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
|
|
1343
|
-
warnings.push(...mergeWarnings);
|
|
1344
1345
|
if (includeRaw && stageResult.raw !== void 0) {
|
|
1345
1346
|
if (stageResult.stage === "openapi" || stageResult.stage === "override") {
|
|
1346
1347
|
const rawObject = stageResult.raw;
|
|
@@ -1360,6 +1361,11 @@ async function runDiscovery({
|
|
|
1360
1361
|
rawSources.interopMpp = stageResult.raw;
|
|
1361
1362
|
}
|
|
1362
1363
|
}
|
|
1364
|
+
if (!stageResult.valid) {
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
|
|
1368
|
+
warnings.push(...mergeWarnings);
|
|
1363
1369
|
if (!detailed) {
|
|
1364
1370
|
selectedStage = selectedStage ?? stageResult.stage;
|
|
1365
1371
|
break;
|
|
@@ -1877,9 +1883,6 @@ var OPENAPI_METHODS = [
|
|
|
1877
1883
|
"OPTIONS",
|
|
1878
1884
|
"TRACE"
|
|
1879
1885
|
];
|
|
1880
|
-
function isRecord5(value) {
|
|
1881
|
-
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
1882
|
-
}
|
|
1883
1886
|
function toFiniteNumber(value) {
|
|
1884
1887
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1885
1888
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
@@ -1937,7 +1940,7 @@ function inferFailureCause(warnings) {
|
|
|
1937
1940
|
return { cause: "not_found" };
|
|
1938
1941
|
}
|
|
1939
1942
|
function getOpenApiInfo(document) {
|
|
1940
|
-
if (!
|
|
1943
|
+
if (!isRecord3(document) || !isRecord3(document.info)) return void 0;
|
|
1941
1944
|
if (typeof document.info.title !== "string") return void 0;
|
|
1942
1945
|
return {
|
|
1943
1946
|
title: document.info.title,
|
|
@@ -1980,15 +1983,15 @@ async function resolveGuidance(options) {
|
|
|
1980
1983
|
};
|
|
1981
1984
|
}
|
|
1982
1985
|
function extractPathsDocument(document) {
|
|
1983
|
-
if (!
|
|
1984
|
-
if (!
|
|
1986
|
+
if (!isRecord3(document)) return void 0;
|
|
1987
|
+
if (!isRecord3(document.paths)) return void 0;
|
|
1985
1988
|
return document.paths;
|
|
1986
1989
|
}
|
|
1987
1990
|
function findMatchingOpenApiPath(paths, targetPath) {
|
|
1988
1991
|
const exact = paths[targetPath];
|
|
1989
|
-
if (
|
|
1992
|
+
if (isRecord3(exact)) return { matchedPath: targetPath, pathItem: exact };
|
|
1990
1993
|
for (const [specPath, entry] of Object.entries(paths)) {
|
|
1991
|
-
if (!
|
|
1994
|
+
if (!isRecord3(entry)) continue;
|
|
1992
1995
|
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
1993
1996
|
const regex = new RegExp(`^${pattern}$`);
|
|
1994
1997
|
if (regex.test(targetPath)) {
|
|
@@ -2004,11 +2007,11 @@ function resolveRef(document, ref, seen) {
|
|
|
2004
2007
|
const parts = ref.slice(2).split("/");
|
|
2005
2008
|
let current = document;
|
|
2006
2009
|
for (const part of parts) {
|
|
2007
|
-
if (!
|
|
2010
|
+
if (!isRecord3(current)) return void 0;
|
|
2008
2011
|
current = current[part];
|
|
2009
2012
|
if (current === void 0) return void 0;
|
|
2010
2013
|
}
|
|
2011
|
-
if (
|
|
2014
|
+
if (isRecord3(current)) return resolveRefs(document, current, seen);
|
|
2012
2015
|
return current;
|
|
2013
2016
|
}
|
|
2014
2017
|
function resolveRefs(document, obj, seen, depth = 0) {
|
|
@@ -2017,20 +2020,20 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
2017
2020
|
for (const [key, value] of Object.entries(obj)) {
|
|
2018
2021
|
if (key === "$ref" && typeof value === "string") {
|
|
2019
2022
|
const deref = resolveRef(document, value, seen);
|
|
2020
|
-
if (
|
|
2023
|
+
if (isRecord3(deref)) {
|
|
2021
2024
|
Object.assign(resolved, deref);
|
|
2022
2025
|
} else {
|
|
2023
2026
|
resolved[key] = value;
|
|
2024
2027
|
}
|
|
2025
2028
|
continue;
|
|
2026
2029
|
}
|
|
2027
|
-
if (
|
|
2030
|
+
if (isRecord3(value)) {
|
|
2028
2031
|
resolved[key] = resolveRefs(document, value, seen, depth + 1);
|
|
2029
2032
|
continue;
|
|
2030
2033
|
}
|
|
2031
2034
|
if (Array.isArray(value)) {
|
|
2032
2035
|
resolved[key] = value.map(
|
|
2033
|
-
(item) =>
|
|
2036
|
+
(item) => isRecord3(item) ? resolveRefs(document, item, seen, depth + 1) : item
|
|
2034
2037
|
);
|
|
2035
2038
|
continue;
|
|
2036
2039
|
}
|
|
@@ -2040,15 +2043,15 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
2040
2043
|
}
|
|
2041
2044
|
function extractRequestBodySchema(operationSchema) {
|
|
2042
2045
|
const requestBody = operationSchema.requestBody;
|
|
2043
|
-
if (!
|
|
2046
|
+
if (!isRecord3(requestBody)) return void 0;
|
|
2044
2047
|
const content = requestBody.content;
|
|
2045
|
-
if (!
|
|
2048
|
+
if (!isRecord3(content)) return void 0;
|
|
2046
2049
|
const jsonMediaType = content["application/json"];
|
|
2047
|
-
if (
|
|
2050
|
+
if (isRecord3(jsonMediaType) && isRecord3(jsonMediaType.schema)) {
|
|
2048
2051
|
return jsonMediaType.schema;
|
|
2049
2052
|
}
|
|
2050
2053
|
for (const mediaType of Object.values(content)) {
|
|
2051
|
-
if (
|
|
2054
|
+
if (isRecord3(mediaType) && isRecord3(mediaType.schema)) {
|
|
2052
2055
|
return mediaType.schema;
|
|
2053
2056
|
}
|
|
2054
2057
|
}
|
|
@@ -2057,7 +2060,7 @@ function extractRequestBodySchema(operationSchema) {
|
|
|
2057
2060
|
function extractParameters(operationSchema) {
|
|
2058
2061
|
const params = operationSchema.parameters;
|
|
2059
2062
|
if (!Array.isArray(params)) return [];
|
|
2060
|
-
return params.filter((value) =>
|
|
2063
|
+
return params.filter((value) => isRecord3(value));
|
|
2061
2064
|
}
|
|
2062
2065
|
function extractInputSchema(operationSchema) {
|
|
2063
2066
|
const requestBody = extractRequestBodySchema(operationSchema);
|
|
@@ -2071,7 +2074,7 @@ function extractInputSchema(operationSchema) {
|
|
|
2071
2074
|
}
|
|
2072
2075
|
function parseOperationPrice(operation) {
|
|
2073
2076
|
const paymentInfo = operation["x-payment-info"];
|
|
2074
|
-
if (!
|
|
2077
|
+
if (!isRecord3(paymentInfo)) return void 0;
|
|
2075
2078
|
const fixed = toFiniteNumber(paymentInfo.price);
|
|
2076
2079
|
if (fixed != null) return `$${String(fixed)}`;
|
|
2077
2080
|
const min = toFiniteNumber(paymentInfo.minPrice);
|
|
@@ -2081,23 +2084,12 @@ function parseOperationPrice(operation) {
|
|
|
2081
2084
|
}
|
|
2082
2085
|
function parseOperationProtocols(operation) {
|
|
2083
2086
|
const paymentInfo = operation["x-payment-info"];
|
|
2084
|
-
if (!
|
|
2087
|
+
if (!isRecord3(paymentInfo) || !Array.isArray(paymentInfo.protocols)) return void 0;
|
|
2085
2088
|
const protocols = paymentInfo.protocols.filter(
|
|
2086
2089
|
(protocol) => typeof protocol === "string" && protocol.length > 0
|
|
2087
2090
|
);
|
|
2088
2091
|
return protocols.length > 0 ? protocols : void 0;
|
|
2089
2092
|
}
|
|
2090
|
-
function parseOperationAuthMode(operation) {
|
|
2091
|
-
const authExtension = operation["x-agentcash-auth"];
|
|
2092
|
-
if (isRecord5(authExtension)) {
|
|
2093
|
-
const mode = authExtension.mode;
|
|
2094
|
-
if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
|
|
2095
|
-
return mode;
|
|
2096
|
-
}
|
|
2097
|
-
}
|
|
2098
|
-
if (isRecord5(operation["x-payment-info"])) return "paid";
|
|
2099
|
-
return void 0;
|
|
2100
|
-
}
|
|
2101
2093
|
function createResourceMap(result) {
|
|
2102
2094
|
const map = /* @__PURE__ */ new Map();
|
|
2103
2095
|
for (const resource of result.resources) {
|
|
@@ -2189,7 +2181,7 @@ async function inspectEndpointForMcp(options) {
|
|
|
2189
2181
|
if (matched) {
|
|
2190
2182
|
for (const candidate of OPENAPI_METHODS) {
|
|
2191
2183
|
const operation = matched.pathItem[candidate.toLowerCase()];
|
|
2192
|
-
if (!
|
|
2184
|
+
if (!isRecord3(operation) || !isRecord3(document)) continue;
|
|
2193
2185
|
specMethods.push(candidate);
|
|
2194
2186
|
const resolvedOperation = resolveRefs(document, operation, /* @__PURE__ */ new Set());
|
|
2195
2187
|
const resource = resourceMap.get(toResourceKey(origin, candidate, matched.matchedPath));
|
|
@@ -2197,7 +2189,7 @@ async function inspectEndpointForMcp(options) {
|
|
|
2197
2189
|
const operationSummary = typeof resolvedOperation.summary === "string" ? resolvedOperation.summary : typeof resolvedOperation.description === "string" ? resolvedOperation.description : void 0;
|
|
2198
2190
|
const operationPrice = parseOperationPrice(resolvedOperation);
|
|
2199
2191
|
const operationProtocols = parseOperationProtocols(resolvedOperation);
|
|
2200
|
-
const operationAuthMode =
|
|
2192
|
+
const operationAuthMode = inferAuthMode(resolvedOperation) ?? "unprotected";
|
|
2201
2193
|
const inputSchema = extractInputSchema(resolvedOperation);
|
|
2202
2194
|
advisories[candidate] = {
|
|
2203
2195
|
method: candidate,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentcash/discovery",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Canonical OpenAPI-first discovery runtime for the agentcash ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -72,7 +72,9 @@
|
|
|
72
72
|
"@changesets/cli": "^2.29.8",
|
|
73
73
|
"@eslint/js": "^10.0.1",
|
|
74
74
|
"@types/node": "^22.18.0",
|
|
75
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
75
76
|
"eslint": "^10.0.0",
|
|
77
|
+
"knip": "^5.85.0",
|
|
76
78
|
"prettier": "^3.8.1",
|
|
77
79
|
"tsup": "^8.5.0",
|
|
78
80
|
"typescript": "^5.9.2",
|
|
@@ -90,6 +92,7 @@
|
|
|
90
92
|
"test:watch": "vitest",
|
|
91
93
|
"audit:registry": "pnpm build && node scripts/audit-registry.mjs",
|
|
92
94
|
"audit:registry:quick": "pnpm build && node scripts/audit-registry.mjs --origin-limit 50 --resource-limit 500",
|
|
93
|
-
"
|
|
95
|
+
"knip": "knip",
|
|
96
|
+
"check": "pnpm format:check && pnpm lint && pnpm knip && pnpm typecheck && pnpm build && pnpm test"
|
|
94
97
|
}
|
|
95
98
|
}
|