@ogygia/core 0.0.0 → 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 (548) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -1
  3. package/ambient.d.ts +194 -0
  4. package/dist/ClientBindingStub.svelte +6 -0
  5. package/dist/ClientBindingStub.svelte.d.ts +26 -0
  6. package/dist/KeepHost.svelte +19 -0
  7. package/dist/KeepHost.svelte.d.ts +10 -0
  8. package/dist/LakeBoundary.svelte +16 -0
  9. package/dist/LakeBoundary.svelte.d.ts +11 -0
  10. package/dist/LateIsland.svelte +22 -0
  11. package/dist/LateIsland.svelte.d.ts +15 -0
  12. package/dist/LateIslandAwait.svelte +17 -0
  13. package/dist/LateIslandAwait.svelte.d.ts +15 -0
  14. package/dist/LiveHost.svelte +19 -0
  15. package/dist/LiveHost.svelte.d.ts +10 -0
  16. package/dist/NestedProvider.svelte +13 -0
  17. package/dist/NestedProvider.svelte.d.ts +8 -0
  18. package/dist/OgygiaBoundary.svelte +5 -0
  19. package/dist/OgygiaBoundary.svelte.d.ts +17 -0
  20. package/dist/PromiseRegion.svelte +40 -0
  21. package/dist/PromiseRegion.svelte.d.ts +15 -0
  22. package/dist/PromiseRegionAwait.svelte +27 -0
  23. package/dist/PromiseRegionAwait.svelte.d.ts +15 -0
  24. package/dist/Provide.svelte +27 -0
  25. package/dist/Provide.svelte.d.ts +8 -0
  26. package/dist/RawHtml.svelte +9 -0
  27. package/dist/RawHtml.svelte.d.ts +6 -0
  28. package/dist/Region.svelte +1173 -0
  29. package/dist/Region.svelte.d.ts +68 -0
  30. package/dist/SlotBoundary.svelte +13 -0
  31. package/dist/SlotBoundary.svelte.d.ts +7 -0
  32. package/dist/app.d.ts +4 -0
  33. package/dist/app.js +3 -0
  34. package/dist/boundary.d.ts +35 -0
  35. package/dist/boundary.js +127 -0
  36. package/dist/build-cache.d.ts +13 -0
  37. package/dist/build-cache.js +77 -0
  38. package/dist/compiler/blank-styles.d.ts +1 -0
  39. package/dist/compiler/blank-styles.js +63 -0
  40. package/dist/compiler/bom.d.ts +2 -0
  41. package/dist/compiler/bom.js +15 -0
  42. package/dist/compiler/browser-full.d.ts +8 -0
  43. package/dist/compiler/browser-full.js +8 -0
  44. package/dist/compiler/browser.d.ts +11 -0
  45. package/dist/compiler/browser.js +11 -0
  46. package/dist/compiler/content/transportables.d.ts +26 -0
  47. package/dist/compiler/content/transportables.js +219 -0
  48. package/dist/compiler/ctx.d.ts +180 -0
  49. package/dist/compiler/ctx.js +183 -0
  50. package/dist/compiler/debarrel/barrel.d.ts +55 -0
  51. package/dist/compiler/debarrel/barrel.js +248 -0
  52. package/dist/compiler/debarrel/options.d.ts +67 -0
  53. package/dist/compiler/debarrel/options.js +31 -0
  54. package/dist/compiler/debarrel/parse.d.ts +65 -0
  55. package/dist/compiler/debarrel/parse.js +256 -0
  56. package/dist/compiler/debarrel/plugin.d.ts +31 -0
  57. package/dist/compiler/debarrel/plugin.js +190 -0
  58. package/dist/compiler/debarrel/rewrite.d.ts +27 -0
  59. package/dist/compiler/debarrel/rewrite.js +118 -0
  60. package/dist/compiler/debarrel/svelte.d.ts +13 -0
  61. package/dist/compiler/debarrel/svelte.js +56 -0
  62. package/dist/compiler/dev/css-scope.d.ts +16 -0
  63. package/dist/compiler/dev/css-scope.js +38 -0
  64. package/dist/compiler/dev/dev-hmr.d.ts +25 -0
  65. package/dist/compiler/dev/dev-hmr.js +29 -0
  66. package/dist/compiler/dev/hmr.d.ts +34 -0
  67. package/dist/compiler/dev/hmr.js +57 -0
  68. package/dist/compiler/dev/region-bytes.d.ts +34 -0
  69. package/dist/compiler/dev/region-bytes.js +126 -0
  70. package/dist/compiler/driver.d.ts +280 -0
  71. package/dist/compiler/driver.js +1352 -0
  72. package/dist/compiler/flags.d.ts +16 -0
  73. package/dist/compiler/flags.js +101 -0
  74. package/dist/compiler/fouc-css.d.ts +97 -0
  75. package/dist/compiler/fouc-css.js +335 -0
  76. package/dist/compiler/free-vars.d.ts +20 -0
  77. package/dist/compiler/free-vars.js +327 -0
  78. package/dist/compiler/host.d.ts +65 -0
  79. package/dist/compiler/host.js +51 -0
  80. package/dist/compiler/ids.d.ts +84 -0
  81. package/dist/compiler/ids.js +86 -0
  82. package/dist/compiler/index.d.ts +11 -0
  83. package/dist/compiler/index.js +11 -0
  84. package/dist/compiler/kit.d.ts +129 -0
  85. package/dist/compiler/kit.js +563 -0
  86. package/dist/compiler/link/build-output.d.ts +44 -0
  87. package/dist/compiler/link/build-output.js +147 -0
  88. package/dist/compiler/link/caps.d.ts +48 -0
  89. package/dist/compiler/link/caps.js +64 -0
  90. package/dist/compiler/link/context-detect.d.ts +23 -0
  91. package/dist/compiler/link/context-detect.js +137 -0
  92. package/dist/compiler/link/emit-gate.d.ts +11 -0
  93. package/dist/compiler/link/emit-gate.js +40 -0
  94. package/dist/compiler/link/entry-shim.d.ts +4 -0
  95. package/dist/compiler/link/entry-shim.js +29 -0
  96. package/dist/compiler/link/island-deps.d.ts +142 -0
  97. package/dist/compiler/link/island-deps.js +525 -0
  98. package/dist/compiler/link/manifest.d.ts +5 -0
  99. package/dist/compiler/link/manifest.js +9 -0
  100. package/dist/compiler/link/page-keys.d.ts +64 -0
  101. package/dist/compiler/link/page-keys.js +683 -0
  102. package/dist/compiler/link/registry-stub.d.ts +41 -0
  103. package/dist/compiler/link/registry-stub.js +212 -0
  104. package/dist/compiler/link/router-config.d.ts +11 -0
  105. package/dist/compiler/link/router-config.js +15 -0
  106. package/dist/compiler/link/router-css.d.ts +22 -0
  107. package/dist/compiler/link/router-css.js +142 -0
  108. package/dist/compiler/link/runtime-entry.d.ts +71 -0
  109. package/dist/compiler/link/runtime-entry.js +132 -0
  110. package/dist/compiler/link/server-manifest.d.ts +12 -0
  111. package/dist/compiler/link/server-manifest.js +45 -0
  112. package/dist/compiler/link/speculation.d.ts +17 -0
  113. package/dist/compiler/link/speculation.js +36 -0
  114. package/dist/compiler/link/transport.d.ts +31 -0
  115. package/dist/compiler/link/transport.js +67 -0
  116. package/dist/compiler/macros/bake.d.ts +20 -0
  117. package/dist/compiler/macros/bake.js +317 -0
  118. package/dist/compiler/macros/browser.d.ts +11 -0
  119. package/dist/compiler/macros/browser.js +69 -0
  120. package/dist/compiler/macros/dedent.d.ts +12 -0
  121. package/dist/compiler/macros/dedent.js +36 -0
  122. package/dist/compiler/macros/dollar.d.ts +15 -0
  123. package/dist/compiler/macros/dollar.js +387 -0
  124. package/dist/compiler/macros/pipeline.d.ts +31 -0
  125. package/dist/compiler/macros/pipeline.js +106 -0
  126. package/dist/compiler/macros/source.d.ts +6 -0
  127. package/dist/compiler/macros/source.js +127 -0
  128. package/dist/compiler/macros/store.d.ts +17 -0
  129. package/dist/compiler/macros/store.js +244 -0
  130. package/dist/compiler/macros/wire.d.ts +14 -0
  131. package/dist/compiler/macros/wire.js +160 -0
  132. package/dist/compiler/ownership-stamps.d.ts +6 -0
  133. package/dist/compiler/ownership-stamps.js +144 -0
  134. package/dist/compiler/parse/oxc.d.ts +34 -0
  135. package/dist/compiler/parse/oxc.js +59 -0
  136. package/dist/compiler/parse/scan.d.ts +43 -0
  137. package/dist/compiler/parse/scan.js +232 -0
  138. package/dist/compiler/program.d.ts +140 -0
  139. package/dist/compiler/program.js +242 -0
  140. package/dist/compiler/region/emit.d.ts +169 -0
  141. package/dist/compiler/region/emit.js +286 -0
  142. package/dist/compiler/region/identity.d.ts +28 -0
  143. package/dist/compiler/region/identity.js +75 -0
  144. package/dist/compiler/region/ir.d.ts +65 -0
  145. package/dist/compiler/region/ir.js +0 -0
  146. package/dist/compiler/region/transform.d.ts +178 -0
  147. package/dist/compiler/region/transform.js +1933 -0
  148. package/dist/compiler/script-request.d.ts +1 -0
  149. package/dist/compiler/script-request.js +43 -0
  150. package/dist/context-bridge.d.ts +65 -0
  151. package/dist/context-bridge.js +217 -0
  152. package/dist/context-registry.d.ts +40 -0
  153. package/dist/context-registry.js +15 -0
  154. package/dist/context.d.ts +72 -0
  155. package/dist/context.js +158 -0
  156. package/dist/current-region.d.ts +14 -0
  157. package/dist/current-region.js +36 -0
  158. package/dist/document.d.ts +41 -0
  159. package/dist/document.js +125 -0
  160. package/dist/entry-hydrate.d.ts +5 -0
  161. package/dist/entry-hydrate.js +42 -0
  162. package/dist/escape.d.ts +18 -0
  163. package/dist/escape.js +37 -0
  164. package/dist/events/bus.d.ts +33 -0
  165. package/dist/events/bus.js +153 -0
  166. package/dist/events/index.d.ts +4 -0
  167. package/dist/events/index.js +4 -0
  168. package/dist/events/schema.d.ts +389 -0
  169. package/dist/events/schema.js +23 -0
  170. package/dist/events/server-registry.d.ts +7 -0
  171. package/dist/events/server-registry.js +13 -0
  172. package/dist/events/sinks.d.ts +64 -0
  173. package/dist/events/sinks.js +85 -0
  174. package/dist/fn-transport.d.ts +33 -0
  175. package/dist/fn-transport.js +140 -0
  176. package/dist/frame.d.ts +20 -0
  177. package/dist/frame.js +19 -0
  178. package/dist/holes-record.d.ts +6 -0
  179. package/dist/holes-record.js +8 -0
  180. package/dist/hooks.d.ts +43 -0
  181. package/dist/hooks.js +1191 -0
  182. package/dist/hydration-info.d.ts +1 -0
  183. package/dist/hydration-info.js +31 -0
  184. package/dist/index.d.ts +21 -0
  185. package/dist/index.js +17 -0
  186. package/dist/insights/attr-rules.d.ts +15 -0
  187. package/dist/insights/attr-rules.js +27 -0
  188. package/dist/insights/cpu.d.ts +82 -0
  189. package/dist/insights/cpu.js +177 -0
  190. package/dist/insights/fp-drift.d.ts +28 -0
  191. package/dist/insights/fp-drift.js +148 -0
  192. package/dist/insights/hole-segments.d.ts +26 -0
  193. package/dist/insights/hole-segments.js +50 -0
  194. package/dist/insights/html-diff.d.ts +25 -0
  195. package/dist/insights/html-diff.js +157 -0
  196. package/dist/insights/hydration-hazards.d.ts +36 -0
  197. package/dist/insights/hydration-hazards.js +136 -0
  198. package/dist/insights/hydration-status.d.ts +2 -0
  199. package/dist/insights/hydration-status.js +0 -0
  200. package/dist/insights/index.d.ts +14 -0
  201. package/dist/insights/index.js +12 -0
  202. package/dist/insights/page-assets.d.ts +211 -0
  203. package/dist/insights/page-assets.js +608 -0
  204. package/dist/insights/page-insights.d.ts +749 -0
  205. package/dist/insights/page-insights.js +2157 -0
  206. package/dist/insights/session-data.d.ts +108 -0
  207. package/dist/insights/session-data.js +0 -0
  208. package/dist/insights/session-insights.d.ts +121 -0
  209. package/dist/insights/session-insights.js +548 -0
  210. package/dist/insights/switch.d.ts +53 -0
  211. package/dist/insights/switch.js +91 -0
  212. package/dist/insights/testing-version.d.ts +19 -0
  213. package/dist/insights/testing-version.js +21 -0
  214. package/dist/insights/third-party.d.ts +75 -0
  215. package/dist/insights/third-party.js +160 -0
  216. package/dist/internal-instruments.d.ts +13 -0
  217. package/dist/internal-instruments.js +12 -0
  218. package/dist/internal-reconcile.d.ts +3 -0
  219. package/dist/internal-reconcile.js +3 -0
  220. package/dist/internal-register.d.ts +7 -0
  221. package/dist/internal-register.js +7 -0
  222. package/dist/internal-server.d.ts +7 -0
  223. package/dist/internal-server.js +7 -0
  224. package/dist/internal.d.ts +13 -0
  225. package/dist/internal.js +13 -0
  226. package/dist/island-graph.d.ts +36 -0
  227. package/dist/island-graph.js +89 -0
  228. package/dist/keep-fallback-marker.d.ts +7 -0
  229. package/dist/keep-fallback-marker.js +9 -0
  230. package/dist/keep-fallback.d.ts +13 -0
  231. package/dist/keep-fallback.js +39 -0
  232. package/dist/kit-paths.d.ts +2 -0
  233. package/dist/kit-paths.js +39 -0
  234. package/dist/late-region-registry.d.ts +40 -0
  235. package/dist/late-region-registry.js +36 -0
  236. package/dist/live-transport.d.ts +57 -0
  237. package/dist/live-transport.js +145 -0
  238. package/dist/markup.d.ts +4 -0
  239. package/dist/markup.js +4 -0
  240. package/dist/own-package.d.ts +15 -0
  241. package/dist/own-package.js +20 -0
  242. package/dist/page-defer.d.ts +33 -0
  243. package/dist/page-defer.js +35 -0
  244. package/dist/page-facts-script.d.ts +7 -0
  245. package/dist/page-facts-script.js +9 -0
  246. package/dist/page-seed-registry.d.ts +72 -0
  247. package/dist/page-seed-registry.js +31 -0
  248. package/dist/plugin/capability.d.ts +14 -0
  249. package/dist/plugin/capability.js +44 -0
  250. package/dist/plugin/client.d.ts +39 -0
  251. package/dist/plugin/client.js +6 -0
  252. package/dist/plugin/css.d.ts +3 -0
  253. package/dist/plugin/css.js +54 -0
  254. package/dist/plugin/facts.d.ts +42 -0
  255. package/dist/plugin/facts.js +37 -0
  256. package/dist/plugin/hooks.d.ts +33 -0
  257. package/dist/plugin/hooks.js +38 -0
  258. package/dist/plugin/index.d.ts +127 -0
  259. package/dist/plugin/index.js +26 -0
  260. package/dist/plugin/routes.d.ts +32 -0
  261. package/dist/plugin/routes.js +35 -0
  262. package/dist/plugin/server.d.ts +27 -0
  263. package/dist/plugin/server.js +92 -0
  264. package/dist/plugin/standard-schema.d.ts +27 -0
  265. package/dist/plugin/standard-schema.js +0 -0
  266. package/dist/plugin/testing.d.ts +13 -0
  267. package/dist/plugin/testing.js +54 -0
  268. package/dist/plugin/utils.d.ts +13 -0
  269. package/dist/plugin/utils.js +19 -0
  270. package/dist/portable-form.d.ts +22 -0
  271. package/dist/portable-form.js +52 -0
  272. package/dist/preference.d.ts +35 -0
  273. package/dist/preference.js +84 -0
  274. package/dist/preload.d.ts +1 -0
  275. package/dist/preload.js +21 -0
  276. package/dist/ref-watch.d.ts +31 -0
  277. package/dist/ref-watch.js +66 -0
  278. package/dist/ref.d.ts +124 -0
  279. package/dist/ref.js +272 -0
  280. package/dist/region-brand.d.ts +8 -0
  281. package/dist/region-brand.js +10 -0
  282. package/dist/region-core.d.ts +2 -0
  283. package/dist/region-core.js +1 -0
  284. package/dist/region-snippet.d.ts +73 -0
  285. package/dist/region-snippet.js +351 -0
  286. package/dist/region.d.ts +127 -0
  287. package/dist/region.js +162 -0
  288. package/dist/request-event.d.ts +1 -0
  289. package/dist/request-event.js +37 -0
  290. package/dist/router-css.d.ts +39 -0
  291. package/dist/router-css.js +66 -0
  292. package/dist/runtime/app-transport.d.ts +2 -0
  293. package/dist/runtime/app-transport.js +13 -0
  294. package/dist/runtime/beacon.d.ts +271 -0
  295. package/dist/runtime/beacon.js +2190 -0
  296. package/dist/runtime/boot-link.d.ts +1 -0
  297. package/dist/runtime/boot-link.js +44 -0
  298. package/dist/runtime/client-hooks.d.ts +5 -0
  299. package/dist/runtime/client-hooks.js +22 -0
  300. package/dist/runtime/client-plugins.d.ts +8 -0
  301. package/dist/runtime/client-plugins.js +34 -0
  302. package/dist/runtime/concurrency.d.ts +12 -0
  303. package/dist/runtime/concurrency.js +29 -0
  304. package/dist/runtime/connected.d.ts +12 -0
  305. package/dist/runtime/connected.js +16 -0
  306. package/dist/runtime/context.d.ts +1 -0
  307. package/dist/runtime/context.js +19 -0
  308. package/dist/runtime/core.d.ts +15 -0
  309. package/dist/runtime/core.js +1173 -0
  310. package/dist/runtime/drift-watch.d.ts +9 -0
  311. package/dist/runtime/drift-watch.js +60 -0
  312. package/dist/runtime/entry-locations.d.ts +33 -0
  313. package/dist/runtime/entry-locations.js +119 -0
  314. package/dist/runtime/foreign-props.d.ts +8 -0
  315. package/dist/runtime/foreign-props.js +14 -0
  316. package/dist/runtime/form-continuity.d.ts +10 -0
  317. package/dist/runtime/form-continuity.js +107 -0
  318. package/dist/runtime/frame-nav.d.ts +36 -0
  319. package/dist/runtime/frame-nav.js +225 -0
  320. package/dist/runtime/frame-store.d.ts +62 -0
  321. package/dist/runtime/frame-store.js +214 -0
  322. package/dist/runtime/frames.d.ts +1 -0
  323. package/dist/runtime/frames.js +25 -0
  324. package/dist/runtime/full.d.ts +4 -0
  325. package/dist/runtime/full.js +32 -0
  326. package/dist/runtime/hash.d.ts +41 -0
  327. package/dist/runtime/hash.js +79 -0
  328. package/dist/runtime/hole-facts.d.ts +8 -0
  329. package/dist/runtime/hole-facts.js +57 -0
  330. package/dist/runtime/host-classes.d.ts +24 -0
  331. package/dist/runtime/host-classes.js +43 -0
  332. package/dist/runtime/hydrate-core.d.ts +101 -0
  333. package/dist/runtime/hydrate-core.js +605 -0
  334. package/dist/runtime/index.d.ts +2 -0
  335. package/dist/runtime/index.js +1 -0
  336. package/dist/runtime/interaction-replay.d.ts +11 -0
  337. package/dist/runtime/interaction-replay.js +70 -0
  338. package/dist/runtime/interaction.d.ts +33 -0
  339. package/dist/runtime/interaction.js +217 -0
  340. package/dist/runtime/island-graph-preload.d.ts +13 -0
  341. package/dist/runtime/island-graph-preload.js +99 -0
  342. package/dist/runtime/kit-boot.d.ts +29 -0
  343. package/dist/runtime/kit-boot.js +60 -0
  344. package/dist/runtime/kit-page-thread.svelte.d.ts +1 -0
  345. package/dist/runtime/kit-page-thread.svelte.js +116 -0
  346. package/dist/runtime/lake-anchors.d.ts +13 -0
  347. package/dist/runtime/lake-anchors.js +19 -0
  348. package/dist/runtime/lakes.d.ts +15 -0
  349. package/dist/runtime/lakes.js +212 -0
  350. package/dist/runtime/live.d.ts +3 -0
  351. package/dist/runtime/live.js +17 -0
  352. package/dist/runtime/load-scheduler.d.ts +53 -0
  353. package/dist/runtime/load-scheduler.js +317 -0
  354. package/dist/runtime/morph.d.ts +42 -0
  355. package/dist/runtime/morph.js +671 -0
  356. package/dist/runtime/nav-handle.d.ts +25 -0
  357. package/dist/runtime/nav-handle.js +71 -0
  358. package/dist/runtime/nav-hooks.d.ts +2 -0
  359. package/dist/runtime/nav-hooks.js +23 -0
  360. package/dist/runtime/nearest-attr.d.ts +4 -0
  361. package/dist/runtime/nearest-attr.js +16 -0
  362. package/dist/runtime/observe.d.ts +27 -0
  363. package/dist/runtime/observe.js +63 -0
  364. package/dist/runtime/own-cost.d.ts +9 -0
  365. package/dist/runtime/own-cost.js +35 -0
  366. package/dist/runtime/ownership.d.ts +101 -0
  367. package/dist/runtime/ownership.js +115 -0
  368. package/dist/runtime/page-cache.d.ts +23 -0
  369. package/dist/runtime/page-cache.js +74 -0
  370. package/dist/runtime/page-defer.d.ts +14 -0
  371. package/dist/runtime/page-defer.js +103 -0
  372. package/dist/runtime/parse-html.d.ts +40 -0
  373. package/dist/runtime/parse-html.js +81 -0
  374. package/dist/runtime/reconcile.d.ts +41 -0
  375. package/dist/runtime/reconcile.js +194 -0
  376. package/dist/runtime/region-attrs.d.ts +95 -0
  377. package/dist/runtime/region-attrs.js +153 -0
  378. package/dist/runtime/region-endpoint-url.d.ts +76 -0
  379. package/dist/runtime/region-endpoint-url.js +169 -0
  380. package/dist/runtime/region-ids.d.ts +8 -0
  381. package/dist/runtime/region-ids.js +33 -0
  382. package/dist/runtime/remote-seeds.d.ts +2 -0
  383. package/dist/runtime/remote-seeds.js +21 -0
  384. package/dist/runtime/render-blocking.d.ts +2 -0
  385. package/dist/runtime/render-blocking.js +30 -0
  386. package/dist/runtime/restore.d.ts +34 -0
  387. package/dist/runtime/restore.js +390 -0
  388. package/dist/runtime/router-nav.d.ts +63 -0
  389. package/dist/runtime/router-nav.js +740 -0
  390. package/dist/runtime/router.d.ts +201 -0
  391. package/dist/runtime/router.js +593 -0
  392. package/dist/runtime/schedule.d.ts +49 -0
  393. package/dist/runtime/schedule.js +256 -0
  394. package/dist/runtime/seeds.d.ts +50 -0
  395. package/dist/runtime/seeds.js +208 -0
  396. package/dist/runtime/session.d.ts +52 -0
  397. package/dist/runtime/session.js +130 -0
  398. package/dist/runtime/sidecar.d.ts +3 -0
  399. package/dist/runtime/sidecar.js +56 -0
  400. package/dist/runtime/slots.d.ts +183 -0
  401. package/dist/runtime/slots.js +44 -0
  402. package/dist/runtime/spa-cacheable.d.ts +7 -0
  403. package/dist/runtime/spa-cacheable.js +18 -0
  404. package/dist/runtime/speculate-hint.d.ts +1 -0
  405. package/dist/runtime/speculate-hint.js +35 -0
  406. package/dist/runtime/svelte-warnings.d.ts +28 -0
  407. package/dist/runtime/svelte-warnings.js +71 -0
  408. package/dist/runtime/wire-classes.d.ts +3 -0
  409. package/dist/runtime/wire-classes.js +69 -0
  410. package/dist/runtime/wire-format.d.ts +7 -0
  411. package/dist/runtime/wire-format.js +22 -0
  412. package/dist/script.d.ts +134 -0
  413. package/dist/script.js +184 -0
  414. package/dist/seed-refs.d.ts +105 -0
  415. package/dist/seed-refs.js +487 -0
  416. package/dist/server/capability-lifetime.d.ts +28 -0
  417. package/dist/server/capability-lifetime.js +31 -0
  418. package/dist/server/dead-kit-resolves.d.ts +1 -0
  419. package/dist/server/dead-kit-resolves.js +39 -0
  420. package/dist/server/document-assembly.d.ts +30 -0
  421. package/dist/server/document-assembly.js +26 -0
  422. package/dist/server/document-tail.d.ts +113 -0
  423. package/dist/server/document-tail.js +208 -0
  424. package/dist/server/endpoint.d.ts +51 -0
  425. package/dist/server/endpoint.js +90 -0
  426. package/dist/server/entry-location.d.ts +8 -0
  427. package/dist/server/entry-location.js +29 -0
  428. package/dist/server/fingerprint.d.ts +1 -0
  429. package/dist/server/fingerprint.js +25 -0
  430. package/dist/server/head-presence.d.ts +45 -0
  431. package/dist/server/head-presence.js +156 -0
  432. package/dist/server/hmac.d.ts +38 -0
  433. package/dist/server/hmac.js +89 -0
  434. package/dist/server/hole-graph.d.ts +7 -0
  435. package/dist/server/hole-graph.js +71 -0
  436. package/dist/server/hole-urls.d.ts +3 -0
  437. package/dist/server/hole-urls.js +76 -0
  438. package/dist/server/html-scan.d.ts +19 -0
  439. package/dist/server/html-scan.js +60 -0
  440. package/dist/server/kit-context.d.ts +78 -0
  441. package/dist/server/kit-context.js +110 -0
  442. package/dist/server/late-wire.d.ts +22 -0
  443. package/dist/server/late-wire.js +28 -0
  444. package/dist/server/page-facts.d.ts +25 -0
  445. package/dist/server/page-facts.js +138 -0
  446. package/dist/server/page-seed.d.ts +33 -0
  447. package/dist/server/page-seed.js +60 -0
  448. package/dist/server/page-stream.d.ts +55 -0
  449. package/dist/server/page-stream.js +121 -0
  450. package/dist/server/payload.d.ts +6 -0
  451. package/dist/server/payload.js +22 -0
  452. package/dist/server/personal-response.d.ts +6 -0
  453. package/dist/server/personal-response.js +13 -0
  454. package/dist/server/props-wire.d.ts +56 -0
  455. package/dist/server/props-wire.js +178 -0
  456. package/dist/server/rate-limit.d.ts +22 -0
  457. package/dist/server/rate-limit.js +63 -0
  458. package/dist/server/region-css.d.ts +5 -0
  459. package/dist/server/region-css.js +30 -0
  460. package/dist/server/region-endpoint.d.ts +35 -0
  461. package/dist/server/region-endpoint.js +142 -0
  462. package/dist/server/region-props.d.ts +6 -0
  463. package/dist/server/region-props.js +44 -0
  464. package/dist/server/remote-seed-gate.d.ts +50 -0
  465. package/dist/server/remote-seed-gate.js +66 -0
  466. package/dist/server/render-cache.d.ts +26 -0
  467. package/dist/server/render-cache.js +51 -0
  468. package/dist/server/render-page.d.ts +51 -0
  469. package/dist/server/render-page.js +176 -0
  470. package/dist/server/render-region-html.d.ts +2 -0
  471. package/dist/server/render-region-html.js +19 -0
  472. package/dist/server/request-stats.d.ts +174 -0
  473. package/dist/server/request-stats.js +54 -0
  474. package/dist/server/reversible.d.ts +83 -0
  475. package/dist/server/reversible.js +994 -0
  476. package/dist/server/seed-shape.d.ts +22 -0
  477. package/dist/server/seed-shape.js +24 -0
  478. package/dist/server/shared-cache.d.ts +35 -0
  479. package/dist/server/shared-cache.js +104 -0
  480. package/dist/server/signing-key.d.ts +11 -0
  481. package/dist/server/signing-key.js +47 -0
  482. package/dist/server/sized-lru.d.ts +20 -0
  483. package/dist/server/sized-lru.js +68 -0
  484. package/dist/server/split-regions.d.ts +81 -0
  485. package/dist/server/split-regions.js +368 -0
  486. package/dist/server/stream-regions.d.ts +5 -0
  487. package/dist/server/stream-regions.js +36 -0
  488. package/dist/shared-state.d.ts +7 -0
  489. package/dist/shared-state.js +152 -0
  490. package/dist/shims/app-environment.d.ts +4 -0
  491. package/dist/shims/app-environment.js +6 -0
  492. package/dist/shims/app-navigation.d.ts +33 -0
  493. package/dist/shims/app-navigation.js +119 -0
  494. package/dist/shims/app-paths.d.ts +6 -0
  495. package/dist/shims/app-paths.js +18 -0
  496. package/dist/shims/app-state.svelte.d.ts +23 -0
  497. package/dist/shims/app-state.svelte.js +50 -0
  498. package/dist/shims/app-stores.d.ts +21 -0
  499. package/dist/shims/app-stores.js +54 -0
  500. package/dist/shims/kit-bridge.d.ts +29 -0
  501. package/dist/shims/kit-bridge.js +7 -0
  502. package/dist/shims/kit-remote/client-stub.d.ts +27 -0
  503. package/dist/shims/kit-remote/client-stub.js +43 -0
  504. package/dist/shims/kit-remote/paths-internal-stub.d.ts +3 -0
  505. package/dist/shims/kit-remote/paths-internal-stub.js +5 -0
  506. package/dist/shims/kit-remote/remote-cache.d.ts +49 -0
  507. package/dist/shims/kit-remote/remote-cache.js +73 -0
  508. package/dist/shims/kit-remote/state-stub.d.ts +8 -0
  509. package/dist/shims/kit-remote/state-stub.js +8 -0
  510. package/dist/shims/page-store.svelte.d.ts +39 -0
  511. package/dist/shims/page-store.svelte.js +77 -0
  512. package/dist/source.d.ts +29 -0
  513. package/dist/source.js +87 -0
  514. package/dist/store-transport.d.ts +86 -0
  515. package/dist/store-transport.js +229 -0
  516. package/dist/tool-fetches.d.ts +5 -0
  517. package/dist/tool-fetches.js +41 -0
  518. package/dist/transport.d.ts +48 -0
  519. package/dist/transport.js +181 -0
  520. package/dist/unscoped-css.d.ts +26 -0
  521. package/dist/unscoped-css.js +53 -0
  522. package/dist/vite/dev-maps.d.ts +33 -0
  523. package/dist/vite/dev-maps.js +140 -0
  524. package/dist/vite/index.d.ts +19 -0
  525. package/dist/vite/index.js +820 -0
  526. package/dist/vite/kit-dirs.d.ts +7 -0
  527. package/dist/vite/kit-dirs.js +67 -0
  528. package/dist/vite/late-island.d.ts +25 -0
  529. package/dist/vite/late-island.js +33 -0
  530. package/dist/vite/module-map.d.ts +8 -0
  531. package/dist/vite/module-map.js +144 -0
  532. package/dist/vite/options.d.ts +208 -0
  533. package/dist/vite/options.js +74 -0
  534. package/dist/vite/package-files.d.ts +3 -0
  535. package/dist/vite/package-files.js +84 -0
  536. package/dist/vite/paths.d.ts +45 -0
  537. package/dist/vite/paths.js +112 -0
  538. package/dist/vite/plugin-api.d.ts +166 -0
  539. package/dist/vite/plugin-api.js +212 -0
  540. package/dist/vite/profiler-maps.d.ts +23 -0
  541. package/dist/vite/profiler-maps.js +178 -0
  542. package/dist/vite/server-sourcemaps.d.ts +8 -0
  543. package/dist/vite/server-sourcemaps.js +80 -0
  544. package/dist/vite/sourcemaps.d.ts +18 -0
  545. package/dist/vite/sourcemaps.js +80 -0
  546. package/dist/vite/style-preprocess.d.ts +2 -0
  547. package/dist/vite/style-preprocess.js +96 -0
  548. package/package.json +180 -6
@@ -0,0 +1,2190 @@
1
+ import { hole_copy_of } from "./hash.js";
2
+ import { tool_made } from "../tool-fetches.js";
3
+ import { paint_blocker } from "./render-blocking.js";
4
+ import { critical_outcome } from "./load-scheduler.js";
5
+ import { devtools_switched_on } from "../insights/switch.js";
6
+ import { charge, metered } from "./own-cost.js";
7
+ // src/runtime/beacon.ts
8
+ /**
9
+ * THE BEACON — the browser's half of the profiler. When the document carries
10
+ * `<meta name="ogygia-profiler-beacon" content="/__profiler/beacon">` (the profiler puts it there
11
+ * for its own logged-in user, never for a visitor), this records what the browser saw of the page
12
+ * and hands it over twice: to the server (so a report on a long-lived host can join it) and to
13
+ * this browser's own IndexedDB (so a report on an ephemeral host, whose instance is gone before
14
+ * the report is opened, still gets it — the profiler UI on the same origin reads it back).
15
+ *
16
+ * What it records: each island's wake (trigger → modules loaded → `data-hydrated`, and whether the
17
+ * markup changed on the way), the app's own `mark()` timings, the web vitals, the whole VISIT —
18
+ * navigation timing, every resource with bytes and blocking status, paints with the island the
19
+ * largest paint sat in, long tasks, the first interaction per island, layout shifts with the
20
+ * island they hit — the islands' markup before and after hydration (browser store only), and a
21
+ * CPU trace of hydration where the browser allows one.
22
+ *
23
+ * Cost when the tag is absent: one `querySelector` on the first hydration, then a boolean. Nothing
24
+ * here runs on the hydration path itself: samples are batched and sent on idle or when the page
25
+ * hides.
26
+ */
27
+ let target;
28
+ let queue = [];
29
+ let scheduled = false;
30
+ let listening = false;
31
+ let marks = [];
32
+ const BEACON_KEY = Symbol.for("ogygia.beacon");
33
+ let self_api;
34
+ /** the page's owning copy when it is not this one, else null */
35
+ function owner() {
36
+ self_api ??= {
37
+ beacon_mark,
38
+ beacon_failed,
39
+ beacon_hydrated,
40
+ beacon_watch,
41
+ beacon_record_cpu,
42
+ beacon_page,
43
+ beacon_warning,
44
+ beacon_hole_failed,
45
+ beacon_hole_answered,
46
+ beacon_hole_batch_missed,
47
+ beacon_entry_fallback,
48
+ beacon_hole_fetched,
49
+ beacon_nav
50
+ };
51
+ const g = globalThis;
52
+ const o = g[BEACON_KEY] ??= self_api;
53
+ return o === self_api ? null : o;
54
+ }
55
+ if (typeof document !== "undefined") owner();
56
+ function beacon_mark(name, ms, attrs, t0) {
57
+ const o = owner();
58
+ if (o) return o.beacon_mark(name, ms, attrs, t0);
59
+ if (!collecting() || !name) return;
60
+ if (visit_marks.length >= 400) return;
61
+ if (endpoint() && marks.length < 400) marks.push({
62
+ name: String(name).slice(0, 120),
63
+ ms: Math.max(0, Math.round(ms * 100) / 100),
64
+ ...t0 !== void 0 ? { t0: Math.round(t0 * 100) / 100 } : {},
65
+ ...attrs ? { attrs } : {}
66
+ });
67
+ visit_marks.push({
68
+ name: String(name).slice(0, 120),
69
+ ms: Math.max(0, Math.round(ms * 100) / 100),
70
+ ...t0 !== void 0 ? { t0: Math.round(t0 * 100) / 100 } : {}
71
+ });
72
+ schedule();
73
+ }
74
+ let vitals = null;
75
+ let vitals_sent = false;
76
+ const ISLAND_SEL = "ogygia-region[data-og-fp]";
77
+ const r2 = (n) => Math.round(n * 100) / 100;
78
+ let visit_islands = [];
79
+ let visit_firsts = [];
80
+ /** the last inputs, any target (a ring): which island something touched while it hydrated */
81
+ const recent_inputs = [];
82
+ /** `name="value"` pairs of one start tag (`<a href="x" hidden>`), as the browser serializes them. */
83
+ function tag_attrs(tag) {
84
+ const out = /* @__PURE__ */ new Map();
85
+ let i = 1;
86
+ while (i < tag.length && tag[i] !== " " && tag[i] !== ">" && tag[i] !== "/") i++;
87
+ while (i < tag.length) {
88
+ while (i < tag.length && (tag[i] === " " || tag[i] === "\n" || tag[i] === " " || tag[i] === "/")) i++;
89
+ if (i >= tag.length || tag[i] === ">") break;
90
+ const start = i;
91
+ while (i < tag.length && tag[i] !== "=" && tag[i] !== " " && tag[i] !== ">") i++;
92
+ const name = tag.slice(start, i);
93
+ let value = "";
94
+ if (tag[i] === "=") {
95
+ i++;
96
+ const q = tag[i];
97
+ if (q === "\"" || q === "'") {
98
+ const end = tag.indexOf(q, i + 1);
99
+ value = tag.slice(i + 1, end === -1 ? tag.length : end);
100
+ i = end === -1 ? tag.length : end + 1;
101
+ } else {
102
+ const s = i;
103
+ while (i < tag.length && tag[i] !== " " && tag[i] !== ">") i++;
104
+ value = tag.slice(s, i);
105
+ }
106
+ }
107
+ if (name) out.set(name, value);
108
+ }
109
+ return out;
110
+ }
111
+ /** The tag's name, lowercase (`<qds-button …>` → `qds-button`). */
112
+ function tag_name(tag) {
113
+ let i = 1;
114
+ while (i < tag.length && tag[i] !== " " && tag[i] !== ">" && tag[i] !== "/" && tag[i] !== "\n") i++;
115
+ return tag.slice(1, i).toLowerCase();
116
+ }
117
+ /**
118
+ * When two markups (comments out) differ ONLY in attributes — the same elements in the same order, the
119
+ * same text — each attribute that differs (at most 20); `null` when text or elements differ. A walk of
120
+ * both strings tag by tag, no regex: it runs once per changed island.
121
+ */
122
+ function attr_changes(a, b) {
123
+ const out = [];
124
+ let i = 0;
125
+ let j = 0;
126
+ while (i < a.length || j < b.length) {
127
+ const ti = a.indexOf("<", i);
128
+ const tj = b.indexOf("<", j);
129
+ if (a.slice(i, ti === -1 ? a.length : ti) !== b.slice(j, tj === -1 ? b.length : tj)) return null;
130
+ if (ti === -1 || tj === -1) return ti === tj ? out : null;
131
+ const ei = a.indexOf(">", ti);
132
+ const ej = b.indexOf(">", tj);
133
+ const x = a.slice(ti, ei === -1 ? a.length : ei + 1);
134
+ const y = b.slice(tj, ej === -1 ? b.length : ej + 1);
135
+ i = ti + x.length;
136
+ j = tj + y.length;
137
+ if (x === y) continue;
138
+ const tag = tag_name(x);
139
+ if (tag !== tag_name(y) || x[1] === "/" || y[1] === "/") return null;
140
+ const xa = tag_attrs(x);
141
+ const ya = tag_attrs(y);
142
+ for (const [name, v] of xa) if (ya.get(name) !== v && out.length < 20) out.push({
143
+ tag,
144
+ name,
145
+ from: v,
146
+ to: ya.has(name) ? ya.get(name) : null
147
+ });
148
+ for (const [name, v] of ya) if (!xa.has(name) && out.length < 20) out.push({
149
+ tag,
150
+ name,
151
+ from: null,
152
+ to: v
153
+ });
154
+ }
155
+ return out;
156
+ }
157
+ let visit_shifts = [];
158
+ let visit_longtasks = [];
159
+ /** the long tasks are frames drawn late (a browser with no long-task timing): see watch_frame_gaps */
160
+ let longtasks_from_frames = false;
161
+ /** main-thread ms per script URL (query off), from long animation frames */
162
+ let visit_scripts = /* @__PURE__ */ new Map();
163
+ /** scripts that forced style and layout (5 ms or more), each with its window on the page's clock */
164
+ let visit_forced = [];
165
+ /** long frames (50 ms or more) that began while the page scrolled, with their two biggest scripts */
166
+ let visit_scroll_jank = [];
167
+ /** when the page scrolled lately (at most one stamp per 50 ms, the last 200): the long frames are
168
+ * delivered after the fact, so each is matched to the scrolls around its own start */
169
+ let scroll_times = [];
170
+ const scrolled_near = (t) => scroll_times.some((s) => s >= t - 150 && s <= t + 50);
171
+ let visit_interaction = null;
172
+ /** the slowest interaction's id and its span so far (its entries arrive one by one) */
173
+ let visit_interaction_id = 0;
174
+ let visit_interaction_span = null;
175
+ let visit_frames = [];
176
+ const MAX_FRAMES = 40;
177
+ /** Svelte's hydration warnings (dev): the server and the browser disagreed, Svelte kept the server's */
178
+ let visit_warnings = [];
179
+ function beacon_warning(w) {
180
+ const o = owner();
181
+ if (o) return o.beacon_warning(w);
182
+ if (!collecting()) return;
183
+ if (!make_room(visit_warnings, 50, (x) => x.t)) return;
184
+ visit_warnings.push(w);
185
+ if (early_visit_done) resend_soon();
186
+ }
187
+ let visit_holes_failed = [];
188
+ function beacon_hole_failed(h) {
189
+ const o = owner();
190
+ if (o) return o.beacon_hole_failed(h);
191
+ if (!collecting() || visit_holes_failed.length >= 30 || visit_holes_failed.some((x) => x.id === h.id)) return;
192
+ visit_holes_failed.push(h);
193
+ if (early_visit_done) resend_soon();
194
+ }
195
+ const FONT_EXT = /* @__PURE__ */ new Set([
196
+ "woff",
197
+ "woff2",
198
+ "ttf",
199
+ "otf"
200
+ ]);
201
+ const IMG_EXT = /* @__PURE__ */ new Set([
202
+ "png",
203
+ "jpg",
204
+ "jpeg",
205
+ "gif",
206
+ "webp",
207
+ "avif",
208
+ "svg"
209
+ ]);
210
+ const LINK_AS = {
211
+ style: "css",
212
+ script: "script",
213
+ font: "font",
214
+ image: "img",
215
+ fetch: "fetch"
216
+ };
217
+ /**
218
+ * A file's type, for the byte counts and the lanes: its extension first, then the `<link>` that
219
+ * fetched it (`as`), then what started it. A `link` initiator is NOT a stylesheet by itself: a
220
+ * `<link rel=preload>` fetches whatever its `as` says — a hole's preload fetches HTML, from a URL
221
+ * with no extension, and every first-screen hole answer landed in the CSS column (and One clock's
222
+ * CSS lane). (Chromium reports a modulepreload's initiator as `other`; its `.js` decides anyway.)
223
+ */
224
+ function resource_type(ext, initiator, link_as) {
225
+ if (FONT_EXT.has(ext)) return "font";
226
+ if (ext === "css") return "css";
227
+ if (ext === "js" || ext === "mjs") return "script";
228
+ if (IMG_EXT.has(ext)) return "img";
229
+ if (initiator === "link") return link_as && LINK_AS[link_as] || (link_as ? "other" : "css");
230
+ if (initiator === "css") return "css";
231
+ if (initiator === "script") return "script";
232
+ if (initiator === "img") return "img";
233
+ if (initiator === "fetch" || initiator === "xmlhttprequest" || initiator === "beacon") return "fetch";
234
+ return "other";
235
+ }
236
+ let visit_hole_batches = [];
237
+ /** The restorer's log (runtime/restore.ts `__og_restore_log`): its late and mismatched hosts. */
238
+ function restore_log() {
239
+ const log = globalThis.__og_restore_log;
240
+ return log?.length ? { restores: log.slice(0, 20) } : {};
241
+ }
242
+ function beacon_hole_batch_missed(m) {
243
+ const o = owner();
244
+ if (o) return o.beacon_hole_batch_missed?.(m);
245
+ if (!collecting() || visit_hole_batches.length >= 10) return;
246
+ const ids = [];
247
+ for (const e of m.endpoints.slice(0, 32)) try {
248
+ ids.push(new URL(e, location.href).searchParams.get("id") ?? "");
249
+ } catch {
250
+ ids.push("");
251
+ }
252
+ visit_hole_batches.push({
253
+ sent: m.sent,
254
+ delivered: m.delivered,
255
+ status: m.status,
256
+ ...m.refused ? { refused: m.refused } : {},
257
+ ...m.final_url ? { final_url: m.final_url.slice(0, 300) } : {},
258
+ ids
259
+ });
260
+ if (early_visit_done) resend_soon();
261
+ }
262
+ /** The browser's timing of the request that answered a hole: the latest one for its URL done by
263
+ * `by` (the swap). It may predate the runtime (the document preloads first-screen holes). `left`
264
+ * is when it went on the wire (`requestStart`: after any wait for a connection), not when it was
265
+ * asked for. Null when the resource buffer has none (full, or no Resource Timing). */
266
+ function hole_request_times(endpoint, by) {
267
+ try {
268
+ const url = new URL(endpoint, location.href).href;
269
+ let hit;
270
+ for (const e of performance.getEntriesByName(url, "resource")) if (e.responseStart > 0 && e.responseEnd <= by + 1) hit = e;
271
+ if (!hit) return null;
272
+ let queue;
273
+ let render;
274
+ for (const s of hit.serverTiming ?? []) if (s.name === "og-queue") queue = Math.round(s.duration);
275
+ else if (s.name === "og-render") render = Math.round(s.duration);
276
+ return {
277
+ left: Math.round(hit.requestStart || hit.startTime),
278
+ first: Math.round(hit.responseStart),
279
+ end: Math.round(hit.responseEnd),
280
+ ...queue !== void 0 ? { queue } : {},
281
+ ...render !== void 0 ? { render } : {}
282
+ };
283
+ } catch {}
284
+ return null;
285
+ }
286
+ let visit_holes_answered = [];
287
+ let visit_entry_fallbacks = [];
288
+ function beacon_entry_fallback(f) {
289
+ const o = owner();
290
+ if (o) return o.beacon_entry_fallback?.(f);
291
+ if (!collecting() || visit_entry_fallbacks.length >= 20 || visit_entry_fallbacks.some((x) => x.entry === f.entry)) return;
292
+ visit_entry_fallbacks.push({
293
+ entry: f.entry.slice(0, 300),
294
+ src: f.src.slice(0, 300),
295
+ recovered: f.recovered
296
+ });
297
+ if (early_visit_done) resend_soon();
298
+ }
299
+ /** each hole URL (absolute) → how many times the runtime asked the network for it */
300
+ let hole_fetches = /* @__PURE__ */ new Map();
301
+ /** The runtime asks for a hole's HTML (each ask, retries and re-asks included): what lets a
302
+ * preload followed by a download read as used-then-asked-again, not as a preload the browser could
303
+ * not use. */
304
+ function beacon_hole_fetched(endpoint) {
305
+ const o = owner();
306
+ if (o) return o.beacon_hole_fetched?.(endpoint);
307
+ if (!collecting() || hole_fetches.size >= 200) return;
308
+ try {
309
+ const url = new URL(endpoint, location.href).href;
310
+ hole_fetches.set(url, (hole_fetches.get(url) ?? 0) + 1);
311
+ } catch {}
312
+ }
313
+ let holes_answered_els = /* @__PURE__ */ new WeakSet();
314
+ /** A hole's first answer landed: the profiler weighs how long its fallback held the first screen.
315
+ * The element is read (id, place) only while measuring. */
316
+ function beacon_hole_answered(el, start, batch) {
317
+ const o = owner();
318
+ if (o) return o.beacon_hole_answered?.(el, start, batch);
319
+ if (!collecting() || visit_holes_answered.length >= 30) return;
320
+ let id = "";
321
+ try {
322
+ id = new URL(el.getAttribute("endpoint") ?? "", location.href).searchParams.get("id") ?? "";
323
+ } catch {
324
+ id = "";
325
+ }
326
+ if (!id || holes_answered_els.has(el)) return;
327
+ holes_answered_els.add(el);
328
+ const rect = el.getBoundingClientRect();
329
+ const times = batch ? {
330
+ left: Math.round(batch.left),
331
+ first: Math.round(batch.at),
332
+ end: Math.round(batch.at),
333
+ batch: batch.size
334
+ } : hole_request_times(el.getAttribute("endpoint") ?? "", performance.now());
335
+ visit_holes_answered.push({
336
+ id,
337
+ n: visit_holes_answered.length,
338
+ start: Math.round(start),
339
+ t: Math.round(performance.now()),
340
+ below_fold: rect.top + scrollY > innerHeight,
341
+ p: hole_copy_of(el.getAttribute("endpoint") ?? ""),
342
+ ...times
343
+ });
344
+ if (early_visit_done) resend_soon();
345
+ }
346
+ let visit_marks = [];
347
+ let visit_paints = {};
348
+ /** the largest paint's element: still in the document when the visit is read, or replaced (an
349
+ * island that rendered it again put a new one in its place — the hero painted twice). Only while
350
+ * its island is still there: an in-app navigation away takes both, and replaces nothing */
351
+ let lcp_el = null;
352
+ let lcp_region = null;
353
+ /** an island's markup as the server sent it and after it hydrated — the browser store only */
354
+ let snapshots = [];
355
+ let visit_sent = false;
356
+ const SNAPSHOT_CAP = 24e3;
357
+ const MAX_SNAPSHOTS = 40;
358
+ /** The snapshot of a changed island: whole when both fit, else the window around the change
359
+ * (`a`, `b`: the two markups without comments, already made for the compare). */
360
+ function snapshot_of(fp, ssr, now, a, b) {
361
+ if (ssr.length <= SNAPSHOT_CAP && now.length <= SNAPSHOT_CAP) return {
362
+ fp,
363
+ ssr,
364
+ hydrated: now
365
+ };
366
+ const n = Math.min(a.length, b.length);
367
+ let i = 0;
368
+ while (i < n && a.charCodeAt(i) === b.charCodeAt(i)) i++;
369
+ let from = Math.max(0, i - SNAPSHOT_CAP / 4);
370
+ const lt = a.indexOf("<", from);
371
+ if (lt !== -1 && lt <= i) from = lt;
372
+ return {
373
+ fp,
374
+ ssr: a.slice(from, from + SNAPSHOT_CAP),
375
+ hydrated: b.slice(from, from + SNAPSHOT_CAP),
376
+ from
377
+ };
378
+ }
379
+ const fp_of = (node) => {
380
+ return (node && node.nodeType === 1 ? node : node && node.nodeType === 3 ? node.parentElement : null)?.closest?.(ISLAND_SEL)?.getAttribute("data-og-fp") ?? void 0;
381
+ };
382
+ /** What was clicked, told briefly: `button "Save"`, `a#home`, `input[name=q]`. No selector engine. */
383
+ function describe_target(node) {
384
+ const el = node && node.nodeType === 1 ? node : node?.parentElement;
385
+ if (!el) return "";
386
+ const tag = el.tagName.toLowerCase();
387
+ const id = el.id ? `#${el.id.slice(0, 30)}` : "";
388
+ const name = el.getAttribute("name");
389
+ const label = el.getAttribute("aria-label") ?? (tag === "input" || tag === "select" || tag === "textarea" ? "" : (el.textContent ?? "").trim().slice(0, 30));
390
+ return `${tag}${id}${name ? `[name=${name.slice(0, 30)}]` : ""}${label ? ` "${label}"` : ""}`;
391
+ }
392
+ const rect_of = (r) => r ? [
393
+ Math.round(r.x),
394
+ Math.round(r.y),
395
+ Math.round(r.width),
396
+ Math.round(r.height)
397
+ ] : void 0;
398
+ /** every resource entry the observer saw (the browser's own buffer stops at 250 by default) */
399
+ let seen_resources = [];
400
+ const MAX_SEEN_RESOURCES = 3e3;
401
+ /** the files a visit lists one by one (the rest are in its totals by type) */
402
+ const MAX_DETAIL_RESOURCES = 200;
403
+ /** content-named files fetched again, at most (a page's own; the count past it is not worth more) */
404
+ const MAX_REFETCHED = 40;
405
+ /** text files (and the document) 4 KB or more sent without compression; the largest few by name */
406
+ const UNCOMPRESSED_MIN = 4096;
407
+ const MAX_UNCOMPRESSED = 10;
408
+ /** extensions that compress well (text, and wasm), whatever fetched them */
409
+ const TEXT_EXT = /* @__PURE__ */ new Set([
410
+ "js",
411
+ "mjs",
412
+ "css",
413
+ "html",
414
+ "htm",
415
+ "json",
416
+ "svg",
417
+ "txt",
418
+ "xml",
419
+ "map",
420
+ "wasm"
421
+ ]);
422
+ function observe_vitals() {
423
+ visit_page();
424
+ if (vitals || typeof PerformanceObserver === "undefined") return;
425
+ const v = vitals = {};
426
+ try {
427
+ const nav = performance.getEntriesByType("navigation")[0];
428
+ if (nav && nav.responseStart > 0) v.ttfb = r2(nav.responseStart);
429
+ } catch {}
430
+ const observe = (type, cb) => {
431
+ try {
432
+ new PerformanceObserver((list) => cb(list.getEntries())).observe({
433
+ type,
434
+ buffered: true,
435
+ ...type === "event" ? { durationThreshold: 16 } : {}
436
+ });
437
+ } catch {}
438
+ };
439
+ observe("paint", (entries) => {
440
+ for (const e of entries) if (e.name === "first-contentful-paint") v.fcp = visit_paints.fcp = r2(e.startTime);
441
+ });
442
+ try {
443
+ performance.setResourceTimingBufferSize(MAX_SEEN_RESOURCES);
444
+ } catch {}
445
+ observe("resource", (entries) => {
446
+ for (const e of entries) if (seen_resources.length < MAX_SEEN_RESOURCES) seen_resources.push(e);
447
+ });
448
+ observe("largest-contentful-paint", (entries) => {
449
+ const last = entries[entries.length - 1];
450
+ if (!last) return;
451
+ v.lcp = visit_paints.lcp = r2(last.startTime);
452
+ const fp = fp_of(last.element);
453
+ visit_paints.lcp_fp = fp;
454
+ visit_paints.lcp_url = last.url || void 0;
455
+ visit_paints.lcp_tag = last.element?.tagName?.toLowerCase();
456
+ visit_paints.lcp_lazy = last.element?.getAttribute?.("loading") === "lazy" ? true : void 0;
457
+ const pri = last.element?.getAttribute?.("fetchpriority");
458
+ visit_paints.lcp_priority = pri === "high" || pri === "low" ? pri : void 0;
459
+ lcp_el = last.element ?? null;
460
+ lcp_region = lcp_el?.closest("ogygia-region") ?? null;
461
+ if (early_visit_done) resend_soon();
462
+ });
463
+ let cls = 0;
464
+ try {
465
+ if (PerformanceObserver.supportedEntryTypes?.includes("layout-shift")) v.cls = 0;
466
+ } catch {}
467
+ observe("layout-shift", (entries) => {
468
+ for (const e of entries) {
469
+ if (e.hadRecentInput || typeof e.value !== "number") continue;
470
+ cls += e.value;
471
+ if (make_room(visit_shifts, 60, (s) => s.t)) {
472
+ const src = e.sources?.[0];
473
+ const tag = src?.node ? describe_target(src.node) : "";
474
+ visit_shifts.push({
475
+ t: r2(e.startTime),
476
+ value: Math.round(e.value * 1e4) / 1e4,
477
+ ...src?.node ? { fp: fp_of(src.node) } : {},
478
+ ...tag ? { tag } : {},
479
+ ...src?.previousRect ? { from: rect_of(src.previousRect) } : {},
480
+ ...src?.currentRect ? { to: rect_of(src.currentRect) } : {}
481
+ });
482
+ }
483
+ }
484
+ v.cls = Math.round(cls * 1e3) / 1e3;
485
+ if (early_visit_done) resend_soon();
486
+ });
487
+ observe("event", (entries) => {
488
+ for (const e of entries) {
489
+ if (!e.interactionId) continue;
490
+ const d = r2(e.duration);
491
+ const same = visit_interaction_id === e.interactionId;
492
+ if (!same && v.inp !== void 0 && d <= v.inp) continue;
493
+ if (v.inp === void 0 || d > v.inp) {
494
+ v.inp = d;
495
+ resend_soon();
496
+ }
497
+ const ps = e.processingStart ?? e.startTime;
498
+ const pe = e.processingEnd ?? ps;
499
+ const fold = same ? visit_interaction_span : null;
500
+ const span = visit_interaction_span = {
501
+ start: fold ? Math.min(fold.start, e.startTime) : e.startTime,
502
+ ps: fold ? Math.min(fold.ps, ps) : ps,
503
+ pe: fold ? Math.max(fold.pe, pe) : pe,
504
+ end: fold ? Math.max(fold.end, e.startTime + e.duration) : e.startTime + e.duration
505
+ };
506
+ visit_interaction_id = e.interactionId;
507
+ const named = !same || e.name === "click" || e.name === "keydown" ? e : null;
508
+ const fp = named ? fp_of(e.target) : visit_interaction?.fp;
509
+ visit_interaction = {
510
+ name: named ? e.name : visit_interaction.name,
511
+ t: r2(span.start),
512
+ ms: r2(span.end - span.start),
513
+ delay: r2(Math.max(0, span.ps - span.start)),
514
+ processing: r2(Math.max(0, span.pe - span.ps)),
515
+ presentation: r2(Math.max(0, span.end - span.pe)),
516
+ target: named ? describe_target(e.target) || visit_interaction?.target || "" : visit_interaction.target,
517
+ ...fp ? { fp } : {}
518
+ };
519
+ }
520
+ if (visit_interaction) interaction_seen(visit_interaction);
521
+ });
522
+ observe("longtask", (entries) => {
523
+ for (const e of entries) if (make_room(visit_longtasks, 100, (l) => l.t)) visit_longtasks.push({
524
+ t: r2(e.startTime),
525
+ ms: r2(e.duration)
526
+ });
527
+ });
528
+ if (!supports("longtask")) watch_frame_gaps();
529
+ observe("long-animation-frame", (entries) => {
530
+ for (const e of entries) {
531
+ if (early_visit_done) resend_soon();
532
+ if (e.duration >= 50 && scrolled_near(e.startTime) && make_room(visit_scroll_jank, 20, (j) => j.start)) visit_scroll_jank.push({
533
+ start: r2(e.startTime),
534
+ ms: r2(e.duration),
535
+ scripts: (e.scripts ?? []).slice().sort((a, b) => (b.duration ?? 0) - (a.duration ?? 0)).slice(0, 2).map((s) => ({
536
+ url: (s.sourceURL ?? "").slice(0, 300),
537
+ fn: (s.sourceFunctionName ?? "").slice(0, 80),
538
+ invoker: (s.invoker ?? "").slice(0, 120),
539
+ ms: r2(s.duration ?? 0)
540
+ }))
541
+ });
542
+ for (const s of e.scripts ?? []) if ((s.forcedStyleAndLayoutDuration ?? 0) >= 5 && make_room(visit_forced, 30, (f) => f.start)) {
543
+ const start = s.startTime ?? e.startTime;
544
+ visit_forced.push({
545
+ start: r2(start),
546
+ end: r2(start + (s.duration ?? 0)),
547
+ ms: r2(s.forcedStyleAndLayoutDuration ?? 0),
548
+ url: (s.sourceURL ?? "").slice(0, 300),
549
+ fn: (s.sourceFunctionName ?? "").slice(0, 80)
550
+ });
551
+ }
552
+ visit_frames.push({
553
+ start: r2(e.startTime),
554
+ end: r2(e.startTime + e.duration),
555
+ scripts: (e.scripts ?? []).slice(0, 8).map((s) => ({
556
+ url: (s.sourceURL ?? "").slice(0, 300),
557
+ fn: (s.sourceFunctionName ?? "").slice(0, 80),
558
+ invoker: (s.invoker ?? "").slice(0, 120),
559
+ start: r2(s.startTime ?? e.startTime),
560
+ ms: r2(s.duration ?? 0),
561
+ ...(s.forcedStyleAndLayoutDuration ?? 0) >= 1 ? { forced: r2(s.forcedStyleAndLayoutDuration) } : {}
562
+ }))
563
+ });
564
+ if (visit_frames.length > MAX_FRAMES) visit_frames.shift();
565
+ for (const s of e.scripts ?? []) {
566
+ const url = s.sourceURL ?? "";
567
+ if (!url || !(s.duration && s.duration > 0)) continue;
568
+ const q = url.indexOf("?");
569
+ const key = (q === -1 ? url : url.slice(0, q)).slice(0, 300);
570
+ const cur = visit_scripts.get(key);
571
+ if (cur) {
572
+ cur.ms += s.duration;
573
+ cur.count++;
574
+ } else if (visit_scripts.size < 100) visit_scripts.set(key, {
575
+ ms: s.duration,
576
+ count: 1
577
+ });
578
+ }
579
+ }
580
+ });
581
+ const note_input = (type) => (ev) => {
582
+ if (!(ev.target instanceof Element)) return;
583
+ recent_inputs.push({
584
+ t: performance.now(),
585
+ el: new WeakRef(ev.target),
586
+ type
587
+ });
588
+ if (recent_inputs.length > 64) recent_inputs.shift();
589
+ };
590
+ try {
591
+ for (const type of [
592
+ "pointerover",
593
+ "pointerdown",
594
+ "keydown",
595
+ "focusin"
596
+ ]) document.addEventListener(type, note_input(type), {
597
+ capture: true,
598
+ passive: true
599
+ });
600
+ } catch {}
601
+ const seen = /* @__PURE__ */ new Set();
602
+ const first = (type) => (ev) => {
603
+ const fp = fp_of(ev.target);
604
+ if (!fp || seen.has(fp)) return;
605
+ seen.add(fp);
606
+ const at = ev.timeStamp > 0 && ev.timeStamp <= performance.now() ? ev.timeStamp : performance.now();
607
+ visit_firsts.push({
608
+ fp,
609
+ t: r2(at),
610
+ type
611
+ });
612
+ };
613
+ try {
614
+ document.addEventListener("pointerdown", first("pointer"), {
615
+ capture: true,
616
+ passive: true
617
+ });
618
+ document.addEventListener("keydown", first("key"), {
619
+ capture: true,
620
+ passive: true
621
+ });
622
+ document.addEventListener("scroll", () => {
623
+ const t = performance.now();
624
+ if (scroll_times.length && t - scroll_times[scroll_times.length - 1] < 50) return;
625
+ scroll_times.push(t);
626
+ if (scroll_times.length > 200) scroll_times.shift();
627
+ }, {
628
+ capture: true,
629
+ passive: true
630
+ });
631
+ } catch {}
632
+ }
633
+ /** sendBeacon and a keepalive fetch both refuse a body over 64 KB (UTF-16 length, with room) */
634
+ const KEEPALIVE_MAX = 6e4;
635
+ /** KEEPALIVE BYTES STILL QUEUED. The 64 KB cap is on everything a page has queued at once — every
636
+ * beacon and keepalive fetch not yet sent — not on each: a hide sends the islands, the vitals, the
637
+ * visit and the trace together, and Safari refused the rest once they passed it ("reached maximum
638
+ * amount of queued data"), the visit among them. A keepalive fetch is held until it settles; a
639
+ * beacon, which says nothing back, for the task that sent it — the burst a hide makes is what
640
+ * overflows, and one sent a moment earlier (the early visit) has left by then. */
641
+ let keepalive_queued = 0;
642
+ const BEACON_HOLD_MS = 0;
643
+ /** the hide's own sends: the page is going away whatever its visibility reads (a link or a reload
644
+ * fires pagehide on a page still "visible") */
645
+ let leaving = false;
646
+ function hold_keepalive(bytes, settled) {
647
+ keepalive_queued += bytes;
648
+ const release = () => {
649
+ keepalive_queued = Math.max(0, keepalive_queued - bytes);
650
+ };
651
+ if (settled) settled.finally(release);
652
+ else setTimeout(release, BEACON_HOLD_MS);
653
+ }
654
+ /** what a keepalive request may still carry */
655
+ function keepalive_room() {
656
+ return KEEPALIVE_MAX - keepalive_queued;
657
+ }
658
+ /** `slim`: the same message without what earlier messages already delivered, for a page going
659
+ * away with a body too big to leave (the server keeps the longest file list and merges regions).
660
+ * A page with ~300 islands sent 100 KB: refused by both, and the fetch's rejection went unhandled,
661
+ * so the profiler never got that page's browser side at all. */
662
+ function send(body, slim) {
663
+ const url = endpoint();
664
+ if (!url) return;
665
+ const post = (b, keepalive) => {
666
+ try {
667
+ const settled = fetch(url, {
668
+ method: "POST",
669
+ body: b,
670
+ keepalive,
671
+ credentials: "same-origin",
672
+ headers: { "content-type": "text/plain" }
673
+ }).catch(() => {});
674
+ if (keepalive) hold_keepalive(b.length, settled);
675
+ } catch {}
676
+ };
677
+ const room = keepalive_room();
678
+ if (body.length > room) {
679
+ if (typeof document === "undefined" || !leaving && document.visibilityState === "visible") return post(body, false);
680
+ const s = slim?.();
681
+ if (!s || s.length > room) return;
682
+ body = s;
683
+ }
684
+ try {
685
+ if (typeof navigator !== "undefined" && navigator.sendBeacon && navigator.sendBeacon(url, body)) {
686
+ hold_keepalive(body.length);
687
+ return;
688
+ }
689
+ } catch {}
690
+ post(body, true);
691
+ }
692
+ function flush_vitals() {
693
+ if (vitals_sent || !vitals || !Object.keys(vitals).length) return;
694
+ vitals_sent = true;
695
+ send(JSON.stringify({
696
+ page: visit_page(),
697
+ at: Math.round(performance.timeOrigin),
698
+ vitals
699
+ }));
700
+ }
701
+ /** The navigation's steps before its first byte, each only when it took time (ms). */
702
+ function nav_phases(n) {
703
+ const p = {};
704
+ const put = (k, v) => {
705
+ if (v > .5) p[k] = r2(v);
706
+ };
707
+ put("redirect", n.redirectEnd - n.redirectStart);
708
+ if (n.workerStart > 0) put("worker", n.fetchStart - n.workerStart);
709
+ put("dns", n.domainLookupEnd - n.domainLookupStart);
710
+ const tls = n.secureConnectionStart > 0 ? n.connectEnd - n.secureConnectionStart : 0;
711
+ put("connect", n.connectEnd - n.connectStart - tls);
712
+ put("tls", tls);
713
+ put("wait", n.responseStart - n.requestStart);
714
+ return Object.keys(p).length ? { phases: p } : {};
715
+ }
716
+ /** The slowest interaction with the scripts of the long frames it overlapped, each put in the phase
717
+ * it started in: `delay` (the input waited behind it), `handler` (it ran the interaction's
718
+ * handlers), `paint` (after them, before the next frame). The heaviest few. */
719
+ function interaction_with_scripts(i) {
720
+ const end = i.t + i.ms;
721
+ const handlers_at = i.t + i.delay;
722
+ const paint_at = handlers_at + i.processing;
723
+ const out = [];
724
+ for (const f of visit_frames) {
725
+ if (f.end < i.t || f.start > end) continue;
726
+ for (const s of f.scripts) {
727
+ if (s.start + s.ms < i.t || s.start > end || !(s.ms > 0)) continue;
728
+ const phase = s.start < handlers_at ? "delay" : s.start <= paint_at ? "handler" : "paint";
729
+ out.push({
730
+ url: s.url,
731
+ fn: s.fn,
732
+ invoker: s.invoker,
733
+ ms: s.ms,
734
+ phase,
735
+ ...s.forced ? { forced: s.forced } : {}
736
+ });
737
+ }
738
+ }
739
+ out.sort((a, b) => b.ms - a.ms);
740
+ return out.length ? {
741
+ ...i,
742
+ scripts: out.slice(0, 6)
743
+ } : { ...i };
744
+ }
745
+ let faces_memo = null;
746
+ /** The `@font-face` rules behind the fonts this page fetched: each family, its `font-display`
747
+ * (`auto` when unset), and the fetched files its `src` names. What says whether a late font left
748
+ * its text invisible. A cross-origin sheet the browser will not let us read is left out. No regex. */
749
+ function font_faces_of(fetched) {
750
+ if (!fetched.size) return [];
751
+ const key = [...fetched].join("\n");
752
+ if (faces_memo?.key === key) return faces_memo.faces;
753
+ const out = [];
754
+ faces_memo = {
755
+ key,
756
+ faces: out
757
+ };
758
+ for (const sheet of document.styleSheets) {
759
+ let rules;
760
+ try {
761
+ rules = sheet.cssRules;
762
+ } catch {
763
+ continue;
764
+ }
765
+ for (const rule of rules) {
766
+ if (out.length >= 12) return out;
767
+ if (!(rule instanceof CSSFontFaceRule)) continue;
768
+ const style = rule.style;
769
+ const src = style.getPropertyValue("src");
770
+ const urls = [];
771
+ let at = src.indexOf("url(");
772
+ while (at !== -1 && urls.length < 6) {
773
+ const end = src.indexOf(")", at);
774
+ if (end === -1) break;
775
+ const raw = src.slice(at + 4, end).trim().split("\"").join("").split("'").join("");
776
+ try {
777
+ const url = new URL(raw, sheet.href ?? location.href).href.slice(0, 500);
778
+ if (fetched.has(url)) urls.push(url);
779
+ } catch {}
780
+ at = src.indexOf("url(", end);
781
+ }
782
+ if (!urls.length) continue;
783
+ const family = style.getPropertyValue("font-family").trim().split("\"").join("").split("'").join("").slice(0, 80);
784
+ out.push({
785
+ family,
786
+ display: style.getPropertyValue("font-display").trim() || "auto",
787
+ urls
788
+ });
789
+ }
790
+ }
791
+ return out;
792
+ }
793
+ /** IMAGES SENT FAR BIGGER THAN SHOWN: a loaded raster `<img>` whose pixels are at least 4× what
794
+ * its box shows on this screen (its device pixel ratio counted), and whose file is 50 KB or more —
795
+ * the bytes past what the box shows are bytes nobody sees. A hidden image (no box), a vector one,
796
+ * and one whose size the browser will not tell (cross-origin, no Timing-Allow-Origin) are left out.
797
+ * One layout read per send, at most 300 images. No regex. */
798
+ function oversized_images() {
799
+ const out = [];
800
+ const dpr = devicePixelRatio || 1;
801
+ const imgs = document.images;
802
+ for (let i = 0; i < imgs.length && i < 300 && out.length < 10; i++) {
803
+ const img = imgs[i];
804
+ if (!img.complete || !img.naturalWidth || !img.naturalHeight) continue;
805
+ const url = img.currentSrc || img.src;
806
+ if (!url || url.startsWith("data:")) continue;
807
+ const q = url.indexOf("?");
808
+ if ((q === -1 ? url : url.slice(0, q)).toLowerCase().endsWith(".svg")) continue;
809
+ const w = img.clientWidth;
810
+ const h = img.clientHeight;
811
+ if (!w || !h) continue;
812
+ if (img.naturalWidth * img.naturalHeight < w * h * dpr * dpr * 4) continue;
813
+ const e = performance.getEntriesByName(url, "resource")[0];
814
+ const bytes = e ? e.encodedBodySize || e.transferSize : 0;
815
+ if (bytes < 5e4) continue;
816
+ const fp = fp_of(img);
817
+ out.push({
818
+ url: url.slice(0, 500),
819
+ natural: [img.naturalWidth, img.naturalHeight],
820
+ shown: [w, h],
821
+ dpr: r2(dpr),
822
+ bytes,
823
+ ...fp ? { fp } : {}
824
+ });
825
+ }
826
+ return out;
827
+ }
828
+ /** PRELOADED, NEVER USED: a `<link rel="preload">` of an image, a font or a stylesheet the page
829
+ * fetched and, 3 s after load (when the browser itself warns), nothing on the page uses — no
830
+ * `<img>` / `srcset` / CSS rule names the image, no `@font-face` the font, no stylesheet link the
831
+ * sheet. Its bytes competed with what the first screen needed. A responsive preload
832
+ * (`imagesrcset`) and anything a cross-origin sheet might use are left out (it cannot be read).
833
+ * Asked once, after that moment; null before it. No regex. */
834
+ let preloads_memo = null;
835
+ function preloads_never_used(load_end) {
836
+ if (preloads_memo) return preloads_memo;
837
+ if (!(load_end > 0) || performance.now() - load_end < 3e3) return null;
838
+ const out = [];
839
+ const links = document.querySelectorAll("link[rel=\"preload\"][href][as]");
840
+ const css = [];
841
+ let opaque = false;
842
+ const faces = /* @__PURE__ */ new Set();
843
+ let sheets_read = false;
844
+ const read_sheets = () => {
845
+ if (sheets_read) return;
846
+ sheets_read = true;
847
+ for (const sheet of document.styleSheets) {
848
+ let rules;
849
+ try {
850
+ rules = sheet.cssRules;
851
+ } catch {
852
+ opaque = true;
853
+ continue;
854
+ }
855
+ for (const rule of rules) if (rule instanceof CSSFontFaceRule) {
856
+ const src = rule.style.getPropertyValue("src");
857
+ let at = src.indexOf("url(");
858
+ while (at !== -1) {
859
+ const end = src.indexOf(")", at);
860
+ if (end === -1) break;
861
+ try {
862
+ faces.add(new URL(src.slice(at + 4, end).trim().split("\"").join("").split("'").join(""), sheet.href ?? location.href).href);
863
+ } catch {}
864
+ at = src.indexOf("url(", end);
865
+ }
866
+ } else css.push(rule.cssText);
867
+ }
868
+ };
869
+ for (let i = 0; i < links.length && i < 30; i++) {
870
+ const l = links[i];
871
+ const as = l.getAttribute("as") ?? "";
872
+ if (as !== "image" && as !== "font" && as !== "style" || l.hasAttribute("imagesrcset")) continue;
873
+ const url = l.href;
874
+ const e = performance.getEntriesByName(url, "resource")[0];
875
+ if (!e) continue;
876
+ let used = false;
877
+ if (as === "style") {
878
+ for (const s of document.querySelectorAll("link[rel=\"stylesheet\"][href]")) if (s.href === url) used = true;
879
+ } else if (as === "image") {
880
+ for (const img of document.images) if (img.currentSrc === url || img.src === url || img.srcset && img.srcset.includes(l.getAttribute("href") ?? url)) used = true;
881
+ if (!used) {
882
+ for (const s of document.querySelectorAll("source[srcset]")) if ((s.getAttribute("srcset") ?? "").includes(l.getAttribute("href") ?? url)) used = true;
883
+ }
884
+ if (!used) {
885
+ read_sheets();
886
+ const raw = l.getAttribute("href") ?? url;
887
+ used = opaque || css.some((t) => t.includes(url) || t.includes(raw));
888
+ }
889
+ } else {
890
+ read_sheets();
891
+ used = opaque || faces.has(url);
892
+ }
893
+ if (!used) out.push({
894
+ url: url.slice(0, 500),
895
+ as,
896
+ bytes: e.encodedBodySize || e.transferSize || 0
897
+ });
898
+ }
899
+ preloads_memo = out;
900
+ return out;
901
+ }
902
+ let dom_memo = null;
903
+ function dom_shape() {
904
+ const n = document.getElementsByTagName("*").length;
905
+ if (dom_memo?.n === n) return dom_memo.shape;
906
+ let shape = null;
907
+ if (n >= 6e4) shape = {
908
+ nodes: n,
909
+ depth: 0,
910
+ deepest: "",
911
+ widest: {
912
+ at: "",
913
+ children: 0
914
+ },
915
+ islands: []
916
+ };
917
+ else if (n >= 1500) {
918
+ const brief = (el) => {
919
+ let cls = "";
920
+ for (const c of el.classList) if (!c.startsWith("svelte-")) {
921
+ cls = c;
922
+ break;
923
+ }
924
+ return `${el.tagName.toLowerCase()}${el.id ? `#${el.id.slice(0, 30)}` : cls ? `.${cls.slice(0, 30)}` : ""}`;
925
+ };
926
+ let depth = 0;
927
+ const root = document.documentElement;
928
+ let deepest = root;
929
+ let widest = root;
930
+ let widest_n = root.childElementCount;
931
+ let el = root;
932
+ let d = 1;
933
+ while (el) {
934
+ if (d > depth) {
935
+ depth = d;
936
+ deepest = el;
937
+ }
938
+ const kids = el.childElementCount;
939
+ if (kids > widest_n) {
940
+ widest_n = kids;
941
+ widest = el;
942
+ }
943
+ const first = el.firstElementChild;
944
+ if (first) {
945
+ el = first;
946
+ d++;
947
+ continue;
948
+ }
949
+ while (el && el !== root && !el.nextElementSibling) {
950
+ el = el.parentElement;
951
+ d--;
952
+ }
953
+ el = el && el !== root ? el.nextElementSibling : null;
954
+ }
955
+ const islands = [];
956
+ for (const r of document.querySelectorAll(ISLAND_SEL)) {
957
+ const fp = r.getAttribute("data-og-fp");
958
+ if (fp) islands.push({
959
+ fp,
960
+ nodes: r.getElementsByTagName("*").length
961
+ });
962
+ }
963
+ islands.sort((a, b) => b.nodes - a.nodes);
964
+ shape = {
965
+ nodes: n,
966
+ depth,
967
+ deepest: brief(deepest),
968
+ widest: {
969
+ at: brief(widest),
970
+ children: widest_n
971
+ },
972
+ islands: islands.slice(0, 3)
973
+ };
974
+ }
975
+ dom_memo = {
976
+ n,
977
+ shape
978
+ };
979
+ return shape;
980
+ }
981
+ /** IMAGES THE BROWSER COULD NOT HOLD ROOM FOR: an `<img>` with a box whose computed aspect-ratio is
982
+ * `auto` — no width and height attributes (they make it `auto W / H`) and no CSS aspect-ratio —
983
+ * so the page below moved when its file arrived. A hidden one (no box, a hidden parent too) is
984
+ * left out. Their srcs, the first 8. */
985
+ function images_unsized() {
986
+ const out = [];
987
+ const imgs = document.images;
988
+ for (let i = 0; i < imgs.length && i < 300 && out.length < 8; i++) {
989
+ const img = imgs[i];
990
+ if (img.hasAttribute("width") && img.hasAttribute("height")) continue;
991
+ if (!img.getClientRects().length) continue;
992
+ if (getComputedStyle(img).aspectRatio !== "auto") continue;
993
+ const src = img.currentSrc || img.src;
994
+ if (src && !src.startsWith("data:")) out.push(src.slice(0, 300));
995
+ }
996
+ return out;
997
+ }
998
+ /** IMAGES FAR BELOW THE FIRST SCREEN THAT LOADED AT START: a raster `<img>` whose top sits more
999
+ * than a screen and a half down the document, not `loading="lazy"`, its file 20 KB or more, and
1000
+ * fetched before the page's load ended — its bytes competed with the first screen's files. A
1001
+ * hidden image (no box) is left out. Positions are the document's (the scroll added back). */
1002
+ function images_eager_below(load_end) {
1003
+ const out = [];
1004
+ const fold = innerHeight * 1.5;
1005
+ const imgs = document.images;
1006
+ for (let i = 0; i < imgs.length && i < 300 && out.length < 10; i++) {
1007
+ const img = imgs[i];
1008
+ if (img.loading === "lazy") continue;
1009
+ const url = img.currentSrc || img.src;
1010
+ if (!url || url.startsWith("data:")) continue;
1011
+ const r = img.getBoundingClientRect();
1012
+ if (!r.width || !r.height) continue;
1013
+ const top = Math.round(r.top + scrollY);
1014
+ if (top < fold) continue;
1015
+ const e = performance.getEntriesByName(url, "resource")[0];
1016
+ if (!e || load_end > 0 && e.startTime > load_end) continue;
1017
+ const bytes = e.encodedBodySize || e.transferSize || 0;
1018
+ if (bytes < 2e4) continue;
1019
+ const fp = fp_of(img);
1020
+ out.push({
1021
+ url: url.slice(0, 500),
1022
+ top,
1023
+ bytes,
1024
+ ...fp ? { fp } : {}
1025
+ });
1026
+ }
1027
+ return out;
1028
+ }
1029
+ /** the visit as one object: the server's copy has no snapshots (they are big and the browser
1030
+ * store keeps them) */
1031
+ function build_visit() {
1032
+ return metered("visit", build_visit_now);
1033
+ }
1034
+ function build_visit_now() {
1035
+ let nav;
1036
+ try {
1037
+ nav = performance.getEntriesByType("navigation")[0];
1038
+ } catch {
1039
+ nav = void 0;
1040
+ }
1041
+ if (!nav || !(nav.responseEnd > 0 || nav.domInteractive > 0)) return null;
1042
+ const start_hidden = !(nav.responseStart > 0);
1043
+ const ext_of = (name) => {
1044
+ const q = name.indexOf("?");
1045
+ const path = q === -1 ? name : name.slice(0, q);
1046
+ const dot = path.lastIndexOf(".");
1047
+ return dot > path.lastIndexOf("/") ? path.slice(dot + 1).toLowerCase() : "";
1048
+ };
1049
+ const link_as = /* @__PURE__ */ new Map();
1050
+ const link_co = /* @__PURE__ */ new Map();
1051
+ try {
1052
+ for (const l of document.querySelectorAll("link[href][as], link[rel=\"modulepreload\"][href]")) {
1053
+ link_as.set(l.href, l.getAttribute("as") ?? "script");
1054
+ link_co.set(l.href, l.getAttribute("crossorigin"));
1055
+ }
1056
+ } catch {}
1057
+ const preload_misses = [];
1058
+ const type_of = (r) => resource_type(ext_of(r.name), r.initiatorType, link_as.get(r.name));
1059
+ let resources = [];
1060
+ const refetched = [];
1061
+ const totals = /* @__PURE__ */ new Map();
1062
+ let all_n = 0;
1063
+ const uncompressed = [];
1064
+ const raw_seen = /* @__PURE__ */ new Set();
1065
+ try {
1066
+ const all = (seen_resources.length ? seen_resources : performance.getEntriesByType("resource")).filter((r) => !r.name.includes("/__profiler/") && !tool_made(r));
1067
+ all_n = all.length;
1068
+ for (const r of all) {
1069
+ const type = type_of(r);
1070
+ const t = totals.get(type) ?? {
1071
+ type,
1072
+ count: 0,
1073
+ transfer: 0,
1074
+ size: 0
1075
+ };
1076
+ t.count++;
1077
+ t.transfer += r.transferSize || 0;
1078
+ t.size += r.decodedBodySize || 0;
1079
+ totals.set(type, t);
1080
+ if (r.decodedBodySize >= UNCOMPRESSED_MIN && r.encodedBodySize >= r.decodedBodySize && !raw_seen.has(r.name) && (type === "script" || type === "style" || TEXT_EXT.has(ext_of(r.name)) || r.initiatorType === "fetch" || r.initiatorType === "xmlhttprequest")) {
1081
+ raw_seen.add(r.name);
1082
+ uncompressed.push({
1083
+ url: r.name.slice(0, 500),
1084
+ type,
1085
+ bytes: r.decodedBodySize
1086
+ });
1087
+ }
1088
+ }
1089
+ uncompressed.sort((a, b) => b.bytes - a.bytes);
1090
+ uncompressed.length = Math.min(uncompressed.length, MAX_UNCOMPRESSED);
1091
+ const by_url = /* @__PURE__ */ new Map();
1092
+ for (const r of all) (by_url.get(r.name) ?? by_url.set(r.name, []).get(r.name)).push(r);
1093
+ for (const [url, list] of by_url) {
1094
+ if (list.length < 2 || preload_misses.length >= 20) continue;
1095
+ const pre = list.find((r) => r.initiatorType === "link");
1096
+ const downloads = list.filter((r) => r !== pre && r.initiatorType !== "link" && r.encodedBodySize > 0 && r.transferSize >= r.encodedBodySize);
1097
+ const again = downloads[0];
1098
+ if ((pre?.responseStatus ?? 0) >= 400) continue;
1099
+ if (downloads.length < (hole_fetches.get(url) ?? 0)) continue;
1100
+ if (pre && again) preload_misses.push({
1101
+ url: url.slice(0, 500),
1102
+ type: type_of(pre),
1103
+ bytes: again.transferSize,
1104
+ as: link_as.get(url) ?? "",
1105
+ crossorigin: link_co.get(url) ?? null,
1106
+ ...hole_fetches.has(url) ? { hole: true } : {}
1107
+ });
1108
+ }
1109
+ const reload = nav.type === "reload";
1110
+ const origin = location.origin;
1111
+ const entry_of = /* @__PURE__ */ new Map();
1112
+ for (const el of document.querySelectorAll("ogygia-region[src][entry]")) {
1113
+ const src = el.getAttribute("src");
1114
+ try {
1115
+ const host = el.parentElement?.closest("ogygia-region[endpoint]");
1116
+ const hole = host ? new URL(host.getAttribute("endpoint"), location.href).searchParams.get("id") ?? "" : "";
1117
+ entry_of.set(new URL(src, document.baseURI).href, {
1118
+ entry: el.getAttribute("entry"),
1119
+ ...hole ? { hole: hole.slice(0, 40) } : {}
1120
+ });
1121
+ } catch {}
1122
+ }
1123
+ const runtime_src = document.querySelector("script[data-ogygia-runtime]")?.src ?? "";
1124
+ const counted = /* @__PURE__ */ new Set();
1125
+ for (const r of all) {
1126
+ if (refetched.length >= MAX_REFETCHED || counted.has(r.name) || !r.name.startsWith(origin) || !r.name.includes("/immutable/")) continue;
1127
+ const body = r.encodedBodySize;
1128
+ if (!(r.transferSize > 0)) continue;
1129
+ const how = body === 0 || r.transferSize < body ? "revalidated" : reload ? "downloaded" : null;
1130
+ if (!how) continue;
1131
+ counted.add(r.name);
1132
+ const island = entry_of.get(r.name);
1133
+ refetched.push({
1134
+ url: r.name.slice(0, 500),
1135
+ how,
1136
+ bytes: body,
1137
+ ms: r2(r.duration),
1138
+ ...island ? {
1139
+ entry: island.entry.slice(0, 300),
1140
+ ...island.hole ? { hole: island.hole } : {}
1141
+ } : {},
1142
+ ...r.name === runtime_src ? { runtime: true } : {}
1143
+ });
1144
+ }
1145
+ const blocking = paint_blocker();
1146
+ const keep = all.filter(blocking).slice(0, MAX_DETAIL_RESOURCES);
1147
+ const lcp_res = visit_paints.lcp_url ? all.find((r) => r.name === visit_paints.lcp_url) : void 0;
1148
+ if (lcp_res && !keep.includes(lcp_res)) keep.push(lcp_res);
1149
+ const kept = new Set(keep);
1150
+ for (const pass of [false, true]) for (const r of all) {
1151
+ if (keep.length >= MAX_DETAIL_RESOURCES) break;
1152
+ if (kept.has(r) || type_of(r) === "script" !== pass) continue;
1153
+ kept.add(r);
1154
+ keep.push(r);
1155
+ }
1156
+ keep.sort((a, b) => a.startTime - b.startTime);
1157
+ resources = keep.map((r) => ({
1158
+ url: r.name.slice(0, 500),
1159
+ type: type_of(r),
1160
+ start: r2(r.startTime),
1161
+ end: r2(r.responseEnd || r.startTime + r.duration),
1162
+ ...r.requestStart ? { req_start: r2(r.requestStart) } : {},
1163
+ ...r.responseStart ? { res_start: r2(r.responseStart) } : {},
1164
+ ...r.transferSize ? { transfer: r.transferSize } : {},
1165
+ ...r.decodedBodySize ? { size: r.decodedBodySize } : {},
1166
+ ...blocking(r) ? { blocking: true } : {}
1167
+ }));
1168
+ } catch {
1169
+ resources = [];
1170
+ }
1171
+ let fonts = [];
1172
+ try {
1173
+ fonts = font_faces_of(new Set(resources.filter((r) => r.type === "font").map((r) => r.url)));
1174
+ } catch {}
1175
+ let oversized = [];
1176
+ let dom = null;
1177
+ let wasted = null;
1178
+ let below = [];
1179
+ let unsized = null;
1180
+ try {
1181
+ oversized = oversized_images();
1182
+ below = images_eager_below(nav.loadEventEnd);
1183
+ unsized = images_unsized();
1184
+ dom = dom_shape();
1185
+ wasted = preloads_never_used(nav.loadEventEnd);
1186
+ } catch {}
1187
+ return {
1188
+ at: Math.round(performance.timeOrigin),
1189
+ origin: location.origin,
1190
+ ...unsupported_types(),
1191
+ nav: {
1192
+ ...start_hidden ? { start_hidden: true } : {
1193
+ req_start: r2(nav.requestStart),
1194
+ res_start: r2(nav.responseStart)
1195
+ },
1196
+ ...nav.responseEnd > 0 ? { res_end: r2(nav.responseEnd) } : {},
1197
+ ...nav.domInteractive ? { dom_interactive: r2(nav.domInteractive) } : {},
1198
+ ...nav.domContentLoadedEventEnd ? { dcl: r2(nav.domContentLoadedEventEnd) } : {},
1199
+ ...nav.loadEventEnd ? { load: r2(nav.loadEventEnd) } : {},
1200
+ ...nav.transferSize ? { transfer: nav.transferSize } : {},
1201
+ ...nav.decodedBodySize ? { size: nav.decodedBodySize } : {},
1202
+ ...nav.decodedBodySize >= UNCOMPRESSED_MIN && nav.encodedBodySize >= nav.decodedBodySize ? { raw: true } : {},
1203
+ ...nav.nextHopProtocol ? { protocol: nav.nextHopProtocol } : {},
1204
+ ...nav_phases(nav),
1205
+ ...nav.serverTiming?.length ? { server_timing: nav.serverTiming.slice(0, 8).map((s) => ({
1206
+ name: s.name.slice(0, 40),
1207
+ ms: r2(s.duration),
1208
+ ...s.description ? { desc: s.description.slice(0, 80) } : {}
1209
+ })) } : {}
1210
+ },
1211
+ paints: {
1212
+ ...visit_paints,
1213
+ ...lcp_el && !lcp_el.isConnected && lcp_region?.isConnected ? { lcp_replaced: true } : {},
1214
+ ...critical_outcome() ? { held: critical_outcome() } : {}
1215
+ },
1216
+ resources,
1217
+ ...all_n > resources.length ? {
1218
+ resource_totals: [...totals.values()],
1219
+ resources_all: all_n
1220
+ } : {},
1221
+ ...preload_misses.length ? { preload_misses } : {},
1222
+ ...uncompressed.length ? { uncompressed } : {},
1223
+ ...fonts.length ? { font_faces: fonts } : {},
1224
+ ...oversized.length ? { images_oversized: oversized } : {},
1225
+ ...dom ? { dom } : {},
1226
+ ...wasted?.length ? { preloads_unused: wasted } : {},
1227
+ ...below.length ? { images_eager_below: below } : {},
1228
+ ...unsized ? { images_unsized: unsized } : {},
1229
+ ...visit_forced.length ? { forced_layout: visit_forced.slice() } : {},
1230
+ ...visit_scroll_jank.length ? { scroll_jank: visit_scroll_jank.slice() } : {},
1231
+ ...refetched.length ? { refetched } : {},
1232
+ ...visit_navs.length ? { navs: visit_navs.slice() } : {},
1233
+ longtasks: visit_longtasks,
1234
+ ...longtasks_from_frames ? { longtasks_from: "frames" } : {},
1235
+ ...island_boxes ? { shifts_from: "boxes" } : {},
1236
+ islands: visit_islands,
1237
+ firsts: visit_firsts,
1238
+ shifts: visit_shifts,
1239
+ ...visit_interaction ? { interaction: interaction_with_scripts(visit_interaction) } : {},
1240
+ ...visit_scripts.size ? { scripts: [...visit_scripts].map(([url, s]) => ({
1241
+ url,
1242
+ ms: r2(s.ms),
1243
+ count: s.count
1244
+ })).sort((a, b) => b.ms - a.ms).slice(0, 50) } : {},
1245
+ regions: visit_regions(),
1246
+ ...visit_warnings.length ? { warnings: visit_warnings.slice() } : {},
1247
+ ...visit_holes_failed.length ? { holes_failed: visit_holes_failed.slice() } : {},
1248
+ ...visit_holes_answered.length ? { holes_answered: visit_holes_answered.slice() } : {},
1249
+ ...visit_hole_batches.length ? { hole_batches: visit_hole_batches.slice() } : {},
1250
+ ...restore_log(),
1251
+ ...visit_entry_fallbacks.length ? { entry_fallbacks: visit_entry_fallbacks.slice() } : {},
1252
+ ...visit_marks.length ? { marks: visit_marks } : {},
1253
+ ...vitals && Object.keys(vitals).length ? { vitals: { ...vitals } } : {},
1254
+ viewport: [innerWidth, innerHeight],
1255
+ ua: navigator.userAgent.slice(0, 200),
1256
+ ...(() => {
1257
+ const at = globalThis[Symbol.for("ogygia.dock-open-at")];
1258
+ return typeof at === "number" ? { dock_open_at: r2(at) } : {};
1259
+ })()
1260
+ };
1261
+ }
1262
+ /** The visit goes out twice: EARLY (on the first idle, so the store has it even if the page is
1263
+ * torn down before a write on hide can finish) and FINAL (on hide, with the last paints, the
1264
+ * islands' final markup and the shifts). The server and the store fold the two by navigation
1265
+ * start. */
1266
+ /**
1267
+ * THE PAGE A VISIT BELONGS TO: the one the document loaded as. The visit is the document's whole
1268
+ * story — its load, its vitals, and every in-app navigation after it (the router's body swaps keep
1269
+ * the document) — so it, its vitals and its CPU traces are filed under the page the visitor landed
1270
+ * on, never under wherever the address bar is when a later message leaves: a navigation to /b then
1271
+ * filed the rest of /a's visit (the navigation itself among it) under /b, where /a's report never
1272
+ * looks. Read at boot (observe_vitals), and on first use after a reset.
1273
+ */
1274
+ let landing_page = null;
1275
+ function visit_page() {
1276
+ if (landing_page === null && typeof location !== "undefined") landing_page = location.pathname;
1277
+ return landing_page ?? "/";
1278
+ }
1279
+ function flush_visit(final) {
1280
+ if (visit_sent) return;
1281
+ const visit = build_visit();
1282
+ if (!visit) return;
1283
+ if (final) {
1284
+ visit_sent = true;
1285
+ for (const s of snapshots) {
1286
+ const el = document.querySelector(`ogygia-region[data-og-fp="${s.fp}"]`);
1287
+ if (el) {
1288
+ const html = s.from === void 0 ? el.innerHTML : without_runtime_marks(without_comments(el.innerHTML)).slice(s.from, s.from + SNAPSHOT_CAP);
1289
+ if (html !== s.hydrated) s.final = html.slice(0, SNAPSHOT_CAP);
1290
+ }
1291
+ }
1292
+ }
1293
+ if (!endpoint()) return;
1294
+ send(JSON.stringify({
1295
+ page: visit_page(),
1296
+ visit
1297
+ }), () => {
1298
+ const no_files = JSON.stringify({
1299
+ page: visit_page(),
1300
+ visit: {
1301
+ ...visit,
1302
+ resources: []
1303
+ }
1304
+ });
1305
+ return no_files.length <= keepalive_room() ? no_files : JSON.stringify({
1306
+ page: visit_page(),
1307
+ visit: {
1308
+ ...visit,
1309
+ resources: [],
1310
+ regions: [],
1311
+ islands: []
1312
+ }
1313
+ });
1314
+ });
1315
+ store_visit({
1316
+ key: `${visit_page()}|${visit.at}`,
1317
+ page: visit_page(),
1318
+ at: visit.at,
1319
+ visit,
1320
+ snapshots
1321
+ });
1322
+ }
1323
+ const DB_NAME = "ogygia-profiler";
1324
+ const DB_VERSION = 1;
1325
+ function open_db() {
1326
+ return new Promise((resolve) => {
1327
+ try {
1328
+ const req = indexedDB.open(DB_NAME, DB_VERSION);
1329
+ req.onupgradeneeded = () => {
1330
+ const db = req.result;
1331
+ if (!db.objectStoreNames.contains("reports")) db.createObjectStore("reports", { keyPath: "id" });
1332
+ if (!db.objectStoreNames.contains("visits")) db.createObjectStore("visits", { keyPath: "key" });
1333
+ };
1334
+ req.onsuccess = () => resolve(req.result);
1335
+ req.onerror = () => resolve(null);
1336
+ req.onblocked = () => resolve(null);
1337
+ } catch {
1338
+ resolve(null);
1339
+ }
1340
+ });
1341
+ }
1342
+ async function store_visit(rec) {
1343
+ const db = await open_db();
1344
+ if (!db) return;
1345
+ try {
1346
+ const store = db.transaction("visits", "readwrite").objectStore("visits");
1347
+ const prior = store.get(rec.key);
1348
+ prior.onsuccess = () => {
1349
+ const old = prior.result;
1350
+ if (old) {
1351
+ const union = (xs, ys, key) => {
1352
+ const m = /* @__PURE__ */ new Map();
1353
+ for (const x of xs ?? []) m.set(key(x), x);
1354
+ for (const y of ys ?? []) m.set(key(y), y);
1355
+ return [...m.values()];
1356
+ };
1357
+ const ov = old.visit;
1358
+ const nv = rec.visit;
1359
+ const arr = (o) => Array.isArray(o) ? o : [];
1360
+ rec = {
1361
+ ...rec,
1362
+ visit: {
1363
+ ...ov,
1364
+ ...nv,
1365
+ nav: {
1366
+ ...ov.nav,
1367
+ ...nv.nav
1368
+ },
1369
+ paints: {
1370
+ ...ov.paints,
1371
+ ...nv.paints
1372
+ },
1373
+ islands: union(arr(ov.islands), arr(nv.islands), (i) => `${i.fp}|${i.t0}`),
1374
+ firsts: union(arr(ov.firsts), arr(nv.firsts), (f) => String(f.fp)),
1375
+ shifts: union(arr(ov.shifts), arr(nv.shifts), (s) => `${s.t}|${s.value}`),
1376
+ longtasks: union(arr(ov.longtasks), arr(nv.longtasks), (l) => `${l.t}|${l.ms}`),
1377
+ marks: union(arr(ov.marks), arr(nv.marks), (m) => `${m.name}|${m.t0 ?? ""}|${m.ms}`),
1378
+ resources: arr(nv.resources).length >= arr(ov.resources).length ? nv.resources : ov.resources
1379
+ },
1380
+ snapshots: union(old.snapshots, rec.snapshots, (s) => s.fp)
1381
+ };
1382
+ }
1383
+ store.put(rec);
1384
+ const all = store.getAllKeys();
1385
+ all.onsuccess = () => {
1386
+ const keys = all.result.sort();
1387
+ for (const k of keys.slice(0, Math.max(0, keys.length - 30))) store.delete(k);
1388
+ };
1389
+ };
1390
+ } catch {}
1391
+ }
1392
+ let cpu = null;
1393
+ let cpu_sent = false;
1394
+ const CPU_WINDOW_MS = 8e3;
1395
+ /** devtools: the load trace, and any recording started from the Page tab, kept in the page */
1396
+ let cpu_kept = [];
1397
+ /** why there is no trace: 'unsupported' (no API), 'no-policy' (the document did not opt in) */
1398
+ let cpu_off = null;
1399
+ let cpu_started_at = 0;
1400
+ function make_profiler() {
1401
+ const Ctor = globalThis.Profiler;
1402
+ if (!Ctor) {
1403
+ cpu_off = "unsupported";
1404
+ return null;
1405
+ }
1406
+ try {
1407
+ return new Ctor({
1408
+ sampleInterval: 10,
1409
+ maxBufferSize: 3e4
1410
+ });
1411
+ } catch {
1412
+ cpu_off = "no-policy";
1413
+ return null;
1414
+ }
1415
+ }
1416
+ /** islands that failed to hydrate (never `data-hydrated`), with the error: the CPU window does not
1417
+ * wait for them, and the visit reports them */
1418
+ const failed_fps = /* @__PURE__ */ new Map();
1419
+ let visit_navs = [];
1420
+ function beacon_nav(n) {
1421
+ const o = owner();
1422
+ if (o) return o.beacon_nav?.(n);
1423
+ if (!collecting() || visit_navs.length >= 20) return;
1424
+ let split = {};
1425
+ try {
1426
+ const entries = n.href ? performance.getEntriesByName(n.href) : [];
1427
+ let e;
1428
+ for (const x of entries) if (x.initiatorType === "fetch" && x.responseEnd <= n.fetched + 1 && (!e || x.startTime > e.startTime)) e = x;
1429
+ if (e && e.responseStart > 0) {
1430
+ const asked = e.requestStart > 0 ? e.requestStart : e.startTime;
1431
+ split = {
1432
+ server: r2(Math.max(0, e.responseStart - asked)),
1433
+ download: r2(Math.max(0, e.responseEnd - e.responseStart)),
1434
+ ...e.transferSize || e.encodedBodySize ? { bytes: e.transferSize || e.encodedBodySize } : {},
1435
+ ...e.startTime < n.t - 1 ? { prefetched: true } : {}
1436
+ };
1437
+ }
1438
+ } catch {
1439
+ split = {};
1440
+ }
1441
+ if (first_nav_t === void 0) {
1442
+ first_nav_t = n.t;
1443
+ snapshot_firsts = snapshots.length;
1444
+ }
1445
+ visit_navs.push({
1446
+ from: n.from.slice(0, 300),
1447
+ to: n.to.slice(0, 300),
1448
+ type: (n.type || "link").slice(0, 20),
1449
+ t: r2(n.t),
1450
+ fetched: r2(n.fetched),
1451
+ styled: r2(n.styled),
1452
+ swapped: r2(n.swapped),
1453
+ ...split
1454
+ });
1455
+ resend_soon();
1456
+ }
1457
+ function beacon_failed(el, message, since, turn) {
1458
+ const o = owner();
1459
+ if (o) return o.beacon_failed(el, message, since, turn);
1460
+ if (!collecting()) return;
1461
+ const fp = el.getAttribute("data-og-fp");
1462
+ if (!fp) return;
1463
+ failed_fps.set(fp, (message ?? "").slice(0, 300));
1464
+ if (typeof since === "number") failed_spans.set(fp, [r2(since), r2(performance.now())]);
1465
+ if (typeof turn === "number") failed_turns.set(fp, r2(turn));
1466
+ }
1467
+ const failed_spans = /* @__PURE__ */ new Map();
1468
+ const failed_turns = /* @__PURE__ */ new Map();
1469
+ const MEASURED_TYPES = [
1470
+ "layout-shift",
1471
+ "longtask",
1472
+ "event",
1473
+ "largest-contentful-paint",
1474
+ "long-animation-frame"
1475
+ ];
1476
+ /** whether this browser can observe an entry type */
1477
+ function supports(type) {
1478
+ try {
1479
+ return (PerformanceObserver.supportedEntryTypes ?? []).includes(type);
1480
+ } catch {
1481
+ return false;
1482
+ }
1483
+ }
1484
+ /**
1485
+ * WHAT A WAKE MOVED, where the browser reports no layout shifts (Safari): each island's box as the
1486
+ * server drew it, noted at boot before any island wakes, and again once it woke. An island whose
1487
+ * height changed while its bottom sat on the screen moved its content by that much: a shift, scored
1488
+ * the way a layout shift traced to it is (its box's share of the screen × how far, against the
1489
+ * screen's larger side), on the island's fingerprint. An estimate — content moving inside a box of
1490
+ * the same height is not seen — and the visit says its shifts are these (`shifts_from: 'boxes'`).
1491
+ */
1492
+ let island_boxes = null;
1493
+ /** an element's box: its own, or — a region draws no box of its own — its children's together */
1494
+ function box_of(el) {
1495
+ const r = el.getBoundingClientRect();
1496
+ if (r.width || r.height) return {
1497
+ top: r.top,
1498
+ bottom: r.bottom,
1499
+ left: r.left,
1500
+ width: r.width
1501
+ };
1502
+ let top = Infinity;
1503
+ let bottom = -Infinity;
1504
+ let left = Infinity;
1505
+ let right = -Infinity;
1506
+ for (const c of el.children) {
1507
+ const b = c.getBoundingClientRect();
1508
+ if (!b.width && !b.height) continue;
1509
+ top = Math.min(top, b.top);
1510
+ bottom = Math.max(bottom, b.bottom);
1511
+ left = Math.min(left, b.left);
1512
+ right = Math.max(right, b.right);
1513
+ }
1514
+ return top === Infinity ? null : {
1515
+ top,
1516
+ bottom,
1517
+ left,
1518
+ width: right - left
1519
+ };
1520
+ }
1521
+ function note_island_boxes() {
1522
+ if (island_boxes || typeof innerHeight === "undefined") return;
1523
+ island_boxes = /* @__PURE__ */ new WeakMap();
1524
+ for (const el of document.querySelectorAll("ogygia-region[data-og-fp]:not([data-hydrated])")) {
1525
+ const b = box_of(el);
1526
+ if (b) island_boxes.set(el, {
1527
+ top: b.top + scrollY,
1528
+ height: b.bottom - b.top
1529
+ });
1530
+ }
1531
+ }
1532
+ /** when a woken island's box is looked at again: two frames on (what its mount drew a frame later —
1533
+ * a banner opened in a requestAnimationFrame), and half a second on (inside the 600 ms a wake's
1534
+ * shifts are counted against it) */
1535
+ const BOX_LOOK_AGAIN_MS = 500;
1536
+ function estimate_wake_shift(el, fp, t) {
1537
+ const before = island_boxes?.get(el);
1538
+ if (!before) return;
1539
+ island_boxes.delete(el);
1540
+ let last = before;
1541
+ const look = (at) => {
1542
+ const moved = box_shift(el, fp, last, at);
1543
+ if (moved) last = moved;
1544
+ };
1545
+ look(t);
1546
+ if (typeof requestAnimationFrame !== "undefined") requestAnimationFrame(() => requestAnimationFrame(() => look(performance.now())));
1547
+ setTimeout(() => look(performance.now()), BOX_LOOK_AGAIN_MS);
1548
+ }
1549
+ /** the island's box against `before`: a shift when its height changed with its bottom on the screen;
1550
+ * the box it has now (the next look's `before`), or null when nothing moved */
1551
+ function box_shift(el, fp, before, t) {
1552
+ const after = box_of(el);
1553
+ if (!after) return null;
1554
+ const dh = after.bottom - after.top - before.height;
1555
+ if (Math.abs(dh) < 1) return null;
1556
+ const now = {
1557
+ top: after.top + scrollY,
1558
+ height: after.bottom - after.top
1559
+ };
1560
+ const vw = innerWidth;
1561
+ const vh = innerHeight;
1562
+ if (before.top - scrollY + before.height >= vh) return now;
1563
+ const moved = Math.min(Math.abs(dh), vh);
1564
+ const seen = Math.max(0, Math.min(vh, after.bottom) - Math.max(0, after.top));
1565
+ const value = Math.round(seen * Math.min(after.width, vw) / (vh * vw) * (moved / Math.max(vw, vh)) * 1e4) / 1e4;
1566
+ if (value < 1e-4 || !make_room(visit_shifts, 60, (s) => s.t)) return now;
1567
+ const tag = describe_target(el);
1568
+ visit_shifts.push({
1569
+ t: r2(t),
1570
+ value,
1571
+ fp,
1572
+ ...tag ? { tag } : {},
1573
+ from: [
1574
+ Math.round(after.left),
1575
+ Math.round(before.top - scrollY),
1576
+ Math.round(after.width),
1577
+ Math.round(before.height)
1578
+ ],
1579
+ to: [
1580
+ Math.round(after.left),
1581
+ Math.round(after.top),
1582
+ Math.round(after.width),
1583
+ Math.round(after.bottom - after.top)
1584
+ ]
1585
+ });
1586
+ if (early_visit_done) resend_soon();
1587
+ return now;
1588
+ }
1589
+ /** a frame's budget at 60 Hz, and how late a frame must be to count: a long task's 50 ms */
1590
+ const FRAME_MS = 1e3 / 60;
1591
+ const STALL_MS = 50;
1592
+ /** how long past the load event the frames are watched, and never past this from the start */
1593
+ const FRAMES_AFTER_LOAD_MS = 3e3;
1594
+ const FRAMES_MAX_MS = 2e4;
1595
+ /**
1596
+ * A browser with no long-task timing (Safari): every long-task finding went silent there. The frames
1597
+ * the page draws stand in — from its first frame (none comes while the paint is blocked, so a slow
1598
+ * stylesheet is never a stall) until a few seconds after the load event, a frame that came more than
1599
+ * 50 ms past its budget means the main thread was held that long. Each is kept as a long task, and
1600
+ * the visit says its long tasks are frame gaps. A hidden page draws no frames: a gap across a hide is
1601
+ * not counted.
1602
+ */
1603
+ function watch_frame_gaps() {
1604
+ if (longtasks_from_frames || typeof requestAnimationFrame === "undefined" || typeof document === "undefined") return;
1605
+ longtasks_from_frames = true;
1606
+ let last = 0;
1607
+ const tick = (now) => {
1608
+ if (document.visibilityState !== "visible") last = 0;
1609
+ else {
1610
+ const late = last ? now - last - FRAME_MS : 0;
1611
+ if (late > STALL_MS && make_room(visit_longtasks, 100, (l) => l.t)) visit_longtasks.push({
1612
+ t: r2(last + FRAME_MS),
1613
+ ms: r2(late)
1614
+ });
1615
+ last = now;
1616
+ }
1617
+ const loaded = performance.getEntriesByType("navigation")[0]?.loadEventEnd || 0;
1618
+ if (now >= FRAMES_MAX_MS || loaded && now >= loaded + FRAMES_AFTER_LOAD_MS) return;
1619
+ requestAnimationFrame(tick);
1620
+ };
1621
+ requestAnimationFrame(tick);
1622
+ }
1623
+ /** `{ unsupported: [...] }` for the entry types this browser cannot observe, or `{}`. */
1624
+ function unsupported_types() {
1625
+ let types = [];
1626
+ try {
1627
+ types = PerformanceObserver.supportedEntryTypes ?? [];
1628
+ } catch {
1629
+ return { unsupported: MEASURED_TYPES.slice() };
1630
+ }
1631
+ const missing = MEASURED_TYPES.filter((t) => !types.includes(t));
1632
+ return missing.length ? { unsupported: missing } : {};
1633
+ }
1634
+ /** Every region on the page as the visit ends: where it sits (document px, so the server can tell
1635
+ * the first screen from below it), how it wakes, whether it woke, and a failure's error. One
1636
+ * layout read per region, when a visit message is built (idle or hide), never on the hydrate path. */
1637
+ function visit_regions() {
1638
+ const out = [];
1639
+ try {
1640
+ const sy = typeof scrollY === "number" ? scrollY : 0;
1641
+ for (const el of document.querySelectorAll("ogygia-region[data-og-fp]")) {
1642
+ if (out.length >= 400) break;
1643
+ const fp = el.getAttribute("data-og-fp");
1644
+ let box = el.getBoundingClientRect();
1645
+ if (!box.height && !box.width) for (const c of el.children) {
1646
+ const b = c.getBoundingClientRect();
1647
+ if (b.height || b.width) {
1648
+ box = b;
1649
+ break;
1650
+ }
1651
+ }
1652
+ const failed = failed_fps.get(fp);
1653
+ out.push({
1654
+ fp,
1655
+ ...el.getAttribute("entry") ? { entry: el.getAttribute("entry") } : {},
1656
+ ...el.getAttribute("wake") ? { wake: el.getAttribute("wake") } : {},
1657
+ ...el.getAttribute("render") === "defer" ? { defer: true } : {},
1658
+ ...el.hasAttribute("data-hydrated") ? { hydrated: true } : {},
1659
+ ...failed !== void 0 ? {
1660
+ failed,
1661
+ ...failed_spans.has(fp) ? { failed_span: failed_spans.get(fp) } : {},
1662
+ ...failed_turns.has(fp) ? { failed_turn: failed_turns.get(fp) } : {}
1663
+ } : {},
1664
+ top: Math.round(box.top + sy),
1665
+ height: Math.round(box.height),
1666
+ ...!box.height && !box.width ? {
1667
+ hidden: true,
1668
+ ...is_headless(el) ? { headless: true } : {}
1669
+ } : {}
1670
+ });
1671
+ }
1672
+ } catch {}
1673
+ return out;
1674
+ }
1675
+ /** a slow device can still be waking islands at 8 s: keep sampling while one woke in the last
1676
+ * 1.5 s, up to 20 s — else the hydration the trace is for would be cut off */
1677
+ const CPU_WINDOW_MAX_MS = 2e4;
1678
+ const CPU_QUIET_MS = 1500;
1679
+ function start_cpu() {
1680
+ if (cpu || cpu_sent || !collecting()) return;
1681
+ cpu = make_profiler();
1682
+ if (!cpu) return;
1683
+ cpu_started_at = performance.now();
1684
+ const check = () => {
1685
+ const now = performance.now();
1686
+ const last = visit_islands.length ? visit_islands[visit_islands.length - 1].done : 0;
1687
+ let waiting = false;
1688
+ try {
1689
+ for (const el of document.querySelectorAll("ogygia-region[data-og-fp]:not([data-hydrated]):not([wake]):not([render=\"defer\"]), ogygia-region[data-og-fp][wake=\"load\"]:not([data-hydrated])")) if (!failed_fps.has(el.getAttribute("data-og-fp") ?? "")) {
1690
+ waiting = true;
1691
+ break;
1692
+ }
1693
+ } catch {
1694
+ waiting = false;
1695
+ }
1696
+ if ((now - last < CPU_QUIET_MS || waiting) && now - cpu_started_at < CPU_WINDOW_MAX_MS) setTimeout(check, CPU_QUIET_MS);
1697
+ else flush_cpu(false);
1698
+ };
1699
+ setTimeout(check, CPU_WINDOW_MS);
1700
+ }
1701
+ async function flush_cpu(hiding) {
1702
+ if (!cpu || cpu_sent) return;
1703
+ const p = cpu;
1704
+ cpu = null;
1705
+ cpu_sent = true;
1706
+ let trace;
1707
+ try {
1708
+ trace = await p.stop();
1709
+ } catch {
1710
+ return;
1711
+ }
1712
+ if (DEVTOOLS && trace) cpu_kept = [{
1713
+ trace,
1714
+ from: cpu_started_at,
1715
+ to: performance.now(),
1716
+ label: "page load"
1717
+ }, ...cpu_kept.slice(0, 4)];
1718
+ if (!hiding) start_interaction_cpu();
1719
+ const url = endpoint();
1720
+ if (!url || !trace) return;
1721
+ const body = JSON.stringify({
1722
+ page: visit_page(),
1723
+ cpu: trace
1724
+ });
1725
+ const keepalive = hiding && body.length <= keepalive_room();
1726
+ if (hiding && !keepalive) return;
1727
+ try {
1728
+ const settled = fetch(url, {
1729
+ method: "POST",
1730
+ body,
1731
+ credentials: "same-origin",
1732
+ headers: { "content-type": "text/plain" },
1733
+ ...keepalive ? { keepalive: true } : {}
1734
+ }).catch(() => {});
1735
+ if (keepalive) hold_keepalive(body.length, settled);
1736
+ } catch {}
1737
+ }
1738
+ let icpu = null;
1739
+ let icpu_timer = null;
1740
+ let icpu_done = false;
1741
+ const ICPU_MAX_MS = 6e4;
1742
+ const ICPU_SLOW_MS = 200;
1743
+ /** the interaction the running sampler caught, when one did */
1744
+ let icpu_caught = null;
1745
+ function start_interaction_cpu() {
1746
+ if (icpu || icpu_done || !collecting()) return;
1747
+ icpu = make_profiler();
1748
+ if (!icpu) return;
1749
+ icpu_timer = setTimeout(() => void stop_interaction_cpu(false), ICPU_MAX_MS);
1750
+ }
1751
+ /** the event observer saw a new slowest interaction: a slow one ends the sampling shortly after */
1752
+ function interaction_seen(i) {
1753
+ if (!icpu || icpu_caught || i.ms < ICPU_SLOW_MS) return;
1754
+ const handlers_at = i.t + i.delay;
1755
+ icpu_caught = {
1756
+ t: i.t,
1757
+ wait: [i.t, handlers_at],
1758
+ handler: [handlers_at, handlers_at + i.processing]
1759
+ };
1760
+ if (icpu_timer) clearTimeout(icpu_timer);
1761
+ icpu_timer = setTimeout(() => void stop_interaction_cpu(false), 300);
1762
+ }
1763
+ async function stop_interaction_cpu(hiding) {
1764
+ if (!icpu) return;
1765
+ const p = icpu;
1766
+ icpu = null;
1767
+ icpu_done = true;
1768
+ if (icpu_timer) clearTimeout(icpu_timer);
1769
+ icpu_timer = null;
1770
+ let trace;
1771
+ try {
1772
+ trace = await p.stop();
1773
+ } catch {
1774
+ return;
1775
+ }
1776
+ let caught = icpu_caught;
1777
+ if (!trace || !caught) return;
1778
+ const i = visit_interaction;
1779
+ if (i && i.t === caught.t) {
1780
+ const handlers_at = i.t + i.delay;
1781
+ caught = {
1782
+ t: i.t,
1783
+ wait: [i.t, handlers_at],
1784
+ handler: [handlers_at, handlers_at + i.processing]
1785
+ };
1786
+ }
1787
+ if (DEVTOOLS) cpu_kept = [{
1788
+ trace,
1789
+ from: caught.wait[0],
1790
+ to: caught.handler[1],
1791
+ label: "interaction",
1792
+ spans: caught
1793
+ }, ...cpu_kept.slice(0, 4)];
1794
+ const url = endpoint();
1795
+ if (!url) return;
1796
+ const body = JSON.stringify({
1797
+ page: visit_page(),
1798
+ cpu: trace,
1799
+ interaction: caught
1800
+ });
1801
+ const keepalive = hiding && body.length <= keepalive_room();
1802
+ if (hiding && !keepalive) return;
1803
+ try {
1804
+ const settled = fetch(url, {
1805
+ method: "POST",
1806
+ body,
1807
+ credentials: "same-origin",
1808
+ headers: { "content-type": "text/plain" },
1809
+ ...keepalive ? { keepalive: true } : {}
1810
+ }).catch(() => {});
1811
+ if (keepalive) hold_keepalive(body.length, settled);
1812
+ } catch {}
1813
+ }
1814
+ const DEVTOOLS = typeof __OGYGIA_DEVTOOLS__ !== "undefined" ? __OGYGIA_DEVTOOLS__ : false;
1815
+ const DEVTOOLS_LAZY = typeof __OGYGIA_DEVTOOLS_LAZY__ !== "undefined" ? __OGYGIA_DEVTOOLS_LAZY__ : false;
1816
+ let opted;
1817
+ function devtools_measures() {
1818
+ if (!DEVTOOLS) return false;
1819
+ if (!DEVTOOLS_LAZY) return true;
1820
+ return opted ??= devtools_switched_on();
1821
+ }
1822
+ /** when the document's first in-app navigation started (its first page's record ends there) */
1823
+ let first_nav_t;
1824
+ /**
1825
+ * Room in a capped list of the visit. Full: the oldest entry from AFTER the document's first in-app
1826
+ * navigation goes — the page in view keeps its record (a long session of navigations filled the
1827
+ * lists with the pages before it: one 320-island page left every later page with no islands at all,
1828
+ * and the Page tab found nothing there), and the page the document loaded as keeps all of its own
1829
+ * (the profiler's report is about that one). `false`: full of the first page's, the new one waits.
1830
+ */
1831
+ /** how many snapshots the first page took (a snapshot has no time of its own) */
1832
+ let snapshot_firsts = 0;
1833
+ function snapshot_room() {
1834
+ if (snapshots.length < MAX_SNAPSHOTS) return true;
1835
+ if (first_nav_t === void 0 || snapshots.length <= snapshot_firsts) return false;
1836
+ snapshots.splice(snapshot_firsts, 1);
1837
+ return true;
1838
+ }
1839
+ function make_room(list, cap, t_of) {
1840
+ if (list.length < cap) return true;
1841
+ if (first_nav_t === void 0) return false;
1842
+ const from = first_nav_t;
1843
+ const i = list.findIndex((x) => t_of(x) >= from);
1844
+ if (i === -1) return false;
1845
+ list.splice(i, 1);
1846
+ return true;
1847
+ }
1848
+ /** recording at all: the profiler's tag, or a devtools build (a lazy one: once opted in) */
1849
+ function collecting() {
1850
+ return devtools_measures() || endpoint() !== null;
1851
+ }
1852
+ function endpoint() {
1853
+ if (target !== void 0) return target;
1854
+ if (typeof document === "undefined") return target = null;
1855
+ const href = document.querySelector("meta[name=\"ogygia-profiler-beacon\"]")?.getAttribute("content") ?? "";
1856
+ return target = href ? href : null;
1857
+ }
1858
+ let early_visit_done = false;
1859
+ let resend_timer = null;
1860
+ let resends = 0;
1861
+ const RESEND_MAX = 8;
1862
+ function resend_soon() {
1863
+ if (!endpoint() || visit_sent || resends >= RESEND_MAX) return;
1864
+ if (resend_timer) clearTimeout(resend_timer);
1865
+ resend_timer = setTimeout(() => {
1866
+ resend_timer = null;
1867
+ resends++;
1868
+ flush_visit(false);
1869
+ }, 1500);
1870
+ }
1871
+ function flush() {
1872
+ metered("send", flush_now);
1873
+ }
1874
+ function flush_now() {
1875
+ scheduled = false;
1876
+ if (queue.length || marks.length) send(JSON.stringify({
1877
+ page: location.pathname,
1878
+ ...queue.length ? { islands: queue.splice(0, 400) } : {},
1879
+ ...marks.length ? { marks: marks.splice(0, 400) } : {}
1880
+ }));
1881
+ if (!early_visit_done) {
1882
+ early_visit_done = true;
1883
+ flush_visit(false);
1884
+ send_after_preload_check();
1885
+ }
1886
+ }
1887
+ /** A page with image, font or stylesheet preloads: the visit once more after the 3 s past load
1888
+ * that tells a preload nothing used — a visitor who leaves without the page hiding cleanly (a
1889
+ * closed tab, a crash) would otherwise never send it. resend_soon waits 1.5 s itself. */
1890
+ function send_after_preload_check() {
1891
+ try {
1892
+ if (!document.querySelector("link[rel=\"preload\"][as=\"image\"]:not([imagesrcset]), link[rel=\"preload\"][as=\"font\"], link[rel=\"preload\"][as=\"style\"]")) return;
1893
+ if (document.readyState === "complete") {
1894
+ const nav = performance.getEntriesByType("navigation")[0];
1895
+ setTimeout(resend_soon, Math.max(0, 1700 - (performance.now() - (nav?.loadEventEnd ?? 0))));
1896
+ } else addEventListener("load", () => setTimeout(resend_soon, 1700), { once: true });
1897
+ } catch {}
1898
+ }
1899
+ /** the page is going away: the islands still queued, then the vitals (final only now), the visit */
1900
+ function on_hide() {
1901
+ leaving = true;
1902
+ try {
1903
+ flush();
1904
+ flush_vitals();
1905
+ flush_visit(true);
1906
+ } finally {
1907
+ leaving = false;
1908
+ }
1909
+ flush_cpu(true);
1910
+ stop_interaction_cpu(true);
1911
+ }
1912
+ function schedule() {
1913
+ if (scheduled) return;
1914
+ scheduled = true;
1915
+ if (!listening) {
1916
+ listening = true;
1917
+ observe_vitals();
1918
+ start_cpu();
1919
+ document.addEventListener("visibilitychange", () => document.visibilityState === "hidden" && on_hide());
1920
+ addEventListener("pagehide", on_hide);
1921
+ }
1922
+ const idle = globalThis.requestIdleCallback;
1923
+ if (idle) idle(flush, { timeout: 2e3 });
1924
+ else setTimeout(flush, 1500);
1925
+ }
1926
+ /**
1927
+ * Record one island's hydration. `t0` is when the wake began (before the module load), `t_loaded`
1928
+ * when its modules were in hand, `t_done` when `data-hydrated` was set; `ssr_html` is the markup
1929
+ * the server sent (the runtime's own copy), compared with what the island shows now. No-op
1930
+ * without the tag.
1931
+ */
1932
+ function beacon_hydrated(el, t0, t_loaded, t_done, ssr_html, t_turn) {
1933
+ const o = owner();
1934
+ if (o) return o.beacon_hydrated(el, t0, t_loaded, t_done, ssr_html, t_turn);
1935
+ if (!collecting()) return;
1936
+ const c0 = performance.now();
1937
+ island_record(el, t0, t_loaded, t_done, ssr_html, t_turn);
1938
+ charge("islands", c0);
1939
+ }
1940
+ function island_record(el, t0, t_loaded, t_done, ssr_html, t_turn) {
1941
+ const fp = el.getAttribute("data-og-fp");
1942
+ if (!fp) return;
1943
+ const recovered = el.hasAttribute("data-og-recovered");
1944
+ const reason = (el.getAttribute("data-og-recovered") || "").slice(0, 300) || void 0;
1945
+ const sent = endpoint() ? {
1946
+ fp,
1947
+ entry: el.getAttribute("entry") ?? "",
1948
+ ms: Math.max(0, r2(t_done - t0)),
1949
+ load: Math.max(0, r2(t_loaded - t0)),
1950
+ ...recovered ? { recovered: true } : {},
1951
+ ...reason ? { reason } : {}
1952
+ } : null;
1953
+ if (sent) queue.push(sent);
1954
+ let changed;
1955
+ let attrs = null;
1956
+ const room = make_room(visit_islands, 400, (i) => i.t0);
1957
+ if (typeof ssr_html === "string" && room) {
1958
+ const now = el.innerHTML;
1959
+ if (now !== ssr_html) {
1960
+ const a = without_runtime_marks(without_comments(ssr_html));
1961
+ const b = without_runtime_marks(without_comments(now));
1962
+ changed = a !== b;
1963
+ if (changed) {
1964
+ attrs = attr_changes(a, b);
1965
+ if (snapshot_room()) snapshots.push(snapshot_of(fp, ssr_html, now, a, b));
1966
+ }
1967
+ } else changed = false;
1968
+ }
1969
+ let input;
1970
+ for (let k = recent_inputs.length - 1; k >= 0; k--) {
1971
+ const x = recent_inputs[k];
1972
+ if (x.t < t0) break;
1973
+ const target = x.el.deref();
1974
+ if (x.t <= t_done && target && el.contains(target)) {
1975
+ input = x.type;
1976
+ break;
1977
+ }
1978
+ }
1979
+ if (island_boxes) estimate_wake_shift(el, fp, t_done);
1980
+ if (early_visit_done) resend_soon();
1981
+ let markers;
1982
+ if (recovered && typeof ssr_html === "string") {
1983
+ const open = count_of(ssr_html, "<!--[");
1984
+ const close = count_of(ssr_html, "<!--]");
1985
+ if (open !== close) markers = [open, close];
1986
+ }
1987
+ const rec = room ? {
1988
+ fp,
1989
+ ...el.getAttribute("entry") ? { entry: el.getAttribute("entry") } : {},
1990
+ t0: r2(t0),
1991
+ loaded: r2(t_loaded),
1992
+ ...t_turn !== void 0 && t_turn >= t_loaded ? { turn: r2(t_turn) } : {},
1993
+ done: r2(t_done),
1994
+ ...recovered ? { recovered: true } : {},
1995
+ ...changed ? { changed: true } : {},
1996
+ ...attrs ? { attrs } : {},
1997
+ ...input ? { input } : {},
1998
+ ...el.hasAttribute("data-og-healed") ? { healed: true } : {},
1999
+ ...typeof ssr_html === "string" ? { ssr_bytes: ssr_html.length } : {},
2000
+ ...markers ? { markers } : {}
2001
+ } : null;
2002
+ if (rec) visit_islands.push(rec);
2003
+ if (rec || sent) queueMicrotask(() => {
2004
+ const fx = performance.now();
2005
+ if (fx - t_done < 1) return;
2006
+ if (rec) rec.fx = r2(fx);
2007
+ if (sent) sent.ms = Math.max(0, r2(fx - t0));
2008
+ });
2009
+ schedule();
2010
+ }
2011
+ /** the attributes the runtime itself sets, empty, on the regions inside an island's markup */
2012
+ const RUNTIME_MARKS = [
2013
+ " data-nested=\"\"",
2014
+ " data-hydrated=\"\"",
2015
+ " data-og-kept=\"\"",
2016
+ " data-revalidated=\"\""
2017
+ ];
2018
+ /** `html` without the runtime's own marks (string search, no regex: it runs per changed hydration) */
2019
+ function without_runtime_marks(html) {
2020
+ for (const m of RUNTIME_MARKS) if (html.includes(m)) html = html.split(m).join("");
2021
+ return html;
2022
+ }
2023
+ /** A HEADLESS island: it renders nothing meant to be seen — no text of its own, and every element
2024
+ * child marked `hidden` (a marker its effects hang on) — so it exists for its effects, and the
2025
+ * screen sizes that would show it are no question. */
2026
+ function is_headless(el) {
2027
+ for (const n of el.childNodes) {
2028
+ if (n.nodeType === 3 && (n.textContent ?? "").trim()) return false;
2029
+ if (n.nodeType === 1 && !n.hasAttribute("hidden")) return false;
2030
+ }
2031
+ return true;
2032
+ }
2033
+ /** How many times `needle` occurs in `html` (string search). */
2034
+ function count_of(html, needle) {
2035
+ let n = 0;
2036
+ for (let at = html.indexOf(needle); at !== -1; at = html.indexOf(needle, at + needle.length)) n++;
2037
+ return n;
2038
+ }
2039
+ /** `html` with every `<!-- … -->` removed (string search, no regex: it runs per hydration). */
2040
+ function without_comments(html) {
2041
+ let at = html.indexOf("<!--");
2042
+ if (at === -1) return html;
2043
+ let out = "";
2044
+ let from = 0;
2045
+ while (at !== -1) {
2046
+ out += html.slice(from, at);
2047
+ const end = html.indexOf("-->", at + 4);
2048
+ if (end === -1) return out;
2049
+ from = end + 3;
2050
+ at = html.indexOf("<!--", from);
2051
+ }
2052
+ return out + html.slice(from);
2053
+ }
2054
+ /** Start watching the page's paints, shifts, long tasks and first interactions now (the devtools
2055
+ * boot calls this, so a page whose islands never wake is still measured). Idempotent. */
2056
+ function beacon_watch() {
2057
+ const o = owner();
2058
+ if (o) return o.beacon_watch();
2059
+ if (!collecting() || typeof document === "undefined") return;
2060
+ if (!supports("layout-shift")) note_island_boxes();
2061
+ schedule();
2062
+ }
2063
+ /** Devtools: sample the main thread for `ms` from now (a click, a scroll, a nav) and keep the trace
2064
+ * in the page. Resolves when it is kept; false when the browser cannot sample here. */
2065
+ async function beacon_record_cpu(ms, label) {
2066
+ const o = owner();
2067
+ if (o) return o.beacon_record_cpu(ms, label);
2068
+ if (!DEVTOOLS) return false;
2069
+ const p = make_profiler();
2070
+ if (!p) return false;
2071
+ const from = performance.now();
2072
+ await new Promise((ok) => setTimeout(ok, Math.max(200, Math.min(3e4, ms))));
2073
+ try {
2074
+ cpu_kept = [{
2075
+ trace: await p.stop(),
2076
+ from,
2077
+ to: performance.now(),
2078
+ label
2079
+ }, ...cpu_kept.slice(0, 4)];
2080
+ return true;
2081
+ } catch {
2082
+ return false;
2083
+ }
2084
+ }
2085
+ function beacon_page() {
2086
+ const o = owner();
2087
+ if (o) return o.beacon_page();
2088
+ if (!collecting()) return null;
2089
+ return {
2090
+ vitals: { ...vitals },
2091
+ visit: build_visit(),
2092
+ islands: visit_islands.slice(),
2093
+ firsts: visit_firsts.slice(),
2094
+ shifts: visit_shifts.slice(),
2095
+ longtasks: visit_longtasks.slice(),
2096
+ ...longtasks_from_frames ? { longtasks_from: "frames" } : {},
2097
+ ...island_boxes ? { shifts_from: "boxes" } : {},
2098
+ marks: visit_marks.slice(),
2099
+ snapshots: snapshots.slice(),
2100
+ cpu: {
2101
+ state: cpu ? "recording" : cpu_kept.length ? "done" : "off",
2102
+ off: cpu_off,
2103
+ traces: cpu_kept.slice()
2104
+ }
2105
+ };
2106
+ }
2107
+ /** @internal tests */
2108
+ function _reset_beacon() {
2109
+ const g = globalThis;
2110
+ if (!self_api || g[BEACON_KEY] === self_api) delete g[BEACON_KEY];
2111
+ target = void 0;
2112
+ queue = [];
2113
+ marks = [];
2114
+ scheduled = false;
2115
+ vitals = null;
2116
+ vitals_sent = false;
2117
+ cpu = null;
2118
+ cpu_sent = false;
2119
+ cpu_kept = [];
2120
+ cpu_off = null;
2121
+ icpu = null;
2122
+ if (icpu_timer) clearTimeout(icpu_timer);
2123
+ icpu_timer = null;
2124
+ icpu_done = false;
2125
+ icpu_caught = null;
2126
+ opted = void 0;
2127
+ failed_fps.clear();
2128
+ failed_spans.clear();
2129
+ failed_turns.clear();
2130
+ visit_navs = [];
2131
+ first_nav_t = void 0;
2132
+ snapshot_firsts = 0;
2133
+ landing_page = null;
2134
+ seen_resources = [];
2135
+ faces_memo = null;
2136
+ dom_memo = null;
2137
+ preloads_memo = null;
2138
+ visit_islands = [];
2139
+ visit_firsts = [];
2140
+ visit_shifts = [];
2141
+ visit_longtasks = [];
2142
+ longtasks_from_frames = false;
2143
+ island_boxes = null;
2144
+ keepalive_queued = 0;
2145
+ visit_scripts = /* @__PURE__ */ new Map();
2146
+ visit_forced = [];
2147
+ visit_scroll_jank = [];
2148
+ scroll_times = [];
2149
+ visit_interaction = null;
2150
+ visit_interaction_id = 0;
2151
+ visit_interaction_span = null;
2152
+ visit_frames = [];
2153
+ visit_warnings = [];
2154
+ visit_holes_failed = [];
2155
+ visit_holes_answered = [];
2156
+ visit_hole_batches = [];
2157
+ visit_entry_fallbacks = [];
2158
+ holes_answered_els = /* @__PURE__ */ new WeakSet();
2159
+ hole_fetches = /* @__PURE__ */ new Map();
2160
+ visit_marks = [];
2161
+ visit_paints = {};
2162
+ lcp_el = lcp_region = null;
2163
+ snapshots = [];
2164
+ visit_sent = false;
2165
+ early_visit_done = false;
2166
+ resends = 0;
2167
+ }
2168
+ /** @internal tests */
2169
+ function _beacon_state() {
2170
+ return {
2171
+ target,
2172
+ queued: queue.length,
2173
+ marks: marks.length,
2174
+ scheduled,
2175
+ snapshots: snapshots.length
2176
+ };
2177
+ }
2178
+ /** @internal tests: the size-aware send */
2179
+ const _beacon_send = send;
2180
+ /** @internal tests: a send from inside the hide (a page leaving while it still reads "visible") */
2181
+ function _beacon_send_leaving(body, slim) {
2182
+ leaving = true;
2183
+ try {
2184
+ send(body, slim);
2185
+ } finally {
2186
+ leaving = false;
2187
+ }
2188
+ }
2189
+ if (typeof document !== "undefined" && owner() === null && (devtools_measures() || !!document.querySelector("meta[name=\"ogygia-profiler-beacon\"]")) && !supports("longtask")) watch_frame_gaps();
2190
+ export { _beacon_send, _beacon_send_leaving, _beacon_state, _reset_beacon, attr_changes, beacon_entry_fallback, beacon_failed, beacon_hole_answered, beacon_hole_batch_missed, beacon_hole_failed, beacon_hole_fetched, beacon_hydrated, beacon_mark, beacon_nav, beacon_page, beacon_record_cpu, beacon_warning, beacon_watch, hole_request_times, is_headless, resource_type, without_comments, without_runtime_marks };