@j0hanz/superfetch 1.1.8 → 1.2.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/README.md +258 -362
- package/dist/config/constants.d.ts +20 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +25 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/formatting.d.ts +0 -1
- package/dist/config/formatting.d.ts.map +1 -1
- package/dist/config/formatting.js +1 -1
- package/dist/config/formatting.js.map +1 -1
- package/dist/config/index.d.ts +8 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +14 -5
- package/dist/config/index.js.map +1 -1
- package/dist/config/types/content.d.ts +1 -19
- package/dist/config/types/content.d.ts.map +1 -1
- package/dist/config/types/runtime.d.ts +7 -4
- package/dist/config/types/runtime.d.ts.map +1 -1
- package/dist/config/types/tools.d.ts +5 -49
- package/dist/config/types/tools.d.ts.map +1 -1
- package/dist/http/auth.d.ts.map +1 -1
- package/dist/http/auth.js +17 -12
- package/dist/http/auth.js.map +1 -1
- package/dist/http/cors.js +4 -0
- package/dist/http/cors.js.map +1 -1
- package/dist/http/download-routes.d.ts +15 -0
- package/dist/http/download-routes.d.ts.map +1 -0
- package/dist/http/download-routes.js +132 -0
- package/dist/http/download-routes.js.map +1 -0
- package/dist/http/mcp-routes.d.ts +1 -1
- package/dist/http/mcp-routes.d.ts.map +1 -1
- package/dist/http/mcp-routes.js +1 -1
- package/dist/http/mcp-routes.js.map +1 -1
- package/dist/http/mcp-session-helpers.d.ts +14 -0
- package/dist/http/mcp-session-helpers.d.ts.map +1 -0
- package/dist/http/mcp-session-helpers.js +65 -0
- package/dist/http/mcp-session-helpers.js.map +1 -0
- package/dist/http/mcp-session.d.ts +0 -1
- package/dist/http/mcp-session.d.ts.map +1 -1
- package/dist/http/mcp-session.js +7 -70
- package/dist/http/mcp-session.js.map +1 -1
- package/dist/http/server-middleware.d.ts +10 -0
- package/dist/http/server-middleware.d.ts.map +1 -0
- package/dist/http/server-middleware.js +56 -0
- package/dist/http/server-middleware.js.map +1 -0
- package/dist/http/server.d.ts.map +1 -1
- package/dist/http/server.js +20 -98
- package/dist/http/server.js.map +1 -1
- package/dist/http/session-cleanup.d.ts +3 -0
- package/dist/http/session-cleanup.d.ts.map +1 -0
- package/dist/http/session-cleanup.js +38 -0
- package/dist/http/session-cleanup.js.map +1 -0
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/resources/cached-content.d.ts.map +1 -1
- package/dist/resources/cached-content.js +76 -11
- package/dist/resources/cached-content.js.map +1 -1
- package/dist/services/cache.d.ts +6 -2
- package/dist/services/cache.d.ts.map +1 -1
- package/dist/services/cache.js +86 -25
- package/dist/services/cache.js.map +1 -1
- package/dist/services/context.d.ts +2 -1
- package/dist/services/context.d.ts.map +1 -1
- package/dist/services/extractor.d.ts.map +1 -1
- package/dist/services/extractor.js +45 -17
- package/dist/services/extractor.js.map +1 -1
- package/dist/services/fetcher/agents.d.ts.map +1 -1
- package/dist/services/fetcher/agents.js +3 -6
- package/dist/services/fetcher/agents.js.map +1 -1
- package/dist/services/fetcher/headers.d.ts.map +1 -1
- package/dist/services/fetcher/headers.js +2 -24
- package/dist/services/fetcher/headers.js.map +1 -1
- package/dist/services/fetcher/interceptors.d.ts +2 -1
- package/dist/services/fetcher/interceptors.d.ts.map +1 -1
- package/dist/services/fetcher/interceptors.js +30 -20
- package/dist/services/fetcher/interceptors.js.map +1 -1
- package/dist/services/fetcher/redirects.d.ts +0 -1
- package/dist/services/fetcher/redirects.d.ts.map +1 -1
- package/dist/services/fetcher/redirects.js +19 -16
- package/dist/services/fetcher/redirects.js.map +1 -1
- package/dist/services/fetcher/retry-policy.d.ts +1 -27
- package/dist/services/fetcher/retry-policy.d.ts.map +1 -1
- package/dist/services/fetcher/retry-policy.js +119 -125
- package/dist/services/fetcher/retry-policy.js.map +1 -1
- package/dist/services/fetcher.d.ts.map +1 -1
- package/dist/services/fetcher.js +15 -9
- package/dist/services/fetcher.js.map +1 -1
- package/dist/services/parser.d.ts +0 -1
- package/dist/services/parser.d.ts.map +1 -1
- package/dist/services/parser.js +5 -38
- package/dist/services/parser.js.map +1 -1
- package/dist/tools/handlers/fetch-links/link-extractor.d.ts.map +1 -1
- package/dist/tools/handlers/fetch-links/link-extractor.js +15 -19
- package/dist/tools/handlers/fetch-links/link-extractor.js.map +1 -1
- package/dist/tools/handlers/fetch-links.tool.d.ts.map +1 -1
- package/dist/tools/handlers/fetch-links.tool.js +0 -2
- package/dist/tools/handlers/fetch-links.tool.js.map +1 -1
- package/dist/tools/handlers/fetch-markdown.tool.d.ts.map +1 -1
- package/dist/tools/handlers/fetch-markdown.tool.js +16 -17
- package/dist/tools/handlers/fetch-markdown.tool.js.map +1 -1
- package/dist/tools/handlers/fetch-single.shared.d.ts +11 -2
- package/dist/tools/handlers/fetch-single.shared.d.ts.map +1 -1
- package/dist/tools/handlers/fetch-single.shared.js +61 -2
- package/dist/tools/handlers/fetch-single.shared.js.map +1 -1
- package/dist/tools/handlers/fetch-url.tool.d.ts.map +1 -1
- package/dist/tools/handlers/fetch-url.tool.js +3 -14
- package/dist/tools/handlers/fetch-url.tool.js.map +1 -1
- package/dist/tools/handlers/fetch-urls/response.d.ts.map +1 -1
- package/dist/tools/handlers/fetch-urls/response.js +5 -5
- package/dist/tools/handlers/fetch-urls/response.js.map +1 -1
- package/dist/tools/handlers/fetch-urls/validation.d.ts +0 -1
- package/dist/tools/handlers/fetch-urls/validation.d.ts.map +1 -1
- package/dist/tools/handlers/fetch-urls/validation.js +1 -1
- package/dist/tools/handlers/fetch-urls/validation.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -19
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/schemas.d.ts +44 -236
- package/dist/tools/schemas.d.ts.map +1 -1
- package/dist/tools/schemas.js +38 -197
- package/dist/tools/schemas.js.map +1 -1
- package/dist/tools/utils/cache-vary.d.ts +0 -1
- package/dist/tools/utils/cache-vary.d.ts.map +1 -1
- package/dist/tools/utils/cache-vary.js +11 -25
- package/dist/tools/utils/cache-vary.js.map +1 -1
- package/dist/tools/utils/common.d.ts +1 -2
- package/dist/tools/utils/common.d.ts.map +1 -1
- package/dist/tools/utils/common.js.map +1 -1
- package/dist/tools/utils/content-transform.d.ts.map +1 -1
- package/dist/tools/utils/content-transform.js +28 -13
- package/dist/tools/utils/content-transform.js.map +1 -1
- package/dist/tools/utils/fetch-pipeline.js +14 -3
- package/dist/tools/utils/fetch-pipeline.js.map +1 -1
- package/dist/tools/utils/inline-content.d.ts +3 -2
- package/dist/tools/utils/inline-content.d.ts.map +1 -1
- package/dist/transformers/markdown.transformer.d.ts.map +1 -1
- package/dist/transformers/markdown.transformer.js +3 -6
- package/dist/transformers/markdown.transformer.js.map +1 -1
- package/dist/utils/code-language.d.ts +3 -0
- package/dist/utils/code-language.d.ts.map +1 -0
- package/dist/utils/code-language.js +57 -0
- package/dist/utils/code-language.js.map +1 -0
- package/dist/utils/content-cleaner.d.ts +0 -1
- package/dist/utils/content-cleaner.d.ts.map +1 -1
- package/dist/utils/content-cleaner.js +0 -3
- package/dist/utils/content-cleaner.js.map +1 -1
- package/dist/utils/crypto.d.ts +3 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +33 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/download-url.d.ts +9 -0
- package/dist/utils/download-url.d.ts.map +1 -0
- package/dist/utils/download-url.js +28 -0
- package/dist/utils/download-url.js.map +1 -0
- package/dist/utils/error-utils.d.ts +4 -0
- package/dist/utils/error-utils.d.ts.map +1 -0
- package/dist/utils/error-utils.js +14 -0
- package/dist/utils/error-utils.js.map +1 -0
- package/dist/utils/filename-generator.d.ts +2 -0
- package/dist/utils/filename-generator.d.ts.map +1 -0
- package/dist/utils/filename-generator.js +60 -0
- package/dist/utils/filename-generator.js.map +1 -0
- package/dist/utils/header-normalizer.d.ts +7 -3
- package/dist/utils/header-normalizer.d.ts.map +1 -1
- package/dist/utils/header-normalizer.js +23 -16
- package/dist/utils/header-normalizer.js.map +1 -1
- package/dist/utils/tool-error-handler.d.ts +0 -1
- package/dist/utils/tool-error-handler.d.ts.map +1 -1
- package/dist/utils/tool-error-handler.js +11 -5
- package/dist/utils/tool-error-handler.js.map +1 -1
- package/dist/utils/url-sanitizer.d.ts +2 -0
- package/dist/utils/url-sanitizer.d.ts.map +1 -0
- package/dist/utils/url-sanitizer.js +12 -0
- package/dist/utils/url-sanitizer.js.map +1 -0
- package/dist/utils/url-validator.d.ts.map +1 -1
- package/dist/utils/url-validator.js +46 -44
- package/dist/utils/url-validator.js.map +1 -1
- package/package.json +4 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-language.d.ts","sourceRoot":"","sources":["../../src/utils/code-language.ts"],"names":[],"mappings":"AAkCA,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOvE;AAED,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,SAAS,CAGpB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const CODE_PATTERNS = [
|
|
2
|
+
[
|
|
3
|
+
/^\s*import\s+.*\s+from\s+['"]react['"]|<[A-Z][a-zA-Z]*[\s/>]|jsx\s*:|className=/m,
|
|
4
|
+
'jsx',
|
|
5
|
+
],
|
|
6
|
+
[
|
|
7
|
+
/:\s*(string|number|boolean|void|any|unknown|never)\b|interface\s+\w+|type\s+\w+\s*=/m,
|
|
8
|
+
'typescript',
|
|
9
|
+
],
|
|
10
|
+
[/^\s*(fn|let\s+mut|impl|struct|enum|use\s+\w+::)/m, 'rust'],
|
|
11
|
+
[
|
|
12
|
+
/^\s*(export|const|let|var|function|class|async|await)\b|^\s*import\s+.*['"]]/m,
|
|
13
|
+
'javascript',
|
|
14
|
+
],
|
|
15
|
+
[/^\s*(def|class|import|from|if __name__|print\()/m, 'python'],
|
|
16
|
+
[
|
|
17
|
+
/^\s*(npm|yarn|pnpm|npx|brew|apt|pip|cargo|go )\s+(install|add|run|build|start)/m,
|
|
18
|
+
'bash',
|
|
19
|
+
],
|
|
20
|
+
[/^\s*[$#]\s+\w+|^\s*#!|^\s*(sudo|chmod|mkdir|cd|ls|cat|echo)\s+/m, 'bash'],
|
|
21
|
+
[/^\s*[.#@]?[\w-]+\s*\{[^}]*\}|@media|@import|@keyframes/m, 'css'],
|
|
22
|
+
[/^\s*<(!DOCTYPE|html|head|body|div|span|p|a|script|style)\b/im, 'html'],
|
|
23
|
+
[/^\s*\{\s*"|^\s*\[\s*("|\d|true|false|null)/m, 'json'],
|
|
24
|
+
[/^\s*[\w-]+:\s*.+$/m, 'yaml'],
|
|
25
|
+
[/^\s*(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\s+/im, 'sql'],
|
|
26
|
+
[/^\s*(func|package|import\s+")/m, 'go'],
|
|
27
|
+
];
|
|
28
|
+
const CLASS_PATTERNS = [
|
|
29
|
+
/language-(\w+)/,
|
|
30
|
+
/lang-(\w+)/,
|
|
31
|
+
/highlight-(\w+)/,
|
|
32
|
+
];
|
|
33
|
+
export function detectLanguageFromCode(code) {
|
|
34
|
+
for (const [pattern, language] of CODE_PATTERNS) {
|
|
35
|
+
if (pattern.test(code)) {
|
|
36
|
+
return language;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
export function resolveLanguageFromAttributes(className, dataLang) {
|
|
42
|
+
const classMatch = matchFirstCapture(className, CLASS_PATTERNS);
|
|
43
|
+
return classMatch ?? resolveLanguageFromDataAttribute(dataLang);
|
|
44
|
+
}
|
|
45
|
+
function matchFirstCapture(value, patterns) {
|
|
46
|
+
for (const pattern of patterns) {
|
|
47
|
+
const match = pattern.exec(value);
|
|
48
|
+
if (match?.[1])
|
|
49
|
+
return match[1];
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
function resolveLanguageFromDataAttribute(dataLang) {
|
|
54
|
+
const match = /^(\w+)$/.exec(dataLang);
|
|
55
|
+
return match?.[1];
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=code-language.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-language.js","sourceRoot":"","sources":["../../src/utils/code-language.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAAgC;IACjD;QACE,kFAAkF;QAClF,KAAK;KACN;IACD;QACE,sFAAsF;QACtF,YAAY;KACb;IACD,CAAC,kDAAkD,EAAE,MAAM,CAAC;IAC5D;QACE,+EAA+E;QAC/E,YAAY;KACb;IACD,CAAC,kDAAkD,EAAE,QAAQ,CAAC;IAC9D;QACE,iFAAiF;QACjF,MAAM;KACP;IACD,CAAC,iEAAiE,EAAE,MAAM,CAAC;IAC3E,CAAC,yDAAyD,EAAE,KAAK,CAAC;IAClE,CAAC,8DAA8D,EAAE,MAAM,CAAC;IACxE,CAAC,6CAA6C,EAAE,MAAM,CAAC;IACvD,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAC9B,CAAC,0DAA0D,EAAE,KAAK,CAAC;IACnE,CAAC,gCAAgC,EAAE,IAAI,CAAC;CACzC,CAAC;AAEF,MAAM,cAAc,GAAG;IACrB,gBAAgB;IAChB,YAAY;IACZ,iBAAiB;CACT,CAAC;AAEX,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,KAAK,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,aAAa,EAAE,CAAC;QAChD,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,SAAiB,EACjB,QAAgB;IAEhB,MAAM,UAAU,GAAG,iBAAiB,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAChE,OAAO,UAAU,IAAI,gCAAgC,CAAC,QAAQ,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,iBAAiB,CACxB,KAAa,EACb,QAA2B;IAE3B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,gCAAgC,CACvC,QAAgB;IAEhB,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvC,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC"}
|
|
@@ -2,6 +2,5 @@ export declare function cleanParagraph(text: string): string | null;
|
|
|
2
2
|
export declare function cleanHeading(text: string): string | null;
|
|
3
3
|
export declare function cleanListItems(items: string[]): string[];
|
|
4
4
|
export declare function cleanCodeBlock(code: string): string | null;
|
|
5
|
-
export declare function stripMarkdownLinks(text: string): string;
|
|
6
5
|
export declare function removeInlineTimestamps(text: string): string;
|
|
7
6
|
//# sourceMappingURL=content-cleaner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-cleaner.d.ts","sourceRoot":"","sources":["../../src/utils/content-cleaner.ts"],"names":[],"mappings":"AA2BA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc1D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBxD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQxD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY1D;AAED,wBAAgB,
|
|
1
|
+
{"version":3,"file":"content-cleaner.d.ts","sourceRoot":"","sources":["../../src/utils/content-cleaner.ts"],"names":[],"mappings":"AA2BA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc1D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBxD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQxD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY1D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgB3D"}
|
|
@@ -67,9 +67,6 @@ export function cleanCodeBlock(code) {
|
|
|
67
67
|
}
|
|
68
68
|
return trimmed;
|
|
69
69
|
}
|
|
70
|
-
export function stripMarkdownLinks(text) {
|
|
71
|
-
return text.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1');
|
|
72
|
-
}
|
|
73
70
|
export function removeInlineTimestamps(text) {
|
|
74
71
|
return text
|
|
75
72
|
.replace(/\b\d+\s*(seconds?|minutes?|hours?|days?|weeks?|months?|years?)\s*ago\b/gi, '')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-cleaner.js","sourceRoot":"","sources":["../../src/utils/content-cleaner.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAAG,IAAI,MAAM,CAC9B;IACE,0DAA0D;IAC1D,oDAAoD;IACpD,wEAAwE;IACxE,6DAA6D;IAC7D,wCAAwC;IACxC,iDAAiD;IACjD,4CAA4C;IAC5C,sDAAsD;IACtD,gBAAgB;CACjB,CAAC,IAAI,CAAC,GAAG,CAAC,EACX,GAAG,CACJ,CAAC;AAEF,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAChC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAEnC,SAAS,WAAW,CAAC,IAAY;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,OAAO,CAAC,MAAM,GAAG,sBAAsB;QAAE,OAAO,KAAK,CAAC;IAC1D,OAAO,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAE5B,IAAI,OAAO,CAAC,MAAM,GAAG,oBAAoB,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAE1B,IAAI,OAAO,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC;IAC1D,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,yCAAyC,EAAE,EAAE,CAAC,CAAC;IACzE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAE3C,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACf,IAAI,IAAI,CAAC,MAAM,GAAG,oBAAoB;YAAE,OAAO,KAAK,CAAC;QACrD,IAAI,WAAW,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAE5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"content-cleaner.js","sourceRoot":"","sources":["../../src/utils/content-cleaner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAiBA,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAKjE;AAmBD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAE5D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createHash, hash as oneShotHash, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
const MAX_HASH_INPUT_BYTES = 5 * 1024 * 1024;
|
|
3
|
+
const ALLOWED_HASH_ALGORITHMS = new Set([
|
|
4
|
+
'sha256',
|
|
5
|
+
'sha512',
|
|
6
|
+
]);
|
|
7
|
+
function byteLength(input) {
|
|
8
|
+
return typeof input === 'string'
|
|
9
|
+
? Buffer.byteLength(input, 'utf8')
|
|
10
|
+
: input.byteLength;
|
|
11
|
+
}
|
|
12
|
+
export function timingSafeEqualUtf8(a, b) {
|
|
13
|
+
const aBuffer = Buffer.from(a, 'utf8');
|
|
14
|
+
const bBuffer = Buffer.from(b, 'utf8');
|
|
15
|
+
if (aBuffer.length !== bBuffer.length)
|
|
16
|
+
return false;
|
|
17
|
+
return timingSafeEqual(aBuffer, bBuffer);
|
|
18
|
+
}
|
|
19
|
+
function hashHex(algorithm, input) {
|
|
20
|
+
if (!ALLOWED_HASH_ALGORITHMS.has(algorithm)) {
|
|
21
|
+
throw new Error(`Hash algorithm not allowed: ${algorithm}`);
|
|
22
|
+
}
|
|
23
|
+
if (byteLength(input) <= MAX_HASH_INPUT_BYTES) {
|
|
24
|
+
return oneShotHash(algorithm, input, 'hex');
|
|
25
|
+
}
|
|
26
|
+
const hasher = createHash(algorithm);
|
|
27
|
+
hasher.update(input);
|
|
28
|
+
return hasher.digest('hex');
|
|
29
|
+
}
|
|
30
|
+
export function sha256Hex(input) {
|
|
31
|
+
return hashHex('sha256', input);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,IAAI,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE/E,MAAM,oBAAoB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAI7C,MAAM,uBAAuB,GAAsC,IAAI,GAAG,CAAC;IACzE,QAAQ;IACR,QAAQ;CACT,CAAC,CAAC;AAEH,SAAS,UAAU,CAAC,KAA0B;IAC5C,OAAO,OAAO,KAAK,KAAK,QAAQ;QAC9B,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC;QAClC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,CAAS,EAAE,CAAS;IACtD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACvC,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACpD,OAAO,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,OAAO,CACd,SAA+B,EAC/B,KAA0B;IAE1B,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,+BAA+B,SAAS,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,oBAAoB,EAAE,CAAC;QAC9C,OAAO,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACrC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAA0B;IAClD,OAAO,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FileDownloadInfo } from '../config/types.js';
|
|
2
|
+
interface DownloadInfoOptions {
|
|
3
|
+
cacheKey: string | null;
|
|
4
|
+
url: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function buildFileDownloadInfo(options: DownloadInfoOptions): FileDownloadInfo | null;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=download-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download-url.d.ts","sourceRoot":"","sources":["../../src/utils/download-url.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAM3D,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,mBAAmB,GAC3B,gBAAgB,GAAG,IAAI,CA0BzB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { config } from '../config/index.js';
|
|
2
|
+
import * as cache from '../services/cache.js';
|
|
3
|
+
import { generateSafeFilename } from './filename-generator.js';
|
|
4
|
+
export function buildFileDownloadInfo(options) {
|
|
5
|
+
if (!config.runtime.httpMode) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
if (!config.cache.enabled || !options.cacheKey) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const parts = cache.parseCacheKey(options.cacheKey);
|
|
12
|
+
if (!parts)
|
|
13
|
+
return null;
|
|
14
|
+
const cacheEntry = cache.get(options.cacheKey);
|
|
15
|
+
if (!cacheEntry)
|
|
16
|
+
return null;
|
|
17
|
+
const { expiresAt, title, url } = cacheEntry;
|
|
18
|
+
const downloadUrl = buildDownloadUrl(parts.namespace, parts.urlHash);
|
|
19
|
+
const fileName = generateSafeFilename(url, title ?? options.title, parts.urlHash, resolveExtension(parts.namespace));
|
|
20
|
+
return { downloadUrl, fileName, expiresAt };
|
|
21
|
+
}
|
|
22
|
+
function buildDownloadUrl(namespace, hash) {
|
|
23
|
+
return `/mcp/downloads/${namespace}/${hash}`;
|
|
24
|
+
}
|
|
25
|
+
function resolveExtension(namespace) {
|
|
26
|
+
return namespace === 'markdown' ? '.md' : '.jsonl';
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=download-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download-url.js","sourceRoot":"","sources":["../../src/utils/download-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAG5C,OAAO,KAAK,KAAK,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAQ/D,MAAM,UAAU,qBAAqB,CACnC,OAA4B;IAE5B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,UAAU,CAAC;IAE7C,MAAM,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,oBAAoB,CACnC,GAAG,EACH,KAAK,IAAI,OAAO,CAAC,KAAK,EACtB,KAAK,CAAC,OAAO,EACb,gBAAgB,CAAC,KAAK,CAAC,SAAS,CAAC,CAClC,CAAC;IAEF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAC9C,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB,EAAE,IAAY;IACvD,OAAO,kBAAkB,SAAS,IAAI,IAAI,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB;IACzC,OAAO,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function getErrorMessage(error: unknown): string;
|
|
2
|
+
export declare function createErrorWithCode(message: string, code: string): NodeJS.ErrnoException;
|
|
3
|
+
export declare function isSystemError(error: unknown): error is NodeJS.ErrnoException;
|
|
4
|
+
//# sourceMappingURL=error-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-utils.d.ts","sourceRoot":"","sources":["../../src/utils/error-utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEtD;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,cAAc,CAIvB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAM5E"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function getErrorMessage(error) {
|
|
2
|
+
return error instanceof Error ? error.message : 'Unknown error';
|
|
3
|
+
}
|
|
4
|
+
export function createErrorWithCode(message, code) {
|
|
5
|
+
const error = new Error(message);
|
|
6
|
+
error.code = code;
|
|
7
|
+
return error;
|
|
8
|
+
}
|
|
9
|
+
export function isSystemError(error) {
|
|
10
|
+
return (error instanceof Error &&
|
|
11
|
+
'code' in error &&
|
|
12
|
+
typeof error.code === 'string');
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=error-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-utils.js","sourceRoot":"","sources":["../../src/utils/error-utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,IAAY;IAEZ,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAA0B,CAAC;IAC1D,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,CACL,KAAK,YAAY,KAAK;QACtB,MAAM,IAAI,KAAK;QACf,OAAQ,KAA+B,CAAC,IAAI,KAAK,QAAQ,CAC1D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filename-generator.d.ts","sourceRoot":"","sources":["../../src/utils/filename-generator.ts"],"names":[],"mappings":"AAMA,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,KAAK,CAAC,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,SAAS,GAAE,MAA0B,GACpC,MAAM,CAcR"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const MAX_FILENAME_LENGTH = 200;
|
|
2
|
+
const UNSAFE_CHARS_REGEX = /[<>:"/\\|?*]|\p{C}/gu;
|
|
3
|
+
const WHITESPACE_REGEX = /\s+/g;
|
|
4
|
+
const DEFAULT_EXTENSION = '.md';
|
|
5
|
+
export function generateSafeFilename(url, title, hashFallback, extension = DEFAULT_EXTENSION) {
|
|
6
|
+
const fromUrl = extractFilenameFromUrl(url);
|
|
7
|
+
if (fromUrl)
|
|
8
|
+
return sanitizeFilename(fromUrl, extension);
|
|
9
|
+
if (title) {
|
|
10
|
+
const fromTitle = slugifyTitle(title);
|
|
11
|
+
if (fromTitle)
|
|
12
|
+
return sanitizeFilename(fromTitle, extension);
|
|
13
|
+
}
|
|
14
|
+
if (hashFallback) {
|
|
15
|
+
return `${hashFallback.substring(0, 16)}${extension}`;
|
|
16
|
+
}
|
|
17
|
+
return `download-${Date.now()}${extension}`;
|
|
18
|
+
}
|
|
19
|
+
function extractFilenameFromUrl(url) {
|
|
20
|
+
try {
|
|
21
|
+
const urlObj = new URL(url);
|
|
22
|
+
const { pathname } = urlObj;
|
|
23
|
+
const segments = pathname.split('/').filter(Boolean);
|
|
24
|
+
if (segments.length === 0)
|
|
25
|
+
return null;
|
|
26
|
+
const lastSegment = segments[segments.length - 1];
|
|
27
|
+
if (!lastSegment)
|
|
28
|
+
return null;
|
|
29
|
+
const cleaned = lastSegment.replace(/\.(html?|php|aspx?|jsp)$/i, '');
|
|
30
|
+
if (!cleaned || cleaned === 'index')
|
|
31
|
+
return null;
|
|
32
|
+
return cleaned;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function slugifyTitle(title) {
|
|
39
|
+
const slug = title
|
|
40
|
+
.toLowerCase()
|
|
41
|
+
.trim()
|
|
42
|
+
.replace(UNSAFE_CHARS_REGEX, '')
|
|
43
|
+
.replace(WHITESPACE_REGEX, '-')
|
|
44
|
+
.replace(/-+/g, '-')
|
|
45
|
+
.replace(/^-|-$/g, '');
|
|
46
|
+
return slug.length > 0 ? slug : null;
|
|
47
|
+
}
|
|
48
|
+
function sanitizeFilename(name, extension) {
|
|
49
|
+
let sanitized = name
|
|
50
|
+
.replace(UNSAFE_CHARS_REGEX, '')
|
|
51
|
+
.replace(WHITESPACE_REGEX, '-')
|
|
52
|
+
.trim();
|
|
53
|
+
// Truncate if too long
|
|
54
|
+
const maxBase = MAX_FILENAME_LENGTH - extension.length;
|
|
55
|
+
if (sanitized.length > maxBase) {
|
|
56
|
+
sanitized = sanitized.substring(0, maxBase);
|
|
57
|
+
}
|
|
58
|
+
return `${sanitized}${extension}`;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=filename-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filename-generator.js","sourceRoot":"","sources":["../../src/utils/filename-generator.ts"],"names":[],"mappings":"AAAA,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAClD,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAEhC,MAAM,UAAU,oBAAoB,CAClC,GAAW,EACX,KAAc,EACd,YAAqB,EACrB,YAAoB,iBAAiB;IAErC,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,OAAO;QAAE,OAAO,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAEzD,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,SAAS;YAAE,OAAO,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC;IACxD,CAAC;IAED,OAAO,YAAY,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;AAC9C,CAAC;AAED,SAAS,sBAAsB,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;QAE5B,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAEvC,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAClD,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAE9B,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;QAErE,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QAEjD,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,MAAM,IAAI,GAAG,KAAK;SACf,WAAW,EAAE;SACb,IAAI,EAAE;SACN,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC;SAC9B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAEzB,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY,EAAE,SAAiB;IACvD,IAAI,SAAS,GAAG,IAAI;SACjB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC;SAC9B,IAAI,EAAE,CAAC;IAEV,uBAAuB;IACvB,MAAM,OAAO,GAAG,mBAAmB,GAAG,SAAS,CAAC,MAAM,CAAC;IACvD,IAAI,SAAS,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;QAC/B,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;AACpC,CAAC"}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
readonly
|
|
1
|
+
interface NormalizeOptions {
|
|
2
|
+
readonly trimValues?: boolean;
|
|
3
3
|
}
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function normalizeHeaderRecord(headers: Record<string, string> | undefined, blockedHeaders: Set<string>, options?: NormalizeOptions): Record<string, string> | undefined;
|
|
5
|
+
export declare function normalizeHeaderEntries(headers: Record<string, string>, blockedHeaders: Set<string>, options?: NormalizeOptions): Headers;
|
|
6
|
+
export declare function hasHeaderEntries(headers: Headers): boolean;
|
|
7
|
+
export declare function headersToRecord(headers: Headers): Record<string, string>;
|
|
8
|
+
export {};
|
|
5
9
|
//# sourceMappingURL=header-normalizer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"header-normalizer.d.ts","sourceRoot":"","sources":["../../src/utils/header-normalizer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"header-normalizer.d.ts","sourceRoot":"","sources":["../../src/utils/header-normalizer.ts"],"names":[],"mappings":"AAAA,UAAU,gBAAgB;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAC3C,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAOpC;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAOT;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE1D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExE"}
|
|
@@ -1,25 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (!headers || Object.keys(headers).length === 0) {
|
|
1
|
+
export function normalizeHeaderRecord(headers, blockedHeaders, options = {}) {
|
|
2
|
+
if (!headers || Object.keys(headers).length === 0)
|
|
4
3
|
return undefined;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const normalized = normalizeHeaderEntries(headers, blockedHeaders, options);
|
|
5
|
+
if (!hasHeaderEntries(normalized))
|
|
6
|
+
return undefined;
|
|
7
|
+
return headersToRecord(normalized);
|
|
8
|
+
}
|
|
9
|
+
export function normalizeHeaderEntries(headers, blockedHeaders, options = {}) {
|
|
8
10
|
const normalized = new Headers();
|
|
9
11
|
for (const [key, value] of Object.entries(headers)) {
|
|
10
12
|
if (blockedHeaders.has(key.toLowerCase()))
|
|
11
13
|
continue;
|
|
12
|
-
|
|
13
|
-
normalized.set(key, sanitizeValue(value));
|
|
14
|
-
}
|
|
15
|
-
catch {
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
14
|
+
setHeaderValue(normalized, key, value, options.trimValues === true);
|
|
18
15
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
return normalized;
|
|
17
|
+
}
|
|
18
|
+
export function hasHeaderEntries(headers) {
|
|
19
|
+
return !headers.keys().next().done;
|
|
20
|
+
}
|
|
21
|
+
export function headersToRecord(headers) {
|
|
22
|
+
return Object.fromEntries(headers.entries());
|
|
23
|
+
}
|
|
24
|
+
function setHeaderValue(headers, key, value, trimValue) {
|
|
25
|
+
try {
|
|
26
|
+
headers.set(key, trimValue ? value.trim() : value);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Ignore invalid header values
|
|
22
30
|
}
|
|
23
|
-
return Object.fromEntries(entries);
|
|
24
31
|
}
|
|
25
32
|
//# sourceMappingURL=header-normalizer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"header-normalizer.js","sourceRoot":"","sources":["../../src/utils/header-normalizer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"header-normalizer.js","sourceRoot":"","sources":["../../src/utils/header-normalizer.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,qBAAqB,CACnC,OAA2C,EAC3C,cAA2B,EAC3B,UAA4B,EAAE;IAE9B,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAEpE,MAAM,UAAU,GAAG,sBAAsB,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAC5E,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC;QAAE,OAAO,SAAS,CAAC;IAEpD,OAAO,eAAe,CAAC,UAAU,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,OAA+B,EAC/B,cAA2B,EAC3B,UAA4B,EAAE;IAE9B,MAAM,UAAU,GAAG,IAAI,OAAO,EAAE,CAAC;IACjC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YAAE,SAAS;QACpD,cAAc,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,cAAc,CACrB,OAAgB,EAChB,GAAW,EACX,KAAa,EACb,SAAkB;IAElB,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;IACjC,CAAC;AACH,CAAC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { ToolErrorResponse } from '../config/types.js';
|
|
2
|
-
export declare function normalizeToolErrorCode(code: string): string;
|
|
3
2
|
export declare function createToolErrorResponse(message: string, url: string, code: string): ToolErrorResponse;
|
|
4
3
|
export declare function handleToolError(error: unknown, url: string, fallbackMessage?: string): ToolErrorResponse;
|
|
5
4
|
//# sourceMappingURL=tool-error-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-error-handler.d.ts","sourceRoot":"","sources":["../../src/utils/tool-error-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-error-handler.d.ts","sourceRoot":"","sources":["../../src/utils/tool-error-handler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AA6B5D,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,iBAAiB,CAanB;AAgBD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,MAAM,EACX,eAAe,SAAqB,GACnC,iBAAiB,CAoBnB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import { FetchError } from '../errors/app-error.js';
|
|
3
|
+
import { isSystemError } from './error-utils.js';
|
|
3
4
|
const IS_DEVELOPMENT_WITH_STACK_TRACES = process.env.NODE_ENV === 'development' &&
|
|
4
5
|
process.env.EXPOSE_STACK_TRACES === 'true';
|
|
5
6
|
const MCP_ERROR_CODE_MAP = {
|
|
@@ -12,13 +13,10 @@ const MCP_ERROR_CODE_MAP = {
|
|
|
12
13
|
UNKNOWN_ERROR: String(ErrorCode.InternalError),
|
|
13
14
|
};
|
|
14
15
|
const NUMERIC_ERROR_CODE = /^-?\d+$/;
|
|
15
|
-
function
|
|
16
|
-
return NUMERIC_ERROR_CODE.test(code);
|
|
17
|
-
}
|
|
18
|
-
export function normalizeToolErrorCode(code) {
|
|
16
|
+
function normalizeToolErrorCode(code) {
|
|
19
17
|
if (!code)
|
|
20
18
|
return String(ErrorCode.InternalError);
|
|
21
|
-
if (
|
|
19
|
+
if (NUMERIC_ERROR_CODE.test(code))
|
|
22
20
|
return code;
|
|
23
21
|
if (code.startsWith('HTTP_'))
|
|
24
22
|
return String(ErrorCode.InternalError);
|
|
@@ -45,6 +43,9 @@ function formatErrorMessage(baseMessage, error, fallback) {
|
|
|
45
43
|
return message;
|
|
46
44
|
}
|
|
47
45
|
export function handleToolError(error, url, fallbackMessage = 'Operation failed') {
|
|
46
|
+
if (isValidationError(error)) {
|
|
47
|
+
return createToolErrorResponse(error.message, url, 'VALIDATION_ERROR');
|
|
48
|
+
}
|
|
48
49
|
if (error instanceof FetchError) {
|
|
49
50
|
const message = formatErrorMessage(error.message, error);
|
|
50
51
|
return createToolErrorResponse(message, url, error.code);
|
|
@@ -55,4 +56,9 @@ export function handleToolError(error, url, fallbackMessage = 'Operation failed'
|
|
|
55
56
|
}
|
|
56
57
|
return createToolErrorResponse(`${fallbackMessage}: Unknown error`, url, 'UNKNOWN_ERROR');
|
|
57
58
|
}
|
|
59
|
+
function isValidationError(error) {
|
|
60
|
+
return (error instanceof Error &&
|
|
61
|
+
isSystemError(error) &&
|
|
62
|
+
error.code === 'VALIDATION_ERROR');
|
|
63
|
+
}
|
|
58
64
|
//# sourceMappingURL=tool-error-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-error-handler.js","sourceRoot":"","sources":["../../src/utils/tool-error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAI/D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,gCAAgC,GACpC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa;IACtC,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,MAAM,CAAC;AAE7C,MAAM,kBAAkB,GAA2B;IACjD,gBAAgB,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC;IACjD,cAAc,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC;IAC/C,cAAc,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC;IAC/C,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC;IAC5C,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC;IAC5C,gBAAgB,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC;IACjD,aAAa,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC;CAC/C,CAAC;AAEF,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAErC,SAAS,
|
|
1
|
+
{"version":3,"file":"tool-error-handler.js","sourceRoot":"","sources":["../../src/utils/tool-error-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-sanitizer.d.ts","sourceRoot":"","sources":["../../src/utils/url-sanitizer.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,GAAG,SAAS,CASpB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function sanitizeUrlForLogging(input) {
|
|
2
|
+
if (!input)
|
|
3
|
+
return input ?? undefined;
|
|
4
|
+
try {
|
|
5
|
+
const parsed = new URL(input);
|
|
6
|
+
return `${parsed.origin}${parsed.pathname}`;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return input.split('?')[0]?.split('#')[0];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=url-sanitizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-sanitizer.js","sourceRoot":"","sources":["../../src/utils/url-sanitizer.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CACnC,KAAgC;IAEhC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,IAAI,SAAS,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-validator.d.ts","sourceRoot":"","sources":["../../src/utils/url-validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"url-validator.d.ts","sourceRoot":"","sources":["../../src/utils/url-validator.ts"],"names":[],"mappings":"AA8CA,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAS/C;AAcD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAYjE;AAiFD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAOnE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BlockList, isIP } from 'node:net';
|
|
2
2
|
import { config } from '../config/index.js';
|
|
3
|
+
import { createErrorWithCode } from './error-utils.js';
|
|
3
4
|
const BLOCK_LIST = new BlockList();
|
|
4
5
|
const BLOCKED_IPV4_SUBNETS = [
|
|
5
6
|
{ subnet: '0.0.0.0', prefix: 8 },
|
|
@@ -59,71 +60,72 @@ function isBlockedByList(ip, ipType) {
|
|
|
59
60
|
}
|
|
60
61
|
return BLOCK_LIST.check(ip, 'ipv6');
|
|
61
62
|
}
|
|
62
|
-
function
|
|
63
|
+
export function validateAndNormalizeUrl(urlString) {
|
|
64
|
+
const trimmedUrl = requireTrimmedUrl(urlString);
|
|
65
|
+
assertUrlLength(trimmedUrl);
|
|
66
|
+
const url = parseUrl(trimmedUrl);
|
|
67
|
+
assertHttpProtocol(url);
|
|
68
|
+
assertNoCredentials(url);
|
|
69
|
+
const hostname = normalizeHostname(url);
|
|
70
|
+
assertHostnameAllowed(hostname);
|
|
71
|
+
return url.href;
|
|
72
|
+
}
|
|
73
|
+
const VALIDATION_ERROR_CODE = 'VALIDATION_ERROR';
|
|
74
|
+
function createValidationError(message) {
|
|
75
|
+
return createErrorWithCode(message, VALIDATION_ERROR_CODE);
|
|
76
|
+
}
|
|
77
|
+
function requireTrimmedUrl(urlString) {
|
|
63
78
|
if (!urlString || typeof urlString !== 'string') {
|
|
64
|
-
throw
|
|
79
|
+
throw createValidationError('URL is required');
|
|
65
80
|
}
|
|
66
|
-
|
|
67
|
-
function assertUrlNotEmpty(trimmedUrl) {
|
|
81
|
+
const trimmedUrl = urlString.trim();
|
|
68
82
|
if (!trimmedUrl) {
|
|
69
|
-
throw
|
|
83
|
+
throw createValidationError('URL cannot be empty');
|
|
70
84
|
}
|
|
85
|
+
return trimmedUrl;
|
|
71
86
|
}
|
|
72
|
-
function assertUrlLength(
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
}
|
|
87
|
+
function assertUrlLength(url) {
|
|
88
|
+
if (url.length <= config.constants.maxUrlLength)
|
|
89
|
+
return;
|
|
90
|
+
throw createValidationError(`URL exceeds maximum length of ${config.constants.maxUrlLength} characters`);
|
|
76
91
|
}
|
|
77
|
-
function parseUrl(
|
|
78
|
-
if (!URL.canParse(
|
|
79
|
-
throw
|
|
92
|
+
function parseUrl(urlString) {
|
|
93
|
+
if (!URL.canParse(urlString)) {
|
|
94
|
+
throw createValidationError('Invalid URL format');
|
|
80
95
|
}
|
|
81
|
-
return new URL(
|
|
96
|
+
return new URL(urlString);
|
|
82
97
|
}
|
|
83
|
-
function
|
|
84
|
-
if (url.protocol
|
|
85
|
-
|
|
86
|
-
}
|
|
98
|
+
function assertHttpProtocol(url) {
|
|
99
|
+
if (url.protocol === 'http:' || url.protocol === 'https:')
|
|
100
|
+
return;
|
|
101
|
+
throw createValidationError(`Invalid protocol: ${url.protocol}. Only http: and https: are allowed`);
|
|
87
102
|
}
|
|
88
103
|
function assertNoCredentials(url) {
|
|
89
|
-
if (url.username
|
|
90
|
-
|
|
91
|
-
|
|
104
|
+
if (!url.username && !url.password)
|
|
105
|
+
return;
|
|
106
|
+
throw createValidationError('URLs with embedded credentials are not allowed');
|
|
92
107
|
}
|
|
93
|
-
function
|
|
108
|
+
function normalizeHostname(url) {
|
|
109
|
+
const hostname = url.hostname.toLowerCase();
|
|
94
110
|
if (!hostname) {
|
|
95
|
-
throw
|
|
111
|
+
throw createValidationError('URL must have a valid hostname');
|
|
96
112
|
}
|
|
113
|
+
return hostname;
|
|
97
114
|
}
|
|
115
|
+
const BLOCKED_HOST_SUFFIXES = ['.local', '.internal'];
|
|
98
116
|
function assertHostnameAllowed(hostname) {
|
|
99
117
|
if (config.security.blockedHosts.has(hostname)) {
|
|
100
|
-
throw
|
|
118
|
+
throw createValidationError(`Blocked host: ${hostname}. Internal hosts are not allowed`);
|
|
101
119
|
}
|
|
102
|
-
}
|
|
103
|
-
function assertHostnameNotIpBlocked(hostname) {
|
|
104
120
|
if (isBlockedIp(hostname)) {
|
|
105
|
-
throw
|
|
121
|
+
throw createValidationError(`Blocked IP range: ${hostname}. Private IPs are not allowed`);
|
|
106
122
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (hostname.endsWith('.local') || hostname.endsWith('.internal')) {
|
|
110
|
-
throw new Error(`Blocked hostname pattern: ${hostname}. Internal domain suffixes are not allowed`);
|
|
123
|
+
if (matchesBlockedSuffix(hostname)) {
|
|
124
|
+
throw createValidationError(`Blocked hostname pattern: ${hostname}. Internal domain suffixes are not allowed`);
|
|
111
125
|
}
|
|
112
126
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const trimmedUrl = urlString.trim();
|
|
116
|
-
assertUrlNotEmpty(trimmedUrl);
|
|
117
|
-
assertUrlLength(trimmedUrl);
|
|
118
|
-
const url = parseUrl(trimmedUrl);
|
|
119
|
-
assertProtocolAllowed(url);
|
|
120
|
-
assertNoCredentials(url);
|
|
121
|
-
const hostname = url.hostname.toLowerCase();
|
|
122
|
-
assertHostnamePresent(hostname);
|
|
123
|
-
assertHostnameAllowed(hostname);
|
|
124
|
-
assertHostnameNotIpBlocked(hostname);
|
|
125
|
-
assertHostnameSuffixAllowed(hostname);
|
|
126
|
-
return url.href;
|
|
127
|
+
function matchesBlockedSuffix(hostname) {
|
|
128
|
+
return BLOCKED_HOST_SUFFIXES.some((suffix) => hostname.endsWith(suffix));
|
|
127
129
|
}
|
|
128
130
|
export function isInternalUrl(url, baseUrl) {
|
|
129
131
|
if (!URL.canParse(baseUrl) || !URL.canParse(url, baseUrl)) {
|