@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,177 @@
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.configureInspectorApp = configureInspectorApp;
7
+ exports.buildInspectorApp = buildInspectorApp;
8
+ exports.main = main;
9
+ /* eslint-disable import/first */
10
+ // Stateful import to ensure serializers are loaded
11
+ require('@atlaspack/core');
12
+ const commander_1 = require("commander");
13
+ const express_1 = __importDefault(require("express"));
14
+ const cors_1 = __importDefault(require("cors"));
15
+ const path_1 = __importDefault(require("path"));
16
+ const feature_flags_1 = require("@atlaspack/feature-flags");
17
+ const loadCacheData_1 = require("./services/loadCacheData");
18
+ const logger_1 = require("./config/logger");
19
+ const errorHandlingMiddleware_1 = require("./config/middleware/errorHandlingMiddleware");
20
+ const loggingMiddleware_1 = require("./config/middleware/loggingMiddleware");
21
+ const FrontendAssetsController_1 = require("./controllers/FrontendAssetsController");
22
+ const cacheDataMiddleware_1 = require("./config/middleware/cacheDataMiddleware");
23
+ const BundleGraphController_1 = require("./controllers/BundleGraphController");
24
+ const TreeMapController_1 = require("./controllers/TreeMapController");
25
+ const CacheDataController_1 = require("./controllers/CacheDataController");
26
+ const findSourceCodeUrl_1 = require("./services/findSourceCodeUrl");
27
+ const InspectorMCPController_1 = require("./controllers/mcp/InspectorMCPController");
28
+ const child_process_1 = require("child_process");
29
+ const AnalyticsService_1 = require("./services/AnalyticsService");
30
+ /**
31
+ * Configures the inspector app.
32
+ *
33
+ * - Find paths for the source repository, project and cache.
34
+ * - Open the cache and deserialize bundler data out of it.
35
+ * - Build the tree-map model.
36
+ */
37
+ function configureInspectorApp({ projectRoot: projectRootFromFlags, target, }) {
38
+ const flags = {
39
+ ...feature_flags_1.DEFAULT_FEATURE_FLAGS,
40
+ cachePerformanceImprovements: true,
41
+ };
42
+ (0, feature_flags_1.setFeatureFlags)(flags);
43
+ const projectRoot = projectRootFromFlags ?? (0, findSourceCodeUrl_1.findProjectRoot)(target) ?? path_1.default.dirname(target);
44
+ const repositoryRoot = (0, findSourceCodeUrl_1.findRepositoryRoot)(target) ?? path_1.default.dirname(target);
45
+ const sourceCodeURL = (0, findSourceCodeUrl_1.findSourceCodeURL)(target);
46
+ logger_1.logger.debug({ target, projectRoot, repositoryRoot, sourceCodeURL }, 'Found paths');
47
+ const cacheData = (0, loadCacheData_1.loadCacheData)({ target, projectRoot, repositoryRoot });
48
+ return {
49
+ cacheData,
50
+ projectRoot,
51
+ repositoryRoot,
52
+ sourceCodeURL,
53
+ };
54
+ }
55
+ /**
56
+ * Wire-up the express server app.
57
+ */
58
+ function buildInspectorApp({ cacheData, projectRoot, repositoryRoot, sourceCodeURL, }) {
59
+ const app = (0, express_1.default)();
60
+ app.use((0, loggingMiddleware_1.loggingMiddleware)());
61
+ app.use((0, cors_1.default)({
62
+ origin: /http:\/\/localhost:(\d+)/,
63
+ credentials: true,
64
+ }));
65
+ app.use(express_1.default.json());
66
+ app.use((0, cacheDataMiddleware_1.cacheDataMiddleware)(cacheData));
67
+ app.use((0, FrontendAssetsController_1.makeFrontendAssetsController)());
68
+ app.use((0, BundleGraphController_1.makeBundleGraphController)({ projectRoot, repositoryRoot }));
69
+ app.use((0, TreeMapController_1.makeTreemapController)({
70
+ projectRoot,
71
+ repositoryRoot,
72
+ sourceCodeURL,
73
+ }));
74
+ app.use((0, InspectorMCPController_1.makeInspectorMCPController)());
75
+ app.use((0, CacheDataController_1.makeCacheDataController)());
76
+ app.use(errorHandlingMiddleware_1.errorHandlingMiddleware);
77
+ return app;
78
+ }
79
+ /**
80
+ * Executes `atlaspack build` to build the client application for the inspector.
81
+ *
82
+ * The inspector requires `cachePerformanceImprovements` to be enabled.
83
+ *
84
+ * @param targets - The targets/entry-points to build.
85
+ */
86
+ async function buildClientApplicationForInspector(targets) {
87
+ logger_1.logger.info({ targets }, 'Building app...');
88
+ const child = (0, child_process_1.spawn)('yarn', [
89
+ 'atlaspack',
90
+ 'build',
91
+ '--feature-flag',
92
+ 'cachePerformanceImprovements=true',
93
+ ...targets,
94
+ ], {
95
+ shell: true,
96
+ stdio: 'inherit',
97
+ });
98
+ await new Promise((resolve, reject) => {
99
+ child.on('error', (error) => {
100
+ logger_1.logger.error(error, 'Build error');
101
+ process.exitCode = 1;
102
+ reject(error);
103
+ });
104
+ child.on('exit', (code) => {
105
+ logger_1.logger.info(`Build process exited with code ${code}`);
106
+ if (code !== 0) {
107
+ process.exitCode = code ?? 1;
108
+ reject(new Error(`Build failed with code ${code}`));
109
+ }
110
+ else {
111
+ resolve(null);
112
+ }
113
+ });
114
+ });
115
+ }
116
+ /**
117
+ * CLI entry point for `@atlaspack/inspector`.
118
+ *
119
+ * Usage:
120
+ *
121
+ * ```bash
122
+ * yarn @atlaspack/inspector --target ./path/to/cache --project-root ./path/to/project
123
+ * ```
124
+ */
125
+ function main() {
126
+ const version = require('../../package.json').version;
127
+ let isStartCommand = false;
128
+ commander_1.program.name('atlaspack-inspector').version(version);
129
+ AnalyticsService_1.analyticsService.sendEvent({
130
+ data: {
131
+ name: 'atlaspack-inspector-start',
132
+ action: 'atlaspack-inspector-start',
133
+ },
134
+ });
135
+ const command = commander_1.program
136
+ .command('start [options]', { isDefault: true })
137
+ .description('Start the inspector server')
138
+ .option('-t, --target <path>', 'Path to the target cache', process.cwd())
139
+ .option('-p, --port <port>', 'Port to run the server on', '3000')
140
+ .option('--project-root <path>', 'Path to the project root', undefined)
141
+ .action(() => {
142
+ isStartCommand = true;
143
+ });
144
+ commander_1.program
145
+ .command('build <target...>')
146
+ .description('Build an app with atlaspack-inspector required feature-flags')
147
+ .action(async (targets) => {
148
+ await buildClientApplicationForInspector(targets);
149
+ });
150
+ commander_1.program.parse(process.argv);
151
+ if (!isStartCommand) {
152
+ return;
153
+ }
154
+ const options = command.opts();
155
+ const inspectorAppParams = configureInspectorApp({
156
+ target: options.target,
157
+ projectRoot: options.projectRoot,
158
+ });
159
+ const app = buildInspectorApp(inspectorAppParams);
160
+ const port = Number(options.port ?? process.env.PORT ?? 3000);
161
+ const server = app.listen(port, () => {
162
+ const address = server.address();
163
+ if (address == null) {
164
+ logger_1.logger.error('Server did not start correctly');
165
+ }
166
+ else {
167
+ const addressString = typeof address === 'string'
168
+ ? address
169
+ : `http://localhost:${address.port}`;
170
+ logger_1.logger.info(`Server is running on ${addressString}`);
171
+ }
172
+ });
173
+ server.on('error', (error) => {
174
+ logger_1.logger.error(error, 'HTTP Server error');
175
+ });
176
+ return server;
177
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyticsService = exports.AnalyticsService = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const logger_1 = require("../config/logger");
6
+ /**
7
+ * Reports analytics events to a daemon server running at port 16621.
8
+ *
9
+ * The application will automatically check if the service is available and will not report
10
+ * anything if it is not.
11
+ */
12
+ class AnalyticsService {
13
+ constructor() {
14
+ this.daemonUrl = 'http://localhost:16621';
15
+ this.isAvailable = null;
16
+ }
17
+ /**
18
+ * Return the analytics service status.
19
+ */
20
+ async checkAvailable() {
21
+ const response = await fetch(`${this.daemonUrl}/version`);
22
+ if (!response.ok) {
23
+ const status = response.status;
24
+ const body = await response.json();
25
+ logger_1.logger.warn({ body, status }, 'Failed to check analytics service availability');
26
+ this.isAvailable = false;
27
+ return { available: false };
28
+ }
29
+ const data = await response.json();
30
+ this.isAvailable = true;
31
+ return {
32
+ available: data.version !== 'unknown',
33
+ name: data.name,
34
+ version: data.version,
35
+ };
36
+ }
37
+ /**
38
+ * Record an analytics event.
39
+ */
40
+ async sendEvent(event) {
41
+ try {
42
+ if (this.isAvailable == null) {
43
+ const available = await this.checkAvailable();
44
+ logger_1.logger.debug(available, `Analytics service is ${available.available ? 'available' : 'not available'}`);
45
+ }
46
+ if (!this.isAvailable) {
47
+ return;
48
+ }
49
+ const body = {
50
+ id: `atlaspack-inspector-${(0, crypto_1.randomUUID)()}`,
51
+ cwd: process.cwd(),
52
+ type: 'DISCRETE_EVENT',
53
+ ...event,
54
+ data: {
55
+ startTimestamp: new Date().toISOString(),
56
+ status: 'success',
57
+ product: 'atlaspack-inspector',
58
+ category: 'atlaspack-internal',
59
+ name: 'atlaspack-inspector',
60
+ ...event.data,
61
+ },
62
+ };
63
+ logger_1.logger.debug({ event: body }, 'Tracking analytics event');
64
+ const response = await fetch(`${this.daemonUrl}/events`, {
65
+ method: 'POST',
66
+ headers: {
67
+ 'Content-Type': 'application/json',
68
+ },
69
+ body: JSON.stringify(body),
70
+ });
71
+ if (!response.ok) {
72
+ const status = response.status;
73
+ const body = await response.json();
74
+ logger_1.logger.warn({ body, status }, 'Failed to send analytics event, skipping');
75
+ return;
76
+ }
77
+ const json = await response.json();
78
+ logger_1.logger.debug({ json }, 'Analytics event sent');
79
+ }
80
+ catch (err) {
81
+ logger_1.logger.warn({ err }, 'Failed to send analytics event');
82
+ }
83
+ }
84
+ }
85
+ exports.AnalyticsService = AnalyticsService;
86
+ exports.analyticsService = new AnalyticsService();
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LazyValue = void 0;
4
+ /**
5
+ * A value that is computed once on read, then cached.
6
+ *
7
+ * @example
8
+ *
9
+ * ```ts
10
+ * const lazyComputation = new LazyValue(() => doExpensiveComputation());
11
+ *
12
+ * const result1 = lazyComputation.get();
13
+ * const result2 = lazyComputation.get();
14
+ *
15
+ * assert(result1 === result2);
16
+ * ```
17
+ */
18
+ class LazyValue {
19
+ constructor(factory) {
20
+ this.factory = factory;
21
+ this.value = null;
22
+ }
23
+ /**
24
+ * Builds the value if it hasn't been built and returns it.
25
+ */
26
+ get() {
27
+ if (this.value == null) {
28
+ this.value = this.factory();
29
+ }
30
+ return this.value;
31
+ }
32
+ }
33
+ exports.LazyValue = LazyValue;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const LazyValue_1 = require("./LazyValue");
4
+ describe('LazyValue', () => {
5
+ it('should return the value by calling the factory function once', () => {
6
+ const mock = jest.fn().mockImplementation(() => 'test');
7
+ const lazyValue = new LazyValue_1.LazyValue(mock);
8
+ expect(lazyValue.get()).toBe('test');
9
+ expect(lazyValue.get()).toBe('test');
10
+ expect(mock).toHaveBeenCalledTimes(1);
11
+ });
12
+ });
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildJsonGraph = buildJsonGraph;
4
+ const graph_1 = require("@atlaspack/graph");
5
+ const getDisplayName_1 = require("./getDisplayName");
6
+ /**
7
+ * Build a simplified representation of a graph for a front-end to render.
8
+ *
9
+ * The graph is simplified by:
10
+ * - being a JSON serialisable object
11
+ * - filtering out unnecessary nodes
12
+ * - limiting the depth of nodes returned from the root
13
+ */
14
+ function buildJsonGraph(graph, rootNodeId, filter = () => true, extra) {
15
+ const depths = new Map();
16
+ const rootNodeIndex = rootNodeId
17
+ ? graph.getNodeIdByContentKey(rootNodeId)
18
+ : graph.rootNodeId;
19
+ // build path from `graph.rootNodeId` node to `rootNodeId`
20
+ let path = null;
21
+ {
22
+ const stack = [];
23
+ const visited = new Set();
24
+ graph.dfs({
25
+ visit: {
26
+ enter(nodeId, context, actions) {
27
+ stack.push(nodeId);
28
+ visited.add(nodeId);
29
+ if (nodeId === rootNodeIndex) {
30
+ actions.stop();
31
+ path = stack.slice();
32
+ }
33
+ },
34
+ exit() {
35
+ stack.pop();
36
+ },
37
+ },
38
+ getChildren: (nodeId) => {
39
+ return graph.getNodeIdsConnectedFrom(nodeId, graph_1.ALL_EDGE_TYPES);
40
+ },
41
+ startNodeId: graph.rootNodeId,
42
+ });
43
+ }
44
+ // Build depths of all nodes in the graph
45
+ {
46
+ const topologicalOrder = [];
47
+ graph.traverse({
48
+ exit(nodeId) {
49
+ topologicalOrder.push(nodeId);
50
+ },
51
+ }, rootNodeIndex, graph_1.ALL_EDGE_TYPES);
52
+ topologicalOrder.reverse();
53
+ for (let i = 0; i < topologicalOrder.length; i++) {
54
+ const nodeId = topologicalOrder[i];
55
+ const currentDepth = depths.get(nodeId) ?? 0;
56
+ const neighbors = graph.getNodeIdsConnectedFrom(nodeId, graph_1.ALL_EDGE_TYPES);
57
+ for (const other of neighbors) {
58
+ const increment = filter(graph.getNode(other)) ? 1 : 0;
59
+ depths.set(other, Math.max(currentDepth + increment, depths.get(other) ?? 0));
60
+ }
61
+ }
62
+ }
63
+ const allNodes = [];
64
+ graph.traverse((nodeId) => {
65
+ allNodes.push(nodeId);
66
+ }, rootNodeIndex, graph_1.ALL_EDGE_TYPES);
67
+ const maxDepth = 100;
68
+ return {
69
+ nodes: allNodes
70
+ .filter((nodeId) => (depths.get(nodeId) ?? 0) < maxDepth)
71
+ .filter((nodeId) => filter(graph.getNode(nodeId)))
72
+ .map((nodeId) => ({
73
+ id: graph.getNode(nodeId).id,
74
+ nodeId,
75
+ path: nodeId === rootNodeIndex
76
+ ? (path?.map((id) => graph.getNode(id).id) ?? null)
77
+ : null,
78
+ displayName: (0, getDisplayName_1.getDisplayName)(graph.getNode(nodeId)),
79
+ level: depths.get(nodeId) ?? 0,
80
+ edges: graph
81
+ .getNodeIdsConnectedFrom(nodeId, graph_1.ALL_EDGE_TYPES)
82
+ .map((nodeId) => graph.getNode(nodeId).id),
83
+ extra: extra ? extra(graph.getNode(nodeId)) : null,
84
+ })),
85
+ };
86
+ }
@@ -0,0 +1,140 @@
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.getWriteBundleRequestsByBundleId = getWriteBundleRequestsByBundleId;
7
+ exports.buildTreemapBundle = buildTreemapBundle;
8
+ exports.findBundleInfo = findBundleInfo;
9
+ exports.buildTreemap = buildTreemap;
10
+ // @ts-expect-error TS2749
11
+ const RequestTracker_js_1 = require("@atlaspack/core/lib/RequestTracker.js");
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const logger_1 = require("../config/logger");
15
+ /**
16
+ * In order to find the sizes of bundles, we look-up write bundle requests for each bundle
17
+ * in this build, then read the sizes of each file from disk.
18
+ */
19
+ function getWriteBundleRequestsByBundleId(requestTracker) {
20
+ const writeBundleRequests = requestTracker.graph.nodes.filter((requestNode) => requestNode &&
21
+ requestNode.type === 1 &&
22
+ requestNode.requestType === RequestTracker_js_1.requestTypes.write_bundle_request);
23
+ return new Map(writeBundleRequests.map((request) => [
24
+ request.result?.bundleId ?? '',
25
+ request,
26
+ ]));
27
+ }
28
+ /**
29
+ * Builds a tree-map model for a bundle graph.
30
+ *
31
+ * The tree-map is a tree structure starting at the bundle and having layers for
32
+ * each asset sub-directory in its asset tree.
33
+ *
34
+ * Asset sizes are calculated from the asset size stats, which should represent
35
+ * sizes post-transformation, but before minification.
36
+ *
37
+ * Bundle sizes are read from the bundle files on disk.
38
+ *
39
+ * The sub-directories are sized to the size of their children.
40
+ */
41
+ function buildTreemapBundle({ writeBundleRequestsByBundleId, node, projectRoot, repositoryRoot, bundleGraph, }) {
42
+ const writeBundleRequest = writeBundleRequestsByBundleId.get(node.id);
43
+ const { size, filePath } = findBundleInfo({
44
+ writeBundleRequest,
45
+ projectRoot,
46
+ repositoryRoot,
47
+ node,
48
+ });
49
+ // this is the directory structure
50
+ const assetTree = {
51
+ id: `${node.id}::/`,
52
+ path: '',
53
+ children: {},
54
+ size: 0,
55
+ };
56
+ const assets = [];
57
+ bundleGraph.traverseAssets(node.value, (asset) => {
58
+ assets.push(asset);
59
+ });
60
+ for (const asset of assets) {
61
+ const filePath = path_1.default.isAbsolute(asset.filePath)
62
+ ? path_1.default.relative(repositoryRoot, asset.filePath)
63
+ : asset.filePath;
64
+ const parts = filePath.split('/');
65
+ const assetSize = asset.stats.size;
66
+ let current = assetTree;
67
+ let currentSubpath = '';
68
+ for (let part of parts) {
69
+ currentSubpath += '/' + part;
70
+ current.size += assetSize;
71
+ current.children[part] = current.children[part] ?? {
72
+ id: `${node.id}::${currentSubpath}`,
73
+ path: currentSubpath,
74
+ children: {},
75
+ size: 0,
76
+ };
77
+ current = current.children[part];
78
+ }
79
+ current.size += assetSize;
80
+ }
81
+ const treemapBundle = {
82
+ id: node.id,
83
+ displayName: node.value.displayName,
84
+ bundle: node,
85
+ size,
86
+ filePath: filePath ?? '',
87
+ assetTree,
88
+ };
89
+ return treemapBundle;
90
+ }
91
+ /**
92
+ * Finds the size and file path of a bundle.
93
+ *
94
+ * If the file path is not absolute, it is made absolute by joining it with the project root.
95
+ *
96
+ * If the file path is not found, the size is 0.
97
+ *
98
+ * If the file path is found but the file cannot be read, an error is logged and the size is 0.
99
+ */
100
+ function findBundleInfo({ writeBundleRequest, projectRoot, repositoryRoot, node, }) {
101
+ let filePath = writeBundleRequest?.result?.filePath
102
+ ? path_1.default.isAbsolute(writeBundleRequest?.result?.filePath)
103
+ ? writeBundleRequest.result.filePath
104
+ : path_1.default.join(projectRoot, writeBundleRequest.result.filePath)
105
+ : null;
106
+ let size = 0;
107
+ try {
108
+ size = filePath ? fs_1.default.statSync(filePath).size : 0;
109
+ }
110
+ catch (e) {
111
+ logger_1.logger.error({ filePath, nodeId: node.id, error: e }, `Error getting size of bundle at ${filePath}`);
112
+ }
113
+ filePath = filePath
114
+ ? path_1.default.isAbsolute(filePath)
115
+ ? path_1.default.relative(repositoryRoot, filePath)
116
+ : filePath
117
+ : null;
118
+ return { size, filePath };
119
+ }
120
+ function buildTreemap({ projectRoot, repositoryRoot, bundleGraph, requestTracker, }) {
121
+ const treemap = {
122
+ bundles: [],
123
+ totalSize: 0,
124
+ };
125
+ const writeBundleRequestsByBundleId = getWriteBundleRequestsByBundleId(requestTracker);
126
+ bundleGraph._graph.nodes.forEach((node) => {
127
+ if (node.type === 'bundle') {
128
+ const treemapBundle = buildTreemapBundle({
129
+ writeBundleRequestsByBundleId,
130
+ node,
131
+ projectRoot,
132
+ repositoryRoot,
133
+ bundleGraph,
134
+ });
135
+ treemap.bundles.push(treemapBundle);
136
+ treemap.totalSize += treemapBundle.size;
137
+ }
138
+ });
139
+ return treemap;
140
+ }