@ogygia/devtools 0.0.0 → 0.11.1

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 (310) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +24 -1
  3. package/dist/client.d.ts +3 -0
  4. package/dist/client.js +24 -0
  5. package/dist/devtools/BoundaryOverlay.svelte +396 -0
  6. package/dist/devtools/BoundaryOverlay.svelte.d.ts +19 -0
  7. package/dist/devtools/Devtools.svelte +663 -0
  8. package/dist/devtools/Devtools.svelte.d.ts +15 -0
  9. package/dist/devtools/HubTab.svelte +206 -0
  10. package/dist/devtools/HubTab.svelte.d.ts +11 -0
  11. package/dist/devtools/HydrationTab.svelte +237 -0
  12. package/dist/devtools/HydrationTab.svelte.d.ts +13 -0
  13. package/dist/devtools/IslandDetail.svelte +615 -0
  14. package/dist/devtools/IslandDetail.svelte.d.ts +15 -0
  15. package/dist/devtools/LedgerTab.svelte +287 -0
  16. package/dist/devtools/LedgerTab.svelte.d.ts +11 -0
  17. package/dist/devtools/LensTab.svelte +290 -0
  18. package/dist/devtools/LensTab.svelte.d.ts +19 -0
  19. package/dist/devtools/NavTab.svelte +229 -0
  20. package/dist/devtools/NavTab.svelte.d.ts +11 -0
  21. package/dist/devtools/PageTab.svelte +1122 -0
  22. package/dist/devtools/PageTab.svelte.d.ts +15 -0
  23. package/dist/devtools/ProfilerTab.svelte +755 -0
  24. package/dist/devtools/ProfilerTab.svelte.d.ts +15 -0
  25. package/dist/devtools/PropsTree.svelte +155 -0
  26. package/dist/devtools/PropsTree.svelte.d.ts +15 -0
  27. package/dist/devtools/SessionTab.svelte +796 -0
  28. package/dist/devtools/SessionTab.svelte.d.ts +11 -0
  29. package/dist/devtools/TimelineTab.svelte +267 -0
  30. package/dist/devtools/TimelineTab.svelte.d.ts +11 -0
  31. package/dist/devtools/WireTab.svelte +149 -0
  32. package/dist/devtools/WireTab.svelte.d.ts +11 -0
  33. package/dist/devtools/bytes.d.ts +70 -0
  34. package/dist/devtools/bytes.js +82 -0
  35. package/dist/devtools/cache-headers.d.ts +20 -0
  36. package/dist/devtools/cache-headers.js +81 -0
  37. package/dist/devtools/highlight.d.ts +7 -0
  38. package/dist/devtools/highlight.js +83 -0
  39. package/dist/devtools/hydration.d.ts +48 -0
  40. package/dist/devtools/hydration.js +93 -0
  41. package/dist/devtools/index.d.ts +3 -0
  42. package/dist/devtools/index.js +3 -0
  43. package/dist/devtools/ledger-dom.d.ts +7 -0
  44. package/dist/devtools/ledger-dom.js +151 -0
  45. package/dist/devtools/leftovers.d.ts +77 -0
  46. package/dist/devtools/leftovers.js +319 -0
  47. package/dist/devtools/names.d.ts +1 -0
  48. package/dist/devtools/names.js +34 -0
  49. package/dist/devtools/page.d.ts +96 -0
  50. package/dist/devtools/page.js +957 -0
  51. package/dist/devtools/profile-anchors.d.ts +22 -0
  52. package/dist/devtools/profile-anchors.js +135 -0
  53. package/dist/devtools/profile-store.d.ts +175 -0
  54. package/dist/devtools/profile-store.js +239 -0
  55. package/dist/devtools/regions.d.ts +77 -0
  56. package/dist/devtools/regions.js +132 -0
  57. package/dist/devtools/session.d.ts +31 -0
  58. package/dist/devtools/session.js +455 -0
  59. package/dist/devtools/since-load.d.ts +50 -0
  60. package/dist/devtools/since-load.js +89 -0
  61. package/dist/devtools/source-lines.d.ts +24 -0
  62. package/dist/devtools/source-lines.js +106 -0
  63. package/dist/devtools/styles.d.ts +52 -0
  64. package/dist/devtools/styles.js +248 -0
  65. package/dist/devtools/testing-engine.d.ts +83 -0
  66. package/dist/devtools/testing-engine.js +220 -0
  67. package/dist/devtools/ui-app.d.ts +5 -0
  68. package/dist/devtools/ui-app.js +69 -0
  69. package/dist/devtools/ui.d.ts +50 -0
  70. package/dist/devtools/ui.js +175 -0
  71. package/dist/profiler/alloc.d.ts +75 -0
  72. package/dist/profiler/alloc.js +76 -0
  73. package/dist/profiler/analyze.d.ts +437 -0
  74. package/dist/profiler/analyze.js +1941 -0
  75. package/dist/profiler/app-path.d.ts +7 -0
  76. package/dist/profiler/app-path.js +26 -0
  77. package/dist/profiler/async-io.d.ts +58 -0
  78. package/dist/profiler/async-io.js +187 -0
  79. package/dist/profiler/beacon-standalone.d.ts +4 -0
  80. package/dist/profiler/beacon-standalone.js +409 -0
  81. package/dist/profiler/browser-findings.d.ts +25 -0
  82. package/dist/profiler/browser-findings.js +260 -0
  83. package/dist/profiler/byte-strip.d.ts +58 -0
  84. package/dist/profiler/byte-strip.js +228 -0
  85. package/dist/profiler/client-files.d.ts +16 -0
  86. package/dist/profiler/client-files.js +60 -0
  87. package/dist/profiler/client-windows.d.ts +49 -0
  88. package/dist/profiler/client-windows.js +95 -0
  89. package/dist/profiler/client.d.ts +40 -0
  90. package/dist/profiler/client.js +82 -0
  91. package/dist/profiler/compare.d.ts +308 -0
  92. package/dist/profiler/compare.js +733 -0
  93. package/dist/profiler/compress.d.ts +10 -0
  94. package/dist/profiler/compress.js +36 -0
  95. package/dist/profiler/contention.d.ts +60 -0
  96. package/dist/profiler/contention.js +86 -0
  97. package/dist/profiler/crypto.d.ts +19 -0
  98. package/dist/profiler/crypto.js +101 -0
  99. package/dist/profiler/doc-diff.d.ts +47 -0
  100. package/dist/profiler/doc-diff.js +214 -0
  101. package/dist/profiler/dom-diff.d.ts +43 -0
  102. package/dist/profiler/dom-diff.js +121 -0
  103. package/dist/profiler/drill.d.ts +89 -0
  104. package/dist/profiler/drill.js +553 -0
  105. package/dist/profiler/embedded-maps.d.ts +37 -0
  106. package/dist/profiler/embedded-maps.js +135 -0
  107. package/dist/profiler/env.d.ts +6 -0
  108. package/dist/profiler/env.js +10 -0
  109. package/dist/profiler/forecast.d.ts +76 -0
  110. package/dist/profiler/forecast.js +225 -0
  111. package/dist/profiler/frames.d.ts +11 -0
  112. package/dist/profiler/frames.js +42 -0
  113. package/dist/profiler/gc.d.ts +144 -0
  114. package/dist/profiler/gc.js +271 -0
  115. package/dist/profiler/hole-slots.d.ts +31 -0
  116. package/dist/profiler/hole-slots.js +90 -0
  117. package/dist/profiler/index.d.ts +288 -0
  118. package/dist/profiler/index.js +4921 -0
  119. package/dist/profiler/insights.d.ts +96 -0
  120. package/dist/profiler/insights.js +239 -0
  121. package/dist/profiler/ledger.d.ts +121 -0
  122. package/dist/profiler/ledger.js +440 -0
  123. package/dist/profiler/lineage.d.ts +81 -0
  124. package/dist/profiler/lineage.js +359 -0
  125. package/dist/profiler/module-map.d.ts +12 -0
  126. package/dist/profiler/module-map.js +94 -0
  127. package/dist/profiler/net.d.ts +169 -0
  128. package/dist/profiler/net.js +586 -0
  129. package/dist/profiler/on-demand.d.ts +11 -0
  130. package/dist/profiler/on-demand.js +15 -0
  131. package/dist/profiler/own-requests.d.ts +9 -0
  132. package/dist/profiler/own-requests.js +17 -0
  133. package/dist/profiler/patterns.d.ts +476 -0
  134. package/dist/profiler/patterns.js +2203 -0
  135. package/dist/profiler/profiler-router.d.ts +245 -0
  136. package/dist/profiler/profiler-router.js +113 -0
  137. package/dist/profiler/refresh-stub.d.ts +2 -0
  138. package/dist/profiler/refresh-stub.js +37 -0
  139. package/dist/profiler/report.d.ts +1404 -0
  140. package/dist/profiler/report.js +2638 -0
  141. package/dist/profiler/river.d.ts +65 -0
  142. package/dist/profiler/river.js +298 -0
  143. package/dist/profiler/route-files.d.ts +22 -0
  144. package/dist/profiler/route-files.js +55 -0
  145. package/dist/profiler/route-imports.d.ts +14 -0
  146. package/dist/profiler/route-imports.js +83 -0
  147. package/dist/profiler/saving.d.ts +22 -0
  148. package/dist/profiler/saving.js +42 -0
  149. package/dist/profiler/score.d.ts +109 -0
  150. package/dist/profiler/score.js +261 -0
  151. package/dist/profiler/session-cookie.d.ts +28 -0
  152. package/dist/profiler/session-cookie.js +45 -0
  153. package/dist/profiler/sink.d.ts +81 -0
  154. package/dist/profiler/sink.js +124 -0
  155. package/dist/profiler/site-fixes.d.ts +25 -0
  156. package/dist/profiler/site-fixes.js +62 -0
  157. package/dist/profiler/source-scan.d.ts +210 -0
  158. package/dist/profiler/source-scan.js +1724 -0
  159. package/dist/profiler/span.d.ts +90 -0
  160. package/dist/profiler/span.js +109 -0
  161. package/dist/profiler/stacks.d.ts +43 -0
  162. package/dist/profiler/stacks.js +107 -0
  163. package/dist/profiler/standalone.d.ts +27 -0
  164. package/dist/profiler/standalone.js +98 -0
  165. package/dist/profiler/steps.d.ts +39 -0
  166. package/dist/profiler/steps.js +74 -0
  167. package/dist/profiler/storage/index.d.ts +87 -0
  168. package/dist/profiler/storage/index.js +76 -0
  169. package/dist/profiler/storage/postgres.d.ts +12 -0
  170. package/dist/profiler/storage/postgres.js +94 -0
  171. package/dist/profiler/storage/redis.d.ts +19 -0
  172. package/dist/profiler/storage/redis.js +148 -0
  173. package/dist/profiler/storage/sqlite.d.ts +2 -0
  174. package/dist/profiler/storage/sqlite.js +85 -0
  175. package/dist/profiler/storage/visits.d.ts +4 -0
  176. package/dist/profiler/storage/visits.js +6 -0
  177. package/dist/profiler/stream-tail.d.ts +26 -0
  178. package/dist/profiler/stream-tail.js +74 -0
  179. package/dist/profiler/timeline.d.ts +279 -0
  180. package/dist/profiler/timeline.js +690 -0
  181. package/dist/profiler/ui/AllocStrip.svelte +146 -0
  182. package/dist/profiler/ui/AllocStrip.svelte.d.ts +17 -0
  183. package/dist/profiler/ui/Awaits.svelte +363 -0
  184. package/dist/profiler/ui/Awaits.svelte.d.ts +16 -0
  185. package/dist/profiler/ui/ByteStrip.svelte +182 -0
  186. package/dist/profiler/ui/ByteStrip.svelte.d.ts +18 -0
  187. package/dist/profiler/ui/Compare.svelte +24 -0
  188. package/dist/profiler/ui/Compare.svelte.d.ts +16 -0
  189. package/dist/profiler/ui/CompareBody.svelte +429 -0
  190. package/dist/profiler/ui/CompareBody.svelte.d.ts +8 -0
  191. package/dist/profiler/ui/ComponentsTable.svelte +265 -0
  192. package/dist/profiler/ui/ComponentsTable.svelte.d.ts +20 -0
  193. package/dist/profiler/ui/Dashboard.svelte +492 -0
  194. package/dist/profiler/ui/Dashboard.svelte.d.ts +31 -0
  195. package/dist/profiler/ui/DataRiver.svelte +206 -0
  196. package/dist/profiler/ui/DataRiver.svelte.d.ts +13 -0
  197. package/dist/profiler/ui/DomTravel.svelte +207 -0
  198. package/dist/profiler/ui/DomTravel.svelte.d.ts +9 -0
  199. package/dist/profiler/ui/DownloadHtml.svelte +52 -0
  200. package/dist/profiler/ui/DownloadHtml.svelte.d.ts +10 -0
  201. package/dist/profiler/ui/Drill.svelte +276 -0
  202. package/dist/profiler/ui/Drill.svelte.d.ts +12 -0
  203. package/dist/profiler/ui/ExportButton.svelte +59 -0
  204. package/dist/profiler/ui/ExportButton.svelte.d.ts +8 -0
  205. package/dist/profiler/ui/Flame.svelte +222 -0
  206. package/dist/profiler/ui/Flame.svelte.d.ts +12 -0
  207. package/dist/profiler/ui/FrameDetails.svelte +308 -0
  208. package/dist/profiler/ui/FrameDetails.svelte.d.ts +16 -0
  209. package/dist/profiler/ui/FunctionsTable.svelte +156 -0
  210. package/dist/profiler/ui/FunctionsTable.svelte.d.ts +17 -0
  211. package/dist/profiler/ui/IslandHeatmap.svelte +151 -0
  212. package/dist/profiler/ui/IslandHeatmap.svelte.d.ts +16 -0
  213. package/dist/profiler/ui/IslandsTable.svelte +448 -0
  214. package/dist/profiler/ui/IslandsTable.svelte.d.ts +16 -0
  215. package/dist/profiler/ui/KeepLocal.svelte +46 -0
  216. package/dist/profiler/ui/KeepLocal.svelte.d.ts +8 -0
  217. package/dist/profiler/ui/Ledger.svelte +196 -0
  218. package/dist/profiler/ui/Ledger.svelte.d.ts +18 -0
  219. package/dist/profiler/ui/LocalCompare.svelte +48 -0
  220. package/dist/profiler/ui/LocalCompare.svelte.d.ts +8 -0
  221. package/dist/profiler/ui/LocalReports.svelte +68 -0
  222. package/dist/profiler/ui/LocalReports.svelte.d.ts +7 -0
  223. package/dist/profiler/ui/Login.svelte +13 -0
  224. package/dist/profiler/ui/Login.svelte.d.ts +12 -0
  225. package/dist/profiler/ui/LoginForm.svelte +42 -0
  226. package/dist/profiler/ui/LoginForm.svelte.d.ts +7 -0
  227. package/dist/profiler/ui/Message.svelte +10 -0
  228. package/dist/profiler/ui/Message.svelte.d.ts +12 -0
  229. package/dist/profiler/ui/OnThisPage.svelte +137 -0
  230. package/dist/profiler/ui/OnThisPage.svelte.d.ts +3 -0
  231. package/dist/profiler/ui/OneClock.svelte +297 -0
  232. package/dist/profiler/ui/OneClock.svelte.d.ts +27 -0
  233. package/dist/profiler/ui/Panel.svelte +10 -0
  234. package/dist/profiler/ui/Panel.svelte.d.ts +16 -0
  235. package/dist/profiler/ui/Paths.svelte +269 -0
  236. package/dist/profiler/ui/Paths.svelte.d.ts +15 -0
  237. package/dist/profiler/ui/Patterns.svelte +364 -0
  238. package/dist/profiler/ui/Patterns.svelte.d.ts +15 -0
  239. package/dist/profiler/ui/PermalinkGate.svelte +143 -0
  240. package/dist/profiler/ui/PermalinkGate.svelte.d.ts +10 -0
  241. package/dist/profiler/ui/RenderSteps.svelte +218 -0
  242. package/dist/profiler/ui/RenderSteps.svelte.d.ts +13 -0
  243. package/dist/profiler/ui/Report.svelte +28 -0
  244. package/dist/profiler/ui/Report.svelte.d.ts +20 -0
  245. package/dist/profiler/ui/ReportBody.svelte +2592 -0
  246. package/dist/profiler/ui/ReportBody.svelte.d.ts +21 -0
  247. package/dist/profiler/ui/Run.svelte +17 -0
  248. package/dist/profiler/ui/Run.svelte.d.ts +14 -0
  249. package/dist/profiler/ui/RunView.svelte +146 -0
  250. package/dist/profiler/ui/RunView.svelte.d.ts +10 -0
  251. package/dist/profiler/ui/ScoreCard.svelte +197 -0
  252. package/dist/profiler/ui/ScoreCard.svelte.d.ts +7 -0
  253. package/dist/profiler/ui/Scrub.svelte +293 -0
  254. package/dist/profiler/ui/Scrub.svelte.d.ts +18 -0
  255. package/dist/profiler/ui/SeedExplainer.svelte +193 -0
  256. package/dist/profiler/ui/SeedExplainer.svelte.d.ts +16 -0
  257. package/dist/profiler/ui/ShareLink.svelte +148 -0
  258. package/dist/profiler/ui/ShareLink.svelte.d.ts +8 -0
  259. package/dist/profiler/ui/Shell.svelte +50 -0
  260. package/dist/profiler/ui/Shell.svelte.d.ts +27 -0
  261. package/dist/profiler/ui/Sidebar.svelte +312 -0
  262. package/dist/profiler/ui/Sidebar.svelte.d.ts +7 -0
  263. package/dist/profiler/ui/Site.svelte +20 -0
  264. package/dist/profiler/ui/Site.svelte.d.ts +23 -0
  265. package/dist/profiler/ui/SiteView.svelte +385 -0
  266. package/dist/profiler/ui/SiteView.svelte.d.ts +27 -0
  267. package/dist/profiler/ui/ThemeSwitch.svelte +78 -0
  268. package/dist/profiler/ui/ThemeSwitch.svelte.d.ts +3 -0
  269. package/dist/profiler/ui/Timeline.svelte +672 -0
  270. package/dist/profiler/ui/Timeline.svelte.d.ts +22 -0
  271. package/dist/profiler/ui/Treemap.svelte +278 -0
  272. package/dist/profiler/ui/Treemap.svelte.d.ts +20 -0
  273. package/dist/profiler/ui/Upload.svelte +19 -0
  274. package/dist/profiler/ui/Upload.svelte.d.ts +10 -0
  275. package/dist/profiler/ui/UploadForm.svelte +59 -0
  276. package/dist/profiler/ui/UploadForm.svelte.d.ts +6 -0
  277. package/dist/profiler/ui/WaitingTable.svelte +55 -0
  278. package/dist/profiler/ui/WaitingTable.svelte.d.ts +14 -0
  279. package/dist/profiler/ui/Waterfall.svelte +371 -0
  280. package/dist/profiler/ui/Waterfall.svelte.d.ts +7 -0
  281. package/dist/profiler/ui/WhatIf.svelte +87 -0
  282. package/dist/profiler/ui/WhatIf.svelte.d.ts +18 -0
  283. package/dist/profiler/ui/fake-progress.svelte.d.ts +15 -0
  284. package/dist/profiler/ui/fake-progress.svelte.js +38 -0
  285. package/dist/profiler/ui/format.d.ts +20 -0
  286. package/dist/profiler/ui/format.js +71 -0
  287. package/dist/profiler/ui/permalink.d.ts +9 -0
  288. package/dist/profiler/ui/permalink.js +108 -0
  289. package/dist/profiler/ui/press.d.ts +5 -0
  290. package/dist/profiler/ui/press.js +19 -0
  291. package/dist/profiler/ui/profiler.css +650 -0
  292. package/dist/profiler/ui/report-data.d.ts +189 -0
  293. package/dist/profiler/ui/report-data.js +393 -0
  294. package/dist/profiler/ui/report-request.d.ts +6 -0
  295. package/dist/profiler/ui/report-request.js +50 -0
  296. package/dist/profiler/ui/row-anchor.svelte.d.ts +12 -0
  297. package/dist/profiler/ui/row-anchor.svelte.js +44 -0
  298. package/dist/profiler/ui/sort.svelte.d.ts +14 -0
  299. package/dist/profiler/ui/sort.svelte.js +37 -0
  300. package/dist/profiler/ui/store.d.ts +45 -0
  301. package/dist/profiler/ui/store.js +92 -0
  302. package/dist/profiler/visit.d.ts +389 -0
  303. package/dist/profiler/visit.js +1002 -0
  304. package/dist/report.d.ts +5 -0
  305. package/dist/report.js +4 -0
  306. package/dist/server.d.ts +11 -0
  307. package/dist/server.js +38 -0
  308. package/dist/vite.d.ts +12 -0
  309. package/dist/vite.js +78 -0
  310. package/package.json +99 -6
@@ -0,0 +1,672 @@
1
+ <script>/**
2
+ * THE CRITICAL PATH of one render (timeline.ts), a `wake:'load'` island: a bar of the request's
3
+ * window, coalesced so it reads (a run of small slivers is one block named after what dominated
4
+ * it), with a real hover tooltip and click-to-step; the phase split; then the numbered steps
5
+ * that set the wall time, with the "awaits in a row" callouts. Solid = CPU, coloured by owner;
6
+ * striped = waiting; dark = nothing recorded.
7
+ */
8
+ import { chain_steps, coalesce, PHASE_LABEL } from "../timeline.js";
9
+ import { fmt_ms, CATEGORY_COLOR, CATEGORY_LABEL, ink_on } from "./format.js";
10
+ let { t, gc = [] } = $props();
11
+ const gc_in = $derived(gc.filter((p) => p.t >= 0 && p.t <= t.window_ms));
12
+ const WAIT = "#5b8fd6";
13
+ const IO = "#d9a03d";
14
+ const GAP = "#2a2f38";
15
+ const is_http = (s) => !!s.calls?.some((c) => /^[A-Z]+ /.test(c.label));
16
+ const fill = (s) => s.kind === "cpu" ? CATEGORY_COLOR[s.category] || "#6b7280" : s.kind === "wait" ? `repeating-linear-gradient(135deg, ${is_http(s) ? WAIT : IO} 0 4px, #0d1014 4px 6px)` : GAP;
17
+ const dot = (s) => s.kind === "cpu" ? CATEGORY_COLOR[s.category] || "#6b7280" : s.kind === "wait" ? is_http(s) ? WAIT : IO : GAP;
18
+ const view = $derived(coalesce(t));
19
+ const steps = $derived(chain_steps(t));
20
+ const step_index = $derived(new Map(steps.map((s) => [s.i, s])));
21
+ const phase_total = $derived(t.phases.reduce((s, p) => s + p.cpu_ms + p.wait_ms, 0) || 1);
22
+ const saves = $derived(t.parallelizable.filter((g) => g.save_ms >= 1));
23
+ // a save callout sits on the first block of its group (`at` indexes the same coalesced view);
24
+ // a chain of calls each too small to be a step (an N+1 loop) gets its callout after the list
25
+ const save_at = $derived.by(() => {
26
+ const m = new Map();
27
+ for (const g of saves) if (step_index.has(g.at[0]) && !m.has(g.at[0])) m.set(g.at[0], g);
28
+ return m;
29
+ });
30
+ const orphan_saves = $derived(saves.filter((g) => !step_index.has(g.at[0]) && g.save_ms >= Math.max(2, t.window_ms * .02)));
31
+ const chain_label = (calls) => calls.length <= 4 ? calls.join(" → ") : `${calls[0]} → ${calls[1]} → … → ${calls[calls.length - 1]} (${calls.length} calls)`;
32
+ let tip = $state(null);
33
+ let picked = $state(null);
34
+ const pct = (s) => (s.t1 - s.t0) / t.window_ms * 100;
35
+ function pick(i) {
36
+ picked = i;
37
+ const step = step_index.get(i);
38
+ if (step) document.getElementById(`tl-step-${i}`)?.scrollIntoView({
39
+ block: "center",
40
+ behavior: "smooth"
41
+ });
42
+ }
43
+ </script>
44
+
45
+ <div class="legend">
46
+ <span><i style="background:{CATEGORY_COLOR.component}"></i> component</span>
47
+ <span><i style="background:{CATEGORY_COLOR.app}"></i> your code</span>
48
+ <span><i style="background:{CATEGORY_COLOR.dependency}"></i> dependency</span>
49
+ <span><i style="background:{CATEGORY_COLOR.svelte}"></i> svelte</span>
50
+ <span><i style="background:{CATEGORY_COLOR.node}"></i> node</span>
51
+ <span><i class="stripe" style="--c:{WAIT}"></i> waiting on a call</span>
52
+ <span><i class="stripe" style="--c:{IO}"></i> waiting on a timer / file / socket</span>
53
+ <span><i style="background:{GAP}"></i> nothing recorded</span>
54
+ <span class="hint"
55
+ >solid = the CPU was running that · striped = the server was waiting · hover a block, click it
56
+ to jump to its step</span
57
+ >
58
+ </div>
59
+
60
+ <!-- a group: its segments are buttons (an image cannot hold buttons), each named for a reader -->
61
+ <div
62
+ class="bar"
63
+ role="group"
64
+ aria-label="the render, start to end"
65
+ onmouseleave={() => (tip = null)}
66
+ >
67
+ {#each view as s, i (i)}
68
+ <button
69
+ type="button"
70
+ class="seg {s.kind}"
71
+ class:picked={picked === i}
72
+ style="width:{Math.max(pct(s), 0.2)}%;background:{fill(s)}"
73
+ onmouseenter={(e) => (tip = { i, x: e.clientX, y: e.clientY })}
74
+ onmousemove={(e) => (tip = { i, x: e.clientX, y: e.clientY })}
75
+ onclick={() => pick(i)}
76
+ onfocus={(e) => {
77
+ // the keyboard gets the hover's detail, under the block
78
+ const r = e.currentTarget.getBoundingClientRect();
79
+ tip = { i, x: r.left, y: r.bottom };
80
+ }}
81
+ onblur={() => (tip = null)}
82
+ aria-label="{s.kind === 'wait' ? 'wait: ' : ''}{s.label}"
83
+ >
84
+ {#if pct(s) > 5}<span style="color:{ink_on(dot(s))}"
85
+ >{s.kind === 'wait' ? 'wait: ' : ''}{s.label}</span
86
+ >{/if}
87
+ </button>
88
+ {/each}
89
+ </div>
90
+ {#if gc_in.length}
91
+ <div class="gc-row" role="img" aria-label="GC pauses in this render">
92
+ {#each gc_in as p, i (i)}
93
+ <i
94
+ class="gc-tick {p.kind}"
95
+ style="left:{(p.t / t.window_ms) * 100}%;width:{Math.max(
96
+ (p.ms / t.window_ms) * 100,
97
+ 0.25
98
+ )}%"
99
+ title="GC {p.kind} · {fmt_ms(p.ms)} ms at {fmt_ms(p.t)} ms — {p.why}{p.top
100
+ ? `. Mostly: ${p.top}`
101
+ : ''}"
102
+ ></i>
103
+ {/each}
104
+ <span class="gc-label hint"
105
+ >GC pauses ({gc_in.length}) — hover one for what filled the heap before it</span
106
+ >
107
+ </div>
108
+ {/if}
109
+ <div class="axis">
110
+ <span>0 ms</span><span>{fmt_ms(t.window_ms / 2)} ms</span><span>{fmt_ms(t.window_ms)} ms</span>
111
+ </div>
112
+ {#if tip}
113
+ {@const s = view[tip.i]}
114
+ <div
115
+ class="tip"
116
+ style="left:{Math.min(
117
+ tip.x + 14,
118
+ (typeof window !== 'undefined' ? window.innerWidth : 1200) - 380
119
+ )}px;top:{tip.y + 16}px"
120
+ >
121
+ <div class="tip-h">
122
+ <i style="background:{dot(s)}"></i>
123
+ <b>{fmt_ms(s.t1 - s.t0)} ms</b> · {pct(s).toFixed(1)}% · from {fmt_ms(s.t0)} to {fmt_ms(s.t1)} ms
124
+ </div>
125
+ {#if s.within}<div class="dim">inside span <b>{s.within}</b></div>{/if}
126
+ {#if s.kind === 'cpu'}
127
+ <div>
128
+ on the CPU: <b>{s.label}</b>{#if s.detail}
129
+ — mostly {s.detail}{/if}
130
+ </div>
131
+ {#if s.file}<div class="mono">{s.file}</div>{/if}
132
+ <div class="dim">{CATEGORY_LABEL[s.category]} · {PHASE_LABEL[s.phase]}</div>
133
+ {:else if s.kind === 'wait'}
134
+ <div>
135
+ waiting on {s.calls && s.calls.length > 1 ? `${s.calls.length} calls at once` : 'one call'} ·
136
+ {PHASE_LABEL[s.phase]}
137
+ </div>
138
+ {#each (s.calls ?? []).slice(0, 8) as c, i (c.label + '\0' + i)}
139
+ <div class="mono">
140
+ {c.label}
141
+ <span class="dim">{fmt_ms(c.ms)} ms{c.caller ? ` · from ${c.caller}` : ''}</span>
142
+ </div>
143
+ {#if c.callers && c.callers.length > 1}
144
+ <div class="mono dim">call path: {c.callers.join(' ← ')}</div>
145
+ {/if}
146
+ {#if c.timings?.length}
147
+ <div class="mono dim">
148
+ their side: {c.timings.map((t) => `${t.desc ?? t.name} ${fmt_ms(t.ms)} ms`).join(' · ')}
149
+ </div>
150
+ {/if}
151
+ {/each}
152
+ {:else}
153
+ <div>nothing recorded — a promise chain, a driver on its own socket, a worker</div>
154
+ {#if s.pending?.length}
155
+ <div class="dim">pending across it:</div>
156
+ {#each s.pending as p (p)}<div class="mono dim">{p}</div>{/each}
157
+ {/if}
158
+ {/if}
159
+ {#if s.inside && s.inside.length > 1}
160
+ <div class="dim" style="margin-top:4px">{s.parts} small pieces folded in:</div>
161
+ {#each s.inside.slice(0, 6) as p (p.kind + p.label)}
162
+ <div class="mono dim">{p.kind === 'wait' ? 'wait ' : ''}{p.label} {fmt_ms(p.ms)} ms</div>
163
+ {/each}
164
+ {/if}
165
+ </div>
166
+ {/if}
167
+ <p class="hint totals">
168
+ <b>{fmt_ms(t.window_ms)} ms</b> wall · {fmt_ms(t.cpu_ms)} ms on the CPU · {fmt_ms(t.wait_ms)} ms waiting
169
+ on calls
170
+ {#if t.gap_ms >= 0.5}· {fmt_ms(t.gap_ms)} ms unaccounted{/if}
171
+ </p>
172
+
173
+ {#if t.lanes?.length}
174
+ <h3>
175
+ Load functions <span class="hint"
176
+ >each lane is one Kit load: when it ran, on this render's clock</span
177
+ >
178
+ </h3>
179
+ <div class="lanes">
180
+ {#each t.lanes as l (l.file)}
181
+ <div
182
+ class="lane"
183
+ class:chained={t.chain && (t.chain.page === l.file || t.chain.layout === l.file)}
184
+ >
185
+ <span class="lname" title={l.file}>
186
+ <code>{l.file.replace(/^routes\//, '')}</code>
187
+ <span class="kind" class:universal={l.kind === 'universal'}>{l.kind}</span>
188
+ {#if l.awaited_parent}<span class="kind parent" title="Kit's parent() ran under this load"
189
+ >await parent()</span
190
+ >{/if}
191
+ </span>
192
+ <div class="ltrack" title="from {fmt_ms(l.t0)} to {fmt_ms(l.t1)} ms">
193
+ <div
194
+ class="lbar"
195
+ style="left:{(l.t0 / t.window_ms) * 100}%;width:{Math.max(
196
+ 0.4,
197
+ ((l.t1 - l.t0) / t.window_ms) * 100
198
+ )}%"
199
+ >
200
+ <div
201
+ class="lcpu"
202
+ style="width:{l.t1 > l.t0 ? Math.min(100, (l.cpu_ms / (l.t1 - l.t0)) * 100) : 0}%"
203
+ ></div>
204
+ </div>
205
+ </div>
206
+ <span class="num"
207
+ >{fmt_ms(l.t0)}–{fmt_ms(l.t1)} ms
208
+ <span class="hint"
209
+ >· {fmt_ms(l.cpu_ms)} ms CPU{l.wait_ms >= 0.5
210
+ ? ` + ${fmt_ms(l.wait_ms)} ms waiting`
211
+ : ''}</span
212
+ ></span
213
+ >
214
+ </div>
215
+ {/each}
216
+ </div>
217
+ {#if t.chain}
218
+ <div class="save chain">
219
+ <b>{t.chain.page.replace(/^routes\//, '')}</b> started only after
220
+ <b>{t.chain.layout.replace(/^routes\//, '')}</b>
221
+ finished, {fmt_ms(t.chain.serial_ms)} ms in
222
+ {#if t.chain.explicit}— it awaits <code>parent()</code>.{:else}— Kit runs a page load and its
223
+ layouts together unless the page awaits <code>parent()</code>.{/if}
224
+ Start the page's own fetches first and await <code>parent()</code> after, and the two overlap:
225
+ <b>up to {fmt_ms(t.chain.serial_ms)} ms back</b>.
226
+ </div>
227
+ {/if}
228
+ {/if}
229
+
230
+ <h3>Phases <span class="hint">where in the request the time sat</span></h3>
231
+ <div class="phases">
232
+ {#each t.phases as p (p.phase)}
233
+ <div class="prow">
234
+ <span class="name">{PHASE_LABEL[p.phase]}</span>
235
+ <div class="track">
236
+ <div
237
+ class="cpu"
238
+ style="width:{(p.cpu_ms / phase_total) * 100}%"
239
+ title="CPU {fmt_ms(p.cpu_ms)} ms"
240
+ ></div>
241
+ <div
242
+ class="wait"
243
+ style="width:{(p.wait_ms / phase_total) * 100}%"
244
+ title="waiting {fmt_ms(p.wait_ms)} ms"
245
+ ></div>
246
+ </div>
247
+ <span class="num"
248
+ >{fmt_ms(p.cpu_ms)} ms CPU{#if p.wait_ms >= 0.5}
249
+ <span class="hint">+ {fmt_ms(p.wait_ms)} ms waiting</span>{/if}</span
250
+ >
251
+ {#if p.top?.length}
252
+ <span class="who hint">{p.top.map((o) => `${o.label} ${fmt_ms(o.ms)} ms`).join(' · ')}</span
253
+ >
254
+ {/if}
255
+ </div>
256
+ {/each}
257
+ </div>
258
+
259
+ <h3>
260
+ The steps that set the time <span class="hint">in order, biggest first is the one to fix</span>
261
+ </h3>
262
+ <ol class="steps">
263
+ {#each steps as s (s.i)}
264
+ {@const g = save_at.get(s.i)}
265
+ <li id="tl-step-{s.i}" class:picked={picked === s.i}>
266
+ <i class="sw" style="background:{dot(s.seg)}"></i>
267
+ <b>{fmt_ms(s.ms)} ms</b>
268
+ <span class="pct">({s.pct.toFixed(0)}%)</span>
269
+ {#if s.seg.kind === 'cpu'}
270
+ <span class="what">CPU: {s.seg.label}</span>
271
+ {#if s.seg.detail}<span class="hint">— mostly {s.seg.detail}</span>{/if}
272
+ {#if s.seg.file}<span class="file">{s.seg.file}</span>{/if}
273
+ {:else if s.seg.kind === 'wait'}
274
+ <span class="what">waiting: {s.seg.label}</span>
275
+ {#if s.seg.calls && s.seg.calls.length > 1}
276
+ <span class="hint"
277
+ >— {s.seg.calls.map((c) => `${c.label} ${fmt_ms(c.ms)} ms`).join(', ')}</span
278
+ >
279
+ {:else if s.seg.calls?.[0]?.caller}
280
+ <span class="hint"
281
+ >— from {s.seg.calls[0].callers && s.seg.calls[0].callers.length > 1
282
+ ? s.seg.calls[0].callers.join(' ← ')
283
+ : s.seg.calls[0].caller}</span
284
+ >
285
+ {/if}
286
+ {#if s.seg.calls?.length === 1 && s.seg.calls[0].timings?.length}
287
+ {@const tm = s.seg.calls[0].timings}
288
+ {@const theirs = tm.reduce((a, t) => a + t.ms, 0)}
289
+ <div class="inside">
290
+ their Server-Timing: {tm
291
+ .map((t) => `${t.desc ?? t.name} ${fmt_ms(t.ms)} ms`)
292
+ .join(' · ')}{#if theirs > 0}
293
+ — <b>{fmt_ms(theirs)} ms on their side</b>, {fmt_ms(Math.max(0, s.ms - theirs))} ms network
294
+ + framework{/if}
295
+ </div>
296
+ {/if}
297
+ {:else}
298
+ <span class="what">nothing recorded</span>
299
+ <span class="hint">— a promise chain, a driver on its own socket pool, a worker</span>
300
+ {/if}
301
+ <span class="pchip">{PHASE_LABEL[s.seg.phase]}</span>
302
+ {#if s.seg.within && !s.seg.label.startsWith('in ')}<span class="pchip span"
303
+ >in {s.seg.within}</span
304
+ >{/if}
305
+ {#if s.seg.inside && s.seg.inside.length > 1}
306
+ <div class="inside">
307
+ {s.seg.parts} pieces: {s.seg.inside
308
+ .slice(0, 5)
309
+ .map((p) => `${p.label} ${fmt_ms(p.ms)} ms`)
310
+ .join(' · ')}{s.seg.inside.length > 5 ? ' · …' : ''}
311
+ </div>
312
+ {/if}
313
+ {#if g}
314
+ <div class="save">
315
+ {g.calls.length} calls ran one after another ({chain_label(g.calls)}): started together
316
+ they would cost
317
+ {fmt_ms(g.ms - g.save_ms)} ms instead of {fmt_ms(g.ms)} —
318
+ <b>save ~{fmt_ms(g.save_ms)} ms</b> if they are independent.
319
+ </div>
320
+ {/if}
321
+ </li>
322
+ {/each}
323
+ </ol>
324
+ {#each orphan_saves as g (g.at[0])}
325
+ <div class="save orphan">
326
+ Between the steps above, {g.calls.length} small calls ran one after another for {fmt_ms(g.ms)} ms
327
+ ({chain_label(g.calls)}): started together they would cost {fmt_ms(g.ms - g.save_ms)} ms —
328
+ <b>save ~{fmt_ms(g.save_ms)} ms</b> if they are independent.
329
+ </div>
330
+ {/each}
331
+
332
+ <style>
333
+ .legend {
334
+ display: flex;
335
+ flex-wrap: wrap;
336
+ gap: 4px 14px;
337
+ margin: 6px 0 4px;
338
+ font-size: 11.5px;
339
+ color: var(--text-dim);
340
+ }
341
+ .legend span {
342
+ display: inline-flex;
343
+ align-items: center;
344
+ gap: 5px;
345
+ }
346
+ .legend i {
347
+ width: 12px;
348
+ height: 12px;
349
+ border-radius: 2px;
350
+ display: inline-block;
351
+ }
352
+ .legend i.stripe {
353
+ background: repeating-linear-gradient(135deg, var(--c) 0 3px, var(--bg-sunken) 3px 5px);
354
+ }
355
+ .legend .hint {
356
+ flex-basis: 100%;
357
+ color: var(--text-faint);
358
+ }
359
+ .bar {
360
+ display: flex;
361
+ height: 34px;
362
+ border-radius: 7px;
363
+ overflow: hidden;
364
+ border: 1px solid var(--line);
365
+ margin: 4px 0 0;
366
+ background: var(--bg-sunken);
367
+ }
368
+ /* no padding or border on a segment: hundreds of thin ones would each keep that much width and
369
+ push the bar past its card (the shell's button padding, border and radius are taken off). The
370
+ divider is a shadow, the inset is on the label. */
371
+ .seg {
372
+ border: 0;
373
+ border-radius: 0;
374
+ padding: 0;
375
+ margin: 0;
376
+ text-align: left;
377
+ min-width: 0;
378
+ overflow: hidden;
379
+ white-space: nowrap;
380
+ font-size: 10.5px;
381
+ font-weight: 600;
382
+ display: flex;
383
+ align-items: center;
384
+ box-shadow: inset -1px 0 0 color-mix(in srgb, var(--bg-sunken) 60%, transparent);
385
+ cursor: pointer;
386
+ color: var(--bg-sunken);
387
+ }
388
+ .seg span {
389
+ text-overflow: ellipsis;
390
+ overflow: hidden;
391
+ padding-left: 4px;
392
+ }
393
+ .seg.wait span {
394
+ color: var(--text);
395
+ background: var(--bg-sunken) aa;
396
+ padding: 0 4px;
397
+ border-radius: 3px;
398
+ }
399
+ .seg.gap {
400
+ color: var(--text-faint);
401
+ font-weight: 400;
402
+ }
403
+ .seg:hover,
404
+ .seg.picked {
405
+ outline: 2px solid var(--text);
406
+ outline-offset: -2px;
407
+ }
408
+ .axis {
409
+ display: flex;
410
+ justify-content: space-between;
411
+ font-size: 10.5px;
412
+ color: var(--text-faint);
413
+ margin: 2px 2px 0;
414
+ }
415
+ .tip {
416
+ position: fixed;
417
+ pointer-events: none;
418
+ background: var(--bg-hover);
419
+ border: 1px solid var(--line);
420
+ border-radius: 6px;
421
+ padding: 7px 10px;
422
+ font-size: 12px;
423
+ max-width: 480px;
424
+ z-index: 10;
425
+ box-shadow: 0 4px 16px #0008;
426
+ line-height: 1.45;
427
+ }
428
+ .tip-h {
429
+ display: flex;
430
+ align-items: center;
431
+ gap: 6px;
432
+ margin-bottom: 3px;
433
+ }
434
+ .tip-h i {
435
+ width: 10px;
436
+ height: 10px;
437
+ border-radius: 2px;
438
+ display: inline-block;
439
+ }
440
+ .mono {
441
+ font-family: ui-monospace, monospace;
442
+ font-size: 11.5px;
443
+ white-space: nowrap;
444
+ overflow: hidden;
445
+ text-overflow: ellipsis;
446
+ }
447
+ .dim {
448
+ color: var(--text-faint);
449
+ }
450
+ .totals {
451
+ margin: 8px 0 10px;
452
+ }
453
+ h3 {
454
+ font-size: 13px;
455
+ color: var(--text);
456
+ margin: 14px 0 4px;
457
+ font-weight: 600;
458
+ }
459
+ h3 .hint {
460
+ font-weight: 400;
461
+ color: var(--text-faint);
462
+ margin-left: 6px;
463
+ }
464
+ .lanes {
465
+ display: grid;
466
+ gap: 4px;
467
+ }
468
+ .lane {
469
+ display: grid;
470
+ grid-template-columns: 300px 1fr 260px;
471
+ gap: 10px;
472
+ align-items: center;
473
+ font-size: 12.5px;
474
+ }
475
+ .lane.chained .lbar {
476
+ outline: 1px solid var(--warn);
477
+ }
478
+ .lname code {
479
+ font-size: 12px;
480
+ }
481
+ .kind {
482
+ display: inline-block;
483
+ margin-left: 6px;
484
+ font-size: 10.5px;
485
+ color: var(--text-faint);
486
+ border: 1px solid var(--line);
487
+ border-radius: 999px;
488
+ padding: 0 6px;
489
+ line-height: 15px;
490
+ }
491
+ .kind.universal {
492
+ color: var(--c-blue);
493
+ border-color: #2a3a5a;
494
+ }
495
+ .kind.parent {
496
+ color: var(--warn);
497
+ border-color: #5a4a20;
498
+ }
499
+ .ltrack {
500
+ position: relative;
501
+ height: 12px;
502
+ background: var(--bg-hover);
503
+ border-radius: 3px;
504
+ overflow: hidden;
505
+ }
506
+ .lbar {
507
+ position: absolute;
508
+ top: 0;
509
+ bottom: 0;
510
+ background: repeating-linear-gradient(135deg, var(--c-blue) 0 4px, var(--bg-sunken) 4px 6px);
511
+ border-radius: 2px;
512
+ }
513
+ .lcpu {
514
+ height: 100%;
515
+ background: #4a9d6e;
516
+ }
517
+ .lane .num {
518
+ font-variant-numeric: tabular-nums;
519
+ color: var(--text-dim);
520
+ white-space: nowrap;
521
+ }
522
+ .save.chain {
523
+ margin-top: 6px;
524
+ }
525
+ .phases {
526
+ display: grid;
527
+ gap: 4px;
528
+ }
529
+ .prow {
530
+ display: grid;
531
+ grid-template-columns: 170px 1fr 220px;
532
+ gap: 10px;
533
+ align-items: center;
534
+ font-size: 12.5px;
535
+ }
536
+ .prow .name {
537
+ color: var(--text);
538
+ }
539
+ .track {
540
+ display: flex;
541
+ height: 12px;
542
+ background: var(--bg-hover);
543
+ border-radius: 3px;
544
+ overflow: hidden;
545
+ }
546
+ .track .cpu {
547
+ background: #4a9d6e;
548
+ }
549
+ .track .wait {
550
+ background: repeating-linear-gradient(135deg, var(--c-blue) 0 4px, var(--bg-sunken) 4px 6px);
551
+ }
552
+ .prow .num {
553
+ font-variant-numeric: tabular-nums;
554
+ color: var(--text-dim);
555
+ }
556
+ /* whose CPU the phase was: under its bar, the full width after the name */
557
+ .prow .who {
558
+ grid-column: 2 / -1;
559
+ margin-top: -3px;
560
+ font-size: 11.5px;
561
+ overflow-wrap: anywhere;
562
+ }
563
+ .steps {
564
+ margin: 4px 0 0;
565
+ padding-left: 22px;
566
+ font-size: 13px;
567
+ line-height: 1.6;
568
+ }
569
+ .steps li {
570
+ margin: 2px 0;
571
+ padding: 2px 6px;
572
+ border-radius: 4px;
573
+ }
574
+ .steps li.picked {
575
+ background: var(--bg-raised);
576
+ }
577
+ .sw {
578
+ display: inline-block;
579
+ width: 10px;
580
+ height: 10px;
581
+ border-radius: 2px;
582
+ vertical-align: -1px;
583
+ margin-right: 3px;
584
+ }
585
+ .steps .what {
586
+ font-family: ui-monospace, monospace;
587
+ font-size: 12.5px;
588
+ }
589
+ .steps .pct,
590
+ .steps .hint,
591
+ .steps .inside {
592
+ color: var(--text-faint);
593
+ }
594
+ .steps .inside {
595
+ font-size: 12px;
596
+ margin-left: 14px;
597
+ }
598
+ .steps .file {
599
+ color: var(--text-faint);
600
+ font-family: ui-monospace, monospace;
601
+ font-size: 11.5px;
602
+ margin-left: 6px;
603
+ }
604
+ .pchip {
605
+ display: inline-block;
606
+ margin-left: 8px;
607
+ font-size: 11px;
608
+ color: var(--text-faint);
609
+ border: 1px solid var(--line);
610
+ border-radius: 999px;
611
+ padding: 0 7px;
612
+ line-height: 16px;
613
+ }
614
+ .pchip.span {
615
+ color: var(--warn);
616
+ border-color: #5a4a20;
617
+ }
618
+ .save.orphan {
619
+ margin-left: 22px;
620
+ }
621
+ .save {
622
+ margin: 4px 0 6px;
623
+ padding: 6px 10px;
624
+ background: var(--bg-raised);
625
+ border-left: 3px solid var(--warn);
626
+ border-radius: 4px;
627
+ font-size: 12.5px;
628
+ }
629
+ /* GC pauses under the bar: a red tick per pause, sized by its length, hover for its cause */
630
+ .gc-row {
631
+ position: relative;
632
+ height: 26px;
633
+ margin-top: 2px;
634
+ }
635
+ .gc-tick {
636
+ position: absolute;
637
+ top: 0;
638
+ height: 8px;
639
+ min-width: 2px;
640
+ background: var(--bad);
641
+ border-radius: 1px;
642
+ cursor: help;
643
+ }
644
+ .gc-tick.major {
645
+ background: #ff4d4d;
646
+ height: 12px;
647
+ }
648
+ .gc-tick.incremental,
649
+ .gc-tick.weak {
650
+ background: var(--warn);
651
+ }
652
+ .gc-label {
653
+ position: absolute;
654
+ left: 0;
655
+ top: 13px;
656
+ font-size: 10px;
657
+ }
658
+ /* a phone: the label, the bar and the numbers of a lane / phase row stack instead of three
659
+ fixed columns wider than the screen */
660
+ @media (max-width: 720px) {
661
+ .lane,
662
+ .prow {
663
+ grid-template-columns: minmax(0, 1fr);
664
+ gap: 2px;
665
+ margin-bottom: 6px;
666
+ }
667
+ .prow .who {
668
+ grid-column: 1 / -1;
669
+ margin-top: 0;
670
+ }
671
+ }
672
+ </style>
@@ -0,0 +1,22 @@
1
+ /**
2
+ * THE CRITICAL PATH of one render (timeline.ts), a `wake:'load'` island: a bar of the request's
3
+ * window, coalesced so it reads (a run of small slivers is one block named after what dominated
4
+ * it), with a real hover tooltip and click-to-step; the phase split; then the numbered steps
5
+ * that set the wall time, with the "awaits in a row" callouts. Solid = CPU, coloured by owner;
6
+ * striped = waiting; dark = nothing recorded.
7
+ */
8
+ import { type Timeline } from '../timeline.js';
9
+ type $$ComponentProps = {
10
+ t: Timeline;
11
+ /** the GC pauses inside this window, on the window's clock, with what caused each */
12
+ gc?: {
13
+ t: number;
14
+ ms: number;
15
+ kind: string;
16
+ why: string;
17
+ top: string;
18
+ }[];
19
+ };
20
+ declare const Timeline: import("svelte").Component<$$ComponentProps, {}, "">;
21
+ type Timeline = ReturnType<typeof Timeline>;
22
+ export default Timeline;