effect-inspect 0.1.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 (38) hide show
  1. package/README.md +122 -0
  2. package/app/dist/client/assets/index-smV05cfr.js +25 -0
  3. package/app/dist/client/assets/rolldown-runtime-CbXtAM7H.js +1 -0
  4. package/app/dist/client/assets/routes-TKgeFdSW.js +5 -0
  5. package/app/dist/client/assets/styles-B3rAZGvS.css +2 -0
  6. package/app/dist/server/assets/_tanstack-start-manifest_v-Co953HeC.js +20 -0
  7. package/app/dist/server/assets/empty-plugin-adapters-D9UWiqvJ.js +5 -0
  8. package/app/dist/server/assets/router-CN98Ramo.js +491 -0
  9. package/app/dist/server/assets/routes-eZ4XqxE9.js +3999 -0
  10. package/app/dist/server/assets/start-5Z2QO8AU.js +4 -0
  11. package/app/dist/server/server.js +1812 -0
  12. package/dist/cli.d.ts +3 -0
  13. package/dist/cli.js +29 -0
  14. package/dist/client/Client.d.ts +52 -0
  15. package/dist/client/Client.js +224 -0
  16. package/dist/client/Edge.d.ts +31 -0
  17. package/dist/client/Edge.js +108 -0
  18. package/dist/client/Inspect.d.ts +49 -0
  19. package/dist/client/Inspect.js +55 -0
  20. package/dist/client/Tracer.d.ts +31 -0
  21. package/dist/client/Tracer.js +119 -0
  22. package/dist/collector/Config.d.ts +8 -0
  23. package/dist/collector/Config.js +9 -0
  24. package/dist/collector/Server.d.ts +24 -0
  25. package/dist/collector/Server.js +172 -0
  26. package/dist/collector/Store.d.ts +86 -0
  27. package/dist/collector/Store.js +119 -0
  28. package/dist/collector/WebApp.d.ts +3 -0
  29. package/dist/collector/WebApp.js +36 -0
  30. package/dist/collector/main.d.ts +1 -0
  31. package/dist/collector/main.js +22 -0
  32. package/dist/index.d.ts +3 -0
  33. package/dist/index.js +3 -0
  34. package/dist/protocol/Codec.d.ts +575 -0
  35. package/dist/protocol/Codec.js +50 -0
  36. package/dist/protocol/Schema.d.ts +1237 -0
  37. package/dist/protocol/Schema.js +327 -0
  38. package/package.json +85 -0
@@ -0,0 +1,491 @@
1
+ import { useContext, useEffect, useSyncExternalStore } from "react";
2
+ import { HeadContent, Link, Outlet, Scripts, createFileRoute, createRootRoute, createRouter, lazyRouteComponent } from "@tanstack/react-router";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { ChevronLeft, ChevronRight, FileQuestion } from "lucide-react";
5
+ import { RegistryContext, RegistryProvider, useAtom } from "@effect/atom-react";
6
+ import { Atom } from "effect/unstable/reactivity";
7
+ import { cva } from "class-variance-authority";
8
+ import { clsx } from "clsx";
9
+ import { twMerge } from "tailwind-merge";
10
+ //#region \0rolldown/runtime.js
11
+ var __defProp = Object.defineProperty;
12
+ var __exportAll = (all, no_symbols) => {
13
+ let target = {};
14
+ for (var name in all) __defProp(target, name, {
15
+ get: all[name],
16
+ enumerable: true
17
+ });
18
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
19
+ return target;
20
+ };
21
+ //#endregion
22
+ //#region app/src/state/panels.ts
23
+ /**
24
+ * Whether the sessions sidebar and the span detail panel are collapsed.
25
+ *
26
+ * Both panels are *chrome around* the chart, not the chart itself, so which of
27
+ * them a user wants open is a durable preference rather than per-visit state —
28
+ * it lives in `localStorage` alongside the theme.
29
+ *
30
+ * The hydration constraint is the same one {@link module:state/theme} has, and
31
+ * so is the answer: the server cannot read `localStorage`, so these atoms are
32
+ * seeded with the *default* and adopt storage in an effect. Unlike the theme
33
+ * there is no boot script and no flash to avoid, because a collapsed panel is
34
+ * a layout the user sees and re-renders once — not a colour that would flash.
35
+ *
36
+ * See `usePanel` in {@link module:components/Panel} for the read side, which
37
+ * defers to the server's value until hydration commits.
38
+ */
39
+ /** `localStorage` key. One record, so a panel added later costs no migration. */
40
+ var PANELS_STORAGE_KEY = "effect-inspect:panels";
41
+ /** Both panels open — what the server renders, and a first visit gets. */
42
+ var DEFAULT_PANELS = {
43
+ sessions: false,
44
+ detail: false
45
+ };
46
+ /** Reads stored collapse state, ignoring anything that is not our shape. */
47
+ var stored = () => {
48
+ if (typeof localStorage === "undefined") return DEFAULT_PANELS;
49
+ try {
50
+ const raw = JSON.parse(localStorage.getItem("effect-inspect:panels") ?? "null");
51
+ if (typeof raw !== "object" || raw === null) return DEFAULT_PANELS;
52
+ const value = raw;
53
+ return {
54
+ sessions: value.sessions === true,
55
+ detail: value.detail === true
56
+ };
57
+ } catch {
58
+ return DEFAULT_PANELS;
59
+ }
60
+ };
61
+ /** The live collapse state. Seeded with the default; see the module comment. */
62
+ var panelsAtom = Atom.make(DEFAULT_PANELS);
63
+ /**
64
+ * Adopts the stored collapse state and persists every change after it.
65
+ *
66
+ * Started once from the root, for the same reason the theme sync is: there is
67
+ * one `localStorage` entry, so there is one owner of it.
68
+ */
69
+ var startPanelSync = (registry) => {
70
+ const off = registry.subscribe(panelsAtom, (panels) => {
71
+ try {
72
+ localStorage.setItem(PANELS_STORAGE_KEY, JSON.stringify(panels));
73
+ } catch {}
74
+ });
75
+ const saved = stored();
76
+ const current = registry.get(panelsAtom);
77
+ if (saved.sessions !== current.sessions || saved.detail !== current.detail) registry.set(panelsAtom, saved);
78
+ return off;
79
+ };
80
+ //#endregion
81
+ //#region app/src/lib/utils.ts
82
+ function cn(...inputs) {
83
+ return twMerge(clsx(inputs));
84
+ }
85
+ //#endregion
86
+ //#region app/src/components/atoms/Button.tsx
87
+ /**
88
+ * Beautiful UI's `button` atom, installed from
89
+ * `https://www.beautifului.dev/r/button.json`.
90
+ *
91
+ * Adapted to repo convention only: relative import with an explicit extension,
92
+ * `readonly` props, and no `"use client"` (nothing in this app is an RSC).
93
+ * The variant table itself is the registry's, unedited — it is the file's whole
94
+ * reason for existing.
95
+ */
96
+ var filledShadow = "shadow-[inset_0_1px_0_rgba(255,255,255,0.14)]";
97
+ var buttonVariants = cva(`inline-flex items-center justify-center font-medium select-none
98
+ transition-[transform,background-color,opacity] duration-150 ease-out
99
+ active:scale-[0.96] disabled:opacity-50 disabled:pointer-events-none`, {
100
+ variants: {
101
+ variant: {
102
+ primary: `bg-ink text-canvas hover:opacity-90 dark:bg-ink dark:text-canvas ${filledShadow}`,
103
+ secondary: "bg-surface text-ink shadow-btn hover:bg-inset aria-expanded:bg-hover",
104
+ ghost: "bg-hover-2 text-ink hover:bg-line-strong",
105
+ accent: `bg-accent text-white hover:bg-accent-ink ${filledShadow}`,
106
+ success: `bg-green text-white hover:brightness-95 ${filledShadow}`,
107
+ quiet: "text-ink hover:bg-hover"
108
+ },
109
+ size: {
110
+ xs: "h-7 rounded-full px-2.5 text-[12px] font-normal leading-none gap-1",
111
+ sm: "h-[27px] px-3 text-[13px] leading-none rounded-full gap-1.5",
112
+ md: "px-4 py-[9px] text-sm leading-none rounded-full gap-2"
113
+ }
114
+ },
115
+ defaultVariants: {
116
+ variant: "secondary",
117
+ size: "md"
118
+ }
119
+ });
120
+ var Button = ({ variant, size, className, ...props }) => /* @__PURE__ */ jsx("button", {
121
+ className: cn(buttonVariants({
122
+ variant,
123
+ size
124
+ }), className),
125
+ ...props
126
+ });
127
+ //#endregion
128
+ //#region app/src/components/Panel.tsx
129
+ /**
130
+ * The shared furniture the side panels are built from: the collapse hook, the
131
+ * rail a collapsed panel leaves behind, and the designed empty state.
132
+ *
133
+ * Both side panels are the same object seen from opposite edges — a titled
134
+ * surface that can fold to a rail — so the collapse affordance, its width and
135
+ * its label orientation live here once rather than being written twice with a
136
+ * left/right difference in each.
137
+ */
138
+ /** No-op subscribe: {@link useHydrated} never changes after the first commit. */
139
+ var noSubscribe = () => () => {};
140
+ /**
141
+ * `false` during server render and while hydrating, `true` afterwards.
142
+ *
143
+ * Same mechanism, and the same reason, as the copy in `ThemeToggle`: the
144
+ * stored panel state is adopted in an effect that can land before a lazily
145
+ * loaded component hydrates, so reading the atom directly would render markup
146
+ * that disagrees with what React is hydrating against.
147
+ */
148
+ var useHydrated = () => useSyncExternalStore(noSubscribe, () => true, () => false);
149
+ /**
150
+ * One panel's collapsed flag and a toggle for it.
151
+ *
152
+ * Returns the *server's* value until hydration commits, so the first client
153
+ * render always matches the markup; the stored preference arrives one commit
154
+ * later, which for a layout is a single re-render rather than a flash.
155
+ */
156
+ var usePanel = (key) => {
157
+ const [panels, setPanels] = useAtom(panelsAtom);
158
+ return [useHydrated() ? panels[key] : DEFAULT_PANELS[key], () => setPanels({
159
+ ...panels,
160
+ [key]: !panels[key]
161
+ })];
162
+ };
163
+ /** Which way the chevron points, per edge and state. */
164
+ var chevron = (edge, collapsed) => {
165
+ return (edge === "left" ? collapsed : !collapsed) ? ChevronRight : ChevronLeft;
166
+ };
167
+ /**
168
+ * The collapse control. Quiet until hovered, like every other chrome button.
169
+ *
170
+ * `aria-expanded` and `aria-controls` rather than a changing label, so the
171
+ * button's accessible name stays stable while its state is announced — the
172
+ * same shape the drawer's collapse button already uses.
173
+ */
174
+ var CollapseButton = ({ edge, collapsed, onToggle, label, controls }) => {
175
+ const Icon = chevron(edge, collapsed);
176
+ return /* @__PURE__ */ jsx(Button, {
177
+ type: "button",
178
+ variant: "quiet",
179
+ size: "xs",
180
+ onClick: onToggle,
181
+ "aria-expanded": !collapsed,
182
+ "aria-controls": controls,
183
+ "aria-label": label,
184
+ title: label,
185
+ className: "size-6 shrink-0 px-0 text-ink-3 hover:text-ink",
186
+ children: /* @__PURE__ */ jsx(Icon, { className: "size-3.5" })
187
+ });
188
+ };
189
+ /**
190
+ * A collapsed panel, as a narrow rail carrying its own name and re-open control.
191
+ *
192
+ * A rail rather than nothing at all: a panel that vanishes entirely leaves no
193
+ * clue that it existed, and the user who collapsed it last week has to
194
+ * rediscover the feature. 28px is the button plus the panel's border.
195
+ */
196
+ var CollapsedRail = ({ edge, title, onToggle, id }) => /* @__PURE__ */ jsxs("aside", {
197
+ id,
198
+ className: `flex w-7 shrink-0 flex-col items-center gap-2 bg-surface py-1.5 ${edge === "left" ? "border-r" : "border-l"} border-line`,
199
+ children: [/* @__PURE__ */ jsx(CollapseButton, {
200
+ edge,
201
+ collapsed: true,
202
+ onToggle,
203
+ label: `Show ${title.toLowerCase()}`,
204
+ controls: id
205
+ }), /* @__PURE__ */ jsx("span", {
206
+ className: "text-[10px] tracking-wider whitespace-nowrap text-ink-3 uppercase",
207
+ style: {
208
+ writingMode: "vertical-rl",
209
+ transform: edge === "left" ? "rotate(180deg)" : void 0
210
+ },
211
+ children: title
212
+ })]
213
+ });
214
+ /**
215
+ * The panel header: a section label, and whatever control belongs beside it.
216
+ *
217
+ * Fixed 28px content height so the sidebar's header, the detail panel's header
218
+ * and the drawer's tab bar all land on the same baseline grid.
219
+ */
220
+ var PanelHeader = ({ title, children }) => /* @__PURE__ */ jsxs("div", {
221
+ className: "flex h-8 shrink-0 items-center gap-2 border-b border-line px-2",
222
+ children: [/* @__PURE__ */ jsx("span", {
223
+ className: "min-w-0 flex-1 truncate text-[10px] tracking-wider text-ink-3 uppercase",
224
+ children: title
225
+ }), children]
226
+ });
227
+ /**
228
+ * The designed empty state: an icon, what is missing, and the action that fixes it.
229
+ *
230
+ * Three lines rather than one sentence, because "Select a span." tells a new
231
+ * user what is absent but not what to do about it. The icon is what makes the
232
+ * block read as a deliberate state rather than as a failed render, and the
233
+ * hint carries the verb.
234
+ */
235
+ var Empty = ({ icon: Icon, title, hint, className = "" }) => /* @__PURE__ */ jsxs("div", {
236
+ className: `flex flex-col items-center justify-center gap-2 px-4 py-8 text-center ${className}`,
237
+ children: [
238
+ /* @__PURE__ */ jsx(Icon, {
239
+ className: "size-5 text-ink-3",
240
+ strokeWidth: 1.5,
241
+ "aria-hidden": true
242
+ }),
243
+ /* @__PURE__ */ jsx("p", {
244
+ className: "text-xs text-ink-2",
245
+ children: title
246
+ }),
247
+ /* @__PURE__ */ jsx("p", {
248
+ className: "max-w-56 text-[11px] leading-relaxed text-balance text-ink-3",
249
+ children: hint
250
+ })
251
+ ]
252
+ });
253
+ //#endregion
254
+ //#region app/src/state/theme.ts
255
+ /**
256
+ * Theme preference, and the one place that owns the `dark` class.
257
+ *
258
+ * Three moving parts, and the split between them is the whole design:
259
+ *
260
+ * - **The preference** (`light | dark | system`) is what the user chose. It
261
+ * lives in an atom and in `localStorage`.
262
+ * - **The resolution** (`light | dark`) is what that preference means right
263
+ * now, which for `system` depends on `prefers-color-scheme` and can change
264
+ * under a stationary preference.
265
+ * - **The class on `<html>`** is what CSS and the canvas actually read.
266
+ *
267
+ * The class is applied *imperatively*, not by React rendering it. TanStack
268
+ * Start renders the document on the server, where `localStorage` and
269
+ * `prefers-color-scheme` are both unavailable, so a React-rendered class can
270
+ * only ever be the default — and correcting it in an effect is a flash. See
271
+ * {@link THEME_BOOT_SCRIPT}, which runs before first paint.
272
+ */
273
+ /** `localStorage` key. Shared with {@link THEME_BOOT_SCRIPT}, which is a string. */
274
+ var THEME_STORAGE_KEY = "effect-inspect:theme";
275
+ /** Dark is the default, per the spec, and is what the server renders. */
276
+ var DEFAULT_THEME = "dark";
277
+ var isTheme = (value) => value === "light" || value === "dark" || value === "system";
278
+ /**
279
+ * Blocking inline script for `<head>`.
280
+ *
281
+ * This is the no-flash mechanism. The server always renders `class="dark"`
282
+ * (the default), so a user whose stored preference is `light` would otherwise
283
+ * see a dark frame before hydration corrects it. Running synchronously in
284
+ * `<head>`, before the body paints, means the correction happens in the same
285
+ * frame as the first paint and there is nothing to see.
286
+ *
287
+ * It is deliberately duplicated logic rather than an import: it must run before
288
+ * any module graph is fetched, so it cannot be a module. It is small and both
289
+ * copies read the same {@link THEME_STORAGE_KEY}.
290
+ *
291
+ * `color-scheme` is set alongside the class so form controls, scrollbars and
292
+ * the canvas's own backdrop match before any stylesheet has applied.
293
+ */
294
+ var THEME_BOOT_SCRIPT = `(function(){try{
295
+ var s=localStorage.getItem(${JSON.stringify(THEME_STORAGE_KEY)});
296
+ var t=(s==='light'||s==='dark'||s==='system')?s:${JSON.stringify(DEFAULT_THEME)};
297
+ var d=t==='dark'||(t==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);
298
+ document.documentElement.classList.toggle('dark',d);
299
+ document.documentElement.style.colorScheme=d?'dark':'light';
300
+ }catch(e){}})()`;
301
+ /** Reads the stored preference. Returns the default on the server or bad data. */
302
+ var storedTheme = () => {
303
+ if (typeof localStorage === "undefined") return DEFAULT_THEME;
304
+ try {
305
+ const stored = localStorage.getItem(THEME_STORAGE_KEY);
306
+ return isTheme(stored) ? stored : DEFAULT_THEME;
307
+ } catch {
308
+ return DEFAULT_THEME;
309
+ }
310
+ };
311
+ /**
312
+ * The user's preference.
313
+ *
314
+ * Seeded with {@link DEFAULT_THEME} rather than with the stored value, even
315
+ * though the stored value is readable on the client. React hydrates against
316
+ * the *server's* markup, so a toggle that rendered `light` as checked on the
317
+ * first client pass would mismatch a server that rendered `dark` — a real
318
+ * hydration error, not a cosmetic one. The stored preference is adopted a beat
319
+ * later by {@link startThemeSync}, in an effect, where a divergence is a normal
320
+ * state update instead.
321
+ *
322
+ * This costs nothing visually: the *class* on `<html>` is already correct by
323
+ * then — {@link THEME_BOOT_SCRIPT} set it before the first paint — so the only
324
+ * thing catching up is which of three radios is checked.
325
+ */
326
+ var themeAtom = Atom.make(DEFAULT_THEME);
327
+ /**
328
+ * What the preference resolves to right now.
329
+ *
330
+ * A separate atom rather than a derived read because it has a second input the
331
+ * preference does not see: the OS setting can change while `system` is
332
+ * selected. {@link startThemeSync} owns writing it.
333
+ */
334
+ var resolvedThemeAtom = Atom.make(typeof document === "undefined" ? DEFAULT_THEME : currentResolved());
335
+ /** Resolves a preference against the OS setting. */
336
+ var resolve = (theme) => {
337
+ if (theme !== "system") return theme;
338
+ if (typeof matchMedia === "undefined") return DEFAULT_THEME;
339
+ return matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
340
+ };
341
+ /** What the DOM is showing, read from the class the boot script set. */
342
+ function currentResolved() {
343
+ return document.documentElement.classList.contains("dark") ? "dark" : "light";
344
+ }
345
+ /**
346
+ * Keeps `<html>`, `localStorage` and {@link resolvedThemeAtom} in step with the
347
+ * preference, for as long as the returned function is not called.
348
+ *
349
+ * Started once from the root component rather than from a hook per consumer:
350
+ * there is exactly one `<html>` element, so there is exactly one owner of its
351
+ * class. Everything else — the toggle, the canvas — reads atoms.
352
+ */
353
+ var startThemeSync = (registry) => {
354
+ const apply = (theme) => {
355
+ const resolved = resolve(theme);
356
+ const root = document.documentElement;
357
+ if (root.classList.contains("dark") !== (resolved === "dark")) {
358
+ root.classList.add("theme-switching");
359
+ root.classList.toggle("dark", resolved === "dark");
360
+ requestAnimationFrame(() => root.classList.remove("theme-switching"));
361
+ }
362
+ root.style.colorScheme = resolved;
363
+ if (registry.get(resolvedThemeAtom) !== resolved) registry.set(resolvedThemeAtom, resolved);
364
+ };
365
+ const offAtom = registry.subscribe(themeAtom, (theme) => {
366
+ try {
367
+ localStorage.setItem(THEME_STORAGE_KEY, theme);
368
+ } catch {}
369
+ apply(theme);
370
+ });
371
+ const stored = storedTheme();
372
+ if (stored === registry.get(themeAtom)) apply(stored);
373
+ else registry.set(themeAtom, stored);
374
+ const query = matchMedia("(prefers-color-scheme: dark)");
375
+ const onSystemChange = () => apply(registry.get(themeAtom));
376
+ query.addEventListener("change", onSystemChange);
377
+ return () => {
378
+ offAtom();
379
+ query.removeEventListener("change", onSystemChange);
380
+ };
381
+ };
382
+ //#endregion
383
+ //#region app/src/styles.css?url
384
+ var styles_default = "/assets/styles-B3rAZGvS.css";
385
+ //#endregion
386
+ //#region app/src/routes/__root.tsx
387
+ var Route$1 = createRootRoute({
388
+ head: () => ({
389
+ meta: [
390
+ { charSet: "utf-8" },
391
+ {
392
+ name: "viewport",
393
+ content: "width=device-width, initial-scale=1"
394
+ },
395
+ { title: "effect-inspect" }
396
+ ],
397
+ links: [{
398
+ rel: "stylesheet",
399
+ href: styles_default
400
+ }]
401
+ }),
402
+ component: RootComponent
403
+ });
404
+ function RootComponent() {
405
+ return /* @__PURE__ */ jsx(RootDocument, { children: /* @__PURE__ */ jsxs(RegistryProvider, { children: [
406
+ /* @__PURE__ */ jsx(ThemeSync, {}),
407
+ /* @__PURE__ */ jsx(PanelSync, {}),
408
+ /* @__PURE__ */ jsx(Outlet, {})
409
+ ] }) });
410
+ }
411
+ /**
412
+ * Owns the `dark` class on `<html>` for the life of the app.
413
+ *
414
+ * Renders nothing: the theme is not React state that something displays, it is
415
+ * a property of the document. One component starts the sync, everything else —
416
+ * the toggle, the flame chart — reads atoms.
417
+ */
418
+ function ThemeSync() {
419
+ const registry = useContext(RegistryContext);
420
+ useEffect(() => startThemeSync(registry), [registry]);
421
+ return null;
422
+ }
423
+ /**
424
+ * Adopts and persists the side panels' collapse state.
425
+ *
426
+ * Separate from `ThemeSync` because they own different storage keys and have
427
+ * different failure modes: the theme has a boot script and a flash to avoid,
428
+ * the panels have neither.
429
+ */
430
+ function PanelSync() {
431
+ const registry = useContext(RegistryContext);
432
+ useEffect(() => startPanelSync(registry), [registry]);
433
+ return null;
434
+ }
435
+ function RootDocument({ children }) {
436
+ return /* @__PURE__ */ jsxs("html", {
437
+ lang: "en",
438
+ className: "dark",
439
+ suppressHydrationWarning: true,
440
+ children: [/* @__PURE__ */ jsxs("head", { children: [/* @__PURE__ */ jsx(HeadContent, {}), /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: THEME_BOOT_SCRIPT } })] }), /* @__PURE__ */ jsxs("body", { children: [children, /* @__PURE__ */ jsx(Scripts, {})] })]
441
+ });
442
+ }
443
+ //#endregion
444
+ //#region app/src/routes/index.tsx
445
+ var $$splitComponentImporter = () => import("./routes-eZ4XqxE9.js");
446
+ //#endregion
447
+ //#region app/src/routeTree.gen.ts
448
+ var rootRouteChildren = { IndexRoute: createFileRoute("/")({ component: lazyRouteComponent($$splitComponentImporter, "component") }).update({
449
+ id: "/",
450
+ path: "/",
451
+ getParentRoute: () => Route$1
452
+ }) };
453
+ var routeTree = Route$1._addFileChildren(rootRouteChildren)._addFileTypes();
454
+ //#endregion
455
+ //#region app/src/router.tsx
456
+ var router_exports = /* @__PURE__ */ __exportAll({ getRouter: () => getRouter });
457
+ /**
458
+ * Shown for any URL the route tree does not match.
459
+ *
460
+ * Configured at the router rather than per route because the app is a
461
+ * single-page inspector: `/` is the only real route, so *every* miss is the
462
+ * same miss, and a `notFoundComponent` on each route would be the same
463
+ * component repeated. Without this, TanStack falls back to a bare
464
+ * `<p>Not Found</p>` that ignores the theme entirely — which is what a stray
465
+ * request (a probe for `/favicon.ico`, a stale bookmark) would otherwise render.
466
+ */
467
+ var NotFound = () => /* @__PURE__ */ jsx("div", {
468
+ className: "flex h-screen flex-col items-center justify-center bg-page font-mono text-ink antialiased",
469
+ children: /* @__PURE__ */ jsx(Empty, {
470
+ icon: FileQuestion,
471
+ title: "No such page",
472
+ hint: /* @__PURE__ */ jsxs(Fragment, { children: [
473
+ "effect-inspect is a single page. Head back to",
474
+ " ",
475
+ /* @__PURE__ */ jsx(Link, {
476
+ to: "/",
477
+ className: "text-accent underline underline-offset-2",
478
+ children: "the inspector"
479
+ }),
480
+ "."
481
+ ] })
482
+ })
483
+ });
484
+ /** TanStack Start calls this per request to build the router. */
485
+ var getRouter = () => createRouter({
486
+ routeTree,
487
+ scrollRestoration: true,
488
+ defaultNotFoundComponent: NotFound
489
+ });
490
+ //#endregion
491
+ export { CollapseButton as a, PanelHeader as c, getRouter, themeAtom as i, usePanel as l, DEFAULT_THEME as n, CollapsedRail as o, resolvedThemeAtom as r, Empty as s, router_exports as t, Button as u };