@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/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
LEGACY_SUNSET_DATE: () => LEGACY_SUNSET_DATE,
|
|
25
25
|
STRICT_ESCALATION_CODES: () => STRICT_ESCALATION_CODES,
|
|
26
26
|
UPGRADE_WARNING_CODES: () => UPGRADE_WARNING_CODES,
|
|
27
|
+
VALIDATION_CODES: () => VALIDATION_CODES,
|
|
27
28
|
auditContextHarness: () => auditContextHarness,
|
|
28
29
|
buildContextHarnessReport: () => buildContextHarnessReport,
|
|
29
30
|
computeUpgradeSignal: () => computeUpgradeSignal,
|
|
@@ -31,9 +32,11 @@ __export(index_exports, {
|
|
|
31
32
|
discover: () => discover,
|
|
32
33
|
discoverDetailed: () => discoverDetailed,
|
|
33
34
|
discoverForMcp: () => discoverForMcp,
|
|
35
|
+
evaluateMetadataCompleteness: () => evaluateMetadataCompleteness,
|
|
34
36
|
getHarnessClientProfile: () => getHarnessClientProfile,
|
|
35
37
|
inspectEndpointForMcp: () => inspectEndpointForMcp,
|
|
36
|
-
listHarnessClientProfiles: () => listHarnessClientProfiles
|
|
38
|
+
listHarnessClientProfiles: () => listHarnessClientProfiles,
|
|
39
|
+
validatePaymentRequiredDetailed: () => validatePaymentRequiredDetailed
|
|
37
40
|
});
|
|
38
41
|
module.exports = __toCommonJS(index_exports);
|
|
39
42
|
|
|
@@ -51,7 +54,7 @@ var STRICT_ESCALATION_CODES = [
|
|
|
51
54
|
];
|
|
52
55
|
|
|
53
56
|
// src/mmm-enabled.ts
|
|
54
|
-
var isMmmEnabled = () => "0.1.
|
|
57
|
+
var isMmmEnabled = () => "0.1.4".includes("-mmm");
|
|
55
58
|
|
|
56
59
|
// src/core/constants.ts
|
|
57
60
|
var OPENAPI_PATH_CANDIDATES = ["/openapi.json", "/.well-known/openapi.json"];
|
|
@@ -221,7 +224,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
|
|
|
221
224
|
"Using /.well-known/x402.instructions as compatibility guidance fallback. Prefer llms.txt.",
|
|
222
225
|
{
|
|
223
226
|
stage: "well-known/x402",
|
|
224
|
-
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."
|
|
225
228
|
}
|
|
226
229
|
)
|
|
227
230
|
);
|
|
@@ -234,7 +237,7 @@ function parseWellKnownPayload(payload, origin, sourceUrl) {
|
|
|
234
237
|
"Using /.well-known/x402.ownershipProofs compatibility field. Prefer OpenAPI provenance extension.",
|
|
235
238
|
{
|
|
236
239
|
stage: "well-known/x402",
|
|
237
|
-
hint: "Move ownership proofs to x-
|
|
240
|
+
hint: "Move ownership proofs to x-discovery.ownershipProofs in OpenAPI."
|
|
238
241
|
}
|
|
239
242
|
)
|
|
240
243
|
);
|
|
@@ -630,10 +633,31 @@ function estimateTokenCount(text) {
|
|
|
630
633
|
return Math.ceil(text.length / 4);
|
|
631
634
|
}
|
|
632
635
|
|
|
633
|
-
// src/core/openapi.ts
|
|
636
|
+
// src/core/openapi-utils.ts
|
|
634
637
|
function isRecord3(value) {
|
|
635
638
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
636
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
|
|
637
661
|
function asString(value) {
|
|
638
662
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
639
663
|
}
|
|
@@ -642,11 +666,6 @@ function parsePriceValue(value) {
|
|
|
642
666
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
643
667
|
return void 0;
|
|
644
668
|
}
|
|
645
|
-
function require402Response(operation) {
|
|
646
|
-
const responses = operation.responses;
|
|
647
|
-
if (!isRecord3(responses)) return false;
|
|
648
|
-
return Boolean(responses["402"]);
|
|
649
|
-
}
|
|
650
669
|
function parseProtocols(paymentInfo) {
|
|
651
670
|
const protocols = paymentInfo.protocols;
|
|
652
671
|
if (!Array.isArray(protocols)) return [];
|
|
@@ -654,15 +673,6 @@ function parseProtocols(paymentInfo) {
|
|
|
654
673
|
(entry) => typeof entry === "string" && entry.length > 0
|
|
655
674
|
);
|
|
656
675
|
}
|
|
657
|
-
function parseAuthMode(operation) {
|
|
658
|
-
const auth = operation["x-agentcash-auth"];
|
|
659
|
-
if (!isRecord3(auth)) return void 0;
|
|
660
|
-
const mode = auth.mode;
|
|
661
|
-
if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
|
|
662
|
-
return mode;
|
|
663
|
-
}
|
|
664
|
-
return void 0;
|
|
665
|
-
}
|
|
666
676
|
async function runOpenApiStage(options) {
|
|
667
677
|
const warnings = [];
|
|
668
678
|
const resources = [];
|
|
@@ -734,10 +744,9 @@ async function runOpenApiStage(options) {
|
|
|
734
744
|
};
|
|
735
745
|
}
|
|
736
746
|
const paths = document.paths;
|
|
737
|
-
const
|
|
738
|
-
const ownershipProofs = Array.isArray(
|
|
739
|
-
const
|
|
740
|
-
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);
|
|
741
750
|
if (ownershipProofs.length > 0) {
|
|
742
751
|
warnings.push(
|
|
743
752
|
warning("OPENAPI_OWNERSHIP_PROOFS_PRESENT", "info", "OpenAPI ownership proofs detected", {
|
|
@@ -782,13 +791,13 @@ async function runOpenApiStage(options) {
|
|
|
782
791
|
)
|
|
783
792
|
);
|
|
784
793
|
}
|
|
785
|
-
const authMode =
|
|
794
|
+
const authMode = inferAuthMode(operation);
|
|
786
795
|
if (!authMode) {
|
|
787
796
|
warnings.push(
|
|
788
797
|
warning(
|
|
789
798
|
"OPENAPI_AUTH_MODE_MISSING",
|
|
790
799
|
"error",
|
|
791
|
-
`${method} ${rawPath} missing x-
|
|
800
|
+
`${method} ${rawPath} missing auth mode (no x-payment-info, 402 response, or security scheme)`,
|
|
792
801
|
{
|
|
793
802
|
stage: "openapi"
|
|
794
803
|
}
|
|
@@ -796,7 +805,7 @@ async function runOpenApiStage(options) {
|
|
|
796
805
|
);
|
|
797
806
|
continue;
|
|
798
807
|
}
|
|
799
|
-
if ((authMode === "paid" || authMode === "siwx") && !
|
|
808
|
+
if ((authMode === "paid" || authMode === "siwx") && !has402Response(operation)) {
|
|
800
809
|
warnings.push(
|
|
801
810
|
warning(
|
|
802
811
|
"OPENAPI_402_MISSING",
|
|
@@ -1375,11 +1384,6 @@ async function runDiscovery({
|
|
|
1375
1384
|
}
|
|
1376
1385
|
}
|
|
1377
1386
|
}
|
|
1378
|
-
if (!stageResult.valid) {
|
|
1379
|
-
continue;
|
|
1380
|
-
}
|
|
1381
|
-
const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
|
|
1382
|
-
warnings.push(...mergeWarnings);
|
|
1383
1387
|
if (includeRaw && stageResult.raw !== void 0) {
|
|
1384
1388
|
if (stageResult.stage === "openapi" || stageResult.stage === "override") {
|
|
1385
1389
|
const rawObject = stageResult.raw;
|
|
@@ -1399,6 +1403,11 @@ async function runDiscovery({
|
|
|
1399
1403
|
rawSources.interopMpp = stageResult.raw;
|
|
1400
1404
|
}
|
|
1401
1405
|
}
|
|
1406
|
+
if (!stageResult.valid) {
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
const mergeWarnings = mergeResources(merged, stageResult.resources, resourceWarnings);
|
|
1410
|
+
warnings.push(...mergeWarnings);
|
|
1402
1411
|
if (!detailed) {
|
|
1403
1412
|
selectedStage = selectedStage ?? stageResult.stage;
|
|
1404
1413
|
break;
|
|
@@ -1439,6 +1448,471 @@ async function runDiscovery({
|
|
|
1439
1448
|
};
|
|
1440
1449
|
}
|
|
1441
1450
|
|
|
1451
|
+
// src/validation/codes.ts
|
|
1452
|
+
var VALIDATION_CODES = {
|
|
1453
|
+
COINBASE_SCHEMA_INVALID: "COINBASE_SCHEMA_INVALID",
|
|
1454
|
+
X402_NOT_OBJECT: "X402_NOT_OBJECT",
|
|
1455
|
+
X402_VERSION_MISSING: "X402_VERSION_MISSING",
|
|
1456
|
+
X402_VERSION_UNSUPPORTED: "X402_VERSION_UNSUPPORTED",
|
|
1457
|
+
X402_ACCEPTS_MISSING: "X402_ACCEPTS_MISSING",
|
|
1458
|
+
X402_ACCEPTS_INVALID: "X402_ACCEPTS_INVALID",
|
|
1459
|
+
X402_ACCEPTS_EMPTY: "X402_ACCEPTS_EMPTY",
|
|
1460
|
+
X402_ACCEPT_ENTRY_INVALID: "X402_ACCEPT_ENTRY_INVALID",
|
|
1461
|
+
NETWORK_CAIP2_INVALID: "NETWORK_CAIP2_INVALID",
|
|
1462
|
+
NETWORK_EIP155_REFERENCE_INVALID: "NETWORK_EIP155_REFERENCE_INVALID",
|
|
1463
|
+
NETWORK_SOLANA_ALIAS_INVALID: "NETWORK_SOLANA_ALIAS_INVALID",
|
|
1464
|
+
NETWORK_SOLANA_ALIAS_COMPAT: "NETWORK_SOLANA_ALIAS_COMPAT",
|
|
1465
|
+
NETWORK_REFERENCE_UNKNOWN: "NETWORK_REFERENCE_UNKNOWN",
|
|
1466
|
+
SCHEMA_INPUT_MISSING: "SCHEMA_INPUT_MISSING",
|
|
1467
|
+
SCHEMA_OUTPUT_MISSING: "SCHEMA_OUTPUT_MISSING",
|
|
1468
|
+
METADATA_TITLE_MISSING: "METADATA_TITLE_MISSING",
|
|
1469
|
+
METADATA_DESCRIPTION_MISSING: "METADATA_DESCRIPTION_MISSING",
|
|
1470
|
+
METADATA_FAVICON_MISSING: "METADATA_FAVICON_MISSING",
|
|
1471
|
+
METADATA_OG_IMAGE_MISSING: "METADATA_OG_IMAGE_MISSING"
|
|
1472
|
+
};
|
|
1473
|
+
|
|
1474
|
+
// src/validation/metadata.ts
|
|
1475
|
+
function hasText(value) {
|
|
1476
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
1477
|
+
}
|
|
1478
|
+
function hasOgImage(metadata) {
|
|
1479
|
+
const images = metadata.ogImages;
|
|
1480
|
+
if (!Array.isArray(images) || images.length === 0) return false;
|
|
1481
|
+
return images.some((entry) => {
|
|
1482
|
+
if (typeof entry === "string") {
|
|
1483
|
+
return entry.trim().length > 0;
|
|
1484
|
+
}
|
|
1485
|
+
if (!entry || typeof entry !== "object") return false;
|
|
1486
|
+
return hasText(entry.url);
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
1489
|
+
function evaluateMetadataCompleteness(metadata) {
|
|
1490
|
+
const issues = [];
|
|
1491
|
+
if (!hasText(metadata.title)) {
|
|
1492
|
+
issues.push({
|
|
1493
|
+
code: VALIDATION_CODES.METADATA_TITLE_MISSING,
|
|
1494
|
+
severity: "warn",
|
|
1495
|
+
message: "Metadata title is missing",
|
|
1496
|
+
hint: "Provide a page title to improve discovery quality and UX.",
|
|
1497
|
+
path: "metadata.title",
|
|
1498
|
+
stage: "metadata"
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
if (!hasText(metadata.description)) {
|
|
1502
|
+
issues.push({
|
|
1503
|
+
code: VALIDATION_CODES.METADATA_DESCRIPTION_MISSING,
|
|
1504
|
+
severity: "warn",
|
|
1505
|
+
message: "Metadata description is missing",
|
|
1506
|
+
hint: "Provide a concise description for integrators and search previews.",
|
|
1507
|
+
path: "metadata.description",
|
|
1508
|
+
stage: "metadata"
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
1511
|
+
if (!hasText(metadata.favicon)) {
|
|
1512
|
+
issues.push({
|
|
1513
|
+
code: VALIDATION_CODES.METADATA_FAVICON_MISSING,
|
|
1514
|
+
severity: "warn",
|
|
1515
|
+
message: "Metadata favicon is missing",
|
|
1516
|
+
hint: "Expose a favicon URL for stronger brand attribution.",
|
|
1517
|
+
path: "metadata.favicon",
|
|
1518
|
+
stage: "metadata"
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
if (!hasOgImage(metadata)) {
|
|
1522
|
+
issues.push({
|
|
1523
|
+
code: VALIDATION_CODES.METADATA_OG_IMAGE_MISSING,
|
|
1524
|
+
severity: "warn",
|
|
1525
|
+
message: "Metadata OG image is missing",
|
|
1526
|
+
hint: "Provide an Open Graph image to improve sharing previews.",
|
|
1527
|
+
path: "metadata.ogImages",
|
|
1528
|
+
stage: "metadata"
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
return issues;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// src/validation/payment-required.ts
|
|
1535
|
+
var import_schemas = require("@x402/core/schemas");
|
|
1536
|
+
var SOLANA_CANONICAL_BY_REF = {
|
|
1537
|
+
"5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": "solana",
|
|
1538
|
+
EtWTRABZaYq6iMfeYKouRu166VU2xqa1: "solana-devnet",
|
|
1539
|
+
"4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z": "solana-testnet"
|
|
1540
|
+
};
|
|
1541
|
+
var SOLANA_ALIAS_BY_REF = {
|
|
1542
|
+
mainnet: "solana",
|
|
1543
|
+
devnet: "solana-devnet",
|
|
1544
|
+
testnet: "solana-testnet"
|
|
1545
|
+
};
|
|
1546
|
+
function isRecord4(value) {
|
|
1547
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1548
|
+
}
|
|
1549
|
+
function asNonEmptyString(value) {
|
|
1550
|
+
if (typeof value !== "string") return void 0;
|
|
1551
|
+
const trimmed = value.trim();
|
|
1552
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
1553
|
+
}
|
|
1554
|
+
function asPositiveNumber(value) {
|
|
1555
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
1556
|
+
}
|
|
1557
|
+
function pushIssue(issues, issue) {
|
|
1558
|
+
issues.push({
|
|
1559
|
+
stage: issue.stage ?? "payment_required",
|
|
1560
|
+
...issue
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
function summarizeIssues(issues) {
|
|
1564
|
+
const summary = {
|
|
1565
|
+
errorCount: 0,
|
|
1566
|
+
warnCount: 0,
|
|
1567
|
+
infoCount: 0,
|
|
1568
|
+
byCode: {}
|
|
1569
|
+
};
|
|
1570
|
+
for (const issue of issues) {
|
|
1571
|
+
if (issue.severity === "error") summary.errorCount += 1;
|
|
1572
|
+
else if (issue.severity === "warn") summary.warnCount += 1;
|
|
1573
|
+
else summary.infoCount += 1;
|
|
1574
|
+
summary.byCode[issue.code] = (summary.byCode[issue.code] ?? 0) + 1;
|
|
1575
|
+
}
|
|
1576
|
+
return summary;
|
|
1577
|
+
}
|
|
1578
|
+
function outputSchemaMissingSeverity(compatMode) {
|
|
1579
|
+
return compatMode === "strict" ? "error" : "warn";
|
|
1580
|
+
}
|
|
1581
|
+
function zodPathToString(path) {
|
|
1582
|
+
if (path.length === 0) return "$";
|
|
1583
|
+
let out = "";
|
|
1584
|
+
for (const segment of path) {
|
|
1585
|
+
if (typeof segment === "number") out += `[${segment}]`;
|
|
1586
|
+
else out += out.length === 0 ? segment : `.${segment}`;
|
|
1587
|
+
}
|
|
1588
|
+
return out;
|
|
1589
|
+
}
|
|
1590
|
+
function parseWithCoinbaseStructuralGate(payload, issues) {
|
|
1591
|
+
const baseParsed = (0, import_schemas.parsePaymentRequired)(payload);
|
|
1592
|
+
if (baseParsed.success) {
|
|
1593
|
+
return baseParsed.data;
|
|
1594
|
+
}
|
|
1595
|
+
for (const issue of baseParsed.error.issues) {
|
|
1596
|
+
pushIssue(issues, {
|
|
1597
|
+
code: VALIDATION_CODES.COINBASE_SCHEMA_INVALID,
|
|
1598
|
+
severity: "error",
|
|
1599
|
+
message: `Coinbase schema validation failed: ${issue.message}`,
|
|
1600
|
+
path: zodPathToString(issue.path),
|
|
1601
|
+
actual: issue.code
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
return void 0;
|
|
1605
|
+
}
|
|
1606
|
+
function validateV2Network(networkRaw, index, issues) {
|
|
1607
|
+
if (!/^[^:\s]+:[^:\s]+$/.test(networkRaw)) {
|
|
1608
|
+
pushIssue(issues, {
|
|
1609
|
+
code: VALIDATION_CODES.NETWORK_CAIP2_INVALID,
|
|
1610
|
+
severity: "error",
|
|
1611
|
+
message: `Accept at index ${index} has invalid CAIP-2 network format`,
|
|
1612
|
+
hint: "Expected '<namespace>:<reference>', e.g. 'eip155:8453' or 'solana:5eykt4...'.",
|
|
1613
|
+
path: `accepts[${index}].network`,
|
|
1614
|
+
expected: "<namespace>:<reference>",
|
|
1615
|
+
actual: networkRaw
|
|
1616
|
+
});
|
|
1617
|
+
return void 0;
|
|
1618
|
+
}
|
|
1619
|
+
const [namespace, reference] = networkRaw.split(":");
|
|
1620
|
+
if (namespace === "eip155") {
|
|
1621
|
+
if (!/^\d+$/.test(reference)) {
|
|
1622
|
+
pushIssue(issues, {
|
|
1623
|
+
code: VALIDATION_CODES.NETWORK_EIP155_REFERENCE_INVALID,
|
|
1624
|
+
severity: "error",
|
|
1625
|
+
message: `Accept at index ${index} has invalid eip155 reference`,
|
|
1626
|
+
hint: "Use a numeric chain id, e.g. 'eip155:8453'.",
|
|
1627
|
+
path: `accepts[${index}].network`,
|
|
1628
|
+
expected: "eip155:<numeric-chain-id>",
|
|
1629
|
+
actual: networkRaw
|
|
1630
|
+
});
|
|
1631
|
+
return void 0;
|
|
1632
|
+
}
|
|
1633
|
+
return networkRaw;
|
|
1634
|
+
}
|
|
1635
|
+
if (namespace === "solana") {
|
|
1636
|
+
const canonical = SOLANA_CANONICAL_BY_REF[reference];
|
|
1637
|
+
if (canonical) return canonical;
|
|
1638
|
+
const alias = SOLANA_ALIAS_BY_REF[reference];
|
|
1639
|
+
if (alias) {
|
|
1640
|
+
pushIssue(issues, {
|
|
1641
|
+
code: VALIDATION_CODES.NETWORK_SOLANA_ALIAS_COMPAT,
|
|
1642
|
+
severity: "warn",
|
|
1643
|
+
message: `Accept at index ${index} uses compatibility Solana reference '${reference}'`,
|
|
1644
|
+
hint: "Use canonical Solana CAIP references for deterministic behavior.",
|
|
1645
|
+
path: `accepts[${index}].network`,
|
|
1646
|
+
actual: networkRaw
|
|
1647
|
+
});
|
|
1648
|
+
return alias;
|
|
1649
|
+
}
|
|
1650
|
+
pushIssue(issues, {
|
|
1651
|
+
code: VALIDATION_CODES.NETWORK_REFERENCE_UNKNOWN,
|
|
1652
|
+
severity: "error",
|
|
1653
|
+
message: `Accept at index ${index} uses unknown Solana reference '${reference}'`,
|
|
1654
|
+
hint: "Use canonical references for mainnet/devnet/testnet.",
|
|
1655
|
+
path: `accepts[${index}].network`,
|
|
1656
|
+
actual: networkRaw
|
|
1657
|
+
});
|
|
1658
|
+
return void 0;
|
|
1659
|
+
}
|
|
1660
|
+
return networkRaw;
|
|
1661
|
+
}
|
|
1662
|
+
function validateV1Network(networkRaw, index, issues) {
|
|
1663
|
+
if (networkRaw === "solana-mainnet-beta") {
|
|
1664
|
+
pushIssue(issues, {
|
|
1665
|
+
code: VALIDATION_CODES.NETWORK_SOLANA_ALIAS_INVALID,
|
|
1666
|
+
severity: "error",
|
|
1667
|
+
message: `Accept at index ${index} uses invalid Solana network alias`,
|
|
1668
|
+
hint: "Use 'solana' (v1) or canonical Solana CAIP reference (v2).",
|
|
1669
|
+
path: `accepts[${index}].network`,
|
|
1670
|
+
expected: "solana",
|
|
1671
|
+
actual: networkRaw
|
|
1672
|
+
});
|
|
1673
|
+
return void 0;
|
|
1674
|
+
}
|
|
1675
|
+
if (networkRaw.startsWith("solana-") && networkRaw !== "solana-devnet") {
|
|
1676
|
+
pushIssue(issues, {
|
|
1677
|
+
code: VALIDATION_CODES.NETWORK_SOLANA_ALIAS_INVALID,
|
|
1678
|
+
severity: "error",
|
|
1679
|
+
message: `Accept at index ${index} uses unsupported Solana network alias`,
|
|
1680
|
+
hint: "Use 'solana' or 'solana-devnet' for v1 payloads.",
|
|
1681
|
+
path: `accepts[${index}].network`,
|
|
1682
|
+
actual: networkRaw
|
|
1683
|
+
});
|
|
1684
|
+
return void 0;
|
|
1685
|
+
}
|
|
1686
|
+
if (networkRaw.includes(":")) {
|
|
1687
|
+
return validateV2Network(networkRaw, index, issues);
|
|
1688
|
+
}
|
|
1689
|
+
return networkRaw;
|
|
1690
|
+
}
|
|
1691
|
+
function validateAccept(acceptRaw, index, version, issues) {
|
|
1692
|
+
if (!isRecord4(acceptRaw)) {
|
|
1693
|
+
pushIssue(issues, {
|
|
1694
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1695
|
+
severity: "error",
|
|
1696
|
+
message: `Accept at index ${index} must be an object`,
|
|
1697
|
+
path: `accepts[${index}]`
|
|
1698
|
+
});
|
|
1699
|
+
return null;
|
|
1700
|
+
}
|
|
1701
|
+
const scheme = asNonEmptyString(acceptRaw.scheme);
|
|
1702
|
+
const networkRaw = asNonEmptyString(acceptRaw.network);
|
|
1703
|
+
const payTo = asNonEmptyString(acceptRaw.payTo);
|
|
1704
|
+
const asset = asNonEmptyString(acceptRaw.asset);
|
|
1705
|
+
const maxTimeoutSeconds = asPositiveNumber(acceptRaw.maxTimeoutSeconds);
|
|
1706
|
+
const amount = version === 2 ? asNonEmptyString(acceptRaw.amount) : asNonEmptyString(acceptRaw.maxAmountRequired);
|
|
1707
|
+
if (!scheme) {
|
|
1708
|
+
pushIssue(issues, {
|
|
1709
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1710
|
+
severity: "error",
|
|
1711
|
+
message: `Accept at index ${index} is missing scheme`,
|
|
1712
|
+
path: `accepts[${index}].scheme`
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
if (!networkRaw) {
|
|
1716
|
+
pushIssue(issues, {
|
|
1717
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1718
|
+
severity: "error",
|
|
1719
|
+
message: `Accept at index ${index} is missing network`,
|
|
1720
|
+
path: `accepts[${index}].network`
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
if (!amount) {
|
|
1724
|
+
pushIssue(issues, {
|
|
1725
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1726
|
+
severity: "error",
|
|
1727
|
+
message: `Accept at index ${index} is missing ${version === 2 ? "amount" : "maxAmountRequired"}`,
|
|
1728
|
+
path: `accepts[${index}].${version === 2 ? "amount" : "maxAmountRequired"}`
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
if (!payTo) {
|
|
1732
|
+
pushIssue(issues, {
|
|
1733
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1734
|
+
severity: "error",
|
|
1735
|
+
message: `Accept at index ${index} is missing payTo`,
|
|
1736
|
+
path: `accepts[${index}].payTo`
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
if (!asset) {
|
|
1740
|
+
pushIssue(issues, {
|
|
1741
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1742
|
+
severity: "error",
|
|
1743
|
+
message: `Accept at index ${index} is missing asset`,
|
|
1744
|
+
path: `accepts[${index}].asset`
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
if (!maxTimeoutSeconds) {
|
|
1748
|
+
pushIssue(issues, {
|
|
1749
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1750
|
+
severity: "error",
|
|
1751
|
+
message: `Accept at index ${index} is missing or has invalid maxTimeoutSeconds`,
|
|
1752
|
+
path: `accepts[${index}].maxTimeoutSeconds`
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1755
|
+
let normalizedNetwork;
|
|
1756
|
+
if (networkRaw) {
|
|
1757
|
+
normalizedNetwork = version === 2 ? validateV2Network(networkRaw, index, issues) : validateV1Network(networkRaw, index, issues);
|
|
1758
|
+
}
|
|
1759
|
+
return {
|
|
1760
|
+
index,
|
|
1761
|
+
network: normalizedNetwork ?? networkRaw ?? "unknown",
|
|
1762
|
+
networkRaw: networkRaw ?? "unknown",
|
|
1763
|
+
scheme,
|
|
1764
|
+
asset,
|
|
1765
|
+
payTo,
|
|
1766
|
+
amount,
|
|
1767
|
+
maxTimeoutSeconds
|
|
1768
|
+
};
|
|
1769
|
+
}
|
|
1770
|
+
function getSchemaPresence(payload, accepts, version) {
|
|
1771
|
+
if (version === 1) {
|
|
1772
|
+
const first = accepts[0];
|
|
1773
|
+
if (!isRecord4(first)) {
|
|
1774
|
+
return { hasInputSchema: false, hasOutputSchema: false };
|
|
1775
|
+
}
|
|
1776
|
+
const outputSchema = isRecord4(first.outputSchema) ? first.outputSchema : void 0;
|
|
1777
|
+
return {
|
|
1778
|
+
hasInputSchema: outputSchema?.input !== void 0 && outputSchema.input !== null,
|
|
1779
|
+
hasOutputSchema: outputSchema?.output !== void 0 && outputSchema.output !== null
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
const extensions = isRecord4(payload.extensions) ? payload.extensions : void 0;
|
|
1783
|
+
const bazaar = extensions && isRecord4(extensions.bazaar) ? extensions.bazaar : void 0;
|
|
1784
|
+
const info = bazaar && isRecord4(bazaar.info) ? bazaar.info : void 0;
|
|
1785
|
+
return {
|
|
1786
|
+
hasInputSchema: info?.input !== void 0 && info.input !== null,
|
|
1787
|
+
hasOutputSchema: info?.output !== void 0 && info.output !== null
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1790
|
+
function validatePaymentRequiredDetailed(payload, options = {}) {
|
|
1791
|
+
const issues = [];
|
|
1792
|
+
const compatMode = options.compatMode ?? DEFAULT_COMPAT_MODE;
|
|
1793
|
+
const requireInputSchema = options.requireInputSchema ?? true;
|
|
1794
|
+
const requireOutputSchema = options.requireOutputSchema ?? true;
|
|
1795
|
+
if (!isRecord4(payload)) {
|
|
1796
|
+
pushIssue(issues, {
|
|
1797
|
+
code: VALIDATION_CODES.X402_NOT_OBJECT,
|
|
1798
|
+
severity: "error",
|
|
1799
|
+
message: "Payment required payload must be a JSON object",
|
|
1800
|
+
path: "$"
|
|
1801
|
+
});
|
|
1802
|
+
if (options.metadata) {
|
|
1803
|
+
issues.push(...evaluateMetadataCompleteness(options.metadata));
|
|
1804
|
+
}
|
|
1805
|
+
return {
|
|
1806
|
+
valid: false,
|
|
1807
|
+
issues,
|
|
1808
|
+
summary: summarizeIssues(issues)
|
|
1809
|
+
};
|
|
1810
|
+
}
|
|
1811
|
+
const coinbaseParsed = parseWithCoinbaseStructuralGate(payload, issues);
|
|
1812
|
+
const versionRaw = payload.x402Version;
|
|
1813
|
+
let version;
|
|
1814
|
+
if (versionRaw === 1 || versionRaw === 2) {
|
|
1815
|
+
version = versionRaw;
|
|
1816
|
+
} else if (versionRaw === void 0) {
|
|
1817
|
+
pushIssue(issues, {
|
|
1818
|
+
code: VALIDATION_CODES.X402_VERSION_MISSING,
|
|
1819
|
+
severity: "error",
|
|
1820
|
+
message: "x402Version is required",
|
|
1821
|
+
path: "x402Version"
|
|
1822
|
+
});
|
|
1823
|
+
} else {
|
|
1824
|
+
pushIssue(issues, {
|
|
1825
|
+
code: VALIDATION_CODES.X402_VERSION_UNSUPPORTED,
|
|
1826
|
+
severity: "error",
|
|
1827
|
+
message: `Unsupported x402Version '${String(versionRaw)}'`,
|
|
1828
|
+
path: "x402Version",
|
|
1829
|
+
expected: "1 | 2",
|
|
1830
|
+
actual: String(versionRaw)
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
const acceptsRaw = payload.accepts;
|
|
1834
|
+
let accepts = [];
|
|
1835
|
+
if (acceptsRaw === void 0) {
|
|
1836
|
+
pushIssue(issues, {
|
|
1837
|
+
code: VALIDATION_CODES.X402_ACCEPTS_MISSING,
|
|
1838
|
+
severity: "error",
|
|
1839
|
+
message: "accepts is required",
|
|
1840
|
+
path: "accepts"
|
|
1841
|
+
});
|
|
1842
|
+
} else if (!Array.isArray(acceptsRaw)) {
|
|
1843
|
+
pushIssue(issues, {
|
|
1844
|
+
code: VALIDATION_CODES.X402_ACCEPTS_INVALID,
|
|
1845
|
+
severity: "error",
|
|
1846
|
+
message: "accepts must be an array",
|
|
1847
|
+
path: "accepts"
|
|
1848
|
+
});
|
|
1849
|
+
} else {
|
|
1850
|
+
accepts = acceptsRaw;
|
|
1851
|
+
if (accepts.length === 0) {
|
|
1852
|
+
pushIssue(issues, {
|
|
1853
|
+
code: VALIDATION_CODES.X402_ACCEPTS_EMPTY,
|
|
1854
|
+
severity: "error",
|
|
1855
|
+
message: "accepts must contain at least one payment requirement",
|
|
1856
|
+
path: "accepts"
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
const normalizedAccepts = [];
|
|
1861
|
+
if (version && Array.isArray(accepts)) {
|
|
1862
|
+
accepts.forEach((accept, index) => {
|
|
1863
|
+
const normalized = validateAccept(accept, index, version, issues);
|
|
1864
|
+
if (normalized) normalizedAccepts.push(normalized);
|
|
1865
|
+
});
|
|
1866
|
+
const schemaPresence = getSchemaPresence(payload, accepts, version);
|
|
1867
|
+
if (requireInputSchema && !schemaPresence.hasInputSchema) {
|
|
1868
|
+
pushIssue(issues, {
|
|
1869
|
+
code: VALIDATION_CODES.SCHEMA_INPUT_MISSING,
|
|
1870
|
+
severity: "error",
|
|
1871
|
+
message: "Input schema is missing",
|
|
1872
|
+
hint: "Include input schema details so clients can invoke the endpoint correctly.",
|
|
1873
|
+
path: version === 1 ? "accepts[0].outputSchema.input" : "extensions.bazaar.info.input"
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
if (requireOutputSchema && !schemaPresence.hasOutputSchema) {
|
|
1877
|
+
pushIssue(issues, {
|
|
1878
|
+
code: VALIDATION_CODES.SCHEMA_OUTPUT_MISSING,
|
|
1879
|
+
severity: outputSchemaMissingSeverity(compatMode),
|
|
1880
|
+
message: "Output schema is missing",
|
|
1881
|
+
hint: "Include output schema details so clients can validate responses.",
|
|
1882
|
+
path: version === 1 ? "accepts[0].outputSchema.output" : "extensions.bazaar.info.output"
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
if (options.metadata) {
|
|
1886
|
+
issues.push(...evaluateMetadataCompleteness(options.metadata));
|
|
1887
|
+
}
|
|
1888
|
+
const summary2 = summarizeIssues(issues);
|
|
1889
|
+
return {
|
|
1890
|
+
valid: summary2.errorCount === 0,
|
|
1891
|
+
version,
|
|
1892
|
+
parsed: coinbaseParsed ?? payload,
|
|
1893
|
+
normalized: {
|
|
1894
|
+
version,
|
|
1895
|
+
accepts: normalizedAccepts,
|
|
1896
|
+
hasInputSchema: schemaPresence.hasInputSchema,
|
|
1897
|
+
hasOutputSchema: schemaPresence.hasOutputSchema
|
|
1898
|
+
},
|
|
1899
|
+
issues,
|
|
1900
|
+
summary: summary2
|
|
1901
|
+
};
|
|
1902
|
+
}
|
|
1903
|
+
if (options.metadata) {
|
|
1904
|
+
issues.push(...evaluateMetadataCompleteness(options.metadata));
|
|
1905
|
+
}
|
|
1906
|
+
const summary = summarizeIssues(issues);
|
|
1907
|
+
return {
|
|
1908
|
+
valid: summary.errorCount === 0,
|
|
1909
|
+
version,
|
|
1910
|
+
parsed: coinbaseParsed ?? payload,
|
|
1911
|
+
issues,
|
|
1912
|
+
summary
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1442
1916
|
// src/adapters/mcp.ts
|
|
1443
1917
|
var DEFAULT_GUIDANCE_AUTO_INCLUDE_MAX_TOKENS = 1e3;
|
|
1444
1918
|
var OPENAPI_METHODS = [
|
|
@@ -1451,9 +1925,6 @@ var OPENAPI_METHODS = [
|
|
|
1451
1925
|
"OPTIONS",
|
|
1452
1926
|
"TRACE"
|
|
1453
1927
|
];
|
|
1454
|
-
function isRecord4(value) {
|
|
1455
|
-
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
1456
|
-
}
|
|
1457
1928
|
function toFiniteNumber(value) {
|
|
1458
1929
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1459
1930
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
@@ -1511,7 +1982,7 @@ function inferFailureCause(warnings) {
|
|
|
1511
1982
|
return { cause: "not_found" };
|
|
1512
1983
|
}
|
|
1513
1984
|
function getOpenApiInfo(document) {
|
|
1514
|
-
if (!
|
|
1985
|
+
if (!isRecord3(document) || !isRecord3(document.info)) return void 0;
|
|
1515
1986
|
if (typeof document.info.title !== "string") return void 0;
|
|
1516
1987
|
return {
|
|
1517
1988
|
title: document.info.title,
|
|
@@ -1554,15 +2025,15 @@ async function resolveGuidance(options) {
|
|
|
1554
2025
|
};
|
|
1555
2026
|
}
|
|
1556
2027
|
function extractPathsDocument(document) {
|
|
1557
|
-
if (!
|
|
1558
|
-
if (!
|
|
2028
|
+
if (!isRecord3(document)) return void 0;
|
|
2029
|
+
if (!isRecord3(document.paths)) return void 0;
|
|
1559
2030
|
return document.paths;
|
|
1560
2031
|
}
|
|
1561
2032
|
function findMatchingOpenApiPath(paths, targetPath) {
|
|
1562
2033
|
const exact = paths[targetPath];
|
|
1563
|
-
if (
|
|
2034
|
+
if (isRecord3(exact)) return { matchedPath: targetPath, pathItem: exact };
|
|
1564
2035
|
for (const [specPath, entry] of Object.entries(paths)) {
|
|
1565
|
-
if (!
|
|
2036
|
+
if (!isRecord3(entry)) continue;
|
|
1566
2037
|
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
1567
2038
|
const regex = new RegExp(`^${pattern}$`);
|
|
1568
2039
|
if (regex.test(targetPath)) {
|
|
@@ -1578,11 +2049,11 @@ function resolveRef(document, ref, seen) {
|
|
|
1578
2049
|
const parts = ref.slice(2).split("/");
|
|
1579
2050
|
let current = document;
|
|
1580
2051
|
for (const part of parts) {
|
|
1581
|
-
if (!
|
|
2052
|
+
if (!isRecord3(current)) return void 0;
|
|
1582
2053
|
current = current[part];
|
|
1583
2054
|
if (current === void 0) return void 0;
|
|
1584
2055
|
}
|
|
1585
|
-
if (
|
|
2056
|
+
if (isRecord3(current)) return resolveRefs(document, current, seen);
|
|
1586
2057
|
return current;
|
|
1587
2058
|
}
|
|
1588
2059
|
function resolveRefs(document, obj, seen, depth = 0) {
|
|
@@ -1591,20 +2062,20 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
1591
2062
|
for (const [key, value] of Object.entries(obj)) {
|
|
1592
2063
|
if (key === "$ref" && typeof value === "string") {
|
|
1593
2064
|
const deref = resolveRef(document, value, seen);
|
|
1594
|
-
if (
|
|
2065
|
+
if (isRecord3(deref)) {
|
|
1595
2066
|
Object.assign(resolved, deref);
|
|
1596
2067
|
} else {
|
|
1597
2068
|
resolved[key] = value;
|
|
1598
2069
|
}
|
|
1599
2070
|
continue;
|
|
1600
2071
|
}
|
|
1601
|
-
if (
|
|
2072
|
+
if (isRecord3(value)) {
|
|
1602
2073
|
resolved[key] = resolveRefs(document, value, seen, depth + 1);
|
|
1603
2074
|
continue;
|
|
1604
2075
|
}
|
|
1605
2076
|
if (Array.isArray(value)) {
|
|
1606
2077
|
resolved[key] = value.map(
|
|
1607
|
-
(item) =>
|
|
2078
|
+
(item) => isRecord3(item) ? resolveRefs(document, item, seen, depth + 1) : item
|
|
1608
2079
|
);
|
|
1609
2080
|
continue;
|
|
1610
2081
|
}
|
|
@@ -1614,15 +2085,15 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
1614
2085
|
}
|
|
1615
2086
|
function extractRequestBodySchema(operationSchema) {
|
|
1616
2087
|
const requestBody = operationSchema.requestBody;
|
|
1617
|
-
if (!
|
|
2088
|
+
if (!isRecord3(requestBody)) return void 0;
|
|
1618
2089
|
const content = requestBody.content;
|
|
1619
|
-
if (!
|
|
2090
|
+
if (!isRecord3(content)) return void 0;
|
|
1620
2091
|
const jsonMediaType = content["application/json"];
|
|
1621
|
-
if (
|
|
2092
|
+
if (isRecord3(jsonMediaType) && isRecord3(jsonMediaType.schema)) {
|
|
1622
2093
|
return jsonMediaType.schema;
|
|
1623
2094
|
}
|
|
1624
2095
|
for (const mediaType of Object.values(content)) {
|
|
1625
|
-
if (
|
|
2096
|
+
if (isRecord3(mediaType) && isRecord3(mediaType.schema)) {
|
|
1626
2097
|
return mediaType.schema;
|
|
1627
2098
|
}
|
|
1628
2099
|
}
|
|
@@ -1631,7 +2102,7 @@ function extractRequestBodySchema(operationSchema) {
|
|
|
1631
2102
|
function extractParameters(operationSchema) {
|
|
1632
2103
|
const params = operationSchema.parameters;
|
|
1633
2104
|
if (!Array.isArray(params)) return [];
|
|
1634
|
-
return params.filter((value) =>
|
|
2105
|
+
return params.filter((value) => isRecord3(value));
|
|
1635
2106
|
}
|
|
1636
2107
|
function extractInputSchema(operationSchema) {
|
|
1637
2108
|
const requestBody = extractRequestBodySchema(operationSchema);
|
|
@@ -1645,7 +2116,7 @@ function extractInputSchema(operationSchema) {
|
|
|
1645
2116
|
}
|
|
1646
2117
|
function parseOperationPrice(operation) {
|
|
1647
2118
|
const paymentInfo = operation["x-payment-info"];
|
|
1648
|
-
if (!
|
|
2119
|
+
if (!isRecord3(paymentInfo)) return void 0;
|
|
1649
2120
|
const fixed = toFiniteNumber(paymentInfo.price);
|
|
1650
2121
|
if (fixed != null) return `$${String(fixed)}`;
|
|
1651
2122
|
const min = toFiniteNumber(paymentInfo.minPrice);
|
|
@@ -1655,23 +2126,12 @@ function parseOperationPrice(operation) {
|
|
|
1655
2126
|
}
|
|
1656
2127
|
function parseOperationProtocols(operation) {
|
|
1657
2128
|
const paymentInfo = operation["x-payment-info"];
|
|
1658
|
-
if (!
|
|
2129
|
+
if (!isRecord3(paymentInfo) || !Array.isArray(paymentInfo.protocols)) return void 0;
|
|
1659
2130
|
const protocols = paymentInfo.protocols.filter(
|
|
1660
2131
|
(protocol) => typeof protocol === "string" && protocol.length > 0
|
|
1661
2132
|
);
|
|
1662
2133
|
return protocols.length > 0 ? protocols : void 0;
|
|
1663
2134
|
}
|
|
1664
|
-
function parseOperationAuthMode(operation) {
|
|
1665
|
-
const authExtension = operation["x-agentcash-auth"];
|
|
1666
|
-
if (isRecord4(authExtension)) {
|
|
1667
|
-
const mode = authExtension.mode;
|
|
1668
|
-
if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
|
|
1669
|
-
return mode;
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
if (isRecord4(operation["x-payment-info"])) return "paid";
|
|
1673
|
-
return void 0;
|
|
1674
|
-
}
|
|
1675
2135
|
function createResourceMap(result) {
|
|
1676
2136
|
const map = /* @__PURE__ */ new Map();
|
|
1677
2137
|
for (const resource of result.resources) {
|
|
@@ -1763,7 +2223,7 @@ async function inspectEndpointForMcp(options) {
|
|
|
1763
2223
|
if (matched) {
|
|
1764
2224
|
for (const candidate of OPENAPI_METHODS) {
|
|
1765
2225
|
const operation = matched.pathItem[candidate.toLowerCase()];
|
|
1766
|
-
if (!
|
|
2226
|
+
if (!isRecord3(operation) || !isRecord3(document)) continue;
|
|
1767
2227
|
specMethods.push(candidate);
|
|
1768
2228
|
const resolvedOperation = resolveRefs(document, operation, /* @__PURE__ */ new Set());
|
|
1769
2229
|
const resource = resourceMap.get(toResourceKey(origin, candidate, matched.matchedPath));
|
|
@@ -1771,7 +2231,7 @@ async function inspectEndpointForMcp(options) {
|
|
|
1771
2231
|
const operationSummary = typeof resolvedOperation.summary === "string" ? resolvedOperation.summary : typeof resolvedOperation.description === "string" ? resolvedOperation.description : void 0;
|
|
1772
2232
|
const operationPrice = parseOperationPrice(resolvedOperation);
|
|
1773
2233
|
const operationProtocols = parseOperationProtocols(resolvedOperation);
|
|
1774
|
-
const operationAuthMode =
|
|
2234
|
+
const operationAuthMode = inferAuthMode(resolvedOperation) ?? "unprotected";
|
|
1775
2235
|
const inputSchema = extractInputSchema(resolvedOperation);
|
|
1776
2236
|
advisories[candidate] = {
|
|
1777
2237
|
method: candidate,
|
|
@@ -2082,6 +2542,7 @@ async function discoverDetailed(options) {
|
|
|
2082
2542
|
LEGACY_SUNSET_DATE,
|
|
2083
2543
|
STRICT_ESCALATION_CODES,
|
|
2084
2544
|
UPGRADE_WARNING_CODES,
|
|
2545
|
+
VALIDATION_CODES,
|
|
2085
2546
|
auditContextHarness,
|
|
2086
2547
|
buildContextHarnessReport,
|
|
2087
2548
|
computeUpgradeSignal,
|
|
@@ -2089,7 +2550,9 @@ async function discoverDetailed(options) {
|
|
|
2089
2550
|
discover,
|
|
2090
2551
|
discoverDetailed,
|
|
2091
2552
|
discoverForMcp,
|
|
2553
|
+
evaluateMetadataCompleteness,
|
|
2092
2554
|
getHarnessClientProfile,
|
|
2093
2555
|
inspectEndpointForMcp,
|
|
2094
|
-
listHarnessClientProfiles
|
|
2556
|
+
listHarnessClientProfiles,
|
|
2557
|
+
validatePaymentRequiredDetailed
|
|
2095
2558
|
});
|