milieu-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +200 -0
- package/README.md +153 -0
- package/dist/bridges/index.d.ts +5 -0
- package/dist/bridges/index.d.ts.map +1 -0
- package/dist/bridges/index.js +6 -0
- package/dist/bridges/index.js.map +1 -0
- package/dist/bridges/reachability/crawler-policy.d.ts +36 -0
- package/dist/bridges/reachability/crawler-policy.d.ts.map +1 -0
- package/dist/bridges/reachability/crawler-policy.js +110 -0
- package/dist/bridges/reachability/crawler-policy.js.map +1 -0
- package/dist/bridges/reachability/http-status.d.ts +7 -0
- package/dist/bridges/reachability/http-status.d.ts.map +1 -0
- package/dist/bridges/reachability/http-status.js +74 -0
- package/dist/bridges/reachability/http-status.js.map +1 -0
- package/dist/bridges/reachability/https-check.d.ts +14 -0
- package/dist/bridges/reachability/https-check.d.ts.map +1 -0
- package/dist/bridges/reachability/https-check.js +38 -0
- package/dist/bridges/reachability/https-check.js.map +1 -0
- package/dist/bridges/reachability/index.d.ts +13 -0
- package/dist/bridges/reachability/index.d.ts.map +1 -0
- package/dist/bridges/reachability/index.js +115 -0
- package/dist/bridges/reachability/index.js.map +1 -0
- package/dist/bridges/reachability/meta-robots.d.ts +16 -0
- package/dist/bridges/reachability/meta-robots.d.ts.map +1 -0
- package/dist/bridges/reachability/meta-robots.js +119 -0
- package/dist/bridges/reachability/meta-robots.js.map +1 -0
- package/dist/bridges/reachability/robots-parser.d.ts +26 -0
- package/dist/bridges/reachability/robots-parser.d.ts.map +1 -0
- package/dist/bridges/reachability/robots-parser.js +105 -0
- package/dist/bridges/reachability/robots-parser.js.map +1 -0
- package/dist/bridges/reachability/robots-txt.d.ts +14 -0
- package/dist/bridges/reachability/robots-txt.d.ts.map +1 -0
- package/dist/bridges/reachability/robots-txt.js +80 -0
- package/dist/bridges/reachability/robots-txt.js.map +1 -0
- package/dist/bridges/separation/api-presence.d.ts +14 -0
- package/dist/bridges/separation/api-presence.d.ts.map +1 -0
- package/dist/bridges/separation/api-presence.js +96 -0
- package/dist/bridges/separation/api-presence.js.map +1 -0
- package/dist/bridges/separation/developer-docs.d.ts +21 -0
- package/dist/bridges/separation/developer-docs.d.ts.map +1 -0
- package/dist/bridges/separation/developer-docs.js +81 -0
- package/dist/bridges/separation/developer-docs.js.map +1 -0
- package/dist/bridges/separation/index.d.ts +20 -0
- package/dist/bridges/separation/index.d.ts.map +1 -0
- package/dist/bridges/separation/index.js +63 -0
- package/dist/bridges/separation/index.js.map +1 -0
- package/dist/bridges/separation/sdk-references.d.ts +12 -0
- package/dist/bridges/separation/sdk-references.d.ts.map +1 -0
- package/dist/bridges/separation/sdk-references.js +93 -0
- package/dist/bridges/separation/sdk-references.js.map +1 -0
- package/dist/bridges/separation/webhook-support.d.ts +19 -0
- package/dist/bridges/separation/webhook-support.d.ts.map +1 -0
- package/dist/bridges/separation/webhook-support.js +94 -0
- package/dist/bridges/separation/webhook-support.js.map +1 -0
- package/dist/bridges/standards/index.d.ts +13 -0
- package/dist/bridges/standards/index.d.ts.map +1 -0
- package/dist/bridges/standards/index.js +79 -0
- package/dist/bridges/standards/index.js.map +1 -0
- package/dist/bridges/standards/json-ld.d.ts +16 -0
- package/dist/bridges/standards/json-ld.d.ts.map +1 -0
- package/dist/bridges/standards/json-ld.js +63 -0
- package/dist/bridges/standards/json-ld.js.map +1 -0
- package/dist/bridges/standards/llms-txt.d.ts +19 -0
- package/dist/bridges/standards/llms-txt.d.ts.map +1 -0
- package/dist/bridges/standards/llms-txt.js +64 -0
- package/dist/bridges/standards/llms-txt.js.map +1 -0
- package/dist/bridges/standards/mcp.d.ts +13 -0
- package/dist/bridges/standards/mcp.d.ts.map +1 -0
- package/dist/bridges/standards/mcp.js +72 -0
- package/dist/bridges/standards/mcp.js.map +1 -0
- package/dist/bridges/standards/openapi.d.ts +14 -0
- package/dist/bridges/standards/openapi.d.ts.map +1 -0
- package/dist/bridges/standards/openapi.js +424 -0
- package/dist/bridges/standards/openapi.js.map +1 -0
- package/dist/bridges/standards/schema-org.d.ts +12 -0
- package/dist/bridges/standards/schema-org.d.ts.map +1 -0
- package/dist/bridges/standards/schema-org.js +101 -0
- package/dist/bridges/standards/schema-org.js.map +1 -0
- package/dist/bridges/standards/well-known.d.ts +16 -0
- package/dist/bridges/standards/well-known.d.ts.map +1 -0
- package/dist/bridges/standards/well-known.js +77 -0
- package/dist/bridges/standards/well-known.js.map +1 -0
- package/dist/bridges/stubs.d.ts +4 -0
- package/dist/bridges/stubs.d.ts.map +1 -0
- package/dist/bridges/stubs.js +25 -0
- package/dist/bridges/stubs.js.map +1 -0
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +83 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/explanations.d.ts +11 -0
- package/dist/core/explanations.d.ts.map +1 -0
- package/dist/core/explanations.js +128 -0
- package/dist/core/explanations.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/scan.d.ts +3 -0
- package/dist/core/scan.d.ts.map +1 -0
- package/dist/core/scan.js +89 -0
- package/dist/core/scan.js.map +1 -0
- package/dist/core/types.d.ts +119 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/version.d.ts +2 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +7 -0
- package/dist/core/version.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/render/colors.d.ts +7 -0
- package/dist/render/colors.d.ts.map +1 -0
- package/dist/render/colors.js +28 -0
- package/dist/render/colors.js.map +1 -0
- package/dist/render/format-bridge.d.ts +3 -0
- package/dist/render/format-bridge.d.ts.map +1 -0
- package/dist/render/format-bridge.js +39 -0
- package/dist/render/format-bridge.js.map +1 -0
- package/dist/render/format-scan.d.ts +3 -0
- package/dist/render/format-scan.d.ts.map +1 -0
- package/dist/render/format-scan.js +44 -0
- package/dist/render/format-scan.js.map +1 -0
- package/dist/render/format-verbose.d.ts +3 -0
- package/dist/render/format-verbose.d.ts.map +1 -0
- package/dist/render/format-verbose.js +14 -0
- package/dist/render/format-verbose.js.map +1 -0
- package/dist/render/index.d.ts +7 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +8 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/progress-bar.d.ts +10 -0
- package/dist/render/progress-bar.d.ts.map +1 -0
- package/dist/render/progress-bar.js +21 -0
- package/dist/render/progress-bar.js.map +1 -0
- package/dist/render/symbols.d.ts +10 -0
- package/dist/render/symbols.d.ts.map +1 -0
- package/dist/render/symbols.js +21 -0
- package/dist/render/symbols.js.map +1 -0
- package/dist/utils/http-client.d.ts +25 -0
- package/dist/utils/http-client.d.ts.map +1 -0
- package/dist/utils/http-client.js +235 -0
- package/dist/utils/http-client.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/ssrf.d.ts +29 -0
- package/dist/utils/ssrf.d.ts.map +1 -0
- package/dist/utils/ssrf.js +134 -0
- package/dist/utils/ssrf.js.map +1 -0
- package/dist/utils/url.d.ts +53 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +64 -0
- package/dist/utils/url.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** API-related response headers that indicate an API backend */
|
|
2
|
+
const API_HEADERS = [
|
|
3
|
+
"x-ratelimit-limit",
|
|
4
|
+
"x-ratelimit-remaining",
|
|
5
|
+
"x-ratelimit-reset",
|
|
6
|
+
"x-request-id",
|
|
7
|
+
"x-api-key",
|
|
8
|
+
"x-api-version",
|
|
9
|
+
"ratelimit-limit",
|
|
10
|
+
"ratelimit-remaining",
|
|
11
|
+
"ratelimit-reset",
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Scan for <a> tags with hrefs containing API-related paths.
|
|
15
|
+
* Matches /api/ followed by a slash, dot, or word boundary.
|
|
16
|
+
* Does NOT match /developer/ (that belongs to the developer-docs check).
|
|
17
|
+
*/
|
|
18
|
+
function scanApiLinks(html) {
|
|
19
|
+
const links = [];
|
|
20
|
+
const regex = /<a\s[^>]*href=["']([^"']*\/api(?:\/|\.|\b)[^"']*)["']/gi;
|
|
21
|
+
let match;
|
|
22
|
+
while ((match = regex.exec(html)) !== null) {
|
|
23
|
+
const href = match[1];
|
|
24
|
+
if (!links.includes(href))
|
|
25
|
+
links.push(href);
|
|
26
|
+
}
|
|
27
|
+
return links;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Scan for Markdown links containing API-related paths.
|
|
31
|
+
* Matches [text](url) where url contains /api/ followed by a slash, dot, or word boundary.
|
|
32
|
+
*/
|
|
33
|
+
function scanApiLinksMarkdown(text) {
|
|
34
|
+
const links = [];
|
|
35
|
+
const regex = /\[[^\]]*\]\(([^)]*\/api(?:\/|\.|\b)[^)]*)\)/g;
|
|
36
|
+
let match;
|
|
37
|
+
while ((match = regex.exec(text)) !== null) {
|
|
38
|
+
const href = match[1];
|
|
39
|
+
if (!links.includes(href))
|
|
40
|
+
links.push(href);
|
|
41
|
+
}
|
|
42
|
+
return links;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Detect API presence via multiple signals across content sources.
|
|
46
|
+
*
|
|
47
|
+
* Four signal sources:
|
|
48
|
+
* 1. OpenAPI spec detected by Bridge 2 (boolean from ctx.shared.openApiDetected)
|
|
49
|
+
* 2. API-related response headers (X-RateLimit-*, X-Request-Id, etc.)
|
|
50
|
+
* 3. HTML links containing /api/ paths (scanned from all content sources)
|
|
51
|
+
* 4. Markdown links containing /api/ paths (scanned from all content sources)
|
|
52
|
+
*
|
|
53
|
+
* Pure function -- no HTTP calls.
|
|
54
|
+
*/
|
|
55
|
+
export function checkApiPresence(openApiDetected, sources, headers) {
|
|
56
|
+
const id = "api_presence";
|
|
57
|
+
const label = "API Presence";
|
|
58
|
+
const signals = [];
|
|
59
|
+
// Signal 1: OpenAPI spec detected by Bridge 2
|
|
60
|
+
if (openApiDetected)
|
|
61
|
+
signals.push("OpenAPI spec");
|
|
62
|
+
// Signal 2: API-related response headers
|
|
63
|
+
const apiHeaders = API_HEADERS.filter((h) => headers[h] !== undefined);
|
|
64
|
+
if (apiHeaders.length > 0)
|
|
65
|
+
signals.push(`API headers (${apiHeaders.join(", ")})`);
|
|
66
|
+
// Signal 3 & 4: HTML and Markdown links to API-related paths
|
|
67
|
+
const apiLinks = [];
|
|
68
|
+
for (const { content } of sources) {
|
|
69
|
+
for (const link of scanApiLinks(content)) {
|
|
70
|
+
if (!apiLinks.includes(link))
|
|
71
|
+
apiLinks.push(link);
|
|
72
|
+
}
|
|
73
|
+
for (const link of scanApiLinksMarkdown(content)) {
|
|
74
|
+
if (!apiLinks.includes(link))
|
|
75
|
+
apiLinks.push(link);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (apiLinks.length > 0)
|
|
79
|
+
signals.push("API links found");
|
|
80
|
+
if (signals.length === 0) {
|
|
81
|
+
return {
|
|
82
|
+
id,
|
|
83
|
+
label,
|
|
84
|
+
status: "fail",
|
|
85
|
+
detail: "No API presence signals detected",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
id,
|
|
90
|
+
label,
|
|
91
|
+
status: "pass",
|
|
92
|
+
detail: `API presence detected: ${signals.join(", ")}`,
|
|
93
|
+
data: { signals, apiLinks, apiHeaders },
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=api-presence.js.map
|
|
@@ -0,0 +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;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,eAAwB,EACxB,OAAwB,EACxB,OAA+B;IAE/B,MAAM,EAAE,GAAG,cAAc,CAAC;IAC1B,MAAM,KAAK,GAAG,cAAc,CAAC;IAE7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,8CAA8C;IAC9C,IAAI,eAAe;QAAE,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAElD,yCAAyC;IACzC,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IACvE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,gBAAgB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEzD,6DAA6D;IAC7D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,OAAO,EAAE,CAAC;QAClC,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpD,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,oBAAoB,CAAC,OAAO,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAEzD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,EAAE;YACF,KAAK;YACL,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,kCAAkC;SAC3C,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE;QACF,KAAK;QACL,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,0BAA0B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACtD,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE;KACxC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Check, ContentSource } from "../../core/types.js";
|
|
2
|
+
/** Result of developer docs check, including page bodies for downstream use */
|
|
3
|
+
export interface DeveloperDocsResult {
|
|
4
|
+
check: Check;
|
|
5
|
+
pages: ContentSource[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Detect developer documentation via path probing and link scanning.
|
|
9
|
+
*
|
|
10
|
+
* Probes 5 well-known documentation paths with GET requests in parallel
|
|
11
|
+
* (capped at 1 MB body). Also scans homepage HTML for links pointing to
|
|
12
|
+
* documentation paths. Returns pass if any path is reachable or linked,
|
|
13
|
+
* fail otherwise.
|
|
14
|
+
*
|
|
15
|
+
* Returns both the check result and page bodies (ContentSource[]) for
|
|
16
|
+
* downstream content scanning by other Bridge 3 checks.
|
|
17
|
+
*
|
|
18
|
+
* This is the only async check module in Bridge 3 -- it requires HTTP.
|
|
19
|
+
*/
|
|
20
|
+
export declare function checkDeveloperDocs(baseUrl: string, html: string, timeout?: number): Promise<DeveloperDocsResult>;
|
|
21
|
+
//# sourceMappingURL=developer-docs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"developer-docs.d.ts","sourceRoot":"","sources":["../../../src/bridges/separation/developer-docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAehE,+EAA+E;AAC/E,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAqBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,CAAC,CAkD9B"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { httpGet } from "../../utils/http-client.js";
|
|
2
|
+
/** Maximum body size for developer docs page fetches (1 MB) */
|
|
3
|
+
const DEV_DOCS_MAX_BODY = 1_048_576;
|
|
4
|
+
/** Well-known paths for developer documentation */
|
|
5
|
+
const DOC_PATHS = [
|
|
6
|
+
"/docs",
|
|
7
|
+
"/developers",
|
|
8
|
+
"/developer",
|
|
9
|
+
"/api/docs",
|
|
10
|
+
"/documentation",
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* Scan homepage HTML for links pointing to documentation paths.
|
|
14
|
+
* Returns matched paths (deduplicated).
|
|
15
|
+
*/
|
|
16
|
+
function scanDocLinks(html) {
|
|
17
|
+
const found = [];
|
|
18
|
+
for (const path of DOC_PATHS) {
|
|
19
|
+
const escaped = path.replace(/\//g, "\\/");
|
|
20
|
+
const regex = new RegExp(`<a\\s[^>]*href=["'][^"']*${escaped}[^"']*["']`, "gi");
|
|
21
|
+
if (regex.test(html)) {
|
|
22
|
+
found.push(path);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return found;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Detect developer documentation via path probing and link scanning.
|
|
29
|
+
*
|
|
30
|
+
* Probes 5 well-known documentation paths with GET requests in parallel
|
|
31
|
+
* (capped at 1 MB body). Also scans homepage HTML for links pointing to
|
|
32
|
+
* documentation paths. Returns pass if any path is reachable or linked,
|
|
33
|
+
* fail otherwise.
|
|
34
|
+
*
|
|
35
|
+
* Returns both the check result and page bodies (ContentSource[]) for
|
|
36
|
+
* downstream content scanning by other Bridge 3 checks.
|
|
37
|
+
*
|
|
38
|
+
* This is the only async check module in Bridge 3 -- it requires HTTP.
|
|
39
|
+
*/
|
|
40
|
+
export async function checkDeveloperDocs(baseUrl, html, timeout) {
|
|
41
|
+
const id = "developer_docs";
|
|
42
|
+
const label = "Developer Documentation";
|
|
43
|
+
// Probe all 5 paths in parallel with GET requests (1 MB cap)
|
|
44
|
+
const results = await Promise.all(DOC_PATHS.map((path) => httpGet(new URL(path, baseUrl).href, { timeout, maxBodyBytes: DEV_DOCS_MAX_BODY })));
|
|
45
|
+
// Filter to reachable paths (2xx responses) and collect page bodies
|
|
46
|
+
const reachablePaths = [];
|
|
47
|
+
const pages = [];
|
|
48
|
+
for (let i = 0; i < DOC_PATHS.length; i++) {
|
|
49
|
+
const response = results[i];
|
|
50
|
+
if (response.ok) {
|
|
51
|
+
reachablePaths.push(DOC_PATHS[i]);
|
|
52
|
+
pages.push({ content: response.body, source: DOC_PATHS[i] });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Also scan homepage HTML for documentation links
|
|
56
|
+
const linkedPaths = scanDocLinks(html);
|
|
57
|
+
// Combine both signals (dedup)
|
|
58
|
+
const allFound = [...new Set([...reachablePaths, ...linkedPaths])];
|
|
59
|
+
if (allFound.length === 0) {
|
|
60
|
+
return {
|
|
61
|
+
check: {
|
|
62
|
+
id,
|
|
63
|
+
label,
|
|
64
|
+
status: "fail",
|
|
65
|
+
detail: "No developer documentation found",
|
|
66
|
+
},
|
|
67
|
+
pages: [],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
check: {
|
|
72
|
+
id,
|
|
73
|
+
label,
|
|
74
|
+
status: "pass",
|
|
75
|
+
detail: `Developer documentation detected: ${allFound.join(", ")}`,
|
|
76
|
+
data: { paths: allFound },
|
|
77
|
+
},
|
|
78
|
+
pages,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=developer-docs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"developer-docs.js","sourceRoot":"","sources":["../../../src/bridges/separation/developer-docs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAErD,+DAA+D;AAC/D,MAAM,iBAAiB,GAAG,SAAS,CAAC;AAEpC,mDAAmD;AACnD,MAAM,SAAS,GAAG;IAChB,OAAO;IACP,aAAa;IACb,YAAY;IACZ,WAAW;IACX,gBAAgB;CACR,CAAC;AAQX;;;GAGG;AACH,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,IAAI,MAAM,CACtB,4BAA4B,OAAO,YAAY,EAC/C,IAAI,CACL,CAAC;QACF,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAe,EACf,IAAY,EACZ,OAAgB;IAEhB,MAAM,EAAE,GAAG,gBAAgB,CAAC;IAC5B,MAAM,KAAK,GAAG,yBAAyB,CAAC;IAExC,6DAA6D;IAC7D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACrB,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC,CACnF,CACF,CAAC;IAEF,oEAAoE;IACpE,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,kDAAkD;IAClD,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEvC,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,cAAc,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAEnE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,KAAK,EAAE;gBACL,EAAE;gBACF,KAAK;gBACL,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,kCAAkC;aAC3C;YACD,KAAK,EAAE,EAAE;SACV,CAAC;IACJ,CAAC;IAED,OAAO;QACL,KAAK,EAAE;YACL,EAAE;YACF,KAAK;YACL,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,qCAAqC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAClE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE;SAC1B;QACD,KAAK;KACN,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BridgeResult, ScanContext } from "../../core/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Run Bridge 3: Separation.
|
|
4
|
+
*
|
|
5
|
+
* Runs 4 checks to detect API/developer separation signals:
|
|
6
|
+
* - 1 async HTTP probe (developer docs) fired first (non-blocking)
|
|
7
|
+
* - 3 synchronous pure-function checks (api presence, SDK references, webhook support)
|
|
8
|
+
*
|
|
9
|
+
* Unlike Bridges 1-2, Bridge 3 is a detection inventory with NO scoring.
|
|
10
|
+
* Returns score: null and scoreLabel: null.
|
|
11
|
+
*
|
|
12
|
+
* Reads from ctx.shared (openApiDetected, pageBody, pageHeaders, llmsTxtBody)
|
|
13
|
+
* set by Bridges 1 and 2. Writes ctx.shared.devDocsBodies with fetched
|
|
14
|
+
* developer documentation page bodies.
|
|
15
|
+
*
|
|
16
|
+
* Assembles ContentSource[] from homepage body, llms.txt body, and developer
|
|
17
|
+
* docs page bodies, then passes to all three pure-function checks.
|
|
18
|
+
*/
|
|
19
|
+
export declare function runSeparationBridge(ctx: ScanContext): Promise<BridgeResult>;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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,CAmDvB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { checkApiPresence } from "./api-presence.js";
|
|
2
|
+
import { checkDeveloperDocs } from "./developer-docs.js";
|
|
3
|
+
import { checkSdkReferences } from "./sdk-references.js";
|
|
4
|
+
import { checkWebhookSupport } from "./webhook-support.js";
|
|
5
|
+
/**
|
|
6
|
+
* Run Bridge 3: Separation.
|
|
7
|
+
*
|
|
8
|
+
* Runs 4 checks to detect API/developer separation signals:
|
|
9
|
+
* - 1 async HTTP probe (developer docs) fired first (non-blocking)
|
|
10
|
+
* - 3 synchronous pure-function checks (api presence, SDK references, webhook support)
|
|
11
|
+
*
|
|
12
|
+
* Unlike Bridges 1-2, Bridge 3 is a detection inventory with NO scoring.
|
|
13
|
+
* Returns score: null and scoreLabel: null.
|
|
14
|
+
*
|
|
15
|
+
* Reads from ctx.shared (openApiDetected, pageBody, pageHeaders, llmsTxtBody)
|
|
16
|
+
* set by Bridges 1 and 2. Writes ctx.shared.devDocsBodies with fetched
|
|
17
|
+
* developer documentation page bodies.
|
|
18
|
+
*
|
|
19
|
+
* Assembles ContentSource[] from homepage body, llms.txt body, and developer
|
|
20
|
+
* docs page bodies, then passes to all three pure-function checks.
|
|
21
|
+
*/
|
|
22
|
+
export async function runSeparationBridge(ctx) {
|
|
23
|
+
const start = performance.now();
|
|
24
|
+
// Extract shared context with safe defaults
|
|
25
|
+
const pageBody = ctx.shared.pageBody ?? "";
|
|
26
|
+
const pageHeaders = ctx.shared.pageHeaders ?? {};
|
|
27
|
+
const openApiDetected = ctx.shared.openApiDetected ?? false;
|
|
28
|
+
const llmsTxtBody = ctx.shared.llmsTxtBody ?? null;
|
|
29
|
+
// Fire async developer docs probe first (non-blocking)
|
|
30
|
+
const devDocsPromise = checkDeveloperDocs(ctx.baseUrl, pageBody, ctx.options.timeout);
|
|
31
|
+
// Await async check (need pages for content sources)
|
|
32
|
+
const devDocsResult = await devDocsPromise;
|
|
33
|
+
// Store dev docs pages in shared context for downstream bridges
|
|
34
|
+
ctx.shared.devDocsBodies = devDocsResult.pages;
|
|
35
|
+
// Assemble content sources from all available bodies
|
|
36
|
+
const contentSources = [];
|
|
37
|
+
if (pageBody)
|
|
38
|
+
contentSources.push({ content: pageBody, source: "homepage" });
|
|
39
|
+
if (llmsTxtBody)
|
|
40
|
+
contentSources.push({ content: llmsTxtBody, source: "llms.txt" });
|
|
41
|
+
contentSources.push(...devDocsResult.pages);
|
|
42
|
+
// Run 3 synchronous pure-function checks with assembled content sources
|
|
43
|
+
const apiPresenceCheck = checkApiPresence(openApiDetected, contentSources, pageHeaders);
|
|
44
|
+
const sdkRefsCheck = checkSdkReferences(contentSources);
|
|
45
|
+
const webhookCheck = checkWebhookSupport(contentSources);
|
|
46
|
+
// Assemble checks array in order
|
|
47
|
+
const checks = [
|
|
48
|
+
apiPresenceCheck,
|
|
49
|
+
devDocsResult.check,
|
|
50
|
+
sdkRefsCheck,
|
|
51
|
+
webhookCheck,
|
|
52
|
+
];
|
|
53
|
+
return {
|
|
54
|
+
id: 3,
|
|
55
|
+
name: "Separation",
|
|
56
|
+
status: "evaluated",
|
|
57
|
+
score: null,
|
|
58
|
+
scoreLabel: null,
|
|
59
|
+
checks,
|
|
60
|
+
durationMs: Math.round(performance.now() - start),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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,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;IACxF,MAAM,YAAY,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,mBAAmB,CAAC,cAAc,CAAC,CAAC;IAEzD,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,12 @@
|
|
|
1
|
+
import type { Check, ContentSource } from "../../core/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Detect SDK/package references across multiple content sources.
|
|
4
|
+
*
|
|
5
|
+
* Scans for package registry URLs (npmjs.com, pypi.org, etc.) and
|
|
6
|
+
* install commands (npm install, pip install, etc.). Returns deduplicated
|
|
7
|
+
* list of detected registries with source attribution.
|
|
8
|
+
*
|
|
9
|
+
* Pure function -- no HTTP calls.
|
|
10
|
+
*/
|
|
11
|
+
export declare function checkSdkReferences(sources: ContentSource[]): Check;
|
|
12
|
+
//# sourceMappingURL=sdk-references.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-references.d.ts","sourceRoot":"","sources":["../../../src/bridges/separation/sdk-references.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAyDhE;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,KAAK,CAwClE"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** Package registry patterns for SDK/package reference detection */
|
|
2
|
+
const REGISTRY_PATTERNS = [
|
|
3
|
+
{
|
|
4
|
+
name: "npm",
|
|
5
|
+
urlPattern: /npmjs\.com\/package\//i,
|
|
6
|
+
installPattern: /npm\s+install\s+\S/i,
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: "npm (CDN)",
|
|
10
|
+
urlPattern: /cdn\.jsdelivr\.net\/npm\/|unpkg\.com\//i,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: "PyPI",
|
|
14
|
+
urlPattern: /pypi\.org\/project\//i,
|
|
15
|
+
installPattern: /pip\s+install\s+\S/i,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: "Maven",
|
|
19
|
+
urlPattern: /search\.maven\.org|mvnrepository\.com/i,
|
|
20
|
+
installPattern: /<groupId>/i,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "NuGet",
|
|
24
|
+
urlPattern: /nuget\.org\/packages\//i,
|
|
25
|
+
installPattern: /dotnet\s+add\s+package\s+\S/i,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "Go",
|
|
29
|
+
urlPattern: /pkg\.go\.dev\//i,
|
|
30
|
+
installPattern: /go\s+get\s+\S/i,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "RubyGems",
|
|
34
|
+
urlPattern: /rubygems\.org\/gems\//i,
|
|
35
|
+
installPattern: /gem\s+install\s+\S/i,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "Packagist",
|
|
39
|
+
urlPattern: /packagist\.org\/packages\//i,
|
|
40
|
+
installPattern: /composer\s+require\s+\S/i,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "Crates.io",
|
|
44
|
+
urlPattern: /crates\.io\/crates\//i,
|
|
45
|
+
installPattern: /cargo\s+add\s+\S/i,
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
/**
|
|
49
|
+
* Detect SDK/package references across multiple content sources.
|
|
50
|
+
*
|
|
51
|
+
* Scans for package registry URLs (npmjs.com, pypi.org, etc.) and
|
|
52
|
+
* install commands (npm install, pip install, etc.). Returns deduplicated
|
|
53
|
+
* list of detected registries with source attribution.
|
|
54
|
+
*
|
|
55
|
+
* Pure function -- no HTTP calls.
|
|
56
|
+
*/
|
|
57
|
+
export function checkSdkReferences(sources) {
|
|
58
|
+
const id = "sdk_references";
|
|
59
|
+
const label = "SDK/Package References";
|
|
60
|
+
const detected = [];
|
|
61
|
+
const detectedSources = [];
|
|
62
|
+
for (const { content, source } of sources) {
|
|
63
|
+
for (const registry of REGISTRY_PATTERNS) {
|
|
64
|
+
if (detected.includes(registry.name))
|
|
65
|
+
continue;
|
|
66
|
+
const matched = registry.urlPattern.test(content) ||
|
|
67
|
+
(registry.installPattern !== undefined &&
|
|
68
|
+
registry.installPattern.test(content));
|
|
69
|
+
if (matched) {
|
|
70
|
+
detected.push(registry.name);
|
|
71
|
+
if (!detectedSources.includes(source))
|
|
72
|
+
detectedSources.push(source);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (detected.length === 0) {
|
|
77
|
+
return {
|
|
78
|
+
id,
|
|
79
|
+
label,
|
|
80
|
+
status: "fail",
|
|
81
|
+
detail: "No SDK/package references found",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const sourceAttr = detectedSources.length > 0 ? ` in ${detectedSources.join(", ")}` : "";
|
|
85
|
+
return {
|
|
86
|
+
id,
|
|
87
|
+
label,
|
|
88
|
+
status: "pass",
|
|
89
|
+
detail: `SDK references detected${sourceAttr}: ${detected.join(", ")}`,
|
|
90
|
+
data: { registries: detected, sources: detectedSources },
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=sdk-references.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-references.js","sourceRoot":"","sources":["../../../src/bridges/separation/sdk-references.ts"],"names":[],"mappings":"AASA,oEAAoE;AACpE,MAAM,iBAAiB,GAAsB;IAC3C;QACE,IAAI,EAAE,KAAK;QACX,UAAU,EAAE,wBAAwB;QACpC,cAAc,EAAE,qBAAqB;KACtC;IACD;QACE,IAAI,EAAE,WAAW;QACjB,UAAU,EAAE,yCAAyC;KACtD;IACD;QACE,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE,uBAAuB;QACnC,cAAc,EAAE,qBAAqB;KACtC;IACD;QACE,IAAI,EAAE,OAAO;QACb,UAAU,EAAE,wCAAwC;QACpD,cAAc,EAAE,YAAY;KAC7B;IACD;QACE,IAAI,EAAE,OAAO;QACb,UAAU,EAAE,yBAAyB;QACrC,cAAc,EAAE,8BAA8B;KAC/C;IACD;QACE,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,iBAAiB;QAC7B,cAAc,EAAE,gBAAgB;KACjC;IACD;QACE,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,wBAAwB;QACpC,cAAc,EAAE,qBAAqB;KACtC;IACD;QACE,IAAI,EAAE,WAAW;QACjB,UAAU,EAAE,6BAA6B;QACzC,cAAc,EAAE,0BAA0B;KAC3C;IACD;QACE,IAAI,EAAE,WAAW;QACjB,UAAU,EAAE,uBAAuB;QACnC,cAAc,EAAE,mBAAmB;KACpC;CACF,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAwB;IACzD,MAAM,EAAE,GAAG,gBAAgB,CAAC;IAC5B,MAAM,KAAK,GAAG,wBAAwB,CAAC;IAEvC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,eAAe,GAAa,EAAE,CAAC;IAErC,KAAK,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QAC1C,KAAK,MAAM,QAAQ,IAAI,iBAAiB,EAAE,CAAC;YACzC,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC/C,MAAM,OAAO,GACX,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;gBACjC,CAAC,QAAQ,CAAC,cAAc,KAAK,SAAS;oBACpC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3C,IAAI,OAAO,EAAE,CAAC;gBACZ,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC7B,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtE,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,EAAE;YACF,KAAK;YACL,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,iCAAiC;SAC1C,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GACd,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAExE,OAAO;QACL,EAAE;QACF,KAAK;QACL,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,0BAA0B,UAAU,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACtE,IAAI,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE;KACzD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Check, ContentSource } from "../../core/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Detect webhook support signals across multiple content sources.
|
|
4
|
+
*
|
|
5
|
+
* Scans for "webhook" keyword in:
|
|
6
|
+
* 1. HTML link hrefs containing "webhook"
|
|
7
|
+
* 2. HTML link text containing "webhook"
|
|
8
|
+
* 3. HTML headings (h1-h6) containing "webhook"
|
|
9
|
+
* 4. Markdown links containing "webhook"
|
|
10
|
+
* 5. Markdown headings containing "webhook"
|
|
11
|
+
* 6. URL paths containing "webhook" in structured data (JSON state, JS config)
|
|
12
|
+
*
|
|
13
|
+
* Avoids matching arbitrary paragraph text to reduce false positives
|
|
14
|
+
* from blog content or incidental mentions.
|
|
15
|
+
*
|
|
16
|
+
* Pure function -- no HTTP calls.
|
|
17
|
+
*/
|
|
18
|
+
export declare function checkWebhookSupport(sources: ContentSource[]): Check;
|
|
19
|
+
//# sourceMappingURL=webhook-support.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-support.d.ts","sourceRoot":"","sources":["../../../src/bridges/separation/webhook-support.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA8BhE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,KAAK,CA6DnE"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/** HTML patterns for webhook detection */
|
|
2
|
+
const HTML_PATTERNS = [
|
|
3
|
+
{
|
|
4
|
+
pattern: /<a\s[^>]*href=["'][^"']*webhook[^"']*["']/gi,
|
|
5
|
+
signal: "webhook link",
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
pattern: /<a\s[^>]*>[^<]*webhook[^<]*<\/a>/gi,
|
|
9
|
+
signal: "webhook link text",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
pattern: /<h[1-6][^>]*>[^<]*webhook[^<]*<\/h[1-6]>/gi,
|
|
13
|
+
signal: "webhook heading",
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
/** Markdown patterns for webhook detection */
|
|
17
|
+
const MARKDOWN_PATTERNS = [
|
|
18
|
+
{ pattern: /\[.*webhook.*\]\(/gi, signal: "webhook link (markdown)" },
|
|
19
|
+
{ pattern: /^#{1,6}\s+.*webhook/gim, signal: "webhook heading (markdown)" },
|
|
20
|
+
];
|
|
21
|
+
/** Structured data patterns — catches webhook paths in JSON state, JS config, etc. */
|
|
22
|
+
const STRUCTURED_PATTERNS = [
|
|
23
|
+
// Matches "/path/webhooks" or "\\u002Fpath\\u002Fwebhooks" in JSON/JS
|
|
24
|
+
{ pattern: /["'](?:\/|\\u002[Ff])[^"']*webhook[^"']*["']/gi, signal: "webhook path" },
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Detect webhook support signals across multiple content sources.
|
|
28
|
+
*
|
|
29
|
+
* Scans for "webhook" keyword in:
|
|
30
|
+
* 1. HTML link hrefs containing "webhook"
|
|
31
|
+
* 2. HTML link text containing "webhook"
|
|
32
|
+
* 3. HTML headings (h1-h6) containing "webhook"
|
|
33
|
+
* 4. Markdown links containing "webhook"
|
|
34
|
+
* 5. Markdown headings containing "webhook"
|
|
35
|
+
* 6. URL paths containing "webhook" in structured data (JSON state, JS config)
|
|
36
|
+
*
|
|
37
|
+
* Avoids matching arbitrary paragraph text to reduce false positives
|
|
38
|
+
* from blog content or incidental mentions.
|
|
39
|
+
*
|
|
40
|
+
* Pure function -- no HTTP calls.
|
|
41
|
+
*/
|
|
42
|
+
export function checkWebhookSupport(sources) {
|
|
43
|
+
const id = "webhook_support";
|
|
44
|
+
const label = "Webhook Support";
|
|
45
|
+
const signals = [];
|
|
46
|
+
const signalSources = [];
|
|
47
|
+
for (const { content, source } of sources) {
|
|
48
|
+
let sourceContributed = false;
|
|
49
|
+
// HTML patterns
|
|
50
|
+
for (const { pattern, signal } of HTML_PATTERNS) {
|
|
51
|
+
pattern.lastIndex = 0;
|
|
52
|
+
if (!signals.includes(signal) && pattern.test(content)) {
|
|
53
|
+
signals.push(signal);
|
|
54
|
+
sourceContributed = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Markdown patterns
|
|
58
|
+
for (const { pattern, signal } of MARKDOWN_PATTERNS) {
|
|
59
|
+
pattern.lastIndex = 0;
|
|
60
|
+
if (!signals.includes(signal) && pattern.test(content)) {
|
|
61
|
+
signals.push(signal);
|
|
62
|
+
sourceContributed = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Structured data patterns (JSON state, JS config)
|
|
66
|
+
for (const { pattern, signal } of STRUCTURED_PATTERNS) {
|
|
67
|
+
pattern.lastIndex = 0;
|
|
68
|
+
if (!signals.includes(signal) && pattern.test(content)) {
|
|
69
|
+
signals.push(signal);
|
|
70
|
+
sourceContributed = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (sourceContributed && !signalSources.includes(source)) {
|
|
74
|
+
signalSources.push(source);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (signals.length === 0) {
|
|
78
|
+
return {
|
|
79
|
+
id,
|
|
80
|
+
label,
|
|
81
|
+
status: "fail",
|
|
82
|
+
detail: "No webhook support signals detected",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const sourceAttr = signalSources.length > 0 ? ` in ${signalSources.join(", ")}` : "";
|
|
86
|
+
return {
|
|
87
|
+
id,
|
|
88
|
+
label,
|
|
89
|
+
status: "pass",
|
|
90
|
+
detail: `Webhook support detected${sourceAttr}: ${signals.join(", ")}`,
|
|
91
|
+
data: { signals, sources: signalSources },
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=webhook-support.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-support.js","sourceRoot":"","sources":["../../../src/bridges/separation/webhook-support.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BridgeResult, ScanContext } from "../../core/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Run Bridge 2: Standards.
|
|
4
|
+
*
|
|
5
|
+
* Runs 8 checks:
|
|
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
|
|
8
|
+
*
|
|
9
|
+
* Stores ctx.shared.openApiDetected for Bridge 3 consumption.
|
|
10
|
+
* Stores ctx.shared.llmsTxtBody for downstream consumption.
|
|
11
|
+
*/
|
|
12
|
+
export declare function runStandardsBridge(ctx: ScanContext): Promise<BridgeResult>;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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;AAiC5E;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,YAAY,CAAC,CAuDvB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { checkOpenApi } from "./openapi.js";
|
|
2
|
+
import { checkLlmsTxt, checkLlmsFullTxt } from "./llms-txt.js";
|
|
3
|
+
import { checkMcpEndpoint } from "./mcp.js";
|
|
4
|
+
import { checkJsonLd } from "./json-ld.js";
|
|
5
|
+
import { checkSchemaOrg } from "./schema-org.js";
|
|
6
|
+
import { checkSecurityTxt, checkAiPlugin } from "./well-known.js";
|
|
7
|
+
/**
|
|
8
|
+
* Calculate bridge score from check results.
|
|
9
|
+
* - Pass = 1 point, Partial = 0.5 points, Fail/Error = 0 points
|
|
10
|
+
* - All 8 checks always count (no skip concept in Bridge 2)
|
|
11
|
+
*/
|
|
12
|
+
function calculateScore(checks) {
|
|
13
|
+
let points = 0;
|
|
14
|
+
let maxPoints = 0;
|
|
15
|
+
for (const check of checks) {
|
|
16
|
+
maxPoints += 1;
|
|
17
|
+
if (check.status === "pass")
|
|
18
|
+
points += 1;
|
|
19
|
+
else if (check.status === "partial")
|
|
20
|
+
points += 0.5;
|
|
21
|
+
// fail and error = 0 points
|
|
22
|
+
}
|
|
23
|
+
const score = maxPoints === 0 ? 0 : Math.round((points / maxPoints) * 100);
|
|
24
|
+
const scoreLabel = score >= 80 ? "pass" : score >= 40 ? "partial" : "fail";
|
|
25
|
+
return { score, scoreLabel };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Run Bridge 2: Standards.
|
|
29
|
+
*
|
|
30
|
+
* Runs 8 checks:
|
|
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
|
+
*
|
|
34
|
+
* Stores ctx.shared.openApiDetected for Bridge 3 consumption.
|
|
35
|
+
* Stores ctx.shared.llmsTxtBody for downstream consumption.
|
|
36
|
+
*/
|
|
37
|
+
export async function runStandardsBridge(ctx) {
|
|
38
|
+
const start = performance.now();
|
|
39
|
+
// Get page body from shared context (set by Bridge 1)
|
|
40
|
+
const pageBody = ctx.shared.pageBody ?? "";
|
|
41
|
+
// Run all independent HTTP probes in parallel
|
|
42
|
+
const [openApiResult, llmsTxtResult, llmsFullTxtCheck, mcpCheck, securityTxtCheck, aiPluginCheck,] = await Promise.all([
|
|
43
|
+
checkOpenApi(ctx.baseUrl, ctx.options.timeout),
|
|
44
|
+
checkLlmsTxt(ctx.baseUrl, ctx.options.timeout),
|
|
45
|
+
checkLlmsFullTxt(ctx.baseUrl, ctx.options.timeout),
|
|
46
|
+
checkMcpEndpoint(ctx.baseUrl, ctx.options.timeout),
|
|
47
|
+
checkSecurityTxt(ctx.baseUrl, ctx.options.timeout),
|
|
48
|
+
checkAiPlugin(ctx.baseUrl, ctx.options.timeout),
|
|
49
|
+
]);
|
|
50
|
+
// Run HTML-based checks (synchronous, no HTTP)
|
|
51
|
+
const jsonLdCheck = checkJsonLd(pageBody);
|
|
52
|
+
const schemaOrgCheck = checkSchemaOrg(pageBody, jsonLdCheck);
|
|
53
|
+
// Store OpenAPI detection result for Bridge 3
|
|
54
|
+
ctx.shared.openApiDetected = openApiResult.detected;
|
|
55
|
+
ctx.shared.llmsTxtBody = llmsTxtResult.body;
|
|
56
|
+
// Collect all 8 checks in order
|
|
57
|
+
const checks = [
|
|
58
|
+
openApiResult.check,
|
|
59
|
+
llmsTxtResult.check,
|
|
60
|
+
llmsFullTxtCheck,
|
|
61
|
+
mcpCheck,
|
|
62
|
+
jsonLdCheck,
|
|
63
|
+
schemaOrgCheck,
|
|
64
|
+
securityTxtCheck,
|
|
65
|
+
aiPluginCheck,
|
|
66
|
+
];
|
|
67
|
+
// Calculate score
|
|
68
|
+
const { score, scoreLabel } = calculateScore(checks);
|
|
69
|
+
return {
|
|
70
|
+
id: 2,
|
|
71
|
+
name: "Standards",
|
|
72
|
+
status: "evaluated",
|
|
73
|
+
score,
|
|
74
|
+
scoreLabel,
|
|
75
|
+
checks,
|
|
76
|
+
durationMs: Math.round(performance.now() - start),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bridges/standards/index.ts"],"names":[],"mappings":"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"}
|