@j0hanz/superfetch 1.1.1 → 1.1.3

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 (206) hide show
  1. package/README.md +57 -32
  2. package/dist/config/formatting.d.ts +9 -0
  3. package/dist/config/formatting.d.ts.map +1 -0
  4. package/dist/config/formatting.js +11 -0
  5. package/dist/config/formatting.js.map +1 -0
  6. package/dist/config/index.d.ts +16 -2
  7. package/dist/config/index.d.ts.map +1 -1
  8. package/dist/config/index.js +43 -14
  9. package/dist/config/index.js.map +1 -1
  10. package/dist/config/types/content.d.ts +107 -0
  11. package/dist/config/types/content.d.ts.map +1 -0
  12. package/dist/config/types/content.js +2 -0
  13. package/dist/config/types/content.js.map +1 -0
  14. package/dist/config/types/runtime.d.ts +78 -0
  15. package/dist/config/types/runtime.d.ts.map +1 -0
  16. package/dist/config/types/runtime.js +2 -0
  17. package/dist/config/types/runtime.js.map +1 -0
  18. package/dist/config/types/tools.d.ts +99 -0
  19. package/dist/config/types/tools.d.ts.map +1 -0
  20. package/dist/config/types/tools.js +2 -0
  21. package/dist/config/types/tools.js.map +1 -0
  22. package/dist/config/types.d.ts +3 -296
  23. package/dist/config/types.d.ts.map +1 -1
  24. package/dist/http/auth.d.ts +3 -0
  25. package/dist/http/auth.d.ts.map +1 -0
  26. package/dist/http/auth.js +34 -0
  27. package/dist/http/auth.js.map +1 -0
  28. package/dist/http/cors.d.ts +8 -0
  29. package/dist/http/cors.d.ts.map +1 -0
  30. package/dist/http/cors.js +47 -0
  31. package/dist/http/cors.js.map +1 -0
  32. package/dist/http/mcp-routes.d.ts +5 -0
  33. package/dist/http/mcp-routes.d.ts.map +1 -0
  34. package/dist/http/mcp-routes.js +110 -0
  35. package/dist/http/mcp-routes.js.map +1 -0
  36. package/dist/http/mcp-session.d.ts +12 -0
  37. package/dist/http/mcp-session.d.ts.map +1 -0
  38. package/dist/http/mcp-session.js +209 -0
  39. package/dist/http/mcp-session.js.map +1 -0
  40. package/dist/http/mcp-validation.d.ts +3 -0
  41. package/dist/http/mcp-validation.d.ts.map +1 -0
  42. package/dist/http/mcp-validation.js +34 -0
  43. package/dist/http/mcp-validation.js.map +1 -0
  44. package/dist/http/rate-limit.d.ts +13 -0
  45. package/dist/http/rate-limit.d.ts.map +1 -0
  46. package/dist/http/rate-limit.js +91 -0
  47. package/dist/http/rate-limit.js.map +1 -0
  48. package/dist/http/server.d.ts +4 -0
  49. package/dist/http/server.d.ts.map +1 -0
  50. package/dist/http/server.js +183 -0
  51. package/dist/http/server.js.map +1 -0
  52. package/dist/http/sessions.d.ts +15 -0
  53. package/dist/http/sessions.d.ts.map +1 -0
  54. package/dist/http/sessions.js +64 -0
  55. package/dist/http/sessions.js.map +1 -0
  56. package/dist/index.js +26 -223
  57. package/dist/index.js.map +1 -1
  58. package/dist/middleware/error-handler.d.ts +2 -2
  59. package/dist/middleware/error-handler.d.ts.map +1 -1
  60. package/dist/middleware/error-handler.js +46 -15
  61. package/dist/middleware/error-handler.js.map +1 -1
  62. package/dist/resources/cached-content.d.ts.map +1 -1
  63. package/dist/resources/cached-content.js +104 -44
  64. package/dist/resources/cached-content.js.map +1 -1
  65. package/dist/resources/index.d.ts.map +1 -1
  66. package/dist/resources/index.js +77 -69
  67. package/dist/resources/index.js.map +1 -1
  68. package/dist/server.d.ts.map +1 -1
  69. package/dist/server.js +9 -3
  70. package/dist/server.js.map +1 -1
  71. package/dist/services/cache.d.ts +13 -1
  72. package/dist/services/cache.d.ts.map +1 -1
  73. package/dist/services/cache.js +90 -13
  74. package/dist/services/cache.js.map +1 -1
  75. package/dist/services/context.d.ts +9 -0
  76. package/dist/services/context.d.ts.map +1 -0
  77. package/dist/services/context.js +9 -0
  78. package/dist/services/context.js.map +1 -0
  79. package/dist/services/extractor.d.ts.map +1 -1
  80. package/dist/services/extractor.js +122 -87
  81. package/dist/services/extractor.js.map +1 -1
  82. package/dist/services/fetcher/agents.d.ts +4 -0
  83. package/dist/services/fetcher/agents.d.ts.map +1 -0
  84. package/dist/services/fetcher/agents.js +111 -0
  85. package/dist/services/fetcher/agents.js.map +1 -0
  86. package/dist/services/fetcher/errors.d.ts +5 -0
  87. package/dist/services/fetcher/errors.d.ts.map +1 -0
  88. package/dist/services/fetcher/errors.js +71 -0
  89. package/dist/services/fetcher/errors.js.map +1 -0
  90. package/dist/services/fetcher/headers.d.ts +2 -0
  91. package/dist/services/fetcher/headers.d.ts.map +1 -0
  92. package/dist/services/fetcher/headers.js +28 -0
  93. package/dist/services/fetcher/headers.js.map +1 -0
  94. package/dist/services/fetcher/interceptors.d.ts +10 -0
  95. package/dist/services/fetcher/interceptors.d.ts.map +1 -0
  96. package/dist/services/fetcher/interceptors.js +82 -0
  97. package/dist/services/fetcher/interceptors.js.map +1 -0
  98. package/dist/services/fetcher/redirects.d.ts +6 -0
  99. package/dist/services/fetcher/redirects.d.ts.map +1 -0
  100. package/dist/services/fetcher/redirects.js +67 -0
  101. package/dist/services/fetcher/redirects.js.map +1 -0
  102. package/dist/services/fetcher/response.d.ts +5 -0
  103. package/dist/services/fetcher/response.d.ts.map +1 -0
  104. package/dist/services/fetcher/response.js +39 -0
  105. package/dist/services/fetcher/response.js.map +1 -0
  106. package/dist/services/fetcher/retry-policy.d.ts +28 -0
  107. package/dist/services/fetcher/retry-policy.d.ts.map +1 -0
  108. package/dist/services/fetcher/retry-policy.js +138 -0
  109. package/dist/services/fetcher/retry-policy.js.map +1 -0
  110. package/dist/services/fetcher.d.ts +2 -1
  111. package/dist/services/fetcher.d.ts.map +1 -1
  112. package/dist/services/fetcher.js +61 -254
  113. package/dist/services/fetcher.js.map +1 -1
  114. package/dist/services/logger.d.ts.map +1 -1
  115. package/dist/services/logger.js +14 -5
  116. package/dist/services/logger.js.map +1 -1
  117. package/dist/services/parser.d.ts +1 -0
  118. package/dist/services/parser.d.ts.map +1 -1
  119. package/dist/services/parser.js +55 -35
  120. package/dist/services/parser.js.map +1 -1
  121. package/dist/tools/handlers/fetch-links/link-extractor.d.ts +4 -0
  122. package/dist/tools/handlers/fetch-links/link-extractor.d.ts.map +1 -0
  123. package/dist/tools/handlers/fetch-links/link-extractor.js +163 -0
  124. package/dist/tools/handlers/fetch-links/link-extractor.js.map +1 -0
  125. package/dist/tools/handlers/fetch-links.tool.d.ts.map +1 -1
  126. package/dist/tools/handlers/fetch-links.tool.js +78 -116
  127. package/dist/tools/handlers/fetch-links.tool.js.map +1 -1
  128. package/dist/tools/handlers/fetch-markdown.tool.d.ts +3 -13
  129. package/dist/tools/handlers/fetch-markdown.tool.d.ts.map +1 -1
  130. package/dist/tools/handlers/fetch-markdown.tool.js +74 -83
  131. package/dist/tools/handlers/fetch-markdown.tool.js.map +1 -1
  132. package/dist/tools/handlers/fetch-single.shared.d.ts +26 -0
  133. package/dist/tools/handlers/fetch-single.shared.d.ts.map +1 -0
  134. package/dist/tools/handlers/fetch-single.shared.js +49 -0
  135. package/dist/tools/handlers/fetch-single.shared.js.map +1 -0
  136. package/dist/tools/handlers/fetch-url.tool.d.ts.map +1 -1
  137. package/dist/tools/handlers/fetch-url.tool.js +82 -54
  138. package/dist/tools/handlers/fetch-url.tool.js.map +1 -1
  139. package/dist/tools/handlers/fetch-urls/processor.d.ts +13 -0
  140. package/dist/tools/handlers/fetch-urls/processor.d.ts.map +1 -0
  141. package/dist/tools/handlers/fetch-urls/processor.js +153 -0
  142. package/dist/tools/handlers/fetch-urls/processor.js.map +1 -0
  143. package/dist/tools/handlers/fetch-urls/response.d.ts +3 -0
  144. package/dist/tools/handlers/fetch-urls/response.d.ts.map +1 -0
  145. package/dist/tools/handlers/fetch-urls/response.js +58 -0
  146. package/dist/tools/handlers/fetch-urls/response.js.map +1 -0
  147. package/dist/tools/handlers/fetch-urls/validation.d.ts +6 -0
  148. package/dist/tools/handlers/fetch-urls/validation.d.ts.map +1 -0
  149. package/dist/tools/handlers/fetch-urls/validation.js +18 -0
  150. package/dist/tools/handlers/fetch-urls/validation.js.map +1 -0
  151. package/dist/tools/handlers/fetch-urls.tool.d.ts.map +1 -1
  152. package/dist/tools/handlers/fetch-urls.tool.js +104 -197
  153. package/dist/tools/handlers/fetch-urls.tool.js.map +1 -1
  154. package/dist/tools/index.d.ts.map +1 -1
  155. package/dist/tools/index.js +36 -237
  156. package/dist/tools/index.js.map +1 -1
  157. package/dist/tools/schemas.d.ts +357 -0
  158. package/dist/tools/schemas.d.ts.map +1 -0
  159. package/dist/tools/schemas.js +272 -0
  160. package/dist/tools/schemas.js.map +1 -0
  161. package/dist/tools/utils/cache-vary.d.ts +3 -0
  162. package/dist/tools/utils/cache-vary.d.ts.map +1 -0
  163. package/dist/tools/utils/cache-vary.js +44 -0
  164. package/dist/tools/utils/cache-vary.js.map +1 -0
  165. package/dist/tools/utils/common.d.ts +2 -2
  166. package/dist/tools/utils/common.d.ts.map +1 -1
  167. package/dist/tools/utils/common.js +5 -1
  168. package/dist/tools/utils/common.js.map +1 -1
  169. package/dist/tools/utils/content-transform.d.ts +16 -0
  170. package/dist/tools/utils/content-transform.d.ts.map +1 -0
  171. package/dist/tools/utils/content-transform.js +49 -0
  172. package/dist/tools/utils/content-transform.js.map +1 -0
  173. package/dist/tools/utils/fetch-pipeline.d.ts.map +1 -1
  174. package/dist/tools/utils/fetch-pipeline.js +32 -18
  175. package/dist/tools/utils/fetch-pipeline.js.map +1 -1
  176. package/dist/tools/utils/inline-content.d.ts +11 -0
  177. package/dist/tools/utils/inline-content.d.ts.map +1 -0
  178. package/dist/tools/utils/inline-content.js +39 -0
  179. package/dist/tools/utils/inline-content.js.map +1 -0
  180. package/dist/tools/utils/markdown-toc.d.ts +3 -0
  181. package/dist/tools/utils/markdown-toc.d.ts.map +1 -0
  182. package/dist/tools/utils/markdown-toc.js +35 -0
  183. package/dist/tools/utils/markdown-toc.js.map +1 -0
  184. package/dist/tools/utils/tool-response.d.ts +9 -0
  185. package/dist/tools/utils/tool-response.d.ts.map +1 -0
  186. package/dist/tools/utils/tool-response.js +19 -0
  187. package/dist/tools/utils/tool-response.js.map +1 -0
  188. package/dist/transformers/jsonl.transformer.d.ts.map +1 -1
  189. package/dist/transformers/jsonl.transformer.js +51 -28
  190. package/dist/transformers/jsonl.transformer.js.map +1 -1
  191. package/dist/transformers/markdown.transformer.d.ts.map +1 -1
  192. package/dist/transformers/markdown.transformer.js +82 -111
  193. package/dist/transformers/markdown.transformer.js.map +1 -1
  194. package/dist/utils/header-normalizer.d.ts +5 -0
  195. package/dist/utils/header-normalizer.d.ts.map +1 -0
  196. package/dist/utils/header-normalizer.js +25 -0
  197. package/dist/utils/header-normalizer.js.map +1 -0
  198. package/dist/utils/tool-error-handler.d.ts +1 -0
  199. package/dist/utils/tool-error-handler.d.ts.map +1 -1
  200. package/dist/utils/tool-error-handler.js +29 -1
  201. package/dist/utils/tool-error-handler.js.map +1 -1
  202. package/dist/utils/url-validator.d.ts +0 -3
  203. package/dist/utils/url-validator.d.ts.map +1 -1
  204. package/dist/utils/url-validator.js +98 -18
  205. package/dist/utils/url-validator.js.map +1 -1
  206. package/package.json +11 -6
@@ -0,0 +1,64 @@
1
+ export function getSessionId(req) {
2
+ const header = req.headers['mcp-session-id'];
3
+ return Array.isArray(header) ? header[0] : header;
4
+ }
5
+ export function createSessionStore(sessionTtlMs) {
6
+ const sessions = new Map();
7
+ return {
8
+ get: (sessionId) => sessions.get(sessionId),
9
+ touch: (sessionId) => {
10
+ touchSession(sessions, sessionId);
11
+ },
12
+ set: (sessionId, entry) => {
13
+ sessions.set(sessionId, entry);
14
+ },
15
+ remove: (sessionId) => removeSession(sessions, sessionId),
16
+ size: () => sessions.size,
17
+ clear: () => clearSessions(sessions),
18
+ evictExpired: () => evictExpiredSessions(sessions, sessionTtlMs),
19
+ evictOldest: () => evictOldestSession(sessions),
20
+ };
21
+ }
22
+ function touchSession(sessions, sessionId) {
23
+ const session = sessions.get(sessionId);
24
+ if (session) {
25
+ session.lastSeen = Date.now();
26
+ }
27
+ }
28
+ function removeSession(sessions, sessionId) {
29
+ const session = sessions.get(sessionId);
30
+ sessions.delete(sessionId);
31
+ return session;
32
+ }
33
+ function clearSessions(sessions) {
34
+ const entries = Array.from(sessions.values());
35
+ sessions.clear();
36
+ return entries;
37
+ }
38
+ function evictExpiredSessions(sessions, sessionTtlMs) {
39
+ const now = Date.now();
40
+ const evicted = [];
41
+ for (const [id, session] of sessions.entries()) {
42
+ if (now - session.lastSeen > sessionTtlMs) {
43
+ sessions.delete(id);
44
+ evicted.push(session);
45
+ }
46
+ }
47
+ return evicted;
48
+ }
49
+ function evictOldestSession(sessions) {
50
+ let oldestId;
51
+ let oldestSeen = Number.POSITIVE_INFINITY;
52
+ for (const [id, session] of sessions.entries()) {
53
+ if (session.lastSeen < oldestSeen) {
54
+ oldestSeen = session.lastSeen;
55
+ oldestId = id;
56
+ }
57
+ }
58
+ if (!oldestId)
59
+ return undefined;
60
+ const session = sessions.get(oldestId);
61
+ sessions.delete(oldestId);
62
+ return session;
63
+ }
64
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/http/sessions.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC7C,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,YAAoB;IACrD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC;IAEjD,OAAO;QACL,GAAG,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;QAC3C,KAAK,EAAE,CAAC,SAAS,EAAE,EAAE;YACnB,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,GAAG,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;YACxB,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACjC,CAAC;QACD,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC;QACzD,IAAI,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI;QACzB,KAAK,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC;QACpC,YAAY,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,QAAQ,EAAE,YAAY,CAAC;QAChE,WAAW,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,QAAQ,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,QAAmC,EACnC,SAAiB;IAEjB,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAChC,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CACpB,QAAmC,EACnC,SAAiB;IAEjB,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,aAAa,CAAC,QAAmC;IACxD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,CAAC;IACjB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,oBAAoB,CAC3B,QAAmC,EACnC,YAAoB;IAEpB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,OAAO,GAAmB,EAAE,CAAC;IAEnC,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,IAAI,GAAG,GAAG,OAAO,CAAC,QAAQ,GAAG,YAAY,EAAE,CAAC;YAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,kBAAkB,CACzB,QAAmC;IAEnC,IAAI,QAA4B,CAAC;IACjC,IAAI,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAE1C,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,IAAI,OAAO,CAAC,QAAQ,GAAG,UAAU,EAAE,CAAC;YAClC,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;YAC9B,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1B,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/dist/index.js CHANGED
@@ -1,242 +1,45 @@
1
1
  #!/usr/bin/env node
2
- import express, {} from 'express';
3
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
- import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
5
- import { config } from './config/index.js';
6
- import { destroyAgents } from './services/fetcher.js';
7
- import { logError, logInfo } from './services/logger.js';
8
- import { errorHandler } from './middleware/error-handler.js';
9
- import { createMcpServer } from './server.js';
2
+ import { parseArgs } from 'node:util';
3
+ import { logError } from './services/logger.js';
4
+ import { startHttpServer } from './http/server.js';
5
+ import { startStdioServer } from './server.js';
6
+ const { values } = parseArgs({
7
+ options: {
8
+ stdio: { type: 'boolean', default: false },
9
+ },
10
+ });
11
+ const isStdioMode = values.stdio;
10
12
  let isShuttingDown = false;
11
13
  const shutdownHandlerRef = {};
14
+ function shouldAttemptShutdown() {
15
+ return !isShuttingDown && !isStdioMode && Boolean(shutdownHandlerRef.current);
16
+ }
17
+ function attemptShutdown(signal) {
18
+ if (!shutdownHandlerRef.current)
19
+ return;
20
+ isShuttingDown = true;
21
+ process.stderr.write('Attempting graceful shutdown...\n');
22
+ void shutdownHandlerRef.current(signal);
23
+ }
12
24
  process.on('uncaughtException', (error) => {
13
25
  logError('Uncaught exception', error);
14
26
  process.stderr.write(`Uncaught exception: ${error.message}\n`);
15
- if (!isShuttingDown && !isStdioMode && shutdownHandlerRef.current) {
16
- isShuttingDown = true;
17
- // Attempt graceful cleanup before exit
18
- process.stderr.write('Attempting graceful shutdown...\n');
19
- void shutdownHandlerRef.current('UNCAUGHT_EXCEPTION');
20
- }
21
- else {
22
- process.exit(1);
27
+ if (shouldAttemptShutdown()) {
28
+ attemptShutdown('UNCAUGHT_EXCEPTION');
29
+ return;
23
30
  }
31
+ process.exit(1);
24
32
  });
25
33
  process.on('unhandledRejection', (reason) => {
26
34
  const error = reason instanceof Error ? reason : new Error(String(reason));
27
35
  logError('Unhandled rejection', error);
28
36
  process.stderr.write(`Unhandled rejection: ${error.message}\n`);
29
37
  });
30
- const isStdioMode = process.argv.includes('--stdio');
31
- const ALLOWED_ORIGINS = process.env.ALLOWED_ORIGINS
32
- ? process.env.ALLOWED_ORIGINS.split(',').map((o) => o.trim())
33
- : [];
34
- const ALLOW_ALL_ORIGINS = process.env.CORS_ALLOW_ALL === 'true';
35
- function getSessionId(req) {
36
- const header = req.headers['mcp-session-id'];
37
- return Array.isArray(header) ? header[0] : header;
38
- }
39
- function isMcpRequestBody(body) {
40
- if (!body || typeof body !== 'object')
41
- return false;
42
- const obj = body;
43
- return ((obj.method === undefined || typeof obj.method === 'string') &&
44
- (obj.id === undefined ||
45
- typeof obj.id === 'string' ||
46
- typeof obj.id === 'number') &&
47
- (obj.jsonrpc === undefined || obj.jsonrpc === '2.0') &&
48
- (obj.params === undefined || typeof obj.params === 'object'));
49
- }
50
- const asyncHandler = (fn) => {
51
- return (req, res, next) => {
52
- Promise.resolve(fn(req, res, next)).catch(next);
53
- };
54
- };
55
38
  if (isStdioMode) {
56
- const { startStdioServer } = await import('./server.js');
57
39
  await startStdioServer();
58
40
  }
59
41
  else {
60
- const app = express();
61
- app.use(express.json({ limit: '1mb' }));
62
- app.use((err, _req, res, next) => {
63
- if (err instanceof SyntaxError && 'body' in err) {
64
- res.status(400).json({
65
- jsonrpc: '2.0',
66
- error: {
67
- code: -32700,
68
- message: 'Parse error: Invalid JSON',
69
- },
70
- id: null,
71
- });
72
- return;
73
- }
74
- next(err);
75
- });
76
- app.use((req, res, next) => {
77
- const { origin } = req.headers;
78
- if (origin) {
79
- try {
80
- new URL(origin);
81
- }
82
- catch {
83
- next();
84
- return;
85
- }
86
- }
87
- if (!origin ||
88
- ALLOW_ALL_ORIGINS ||
89
- (ALLOWED_ORIGINS.length > 0 && ALLOWED_ORIGINS.includes(origin))) {
90
- res.header('Access-Control-Allow-Origin', origin ?? '*');
91
- res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
92
- res.header('Access-Control-Allow-Headers', 'Content-Type, mcp-session-id');
93
- res.header('Access-Control-Max-Age', '86400');
94
- }
95
- else if (ALLOWED_ORIGINS.length > 0) {
96
- // Origin not in allowlist
97
- next();
98
- return;
99
- }
100
- if (req.method === 'OPTIONS') {
101
- res.sendStatus(200);
102
- return;
103
- }
104
- next();
105
- });
106
- app.get('/health', (_req, res) => {
107
- res.json({
108
- status: 'healthy',
109
- name: config.server.name,
110
- version: config.server.version,
111
- uptime: process.uptime(),
112
- });
113
- });
114
- // Simple session storage - Map suffices for debugging HTTP mode
115
- const sessions = new Map();
116
- app.post('/mcp', asyncHandler(async (req, res) => {
117
- const sessionId = getSessionId(req);
118
- let transport;
119
- // Validate request body structure
120
- if (!isMcpRequestBody(req.body)) {
121
- res.status(400).json({
122
- jsonrpc: '2.0',
123
- error: {
124
- code: -32600,
125
- message: 'Invalid Request: Malformed request body',
126
- },
127
- id: null,
128
- });
129
- return;
130
- }
131
- // Body is validated above as McpRequestBody via type guard
132
- logInfo('[MCP POST]', {
133
- method: req.body.method,
134
- id: req.body.id,
135
- sessionId: sessionId ?? 'none',
136
- isInitialize: isInitializeRequest(req.body),
137
- sessionCount: sessions.size,
138
- });
139
- const existingSession = sessionId ? sessions.get(sessionId) : undefined;
140
- if (existingSession && sessionId) {
141
- ({ transport } = existingSession);
142
- }
143
- else if (!sessionId && isInitializeRequest(req.body)) {
144
- transport = new StreamableHTTPServerTransport({
145
- sessionIdGenerator: () => crypto.randomUUID(),
146
- onsessioninitialized: (id) => {
147
- sessions.set(id, { transport, createdAt: Date.now() });
148
- logInfo('Session initialized', { sessionId: id });
149
- },
150
- onsessionclosed: (id) => {
151
- sessions.delete(id);
152
- logInfo('Session closed', { sessionId: id });
153
- },
154
- });
155
- transport.onclose = () => {
156
- if (transport.sessionId) {
157
- sessions.delete(transport.sessionId);
158
- }
159
- };
160
- const mcpServer = createMcpServer();
161
- await mcpServer.connect(transport);
162
- }
163
- else {
164
- res.status(400).json({
165
- jsonrpc: '2.0',
166
- error: {
167
- code: -32000,
168
- message: 'Bad Request: Missing session ID or not an initialize request',
169
- },
170
- id: null,
171
- });
172
- return;
173
- }
174
- await transport.handleRequest(req, res, req.body);
175
- }));
176
- app.get('/mcp', asyncHandler(async (req, res) => {
177
- const sessionId = getSessionId(req);
178
- if (!sessionId) {
179
- res.status(400).json({ error: 'Missing mcp-session-id header' });
180
- return;
181
- }
182
- const session = sessionId ? sessions.get(sessionId) : undefined;
183
- if (!session) {
184
- res.status(404).json({ error: 'Session not found' });
185
- return;
186
- }
187
- await session.transport.handleRequest(req, res);
188
- }));
189
- app.delete('/mcp', asyncHandler(async (req, res) => {
190
- const sessionId = getSessionId(req);
191
- const session = sessionId ? sessions.get(sessionId) : undefined;
192
- if (session) {
193
- await session.transport.handleRequest(req, res);
194
- }
195
- else {
196
- res.status(204).end();
197
- }
198
- }));
199
- app.use(errorHandler);
200
- const server = app
201
- .listen(config.server.port, config.server.host, () => {
202
- logInfo(`superFetch MCP server started`, {
203
- host: config.server.host,
204
- port: config.server.port,
205
- });
206
- process.stdout.write(`✓ superFetch MCP server running at http://${config.server.host}:${config.server.port}\n`);
207
- process.stdout.write(` Health check: http://${config.server.host}:${config.server.port}/health\n`);
208
- process.stdout.write(` MCP endpoint: http://${config.server.host}:${config.server.port}/mcp\n`);
209
- process.stdout.write(`\nRun with --stdio flag for direct stdio integration\n`);
210
- })
211
- .on('error', (err) => {
212
- logError('Failed to start server', err);
213
- process.exit(1);
214
- });
215
- const shutdownFn = async (signal) => {
216
- if (isShuttingDown)
217
- return;
218
- isShuttingDown = true;
219
- process.stdout.write(`\n${signal} received, shutting down gracefully...\n`);
220
- // Close all sessions
221
- const closePromises = Array.from(sessions.values()).map((session) => session.transport.close());
222
- await Promise.allSettled(closePromises);
223
- sessions.clear();
224
- destroyAgents();
225
- server.close(() => {
226
- logInfo('HTTP server closed');
227
- process.exit(0);
228
- });
229
- setTimeout(() => {
230
- logError('Forced shutdown after timeout');
231
- process.exit(1);
232
- }, 10000).unref();
233
- };
234
- shutdownHandlerRef.current = shutdownFn;
235
- process.on('SIGINT', () => {
236
- void shutdownFn('SIGINT');
237
- });
238
- process.on('SIGTERM', () => {
239
- void shutdownFn('SIGTERM');
240
- });
42
+ const { shutdown } = await startHttpServer();
43
+ shutdownHandlerRef.current = shutdown;
241
44
  }
242
45
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE;QACP,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;KAC3C;CACF,CAAC,CAAC;AACH,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC;AACjC,IAAI,cAAc,GAAG,KAAK,CAAC;AAE3B,MAAM,kBAAkB,GAAoD,EAAE,CAAC;AAE/E,SAAS,qBAAqB;IAC5B,OAAO,CAAC,cAAc,IAAI,CAAC,WAAW,IAAI,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,eAAe,CAAC,MAAc;IACrC,IAAI,CAAC,kBAAkB,CAAC,OAAO;QAAE,OAAO;IACxC,cAAc,GAAG,IAAI,CAAC;IACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAC1D,KAAK,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE;IACxC,QAAQ,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;IAE/D,IAAI,qBAAqB,EAAE,EAAE,CAAC;QAC5B,eAAe,CAAC,oBAAoB,CAAC,CAAC;QACtC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;IAC1C,MAAM,KAAK,GAAG,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3E,QAAQ,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;IACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC;AAEH,IAAI,WAAW,EAAE,CAAC;IAChB,MAAM,gBAAgB,EAAE,CAAC;AAC3B,CAAC;KAAM,CAAC;IACN,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,eAAe,EAAE,CAAC;IAC7C,kBAAkB,CAAC,OAAO,GAAG,QAAQ,CAAC;AACxC,CAAC"}
@@ -1,3 +1,3 @@
1
- import type { Request, Response } from 'express';
2
- export declare function errorHandler(err: Error, req: Request, res: Response): void;
1
+ import type { NextFunction, Request, Response } from 'express';
2
+ export declare function errorHandler(err: Error, req: Request, res: Response, _next: NextFunction): void;
3
3
  //# sourceMappingURL=error-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQjD,wBAAgB,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CA+B1E"}
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAgE/D,wBAAgB,YAAY,CAC1B,GAAG,EAAE,KAAK,EACV,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,YAAY,GAClB,IAAI,CAWN"}
@@ -1,27 +1,58 @@
1
1
  import { FetchError } from '../errors/app-error.js';
2
2
  import { logError } from '../services/logger.js';
3
- export function errorHandler(err, req, res) {
4
- const isFetchError = err instanceof FetchError;
5
- const statusCode = isFetchError ? err.statusCode : 500;
6
- const code = isFetchError ? err.code : 'INTERNAL_ERROR';
7
- const message = isFetchError ? err.message : 'Internal Server Error';
8
- logError(`HTTP ${statusCode}: ${err.message} - ${req.method} ${req.path}`, err);
9
- if (isFetchError && err.code === 'RATE_LIMITED' && err.details.retryAfter) {
10
- const retryAfter = err.details.retryAfter;
11
- res.set('Retry-After', String(retryAfter));
3
+ function getStatusCode(err) {
4
+ return err instanceof FetchError ? err.statusCode : 500;
5
+ }
6
+ function getErrorCode(err) {
7
+ return err instanceof FetchError ? err.code : 'INTERNAL_ERROR';
8
+ }
9
+ function getErrorMessage(err) {
10
+ return err instanceof FetchError ? err.message : 'Internal Server Error';
11
+ }
12
+ function getErrorDetails(err) {
13
+ if (err instanceof FetchError && Object.keys(err.details).length > 0) {
14
+ return err.details;
12
15
  }
16
+ return undefined;
17
+ }
18
+ function setRetryAfterHeader(res, err) {
19
+ const retryAfter = resolveRetryAfter(err);
20
+ if (!retryAfter)
21
+ return;
22
+ res.set('Retry-After', retryAfter);
23
+ }
24
+ function buildErrorResponse(err) {
25
+ const details = getErrorDetails(err);
13
26
  const response = {
14
27
  error: {
15
- message,
16
- code,
17
- statusCode,
18
- ...(isFetchError &&
19
- Object.keys(err.details).length > 0 && { details: err.details }),
28
+ message: getErrorMessage(err),
29
+ code: getErrorCode(err),
30
+ statusCode: getStatusCode(err),
31
+ ...(details && { details }),
20
32
  },
21
33
  };
22
34
  if (process.env.NODE_ENV === 'development') {
23
35
  response.error.stack = err.stack;
24
36
  }
25
- res.status(statusCode).json(response);
37
+ return response;
38
+ }
39
+ function resolveRetryAfter(err) {
40
+ if (!(err instanceof FetchError))
41
+ return null;
42
+ if (err.statusCode !== 429)
43
+ return null;
44
+ const { retryAfter } = err.details;
45
+ if (!isRetryAfterValue(retryAfter))
46
+ return null;
47
+ return String(retryAfter);
48
+ }
49
+ function isRetryAfterValue(value) {
50
+ return typeof value === 'number' || typeof value === 'string';
51
+ }
52
+ export function errorHandler(err, req, res, _next) {
53
+ const statusCode = getStatusCode(err);
54
+ logError(`HTTP ${statusCode}: ${err.message} - ${req.method} ${req.path}`, err);
55
+ setRetryAfterHeader(res, err);
56
+ res.status(statusCode).json(buildErrorResponse(err));
26
57
  }
27
58
  //# sourceMappingURL=error-handler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,UAAU,YAAY,CAAC,GAAU,EAAE,GAAY,EAAE,GAAa;IAClE,MAAM,YAAY,GAAG,GAAG,YAAY,UAAU,CAAC;IAC/C,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;IACvD,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACxD,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,CAAC;IAErE,QAAQ,CACN,QAAQ,UAAU,KAAK,GAAG,CAAC,OAAO,MAAM,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,EAChE,GAAG,CACJ,CAAC;IAEF,IAAI,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QAC1E,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,UAAoB,CAAC;QACpD,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,QAAQ,GAAkB;QAC9B,KAAK,EAAE;YACL,OAAO;YACP,IAAI;YACJ,UAAU;YACV,GAAG,CAAC,YAAY;gBACd,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;SACnE;KACF,CAAC;IAEF,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC3C,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IACnC,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"cached-content.d.ts","sourceRoot":"","sources":["../../src/resources/cached-content.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6ErE"}
1
+ {"version":3,"file":"cached-content.d.ts","sourceRoot":"","sources":["../../src/resources/cached-content.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgEzE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAIrE"}
@@ -1,62 +1,122 @@
1
1
  import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import * as cache from '../services/cache.js';
3
+ import { logWarn } from '../services/logger.js';
4
+ function buildResourceEntry(namespace, urlHash) {
5
+ return {
6
+ name: `${namespace}:${urlHash}`,
7
+ uri: `superfetch://cache/${namespace}/${urlHash}`,
8
+ description: `Cached content entry for ${namespace}`,
9
+ mimeType: 'application/json',
10
+ };
11
+ }
12
+ function listCachedResources() {
13
+ const resources = cache
14
+ .keys()
15
+ .map((key) => {
16
+ const parts = cache.parseCacheKey(key);
17
+ return parts ? buildResourceEntry(parts.namespace, parts.urlHash) : null;
18
+ })
19
+ .filter((entry) => entry !== null);
20
+ return { resources };
21
+ }
22
+ function buildCacheListPayload() {
23
+ const cacheKeys = cache.keys();
24
+ return {
25
+ totalEntries: cacheKeys.length,
26
+ entries: cacheKeys.map((key) => {
27
+ const parts = cache.parseCacheKey(key);
28
+ const namespace = parts?.namespace ?? 'unknown';
29
+ const urlHash = parts?.urlHash ?? 'unknown';
30
+ return {
31
+ namespace,
32
+ urlHash,
33
+ resourceUri: `superfetch://cache/${namespace}/${urlHash}`,
34
+ };
35
+ }),
36
+ timestamp: new Date().toISOString(),
37
+ };
38
+ }
39
+ function notifyResourceUpdate(server, uri) {
40
+ if (!server.isConnected())
41
+ return;
42
+ void server.server.sendResourceUpdated({ uri }).catch((error) => {
43
+ logWarn('Failed to send resource update notification', {
44
+ uri,
45
+ error: error instanceof Error ? error.message : 'Unknown error',
46
+ });
47
+ });
48
+ }
3
49
  export function registerCachedContentResource(server) {
50
+ registerCacheContentResource(server);
51
+ registerCacheListResource(server);
52
+ registerCacheUpdateSubscription(server);
53
+ }
54
+ function resolveCacheParams(params) {
55
+ const namespace = params.namespace;
56
+ const urlHash = params.urlHash;
57
+ if (!namespace || !urlHash) {
58
+ throw new Error('Both namespace and urlHash parameters are required');
59
+ }
60
+ return { namespace, urlHash };
61
+ }
62
+ function buildCachedContentResponse(uri, cacheKey) {
63
+ const cached = cache.get(cacheKey);
64
+ if (!cached) {
65
+ throw new Error(`Content not found in cache for key: ${cacheKey}. Use superfetch://stats to see available cache entries.`);
66
+ }
67
+ return {
68
+ contents: [
69
+ {
70
+ uri: uri.href,
71
+ mimeType: 'application/json',
72
+ text: cached.content,
73
+ },
74
+ ],
75
+ };
76
+ }
77
+ function registerCacheContentResource(server) {
4
78
  server.registerResource('cached-content', new ResourceTemplate('superfetch://cache/{namespace}/{urlHash}', {
5
- list: undefined,
79
+ list: listCachedResources,
6
80
  }), {
7
81
  title: 'Cached Content',
8
82
  description: 'Access previously fetched web content from cache. Namespace: url, links, markdown. UrlHash: SHA-256 hash of the URL.',
9
83
  mimeType: 'application/json',
10
84
  }, (uri, params) => {
11
- const namespace = params.namespace;
12
- const urlHash = params.urlHash;
13
- if (!namespace || !urlHash) {
14
- throw new Error('Both namespace and urlHash parameters are required');
15
- }
85
+ const { namespace, urlHash } = resolveCacheParams(params);
16
86
  const cacheKey = `${namespace}:${urlHash}`;
17
- const cached = cache.get(cacheKey);
18
- if (!cached) {
19
- throw new Error(`Content not found in cache for key: ${cacheKey}. Use superfetch://stats to see available cache entries.`);
20
- }
21
- return {
22
- contents: [
23
- {
24
- uri: uri.href,
25
- mimeType: 'application/json',
26
- text: cached.content,
27
- },
28
- ],
29
- };
87
+ return buildCachedContentResponse(uri, cacheKey);
30
88
  });
89
+ }
90
+ function registerCacheListResource(server) {
31
91
  server.registerResource('cached-urls', 'superfetch://cache/list', {
32
92
  title: 'Cached URLs List',
33
93
  description: 'List all URLs currently in cache with their namespaces',
34
94
  mimeType: 'application/json',
35
- }, (uri) => {
36
- const cacheKeys = cache.keys();
37
- const cacheList = {
38
- totalEntries: cacheKeys.length,
39
- entries: cacheKeys.map((key) => {
40
- const parts = key.split(':');
41
- const namespace = parts[0] ?? 'unknown';
42
- const urlHash = parts.slice(1).join(':') || 'unknown';
43
- return {
44
- namespace,
45
- urlHash,
46
- resourceUri: `superfetch://cache/${namespace}/${urlHash}`,
47
- };
48
- }),
49
- timestamp: new Date().toISOString(),
50
- };
51
- return {
52
- contents: [
53
- {
54
- uri: uri.href,
55
- mimeType: 'application/json',
56
- text: JSON.stringify(cacheList, null, 2),
57
- },
58
- ],
59
- };
95
+ }, (uri) => ({
96
+ contents: [
97
+ {
98
+ uri: uri.href,
99
+ mimeType: 'application/json',
100
+ text: JSON.stringify(buildCacheListPayload(), null, 2),
101
+ },
102
+ ],
103
+ }));
104
+ }
105
+ function registerCacheUpdateSubscription(server) {
106
+ const unsubscribe = cache.onCacheUpdate(({ cacheKey }) => {
107
+ const resourceUri = cache.toResourceUri(cacheKey);
108
+ if (!resourceUri)
109
+ return;
110
+ notifyResourceUpdate(server, resourceUri);
111
+ notifyResourceUpdate(server, 'superfetch://cache/list');
112
+ if (server.isConnected()) {
113
+ server.sendResourceListChanged();
114
+ }
60
115
  });
116
+ const previousOnClose = server.server.onclose;
117
+ server.server.onclose = () => {
118
+ previousOnClose?.();
119
+ unsubscribe();
120
+ };
61
121
  }
62
122
  //# sourceMappingURL=cached-content.js.map