@agentcash/discovery 1.0.2 → 1.1.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/cli.cjs +54 -39
- package/dist/cli.js +44 -39
- package/dist/index.cjs +56 -41
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +46 -41
- package/package.json +2 -1
package/dist/cli.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/cli.ts
|
|
@@ -194,7 +204,7 @@ function fetchSafe(url, init) {
|
|
|
194
204
|
}
|
|
195
205
|
|
|
196
206
|
// src/mmm-enabled.ts
|
|
197
|
-
var isMmmEnabled = () => "1.0
|
|
207
|
+
var isMmmEnabled = () => "1.1.0".includes("-mmm");
|
|
198
208
|
|
|
199
209
|
// src/core/source/openapi/index.ts
|
|
200
210
|
var OpenApiParsedSchema = OpenApiDocSchema.transform((doc) => {
|
|
@@ -360,6 +370,7 @@ var AUDIT_CODES = {
|
|
|
360
370
|
L2_NO_ROUTES: "L2_NO_ROUTES",
|
|
361
371
|
L2_ROUTE_COUNT_HIGH: "L2_ROUTE_COUNT_HIGH",
|
|
362
372
|
L2_AUTH_MODE_MISSING: "L2_AUTH_MODE_MISSING",
|
|
373
|
+
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
363
374
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
364
375
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
365
376
|
// ─── L3 endpoint advisory checks ─────────────────────────────────────────────
|
|
@@ -421,6 +432,15 @@ function getWarningsForL2(l2) {
|
|
|
421
432
|
});
|
|
422
433
|
return warnings;
|
|
423
434
|
}
|
|
435
|
+
const hasPaidRoute = l2.routes.some((r) => r.authMode === "paid" || r.authMode === "apiKey+paid");
|
|
436
|
+
if (!hasPaidRoute) {
|
|
437
|
+
warnings.push({
|
|
438
|
+
code: AUDIT_CODES.L2_NO_PAID_ROUTES,
|
|
439
|
+
severity: "info",
|
|
440
|
+
message: "No endpoints are marked as paid or apiKey+paid.",
|
|
441
|
+
hint: "Add x-payment-info to operations that require payment so agents know which endpoints are monetized."
|
|
442
|
+
});
|
|
443
|
+
}
|
|
424
444
|
if (l2.routes.length > ROUTE_COUNT_HIGH) {
|
|
425
445
|
warnings.push({
|
|
426
446
|
code: AUDIT_CODES.L2_ROUTE_COUNT_HIGH,
|
|
@@ -507,8 +527,8 @@ function getWarningsForL4(l4) {
|
|
|
507
527
|
{
|
|
508
528
|
code: AUDIT_CODES.L4_GUIDANCE_MISSING,
|
|
509
529
|
severity: "info",
|
|
510
|
-
message: "No guidance text found (
|
|
511
|
-
hint: "Add an info.guidance field to your OpenAPI spec
|
|
530
|
+
message: "No guidance text found (OpenAPI info.guidance).",
|
|
531
|
+
hint: "Add an info.guidance field to your OpenAPI spec for agent-readable instructions."
|
|
512
532
|
}
|
|
513
533
|
];
|
|
514
534
|
}
|
|
@@ -817,54 +837,31 @@ function extractPaymentOptions4(wwwAuthenticate) {
|
|
|
817
837
|
return options;
|
|
818
838
|
}
|
|
819
839
|
|
|
820
|
-
// src/core/
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
if (!isRecord(entry)) continue;
|
|
826
|
-
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
827
|
-
const regex = new RegExp(`^${pattern}$`);
|
|
828
|
-
if (regex.test(targetPath)) {
|
|
829
|
-
return { matchedPath: specPath, pathItem: entry };
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
return null;
|
|
833
|
-
}
|
|
834
|
-
function resolveRef(document, ref, seen) {
|
|
835
|
-
if (!ref.startsWith("#/")) return void 0;
|
|
836
|
-
if (seen.has(ref)) return { $circular: ref };
|
|
837
|
-
seen.add(ref);
|
|
838
|
-
const parts = ref.slice(2).split("/");
|
|
839
|
-
let current = document;
|
|
840
|
-
for (const part of parts) {
|
|
841
|
-
if (!isRecord(current)) return void 0;
|
|
842
|
-
current = current[part];
|
|
843
|
-
if (current === void 0) return void 0;
|
|
844
|
-
}
|
|
845
|
-
if (isRecord(current)) return resolveRefs(document, current, seen);
|
|
846
|
-
return current;
|
|
840
|
+
// src/core/lib/resolve-ref.ts
|
|
841
|
+
var import_dereference_json_schema = __toESM(require("dereference-json-schema"), 1);
|
|
842
|
+
var { resolveRefSync } = import_dereference_json_schema.default;
|
|
843
|
+
function isRecord2(value) {
|
|
844
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
847
845
|
}
|
|
848
|
-
function
|
|
849
|
-
if (depth > 4) return obj;
|
|
846
|
+
function deepResolveRefs(document, obj) {
|
|
850
847
|
const resolved = {};
|
|
851
848
|
for (const [key, value] of Object.entries(obj)) {
|
|
852
849
|
if (key === "$ref" && typeof value === "string") {
|
|
853
|
-
const deref =
|
|
854
|
-
if (
|
|
855
|
-
Object.assign(resolved, deref);
|
|
850
|
+
const deref = resolveRefSync(document, value);
|
|
851
|
+
if (isRecord2(deref)) {
|
|
852
|
+
Object.assign(resolved, deepResolveRefs(document, deref));
|
|
856
853
|
} else {
|
|
857
854
|
resolved[key] = value;
|
|
858
855
|
}
|
|
859
856
|
continue;
|
|
860
857
|
}
|
|
861
|
-
if (
|
|
862
|
-
resolved[key] =
|
|
858
|
+
if (isRecord2(value)) {
|
|
859
|
+
resolved[key] = deepResolveRefs(document, value);
|
|
863
860
|
continue;
|
|
864
861
|
}
|
|
865
862
|
if (Array.isArray(value)) {
|
|
866
863
|
resolved[key] = value.map(
|
|
867
|
-
(item) =>
|
|
864
|
+
(item) => isRecord2(item) ? deepResolveRefs(document, item) : item
|
|
868
865
|
);
|
|
869
866
|
continue;
|
|
870
867
|
}
|
|
@@ -872,6 +869,24 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
872
869
|
}
|
|
873
870
|
return resolved;
|
|
874
871
|
}
|
|
872
|
+
function resolveRefs(obj, document) {
|
|
873
|
+
return deepResolveRefs(document, obj);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// src/core/layers/l3.ts
|
|
877
|
+
function findMatchingOpenApiPath(paths, targetPath) {
|
|
878
|
+
const exact = paths[targetPath];
|
|
879
|
+
if (isRecord(exact)) return { matchedPath: targetPath, pathItem: exact };
|
|
880
|
+
for (const [specPath, entry] of Object.entries(paths)) {
|
|
881
|
+
if (!isRecord(entry)) continue;
|
|
882
|
+
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
883
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
884
|
+
if (regex.test(targetPath)) {
|
|
885
|
+
return { matchedPath: specPath, pathItem: entry };
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
return null;
|
|
889
|
+
}
|
|
875
890
|
function extractRequestBodySchema(operationSchema) {
|
|
876
891
|
const requestBody = operationSchema.requestBody;
|
|
877
892
|
if (!isRecord(requestBody)) return void 0;
|
|
@@ -951,7 +966,7 @@ function getL3ForOpenAPI(openApi, path, method) {
|
|
|
951
966
|
if (!matched) return null;
|
|
952
967
|
const operation = matched.pathItem[method.toLowerCase()];
|
|
953
968
|
if (!isRecord(operation)) return null;
|
|
954
|
-
const resolvedOperation = resolveRefs(
|
|
969
|
+
const resolvedOperation = resolveRefs(operation, document);
|
|
955
970
|
const summary = typeof resolvedOperation.summary === "string" ? resolvedOperation.summary : typeof resolvedOperation.description === "string" ? resolvedOperation.description : void 0;
|
|
956
971
|
return {
|
|
957
972
|
source: "openapi",
|
package/dist/cli.js
CHANGED
|
@@ -168,7 +168,7 @@ function fetchSafe(url, init) {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
// src/mmm-enabled.ts
|
|
171
|
-
var isMmmEnabled = () => "1.0
|
|
171
|
+
var isMmmEnabled = () => "1.1.0".includes("-mmm");
|
|
172
172
|
|
|
173
173
|
// src/core/source/openapi/index.ts
|
|
174
174
|
var OpenApiParsedSchema = OpenApiDocSchema.transform((doc) => {
|
|
@@ -334,6 +334,7 @@ var AUDIT_CODES = {
|
|
|
334
334
|
L2_NO_ROUTES: "L2_NO_ROUTES",
|
|
335
335
|
L2_ROUTE_COUNT_HIGH: "L2_ROUTE_COUNT_HIGH",
|
|
336
336
|
L2_AUTH_MODE_MISSING: "L2_AUTH_MODE_MISSING",
|
|
337
|
+
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
337
338
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
338
339
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
339
340
|
// ─── L3 endpoint advisory checks ─────────────────────────────────────────────
|
|
@@ -395,6 +396,15 @@ function getWarningsForL2(l2) {
|
|
|
395
396
|
});
|
|
396
397
|
return warnings;
|
|
397
398
|
}
|
|
399
|
+
const hasPaidRoute = l2.routes.some((r) => r.authMode === "paid" || r.authMode === "apiKey+paid");
|
|
400
|
+
if (!hasPaidRoute) {
|
|
401
|
+
warnings.push({
|
|
402
|
+
code: AUDIT_CODES.L2_NO_PAID_ROUTES,
|
|
403
|
+
severity: "info",
|
|
404
|
+
message: "No endpoints are marked as paid or apiKey+paid.",
|
|
405
|
+
hint: "Add x-payment-info to operations that require payment so agents know which endpoints are monetized."
|
|
406
|
+
});
|
|
407
|
+
}
|
|
398
408
|
if (l2.routes.length > ROUTE_COUNT_HIGH) {
|
|
399
409
|
warnings.push({
|
|
400
410
|
code: AUDIT_CODES.L2_ROUTE_COUNT_HIGH,
|
|
@@ -481,8 +491,8 @@ function getWarningsForL4(l4) {
|
|
|
481
491
|
{
|
|
482
492
|
code: AUDIT_CODES.L4_GUIDANCE_MISSING,
|
|
483
493
|
severity: "info",
|
|
484
|
-
message: "No guidance text found (
|
|
485
|
-
hint: "Add an info.guidance field to your OpenAPI spec
|
|
494
|
+
message: "No guidance text found (OpenAPI info.guidance).",
|
|
495
|
+
hint: "Add an info.guidance field to your OpenAPI spec for agent-readable instructions."
|
|
486
496
|
}
|
|
487
497
|
];
|
|
488
498
|
}
|
|
@@ -791,54 +801,31 @@ function extractPaymentOptions4(wwwAuthenticate) {
|
|
|
791
801
|
return options;
|
|
792
802
|
}
|
|
793
803
|
|
|
794
|
-
// src/core/
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
if (!isRecord(entry)) continue;
|
|
800
|
-
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
801
|
-
const regex = new RegExp(`^${pattern}$`);
|
|
802
|
-
if (regex.test(targetPath)) {
|
|
803
|
-
return { matchedPath: specPath, pathItem: entry };
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
return null;
|
|
807
|
-
}
|
|
808
|
-
function resolveRef(document, ref, seen) {
|
|
809
|
-
if (!ref.startsWith("#/")) return void 0;
|
|
810
|
-
if (seen.has(ref)) return { $circular: ref };
|
|
811
|
-
seen.add(ref);
|
|
812
|
-
const parts = ref.slice(2).split("/");
|
|
813
|
-
let current = document;
|
|
814
|
-
for (const part of parts) {
|
|
815
|
-
if (!isRecord(current)) return void 0;
|
|
816
|
-
current = current[part];
|
|
817
|
-
if (current === void 0) return void 0;
|
|
818
|
-
}
|
|
819
|
-
if (isRecord(current)) return resolveRefs(document, current, seen);
|
|
820
|
-
return current;
|
|
804
|
+
// src/core/lib/resolve-ref.ts
|
|
805
|
+
import pkg from "dereference-json-schema";
|
|
806
|
+
var { resolveRefSync } = pkg;
|
|
807
|
+
function isRecord2(value) {
|
|
808
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
821
809
|
}
|
|
822
|
-
function
|
|
823
|
-
if (depth > 4) return obj;
|
|
810
|
+
function deepResolveRefs(document, obj) {
|
|
824
811
|
const resolved = {};
|
|
825
812
|
for (const [key, value] of Object.entries(obj)) {
|
|
826
813
|
if (key === "$ref" && typeof value === "string") {
|
|
827
|
-
const deref =
|
|
828
|
-
if (
|
|
829
|
-
Object.assign(resolved, deref);
|
|
814
|
+
const deref = resolveRefSync(document, value);
|
|
815
|
+
if (isRecord2(deref)) {
|
|
816
|
+
Object.assign(resolved, deepResolveRefs(document, deref));
|
|
830
817
|
} else {
|
|
831
818
|
resolved[key] = value;
|
|
832
819
|
}
|
|
833
820
|
continue;
|
|
834
821
|
}
|
|
835
|
-
if (
|
|
836
|
-
resolved[key] =
|
|
822
|
+
if (isRecord2(value)) {
|
|
823
|
+
resolved[key] = deepResolveRefs(document, value);
|
|
837
824
|
continue;
|
|
838
825
|
}
|
|
839
826
|
if (Array.isArray(value)) {
|
|
840
827
|
resolved[key] = value.map(
|
|
841
|
-
(item) =>
|
|
828
|
+
(item) => isRecord2(item) ? deepResolveRefs(document, item) : item
|
|
842
829
|
);
|
|
843
830
|
continue;
|
|
844
831
|
}
|
|
@@ -846,6 +833,24 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
846
833
|
}
|
|
847
834
|
return resolved;
|
|
848
835
|
}
|
|
836
|
+
function resolveRefs(obj, document) {
|
|
837
|
+
return deepResolveRefs(document, obj);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// src/core/layers/l3.ts
|
|
841
|
+
function findMatchingOpenApiPath(paths, targetPath) {
|
|
842
|
+
const exact = paths[targetPath];
|
|
843
|
+
if (isRecord(exact)) return { matchedPath: targetPath, pathItem: exact };
|
|
844
|
+
for (const [specPath, entry] of Object.entries(paths)) {
|
|
845
|
+
if (!isRecord(entry)) continue;
|
|
846
|
+
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
847
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
848
|
+
if (regex.test(targetPath)) {
|
|
849
|
+
return { matchedPath: specPath, pathItem: entry };
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
849
854
|
function extractRequestBodySchema(operationSchema) {
|
|
850
855
|
const requestBody = operationSchema.requestBody;
|
|
851
856
|
if (!isRecord(requestBody)) return void 0;
|
|
@@ -925,7 +930,7 @@ function getL3ForOpenAPI(openApi, path, method) {
|
|
|
925
930
|
if (!matched) return null;
|
|
926
931
|
const operation = matched.pathItem[method.toLowerCase()];
|
|
927
932
|
if (!isRecord(operation)) return null;
|
|
928
|
-
const resolvedOperation = resolveRefs(
|
|
933
|
+
const resolvedOperation = resolveRefs(operation, document);
|
|
929
934
|
const summary = typeof resolvedOperation.summary === "string" ? resolvedOperation.summary : typeof resolvedOperation.description === "string" ? resolvedOperation.description : void 0;
|
|
930
935
|
return {
|
|
931
936
|
source: "openapi",
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -215,7 +225,7 @@ function fetchSafe(url, init) {
|
|
|
215
225
|
}
|
|
216
226
|
|
|
217
227
|
// src/mmm-enabled.ts
|
|
218
|
-
var isMmmEnabled = () => "1.0
|
|
228
|
+
var isMmmEnabled = () => "1.1.0".includes("-mmm");
|
|
219
229
|
|
|
220
230
|
// src/core/source/openapi/index.ts
|
|
221
231
|
var OpenApiParsedSchema = OpenApiDocSchema.transform((doc) => {
|
|
@@ -990,54 +1000,31 @@ function extractPaymentOptions4(wwwAuthenticate) {
|
|
|
990
1000
|
return options;
|
|
991
1001
|
}
|
|
992
1002
|
|
|
993
|
-
// src/core/
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
if (!isRecord(entry)) continue;
|
|
999
|
-
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
1000
|
-
const regex = new RegExp(`^${pattern}$`);
|
|
1001
|
-
if (regex.test(targetPath)) {
|
|
1002
|
-
return { matchedPath: specPath, pathItem: entry };
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
return null;
|
|
1006
|
-
}
|
|
1007
|
-
function resolveRef(document, ref, seen) {
|
|
1008
|
-
if (!ref.startsWith("#/")) return void 0;
|
|
1009
|
-
if (seen.has(ref)) return { $circular: ref };
|
|
1010
|
-
seen.add(ref);
|
|
1011
|
-
const parts = ref.slice(2).split("/");
|
|
1012
|
-
let current = document;
|
|
1013
|
-
for (const part of parts) {
|
|
1014
|
-
if (!isRecord(current)) return void 0;
|
|
1015
|
-
current = current[part];
|
|
1016
|
-
if (current === void 0) return void 0;
|
|
1017
|
-
}
|
|
1018
|
-
if (isRecord(current)) return resolveRefs(document, current, seen);
|
|
1019
|
-
return current;
|
|
1003
|
+
// src/core/lib/resolve-ref.ts
|
|
1004
|
+
var import_dereference_json_schema = __toESM(require("dereference-json-schema"), 1);
|
|
1005
|
+
var { resolveRefSync } = import_dereference_json_schema.default;
|
|
1006
|
+
function isRecord2(value) {
|
|
1007
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1020
1008
|
}
|
|
1021
|
-
function
|
|
1022
|
-
if (depth > 4) return obj;
|
|
1009
|
+
function deepResolveRefs(document, obj) {
|
|
1023
1010
|
const resolved = {};
|
|
1024
1011
|
for (const [key, value] of Object.entries(obj)) {
|
|
1025
1012
|
if (key === "$ref" && typeof value === "string") {
|
|
1026
|
-
const deref =
|
|
1027
|
-
if (
|
|
1028
|
-
Object.assign(resolved, deref);
|
|
1013
|
+
const deref = resolveRefSync(document, value);
|
|
1014
|
+
if (isRecord2(deref)) {
|
|
1015
|
+
Object.assign(resolved, deepResolveRefs(document, deref));
|
|
1029
1016
|
} else {
|
|
1030
1017
|
resolved[key] = value;
|
|
1031
1018
|
}
|
|
1032
1019
|
continue;
|
|
1033
1020
|
}
|
|
1034
|
-
if (
|
|
1035
|
-
resolved[key] =
|
|
1021
|
+
if (isRecord2(value)) {
|
|
1022
|
+
resolved[key] = deepResolveRefs(document, value);
|
|
1036
1023
|
continue;
|
|
1037
1024
|
}
|
|
1038
1025
|
if (Array.isArray(value)) {
|
|
1039
1026
|
resolved[key] = value.map(
|
|
1040
|
-
(item) =>
|
|
1027
|
+
(item) => isRecord2(item) ? deepResolveRefs(document, item) : item
|
|
1041
1028
|
);
|
|
1042
1029
|
continue;
|
|
1043
1030
|
}
|
|
@@ -1045,6 +1032,24 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
1045
1032
|
}
|
|
1046
1033
|
return resolved;
|
|
1047
1034
|
}
|
|
1035
|
+
function resolveRefs(obj, document) {
|
|
1036
|
+
return deepResolveRefs(document, obj);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// src/core/layers/l3.ts
|
|
1040
|
+
function findMatchingOpenApiPath(paths, targetPath) {
|
|
1041
|
+
const exact = paths[targetPath];
|
|
1042
|
+
if (isRecord(exact)) return { matchedPath: targetPath, pathItem: exact };
|
|
1043
|
+
for (const [specPath, entry] of Object.entries(paths)) {
|
|
1044
|
+
if (!isRecord(entry)) continue;
|
|
1045
|
+
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
1046
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
1047
|
+
if (regex.test(targetPath)) {
|
|
1048
|
+
return { matchedPath: specPath, pathItem: entry };
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
return null;
|
|
1052
|
+
}
|
|
1048
1053
|
function extractRequestBodySchema(operationSchema) {
|
|
1049
1054
|
const requestBody = operationSchema.requestBody;
|
|
1050
1055
|
if (!isRecord(requestBody)) return void 0;
|
|
@@ -1124,7 +1129,7 @@ function getL3ForOpenAPI(openApi, path, method) {
|
|
|
1124
1129
|
if (!matched) return null;
|
|
1125
1130
|
const operation = matched.pathItem[method.toLowerCase()];
|
|
1126
1131
|
if (!isRecord(operation)) return null;
|
|
1127
|
-
const resolvedOperation = resolveRefs(
|
|
1132
|
+
const resolvedOperation = resolveRefs(operation, document);
|
|
1128
1133
|
const summary = typeof resolvedOperation.summary === "string" ? resolvedOperation.summary : typeof resolvedOperation.description === "string" ? resolvedOperation.description : void 0;
|
|
1129
1134
|
return {
|
|
1130
1135
|
source: "openapi",
|
|
@@ -1309,7 +1314,7 @@ var import_schemas3 = require("@x402/core/schemas");
|
|
|
1309
1314
|
var DEFAULT_COMPAT_MODE = "on";
|
|
1310
1315
|
|
|
1311
1316
|
// src/x402scan-validation/payment-required.ts
|
|
1312
|
-
function
|
|
1317
|
+
function isRecord3(value) {
|
|
1313
1318
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1314
1319
|
}
|
|
1315
1320
|
function pushIssue2(issues, issue) {
|
|
@@ -1363,7 +1368,7 @@ function validatePaymentRequiredDetailed(payload, options = {}) {
|
|
|
1363
1368
|
const compatMode = options.compatMode ?? DEFAULT_COMPAT_MODE;
|
|
1364
1369
|
const requireInputSchema = options.requireInputSchema ?? true;
|
|
1365
1370
|
const requireOutputSchema = options.requireOutputSchema ?? true;
|
|
1366
|
-
if (!
|
|
1371
|
+
if (!isRecord3(payload)) {
|
|
1367
1372
|
pushIssue2(issues, {
|
|
1368
1373
|
code: VALIDATION_CODES.X402_NOT_OBJECT,
|
|
1369
1374
|
severity: "error",
|
|
@@ -1482,6 +1487,7 @@ var AUDIT_CODES = {
|
|
|
1482
1487
|
L2_NO_ROUTES: "L2_NO_ROUTES",
|
|
1483
1488
|
L2_ROUTE_COUNT_HIGH: "L2_ROUTE_COUNT_HIGH",
|
|
1484
1489
|
L2_AUTH_MODE_MISSING: "L2_AUTH_MODE_MISSING",
|
|
1490
|
+
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
1485
1491
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
1486
1492
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
1487
1493
|
// ─── L3 endpoint advisory checks ─────────────────────────────────────────────
|
|
@@ -1543,6 +1549,15 @@ function getWarningsForL2(l2) {
|
|
|
1543
1549
|
});
|
|
1544
1550
|
return warnings;
|
|
1545
1551
|
}
|
|
1552
|
+
const hasPaidRoute = l2.routes.some((r) => r.authMode === "paid" || r.authMode === "apiKey+paid");
|
|
1553
|
+
if (!hasPaidRoute) {
|
|
1554
|
+
warnings.push({
|
|
1555
|
+
code: AUDIT_CODES.L2_NO_PAID_ROUTES,
|
|
1556
|
+
severity: "info",
|
|
1557
|
+
message: "No endpoints are marked as paid or apiKey+paid.",
|
|
1558
|
+
hint: "Add x-payment-info to operations that require payment so agents know which endpoints are monetized."
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1546
1561
|
if (l2.routes.length > ROUTE_COUNT_HIGH) {
|
|
1547
1562
|
warnings.push({
|
|
1548
1563
|
code: AUDIT_CODES.L2_ROUTE_COUNT_HIGH,
|
|
@@ -1629,8 +1644,8 @@ function getWarningsForL4(l4) {
|
|
|
1629
1644
|
{
|
|
1630
1645
|
code: AUDIT_CODES.L4_GUIDANCE_MISSING,
|
|
1631
1646
|
severity: "info",
|
|
1632
|
-
message: "No guidance text found (
|
|
1633
|
-
hint: "Add an info.guidance field to your OpenAPI spec
|
|
1647
|
+
message: "No guidance text found (OpenAPI info.guidance).",
|
|
1648
|
+
hint: "Add an info.guidance field to your OpenAPI spec for agent-readable instructions."
|
|
1634
1649
|
}
|
|
1635
1650
|
];
|
|
1636
1651
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -325,6 +325,7 @@ declare const AUDIT_CODES: {
|
|
|
325
325
|
readonly L2_NO_ROUTES: "L2_NO_ROUTES";
|
|
326
326
|
readonly L2_ROUTE_COUNT_HIGH: "L2_ROUTE_COUNT_HIGH";
|
|
327
327
|
readonly L2_AUTH_MODE_MISSING: "L2_AUTH_MODE_MISSING";
|
|
328
|
+
readonly L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES";
|
|
328
329
|
readonly L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID";
|
|
329
330
|
readonly L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID";
|
|
330
331
|
readonly L3_NOT_FOUND: "L3_NOT_FOUND";
|
package/dist/index.d.ts
CHANGED
|
@@ -325,6 +325,7 @@ declare const AUDIT_CODES: {
|
|
|
325
325
|
readonly L2_NO_ROUTES: "L2_NO_ROUTES";
|
|
326
326
|
readonly L2_ROUTE_COUNT_HIGH: "L2_ROUTE_COUNT_HIGH";
|
|
327
327
|
readonly L2_AUTH_MODE_MISSING: "L2_AUTH_MODE_MISSING";
|
|
328
|
+
readonly L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES";
|
|
328
329
|
readonly L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID";
|
|
329
330
|
readonly L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID";
|
|
330
331
|
readonly L3_NOT_FOUND: "L3_NOT_FOUND";
|
package/dist/index.js
CHANGED
|
@@ -168,7 +168,7 @@ function fetchSafe(url, init) {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
// src/mmm-enabled.ts
|
|
171
|
-
var isMmmEnabled = () => "1.0
|
|
171
|
+
var isMmmEnabled = () => "1.1.0".includes("-mmm");
|
|
172
172
|
|
|
173
173
|
// src/core/source/openapi/index.ts
|
|
174
174
|
var OpenApiParsedSchema = OpenApiDocSchema.transform((doc) => {
|
|
@@ -943,54 +943,31 @@ function extractPaymentOptions4(wwwAuthenticate) {
|
|
|
943
943
|
return options;
|
|
944
944
|
}
|
|
945
945
|
|
|
946
|
-
// src/core/
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
if (!isRecord(entry)) continue;
|
|
952
|
-
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
953
|
-
const regex = new RegExp(`^${pattern}$`);
|
|
954
|
-
if (regex.test(targetPath)) {
|
|
955
|
-
return { matchedPath: specPath, pathItem: entry };
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
return null;
|
|
959
|
-
}
|
|
960
|
-
function resolveRef(document, ref, seen) {
|
|
961
|
-
if (!ref.startsWith("#/")) return void 0;
|
|
962
|
-
if (seen.has(ref)) return { $circular: ref };
|
|
963
|
-
seen.add(ref);
|
|
964
|
-
const parts = ref.slice(2).split("/");
|
|
965
|
-
let current = document;
|
|
966
|
-
for (const part of parts) {
|
|
967
|
-
if (!isRecord(current)) return void 0;
|
|
968
|
-
current = current[part];
|
|
969
|
-
if (current === void 0) return void 0;
|
|
970
|
-
}
|
|
971
|
-
if (isRecord(current)) return resolveRefs(document, current, seen);
|
|
972
|
-
return current;
|
|
946
|
+
// src/core/lib/resolve-ref.ts
|
|
947
|
+
import pkg from "dereference-json-schema";
|
|
948
|
+
var { resolveRefSync } = pkg;
|
|
949
|
+
function isRecord2(value) {
|
|
950
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
973
951
|
}
|
|
974
|
-
function
|
|
975
|
-
if (depth > 4) return obj;
|
|
952
|
+
function deepResolveRefs(document, obj) {
|
|
976
953
|
const resolved = {};
|
|
977
954
|
for (const [key, value] of Object.entries(obj)) {
|
|
978
955
|
if (key === "$ref" && typeof value === "string") {
|
|
979
|
-
const deref =
|
|
980
|
-
if (
|
|
981
|
-
Object.assign(resolved, deref);
|
|
956
|
+
const deref = resolveRefSync(document, value);
|
|
957
|
+
if (isRecord2(deref)) {
|
|
958
|
+
Object.assign(resolved, deepResolveRefs(document, deref));
|
|
982
959
|
} else {
|
|
983
960
|
resolved[key] = value;
|
|
984
961
|
}
|
|
985
962
|
continue;
|
|
986
963
|
}
|
|
987
|
-
if (
|
|
988
|
-
resolved[key] =
|
|
964
|
+
if (isRecord2(value)) {
|
|
965
|
+
resolved[key] = deepResolveRefs(document, value);
|
|
989
966
|
continue;
|
|
990
967
|
}
|
|
991
968
|
if (Array.isArray(value)) {
|
|
992
969
|
resolved[key] = value.map(
|
|
993
|
-
(item) =>
|
|
970
|
+
(item) => isRecord2(item) ? deepResolveRefs(document, item) : item
|
|
994
971
|
);
|
|
995
972
|
continue;
|
|
996
973
|
}
|
|
@@ -998,6 +975,24 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
998
975
|
}
|
|
999
976
|
return resolved;
|
|
1000
977
|
}
|
|
978
|
+
function resolveRefs(obj, document) {
|
|
979
|
+
return deepResolveRefs(document, obj);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// src/core/layers/l3.ts
|
|
983
|
+
function findMatchingOpenApiPath(paths, targetPath) {
|
|
984
|
+
const exact = paths[targetPath];
|
|
985
|
+
if (isRecord(exact)) return { matchedPath: targetPath, pathItem: exact };
|
|
986
|
+
for (const [specPath, entry] of Object.entries(paths)) {
|
|
987
|
+
if (!isRecord(entry)) continue;
|
|
988
|
+
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
989
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
990
|
+
if (regex.test(targetPath)) {
|
|
991
|
+
return { matchedPath: specPath, pathItem: entry };
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
return null;
|
|
995
|
+
}
|
|
1001
996
|
function extractRequestBodySchema(operationSchema) {
|
|
1002
997
|
const requestBody = operationSchema.requestBody;
|
|
1003
998
|
if (!isRecord(requestBody)) return void 0;
|
|
@@ -1077,7 +1072,7 @@ function getL3ForOpenAPI(openApi, path, method) {
|
|
|
1077
1072
|
if (!matched) return null;
|
|
1078
1073
|
const operation = matched.pathItem[method.toLowerCase()];
|
|
1079
1074
|
if (!isRecord(operation)) return null;
|
|
1080
|
-
const resolvedOperation = resolveRefs(
|
|
1075
|
+
const resolvedOperation = resolveRefs(operation, document);
|
|
1081
1076
|
const summary = typeof resolvedOperation.summary === "string" ? resolvedOperation.summary : typeof resolvedOperation.description === "string" ? resolvedOperation.description : void 0;
|
|
1082
1077
|
return {
|
|
1083
1078
|
source: "openapi",
|
|
@@ -1262,7 +1257,7 @@ import { parsePaymentRequired } from "@x402/core/schemas";
|
|
|
1262
1257
|
var DEFAULT_COMPAT_MODE = "on";
|
|
1263
1258
|
|
|
1264
1259
|
// src/x402scan-validation/payment-required.ts
|
|
1265
|
-
function
|
|
1260
|
+
function isRecord3(value) {
|
|
1266
1261
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1267
1262
|
}
|
|
1268
1263
|
function pushIssue2(issues, issue) {
|
|
@@ -1316,7 +1311,7 @@ function validatePaymentRequiredDetailed(payload, options = {}) {
|
|
|
1316
1311
|
const compatMode = options.compatMode ?? DEFAULT_COMPAT_MODE;
|
|
1317
1312
|
const requireInputSchema = options.requireInputSchema ?? true;
|
|
1318
1313
|
const requireOutputSchema = options.requireOutputSchema ?? true;
|
|
1319
|
-
if (!
|
|
1314
|
+
if (!isRecord3(payload)) {
|
|
1320
1315
|
pushIssue2(issues, {
|
|
1321
1316
|
code: VALIDATION_CODES.X402_NOT_OBJECT,
|
|
1322
1317
|
severity: "error",
|
|
@@ -1435,6 +1430,7 @@ var AUDIT_CODES = {
|
|
|
1435
1430
|
L2_NO_ROUTES: "L2_NO_ROUTES",
|
|
1436
1431
|
L2_ROUTE_COUNT_HIGH: "L2_ROUTE_COUNT_HIGH",
|
|
1437
1432
|
L2_AUTH_MODE_MISSING: "L2_AUTH_MODE_MISSING",
|
|
1433
|
+
L2_NO_PAID_ROUTES: "L2_NO_PAID_ROUTES",
|
|
1438
1434
|
L2_PRICE_MISSING_ON_PAID: "L2_PRICE_MISSING_ON_PAID",
|
|
1439
1435
|
L2_PROTOCOLS_MISSING_ON_PAID: "L2_PROTOCOLS_MISSING_ON_PAID",
|
|
1440
1436
|
// ─── L3 endpoint advisory checks ─────────────────────────────────────────────
|
|
@@ -1496,6 +1492,15 @@ function getWarningsForL2(l2) {
|
|
|
1496
1492
|
});
|
|
1497
1493
|
return warnings;
|
|
1498
1494
|
}
|
|
1495
|
+
const hasPaidRoute = l2.routes.some((r) => r.authMode === "paid" || r.authMode === "apiKey+paid");
|
|
1496
|
+
if (!hasPaidRoute) {
|
|
1497
|
+
warnings.push({
|
|
1498
|
+
code: AUDIT_CODES.L2_NO_PAID_ROUTES,
|
|
1499
|
+
severity: "info",
|
|
1500
|
+
message: "No endpoints are marked as paid or apiKey+paid.",
|
|
1501
|
+
hint: "Add x-payment-info to operations that require payment so agents know which endpoints are monetized."
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1499
1504
|
if (l2.routes.length > ROUTE_COUNT_HIGH) {
|
|
1500
1505
|
warnings.push({
|
|
1501
1506
|
code: AUDIT_CODES.L2_ROUTE_COUNT_HIGH,
|
|
@@ -1582,8 +1587,8 @@ function getWarningsForL4(l4) {
|
|
|
1582
1587
|
{
|
|
1583
1588
|
code: AUDIT_CODES.L4_GUIDANCE_MISSING,
|
|
1584
1589
|
severity: "info",
|
|
1585
|
-
message: "No guidance text found (
|
|
1586
|
-
hint: "Add an info.guidance field to your OpenAPI spec
|
|
1590
|
+
message: "No guidance text found (OpenAPI info.guidance).",
|
|
1591
|
+
hint: "Add an info.guidance field to your OpenAPI spec for agent-readable instructions."
|
|
1587
1592
|
}
|
|
1588
1593
|
];
|
|
1589
1594
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentcash/discovery",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Canonical OpenAPI-first discovery runtime for the agentcash ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@x402/core": "^2.5.0",
|
|
68
|
+
"dereference-json-schema": "^0.2.2",
|
|
68
69
|
"neverthrow": "^8.2.0",
|
|
69
70
|
"zod": "^4.0.0"
|
|
70
71
|
},
|