@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,1941 @@
1
+ import { build_timeline, owner_of_stack } from "./timeline.js";
2
+ import { handle_parts } from "./source-scan.js";
3
+ import { another_routes_file, route_dirs, route_file_of } from "./route-files.js";
4
+ import { app_relative } from "./app-path.js";
5
+ // src/profiler/analyze.ts
6
+ /**
7
+ * Analysis of a raw V8 .cpuprofile into readable aggregates.
8
+ *
9
+ * Framework-blind: understands Svelte/SvelteKit/Vite conventions when it sees
10
+ * them (a `.svelte` URL, a `node_modules` segment) but works on any Node
11
+ * server profile. No imports from the rest of ogygia — this file plus
12
+ * report.ts/index.ts can be dropped into any SvelteKit project.
13
+ */
14
+ /** script id → its url, learned from every CPU profile: V8's heap sampler leaves `url` empty for a
15
+ * script made from a string (the dev server's modules: `new AsyncFunction(code)` with a
16
+ * `//# sourceURL`), where the CPU profiler names it. Ids hold for the life of the process */
17
+ const script_urls = /* @__PURE__ */ new Map();
18
+ function learn_script_urls(profile) {
19
+ for (const n of profile?.nodes ?? []) {
20
+ const f = n.callFrame;
21
+ if (f.scriptId && f.url && !script_urls.has(f.scriptId)) script_urls.set(f.scriptId, f.url);
22
+ }
23
+ }
24
+ /** a frame with its url filled from its script id when the profile left it empty */
25
+ function with_script_url(f) {
26
+ if (f.url || !f.scriptId) return f;
27
+ const url = script_urls.get(f.scriptId);
28
+ return url ? {
29
+ ...f,
30
+ url
31
+ } : f;
32
+ }
33
+ const MAX_INDEX_SAMPLES = 2e4;
34
+ /**
35
+ * The stack index of one window (see `StackIndex`). `frame_of` gives a node's resolved frame,
36
+ * `parent_of` its parent node; only nodes on a sampled stack inside the window enter the table.
37
+ */
38
+ function build_stack_index(profile, frame_of, parent_of, perf_start, window) {
39
+ const samples = profile.samples ?? [];
40
+ const deltas = profile.timeDeltas ?? [];
41
+ if (!samples.length || !deltas.length) return void 0;
42
+ const frames = [];
43
+ const index_of = /* @__PURE__ */ new Map();
44
+ const ref = (id) => {
45
+ const hit = index_of.get(id);
46
+ if (hit !== void 0) return hit;
47
+ const f = frame_of(id);
48
+ const name = f.name;
49
+ if (f.category === "idle" || name === "(root)" || name === "(program)") {
50
+ index_of.set(id, -1);
51
+ return -1;
52
+ }
53
+ const pid = parent_of(id);
54
+ const p = pid === void 0 ? -1 : ref(pid);
55
+ const i = frames.length;
56
+ const url = short_path(f.url);
57
+ frames.push({
58
+ n: name,
59
+ ...url ? { f: f.line > 0 ? `${url}:${f.line}` : url } : {},
60
+ c: f.category,
61
+ p
62
+ });
63
+ index_of.set(id, i);
64
+ return i;
65
+ };
66
+ const t = [];
67
+ const d = [];
68
+ const leaf = [];
69
+ let raw = 0;
70
+ let t_us = profile.startTime;
71
+ const w0 = window.start;
72
+ const w1 = window.end;
73
+ let last_leaf = NaN;
74
+ for (let i = 0; i < samples.length; i++) {
75
+ const delta = deltas[i] ?? 0;
76
+ t_us += delta;
77
+ if (delta <= 0) continue;
78
+ const at = perf_start + (t_us - profile.startTime) / 1e3;
79
+ if (at < w0) continue;
80
+ if (at > w1) break;
81
+ raw++;
82
+ const l = ref(samples[i]);
83
+ const ms = delta / 1e3;
84
+ if (l === last_leaf && t.length) {
85
+ d[d.length - 1] += ms;
86
+ continue;
87
+ }
88
+ last_leaf = l;
89
+ t.push(Math.max(0, at - w0 - ms));
90
+ d.push(ms);
91
+ leaf.push(l);
92
+ }
93
+ if (!t.length) return void 0;
94
+ if (t.length > MAX_INDEX_SAMPLES) {
95
+ const k = Math.ceil(t.length / MAX_INDEX_SAMPLES);
96
+ const t2 = [];
97
+ const d2 = [];
98
+ const l2 = [];
99
+ for (let i = 0; i < t.length; i += k) {
100
+ let sum = 0;
101
+ for (let j = i; j < Math.min(i + k, t.length); j++) sum += d[j];
102
+ t2.push(t[i]);
103
+ d2.push(sum);
104
+ l2.push(leaf[i]);
105
+ }
106
+ return {
107
+ frames,
108
+ t: t2.map(round2),
109
+ d: d2.map(round3),
110
+ leaf: l2,
111
+ raw,
112
+ window_ms: round2(w1 - w0)
113
+ };
114
+ }
115
+ return {
116
+ frames,
117
+ t: t.map(round2),
118
+ d: d.map(round3),
119
+ leaf,
120
+ raw,
121
+ window_ms: round2(w1 - w0)
122
+ };
123
+ }
124
+ const round3 = (n) => Math.round(n * 1e3) / 1e3;
125
+ const component_name_re = /^[A-Z][A-Za-z0-9_$]*$/;
126
+ const ROUTE_FILE_FN_RE = /^_(page|layout|error)$/;
127
+ const SVELTE_BASENAME_RE = /([^/\\]+)\.svelte$/;
128
+ /** A rune module SOURCE (`state.svelte.ts`) compiles no component. Only the `.ts` spelling is
129
+ * excluded outright: Kit names a route's BUILT entry chunk `_page.svelte.js`, and that is the
130
+ * bundled component — a `.svelte.js` rune module's class stays a candidate and falls to app
131
+ * code through the structural confirmation (nothing under it calls Svelte's server internals). */
132
+ const SVELTE_MODULE_EXT_RE = /\.svelte\.ts$/;
133
+ /** A bundler's collision suffix (`Header$1`, `Header$2`): two components with one basename in
134
+ * one chunk. Stripped for naming and matching — the frame is still the `Header` component. */
135
+ const BUNDLER_SUFFIX_RE = /\$\d+$/;
136
+ /** ogygia's own files: the `ogygia` package and the `@ogygia/core` it re-exports (a checkout's
137
+ * `packages/core`), source or build */
138
+ const OGYGIA_OWN_RE = /\/(?:ogygia|@ogygia\/core|packages\/core)\/(?:src|dist)\//;
139
+ /** ogygia's own wrapper components. The app's Vite compiles them into the app's chunks (a
140
+ * `.svelte` from a dependency is compiled by the consumer), so in a production profile they sit
141
+ * at a chunk URL with the component's name and no `.svelte` path to vouch for them — and every
142
+ * island page renders `Region` once per island, so it would top the Components table. */
143
+ const OGYGIA_WRAPPERS = /* @__PURE__ */ new Set([
144
+ "Region",
145
+ "SlotBoundary",
146
+ "LakeBoundary",
147
+ "OgygiaBoundary",
148
+ "NestedProvider",
149
+ "LiveHost",
150
+ "KeepHost",
151
+ "Blocks",
152
+ "RawHtml",
153
+ "Provide",
154
+ "ClientBindingStub"
155
+ ]);
156
+ const NON_IDENT_G = /[^a-zA-Z0-9_$]/g;
157
+ /** A frame name with the bundler's `$N` collision suffix removed. */
158
+ function strip_bundler_suffix(name) {
159
+ return name.replace(BUNDLER_SUFFIX_RE, "");
160
+ }
161
+ /** SvelteKit endpoint/handler exports — capitalized, but not components. */
162
+ const handler_names = /* @__PURE__ */ new Set([
163
+ "GET",
164
+ "POST",
165
+ "PUT",
166
+ "PATCH",
167
+ "DELETE",
168
+ "HEAD",
169
+ "OPTIONS",
170
+ "fallback"
171
+ ]);
172
+ /** Svelte derives the SSR function name from the filename: Header.svelte →
173
+ * Header, +page.svelte → _page. Helper closures inside a component keep the
174
+ * file's url but not a component-shaped name. A component-SHAPED name is only
175
+ * a candidate: `analyze` confirms it structurally (see `confirm_components`). */
176
+ const is_component_name = (name) => !handler_names.has(name) && (component_name_re.test(strip_bundler_suffix(name)) || ROUTE_FILE_FN_RE.test(name));
177
+ function component_name_from_file(url) {
178
+ const m = SVELTE_BASENAME_RE.exec(url);
179
+ if (!m) return void 0;
180
+ const base = m[1];
181
+ if (base.startsWith("+")) {
182
+ const kind = base.slice(1);
183
+ return kind === "page" || kind === "layout" || kind === "error" ? `_${kind}` : void 0;
184
+ }
185
+ let name = base.replace(NON_IDENT_G, "_");
186
+ if (/^\d/.test(name)) name = "_" + name;
187
+ return name.charAt(0).toUpperCase() + name.slice(1);
188
+ }
189
+ function clean_url(url) {
190
+ if (url.startsWith("file://")) try {
191
+ return decodeURIComponent(url.slice(7));
192
+ } catch {
193
+ return url.slice(7);
194
+ }
195
+ return url;
196
+ }
197
+ const SCHEME_RE = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
198
+ const WIN_ABS_RE = /^[A-Za-z]:[\\/]/;
199
+ /**
200
+ * A sourcemap's `sources` are relative to the MAP FILE (`../../src/lib/Foo.svelte` from
201
+ * `.svelte-kit/output/server/chunks/x.js.map`). Joined onto the chunk's own directory they become
202
+ * the real path — absolute when V8 reported the chunk absolutely (a `vite preview`, adapter-node),
203
+ * which is what lets a row open in an editor. Pure string work (no `node:path`): this module runs
204
+ * anywhere. An absolute source, a URL, or a chunk with no directory passes through unchanged.
205
+ */
206
+ function join_source(chunk, source) {
207
+ if (!source || source.startsWith("/") || WIN_ABS_RE.test(source) || SCHEME_RE.test(source)) return source;
208
+ const dir = clean_url(chunk).replace(/\\/g, "/");
209
+ const slash = dir.lastIndexOf("/");
210
+ if (slash === -1) return source;
211
+ const out = dir.slice(0, slash).split("/");
212
+ for (const seg of source.split("/")) {
213
+ if (seg === "" || seg === ".") continue;
214
+ if (seg === "..") {
215
+ if (out.length > 1 || out.length === 1 && out[0] !== "") out.pop();
216
+ continue;
217
+ }
218
+ out.push(seg);
219
+ }
220
+ return out.join("/");
221
+ }
222
+ /** ogygia under the name its users know: `@ogygia/core` is what the `ogygia` package re-exports */
223
+ const ogygia_named = (pkg) => pkg === "@ogygia/core" ? "ogygia" : pkg;
224
+ function package_of(url) {
225
+ const i = url.lastIndexOf("node_modules/");
226
+ if (i === -1) return void 0;
227
+ const parts = url.slice(i + 13).split("/");
228
+ if (parts[0] === ".vite" && parts[2]) return ogygia_named(prebundled_package(parts[2]));
229
+ if (parts[0]?.startsWith("@") && parts[1]) return ogygia_named(`${parts[0]}/${parts[1]}`);
230
+ return parts[0] || void 0;
231
+ }
232
+ /** `svelte_internal_server.js` → `svelte`, `@acme_ui_components.js` → `@acme/ui` */
233
+ function prebundled_package(file) {
234
+ let base = file.split("?")[0];
235
+ if (base.endsWith(".mjs")) base = base.slice(0, -4);
236
+ else if (base.endsWith(".js")) base = base.slice(0, -3);
237
+ const bits = base.split("_");
238
+ if (base.startsWith("@")) return bits[1] ? `${bits[0]}/${bits[1]}` : void 0;
239
+ return bits[0] || void 0;
240
+ }
241
+ function categorize(frame) {
242
+ const name = frame.functionName;
243
+ const url = clean_url(frame.url);
244
+ if (!url) {
245
+ if (name === "(garbage collector)") return { category: "gc" };
246
+ if (name === "(idle)") return { category: "idle" };
247
+ if (name === "(root)" || name === "(program)" || name.startsWith("(")) return { category: "v8" };
248
+ }
249
+ if (url.startsWith("node:inspector")) return { category: "profiler" };
250
+ if (url.startsWith("node:internal/async_hooks")) return { category: "profiler" };
251
+ if (url.startsWith("node:")) return { category: "node" };
252
+ if (url.startsWith("wasm://")) return { category: "node" };
253
+ if (url.includes("/ogygia/src/profiler/") || url.includes("/ogygia/dist/profiler/") || url.includes("/devtools/src/profiler/") || url.includes("/devtools/dist/profiler/")) return { category: "profiler" };
254
+ const pkg = package_of(url);
255
+ if (pkg === "svelte") return {
256
+ category: "svelte",
257
+ pkg
258
+ };
259
+ if (pkg) return {
260
+ category: "dependency",
261
+ pkg
262
+ };
263
+ if (OGYGIA_OWN_RE.test(url)) return {
264
+ category: "dependency",
265
+ pkg: "ogygia"
266
+ };
267
+ if (url.endsWith(".svelte")) {
268
+ const own = component_name_from_file(url);
269
+ const stripped = strip_bundler_suffix(name);
270
+ return { category: own !== void 0 && (stripped === own || ROUTE_FILE_FN_RE.test(stripped)) ? "component" : "app" };
271
+ }
272
+ if (url) {
273
+ if (!SVELTE_MODULE_EXT_RE.test(url) && is_component_name(name)) return OGYGIA_WRAPPERS.has(strip_bundler_suffix(name)) ? {
274
+ category: "dependency",
275
+ pkg: "ogygia"
276
+ } : { category: "component" };
277
+ return { category: "app" };
278
+ }
279
+ if (name && !name.startsWith("(")) return { category: "node" };
280
+ return { category: "unknown" };
281
+ }
282
+ const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
283
+ /** char code → its base64 digit, -1 for a character outside the alphabet */
284
+ const B64_DIGIT = (/* @__PURE__ */ new Int8Array(128)).fill(-1);
285
+ for (let i = 0; i < 64; i++) B64_DIGIT[b64.charCodeAt(i)] = i;
286
+ /** the fields of one packed segment, in order */
287
+ const SEG = 5;
288
+ /** Decode one VLQ-encoded sourcemap `mappings` string, packed. */
289
+ function decode_packed(mappings) {
290
+ let segs = new Int32Array(Math.max(64, (mappings.length >> 2) * SEG));
291
+ let n = 0;
292
+ const starts = [0];
293
+ let col = 0, src = 0, src_line = 0, src_col = 0, name_idx = 0;
294
+ let i = 0;
295
+ const len = mappings.length;
296
+ const seg = [
297
+ 0,
298
+ 0,
299
+ 0,
300
+ 0,
301
+ 0
302
+ ];
303
+ outer: while (i < len) {
304
+ const ch = mappings.charCodeAt(i);
305
+ if (ch === 59) {
306
+ starts.push(n);
307
+ col = 0;
308
+ i++;
309
+ continue;
310
+ }
311
+ if (ch === 44) {
312
+ i++;
313
+ continue;
314
+ }
315
+ let count = 0;
316
+ while (i < len) {
317
+ let value = 0, shift = 0, digit;
318
+ do {
319
+ const c = mappings.charCodeAt(i);
320
+ digit = c < 128 ? B64_DIGIT[c] : -1;
321
+ if (digit < 0) break outer;
322
+ i++;
323
+ value += (digit & 31) << shift;
324
+ shift += 5;
325
+ } while (digit & 32);
326
+ if (count < SEG) seg[count] = value & 1 ? -(value >>> 1) : value >>> 1;
327
+ count++;
328
+ const next = i < len ? mappings.charCodeAt(i) : 0;
329
+ if (next === 44 || next === 59 || i >= len) break;
330
+ }
331
+ col += seg[0];
332
+ if (count >= 4) {
333
+ src += seg[1];
334
+ src_line += seg[2];
335
+ src_col += seg[3];
336
+ if (count >= 5) name_idx += seg[4];
337
+ if ((n + 1) * SEG > segs.length) {
338
+ const grown = new Int32Array(segs.length * 2);
339
+ grown.set(segs);
340
+ segs = grown;
341
+ }
342
+ const at = n * SEG;
343
+ segs[at] = col;
344
+ segs[at + 1] = src;
345
+ segs[at + 2] = src_line;
346
+ segs[at + 3] = count >= 5 ? name_idx : -1;
347
+ segs[at + 4] = src_col;
348
+ n++;
349
+ }
350
+ }
351
+ starts.push(n);
352
+ return {
353
+ segs: segs.slice(0, n * SEG),
354
+ starts: Int32Array.from(starts)
355
+ };
356
+ }
357
+ /** Decode one VLQ-encoded sourcemap `mappings` string into per-line column maps (the readable
358
+ * form of {@link decode_packed}) */
359
+ function decode_mappings(mappings) {
360
+ const { segs, starts } = decode_packed(mappings);
361
+ const lines = [];
362
+ for (let l = 0; l + 1 < starts.length; l++) {
363
+ const cols = [];
364
+ for (let s = starts[l]; s < starts[l + 1]; s++) {
365
+ const at = s * SEG;
366
+ cols.push([
367
+ segs[at],
368
+ segs[at + 1],
369
+ segs[at + 2],
370
+ segs[at + 3],
371
+ segs[at + 4]
372
+ ]);
373
+ }
374
+ lines.push({ cols });
375
+ }
376
+ return lines;
377
+ }
378
+ /**
379
+ * Resolves generated positions back to source via `.map` files sitting next to
380
+ * the chunks. `read` abstracts fs so this module stays platform-free. Holds a
381
+ * cache and a `hit` flag, so it is a class rather than a closure.
382
+ */
383
+ /** words that sit where a name would but are not one (`if (`, `return (`, `= function`, `=> {`) */
384
+ const RESERVED_NAME_RE = /^(?:if|for|while|switch|return|catch|await|typeof|function|new|else|do|in|of|throw|yield|void|delete|case|with|async)$/;
385
+ var SourceMapResolver = class {
386
+ /** whether any lookup succeeded */
387
+ hit = false;
388
+ /** whether any line of a chunk WITHOUT a map was matched to its source by text */
389
+ text_hit = false;
390
+ #read;
391
+ #cache = /* @__PURE__ */ new Map();
392
+ #src_cache = /* @__PURE__ */ new Map();
393
+ /** the ORIGINAL source text a map carries (`sourcesContent`), keyed by the same resolved path
394
+ * `resolve()` returns — the code exactly as it was when the bundle was built, and the only copy
395
+ * on a deployed host, where the source files are not on disk */
396
+ #embedded = /* @__PURE__ */ new Map();
397
+ /** A CHUNK WITH NO MAP (a build that turned sourcemaps off): the module at a chunk line
398
+ * (1-based), from the build's module map. `text`: the app's own script module, whose lines are
399
+ * found by their text (`#by_text`); else a package's or the framework's module, named by its
400
+ * path with no line (what it IS decides how it is filed: Kit's `fetch` wrapper is not the app's
401
+ * caller). Undefined = leave the line as the chunk's */
402
+ #module_at;
403
+ /** every script may have a map, not only built `.js` (the dev server) */
404
+ #any_ext;
405
+ constructor(read, module_at, opts = {}) {
406
+ this.#read = read;
407
+ this.#module_at = module_at;
408
+ this.#any_ext = !!opts.any_ext;
409
+ }
410
+ /** The lines of an original source file: the map's embedded copy first (exact, and present on a
411
+ * deployed host), else the file on this machine. `null` when neither exists. */
412
+ #lines_of(source) {
413
+ let lines = this.#src_cache.get(source);
414
+ if (lines === void 0) {
415
+ const text = this.#embedded.get(source) ?? this.#read(source);
416
+ lines = text === void 0 ? null : text.split("\n");
417
+ this.#src_cache.set(source, lines);
418
+ }
419
+ return lines;
420
+ }
421
+ /** every original source a loaded map carries a copy of */
422
+ embedded_sources() {
423
+ return this.#embedded.keys();
424
+ }
425
+ /** Lines `from`..`to` (1-based, inclusive) of an original source, untrimmed — the source view.
426
+ * Undefined when the source is not available (no embedded copy, not on this machine). */
427
+ source_lines(source, from, to) {
428
+ const all = this.#lines_of(source);
429
+ if (!all) return void 0;
430
+ const a = Math.max(1, from);
431
+ const b = Math.min(all.length, to);
432
+ if (b < a) return void 0;
433
+ return {
434
+ start: a,
435
+ lines: all.slice(a - 1, b)
436
+ };
437
+ }
438
+ /** The original source LINE at a mapped position, trimmed and cut: what an anonymous callback
439
+ * IS (`tags.map(async (tag) => {`), for a label a name cannot give. Undefined when the source
440
+ * is not available. */
441
+ line_at_source(source, line, max = 56) {
442
+ const row = this.#lines_of(source)?.[line - 1]?.trim();
443
+ if (!row) return void 0;
444
+ return row.length > max ? row.slice(0, max - 1) + "…" : row;
445
+ }
446
+ /** The function name written in the ORIGINAL source at a mapped position (1-based line and
447
+ * column), for a frame whose map carries no name there: `function foo(`, a method `foo(` /
448
+ * `#foo(` / `async foo(`, or an arrow assigned to `foo` (`const foo = () =>`, `foo: () =>`).
449
+ * Undefined for a true anonymous callback. Reads the source through the same `read`. */
450
+ name_at_source(source, line, column) {
451
+ const row = this.#lines_of(source)?.[line - 1];
452
+ if (row === void 0) return void 0;
453
+ const col = Math.max(0, Math.min(column - 1, row.length));
454
+ const after = row.slice(col);
455
+ const before = row.slice(0, col);
456
+ const tries = [
457
+ [/^(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/, after],
458
+ [/^(?:static\s+)?(?:async\s+)?(?:(?:get|set)\s+)?(#?[A-Za-z_$][\w$]*)\s*\(/, after],
459
+ [/(?:const|let|var|,)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?$/, before],
460
+ [/(#?[A-Za-z_$][\w$]*)\s*[:=]\s*(?:async\s*)?$/, before],
461
+ [/(?:static\s+)?(?:async\s+)?(#?[A-Za-z_$][\w$]*)\s*\(\s*$/, before]
462
+ ];
463
+ for (const [re, text] of tries) {
464
+ const name = re.exec(text)?.[1];
465
+ if (name && !RESERVED_NAME_RE.test(name)) return name;
466
+ }
467
+ }
468
+ /** map a generated (url, line0, col0) to the original file/line/column (1-based), plus the
469
+ * original identifier at that position when the map carries `names` — that's
470
+ * what turns a bundled `(anonymous)` back into a real name */
471
+ /** generated file → its lines, for the text match below */
472
+ #gen_lines = /* @__PURE__ */ new Map();
473
+ /**
474
+ * A MAP WITH NO MAPPINGS: one source named, not one segment. A plugin that returns code without a
475
+ * map breaks the chain and the bundler writes an empty map (SvelteKit's remote-function step
476
+ * appends its registration and does exactly this: every `.remote.ts` call site read as its
477
+ * built chunk). Most lines survive a build word for word, so the generated line's text is found
478
+ * in the one source; a line that changed (types stripped, two lines joined) takes the nearest
479
+ * matching line above it. Only inside that source's `//#region <file>` when the bundler marked
480
+ * one: the imports and the appended code around it are not the source's lines. Undefined when
481
+ * nothing matches.
482
+ */
483
+ #by_text(path, source, line) {
484
+ let gen = this.#gen_lines.get(path);
485
+ if (gen === void 0) {
486
+ const text = this.#read(path);
487
+ gen = text === void 0 ? null : text.split("\n");
488
+ this.#gen_lines.set(path, gen);
489
+ }
490
+ const src = this.#lines_of(source);
491
+ if (!gen || !src) return void 0;
492
+ for (let i = line; i >= 0; i--) {
493
+ const t = gen[i]?.trim() ?? "";
494
+ if (t.startsWith("//#endregion") && i < line) return void 0;
495
+ if (t.startsWith("//#region ")) {
496
+ const file = t.slice(10).trim();
497
+ if (!source.endsWith(file)) return void 0;
498
+ break;
499
+ }
500
+ }
501
+ const norm = (s) => {
502
+ let out = "";
503
+ let quote = "";
504
+ for (let i = 0; i < s.length; i++) {
505
+ const ch = s[i];
506
+ if (quote) {
507
+ if (ch === "\\") {
508
+ out += ch + (s[i + 1] ?? "");
509
+ i++;
510
+ continue;
511
+ }
512
+ if (ch === quote) quote = "";
513
+ } else if (ch === "\"" || ch === "'" || ch === "`") quote = ch;
514
+ else if (ch === "/" && s[i + 1] === "/") break;
515
+ if (ch === " " || ch === " ") continue;
516
+ out += ch === "\"" || ch === "`" ? "'" : ch;
517
+ }
518
+ if (out.startsWith("export")) out = out.slice(6);
519
+ for (const kw of [
520
+ "const",
521
+ "let",
522
+ "var"
523
+ ]) if (out.startsWith(kw)) return out.slice(kw.length);
524
+ return out;
525
+ };
526
+ const normed = src.map(norm);
527
+ const decl = declared_function(gen[line] ?? "");
528
+ if (decl) {
529
+ const at = normed.findIndex((s) => s.includes(`function${decl}(`) || s.includes(`function${decl}<`) || s.startsWith(`${decl}=`) || s.startsWith(`${decl}:`));
530
+ if (at !== -1) return {
531
+ source,
532
+ line: at + 1,
533
+ column: 1,
534
+ text: true
535
+ };
536
+ }
537
+ for (let i = line, k = 0; i >= 0 && k <= 8; i--, k++) {
538
+ const raw = gen[i]?.trim() ?? "";
539
+ if (i < line && (raw.startsWith("//#region") || raw.startsWith("//#endregion"))) break;
540
+ const t = gen[i] ? norm(gen[i]) : "";
541
+ if (t.length < 6 || t.startsWith("//")) continue;
542
+ let at = normed.indexOf(t);
543
+ let wrapped = false;
544
+ if (at === -1 && t.length >= 6) {
545
+ at = normed.findIndex((s) => s.length > t.length && s.startsWith(t));
546
+ wrapped = at !== -1;
547
+ }
548
+ if (at === -1 && i < line) {
549
+ const d = declared_function(gen[i] ?? "");
550
+ if (d) at = normed.findIndex((s) => s.includes(`function${d}(`) || s.startsWith(`${d}=`) || s.startsWith(`${d}:`));
551
+ }
552
+ if (at === -1) continue;
553
+ let open = 0;
554
+ let inside = i < line;
555
+ for (let j = i; j < line && inside; j++) {
556
+ open += bracket_balance(gen[j] ?? "");
557
+ if (open <= 0) inside = false;
558
+ }
559
+ const same = inside && (wrapped || bracket_balance(src[at]) <= 0);
560
+ if (wrapped && i < line && !same) continue;
561
+ const hit = same || i === line ? at + 1 : at + 1 + (line - i);
562
+ return hit <= src.length ? {
563
+ source,
564
+ line: hit,
565
+ column: 1,
566
+ text: true
567
+ } : void 0;
568
+ }
569
+ for (let i = line + 1; i <= line + 3 && i < gen.length; i++) {
570
+ const raw = gen[i]?.trim() ?? "";
571
+ if (raw.startsWith("//#endregion") || raw.startsWith("//#region")) break;
572
+ const t = norm(gen[i]);
573
+ if (t.length < 6 || t.startsWith("//")) continue;
574
+ const at = normed.indexOf(t);
575
+ if (at === -1) continue;
576
+ const hit = at + 1 - (i - line);
577
+ return hit >= 1 ? {
578
+ source,
579
+ line: hit,
580
+ column: 1,
581
+ text: true
582
+ } : void 0;
583
+ }
584
+ }
585
+ /**
586
+ * A LINE OF A FUNCTION MATCHED BY TEXT that matched nothing itself (a build without maps: the
587
+ * build wrote `void 0`, folded a declaration into the next line, or wrapped one statement over
588
+ * several lines). From the nearest line above it that did match, within the function: still
589
+ * inside that statement (its brackets not yet closed) → that statement's line; else as far
590
+ * below it as in the build. Else from the function's own line. 0-based lines in, 1-based out.
591
+ */
592
+ text_nearby(url, line, fn_line) {
593
+ const path = clean_url(url);
594
+ for (let up = line - 1; up >= fn_line && up >= line - 8; up--) {
595
+ const near = this.resolve(url, up, 0);
596
+ if (!near?.text) continue;
597
+ const gen = this.#gen_lines.get(path);
598
+ let open = 0;
599
+ for (let i = up; i < line && gen; i++) open += bracket_balance(gen[i] ?? "");
600
+ return open > 0 ? near.line : near.line + (line - up);
601
+ }
602
+ const head = this.resolve(url, fn_line, 0);
603
+ return head?.text ? head.line + (line - fn_line) : void 0;
604
+ }
605
+ /** A FUNCTION whose own line carries no mapping (Svelte leaves `function _page($$renderer…) {`
606
+ * unmapped and maps the body from its next line to `+page.svelte`): the first mapped line of
607
+ * its body, a few lines down. V8 places a function at its definition, so without this every
608
+ * route component read as its built chunk. Generated code (ogygia's virtual modules) is not a
609
+ * source anyone opens, and is left unmapped. */
610
+ resolve_body(url, line) {
611
+ for (let k = 1; k <= 3; k++) {
612
+ const m = this.resolve(url, line + k, 0);
613
+ if (!m) continue;
614
+ return m.source.includes("virtual:") ? void 0 : m;
615
+ }
616
+ }
617
+ resolve(url, line, column) {
618
+ const first = this.#resolve_one(url, line, column);
619
+ if (!first) return first;
620
+ const s = first.source;
621
+ if (first.line > 0 && (s.endsWith(".js") || s.endsWith(".mjs") || s.endsWith(".cjs"))) {
622
+ const deeper = this.#resolve_one(s, first.line - 1, first.column - 1);
623
+ if (deeper) return {
624
+ ...deeper,
625
+ ...deeper.name || !first.name ? {} : { name: first.name },
626
+ ...deeper.near_name || !first.near_name ? {} : { near_name: first.near_name }
627
+ };
628
+ }
629
+ return first;
630
+ }
631
+ #resolve_one(url, line, column) {
632
+ let path = clean_url(url);
633
+ const q = path.indexOf("?");
634
+ if (q !== -1) {
635
+ const base = path.slice(0, q);
636
+ if (base.endsWith(".js") || base.endsWith(".mjs") || base.endsWith(".cjs")) path = base;
637
+ }
638
+ if (!this.#any_ext && !path.endsWith(".js") && !path.endsWith(".mjs") && !path.endsWith(".cjs")) return;
639
+ let entry = this.#cache.get(path);
640
+ if (entry === void 0) {
641
+ entry = null;
642
+ const raw = this.#read(path + ".map");
643
+ if (raw) try {
644
+ const map = JSON.parse(raw);
645
+ if (typeof map.mappings === "string" && Array.isArray(map.sources)) {
646
+ const root = map.sourceRoot ?? "";
647
+ entry = {
648
+ lines: decode_packed(map.mappings),
649
+ sources: map.sources.map((s) => root + s),
650
+ names: Array.isArray(map.names) ? map.names : []
651
+ };
652
+ if (Array.isArray(map.sourcesContent)) for (let i = 0; i < entry.sources.length; i++) {
653
+ const text = map.sourcesContent[i];
654
+ if (typeof text === "string") {
655
+ const key = join_source(path, entry.sources[i]);
656
+ if (!this.#embedded.has(key)) this.#embedded.set(key, text);
657
+ }
658
+ }
659
+ }
660
+ } catch {}
661
+ this.#cache.set(path, entry);
662
+ }
663
+ if (!entry) {
664
+ const m = this.#module_at?.(path, line + 1);
665
+ if (!m) return void 0;
666
+ if (!m.text) return {
667
+ source: m.source,
668
+ line: 0,
669
+ column: 0
670
+ };
671
+ const r = this.#by_text(path, m.source, line);
672
+ if (r) this.text_hit = true;
673
+ return r;
674
+ }
675
+ const { segs, starts } = entry.lines;
676
+ if (entry.sources.length === 1 && segs.length === 0) return this.#by_text(path, join_source(path, entry.sources[0]), line);
677
+ if (line < 0 || line + 1 >= starts.length) return void 0;
678
+ const first = starts[line];
679
+ const end = starts[line + 1];
680
+ if (end <= first) return void 0;
681
+ let lo = first, hi = end - 1, best = -1;
682
+ while (lo <= hi) {
683
+ const mid = lo + hi >> 1;
684
+ if (segs[mid * SEG] <= column) {
685
+ best = mid;
686
+ lo = mid + 1;
687
+ } else hi = mid - 1;
688
+ }
689
+ const m = (best === -1 ? first : best) * SEG;
690
+ const m_src = segs[m + 1];
691
+ const m_line = segs[m + 2];
692
+ const m_name = segs[m + 3];
693
+ const source = entry.sources[m_src];
694
+ if (!source) return void 0;
695
+ this.hit = true;
696
+ let near_name;
697
+ if (m_name < 0 && best !== -1) for (let d = 1; d <= 4 && !near_name; d++) for (const i of [best + d, best - d]) {
698
+ if (i < first || i >= end) continue;
699
+ const s = i * SEG;
700
+ if (segs[s + 1] !== m_src || segs[s + 2] !== m_line || segs[s + 3] < 0 || Math.abs(segs[s] - column) > 32) continue;
701
+ near_name = entry.names[segs[s + 3]];
702
+ break;
703
+ }
704
+ return {
705
+ source: join_source(path, source),
706
+ line: m_line + 1,
707
+ column: segs[m + 4] + 1,
708
+ name: m_name >= 0 ? entry.names[m_name] : void 0,
709
+ ...near_name ? { near_name } : {}
710
+ };
711
+ }
712
+ };
713
+ /** opened minus closed brackets on a line, outside strings and after no `//` comment */
714
+ function bracket_balance(line) {
715
+ let n = 0;
716
+ let quote = "";
717
+ for (let i = 0; i < line.length; i++) {
718
+ const c = line[i];
719
+ if (quote) {
720
+ if (c === "\\") i++;
721
+ else if (c === quote) quote = "";
722
+ continue;
723
+ }
724
+ if (c === "\"" || c === "'" || c === "`") quote = c;
725
+ else if (c === "/" && line[i + 1] === "/") break;
726
+ else if (c === "(" || c === "[" || c === "{") n++;
727
+ else if (c === ")" || c === "]" || c === "}") n--;
728
+ }
729
+ return n;
730
+ }
731
+ /** the function a built line declares: `async function lookup(key) {` → `lookup`,
732
+ * `const load = async (e) => {` → `load`; undefined for any other line */
733
+ function declared_function(line) {
734
+ const t = line.trim();
735
+ const word = (from) => {
736
+ let end = from;
737
+ while (end < t.length && /[\w$]/.test(t[end])) end++;
738
+ return end > from ? t.slice(from, end) : void 0;
739
+ };
740
+ const fn = t.indexOf("function");
741
+ if (fn !== -1) {
742
+ let i = fn + 8;
743
+ if (t[i] === "*") i++;
744
+ while (t[i] === " ") i++;
745
+ const name = word(i);
746
+ if (name && (t[i + name.length] === "(" || t[i + name.length] === " ")) return name;
747
+ }
748
+ for (const kw of [
749
+ "const ",
750
+ "let ",
751
+ "var "
752
+ ]) {
753
+ if (!t.startsWith(kw)) continue;
754
+ const name = word(kw.length);
755
+ if (!name) return void 0;
756
+ const rest = t.slice(kw.length + name.length).trimStart();
757
+ return rest.startsWith("= (") || rest.startsWith("= async") || rest.startsWith("= function") ? name : void 0;
758
+ }
759
+ }
760
+ function sourcemap_resolver(read, module_at, opts) {
761
+ return new SourceMapResolver(read, module_at, opts);
762
+ }
763
+ function display_name(f) {
764
+ return f.functionName || "(anonymous)";
765
+ }
766
+ function short_path(url) {
767
+ const u = clean_url(url);
768
+ const nm = u.lastIndexOf("node_modules/");
769
+ if (nm !== -1) return u.slice(nm + 13);
770
+ const own = app_relative(u);
771
+ if (own !== void 0) return own;
772
+ const parts = u.split("/");
773
+ return parts.length > 4 ? parts.slice(-4).join("/") : u;
774
+ }
775
+ function analyze(profile, resolver, call_counts, timeline_input, rename, url_category) {
776
+ const calls_by_key = /* @__PURE__ */ new Map();
777
+ const by_id = /* @__PURE__ */ new Map();
778
+ for (const n of profile.nodes) by_id.set(n.id, n);
779
+ /** µs per tick: V8's line ticks are sample counts, the profile's mean delta turns them into time */
780
+ const samples_n = profile.samples?.length ?? 0;
781
+ const us_per_tick = samples_n > 0 ? (profile.endTime - profile.startTime) / samples_n : 0;
782
+ const self_us = /* @__PURE__ */ new Map();
783
+ const samples = profile.samples ?? [];
784
+ const deltas = profile.timeDeltas ?? [];
785
+ /** CPU set aside as another request's: a render of the same page another visitor overlapped (by
786
+ * time, here), or a stack under another route's file (below) */
787
+ let other_us = 0;
788
+ const aside = timeline_input?.set_aside?.length ? timeline_input.set_aside : void 0;
789
+ if (samples.length && deltas.length) {
790
+ let t = profile.startTime;
791
+ for (let i = 0; i < samples.length; i++) {
792
+ const d = deltas[i] ?? 0;
793
+ t += d;
794
+ if (d <= 0) continue;
795
+ if (aside) {
796
+ const ms = timeline_input.perf_start + (t - profile.startTime) / 1e3;
797
+ if (aside.some((w) => ms >= w.start && ms <= w.end)) {
798
+ other_us += d;
799
+ continue;
800
+ }
801
+ }
802
+ self_us.set(samples[i], (self_us.get(samples[i]) ?? 0) + d);
803
+ }
804
+ } else {
805
+ const total = profile.endTime - profile.startTime;
806
+ let hits = 0;
807
+ for (const n of profile.nodes) hits += n.hitCount ?? 0;
808
+ const per_hit = hits > 0 ? total / hits : 0;
809
+ for (const n of profile.nodes) if (n.hitCount) self_us.set(n.id, n.hitCount * per_hit);
810
+ }
811
+ const resolved = /* @__PURE__ */ new Map();
812
+ /** per function key: source line → µs (the hot lines), filled from every node's positionTicks */
813
+ const line_us = /* @__PURE__ */ new Map();
814
+ /** per merged component key: the start line of each frame it merged → its self µs */
815
+ const comp_line_self = /* @__PURE__ */ new Map();
816
+ /** a node's line ticks, mapped to source lines when the frame was */
817
+ const line_ticks_of = /* @__PURE__ */ new Map();
818
+ for (const n of profile.nodes) {
819
+ const f = n.callFrame;
820
+ let url = f.url;
821
+ let line = f.lineNumber + 1;
822
+ let col = f.columnNumber + 1;
823
+ let name = display_name(f);
824
+ let cat = categorize(f);
825
+ let hinted = false;
826
+ if (url_category && f.url && (cat.category === "app" || cat.category === "component")) {
827
+ const h = url_category(f.url, f.functionName, f.lineNumber + 1);
828
+ if (typeof h === "string") cat = {
829
+ category: h,
830
+ ...h === "dependency" ? { pkg: "ogygia" } : {}
831
+ };
832
+ else if (h) cat = {
833
+ category: h.category,
834
+ ...h.pkg ? { pkg: h.pkg } : {}
835
+ };
836
+ hinted = !!h;
837
+ }
838
+ const mapping = resolver && (cat.category === "app" || cat.category === "component" || hinted || f.url.includes("/node_modules/.vite/"));
839
+ if (n.positionTicks?.length && us_per_tick > 0) {
840
+ let tick_n = 0;
841
+ for (const p of n.positionTicks) tick_n += p.ticks;
842
+ const own = self_us.get(n.id);
843
+ const per = own !== void 0 && tick_n > 0 ? own / tick_n : us_per_tick;
844
+ const ticks = [];
845
+ for (const p of n.positionTicks) {
846
+ const at = (mapping ? resolver.resolve(f.url, p.line - 1, 0) : void 0)?.line ?? (mapping ? resolver.text_nearby(f.url, p.line - 1, f.lineNumber) : void 0);
847
+ ticks.push({
848
+ line: at ?? p.line,
849
+ us: p.ticks * per
850
+ });
851
+ }
852
+ line_ticks_of.set(n.id, ticks);
853
+ }
854
+ if (mapping) {
855
+ const mapped = resolver.resolve(f.url, f.lineNumber, f.columnNumber) ?? resolver.resolve_body(f.url, f.lineNumber);
856
+ if (mapped) {
857
+ url = mapped.source;
858
+ line = mapped.line;
859
+ col = mapped.column;
860
+ if (!f.functionName && mapped.name) name = mapped.name;
861
+ else if (f.functionName && MINIFIED_NAME_RE.test(f.functionName)) {
862
+ const from_source = mapped.name ? void 0 : resolver.name_at_source(mapped.source, mapped.line, mapped.column);
863
+ const better = mapped.name ?? from_source ?? mapped.near_name;
864
+ if (better) name = better;
865
+ }
866
+ const recat = categorize({
867
+ ...f,
868
+ functionName: name === "(anonymous)" ? "" : name,
869
+ url: mapped.source
870
+ });
871
+ if (!(hinted && recat.category === "app")) cat = recat;
872
+ }
873
+ }
874
+ if ((!f.functionName || f.functionName === "(anonymous)") && cat.category !== "dependency") {
875
+ const derived = component_name_from_file(clean_url(url));
876
+ if (derived) {
877
+ name = derived;
878
+ cat = { category: "component" };
879
+ }
880
+ }
881
+ if (cat.category === "component") name = strip_bundler_suffix(name);
882
+ if (rename) {
883
+ const better = rename(name, url, "frame");
884
+ if (better) {
885
+ name = better;
886
+ cat = { category: "component" };
887
+ }
888
+ }
889
+ resolved.set(n.id, {
890
+ key: "",
891
+ name,
892
+ url,
893
+ line,
894
+ col,
895
+ category: cat.category,
896
+ pkg: cat.pkg,
897
+ candidate: cat.category === "component" && !clean_url(url).endsWith(".svelte")
898
+ });
899
+ }
900
+ const parent_of = /* @__PURE__ */ new Map();
901
+ for (const n of profile.nodes) for (const c of n.children ?? []) parent_of.set(c, n.id);
902
+ const roots = profile.nodes.filter((n) => !parent_of.has(n.id));
903
+ for (const n of profile.nodes) {
904
+ const r = resolved.get(n.id);
905
+ if (!r || r.name !== "hash" || r.category !== "app") continue;
906
+ const up = parent_of.get(n.id);
907
+ if (up !== void 0 && resolved.get(up)?.name === "render_response") resolved.set(n.id, {
908
+ ...r,
909
+ category: "dependency",
910
+ pkg: "@sveltejs/kit"
911
+ });
912
+ }
913
+ {
914
+ const verdict = /* @__PURE__ */ new Map();
915
+ const owned = (id) => {
916
+ const hit = verdict.get(id);
917
+ if (hit !== void 0) return hit;
918
+ const r = resolved.get(id);
919
+ let out = false;
920
+ if (r && (r.category === "node" || r.category === "v8")) {
921
+ const up = parent_of.get(id);
922
+ out = up !== void 0 && (resolved.get(up)?.category === "profiler" || owned(up));
923
+ }
924
+ verdict.set(id, out);
925
+ return out;
926
+ };
927
+ for (const n of profile.nodes) {
928
+ if (!owned(n.id)) continue;
929
+ const r = resolved.get(n.id);
930
+ resolved.set(n.id, {
931
+ ...r,
932
+ category: "profiler",
933
+ key: "profiler:" + r.name + " " + r.url
934
+ });
935
+ }
936
+ }
937
+ const foreign_ids = /* @__PURE__ */ new Set();
938
+ if (timeline_input?.route) {
939
+ const route = timeline_input.route;
940
+ const foreign = (url) => another_routes_file(route, clean_url(url));
941
+ const walk = (id, under) => {
942
+ const r = resolved.get(id);
943
+ const here = under || !!r && foreign(r.url);
944
+ if (here) foreign_ids.add(id);
945
+ for (const c of by_id.get(id)?.children ?? []) walk(c, here);
946
+ };
947
+ for (const root of roots) walk(root.id, false);
948
+ for (const id of foreign_ids) {
949
+ other_us += self_us.get(id) ?? 0;
950
+ resolved.set(id, {
951
+ key: "(other requests)",
952
+ name: "(other requests)",
953
+ url: "",
954
+ line: 0,
955
+ col: 0,
956
+ category: "idle",
957
+ candidate: false
958
+ });
959
+ line_ticks_of.delete(id);
960
+ }
961
+ }
962
+ const svelte_below = /* @__PURE__ */ new Map();
963
+ const has_svelte_below = (node) => {
964
+ const cached = svelte_below.get(node.id);
965
+ if (cached !== void 0) return cached;
966
+ let below = false;
967
+ for (const c of node.children ?? []) {
968
+ const child = by_id.get(c);
969
+ if (!child) continue;
970
+ if (resolved.get(child.id).category === "svelte" || has_svelte_below(child)) below = true;
971
+ }
972
+ svelte_below.set(node.id, below);
973
+ return below;
974
+ };
975
+ const confirmed = /* @__PURE__ */ new Set();
976
+ for (const n of profile.nodes) {
977
+ const r = resolved.get(n.id);
978
+ if (r.category !== "component") continue;
979
+ if (!r.candidate || ROUTE_FILE_FN_RE.test(r.name) || has_svelte_below(n)) confirmed.add(r.name);
980
+ }
981
+ for (const n of profile.nodes) {
982
+ const r = resolved.get(n.id);
983
+ if (r.candidate && !confirmed.has(r.name)) r.category = "app";
984
+ else if (r.candidate && rename) {
985
+ const better = rename(r.name, r.url, "confirmed");
986
+ if (better) r.name = better;
987
+ }
988
+ r.key = r.category === "component" ? `C:${r.name}` : r.category === "profiler" ? `profiler:${r.name} ${r.url}` : r.name === "(anonymous)" && r.url ? `${r.name} ${r.url}:${r.line}` : `${r.name} ${r.url}`;
989
+ if (call_counts && !calls_by_key.has(r.key)) {
990
+ const f = n.callFrame;
991
+ const c = call_counts[(f.functionName || "") + "\0" + f.url] ?? (f.scriptId ? call_counts[(f.functionName || "") + "\0#" + f.scriptId] : void 0);
992
+ if (c && (r.category !== "component" || strip_bundler_suffix(f.functionName) === r.name)) calls_by_key.set(r.key, c);
993
+ }
994
+ }
995
+ const agg = /* @__PURE__ */ new Map();
996
+ const files = /* @__PURE__ */ new Map();
997
+ const buckets = /* @__PURE__ */ new Map();
998
+ let idle_us = 0;
999
+ let gc_us = 0;
1000
+ let busy_us = 0;
1001
+ let overhead_us = 0;
1002
+ const path = /* @__PURE__ */ new Map();
1003
+ /** inclusive µs per profile NODE (one node = one distinct call path) — what ranks the stacks */
1004
+ const node_total_us = /* @__PURE__ */ new Map();
1005
+ /** every node of a key, for the stacks below */
1006
+ const nodes_by_key = /* @__PURE__ */ new Map();
1007
+ const comp_stack = [];
1008
+ const markup_us = /* @__PURE__ */ new Map();
1009
+ const logic_us = /* @__PURE__ */ new Map();
1010
+ const parent_us = /* @__PURE__ */ new Map();
1011
+ const visit = (node) => {
1012
+ const r = resolved.get(node.id);
1013
+ const s = self_us.get(node.id) ?? 0;
1014
+ const nested = (path.get(r.key) ?? 0) > 0;
1015
+ path.set(r.key, (path.get(r.key) ?? 0) + 1);
1016
+ if (!nested) {
1017
+ const list = nodes_by_key.get(r.key);
1018
+ if (list) list.push(node.id);
1019
+ else nodes_by_key.set(r.key, [node.id]);
1020
+ }
1021
+ const is_comp = r.category === "component";
1022
+ const parent_comp = comp_stack[comp_stack.length - 1];
1023
+ if (is_comp) comp_stack.push(r.key);
1024
+ const ticks = line_ticks_of.get(node.id);
1025
+ if (ticks) {
1026
+ let m = line_us.get(r.key);
1027
+ if (!m) line_us.set(r.key, m = /* @__PURE__ */ new Map());
1028
+ for (const t of ticks) m.set(t.line, (m.get(t.line) ?? 0) + t.us);
1029
+ }
1030
+ let stat = agg.get(r.key);
1031
+ if (!stat) {
1032
+ stat = {
1033
+ key: r.key,
1034
+ name: r.name,
1035
+ url: short_path(r.url),
1036
+ path: clean_url(r.url),
1037
+ line: r.line,
1038
+ col: r.col,
1039
+ category: r.category,
1040
+ pkg: r.pkg,
1041
+ self_ms: 0,
1042
+ total_ms: 0,
1043
+ calls: calls_by_key.get(r.key)
1044
+ };
1045
+ agg.set(r.key, stat);
1046
+ } else if (r.url.endsWith(".svelte") && !stat.url.endsWith(".svelte")) {
1047
+ stat.url = short_path(r.url);
1048
+ stat.path = clean_url(r.url);
1049
+ stat.line = r.line;
1050
+ stat.col = r.col;
1051
+ }
1052
+ if (is_comp && s > 0 && r.url.endsWith(".svelte")) {
1053
+ let m = comp_line_self.get(r.key);
1054
+ if (!m) comp_line_self.set(r.key, m = /* @__PURE__ */ new Map());
1055
+ m.set(r.line, (m.get(r.line) ?? 0) + s);
1056
+ }
1057
+ if (s > 0) {
1058
+ stat.self_ms += s / 1e3;
1059
+ for (const [k, count] of path) if (count > 0) agg.get(k).total_ms += s / 1e3;
1060
+ if (r.category === "idle") idle_us += s;
1061
+ else if (r.category === "profiler") overhead_us += s;
1062
+ else {
1063
+ busy_us += s;
1064
+ if (r.category === "gc") gc_us += s;
1065
+ }
1066
+ const near = comp_stack[comp_stack.length - 1];
1067
+ if (near !== void 0) {
1068
+ if (r.category === "svelte") markup_us.set(near, (markup_us.get(near) ?? 0) + s);
1069
+ else if (r.category === "component" || r.category === "app" || r.category === "dependency" || r.category === "node") logic_us.set(near, (logic_us.get(near) ?? 0) + s);
1070
+ }
1071
+ if (r.url) {
1072
+ const fk = short_path(r.url);
1073
+ const fg = files.get(fk) ?? {
1074
+ key: fk,
1075
+ category: r.category,
1076
+ self_ms: 0
1077
+ };
1078
+ fg.self_ms += s / 1e3;
1079
+ files.set(fk, fg);
1080
+ }
1081
+ const bk = r.category === "dependency" || r.category === "svelte" ? r.pkg ?? "node_modules" : r.category === "component" || r.category === "app" ? "your code" : r.category === "node" ? "node core" : r.category === "gc" ? "garbage collection" : r.category === "idle" ? "idle (waiting)" : r.category === "profiler" ? "profiler overhead" : "v8 internals";
1082
+ const bg = buckets.get(bk) ?? {
1083
+ key: bk,
1084
+ category: r.category,
1085
+ self_ms: 0
1086
+ };
1087
+ bg.self_ms += s / 1e3;
1088
+ buckets.set(bk, bg);
1089
+ }
1090
+ let total = s;
1091
+ for (const c of node.children ?? []) {
1092
+ const child = by_id.get(c);
1093
+ if (child) total += visit(child);
1094
+ }
1095
+ node_total_us.set(node.id, total);
1096
+ if (is_comp) {
1097
+ comp_stack.pop();
1098
+ if (!nested && parent_comp !== void 0 && parent_comp !== r.key) {
1099
+ let m = parent_us.get(r.key);
1100
+ if (!m) parent_us.set(r.key, m = /* @__PURE__ */ new Map());
1101
+ m.set(parent_comp, (m.get(parent_comp) ?? 0) + total);
1102
+ }
1103
+ }
1104
+ const left = path.get(r.key) - 1;
1105
+ if (left === 0) path.delete(r.key);
1106
+ else path.set(r.key, left);
1107
+ return total;
1108
+ };
1109
+ for (const root of roots) visit(root);
1110
+ const STACKS_PER_FN = 3;
1111
+ const STACK_DEPTH = 14;
1112
+ const frames_above = (id) => {
1113
+ const frames = [];
1114
+ let cur = parent_of.get(id);
1115
+ while (cur !== void 0 && frames.length < STACK_DEPTH) {
1116
+ const r = resolved.get(cur);
1117
+ if (r.category === "profiler") {
1118
+ while (frames.length && frames[frames.length - 1].c === "node" && frames[frames.length - 1].f.includes("async_local_storage")) frames.pop();
1119
+ cur = parent_of.get(cur);
1120
+ continue;
1121
+ }
1122
+ if (!r.name.startsWith("(")) {
1123
+ const f = {
1124
+ n: r.name,
1125
+ f: r.url ? `${short_path(r.url)}:${r.line}` : "",
1126
+ c: r.category
1127
+ };
1128
+ if (r.category === "component") {
1129
+ let i = frames.length - 1;
1130
+ while (i >= 0 && frames[i].c === "svelte") i--;
1131
+ const prev = i >= 0 && frames[i].c === "component" && frames[i].n === r.name ? frames[i] : null;
1132
+ if (prev) {
1133
+ frames.length = i + 1;
1134
+ const is_body = (x) => x.f.includes(".svelte:");
1135
+ if (is_body(f) && (!is_body(prev) || r.line < Number(prev.f.split(":").pop()))) frames[i] = f;
1136
+ cur = parent_of.get(cur);
1137
+ continue;
1138
+ }
1139
+ }
1140
+ frames.push(f);
1141
+ }
1142
+ cur = parent_of.get(cur);
1143
+ }
1144
+ return frames;
1145
+ };
1146
+ const stacks_of = (key) => {
1147
+ const ids = nodes_by_key.get(key);
1148
+ if (!ids) return [];
1149
+ const by_path = /* @__PURE__ */ new Map();
1150
+ for (const id of ids) {
1151
+ const us = node_total_us.get(id) ?? 0;
1152
+ if (us <= 0) continue;
1153
+ const frames = frames_above(id);
1154
+ const sig = frames.map((f) => f.n + "\0" + f.f).join("\n");
1155
+ const seen = by_path.get(sig);
1156
+ if (seen) seen.ms += us;
1157
+ else by_path.set(sig, {
1158
+ ms: us,
1159
+ frames
1160
+ });
1161
+ }
1162
+ return [...by_path.values()].sort((a, b) => b.ms - a.ms).slice(0, STACKS_PER_FN).map((s) => ({
1163
+ ms: round2(s.ms / 1e3),
1164
+ frames: s.frames
1165
+ }));
1166
+ };
1167
+ /** a node's children as the app sees them: the profiler's own wrappers (`span`, `within`) and the
1168
+ * AsyncLocalStorage `run` right under them fold away, their children hung on the real caller
1169
+ * (their own self time is the profiler's, not drawn) */
1170
+ const app_children = (node, under_profiler = false) => {
1171
+ const out = [];
1172
+ for (const c of node.children ?? []) {
1173
+ const child = by_id.get(c);
1174
+ if (!child) continue;
1175
+ const r = resolved.get(child.id);
1176
+ if (r.category === "profiler" || under_profiler && r.category === "node" && r.url.includes("async_local_storage")) out.push(...app_children(child, r.category === "profiler"));
1177
+ else out.push(child);
1178
+ }
1179
+ return out;
1180
+ };
1181
+ const to_flame = (node) => {
1182
+ const r = resolved.get(node.id);
1183
+ const s = (self_us.get(node.id) ?? 0) / 1e3;
1184
+ const children = [];
1185
+ const merged = /* @__PURE__ */ new Map();
1186
+ for (const child of app_children(node)) {
1187
+ const fn = to_flame(child);
1188
+ if (!fn) continue;
1189
+ const existing = merged.get(fn.n + " " + fn.f);
1190
+ if (existing) {
1191
+ existing.t += fn.t;
1192
+ existing.s += fn.s;
1193
+ if (fn.ch) existing.ch = [...existing.ch ?? [], ...fn.ch];
1194
+ } else merged.set(fn.n + " " + fn.f, fn);
1195
+ }
1196
+ for (const m of merged.values()) children.push(m);
1197
+ children.sort((a, b) => b.t - a.t);
1198
+ const total = s + children.reduce((acc, c) => acc + c.t, 0);
1199
+ if (total < .005) return null;
1200
+ const fn = {
1201
+ n: r.name,
1202
+ c: r.category,
1203
+ t: round2(total),
1204
+ s: round2(s),
1205
+ f: r.url ? `${short_path(r.url)}:${r.line}` : ""
1206
+ };
1207
+ if (children.length) fn.ch = children;
1208
+ return fn;
1209
+ };
1210
+ const flame_roots = [];
1211
+ for (const root of roots) if (resolved.get(root.id).name === "(root)") for (const child of app_children(root)) {
1212
+ const fn = to_flame(child);
1213
+ if (fn && fn.c !== "idle") flame_roots.push(fn);
1214
+ }
1215
+ else {
1216
+ const fn = to_flame(root);
1217
+ if (fn && fn.c !== "idle") flame_roots.push(fn);
1218
+ }
1219
+ flame_roots.sort((a, b) => b.t - a.t);
1220
+ const flame = {
1221
+ n: "all",
1222
+ c: "v8",
1223
+ t: round2(flame_roots.reduce((a, c) => a + c.t, 0)),
1224
+ s: 0,
1225
+ f: "",
1226
+ ch: flame_roots
1227
+ };
1228
+ const min_t = flame.t * .001;
1229
+ const prune = (node) => {
1230
+ if (!node.ch) return;
1231
+ node.ch = node.ch.filter((c) => c.t >= min_t);
1232
+ if (!node.ch.length) delete node.ch;
1233
+ else for (const c of node.ch) prune(c);
1234
+ };
1235
+ prune(flame);
1236
+ const deopt_by_key = /* @__PURE__ */ new Map();
1237
+ for (const n of profile.nodes) {
1238
+ if (!n.deoptReason) continue;
1239
+ const r = resolved.get(n.id);
1240
+ if (!r || r.category === "idle" || r.category === "gc" || r.category === "v8" || r.category === "profiler") continue;
1241
+ let row = deopt_by_key.get(r.key);
1242
+ if (!row) deopt_by_key.set(r.key, row = {
1243
+ key: r.key,
1244
+ name: r.name,
1245
+ url: short_path(r.url),
1246
+ line: r.line,
1247
+ category: r.category,
1248
+ reasons: {},
1249
+ count: 0,
1250
+ self_ms: 0
1251
+ });
1252
+ row.reasons[n.deoptReason] = (row.reasons[n.deoptReason] ?? 0) + 1;
1253
+ row.count++;
1254
+ }
1255
+ for (const row of deopt_by_key.values()) row.self_ms = round2(agg.get(row.key)?.self_ms ?? 0);
1256
+ const deopts = [...deopt_by_key.values()].sort((x, y) => y.self_ms - x.self_ms || y.count - x.count).slice(0, 40);
1257
+ const overhead_functions = [...agg.values()].filter((f) => f.category === "profiler" && f.self_ms >= .01).sort((x, y) => y.self_ms - x.self_ms).slice(0, 10).map((f) => ({
1258
+ name: f.name,
1259
+ url: f.url,
1260
+ line: f.line,
1261
+ self_ms: round2(f.self_ms)
1262
+ }));
1263
+ const functions = [...agg.values()].filter((f) => (f.self_ms >= .01 || (f.category === "app" || f.category === "component") && f.total_ms >= .05) && f.category !== "idle" && f.category !== "gc" && f.category !== "v8" && f.category !== "profiler").sort((a, b) => b.self_ms - a.self_ms);
1264
+ for (const [key, m] of comp_line_self) {
1265
+ if (line_us.has(key)) continue;
1266
+ const stat = agg.get(key);
1267
+ if (!stat) continue;
1268
+ let sum = 0;
1269
+ let best = -1;
1270
+ let best_us = 0;
1271
+ for (const [line, us] of m) {
1272
+ sum += us;
1273
+ if (us > best_us) {
1274
+ best_us = us;
1275
+ best = line;
1276
+ }
1277
+ }
1278
+ if (best > 0 && best_us >= sum / 2) stat.line = best;
1279
+ }
1280
+ const LINES_PER_FN = 8;
1281
+ const lines_of = (key) => {
1282
+ const m = line_us.get(key);
1283
+ if (!m) return void 0;
1284
+ const list = [...m].map(([line, us]) => ({
1285
+ line,
1286
+ ms: round2(us / 1e3)
1287
+ })).filter((l) => l.ms > 0).sort((a, b) => b.ms - a.ms).slice(0, LINES_PER_FN);
1288
+ return list.length ? list : void 0;
1289
+ };
1290
+ /** the code around a function's hot lines: the top three when they sit close together, else the
1291
+ * hottest with a little context — enough to recognise the line, never the whole file */
1292
+ const src_of = (f) => {
1293
+ if (!resolver || !f.path) return void 0;
1294
+ const hot = (f.lines ?? []).slice(0, 3).map((l) => l.line);
1295
+ if (!hot.length && f.line > 0) hot.push(f.line);
1296
+ if (!hot.length) return void 0;
1297
+ let a = Math.min(...hot) - 2;
1298
+ let b = Math.max(...hot) + 2;
1299
+ if (b - a > 16) {
1300
+ a = hot[0] - 3;
1301
+ b = hot[0] + 3;
1302
+ }
1303
+ return resolver.source_lines(f.path, a, b);
1304
+ };
1305
+ /** what a function called: every child of its outermost nodes, grouped by the child's key. A
1306
+ * child with the SAME key (recursion, a component's inner frame under its wrapper) is walked
1307
+ * through, so its children count as the caller's own. Pseudo frames never show. */
1308
+ const CALLEES_PER_FN = 6;
1309
+ const callees_of = (key, total_ms) => {
1310
+ const ids = nodes_by_key.get(key);
1311
+ if (!ids || total_ms <= 0) return void 0;
1312
+ const by = /* @__PURE__ */ new Map();
1313
+ const walk = (id) => {
1314
+ for (const c of by_id.get(id)?.children ?? []) {
1315
+ const rc = resolved.get(c);
1316
+ if (!rc) continue;
1317
+ if (rc.key === key) {
1318
+ walk(c);
1319
+ continue;
1320
+ }
1321
+ if (rc.name.startsWith("(") && !rc.url) continue;
1322
+ const us = node_total_us.get(c) ?? 0;
1323
+ if (us <= 0) continue;
1324
+ const e = by.get(rc.key);
1325
+ if (e) e.us += us;
1326
+ else by.set(rc.key, {
1327
+ r: rc,
1328
+ us
1329
+ });
1330
+ }
1331
+ };
1332
+ for (const id of ids) walk(id);
1333
+ const list = [...by.values()].sort((a, b) => b.us - a.us).slice(0, CALLEES_PER_FN).map(({ r, us }) => ({
1334
+ key: r.key,
1335
+ name: r.name,
1336
+ category: r.category,
1337
+ ...r.pkg ? { pkg: r.pkg } : {},
1338
+ file: r.url ? `${short_path(r.url)}:${r.line}` : "",
1339
+ ms: round2(us / 1e3),
1340
+ share: Math.min(1, round2(us / 1e3 / total_ms))
1341
+ })).filter((c) => c.ms >= .05);
1342
+ return list.length ? list : void 0;
1343
+ };
1344
+ const FRAMEWORK_PKG = (p) => p.startsWith("@sveltejs/") || p === "svelte" || p.startsWith("ogygia") || p === "vite";
1345
+ const facts_of = /* @__PURE__ */ new Map();
1346
+ const facts = (id) => {
1347
+ const hit = facts_of.get(id);
1348
+ if (hit) return hit;
1349
+ const out = {
1350
+ app: false,
1351
+ edges: []
1352
+ };
1353
+ let child;
1354
+ let cur = id;
1355
+ while (cur !== void 0) {
1356
+ const r = resolved.get(cur);
1357
+ if (r.category === "app" || r.category === "component") {
1358
+ out.app = true;
1359
+ if (child && child.category === "dependency" && child.pkg && !FRAMEWORK_PKG(child.pkg)) out.edges.push({
1360
+ app: r.key,
1361
+ lib: child,
1362
+ pkg: child.pkg
1363
+ });
1364
+ }
1365
+ if (r.category === "dependency" && r.pkg && !FRAMEWORK_PKG(r.pkg)) out.root_pkg = r.pkg;
1366
+ child = r;
1367
+ cur = parent_of.get(cur);
1368
+ }
1369
+ facts_of.set(id, out);
1370
+ return out;
1371
+ };
1372
+ /** per package, the app → library entries in time order */
1373
+ const entries = /* @__PURE__ */ new Map();
1374
+ const orphans = [];
1375
+ {
1376
+ let t = 0;
1377
+ for (let i = 0; i < samples.length; i++) {
1378
+ const d = deltas[i] ?? 0;
1379
+ t += d;
1380
+ const r = resolved.get(samples[i]);
1381
+ if (!r || r.category === "idle" || r.category === "profiler") continue;
1382
+ const fx = facts(samples[i]);
1383
+ if (fx.app) for (const e of fx.edges) {
1384
+ let list = entries.get(e.pkg);
1385
+ if (!list) entries.set(e.pkg, list = []);
1386
+ list.push({
1387
+ t,
1388
+ app: e.app,
1389
+ lib: e.lib
1390
+ });
1391
+ }
1392
+ else if (fx.root_pkg && d > 0) orphans.push({
1393
+ t,
1394
+ us: d,
1395
+ pkg: fx.root_pkg
1396
+ });
1397
+ }
1398
+ }
1399
+ /** app key → library key → { the library frame, µs of orphan work it started } */
1400
+ const async_us = /* @__PURE__ */ new Map();
1401
+ for (const o of orphans) {
1402
+ const list = entries.get(o.pkg);
1403
+ if (!list?.length) continue;
1404
+ let lo = 0;
1405
+ let hi = list.length - 1;
1406
+ let at = -1;
1407
+ while (lo <= hi) {
1408
+ const mid = lo + hi >> 1;
1409
+ if (list[mid].t <= o.t) {
1410
+ at = mid;
1411
+ lo = mid + 1;
1412
+ } else hi = mid - 1;
1413
+ }
1414
+ const e = list[at >= 0 ? at : 0];
1415
+ let m = async_us.get(e.app);
1416
+ if (!m) async_us.set(e.app, m = /* @__PURE__ */ new Map());
1417
+ const cur = m.get(e.lib.key);
1418
+ if (cur) cur.us += o.us;
1419
+ else m.set(e.lib.key, {
1420
+ lib: e.lib,
1421
+ us: o.us
1422
+ });
1423
+ }
1424
+ for (const k of async_us.keys()) {
1425
+ const s = agg.get(k);
1426
+ if (s && !functions.includes(s)) functions.push(s);
1427
+ }
1428
+ /** a function's callees with its async library work merged in (and its total grown by it) */
1429
+ const with_async = (key, total_ms, callees) => {
1430
+ const m = async_us.get(key);
1431
+ if (!m) return {
1432
+ ...callees ? { callees } : {},
1433
+ async_ms: 0
1434
+ };
1435
+ let async_ms = 0;
1436
+ const list = [...callees ?? []];
1437
+ for (const { lib, us } of m.values()) {
1438
+ const ms = us / 1e3;
1439
+ async_ms += ms;
1440
+ const same = list.find((c) => c.key === lib.key);
1441
+ if (same) {
1442
+ same.ms = round2(same.ms + ms);
1443
+ same.async_ms = round2((same.async_ms ?? 0) + ms);
1444
+ } else list.push({
1445
+ key: lib.key,
1446
+ name: lib.name,
1447
+ category: lib.category,
1448
+ file: lib.url ? `${short_path(lib.url)}:${lib.line}` : "",
1449
+ ms: round2(ms),
1450
+ share: 0,
1451
+ async_ms: round2(ms)
1452
+ });
1453
+ }
1454
+ const whole = total_ms + async_ms;
1455
+ for (const c of list) c.share = whole > 0 ? Math.min(1, round2(c.ms / whole)) : 0;
1456
+ list.sort((a, b) => b.ms - a.ms);
1457
+ return {
1458
+ callees: list.slice(0, CALLEES_PER_FN),
1459
+ async_ms: round2(async_ms)
1460
+ };
1461
+ };
1462
+ for (const [i, f] of functions.entries()) {
1463
+ f.self_ms = round2(f.self_ms);
1464
+ f.total_ms = round2(f.total_ms);
1465
+ if (i < 120) {
1466
+ f.stacks = stacks_of(f.key);
1467
+ f.lines = lines_of(f.key);
1468
+ const src = src_of(f);
1469
+ if (src) f.src = src;
1470
+ if (f.name.startsWith("(") && f.line > 0 && (f.category === "app" || f.category === "component")) {
1471
+ const snip = resolver?.line_at_source(f.path || clean_url(f.url), f.line);
1472
+ if (snip) f.label = snip;
1473
+ }
1474
+ }
1475
+ if ((i < 120 || f.total_ms >= .5 || async_us.has(f.key)) && (f.category === "app" || f.category === "component")) {
1476
+ const { callees, async_ms } = with_async(f.key, f.total_ms, callees_of(f.key, f.total_ms));
1477
+ if (callees) f.callees = callees;
1478
+ if (async_ms) f.async_ms = async_ms;
1479
+ if (!f.stacks) f.stacks = stacks_of(f.key);
1480
+ }
1481
+ }
1482
+ const run_us = /* @__PURE__ */ new Map();
1483
+ const runs = timeline_input?.runs;
1484
+ const overhead_run_us = runs ? Array.from({ length: runs.length }, () => 0) : [];
1485
+ const owner_run_us = /* @__PURE__ */ new Map();
1486
+ const owner_memo = /* @__PURE__ */ new Map();
1487
+ const owner_group_of = (id) => {
1488
+ if (owner_memo.has(id)) return owner_memo.get(id);
1489
+ const frames = [];
1490
+ let cur = id;
1491
+ while (cur !== void 0 && frames.length < 64) {
1492
+ const rr = resolved.get(cur);
1493
+ frames.push({
1494
+ name: rr.name,
1495
+ url: rr.url,
1496
+ line: rr.line,
1497
+ category: rr.category,
1498
+ pkg: rr.pkg
1499
+ });
1500
+ cur = parent_of.get(cur);
1501
+ }
1502
+ const leaf = frames[0];
1503
+ const o = !leaf || leaf.category === "idle" || leaf.name === "(root)" || leaf.name === "(program)" ? void 0 : owner_of_stack(frames);
1504
+ const open = o ? o.label.lastIndexOf(" (") : -1;
1505
+ const g = !o || o.category === "profiler" ? void 0 : o.category === "dependency" && open !== -1 && o.label.endsWith(")") ? o.label.slice(open + 2, -1) : o.category === "node" ? "node core" : o.label;
1506
+ owner_memo.set(id, g);
1507
+ return g;
1508
+ };
1509
+ if (runs?.length && samples.length && deltas.length) {
1510
+ let t_us = profile.startTime;
1511
+ let ri = 0;
1512
+ const comps_on_stack = /* @__PURE__ */ new Map();
1513
+ const comps_of = (id) => {
1514
+ const hit = comps_on_stack.get(id);
1515
+ if (hit) return hit;
1516
+ const out = [];
1517
+ let cur = id;
1518
+ while (cur !== void 0) {
1519
+ const rr = resolved.get(cur);
1520
+ if (rr.category === "component" && !out.includes(rr.key)) out.push(rr.key);
1521
+ cur = parent_of.get(cur);
1522
+ }
1523
+ comps_on_stack.set(id, out);
1524
+ return out;
1525
+ };
1526
+ for (let i = 0; i < samples.length; i++) {
1527
+ const d = deltas[i] ?? 0;
1528
+ t_us += d;
1529
+ if (d <= 0) continue;
1530
+ const t = timeline_input.perf_start + (t_us - profile.startTime) / 1e3;
1531
+ while (ri < runs.length && t > runs[ri].end) ri++;
1532
+ if (ri >= runs.length) break;
1533
+ if (t < runs[ri].start) continue;
1534
+ if (resolved.get(samples[i])?.category === "profiler") overhead_run_us[ri] += d;
1535
+ const owner = owner_group_of(samples[i]);
1536
+ if (owner) {
1537
+ let arr = owner_run_us.get(owner);
1538
+ if (!arr) owner_run_us.set(owner, arr = Array.from({ length: runs.length }, () => 0));
1539
+ arr[ri] += d;
1540
+ }
1541
+ for (const key of comps_of(samples[i])) {
1542
+ let arr = run_us.get(key);
1543
+ if (!arr) run_us.set(key, arr = Array.from({ length: runs.length }, () => 0));
1544
+ arr[ri] += d;
1545
+ }
1546
+ }
1547
+ }
1548
+ const components = [...agg.values()].filter((f) => f.category === "component" && f.total_ms >= .01).sort((a, b) => b.total_ms - a.total_ms).map((f) => {
1549
+ let parent;
1550
+ let best = 0;
1551
+ for (const [p, us] of parent_us.get(f.key) ?? []) if (us > best) {
1552
+ best = us;
1553
+ parent = agg.get(p)?.name;
1554
+ }
1555
+ const per_run = run_us.get(f.key);
1556
+ const lines = f.lines ?? lines_of(f.key);
1557
+ const src = f.src ?? src_of({
1558
+ path: f.path,
1559
+ line: f.line,
1560
+ lines
1561
+ });
1562
+ const { callees, async_ms } = f.callees ? {
1563
+ callees: f.callees,
1564
+ async_ms: f.async_ms ?? 0
1565
+ } : with_async(f.key, f.total_ms, callees_of(f.key, f.total_ms));
1566
+ return {
1567
+ ...f,
1568
+ self_ms: round2(f.self_ms),
1569
+ total_ms: round2(f.total_ms),
1570
+ stacks: f.stacks ?? stacks_of(f.key),
1571
+ lines,
1572
+ ...src ? { src } : {},
1573
+ ...callees ? { callees } : {},
1574
+ ...async_ms ? { async_ms } : {},
1575
+ markup_ms: round2((markup_us.get(f.key) ?? 0) / 1e3),
1576
+ logic_ms: round2((logic_us.get(f.key) ?? 0) / 1e3),
1577
+ ...parent ? { parent } : {},
1578
+ ...per_run ? { runs_ms: per_run.map((us) => round2(us / 1e3)) } : {}
1579
+ };
1580
+ });
1581
+ const by_name = new Map(components.map((c) => [c.name, c]));
1582
+ for (const c of components) {
1583
+ if (!c.name.endsWith(" (island host)")) continue;
1584
+ const island = by_name.get(c.name.slice(0, -14));
1585
+ if (!island?.path || island.path.includes("/.svelte-kit/")) continue;
1586
+ c.url = island.url;
1587
+ c.path = island.path;
1588
+ c.line = island.line;
1589
+ c.lines = [];
1590
+ delete c.src;
1591
+ }
1592
+ const file_list = [...files.values()].sort((a, b) => b.self_ms - a.self_ms);
1593
+ for (const f of file_list) f.self_ms = round2(f.self_ms);
1594
+ const bucket_list = [...buckets.values()].sort((a, b) => b.self_ms - a.self_ms);
1595
+ for (const b of bucket_list) b.self_ms = round2(b.self_ms);
1596
+ const HOT_FOR_PATHS = 40;
1597
+ const ROOT_NAME_RE = /^(?:_(?:page|layout|error)|Root|children|handle|respond|render_response|render_page)$/;
1598
+ const BUILT_CHUNK_RE = /\/(?:chunks|output|\.svelte-kit)\//;
1599
+ const SVELTE_GLUE_RE = /^(?:child|component|each|push|pop|head|slot|snippet|render)$/;
1600
+ /** the profiler's own wrapper frames, by name, for a build that bundled span.ts into the app chunk */
1601
+ const PROFILER_WRAPPER_RE = /^(?:span|within|wrapped|wrap_call)$/;
1602
+ const not_glue = functions.filter((f) => f.self_ms >= .01 && !(f.category === "svelte" && SVELTE_GLUE_RE.test(f.name)));
1603
+ const hot_keys = /* @__PURE__ */ new Set([...not_glue.slice(0, HOT_FOR_PATHS).map((f) => f.key), ...not_glue.filter((f) => f.category === "app" || f.category === "component").slice(0, HOT_FOR_PATHS).map((f) => f.key)]);
1604
+ const can_own = (a) => !ROOT_NAME_RE.test(a.name) && !a.name.startsWith("(") && !a.name.endsWith("(island host)") && (a.category === "component" || a.category === "app" && !BUILT_CHUNK_RE.test(a.url));
1605
+ const cover = /* @__PURE__ */ new Map();
1606
+ /** the hot nodes (every node of a hot key with self time), for the trees below */
1607
+ const hot_nodes = [];
1608
+ for (const n of profile.nodes) {
1609
+ const r = resolved.get(n.id);
1610
+ if (!hot_keys.has(r.key)) continue;
1611
+ const s = self_us.get(n.id) ?? 0;
1612
+ if (s <= 0) continue;
1613
+ hot_nodes.push({
1614
+ id: n.id,
1615
+ key: r.key,
1616
+ us: s
1617
+ });
1618
+ const seen = /* @__PURE__ */ new Set([r.key]);
1619
+ let cur = parent_of.get(n.id);
1620
+ while (cur !== void 0) {
1621
+ const a = resolved.get(cur);
1622
+ if (can_own(a) && !seen.has(a.key)) {
1623
+ seen.add(a.key);
1624
+ let m = cover.get(a.key);
1625
+ if (!m) cover.set(a.key, m = /* @__PURE__ */ new Map());
1626
+ m.set(r.key, (m.get(r.key) ?? 0) + s);
1627
+ }
1628
+ cur = parent_of.get(cur);
1629
+ }
1630
+ }
1631
+ const TREE_FANOUT = 6;
1632
+ /** an anonymous function reads by where it is (`fn @ ds-ssr.ts:46`), everything else by name */
1633
+ const path_label = (name, url, line, path) => {
1634
+ if (!name.startsWith("(") || !url) return name;
1635
+ const file = url.split("/").pop()?.split("?")[0] ?? url;
1636
+ const snippet = resolver?.line_at_source(path ?? clean_url(url), line);
1637
+ return snippet ? `fn @ ${file}:${line} · ${snippet}` : `fn @ ${file}:${line}`;
1638
+ };
1639
+ const build_tree = (owner_key, fn_keys) => {
1640
+ const o = agg.get(owner_key);
1641
+ const root = {
1642
+ key: o.key,
1643
+ name: o.name,
1644
+ category: o.category,
1645
+ file: o.url ? `${o.url}:${o.line}` : "",
1646
+ ms: 0,
1647
+ hot: hot_keys.has(o.key),
1648
+ calls: o.calls ?? null,
1649
+ children: []
1650
+ };
1651
+ const node_of = (parent, r) => {
1652
+ let c = parent.children.find((x) => x.key === r.key);
1653
+ if (!c) {
1654
+ c = {
1655
+ key: r.key,
1656
+ name: path_label(r.name, r.url, r.line),
1657
+ category: r.category,
1658
+ file: r.url ? `${short_path(r.url)}:${r.line}` : "",
1659
+ ms: 0,
1660
+ hot: hot_keys.has(r.key),
1661
+ calls: agg.get(r.key)?.calls ?? null,
1662
+ children: []
1663
+ };
1664
+ parent.children.push(c);
1665
+ }
1666
+ return c;
1667
+ };
1668
+ for (const h of hot_nodes) {
1669
+ if (!fn_keys.has(h.key)) continue;
1670
+ const chain = [];
1671
+ let cur = h.id;
1672
+ let found = false;
1673
+ while (cur !== void 0 && chain.length < 64) {
1674
+ const r = resolved.get(cur);
1675
+ if (r.key === owner_key && cur !== h.id) {
1676
+ found = true;
1677
+ break;
1678
+ }
1679
+ if (!(r.category === "profiler" || (r.name.startsWith("(") || r.category === "svelte" || r.name === "Region" || PROFILER_WRAPPER_RE.test(r.name)) && !hot_keys.has(r.key)) && (chain.length === 0 || chain[chain.length - 1].key !== r.key)) chain.push(r);
1680
+ cur = parent_of.get(cur);
1681
+ }
1682
+ if (!found) continue;
1683
+ chain.reverse();
1684
+ const us = h.us;
1685
+ root.ms += us;
1686
+ let at = root;
1687
+ for (const r of chain.slice(-10)) {
1688
+ at = node_of(at, r);
1689
+ at.ms += us;
1690
+ }
1691
+ }
1692
+ const finish = (n) => {
1693
+ n.ms = round2(n.ms / 1e3);
1694
+ n.children.sort((x, y) => y.ms - x.ms);
1695
+ if (n.children.length > TREE_FANOUT) {
1696
+ const rest = n.children.slice(TREE_FANOUT);
1697
+ n.children = n.children.slice(0, TREE_FANOUT);
1698
+ n.children.push({
1699
+ key: "",
1700
+ name: `(${rest.length} more)`,
1701
+ category: "unknown",
1702
+ file: "",
1703
+ ms: round2(rest.reduce((t, c) => t + c.ms, 0) / 1e3),
1704
+ hot: false,
1705
+ children: []
1706
+ });
1707
+ }
1708
+ for (const c of n.children) if (c.key) finish(c);
1709
+ };
1710
+ finish(root);
1711
+ return root;
1712
+ };
1713
+ const paths = [];
1714
+ const taken = /* @__PURE__ */ new Set();
1715
+ const min_path_us = Math.max(2e3, busy_us * .01);
1716
+ for (let round = 0; round < 5; round++) {
1717
+ let best = null;
1718
+ const scored = [];
1719
+ for (const [ak, m] of cover) {
1720
+ if (taken.has(ak)) continue;
1721
+ const fns = [...m].filter(([hk]) => !taken.has(hk));
1722
+ if (fns.length < 2) continue;
1723
+ const us = fns.reduce((t, [, v]) => t + v, 0);
1724
+ if (us < min_path_us) continue;
1725
+ scored.push({
1726
+ key: ak,
1727
+ us,
1728
+ fns
1729
+ });
1730
+ }
1731
+ if (!scored.length) break;
1732
+ scored.sort((x, y) => y.us - x.us);
1733
+ best = scored[0];
1734
+ const by_key = new Map(scored.map((c) => [c.key, c]));
1735
+ let node = build_tree(best.key, new Set(best.fns.map(([hk]) => hk)));
1736
+ for (let depth = 0; depth < 12; depth++) {
1737
+ const c = node.children[0];
1738
+ if (!c || !c.key || c.ms < node.ms * .9) break;
1739
+ if (c.name.startsWith("(")) break;
1740
+ node = c;
1741
+ const cand = by_key.get(c.key);
1742
+ if (cand) best = cand;
1743
+ }
1744
+ const owner = agg.get(best.key);
1745
+ if (!owner) break;
1746
+ taken.add(best.key);
1747
+ for (const [hk] of best.fns) taken.add(hk);
1748
+ const fns = best.fns.map(([hk, us]) => {
1749
+ const f = agg.get(hk);
1750
+ return {
1751
+ key: hk,
1752
+ name: path_label(f.name, f.url, f.line, f.path),
1753
+ url: f.url,
1754
+ line: f.line,
1755
+ category: f.category,
1756
+ pkg: f.pkg,
1757
+ ms: round2(us / 1e3)
1758
+ };
1759
+ }).sort((x, y) => y.ms - x.ms);
1760
+ paths.push({
1761
+ owner: {
1762
+ key: owner.key,
1763
+ name: owner.name,
1764
+ url: owner.url,
1765
+ line: owner.line,
1766
+ category: owner.category,
1767
+ total_ms: round2(owner.total_ms),
1768
+ calls: owner.calls
1769
+ },
1770
+ fns,
1771
+ ms: round2(best.us / 1e3),
1772
+ share: owner.total_ms > 0 ? round2(Math.min(1, best.us / 1e3 / owner.total_ms)) : 0,
1773
+ tree: build_tree(best.key, new Set(best.fns.map(([hk]) => hk)))
1774
+ });
1775
+ }
1776
+ if (timeline_input && resolver && !timeline_input.hooks) {
1777
+ let hooks_file;
1778
+ const is_hooks = (u) => u.endsWith("hooks.server.ts") || u.endsWith("hooks.server.js");
1779
+ for (const s of resolver.embedded_sources()) if (is_hooks(s)) hooks_file = s;
1780
+ if (!hooks_file) {
1781
+ for (const r of resolved.values()) if (r.url && is_hooks(r.url)) hooks_file = r.url;
1782
+ }
1783
+ if (hooks_file) {
1784
+ const parts = handle_parts((p, a, b) => resolver.source_lines(p, a, b), hooks_file);
1785
+ if (parts.size) timeline_input = {
1786
+ ...timeline_input,
1787
+ hooks: parts
1788
+ };
1789
+ }
1790
+ }
1791
+ const timeline = timeline_input ? build_timeline(profile, (id) => {
1792
+ const r = resolved.get(id);
1793
+ return {
1794
+ name: r.name,
1795
+ url: r.url,
1796
+ line: r.line,
1797
+ category: r.category,
1798
+ pkg: r.pkg
1799
+ };
1800
+ }, (id) => parent_of.get(id), timeline_input) : void 0;
1801
+ const capture_cpu = timeline_input?.runs?.length ? build_timeline(profile, (id) => {
1802
+ const r = resolved.get(id);
1803
+ return {
1804
+ name: r.name,
1805
+ url: r.url,
1806
+ line: r.line,
1807
+ category: r.category,
1808
+ pkg: r.pkg
1809
+ };
1810
+ }, (id) => parent_of.get(id), {
1811
+ perf_start: timeline_input.perf_start,
1812
+ window: {
1813
+ start: timeline_input.perf_start,
1814
+ end: timeline_input.perf_start + (profile.endTime - profile.startTime) / 1e3
1815
+ },
1816
+ calls: []
1817
+ }).segments.filter((s) => s.kind === "cpu").map((s) => ({
1818
+ t0: s.t0,
1819
+ t1: s.t1,
1820
+ label: s.label,
1821
+ category: s.category,
1822
+ ...s.file ? { file: s.file } : {}
1823
+ })) : void 0;
1824
+ const stacks = timeline_input ? build_stack_index(profile, (id) => {
1825
+ const r = resolved.get(id);
1826
+ return {
1827
+ name: r.name,
1828
+ url: r.url,
1829
+ line: r.line,
1830
+ category: r.category
1831
+ };
1832
+ }, (id) => parent_of.get(id), timeline_input.perf_start, timeline_input.window) : void 0;
1833
+ return {
1834
+ duration_ms: round2((profile.endTime - profile.startTime) / 1e3),
1835
+ busy_ms: round2(busy_us / 1e3),
1836
+ idle_ms: round2(idle_us / 1e3),
1837
+ gc_ms: round2(gc_us / 1e3),
1838
+ overhead_ms: round2(overhead_us / 1e3),
1839
+ overhead_functions,
1840
+ ...runs?.length ? { overhead_by_run_ms: overhead_run_us.map((us) => round2(us / 1e3)) } : {},
1841
+ ...capture_cpu ? { capture_cpu } : {},
1842
+ ...owner_run_us.size ? { owner_runs_ms: Object.fromEntries([...owner_run_us].map(([k, v]) => [k, v.map((us) => round2(us / 1e3))])) } : {},
1843
+ deopts,
1844
+ sample_count: samples.length,
1845
+ functions,
1846
+ components,
1847
+ files: file_list,
1848
+ buckets: bucket_list,
1849
+ flame,
1850
+ sourcemapped: resolver?.hit ?? false,
1851
+ ...other_us > 0 ? { other_requests_ms: round2(other_us / 1e3) } : {},
1852
+ ...resolver?.text_hit ? { text_mapped: true } : {},
1853
+ ...timeline ? { timeline } : {},
1854
+ ...stacks ? { stacks } : {},
1855
+ paths
1856
+ };
1857
+ }
1858
+ function round2(n) {
1859
+ return Math.round(n * 100) / 100;
1860
+ }
1861
+ /** Aggregate a sampled heap profile into "who allocates the most" rows. */
1862
+ /** BYTES PER COMPONENT: every sampled allocation credited to the nearest component above it in
1863
+ * the heap tree (the same rule as markup/logic: nested components take their own). */
1864
+ /** A minified identifier: what a production client chunk calls its functions (`Y`, `Gr`, `_a`, `#u`). */
1865
+ const MINIFIED_NAME_RE = /^#?[A-Za-z_$][A-Za-z0-9_$]?$/;
1866
+ /**
1867
+ * The renamer for a BROWSER profile: a component confirmed in a minified client chunk (Svelte's
1868
+ * runtime is below it, so it is one, but its name is `Y`) is named after the `.svelte` files the
1869
+ * build put in that chunk — `ProductCard`, or `ProductCard (+2 in chunk)` when the chunk holds
1870
+ * several. `contents` is the build handoff's chunk summary by path (`chunkContents`). Only the
1871
+ * confirmed stage renames: an unconfirmed `Pt` is a helper and stays app code.
1872
+ */
1873
+ function chunk_component_renamer(contents) {
1874
+ const cache = /* @__PURE__ */ new Map();
1875
+ return (name, url, stage) => {
1876
+ if (stage !== "confirmed" || !MINIFIED_NAME_RE.test(name)) return void 0;
1877
+ let path;
1878
+ try {
1879
+ path = new URL(url, "http://x").pathname;
1880
+ } catch {
1881
+ return;
1882
+ }
1883
+ if (!cache.has(path)) {
1884
+ const comps = (contents(path) ?? []).filter((s) => s.endsWith(".svelte")).map((s) => component_name_from_file(s) ?? s.split("/").pop().replace(/\.svelte$/, ""));
1885
+ cache.set(path, comps.length ? comps.length === 1 ? comps[0] : `${comps[0]} (+${comps.length - 1} in chunk)` : void 0);
1886
+ }
1887
+ return cache.get(path);
1888
+ };
1889
+ }
1890
+ function heap_by_component(head, limit = 60) {
1891
+ const by = /* @__PURE__ */ new Map();
1892
+ const stack = [];
1893
+ const visit = (node) => {
1894
+ const f = with_script_url(node.callFrame);
1895
+ const c = categorize(f);
1896
+ let name = f.functionName;
1897
+ if (c.category === "component") name = strip_bundler_suffix(name);
1898
+ else if ((!f.functionName || f.functionName === "(anonymous)") && c.category !== "dependency") {
1899
+ const derived = component_name_from_file(clean_url(f.url));
1900
+ if (derived) name = derived;
1901
+ }
1902
+ const is_comp = c.category === "component" || name !== f.functionName && !!name;
1903
+ if (is_comp) stack.push(name);
1904
+ const near = stack[stack.length - 1];
1905
+ if (near !== void 0 && node.selfSize > 0) by.set(near, (by.get(near) ?? 0) + node.selfSize);
1906
+ for (const ch of node.children ?? []) visit(ch);
1907
+ if (is_comp) stack.pop();
1908
+ };
1909
+ visit(head);
1910
+ return [...by.entries()].map(([name, bytes]) => ({
1911
+ name,
1912
+ bytes
1913
+ })).sort((a, b) => b.bytes - a.bytes).slice(0, limit);
1914
+ }
1915
+ function analyze_heap(head, limit = 25) {
1916
+ const agg = /* @__PURE__ */ new Map();
1917
+ const visit = (node) => {
1918
+ const f = with_script_url(node.callFrame);
1919
+ const key = `${f.functionName} ${f.url}`;
1920
+ let stat = agg.get(key);
1921
+ if (!stat) {
1922
+ stat = {
1923
+ name: f.functionName || "(anonymous)",
1924
+ url: short_path(f.url),
1925
+ line: f.lineNumber + 1,
1926
+ category: categorize(f).category,
1927
+ self_bytes: 0,
1928
+ total_bytes: 0
1929
+ };
1930
+ agg.set(key, stat);
1931
+ }
1932
+ stat.self_bytes += node.selfSize;
1933
+ let total = node.selfSize;
1934
+ for (const c of node.children ?? []) total += visit(c);
1935
+ stat.total_bytes += total;
1936
+ return total;
1937
+ };
1938
+ visit(head);
1939
+ return [...agg.values()].filter((a) => a.self_bytes > 0 && a.category !== "v8" && a.category !== "gc" && a.category !== "profiler").sort((a, b) => b.self_bytes - a.self_bytes).slice(0, limit);
1940
+ }
1941
+ export { SourceMapResolver, analyze, analyze_heap, another_routes_file, build_stack_index, categorize, chunk_component_renamer, clean_url, component_name_from_file, decode_mappings, decode_packed, heap_by_component, join_source, learn_script_urls, route_dirs, route_file_of, sourcemap_resolver, strip_bundler_suffix, with_script_url };