@atlaspack/inspector 0.0.19-canary.3998

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 (235) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +126 -0
  3. package/bin/atlaspack-inspector.js +2 -0
  4. package/lib/backend/cli.js +4 -0
  5. package/lib/backend/config/logger.js +16 -0
  6. package/lib/backend/config/middleware/cacheDataMiddleware.js +60 -0
  7. package/lib/backend/config/middleware/errorHandlingMiddleware.js +17 -0
  8. package/lib/backend/config/middleware/errorHandlingMiddleware.test.js +44 -0
  9. package/lib/backend/config/middleware/loggingMiddleware.js +22 -0
  10. package/lib/backend/controllers/BundleGraphController.js +42 -0
  11. package/lib/backend/controllers/CacheDataController.js +143 -0
  12. package/lib/backend/controllers/FrontendAssetsController.js +61 -0
  13. package/lib/backend/controllers/TreeMapController.js +108 -0
  14. package/lib/backend/controllers/mcp/InspectorMCP.js +231 -0
  15. package/lib/backend/controllers/mcp/InspectorMCPController.js +16 -0
  16. package/lib/backend/errors/HTTPError.js +16 -0
  17. package/lib/backend/errors/HTTPError.test.js +21 -0
  18. package/lib/backend/index.js +177 -0
  19. package/lib/backend/services/AnalyticsService.js +86 -0
  20. package/lib/backend/services/LazyValue.js +33 -0
  21. package/lib/backend/services/LazyValue.test.js +12 -0
  22. package/lib/backend/services/buildJsonGraph.js +86 -0
  23. package/lib/backend/services/buildTreemap.js +140 -0
  24. package/lib/backend/services/buildTreemapBundle.test.js +298 -0
  25. package/lib/backend/services/findSourceCodeUrl.js +107 -0
  26. package/lib/backend/services/findSourceCodeUrl.test.js +216 -0
  27. package/lib/backend/services/getCacheStats.js +36 -0
  28. package/lib/backend/services/getCacheStats.test.js +162 -0
  29. package/lib/backend/services/getDisplayName.js +18 -0
  30. package/lib/backend/services/getDisplayName.test.js +71 -0
  31. package/lib/backend/services/loadCacheData.js +209 -0
  32. package/lib/backend/services/loadCacheData.test.js +79 -0
  33. package/lib/backend/testing/TemporaryDirectory.js +46 -0
  34. package/lib/frontend/node_modules/@atlaspack/packager-js/lib/dev-prelude.js +145 -0
  35. package/lib/frontend/node_modules/@atlaspack/packager-js/src/dev-prelude.js +145 -0
  36. package/package.json +75 -0
  37. package/screenshots/bottom-up.png +0 -0
  38. package/screenshots/cache-inspector.png +0 -0
  39. package/screenshots/treemap.png +0 -0
  40. package/src/backend/README.md +14 -0
  41. package/src/backend/cli.ts +3 -0
  42. package/src/backend/config/logger.ts +14 -0
  43. package/src/backend/config/middleware/cacheDataMiddleware.ts +94 -0
  44. package/src/backend/config/middleware/errorHandlingMiddleware.test.ts +52 -0
  45. package/src/backend/config/middleware/errorHandlingMiddleware.ts +20 -0
  46. package/src/backend/config/middleware/loggingMiddleware.ts +24 -0
  47. package/src/backend/controllers/BundleGraphController.ts +73 -0
  48. package/src/backend/controllers/CacheDataController.ts +187 -0
  49. package/src/backend/controllers/FrontendAssetsController.ts +28 -0
  50. package/src/backend/controllers/TreeMapController.ts +143 -0
  51. package/src/backend/controllers/mcp/InspectorMCP.ts +311 -0
  52. package/src/backend/controllers/mcp/InspectorMCPController.ts +17 -0
  53. package/src/backend/errors/HTTPError.test.ts +19 -0
  54. package/src/backend/errors/HTTPError.ts +14 -0
  55. package/src/backend/globals.d.ts +9 -0
  56. package/src/backend/index.ts +271 -0
  57. package/src/backend/services/AnalyticsService.ts +118 -0
  58. package/src/backend/services/LazyValue.test.ts +13 -0
  59. package/src/backend/services/LazyValue.ts +29 -0
  60. package/src/backend/services/buildJsonGraph.ts +124 -0
  61. package/src/backend/services/buildTreemap.ts +273 -0
  62. package/src/backend/services/buildTreemapBundle.test.ts +348 -0
  63. package/src/backend/services/findSourceCodeUrl.test.ts +228 -0
  64. package/src/backend/services/findSourceCodeUrl.ts +146 -0
  65. package/src/backend/services/getCacheStats.test.ts +169 -0
  66. package/src/backend/services/getCacheStats.ts +46 -0
  67. package/src/backend/services/getDisplayName.test.ts +84 -0
  68. package/src/backend/services/getDisplayName.ts +20 -0
  69. package/src/backend/services/loadCacheData.test.ts +101 -0
  70. package/src/backend/services/loadCacheData.ts +294 -0
  71. package/src/backend/testing/TemporaryDirectory.ts +50 -0
  72. package/src/frontend/.atlaspackrc +4 -0
  73. package/src/frontend/.eslintrc.json +19 -0
  74. package/src/frontend/dist/atlassian-dark-brand-refresh.91b786da.js +2 -0
  75. package/src/frontend/dist/atlassian-dark-brand-refresh.91b786da.js.map +1 -0
  76. package/src/frontend/dist/atlassian-dark-future.59ebadca.js +2 -0
  77. package/src/frontend/dist/atlassian-dark-future.59ebadca.js.map +1 -0
  78. package/src/frontend/dist/atlassian-dark-increased-contrast.ff6775f2.js +2 -0
  79. package/src/frontend/dist/atlassian-dark-increased-contrast.ff6775f2.js.map +1 -0
  80. package/src/frontend/dist/atlassian-dark.ad679134.js +2 -0
  81. package/src/frontend/dist/atlassian-dark.ad679134.js.map +1 -0
  82. package/src/frontend/dist/atlassian-legacy-dark.8aa27f7f.js +2 -0
  83. package/src/frontend/dist/atlassian-legacy-dark.8aa27f7f.js.map +1 -0
  84. package/src/frontend/dist/atlassian-legacy-light.2eb372ce.js +2 -0
  85. package/src/frontend/dist/atlassian-legacy-light.2eb372ce.js.map +1 -0
  86. package/src/frontend/dist/atlassian-light-brand-refresh.fadcab0a.js +2 -0
  87. package/src/frontend/dist/atlassian-light-brand-refresh.fadcab0a.js.map +1 -0
  88. package/src/frontend/dist/atlassian-light-future.612afe8a.js +2 -0
  89. package/src/frontend/dist/atlassian-light-future.612afe8a.js.map +1 -0
  90. package/src/frontend/dist/atlassian-light-increased-contrast.7161cd79.js +2 -0
  91. package/src/frontend/dist/atlassian-light-increased-contrast.7161cd79.js.map +1 -0
  92. package/src/frontend/dist/atlassian-light.bc343d4c.js +2 -0
  93. package/src/frontend/dist/atlassian-light.bc343d4c.js.map +1 -0
  94. package/src/frontend/dist/atlassian-shape.b92d69c0.js +2 -0
  95. package/src/frontend/dist/atlassian-shape.b92d69c0.js.map +1 -0
  96. package/src/frontend/dist/atlassian-spacing.60ddd8e7.js +2 -0
  97. package/src/frontend/dist/atlassian-spacing.60ddd8e7.js.map +1 -0
  98. package/src/frontend/dist/atlassian-typography-adg3.f88947f6.js +2 -0
  99. package/src/frontend/dist/atlassian-typography-adg3.f88947f6.js.map +1 -0
  100. package/src/frontend/dist/atlassian-typography-modernized.42016c51.js +2 -0
  101. package/src/frontend/dist/atlassian-typography-modernized.42016c51.js.map +1 -0
  102. package/src/frontend/dist/atlassian-typography-refreshed.ec0d111b.js +2 -0
  103. package/src/frontend/dist/atlassian-typography-refreshed.ec0d111b.js.map +1 -0
  104. package/src/frontend/dist/atlassian-typography.66d7e8f4.js +2 -0
  105. package/src/frontend/dist/atlassian-typography.66d7e8f4.js.map +1 -0
  106. package/src/frontend/dist/badge-light.7e55986a.png +0 -0
  107. package/src/frontend/dist/custom-theme.4680282a.js +2 -0
  108. package/src/frontend/dist/custom-theme.4680282a.js.map +1 -0
  109. package/src/frontend/dist/drag-handle.136830d3.js +2 -0
  110. package/src/frontend/dist/drag-handle.136830d3.js.map +1 -0
  111. package/src/frontend/dist/drag-handle.63bdb345.css +2 -0
  112. package/src/frontend/dist/drag-handle.63bdb345.css.map +1 -0
  113. package/src/frontend/dist/index.a41fafce.css +2 -0
  114. package/src/frontend/dist/index.a41fafce.css.map +1 -0
  115. package/src/frontend/dist/index.a4ce2b12.js +28 -0
  116. package/src/frontend/dist/index.a4ce2b12.js.map +1 -0
  117. package/src/frontend/dist/index.html +1 -0
  118. package/src/frontend/dist/index.runtime.a729d997.js +2 -0
  119. package/src/frontend/dist/index.runtime.a729d997.js.map +1 -0
  120. package/src/frontend/dist/refractor.2c1fd9a1.js +2 -0
  121. package/src/frontend/dist/refractor.2c1fd9a1.js.map +1 -0
  122. package/src/frontend/index.html +11 -0
  123. package/src/frontend/jest.config.js +16 -0
  124. package/src/frontend/package.json +64 -0
  125. package/src/frontend/src/APIError.test.ts +72 -0
  126. package/src/frontend/src/APIError.tsx +29 -0
  127. package/src/frontend/src/AppRoutes.tsx +56 -0
  128. package/src/frontend/src/hack-feature-flags.ts +6 -0
  129. package/src/frontend/src/main.tsx +50 -0
  130. package/src/frontend/src/test/stubCssModule.js +1 -0
  131. package/src/frontend/src/ui/App.module.css +122 -0
  132. package/src/frontend/src/ui/App.module.css.d.ts +8 -0
  133. package/src/frontend/src/ui/AppLayout/AppLayout.tsx +26 -0
  134. package/src/frontend/src/ui/AppLayout/SidebarNavigation/LinkItem.tsx +26 -0
  135. package/src/frontend/src/ui/AppLayout/SidebarNavigation/SidebarNavigation.tsx +45 -0
  136. package/src/frontend/src/ui/AppLayout/TopNavigation/Logo.module.css +12 -0
  137. package/src/frontend/src/ui/AppLayout/TopNavigation/Logo.module.css.d.ts +4 -0
  138. package/src/frontend/src/ui/AppLayout/TopNavigation/Logo.tsx +11 -0
  139. package/src/frontend/src/ui/AppLayout/TopNavigation/TopNavigation.module.css +14 -0
  140. package/src/frontend/src/ui/AppLayout/TopNavigation/TopNavigation.module.css.d.ts +3 -0
  141. package/src/frontend/src/ui/AppLayout/TopNavigation/TopNavigation.tsx +45 -0
  142. package/src/frontend/src/ui/AppLayout/TopNavigation/badge-light.png +0 -0
  143. package/src/frontend/src/ui/AppLayout/TopNavigation/logo-light.png +0 -0
  144. package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css +9 -0
  145. package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.module.css.d.ts +3 -0
  146. package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.test.tsx +15 -0
  147. package/src/frontend/src/ui/DefaultLoadingIndicator/DefaultLoadingIndicator.tsx +14 -0
  148. package/src/frontend/src/ui/app/StatsPage.tsx +77 -0
  149. package/src/frontend/src/ui/app/cache/CacheKeysIndexPage.tsx +13 -0
  150. package/src/frontend/src/ui/app/cache/CacheKeysPage.module.css +11 -0
  151. package/src/frontend/src/ui/app/cache/CacheKeysPage.module.css.d.ts +4 -0
  152. package/src/frontend/src/ui/app/cache/CacheKeysPage.tsx +23 -0
  153. package/src/frontend/src/ui/app/cache/[key]/CacheValuePage.tsx +40 -0
  154. package/src/frontend/src/ui/app/cache/ui/CacheKeyList.module.css +40 -0
  155. package/src/frontend/src/ui/app/cache/ui/CacheKeyList.module.css.d.ts +7 -0
  156. package/src/frontend/src/ui/app/cache/ui/CacheKeyList.tsx +187 -0
  157. package/src/frontend/src/ui/app/cache-invalidation/CacheInvalidationPage.tsx +22 -0
  158. package/src/frontend/src/ui/app/cache-invalidation/[fileId]/CacheInvalidationFilePage.tsx +22 -0
  159. package/src/frontend/src/ui/app/cache-invalidation/ui/CacheFileList.module.css +40 -0
  160. package/src/frontend/src/ui/app/cache-invalidation/ui/CacheFileList.module.css.d.ts +7 -0
  161. package/src/frontend/src/ui/app/cache-invalidation/ui/CacheFileList.tsx +185 -0
  162. package/src/frontend/src/ui/app/treemap/BottomPanelResizeState.test.ts +25 -0
  163. package/src/frontend/src/ui/app/treemap/BottomPanelResizeState.tsx +48 -0
  164. package/src/frontend/src/ui/app/treemap/FoamTreemapPage.module.css +24 -0
  165. package/src/frontend/src/ui/app/treemap/FoamTreemapPage.module.css.d.ts +6 -0
  166. package/src/frontend/src/ui/app/treemap/FoamTreemapPage.tsx +47 -0
  167. package/src/frontend/src/ui/app/treemap/controllers/RelatedBundlesController.tsx +41 -0
  168. package/src/frontend/src/ui/app/treemap/controllers/UrlFocusController.tsx +33 -0
  169. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css +24 -0
  170. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/BottomPanel.module.css.d.ts +5 -0
  171. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/BottomPanel.tsx +24 -0
  172. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css +13 -0
  173. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.module.css.d.ts +5 -0
  174. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AdvancedSettings.tsx +53 -0
  175. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/AssetTable.tsx +135 -0
  176. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css +7 -0
  177. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.module.css.d.ts +3 -0
  178. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTable.tsx +123 -0
  179. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableModel.tsx +18 -0
  180. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css +20 -0
  181. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.module.css.d.ts +6 -0
  182. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/CollapsibleTable/CollapsibleTableRow.tsx +79 -0
  183. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.test.ts +19 -0
  184. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/AssetTable/getFileURL.ts +24 -0
  185. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css +20 -0
  186. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.module.css.d.ts +5 -0
  187. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfo.tsx +42 -0
  188. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css +29 -0
  189. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.module.css.d.ts +6 -0
  190. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/FocusedGroupInfoInner.tsx +107 -0
  191. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css +7 -0
  192. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.module.css.d.ts +3 -0
  193. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/GraphContainer.tsx +20 -0
  194. package/src/frontend/src/ui/app/treemap/ui/BottomPanel/FocusedGroupInfo/SourceCodeURL.tsx +5 -0
  195. package/src/frontend/src/ui/app/treemap/ui/BundleGraphRenderer.module.css +13 -0
  196. package/src/frontend/src/ui/app/treemap/ui/BundleGraphRenderer.module.css.d.ts +4 -0
  197. package/src/frontend/src/ui/app/treemap/ui/BundleGraphRenderer.tsx +95 -0
  198. package/src/frontend/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css +6 -0
  199. package/src/frontend/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.module.css.d.ts +3 -0
  200. package/src/frontend/src/ui/app/treemap/ui/FocusBreadcrumbs/FocusBreadcrumbs.tsx +49 -0
  201. package/src/frontend/src/ui/app/treemap/ui/SigmaGraph.module.css +5 -0
  202. package/src/frontend/src/ui/app/treemap/ui/SigmaGraph.module.css.d.ts +3 -0
  203. package/src/frontend/src/ui/app/treemap/ui/SigmaGraph.tsx +80 -0
  204. package/src/frontend/src/ui/app/treemap/ui/Treemap.tsx +14 -0
  205. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css +32 -0
  206. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.module.css.d.ts +5 -0
  207. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/ImpactScore.tsx +24 -0
  208. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css +14 -0
  209. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.module.css.d.ts +4 -0
  210. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapRenderer.tsx +271 -0
  211. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css +15 -0
  212. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.module.css.d.ts +4 -0
  213. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/TreemapTooltip.tsx +111 -0
  214. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.test.ts +27 -0
  215. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/controllers/useStableCallback.ts +21 -0
  216. package/src/frontend/src/ui/app/treemap/ui/TreemapRenderer/useMouseMoveController.ts +20 -0
  217. package/src/frontend/src/ui/globals.css +26 -0
  218. package/src/frontend/src/ui/globals.css.d.ts +1 -0
  219. package/src/frontend/src/ui/globals.d.ts +9 -0
  220. package/src/frontend/src/ui/model/ViewModel.test.ts +31 -0
  221. package/src/frontend/src/ui/model/ViewModel.ts +62 -0
  222. package/src/frontend/src/ui/not-found/NotFoundPage.module.css +7 -0
  223. package/src/frontend/src/ui/not-found/NotFoundPage.module.css.d.ts +3 -0
  224. package/src/frontend/src/ui/not-found/NotFoundPage.tsx +9 -0
  225. package/src/frontend/src/ui/types/Graph.tsx +12 -0
  226. package/src/frontend/src/ui/util/ErrorBoundary.module.css +3 -0
  227. package/src/frontend/src/ui/util/ErrorBoundary.module.css.d.ts +3 -0
  228. package/src/frontend/src/ui/util/ErrorBoundary.test.tsx +65 -0
  229. package/src/frontend/src/ui/util/ErrorBoundary.tsx +75 -0
  230. package/src/frontend/src/ui/util/colorPalette.tsx +122 -0
  231. package/src/frontend/src/ui/util/formatBytes.test.ts +13 -0
  232. package/src/frontend/src/ui/util/formatBytes.tsx +9 -0
  233. package/src/frontend/src/ui/util/getRandomDarkerColor.tsx +31 -0
  234. package/src/frontend/tsconfig.json +12 -0
  235. package/src/frontend/yarn.lock +0 -0
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeCacheDataController = makeCacheDataController;
4
+ const express_1 = require("express");
5
+ const getCacheStats_1 = require("../services/getCacheStats");
6
+ const cacheDataMiddleware_1 = require("../config/middleware/cacheDataMiddleware");
7
+ function makeCacheDataController() {
8
+ const router = (0, express_1.Router)();
9
+ router.get('/api/stats', (_req, res) => {
10
+ const cache = (0, cacheDataMiddleware_1.getCache)(res);
11
+ const stats = (0, getCacheStats_1.getCacheStats)(cache);
12
+ res.json(stats);
13
+ });
14
+ router.get('/api/cache-invalidation-files/', (req, res) => {
15
+ const limit = req.query.limit != null ? Number(req.query.limit) : 100;
16
+ const cursor = req.query.cursor;
17
+ const sortBy = req.query.sortBy;
18
+ const requestTracker = (0, cacheDataMiddleware_1.getRequestTracker)(res);
19
+ // 0 is file
20
+ let files = requestTracker.graph.nodes
21
+ .filter((node) => node.type === 0)
22
+ .map((node) => ({
23
+ ...node,
24
+ invalidationCount: requestTracker.graph
25
+ .getNodeIdsConnectedTo(requestTracker.graph.getNodeIdByContentKey(node.id), -1)
26
+ // type 1 is request
27
+ .filter((node) => requestTracker.graph.getNode(node).type === 1)
28
+ .length,
29
+ }));
30
+ if (sortBy == null || sortBy === 'invalidationCount') {
31
+ files.sort((a, b) => b.invalidationCount - a.invalidationCount);
32
+ }
33
+ const count = files.length;
34
+ const cursorIndex = cursor != null && cursor !== ''
35
+ ? files.findIndex((node) => node.id === cursor) + 1
36
+ : 0;
37
+ const resultFiles = files.slice(cursorIndex, cursorIndex + limit);
38
+ res.json({
39
+ files: resultFiles,
40
+ count,
41
+ nextPageCursor: cursorIndex + limit < count
42
+ ? resultFiles[resultFiles.length - 1]
43
+ : null,
44
+ hasNextPage: cursorIndex + limit < count,
45
+ limit,
46
+ });
47
+ });
48
+ router.get('/api/cache-invalidation-files/:fileId', (req, res) => {
49
+ const requestTracker = (0, cacheDataMiddleware_1.getRequestTracker)(res);
50
+ const file = requestTracker.graph.nodes.find((node) => node.id === req.params.fileId);
51
+ if (!file) {
52
+ res.status(400).json({ error: 'File not found' });
53
+ return;
54
+ }
55
+ const nodeId = requestTracker.graph.getNodeIdByContentKey(file.id);
56
+ const nodes = requestTracker.graph.getNodeIdsConnectedTo(nodeId, -1);
57
+ const invalidatedNodes = nodes
58
+ .map((node) => requestTracker.graph.getNode(node))
59
+ .filter((node) => node.type === 1);
60
+ const response = {
61
+ file,
62
+ invalidatedNodesCount: invalidatedNodes.length,
63
+ };
64
+ res.json(response);
65
+ });
66
+ router.get('/api/cache-invalidation-files/:fileId/invalidated-nodes', (req, res) => {
67
+ const limit = req.query.limit != null ? Number(req.query.limit) : 100;
68
+ const cursor = req.query.cursor;
69
+ const requestTracker = (0, cacheDataMiddleware_1.getRequestTracker)(res);
70
+ const file = requestTracker.graph.nodes.find((node) => node.id === req.params.fileId);
71
+ if (!file) {
72
+ res.status(400).json({ error: 'File not found' });
73
+ return;
74
+ }
75
+ const nodeId = requestTracker.graph.getNodeIdByContentKey(file.id);
76
+ const nodes = requestTracker.graph.getNodeIdsConnectedTo(nodeId, -1);
77
+ const invalidatedNodes = nodes
78
+ .map((node) => requestTracker.graph.getNode(node))
79
+ .filter((node) => node.type === 1);
80
+ const cursorIndex = cursor != null && cursor !== ''
81
+ ? invalidatedNodes.findIndex((node) => node.id === cursor) + 1
82
+ : 0;
83
+ const resultNodes = invalidatedNodes.slice(cursorIndex, cursorIndex + limit);
84
+ const response = {
85
+ data: resultNodes,
86
+ count: invalidatedNodes.length,
87
+ nextPageCursor: cursorIndex + limit < invalidatedNodes.length
88
+ ? resultNodes[resultNodes.length - 1]
89
+ : null,
90
+ hasNextPage: cursorIndex + limit < invalidatedNodes.length,
91
+ limit,
92
+ };
93
+ res.json(response);
94
+ });
95
+ router.get('/api/cache-keys/', (req, res) => {
96
+ const cache = (0, cacheDataMiddleware_1.getCache)(res);
97
+ const sortBy = req.query.sortBy;
98
+ const limit = req.query.limit != null ? Number(req.query.limit) : 100;
99
+ const cursor = req.query.cursor;
100
+ let resultKeys = Array.from(cache.keys());
101
+ if (sortBy === 'size') {
102
+ const sizes = resultKeys.map((key) => [
103
+ key,
104
+ cache.getBlobSync(key).length,
105
+ ]);
106
+ sizes.sort((a, b) => b[1] - a[1]);
107
+ resultKeys = sizes.map(([key]) => key);
108
+ }
109
+ const count = resultKeys.length;
110
+ const cursorIndex = cursor != null ? resultKeys.indexOf(cursor) + 1 : 0;
111
+ resultKeys = resultKeys.slice(cursorIndex, cursorIndex + limit);
112
+ res.json({
113
+ keys: resultKeys,
114
+ count,
115
+ nextPageCursor: cursorIndex + limit < count ? resultKeys[resultKeys.length - 1] : null,
116
+ hasNextPage: cursorIndex + limit < count,
117
+ limit,
118
+ });
119
+ });
120
+ router.get('/api/cache-value/:key', (req, res) => {
121
+ const cache = (0, cacheDataMiddleware_1.getCache)(res);
122
+ const key = req.params.key;
123
+ try {
124
+ const value = cache.getBlobSync(key);
125
+ // bigger than 1MB
126
+ if (typeof value.length === 'number' && value.length > 1024 * 1024) {
127
+ res.json({
128
+ size: value.length,
129
+ value: value.slice(0, 1024 * 1024).toString('utf-8'),
130
+ });
131
+ return;
132
+ }
133
+ res.json({
134
+ size: value.length,
135
+ value: value.toString('utf-8'),
136
+ });
137
+ }
138
+ catch (error) {
139
+ res.status(500).json({ error: error.message });
140
+ }
141
+ });
142
+ return router;
143
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.makeFrontendAssetsController = makeFrontendAssetsController;
40
+ const path_1 = __importDefault(require("path"));
41
+ const express_1 = __importStar(require("express"));
42
+ /**
43
+ * On production builds, we intend to serve a pre-built version of the front-end `dist`
44
+ * directory in `src/frontend/dist`.
45
+ *
46
+ * On development mode, you should be running the front-end dev-server separately
47
+ * and pointing it at this host.
48
+ */
49
+ function makeFrontendAssetsController() {
50
+ const router = (0, express_1.Router)();
51
+ router.use(express_1.default.static(path_1.default.join(__dirname, '../../../src/frontend/dist')));
52
+ router.use('/app/', (req, res, next) => {
53
+ if (req.method === 'GET') {
54
+ res.sendFile(path_1.default.join(__dirname, '../../../src/frontend/dist/index.html'));
55
+ }
56
+ else {
57
+ next();
58
+ }
59
+ });
60
+ return router;
61
+ }
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.makeTreemapController = makeTreemapController;
7
+ /* eslint-disable import/no-extraneous-dependencies */
8
+ /* eslint-disable monorepo/no-internal-import */
9
+ const express_1 = require("express");
10
+ const path_1 = __importDefault(require("path"));
11
+ const cacheDataMiddleware_1 = require("../config/middleware/cacheDataMiddleware");
12
+ const graph_1 = require("@atlaspack/graph");
13
+ const logger_1 = require("../config/logger");
14
+ function makeTreemapController({ sourceCodeURL, projectRoot, repositoryRoot, }) {
15
+ const router = (0, express_1.Router)();
16
+ router.get('/api/treemap/reasons', (req, res) => {
17
+ const bundleGraph = (0, cacheDataMiddleware_1.getBundleGraph)(res);
18
+ const queryPath = req.query.path;
19
+ const bundle = req.query.bundle;
20
+ const bundleNode = bundleGraph._graph.getNode(bundleGraph._graph.getNodeIdByContentKey(bundle));
21
+ const relevantPaths = [];
22
+ let tooManyPaths = false;
23
+ bundleGraph.traverseBundle(bundleNode.value, {
24
+ enter(node, context, actions) {
25
+ if (context == null) {
26
+ context = [];
27
+ }
28
+ if (node.type === 'asset') {
29
+ context.push(path_1.default.relative(repositoryRoot, node.value.filePath));
30
+ }
31
+ if (node.type === 'dependency') {
32
+ try {
33
+ const childNodeIds = bundleGraph._graph.getNodeIdsConnectedFrom(bundleGraph._graph.getNodeIdByContentKey(node.id), graph_1.ALL_EDGE_TYPES);
34
+ let isParent = false;
35
+ for (const childNodeId of childNodeIds) {
36
+ const childNode = bundleGraph._graph.getNode(childNodeId);
37
+ if (childNode.type === 'asset' &&
38
+ path_1.default
39
+ .relative(repositoryRoot, childNode.value.filePath)
40
+ .startsWith(queryPath)) {
41
+ actions.skipChildren();
42
+ isParent = true;
43
+ }
44
+ }
45
+ // For some reason we visit all nodes from the bundle, so we need to filter out
46
+ // stuff that is directly connected to the bundle node, since that's not useful
47
+ // information.
48
+ // e.g.: On the cases where the file is included directly to the bundle either due
49
+ // to manual bundling or entry dependencies, the user probably already knows about
50
+ // it.
51
+ if (isParent && context.length > 1) {
52
+ relevantPaths.push(context.slice());
53
+ if (relevantPaths.length > 50) {
54
+ tooManyPaths = true;
55
+ actions.stop();
56
+ }
57
+ }
58
+ }
59
+ catch (err) {
60
+ logger_1.logger.error(err);
61
+ }
62
+ }
63
+ return context;
64
+ },
65
+ exit(node, context = []) {
66
+ if (node.type === 'asset') {
67
+ context.pop();
68
+ }
69
+ return context;
70
+ },
71
+ });
72
+ res.json({
73
+ tooManyPaths,
74
+ relevantPaths,
75
+ sourceCodeURL,
76
+ projectRoot,
77
+ repositoryRoot,
78
+ });
79
+ });
80
+ router.get('/api/treemap', (req, res) => {
81
+ const treemap = (0, cacheDataMiddleware_1.getTreemap)(res);
82
+ const limit = Number(req.query.limit ?? 10000);
83
+ const offset = Number(req.query.offset ?? 0);
84
+ const bundleId = req.query.bundle;
85
+ let bundles = treemap.bundles;
86
+ if (bundleId) {
87
+ bundles = bundles.filter((bundle) => bundle.id === bundleId);
88
+ }
89
+ else {
90
+ bundles = bundles.map((bundle) => ({
91
+ ...bundle,
92
+ assetTree: {
93
+ id: `${bundle.id}::/`,
94
+ path: '',
95
+ children: {},
96
+ size: bundle.size,
97
+ },
98
+ }));
99
+ }
100
+ res.json({
101
+ bundles: bundles.slice(offset, offset + limit),
102
+ next: offset + limit < bundles.length ? offset + limit : null,
103
+ count: bundles.length,
104
+ totalSize: treemap.totalSize,
105
+ });
106
+ });
107
+ return router;
108
+ }
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InspectorMCP = void 0;
4
+ /* eslint-disable monorepo/no-internal-import */
5
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
6
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
+ const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
8
+ const crypto_1 = require("crypto");
9
+ const zod_1 = require("zod");
10
+ const cacheDataMiddleware_1 = require("../../config/middleware/cacheDataMiddleware");
11
+ /**
12
+ * Incomplete, toy MCP server for the Atlaspack Inspector.
13
+ */
14
+ function makeInspectorMCPServer({ cache, bundleGraph, treemap, }) {
15
+ const server = new mcp_js_1.McpServer({
16
+ name: 'atlaspack-inspector-mcp',
17
+ version: '1.0.0',
18
+ });
19
+ server.registerTool('list-treemap-bundles', {
20
+ title: 'List Treemap Bundles',
21
+ description: `List the bundles in the treemap.`,
22
+ inputSchema: {},
23
+ }, () => {
24
+ return {
25
+ content: [
26
+ {
27
+ type: 'text',
28
+ text: [
29
+ `Treemap bundles:`,
30
+ ...treemap.bundles.flatMap((bundle) => [
31
+ `- ${bundle.displayName} - ${bundle.id} - atlaspack://bundle-info/${bundle.id}`,
32
+ ` * ${bundle.size} bytes`,
33
+ ` * ${bundle.filePath} file path`,
34
+ ` * Run 'query-treemap ${bundle.id}' to get more information about this bundle`,
35
+ ]),
36
+ ].join('\n'),
37
+ },
38
+ ],
39
+ };
40
+ });
41
+ server.registerTool('query-treemap', {
42
+ title: 'Query Treemap',
43
+ description: `Query the treemap for information about a given bundle.`,
44
+ inputSchema: {
45
+ bundleId: zod_1.z.string(),
46
+ },
47
+ }, ({ bundleId }) => {
48
+ const bundle = treemap.bundles.find((bundle) => bundle.id === bundleId);
49
+ if (!bundle) {
50
+ return {
51
+ content: [{ type: 'text', text: `Bundle not found: ${bundleId}` }],
52
+ };
53
+ }
54
+ return {
55
+ content: [
56
+ {
57
+ type: 'text',
58
+ text: [
59
+ `Bundle: ${bundle.displayName}`,
60
+ `Bundle size: ${bundle.size} bytes`,
61
+ ].join('\n'),
62
+ },
63
+ {
64
+ type: 'text',
65
+ text: `Raw treemap JSON:\n${JSON.stringify(bundle)}`,
66
+ },
67
+ ],
68
+ };
69
+ });
70
+ server.registerTool('get-resolved-imports', {
71
+ title: 'Get Resolved Imports',
72
+ description: `Get the resolved imports for a given JavaScript/TypeScript file, if it appears on the output bundles.`,
73
+ inputSchema: {
74
+ file: zod_1.z.string(),
75
+ },
76
+ }, ({ file }) => {
77
+ const assetId = bundleGraph._graph.nodes.find((node) => {
78
+ return node.type === 'asset' && node.value.filePath === file;
79
+ })?.id;
80
+ if (!assetId) {
81
+ return {
82
+ content: [
83
+ { type: 'text', text: `File not found in any bundles: ${file}` },
84
+ ],
85
+ };
86
+ }
87
+ const asset = bundleGraph.getAssetById(assetId);
88
+ const bundlesWithAsset = bundleGraph.getBundlesWithAsset(asset);
89
+ return {
90
+ content: [
91
+ {
92
+ type: 'text',
93
+ text: [
94
+ `Bundles with asset:`,
95
+ ...bundlesWithAsset.map((bundle) => `- ${bundle.id} - ${bundle.displayName} - atlaspack://bundle-info/${bundle.id}`),
96
+ ].join('\n'),
97
+ },
98
+ {
99
+ type: 'text',
100
+ text: `Raw asset JSON: ${JSON.stringify(asset)}`,
101
+ },
102
+ ],
103
+ };
104
+ });
105
+ server.registerResource('treemap-bundle-info', new mcp_js_1.ResourceTemplate('atlaspack://bundle-info/{id}', {
106
+ list() {
107
+ const resources = treemap.bundles
108
+ .slice(0, 10)
109
+ .map((bundle) => ({
110
+ uri: `atlaspack://bundle-info/${bundle.id}`,
111
+ name: `Bundle: ${bundle.displayName}`,
112
+ }));
113
+ return {
114
+ resources,
115
+ };
116
+ },
117
+ }), {
118
+ name: 'Atlaspack Treemap Bundle Information',
119
+ description: `Information about a built JavaScript bundle in the application and its bundle size. Can be used to list available bundles in the application.`,
120
+ }, (uri) => {
121
+ const id = uri.pathname.split('/').slice(1).join('/');
122
+ const bundle = treemap.bundles.find((bundle) => bundle.id === id);
123
+ if (!bundle) {
124
+ return {
125
+ contents: [],
126
+ };
127
+ }
128
+ return {
129
+ contents: [
130
+ {
131
+ uri: uri.toString(),
132
+ text: [
133
+ `Bundle: ${bundle.displayName}`,
134
+ `Bundle size: ${bundle.size} bytes`,
135
+ ].join('\n---\n'),
136
+ },
137
+ ],
138
+ };
139
+ });
140
+ server.registerResource('cache-key', new mcp_js_1.ResourceTemplate('atlaspack://cache/{key}', {
141
+ list: undefined,
142
+ }), {
143
+ name: 'Atlaspack Cache Entry',
144
+ }, (uri) => {
145
+ const key = uri.pathname.split('/').slice(1).join('/');
146
+ const value = cache.getBlobSync(key);
147
+ return {
148
+ contents: [
149
+ {
150
+ uri: uri.toString(),
151
+ type: 'text',
152
+ text: [
153
+ `Cache key: ${key}`,
154
+ `Cache value total size: ${value.length} bytes`,
155
+ `First 500KB of cache value:\n\n${value.subarray(0, 1024 * 500).toString()}`,
156
+ ].join('\n---\n'),
157
+ },
158
+ ],
159
+ };
160
+ });
161
+ return server;
162
+ }
163
+ class InspectorMCP {
164
+ constructor() {
165
+ this.sessions = new Map();
166
+ }
167
+ getSession(request) {
168
+ const sessionId = request.headers['mcp-session-id'];
169
+ if (!sessionId) {
170
+ return undefined;
171
+ }
172
+ return this.sessions.get(sessionId);
173
+ }
174
+ async get(request, response) {
175
+ const session = this.getSession(request);
176
+ if (!session) {
177
+ response.status(400).send('Invalid or missing session ID');
178
+ return;
179
+ }
180
+ await session.transport.handleRequest(request, response);
181
+ }
182
+ async post(request, response) {
183
+ const sessionId = request.headers['mcp-session-id'];
184
+ let transport;
185
+ if (sessionId && this.sessions.has(sessionId)) {
186
+ transport = this.sessions.get(sessionId).transport;
187
+ }
188
+ else if (!sessionId && (0, types_js_1.isInitializeRequest)(request.body)) {
189
+ transport = await this.createSession(response);
190
+ }
191
+ else {
192
+ response.status(400).json({
193
+ jsonrpc: '2.0',
194
+ error: {
195
+ code: -32000,
196
+ message: 'Bad Request: No valid session ID provided',
197
+ },
198
+ id: null,
199
+ });
200
+ return;
201
+ }
202
+ await transport.handleRequest(request, response, request.body);
203
+ }
204
+ async createSession(response) {
205
+ const cache = (0, cacheDataMiddleware_1.getCache)(response);
206
+ const bundleGraph = (0, cacheDataMiddleware_1.getBundleGraph)(response);
207
+ const treemap = (0, cacheDataMiddleware_1.getTreemap)(response);
208
+ const server = makeInspectorMCPServer({
209
+ cache,
210
+ bundleGraph,
211
+ treemap,
212
+ });
213
+ const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
214
+ sessionIdGenerator: () => (0, crypto_1.randomUUID)(),
215
+ onsessioninitialized: (sessionId) => {
216
+ this.sessions.set(sessionId, {
217
+ transport,
218
+ server,
219
+ });
220
+ },
221
+ });
222
+ transport.onclose = () => {
223
+ if (transport.sessionId) {
224
+ this.sessions.delete(transport.sessionId);
225
+ }
226
+ };
227
+ await server.connect(transport);
228
+ return transport;
229
+ }
230
+ }
231
+ exports.InspectorMCP = InspectorMCP;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeInspectorMCPController = makeInspectorMCPController;
4
+ const express_1 = require("express");
5
+ const InspectorMCP_1 = require("./InspectorMCP");
6
+ function makeInspectorMCPController() {
7
+ const router = (0, express_1.Router)();
8
+ const mcp = new InspectorMCP_1.InspectorMCP();
9
+ router.post('/api/mcp', (req, res) => {
10
+ mcp.post(req, res);
11
+ });
12
+ router.get('/api/mcp', (req, res) => {
13
+ mcp.get(req, res);
14
+ });
15
+ return router;
16
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HTTPError = void 0;
4
+ /**
5
+ * A custom error class for HTTP errors.
6
+ *
7
+ * The {@link errorHandlingMiddleware} will automatically set HTTP response
8
+ * status codes for instances of this class.
9
+ */
10
+ class HTTPError extends Error {
11
+ constructor(message, status) {
12
+ super(message);
13
+ this.status = status;
14
+ }
15
+ }
16
+ exports.HTTPError = HTTPError;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const assert_1 = __importDefault(require("assert"));
7
+ const HTTPError_1 = require("./HTTPError");
8
+ describe('HTTPError', function () {
9
+ it('should create HTTPError with message and status', function () {
10
+ const error = new HTTPError_1.HTTPError('Not found', 404);
11
+ assert_1.default.equal(error.message, 'Not found');
12
+ assert_1.default.equal(error.status, 404);
13
+ (0, assert_1.default)(error instanceof Error);
14
+ (0, assert_1.default)(error instanceof HTTPError_1.HTTPError);
15
+ });
16
+ it('should be throwable', function () {
17
+ assert_1.default.throws(() => {
18
+ throw new HTTPError_1.HTTPError('Server error', 500);
19
+ }, HTTPError_1.HTTPError);
20
+ });
21
+ });