vite-devtools-svelte 0.2.1 → 0.4.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.
- package/README.md +159 -56
- package/dist/analyzers/api.d.ts +16 -0
- package/dist/analyzers/assets.d.ts +6 -1
- package/dist/analyzers/build.d.ts +3 -0
- package/dist/analyzers/module-graph.d.ts +13 -0
- package/dist/analyzers/og.d.ts +7 -0
- package/dist/analyzers/source.d.ts +6 -0
- package/dist/client/assets/ApiPlayground-BMx5j-7t.js +3 -0
- package/dist/client/assets/ApiPlayground-D6P2iQCp.css +1 -0
- package/dist/client/assets/Assets-BHhg5Smm.js +1 -0
- package/dist/client/assets/Assets-D-EORnuB.css +1 -0
- package/dist/client/assets/Badge-BBLKgCiU.css +1 -0
- package/dist/client/assets/Badge-CBVv8IFU.js +1 -0
- package/dist/client/assets/BuildAnalysis-BdVCnWpb.js +1 -0
- package/dist/client/assets/BuildAnalysis-ClES_VN-.css +1 -0
- package/dist/client/assets/CaptureNotice-B2odNyXw.css +1 -0
- package/dist/client/assets/CaptureNotice-BeXCVhO0.js +1 -0
- package/dist/client/assets/Components-Co50xTrv.css +1 -0
- package/dist/client/assets/Components-D_qDgEUt.js +1 -0
- package/dist/client/assets/DataTable-C6-tmcTQ.js +1 -0
- package/dist/client/assets/DataTable-CdVIFm8T.css +1 -0
- package/dist/client/assets/ErrorDashboard-0CGkszcN.css +1 -0
- package/dist/client/assets/ErrorDashboard-CfUhPzue.js +1 -0
- package/dist/client/assets/FpsMonitor-B_AuHgyu.js +1 -0
- package/dist/client/assets/FpsMonitor-BmS11Tn7.css +1 -0
- package/dist/client/assets/Inspect-BOgmKm6W.js +3 -0
- package/dist/client/assets/Inspect-Ci9HWo78.css +1 -0
- package/dist/client/assets/Inspector-CDwlmfEg.css +1 -0
- package/dist/client/assets/Inspector-DGmAzhki.js +1 -0
- package/dist/client/assets/LoadProfiler-5xhnDLjR.js +1 -0
- package/dist/client/assets/LoadProfiler-cg28l5zW.css +1 -0
- package/dist/client/assets/ModuleGraph-B6XWZJQb.css +1 -0
- package/dist/client/assets/ModuleGraph-Cp7f0Nz0.js +1 -0
- package/dist/client/assets/OGPreview-CSIAKIGn.css +1 -0
- package/dist/client/assets/OGPreview-CjBhXSgn.js +1 -0
- package/dist/client/assets/Overview-B8hvIsIM.css +1 -0
- package/dist/client/assets/Overview-Kbpkgsas.js +1 -0
- package/dist/client/assets/ReactiveGraph-Bq_aP4uo.css +1 -0
- package/dist/client/assets/ReactiveGraph-w2TK82c8.js +5 -0
- package/dist/client/assets/RenderProfiler-CS1FAvX6.css +1 -0
- package/dist/client/assets/RenderProfiler-CeF8_j3b.js +1 -0
- package/dist/client/assets/Routes-DArWZtzC.js +1 -0
- package/dist/client/assets/Routes-eFPp9T07.css +1 -0
- package/dist/client/assets/SearchField-DWMQuleP.css +1 -0
- package/dist/client/assets/SearchField-eocQu1eB.js +1 -0
- package/dist/client/assets/Segmented-JGNuI5EZ.js +1 -0
- package/dist/client/assets/Segmented-OaYMdNpv.css +1 -0
- package/dist/client/assets/SplitView-B8lYXXEm.js +1 -0
- package/dist/client/assets/SplitView-CbR-hDtW.css +1 -0
- package/dist/client/assets/StateTimeline-B4FdF3L3.css +1 -0
- package/dist/client/assets/StateTimeline-HpyvgoK1.js +1 -0
- package/dist/client/assets/TreeView-BL5XbGhe.css +1 -0
- package/dist/client/assets/TreeView-fty5aCC5.js +1 -0
- package/dist/client/assets/VirtualList-BvOBTnYJ.js +1 -0
- package/dist/client/assets/VirtualList-CRDBwjCp.css +1 -0
- package/dist/client/assets/browser-agent-rpc-BXhoSh1z-D9g7mT9G.js +1 -0
- package/dist/client/assets/capture.svelte-CUhwdJwX.js +1 -0
- package/dist/client/assets/format-CW_NXiBg.js +1 -0
- package/dist/client/assets/index-BzMw8R8l.js +7 -0
- package/dist/client/assets/index-eZHqMk0z.css +1 -0
- package/dist/client/assets/reactive-C2hv2QLH.js +1 -0
- package/dist/client/assets/reactive-selection.svelte-Dfd9zWsh.js +1 -0
- package/dist/client/assets/versions-CZjRj40E.js +1 -0
- package/dist/client/assets/versions-Co596WUJ.css +1 -0
- package/dist/client/index.html +3 -14
- package/dist/collector.d.ts +284 -0
- package/dist/devframe.d.ts +90 -0
- package/dist/index.mjs +1839 -808
- package/dist/index.mjs.map +1 -1
- package/dist/mcp/server.d.ts +21 -1
- package/dist/mcp/sessions.d.ts +9 -0
- package/dist/mount.d.ts +18 -0
- package/dist/runtime.d.ts +4 -2
- package/dist/security.d.ts +27 -0
- package/dist/template-injector.d.ts +14 -2
- package/dist/types.d.ts +176 -0
- package/package.json +23 -22
- package/skills/vite-devtools-svelte-perf-audit/SKILL.md +1 -1
- package/dist/client/assets/client-BF-DBa_K.js +0 -4
- package/dist/client/assets/index-CnFg6eG8.js +0 -6
- package/dist/client/assets/index-D-ChuYqP.css +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,50 +1,56 @@
|
|
|
1
1
|
import e from "node:path";
|
|
2
|
-
import t from "node:
|
|
3
|
-
import n from "
|
|
4
|
-
import r from "
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import o from "
|
|
8
|
-
import s from "
|
|
9
|
-
import {
|
|
10
|
-
import { StreamableHTTPServerTransport as l } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2
|
+
import t from "node:crypto";
|
|
3
|
+
import { launchEditor as n } from "devframe/utils/launch-editor";
|
|
4
|
+
import r from "fs";
|
|
5
|
+
import i from "path";
|
|
6
|
+
import a from "node:fs";
|
|
7
|
+
import { createRequire as o } from "node:module";
|
|
8
|
+
import { fileURLToPath as s } from "node:url";
|
|
9
|
+
import { defineDevframe as c, defineRpcFunction as l } from "devframe";
|
|
11
10
|
import { z as u } from "zod";
|
|
11
|
+
import d from "node:dns/promises";
|
|
12
|
+
import f from "node:net";
|
|
13
|
+
import p from "node:os";
|
|
14
|
+
import { initDevframe as m } from "devframe/initiate";
|
|
15
|
+
import { McpServer as ee } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
16
|
+
import { StreamableHTTPServerTransport as te } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
17
|
+
import { DEVTOOLS_MOUNT_PATH as ne } from "@vitejs/devtools-kit/constants";
|
|
12
18
|
//#region src/analyzers/routes.ts
|
|
13
|
-
function
|
|
14
|
-
if (!
|
|
19
|
+
function re(e) {
|
|
20
|
+
if (!r.existsSync(e)) return [];
|
|
15
21
|
let t = [];
|
|
16
|
-
return
|
|
22
|
+
return ie(e, e, t), t.sort((e, t) => e.path.localeCompare(t.path));
|
|
17
23
|
}
|
|
18
|
-
function
|
|
19
|
-
let
|
|
20
|
-
for (let
|
|
21
|
-
if (
|
|
22
|
-
|
|
24
|
+
function ie(e, t, n) {
|
|
25
|
+
let a = r.readdirSync(e, { withFileTypes: !0 }), o = [], s = !1;
|
|
26
|
+
for (let r of a) {
|
|
27
|
+
if (r.isDirectory()) {
|
|
28
|
+
ie(i.join(e, r.name), t, n);
|
|
23
29
|
continue;
|
|
24
30
|
}
|
|
25
|
-
let
|
|
26
|
-
|
|
31
|
+
let a = ae(r.name, i.join(e, r.name));
|
|
32
|
+
a && (o.push(a), s = !0);
|
|
27
33
|
}
|
|
28
|
-
if (
|
|
29
|
-
let r =
|
|
34
|
+
if (s) {
|
|
35
|
+
let r = i.relative(t, e), a = oe(r), s = se(r);
|
|
30
36
|
n.push({
|
|
31
37
|
id: r || "/",
|
|
32
38
|
path: a,
|
|
33
39
|
pattern: a,
|
|
34
40
|
segments: a.split("/").filter(Boolean),
|
|
35
|
-
hasPage:
|
|
36
|
-
hasLayout:
|
|
37
|
-
hasServerPage:
|
|
38
|
-
hasServerLayout:
|
|
39
|
-
hasEndpoint:
|
|
40
|
-
hasPageLoad:
|
|
41
|
-
hasLayoutLoad:
|
|
42
|
-
params:
|
|
43
|
-
files:
|
|
41
|
+
hasPage: o.some((e) => e.type === "page"),
|
|
42
|
+
hasLayout: o.some((e) => e.type === "layout"),
|
|
43
|
+
hasServerPage: o.some((e) => e.type === "page-load-server"),
|
|
44
|
+
hasServerLayout: o.some((e) => e.type === "layout-load-server"),
|
|
45
|
+
hasEndpoint: o.some((e) => e.type === "endpoint"),
|
|
46
|
+
hasPageLoad: o.some((e) => e.type === "page-load"),
|
|
47
|
+
hasLayoutLoad: o.some((e) => e.type === "layout-load"),
|
|
48
|
+
params: s,
|
|
49
|
+
files: o
|
|
44
50
|
});
|
|
45
51
|
}
|
|
46
52
|
}
|
|
47
|
-
function
|
|
53
|
+
function ae(e, t) {
|
|
48
54
|
let n = {
|
|
49
55
|
"+page.svelte": "page",
|
|
50
56
|
"+layout.svelte": "layout",
|
|
@@ -65,8 +71,8 @@ function p(e, t) {
|
|
|
65
71
|
path: t
|
|
66
72
|
} : null;
|
|
67
73
|
}
|
|
68
|
-
function
|
|
69
|
-
return e ? "/" + e.split(
|
|
74
|
+
function oe(e) {
|
|
75
|
+
return e ? "/" + e.split(i.sep).map((e) => {
|
|
70
76
|
if (e.startsWith("(") && e.endsWith(")")) return null;
|
|
71
77
|
if (e.startsWith("[") && e.endsWith("]")) {
|
|
72
78
|
let t = e.slice(1, -1);
|
|
@@ -75,9 +81,9 @@ function m(e) {
|
|
|
75
81
|
return e;
|
|
76
82
|
}).filter(Boolean).join("/") : "/";
|
|
77
83
|
}
|
|
78
|
-
function
|
|
84
|
+
function se(e) {
|
|
79
85
|
if (!e) return [];
|
|
80
|
-
let t = [], n = e.split(
|
|
86
|
+
let t = [], n = e.split(i.sep);
|
|
81
87
|
for (let e of n) {
|
|
82
88
|
if (!e.startsWith("[") || !e.endsWith("]")) continue;
|
|
83
89
|
let n = e.slice(1, -1);
|
|
@@ -104,8 +110,812 @@ function h(e) {
|
|
|
104
110
|
return t;
|
|
105
111
|
}
|
|
106
112
|
//#endregion
|
|
107
|
-
//#region src/analyzers/
|
|
108
|
-
var g =
|
|
113
|
+
//#region src/analyzers/project.ts
|
|
114
|
+
var ce = 5e3, h = null, g = null, _ = 0;
|
|
115
|
+
function v(e) {
|
|
116
|
+
let t = Date.now();
|
|
117
|
+
if (h && g === e && t - _ < ce) return h;
|
|
118
|
+
let n = le(e);
|
|
119
|
+
return h = n, g = e, _ = t, n;
|
|
120
|
+
}
|
|
121
|
+
function le(e) {
|
|
122
|
+
let t = i.join(e, "package.json"), n = r.existsSync(t) ? JSON.parse(r.readFileSync(t, "utf-8")) : {}, a = n.dependencies || {}, o = n.devDependencies || {};
|
|
123
|
+
return {
|
|
124
|
+
name: n.name || i.basename(e),
|
|
125
|
+
version: n.version || "0.0.0",
|
|
126
|
+
svelteVersion: y(e, "svelte") || a.svelte || o.svelte || "unknown",
|
|
127
|
+
sveltekitVersion: y(e, "@sveltejs/kit") || a["@sveltejs/kit"] || o["@sveltejs/kit"] || "unknown",
|
|
128
|
+
viteVersion: y(e, "vite") || a.vite || o.vite || "unknown",
|
|
129
|
+
dependencies: a,
|
|
130
|
+
devDependencies: o,
|
|
131
|
+
routesDir: ue(e),
|
|
132
|
+
staticDir: de(e)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function y(e, t) {
|
|
136
|
+
try {
|
|
137
|
+
let n = i.join(e, "node_modules", t, "package.json");
|
|
138
|
+
if (r.existsSync(n)) return JSON.parse(r.readFileSync(n, "utf-8")).version;
|
|
139
|
+
} catch {}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
function ue(e) {
|
|
143
|
+
let t = [i.join(e, "src", "routes"), i.join(e, "src", "pages")];
|
|
144
|
+
for (let e of t) if (r.existsSync(e)) return e;
|
|
145
|
+
return i.join(e, "src", "routes");
|
|
146
|
+
}
|
|
147
|
+
function de(e) {
|
|
148
|
+
let t = [i.join(e, "static"), i.join(e, "public")];
|
|
149
|
+
for (let e of t) if (r.existsSync(e)) return e;
|
|
150
|
+
return i.join(e, "static");
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region src/analyzers/components.ts
|
|
154
|
+
function b(e) {
|
|
155
|
+
let t = i.join(e, "src");
|
|
156
|
+
if (!r.existsSync(t)) return [];
|
|
157
|
+
let n = [];
|
|
158
|
+
return x(t, n), n.map((t) => {
|
|
159
|
+
let n = fe(r.readFileSync(t, "utf-8"), t), a = he(t);
|
|
160
|
+
return {
|
|
161
|
+
file: i.relative(e, t),
|
|
162
|
+
name: a,
|
|
163
|
+
imports: n.map((t) => i.relative(e, t))
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function x(e, t) {
|
|
168
|
+
let n = r.readdirSync(e, { withFileTypes: !0 });
|
|
169
|
+
for (let r of n) {
|
|
170
|
+
let n = i.join(e, r.name);
|
|
171
|
+
if (r.isDirectory()) {
|
|
172
|
+
if (r.name === "node_modules" || r.name === ".svelte-kit") continue;
|
|
173
|
+
x(n, t);
|
|
174
|
+
} else r.name.endsWith(".svelte") && t.push(n);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function fe(e, t) {
|
|
178
|
+
let n = [], r = i.dirname(t), a = /import\s+[\w{}\s,*]+\s+from\s+['"]([^'"]+\.svelte)['"]/g, o;
|
|
179
|
+
for (; (o = a.exec(e)) !== null;) {
|
|
180
|
+
let e = o[1], i = pe(e, r, t);
|
|
181
|
+
i && n.push(i);
|
|
182
|
+
}
|
|
183
|
+
return n;
|
|
184
|
+
}
|
|
185
|
+
function pe(e, t, n) {
|
|
186
|
+
if (e.startsWith("$lib/") || e.startsWith("#lib/")) {
|
|
187
|
+
let t = me(n);
|
|
188
|
+
if (t) {
|
|
189
|
+
let n = i.join(t, "src", "lib", e.slice(5));
|
|
190
|
+
if (r.existsSync(n)) return n;
|
|
191
|
+
}
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
if (e.startsWith(".")) {
|
|
195
|
+
let n = i.resolve(t, e);
|
|
196
|
+
if (r.existsSync(n)) return n;
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
function me(e) {
|
|
201
|
+
let t = i.dirname(e);
|
|
202
|
+
for (; t !== i.dirname(t);) {
|
|
203
|
+
if (r.existsSync(i.join(t, "package.json"))) return t;
|
|
204
|
+
t = i.dirname(t);
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
function he(e) {
|
|
209
|
+
return i.basename(e, ".svelte");
|
|
210
|
+
}
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/runtime.ts
|
|
213
|
+
var S = "virtual:svelte-devtools-runtime", ge = "\0virtual:svelte-devtools-runtime", _e = "\0svelte-devtools:wrapped-client", ve = "\nimport * as __svelte_original from 'svelte/internal/client';\nexport * from 'svelte/internal/client';\n\nfunction __dt() {\n return typeof window !== 'undefined' ? window.__SVELTE_DEVTOOLS__ : null;\n}\n\n// Component ID stack (parallel to runtime._stack but local to wrapper)\nconst __idStack = [];\nfunction __currentId() {\n return __idStack.length > 0 ? __idStack[__idStack.length - 1] : null;\n}\n\n// Tracks the most recently created signal for type determination in tag()\nconst __pendingSignal = { ref: null, type: null };\n\n// Component context -> devtools id (review B1b). A component created later\n// by a block update ({#each}/{#if} after mount) runs outside its parent's\n// push..pop, where the runtime's init stack is empty (the wrapper stack\n// below covers the wrapped block helpers; this covers the rest). Svelte (5.56.8,\n// internal/client) exports active_effect; every effect records the\n// component context it was created in (effect.ctx) and runs with that\n// context restored. The block effect that creates the child belongs to the\n// parent's template, so active_effect.ctx at push time IS the parent's\n// context. Each context is mapped to its id once the component mounted\n// (inside its own deferred effect, where active_effect.ctx is the\n// component's own context). Weak map: no leak, no Svelte state touched.\nconst __idByContext = new WeakMap();\nfunction __parentFromContext() {\n const effect = __svelte_original.active_effect;\n const ctx = effect ? effect.ctx : null;\n return ctx ? __idByContext.get(ctx) : undefined;\n}\n\n// --- Component Lifecycle ---\n//\n// Observer must not break the observed: every devtools side-effect below is\n// wrapped in try/catch so a bug or an out-of-shape runtime cannot tear down\n// the user's app. The original Svelte function is always called, and its\n// return value always returned, regardless of devtools failures.\n\nexport function push() {\n // Parent hint, read before this component's own id exists:\n // 1. the wrapper stack: the component whose init is running (children\n // rendered directly by a template, where active_effect still belongs to\n // an outer block), or the block owner re-pushed by __wrapBlockFn for a\n // later {#each}/{#if}/{#key} update (see Block Attribution below);\n // 2. else the context-derived owner, for re-creation paths the wrapper\n // does not wrap (snippet, svelte:element, ...).\n let parentHint = null;\n try { parentHint = __currentId(); } catch {}\n if (parentHint === null) {\n try { parentHint = __parentFromContext(); } catch {}\n }\n const result = __svelte_original.push.apply(null, arguments);\n try {\n const dt = __dt();\n if (dt) {\n const file = dt._pendingFile || 'Unknown';\n dt._pendingFile = null;\n dt._pendingParent = parentHint;\n const id = dt.register(file);\n __idStack.push(id);\n dt.startInit(id);\n try {\n __svelte_original.user_effect(() => {\n try {\n const own = __svelte_original.active_effect;\n if (own && own.ctx) __idByContext.set(own.ctx, id);\n } catch {}\n return () => { try { dt.unmount(id); } catch {} };\n });\n } catch {}\n }\n } catch {}\n return result;\n}\n\nexport function pop() {\n // Capture devtools errors but ALWAYS forward to the original pop so the\n // Svelte component stack stays balanced.\n try {\n const dt = __dt();\n if (dt && __idStack.length > 0) {\n const id = __idStack.pop();\n try { dt.endInit(id); } catch {}\n try { dt.registered(id); } catch {}\n }\n } catch {}\n return __svelte_original.pop.apply(null, arguments);\n}\n\n// --- Signal Creation (type markers) ---\n\nexport function state() {\n const signal = __svelte_original.state.apply(null, arguments);\n try {\n __pendingSignal.ref = signal;\n __pendingSignal.type = 'state';\n } catch {}\n return signal;\n}\n\nexport function derived() {\n const signal = __svelte_original.derived.apply(null, arguments);\n try {\n __pendingSignal.ref = signal;\n __pendingSignal.type = 'derived';\n } catch {}\n return signal;\n}\n\nexport function proxy() {\n const p = __svelte_original.proxy.apply(null, arguments);\n try {\n __pendingSignal.ref = p;\n __pendingSignal.type = 'proxy';\n } catch {}\n return p;\n}\n\n// --- Signal Tagging (Svelte dev mode) ---\n\nexport function tag(signal, name) {\n const result = __svelte_original.tag.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n const type = (__pendingSignal.ref === signal) ? __pendingSignal.type : 'state';\n if (type === 'derived') {\n dt.trackDerived(signal, name, cid);\n } else {\n dt.trackState(signal, name, cid);\n }\n }\n __pendingSignal.ref = null;\n __pendingSignal.type = null;\n } catch {}\n return result;\n}\n\nexport function tag_proxy(proxy, name) {\n const result = __svelte_original.tag_proxy.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt.trackProxy(proxy, name, cid);\n }\n __pendingSignal.ref = null;\n __pendingSignal.type = null;\n } catch {}\n return result;\n}\n\n// --- Effect Tracking ---\n\nexport function user_effect() {\n const result = __svelte_original.user_effect.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt._effectCounter = (dt._effectCounter || 0) + 1;\n // Track the effect OBJECT (not the callback). The Svelte runtime\n // populates result.deps with the signals this effect depends on,\n // which is what getReactiveGraph() reads to build edges.\n dt.trackEffect(result, 'effect_' + dt._effectCounter, cid);\n }\n } catch {}\n return result;\n}\n\nexport function user_pre_effect() {\n const result = __svelte_original.user_pre_effect.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt._effectCounter = (dt._effectCounter || 0) + 1;\n dt.trackEffect(result, 'effect_pre_' + dt._effectCounter, cid);\n }\n } catch {}\n return result;\n}\n\n// --- Render Profiling ---\n//\n// Svelte 5 has no virtual DOM: the compiler wraps every dynamic part of a\n// template in a template_effect (deferred_template_effect for <svelte:head>\n// <title>). A re-run of such an effect IS the component updating the DOM, so\n// these two functions are the measurement points for renders / render time.\n//\n// The first run of an effect is the mount-time paint, already covered by\n// initTime, so it is skipped (initialRun). One state change re-runs several\n// effects of the same component, so durations are pooled per microtask and\n// recorded once per flush: recordRender() +1, recordRenderTime() the sum.\n\nconst __pendingRenderDurations = new Map();\nlet __renderFlushScheduled = false;\n\nfunction __flushRenderDurations() {\n __renderFlushScheduled = false;\n const dt = __dt();\n for (const [cid, duration] of __pendingRenderDurations) {\n if (dt) {\n try { dt.recordRender(cid); } catch {}\n try { dt.recordRenderTime(cid, duration); } catch {}\n }\n }\n __pendingRenderDurations.clear();\n}\n\nfunction __recordRenderDuration(cid, duration) {\n __pendingRenderDurations.set(cid, (__pendingRenderDurations.get(cid) || 0) + duration);\n if (!__renderFlushScheduled) {\n __renderFlushScheduled = true;\n queueMicrotask(__flushRenderDurations);\n }\n}\n\n// Returns a (possibly new) args array whose first element times each re-run\n// of the effect closure. The owning component is whatever id is on top of\n// __idStack at effect-creation time. User exceptions propagate untouched;\n// only the args are built inside try so the original is called exactly once.\nfunction __wrapTemplateEffect(args) {\n const cid = __currentId();\n const fn = args[0];\n if (cid === null || typeof fn !== 'function') return args;\n const wrapped = Array.prototype.slice.call(args);\n let initialRun = true;\n wrapped[0] = function () {\n if (initialRun) {\n initialRun = false;\n return fn.apply(this, arguments);\n }\n const start = performance.now();\n try {\n return fn.apply(this, arguments);\n } finally {\n try { __recordRenderDuration(cid, performance.now() - start); } catch {}\n }\n };\n return wrapped;\n}\n\nexport function template_effect() {\n let args = arguments;\n try { args = __wrapTemplateEffect(arguments); } catch {}\n return __svelte_original.template_effect.apply(null, args);\n}\n\nexport function deferred_template_effect() {\n let args = arguments;\n try { args = __wrapTemplateEffect(arguments); } catch {}\n return __svelte_original.deferred_template_effect.apply(null, args);\n}\n\n// --- Block Attribution ---\n//\n// Svelte creates render effects synchronously at creation time. At mount this\n// happens during the component function (between push/pop), so __idStack has\n// the owner. But effects for {#each} items added later or re-created {#if}\n// branches are created during a batch flush, when the stack is empty — they\n// would never be attributed. Block helpers themselves ARE always called\n// during their owner's init (or inside an outer block's callback), so the\n// owner id is on the stack at block-creation time. __wrapBlock captures it\n// and re-pushes it around every function argument the block invokes later,\n// so effects created inside land on the innermost owner. Child components\n// push their own id on top, keeping nested attribution correct.\n\nfunction __wrapBlockFn(fn, cid) {\n return function () {\n let pushed = false;\n try { __idStack.push(cid); pushed = true; } catch {}\n try {\n return fn.apply(this, arguments);\n } finally {\n if (pushed) { try { __idStack.pop(); } catch {} }\n }\n };\n}\n\nfunction __wrapBlock(args) {\n const cid = __currentId();\n if (cid === null) return args;\n const wrapped = Array.prototype.slice.call(args);\n for (let i = 0; i < wrapped.length; i++) {\n if (typeof wrapped[i] === 'function') wrapped[i] = __wrapBlockFn(wrapped[i], cid);\n }\n return wrapped;\n}\n\nexport function each() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original.each.apply(null, args);\n}\n\nexport function key() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original.key.apply(null, args);\n}\n\nexport function component() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original.component.apply(null, args);\n}\n\nexport function boundary() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original.boundary.apply(null, args);\n}\n\n// 'if' and 'await' are reserved words, so they cannot be declared as\n// function names and are exported via aliases instead.\nfunction __if_block() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original['if'].apply(null, args);\n}\n\nfunction __await_block() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original['await'].apply(null, args);\n}\n\nexport { __if_block as if, __await_block as await };\n", ye = "\nif (typeof window !== 'undefined' && !window.__SVELTE_DEVTOOLS__) {\n const __NO_VALUE = Symbol('no value');\n // FNV-1a over UTF-16 code units: cheap change detection for large snapshots.\n const __hash = (str) => {\n let h = 0x811c9dc5;\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return (h >>> 0).toString(36);\n };\n const __SVELTE_DT = {\n _nextId: 0,\n _instances: new Map(),\n _stack: [],\n _pendingParent: undefined,\n _pendingFile: null,\n _effectCounter: 0,\n _debounceTimer: null,\n _listeners: new Set(),\n\n // Phase 2: Profiling data\n _profiles: new Map(),\n _initStartTimes: new Map(),\n _profileDebounceTimer: null,\n\n // Phase 2: Reactive graph data\n _reactiveNodes: new Map(),\n _reactiveProxies: new Map(),\n\n // componentId -> Set<nodeId>. Lets unmount purge a component's reactive\n // nodes without scanning every node of the app (was O(components x nodes)).\n _nodesByComponent: new Map(),\n\n // Phase 3: State timeline\n _stateTimeline: [],\n _stateSnapshots: new Map(),\n _timelineDebounceTimer: null,\n // signal (or proxy marker) -> nodeId, set at track time and removed by\n // _forgetNode: a scoped graph resolves dependencies without scanning\n // every node (§6.7 D).\n _idBySignal: new WeakMap(),\n // Polling bookkeeping (§6.7 D): $state node ids in a dense array kept up\n // to date incrementally (_pollIndex: nodeId -> position; removal is\n // swap-with-last), a cursor carried across ticks, nodes found changed but\n // not yet serialized (_pollDirty), and per-node change hints\n // (nodeId -> { ref, wv, nextCheckAt }).\n _pollIds: [],\n _pollIndex: new Map(),\n _pollCursor: 0,\n _pollDirty: new Set(),\n // Full-sweep bookkeeping: how long the last complete pass over all $state\n // nodes took (ms), for disclosure (= the worst-case detection delay).\n _pollSweep: { startedAt: 0, lastMs: null, nodes: 0 },\n _pollMeta: new Map(),\n _deepCredit: 0,\n _lastSnapshotSize: new Map(),\n _timelineSeq: 0,\n _pushedSeq: 0,\n _timelineReset: false,\n _entryInfo: new WeakMap(),\n // Sum of _entryInfo.bytes over _stateTimeline (runtime byte budget).\n _timelineBytes: 0,\n // Disclosure since the last push (§6.7 C): unsent entries the ring removed\n // (by count / by bytes) and changes recorded only as a size summary.\n _timelineDropped: { 'runtime-count': 0, 'runtime-bytes': 0 },\n _valueTooLarge: 0,\n\n // Overview aggregate (§6.7 I/J), O(1) per event: registered nodes per\n // component and type (+ app totals), and per-component activity in a\n // ring of 60 one-second buckets (sampled changes, renders, render ms,\n // plus how long sampling ran in that second).\n _nodeCounts: new Map(),\n _nodeTotals: { state: 0, derived: 0, effect: 0 },\n _activity: [],\n _epoch: Math.random().toString(36).slice(2) + Date.now().toString(36),\n\n // --- Activity subscription (docs/devframe-migration.md §6.3) ---\n // Inactive until the server says a DevTools client (UI tab or MCP lease)\n // is watching: no state polling, FPS rAF loop, or periodic HMR sends.\n _active: false,\n _componentsCost: { ms: 0, bytes: 0 },\n _componentDeltas: false,\n _pendingAdded: new Set(),\n _pendingRemoved: new Set(),\n _lastFullAt: 0,\n _resync: false,\n _profilesCost: { ms: 0, bytes: 0 },\n // = collector LIMITS.renderProfiles (pinned by a unit test): the server\n // keeps only the newest entries, so sending more is wasted bytes.\n _profileCap: 5000,\n _sampling: null,\n _baselining: false,\n // Polled state nodes not observed yet (no seed value). Their first\n // observation is a seed, not a change: no timeline entry, no activity\n // count, no drops — the old value is unknown, not null (review B-1/B-2).\n _unseeded: new Set(),\n // pendingNodes last sent on a state-timeline message (null = none yet)\n _sentPendingNodes: null,\n _fpsGen: 0,\n\n register(file) {\n const id = this._nextId++;\n // Parent: the wrapper's context-derived hint (components created by a\n // later block update, review B1b) when it names a live instance, else\n // the synchronous init stack (children created during the parent's own\n // init, before the parent is mapped).\n const hint = this._pendingParent;\n this._pendingParent = undefined;\n const parentId =\n hint !== undefined && hint !== null && this._instances.has(hint)\n ? hint\n : this._stack.length > 0 ? this._stack[this._stack.length - 1] : null;\n const name = file.split('/').pop()?.replace('.svelte', '') || 'Unknown';\n // children is a Set so unmounting one row of a 5 000-row list is O(1).\n this._instances.set(id, { id, file, name, parentId, mounted: true, children: new Set() });\n if (parentId !== null) {\n const parent = this._instances.get(parentId);\n if (parent) parent.children.add(id);\n }\n this._stack.push(id);\n if (this._active) this._pendingAdded.add(id);\n this._scheduleUpdate();\n return id;\n },\n\n registered(id) {\n const idx = this._stack.indexOf(id);\n if (idx !== -1) this._stack.splice(idx, 1);\n },\n\n mount(id) {\n const instance = this._instances.get(id);\n if (instance && !instance.mounted) {\n instance.mounted = true;\n if (this._active) this._pendingAdded.add(id);\n this._scheduleUpdate();\n }\n },\n\n unmount(id) {\n const instance = this._instances.get(id);\n if (instance) {\n if (instance.parentId !== null) {\n const parent = this._instances.get(instance.parentId);\n if (parent) parent.children.delete(id);\n }\n this._removeChildren(id);\n this._cleanupComponent(id);\n }\n this._scheduleUpdate();\n this._scheduleProfileUpdate();\n },\n\n // Remounts get a fresh id, so entries keyed by a dead id would otherwise\n // survive forever — every per-component map must be purged here.\n _cleanupComponent(id) {\n // Delta bookkeeping: an id added and removed between two pushes was\n // never sent, so it cancels out.\n if (this._active && !this._pendingAdded.delete(id)) this._pendingRemoved.add(id);\n this._cleanupReactiveNodes(id);\n this._instances.delete(id);\n this._profiles.delete(id);\n this._initStartTimes.delete(id);\n },\n\n _cleanupReactiveNodes(componentId) {\n const nodeIds = this._nodesByComponent.get(componentId);\n if (!nodeIds) return;\n this._nodesByComponent.delete(componentId);\n for (const nodeId of nodeIds) this._forgetNode(nodeId);\n },\n\n _forgetNode(nodeId) {\n const entry = this._reactiveNodes.get(nodeId);\n if (entry) this._countNode(entry.meta.componentId, entry.meta.type, -1);\n const signal = entry && entry.signal.deref();\n if (signal && this._idBySignal.get(signal) === nodeId) this._idBySignal.delete(signal);\n this._pollRemove(nodeId);\n this._pollDirty.delete(nodeId);\n this._reactiveNodes.delete(nodeId);\n this._reactiveProxies.delete(nodeId);\n this._stateSnapshots.delete(nodeId);\n if (this._stateSnapshotStrs) this._stateSnapshotStrs.delete(nodeId);\n this._pollMeta.delete(nodeId);\n this._lastSnapshotSize.delete(nodeId);\n },\n\n _indexNode(nodeId, componentId) {\n let set = this._nodesByComponent.get(componentId);\n if (!set) {\n set = new Set();\n this._nodesByComponent.set(componentId, set);\n }\n set.add(nodeId);\n },\n\n _pollAdd(nodeId) {\n if (this._pollIndex.has(nodeId)) return;\n if (!this._stateSnapshots.has(nodeId)) this._unseeded.add(nodeId);\n this._pollIndex.set(nodeId, this._pollIds.length);\n this._pollIds.push(nodeId);\n },\n\n // O(1): the last id takes the removed slot. If that slot is behind the\n // cursor, the moved id is visited in the next sweep instead of this one\n // (still visited within a bounded number of ticks).\n // Before a track* call replaces/creates nodeId: move the count from the\n // previous registration (same name re-tracked) to the new one.\n _trackNodeCount(nodeId, componentId, type) {\n const prev = this._reactiveNodes.get(nodeId);\n if (prev) this._countNode(prev.meta.componentId, prev.meta.type, -1);\n this._countNode(componentId, type, 1);\n },\n\n _countNode(componentId, type, d) {\n const kind = type === 'derived' || type === 'effect' ? type : 'state';\n let c = this._nodeCounts.get(componentId);\n if (!c) {\n if (d < 0) return;\n c = { state: 0, derived: 0, effect: 0 };\n this._nodeCounts.set(componentId, c);\n }\n c[kind] += d;\n this._nodeTotals[kind] += d;\n if (c.state + c.derived + c.effect <= 0) this._nodeCounts.delete(componentId);\n },\n\n _bucket() {\n const sec = Math.floor(performance.now() / 1000);\n const slot = ((sec % 60) + 60) % 60;\n let b = this._activity[slot];\n if (!b || b.second !== sec) {\n b = { second: sec, sampledMs: 0, rows: new Map() };\n this._activity[slot] = b;\n }\n return b;\n },\n\n _activityRow(componentId) {\n const rows = this._bucket().rows;\n let r = rows.get(componentId);\n if (!r) {\n r = { changes: 0, renders: 0, renderMs: 0 };\n rows.set(componentId, r);\n }\n return r;\n },\n\n _pollRemove(nodeId) {\n const i = this._pollIndex.get(nodeId);\n if (i === undefined) return;\n this._unseeded.delete(nodeId);\n const ids = this._pollIds;\n const last = ids.pop();\n this._pollIndex.delete(nodeId);\n if (i < ids.length) {\n ids[i] = last;\n this._pollIndex.set(last, i);\n }\n },\n\n _removeChildren(parentId) {\n const parent = this._instances.get(parentId);\n if (!parent) return;\n for (const childId of [...parent.children]) {\n this._removeChildren(childId);\n this._cleanupComponent(childId);\n }\n },\n\n // Full-list pushes are throttled, not debounced: a pending timer is not\n // reset, so continuous churn still produces updates (a debounce would\n // starve), and the interval adapts to the last push's cost so a 10 000+\n // instance app can't spend its main thread serializing (review P3):\n // max(min, 20 x last send ms, 1 s when the last payload exceeded ~1 MB).\n _sendInterval(cost, min) {\n return Math.max(min, 20 * cost.ms, cost.bytes > 1000000 ? 1000 : 0);\n },\n\n _scheduleUpdate() {\n if (!this._active || this._debounceTimer) return;\n this._debounceTimer = setTimeout(() => {\n this._debounceTimer = null;\n this._sendUpdate();\n }, this._sendInterval(this._componentsCost, 100));\n },\n\n // components push (§6.5). Full form { epoch, components } replaces the\n // server's tree for this epoch: sent on activation, when the server does\n // not advertise componentDeltas, as a periodic checkpoint, or when the\n // delta would be larger than the tree. Otherwise the delta form\n // { epoch, added, removed } (removed ids first, ≤ 2 000 entries per\n // message, added in registration order = parents first).\n _sendUpdate(forceFull) {\n // Nobody watching: keep the registry, skip the O(N) payload. A full\n // snapshot is sent on activation (§6.3).\n if (!this._active) return;\n const t0 = performance.now();\n const CHUNK = 2000;\n const CHECKPOINT_MS = 30000;\n const pending = this._pendingAdded.size + this._pendingRemoved.size;\n const full =\n forceFull ||\n !this._componentDeltas ||\n t0 - this._lastFullAt >= CHECKPOINT_MS ||\n pending > this._instances.size;\n const toEntry = (instance) => ({\n id: instance.id,\n file: instance.file,\n name: instance.name,\n parentId: instance.parentId,\n mounted: instance.mounted,\n });\n let bytes = 0;\n const msgs = [];\n if (full) {\n const components = [];\n for (const [, instance] of this._instances) {\n if (instance.mounted) {\n components.push(toEntry(instance));\n bytes += instance.file.length + instance.name.length + 72;\n }\n }\n msgs.push({ epoch: this._epoch, reset: true, components });\n this._lastFullAt = t0;\n } else if (pending > 0) {\n const removed = [...this._pendingRemoved];\n const added = [];\n for (const id of this._pendingAdded) {\n const instance = this._instances.get(id);\n if (instance && instance.mounted) {\n added.push(toEntry(instance));\n bytes += instance.file.length + instance.name.length + 72;\n }\n }\n bytes += removed.length * 8;\n for (let r = 0; r < removed.length; r += CHUNK) {\n msgs.push({ epoch: this._epoch, added: [], removed: removed.slice(r, r + CHUNK) });\n }\n for (let a = 0; a < added.length; a += CHUNK) {\n msgs.push({ epoch: this._epoch, added: added.slice(a, a + CHUNK), removed: [] });\n }\n }\n this._pendingAdded.clear();\n this._pendingRemoved.clear();\n if (import.meta.hot) {\n for (const msg of msgs) import.meta.hot.send('svelte-devtools:components', msg);\n }\n this._componentsCost = { ms: performance.now() - t0, bytes };\n },\n\n getTree() {\n const components = [];\n for (const [, instance] of this._instances) {\n if (instance.mounted) {\n components.push({\n id: instance.id,\n file: instance.file,\n name: instance.name,\n parentId: instance.parentId,\n mounted: instance.mounted,\n });\n }\n }\n return components;\n },\n\n // --- Phase 2: Render Profiling ---\n\n startInit(id) {\n this._initStartTimes.set(id, performance.now());\n },\n\n endInit(id) {\n const start = this._initStartTimes.get(id);\n if (start === undefined) return;\n const initTime = performance.now() - start;\n this._initStartTimes.delete(id);\n const instance = this._instances.get(id);\n if (!instance) return;\n this._profiles.set(id, {\n componentId: id,\n file: instance.file,\n name: instance.name,\n initTime,\n renderCount: 0,\n totalRenderTime: 0,\n lastRenderTime: 0,\n lastRenderAt: Date.now(),\n });\n this._scheduleProfileUpdate();\n },\n\n recordRender(id) {\n const profile = this._profiles.get(id);\n if (!profile) {\n const instance = this._instances.get(id);\n if (!instance) return;\n this._profiles.set(id, {\n componentId: id,\n file: instance.file,\n name: instance.name,\n initTime: 0,\n renderCount: 1,\n totalRenderTime: 0,\n lastRenderTime: 0,\n lastRenderAt: Date.now(),\n });\n } else {\n profile.renderCount++;\n profile.lastRenderAt = Date.now();\n }\n this._activityRow(id).renders++;\n this._scheduleProfileUpdate();\n },\n\n recordRenderTime(id, duration) {\n const profile = this._profiles.get(id);\n if (profile) {\n profile.totalRenderTime += duration;\n profile.lastRenderTime = duration;\n this._activityRow(id).renderMs += duration;\n }\n },\n\n // Profiles push (review P-1 Option A; contract in\n // docs/performance-status.md). Throttled like components, but the floor\n // grows with the payload: every push carries the whole retained map, so\n // a large app coalesces bursts instead of resending ~1 MB twice a second.\n // Hard cap 2 s (contract R6): a slow serialization must not stretch the\n // latency beyond it.\n _profileInterval() {\n const cost = this._profilesCost;\n return Math.min(\n 2000,\n Math.max(500, 20 * cost.ms, cost.bytes > 1000000 ? 2000 : cost.bytes > 250000 ? 1000 : 0),\n );\n },\n\n _scheduleProfileUpdate() {\n if (!this._active || this._profileDebounceTimer) return;\n this._profileDebounceTimer = setTimeout(() => {\n this._profileDebounceTimer = null;\n this._sendProfileUpdate();\n }, this._profileInterval());\n },\n\n // Also the forced path (activation / resync): a pending throttled push is\n // cancelled so the same state is not sent twice.\n _sendProfileUpdate() {\n if (this._profileDebounceTimer) {\n clearTimeout(this._profileDebounceTimer);\n this._profileDebounceTimer = null;\n }\n if (!this._active) return;\n const t0 = performance.now();\n const all = Array.from(this._profiles.values());\n // Exactly what the collector retains: its tail, in the same order.\n const profiles = all.length > this._profileCap ? all.slice(all.length - this._profileCap) : all;\n if (import.meta.hot) {\n // total = all retained profiles; the message carries the newest-mounted\n // tail (§6.7 J IA1 capture policy 'newest-mounted').\n import.meta.hot.send('svelte-devtools:profiles', { epoch: this._epoch, profiles, total: all.length });\n }\n // Payload size from a small sample (entries differ mainly by file path).\n const k = Math.min(8, profiles.length);\n let sampled = 0;\n for (let i = 0; i < k; i++) sampled += JSON.stringify(profiles[i]).length;\n const bytes = k > 0 ? Math.round((sampled / k) * profiles.length) : 0;\n this._profilesCost = { ms: performance.now() - t0, bytes };\n },\n\n getProfiles() {\n return Array.from(this._profiles.values());\n },\n\n resetProfiles() {\n this._profiles.clear();\n this._scheduleProfileUpdate();\n },\n\n // --- Phase 2: Reactive Graph Tracking ---\n\n trackState(signal, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._trackNodeCount(nodeId, componentId, 'state');\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(signal),\n meta: { id: nodeId, type: 'state', name, componentId, componentFile: instance ? instance.file : '' }\n });\n this._idBySignal.set(signal, nodeId);\n this._indexNode(nodeId, componentId);\n this._pollAdd(nodeId);\n },\n\n trackProxy(proxy, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveProxies.set(nodeId, new WeakRef(proxy));\n // The proxy itself stays weakly held (_reactiveProxies). The marker is\n // held strongly so the node is not GC-dropped while the component lives;\n // _cleanupComponent removes it on unmount.\n const marker = { v: '(proxy)', _isProxy: true };\n this._trackNodeCount(nodeId, componentId, 'state');\n this._reactiveNodes.set(nodeId, {\n signal: { deref: () => marker },\n meta: { id: nodeId, type: 'state', name, componentId, componentFile: instance ? instance.file : '' }\n });\n this._idBySignal.set(marker, nodeId);\n this._indexNode(nodeId, componentId);\n this._pollAdd(nodeId);\n },\n\n trackDerived(signal, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._trackNodeCount(nodeId, componentId, 'derived');\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(signal),\n meta: { id: nodeId, type: 'derived', name, componentId, componentFile: instance ? instance.file : '' }\n });\n this._idBySignal.set(signal, nodeId);\n this._indexNode(nodeId, componentId);\n },\n\n trackEffect(effect, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n const target = effect || { v: undefined, _isEffect: true };\n this._trackNodeCount(nodeId, componentId, 'effect');\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(target),\n meta: { id: nodeId, type: 'effect', name, componentId, componentFile: instance ? instance.file : '' }\n });\n this._idBySignal.set(target, nodeId);\n this._indexNode(nodeId, componentId);\n return effect;\n },\n\n _graphNode(nodeId, entry, signal) {\n const node = { ...entry.meta };\n if (signal._isProxy) {\n const proxy = this._reactiveProxies.get(nodeId)?.deref();\n if (proxy) {\n try {\n node.value = Array.isArray(proxy) ? '[' + proxy.length + ']' : '{' + Object.keys(proxy).length + '}';\n } catch { node.value = '(proxy)'; }\n }\n } else if (node.type !== 'effect' && signal.v !== undefined && typeof signal.v !== 'symbol') {\n try {\n const v = signal.v;\n if (typeof v === 'number' || typeof v === 'string' || typeof v === 'boolean' || v === null) {\n node.value = v;\n } else {\n node.value = '(object)';\n }\n } catch { /* ignore */ }\n }\n return node;\n },\n\n // Reactive graph (§6.7 A/D). Caps are applied while building: past\n // maxNodes no node objects are created and only edges whose endpoints\n // are both included are emitted (the rest are counted in edgesOmitted).\n // - scoped (componentId): that component's nodes plus the tracked nodes\n // directly connected to them (via deps / reactions through untracked\n // intermediates). Dependencies are resolved through _idBySignal, so\n // the cost is O(scope + neighbours), not O(all nodes). The walk is\n // completed even past the cap, so total.nodes/edges are exact.\n // - global: nodes in registration order up to maxNodes ('global-head'),\n // with their incoming dependency edges. Nodes past the cap are not\n // dereferenced; total.nodes is the registered count (may include\n // nodes whose signal was already collected, nodesKind 'registered')\n // and total.edges is null when the walk stopped early (not guessed).\n getReactiveGraph(componentId, caps) {\n const scoped = componentId !== undefined && componentId !== null;\n const maxNodes = this._graphCap(caps && caps.maxNodes, 5000);\n const maxEdges = this._graphCap(caps && caps.maxEdges, 20000);\n const live = new Map();\n // Live signal of a tracked node, or null (forgets dead / unmounted nodes).\n const liveSignal = (nodeId) => {\n if (live.has(nodeId)) return live.get(nodeId);\n const entry = this._reactiveNodes.get(nodeId);\n let signal = entry ? entry.signal.deref() : null;\n if (entry && (!signal || !this._instances.has(entry.meta.componentId))) {\n this._forgetNode(nodeId);\n signal = null;\n }\n live.set(nodeId, signal || null);\n return signal || null;\n };\n const idOf = (dep) => {\n const id = this._idBySignal.get(dep);\n return id !== undefined && liveSignal(id) === dep ? id : null;\n };\n\n const included = new Set();\n const seen = new Set();\n const edges = [];\n const edgeSet = new Set();\n let edgesOmitted = 0;\n let truncated = false;\n const see = (id) => {\n seen.add(id);\n if (!included.has(id) && included.size < maxNodes) included.add(id);\n return included.has(id);\n };\n const addEdge = (from, to) => {\n const key = from + '>' + to;\n if (from === to || edgeSet.has(key)) return;\n edgeSet.add(key);\n const inFrom = see(from);\n const inTo = see(to);\n if (inFrom && inTo && edges.length < maxEdges) edges.push({ from, to });\n else edgesOmitted++;\n };\n // Walk a signal's neighbours (deps or reactions) through untracked\n // intermediates until tracked nodes are reached.\n const walk = (start, field, onHit) => {\n if (!start) return;\n const visited = new Set();\n const queue = [...start];\n // Index cursor instead of queue.shift(): shift is O(queue) per pop.\n for (let qi = 0; qi < queue.length; qi++) {\n const dep = queue[qi];\n if (!dep || visited.has(dep)) continue;\n visited.add(dep);\n const id = idOf(dep);\n if (id) onHit(id);\n else if (dep[field]) for (const d of dep[field]) queue.push(d);\n }\n };\n\n let totalNodes = 0;\n let totalEdges = null;\n if (scoped) {\n for (const nodeId of [...(this._nodesByComponent.get(componentId) || [])]) {\n const signal = liveSignal(nodeId);\n if (!signal) continue;\n see(nodeId);\n walk(signal.deps, 'deps', (depId) => addEdge(depId, nodeId));\n walk(signal.reactions, 'reactions', (rId) => addEdge(nodeId, rId));\n }\n totalNodes = seen.size;\n totalEdges = edgeSet.size;\n truncated = included.size < seen.size || edgesOmitted > 0;\n } else {\n let complete = true;\n for (const nodeId of [...this._reactiveNodes.keys()]) {\n if (included.size >= maxNodes && !included.has(nodeId)) {\n complete = false;\n break;\n }\n const signal = liveSignal(nodeId);\n if (!signal) continue;\n see(nodeId);\n walk(signal.deps, 'deps', (depId) => addEdge(depId, nodeId));\n }\n // registered count, minus nodes found dead while building\n totalNodes = this._reactiveNodes.size;\n totalEdges = complete ? edgeSet.size : null;\n truncated = !complete || edgesOmitted > 0;\n }\n\n const nodes = [];\n for (const nodeId of included) {\n const signal = liveSignal(nodeId);\n if (signal) nodes.push(this._graphNode(nodeId, this._reactiveNodes.get(nodeId), signal));\n }\n return {\n scope: scoped ? componentId : null,\n nodes,\n edges,\n total: { nodes: totalNodes, nodesKind: 'registered', edges: totalEdges },\n truncated,\n edgesOmitted,\n policy: scoped ? 'scoped' : 'global-head',\n };\n },\n\n _graphCap(value, max) {\n const n = Math.floor(Number(value));\n return Number.isFinite(n) && n >= 1 ? Math.min(n, max) : max;\n },\n\n // Request (§6.7 A + review M1): { requestId?, epoch?, componentId?,\n // maxNodes?, maxEdges? }. A request for another page load (epoch) is not\n // answered by this one; the reply echoes requestId and epoch. An old\n // server sends {} → global graph with the default caps (= its LIMITS).\n sendReactiveGraph(request) {\n const req = request || {};\n if (req.epoch !== undefined && req.epoch !== null && req.epoch !== this._epoch) return;\n const cid = typeof req.componentId === 'number' ? req.componentId : null;\n const graph = this.getReactiveGraph(cid, { maxNodes: req.maxNodes, maxEdges: req.maxEdges });\n graph.epoch = this._epoch;\n // freshness (review): when this answer was built; caches keep it\n graph.computedAt = Date.now();\n if (req.requestId !== undefined) graph.requestId = req.requestId;\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:reactive-graph', graph);\n }\n },\n\n // Overview aggregate (§6.7 I/J). Built from the activity buckets of the\n // window (whole seconds: the current partial second plus the previous\n // ones, ceil(windowMs / 1000) buckets) — cost O(components active in the\n // window), no graph, no node scan. Rows rank by sampled changes, then\n // renders, then render ms; rows + other = total (components and nodes).\n getReactiveSummary(opts) {\n const o = opts || {};\n const clampInt = (v, lo, hi, d) => {\n const n = Math.floor(Number(v));\n return Number.isFinite(n) ? Math.min(hi, Math.max(lo, n)) : d;\n };\n const topK = clampInt(o.topK, 1, 200, 50);\n const windowMs = clampInt(o.windowMs, 1000, 60000, 10000);\n const nowSec = Math.floor(performance.now() / 1000);\n const agg = new Map();\n let sampledMs = 0;\n for (let k = 0; k < Math.ceil(windowMs / 1000); k++) {\n const sec = nowSec - k;\n const b = this._activity[((sec % 60) + 60) % 60];\n if (!b || b.second !== sec) continue;\n sampledMs += b.sampledMs;\n for (const [cid, r] of b.rows) {\n if (!this._instances.has(cid)) continue;\n let a = agg.get(cid);\n if (!a) {\n a = { changes: 0, renders: 0, renderMs: 0 };\n agg.set(cid, a);\n }\n a.changes += r.changes;\n a.renders += r.renders;\n a.renderMs += r.renderMs;\n }\n }\n const ranked = [...agg].sort(\n (x, y) =>\n y[1].changes - x[1].changes || y[1].renders - x[1].renders || y[1].renderMs - x[1].renderMs || x[0] - y[0],\n );\n let rowNodes = 0;\n const rows = ranked.slice(0, topK).map(([cid, a]) => {\n const n = this._nodeCounts.get(cid) || { state: 0, derived: 0, effect: 0 };\n rowNodes += n.state + n.derived + n.effect;\n return {\n componentId: cid,\n file: this._instances.get(cid).file,\n nodes: { state: n.state, derived: n.derived, effect: n.effect },\n changes: a.changes,\n renders: a.renders,\n renderMs: Math.round(a.renderMs * 1000) / 1000,\n };\n });\n const t = this._nodeTotals;\n const until = Date.now();\n return {\n epoch: this._epoch,\n window: { ms: windowMs, since: until - windowMs, until, sampledActiveMs: Math.min(windowMs, sampledMs) },\n policy: 'sampled-200ms',\n coverage: 'component-init',\n components: { total: this._instances.size, withActivity: agg.size },\n rows,\n other: { components: this._instances.size - rows.length, nodes: t.state + t.derived + t.effect - rowNodes },\n truncated: agg.size > topK,\n capabilities: { valueInspection: false, signalHistory: false, writeCause: false },\n // Seed coverage: changes of pending nodes are not observable yet.\n baseline: this._baselineInfo(),\n };\n },\n\n // Request { requestId?, epoch?, topK?, windowMs? } (same correlation as\n // the graph, review M1).\n sendReactiveSummary(request) {\n const req = request || {};\n if (req.epoch !== undefined && req.epoch !== null && req.epoch !== this._epoch) return;\n const summary = this.getReactiveSummary(req);\n if (req.requestId !== undefined) summary.requestId = req.requestId;\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:reactive-summary', summary);\n }\n },\n\n // --- Phase 3: State Timeline ---\n\n // Current value of a $state node: the signal value, or for tag_proxy\n // nodes (non-reassigned object/array state) the live proxy itself.\n // Returns a sentinel when the value can't be read.\n _readStateValue(nodeId, signal) {\n if (signal._isProxy) {\n const proxy = this._reactiveProxies.get(nodeId)?.deref();\n return proxy === undefined ? __NO_VALUE : proxy;\n }\n const v = signal.v;\n // Svelte's UNINITIALIZED marker is a symbol; functions aren't state data.\n return typeof v === 'symbol' || typeof v === 'function' ? __NO_VALUE : v;\n },\n\n // Runs every 200 ms in the user's app, so it must stay cheap regardless of\n // how much state the app holds (§6.7 D).\n // 1. Hint pass, time-sliced: at most HINT_NODES $state nodes per tick,\n // continuing from a cursor carried across ticks, so a full sweep over\n // n nodes takes ceil(n / HINT_NODES) ticks (_pollSweep.lastMs is the\n // measured sweep time = worst-case detection delay). Per node O(1):\n // primitives are compared directly and recorded at once; objects\n // whose reference or Svelte write version (wv) changed are added to\n // _pollDirty, which persists across ticks until serialized.\n // 2. Serialization work is limited to BUDGET_MS per tick (dirty nodes\n // carry over, nothing is dropped).\n // 3. In-place deep mutations (proxies don't bump an outer wv) are found by\n // time-based re-checks: each object is re-verified no earlier than\n // nextCheckAt = now + max(RECHECK_MS, 50 x its serialization cost),\n // paid from a DEEP_MS-per-tick credit, so the amortized cost is bounded\n // however many large states the app holds.\n // 4. Values serializing above MAX_SNAPSHOT_CHARS are kept as length+hash\n // (not the string) and appear in the timeline as a summary.\n // Writes between two visits of a node are observed as one change (the\n // timeline is a sample, policy 'sampled-200ms'; not counted as dropped).\n _pollStateValues(baseline) {\n const HINT_NODES = 4096;\n const BUDGET_MS = 2;\n const DEEP_MS = 0.5;\n const now = performance.now();\n if (!baseline) {\n this._deepCredit = Math.min(10 * DEEP_MS, (this._deepCredit || 0) + DEEP_MS);\n // this tick samples 200 ms of wall time (window.sampledActiveMs)\n const bucket = this._bucket();\n bucket.sampledMs = Math.min(1000, bucket.sampledMs + 200);\n }\n const ids = this._pollIds;\n const due = [];\n const limit = Math.min(HINT_NODES, ids.length);\n for (let visited = 0; visited < limit && ids.length > 0; visited++) {\n if (this._pollCursor >= ids.length) {\n this._pollCursor = 0;\n if (!baseline) {\n if (this._pollSweep.startedAt) this._pollSweep.lastMs = now - this._pollSweep.startedAt;\n this._pollSweep.startedAt = now;\n this._pollSweep.nodes = ids.length;\n }\n }\n if (!baseline && !this._pollSweep.startedAt) this._pollSweep.startedAt = now;\n const nodeId = ids[this._pollCursor];\n const entry = this._reactiveNodes.get(nodeId);\n if (!entry || entry.meta.type !== 'state') {\n // re-tracked as another type: drop from the poll list (slot reused)\n this._pollRemove(nodeId);\n continue;\n }\n if (!this._instances.has(entry.meta.componentId)) {\n this._forgetNode(nodeId); // swaps the last id into this slot\n continue;\n }\n this._pollCursor++;\n const signal = entry.signal.deref();\n const value = signal ? this._readStateValue(nodeId, signal) : __NO_VALUE;\n if (value === __NO_VALUE) {\n // nothing readable (collected, uninitialized, function): not pending\n this._unseeded.delete(nodeId);\n continue;\n }\n if (value === null || typeof value !== 'object') {\n const had = this._stateSnapshots.has(nodeId);\n const prev = this._stateSnapshots.get(nodeId);\n if (had && Object.is(prev, value)) continue;\n // Forget the object key so object -> primitive -> same object again\n // is still recorded as a change.\n if (this._stateSnapshotStrs) this._stateSnapshotStrs.delete(nodeId);\n this._pollDirty.delete(nodeId);\n if (!had) {\n // first observation: seed only\n this._stateSnapshots.set(nodeId, value);\n this._unseeded.delete(nodeId);\n continue;\n }\n this._recordChange(nodeId, entry, prev, value, typeof value === 'string' ? 2 * value.length : 64);\n continue;\n }\n let meta = this._pollMeta.get(nodeId);\n if (!meta) {\n meta = { ref: undefined, wv: undefined, nextCheckAt: 0 };\n this._pollMeta.set(nodeId, meta);\n }\n if (meta.ref !== value || meta.wv !== signal.wv) this._pollDirty.add(nodeId);\n else if (now >= meta.nextCheckAt) due.push(nodeId);\n }\n const start = performance.now();\n for (const nodeId of this._pollDirty) {\n if (performance.now() - start > BUDGET_MS) return;\n this._pollDirty.delete(nodeId);\n this._serializeNode(nodeId, false);\n }\n for (const nodeId of due) {\n if (this._deepCredit <= 0 || performance.now() - start > BUDGET_MS) return;\n this._serializeNode(nodeId, true);\n }\n },\n\n // Activation (late consumer): nodes registered while inactive have no\n // seed yet, so a write before their first visit could not be seen as a\n // change. The first slice is seeded at activation instead of 200 ms later:\n // ONE normal pass (<= HINT_NODES nodes, the per-tick serialization budget;\n // the rest follow on the usual ticks). Seeds record nothing; readiness is\n // disclosed in the summary as baseline { complete, pendingNodes }.\n _pollBaseline() {\n this._baselining = true;\n try {\n this._pollStateValues(true);\n } catch { /* never break activation */ } finally {\n this._baselining = false;\n }\n },\n\n _serializeNode(nodeId, deep) {\n const MAX_SNAPSHOT_CHARS = 32768;\n const RECHECK_MS = 1000;\n const entry = this._reactiveNodes.get(nodeId);\n const meta = this._pollMeta.get(nodeId);\n if (!entry || !meta) return;\n const signal = entry.signal.deref();\n if (!signal) return;\n const value = this._readStateValue(nodeId, signal);\n if (value === __NO_VALUE || value === null || typeof value !== 'object') return;\n try {\n const t0 = performance.now();\n const str = JSON.stringify(value);\n const cost = performance.now() - t0;\n if (deep) this._deepCredit -= cost;\n meta.ref = value;\n meta.wv = signal.wv;\n meta.nextCheckAt = t0 + Math.max(RECHECK_MS, 50 * cost);\n // Small values keep the string (exact compare); large ones only a\n // length+hash so a 5 MB array doesn't pin 5 MB per node.\n const key = str === undefined ? '' : str.length > MAX_SNAPSHOT_CHARS ? str.length + ':' + __hash(str) : str;\n if (!this._stateSnapshotStrs) this._stateSnapshotStrs = new Map();\n const hadKey = this._stateSnapshotStrs.has(nodeId);\n if (hadKey && this._stateSnapshotStrs.get(nodeId) === key) return;\n this._stateSnapshotStrs.set(nodeId, key);\n const tooLarge = str !== undefined && str.length > MAX_SNAPSHOT_CHARS;\n const snapshot =\n str === undefined\n ? null\n : tooLarge\n ? '(object: ' + str.length + ' chars, too large to snapshot)'\n : JSON.parse(str);\n const size = typeof snapshot === 'string' ? 64 : str.length;\n if (!this._stateSnapshots.has(nodeId)) {\n // first observation: seed only (no entry, no counters)\n this._stateSnapshots.set(nodeId, snapshot);\n this._lastSnapshotSize.set(nodeId, size);\n this._unseeded.delete(nodeId);\n return;\n }\n if (tooLarge) this._valueTooLarge++;\n const prev = this._stateSnapshots.get(nodeId);\n this._recordChange(nodeId, entry, prev, snapshot, size + (this._lastSnapshotSize.get(nodeId) || 0));\n this._lastSnapshotSize.set(nodeId, size);\n } catch {\n // non-serializable (cycles, BigInt): never observable, so not pending\n this._unseeded.delete(nodeId);\n }\n },\n\n _recordChange(nodeId, entry, oldValue, newValue, approxBytes) {\n const TIMELINE_BYTES = 4 * 1024 * 1024;\n const change = {\n id: nodeId,\n name: entry.meta.name,\n componentFile: entry.meta.componentFile,\n oldValue,\n newValue,\n timestamp: Date.now(),\n };\n const bytes = (approxBytes || 64) + 192;\n // seq stays runtime-internal: the server assigns its own seq (§6.4).\n this._entryInfo.set(change, { seq: ++this._timelineSeq, bytes });\n this._stateTimeline.push(change);\n this._timelineBytes += bytes;\n // sampled change count (§6.7 J IA2): independent of the ring\n this._activityRow(entry.meta.componentId).changes++;\n this._stateSnapshots.set(nodeId, newValue);\n // Ring: at most 500 entries and TIMELINE_BYTES (the newest entry is\n // always kept). Removed entries that were never pushed are disclosed\n // as dropped (§6.7 C); pushed ones are already on the server.\n const all = this._stateTimeline;\n let cut = 0;\n let bytesLeft = this._timelineBytes;\n while (cut < all.length - 1 && (all.length - cut > 500 || bytesLeft > TIMELINE_BYTES)) {\n const info = this._entryInfo.get(all[cut]);\n const reason = all.length - cut > 500 ? 'runtime-count' : 'runtime-bytes';\n if (info.seq > this._pushedSeq) this._timelineDropped[reason]++;\n bytesLeft -= info.bytes;\n cut++;\n }\n if (cut > 0) {\n all.splice(0, cut);\n this._timelineBytes = bytesLeft;\n }\n this._scheduleTimelineUpdate();\n },\n\n // Push (§6.7 C): a throttle, not a debounce — a pending timer is never\n // re-armed, so unsent entries leave within 300 ms of the first one even\n // under continuous change — plus an immediate flush once 200 entries\n // (one message) are unsent, since one poll tick can record thousands.\n _scheduleTimelineUpdate() {\n if (!this._active || this._baselining) return;\n if (this._timelineSeq - this._pushedSeq >= 200) {\n this._flushTimeline();\n return;\n }\n if (this._timelineDebounceTimer) return;\n this._timelineDebounceTimer = setTimeout(() => {\n this._timelineDebounceTimer = null;\n this._flushTimeline();\n }, 300);\n },\n\n _flushTimeline() {\n if (this._timelineDebounceTimer) {\n clearTimeout(this._timelineDebounceTimer);\n this._timelineDebounceTimer = null;\n }\n if (!import.meta.hot) return;\n for (const msg of this._timelineDeltas()) {\n import.meta.hot.send('svelte-devtools:state-timeline', msg);\n }\n },\n\n // Disclosure counters since the previous push, attached to (and reset\n // by) the next message: dropped [{ reason, count }] and valueTooLarge.\n _takeTimelineDisclosure(msg) {\n msg.baseline = this._baselineInfo();\n this._sentPendingNodes = msg.baseline.pendingNodes;\n const dropped = [];\n for (const reason of ['runtime-count', 'runtime-bytes']) {\n const count = this._timelineDropped[reason];\n if (count > 0) dropped.push({ reason, count });\n this._timelineDropped[reason] = 0;\n }\n if (dropped.length) msg.dropped = dropped;\n if (this._valueTooLarge > 0) msg.valueTooLarge = this._valueTooLarge;\n this._valueTooLarge = 0;\n return msg;\n },\n\n // Seed coverage (review B-2), on every state-timeline message and the\n // summary: pendingNodes = polled $state nodes without a first sample;\n // their writes are not observable yet.\n _baselineInfo() {\n return { complete: this._unseeded.size === 0, pendingNodes: this._unseeded.size };\n },\n\n _hasTimelineDisclosure() {\n return (\n this._sentPendingNodes !== this._unseeded.size ||\n this._timelineDropped['runtime-count'] > 0 ||\n this._timelineDropped['runtime-bytes'] > 0 ||\n this._valueTooLarge > 0\n );\n },\n\n // Delta push (docs/devframe-migration.md §6.4): only entries recorded\n // since the previous push, ≤ 200 per message, tagged with a per-page-load\n // epoch; reset after clearStateTimeline(). A message with no changes is\n // still sent when there is something to disclose (all unsent dropped).\n _timelineDeltas() {\n const all = this._stateTimeline;\n let start = all.length;\n while (start > 0 && this._entryInfo.get(all[start - 1]).seq > this._pushedSeq) start--;\n const pending = all.slice(start);\n const msgs = [];\n const first = this._timelineReset || this._hasTimelineDisclosure();\n for (let i = 0; i < pending.length || (first && i === 0); i += 200) {\n const msg = { epoch: this._epoch, changes: pending.slice(i, i + 200) };\n if (i === 0 && this._timelineReset) msg.reset = true;\n if (i === 0) this._takeTimelineDisclosure(msg);\n else msg.baseline = this._baselineInfo();\n msgs.push(msg);\n }\n this._timelineReset = false;\n this._pushedSeq = this._timelineSeq;\n return msgs;\n },\n\n // Full buffer (reset: true) — reply to request-state-timeline and the\n // activation snapshot. Newest entries first up to TIMELINE_BYTES, the\n // server's own buffer budget, so nothing is sent that it would drop.\n _timelineFull() {\n const TIMELINE_BYTES = 4 * 1024 * 1024;\n const all = this._stateTimeline;\n let start = all.length;\n let bytes = 0;\n while (start > 0) {\n const size = this._entryInfo.get(all[start - 1]).bytes;\n if (bytes + size > TIMELINE_BYTES && start < all.length) break;\n bytes += size;\n start--;\n }\n this._timelineReset = false;\n this._pushedSeq = this._timelineSeq;\n return this._takeTimelineDisclosure({ epoch: this._epoch, changes: all.slice(start), reset: true });\n },\n\n getStateTimeline() {\n return this._stateTimeline;\n },\n\n clearStateTimeline() {\n this._stateTimeline = [];\n this._timelineBytes = 0;\n this._pushedSeq = this._timelineSeq;\n this._timelineReset = true;\n this._scheduleTimelineUpdate();\n },\n\n // --- FPS Monitoring ---\n // Uses requestAnimationFrame to measure frame rate with minimal overhead.\n // Only stores timestamps - no allocations per frame beyond a single array push.\n _fpsFrameTimes: [],\n\n _fpsLoop(gen) {\n if (gen !== this._fpsGen) return;\n this._fpsFrameTimes.push(performance.now());\n requestAnimationFrame(() => this._fpsLoop(gen));\n },\n\n _isVisible() {\n return typeof document === 'undefined' || document.visibilityState !== 'hidden';\n },\n\n _setSubscription(data) {\n const wasActive = this._active;\n this._active = !!(data && data.active);\n this._componentDeltas = !!(data && data.componentDeltas);\n if (!this._active) {\n this._pendingAdded.clear();\n this._pendingRemoved.clear();\n }\n // resync: the server holds no full base for this epoch (§6.5, review\n // C1), or we reconnected to a possibly restarted server.\n const resync = this._resync || !!(data && data.resync);\n this._resync = false;\n if (this._active && !wasActive) this._pollBaseline();\n if (this._active && (!wasActive || resync)) {\n // Collector state may be stale or empty (first activation, resync, or a\n // reconnect to a possibly restarted server): resend everything once, in\n // the order components -> profiles -> timeline(reset: true); the\n // reset push marks the activation snapshot complete (D4).\n this._sendUpdate(true);\n this._sendProfileUpdate();\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:state-timeline', this._timelineFull());\n }\n }\n this._syncSampling();\n },\n\n // Sampling (state poll + FPS) runs only while active AND the app tab is\n // visible.\n _syncSampling() {\n const want = this._active && this._isVisible();\n if (want && !this._sampling) {\n this._fpsFrameTimes = [];\n const gen = ++this._fpsGen;\n this._sampling = {\n poll: setInterval(() => {\n this._pollStateValues();\n // seed progress changed: push it even without changes (B-2)\n if (this._sentPendingNodes !== this._unseeded.size) this._scheduleTimelineUpdate();\n }, 200),\n fps: setInterval(() => { this._sampleFps(); }, 500),\n };\n requestAnimationFrame(() => this._fpsLoop(gen));\n } else if (!want && this._sampling) {\n clearInterval(this._sampling.poll);\n clearInterval(this._sampling.fps);\n this._sampling = null;\n this._fpsGen++;\n this._fpsFrameTimes = [];\n }\n },\n\n _sampleFps() {\n const now = performance.now();\n // Remove frame timestamps older than 1 second\n const cutoff = now - 1000;\n let i = 0;\n while (i < this._fpsFrameTimes.length && this._fpsFrameTimes[i] < cutoff) i++;\n if (i > 0) this._fpsFrameTimes.splice(0, i);\n const fps = this._fpsFrameTimes.length;\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:fps', { timestamp: Date.now(), fps });\n }\n }\n };\n\n window.__SVELTE_DEVTOOLS__ = __SVELTE_DT;\n\n // State polling and FPS sampling start on the server's subscription\n // message (§6.3) and pause while the app tab is hidden.\n if (typeof document !== 'undefined' && document.addEventListener) {\n document.addEventListener('visibilitychange', () => __SVELTE_DT._syncSampling());\n }\n\n // Phase 3: Capture runtime errors\n window.addEventListener('error', (event) => {\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:runtime-error', {\n message: event.message,\n file: event.filename,\n line: event.lineno,\n column: event.colno,\n stack: event.error?.stack || '',\n timestamp: Date.now(),\n });\n }\n });\n window.addEventListener('unhandledrejection', (event) => {\n if (import.meta.hot) {\n const reason = event.reason;\n import.meta.hot.send('svelte-devtools:runtime-error', {\n message: reason?.message || String(reason),\n stack: reason?.stack || '',\n timestamp: Date.now(),\n });\n }\n });\n\n // Listen for reactive graph requests from server\n // Pull requests are answered regardless of the subscription state.\n if (import.meta.hot) {\n import.meta.hot.on('svelte-devtools:subscription', (data) => {\n __SVELTE_DT._setSubscription(data);\n });\n import.meta.hot.on('vite:ws:connect', () => {\n // The server may have restarted with an empty collector: the reply to\n // runtime-ready is treated as a fresh activation (full snapshot).\n __SVELTE_DT._resync = true;\n import.meta.hot.send('svelte-devtools:runtime-ready', {});\n });\n import.meta.hot.send('svelte-devtools:runtime-ready', {});\n import.meta.hot.on('svelte-devtools:request-reactive-graph', (data) => {\n __SVELTE_DT.sendReactiveGraph(data);\n });\n import.meta.hot.on('svelte-devtools:request-reactive-summary', (data) => {\n __SVELTE_DT.sendReactiveSummary(data);\n });\n import.meta.hot.on('svelte-devtools:request-state-timeline', () => {\n import.meta.hot.send('svelte-devtools:state-timeline', __SVELTE_DT._timelineFull());\n });\n import.meta.hot.on('svelte-devtools:clear-state-timeline', () => {\n __SVELTE_DT.clearStateTimeline();\n });\n }\n}\n", C = {
|
|
214
|
+
liveComponents: 5e4,
|
|
215
|
+
renderProfiles: 5e3,
|
|
216
|
+
stateTimeline: 500,
|
|
217
|
+
reactiveNodes: 5e3,
|
|
218
|
+
reactiveEdges: 2e4,
|
|
219
|
+
fpsSamples: 1200,
|
|
220
|
+
runtimeErrors: 200,
|
|
221
|
+
loadProfiles: 200,
|
|
222
|
+
compilerWarnings: 500
|
|
223
|
+
}, be = 1e3, xe = Date.now() * 1e3, w = () => ++xe, T = "(legacy)", E = {
|
|
224
|
+
components: "svelte-devtools:components",
|
|
225
|
+
profiles: "svelte-devtools:profiles",
|
|
226
|
+
stateTimeline: "svelte-devtools:state-timeline",
|
|
227
|
+
fps: "svelte-devtools:fps",
|
|
228
|
+
runtimeError: "svelte-devtools:runtime-error",
|
|
229
|
+
reactiveGraph: "svelte-devtools:reactive-graph",
|
|
230
|
+
requestReactiveGraph: "svelte-devtools:request-reactive-graph",
|
|
231
|
+
requestReactiveSummary: "svelte-devtools:request-reactive-summary",
|
|
232
|
+
reactiveSummary: "svelte-devtools:reactive-summary",
|
|
233
|
+
requestStateTimeline: "svelte-devtools:request-state-timeline",
|
|
234
|
+
clearStateTimeline: "svelte-devtools:clear-state-timeline",
|
|
235
|
+
runtimeReady: "svelte-devtools:runtime-ready",
|
|
236
|
+
subscription: "svelte-devtools:subscription"
|
|
237
|
+
}, Se = 32, D = {
|
|
238
|
+
topK: 50,
|
|
239
|
+
maxTopK: 200,
|
|
240
|
+
windowMs: 1e4,
|
|
241
|
+
minWindowMs: 1e3,
|
|
242
|
+
maxWindowMs: 6e4
|
|
243
|
+
}, O = [
|
|
244
|
+
"runtime-count",
|
|
245
|
+
"runtime-bytes",
|
|
246
|
+
"server-count",
|
|
247
|
+
"server-bytes"
|
|
248
|
+
];
|
|
249
|
+
function k(e) {
|
|
250
|
+
let t = e;
|
|
251
|
+
return !!t && typeof t.complete == "boolean" && Number.isInteger(t.pendingNodes) && t.pendingNodes >= 0;
|
|
252
|
+
}
|
|
253
|
+
function A(e, t, n, r) {
|
|
254
|
+
return typeof e != "number" || !Number.isFinite(e) ? r : Math.min(n, Math.max(t, Math.trunc(e)));
|
|
255
|
+
}
|
|
256
|
+
var Ce = 15e3;
|
|
257
|
+
function j(e, t) {
|
|
258
|
+
let n = Array.isArray(e) ? e : [];
|
|
259
|
+
return n.length > t ? n.slice(-t) : n;
|
|
260
|
+
}
|
|
261
|
+
function M(e, t) {
|
|
262
|
+
let n = Array.isArray(e) ? e : [];
|
|
263
|
+
return n.length > t ? n.slice(0, t) : n;
|
|
264
|
+
}
|
|
265
|
+
var we = class {
|
|
266
|
+
hooks;
|
|
267
|
+
epochs = /* @__PURE__ */ new Map();
|
|
268
|
+
servedEpoch;
|
|
269
|
+
liveCache;
|
|
270
|
+
loadProfiles = [];
|
|
271
|
+
reactiveGraph = {
|
|
272
|
+
nodes: [],
|
|
273
|
+
edges: []
|
|
274
|
+
};
|
|
275
|
+
compilerWarnings = [];
|
|
276
|
+
runtimeErrors = [];
|
|
277
|
+
fpsSamples = [];
|
|
278
|
+
versions = {
|
|
279
|
+
components: w(),
|
|
280
|
+
renderProfiles: w(),
|
|
281
|
+
loadProfiles: w(),
|
|
282
|
+
stateTimeline: w(),
|
|
283
|
+
reactiveGraph: w(),
|
|
284
|
+
errors: w(),
|
|
285
|
+
fps: w()
|
|
286
|
+
};
|
|
287
|
+
bump(...e) {
|
|
288
|
+
for (let t of e) this.versions[t] = w();
|
|
289
|
+
}
|
|
290
|
+
timeline = [];
|
|
291
|
+
timelineSizes = [];
|
|
292
|
+
timelineEpochs = [];
|
|
293
|
+
timelineBytes = 0;
|
|
294
|
+
timelineSeq = w();
|
|
295
|
+
timelineResetAt = this.timelineSeq;
|
|
296
|
+
timelineTrimmedAt = this.timelineSeq;
|
|
297
|
+
lastPull = { stateTimeline: 0 };
|
|
298
|
+
inflight = {};
|
|
299
|
+
pulls = /* @__PURE__ */ new Map();
|
|
300
|
+
pullCache = /* @__PURE__ */ new Map();
|
|
301
|
+
pullInflight = /* @__PURE__ */ new Map();
|
|
302
|
+
requestSeq = 0;
|
|
303
|
+
lastGraph;
|
|
304
|
+
timelineDrops = /* @__PURE__ */ new Map();
|
|
305
|
+
timelineBaseline = /* @__PURE__ */ new Map();
|
|
306
|
+
timelineTooLarge = /* @__PURE__ */ new Map();
|
|
307
|
+
received = {
|
|
308
|
+
fps: 0,
|
|
309
|
+
runtimeErrors: 0,
|
|
310
|
+
loadProfiles: 0,
|
|
311
|
+
compilerWarnings: 0
|
|
312
|
+
};
|
|
313
|
+
hot;
|
|
314
|
+
detachHot;
|
|
315
|
+
leases = /* @__PURE__ */ new Map();
|
|
316
|
+
snapshotWaiters = [];
|
|
317
|
+
active = !1;
|
|
318
|
+
sweepTimer;
|
|
319
|
+
stateTimelineResolvers = [];
|
|
320
|
+
constructor(e = {}) {
|
|
321
|
+
this.hooks = e;
|
|
322
|
+
}
|
|
323
|
+
attach(e) {
|
|
324
|
+
this.detach(), this.hot = e;
|
|
325
|
+
let t = [
|
|
326
|
+
[E.runtimeReady, (e, t) => t?.send(E.subscription, this.subscription)],
|
|
327
|
+
[E.components, (e, t) => this.ingestComponents(e, t)],
|
|
328
|
+
[E.profiles, (e) => this.ingestProfiles(e)],
|
|
329
|
+
[E.stateTimeline, (e) => this.ingestStateTimeline(e)],
|
|
330
|
+
[E.fps, (e) => this.ingestFps(e)],
|
|
331
|
+
[E.runtimeError, (e) => this.ingestRuntimeError(e)],
|
|
332
|
+
[E.reactiveGraph, (e) => this.ingestReactiveGraph(e)],
|
|
333
|
+
[E.reactiveSummary, (e) => this.ingestReactiveSummary(e)]
|
|
334
|
+
];
|
|
335
|
+
for (let [n, r] of t) e.on(n, r);
|
|
336
|
+
this.detachHot = () => {
|
|
337
|
+
for (let [n, r] of t) e.off?.(n, r);
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
detach() {
|
|
341
|
+
clearTimeout(this.sweepTimer), this.sweepTimer = void 0, this.detachHot?.(), this.detachHot = void 0, this.hot = void 0, this.flushPulls("no-runtime"), this.flushStateTimeline();
|
|
342
|
+
}
|
|
343
|
+
get subscription() {
|
|
344
|
+
return {
|
|
345
|
+
active: this.active,
|
|
346
|
+
componentDeltas: !0
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
resyncRequested = /* @__PURE__ */ new Set();
|
|
350
|
+
get liveComponents() {
|
|
351
|
+
if (!this.liveCache) {
|
|
352
|
+
let e = this.servedState();
|
|
353
|
+
this.liveCache = e ? [...e.components.values()] : [];
|
|
354
|
+
}
|
|
355
|
+
return this.liveCache;
|
|
356
|
+
}
|
|
357
|
+
get liveSnapshot() {
|
|
358
|
+
return {
|
|
359
|
+
epoch: this.servedState() ? this.servedEpoch ?? null : null,
|
|
360
|
+
total: this.liveComponentsTotal,
|
|
361
|
+
components: this.liveComponents
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
get liveComponentsTotal() {
|
|
365
|
+
let e = this.servedState();
|
|
366
|
+
return e ? e.components.size + e.overflow.size : 0;
|
|
367
|
+
}
|
|
368
|
+
get renderProfiles() {
|
|
369
|
+
return this.servedState()?.profiles ?? [];
|
|
370
|
+
}
|
|
371
|
+
get epochInfo() {
|
|
372
|
+
return {
|
|
373
|
+
epoch: this.servedEpoch ?? [...this.epochs.keys()].at(-1),
|
|
374
|
+
epochs: this.epochs.size
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
servedState() {
|
|
378
|
+
if (this.servedEpoch !== void 0) return this.epochs.get(this.servedEpoch);
|
|
379
|
+
let e;
|
|
380
|
+
for (let t of this.epochs.values()) e = t;
|
|
381
|
+
return e;
|
|
382
|
+
}
|
|
383
|
+
touchEpoch(e) {
|
|
384
|
+
let t = this.epochs.get(e);
|
|
385
|
+
for (t ? this.epochs.delete(e) : t = {
|
|
386
|
+
components: /* @__PURE__ */ new Map(),
|
|
387
|
+
overflow: /* @__PURE__ */ new Set(),
|
|
388
|
+
hasBase: !1,
|
|
389
|
+
profiles: [],
|
|
390
|
+
profilesTotal: null
|
|
391
|
+
}, this.epochs.set(e, t); this.epochs.size > 4;) {
|
|
392
|
+
let e = this.epochs.keys().next().value;
|
|
393
|
+
this.epochs.delete(e), this.resyncRequested.delete(e), this.dropEpoch(e), this.timelineDrops.delete(e), this.timelineTooLarge.delete(e), this.timelineBaseline.delete(e), this.servedEpoch === e && this.serve(this.newestBasedEpoch());
|
|
394
|
+
}
|
|
395
|
+
return t.hasBase && this.serve(e), t;
|
|
396
|
+
}
|
|
397
|
+
newestBasedEpoch() {
|
|
398
|
+
let e;
|
|
399
|
+
for (let [t, n] of this.epochs) n.hasBase && (e = t);
|
|
400
|
+
return e;
|
|
401
|
+
}
|
|
402
|
+
serve(e) {
|
|
403
|
+
this.servedEpoch !== e && (this.servedEpoch !== void 0 && this.bump("components", "renderProfiles"), this.servedEpoch = e, this.liveCache = void 0);
|
|
404
|
+
}
|
|
405
|
+
lease(e, t = Ce) {
|
|
406
|
+
let n = this.active;
|
|
407
|
+
return this.leases.set(e, Date.now() + t), this.updateSubscription(), !n && this.active;
|
|
408
|
+
}
|
|
409
|
+
waitForSnapshot(e) {
|
|
410
|
+
return new Promise((t) => {
|
|
411
|
+
let n = () => {
|
|
412
|
+
clearTimeout(r);
|
|
413
|
+
let e = this.snapshotWaiters.indexOf(n);
|
|
414
|
+
e !== -1 && this.snapshotWaiters.splice(e, 1), t();
|
|
415
|
+
}, r = setTimeout(n, e);
|
|
416
|
+
this.snapshotWaiters.push(n);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
release(e) {
|
|
420
|
+
this.leases.delete(e) && this.updateSubscription();
|
|
421
|
+
}
|
|
422
|
+
updateSubscription() {
|
|
423
|
+
let e = Date.now(), t = Infinity;
|
|
424
|
+
for (let [n, r] of this.leases) r <= e ? this.leases.delete(n) : t = Math.min(t, r);
|
|
425
|
+
let n = this.leases.size > 0;
|
|
426
|
+
n !== this.active && (this.active = n, this.hot?.send(E.subscription, this.subscription)), clearTimeout(this.sweepTimer), this.sweepTimer = void 0, t !== Infinity && (this.sweepTimer = setTimeout(() => this.updateSubscription(), t - e + 1), this.sweepTimer.unref?.());
|
|
427
|
+
}
|
|
428
|
+
ingestComponents(e, t) {
|
|
429
|
+
let n = typeof e?.epoch == "string" ? e.epoch : T, r = !Array.isArray(e?.components) && (Array.isArray(e?.added) || Array.isArray(e?.removed));
|
|
430
|
+
if (r && !this.epochs.get(n)?.hasBase) {
|
|
431
|
+
this.resyncRequested.has(n) || (this.resyncRequested.add(n), t?.send(E.subscription, {
|
|
432
|
+
...this.subscription,
|
|
433
|
+
resync: !0
|
|
434
|
+
}));
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
let i = this.touchEpoch(n);
|
|
438
|
+
if (r || (this.resyncRequested.delete(n), i.hasBase = !0, this.serve(n), i.components = /* @__PURE__ */ new Map(), i.overflow = /* @__PURE__ */ new Set()), r && Array.isArray(e?.removed)) for (let t of e.removed) i.components.delete(t) || i.overflow.delete(t);
|
|
439
|
+
let a = r ? e?.added : e?.components;
|
|
440
|
+
if (Array.isArray(a)) for (let e of a) {
|
|
441
|
+
let t = e?.id;
|
|
442
|
+
if (i.components.has(t)) {
|
|
443
|
+
i.components.set(t, e);
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
(e?.parentId == null || i.components.has(e.parentId)) && i.components.size < C.liveComponents ? (i.overflow.delete(t), i.components.set(t, e)) : i.overflow.add(t);
|
|
447
|
+
}
|
|
448
|
+
this.liveCache = void 0, this.bump("components");
|
|
449
|
+
}
|
|
450
|
+
ingestProfiles(e) {
|
|
451
|
+
let t = typeof e?.epoch == "string" ? e.epoch : T, n = this.touchEpoch(t);
|
|
452
|
+
n.profiles = j(e?.profiles, C.renderProfiles), n.profilesTotal = typeof e?.total == "number" && Number.isFinite(e.total) ? e.total : null, this.bump("renderProfiles");
|
|
453
|
+
}
|
|
454
|
+
getCaptureInfo() {
|
|
455
|
+
let e = this.servedState(), t = this.servedEpoch, n = (e, t) => ({
|
|
456
|
+
captured: e,
|
|
457
|
+
total: t,
|
|
458
|
+
truncated: t > e,
|
|
459
|
+
policy: "tail"
|
|
460
|
+
}), r = {
|
|
461
|
+
"runtime-count": 0,
|
|
462
|
+
"runtime-bytes": 0,
|
|
463
|
+
"server-count": 0,
|
|
464
|
+
"server-bytes": 0
|
|
465
|
+
};
|
|
466
|
+
for (let e of this.timelineDrops.values()) for (let t of O) r[t] += e[t];
|
|
467
|
+
let i = O.filter((e) => r[e] > 0).map((e) => ({
|
|
468
|
+
reason: e,
|
|
469
|
+
count: r[e]
|
|
470
|
+
})), a = 0;
|
|
471
|
+
for (let e of this.timelineTooLarge.values()) a += e;
|
|
472
|
+
let o = e?.profiles.length ?? 0, s = e?.profilesTotal ?? null, c = this.lastGraph, l = {
|
|
473
|
+
liveComponents: {
|
|
474
|
+
captured: e?.components.size ?? 0,
|
|
475
|
+
total: this.liveComponentsTotal,
|
|
476
|
+
truncated: (e?.overflow.size ?? 0) > 0,
|
|
477
|
+
policy: "roots-first",
|
|
478
|
+
...t !== void 0 && { epoch: t }
|
|
479
|
+
},
|
|
480
|
+
renderProfiles: {
|
|
481
|
+
captured: o,
|
|
482
|
+
total: s,
|
|
483
|
+
truncated: s !== null && s > o,
|
|
484
|
+
policy: "newest-mounted",
|
|
485
|
+
...t !== void 0 && { epoch: t }
|
|
486
|
+
},
|
|
487
|
+
stateTimeline: {
|
|
488
|
+
captured: this.timeline.length,
|
|
489
|
+
total: null,
|
|
490
|
+
truncated: i.length > 0,
|
|
491
|
+
policy: "sampled-200ms",
|
|
492
|
+
...i.length > 0 && { dropped: i },
|
|
493
|
+
...a > 0 && { valueTooLarge: a },
|
|
494
|
+
...t !== void 0 && this.timelineBaseline.has(t) && { baseline: this.timelineBaseline.get(t) }
|
|
495
|
+
},
|
|
496
|
+
fpsSamples: n(this.fpsSamples.length, this.received.fps),
|
|
497
|
+
runtimeErrors: n(this.runtimeErrors.length, this.received.runtimeErrors),
|
|
498
|
+
loadProfiles: n(this.loadProfiles.length, this.received.loadProfiles),
|
|
499
|
+
compilerWarnings: n(this.compilerWarnings.length, this.received.compilerWarnings)
|
|
500
|
+
};
|
|
501
|
+
if (c) {
|
|
502
|
+
let e = {
|
|
503
|
+
truncated: c.truncated,
|
|
504
|
+
policy: c.policy,
|
|
505
|
+
...c.epoch !== null && { epoch: c.epoch }
|
|
506
|
+
};
|
|
507
|
+
l.reactiveNodes = {
|
|
508
|
+
captured: c.nodes.length,
|
|
509
|
+
total: c.total?.nodes ?? null,
|
|
510
|
+
...e
|
|
511
|
+
}, l.reactiveEdges = {
|
|
512
|
+
captured: c.edges.length,
|
|
513
|
+
total: c.total?.edges ?? null,
|
|
514
|
+
...e
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
return l;
|
|
518
|
+
}
|
|
519
|
+
get stateTimeline() {
|
|
520
|
+
return this.timeline;
|
|
521
|
+
}
|
|
522
|
+
ingestStateTimeline(e) {
|
|
523
|
+
let t = j(e?.changes, C.stateTimeline);
|
|
524
|
+
if (typeof e?.epoch == "string") this.touchEpoch(e.epoch), this.countRuntimeLosses(e.epoch, e.dropped, e.valueTooLarge), e.reset === !0 && this.dropEpoch(e.epoch), this.appendTimeline(t, e.epoch), k(e.baseline) && this.timelineBaseline.set(e.epoch, {
|
|
525
|
+
complete: e.baseline.complete,
|
|
526
|
+
pendingNodes: e.baseline.pendingNodes
|
|
527
|
+
});
|
|
528
|
+
else {
|
|
529
|
+
let e;
|
|
530
|
+
for (let t = this.timeline.length - 1; t >= 0 && !e; t--) this.timelineEpochs[t] === T && (e = this.timeline[t]);
|
|
531
|
+
let n = -1;
|
|
532
|
+
if (e) {
|
|
533
|
+
for (let r = t.length - 1; r >= 0; r--) if (t[r].timestamp === e.timestamp && t[r].id === e.id) {
|
|
534
|
+
n = r + 1;
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
n === -1 && (this.dropEpoch(T), n = 0), this.appendTimeline(t.slice(n), T);
|
|
539
|
+
}
|
|
540
|
+
this.lastPull.stateTimeline = Date.now(), this.flushStateTimeline(), e?.reset === !0 && this.resolveSnapshotWaiters();
|
|
541
|
+
}
|
|
542
|
+
countRuntimeLosses(e, t, n) {
|
|
543
|
+
if (Array.isArray(t)) for (let n of t) {
|
|
544
|
+
if (n?.reason !== "runtime-count" && n?.reason !== "runtime-bytes") continue;
|
|
545
|
+
let t = A(n.count, 0, 2 ** 53 - 1, 0);
|
|
546
|
+
t > 0 && this.addDrop(e, n.reason, t);
|
|
547
|
+
}
|
|
548
|
+
let r = A(n, 0, 2 ** 53 - 1, 0);
|
|
549
|
+
r > 0 && this.timelineTooLarge.set(e, (this.timelineTooLarge.get(e) ?? 0) + r);
|
|
550
|
+
}
|
|
551
|
+
addDrop(e, t, n) {
|
|
552
|
+
let r = this.timelineDrops.get(e);
|
|
553
|
+
r || (r = {
|
|
554
|
+
"runtime-count": 0,
|
|
555
|
+
"runtime-bytes": 0,
|
|
556
|
+
"server-count": 0,
|
|
557
|
+
"server-bytes": 0
|
|
558
|
+
}, this.timelineDrops.set(e, r)), r[t] += n;
|
|
559
|
+
}
|
|
560
|
+
getStateTimelineDelta(e) {
|
|
561
|
+
let t = this.timelineSeq;
|
|
562
|
+
if (e === void 0 || e < this.timelineResetAt || e < this.timelineTrimmedAt || e > t) return {
|
|
563
|
+
cursor: t,
|
|
564
|
+
reset: !0,
|
|
565
|
+
changes: this.timeline
|
|
566
|
+
};
|
|
567
|
+
let n = this.timeline.length;
|
|
568
|
+
for (; n > 0 && this.timeline[n - 1].seq > e;) n--;
|
|
569
|
+
return {
|
|
570
|
+
cursor: t,
|
|
571
|
+
reset: !1,
|
|
572
|
+
changes: this.timeline.slice(n)
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
markTimelineReset() {
|
|
576
|
+
this.timelineResetAt = this.timelineSeq = w(), this.bump("stateTimeline");
|
|
577
|
+
}
|
|
578
|
+
dropEpoch(e) {
|
|
579
|
+
if (!this.timelineEpochs.includes(e)) return;
|
|
580
|
+
let t = this.timelineEpochs.map((t) => t !== e);
|
|
581
|
+
this.timeline = this.timeline.filter((e, n) => t[n]), this.timelineSizes = this.timelineSizes.filter((e, n) => t[n]), this.timelineEpochs = this.timelineEpochs.filter((e, n) => t[n]), this.timelineBytes = this.timelineSizes.reduce((e, t) => e + t, 0), this.markTimelineReset();
|
|
582
|
+
}
|
|
583
|
+
appendTimeline(e, t) {
|
|
584
|
+
if (e.length === 0) return;
|
|
585
|
+
for (let n of e) {
|
|
586
|
+
let e = 0;
|
|
587
|
+
try {
|
|
588
|
+
e = JSON.stringify(n).length;
|
|
589
|
+
} catch {
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
this.timeline.push({
|
|
593
|
+
...n,
|
|
594
|
+
seq: this.timelineSeq = w()
|
|
595
|
+
}), this.timelineSizes.push(e), this.timelineEpochs.push(t), this.timelineBytes += e;
|
|
596
|
+
}
|
|
597
|
+
let n = Math.max(0, this.timeline.length - C.stateTimeline), r = this.timelineBytes;
|
|
598
|
+
for (let e = 0; e < n; e++) r -= this.timelineSizes[e], this.addDrop(this.timelineEpochs[e], "server-count", 1);
|
|
599
|
+
for (; r > 4194304 && n < this.timeline.length - 1;) this.addDrop(this.timelineEpochs[n], "server-bytes", 1), r -= this.timelineSizes[n++];
|
|
600
|
+
n > 0 && (this.timelineTrimmedAt = this.timeline[n - 1].seq, this.timeline = this.timeline.slice(n), this.timelineSizes = this.timelineSizes.slice(n), this.timelineEpochs = this.timelineEpochs.slice(n)), this.timelineBytes = r, this.bump("stateTimeline");
|
|
601
|
+
}
|
|
602
|
+
resolveSnapshotWaiters() {
|
|
603
|
+
for (let e of this.snapshotWaiters.slice()) e();
|
|
604
|
+
}
|
|
605
|
+
ingestReactiveGraph(e) {
|
|
606
|
+
let t = typeof e?.requestId == "string" ? e.requestId : void 0;
|
|
607
|
+
if (t !== void 0) {
|
|
608
|
+
let n = this.pulls.get(t);
|
|
609
|
+
if (!n || n.kind !== "graph" || n.epoch !== null && typeof e?.epoch == "string" && e.epoch !== n.epoch) return;
|
|
610
|
+
this.settle(t, this.normalizeGraph(e, n.scope, n.epoch));
|
|
611
|
+
} else {
|
|
612
|
+
let t = !1;
|
|
613
|
+
for (let [n, r] of this.pulls) r.kind === "graph" && (t = !0, this.settle(n, this.normalizeGraph(e, r.scope, r.epoch)));
|
|
614
|
+
t || this.storeGraph(this.normalizeGraph(e, null, this.servedEpoch ?? null));
|
|
615
|
+
}
|
|
616
|
+
this.bump("reactiveGraph");
|
|
617
|
+
}
|
|
618
|
+
normalizeGraph(e, t, n) {
|
|
619
|
+
let r = typeof e?.requestId != "string", i = M(e?.nodes, Infinity), a = M(e?.edges, Infinity), o = e?.policy === "scoped" || e?.policy === "global-head" ? e.policy : t === null ? "global-head" : "scoped", s = null;
|
|
620
|
+
if (!r && e?.total && typeof e.total.nodes == "number" && (s = {
|
|
621
|
+
nodes: e.total.nodes,
|
|
622
|
+
nodesKind: "registered",
|
|
623
|
+
edges: typeof e.total.edges == "number" ? e.total.edges : null
|
|
624
|
+
}), r && t !== null) {
|
|
625
|
+
let e = new Set(i.filter((e) => e?.componentId === t).map((e) => e.id)), n = new Set(e);
|
|
626
|
+
for (let t of a) e.has(t?.from) && n.add(t.to), e.has(t?.to) && n.add(t.from);
|
|
627
|
+
i = i.filter((e) => n.has(e?.id)), o = "server-filter";
|
|
628
|
+
} else r && (s = {
|
|
629
|
+
nodes: i.length,
|
|
630
|
+
nodesKind: "sent",
|
|
631
|
+
edges: a.length
|
|
632
|
+
});
|
|
633
|
+
let c = e?.truncated === !0;
|
|
634
|
+
i.length > C.reactiveNodes && (i = i.slice(0, C.reactiveNodes), c = !0);
|
|
635
|
+
let l = new Set(i.map((e) => e?.id)), u = A(e?.edgesOmitted, 0, 2 ** 53 - 1, 0), d = [];
|
|
636
|
+
for (let e of a) !l.has(e?.from) || !l.has(e?.to) ? o !== "server-filter" && u++ : d.length < C.reactiveEdges ? d.push(e) : (u++, c = !0);
|
|
637
|
+
return {
|
|
638
|
+
nodes: i,
|
|
639
|
+
edges: d,
|
|
640
|
+
scope: t,
|
|
641
|
+
epoch: typeof e?.epoch == "string" ? e.epoch : n,
|
|
642
|
+
total: s,
|
|
643
|
+
truncated: c,
|
|
644
|
+
edgesOmitted: u,
|
|
645
|
+
computedAt: typeof e?.computedAt == "number" && Number.isFinite(e.computedAt) ? e.computedAt : null,
|
|
646
|
+
policy: o
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
storeGraph(e) {
|
|
650
|
+
this.lastGraph = e, e.scope === null && (this.reactiveGraph = {
|
|
651
|
+
nodes: e.nodes,
|
|
652
|
+
edges: e.edges
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
ingestReactiveSummary(e) {
|
|
656
|
+
let t = typeof e?.requestId == "string" ? e.requestId : void 0, n = t === void 0 ? void 0 : this.pulls.get(t);
|
|
657
|
+
n && n.kind === "summary" && (n.epoch === null || typeof e?.epoch != "string" || e.epoch === n.epoch) && this.settle(t, this.normalizeSummary(e, n.epoch));
|
|
658
|
+
}
|
|
659
|
+
normalizeSummary(e, t) {
|
|
660
|
+
let n = (e) => A(e, 0, 2 ** 53 - 1, 0), r = M(e?.rows, D.maxTopK).map((e) => ({
|
|
661
|
+
componentId: n(e?.componentId),
|
|
662
|
+
file: typeof e?.file == "string" ? e.file : "",
|
|
663
|
+
nodes: {
|
|
664
|
+
state: n(e?.nodes?.state),
|
|
665
|
+
derived: n(e?.nodes?.derived),
|
|
666
|
+
effect: n(e?.nodes?.effect)
|
|
667
|
+
},
|
|
668
|
+
changes: n(e?.changes),
|
|
669
|
+
renders: n(e?.renders),
|
|
670
|
+
renderMs: typeof e?.renderMs == "number" && e.renderMs >= 0 ? e.renderMs : 0
|
|
671
|
+
})), i = e?.window;
|
|
672
|
+
return {
|
|
673
|
+
epoch: typeof e?.epoch == "string" ? e.epoch : t,
|
|
674
|
+
window: {
|
|
675
|
+
ms: n(i?.ms),
|
|
676
|
+
since: n(i?.since),
|
|
677
|
+
until: n(i?.until),
|
|
678
|
+
sampledActiveMs: n(i?.sampledActiveMs)
|
|
679
|
+
},
|
|
680
|
+
policy: "sampled-200ms",
|
|
681
|
+
coverage: "component-init",
|
|
682
|
+
components: {
|
|
683
|
+
total: typeof e?.components?.total == "number" ? e.components.total : null,
|
|
684
|
+
withActivity: n(e?.components?.withActivity)
|
|
685
|
+
},
|
|
686
|
+
rows: r,
|
|
687
|
+
other: e?.other && typeof e.other.components == "number" && typeof e.other.nodes == "number" ? {
|
|
688
|
+
components: e.other.components,
|
|
689
|
+
nodes: e.other.nodes
|
|
690
|
+
} : null,
|
|
691
|
+
truncated: e?.truncated === !0,
|
|
692
|
+
capabilities: {
|
|
693
|
+
valueInspection: e?.capabilities?.valueInspection === !0,
|
|
694
|
+
signalHistory: e?.capabilities?.signalHistory === !0,
|
|
695
|
+
writeCause: e?.capabilities?.writeCause === !0
|
|
696
|
+
},
|
|
697
|
+
...k(e?.baseline) && { baseline: { ...e.baseline } }
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
ingestFps(e) {
|
|
701
|
+
this.received.fps++, this.fpsSamples.push(e), this.fpsSamples.length > C.fpsSamples && (this.fpsSamples = this.fpsSamples.slice(-C.fpsSamples)), this.bump("fps"), this.hooks.onFpsSample?.(e);
|
|
702
|
+
}
|
|
703
|
+
ingestRuntimeError(e) {
|
|
704
|
+
this.received.runtimeErrors++, this.runtimeErrors.push(e), this.runtimeErrors.length > C.runtimeErrors && (this.runtimeErrors = this.runtimeErrors.slice(-C.runtimeErrors)), this.bump("errors");
|
|
705
|
+
}
|
|
706
|
+
recordLoadProfile(e) {
|
|
707
|
+
this.received.loadProfiles++, this.loadProfiles.push(e), this.loadProfiles.length > C.loadProfiles && (this.loadProfiles = this.loadProfiles.slice(-C.loadProfiles)), this.bump("loadProfiles"), this.hooks.onLoadProfile?.(e);
|
|
708
|
+
}
|
|
709
|
+
recordCompilerWarning(e) {
|
|
710
|
+
this.received.compilerWarnings++, this.compilerWarnings.push(e), this.compilerWarnings.length > C.compilerWarnings && (this.compilerWarnings = this.compilerWarnings.slice(-C.compilerWarnings)), this.bump("errors");
|
|
711
|
+
}
|
|
712
|
+
clearLoadProfiles() {
|
|
713
|
+
this.loadProfiles = [], this.received.loadProfiles = 0, this.bump("loadProfiles");
|
|
714
|
+
}
|
|
715
|
+
clearErrors() {
|
|
716
|
+
this.compilerWarnings = [], this.runtimeErrors = [], this.received.compilerWarnings = 0, this.received.runtimeErrors = 0, this.bump("errors");
|
|
717
|
+
}
|
|
718
|
+
clearFps() {
|
|
719
|
+
this.fpsSamples = [], this.received.fps = 0, this.bump("fps");
|
|
720
|
+
}
|
|
721
|
+
clearStateTimeline() {
|
|
722
|
+
this.timeline = [], this.timelineSizes = [], this.timelineEpochs = [], this.timelineBytes = 0, this.timelineDrops.clear(), this.timelineTooLarge.clear(), this.markTimelineReset(), this.hot?.send(E.clearStateTimeline, {});
|
|
723
|
+
}
|
|
724
|
+
requestReactiveGraph(e = {}) {
|
|
725
|
+
let t = typeof e.componentId == "number" && Number.isInteger(e.componentId) && e.componentId >= 0 ? e.componentId : null, n = A(e.maxNodes, 1, C.reactiveNodes, C.reactiveNodes), r = A(e.maxEdges, 1, C.reactiveEdges, C.reactiveEdges), i = this.servedEpoch ?? null;
|
|
726
|
+
if (t !== null && i === null) return Promise.resolve({
|
|
727
|
+
nodes: [],
|
|
728
|
+
edges: [],
|
|
729
|
+
scope: t,
|
|
730
|
+
epoch: i,
|
|
731
|
+
total: null,
|
|
732
|
+
truncated: !1,
|
|
733
|
+
edgesOmitted: 0,
|
|
734
|
+
computedAt: null,
|
|
735
|
+
policy: "scoped",
|
|
736
|
+
stale: !0,
|
|
737
|
+
staleReason: "no-runtime"
|
|
738
|
+
});
|
|
739
|
+
if (t !== null && typeof e.epoch == "string" && e.epoch !== i) return Promise.resolve({
|
|
740
|
+
nodes: [],
|
|
741
|
+
edges: [],
|
|
742
|
+
scope: t,
|
|
743
|
+
epoch: i,
|
|
744
|
+
total: null,
|
|
745
|
+
truncated: !1,
|
|
746
|
+
edgesOmitted: 0,
|
|
747
|
+
computedAt: null,
|
|
748
|
+
policy: "scoped",
|
|
749
|
+
stale: !0,
|
|
750
|
+
staleReason: "epoch-changed"
|
|
751
|
+
});
|
|
752
|
+
let a = `graph|${i ?? ""}|${t ?? "*"}|${n}|${r}`;
|
|
753
|
+
return this.keyedPull("graph", a, i, t, E.requestReactiveGraph, {
|
|
754
|
+
...t !== null && { componentId: t },
|
|
755
|
+
maxNodes: n,
|
|
756
|
+
maxEdges: r
|
|
757
|
+
}, (e) => ({
|
|
758
|
+
nodes: [],
|
|
759
|
+
edges: [],
|
|
760
|
+
scope: t,
|
|
761
|
+
epoch: i,
|
|
762
|
+
total: null,
|
|
763
|
+
truncated: !1,
|
|
764
|
+
edgesOmitted: 0,
|
|
765
|
+
computedAt: null,
|
|
766
|
+
policy: t === null ? "global-head" : "scoped",
|
|
767
|
+
stale: !0,
|
|
768
|
+
staleReason: e
|
|
769
|
+
}));
|
|
770
|
+
}
|
|
771
|
+
requestReactiveSummary(e = {}) {
|
|
772
|
+
let t = A(e.topK, 1, D.maxTopK, D.topK), n = A(e.windowMs, D.minWindowMs, D.maxWindowMs, D.windowMs), r = this.servedEpoch ?? null, i = `summary|${r ?? ""}|${t}|${n}`;
|
|
773
|
+
return this.keyedPull("summary", i, r, null, E.requestReactiveSummary, {
|
|
774
|
+
topK: t,
|
|
775
|
+
windowMs: n
|
|
776
|
+
}, (e) => ({
|
|
777
|
+
epoch: r,
|
|
778
|
+
window: {
|
|
779
|
+
ms: n,
|
|
780
|
+
since: 0,
|
|
781
|
+
until: 0,
|
|
782
|
+
sampledActiveMs: 0
|
|
783
|
+
},
|
|
784
|
+
policy: "sampled-200ms",
|
|
785
|
+
coverage: "component-init",
|
|
786
|
+
components: {
|
|
787
|
+
total: null,
|
|
788
|
+
withActivity: 0
|
|
789
|
+
},
|
|
790
|
+
rows: [],
|
|
791
|
+
other: null,
|
|
792
|
+
truncated: !1,
|
|
793
|
+
capabilities: {
|
|
794
|
+
valueInspection: !1,
|
|
795
|
+
signalHistory: !1,
|
|
796
|
+
writeCause: !1
|
|
797
|
+
},
|
|
798
|
+
stale: !0,
|
|
799
|
+
staleReason: e
|
|
800
|
+
}));
|
|
801
|
+
}
|
|
802
|
+
keyedPull(e, t, n, r, i, a, o) {
|
|
803
|
+
let s = (e) => {
|
|
804
|
+
let n = this.pullCache.get(t);
|
|
805
|
+
return n ? {
|
|
806
|
+
...n.value,
|
|
807
|
+
stale: !0,
|
|
808
|
+
staleReason: e
|
|
809
|
+
} : o(e);
|
|
810
|
+
}, c = this.pullCache.get(t);
|
|
811
|
+
if (!this.hot) return Promise.resolve(s("no-runtime"));
|
|
812
|
+
if (c && Date.now() - c.at < 1e3) return Promise.resolve(c.value);
|
|
813
|
+
let l = this.pullInflight.get(t);
|
|
814
|
+
if (l) return l;
|
|
815
|
+
let u = this.hot, d = `r${++this.requestSeq}`, f = new Promise((o) => {
|
|
816
|
+
let c = setTimeout(() => {
|
|
817
|
+
this.pulls.delete(d), o(s("timeout"));
|
|
818
|
+
}, be);
|
|
819
|
+
this.pulls.set(d, {
|
|
820
|
+
kind: e,
|
|
821
|
+
key: t,
|
|
822
|
+
epoch: n,
|
|
823
|
+
scope: r,
|
|
824
|
+
resolve: o,
|
|
825
|
+
timer: c
|
|
826
|
+
}), u.send(i, {
|
|
827
|
+
requestId: d,
|
|
828
|
+
...n !== null && { epoch: n },
|
|
829
|
+
...a
|
|
830
|
+
});
|
|
831
|
+
}).finally(() => {
|
|
832
|
+
this.pullInflight.get(t) === f && this.pullInflight.delete(t);
|
|
833
|
+
});
|
|
834
|
+
return this.pullInflight.set(t, f), f;
|
|
835
|
+
}
|
|
836
|
+
settle(e, t) {
|
|
837
|
+
let n = this.pulls.get(e);
|
|
838
|
+
if (n) {
|
|
839
|
+
for (this.pulls.delete(e), clearTimeout(n.timer), this.pullCache.delete(n.key), this.pullCache.set(n.key, {
|
|
840
|
+
value: t,
|
|
841
|
+
at: Date.now()
|
|
842
|
+
}); this.pullCache.size > Se;) this.pullCache.delete(this.pullCache.keys().next().value);
|
|
843
|
+
n.kind === "graph" && this.storeGraph(t), n.resolve(t);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
flushPulls(e) {
|
|
847
|
+
for (let [t, n] of this.pulls) {
|
|
848
|
+
this.pulls.delete(t), clearTimeout(n.timer);
|
|
849
|
+
let r = this.pullCache.get(n.key);
|
|
850
|
+
r ? n.resolve({
|
|
851
|
+
...r.value,
|
|
852
|
+
stale: !0,
|
|
853
|
+
staleReason: e
|
|
854
|
+
}) : n.kind === "graph" ? n.resolve({
|
|
855
|
+
nodes: [],
|
|
856
|
+
edges: [],
|
|
857
|
+
scope: n.scope,
|
|
858
|
+
epoch: n.epoch,
|
|
859
|
+
total: null,
|
|
860
|
+
truncated: !1,
|
|
861
|
+
edgesOmitted: 0,
|
|
862
|
+
computedAt: null,
|
|
863
|
+
policy: n.scope === null ? "global-head" : "scoped",
|
|
864
|
+
stale: !0,
|
|
865
|
+
staleReason: e
|
|
866
|
+
}) : n.resolve({
|
|
867
|
+
epoch: n.epoch,
|
|
868
|
+
window: {
|
|
869
|
+
ms: 0,
|
|
870
|
+
since: 0,
|
|
871
|
+
until: 0,
|
|
872
|
+
sampledActiveMs: 0
|
|
873
|
+
},
|
|
874
|
+
policy: "sampled-200ms",
|
|
875
|
+
coverage: "component-init",
|
|
876
|
+
components: {
|
|
877
|
+
total: null,
|
|
878
|
+
withActivity: 0
|
|
879
|
+
},
|
|
880
|
+
rows: [],
|
|
881
|
+
other: null,
|
|
882
|
+
truncated: !1,
|
|
883
|
+
capabilities: {
|
|
884
|
+
valueInspection: !1,
|
|
885
|
+
signalHistory: !1,
|
|
886
|
+
writeCause: !1
|
|
887
|
+
},
|
|
888
|
+
stale: !0,
|
|
889
|
+
staleReason: e
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
requestStateTimeline() {
|
|
894
|
+
return this.pull("stateTimeline", E.requestStateTimeline, this.stateTimelineResolvers, () => this.stateTimeline);
|
|
895
|
+
}
|
|
896
|
+
pull(e, t, n, r) {
|
|
897
|
+
if (!this.hot || Date.now() - this.lastPull[e] < 1e3) return Promise.resolve(r());
|
|
898
|
+
let i = this.inflight[e];
|
|
899
|
+
if (i) return i;
|
|
900
|
+
let a = this.hot, o = new Promise((e) => {
|
|
901
|
+
let i = (t) => {
|
|
902
|
+
clearTimeout(o), e(t);
|
|
903
|
+
}, o = setTimeout(() => {
|
|
904
|
+
let t = n.indexOf(i);
|
|
905
|
+
t !== -1 && n.splice(t, 1), e(r());
|
|
906
|
+
}, be);
|
|
907
|
+
n.push(i), a.send(t, {});
|
|
908
|
+
}).finally(() => {
|
|
909
|
+
this.inflight[e] === o && (this.inflight[e] = void 0);
|
|
910
|
+
});
|
|
911
|
+
return this.inflight[e] = o, o;
|
|
912
|
+
}
|
|
913
|
+
flushStateTimeline() {
|
|
914
|
+
let e = this.stateTimelineResolvers;
|
|
915
|
+
this.stateTimelineResolvers = [];
|
|
916
|
+
for (let t of e) t(this.stateTimeline);
|
|
917
|
+
}
|
|
918
|
+
}, Te = {
|
|
109
919
|
".png": "image/png",
|
|
110
920
|
".jpg": "image/jpeg",
|
|
111
921
|
".jpeg": "image/jpeg",
|
|
@@ -132,134 +942,664 @@ var g = {
|
|
|
132
942
|
".js": "text/javascript",
|
|
133
943
|
".html": "text/html"
|
|
134
944
|
};
|
|
135
|
-
function
|
|
136
|
-
if (!
|
|
137
|
-
let
|
|
138
|
-
return
|
|
945
|
+
function Ee(e, t = "/") {
|
|
946
|
+
if (!r.existsSync(e)) return [];
|
|
947
|
+
let n = [];
|
|
948
|
+
return N(e, e, t.endsWith("/") ? t : `${t}/`, n), n.sort((e, t) => e.relativePath.localeCompare(t.relativePath));
|
|
139
949
|
}
|
|
140
|
-
function
|
|
141
|
-
let
|
|
142
|
-
for (let
|
|
143
|
-
let
|
|
144
|
-
if (
|
|
145
|
-
|
|
950
|
+
function N(e, t, n, a) {
|
|
951
|
+
let o = r.readdirSync(e, { withFileTypes: !0 });
|
|
952
|
+
for (let s of o) {
|
|
953
|
+
let o = i.join(e, s.name);
|
|
954
|
+
if (s.isDirectory()) {
|
|
955
|
+
N(o, t, n, a);
|
|
146
956
|
continue;
|
|
147
957
|
}
|
|
148
|
-
if (
|
|
149
|
-
let
|
|
150
|
-
|
|
151
|
-
name:
|
|
152
|
-
path:
|
|
153
|
-
relativePath:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
958
|
+
if (s.name.startsWith(".")) continue;
|
|
959
|
+
let c = r.statSync(o), l = i.extname(s.name).toLowerCase(), u = i.relative(t, o);
|
|
960
|
+
a.push({
|
|
961
|
+
name: s.name,
|
|
962
|
+
path: o,
|
|
963
|
+
relativePath: u,
|
|
964
|
+
url: n + u.split(i.sep).map(encodeURIComponent).join("/"),
|
|
965
|
+
size: c.size,
|
|
966
|
+
type: Te[l] || "application/octet-stream",
|
|
967
|
+
mtime: c.mtimeMs
|
|
157
968
|
});
|
|
158
969
|
}
|
|
159
970
|
}
|
|
160
971
|
//#endregion
|
|
161
|
-
//#region src/
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
let
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
routesDir: E(e),
|
|
180
|
-
staticDir: D(e)
|
|
181
|
-
};
|
|
972
|
+
//#region src/security.ts
|
|
973
|
+
function De(e) {
|
|
974
|
+
let t;
|
|
975
|
+
try {
|
|
976
|
+
t = new URL(e);
|
|
977
|
+
} catch {
|
|
978
|
+
throw Error(`Invalid URL: ${e}`);
|
|
979
|
+
}
|
|
980
|
+
if (t.protocol !== "http:" && t.protocol !== "https:") throw Error(`Blocked URL scheme: ${t.protocol}`);
|
|
981
|
+
let n = t.hostname;
|
|
982
|
+
if (n === "::1" || n === "[::1]") throw Error("Blocked: loopback address");
|
|
983
|
+
if (f.isIP(n)) {
|
|
984
|
+
if (F(n)) throw Error(`Blocked: private IP address ${n}`);
|
|
985
|
+
} else {
|
|
986
|
+
let e = n.toLowerCase();
|
|
987
|
+
if (e === "localhost" || e.endsWith(".local") || e.endsWith(".internal")) throw Error(`Blocked: internal hostname ${n}`);
|
|
988
|
+
}
|
|
989
|
+
return t;
|
|
182
990
|
}
|
|
183
|
-
function
|
|
991
|
+
async function P(e, t = {}) {
|
|
992
|
+
let n;
|
|
184
993
|
try {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
994
|
+
n = new URL(e);
|
|
995
|
+
} catch {
|
|
996
|
+
throw Error(`Invalid URL: ${e}`);
|
|
997
|
+
}
|
|
998
|
+
if (t.allowedOrigins?.includes(n.origin)) return n;
|
|
999
|
+
De(e);
|
|
1000
|
+
let r = n.hostname.replace(/^\[|\]$/g, "");
|
|
1001
|
+
if (f.isIP(r)) return n;
|
|
1002
|
+
let i = await d.lookup(r, { all: !0 }).catch(() => []);
|
|
1003
|
+
for (let { address: e } of i) if (F(e)) throw Error(`Blocked: ${r} resolves to private address`);
|
|
1004
|
+
return n;
|
|
1005
|
+
}
|
|
1006
|
+
function F(e) {
|
|
1007
|
+
if (e.includes(":")) return Oe(e);
|
|
1008
|
+
let t = e.split(".").map(Number);
|
|
1009
|
+
return !!(t.length === 4 && (t[0] === 127 || t[0] === 10 || t[0] === 172 && t[1] >= 16 && t[1] <= 31 || t[0] === 192 && t[1] === 168 || t[0] === 169 && t[1] === 254 || t.every((e) => e === 0)));
|
|
189
1010
|
}
|
|
190
|
-
function
|
|
191
|
-
let t =
|
|
192
|
-
|
|
193
|
-
return s.join(e, "src", "routes");
|
|
1011
|
+
function Oe(e) {
|
|
1012
|
+
let t = e.toLowerCase().replace(/^\[|\]$/g, ""), n = t.match(/^::(?:ffff:)?(\d+\.\d+\.\d+\.\d+)$/);
|
|
1013
|
+
return n ? F(n[1]) : t === "::" || t === "::1" || /^f[cd][0-9a-f]{2}:/.test(t) || /^fe[89ab][0-9a-f]:/.test(t);
|
|
194
1014
|
}
|
|
195
|
-
function
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
1015
|
+
function I(t, n) {
|
|
1016
|
+
if (typeof n != "string" || n.length === 0) throw Error("Invalid file path");
|
|
1017
|
+
let r = a.realpathSync(t), i = e.isAbsolute(n) ? n : e.resolve(t, n), o;
|
|
1018
|
+
try {
|
|
1019
|
+
o = a.realpathSync(i);
|
|
1020
|
+
} catch {
|
|
1021
|
+
throw Error("File not found");
|
|
1022
|
+
}
|
|
1023
|
+
if (o !== r && !o.startsWith(r + e.sep)) throw Error("Forbidden: path outside project root");
|
|
1024
|
+
return o;
|
|
199
1025
|
}
|
|
200
1026
|
//#endregion
|
|
201
|
-
//#region src/analyzers/
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
1027
|
+
//#region src/analyzers/api.ts
|
|
1028
|
+
var ke = [
|
|
1029
|
+
"GET",
|
|
1030
|
+
"POST",
|
|
1031
|
+
"PUT",
|
|
1032
|
+
"PATCH",
|
|
1033
|
+
"DELETE"
|
|
1034
|
+
];
|
|
1035
|
+
function Ae(e) {
|
|
1036
|
+
let t = [];
|
|
1037
|
+
for (let n of e) {
|
|
1038
|
+
let e = n.files.find((e) => e.type === "endpoint");
|
|
1039
|
+
if (!e) continue;
|
|
1040
|
+
let r = "";
|
|
1041
|
+
try {
|
|
1042
|
+
r = a.readFileSync(e.path, "utf-8");
|
|
1043
|
+
} catch {}
|
|
1044
|
+
let i = ke.filter((e) => r.includes(`export const ${e}`) || r.includes(`export async function ${e}`) || r.includes(`export function ${e}`));
|
|
1045
|
+
i.length === 0 && i.push("GET"), t.push({
|
|
1046
|
+
route: n.id,
|
|
1047
|
+
path: n.path,
|
|
1048
|
+
methods: i,
|
|
1049
|
+
file: e.path
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
return t;
|
|
1053
|
+
}
|
|
1054
|
+
async function je(e, t = {}) {
|
|
1055
|
+
let n = performance.now(), r = () => Math.round((performance.now() - n) * 100) / 100;
|
|
1056
|
+
try {
|
|
1057
|
+
await P(e.url, t);
|
|
1058
|
+
let n = e.headers ? JSON.parse(e.headers) : {}, i = {
|
|
1059
|
+
method: e.method,
|
|
1060
|
+
headers: n,
|
|
1061
|
+
redirect: "manual"
|
|
1062
|
+
};
|
|
1063
|
+
e.body && e.method !== "GET" && e.method !== "HEAD" && (i.body = e.body);
|
|
1064
|
+
let a = await fetch(e.url, i), o = await a.text(), s = {};
|
|
1065
|
+
return a.headers.forEach((e, t) => {
|
|
1066
|
+
s[t] = e;
|
|
1067
|
+
}), {
|
|
1068
|
+
status: a.status,
|
|
1069
|
+
statusText: a.statusText,
|
|
1070
|
+
headers: s,
|
|
1071
|
+
body: o,
|
|
1072
|
+
duration: r()
|
|
1073
|
+
};
|
|
1074
|
+
} catch (e) {
|
|
208
1075
|
return {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
1076
|
+
status: 0,
|
|
1077
|
+
statusText: String(e),
|
|
1078
|
+
headers: {},
|
|
1079
|
+
body: "",
|
|
1080
|
+
duration: r()
|
|
212
1081
|
};
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
function k(e, t) {
|
|
216
|
-
let n = o.readdirSync(e, { withFileTypes: !0 });
|
|
217
|
-
for (let r of n) {
|
|
218
|
-
let n = s.join(e, r.name);
|
|
219
|
-
if (r.isDirectory()) {
|
|
220
|
-
if (r.name === "node_modules" || r.name === ".svelte-kit") continue;
|
|
221
|
-
k(n, t);
|
|
222
|
-
} else r.name.endsWith(".svelte") && t.push(n);
|
|
223
1082
|
}
|
|
224
1083
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
1084
|
+
//#endregion
|
|
1085
|
+
//#region src/analyzers/build.ts
|
|
1086
|
+
var Me = /* @__PURE__ */ new Set([
|
|
1087
|
+
".js",
|
|
1088
|
+
".css",
|
|
1089
|
+
".html"
|
|
1090
|
+
]);
|
|
1091
|
+
function Ne(t) {
|
|
1092
|
+
let n = [], r = [
|
|
1093
|
+
e.resolve(t, ".svelte-kit/output"),
|
|
1094
|
+
e.resolve(t, "build/client"),
|
|
1095
|
+
e.resolve(t, "build")
|
|
1096
|
+
], i = (r) => {
|
|
1097
|
+
for (let o of a.readdirSync(r, { withFileTypes: !0 })) {
|
|
1098
|
+
let s = e.join(r, o.name);
|
|
1099
|
+
if (o.isDirectory()) {
|
|
1100
|
+
i(s);
|
|
1101
|
+
continue;
|
|
1102
|
+
}
|
|
1103
|
+
Me.has(e.extname(o.name).toLowerCase()) && n.push({
|
|
1104
|
+
name: o.name,
|
|
1105
|
+
file: e.relative(t, s),
|
|
1106
|
+
size: a.statSync(s).size,
|
|
1107
|
+
modules: [],
|
|
1108
|
+
isEntry: o.name.includes("index") || o.name.includes("start")
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
};
|
|
1112
|
+
for (let e of r) try {
|
|
1113
|
+
i(e);
|
|
1114
|
+
} catch {}
|
|
1115
|
+
return n.sort((e, t) => t.size - e.size), {
|
|
1116
|
+
chunks: n,
|
|
1117
|
+
totalSize: n.reduce((e, t) => e + t.size, 0),
|
|
1118
|
+
timestamp: Date.now()
|
|
1119
|
+
};
|
|
232
1120
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
1121
|
+
//#endregion
|
|
1122
|
+
//#region src/analyzers/module-graph.ts
|
|
1123
|
+
function Pe(t) {
|
|
1124
|
+
let n = e.extname(t).toLowerCase();
|
|
1125
|
+
return n === ".svelte" ? "svelte" : n === ".ts" ? "ts" : n === ".js" ? "js" : n === ".css" ? "css" : "other";
|
|
1126
|
+
}
|
|
1127
|
+
function Fe(t, n) {
|
|
1128
|
+
let r = [], i = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
|
|
1129
|
+
for (let s of n) {
|
|
1130
|
+
if (!s.file || s.file.includes("node_modules")) continue;
|
|
1131
|
+
let n = e.relative(t, s.file);
|
|
1132
|
+
if (n.startsWith("..") || i.has(s.file)) continue;
|
|
1133
|
+
let c;
|
|
1134
|
+
try {
|
|
1135
|
+
c = a.statSync(s.file).size;
|
|
1136
|
+
} catch {}
|
|
1137
|
+
let l = {
|
|
1138
|
+
id: n,
|
|
1139
|
+
file: s.file,
|
|
1140
|
+
type: Pe(s.file),
|
|
1141
|
+
importedBy: [],
|
|
1142
|
+
imports: [],
|
|
1143
|
+
size: c
|
|
1144
|
+
};
|
|
1145
|
+
i.set(s.file, l), o.set(n, l), r.push(l);
|
|
1146
|
+
}
|
|
1147
|
+
let s = /* @__PURE__ */ new Map();
|
|
1148
|
+
for (let e of n) {
|
|
1149
|
+
if (!e.file) continue;
|
|
1150
|
+
let t = i.get(e.file);
|
|
1151
|
+
if (!t) continue;
|
|
1152
|
+
let n = new Set(t.imports);
|
|
1153
|
+
for (let r of e.importedModules) {
|
|
1154
|
+
let e = r.file ? i.get(r.file) : void 0;
|
|
1155
|
+
if (!e) continue;
|
|
1156
|
+
n.has(e.id) || (n.add(e.id), t.imports.push(e.id));
|
|
1157
|
+
let a = s.get(e);
|
|
1158
|
+
a || s.set(e, a = new Set(e.importedBy)), a.has(t.id) || (a.add(t.id), e.importedBy.push(t.id));
|
|
239
1159
|
}
|
|
240
|
-
return null;
|
|
241
1160
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if (
|
|
1161
|
+
let c = [], l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set(), d = [];
|
|
1162
|
+
function f(e) {
|
|
1163
|
+
if (u.has(e)) {
|
|
1164
|
+
let t = d.indexOf(e);
|
|
1165
|
+
if (t >= 0) {
|
|
1166
|
+
let n = d.slice(t).concat(e);
|
|
1167
|
+
n.length > 2 && c.push(n);
|
|
1168
|
+
}
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
if (l.has(e)) return;
|
|
1172
|
+
l.add(e), u.add(e), d.push(e);
|
|
1173
|
+
let t = o.get(e);
|
|
1174
|
+
if (t) for (let e of t.imports) f(e);
|
|
1175
|
+
d.pop(), u.delete(e);
|
|
245
1176
|
}
|
|
246
|
-
|
|
1177
|
+
for (let e of r) f(e.id);
|
|
1178
|
+
let p = new Set(c.flat());
|
|
1179
|
+
for (let e of r) p.has(e.id) && (e.isCyclic = !0);
|
|
1180
|
+
return {
|
|
1181
|
+
modules: r,
|
|
1182
|
+
cycles: c
|
|
1183
|
+
};
|
|
247
1184
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
1185
|
+
//#endregion
|
|
1186
|
+
//#region src/analyzers/og.ts
|
|
1187
|
+
async function Ie(e, t = {}) {
|
|
1188
|
+
let n = {
|
|
1189
|
+
url: e,
|
|
1190
|
+
title: "",
|
|
1191
|
+
description: "",
|
|
1192
|
+
image: "",
|
|
1193
|
+
tags: [],
|
|
1194
|
+
issues: []
|
|
1195
|
+
};
|
|
1196
|
+
try {
|
|
1197
|
+
await P(e, t);
|
|
1198
|
+
let r = await fetch(e, { redirect: "manual" });
|
|
1199
|
+
if (r.status >= 300 && r.status < 400) return n.issues.push(`Redirects to ${r.headers.get("location") ?? "(no location)"} (not followed)`), n;
|
|
1200
|
+
let i = await r.text(), a = /<meta\s+([^>]*?)\/?>/gi, o = /(?:property|name)=["']([^"']+)["']/, s = /content=["']([^"']+)["']/, c;
|
|
1201
|
+
for (; (c = a.exec(i)) !== null;) {
|
|
1202
|
+
let e = c[1], t = e.match(o), r = e.match(s);
|
|
1203
|
+
if (t && r) {
|
|
1204
|
+
let e = t[1], i = r[1];
|
|
1205
|
+
n.tags.push({
|
|
1206
|
+
property: e,
|
|
1207
|
+
content: i
|
|
1208
|
+
}), e === "og:title" ? n.title = i : e === "og:description" ? n.description = i : e === "og:image" && (n.image = i);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
if (!n.title) {
|
|
1212
|
+
let e = i.match(/<title>([^<]+)<\/title>/i);
|
|
1213
|
+
e && (n.title = e[1]);
|
|
1214
|
+
}
|
|
1215
|
+
if (!n.description) {
|
|
1216
|
+
let e = n.tags.find((e) => e.property === "description");
|
|
1217
|
+
e && (n.description = e.content);
|
|
1218
|
+
}
|
|
1219
|
+
n.title || n.issues.push("Missing og:title or <title>"), n.description || n.issues.push("Missing og:description or meta description"), n.image || n.issues.push("Missing og:image"), n.tags.some((e) => e.property === "og:url") || n.issues.push("Missing og:url"), n.tags.some((e) => e.property === "og:type") || n.issues.push("Missing og:type");
|
|
1220
|
+
} catch (e) {
|
|
1221
|
+
n.issues.push(`Failed to fetch: ${String(e)}`);
|
|
253
1222
|
}
|
|
254
|
-
return
|
|
1223
|
+
return n;
|
|
255
1224
|
}
|
|
256
|
-
|
|
257
|
-
|
|
1225
|
+
//#endregion
|
|
1226
|
+
//#region src/analyzers/source.ts
|
|
1227
|
+
function Le(e, t, n) {
|
|
1228
|
+
let r = e.split("\n");
|
|
1229
|
+
if (n === "effect") return r.findIndex((e) => e.includes("$effect(") || e.includes("$effect.pre(")) + 1;
|
|
1230
|
+
let i = t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), a = RegExp(`(?:let|const|var)\\s+${i}\\b`);
|
|
1231
|
+
return r.findIndex((e) => a.test(e)) + 1;
|
|
258
1232
|
}
|
|
259
1233
|
//#endregion
|
|
260
|
-
//#region src/
|
|
261
|
-
var P = "virtual:svelte-devtools-runtime", ee = "\0virtual:svelte-devtools-runtime", F = "\0svelte-devtools:wrapped-client", I = "\nimport * as __svelte_original from 'svelte/internal/client';\nexport * from 'svelte/internal/client';\n\nfunction __dt() {\n return typeof window !== 'undefined' ? window.__SVELTE_DEVTOOLS__ : null;\n}\n\n// Component ID stack (parallel to runtime._stack but local to wrapper)\nconst __idStack = [];\nfunction __currentId() {\n return __idStack.length > 0 ? __idStack[__idStack.length - 1] : null;\n}\n\n// Tracks the most recently created signal for type determination in tag()\nconst __pendingSignal = { ref: null, type: null };\n\n// --- Component Lifecycle ---\n//\n// Observer must not break the observed: every devtools side-effect below is\n// wrapped in try/catch so a bug or an out-of-shape runtime cannot tear down\n// the user's app. The original Svelte function is always called, and its\n// return value always returned, regardless of devtools failures.\n\nexport function push() {\n const result = __svelte_original.push.apply(null, arguments);\n try {\n const dt = __dt();\n if (dt) {\n const file = dt._pendingFile || 'Unknown';\n dt._pendingFile = null;\n const id = dt.register(file);\n __idStack.push(id);\n dt.startInit(id);\n try {\n __svelte_original.user_effect(() => {\n return () => { try { dt.unmount(id); } catch {} };\n });\n } catch {}\n }\n } catch {}\n return result;\n}\n\nexport function pop() {\n // Capture devtools errors but ALWAYS forward to the original pop so the\n // Svelte component stack stays balanced.\n try {\n const dt = __dt();\n if (dt && __idStack.length > 0) {\n const id = __idStack.pop();\n try { dt.endInit(id); } catch {}\n try { dt.registered(id); } catch {}\n }\n } catch {}\n return __svelte_original.pop.apply(null, arguments);\n}\n\n// --- Signal Creation (type markers) ---\n\nexport function state() {\n const signal = __svelte_original.state.apply(null, arguments);\n try {\n __pendingSignal.ref = signal;\n __pendingSignal.type = 'state';\n } catch {}\n return signal;\n}\n\nexport function derived() {\n const signal = __svelte_original.derived.apply(null, arguments);\n try {\n __pendingSignal.ref = signal;\n __pendingSignal.type = 'derived';\n } catch {}\n return signal;\n}\n\nexport function proxy() {\n const p = __svelte_original.proxy.apply(null, arguments);\n try {\n __pendingSignal.ref = p;\n __pendingSignal.type = 'proxy';\n } catch {}\n return p;\n}\n\n// --- Signal Tagging (Svelte dev mode) ---\n\nexport function tag(signal, name) {\n const result = __svelte_original.tag.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n const type = (__pendingSignal.ref === signal) ? __pendingSignal.type : 'state';\n if (type === 'derived') {\n dt.trackDerived(signal, name, cid);\n } else {\n dt.trackState(signal, name, cid);\n }\n }\n __pendingSignal.ref = null;\n __pendingSignal.type = null;\n } catch {}\n return result;\n}\n\nexport function tag_proxy(proxy, name) {\n const result = __svelte_original.tag_proxy.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt.trackProxy(proxy, name, cid);\n }\n __pendingSignal.ref = null;\n __pendingSignal.type = null;\n } catch {}\n return result;\n}\n\n// --- Effect Tracking ---\n\nexport function user_effect() {\n const result = __svelte_original.user_effect.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt._effectCounter = (dt._effectCounter || 0) + 1;\n // Track the effect OBJECT (not the callback). The Svelte runtime\n // populates result.deps with the signals this effect depends on,\n // which is what getReactiveGraph() reads to build edges.\n dt.trackEffect(result, 'effect_' + dt._effectCounter, cid);\n }\n } catch {}\n return result;\n}\n\nexport function user_pre_effect() {\n const result = __svelte_original.user_pre_effect.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt._effectCounter = (dt._effectCounter || 0) + 1;\n dt.trackEffect(result, 'effect_pre_' + dt._effectCounter, cid);\n }\n } catch {}\n return result;\n}\n", L = "\nif (typeof window !== 'undefined' && !window.__SVELTE_DEVTOOLS__) {\n const __SVELTE_DT = {\n _nextId: 0,\n _instances: new Map(),\n _stack: [],\n _pendingFile: null,\n _effectCounter: 0,\n _debounceTimer: null,\n _listeners: new Set(),\n\n // Phase 2: Profiling data\n _profiles: new Map(),\n _initStartTimes: new Map(),\n _profileDebounceTimer: null,\n\n // Phase 2: Reactive graph data\n _reactiveNodes: new Map(),\n _reactiveProxies: new Map(),\n\n // Phase 3: State timeline\n _stateTimeline: [],\n _stateSnapshots: new Map(),\n _timelineDebounceTimer: null,\n\n register(file) {\n const id = this._nextId++;\n const parentId = this._stack.length > 0 ? this._stack[this._stack.length - 1] : null;\n const name = file.split('/').pop()?.replace('.svelte', '') || 'Unknown';\n this._instances.set(id, { id, file, name, parentId, mounted: true, children: [] });\n if (parentId !== null) {\n const parent = this._instances.get(parentId);\n if (parent) parent.children.push(id);\n }\n this._stack.push(id);\n this._scheduleUpdate();\n return id;\n },\n\n registered(id) {\n const idx = this._stack.indexOf(id);\n if (idx !== -1) this._stack.splice(idx, 1);\n },\n\n mount(id) {\n const instance = this._instances.get(id);\n if (instance && !instance.mounted) {\n instance.mounted = true;\n this._scheduleUpdate();\n }\n },\n\n unmount(id) {\n const instance = this._instances.get(id);\n if (instance) {\n if (instance.parentId !== null) {\n const parent = this._instances.get(instance.parentId);\n if (parent) {\n parent.children = parent.children.filter(cid => cid !== id);\n }\n }\n this._removeChildren(id);\n this._cleanupReactiveNodes(id);\n this._instances.delete(id);\n }\n this._scheduleUpdate();\n },\n\n _cleanupReactiveNodes(componentId) {\n for (const [nodeId, entry] of this._reactiveNodes) {\n if (entry.meta.componentId === componentId) {\n this._reactiveNodes.delete(nodeId);\n }\n }\n },\n\n _removeChildren(parentId) {\n const parent = this._instances.get(parentId);\n if (!parent) return;\n for (const childId of [...parent.children]) {\n this._removeChildren(childId);\n this._cleanupReactiveNodes(childId);\n this._instances.delete(childId);\n }\n },\n\n _scheduleUpdate() {\n if (this._debounceTimer) clearTimeout(this._debounceTimer);\n this._debounceTimer = setTimeout(() => {\n this._sendUpdate();\n }, 100);\n },\n\n _sendUpdate() {\n const components = [];\n for (const [, instance] of this._instances) {\n if (instance.mounted) {\n components.push({\n id: instance.id,\n file: instance.file,\n name: instance.name,\n parentId: instance.parentId,\n mounted: instance.mounted,\n });\n }\n }\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:components', { components });\n }\n },\n\n getTree() {\n const components = [];\n for (const [, instance] of this._instances) {\n if (instance.mounted) {\n components.push({\n id: instance.id,\n file: instance.file,\n name: instance.name,\n parentId: instance.parentId,\n mounted: instance.mounted,\n });\n }\n }\n return components;\n },\n\n // --- Phase 2: Render Profiling ---\n\n startInit(id) {\n this._initStartTimes.set(id, performance.now());\n },\n\n endInit(id) {\n const start = this._initStartTimes.get(id);\n if (start === undefined) return;\n const initTime = performance.now() - start;\n this._initStartTimes.delete(id);\n const instance = this._instances.get(id);\n if (!instance) return;\n this._profiles.set(id, {\n componentId: id,\n file: instance.file,\n name: instance.name,\n initTime,\n renderCount: 0,\n totalRenderTime: 0,\n lastRenderTime: 0,\n lastRenderAt: Date.now(),\n });\n this._scheduleProfileUpdate();\n },\n\n recordRender(id) {\n const profile = this._profiles.get(id);\n if (!profile) {\n const instance = this._instances.get(id);\n if (!instance) return;\n this._profiles.set(id, {\n componentId: id,\n file: instance.file,\n name: instance.name,\n initTime: 0,\n renderCount: 1,\n totalRenderTime: 0,\n lastRenderTime: 0,\n lastRenderAt: Date.now(),\n });\n } else {\n profile.renderCount++;\n profile.lastRenderAt = Date.now();\n }\n this._scheduleProfileUpdate();\n },\n\n recordRenderTime(id, duration) {\n const profile = this._profiles.get(id);\n if (profile) {\n profile.totalRenderTime += duration;\n profile.lastRenderTime = duration;\n }\n },\n\n _scheduleProfileUpdate() {\n if (this._profileDebounceTimer) clearTimeout(this._profileDebounceTimer);\n this._profileDebounceTimer = setTimeout(() => {\n this._sendProfileUpdate();\n }, 500);\n },\n\n _sendProfileUpdate() {\n const profiles = Array.from(this._profiles.values());\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:profiles', { profiles });\n }\n },\n\n getProfiles() {\n return Array.from(this._profiles.values());\n },\n\n resetProfiles() {\n this._profiles.clear();\n this._scheduleProfileUpdate();\n },\n\n // --- Phase 2: Reactive Graph Tracking ---\n\n trackState(signal, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(signal),\n meta: { id: nodeId, type: 'state', name, componentId, componentFile: instance ? instance.file : '' }\n });\n },\n\n trackProxy(proxy, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveProxies.set(nodeId, new WeakRef(proxy));\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef({ v: '(proxy)', _isProxy: true }),\n meta: { id: nodeId, type: 'state', name, componentId, componentFile: instance ? instance.file : '' }\n });\n },\n\n trackDerived(signal, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(signal),\n meta: { id: nodeId, type: 'derived', name, componentId, componentFile: instance ? instance.file : '' }\n });\n },\n\n trackEffect(effect, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(effect || { v: undefined, _isEffect: true }),\n meta: { id: nodeId, type: 'effect', name, componentId, componentFile: instance ? instance.file : '' }\n });\n return effect;\n },\n\n getReactiveGraph() {\n const nodes = [];\n const edges = [];\n const signalToId = new Map();\n\n for (const [nodeId, entry] of this._reactiveNodes) {\n const signal = entry.signal.deref();\n if (!signal || !this._instances.has(entry.meta.componentId)) {\n this._reactiveNodes.delete(nodeId);\n continue;\n }\n signalToId.set(signal, nodeId);\n const node = { ...entry.meta };\n if (signal._isProxy) {\n const proxyRef = this._reactiveProxies.get(nodeId);\n const proxy = proxyRef?.deref();\n if (proxy) {\n try {\n node.value = Array.isArray(proxy) ? '[' + proxy.length + ']' : '{' + Object.keys(proxy).length + '}';\n } catch { node.value = '(proxy)'; }\n }\n } else if (node.type !== 'effect' && signal.v !== undefined && typeof signal.v !== 'symbol') {\n try {\n const v = signal.v;\n if (typeof v === 'number' || typeof v === 'string' || typeof v === 'boolean' || v === null) {\n node.value = v;\n } else {\n node.value = '(object)';\n }\n } catch { /* ignore */ }\n }\n nodes.push(node);\n }\n\n // Map proxy internal signals to their proxy node ID\n for (const [nodeId, ref] of this._reactiveProxies) {\n const proxy = ref.deref();\n if (!proxy) { this._reactiveProxies.delete(nodeId); continue; }\n const meta = this._reactiveNodes.get(nodeId)?.meta;\n if (!meta || !this._instances.has(meta.componentId)) { this._reactiveProxies.delete(nodeId); continue; }\n }\n\n // Build edges from deps\n const edgeSet = new Set();\n for (const [nodeId, entry] of this._reactiveNodes) {\n const signal = entry.signal.deref();\n if (!signal) continue;\n if (!signal.deps) continue;\n\n const visited = new Set();\n const queue = [...signal.deps];\n while (queue.length > 0) {\n const dep = queue.shift();\n if (!dep || visited.has(dep)) continue;\n visited.add(dep);\n const depId = signalToId.get(dep);\n if (depId) {\n const key = depId + '>' + nodeId;\n if (depId !== nodeId && !edgeSet.has(key)) {\n edgeSet.add(key);\n edges.push({ from: depId, to: nodeId });\n }\n } else if (dep.deps) {\n for (const d of dep.deps) queue.push(d);\n }\n }\n }\n\n return { nodes, edges };\n },\n\n sendReactiveGraph() {\n const graph = this.getReactiveGraph();\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:reactive-graph', graph);\n }\n },\n\n // --- Phase 3: State Timeline ---\n\n _pollStateValues() {\n for (const [nodeId, entry] of this._reactiveNodes) {\n if (entry.meta.type !== 'state') continue;\n if (!this._instances.has(entry.meta.componentId)) {\n this._reactiveNodes.delete(nodeId);\n continue;\n }\n const signal = entry.signal.deref();\n if (!signal || signal.v === undefined) continue;\n try {\n const currentVal = signal.v;\n const prev = this._stateSnapshots.get(nodeId);\n if (prev !== undefined && currentVal === prev) continue;\n const isPrimitive = currentVal === null || typeof currentVal !== 'object';\n let newSnapshot;\n if (isPrimitive) {\n if (prev !== undefined && prev === currentVal) continue;\n newSnapshot = currentVal;\n } else {\n const currStr = JSON.stringify(currentVal);\n const prevStr = this._stateSnapshotStrs?.get(nodeId);\n if (prevStr === currStr) continue;\n newSnapshot = JSON.parse(currStr);\n if (!this._stateSnapshotStrs) this._stateSnapshotStrs = new Map();\n this._stateSnapshotStrs.set(nodeId, currStr);\n }\n if (this._stateTimeline.length >= 500) this._stateTimeline.splice(0, this._stateTimeline.length - 499);\n this._stateTimeline.push({\n id: nodeId,\n name: entry.meta.name,\n componentFile: entry.meta.componentFile,\n oldValue: prev !== undefined ? prev : null,\n newValue: newSnapshot,\n timestamp: Date.now(),\n });\n this._stateSnapshots.set(nodeId, newSnapshot);\n this._scheduleTimelineUpdate();\n } catch { /* ignore non-serializable */ }\n }\n },\n\n _scheduleTimelineUpdate() {\n if (this._timelineDebounceTimer) clearTimeout(this._timelineDebounceTimer);\n this._timelineDebounceTimer = setTimeout(() => {\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:state-timeline', { changes: this._stateTimeline });\n }\n }, 300);\n },\n\n getStateTimeline() {\n return this._stateTimeline;\n },\n\n clearStateTimeline() {\n this._stateTimeline = [];\n this._scheduleTimelineUpdate();\n },\n\n // --- FPS Monitoring ---\n // Uses requestAnimationFrame to measure frame rate with minimal overhead.\n // Only stores timestamps - no allocations per frame beyond a single array push.\n _fpsFrameTimes: [],\n\n _fpsLoop() {\n this._fpsFrameTimes.push(performance.now());\n requestAnimationFrame(() => this._fpsLoop());\n },\n\n _sampleFps() {\n const now = performance.now();\n // Remove frame timestamps older than 1 second\n const cutoff = now - 1000;\n let i = 0;\n while (i < this._fpsFrameTimes.length && this._fpsFrameTimes[i] < cutoff) i++;\n if (i > 0) this._fpsFrameTimes.splice(0, i);\n const fps = this._fpsFrameTimes.length;\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:fps', { timestamp: Date.now(), fps });\n }\n }\n };\n\n window.__SVELTE_DEVTOOLS__ = __SVELTE_DT;\n\n // Poll state values for timeline\n setInterval(() => { __SVELTE_DT._pollStateValues(); }, 200);\n\n // FPS monitoring\n requestAnimationFrame(() => __SVELTE_DT._fpsLoop());\n setInterval(() => __SVELTE_DT._sampleFps(), 500);\n\n // Phase 3: Capture runtime errors\n window.addEventListener('error', (event) => {\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:runtime-error', {\n message: event.message,\n file: event.filename,\n line: event.lineno,\n column: event.colno,\n stack: event.error?.stack || '',\n timestamp: Date.now(),\n });\n }\n });\n window.addEventListener('unhandledrejection', (event) => {\n if (import.meta.hot) {\n const reason = event.reason;\n import.meta.hot.send('svelte-devtools:runtime-error', {\n message: reason?.message || String(reason),\n stack: reason?.stack || '',\n timestamp: Date.now(),\n });\n }\n });\n\n // Listen for reactive graph requests from server\n if (import.meta.hot) {\n import.meta.hot.on('svelte-devtools:request-reactive-graph', () => {\n __SVELTE_DT.sendReactiveGraph();\n });\n import.meta.hot.on('svelte-devtools:request-state-timeline', () => {\n import.meta.hot.send('svelte-devtools:state-timeline', { changes: __SVELTE_DT._stateTimeline });\n });\n import.meta.hot.on('svelte-devtools:clear-state-timeline', () => {\n __SVELTE_DT.clearStateTimeline();\n });\n }\n}\n", R = 1, z = 5, B = 1, V = 30;
|
|
262
|
-
function
|
|
1234
|
+
//#region src/devframe.ts
|
|
1235
|
+
var Re = "svelte-devtools", L = "/.svelte-devtools/", R = o(import.meta.url)("../package.json"), ze = e.resolve(e.dirname(s(import.meta.url)), "client"), z = u.string().min(1).max(4096);
|
|
1236
|
+
function Be(e) {
|
|
1237
|
+
let { collector: t } = e, n = () => v(e.root()), r = () => re(n().routesDir);
|
|
1238
|
+
return [
|
|
1239
|
+
l({
|
|
1240
|
+
name: "get-project",
|
|
1241
|
+
type: "query",
|
|
1242
|
+
jsonSerializable: !0,
|
|
1243
|
+
handler: () => n()
|
|
1244
|
+
}),
|
|
1245
|
+
l({
|
|
1246
|
+
name: "get-routes",
|
|
1247
|
+
type: "query",
|
|
1248
|
+
jsonSerializable: !0,
|
|
1249
|
+
handler: () => r()
|
|
1250
|
+
}),
|
|
1251
|
+
l({
|
|
1252
|
+
name: "get-assets",
|
|
1253
|
+
type: "query",
|
|
1254
|
+
jsonSerializable: !0,
|
|
1255
|
+
handler: () => Ee(n().staticDir, e.publicBase())
|
|
1256
|
+
}),
|
|
1257
|
+
l({
|
|
1258
|
+
name: "get-component-relations",
|
|
1259
|
+
type: "query",
|
|
1260
|
+
jsonSerializable: !0,
|
|
1261
|
+
handler: () => b(e.root())
|
|
1262
|
+
}),
|
|
1263
|
+
l({
|
|
1264
|
+
name: "get-svelte-files",
|
|
1265
|
+
type: "query",
|
|
1266
|
+
jsonSerializable: !0,
|
|
1267
|
+
handler: () => b(e.root()).map((e) => ({
|
|
1268
|
+
file: e.file,
|
|
1269
|
+
name: e.name
|
|
1270
|
+
}))
|
|
1271
|
+
}),
|
|
1272
|
+
l({
|
|
1273
|
+
name: "get-live-components",
|
|
1274
|
+
type: "query",
|
|
1275
|
+
jsonSerializable: !0,
|
|
1276
|
+
handler: () => t.liveComponents
|
|
1277
|
+
}),
|
|
1278
|
+
l({
|
|
1279
|
+
name: "get-live-components-meta",
|
|
1280
|
+
type: "query",
|
|
1281
|
+
jsonSerializable: !0,
|
|
1282
|
+
handler: () => ({
|
|
1283
|
+
total: t.liveComponentsTotal,
|
|
1284
|
+
kept: t.liveComponents.length,
|
|
1285
|
+
truncated: t.liveComponentsTotal > t.liveComponents.length,
|
|
1286
|
+
...t.epochInfo
|
|
1287
|
+
})
|
|
1288
|
+
}),
|
|
1289
|
+
l({
|
|
1290
|
+
name: "set-active",
|
|
1291
|
+
type: "action",
|
|
1292
|
+
jsonSerializable: !0,
|
|
1293
|
+
args: [u.object({
|
|
1294
|
+
client: u.string().min(1).max(64),
|
|
1295
|
+
active: u.boolean()
|
|
1296
|
+
})],
|
|
1297
|
+
returns: u.void(),
|
|
1298
|
+
handler: ({ client: e, active: n }) => {
|
|
1299
|
+
n ? t.lease(`ui:${e}`) : t.release(`ui:${e}`);
|
|
1300
|
+
}
|
|
1301
|
+
}),
|
|
1302
|
+
l({
|
|
1303
|
+
name: "open-in-editor",
|
|
1304
|
+
type: "action",
|
|
1305
|
+
jsonSerializable: !0,
|
|
1306
|
+
args: [u.object({
|
|
1307
|
+
file: z,
|
|
1308
|
+
line: u.number().int().nonnegative().optional()
|
|
1309
|
+
})],
|
|
1310
|
+
returns: u.void(),
|
|
1311
|
+
handler: ({ file: t, line: n }) => {
|
|
1312
|
+
let r = I(e.root(), t);
|
|
1313
|
+
e.openInEditor(n ? `${r}:${n}` : r);
|
|
1314
|
+
}
|
|
1315
|
+
}),
|
|
1316
|
+
l({
|
|
1317
|
+
name: "open-reactive-in-editor",
|
|
1318
|
+
type: "action",
|
|
1319
|
+
jsonSerializable: !0,
|
|
1320
|
+
args: [u.object({
|
|
1321
|
+
file: z,
|
|
1322
|
+
name: u.string().max(256),
|
|
1323
|
+
type: u.string().max(32)
|
|
1324
|
+
})],
|
|
1325
|
+
returns: u.void(),
|
|
1326
|
+
handler: ({ file: t, name: n, type: r }) => {
|
|
1327
|
+
let i = I(e.root(), t), o = 0;
|
|
1328
|
+
try {
|
|
1329
|
+
o = Le(a.readFileSync(i, "utf-8"), n, r);
|
|
1330
|
+
} catch {}
|
|
1331
|
+
e.openInEditor(o > 0 ? `${i}:${o}` : i);
|
|
1332
|
+
}
|
|
1333
|
+
}),
|
|
1334
|
+
l({
|
|
1335
|
+
name: "get-render-profiles",
|
|
1336
|
+
type: "query",
|
|
1337
|
+
jsonSerializable: !0,
|
|
1338
|
+
handler: () => t.renderProfiles
|
|
1339
|
+
}),
|
|
1340
|
+
l({
|
|
1341
|
+
name: "get-reactive-graph",
|
|
1342
|
+
type: "query",
|
|
1343
|
+
jsonSerializable: !0,
|
|
1344
|
+
args: [u.object({
|
|
1345
|
+
componentId: u.number().int().nonnegative().optional(),
|
|
1346
|
+
epoch: u.string().max(200).optional(),
|
|
1347
|
+
maxNodes: u.number().int().positive().optional(),
|
|
1348
|
+
maxEdges: u.number().int().positive().optional()
|
|
1349
|
+
}).optional()],
|
|
1350
|
+
returns: u.custom(),
|
|
1351
|
+
handler: (e) => t.requestReactiveGraph(e ?? {})
|
|
1352
|
+
}),
|
|
1353
|
+
l({
|
|
1354
|
+
name: "get-reactive-summary",
|
|
1355
|
+
type: "query",
|
|
1356
|
+
jsonSerializable: !0,
|
|
1357
|
+
args: [u.object({
|
|
1358
|
+
topK: u.number().int().positive().optional(),
|
|
1359
|
+
windowMs: u.number().int().positive().optional()
|
|
1360
|
+
}).optional()],
|
|
1361
|
+
returns: u.custom(),
|
|
1362
|
+
handler: (e) => t.requestReactiveSummary(e ?? {})
|
|
1363
|
+
}),
|
|
1364
|
+
l({
|
|
1365
|
+
name: "get-capture-info",
|
|
1366
|
+
type: "query",
|
|
1367
|
+
jsonSerializable: !0,
|
|
1368
|
+
handler: () => t.getCaptureInfo()
|
|
1369
|
+
}),
|
|
1370
|
+
l({
|
|
1371
|
+
name: "get-load-profiles",
|
|
1372
|
+
type: "query",
|
|
1373
|
+
jsonSerializable: !0,
|
|
1374
|
+
handler: () => t.loadProfiles
|
|
1375
|
+
}),
|
|
1376
|
+
l({
|
|
1377
|
+
name: "clear-load-profiles",
|
|
1378
|
+
type: "action",
|
|
1379
|
+
jsonSerializable: !0,
|
|
1380
|
+
handler: () => t.clearLoadProfiles()
|
|
1381
|
+
}),
|
|
1382
|
+
l({
|
|
1383
|
+
name: "get-state-timeline",
|
|
1384
|
+
type: "query",
|
|
1385
|
+
jsonSerializable: !0,
|
|
1386
|
+
handler: () => t.requestStateTimeline()
|
|
1387
|
+
}),
|
|
1388
|
+
l({
|
|
1389
|
+
name: "get-state-timeline-delta",
|
|
1390
|
+
type: "query",
|
|
1391
|
+
jsonSerializable: !0,
|
|
1392
|
+
args: [u.object({ since: u.number().int().nonnegative().optional() })],
|
|
1393
|
+
returns: u.custom(),
|
|
1394
|
+
handler: ({ since: e }) => t.getStateTimelineDelta(e)
|
|
1395
|
+
}),
|
|
1396
|
+
l({
|
|
1397
|
+
name: "get-versions",
|
|
1398
|
+
type: "query",
|
|
1399
|
+
jsonSerializable: !0,
|
|
1400
|
+
handler: () => ({ ...t.versions })
|
|
1401
|
+
}),
|
|
1402
|
+
l({
|
|
1403
|
+
name: "clear-state-timeline",
|
|
1404
|
+
type: "action",
|
|
1405
|
+
jsonSerializable: !0,
|
|
1406
|
+
handler: () => t.clearStateTimeline()
|
|
1407
|
+
}),
|
|
1408
|
+
l({
|
|
1409
|
+
name: "get-api-endpoints",
|
|
1410
|
+
type: "query",
|
|
1411
|
+
jsonSerializable: !0,
|
|
1412
|
+
handler: () => Ae(r())
|
|
1413
|
+
}),
|
|
1414
|
+
l({
|
|
1415
|
+
name: "send-api-request",
|
|
1416
|
+
type: "action",
|
|
1417
|
+
jsonSerializable: !0,
|
|
1418
|
+
args: [u.object({
|
|
1419
|
+
url: u.string().max(8192),
|
|
1420
|
+
method: u.enum([
|
|
1421
|
+
"GET",
|
|
1422
|
+
"POST",
|
|
1423
|
+
"PUT",
|
|
1424
|
+
"PATCH",
|
|
1425
|
+
"DELETE",
|
|
1426
|
+
"HEAD",
|
|
1427
|
+
"OPTIONS"
|
|
1428
|
+
]),
|
|
1429
|
+
headers: u.string().max(65536),
|
|
1430
|
+
body: u.string().max(1e6)
|
|
1431
|
+
})],
|
|
1432
|
+
returns: u.custom(),
|
|
1433
|
+
handler: (t) => je(t, { allowedOrigins: e.serverOrigins() })
|
|
1434
|
+
}),
|
|
1435
|
+
l({
|
|
1436
|
+
name: "get-compiler-warnings",
|
|
1437
|
+
type: "query",
|
|
1438
|
+
jsonSerializable: !0,
|
|
1439
|
+
handler: () => t.compilerWarnings
|
|
1440
|
+
}),
|
|
1441
|
+
l({
|
|
1442
|
+
name: "get-runtime-errors",
|
|
1443
|
+
type: "query",
|
|
1444
|
+
jsonSerializable: !0,
|
|
1445
|
+
handler: () => t.runtimeErrors
|
|
1446
|
+
}),
|
|
1447
|
+
l({
|
|
1448
|
+
name: "clear-errors",
|
|
1449
|
+
type: "action",
|
|
1450
|
+
jsonSerializable: !0,
|
|
1451
|
+
handler: () => t.clearErrors()
|
|
1452
|
+
}),
|
|
1453
|
+
l({
|
|
1454
|
+
name: "inspect-file",
|
|
1455
|
+
type: "query",
|
|
1456
|
+
jsonSerializable: !0,
|
|
1457
|
+
args: [u.object({ file: z })],
|
|
1458
|
+
returns: u.custom(),
|
|
1459
|
+
handler: async ({ file: t }) => {
|
|
1460
|
+
let n = {
|
|
1461
|
+
source: "",
|
|
1462
|
+
compiled: "",
|
|
1463
|
+
file: t
|
|
1464
|
+
}, r, i;
|
|
1465
|
+
try {
|
|
1466
|
+
r = I(e.root(), t), i = a.readFileSync(r, "utf-8");
|
|
1467
|
+
} catch {
|
|
1468
|
+
return n;
|
|
1469
|
+
}
|
|
1470
|
+
if (!e.transformRequest) return {
|
|
1471
|
+
...n,
|
|
1472
|
+
source: i
|
|
1473
|
+
};
|
|
1474
|
+
try {
|
|
1475
|
+
let n = await e.transformRequest(r), a = typeof n?.map == "string" ? JSON.parse(n.map) : n?.map;
|
|
1476
|
+
return {
|
|
1477
|
+
source: i,
|
|
1478
|
+
compiled: n?.code || "",
|
|
1479
|
+
file: t,
|
|
1480
|
+
mappings: a?.mappings,
|
|
1481
|
+
sources: a?.sources
|
|
1482
|
+
};
|
|
1483
|
+
} catch {
|
|
1484
|
+
return {
|
|
1485
|
+
source: i,
|
|
1486
|
+
compiled: "// Transform failed",
|
|
1487
|
+
file: t
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}),
|
|
1492
|
+
l({
|
|
1493
|
+
name: "get-module-graph",
|
|
1494
|
+
type: "query",
|
|
1495
|
+
jsonSerializable: !0,
|
|
1496
|
+
handler: () => Fe(e.root(), e.modules())
|
|
1497
|
+
}),
|
|
1498
|
+
l({
|
|
1499
|
+
name: "get-og-preview",
|
|
1500
|
+
type: "action",
|
|
1501
|
+
jsonSerializable: !0,
|
|
1502
|
+
args: [u.object({ url: u.string().max(8192) })],
|
|
1503
|
+
returns: u.custom(),
|
|
1504
|
+
handler: ({ url: t }) => Ie(t, { allowedOrigins: e.serverOrigins() })
|
|
1505
|
+
}),
|
|
1506
|
+
l({
|
|
1507
|
+
name: "get-build-analysis",
|
|
1508
|
+
type: "query",
|
|
1509
|
+
jsonSerializable: !0,
|
|
1510
|
+
handler: () => Ne(e.root())
|
|
1511
|
+
}),
|
|
1512
|
+
l({
|
|
1513
|
+
name: "get-fps",
|
|
1514
|
+
type: "query",
|
|
1515
|
+
jsonSerializable: !0,
|
|
1516
|
+
handler: () => t.fpsSamples
|
|
1517
|
+
}),
|
|
1518
|
+
l({
|
|
1519
|
+
name: "clear-fps",
|
|
1520
|
+
type: "action",
|
|
1521
|
+
jsonSerializable: !0,
|
|
1522
|
+
handler: () => t.clearFps()
|
|
1523
|
+
})
|
|
1524
|
+
];
|
|
1525
|
+
}
|
|
1526
|
+
function Ve(e) {
|
|
1527
|
+
return c({
|
|
1528
|
+
id: Re,
|
|
1529
|
+
name: "Svelte",
|
|
1530
|
+
version: R.version,
|
|
1531
|
+
packageName: R.name,
|
|
1532
|
+
importMetaUrl: import.meta.url,
|
|
1533
|
+
homepage: R.homepage,
|
|
1534
|
+
description: R.description,
|
|
1535
|
+
icon: "simple-icons:svelte",
|
|
1536
|
+
basePath: L,
|
|
1537
|
+
capabilities: {
|
|
1538
|
+
dev: !0,
|
|
1539
|
+
build: !1
|
|
1540
|
+
},
|
|
1541
|
+
dock: { category: "framework" },
|
|
1542
|
+
clientAssets: ze,
|
|
1543
|
+
setup(t) {
|
|
1544
|
+
let n = t.scope(Re);
|
|
1545
|
+
for (let t of Be(e)) n.rpc.register(t);
|
|
1546
|
+
}
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
//#endregion
|
|
1550
|
+
//#region src/mount.ts
|
|
1551
|
+
var He = /* @__PURE__ */ new Set(["0.0.0.0", "::"]), Ue = /* @__PURE__ */ new Set([
|
|
1552
|
+
"127.0.0.1",
|
|
1553
|
+
"::1",
|
|
1554
|
+
"localhost"
|
|
1555
|
+
]);
|
|
1556
|
+
function We(e) {
|
|
1557
|
+
return e.includes(":") ? `[${e}]` : e;
|
|
1558
|
+
}
|
|
1559
|
+
function Ge(e, t) {
|
|
1560
|
+
return Ue.has(e.address) ? [] : (He.has(e.address) ? Object.values(p.networkInterfaces()).flat().filter((e) => e && !e.internal).map((e) => e.address) : [e.address]).map((n) => `${t}://${We(n)}:${e.port}`);
|
|
1561
|
+
}
|
|
1562
|
+
function Ke(e, t) {
|
|
1563
|
+
let n, r = !1, i = e.httpServer;
|
|
1564
|
+
if (e.middlewares.use((e, t, r) => {
|
|
1565
|
+
if (n) return n.nodeMiddleware(e, t, r);
|
|
1566
|
+
if (e.url?.startsWith("/.svelte-devtools/")) {
|
|
1567
|
+
t.statusCode = 503, t.end("Svelte DevTools is starting");
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
r();
|
|
1571
|
+
}), !i) {
|
|
1572
|
+
let e = m(t, {
|
|
1573
|
+
base: L,
|
|
1574
|
+
ws: !1,
|
|
1575
|
+
sse: !0,
|
|
1576
|
+
mcp: !1
|
|
1577
|
+
});
|
|
1578
|
+
return n = e, async () => {
|
|
1579
|
+
n = void 0, await e.close().catch(() => {});
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
i.once("listening", () => {
|
|
1583
|
+
let a = i.address();
|
|
1584
|
+
if (r || !a || typeof a == "string") return;
|
|
1585
|
+
let o = e.config.server.https ? "https" : "http", s = `${o}://localhost:${a.port}`;
|
|
1586
|
+
n = m(t, {
|
|
1587
|
+
base: L,
|
|
1588
|
+
server: i,
|
|
1589
|
+
mcp: !1,
|
|
1590
|
+
origin: `${s}${L}`,
|
|
1591
|
+
allowedOrigins: Ge(a, o)
|
|
1592
|
+
}), e.config.logger.info(` ➜ Svelte DevTools: ${s}${L}`);
|
|
1593
|
+
}), i.once("close", () => {
|
|
1594
|
+
r = !0;
|
|
1595
|
+
let e = n;
|
|
1596
|
+
n = void 0, e?.close().catch(() => {});
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
//#endregion
|
|
1600
|
+
//#region src/mcp/sessions.ts
|
|
1601
|
+
var qe = 1, Je = 5, Ye = 1, Xe = 30;
|
|
1602
|
+
function B(e) {
|
|
263
1603
|
return {
|
|
264
1604
|
renderProfiles: e.getRenderProfiles().map((e) => ({
|
|
265
1605
|
componentId: e.componentId,
|
|
@@ -273,29 +1613,33 @@ function H(e) {
|
|
|
273
1613
|
takenAt: Date.now()
|
|
274
1614
|
};
|
|
275
1615
|
}
|
|
276
|
-
function
|
|
1616
|
+
function V(e, t, n) {
|
|
277
1617
|
return Math.abs(e) < t ? "unchanged" : n ? e < 0 ? "improved" : "regressed" : e > 0 ? "improved" : "regressed";
|
|
278
1618
|
}
|
|
279
|
-
var
|
|
1619
|
+
var H = /^s_[0-9a-z]{1,16}_[0-9a-f]{6}$/;
|
|
1620
|
+
function U(e) {
|
|
1621
|
+
return typeof e == "string" && H.test(e);
|
|
1622
|
+
}
|
|
1623
|
+
var Ze = class {
|
|
280
1624
|
sessions = /* @__PURE__ */ new Map();
|
|
281
1625
|
active = null;
|
|
282
1626
|
persistDir;
|
|
283
1627
|
getters;
|
|
284
|
-
constructor(
|
|
285
|
-
this.persistDir = e.persistDir, this.getters =
|
|
1628
|
+
constructor(t) {
|
|
1629
|
+
this.persistDir = e.resolve(t.persistDir), this.getters = t.getters;
|
|
286
1630
|
}
|
|
287
|
-
start(e,
|
|
1631
|
+
start(e, n) {
|
|
288
1632
|
if (this.active) throw Error(`A session is already active: ${this.active}. Call end_session before starting a new one.`);
|
|
289
|
-
let
|
|
290
|
-
id:
|
|
1633
|
+
let r = `s_${Date.now().toString(36)}_${t.randomBytes(3).toString("hex")}`, i = {
|
|
1634
|
+
id: r,
|
|
291
1635
|
label: e,
|
|
292
1636
|
startedAt: Date.now(),
|
|
293
|
-
persist:
|
|
294
|
-
startSnapshot:
|
|
1637
|
+
persist: n,
|
|
1638
|
+
startSnapshot: B(this.getters),
|
|
295
1639
|
loadProfiles: [],
|
|
296
1640
|
fpsSamples: []
|
|
297
1641
|
};
|
|
298
|
-
return this.sessions.set(
|
|
1642
|
+
return this.sessions.set(r, i), this.active = r, i;
|
|
299
1643
|
}
|
|
300
1644
|
recordLoadProfile(e) {
|
|
301
1645
|
if (!this.active) return;
|
|
@@ -311,47 +1655,49 @@ var te = class {
|
|
|
311
1655
|
if (!this.active) throw Error("No active session");
|
|
312
1656
|
let t = this.sessions.get(this.active);
|
|
313
1657
|
if (!t) throw Error("Active session missing from store");
|
|
314
|
-
return t.endedAt = Date.now(), t.endSnapshot =
|
|
1658
|
+
return t.endedAt = Date.now(), t.endSnapshot = B(this.getters), this.active = null, e === "discard" ? this.sessions.delete(t.id) : (e === "disk" || t.persist) && this.persistToDisk(t), t;
|
|
315
1659
|
}
|
|
316
1660
|
get(e) {
|
|
317
|
-
return this.sessions.get(e) || this.loadFromDisk(e);
|
|
1661
|
+
return U(e) ? this.sessions.get(e) || this.loadFromDisk(e) : void 0;
|
|
318
1662
|
}
|
|
319
1663
|
list() {
|
|
320
|
-
let
|
|
321
|
-
for (let
|
|
322
|
-
id:
|
|
323
|
-
label:
|
|
324
|
-
startedAt:
|
|
325
|
-
endedAt:
|
|
326
|
-
persisted:
|
|
327
|
-
active: this.active ===
|
|
1664
|
+
let e = /* @__PURE__ */ new Set(), t = [];
|
|
1665
|
+
for (let n of this.sessions.values()) e.add(n.id), t.push({
|
|
1666
|
+
id: n.id,
|
|
1667
|
+
label: n.label,
|
|
1668
|
+
startedAt: n.startedAt,
|
|
1669
|
+
endedAt: n.endedAt,
|
|
1670
|
+
persisted: a.existsSync(this.pathFor(n.id)),
|
|
1671
|
+
active: this.active === n.id
|
|
328
1672
|
});
|
|
329
1673
|
try {
|
|
330
|
-
if (
|
|
331
|
-
if (!
|
|
332
|
-
let
|
|
333
|
-
if (!
|
|
334
|
-
let
|
|
335
|
-
r
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
1674
|
+
if (a.existsSync(this.persistDir)) for (let n of a.readdirSync(this.persistDir)) {
|
|
1675
|
+
if (!n.endsWith(".json")) continue;
|
|
1676
|
+
let r = n.slice(0, -5);
|
|
1677
|
+
if (U(r) && !e.has(r)) try {
|
|
1678
|
+
let e = JSON.parse(a.readFileSync(this.pathFor(r), "utf-8"));
|
|
1679
|
+
if (e?.id !== r) continue;
|
|
1680
|
+
t.push({
|
|
1681
|
+
id: e.id,
|
|
1682
|
+
label: e.label,
|
|
1683
|
+
startedAt: e.startedAt,
|
|
1684
|
+
endedAt: e.endedAt,
|
|
340
1685
|
persisted: !0,
|
|
341
1686
|
active: !1
|
|
342
1687
|
});
|
|
343
1688
|
} catch {}
|
|
344
1689
|
}
|
|
345
1690
|
} catch {}
|
|
346
|
-
return
|
|
1691
|
+
return t.sort((e, t) => t.startedAt - e.startedAt);
|
|
347
1692
|
}
|
|
348
1693
|
delete(e) {
|
|
349
|
-
|
|
1694
|
+
if (!U(e)) return !1;
|
|
1695
|
+
let t = this.sessions.delete(e), n = !1;
|
|
350
1696
|
try {
|
|
351
|
-
let
|
|
352
|
-
|
|
1697
|
+
let t = this.pathFor(e);
|
|
1698
|
+
a.existsSync(t) && (a.unlinkSync(t), n = !0);
|
|
353
1699
|
} catch {}
|
|
354
|
-
return this.active === e && (this.active = null),
|
|
1700
|
+
return this.active === e && (this.active = null), t || n;
|
|
355
1701
|
}
|
|
356
1702
|
delta(e) {
|
|
357
1703
|
let t = this.get(e);
|
|
@@ -367,7 +1713,7 @@ var te = class {
|
|
|
367
1713
|
totalRenderTimeDelta: o,
|
|
368
1714
|
avgRenderTimeDelta: a > 0 ? o / a : 0
|
|
369
1715
|
};
|
|
370
|
-
}).filter((e) => e.renderCountDelta > 0).sort((e, t) => t.totalRenderTimeDelta - e.totalRenderTimeDelta), i = t.loadProfiles.map((e) => e.duration), a = W(i), o =
|
|
1716
|
+
}).filter((e) => e.renderCountDelta > 0).sort((e, t) => t.totalRenderTimeDelta - e.totalRenderTimeDelta), i = t.loadProfiles.map((e) => e.duration), a = W(i), o = Qe(i, 95), s = t.fpsSamples.map((e) => e.fps), c = W(s), l = s.length ? Math.min(...s) : 0, u = s.filter((e) => e < Xe).length;
|
|
371
1717
|
return {
|
|
372
1718
|
durationMs: t.endedAt - t.startedAt,
|
|
373
1719
|
components: r,
|
|
@@ -399,34 +1745,37 @@ var te = class {
|
|
|
399
1745
|
totalRenderTimeDeltaA: o,
|
|
400
1746
|
totalRenderTimeDeltaB: s,
|
|
401
1747
|
diff: c,
|
|
402
|
-
verdict:
|
|
1748
|
+
verdict: V(c, qe, !0)
|
|
403
1749
|
},
|
|
404
1750
|
load: {
|
|
405
1751
|
avgA: n.loadProfiles.avgDuration,
|
|
406
1752
|
avgB: r.loadProfiles.avgDuration,
|
|
407
1753
|
diff: l,
|
|
408
|
-
verdict:
|
|
1754
|
+
verdict: V(l, Je, !0)
|
|
409
1755
|
},
|
|
410
1756
|
fps: {
|
|
411
1757
|
avgA: n.fps.avg,
|
|
412
1758
|
avgB: r.fps.avg,
|
|
413
1759
|
diff: u,
|
|
414
|
-
verdict:
|
|
1760
|
+
verdict: V(u, Ye, !1)
|
|
415
1761
|
}
|
|
416
1762
|
};
|
|
417
1763
|
}
|
|
418
1764
|
pathFor(t) {
|
|
419
|
-
|
|
1765
|
+
if (!U(t)) throw Error("Invalid session id");
|
|
1766
|
+
let n = e.resolve(this.persistDir, `${t}.json`);
|
|
1767
|
+
if (e.dirname(n) !== this.persistDir) throw Error("Invalid session id");
|
|
1768
|
+
return n;
|
|
420
1769
|
}
|
|
421
1770
|
persistToDisk(e) {
|
|
422
1771
|
try {
|
|
423
|
-
|
|
1772
|
+
a.mkdirSync(this.persistDir, { recursive: !0 }), a.writeFileSync(this.pathFor(e.id), JSON.stringify(e, null, 2), { mode: 384 });
|
|
424
1773
|
} catch {}
|
|
425
1774
|
}
|
|
426
1775
|
loadFromDisk(e) {
|
|
427
1776
|
try {
|
|
428
|
-
let
|
|
429
|
-
return
|
|
1777
|
+
let t = a.readFileSync(this.pathFor(e), "utf-8"), n = JSON.parse(t);
|
|
1778
|
+
return n?.id === e ? n : void 0;
|
|
430
1779
|
} catch {
|
|
431
1780
|
return;
|
|
432
1781
|
}
|
|
@@ -435,7 +1784,7 @@ var te = class {
|
|
|
435
1784
|
function W(e) {
|
|
436
1785
|
return e.length ? e.reduce((e, t) => e + t, 0) / e.length : 0;
|
|
437
1786
|
}
|
|
438
|
-
function
|
|
1787
|
+
function Qe(e, t) {
|
|
439
1788
|
if (!e.length) return 0;
|
|
440
1789
|
let n = [...e].sort((e, t) => e - t);
|
|
441
1790
|
return n[Math.min(n.length - 1, Math.floor(t / 100 * n.length))];
|
|
@@ -449,7 +1798,7 @@ var G = {
|
|
|
449
1798
|
fpsDropThreshold: 40,
|
|
450
1799
|
effectMaxDeps: 8
|
|
451
1800
|
};
|
|
452
|
-
function
|
|
1801
|
+
function $e(e, t = {}) {
|
|
453
1802
|
let n = {
|
|
454
1803
|
...G,
|
|
455
1804
|
...t
|
|
@@ -539,20 +1888,20 @@ function re(e, t = {}) {
|
|
|
539
1888
|
});
|
|
540
1889
|
}
|
|
541
1890
|
}
|
|
542
|
-
return r.sort(
|
|
1891
|
+
return r.sort(et);
|
|
543
1892
|
}
|
|
544
1893
|
var K = {
|
|
545
1894
|
high: 0,
|
|
546
1895
|
medium: 1,
|
|
547
1896
|
low: 2
|
|
548
1897
|
};
|
|
549
|
-
function
|
|
1898
|
+
function et(e, t) {
|
|
550
1899
|
return K[e.severity] - K[t.severity];
|
|
551
1900
|
}
|
|
552
1901
|
function q(e) {
|
|
553
1902
|
return Math.round(e * 100) / 100;
|
|
554
1903
|
}
|
|
555
|
-
function
|
|
1904
|
+
function tt(e, t = {}) {
|
|
556
1905
|
let n = {
|
|
557
1906
|
...G,
|
|
558
1907
|
...t
|
|
@@ -583,18 +1932,33 @@ function ae(e, t = {}) {
|
|
|
583
1932
|
isolatedNodes: s
|
|
584
1933
|
};
|
|
585
1934
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
1935
|
+
var J = {
|
|
1936
|
+
default: 2048,
|
|
1937
|
+
max: 32768
|
|
1938
|
+
};
|
|
1939
|
+
function Y(e, t) {
|
|
1940
|
+
let n;
|
|
1941
|
+
try {
|
|
1942
|
+
n = JSON.stringify(e);
|
|
1943
|
+
} catch {
|
|
1944
|
+
return { omitted: "not serializable" };
|
|
1945
|
+
}
|
|
1946
|
+
return n === void 0 || n.length <= t ? e : {
|
|
1947
|
+
omitted: "too large",
|
|
1948
|
+
chars: n.length,
|
|
1949
|
+
preview: n.slice(0, Math.min(200, t))
|
|
1950
|
+
};
|
|
1951
|
+
}
|
|
1952
|
+
var X = u.string().max(64).regex(H, "not a session id"), Z = (e) => ({ content: [{
|
|
589
1953
|
type: "text",
|
|
590
1954
|
text: typeof e == "string" ? e : JSON.stringify(e, null, 2)
|
|
591
1955
|
}] });
|
|
592
|
-
function
|
|
593
|
-
let t = new
|
|
1956
|
+
function nt(e) {
|
|
1957
|
+
let t = new ee({
|
|
594
1958
|
name: "vite-devtools-svelte",
|
|
595
1959
|
version: "0.1.0"
|
|
596
1960
|
});
|
|
597
|
-
|
|
1961
|
+
if (t.registerTool("list_performance_issues", {
|
|
598
1962
|
title: "List performance issues",
|
|
599
1963
|
description: "Cross-cuts render/reactive/load/fps metrics and returns ranked issues. The entry point for AI-driven performance audits. Each issue carries `suggestedTool` naming the detail tool to call next.",
|
|
600
1964
|
inputSchema: {
|
|
@@ -605,13 +1969,13 @@ function oe(e) {
|
|
|
605
1969
|
effectMaxDeps: u.number().optional()
|
|
606
1970
|
}
|
|
607
1971
|
}, async (t) => {
|
|
608
|
-
let n = t, r = await e.getReactiveGraph(), i =
|
|
1972
|
+
let n = t, r = await e.getReactiveGraph(), i = $e({
|
|
609
1973
|
renderProfiles: e.getRenderProfiles(),
|
|
610
1974
|
reactiveGraph: r,
|
|
611
1975
|
loadProfiles: e.getLoadProfiles(),
|
|
612
1976
|
fpsSamples: e.getFpsSamples()
|
|
613
1977
|
}, n);
|
|
614
|
-
return
|
|
1978
|
+
return Z({
|
|
615
1979
|
count: i.length,
|
|
616
1980
|
issues: i
|
|
617
1981
|
});
|
|
@@ -619,20 +1983,20 @@ function oe(e) {
|
|
|
619
1983
|
title: "Component render hotspots",
|
|
620
1984
|
description: "Top components by total render time, with render count and per-render average.",
|
|
621
1985
|
inputSchema: { topN: u.number().int().min(1).max(200).optional() }
|
|
622
|
-
}, async ({ topN: t = 20 }) =>
|
|
1986
|
+
}, async ({ topN: t = 20 }) => Z([...e.getRenderProfiles()].map((e) => ({
|
|
623
1987
|
file: e.file,
|
|
624
1988
|
name: e.name,
|
|
625
1989
|
componentId: e.componentId,
|
|
626
1990
|
renderCount: e.renderCount,
|
|
627
|
-
totalRenderTimeMs:
|
|
628
|
-
avgRenderTimeMs:
|
|
629
|
-
lastRenderTimeMs:
|
|
1991
|
+
totalRenderTimeMs: Q(e.totalRenderTime),
|
|
1992
|
+
avgRenderTimeMs: Q(e.renderCount > 0 ? e.totalRenderTime / e.renderCount : 0),
|
|
1993
|
+
lastRenderTimeMs: Q(e.lastRenderTime),
|
|
630
1994
|
lastRenderAt: e.lastRenderAt
|
|
631
1995
|
})).sort((e, t) => t.totalRenderTimeMs - e.totalRenderTimeMs).slice(0, t))), t.registerTool("get_reactive_graph_problems", {
|
|
632
1996
|
title: "Reactive graph problems",
|
|
633
1997
|
description: "Classified reactive graph issues: over-connected effects, orphan deriveds, isolated nodes. Returns categories instead of the full graph.",
|
|
634
1998
|
inputSchema: { effectMaxDeps: u.number().int().min(1).optional() }
|
|
635
|
-
}, async ({ effectMaxDeps: t }) =>
|
|
1999
|
+
}, async ({ effectMaxDeps: t }) => Z(tt(await e.getReactiveGraph(), { effectMaxDeps: t }))), t.registerTool("get_load_waterfall", {
|
|
636
2000
|
title: "SvelteKit load waterfall",
|
|
637
2001
|
description: "Load profiles grouped by route, with timing and data size. Optionally filtered by route.",
|
|
638
2002
|
inputSchema: { route: u.string().optional() }
|
|
@@ -644,14 +2008,14 @@ function oe(e) {
|
|
|
644
2008
|
let t = r.get(e.route) ?? [];
|
|
645
2009
|
t.push(e), r.set(e.route, t);
|
|
646
2010
|
}
|
|
647
|
-
return
|
|
2011
|
+
return Z([...r.entries()].map(([e, t]) => {
|
|
648
2012
|
let n = t.map((e) => e.duration);
|
|
649
2013
|
return {
|
|
650
2014
|
route: e,
|
|
651
2015
|
file: t[0]?.file,
|
|
652
2016
|
count: t.length,
|
|
653
|
-
avgDuration:
|
|
654
|
-
maxDuration:
|
|
2017
|
+
avgDuration: Q(rt(n)),
|
|
2018
|
+
maxDuration: Q(Math.max(...n)),
|
|
655
2019
|
totalDataBytes: t.reduce((e, t) => e + t.dataSize, 0),
|
|
656
2020
|
samples: t
|
|
657
2021
|
};
|
|
@@ -670,7 +2034,7 @@ function oe(e) {
|
|
|
670
2034
|
r = r.filter((t) => t.timestamp >= e);
|
|
671
2035
|
}
|
|
672
2036
|
let i = r.filter((e) => e.fps < t);
|
|
673
|
-
return
|
|
2037
|
+
return Z({
|
|
674
2038
|
threshold: t,
|
|
675
2039
|
sampleCount: r.length,
|
|
676
2040
|
dropCount: i.length,
|
|
@@ -681,27 +2045,113 @@ function oe(e) {
|
|
|
681
2045
|
title: "Render profile for a specific file",
|
|
682
2046
|
description: "Returns render profile entries matching the given component file (substring match).",
|
|
683
2047
|
inputSchema: { file: u.string() }
|
|
684
|
-
}, async ({ file: t }) =>
|
|
2048
|
+
}, async ({ file: t }) => Z(e.getRenderProfiles().filter((e) => e.file.includes(t)).map((e) => ({
|
|
685
2049
|
...e,
|
|
686
|
-
totalRenderTimeMs:
|
|
687
|
-
avgRenderTimeMs:
|
|
2050
|
+
totalRenderTimeMs: Q(e.totalRenderTime),
|
|
2051
|
+
avgRenderTimeMs: Q(e.renderCount > 0 ? e.totalRenderTime / e.renderCount : 0)
|
|
688
2052
|
})))), t.registerTool("get_project_info", {
|
|
689
2053
|
title: "Project info",
|
|
690
2054
|
description: "Package name/version, Svelte / SvelteKit / Vite versions, dependency lists.",
|
|
691
2055
|
inputSchema: {}
|
|
692
|
-
}, async () =>
|
|
2056
|
+
}, async () => Z(e.getProject())), t.registerTool("get_routes", {
|
|
693
2057
|
title: "SvelteKit routes",
|
|
694
2058
|
description: "Static analysis of the SvelteKit routes tree.",
|
|
695
2059
|
inputSchema: {}
|
|
696
|
-
}, async () =>
|
|
2060
|
+
}, async () => Z(e.getRoutes())), t.registerTool("get_live_components", {
|
|
697
2061
|
title: "Currently mounted components",
|
|
698
|
-
description: "Component instances with file, parent, mounted status as currently mounted in the browser.",
|
|
699
|
-
inputSchema: {
|
|
700
|
-
|
|
2062
|
+
description: "Component instances with file, parent, mounted status as currently mounted in the browser (an array, parents first). With `includeMeta: true` the answer is `{ epoch, total, captured, truncated, components }` instead, limited to `limit` (default 1000): component ids are only valid within that `epoch` (one page load), so pass both to get_reactive_scope.",
|
|
2063
|
+
inputSchema: {
|
|
2064
|
+
includeMeta: u.boolean().optional(),
|
|
2065
|
+
limit: u.number().int().min(1).max(5e4).optional()
|
|
2066
|
+
}
|
|
2067
|
+
}, async ({ includeMeta: t, limit: n }) => {
|
|
2068
|
+
if (!t || !e.getLiveSnapshot) {
|
|
2069
|
+
let t = e.getLiveComponents();
|
|
2070
|
+
return Z(n === void 0 ? t : t.slice(0, n));
|
|
2071
|
+
}
|
|
2072
|
+
let r = e.getLiveSnapshot(), i = n ?? 1e3;
|
|
2073
|
+
return Z({
|
|
2074
|
+
epoch: r.epoch,
|
|
2075
|
+
total: r.total,
|
|
2076
|
+
captured: r.components.length,
|
|
2077
|
+
truncated: r.total > r.components.length || r.components.length > i,
|
|
2078
|
+
components: r.components.slice(0, i)
|
|
2079
|
+
});
|
|
2080
|
+
}), t.registerTool("get_component_relations", {
|
|
701
2081
|
title: "Component import graph",
|
|
702
2082
|
description: "Static import relations between .svelte components.",
|
|
703
2083
|
inputSchema: {}
|
|
704
|
-
}, async () =>
|
|
2084
|
+
}, async () => Z(e.getComponentRelations())), e.getReactiveSummary) {
|
|
2085
|
+
let n = e.getReactiveSummary;
|
|
2086
|
+
t.registerTool("get_reactive_summary", {
|
|
2087
|
+
title: "Reactive overview (top components)",
|
|
2088
|
+
description: "Busiest component instances from runtime counters over all instances, without capturing the graph. Counts are sampled state changes (at most one per state per 200 ms) and renders within the window, not rates. Only state created during component init is tracked. `rows` + `other` add up to the totals; null means unknown. Use get_reactive_scope with a componentId to look at one instance. The same request is answered from a cache for up to 1 s; `window.until` says when the answer was computed.",
|
|
2089
|
+
inputSchema: {
|
|
2090
|
+
topK: u.number().int().min(1).max(200).optional(),
|
|
2091
|
+
windowMs: u.number().int().min(1e3).max(6e4).optional()
|
|
2092
|
+
}
|
|
2093
|
+
}, async ({ topK: e, windowMs: t }) => Z(await n({
|
|
2094
|
+
topK: e,
|
|
2095
|
+
windowMs: t
|
|
2096
|
+
})));
|
|
2097
|
+
}
|
|
2098
|
+
if (e.getReactiveScope) {
|
|
2099
|
+
let n = e.getReactiveScope;
|
|
2100
|
+
t.registerTool("get_reactive_scope", {
|
|
2101
|
+
title: "Reactive graph of one component",
|
|
2102
|
+
description: "$state/$derived/$effect nodes of one component instance and their direct neighbours, built in the app within the caps. Edges mean 'can affect' (current dependencies), not a recorded cause. `componentId` requires the `epoch` it came from (get_live_components with includeMeta): after a reload the answer is empty with staleReason 'epoch-changed' instead of another instance. Omit componentId only for the whole-app graph (capped; see total/truncated). The same request may be answered from a cache for up to 1 s; `computedAt` says when the app built the graph (null when unknown or for an empty fallback). `stale: true` only marks a fallback after the app did not answer (an earlier answer with its own computedAt, or empty).",
|
|
2103
|
+
inputSchema: {
|
|
2104
|
+
componentId: u.number().int().nonnegative().optional(),
|
|
2105
|
+
epoch: u.string().max(200).optional(),
|
|
2106
|
+
maxNodes: u.number().int().min(1).max(5e3).optional(),
|
|
2107
|
+
maxEdges: u.number().int().min(1).max(2e4).optional()
|
|
2108
|
+
}
|
|
2109
|
+
}, async ({ componentId: e, epoch: t, maxNodes: r, maxEdges: i }) => e !== void 0 && t === void 0 ? {
|
|
2110
|
+
content: [{
|
|
2111
|
+
type: "text",
|
|
2112
|
+
text: "componentId requires epoch (from get_live_components with includeMeta: true)"
|
|
2113
|
+
}],
|
|
2114
|
+
isError: !0
|
|
2115
|
+
} : Z(await n({
|
|
2116
|
+
componentId: e,
|
|
2117
|
+
epoch: t,
|
|
2118
|
+
maxNodes: r,
|
|
2119
|
+
maxEdges: i
|
|
2120
|
+
})));
|
|
2121
|
+
}
|
|
2122
|
+
if (e.getStateTimelineDelta) {
|
|
2123
|
+
let n = e.getStateTimelineDelta;
|
|
2124
|
+
t.registerTool("get_state_timeline", {
|
|
2125
|
+
title: "State changes since a cursor",
|
|
2126
|
+
description: "Sampled $state changes (200 ms) after `since` (the cursor from the previous call). Contains values of state in the running app. `reset: true` means the cursor was stale and this is the whole buffer. At most `limit` newest entries are returned; `omitted` counts older ones in the range that were left out. Values larger than `maxValueChars` (JSON) are replaced by a size summary. Timestamps are detection times, so order within about a second is not causal.",
|
|
2127
|
+
inputSchema: {
|
|
2128
|
+
since: u.number().int().nonnegative().optional(),
|
|
2129
|
+
limit: u.number().int().min(1).max(500).optional(),
|
|
2130
|
+
maxValueChars: u.number().int().min(16).max(J.max).optional()
|
|
2131
|
+
}
|
|
2132
|
+
}, async ({ since: e, limit: t, maxValueChars: r }) => {
|
|
2133
|
+
let i = n(e), a = t ?? 100, o = r ?? J.default, s = Math.max(0, i.changes.length - a), c = i.changes.slice(s).map((e) => ({
|
|
2134
|
+
...e,
|
|
2135
|
+
oldValue: Y(e.oldValue, o),
|
|
2136
|
+
newValue: Y(e.newValue, o)
|
|
2137
|
+
}));
|
|
2138
|
+
return Z({
|
|
2139
|
+
...i,
|
|
2140
|
+
changes: c,
|
|
2141
|
+
omitted: s,
|
|
2142
|
+
maxValueChars: o
|
|
2143
|
+
});
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
if (e.getCaptureInfo) {
|
|
2147
|
+
let n = e.getCaptureInfo;
|
|
2148
|
+
t.registerTool("get_capture_info", {
|
|
2149
|
+
title: "What the DevTools hold versus what the app reported",
|
|
2150
|
+
description: "Per dataset: captured count, total (null = unknown), truncated, selection policy and dropped counts by reason. Read this before drawing conclusions from capped data.",
|
|
2151
|
+
inputSchema: {}
|
|
2152
|
+
}, async () => Z(n()));
|
|
2153
|
+
}
|
|
2154
|
+
return t.registerTool("start_session", {
|
|
705
2155
|
title: "Start measurement session",
|
|
706
2156
|
description: "Begin capturing metrics under a labelled session. Required before compare_sessions. Set `persist:true` to write to disk on end; otherwise the session lives in memory only.",
|
|
707
2157
|
inputSchema: {
|
|
@@ -710,7 +2160,7 @@ function oe(e) {
|
|
|
710
2160
|
}
|
|
711
2161
|
}, async ({ label: t, persist: n = !1 }) => {
|
|
712
2162
|
let r = e.sessions.start(t, n);
|
|
713
|
-
return
|
|
2163
|
+
return Z({
|
|
714
2164
|
id: r.id,
|
|
715
2165
|
label: r.label,
|
|
716
2166
|
startedAt: r.startedAt,
|
|
@@ -726,7 +2176,7 @@ function oe(e) {
|
|
|
726
2176
|
]).optional() }
|
|
727
2177
|
}, async ({ keep: t = "memory" }) => {
|
|
728
2178
|
let n = e.sessions.end(t), r = n.endedAt ? e.sessions.delta(n.id) : null;
|
|
729
|
-
return
|
|
2179
|
+
return Z({
|
|
730
2180
|
id: n.id,
|
|
731
2181
|
label: n.label,
|
|
732
2182
|
startedAt: n.startedAt,
|
|
@@ -738,53 +2188,53 @@ function oe(e) {
|
|
|
738
2188
|
title: "Compare two sessions",
|
|
739
2189
|
description: "Diff render / load / fps metrics between two ended sessions. Each section carries `verdict`: improved | regressed | unchanged.",
|
|
740
2190
|
inputSchema: {
|
|
741
|
-
a:
|
|
742
|
-
b:
|
|
2191
|
+
a: X,
|
|
2192
|
+
b: X
|
|
743
2193
|
}
|
|
744
|
-
}, async ({ a: t, b: n }) =>
|
|
2194
|
+
}, async ({ a: t, b: n }) => Z(e.sessions.compare(t, n))), t.registerTool("list_sessions", {
|
|
745
2195
|
title: "List sessions",
|
|
746
2196
|
description: "In-memory + on-disk sessions, most recent first.",
|
|
747
2197
|
inputSchema: {}
|
|
748
|
-
}, async () =>
|
|
2198
|
+
}, async () => Z(e.sessions.list())), t.registerTool("load_session", {
|
|
749
2199
|
title: "Load a session by id",
|
|
750
2200
|
description: "Returns the full session record (including delta if ended) by id.",
|
|
751
|
-
inputSchema: { id:
|
|
2201
|
+
inputSchema: { id: X }
|
|
752
2202
|
}, async ({ id: t }) => {
|
|
753
2203
|
let n = e.sessions.get(t);
|
|
754
|
-
if (!n) return
|
|
2204
|
+
if (!n) return Z({ error: `Session not found: ${t}` });
|
|
755
2205
|
let r = n.endedAt ? e.sessions.delta(t) : null;
|
|
756
|
-
return
|
|
2206
|
+
return Z({
|
|
757
2207
|
...n,
|
|
758
2208
|
delta: r
|
|
759
2209
|
});
|
|
760
2210
|
}), t.registerTool("delete_session", {
|
|
761
2211
|
title: "Delete a session",
|
|
762
2212
|
description: "Removes a session from memory and disk.",
|
|
763
|
-
inputSchema: { id:
|
|
764
|
-
}, async ({ id: t }) =>
|
|
2213
|
+
inputSchema: { id: X }
|
|
2214
|
+
}, async ({ id: t }) => Z({ deleted: e.sessions.delete(t) })), t;
|
|
765
2215
|
}
|
|
766
|
-
function
|
|
2216
|
+
function rt(e) {
|
|
767
2217
|
return e.length ? e.reduce((e, t) => e + t, 0) / e.length : 0;
|
|
768
2218
|
}
|
|
769
|
-
function
|
|
2219
|
+
function Q(e) {
|
|
770
2220
|
return Math.round(e * 100) / 100;
|
|
771
2221
|
}
|
|
772
|
-
var
|
|
773
|
-
function
|
|
774
|
-
if (!e.includes("templates: {") || !e.includes(
|
|
775
|
-
let t = e.indexOf(
|
|
776
|
-
return n === -1 ? null : e.slice(0, n) +
|
|
2222
|
+
var it = [".svelte-kit/generated/server/internal.js", ".svelte-kit/generated/dev/server.js"], at = "templates: {", ot = `${ne}embedded.js`, st = `<script type=\\"module\\" src=\\"${ot}\\"><\/script>`, ct = "</body>";
|
|
2223
|
+
function lt(e) {
|
|
2224
|
+
if (!e.includes("templates: {") || !e.includes(ct) || e.includes(ot)) return null;
|
|
2225
|
+
let t = e.indexOf(at), n = e.indexOf(ct, t);
|
|
2226
|
+
return n === -1 ? null : e.slice(0, n) + st + e.slice(n);
|
|
777
2227
|
}
|
|
778
|
-
function
|
|
2228
|
+
function ut(e) {
|
|
779
2229
|
return {
|
|
780
2230
|
name: "vite-devtools-svelte:sveltekit-template-injector",
|
|
781
2231
|
enforce: "post",
|
|
782
2232
|
apply: (e, t) => t.command === "serve" && !t.isSsrBuild,
|
|
783
|
-
transform(
|
|
784
|
-
if (!
|
|
785
|
-
let
|
|
786
|
-
if (
|
|
787
|
-
code:
|
|
2233
|
+
transform(t, n) {
|
|
2234
|
+
if (!it.some((e) => n.endsWith(e)) || !e()) return;
|
|
2235
|
+
let r = lt(t);
|
|
2236
|
+
if (r !== null) return {
|
|
2237
|
+
code: r,
|
|
788
2238
|
map: null
|
|
789
2239
|
};
|
|
790
2240
|
}
|
|
@@ -792,582 +2242,158 @@ function de() {
|
|
|
792
2242
|
}
|
|
793
2243
|
//#endregion
|
|
794
2244
|
//#region src/plugin.ts
|
|
795
|
-
var
|
|
796
|
-
function
|
|
797
|
-
let t;
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
throw Error(`Invalid URL: ${e}`);
|
|
2245
|
+
var dt = "vite:devtools", $ = Symbol.for("vite-devtools-svelte:warn-sink"), ft = 0;
|
|
2246
|
+
function pt(e) {
|
|
2247
|
+
let t = [];
|
|
2248
|
+
for (let n of Object.values(e.environments ?? {})) {
|
|
2249
|
+
let e = n.moduleGraph;
|
|
2250
|
+
e?.idToModuleMap && t.push(...e.idToModuleMap.values());
|
|
802
2251
|
}
|
|
803
|
-
if (t.
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
if (n.isIP(r)) {
|
|
807
|
-
if (fe(r)) throw Error(`Blocked: private IP address ${r}`);
|
|
808
|
-
} else {
|
|
809
|
-
let e = r.toLowerCase();
|
|
810
|
-
if (e === "localhost" || e.endsWith(".local") || e.endsWith(".internal")) throw Error(`Blocked: internal hostname ${r}`);
|
|
2252
|
+
if (t.length === 0) {
|
|
2253
|
+
let n = e.moduleGraph;
|
|
2254
|
+
n?.idToModuleMap && t.push(...n.idToModuleMap.values());
|
|
811
2255
|
}
|
|
2256
|
+
return t;
|
|
812
2257
|
}
|
|
813
|
-
function
|
|
814
|
-
let
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
let { componentTracking: i = !0 } = n, o, s, c, u = r.randomUUID();
|
|
819
|
-
function f(n) {
|
|
820
|
-
if (typeof n != "string" || n.length === 0) throw Error("Invalid file path");
|
|
821
|
-
let r = t.realpathSync(c), i = e.isAbsolute(n) ? n : e.resolve(c, n), a;
|
|
822
|
-
try {
|
|
823
|
-
a = t.realpathSync(i);
|
|
824
|
-
} catch {
|
|
825
|
-
throw Error("File not found");
|
|
826
|
-
}
|
|
827
|
-
if (a !== r && !a.startsWith(r + e.sep)) throw Error("Forbidden: path outside project root");
|
|
828
|
-
return a;
|
|
829
|
-
}
|
|
830
|
-
let p = [], m = [], h = [], v = {
|
|
831
|
-
nodes: [],
|
|
832
|
-
edges: []
|
|
833
|
-
}, y = [], b = [], x = [], S = [], w = [], T = [], E = null;
|
|
834
|
-
function D() {
|
|
835
|
-
return E ||= new te({
|
|
836
|
-
persistDir: e.join(c, "node_modules", ".vite-devtools-svelte", "sessions"),
|
|
2258
|
+
function mt(r = {}) {
|
|
2259
|
+
let { componentTracking: i = !0 } = r, a, o, s, c = !1, l = t.randomUUID(), u = null;
|
|
2260
|
+
function d() {
|
|
2261
|
+
return u ||= new Ze({
|
|
2262
|
+
persistDir: e.join(s, "node_modules", ".vite-devtools-svelte", "sessions"),
|
|
837
2263
|
getters: {
|
|
838
|
-
getRenderProfiles: () =>
|
|
839
|
-
getLoadProfiles: () =>
|
|
840
|
-
getFpsSamples: () =>
|
|
2264
|
+
getRenderProfiles: () => f.renderProfiles,
|
|
2265
|
+
getLoadProfiles: () => f.loadProfiles,
|
|
2266
|
+
getFpsSamples: () => f.fpsSamples
|
|
841
2267
|
}
|
|
842
|
-
}),
|
|
843
|
-
}
|
|
844
|
-
let
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
2268
|
+
}), u;
|
|
2269
|
+
}
|
|
2270
|
+
let f = new we({
|
|
2271
|
+
onFpsSample: (e) => d().recordFpsSample(e),
|
|
2272
|
+
onLoadProfile: (e) => d().recordLoadProfile(e)
|
|
2273
|
+
}), p = Ve({
|
|
2274
|
+
collector: f,
|
|
2275
|
+
root: () => s,
|
|
2276
|
+
publicBase: () => a?.base ?? "/",
|
|
2277
|
+
modules: () => o ? pt(o) : [],
|
|
2278
|
+
transformRequest: (e) => o ? o.transformRequest(e) : Promise.resolve(null),
|
|
2279
|
+
serverOrigins: () => {
|
|
2280
|
+
let e = o?.resolvedUrls;
|
|
2281
|
+
return e ? [...e.local, ...e.network].map((e) => new URL(e).origin) : [];
|
|
2282
|
+
},
|
|
2283
|
+
openInEditor: (e) => n(e)
|
|
2284
|
+
}), m = [];
|
|
2285
|
+
return [
|
|
2286
|
+
{
|
|
2287
|
+
name: "vite-devtools-svelte",
|
|
2288
|
+
enforce: "pre",
|
|
2289
|
+
apply: "serve",
|
|
2290
|
+
api: { getDevtoolsToken: () => l },
|
|
2291
|
+
configResolved(e) {
|
|
2292
|
+
a = e, s = a.root, c = a.plugins.some((e) => e.name === dt);
|
|
855
2293
|
},
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
2294
|
+
configureServer(e) {
|
|
2295
|
+
o = e;
|
|
2296
|
+
let t = ++ft;
|
|
2297
|
+
if (f.attach(e.hot), e.httpServer?.once("close", () => {
|
|
2298
|
+
o === e && (f.detach(), o = void 0);
|
|
2299
|
+
}), !c) {
|
|
2300
|
+
let n = Ke(e, p);
|
|
2301
|
+
n && m.push({
|
|
2302
|
+
generation: t,
|
|
2303
|
+
dispose: n
|
|
2304
|
+
});
|
|
2305
|
+
}
|
|
2306
|
+
let n = () => nt({
|
|
2307
|
+
getProject: () => v(s),
|
|
2308
|
+
getRoutes: () => re(v(s).routesDir),
|
|
2309
|
+
getLiveComponents: () => f.liveComponents,
|
|
2310
|
+
getLiveSnapshot: () => f.liveSnapshot,
|
|
2311
|
+
getComponentRelations: () => b(s),
|
|
2312
|
+
getRenderProfiles: () => f.renderProfiles,
|
|
2313
|
+
getReactiveGraph: () => f.requestReactiveGraph(),
|
|
2314
|
+
getLoadProfiles: () => f.loadProfiles,
|
|
2315
|
+
getFpsSamples: () => f.fpsSamples,
|
|
2316
|
+
sessions: d(),
|
|
2317
|
+
getReactiveSummary: (e) => f.requestReactiveSummary(e),
|
|
2318
|
+
getReactiveScope: (e) => f.requestReactiveGraph(e),
|
|
2319
|
+
getStateTimelineDelta: (e) => f.getStateTimelineDelta(e),
|
|
2320
|
+
getCaptureInfo: () => f.getCaptureInfo()
|
|
2321
|
+
});
|
|
2322
|
+
e.httpServer?.once("listening", () => {
|
|
2323
|
+
try {
|
|
2324
|
+
let t = e.httpServer?.address();
|
|
2325
|
+
if (!t || typeof t == "string") return;
|
|
2326
|
+
let n = `claude mcp add --transport http svelte ${`${e.config.server?.https ? "https" : "http"}://${t.address === "::" || t.address === "0.0.0.0" || t.address === "::1" || t.address === "127.0.0.1" ? "localhost" : t.family === "IPv6" ? `[${t.address}]` : t.address}:${t.port}/__svelte-devtools/mcp`} --header x-svelte-devtools-token:${l}`;
|
|
2327
|
+
e.config.logger.info(""), e.config.logger.info(" svelte-devtools MCP ready — register with Claude Code:"), e.config.logger.info(` ${n}`), e.config.logger.info("");
|
|
2328
|
+
} catch {}
|
|
2329
|
+
}), e.middlewares.use("/__svelte-devtools/mcp", async (t, r) => {
|
|
2330
|
+
let i = t.headers["x-svelte-devtools-token"];
|
|
2331
|
+
if ((Array.isArray(i) ? i[0] : i) !== l) {
|
|
2332
|
+
r.statusCode = 403, r.end("Forbidden");
|
|
2333
|
+
return;
|
|
871
2334
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
h = [];
|
|
2335
|
+
f.lease("mcp", 6e4) && await f.waitForSnapshot(1e3);
|
|
2336
|
+
let a = n(), o = new te({
|
|
2337
|
+
sessionIdGenerator: void 0,
|
|
2338
|
+
enableJsonResponse: !0
|
|
2339
|
+
});
|
|
2340
|
+
o.onerror = (t) => {
|
|
2341
|
+
e.config.logger.error(`[svelte-devtools] MCP transport error: ${t.stack || t.message}`);
|
|
2342
|
+
};
|
|
2343
|
+
try {
|
|
2344
|
+
await a.connect(o), await o.handleRequest(t, r);
|
|
2345
|
+
} catch (t) {
|
|
2346
|
+
e.config.logger.error(`[svelte-devtools] MCP handler error: ${t instanceof Error ? t.stack || t.message : String(t)}`), r.headersSent || (r.statusCode = 500, r.setHeader("Content-Type", "application/json"), r.end(JSON.stringify({ error: String(t) })));
|
|
2347
|
+
} finally {
|
|
2348
|
+
await o.close().catch(() => {}), await a.close().catch(() => {});
|
|
2349
|
+
}
|
|
2350
|
+
});
|
|
889
2351
|
},
|
|
890
|
-
|
|
891
|
-
let t =
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
t = !0;
|
|
895
|
-
let r = x.indexOf(n);
|
|
896
|
-
r !== -1 && x.splice(r, 1), e(b);
|
|
897
|
-
}, 1e3);
|
|
898
|
-
x.push(n);
|
|
899
|
-
})) : b,
|
|
900
|
-
"svelte-devtools:clear-state-timeline": async () => {
|
|
901
|
-
b = [], s?.hot.send("svelte-devtools:clear-state-timeline", {});
|
|
2352
|
+
async closeServer({ reason: e }) {
|
|
2353
|
+
let t = m.filter((t) => e === "close" || t.generation < ft);
|
|
2354
|
+
for (let e of t) m.splice(m.indexOf(e), 1);
|
|
2355
|
+
await Promise.all(t.map((e) => e.dispose()));
|
|
902
2356
|
},
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
if (e) {
|
|
908
|
-
let i = "";
|
|
909
|
-
try {
|
|
910
|
-
i = t.readFileSync(e.path, "utf-8");
|
|
911
|
-
} catch {}
|
|
912
|
-
let a = [];
|
|
913
|
-
for (let e of [
|
|
914
|
-
"GET",
|
|
915
|
-
"POST",
|
|
916
|
-
"PUT",
|
|
917
|
-
"PATCH",
|
|
918
|
-
"DELETE"
|
|
919
|
-
]) (i.includes(`export const ${e}`) || i.includes(`export async function ${e}`) || i.includes(`export function ${e}`)) && a.push(e);
|
|
920
|
-
a.length === 0 && a.push("GET"), n.push({
|
|
921
|
-
route: r.id,
|
|
922
|
-
path: r.path,
|
|
923
|
-
methods: a,
|
|
924
|
-
file: e.path
|
|
925
|
-
});
|
|
926
|
-
}
|
|
2357
|
+
resolveId(e, t) {
|
|
2358
|
+
if (a?.command === "serve") {
|
|
2359
|
+
if (e === "virtual:svelte-devtools-runtime") return ge;
|
|
2360
|
+
if (i && e === "svelte/internal/client" && t && !t.includes("node_modules") && !t.startsWith("\0")) return _e;
|
|
927
2361
|
}
|
|
928
|
-
return n;
|
|
929
2362
|
},
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
let a = n ? JSON.parse(String(n)) : {}, o = {
|
|
935
|
-
method: String(t),
|
|
936
|
-
headers: a
|
|
937
|
-
};
|
|
938
|
-
r && String(t) !== "GET" && String(t) !== "HEAD" && (o.body = String(r));
|
|
939
|
-
let s = await fetch(String(e), o), c = await s.text(), l = {};
|
|
940
|
-
return s.headers.forEach((e, t) => {
|
|
941
|
-
l[t] = e;
|
|
942
|
-
}), {
|
|
943
|
-
status: s.status,
|
|
944
|
-
statusText: s.statusText,
|
|
945
|
-
headers: l,
|
|
946
|
-
body: c,
|
|
947
|
-
duration: Math.round((performance.now() - i) * 100) / 100
|
|
948
|
-
};
|
|
949
|
-
} catch (e) {
|
|
950
|
-
return {
|
|
951
|
-
status: 0,
|
|
952
|
-
statusText: String(e),
|
|
953
|
-
headers: {},
|
|
954
|
-
body: "",
|
|
955
|
-
duration: Math.round((performance.now() - i) * 100) / 100
|
|
956
|
-
};
|
|
2363
|
+
load(e) {
|
|
2364
|
+
if (a?.command === "serve") {
|
|
2365
|
+
if (e === "\0virtual:svelte-devtools-runtime") return ye;
|
|
2366
|
+
if (e === "\0svelte-devtools:wrapped-client") return ve;
|
|
957
2367
|
}
|
|
958
2368
|
},
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
2369
|
+
transformIndexHtml() {
|
|
2370
|
+
return a.command === "serve" ? [{
|
|
2371
|
+
tag: "script",
|
|
2372
|
+
attrs: { type: "module" },
|
|
2373
|
+
children: `import '${S}'`,
|
|
2374
|
+
injectTo: "head-prepend"
|
|
2375
|
+
}] : [];
|
|
963
2376
|
},
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
} catch {
|
|
973
|
-
return {
|
|
974
|
-
source: "",
|
|
975
|
-
compiled: "",
|
|
976
|
-
file: n
|
|
977
|
-
};
|
|
2377
|
+
devtools: {
|
|
2378
|
+
capabilities: {
|
|
2379
|
+
dev: !0,
|
|
2380
|
+
build: !1
|
|
2381
|
+
},
|
|
2382
|
+
async setup(e) {
|
|
2383
|
+
let { createPluginFromDevframe: t } = await import("@vitejs/devtools-kit/node");
|
|
2384
|
+
await t(p, { base: L }).devtools?.setup?.(e);
|
|
978
2385
|
}
|
|
979
|
-
let i = "";
|
|
980
|
-
try {
|
|
981
|
-
i = t.readFileSync(r, "utf-8");
|
|
982
|
-
} catch {
|
|
983
|
-
return {
|
|
984
|
-
source: "",
|
|
985
|
-
compiled: "",
|
|
986
|
-
file: n
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
|
-
let a = "", o, c;
|
|
990
|
-
if (s) try {
|
|
991
|
-
let e = await s.transformRequest(r);
|
|
992
|
-
if (a = e?.code || "", e?.map) {
|
|
993
|
-
let t = typeof e.map == "string" ? JSON.parse(e.map) : e.map;
|
|
994
|
-
o = t.mappings, c = t.sources;
|
|
995
|
-
}
|
|
996
|
-
} catch {
|
|
997
|
-
a = "// Transform failed";
|
|
998
|
-
}
|
|
999
|
-
return {
|
|
1000
|
-
source: i,
|
|
1001
|
-
compiled: a,
|
|
1002
|
-
file: n,
|
|
1003
|
-
mappings: o,
|
|
1004
|
-
sources: c
|
|
1005
|
-
};
|
|
1006
|
-
},
|
|
1007
|
-
"svelte-devtools:get-module-graph": async () => M(),
|
|
1008
|
-
"svelte-devtools:get-og-preview": async (e) => N(String(e)),
|
|
1009
|
-
"svelte-devtools:get-build-analysis": async () => R(),
|
|
1010
|
-
"svelte-devtools:get-fps": async () => T,
|
|
1011
|
-
"svelte-devtools:clear-fps": async () => {
|
|
1012
|
-
T = [];
|
|
1013
2386
|
}
|
|
1014
|
-
}, k);
|
|
1015
|
-
}
|
|
1016
|
-
let j = {
|
|
1017
|
-
name: "vite-devtools-svelte",
|
|
1018
|
-
enforce: "pre",
|
|
1019
|
-
api: { getDevtoolsToken: () => u },
|
|
1020
|
-
configResolved(e) {
|
|
1021
|
-
o = e, c = o.root;
|
|
1022
2387
|
},
|
|
1023
|
-
configureServer(n) {
|
|
1024
|
-
s = n;
|
|
1025
|
-
let r = 5e3, i = 2e4;
|
|
1026
|
-
s.hot.on("svelte-devtools:components", (e) => {
|
|
1027
|
-
let t = Array.isArray(e?.components) ? e.components : [];
|
|
1028
|
-
p = t.length > 5e3 ? t.slice(-5e3) : t;
|
|
1029
|
-
}), s.hot.on("svelte-devtools:profiles", (e) => {
|
|
1030
|
-
let t = Array.isArray(e?.profiles) ? e.profiles : [];
|
|
1031
|
-
m = t.length > 5e3 ? t.slice(-5e3) : t;
|
|
1032
|
-
}), s.hot.on("svelte-devtools:state-timeline", (e) => {
|
|
1033
|
-
let t = Array.isArray(e?.changes) ? e.changes : [];
|
|
1034
|
-
b = t.length > 500 ? t.slice(-500) : t;
|
|
1035
|
-
let n = x;
|
|
1036
|
-
x = [];
|
|
1037
|
-
for (let e of n) e(b);
|
|
1038
|
-
}), s.hot.on("svelte-devtools:fps", (e) => {
|
|
1039
|
-
T.push(e), T.length > 1200 && (T = T.slice(-1200)), D().recordFpsSample(e);
|
|
1040
|
-
}), s.hot.on("svelte-devtools:runtime-error", (e) => {
|
|
1041
|
-
w.push(e), w.length > 200 && (w = w.slice(-200));
|
|
1042
|
-
}), s.hot.on("svelte-devtools:reactive-graph", (e) => {
|
|
1043
|
-
let t = Array.isArray(e?.nodes) ? e.nodes : [], n = Array.isArray(e?.edges) ? e.edges : [];
|
|
1044
|
-
v = {
|
|
1045
|
-
nodes: t.length > r ? t.slice(0, r) : t,
|
|
1046
|
-
edges: n.length > i ? n.slice(0, i) : n
|
|
1047
|
-
};
|
|
1048
|
-
let a = y;
|
|
1049
|
-
y = [];
|
|
1050
|
-
for (let e of a) e(v);
|
|
1051
|
-
});
|
|
1052
|
-
let a = () => {
|
|
1053
|
-
let e = /* @__PURE__ */ new Set(), t = s?.config?.server ?? o?.server, n = t?.port ?? 5173, r = t?.https ? "https" : "http";
|
|
1054
|
-
for (let t of [
|
|
1055
|
-
"localhost",
|
|
1056
|
-
"127.0.0.1",
|
|
1057
|
-
"[::1]"
|
|
1058
|
-
]) e.add(`${r}://${t}`), e.add(`${r}://${t}:${n}`);
|
|
1059
|
-
return e;
|
|
1060
|
-
}, f = (e) => {
|
|
1061
|
-
let t = a(), n = e.headers.origin, r = e.headers.referer, i = (() => {
|
|
1062
|
-
if (typeof n == "string" && n) return n;
|
|
1063
|
-
if (typeof r == "string" && r) try {
|
|
1064
|
-
return new URL(r).origin;
|
|
1065
|
-
} catch {
|
|
1066
|
-
return null;
|
|
1067
|
-
}
|
|
1068
|
-
return null;
|
|
1069
|
-
})();
|
|
1070
|
-
if (i !== null && !t.has(i)) return !1;
|
|
1071
|
-
let o = e.headers["x-svelte-devtools-token"];
|
|
1072
|
-
return (Array.isArray(o) ? o[0] : o) === u;
|
|
1073
|
-
}, _ = e.resolve(Q, "client");
|
|
1074
|
-
s.middlewares.use("/.svelte-devtools", (n, r, i) => {
|
|
1075
|
-
let a = (n.url || "/").split("?")[0], o = a === "/" || a === "" || a === "/index.html", s = o ? e.join(_, "index.html") : e.join(_, a);
|
|
1076
|
-
try {
|
|
1077
|
-
if (t.statSync(s).isFile()) {
|
|
1078
|
-
let n = e.extname(s).toLowerCase();
|
|
1079
|
-
if (r.setHeader("Content-Type", g[n] || "application/octet-stream"), o) {
|
|
1080
|
-
let e = t.readFileSync(s, "utf-8"), n = `<meta name="svelte-devtools-token" content="${u}">`, i = e.includes("</head>") ? e.replace("</head>", ` ${n}\n</head>`) : `${n}\n${e}`;
|
|
1081
|
-
r.end(i);
|
|
1082
|
-
} else t.createReadStream(s).pipe(r);
|
|
1083
|
-
return;
|
|
1084
|
-
}
|
|
1085
|
-
} catch {}
|
|
1086
|
-
i();
|
|
1087
|
-
}), s.middlewares.use("/__svelte-devtools/rpc", (e, t) => {
|
|
1088
|
-
if (e.method !== "POST") {
|
|
1089
|
-
t.statusCode = 405, t.end("Method not allowed");
|
|
1090
|
-
return;
|
|
1091
|
-
}
|
|
1092
|
-
if (!f(e)) {
|
|
1093
|
-
t.statusCode = 403, t.end("Forbidden");
|
|
1094
|
-
return;
|
|
1095
|
-
}
|
|
1096
|
-
let n = e.headers["content-type"], r = Array.isArray(n) ? n[0] : n;
|
|
1097
|
-
if (!r || !r.includes("application/json")) {
|
|
1098
|
-
t.statusCode = 415, t.end("Unsupported Media Type");
|
|
1099
|
-
return;
|
|
1100
|
-
}
|
|
1101
|
-
let i = "", a = !1;
|
|
1102
|
-
e.on("data", (e) => {
|
|
1103
|
-
a || (i += e.toString(), i.length > 1e6 && (a = !0, t.statusCode = 413, t.end("Payload Too Large")));
|
|
1104
|
-
}), e.on("end", async () => {
|
|
1105
|
-
if (!a) try {
|
|
1106
|
-
let { method: e, args: n } = JSON.parse(i), r = A()[e];
|
|
1107
|
-
if (!r) throw Error(`Unknown RPC method: ${e}`);
|
|
1108
|
-
let a = await r(...n);
|
|
1109
|
-
t.setHeader("Content-Type", "application/json"), t.end(JSON.stringify(a));
|
|
1110
|
-
} catch (e) {
|
|
1111
|
-
t.statusCode = 500, t.end(JSON.stringify({ error: String(e) }));
|
|
1112
|
-
}
|
|
1113
|
-
});
|
|
1114
|
-
}), s.middlewares.use("/__svelte-devtools/asset", (n, r) => {
|
|
1115
|
-
if (!f(n)) {
|
|
1116
|
-
r.statusCode = 403, r.end("Forbidden");
|
|
1117
|
-
return;
|
|
1118
|
-
}
|
|
1119
|
-
let i = n.url || "", a = i.indexOf("?"), o = a >= 0 ? i.slice(a) : "", s = new URLSearchParams(o).get("path");
|
|
1120
|
-
if (!s) {
|
|
1121
|
-
r.statusCode = 400, r.end("Missing path parameter");
|
|
1122
|
-
return;
|
|
1123
|
-
}
|
|
1124
|
-
let l = C(c), u = t.realpathSync(l.staticDir), d = e.resolve(s), p;
|
|
1125
|
-
try {
|
|
1126
|
-
p = t.realpathSync(d);
|
|
1127
|
-
} catch {
|
|
1128
|
-
r.statusCode = 404, r.end("Not found");
|
|
1129
|
-
return;
|
|
1130
|
-
}
|
|
1131
|
-
if (!p.startsWith(u + e.sep) && p !== u) {
|
|
1132
|
-
r.statusCode = 403, r.end("Forbidden");
|
|
1133
|
-
return;
|
|
1134
|
-
}
|
|
1135
|
-
try {
|
|
1136
|
-
if (!t.statSync(p).isFile()) throw Error("Not a file");
|
|
1137
|
-
let n = e.extname(p).toLowerCase();
|
|
1138
|
-
r.setHeader("Content-Type", g[n] || "application/octet-stream"), t.createReadStream(p).pipe(r);
|
|
1139
|
-
} catch {
|
|
1140
|
-
r.statusCode = 404, r.end("Not found");
|
|
1141
|
-
}
|
|
1142
|
-
});
|
|
1143
|
-
let S = () => oe({
|
|
1144
|
-
getProject: () => C(c),
|
|
1145
|
-
getRoutes: () => d(C(c).routesDir),
|
|
1146
|
-
getLiveComponents: () => p,
|
|
1147
|
-
getComponentRelations: () => O(c),
|
|
1148
|
-
getRenderProfiles: () => m,
|
|
1149
|
-
getReactiveGraph: () => A()["svelte-devtools:get-reactive-graph"](),
|
|
1150
|
-
getLoadProfiles: () => h,
|
|
1151
|
-
getFpsSamples: () => T,
|
|
1152
|
-
sessions: D()
|
|
1153
|
-
});
|
|
1154
|
-
n.httpServer?.once("listening", () => {
|
|
1155
|
-
try {
|
|
1156
|
-
let e = n.httpServer?.address();
|
|
1157
|
-
if (!e || typeof e == "string") return;
|
|
1158
|
-
let t = `claude mcp add --transport http svelte ${`${n.config.server?.https ? "https" : "http"}://${e.address === "::" || e.address === "0.0.0.0" || e.address === "::1" || e.address === "127.0.0.1" ? "localhost" : e.family === "IPv6" ? `[${e.address}]` : e.address}:${e.port}/__svelte-devtools/mcp`} --header x-svelte-devtools-token:${u}`;
|
|
1159
|
-
n.config.logger.info(""), n.config.logger.info(" svelte-devtools MCP ready — register with Claude Code:"), n.config.logger.info(` ${t}`), n.config.logger.info("");
|
|
1160
|
-
} catch {}
|
|
1161
|
-
}), s.middlewares.use("/__svelte-devtools/mcp", async (e, t) => {
|
|
1162
|
-
let r = e.headers["x-svelte-devtools-token"];
|
|
1163
|
-
if ((Array.isArray(r) ? r[0] : r) !== u) {
|
|
1164
|
-
t.statusCode = 403, t.end("Forbidden");
|
|
1165
|
-
return;
|
|
1166
|
-
}
|
|
1167
|
-
let i = S(), a = new l({
|
|
1168
|
-
sessionIdGenerator: void 0,
|
|
1169
|
-
enableJsonResponse: !0
|
|
1170
|
-
});
|
|
1171
|
-
a.onerror = (e) => {
|
|
1172
|
-
n.config.logger.error(`[svelte-devtools] MCP transport error: ${e.stack || e.message}`);
|
|
1173
|
-
};
|
|
1174
|
-
try {
|
|
1175
|
-
await i.connect(a), await a.handleRequest(e, t);
|
|
1176
|
-
} catch (e) {
|
|
1177
|
-
n.config.logger.error(`[svelte-devtools] MCP handler error: ${e instanceof Error ? e.stack || e.message : String(e)}`), t.headersSent || (t.statusCode = 500, t.setHeader("Content-Type", "application/json"), t.end(JSON.stringify({ error: String(e) })));
|
|
1178
|
-
} finally {
|
|
1179
|
-
await a.close().catch(() => {}), await i.close().catch(() => {});
|
|
1180
|
-
}
|
|
1181
|
-
});
|
|
1182
|
-
},
|
|
1183
|
-
resolveId(e, t) {
|
|
1184
|
-
if (o?.command === "serve") {
|
|
1185
|
-
if (e === "virtual:svelte-devtools-runtime") return ee;
|
|
1186
|
-
if (i && e === "svelte/internal/client" && t && !t.includes("node_modules") && !t.startsWith("\0")) return F;
|
|
1187
|
-
}
|
|
1188
|
-
},
|
|
1189
|
-
load(e) {
|
|
1190
|
-
if (o?.command === "serve") {
|
|
1191
|
-
if (e === "\0virtual:svelte-devtools-runtime") return L;
|
|
1192
|
-
if (e === "\0svelte-devtools:wrapped-client") return I;
|
|
1193
|
-
}
|
|
1194
|
-
},
|
|
1195
|
-
transformIndexHtml() {
|
|
1196
|
-
return o.command === "serve" ? [{
|
|
1197
|
-
tag: "script",
|
|
1198
|
-
attrs: { type: "module" },
|
|
1199
|
-
children: `import '${P}'`,
|
|
1200
|
-
injectTo: "head-prepend"
|
|
1201
|
-
}] : [];
|
|
1202
|
-
},
|
|
1203
|
-
devtools: { setup(t) {
|
|
1204
|
-
let n = e.resolve(Q, "client");
|
|
1205
|
-
t.views.hostStatic("/.svelte-devtools/", n), t.docks.register({
|
|
1206
|
-
id: "svelte-devtools",
|
|
1207
|
-
title: "Svelte",
|
|
1208
|
-
icon: "simple-icons:svelte",
|
|
1209
|
-
type: "iframe",
|
|
1210
|
-
url: "/.svelte-devtools/",
|
|
1211
|
-
category: "framework"
|
|
1212
|
-
});
|
|
1213
|
-
let r = A();
|
|
1214
|
-
for (let [e, n] of Object.entries(r)) t.rpc.register({
|
|
1215
|
-
name: e,
|
|
1216
|
-
handler: n
|
|
1217
|
-
});
|
|
1218
|
-
} }
|
|
1219
|
-
};
|
|
1220
|
-
function M() {
|
|
1221
|
-
if (!s) return {
|
|
1222
|
-
modules: [],
|
|
1223
|
-
cycles: []
|
|
1224
|
-
};
|
|
1225
|
-
let n = [], r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map(), a = [];
|
|
1226
|
-
try {
|
|
1227
|
-
for (let e of Object.values(s.environments || {})) if (e && "moduleGraph" in e) {
|
|
1228
|
-
let t = e.moduleGraph;
|
|
1229
|
-
if (t?.idToModuleMap) for (let e of t.idToModuleMap.values()) a.push(e);
|
|
1230
|
-
}
|
|
1231
|
-
} catch {}
|
|
1232
|
-
if (a.length === 0) try {
|
|
1233
|
-
let e = s.moduleGraph;
|
|
1234
|
-
if (e?.idToModuleMap) for (let t of e.idToModuleMap.values()) a.push(t);
|
|
1235
|
-
} catch {}
|
|
1236
|
-
for (let o of a) {
|
|
1237
|
-
if (!o.file || o.file.includes("node_modules")) continue;
|
|
1238
|
-
let a = e.relative(c, o.file);
|
|
1239
|
-
if (a.startsWith("..") || r.has(o.file)) continue;
|
|
1240
|
-
let s = e.extname(o.file).toLowerCase(), l = s === ".svelte" ? "svelte" : s === ".ts" || s === ".js" ? s === ".ts" ? "ts" : "js" : s === ".css" ? "css" : "other", u;
|
|
1241
|
-
try {
|
|
1242
|
-
u = t.statSync(o.file).size;
|
|
1243
|
-
} catch {}
|
|
1244
|
-
let d = {
|
|
1245
|
-
id: a,
|
|
1246
|
-
file: o.file,
|
|
1247
|
-
type: l,
|
|
1248
|
-
importedBy: [],
|
|
1249
|
-
imports: [],
|
|
1250
|
-
size: u
|
|
1251
|
-
};
|
|
1252
|
-
r.set(o.file, d), i.set(a, d), n.push(d);
|
|
1253
|
-
}
|
|
1254
|
-
for (let e of a) {
|
|
1255
|
-
if (!e.file || !r.has(e.file)) continue;
|
|
1256
|
-
let t = r.get(e.file), n = new Set(t.imports);
|
|
1257
|
-
for (let i of e.importedModules) if (i.file && r.has(i.file)) {
|
|
1258
|
-
let e = r.get(i.file), a = e.id;
|
|
1259
|
-
n.has(a) || (n.add(a), t.imports.push(a)), e.importedBy.includes(t.id) || e.importedBy.push(t.id);
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
let o = [], l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set(), d = [];
|
|
1263
|
-
function f(e) {
|
|
1264
|
-
if (u.has(e)) {
|
|
1265
|
-
let t = d.indexOf(e);
|
|
1266
|
-
if (t >= 0 && d.length - t > 0) {
|
|
1267
|
-
let n = d.slice(t).concat(e);
|
|
1268
|
-
n.length > 2 && o.push(n);
|
|
1269
|
-
}
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
if (l.has(e)) return;
|
|
1273
|
-
l.add(e), u.add(e), d.push(e);
|
|
1274
|
-
let t = i.get(e);
|
|
1275
|
-
if (t) for (let e of t.imports) f(e);
|
|
1276
|
-
d.pop(), u.delete(e);
|
|
1277
|
-
}
|
|
1278
|
-
for (let e of n) f(e.id);
|
|
1279
|
-
let p = new Set(o.flat());
|
|
1280
|
-
for (let e of n) p.has(e.id) && (e.isCyclic = !0);
|
|
1281
|
-
return {
|
|
1282
|
-
modules: n,
|
|
1283
|
-
cycles: o
|
|
1284
|
-
};
|
|
1285
|
-
}
|
|
1286
|
-
async function N(e) {
|
|
1287
|
-
let t = {
|
|
1288
|
-
url: e,
|
|
1289
|
-
title: "",
|
|
1290
|
-
description: "",
|
|
1291
|
-
image: "",
|
|
1292
|
-
tags: [],
|
|
1293
|
-
issues: []
|
|
1294
|
-
};
|
|
1295
|
-
try {
|
|
1296
|
-
$(e);
|
|
1297
|
-
let n = await (await fetch(e)).text(), r = /<meta\s+([^>]*?)\/?>/gi, i = /(?:property|name)=["']([^"']+)["']/, a = /content=["']([^"']+)["']/, o;
|
|
1298
|
-
for (; (o = r.exec(n)) !== null;) {
|
|
1299
|
-
let e = o[1], n = e.match(i), r = e.match(a);
|
|
1300
|
-
if (n && r) {
|
|
1301
|
-
let e = n[1], i = r[1];
|
|
1302
|
-
t.tags.push({
|
|
1303
|
-
property: e,
|
|
1304
|
-
content: i
|
|
1305
|
-
}), e === "og:title" ? t.title = i : e === "og:description" ? t.description = i : e === "og:image" && (t.image = i);
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
if (!t.title) {
|
|
1309
|
-
let e = n.match(/<title>([^<]+)<\/title>/i);
|
|
1310
|
-
e && (t.title = e[1]);
|
|
1311
|
-
}
|
|
1312
|
-
if (!t.description) {
|
|
1313
|
-
let e = t.tags.find((e) => e.property === "description");
|
|
1314
|
-
e && (t.description = e.content);
|
|
1315
|
-
}
|
|
1316
|
-
t.title || t.issues.push("Missing og:title or <title>"), t.description || t.issues.push("Missing og:description or meta description"), t.image || t.issues.push("Missing og:image"), t.tags.some((e) => e.property === "og:url") || t.issues.push("Missing og:url"), t.tags.some((e) => e.property === "og:type") || t.issues.push("Missing og:type");
|
|
1317
|
-
} catch (e) {
|
|
1318
|
-
t.issues.push(`Failed to fetch: ${String(e)}`);
|
|
1319
|
-
}
|
|
1320
|
-
return t;
|
|
1321
|
-
}
|
|
1322
|
-
function R() {
|
|
1323
|
-
let n = e.resolve(c, ".svelte-kit/output"), r = e.resolve(c, "build/client"), i = [];
|
|
1324
|
-
for (let a of [
|
|
1325
|
-
n,
|
|
1326
|
-
r,
|
|
1327
|
-
e.resolve(c, "build")
|
|
1328
|
-
]) try {
|
|
1329
|
-
let n = (r) => {
|
|
1330
|
-
for (let a of t.readdirSync(r, { withFileTypes: !0 })) {
|
|
1331
|
-
let o = e.join(r, a.name);
|
|
1332
|
-
if (a.isDirectory()) {
|
|
1333
|
-
n(o);
|
|
1334
|
-
continue;
|
|
1335
|
-
}
|
|
1336
|
-
let s = e.extname(a.name).toLowerCase();
|
|
1337
|
-
if ([
|
|
1338
|
-
".js",
|
|
1339
|
-
".css",
|
|
1340
|
-
".html"
|
|
1341
|
-
].includes(s)) {
|
|
1342
|
-
let n = t.statSync(o);
|
|
1343
|
-
i.push({
|
|
1344
|
-
name: a.name,
|
|
1345
|
-
file: e.relative(c, o),
|
|
1346
|
-
size: n.size,
|
|
1347
|
-
modules: [],
|
|
1348
|
-
isEntry: a.name.includes("index") || a.name.includes("start")
|
|
1349
|
-
});
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
};
|
|
1353
|
-
n(a);
|
|
1354
|
-
} catch {}
|
|
1355
|
-
return i.sort((e, t) => t.size - e.size), {
|
|
1356
|
-
chunks: i,
|
|
1357
|
-
totalSize: i.reduce((e, t) => e + t.size, 0),
|
|
1358
|
-
timestamp: Date.now()
|
|
1359
|
-
};
|
|
1360
|
-
}
|
|
1361
|
-
return [
|
|
1362
|
-
j,
|
|
1363
2388
|
{
|
|
1364
2389
|
name: "vite-devtools-svelte:tracking",
|
|
1365
2390
|
enforce: "post",
|
|
2391
|
+
apply: "serve",
|
|
1366
2392
|
transform(e, t) {
|
|
1367
|
-
if (!i || !t.endsWith(".svelte") || t.includes("node_modules") ||
|
|
2393
|
+
if (!i || !t.endsWith(".svelte") || t.includes("node_modules") || a?.command !== "serve" || !e.includes("$.push(")) return null;
|
|
1368
2394
|
let n = JSON.stringify(t);
|
|
1369
2395
|
return {
|
|
1370
|
-
code: `import '${
|
|
2396
|
+
code: `import '${S}';\n` + e.replace(/(\$\.push\([^)]+\);?)/, `if (typeof window !== 'undefined' && window.__SVELTE_DEVTOOLS__) { window.__SVELTE_DEVTOOLS__._pendingFile = ${n}; }\n$1`),
|
|
1371
2397
|
map: null
|
|
1372
2398
|
};
|
|
1373
2399
|
}
|
|
@@ -1375,11 +2401,12 @@ function pe(n = {}) {
|
|
|
1375
2401
|
{
|
|
1376
2402
|
name: "vite-devtools-svelte:load-profile",
|
|
1377
2403
|
enforce: "post",
|
|
2404
|
+
apply: "serve",
|
|
1378
2405
|
transform(e, t) {
|
|
1379
|
-
if (
|
|
2406
|
+
if (a?.command !== "serve") return null;
|
|
1380
2407
|
let n = /\+page\.server\.[tj]s$/.test(t) || /\+layout\.server\.[tj]s$/.test(t), r = /\+(page|layout)\.[tj]s$/.test(t) && !t.includes(".server.");
|
|
1381
2408
|
if (!n && !r || t.includes("node_modules") || !e.includes("export") || !e.includes("load")) return null;
|
|
1382
|
-
let i = n ? "server" : "universal",
|
|
2409
|
+
let i = n ? "server" : "universal", o = t.match(/routes(.*)\/\+/), s = o && o[1] || "/", c = JSON.stringify(s), l = JSON.stringify(t), u = JSON.stringify(i), d = e.replace(/export\s+const\s+load\s*=\s*/, "const __original_load = ");
|
|
1383
2410
|
if (d === e && (d = e.replace(/export\s+(async\s+)?function\s+load\s*\(/, "const __original_load = $1function __load_impl(")), d === e) return null;
|
|
1384
2411
|
let f = `
|
|
1385
2412
|
export const load = async (event) => {
|
|
@@ -1401,6 +2428,7 @@ export const load = async (event) => {
|
|
|
1401
2428
|
},
|
|
1402
2429
|
{
|
|
1403
2430
|
name: "vite-devtools-svelte:load-profile-server",
|
|
2431
|
+
apply: "serve",
|
|
1404
2432
|
configureServer() {
|
|
1405
2433
|
globalThis.__svelte_devtools_record_load = (e, t, n, r, i) => {
|
|
1406
2434
|
let a = {
|
|
@@ -1411,34 +2439,37 @@ export const load = async (event) => {
|
|
|
1411
2439
|
dataSize: i,
|
|
1412
2440
|
timestamp: Date.now()
|
|
1413
2441
|
};
|
|
1414
|
-
|
|
2442
|
+
f.recordLoadProfile(a);
|
|
1415
2443
|
};
|
|
1416
2444
|
}
|
|
1417
2445
|
},
|
|
1418
2446
|
{
|
|
1419
2447
|
name: "vite-devtools-svelte:warning-capture",
|
|
1420
2448
|
enforce: "post",
|
|
2449
|
+
apply: "serve",
|
|
1421
2450
|
configResolved(e) {
|
|
1422
|
-
let t = e.logger
|
|
1423
|
-
|
|
1424
|
-
if (e.includes(".svelte")
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
2451
|
+
let t = e.logger, n = $ in t;
|
|
2452
|
+
if (t[$] = (e) => {
|
|
2453
|
+
if (!e.includes(".svelte") || a?.command !== "serve") return;
|
|
2454
|
+
let t = e.match(/(?:^|\s)((?:\/|\.\/|\w:)[^\s:]+\.svelte)(?::(\d+):(\d+))?/), n = e.match(/\(([a-z0-9_-]+)\)/);
|
|
2455
|
+
f.recordCompilerWarning({
|
|
2456
|
+
code: n?.[1] || "unknown",
|
|
2457
|
+
message: e.replace(/\x1b\[[0-9;]*m/g, "").trim(),
|
|
2458
|
+
file: t?.[1] || "",
|
|
2459
|
+
line: t?.[2] ? parseInt(t[2]) : void 0,
|
|
2460
|
+
column: t?.[3] ? parseInt(t[3]) : void 0
|
|
2461
|
+
});
|
|
2462
|
+
}, n) return;
|
|
2463
|
+
let r = t.warn;
|
|
2464
|
+
t.warn = (e, n) => {
|
|
2465
|
+
t[$]?.(e), r(e, n);
|
|
1435
2466
|
};
|
|
1436
2467
|
}
|
|
1437
2468
|
},
|
|
1438
|
-
|
|
2469
|
+
ut(() => c)
|
|
1439
2470
|
];
|
|
1440
2471
|
}
|
|
1441
2472
|
//#endregion
|
|
1442
|
-
export {
|
|
2473
|
+
export { mt as svelteDevtools };
|
|
1443
2474
|
|
|
1444
2475
|
//# sourceMappingURL=index.mjs.map
|