@j0hanz/superfetch 1.1.9 → 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.
Files changed (174) hide show
  1. package/README.md +258 -362
  2. package/dist/config/constants.d.ts +20 -0
  3. package/dist/config/constants.d.ts.map +1 -0
  4. package/dist/config/constants.js +25 -0
  5. package/dist/config/constants.js.map +1 -0
  6. package/dist/config/formatting.d.ts +0 -1
  7. package/dist/config/formatting.d.ts.map +1 -1
  8. package/dist/config/formatting.js +1 -1
  9. package/dist/config/formatting.js.map +1 -1
  10. package/dist/config/index.d.ts +8 -1
  11. package/dist/config/index.d.ts.map +1 -1
  12. package/dist/config/index.js +14 -5
  13. package/dist/config/index.js.map +1 -1
  14. package/dist/config/types/content.d.ts +1 -19
  15. package/dist/config/types/content.d.ts.map +1 -1
  16. package/dist/config/types/runtime.d.ts +7 -4
  17. package/dist/config/types/runtime.d.ts.map +1 -1
  18. package/dist/config/types/tools.d.ts +5 -49
  19. package/dist/config/types/tools.d.ts.map +1 -1
  20. package/dist/http/auth.d.ts.map +1 -1
  21. package/dist/http/auth.js +17 -12
  22. package/dist/http/auth.js.map +1 -1
  23. package/dist/http/cors.js +4 -0
  24. package/dist/http/cors.js.map +1 -1
  25. package/dist/http/download-routes.d.ts +15 -0
  26. package/dist/http/download-routes.d.ts.map +1 -0
  27. package/dist/http/download-routes.js +132 -0
  28. package/dist/http/download-routes.js.map +1 -0
  29. package/dist/http/mcp-routes.d.ts +1 -1
  30. package/dist/http/mcp-routes.d.ts.map +1 -1
  31. package/dist/http/mcp-routes.js +1 -1
  32. package/dist/http/mcp-routes.js.map +1 -1
  33. package/dist/http/mcp-session-helpers.d.ts +14 -0
  34. package/dist/http/mcp-session-helpers.d.ts.map +1 -0
  35. package/dist/http/mcp-session-helpers.js +65 -0
  36. package/dist/http/mcp-session-helpers.js.map +1 -0
  37. package/dist/http/mcp-session.d.ts +0 -1
  38. package/dist/http/mcp-session.d.ts.map +1 -1
  39. package/dist/http/mcp-session.js +7 -70
  40. package/dist/http/mcp-session.js.map +1 -1
  41. package/dist/http/server-middleware.d.ts +10 -0
  42. package/dist/http/server-middleware.d.ts.map +1 -0
  43. package/dist/http/server-middleware.js +56 -0
  44. package/dist/http/server-middleware.js.map +1 -0
  45. package/dist/http/server.d.ts.map +1 -1
  46. package/dist/http/server.js +20 -98
  47. package/dist/http/server.js.map +1 -1
  48. package/dist/http/session-cleanup.d.ts +3 -0
  49. package/dist/http/session-cleanup.d.ts.map +1 -0
  50. package/dist/http/session-cleanup.js +38 -0
  51. package/dist/http/session-cleanup.js.map +1 -0
  52. package/dist/index.js +13 -5
  53. package/dist/index.js.map +1 -1
  54. package/dist/resources/cached-content.d.ts.map +1 -1
  55. package/dist/resources/cached-content.js +76 -11
  56. package/dist/resources/cached-content.js.map +1 -1
  57. package/dist/services/cache.d.ts +6 -2
  58. package/dist/services/cache.d.ts.map +1 -1
  59. package/dist/services/cache.js +86 -25
  60. package/dist/services/cache.js.map +1 -1
  61. package/dist/services/context.d.ts +2 -1
  62. package/dist/services/context.d.ts.map +1 -1
  63. package/dist/services/extractor.d.ts.map +1 -1
  64. package/dist/services/extractor.js +45 -17
  65. package/dist/services/extractor.js.map +1 -1
  66. package/dist/services/fetcher/agents.d.ts.map +1 -1
  67. package/dist/services/fetcher/agents.js +3 -6
  68. package/dist/services/fetcher/agents.js.map +1 -1
  69. package/dist/services/fetcher/headers.d.ts.map +1 -1
  70. package/dist/services/fetcher/headers.js +2 -24
  71. package/dist/services/fetcher/headers.js.map +1 -1
  72. package/dist/services/fetcher/interceptors.d.ts +2 -1
  73. package/dist/services/fetcher/interceptors.d.ts.map +1 -1
  74. package/dist/services/fetcher/interceptors.js +30 -20
  75. package/dist/services/fetcher/interceptors.js.map +1 -1
  76. package/dist/services/fetcher/redirects.d.ts +0 -1
  77. package/dist/services/fetcher/redirects.d.ts.map +1 -1
  78. package/dist/services/fetcher/redirects.js +19 -16
  79. package/dist/services/fetcher/redirects.js.map +1 -1
  80. package/dist/services/fetcher/retry-policy.d.ts +1 -27
  81. package/dist/services/fetcher/retry-policy.d.ts.map +1 -1
  82. package/dist/services/fetcher/retry-policy.js +119 -125
  83. package/dist/services/fetcher/retry-policy.js.map +1 -1
  84. package/dist/services/fetcher.d.ts.map +1 -1
  85. package/dist/services/fetcher.js +15 -9
  86. package/dist/services/fetcher.js.map +1 -1
  87. package/dist/services/parser.d.ts +0 -1
  88. package/dist/services/parser.d.ts.map +1 -1
  89. package/dist/services/parser.js +5 -38
  90. package/dist/services/parser.js.map +1 -1
  91. package/dist/tools/handlers/fetch-links/link-extractor.d.ts.map +1 -1
  92. package/dist/tools/handlers/fetch-links/link-extractor.js +15 -19
  93. package/dist/tools/handlers/fetch-links/link-extractor.js.map +1 -1
  94. package/dist/tools/handlers/fetch-links.tool.d.ts.map +1 -1
  95. package/dist/tools/handlers/fetch-links.tool.js +0 -2
  96. package/dist/tools/handlers/fetch-links.tool.js.map +1 -1
  97. package/dist/tools/handlers/fetch-markdown.tool.d.ts.map +1 -1
  98. package/dist/tools/handlers/fetch-markdown.tool.js +16 -17
  99. package/dist/tools/handlers/fetch-markdown.tool.js.map +1 -1
  100. package/dist/tools/handlers/fetch-single.shared.d.ts +11 -2
  101. package/dist/tools/handlers/fetch-single.shared.d.ts.map +1 -1
  102. package/dist/tools/handlers/fetch-single.shared.js +61 -2
  103. package/dist/tools/handlers/fetch-single.shared.js.map +1 -1
  104. package/dist/tools/handlers/fetch-url.tool.d.ts.map +1 -1
  105. package/dist/tools/handlers/fetch-url.tool.js +3 -14
  106. package/dist/tools/handlers/fetch-url.tool.js.map +1 -1
  107. package/dist/tools/handlers/fetch-urls/validation.d.ts +0 -1
  108. package/dist/tools/handlers/fetch-urls/validation.d.ts.map +1 -1
  109. package/dist/tools/handlers/fetch-urls/validation.js +1 -1
  110. package/dist/tools/handlers/fetch-urls/validation.js.map +1 -1
  111. package/dist/tools/index.d.ts.map +1 -1
  112. package/dist/tools/index.js +1 -19
  113. package/dist/tools/index.js.map +1 -1
  114. package/dist/tools/schemas.d.ts +44 -236
  115. package/dist/tools/schemas.d.ts.map +1 -1
  116. package/dist/tools/schemas.js +38 -197
  117. package/dist/tools/schemas.js.map +1 -1
  118. package/dist/tools/utils/cache-vary.d.ts +0 -1
  119. package/dist/tools/utils/cache-vary.d.ts.map +1 -1
  120. package/dist/tools/utils/cache-vary.js +11 -25
  121. package/dist/tools/utils/cache-vary.js.map +1 -1
  122. package/dist/tools/utils/common.d.ts +1 -2
  123. package/dist/tools/utils/common.d.ts.map +1 -1
  124. package/dist/tools/utils/common.js.map +1 -1
  125. package/dist/tools/utils/content-transform.d.ts.map +1 -1
  126. package/dist/tools/utils/content-transform.js +28 -13
  127. package/dist/tools/utils/content-transform.js.map +1 -1
  128. package/dist/tools/utils/fetch-pipeline.js +14 -3
  129. package/dist/tools/utils/fetch-pipeline.js.map +1 -1
  130. package/dist/tools/utils/inline-content.d.ts +3 -2
  131. package/dist/tools/utils/inline-content.d.ts.map +1 -1
  132. package/dist/transformers/markdown.transformer.d.ts.map +1 -1
  133. package/dist/transformers/markdown.transformer.js +3 -6
  134. package/dist/transformers/markdown.transformer.js.map +1 -1
  135. package/dist/utils/code-language.d.ts +3 -0
  136. package/dist/utils/code-language.d.ts.map +1 -0
  137. package/dist/utils/code-language.js +57 -0
  138. package/dist/utils/code-language.js.map +1 -0
  139. package/dist/utils/content-cleaner.d.ts +0 -1
  140. package/dist/utils/content-cleaner.d.ts.map +1 -1
  141. package/dist/utils/content-cleaner.js +0 -3
  142. package/dist/utils/content-cleaner.js.map +1 -1
  143. package/dist/utils/crypto.d.ts +3 -0
  144. package/dist/utils/crypto.d.ts.map +1 -0
  145. package/dist/utils/crypto.js +33 -0
  146. package/dist/utils/crypto.js.map +1 -0
  147. package/dist/utils/download-url.d.ts +9 -0
  148. package/dist/utils/download-url.d.ts.map +1 -0
  149. package/dist/utils/download-url.js +28 -0
  150. package/dist/utils/download-url.js.map +1 -0
  151. package/dist/utils/error-utils.d.ts +4 -0
  152. package/dist/utils/error-utils.d.ts.map +1 -0
  153. package/dist/utils/error-utils.js +14 -0
  154. package/dist/utils/error-utils.js.map +1 -0
  155. package/dist/utils/filename-generator.d.ts +2 -0
  156. package/dist/utils/filename-generator.d.ts.map +1 -0
  157. package/dist/utils/filename-generator.js +60 -0
  158. package/dist/utils/filename-generator.js.map +1 -0
  159. package/dist/utils/header-normalizer.d.ts +7 -3
  160. package/dist/utils/header-normalizer.d.ts.map +1 -1
  161. package/dist/utils/header-normalizer.js +23 -16
  162. package/dist/utils/header-normalizer.js.map +1 -1
  163. package/dist/utils/tool-error-handler.d.ts +0 -1
  164. package/dist/utils/tool-error-handler.d.ts.map +1 -1
  165. package/dist/utils/tool-error-handler.js +11 -5
  166. package/dist/utils/tool-error-handler.js.map +1 -1
  167. package/dist/utils/url-sanitizer.d.ts +2 -0
  168. package/dist/utils/url-sanitizer.d.ts.map +1 -0
  169. package/dist/utils/url-sanitizer.js +12 -0
  170. package/dist/utils/url-sanitizer.js.map +1 -0
  171. package/dist/utils/url-validator.d.ts.map +1 -1
  172. package/dist/utils/url-validator.js +46 -44
  173. package/dist/utils/url-validator.js.map +1 -1
  174. package/package.json +4 -6
@@ -0,0 +1,3 @@
1
+ export declare function detectLanguageFromCode(code: string): string | undefined;
2
+ export declare function resolveLanguageFromAttributes(className: string, dataLang: string): string | undefined;
3
+ //# sourceMappingURL=code-language.d.ts.map
@@ -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,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgB3D"}
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":"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"}
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,sBAAsB,CAAC,IAAY;IACjD,OAAO,IAAI;SACR,OAAO,CACN,0EAA0E,EAC1E,EAAE,CACH;SACA,OAAO,CACN,6HAA6H,EAC7H,EAAE,CACH;SACA,OAAO,CACN,6EAA6E,EAC7E,EAAE,CACH;SACA,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,IAAI,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function timingSafeEqualUtf8(a: string, b: string): boolean;
2
+ export declare function sha256Hex(input: string | Uint8Array): string;
3
+ //# sourceMappingURL=crypto.d.ts.map
@@ -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,2 @@
1
+ export declare function generateSafeFilename(url: string, title?: string, hashFallback?: string, extension?: string): string;
2
+ //# sourceMappingURL=filename-generator.d.ts.map
@@ -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
- export interface HeaderNormalizeOptions {
2
- readonly sanitizeValue?: (value: string) => string;
1
+ interface NormalizeOptions {
2
+ readonly trimValues?: boolean;
3
3
  }
4
- export declare function normalizeHeaders(headers?: Record<string, string>, options?: HeaderNormalizeOptions): Record<string, string> | undefined;
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":"AAEA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACpD;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAwBpC"}
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
- import { config } from '../config/index.js';
2
- export function normalizeHeaders(headers, options) {
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
- const sanitizeValue = options?.sanitizeValue ?? ((value) => value);
7
- const { blockedHeaders } = config.security;
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
- try {
13
- normalized.set(key, sanitizeValue(value));
14
- }
15
- catch {
16
- continue;
17
- }
14
+ setHeaderValue(normalized, key, value, options.trimValues === true);
18
15
  }
19
- const entries = Array.from(normalized.entries());
20
- if (entries.length === 0) {
21
- return undefined;
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":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAM5C,MAAM,UAAU,gBAAgB,CAC9B,OAAgC,EAChC,OAAgC;IAEhC,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IACnE,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC3C,MAAM,UAAU,GAAG,IAAI,OAAO,EAAE,CAAC;IAEjC,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,IAAI,CAAC;YACH,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;IACjD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC"}
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;AAwB5D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED,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,CAgBnB"}
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 isNumericErrorCode(code) {
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 (isNumericErrorCode(code))
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":"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"}
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,2 @@
1
+ export declare function sanitizeUrlForLogging(input: string | null | undefined): string | undefined;
2
+ //# sourceMappingURL=url-sanitizer.d.ts.map
@@ -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":"AA4CA,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAS/C;AAqFD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAkBjE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAOnE"}
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 assertUrlProvided(urlString) {
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 new Error('URL is required');
79
+ throw createValidationError('URL is required');
65
80
  }
66
- }
67
- function assertUrlNotEmpty(trimmedUrl) {
81
+ const trimmedUrl = urlString.trim();
68
82
  if (!trimmedUrl) {
69
- throw new Error('URL cannot be empty');
83
+ throw createValidationError('URL cannot be empty');
70
84
  }
85
+ return trimmedUrl;
71
86
  }
72
- function assertUrlLength(trimmedUrl) {
73
- if (trimmedUrl.length > config.constants.maxUrlLength) {
74
- throw new Error(`URL exceeds maximum length of ${config.constants.maxUrlLength} characters`);
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(trimmedUrl) {
78
- if (!URL.canParse(trimmedUrl)) {
79
- throw new Error('Invalid URL format');
92
+ function parseUrl(urlString) {
93
+ if (!URL.canParse(urlString)) {
94
+ throw createValidationError('Invalid URL format');
80
95
  }
81
- return new URL(trimmedUrl);
96
+ return new URL(urlString);
82
97
  }
83
- function assertProtocolAllowed(url) {
84
- if (url.protocol !== 'http:' && url.protocol !== 'https:') {
85
- throw new Error(`Invalid protocol: ${url.protocol}. Only http: and https: are allowed`);
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 || url.password) {
90
- throw new Error('URLs with embedded credentials are not allowed');
91
- }
104
+ if (!url.username && !url.password)
105
+ return;
106
+ throw createValidationError('URLs with embedded credentials are not allowed');
92
107
  }
93
- function assertHostnamePresent(hostname) {
108
+ function normalizeHostname(url) {
109
+ const hostname = url.hostname.toLowerCase();
94
110
  if (!hostname) {
95
- throw new Error('URL must have a valid hostname');
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 new Error(`Blocked host: ${hostname}. Internal hosts are not allowed`);
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 new Error(`Blocked IP range: ${hostname}. Private IPs are not allowed`);
121
+ throw createValidationError(`Blocked IP range: ${hostname}. Private IPs are not allowed`);
106
122
  }
107
- }
108
- function assertHostnameSuffixAllowed(hostname) {
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
- export function validateAndNormalizeUrl(urlString) {
114
- assertUrlProvided(urlString);
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)) {