milieu-cli 0.1.5 → 0.1.7
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 +53 -7
- package/dist/bridges/reachability/index.d.ts.map +1 -1
- package/dist/bridges/reachability/index.js +2 -0
- package/dist/bridges/reachability/index.js.map +1 -1
- package/dist/bridges/separation/api-presence.d.ts +6 -5
- package/dist/bridges/separation/api-presence.d.ts.map +1 -1
- package/dist/bridges/separation/api-presence.js +9 -5
- package/dist/bridges/separation/api-presence.js.map +1 -1
- package/dist/bridges/separation/index.d.ts.map +1 -1
- package/dist/bridges/separation/index.js +2 -1
- package/dist/bridges/separation/index.js.map +1 -1
- package/dist/bridges/standards/graphql.d.ts +20 -0
- package/dist/bridges/standards/graphql.d.ts.map +1 -0
- package/dist/bridges/standards/graphql.js +174 -0
- package/dist/bridges/standards/graphql.js.map +1 -0
- package/dist/bridges/standards/index.d.ts +10 -5
- package/dist/bridges/standards/index.d.ts.map +1 -1
- package/dist/bridges/standards/index.js +33 -13
- package/dist/bridges/standards/index.js.map +1 -1
- package/dist/bridges/standards/markdown-negotiation.d.ts +25 -0
- package/dist/bridges/standards/markdown-negotiation.d.ts.map +1 -0
- package/dist/bridges/standards/markdown-negotiation.js +127 -0
- package/dist/bridges/standards/markdown-negotiation.js.map +1 -0
- package/dist/bridges/standards/openapi.d.ts +4 -1
- package/dist/bridges/standards/openapi.d.ts.map +1 -1
- package/dist/bridges/standards/openapi.js +10 -1
- package/dist/bridges/standards/openapi.js.map +1 -1
- package/dist/bridges/standards/sitemap.d.ts +21 -0
- package/dist/bridges/standards/sitemap.d.ts.map +1 -0
- package/dist/bridges/standards/sitemap.js +174 -0
- package/dist/bridges/standards/sitemap.js.map +1 -0
- package/dist/cli/index.js +0 -0
- package/dist/core/explanations.d.ts.map +1 -1
- package/dist/core/explanations.js +18 -0
- package/dist/core/explanations.js.map +1 -1
- package/dist/utils/http-client.d.ts +9 -4
- package/dist/utils/http-client.d.ts.map +1 -1
- package/dist/utils/http-client.js +23 -3
- package/dist/utils/http-client.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -4,6 +4,19 @@ The API is the new product UI. Your customers are no longer just humans. They're
|
|
|
4
4
|
|
|
5
5
|
As an industry, we've spent decades perfecting UI & UX design for humans. Now we need the same rigor for the interface AI agents actually see: your product's **milieu**.
|
|
6
6
|
|
|
7
|
+
## Table of contents
|
|
8
|
+
|
|
9
|
+
- [What is milieu?](#what-is-milieu)
|
|
10
|
+
- [Quick start](#quick-start)
|
|
11
|
+
- [The 5 Bridges](#the-5-bridges)
|
|
12
|
+
- [Install](#install)
|
|
13
|
+
- [CI/CD integration](#cicd-integration)
|
|
14
|
+
- [Options](#options)
|
|
15
|
+
- [How scoring works](#how-scoring-works)
|
|
16
|
+
- [Programmatic API](#programmatic-api)
|
|
17
|
+
- [Requirements](#requirements)
|
|
18
|
+
- [License](#license)
|
|
19
|
+
|
|
7
20
|
## What is milieu?
|
|
8
21
|
|
|
9
22
|
*Milieu* is the totality of machine-readable signals that surround your product — the environment an AI agent encounters when it tries to discover, understand, and integrate with what you've built. It's not any single file or endpoint. It's robots.txt and OpenAPI specs and llms.txt and JSON-LD and developer docs and SDK references, all working together. It's the difference between a product that AI agents can use and one they walk past.
|
|
@@ -13,7 +26,7 @@ Good design made products usable for humans. Good milieu design makes products u
|
|
|
13
26
|
milieu-cli measures this. It scans your site and tells you what AI agents can actually see.
|
|
14
27
|
|
|
15
28
|
```bash
|
|
16
|
-
npx milieu-cli scan
|
|
29
|
+
npx milieu-cli scan petstore.swagger.io
|
|
17
30
|
```
|
|
18
31
|
|
|
19
32
|
```bash
|
|
@@ -21,6 +34,39 @@ npx milieu-cli scan stripe.com
|
|
|
21
34
|
milieu scan api.example.com --threshold 70
|
|
22
35
|
```
|
|
23
36
|
|
|
37
|
+
## Quick start
|
|
38
|
+
|
|
39
|
+
Run your first scan in under a minute:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx milieu-cli scan petstore.swagger.io
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
No config, no API keys. You'll get a scored report showing what AI agents can see when they visit that site.
|
|
46
|
+
|
|
47
|
+
### Example sites to try
|
|
48
|
+
|
|
49
|
+
Each of these exercises different parts of the scanner:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# The classic OpenAPI demo — Swagger spec at a well-known path
|
|
53
|
+
npx milieu-cli scan petstore.swagger.io
|
|
54
|
+
|
|
55
|
+
# Rich structured data — JSON-LD and Schema.org markup
|
|
56
|
+
npx milieu-cli scan schema.org
|
|
57
|
+
|
|
58
|
+
# Minimal API service — clean reachability, few standards signals
|
|
59
|
+
npx milieu-cli scan httpbin.org
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Add `--verbose` to any scan to see individual check results and explanations:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx milieu-cli scan petstore.swagger.io --verbose
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Once you've seen how these score, scan your own site and compare.
|
|
69
|
+
|
|
24
70
|
## The 5 Bridges
|
|
25
71
|
|
|
26
72
|
Milieu evaluates your product through five progressive bridges. Each one represents a layer of machine legibility that AI agents need, from "can I reach you?" to "can I trust you?"
|
|
@@ -28,7 +74,7 @@ Milieu evaluates your product through five progressive bridges. Each one represe
|
|
|
28
74
|
| | Bridge | Question | What milieu checks | Score |
|
|
29
75
|
|---|---|---|---|---|
|
|
30
76
|
| 1 | **Reachability** | **Can agents reach you?** | HTTPS, HTTP status, robots.txt (RFC 9309), per-bot crawler policies (GPTBot, ClaudeBot, CCBot, Googlebot, Bingbot, PerplexityBot), meta robots, X-Robots-Tag | 0–100 |
|
|
31
|
-
| 2 | **Standards** | **Can agents read you?** | OpenAPI spec, llms.txt, llms-full.txt, MCP endpoint, JSON-LD, Schema.org, security.txt, ai-plugin.json | 0–100 |
|
|
77
|
+
| 2 | **Standards** | **Can agents read you?** | OpenAPI spec, GraphQL introspection, XML sitemap, markdown content negotiation, llms.txt, llms-full.txt, MCP endpoint, JSON-LD, Schema.org, security.txt, ai-plugin.json | 0–100 |
|
|
32
78
|
| 3 | **Separation** | **Can agents integrate with you?** | API endpoints, developer docs, SDK/package references, webhook support | Detection only* |
|
|
33
79
|
| 4 | **Schema** | **Can agents use you correctly?** | Planned | — |
|
|
34
80
|
| 5 | **Context** | **Can agents trust you?** | Planned | — |
|
|
@@ -39,7 +85,7 @@ The bridges are progressive: there's no point checking your OpenAPI spec (Bridge
|
|
|
39
85
|
|
|
40
86
|
**Bridge 1 — Reachability** is the front door. Can AI agents get to your content at all? Are you blocking specific crawlers without realizing it? This is the most actionable bridge for most sites — many are unknowingly blocking GPTBot or ClaudeBot in their robots.txt.
|
|
41
87
|
|
|
42
|
-
**Bridge 2 — Standards** is the shared language. Do you speak the protocols AI agents understand? OpenAPI specs, llms.txt, MCP endpoints, structured data — these are the machine-readable standards that let agents go beyond scraping your HTML.
|
|
88
|
+
**Bridge 2 — Standards** is the shared language. Do you speak the protocols AI agents understand? OpenAPI specs, GraphQL endpoints, XML sitemaps, markdown content negotiation, llms.txt, MCP endpoints, structured data — these are the machine-readable standards that let agents go beyond scraping your HTML. milieu also checks if your server returns markdown via HTTP content negotiation (`Accept: text/markdown`), which cuts agent token usage by ~80% compared to raw HTML.
|
|
43
89
|
|
|
44
90
|
**Bridge 3 — Separation** is the developer surface. Do you have a clear API boundary? Developer docs? SDKs? Webhooks? This is where agents look to determine if your product is something they can build with, not just read from.
|
|
45
91
|
|
|
@@ -57,9 +103,9 @@ Each policy is checked individually — you might be allowing Googlebot but bloc
|
|
|
57
103
|
## Install
|
|
58
104
|
|
|
59
105
|
```bash
|
|
60
|
-
npx milieu-cli scan
|
|
61
|
-
npm install -g milieu-cli
|
|
62
|
-
milieu scan
|
|
106
|
+
npx milieu-cli scan petstore.swagger.io # one-off, no install
|
|
107
|
+
npm install -g milieu-cli # global install
|
|
108
|
+
milieu scan petstore.swagger.io # short alias after install
|
|
63
109
|
```
|
|
64
110
|
|
|
65
111
|
> Both `milieu` and `milieu-cli` work as commands after global install.
|
|
@@ -121,7 +167,7 @@ const options: ScanOptions = {
|
|
|
121
167
|
silent: true, // suppress spinner output (recommended for library use)
|
|
122
168
|
};
|
|
123
169
|
|
|
124
|
-
const result = await scan("https://
|
|
170
|
+
const result = await scan("https://petstore.swagger.io", options);
|
|
125
171
|
|
|
126
172
|
console.log(result.overallScore); // number (average of scored bridges)
|
|
127
173
|
console.log(result.overallScoreLabel); // "pass" | "partial" | "fail"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bridges/reachability/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAS,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAyC5E;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bridges/reachability/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAS,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAyC5E;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,YAAY,CAAC,CA2FvB"}
|
|
@@ -70,6 +70,8 @@ export async function runReachabilityBridge(ctx) {
|
|
|
70
70
|
const httpStatusCheck = checkHttpStatus(pageResponse);
|
|
71
71
|
// 4. robots.txt fetch + parse
|
|
72
72
|
const robotsResult = await checkRobotsTxt(ctx.domain, ctx.options.timeout);
|
|
73
|
+
// Store sitemap URLs for Bridge 2 consumption
|
|
74
|
+
ctx.shared.robotsSitemaps = robotsResult.parsed?.sitemaps ?? [];
|
|
73
75
|
// 5. Crawler policies (uses parsed robots.txt data)
|
|
74
76
|
let targetPath;
|
|
75
77
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bridges/reachability/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bridges/reachability/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,13 +2,14 @@ import type { Check, ContentSource } from "../../core/types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Detect API presence via multiple signals across content sources.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Five signal sources:
|
|
6
6
|
* 1. OpenAPI spec detected by Bridge 2 (boolean from ctx.shared.openApiDetected)
|
|
7
|
-
* 2.
|
|
8
|
-
* 3.
|
|
9
|
-
* 4.
|
|
7
|
+
* 2. GraphQL endpoint detected by Bridge 2 (boolean from ctx.shared.graphqlDetected)
|
|
8
|
+
* 3. API-related response headers (X-RateLimit-*, X-Request-Id, etc.)
|
|
9
|
+
* 4. HTML links containing /api/ paths (scanned from all content sources)
|
|
10
|
+
* 5. Markdown links containing /api/ paths (scanned from all content sources)
|
|
10
11
|
*
|
|
11
12
|
* Pure function -- no HTTP calls.
|
|
12
13
|
*/
|
|
13
|
-
export declare function checkApiPresence(openApiDetected: boolean, sources: ContentSource[], headers: Record<string, string
|
|
14
|
+
export declare function checkApiPresence(openApiDetected: boolean, sources: ContentSource[], headers: Record<string, string>, graphqlDetected?: boolean): Check;
|
|
14
15
|
//# sourceMappingURL=api-presence.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-presence.d.ts","sourceRoot":"","sources":["../../../src/bridges/separation/api-presence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA8ChE
|
|
1
|
+
{"version":3,"file":"api-presence.d.ts","sourceRoot":"","sources":["../../../src/bridges/separation/api-presence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA8ChE;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,OAAO,EACxB,OAAO,EAAE,aAAa,EAAE,EACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,eAAe,UAAQ,GACtB,KAAK,CA6CP"}
|
|
@@ -44,21 +44,25 @@ function scanApiLinksMarkdown(text) {
|
|
|
44
44
|
/**
|
|
45
45
|
* Detect API presence via multiple signals across content sources.
|
|
46
46
|
*
|
|
47
|
-
*
|
|
47
|
+
* Five signal sources:
|
|
48
48
|
* 1. OpenAPI spec detected by Bridge 2 (boolean from ctx.shared.openApiDetected)
|
|
49
|
-
* 2.
|
|
50
|
-
* 3.
|
|
51
|
-
* 4.
|
|
49
|
+
* 2. GraphQL endpoint detected by Bridge 2 (boolean from ctx.shared.graphqlDetected)
|
|
50
|
+
* 3. API-related response headers (X-RateLimit-*, X-Request-Id, etc.)
|
|
51
|
+
* 4. HTML links containing /api/ paths (scanned from all content sources)
|
|
52
|
+
* 5. Markdown links containing /api/ paths (scanned from all content sources)
|
|
52
53
|
*
|
|
53
54
|
* Pure function -- no HTTP calls.
|
|
54
55
|
*/
|
|
55
|
-
export function checkApiPresence(openApiDetected, sources, headers) {
|
|
56
|
+
export function checkApiPresence(openApiDetected, sources, headers, graphqlDetected = false) {
|
|
56
57
|
const id = "api_presence";
|
|
57
58
|
const label = "API Presence";
|
|
58
59
|
const signals = [];
|
|
59
60
|
// Signal 1: OpenAPI spec detected by Bridge 2
|
|
60
61
|
if (openApiDetected)
|
|
61
62
|
signals.push("OpenAPI spec");
|
|
63
|
+
// Signal 2: GraphQL endpoint detected by Bridge 2
|
|
64
|
+
if (graphqlDetected)
|
|
65
|
+
signals.push("GraphQL endpoint");
|
|
62
66
|
// Signal 2: API-related response headers
|
|
63
67
|
const apiHeaders = API_HEADERS.filter((h) => headers[h] !== undefined);
|
|
64
68
|
if (apiHeaders.length > 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-presence.js","sourceRoot":"","sources":["../../../src/bridges/separation/api-presence.ts"],"names":[],"mappings":"AAEA,gEAAgE;AAChE,MAAM,WAAW,GAAG;IAClB,mBAAmB;IACnB,uBAAuB;IACvB,mBAAmB;IACnB,cAAc;IACd,WAAW;IACX,eAAe;IACf,iBAAiB;IACjB,qBAAqB;IACrB,iBAAiB;CAClB,CAAC;AAEF;;;;GAIG;AACH,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,yDAAyD,CAAC;IACxE,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,oBAAoB,CAAC,IAAY;IACxC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,8CAA8C,CAAC;IAC7D,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"api-presence.js","sourceRoot":"","sources":["../../../src/bridges/separation/api-presence.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bridges/separation/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAwB,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAM3F;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bridges/separation/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAwB,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAM3F;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,YAAY,CAAC,CA0DvB"}
|
|
@@ -27,6 +27,7 @@ export async function runSeparationBridge(ctx) {
|
|
|
27
27
|
const openApiDetected = ctx.shared.openApiDetected ?? false;
|
|
28
28
|
const openApiHasWebhooks = ctx.shared.openApiHasWebhooks ?? false;
|
|
29
29
|
const openApiHasCallbacks = ctx.shared.openApiHasCallbacks ?? false;
|
|
30
|
+
const graphqlDetected = ctx.shared.graphqlDetected ?? false;
|
|
30
31
|
const llmsTxtBody = ctx.shared.llmsTxtBody ?? null;
|
|
31
32
|
// Fire async developer docs probe first (non-blocking)
|
|
32
33
|
const devDocsPromise = checkDeveloperDocs(ctx.baseUrl, pageBody, ctx.options.timeout);
|
|
@@ -42,7 +43,7 @@ export async function runSeparationBridge(ctx) {
|
|
|
42
43
|
contentSources.push({ content: llmsTxtBody, source: "llms.txt" });
|
|
43
44
|
contentSources.push(...devDocsResult.pages);
|
|
44
45
|
// Run 3 synchronous pure-function checks with assembled content sources
|
|
45
|
-
const apiPresenceCheck = checkApiPresence(openApiDetected, contentSources, pageHeaders);
|
|
46
|
+
const apiPresenceCheck = checkApiPresence(openApiDetected, contentSources, pageHeaders, graphqlDetected);
|
|
46
47
|
const sdkRefsCheck = checkSdkReferences(contentSources);
|
|
47
48
|
const webhookCheck = checkWebhookSupport(contentSources, {
|
|
48
49
|
pageHeaders,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bridges/separation/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAgB;IAEhB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAEhC,4CAA4C;IAC5C,MAAM,QAAQ,GAAI,GAAG,CAAC,MAAM,CAAC,QAAmB,IAAI,EAAE,CAAC;IACvD,MAAM,WAAW,GACd,GAAG,CAAC,MAAM,CAAC,WAAsC,IAAI,EAAE,CAAC;IAC3D,MAAM,eAAe,GAAI,GAAG,CAAC,MAAM,CAAC,eAA2B,IAAI,KAAK,CAAC;IACzE,MAAM,kBAAkB,GAAI,GAAG,CAAC,MAAM,CAAC,kBAA8B,IAAI,KAAK,CAAC;IAC/E,MAAM,mBAAmB,GAAI,GAAG,CAAC,MAAM,CAAC,mBAA+B,IAAI,KAAK,CAAC;IACjF,MAAM,WAAW,GAAI,GAAG,CAAC,MAAM,CAAC,WAAkC,IAAI,IAAI,CAAC;IAE3E,uDAAuD;IACvD,MAAM,cAAc,GAAG,kBAAkB,CACvC,GAAG,CAAC,OAAO,EACX,QAAQ,EACR,GAAG,CAAC,OAAO,CAAC,OAAO,CACpB,CAAC;IAEF,qDAAqD;IACrD,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC;IAE3C,gEAAgE;IAChE,GAAG,CAAC,MAAM,CAAC,aAAa,GAAG,aAAa,CAAC,KAAK,CAAC;IAE/C,qDAAqD;IACrD,MAAM,cAAc,GAAoB,EAAE,CAAC;IAC3C,IAAI,QAAQ;QAAE,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IAC7E,IAAI,WAAW;QAAE,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACnF,cAAc,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE5C,wEAAwE;IACxE,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,eAAe,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bridges/separation/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAgB;IAEhB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAEhC,4CAA4C;IAC5C,MAAM,QAAQ,GAAI,GAAG,CAAC,MAAM,CAAC,QAAmB,IAAI,EAAE,CAAC;IACvD,MAAM,WAAW,GACd,GAAG,CAAC,MAAM,CAAC,WAAsC,IAAI,EAAE,CAAC;IAC3D,MAAM,eAAe,GAAI,GAAG,CAAC,MAAM,CAAC,eAA2B,IAAI,KAAK,CAAC;IACzE,MAAM,kBAAkB,GAAI,GAAG,CAAC,MAAM,CAAC,kBAA8B,IAAI,KAAK,CAAC;IAC/E,MAAM,mBAAmB,GAAI,GAAG,CAAC,MAAM,CAAC,mBAA+B,IAAI,KAAK,CAAC;IACjF,MAAM,eAAe,GAAI,GAAG,CAAC,MAAM,CAAC,eAA2B,IAAI,KAAK,CAAC;IACzE,MAAM,WAAW,GAAI,GAAG,CAAC,MAAM,CAAC,WAAkC,IAAI,IAAI,CAAC;IAE3E,uDAAuD;IACvD,MAAM,cAAc,GAAG,kBAAkB,CACvC,GAAG,CAAC,OAAO,EACX,QAAQ,EACR,GAAG,CAAC,OAAO,CAAC,OAAO,CACpB,CAAC;IAEF,qDAAqD;IACrD,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC;IAE3C,gEAAgE;IAChE,GAAG,CAAC,MAAM,CAAC,aAAa,GAAG,aAAa,CAAC,KAAK,CAAC;IAE/C,qDAAqD;IACrD,MAAM,cAAc,GAAoB,EAAE,CAAC;IAC3C,IAAI,QAAQ;QAAE,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IAC7E,IAAI,WAAW;QAAE,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACnF,cAAc,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAE5C,wEAAwE;IACxE,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,eAAe,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;IACzG,MAAM,YAAY,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,mBAAmB,CAAC,cAAc,EAAE;QACvD,WAAW;QACX,kBAAkB;QAClB,mBAAmB;KACpB,CAAC,CAAC;IAEH,iCAAiC;IACjC,MAAM,MAAM,GAAY;QACtB,gBAAgB;QAChB,aAAa,CAAC,KAAK;QACnB,YAAY;QACZ,YAAY;KACb,CAAC;IAEF,OAAO;QACL,EAAE,EAAE,CAAC;QACL,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,WAAW;QACnB,KAAK,EAAE,IAAI;QACX,UAAU,EAAE,IAAI;QAChB,MAAM;QACN,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;KAClD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Check } from "../../core/types.js";
|
|
2
|
+
export interface GraphqlResult {
|
|
3
|
+
check: Check;
|
|
4
|
+
detected: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Probe common GraphQL endpoint paths via POST introspection query.
|
|
8
|
+
*
|
|
9
|
+
* Detection strategy per path:
|
|
10
|
+
* 1. POST introspection query with Content-Type: application/json
|
|
11
|
+
* 2. Parse response:
|
|
12
|
+
* - pass: 200 + valid __schema in response
|
|
13
|
+
* - partial: 200 + errors mentioning "introspection" (disabled)
|
|
14
|
+
* - partial: 401/403 (auth required)
|
|
15
|
+
* - skip: 404, non-JSON, connection error
|
|
16
|
+
*
|
|
17
|
+
* Returns early on first successful detection (highest confidence first).
|
|
18
|
+
*/
|
|
19
|
+
export declare function checkGraphql(baseUrl: string, timeout?: number): Promise<GraphqlResult>;
|
|
20
|
+
//# sourceMappingURL=graphql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../../src/bridges/standards/graphql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAOjD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAgFD;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,CAAC,CA4GxB"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { httpGet } from "../../utils/http-client.js";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Constants
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
/** Common GraphQL endpoint paths */
|
|
6
|
+
const GRAPHQL_PATHS = [
|
|
7
|
+
"/graphql",
|
|
8
|
+
"/api/graphql",
|
|
9
|
+
"/graphql/v1",
|
|
10
|
+
"/api/v1/graphql",
|
|
11
|
+
"/gql",
|
|
12
|
+
];
|
|
13
|
+
/** Minimal introspection query to confirm a GraphQL endpoint */
|
|
14
|
+
const INTROSPECTION_QUERY = JSON.stringify({
|
|
15
|
+
query: "{ __schema { queryType { name } mutationType { name } subscriptionType { name } } }",
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Parse a successful introspection response body.
|
|
19
|
+
* Returns metadata if the response contains valid `data.__schema`,
|
|
20
|
+
* or null if the JSON doesn't match the expected shape.
|
|
21
|
+
*/
|
|
22
|
+
function parseIntrospectionResponse(body) {
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(body);
|
|
25
|
+
const schema = parsed?.data?.__schema;
|
|
26
|
+
if (!schema || typeof schema !== "object")
|
|
27
|
+
return null;
|
|
28
|
+
return {
|
|
29
|
+
queryType: schema.queryType?.name != null,
|
|
30
|
+
mutationType: schema.mutationType?.name != null,
|
|
31
|
+
subscriptionType: schema.subscriptionType?.name != null,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if a JSON response body indicates a GraphQL endpoint
|
|
40
|
+
* with introspection disabled (common security practice).
|
|
41
|
+
*/
|
|
42
|
+
function isIntrospectionDisabled(body) {
|
|
43
|
+
try {
|
|
44
|
+
const parsed = JSON.parse(body);
|
|
45
|
+
if (!parsed?.errors || !Array.isArray(parsed.errors))
|
|
46
|
+
return false;
|
|
47
|
+
return parsed.errors.some((err) => typeof err.message === "string" &&
|
|
48
|
+
err.message.toLowerCase().includes("introspection"));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Returns true if response is a 401/403 HTTP error */
|
|
55
|
+
function isAuthRequired(statusCode) {
|
|
56
|
+
return statusCode === 401 || statusCode === 403;
|
|
57
|
+
}
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Public API
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
/**
|
|
62
|
+
* Probe common GraphQL endpoint paths via POST introspection query.
|
|
63
|
+
*
|
|
64
|
+
* Detection strategy per path:
|
|
65
|
+
* 1. POST introspection query with Content-Type: application/json
|
|
66
|
+
* 2. Parse response:
|
|
67
|
+
* - pass: 200 + valid __schema in response
|
|
68
|
+
* - partial: 200 + errors mentioning "introspection" (disabled)
|
|
69
|
+
* - partial: 401/403 (auth required)
|
|
70
|
+
* - skip: 404, non-JSON, connection error
|
|
71
|
+
*
|
|
72
|
+
* Returns early on first successful detection (highest confidence first).
|
|
73
|
+
*/
|
|
74
|
+
export async function checkGraphql(baseUrl, timeout) {
|
|
75
|
+
const id = "graphql_endpoint";
|
|
76
|
+
const label = "GraphQL Endpoint";
|
|
77
|
+
// Fire all probes in parallel
|
|
78
|
+
const responses = await Promise.all(GRAPHQL_PATHS.map((path) => httpGet(new URL(path, baseUrl).href, {
|
|
79
|
+
method: "POST",
|
|
80
|
+
timeout,
|
|
81
|
+
body: INTROSPECTION_QUERY,
|
|
82
|
+
headers: {
|
|
83
|
+
"Content-Type": "application/json",
|
|
84
|
+
Accept: "application/json",
|
|
85
|
+
},
|
|
86
|
+
})));
|
|
87
|
+
// Phase 1: Check for successful introspection (pass)
|
|
88
|
+
for (let i = 0; i < responses.length; i++) {
|
|
89
|
+
const response = responses[i];
|
|
90
|
+
if (!response.ok)
|
|
91
|
+
continue;
|
|
92
|
+
const introspection = parseIntrospectionResponse(response.body);
|
|
93
|
+
if (introspection) {
|
|
94
|
+
const capabilities = [];
|
|
95
|
+
if (introspection.queryType)
|
|
96
|
+
capabilities.push("query");
|
|
97
|
+
if (introspection.mutationType)
|
|
98
|
+
capabilities.push("mutation");
|
|
99
|
+
if (introspection.subscriptionType)
|
|
100
|
+
capabilities.push("subscription");
|
|
101
|
+
return {
|
|
102
|
+
check: {
|
|
103
|
+
id,
|
|
104
|
+
label,
|
|
105
|
+
status: "pass",
|
|
106
|
+
detail: `GraphQL endpoint at ${GRAPHQL_PATHS[i]} with ${capabilities.join(", ")} support`,
|
|
107
|
+
data: {
|
|
108
|
+
path: GRAPHQL_PATHS[i],
|
|
109
|
+
introspectionEnabled: true,
|
|
110
|
+
hasQueries: introspection.queryType,
|
|
111
|
+
hasMutations: introspection.mutationType,
|
|
112
|
+
hasSubscriptions: introspection.subscriptionType,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
detected: true,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Phase 2: Check for introspection-disabled endpoints (partial)
|
|
120
|
+
for (let i = 0; i < responses.length; i++) {
|
|
121
|
+
const response = responses[i];
|
|
122
|
+
if (!response.ok)
|
|
123
|
+
continue;
|
|
124
|
+
if (isIntrospectionDisabled(response.body)) {
|
|
125
|
+
return {
|
|
126
|
+
check: {
|
|
127
|
+
id,
|
|
128
|
+
label,
|
|
129
|
+
status: "partial",
|
|
130
|
+
detail: `GraphQL endpoint detected at ${GRAPHQL_PATHS[i]} (introspection disabled)`,
|
|
131
|
+
data: {
|
|
132
|
+
path: GRAPHQL_PATHS[i],
|
|
133
|
+
introspectionEnabled: false,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
detected: true,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Phase 3: Check for auth-protected endpoints (partial)
|
|
141
|
+
for (let i = 0; i < responses.length; i++) {
|
|
142
|
+
const response = responses[i];
|
|
143
|
+
if (response.ok)
|
|
144
|
+
continue;
|
|
145
|
+
if (response.error.kind === "http_error" &&
|
|
146
|
+
isAuthRequired(response.error.statusCode)) {
|
|
147
|
+
return {
|
|
148
|
+
check: {
|
|
149
|
+
id,
|
|
150
|
+
label,
|
|
151
|
+
status: "partial",
|
|
152
|
+
detail: `GraphQL endpoint detected at ${GRAPHQL_PATHS[i]} (authentication required)`,
|
|
153
|
+
data: {
|
|
154
|
+
path: GRAPHQL_PATHS[i],
|
|
155
|
+
introspectionEnabled: false,
|
|
156
|
+
protected: true,
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
detected: true,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Phase 4: Nothing found
|
|
164
|
+
return {
|
|
165
|
+
check: {
|
|
166
|
+
id,
|
|
167
|
+
label,
|
|
168
|
+
status: "fail",
|
|
169
|
+
detail: "No GraphQL endpoint found",
|
|
170
|
+
},
|
|
171
|
+
detected: false,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=graphql.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../src/bridges/standards/graphql.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,12 +2,17 @@ import type { BridgeResult, ScanContext } from "../../core/types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Run Bridge 2: Standards.
|
|
4
4
|
*
|
|
5
|
-
* Runs
|
|
6
|
-
* - 6 independent HTTP probes in parallel (OpenAPI, llms.txt, llms-full.txt, MCP, security.txt, ai-plugin.json)
|
|
7
|
-
* - 2 synchronous HTML-based checks (JSON-LD, Schema.org) using ctx.shared.pageBody from Bridge 1
|
|
5
|
+
* Runs 11 checks in two phases:
|
|
8
6
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Phase 1 (parallel): Sitemap + Markdown negotiation + llms.txt + llms-full.txt + MCP + security.txt + ai-plugin.json
|
|
8
|
+
* Phase 2 (parallel): OpenAPI (fed sitemap API URLs as candidates) + GraphQL
|
|
9
|
+
* Synchronous: JSON-LD + Schema.org (from ctx.shared.pageBody)
|
|
10
|
+
*
|
|
11
|
+
* Two-phase execution is required because sitemap results feed into
|
|
12
|
+
* OpenAPI detection as candidate spec URLs.
|
|
13
|
+
*
|
|
14
|
+
* Stores ctx.shared.openApiDetected, ctx.shared.graphqlDetected,
|
|
15
|
+
* ctx.shared.sitemapUrls, and ctx.shared.llmsTxtBody for Bridge 3 consumption.
|
|
11
16
|
*/
|
|
12
17
|
export declare function runStandardsBridge(ctx: ScanContext): Promise<BridgeResult>;
|
|
13
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bridges/standards/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAS,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bridges/standards/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAS,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAoC5E;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,YAAY,CAAC,CAuEvB"}
|
|
@@ -4,10 +4,13 @@ import { checkMcpEndpoint } from "./mcp.js";
|
|
|
4
4
|
import { checkJsonLd } from "./json-ld.js";
|
|
5
5
|
import { checkSchemaOrg } from "./schema-org.js";
|
|
6
6
|
import { checkSecurityTxt, checkAiPlugin } from "./well-known.js";
|
|
7
|
+
import { checkGraphql } from "./graphql.js";
|
|
8
|
+
import { checkSitemap } from "./sitemap.js";
|
|
9
|
+
import { checkMarkdownNegotiation } from "./markdown-negotiation.js";
|
|
7
10
|
/**
|
|
8
11
|
* Calculate bridge score from check results.
|
|
9
12
|
* - Pass = 1 point, Partial = 0.5 points, Fail/Error = 0 points
|
|
10
|
-
* - All
|
|
13
|
+
* - All checks always count (no skip concept in Bridge 2)
|
|
11
14
|
*/
|
|
12
15
|
function calculateScore(checks) {
|
|
13
16
|
let points = 0;
|
|
@@ -27,37 +30,54 @@ function calculateScore(checks) {
|
|
|
27
30
|
/**
|
|
28
31
|
* Run Bridge 2: Standards.
|
|
29
32
|
*
|
|
30
|
-
* Runs
|
|
31
|
-
* - 6 independent HTTP probes in parallel (OpenAPI, llms.txt, llms-full.txt, MCP, security.txt, ai-plugin.json)
|
|
32
|
-
* - 2 synchronous HTML-based checks (JSON-LD, Schema.org) using ctx.shared.pageBody from Bridge 1
|
|
33
|
+
* Runs 11 checks in two phases:
|
|
33
34
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
35
|
+
* Phase 1 (parallel): Sitemap + Markdown negotiation + llms.txt + llms-full.txt + MCP + security.txt + ai-plugin.json
|
|
36
|
+
* Phase 2 (parallel): OpenAPI (fed sitemap API URLs as candidates) + GraphQL
|
|
37
|
+
* Synchronous: JSON-LD + Schema.org (from ctx.shared.pageBody)
|
|
38
|
+
*
|
|
39
|
+
* Two-phase execution is required because sitemap results feed into
|
|
40
|
+
* OpenAPI detection as candidate spec URLs.
|
|
41
|
+
*
|
|
42
|
+
* Stores ctx.shared.openApiDetected, ctx.shared.graphqlDetected,
|
|
43
|
+
* ctx.shared.sitemapUrls, and ctx.shared.llmsTxtBody for Bridge 3 consumption.
|
|
36
44
|
*/
|
|
37
45
|
export async function runStandardsBridge(ctx) {
|
|
38
46
|
const start = performance.now();
|
|
39
|
-
// Get
|
|
47
|
+
// Get shared context from Bridge 1
|
|
40
48
|
const pageBody = ctx.shared.pageBody ?? "";
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
const robotsSitemaps = ctx.shared.robotsSitemaps ?? [];
|
|
50
|
+
// Phase 1: Sitemap + Markdown negotiation + independent HTTP probes (parallel)
|
|
51
|
+
const [sitemapResult, markdownResult, llmsTxtResult, llmsFullTxtCheck, mcpCheck, securityTxtCheck, aiPluginCheck,] = await Promise.all([
|
|
52
|
+
checkSitemap(ctx.baseUrl, robotsSitemaps, ctx.options.timeout),
|
|
53
|
+
checkMarkdownNegotiation(ctx.baseUrl, ctx.options.timeout),
|
|
44
54
|
checkLlmsTxt(ctx.baseUrl, ctx.options.timeout),
|
|
45
55
|
checkLlmsFullTxt(ctx.baseUrl, ctx.options.timeout),
|
|
46
56
|
checkMcpEndpoint(ctx.baseUrl, ctx.options.timeout),
|
|
47
57
|
checkSecurityTxt(ctx.baseUrl, ctx.options.timeout),
|
|
48
58
|
checkAiPlugin(ctx.baseUrl, ctx.options.timeout),
|
|
49
59
|
]);
|
|
50
|
-
//
|
|
60
|
+
// Phase 2: OpenAPI (with sitemap API URLs) + GraphQL (parallel)
|
|
61
|
+
const [openApiResult, graphqlResult] = await Promise.all([
|
|
62
|
+
checkOpenApi(ctx.baseUrl, ctx.options.timeout, sitemapResult.apiRelevantUrls),
|
|
63
|
+
checkGraphql(ctx.baseUrl, ctx.options.timeout),
|
|
64
|
+
]);
|
|
65
|
+
// Synchronous HTML-based checks (no HTTP)
|
|
51
66
|
const jsonLdCheck = checkJsonLd(pageBody);
|
|
52
67
|
const schemaOrgCheck = checkSchemaOrg(pageBody, jsonLdCheck);
|
|
53
|
-
// Store
|
|
68
|
+
// Store detection results for Bridge 3
|
|
54
69
|
ctx.shared.openApiDetected = openApiResult.detected;
|
|
55
70
|
ctx.shared.openApiHasWebhooks = openApiResult.hasWebhooks;
|
|
56
71
|
ctx.shared.openApiHasCallbacks = openApiResult.hasCallbacks;
|
|
72
|
+
ctx.shared.graphqlDetected = graphqlResult.detected;
|
|
73
|
+
ctx.shared.sitemapUrls = sitemapResult.urls;
|
|
57
74
|
ctx.shared.llmsTxtBody = llmsTxtResult.body;
|
|
58
|
-
// Collect all
|
|
75
|
+
// Collect all 11 checks in order
|
|
59
76
|
const checks = [
|
|
60
77
|
openApiResult.check,
|
|
78
|
+
graphqlResult.check,
|
|
79
|
+
sitemapResult.check,
|
|
80
|
+
markdownResult.check,
|
|
61
81
|
llmsTxtResult.check,
|
|
62
82
|
llmsFullTxtCheck,
|
|
63
83
|
mcpCheck,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bridges/standards/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bridges/standards/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Check } from "../../core/types.js";
|
|
2
|
+
export interface MarkdownNegotiationResult {
|
|
3
|
+
check: Check;
|
|
4
|
+
/** Whether the server supports markdown content negotiation */
|
|
5
|
+
supported: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Detect whether a site supports markdown content negotiation for AI agents.
|
|
9
|
+
*
|
|
10
|
+
* Three signals checked:
|
|
11
|
+
* 1. **Markdown response** — Send `Accept: text/markdown` to homepage,
|
|
12
|
+
* check if response has `content-type: text/markdown`
|
|
13
|
+
* 2. **x-markdown-tokens header** — Indicates the server is markdown-aware
|
|
14
|
+
* and provides token count estimates
|
|
15
|
+
* 3. **Content-Signal header** — AI permission directives like
|
|
16
|
+
* `ai-train=yes, ai-input=yes, search=yes`
|
|
17
|
+
*
|
|
18
|
+
* Status mapping:
|
|
19
|
+
* - pass: Server returns markdown when requested (content negotiation works)
|
|
20
|
+
* - partial: Content-Signal header present but no markdown negotiation,
|
|
21
|
+
* or x-markdown-tokens header found
|
|
22
|
+
* - fail: No markdown support detected
|
|
23
|
+
*/
|
|
24
|
+
export declare function checkMarkdownNegotiation(baseUrl: string, timeout?: number): Promise<MarkdownNegotiationResult>;
|
|
25
|
+
//# sourceMappingURL=markdown-negotiation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-negotiation.d.ts","sourceRoot":"","sources":["../../../src/bridges/standards/markdown-negotiation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAOjD,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,KAAK,CAAC;IACb,+DAA+D;IAC/D,SAAS,EAAE,OAAO,CAAC;CACpB;AA6CD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,yBAAyB,CAAC,CAoFpC"}
|