@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.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;
|
|
@@ -1400,6 +1406,471 @@ async function runDiscovery({
|
|
|
1400
1406
|
};
|
|
1401
1407
|
}
|
|
1402
1408
|
|
|
1409
|
+
// src/validation/codes.ts
|
|
1410
|
+
var VALIDATION_CODES = {
|
|
1411
|
+
COINBASE_SCHEMA_INVALID: "COINBASE_SCHEMA_INVALID",
|
|
1412
|
+
X402_NOT_OBJECT: "X402_NOT_OBJECT",
|
|
1413
|
+
X402_VERSION_MISSING: "X402_VERSION_MISSING",
|
|
1414
|
+
X402_VERSION_UNSUPPORTED: "X402_VERSION_UNSUPPORTED",
|
|
1415
|
+
X402_ACCEPTS_MISSING: "X402_ACCEPTS_MISSING",
|
|
1416
|
+
X402_ACCEPTS_INVALID: "X402_ACCEPTS_INVALID",
|
|
1417
|
+
X402_ACCEPTS_EMPTY: "X402_ACCEPTS_EMPTY",
|
|
1418
|
+
X402_ACCEPT_ENTRY_INVALID: "X402_ACCEPT_ENTRY_INVALID",
|
|
1419
|
+
NETWORK_CAIP2_INVALID: "NETWORK_CAIP2_INVALID",
|
|
1420
|
+
NETWORK_EIP155_REFERENCE_INVALID: "NETWORK_EIP155_REFERENCE_INVALID",
|
|
1421
|
+
NETWORK_SOLANA_ALIAS_INVALID: "NETWORK_SOLANA_ALIAS_INVALID",
|
|
1422
|
+
NETWORK_SOLANA_ALIAS_COMPAT: "NETWORK_SOLANA_ALIAS_COMPAT",
|
|
1423
|
+
NETWORK_REFERENCE_UNKNOWN: "NETWORK_REFERENCE_UNKNOWN",
|
|
1424
|
+
SCHEMA_INPUT_MISSING: "SCHEMA_INPUT_MISSING",
|
|
1425
|
+
SCHEMA_OUTPUT_MISSING: "SCHEMA_OUTPUT_MISSING",
|
|
1426
|
+
METADATA_TITLE_MISSING: "METADATA_TITLE_MISSING",
|
|
1427
|
+
METADATA_DESCRIPTION_MISSING: "METADATA_DESCRIPTION_MISSING",
|
|
1428
|
+
METADATA_FAVICON_MISSING: "METADATA_FAVICON_MISSING",
|
|
1429
|
+
METADATA_OG_IMAGE_MISSING: "METADATA_OG_IMAGE_MISSING"
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1432
|
+
// src/validation/metadata.ts
|
|
1433
|
+
function hasText(value) {
|
|
1434
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
1435
|
+
}
|
|
1436
|
+
function hasOgImage(metadata) {
|
|
1437
|
+
const images = metadata.ogImages;
|
|
1438
|
+
if (!Array.isArray(images) || images.length === 0) return false;
|
|
1439
|
+
return images.some((entry) => {
|
|
1440
|
+
if (typeof entry === "string") {
|
|
1441
|
+
return entry.trim().length > 0;
|
|
1442
|
+
}
|
|
1443
|
+
if (!entry || typeof entry !== "object") return false;
|
|
1444
|
+
return hasText(entry.url);
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
function evaluateMetadataCompleteness(metadata) {
|
|
1448
|
+
const issues = [];
|
|
1449
|
+
if (!hasText(metadata.title)) {
|
|
1450
|
+
issues.push({
|
|
1451
|
+
code: VALIDATION_CODES.METADATA_TITLE_MISSING,
|
|
1452
|
+
severity: "warn",
|
|
1453
|
+
message: "Metadata title is missing",
|
|
1454
|
+
hint: "Provide a page title to improve discovery quality and UX.",
|
|
1455
|
+
path: "metadata.title",
|
|
1456
|
+
stage: "metadata"
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
if (!hasText(metadata.description)) {
|
|
1460
|
+
issues.push({
|
|
1461
|
+
code: VALIDATION_CODES.METADATA_DESCRIPTION_MISSING,
|
|
1462
|
+
severity: "warn",
|
|
1463
|
+
message: "Metadata description is missing",
|
|
1464
|
+
hint: "Provide a concise description for integrators and search previews.",
|
|
1465
|
+
path: "metadata.description",
|
|
1466
|
+
stage: "metadata"
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
if (!hasText(metadata.favicon)) {
|
|
1470
|
+
issues.push({
|
|
1471
|
+
code: VALIDATION_CODES.METADATA_FAVICON_MISSING,
|
|
1472
|
+
severity: "warn",
|
|
1473
|
+
message: "Metadata favicon is missing",
|
|
1474
|
+
hint: "Expose a favicon URL for stronger brand attribution.",
|
|
1475
|
+
path: "metadata.favicon",
|
|
1476
|
+
stage: "metadata"
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
if (!hasOgImage(metadata)) {
|
|
1480
|
+
issues.push({
|
|
1481
|
+
code: VALIDATION_CODES.METADATA_OG_IMAGE_MISSING,
|
|
1482
|
+
severity: "warn",
|
|
1483
|
+
message: "Metadata OG image is missing",
|
|
1484
|
+
hint: "Provide an Open Graph image to improve sharing previews.",
|
|
1485
|
+
path: "metadata.ogImages",
|
|
1486
|
+
stage: "metadata"
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
1489
|
+
return issues;
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// src/validation/payment-required.ts
|
|
1493
|
+
import { parsePaymentRequired } from "@x402/core/schemas";
|
|
1494
|
+
var SOLANA_CANONICAL_BY_REF = {
|
|
1495
|
+
"5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": "solana",
|
|
1496
|
+
EtWTRABZaYq6iMfeYKouRu166VU2xqa1: "solana-devnet",
|
|
1497
|
+
"4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z": "solana-testnet"
|
|
1498
|
+
};
|
|
1499
|
+
var SOLANA_ALIAS_BY_REF = {
|
|
1500
|
+
mainnet: "solana",
|
|
1501
|
+
devnet: "solana-devnet",
|
|
1502
|
+
testnet: "solana-testnet"
|
|
1503
|
+
};
|
|
1504
|
+
function isRecord4(value) {
|
|
1505
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1506
|
+
}
|
|
1507
|
+
function asNonEmptyString(value) {
|
|
1508
|
+
if (typeof value !== "string") return void 0;
|
|
1509
|
+
const trimmed = value.trim();
|
|
1510
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
1511
|
+
}
|
|
1512
|
+
function asPositiveNumber(value) {
|
|
1513
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
1514
|
+
}
|
|
1515
|
+
function pushIssue(issues, issue) {
|
|
1516
|
+
issues.push({
|
|
1517
|
+
stage: issue.stage ?? "payment_required",
|
|
1518
|
+
...issue
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
function summarizeIssues(issues) {
|
|
1522
|
+
const summary = {
|
|
1523
|
+
errorCount: 0,
|
|
1524
|
+
warnCount: 0,
|
|
1525
|
+
infoCount: 0,
|
|
1526
|
+
byCode: {}
|
|
1527
|
+
};
|
|
1528
|
+
for (const issue of issues) {
|
|
1529
|
+
if (issue.severity === "error") summary.errorCount += 1;
|
|
1530
|
+
else if (issue.severity === "warn") summary.warnCount += 1;
|
|
1531
|
+
else summary.infoCount += 1;
|
|
1532
|
+
summary.byCode[issue.code] = (summary.byCode[issue.code] ?? 0) + 1;
|
|
1533
|
+
}
|
|
1534
|
+
return summary;
|
|
1535
|
+
}
|
|
1536
|
+
function outputSchemaMissingSeverity(compatMode) {
|
|
1537
|
+
return compatMode === "strict" ? "error" : "warn";
|
|
1538
|
+
}
|
|
1539
|
+
function zodPathToString(path) {
|
|
1540
|
+
if (path.length === 0) return "$";
|
|
1541
|
+
let out = "";
|
|
1542
|
+
for (const segment of path) {
|
|
1543
|
+
if (typeof segment === "number") out += `[${segment}]`;
|
|
1544
|
+
else out += out.length === 0 ? segment : `.${segment}`;
|
|
1545
|
+
}
|
|
1546
|
+
return out;
|
|
1547
|
+
}
|
|
1548
|
+
function parseWithCoinbaseStructuralGate(payload, issues) {
|
|
1549
|
+
const baseParsed = parsePaymentRequired(payload);
|
|
1550
|
+
if (baseParsed.success) {
|
|
1551
|
+
return baseParsed.data;
|
|
1552
|
+
}
|
|
1553
|
+
for (const issue of baseParsed.error.issues) {
|
|
1554
|
+
pushIssue(issues, {
|
|
1555
|
+
code: VALIDATION_CODES.COINBASE_SCHEMA_INVALID,
|
|
1556
|
+
severity: "error",
|
|
1557
|
+
message: `Coinbase schema validation failed: ${issue.message}`,
|
|
1558
|
+
path: zodPathToString(issue.path),
|
|
1559
|
+
actual: issue.code
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
return void 0;
|
|
1563
|
+
}
|
|
1564
|
+
function validateV2Network(networkRaw, index, issues) {
|
|
1565
|
+
if (!/^[^:\s]+:[^:\s]+$/.test(networkRaw)) {
|
|
1566
|
+
pushIssue(issues, {
|
|
1567
|
+
code: VALIDATION_CODES.NETWORK_CAIP2_INVALID,
|
|
1568
|
+
severity: "error",
|
|
1569
|
+
message: `Accept at index ${index} has invalid CAIP-2 network format`,
|
|
1570
|
+
hint: "Expected '<namespace>:<reference>', e.g. 'eip155:8453' or 'solana:5eykt4...'.",
|
|
1571
|
+
path: `accepts[${index}].network`,
|
|
1572
|
+
expected: "<namespace>:<reference>",
|
|
1573
|
+
actual: networkRaw
|
|
1574
|
+
});
|
|
1575
|
+
return void 0;
|
|
1576
|
+
}
|
|
1577
|
+
const [namespace, reference] = networkRaw.split(":");
|
|
1578
|
+
if (namespace === "eip155") {
|
|
1579
|
+
if (!/^\d+$/.test(reference)) {
|
|
1580
|
+
pushIssue(issues, {
|
|
1581
|
+
code: VALIDATION_CODES.NETWORK_EIP155_REFERENCE_INVALID,
|
|
1582
|
+
severity: "error",
|
|
1583
|
+
message: `Accept at index ${index} has invalid eip155 reference`,
|
|
1584
|
+
hint: "Use a numeric chain id, e.g. 'eip155:8453'.",
|
|
1585
|
+
path: `accepts[${index}].network`,
|
|
1586
|
+
expected: "eip155:<numeric-chain-id>",
|
|
1587
|
+
actual: networkRaw
|
|
1588
|
+
});
|
|
1589
|
+
return void 0;
|
|
1590
|
+
}
|
|
1591
|
+
return networkRaw;
|
|
1592
|
+
}
|
|
1593
|
+
if (namespace === "solana") {
|
|
1594
|
+
const canonical = SOLANA_CANONICAL_BY_REF[reference];
|
|
1595
|
+
if (canonical) return canonical;
|
|
1596
|
+
const alias = SOLANA_ALIAS_BY_REF[reference];
|
|
1597
|
+
if (alias) {
|
|
1598
|
+
pushIssue(issues, {
|
|
1599
|
+
code: VALIDATION_CODES.NETWORK_SOLANA_ALIAS_COMPAT,
|
|
1600
|
+
severity: "warn",
|
|
1601
|
+
message: `Accept at index ${index} uses compatibility Solana reference '${reference}'`,
|
|
1602
|
+
hint: "Use canonical Solana CAIP references for deterministic behavior.",
|
|
1603
|
+
path: `accepts[${index}].network`,
|
|
1604
|
+
actual: networkRaw
|
|
1605
|
+
});
|
|
1606
|
+
return alias;
|
|
1607
|
+
}
|
|
1608
|
+
pushIssue(issues, {
|
|
1609
|
+
code: VALIDATION_CODES.NETWORK_REFERENCE_UNKNOWN,
|
|
1610
|
+
severity: "error",
|
|
1611
|
+
message: `Accept at index ${index} uses unknown Solana reference '${reference}'`,
|
|
1612
|
+
hint: "Use canonical references for mainnet/devnet/testnet.",
|
|
1613
|
+
path: `accepts[${index}].network`,
|
|
1614
|
+
actual: networkRaw
|
|
1615
|
+
});
|
|
1616
|
+
return void 0;
|
|
1617
|
+
}
|
|
1618
|
+
return networkRaw;
|
|
1619
|
+
}
|
|
1620
|
+
function validateV1Network(networkRaw, index, issues) {
|
|
1621
|
+
if (networkRaw === "solana-mainnet-beta") {
|
|
1622
|
+
pushIssue(issues, {
|
|
1623
|
+
code: VALIDATION_CODES.NETWORK_SOLANA_ALIAS_INVALID,
|
|
1624
|
+
severity: "error",
|
|
1625
|
+
message: `Accept at index ${index} uses invalid Solana network alias`,
|
|
1626
|
+
hint: "Use 'solana' (v1) or canonical Solana CAIP reference (v2).",
|
|
1627
|
+
path: `accepts[${index}].network`,
|
|
1628
|
+
expected: "solana",
|
|
1629
|
+
actual: networkRaw
|
|
1630
|
+
});
|
|
1631
|
+
return void 0;
|
|
1632
|
+
}
|
|
1633
|
+
if (networkRaw.startsWith("solana-") && networkRaw !== "solana-devnet") {
|
|
1634
|
+
pushIssue(issues, {
|
|
1635
|
+
code: VALIDATION_CODES.NETWORK_SOLANA_ALIAS_INVALID,
|
|
1636
|
+
severity: "error",
|
|
1637
|
+
message: `Accept at index ${index} uses unsupported Solana network alias`,
|
|
1638
|
+
hint: "Use 'solana' or 'solana-devnet' for v1 payloads.",
|
|
1639
|
+
path: `accepts[${index}].network`,
|
|
1640
|
+
actual: networkRaw
|
|
1641
|
+
});
|
|
1642
|
+
return void 0;
|
|
1643
|
+
}
|
|
1644
|
+
if (networkRaw.includes(":")) {
|
|
1645
|
+
return validateV2Network(networkRaw, index, issues);
|
|
1646
|
+
}
|
|
1647
|
+
return networkRaw;
|
|
1648
|
+
}
|
|
1649
|
+
function validateAccept(acceptRaw, index, version, issues) {
|
|
1650
|
+
if (!isRecord4(acceptRaw)) {
|
|
1651
|
+
pushIssue(issues, {
|
|
1652
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1653
|
+
severity: "error",
|
|
1654
|
+
message: `Accept at index ${index} must be an object`,
|
|
1655
|
+
path: `accepts[${index}]`
|
|
1656
|
+
});
|
|
1657
|
+
return null;
|
|
1658
|
+
}
|
|
1659
|
+
const scheme = asNonEmptyString(acceptRaw.scheme);
|
|
1660
|
+
const networkRaw = asNonEmptyString(acceptRaw.network);
|
|
1661
|
+
const payTo = asNonEmptyString(acceptRaw.payTo);
|
|
1662
|
+
const asset = asNonEmptyString(acceptRaw.asset);
|
|
1663
|
+
const maxTimeoutSeconds = asPositiveNumber(acceptRaw.maxTimeoutSeconds);
|
|
1664
|
+
const amount = version === 2 ? asNonEmptyString(acceptRaw.amount) : asNonEmptyString(acceptRaw.maxAmountRequired);
|
|
1665
|
+
if (!scheme) {
|
|
1666
|
+
pushIssue(issues, {
|
|
1667
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1668
|
+
severity: "error",
|
|
1669
|
+
message: `Accept at index ${index} is missing scheme`,
|
|
1670
|
+
path: `accepts[${index}].scheme`
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
if (!networkRaw) {
|
|
1674
|
+
pushIssue(issues, {
|
|
1675
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1676
|
+
severity: "error",
|
|
1677
|
+
message: `Accept at index ${index} is missing network`,
|
|
1678
|
+
path: `accepts[${index}].network`
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
if (!amount) {
|
|
1682
|
+
pushIssue(issues, {
|
|
1683
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1684
|
+
severity: "error",
|
|
1685
|
+
message: `Accept at index ${index} is missing ${version === 2 ? "amount" : "maxAmountRequired"}`,
|
|
1686
|
+
path: `accepts[${index}].${version === 2 ? "amount" : "maxAmountRequired"}`
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
if (!payTo) {
|
|
1690
|
+
pushIssue(issues, {
|
|
1691
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1692
|
+
severity: "error",
|
|
1693
|
+
message: `Accept at index ${index} is missing payTo`,
|
|
1694
|
+
path: `accepts[${index}].payTo`
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
if (!asset) {
|
|
1698
|
+
pushIssue(issues, {
|
|
1699
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1700
|
+
severity: "error",
|
|
1701
|
+
message: `Accept at index ${index} is missing asset`,
|
|
1702
|
+
path: `accepts[${index}].asset`
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
if (!maxTimeoutSeconds) {
|
|
1706
|
+
pushIssue(issues, {
|
|
1707
|
+
code: VALIDATION_CODES.X402_ACCEPT_ENTRY_INVALID,
|
|
1708
|
+
severity: "error",
|
|
1709
|
+
message: `Accept at index ${index} is missing or has invalid maxTimeoutSeconds`,
|
|
1710
|
+
path: `accepts[${index}].maxTimeoutSeconds`
|
|
1711
|
+
});
|
|
1712
|
+
}
|
|
1713
|
+
let normalizedNetwork;
|
|
1714
|
+
if (networkRaw) {
|
|
1715
|
+
normalizedNetwork = version === 2 ? validateV2Network(networkRaw, index, issues) : validateV1Network(networkRaw, index, issues);
|
|
1716
|
+
}
|
|
1717
|
+
return {
|
|
1718
|
+
index,
|
|
1719
|
+
network: normalizedNetwork ?? networkRaw ?? "unknown",
|
|
1720
|
+
networkRaw: networkRaw ?? "unknown",
|
|
1721
|
+
scheme,
|
|
1722
|
+
asset,
|
|
1723
|
+
payTo,
|
|
1724
|
+
amount,
|
|
1725
|
+
maxTimeoutSeconds
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
function getSchemaPresence(payload, accepts, version) {
|
|
1729
|
+
if (version === 1) {
|
|
1730
|
+
const first = accepts[0];
|
|
1731
|
+
if (!isRecord4(first)) {
|
|
1732
|
+
return { hasInputSchema: false, hasOutputSchema: false };
|
|
1733
|
+
}
|
|
1734
|
+
const outputSchema = isRecord4(first.outputSchema) ? first.outputSchema : void 0;
|
|
1735
|
+
return {
|
|
1736
|
+
hasInputSchema: outputSchema?.input !== void 0 && outputSchema.input !== null,
|
|
1737
|
+
hasOutputSchema: outputSchema?.output !== void 0 && outputSchema.output !== null
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
const extensions = isRecord4(payload.extensions) ? payload.extensions : void 0;
|
|
1741
|
+
const bazaar = extensions && isRecord4(extensions.bazaar) ? extensions.bazaar : void 0;
|
|
1742
|
+
const info = bazaar && isRecord4(bazaar.info) ? bazaar.info : void 0;
|
|
1743
|
+
return {
|
|
1744
|
+
hasInputSchema: info?.input !== void 0 && info.input !== null,
|
|
1745
|
+
hasOutputSchema: info?.output !== void 0 && info.output !== null
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
function validatePaymentRequiredDetailed(payload, options = {}) {
|
|
1749
|
+
const issues = [];
|
|
1750
|
+
const compatMode = options.compatMode ?? DEFAULT_COMPAT_MODE;
|
|
1751
|
+
const requireInputSchema = options.requireInputSchema ?? true;
|
|
1752
|
+
const requireOutputSchema = options.requireOutputSchema ?? true;
|
|
1753
|
+
if (!isRecord4(payload)) {
|
|
1754
|
+
pushIssue(issues, {
|
|
1755
|
+
code: VALIDATION_CODES.X402_NOT_OBJECT,
|
|
1756
|
+
severity: "error",
|
|
1757
|
+
message: "Payment required payload must be a JSON object",
|
|
1758
|
+
path: "$"
|
|
1759
|
+
});
|
|
1760
|
+
if (options.metadata) {
|
|
1761
|
+
issues.push(...evaluateMetadataCompleteness(options.metadata));
|
|
1762
|
+
}
|
|
1763
|
+
return {
|
|
1764
|
+
valid: false,
|
|
1765
|
+
issues,
|
|
1766
|
+
summary: summarizeIssues(issues)
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
const coinbaseParsed = parseWithCoinbaseStructuralGate(payload, issues);
|
|
1770
|
+
const versionRaw = payload.x402Version;
|
|
1771
|
+
let version;
|
|
1772
|
+
if (versionRaw === 1 || versionRaw === 2) {
|
|
1773
|
+
version = versionRaw;
|
|
1774
|
+
} else if (versionRaw === void 0) {
|
|
1775
|
+
pushIssue(issues, {
|
|
1776
|
+
code: VALIDATION_CODES.X402_VERSION_MISSING,
|
|
1777
|
+
severity: "error",
|
|
1778
|
+
message: "x402Version is required",
|
|
1779
|
+
path: "x402Version"
|
|
1780
|
+
});
|
|
1781
|
+
} else {
|
|
1782
|
+
pushIssue(issues, {
|
|
1783
|
+
code: VALIDATION_CODES.X402_VERSION_UNSUPPORTED,
|
|
1784
|
+
severity: "error",
|
|
1785
|
+
message: `Unsupported x402Version '${String(versionRaw)}'`,
|
|
1786
|
+
path: "x402Version",
|
|
1787
|
+
expected: "1 | 2",
|
|
1788
|
+
actual: String(versionRaw)
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
const acceptsRaw = payload.accepts;
|
|
1792
|
+
let accepts = [];
|
|
1793
|
+
if (acceptsRaw === void 0) {
|
|
1794
|
+
pushIssue(issues, {
|
|
1795
|
+
code: VALIDATION_CODES.X402_ACCEPTS_MISSING,
|
|
1796
|
+
severity: "error",
|
|
1797
|
+
message: "accepts is required",
|
|
1798
|
+
path: "accepts"
|
|
1799
|
+
});
|
|
1800
|
+
} else if (!Array.isArray(acceptsRaw)) {
|
|
1801
|
+
pushIssue(issues, {
|
|
1802
|
+
code: VALIDATION_CODES.X402_ACCEPTS_INVALID,
|
|
1803
|
+
severity: "error",
|
|
1804
|
+
message: "accepts must be an array",
|
|
1805
|
+
path: "accepts"
|
|
1806
|
+
});
|
|
1807
|
+
} else {
|
|
1808
|
+
accepts = acceptsRaw;
|
|
1809
|
+
if (accepts.length === 0) {
|
|
1810
|
+
pushIssue(issues, {
|
|
1811
|
+
code: VALIDATION_CODES.X402_ACCEPTS_EMPTY,
|
|
1812
|
+
severity: "error",
|
|
1813
|
+
message: "accepts must contain at least one payment requirement",
|
|
1814
|
+
path: "accepts"
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
const normalizedAccepts = [];
|
|
1819
|
+
if (version && Array.isArray(accepts)) {
|
|
1820
|
+
accepts.forEach((accept, index) => {
|
|
1821
|
+
const normalized = validateAccept(accept, index, version, issues);
|
|
1822
|
+
if (normalized) normalizedAccepts.push(normalized);
|
|
1823
|
+
});
|
|
1824
|
+
const schemaPresence = getSchemaPresence(payload, accepts, version);
|
|
1825
|
+
if (requireInputSchema && !schemaPresence.hasInputSchema) {
|
|
1826
|
+
pushIssue(issues, {
|
|
1827
|
+
code: VALIDATION_CODES.SCHEMA_INPUT_MISSING,
|
|
1828
|
+
severity: "error",
|
|
1829
|
+
message: "Input schema is missing",
|
|
1830
|
+
hint: "Include input schema details so clients can invoke the endpoint correctly.",
|
|
1831
|
+
path: version === 1 ? "accepts[0].outputSchema.input" : "extensions.bazaar.info.input"
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
if (requireOutputSchema && !schemaPresence.hasOutputSchema) {
|
|
1835
|
+
pushIssue(issues, {
|
|
1836
|
+
code: VALIDATION_CODES.SCHEMA_OUTPUT_MISSING,
|
|
1837
|
+
severity: outputSchemaMissingSeverity(compatMode),
|
|
1838
|
+
message: "Output schema is missing",
|
|
1839
|
+
hint: "Include output schema details so clients can validate responses.",
|
|
1840
|
+
path: version === 1 ? "accepts[0].outputSchema.output" : "extensions.bazaar.info.output"
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
if (options.metadata) {
|
|
1844
|
+
issues.push(...evaluateMetadataCompleteness(options.metadata));
|
|
1845
|
+
}
|
|
1846
|
+
const summary2 = summarizeIssues(issues);
|
|
1847
|
+
return {
|
|
1848
|
+
valid: summary2.errorCount === 0,
|
|
1849
|
+
version,
|
|
1850
|
+
parsed: coinbaseParsed ?? payload,
|
|
1851
|
+
normalized: {
|
|
1852
|
+
version,
|
|
1853
|
+
accepts: normalizedAccepts,
|
|
1854
|
+
hasInputSchema: schemaPresence.hasInputSchema,
|
|
1855
|
+
hasOutputSchema: schemaPresence.hasOutputSchema
|
|
1856
|
+
},
|
|
1857
|
+
issues,
|
|
1858
|
+
summary: summary2
|
|
1859
|
+
};
|
|
1860
|
+
}
|
|
1861
|
+
if (options.metadata) {
|
|
1862
|
+
issues.push(...evaluateMetadataCompleteness(options.metadata));
|
|
1863
|
+
}
|
|
1864
|
+
const summary = summarizeIssues(issues);
|
|
1865
|
+
return {
|
|
1866
|
+
valid: summary.errorCount === 0,
|
|
1867
|
+
version,
|
|
1868
|
+
parsed: coinbaseParsed ?? payload,
|
|
1869
|
+
issues,
|
|
1870
|
+
summary
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1403
1874
|
// src/adapters/mcp.ts
|
|
1404
1875
|
var DEFAULT_GUIDANCE_AUTO_INCLUDE_MAX_TOKENS = 1e3;
|
|
1405
1876
|
var OPENAPI_METHODS = [
|
|
@@ -1412,9 +1883,6 @@ var OPENAPI_METHODS = [
|
|
|
1412
1883
|
"OPTIONS",
|
|
1413
1884
|
"TRACE"
|
|
1414
1885
|
];
|
|
1415
|
-
function isRecord4(value) {
|
|
1416
|
-
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
1417
|
-
}
|
|
1418
1886
|
function toFiniteNumber(value) {
|
|
1419
1887
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1420
1888
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
@@ -1472,7 +1940,7 @@ function inferFailureCause(warnings) {
|
|
|
1472
1940
|
return { cause: "not_found" };
|
|
1473
1941
|
}
|
|
1474
1942
|
function getOpenApiInfo(document) {
|
|
1475
|
-
if (!
|
|
1943
|
+
if (!isRecord3(document) || !isRecord3(document.info)) return void 0;
|
|
1476
1944
|
if (typeof document.info.title !== "string") return void 0;
|
|
1477
1945
|
return {
|
|
1478
1946
|
title: document.info.title,
|
|
@@ -1515,15 +1983,15 @@ async function resolveGuidance(options) {
|
|
|
1515
1983
|
};
|
|
1516
1984
|
}
|
|
1517
1985
|
function extractPathsDocument(document) {
|
|
1518
|
-
if (!
|
|
1519
|
-
if (!
|
|
1986
|
+
if (!isRecord3(document)) return void 0;
|
|
1987
|
+
if (!isRecord3(document.paths)) return void 0;
|
|
1520
1988
|
return document.paths;
|
|
1521
1989
|
}
|
|
1522
1990
|
function findMatchingOpenApiPath(paths, targetPath) {
|
|
1523
1991
|
const exact = paths[targetPath];
|
|
1524
|
-
if (
|
|
1992
|
+
if (isRecord3(exact)) return { matchedPath: targetPath, pathItem: exact };
|
|
1525
1993
|
for (const [specPath, entry] of Object.entries(paths)) {
|
|
1526
|
-
if (!
|
|
1994
|
+
if (!isRecord3(entry)) continue;
|
|
1527
1995
|
const pattern = specPath.replace(/\{[^}]+\}/g, "[^/]+");
|
|
1528
1996
|
const regex = new RegExp(`^${pattern}$`);
|
|
1529
1997
|
if (regex.test(targetPath)) {
|
|
@@ -1539,11 +2007,11 @@ function resolveRef(document, ref, seen) {
|
|
|
1539
2007
|
const parts = ref.slice(2).split("/");
|
|
1540
2008
|
let current = document;
|
|
1541
2009
|
for (const part of parts) {
|
|
1542
|
-
if (!
|
|
2010
|
+
if (!isRecord3(current)) return void 0;
|
|
1543
2011
|
current = current[part];
|
|
1544
2012
|
if (current === void 0) return void 0;
|
|
1545
2013
|
}
|
|
1546
|
-
if (
|
|
2014
|
+
if (isRecord3(current)) return resolveRefs(document, current, seen);
|
|
1547
2015
|
return current;
|
|
1548
2016
|
}
|
|
1549
2017
|
function resolveRefs(document, obj, seen, depth = 0) {
|
|
@@ -1552,20 +2020,20 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
1552
2020
|
for (const [key, value] of Object.entries(obj)) {
|
|
1553
2021
|
if (key === "$ref" && typeof value === "string") {
|
|
1554
2022
|
const deref = resolveRef(document, value, seen);
|
|
1555
|
-
if (
|
|
2023
|
+
if (isRecord3(deref)) {
|
|
1556
2024
|
Object.assign(resolved, deref);
|
|
1557
2025
|
} else {
|
|
1558
2026
|
resolved[key] = value;
|
|
1559
2027
|
}
|
|
1560
2028
|
continue;
|
|
1561
2029
|
}
|
|
1562
|
-
if (
|
|
2030
|
+
if (isRecord3(value)) {
|
|
1563
2031
|
resolved[key] = resolveRefs(document, value, seen, depth + 1);
|
|
1564
2032
|
continue;
|
|
1565
2033
|
}
|
|
1566
2034
|
if (Array.isArray(value)) {
|
|
1567
2035
|
resolved[key] = value.map(
|
|
1568
|
-
(item) =>
|
|
2036
|
+
(item) => isRecord3(item) ? resolveRefs(document, item, seen, depth + 1) : item
|
|
1569
2037
|
);
|
|
1570
2038
|
continue;
|
|
1571
2039
|
}
|
|
@@ -1575,15 +2043,15 @@ function resolveRefs(document, obj, seen, depth = 0) {
|
|
|
1575
2043
|
}
|
|
1576
2044
|
function extractRequestBodySchema(operationSchema) {
|
|
1577
2045
|
const requestBody = operationSchema.requestBody;
|
|
1578
|
-
if (!
|
|
2046
|
+
if (!isRecord3(requestBody)) return void 0;
|
|
1579
2047
|
const content = requestBody.content;
|
|
1580
|
-
if (!
|
|
2048
|
+
if (!isRecord3(content)) return void 0;
|
|
1581
2049
|
const jsonMediaType = content["application/json"];
|
|
1582
|
-
if (
|
|
2050
|
+
if (isRecord3(jsonMediaType) && isRecord3(jsonMediaType.schema)) {
|
|
1583
2051
|
return jsonMediaType.schema;
|
|
1584
2052
|
}
|
|
1585
2053
|
for (const mediaType of Object.values(content)) {
|
|
1586
|
-
if (
|
|
2054
|
+
if (isRecord3(mediaType) && isRecord3(mediaType.schema)) {
|
|
1587
2055
|
return mediaType.schema;
|
|
1588
2056
|
}
|
|
1589
2057
|
}
|
|
@@ -1592,7 +2060,7 @@ function extractRequestBodySchema(operationSchema) {
|
|
|
1592
2060
|
function extractParameters(operationSchema) {
|
|
1593
2061
|
const params = operationSchema.parameters;
|
|
1594
2062
|
if (!Array.isArray(params)) return [];
|
|
1595
|
-
return params.filter((value) =>
|
|
2063
|
+
return params.filter((value) => isRecord3(value));
|
|
1596
2064
|
}
|
|
1597
2065
|
function extractInputSchema(operationSchema) {
|
|
1598
2066
|
const requestBody = extractRequestBodySchema(operationSchema);
|
|
@@ -1606,7 +2074,7 @@ function extractInputSchema(operationSchema) {
|
|
|
1606
2074
|
}
|
|
1607
2075
|
function parseOperationPrice(operation) {
|
|
1608
2076
|
const paymentInfo = operation["x-payment-info"];
|
|
1609
|
-
if (!
|
|
2077
|
+
if (!isRecord3(paymentInfo)) return void 0;
|
|
1610
2078
|
const fixed = toFiniteNumber(paymentInfo.price);
|
|
1611
2079
|
if (fixed != null) return `$${String(fixed)}`;
|
|
1612
2080
|
const min = toFiniteNumber(paymentInfo.minPrice);
|
|
@@ -1616,23 +2084,12 @@ function parseOperationPrice(operation) {
|
|
|
1616
2084
|
}
|
|
1617
2085
|
function parseOperationProtocols(operation) {
|
|
1618
2086
|
const paymentInfo = operation["x-payment-info"];
|
|
1619
|
-
if (!
|
|
2087
|
+
if (!isRecord3(paymentInfo) || !Array.isArray(paymentInfo.protocols)) return void 0;
|
|
1620
2088
|
const protocols = paymentInfo.protocols.filter(
|
|
1621
2089
|
(protocol) => typeof protocol === "string" && protocol.length > 0
|
|
1622
2090
|
);
|
|
1623
2091
|
return protocols.length > 0 ? protocols : void 0;
|
|
1624
2092
|
}
|
|
1625
|
-
function parseOperationAuthMode(operation) {
|
|
1626
|
-
const authExtension = operation["x-agentcash-auth"];
|
|
1627
|
-
if (isRecord4(authExtension)) {
|
|
1628
|
-
const mode = authExtension.mode;
|
|
1629
|
-
if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
|
|
1630
|
-
return mode;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
if (isRecord4(operation["x-payment-info"])) return "paid";
|
|
1634
|
-
return void 0;
|
|
1635
|
-
}
|
|
1636
2093
|
function createResourceMap(result) {
|
|
1637
2094
|
const map = /* @__PURE__ */ new Map();
|
|
1638
2095
|
for (const resource of result.resources) {
|
|
@@ -1724,7 +2181,7 @@ async function inspectEndpointForMcp(options) {
|
|
|
1724
2181
|
if (matched) {
|
|
1725
2182
|
for (const candidate of OPENAPI_METHODS) {
|
|
1726
2183
|
const operation = matched.pathItem[candidate.toLowerCase()];
|
|
1727
|
-
if (!
|
|
2184
|
+
if (!isRecord3(operation) || !isRecord3(document)) continue;
|
|
1728
2185
|
specMethods.push(candidate);
|
|
1729
2186
|
const resolvedOperation = resolveRefs(document, operation, /* @__PURE__ */ new Set());
|
|
1730
2187
|
const resource = resourceMap.get(toResourceKey(origin, candidate, matched.matchedPath));
|
|
@@ -1732,7 +2189,7 @@ async function inspectEndpointForMcp(options) {
|
|
|
1732
2189
|
const operationSummary = typeof resolvedOperation.summary === "string" ? resolvedOperation.summary : typeof resolvedOperation.description === "string" ? resolvedOperation.description : void 0;
|
|
1733
2190
|
const operationPrice = parseOperationPrice(resolvedOperation);
|
|
1734
2191
|
const operationProtocols = parseOperationProtocols(resolvedOperation);
|
|
1735
|
-
const operationAuthMode =
|
|
2192
|
+
const operationAuthMode = inferAuthMode(resolvedOperation) ?? "unprotected";
|
|
1736
2193
|
const inputSchema = extractInputSchema(resolvedOperation);
|
|
1737
2194
|
advisories[candidate] = {
|
|
1738
2195
|
method: candidate,
|
|
@@ -2042,6 +2499,7 @@ export {
|
|
|
2042
2499
|
LEGACY_SUNSET_DATE,
|
|
2043
2500
|
STRICT_ESCALATION_CODES,
|
|
2044
2501
|
UPGRADE_WARNING_CODES,
|
|
2502
|
+
VALIDATION_CODES,
|
|
2045
2503
|
auditContextHarness,
|
|
2046
2504
|
buildContextHarnessReport,
|
|
2047
2505
|
computeUpgradeSignal,
|
|
@@ -2049,7 +2507,9 @@ export {
|
|
|
2049
2507
|
discover,
|
|
2050
2508
|
discoverDetailed,
|
|
2051
2509
|
discoverForMcp,
|
|
2510
|
+
evaluateMetadataCompleteness,
|
|
2052
2511
|
getHarnessClientProfile,
|
|
2053
2512
|
inspectEndpointForMcp,
|
|
2054
|
-
listHarnessClientProfiles
|
|
2513
|
+
listHarnessClientProfiles,
|
|
2514
|
+
validatePaymentRequiredDetailed
|
|
2055
2515
|
};
|