@ogygia/devtools 0.0.0-stage → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -2
  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 +103 -3
@@ -0,0 +1,278 @@
1
+ <script>let { hierarchy } = $props();
2
+ const H = 440;
3
+ let canvas;
4
+ // the zoom stack starts at the root it was given; clicks own it after
5
+ // svelte-ignore state_referenced_locally
6
+ let stack = $state([hierarchy]);
7
+ let resizeTick = $state(0);
8
+ let tip = $state(null);
9
+ let rects = [];
10
+ function squarify(items, x, y, w, h) {
11
+ const out = [];
12
+ let total = 0;
13
+ for (const it of items) total += it.value;
14
+ if (total <= 0 || w <= 0 || h <= 0) return out;
15
+ const scale = w * h / total;
16
+ let rest = items.map((it) => ({
17
+ it,
18
+ area: it.value * scale
19
+ }));
20
+ let rx = x, ry = y, rw = w, rh = h;
21
+ const worst = (row, side) => {
22
+ let sum = 0, mx = 0, mn = Infinity;
23
+ for (const r of row) {
24
+ sum += r.area;
25
+ if (r.area > mx) mx = r.area;
26
+ if (r.area < mn) mn = r.area;
27
+ }
28
+ const s2 = sum * sum;
29
+ return Math.max(side * side * mx / s2, s2 / (side * side * mn));
30
+ };
31
+ while (rest.length) {
32
+ const side = Math.min(rw, rh);
33
+ const row = [];
34
+ let idx = 0;
35
+ while (idx < rest.length) {
36
+ if (row.length === 0 || worst(row.concat([rest[idx]]), side) <= worst(row, side)) {
37
+ row.push(rest[idx]);
38
+ idx++;
39
+ } else break;
40
+ }
41
+ let rowSum = 0;
42
+ for (const r of row) rowSum += r.area;
43
+ if (rw <= rh) {
44
+ const sH = rowSum / rw;
45
+ let cx = rx;
46
+ for (const r of row) {
47
+ const iw = r.area / sH;
48
+ out.push({
49
+ it: r.it,
50
+ x: cx,
51
+ y: ry,
52
+ w: iw,
53
+ h: sH
54
+ });
55
+ cx += iw;
56
+ }
57
+ ry += sH;
58
+ rh -= sH;
59
+ } else {
60
+ const sW = rowSum / rh;
61
+ let cy = ry;
62
+ for (const r of row) {
63
+ const ih = r.area / sW;
64
+ out.push({
65
+ it: r.it,
66
+ x: rx,
67
+ y: cy,
68
+ w: sW,
69
+ h: ih
70
+ });
71
+ cy += ih;
72
+ }
73
+ rx += sW;
74
+ rw -= sW;
75
+ }
76
+ rest = rest.slice(row.length);
77
+ }
78
+ return out;
79
+ }
80
+ function draw() {
81
+ if (!canvas) return;
82
+ const ctx = canvas.getContext("2d");
83
+ const dpr = window.devicePixelRatio || 1;
84
+ const W = canvas.clientWidth || 900;
85
+ canvas.width = W * dpr;
86
+ canvas.height = H * dpr;
87
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
88
+ ctx.clearRect(0, 0, W, H);
89
+ rects = [];
90
+ const box = (x, y, w, h, color, alpha) => {
91
+ ctx.globalAlpha = alpha;
92
+ ctx.fillStyle = color;
93
+ ctx.fillRect(x, y, Math.max(0, w - 1), Math.max(0, h - 1));
94
+ ctx.globalAlpha = 1;
95
+ };
96
+ const label = (x, y, w, txt, sub) => {
97
+ if (w < 46) return;
98
+ ctx.fillStyle = "#0d1014";
99
+ ctx.font = "600 10px ui-monospace,monospace";
100
+ ctx.save();
101
+ ctx.beginPath();
102
+ ctx.rect(x + 2, y, w - 4, 20);
103
+ ctx.clip();
104
+ ctx.fillText(txt, x + 4, y + 11);
105
+ if (sub) {
106
+ ctx.font = "9px ui-monospace,monospace";
107
+ ctx.globalAlpha = .75;
108
+ ctx.fillText(sub, x + 4, y + 21);
109
+ ctx.globalAlpha = 1;
110
+ }
111
+ ctx.restore();
112
+ };
113
+ const cur = stack[stack.length - 1];
114
+ const atRoot = stack.length === 1;
115
+ const cells = squarify(cur.children ?? [], 0, 0, W, H);
116
+ for (const c of cells) {
117
+ const node = c.it;
118
+ if (node.children && atRoot) {
119
+ box(c.x, c.y, c.w, c.h, node.color, .16);
120
+ if (c.w > 60 && c.h > 22) {
121
+ ctx.fillStyle = node.color;
122
+ ctx.font = "700 11px ui-monospace,monospace";
123
+ ctx.save();
124
+ ctx.beginPath();
125
+ ctx.rect(c.x + 2, c.y, c.w - 4, 14);
126
+ ctx.clip();
127
+ ctx.fillText(node.label + " · " + node.value + " ms", c.x + 4, c.y + 11);
128
+ ctx.restore();
129
+ }
130
+ const inner = squarify(node.children, c.x + 2, c.y + 15, Math.max(0, c.w - 4), Math.max(0, c.h - 17));
131
+ for (const ic of inner) {
132
+ const leaf = ic.it;
133
+ const op = .55 + Math.min(.4, (leaf.pct ?? 0) / 40);
134
+ box(ic.x, ic.y, ic.w, ic.h, leaf.color, op);
135
+ if (ic.w > 46 && ic.h > 14) label(ic.x, ic.y, ic.w, leaf.label, ic.h > 26 ? leaf.value + " ms" : "");
136
+ rects.push({
137
+ x: ic.x,
138
+ y: ic.y,
139
+ w: ic.w,
140
+ h: ic.h,
141
+ node: leaf,
142
+ zoom: node
143
+ });
144
+ }
145
+ rects.push({
146
+ x: c.x,
147
+ y: c.y,
148
+ w: c.w,
149
+ h: 15,
150
+ node,
151
+ zoom: node
152
+ });
153
+ } else {
154
+ const op = .55 + Math.min(.4, (node.pct ?? 0) / 40);
155
+ box(c.x, c.y, c.w, c.h, node.color, op);
156
+ if (c.w > 46 && c.h > 16) {
157
+ ctx.fillStyle = "#0d1014";
158
+ ctx.font = "600 11px ui-monospace,monospace";
159
+ ctx.save();
160
+ ctx.beginPath();
161
+ ctx.rect(c.x + 3, c.y, c.w - 6, 30);
162
+ ctx.clip();
163
+ ctx.fillText(node.label, c.x + 4, c.y + 13);
164
+ if (c.h > 28) {
165
+ ctx.font = "9px ui-monospace,monospace";
166
+ ctx.globalAlpha = .8;
167
+ ctx.fillText(node.value + " ms", c.x + 4, c.y + 24);
168
+ ctx.globalAlpha = 1;
169
+ }
170
+ ctx.restore();
171
+ }
172
+ rects.push({
173
+ x: c.x,
174
+ y: c.y,
175
+ w: c.w,
176
+ h: c.h,
177
+ node,
178
+ zoom: node.children ? node : null
179
+ });
180
+ }
181
+ }
182
+ }
183
+ // redraw when the zoom stack changes or the window resizes; the effect reads both so it re-runs.
184
+ $effect(() => {
185
+ void stack;
186
+ void resizeTick;
187
+ draw();
188
+ });
189
+ $effect(() => {
190
+ const on = () => resizeTick++;
191
+ window.addEventListener("resize", on);
192
+ return () => window.removeEventListener("resize", on);
193
+ });
194
+ function at(ev) {
195
+ const r = canvas.getBoundingClientRect();
196
+ const mx = ev.clientX - r.left, my = ev.clientY - r.top;
197
+ for (let i = rects.length - 1; i >= 0; i--) {
198
+ const q = rects[i];
199
+ if (mx >= q.x && mx <= q.x + q.w && my >= q.y && my <= q.y + q.h) return q;
200
+ }
201
+ return null;
202
+ }
203
+ function onMove(ev) {
204
+ const q = at(ev);
205
+ if (!q || !q.node.label) {
206
+ tip = null;
207
+ return;
208
+ }
209
+ tip = {
210
+ node: q.node,
211
+ x: Math.min(ev.clientX + 14, window.innerWidth - 430),
212
+ y: ev.clientY + 14
213
+ };
214
+ }
215
+ function onClick(ev) {
216
+ const q = at(ev);
217
+ if (q && q.zoom && q.zoom.children) stack = [...stack, q.zoom];
218
+ }
219
+ function zoomOut(ev) {
220
+ ev.preventDefault();
221
+ stack = stack.slice(0, -1);
222
+ }
223
+ </script>
224
+
225
+ <div class="crumb">
226
+ {#if stack.length === 1}
227
+ <span style="color:var(--text-faint)">click a box to zoom in</span>
228
+ {:else}
229
+ {stack
230
+ .slice(1)
231
+ .map((n) => n.label)
232
+ .join(' › ')} —
233
+ <a href="#top" onclick={zoomOut}>zoom out</a>
234
+ {/if}
235
+ </div>
236
+ <canvas
237
+ class="tree"
238
+ bind:this={canvas}
239
+ onmousemove={onMove}
240
+ onmouseleave={() => (tip = null)}
241
+ onclick={onClick}
242
+ ></canvas>
243
+ {#if tip}
244
+ <div class="tree-tip" style="display:block;left:{tip.x}px;top:{tip.y}px">
245
+ <b>{tip.node.label}</b>
246
+ {#if tip.node.sub}<br /><span style="color:var(--text-faint)">{tip.node.sub}</span>{/if}
247
+ <br />{tip.node.value} ms{#if tip.node.pct != null}
248
+ · {tip.node.pct}% of busy{/if}
249
+ </div>
250
+ {/if}
251
+
252
+ <style>
253
+ .tree {
254
+ width: 100%;
255
+ height: 440px;
256
+ border: 1px solid var(--line);
257
+ border-radius: 8px;
258
+ background: var(--bg-sunken);
259
+ display: block;
260
+ cursor: pointer;
261
+ }
262
+ .tree-tip {
263
+ position: fixed;
264
+ pointer-events: none;
265
+ background: var(--bg-hover);
266
+ border: 1px solid var(--line);
267
+ border-radius: 6px;
268
+ padding: 6px 10px;
269
+ font-size: 12px;
270
+ display: none;
271
+ max-width: 420px;
272
+ z-index: 10;
273
+ box-shadow: 0 4px 16px #0008;
274
+ }
275
+ .tree-tip b {
276
+ font-family: ui-monospace, monospace;
277
+ }
278
+ </style>
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CPU treemap — a `wake:'load'` canvas island (was TREE_JS). Squarified layout of self-time,
3
+ * root → category → leaf; click a box to drill in, the breadcrumb zooms back out; hover for detail.
4
+ * The zoom stack and tooltip are `$state`; the canvas redraws in an `$effect` when either the stack
5
+ * or a resize changes. `rects` (hit regions) is plain (non-reactive) — it's rebuilt each draw.
6
+ */
7
+ interface Leaf {
8
+ label: string;
9
+ value: number;
10
+ color: string;
11
+ pct?: number;
12
+ sub?: string;
13
+ children?: Leaf[];
14
+ }
15
+ type $$ComponentProps = {
16
+ hierarchy: Leaf;
17
+ };
18
+ declare const Treemap: import("svelte").Component<$$ComponentProps, {}, "">;
19
+ type Treemap = ReturnType<typeof Treemap>;
20
+ export default Treemap;
@@ -0,0 +1,19 @@
1
+ <script>/** Open a saved profile (the /view GET page). Shell + the reactive UploadForm island. Ports
2
+ * render_upload_page. */
3
+ import Shell from "./Shell.svelte";
4
+ import UploadForm from "./UploadForm.svelte" with { wake: "load" };
5
+ let { data } = $props();
6
+ const { base } = $derived(data);
7
+ </script>
8
+
9
+ <Shell {base}>
10
+ <h1>Open a saved profile</h1>
11
+ <p class="hint">
12
+ Recorded on a serverless host (Amplify, Vercel, Netlify) where the report can't be kept in
13
+ memory? Export the <code>.ogp</code> there, then open it here — it's decrypted and rendered by
14
+ this profiler. ANY <code>.ogp</code> opens in ANY profiler: enter the key it was exported with. Leave
15
+ it blank and this profiler tries its OWN secret — so a report this profiler made re-opens without
16
+ retyping the key.
17
+ </p>
18
+ <UploadForm {base} />
19
+ </Shell>
@@ -0,0 +1,10 @@
1
+ declare const Upload: import("svelte").Component<{
2
+ data: {
3
+ base: string;
4
+ };
5
+ form: Response | null;
6
+ params: {};
7
+ search: {};
8
+ }, {}, "">;
9
+ type Upload = ReturnType<typeof Upload>;
10
+ export default Upload;
@@ -0,0 +1,59 @@
1
+ <script>/**
2
+ * The .ogp upload — a `wake:'load'` island (was report.ts's inline upload script). Posts the file
3
+ * bytes + key; the server decrypts and returns the rendered report, which replaces the document.
4
+ */
5
+ let { base } = $props();
6
+ let key = $state("");
7
+ let error = $state("");
8
+ let busy = $state(false);
9
+ let fileInput;
10
+ async function onFile() {
11
+ const f = fileInput.files?.[0];
12
+ if (!f) return;
13
+ error = "";
14
+ busy = true;
15
+ try {
16
+ const buf = await f.arrayBuffer();
17
+ const res = await fetch(location.pathname, {
18
+ method: "POST",
19
+ headers: {
20
+ "content-type": "application/octet-stream",
21
+ "x-ogp-key": key
22
+ },
23
+ body: buf
24
+ });
25
+ const d = await res.json();
26
+ // the report is an islands page, so navigate to it (it renders + hydrates on load)
27
+ if (d.url) location.href = d.url;
28
+ else error = d.error || "Could not open that file.";
29
+ } catch {
30
+ error = "Could not read that file.";
31
+ } finally {
32
+ busy = false;
33
+ if (fileInput) fileInput.value = "";
34
+ }
35
+ }
36
+ </script>
37
+
38
+ <p>
39
+ <label>
40
+ key
41
+ <input
42
+ type="password"
43
+ bind:value={key}
44
+ placeholder="the .ogp's export key — blank tries this profiler's own secret"
45
+ size="44"
46
+ />
47
+ </label>
48
+ </p>
49
+ <p>
50
+ <input
51
+ type="file"
52
+ bind:this={fileInput}
53
+ onchange={onFile}
54
+ accept=".ogp,application/octet-stream"
55
+ disabled={busy}
56
+ />
57
+ </p>
58
+ {#if error}<p class="verdict">{error}</p>{/if}
59
+ <p class="hint"><a href={base}>← dashboard</a></p>
@@ -0,0 +1,6 @@
1
+ type $$ComponentProps = {
2
+ base: string;
3
+ };
4
+ declare const UploadForm: import("svelte").Component<$$ComponentProps, {}, "">;
5
+ type UploadForm = ReturnType<typeof UploadForm>;
6
+ export default UploadForm;
@@ -0,0 +1,55 @@
1
+ <script>/** Waiting-by-function table — a `wake:'load'` island with reactive sort (count / wait ms). Where
2
+ * the server WAITED (not computed), attributed to the function that started the I/O. */
3
+ import { fmt_ms, kind_color } from "./format.js";
4
+ import { sortable } from "./sort.svelte.js";
5
+ import { pressable } from "./press.js";
6
+ let { rows, maxMs } = $props();
7
+ const s = sortable(() => rows, "ms");
8
+ </script>
9
+
10
+ <table>
11
+ <thead>
12
+ <tr>
13
+ <th>function</th>
14
+ <th>kind</th>
15
+ <th>wait</th>
16
+ <th
17
+ class="num sort"
18
+ class:active={s.key === 'count'}
19
+ onclick={() => s.click('count')}
20
+ {@attach pressable}
21
+ aria-sort={s.aria('count')}>count<span class="arr">{s.arrow('count')}</span></th
22
+ >
23
+ <th
24
+ class="num sort"
25
+ class:active={s.key === 'ms'}
26
+ onclick={() => s.click('ms')}
27
+ {@attach pressable}
28
+ aria-sort={s.aria('ms')}>wait ms<span class="arr">{s.arrow('ms')}</span></th
29
+ >
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ {#each s.sorted as r (r.caller + '|' + r.kind)}
34
+ <tr>
35
+ <td class="fn">{r.caller}</td>
36
+ <td>{r.kind}</td>
37
+ <td class="split">
38
+ <div
39
+ class="split-bar"
40
+ title="{fmt_ms(r.ms)} ms across {r.count} call{r.count > 1 ? 's' : ''}"
41
+ >
42
+ <div
43
+ class="slf"
44
+ style="width:{((r.ms / maxMs) * 100).toFixed(1)}%;background:{kind_color(r.kind)}"
45
+ ></div>
46
+ </div>
47
+ </td>
48
+ <td class="num"
49
+ >{r.count}{#if r.open}<span class="warn"> ({r.open} open)</span>{/if}</td
50
+ >
51
+ <td class="num"><b>{fmt_ms(r.ms)}</b></td>
52
+ </tr>
53
+ {/each}
54
+ </tbody>
55
+ </table>
@@ -0,0 +1,14 @@
1
+ type Row = {
2
+ caller: string;
3
+ kind: string;
4
+ count: number;
5
+ ms: number;
6
+ open: number;
7
+ };
8
+ type $$ComponentProps = {
9
+ rows: Row[];
10
+ maxMs: number;
11
+ };
12
+ declare const WaitingTable: import("svelte").Component<$$ComponentProps, {}, "">;
13
+ type WaitingTable = ReturnType<typeof WaitingTable>;
14
+ export default WaitingTable;