vite-devtools-svelte 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/README.md +17 -5
  2. package/dist/analyzers/api.d.ts +17 -4
  3. package/dist/analyzers/assets.d.ts +0 -1
  4. package/dist/analyzers/build.d.ts +7 -1
  5. package/dist/analyzers/html.d.ts +24 -0
  6. package/dist/analyzers/http.d.ts +9 -0
  7. package/dist/analyzers/module-graph.d.ts +9 -0
  8. package/dist/analyzers/og.d.ts +18 -4
  9. package/dist/analyzers/project.d.ts +1 -0
  10. package/dist/analyzers/routes.d.ts +22 -1
  11. package/dist/analyzers/script.d.ts +26 -0
  12. package/dist/analyzers/source.d.ts +8 -3
  13. package/dist/analyzers/text.d.ts +6 -0
  14. package/dist/client/assets/ApiPlayground-r3PMCbhw.js +3 -0
  15. package/dist/client/assets/Assets-F6ySiRNw.js +1 -0
  16. package/dist/client/assets/BuildAnalysis-Ci5Or0e4.js +1 -0
  17. package/dist/client/assets/CaptureNotice-DNYJjRjY.js +1 -0
  18. package/dist/client/assets/{Components-Co50xTrv.css → Components-DcHDCSmh.css} +1 -1
  19. package/dist/client/assets/Components-DzrFq-Jl.js +2 -0
  20. package/dist/client/assets/DataTable-C8wIHfdk.js +1 -0
  21. package/dist/client/assets/DataTable-gMBzprA7.css +1 -0
  22. package/dist/client/assets/ErrorDashboard-DvBrkCGu.js +1 -0
  23. package/dist/client/assets/FpsMonitor-Bot5x4nP.js +1 -0
  24. package/dist/client/assets/FpsMonitor-D0MLqumc.css +1 -0
  25. package/dist/client/assets/Inspect-TF2sVdn4.js +4 -0
  26. package/dist/client/assets/Inspector-pD5_jg0-.js +1 -0
  27. package/dist/client/assets/LiveControls-BDWnVlkm.js +1 -0
  28. package/dist/client/assets/LoadProfiler-9jiBcPzy.css +1 -0
  29. package/dist/client/assets/LoadProfiler-RcwiKanZ.js +1 -0
  30. package/dist/client/assets/ModuleGraph-BscNTo-U.js +1 -0
  31. package/dist/client/assets/OGPreview-Ca39RUrW.js +1 -0
  32. package/dist/client/assets/Overview-CNCVS-EJ.js +1 -0
  33. package/dist/client/assets/Panel-BoUvB1nh.js +1 -0
  34. package/dist/client/assets/Panel-b1jDvzob.css +1 -0
  35. package/dist/client/assets/ReactiveGraph-BInCBdAu.css +1 -0
  36. package/dist/client/assets/ReactiveGraph-BmQbARuQ.js +17 -0
  37. package/dist/client/assets/RefreshButton-QYzgSJG9.js +1 -0
  38. package/dist/client/assets/RenderProfiler-Brp8i8K4.js +1 -0
  39. package/dist/client/assets/RenderProfiler-C0XQZUzw.css +1 -0
  40. package/dist/client/assets/ResourceEmpty-BBhK6GZB.js +1 -0
  41. package/dist/client/assets/Routes-BS5YDx3C.js +1 -0
  42. package/dist/client/assets/SearchField-C1RVVJht.js +1 -0
  43. package/dist/client/assets/Segmented-CK2euuus.js +1 -0
  44. package/dist/client/assets/SplitView-D7jY4n9A.js +1 -0
  45. package/dist/client/assets/StatList-Cd2sByRK.js +1 -0
  46. package/dist/client/assets/StatList-CwVfs0x8.css +1 -0
  47. package/dist/client/assets/StateTimeline-CaYBN88_.js +1 -0
  48. package/dist/client/assets/TreeView-T5wWFSLQ.js +1 -0
  49. package/dist/client/assets/VirtualList-CLxNqdaN.js +1 -0
  50. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-DrvKG05N.js +1 -0
  51. package/dist/client/assets/capture.svelte-CetYVdiG.js +1 -0
  52. package/dist/client/assets/collections-BtFss6Lo.js +1 -0
  53. package/dist/client/assets/index-BBFupqc_.js +3 -0
  54. package/dist/client/assets/index-C_6yCKMs.css +1 -0
  55. package/dist/client/assets/kind-options-BLIV2wQY.js +1 -0
  56. package/dist/client/assets/nanoid-Cya-tyvy.js +1 -0
  57. package/dist/client/assets/reactive-BQ_s2f5H.js +1 -0
  58. package/dist/client/assets/reactive-selection.svelte-DI6qEBmx.js +1 -0
  59. package/dist/client/assets/resource-f-V9vBwK.css +1 -0
  60. package/dist/client/assets/resource.svelte-GBY8qvgR.js +5 -0
  61. package/dist/client/assets/versions-Dmo1-Hsc.js +1 -0
  62. package/dist/client/index.html +5 -2
  63. package/dist/index.mjs +2464 -1951
  64. package/dist/index.mjs.map +1 -1
  65. package/dist/mcp/http.d.ts +24 -0
  66. package/dist/mcp/issues.d.ts +10 -6
  67. package/dist/mcp/server.d.ts +6 -17
  68. package/dist/mcp/sessions.d.ts +27 -17
  69. package/dist/mcp/stats.d.ts +13 -0
  70. package/dist/plugin.d.ts +14 -22
  71. package/dist/runtime/ids.d.ts +3 -0
  72. package/dist/runtime/index.d.ts +18 -0
  73. package/dist/runtime/transform.d.ts +22 -0
  74. package/dist/{collector.d.ts → server/collector.d.ts} +59 -119
  75. package/dist/server/compiler-warnings.d.ts +13 -0
  76. package/dist/{devframe.d.ts → server/devframe.d.ts} +11 -11
  77. package/dist/server/load-profile.d.ts +12 -0
  78. package/dist/{mount.d.ts → server/mount.d.ts} +6 -9
  79. package/dist/server/payload.d.ts +11 -0
  80. package/dist/server/reactive.d.ts +30 -0
  81. package/dist/server/ring.d.ts +11 -0
  82. package/dist/{security.d.ts → server/security.d.ts} +13 -3
  83. package/dist/server/state-timeline.d.ts +72 -0
  84. package/package.json +9 -4
  85. package/skills/vite-devtools-svelte-perf-audit/SKILL.md +2 -2
  86. package/skills/vite-devtools-svelte-perf-fix/SKILL.md +3 -3
  87. package/dist/client/assets/ApiPlayground-B28mCUlr.js +0 -3
  88. package/dist/client/assets/Assets-BVT22xZ3.js +0 -1
  89. package/dist/client/assets/Badge-BBLKgCiU.css +0 -1
  90. package/dist/client/assets/Badge-x4Lbd8pc.js +0 -1
  91. package/dist/client/assets/BuildAnalysis-BscZFEWI.js +0 -1
  92. package/dist/client/assets/CaptureNotice-D0u6WNeR.js +0 -1
  93. package/dist/client/assets/Components-sw5zdu0k.js +0 -1
  94. package/dist/client/assets/DataTable-CdM2Vyvn.js +0 -1
  95. package/dist/client/assets/DataTable-CdVIFm8T.css +0 -1
  96. package/dist/client/assets/ErrorDashboard-BwGMVW_-.js +0 -1
  97. package/dist/client/assets/FpsMonitor-BmS11Tn7.css +0 -1
  98. package/dist/client/assets/FpsMonitor-C0FeLiag.js +0 -1
  99. package/dist/client/assets/Inspect-B-jb8MaB.js +0 -3
  100. package/dist/client/assets/Inspector-C4wr2Zb4.js +0 -1
  101. package/dist/client/assets/LoadProfiler-WeP1orWN.js +0 -1
  102. package/dist/client/assets/LoadProfiler-cg28l5zW.css +0 -1
  103. package/dist/client/assets/ModuleGraph-BYer7OEL.js +0 -1
  104. package/dist/client/assets/OGPreview-MRxnmCmb.js +0 -1
  105. package/dist/client/assets/Overview-CDBKKylY.js +0 -1
  106. package/dist/client/assets/ReactiveGraph-Bni33DP4.js +0 -5
  107. package/dist/client/assets/ReactiveGraph-Bq_aP4uo.css +0 -1
  108. package/dist/client/assets/RenderProfiler-2rA8kCUf.js +0 -1
  109. package/dist/client/assets/RenderProfiler-CS1FAvX6.css +0 -1
  110. package/dist/client/assets/Routes-BZ5XcmEt.js +0 -1
  111. package/dist/client/assets/SearchField-D85HSGV_.js +0 -1
  112. package/dist/client/assets/Segmented-BCcIUjA2.js +0 -1
  113. package/dist/client/assets/SplitView-DVk1HAf9.js +0 -1
  114. package/dist/client/assets/StateTimeline-DjTXe54T.js +0 -1
  115. package/dist/client/assets/TreeView-e7dNH8HW.js +0 -1
  116. package/dist/client/assets/VirtualList-Ba0GhFn8.js +0 -1
  117. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-UMmvacmP.js +0 -1
  118. package/dist/client/assets/capture.svelte-fve1ihQA.js +0 -1
  119. package/dist/client/assets/format-CW_NXiBg.js +0 -1
  120. package/dist/client/assets/index-CuoAAt-d.js +0 -7
  121. package/dist/client/assets/index-u73uo_Ri.css +0 -1
  122. package/dist/client/assets/reactive-BSjTkgqc.js +0 -1
  123. package/dist/client/assets/reactive-selection.svelte-BmjgYyWR.js +0 -1
  124. package/dist/client/assets/versions-zyEGB_mz.js +0 -1
  125. package/dist/runtime.d.ts +0 -19
  126. /package/dist/client/assets/{versions-CMau2xlU.css → LiveControls-CMau2xlU.css} +0 -0
  127. /package/dist/{template-injector.d.ts → server/template-injector.d.ts} +0 -0
@@ -0,0 +1,24 @@
1
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { Logger } from 'vite';
4
+ import { Collector } from '../server/collector.js';
5
+ /** Dev-server path of the MCP endpoint. */
6
+ export declare const MCP_PATH = "/__svelte-devtools/mcp";
7
+ /**
8
+ * Whether the request's `x-svelte-devtools-token` header is exactly `token`.
9
+ * Constant-time for equal lengths (the length itself is not secret: every
10
+ * token is a UUID). A repeated header (string array) is never accepted.
11
+ */
12
+ export declare function isValidMcpToken(header: string | string[] | undefined, token: string): boolean;
13
+ /**
14
+ * Connect middleware for the MCP endpoint: lets AI agents (Claude Code etc.)
15
+ * read metrics and run measurement sessions over the Streamable HTTP
16
+ * transport. Same-origin is *not* required because MCP clients are local
17
+ * processes that don't run inside a browser tab; the token is the gate.
18
+ */
19
+ export declare function createMcpMiddleware(opts: {
20
+ token: string;
21
+ collector: Collector;
22
+ logger: Logger;
23
+ createServer: () => McpServer;
24
+ }): (req: IncomingMessage, res: ServerResponse) => void;
@@ -1,5 +1,5 @@
1
1
  import { RenderProfile, ReactiveGraph, LoadProfile, FpsSample } from '../types.js';
2
- export type IssueKind = 'slow-component-render' | 'over-rendered-component' | 'slow-load' | 'fps-drop' | 'effect-overconnected';
2
+ type IssueKind = 'slow-component-render' | 'over-rendered-component' | 'slow-load' | 'fps-drop' | 'effect-overconnected';
3
3
  export interface PerformanceIssue {
4
4
  id: string;
5
5
  kind: IssueKind;
@@ -12,15 +12,18 @@ export interface PerformanceIssue {
12
12
  suggestedTool: string;
13
13
  }
14
14
  export interface IssueThresholds {
15
- /** Per-render time (ms) above which a component render is considered slow. */
15
+ /** Per-render time (ms) at or above which a component render is considered slow. */
16
16
  avgRenderTimeMs?: number;
17
- /** Render count above which a component is considered over-rendered. */
17
+ /** Render count at or above which a component is considered over-rendered. */
18
18
  renderCount?: number;
19
- /** Load duration (ms) above which a SvelteKit load is slow. */
19
+ /** Load duration (ms) at or above which a SvelteKit load is slow. */
20
20
  loadDurationMs?: number;
21
- /** FPS below which we record a drop. */
21
+ /** FPS strictly below which we record a drop. */
22
22
  fpsDropThreshold?: number;
23
- /** Outgoing edge count from an effect above which it is over-connected. */
23
+ /**
24
+ * Dependency count (incoming edges: what the effect reads) at or above
25
+ * which an effect is over-connected.
26
+ */
24
27
  effectMaxDeps?: number;
25
28
  }
26
29
  export interface IssueInputs {
@@ -59,3 +62,4 @@ export interface ReactiveProblems {
59
62
  }>;
60
63
  }
61
64
  export declare function summarizeReactiveProblems(graph: ReactiveGraph, t?: IssueThresholds): ReactiveProblems;
65
+ export {};
@@ -1,16 +1,11 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3
2
  import { RenderProfile, ReactiveGraph, LoadProfile, FpsSample, ComponentInstance, ProjectInfo, RouteInfo, ComponentRelation, CaptureInfoMap, ReactiveGraphRequest, ReactiveGraphResult, ReactiveSummary, ReactiveSummaryRequest, StateTimelineDelta } from '../types.js';
4
3
  import { SessionStore } from './sessions.js';
5
4
  export interface McpDeps {
6
5
  getProject: () => ProjectInfo;
7
6
  getRoutes: () => RouteInfo[];
8
- getLiveComponents: () => ComponentInstance[];
9
- /**
10
- * The served page load's components with its epoch, read together
11
- * (`get_live_components` with `includeMeta`).
12
- */
13
- getLiveSnapshot?: () => {
7
+ /** The served page load's components with its epoch, read together. */
8
+ getLiveSnapshot: () => {
14
9
  epoch: string | null;
15
10
  total: number;
16
11
  components: ComponentInstance[];
@@ -22,17 +17,11 @@ export interface McpDeps {
22
17
  getLoadProfiles: () => LoadProfile[];
23
18
  getFpsSamples: () => FpsSample[];
24
19
  sessions: SessionStore;
25
- getReactiveSummary?: (req: ReactiveSummaryRequest) => Promise<ReactiveSummary>;
26
- getReactiveScope?: (req: ReactiveGraphRequest) => Promise<ReactiveGraphResult>;
27
- getStateTimelineDelta?: (since?: number) => StateTimelineDelta;
28
- getCaptureInfo?: () => CaptureInfoMap;
20
+ getReactiveSummary: (req: ReactiveSummaryRequest) => Promise<ReactiveSummary>;
21
+ getReactiveScope: (req: ReactiveGraphRequest) => Promise<ReactiveGraphResult>;
22
+ getStateTimelineDelta: (since?: number) => StateTimelineDelta;
23
+ getCaptureInfo: () => CaptureInfoMap;
29
24
  }
30
25
  /** Most timeline entries one `get_state_timeline` call returns. */
31
26
  export declare const MCP_TIMELINE_LIMIT = 500;
32
- /** Default / largest JSON size of one old/new value in `get_state_timeline` output. */
33
- export declare const MCP_VALUE_CHARS: {
34
- readonly default: 2048;
35
- readonly max: 32768;
36
- };
37
27
  export declare function buildMcpServer(deps: McpDeps): McpServer;
38
- export { StreamableHTTPServerTransport };
@@ -1,5 +1,5 @@
1
1
  import { RenderProfile, LoadProfile, FpsSample } from '../types.js';
2
- export interface SessionSnapshot {
2
+ interface SessionSnapshot {
3
3
  /** componentId -> { renderCount, totalRenderTime } at snapshot moment */
4
4
  renderProfiles: Array<{
5
5
  componentId: number;
@@ -47,6 +47,7 @@ export interface SessionDelta {
47
47
  drops: number;
48
48
  };
49
49
  }
50
+ type Verdict = 'improved' | 'regressed' | 'unchanged';
50
51
  export interface SessionDiff {
51
52
  a: {
52
53
  id: string;
@@ -60,33 +61,40 @@ export interface SessionDiff {
60
61
  totalRenderTimeDeltaA: number;
61
62
  totalRenderTimeDeltaB: number;
62
63
  diff: number;
63
- verdict: 'improved' | 'regressed' | 'unchanged';
64
+ verdict: Verdict;
64
65
  };
65
66
  load: {
66
67
  avgA: number;
67
68
  avgB: number;
68
69
  diff: number;
69
- verdict: 'improved' | 'regressed' | 'unchanged';
70
+ verdict: Verdict;
70
71
  };
71
72
  fps: {
72
73
  avgA: number;
73
74
  avgB: number;
74
75
  diff: number;
75
- verdict: 'improved' | 'regressed' | 'unchanged';
76
+ verdict: Verdict;
76
77
  };
77
78
  }
79
+ interface SessionSummary {
80
+ id: string;
81
+ label: string;
82
+ startedAt: number;
83
+ endedAt?: number;
84
+ persisted: boolean;
85
+ active: boolean;
86
+ }
78
87
  export interface MetricGetters {
79
88
  getRenderProfiles: () => RenderProfile[];
80
89
  getLoadProfiles: () => LoadProfile[];
81
90
  getFpsSamples: () => FpsSample[];
82
91
  }
83
92
  /**
84
- * The only id shape `start()` issues: `s_<Date.now() base36>_<6 hex>`. Ids
85
- * reach the store from MCP clients and become file names, so anything else
86
- * (path separators, `..`, absolute paths) is rejected before touching disk
87
- * (review C-7).
93
+ * Whether `id` has the only shape `start()` issues: `s_<Date.now() base36>_<6
94
+ * hex>`. Ids reach the store from MCP clients and become file names, so
95
+ * anything else (path separators, `..`, absolute paths) is rejected before
96
+ * touching disk (review C-7).
88
97
  */
89
- export declare const SESSION_ID_PATTERN: RegExp;
90
98
  export declare function isSessionId(id: unknown): id is string;
91
99
  export interface SessionStoreOptions {
92
100
  persistDir: string;
@@ -99,25 +107,27 @@ export declare class SessionStore {
99
107
  private readonly getters;
100
108
  constructor(opts: SessionStoreOptions);
101
109
  start(label: string, persist: boolean): SessionRecord;
110
+ private get activeRecord();
102
111
  /** Called by the plugin whenever a new load profile arrives. */
103
112
  recordLoadProfile(p: LoadProfile): void;
104
113
  /** Called by the plugin whenever a new fps sample arrives. */
105
114
  recordFpsSample(s: FpsSample): void;
106
115
  end(keep: 'memory' | 'disk' | 'discard'): SessionRecord;
107
116
  get(id: string): SessionRecord | undefined;
108
- list(): Array<{
109
- id: string;
110
- label: string;
111
- startedAt: number;
112
- endedAt?: number;
113
- persisted: boolean;
114
- active: boolean;
115
- }>;
117
+ list(): SessionSummary[];
116
118
  delete(id: string): boolean;
119
+ /**
120
+ * The delta of a record in hand. `end('discard')` removes the record from
121
+ * the store, so end_session must not look it up again by id (it used to,
122
+ * and failed with "Session not found" for every discarded session).
123
+ */
124
+ deltaOf(rec: SessionRecord): SessionDelta;
117
125
  delta(id: string): SessionDelta;
126
+ private found;
118
127
  compare(idA: string, idB: string): SessionDiff;
119
128
  /** The session's file, guaranteed to be a direct child of `persistDir`. */
120
129
  private pathFor;
121
130
  private persistToDisk;
122
131
  private loadFromDisk;
123
132
  }
133
+ export {};
@@ -0,0 +1,13 @@
1
+ /** Arithmetic mean, 0 for no values. */
2
+ export declare function avg(xs: number[]): number;
3
+ /** Smallest value, `fallback` for no values (reduce, not `Math.min(...)`: long lists overflow the stack). */
4
+ export declare function min<T>(xs: number[], fallback: T): number | T;
5
+ /** Largest value, `fallback` for no values. */
6
+ export declare function max<T>(xs: number[], fallback: T): number | T;
7
+ /** Rounded to 2 decimals. */
8
+ export declare function round(n: number): number;
9
+ /** Average render time of a profile, 0 when it never rendered. */
10
+ export declare function avgRenderTime(p: {
11
+ renderCount: number;
12
+ totalRenderTime: number;
13
+ }): number;
package/dist/plugin.d.ts CHANGED
@@ -5,27 +5,19 @@ export interface SvelteDevtoolsOptions {
5
5
  * @default true
6
6
  */
7
7
  componentTracking?: boolean;
8
+ /**
9
+ * Require the one-time code before a browser can use the standalone
10
+ * DevTools (`/.svelte-devtools/`). Set `false` to skip it on a trusted,
11
+ * single-user machine.
12
+ *
13
+ * Beware: without it, any page or device that can reach the dev server
14
+ * can read files in your project through the DevTools (including other
15
+ * devices when the dev server listens on a LAN address, `--host`).
16
+ * Inside the Vite DevTools dock this option has no effect: use
17
+ * `DevTools({ clientAuth: false })` from `@vitejs/devtools` instead.
18
+ * The MCP endpoint keeps its own token either way.
19
+ * @default true
20
+ */
21
+ clientAuth?: boolean;
8
22
  }
9
- /**
10
- * Component-tracking transform for one compiled client `.svelte` module:
11
- * imports the runtime and names the file for the wrapper's next `push()`.
12
- * `null` when the module has no component (`$.push(`) to track.
13
- *
14
- * Nothing is inserted as a new line, so every original line keeps its
15
- * number (`map: null` = mappings unchanged; stack traces and the
16
- * compiler's sourcemap stay aligned).
17
- */
18
- export declare function injectComponentTracking(code: string, id: string): string | null;
19
- /** A Svelte module (`.svelte.js` / `.svelte.ts`, runes outside components). */
20
- export declare const SVELTE_MODULE_RE: RegExp;
21
- /**
22
- * Module-scope transform for one client Svelte module: signals created while
23
- * its body runs (shared state, `export const cart = $state(...)`) are tracked
24
- * under a scope named after the file. The body is bracketed by enter/leave
25
- * calls; nothing is inserted as a new line. The bracket is plain JS, so it
26
- * works before or after vite-plugin-svelte compiles the module (with
27
- * `svelteDevtools()` listed before `sveltekit()`, a `.svelte.ts` module is
28
- * compiled after this transform). `null` for a server-compiled module.
29
- */
30
- export declare function injectModuleTracking(code: string, id: string): string | null;
31
23
  export declare function svelteDevtools(options?: SvelteDevtoolsOptions): Plugin[];
@@ -0,0 +1,3 @@
1
+ export declare const RUNTIME_MODULE_ID = "virtual:svelte-devtools-runtime";
2
+ export declare const RESOLVED_RUNTIME_ID: string;
3
+ export declare const WRAPPER_MODULE_ID = "\0svelte-devtools:wrapped-client";
@@ -0,0 +1,18 @@
1
+ export { RESOLVED_RUNTIME_ID, RUNTIME_MODULE_ID, WRAPPER_MODULE_ID } from './ids.js';
2
+ /**
3
+ * Wrapper code for svelte/internal/client (`./wrapper.js`).
4
+ *
5
+ * Re-exports everything from the real module, then overrides:
6
+ * - push/pop: component lifecycle tracking
7
+ * - tag/tag_proxy: named signal/proxy tracking (Svelte dev mode)
8
+ * - state/derived/proxy: type markers consumed by tag/tag_proxy
9
+ * - user_effect/user_pre_effect: effect tracking
10
+ * - template_effect/deferred_template_effect: render count/time profiling
11
+ * - each/if/key/await/component/boundary: block-callback owner attribution
12
+ *
13
+ * This single module replaces all post-compilation regex transforms
14
+ * for reactive tracking, making the approach Svelte-compiler-output agnostic.
15
+ */
16
+ export declare const wrapperCode: string;
17
+ /** The devtools runtime (`./client.js`), installed once as `window.__SVELTE_DEVTOOLS__`. */
18
+ export declare const runtimeCode: string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Component-tracking transform for one compiled client `.svelte` module:
3
+ * imports the runtime and names the file for the wrapper's next `push()`.
4
+ * `null` when the module has no component (`$.push($$props`) to track.
5
+ *
6
+ * Nothing is inserted as a new line, so every original line keeps its
7
+ * number (`map: null` = mappings unchanged; stack traces and the
8
+ * compiler's sourcemap stay aligned).
9
+ */
10
+ export declare function injectComponentTracking(code: string, id: string): string | null;
11
+ /** A Svelte module (`.svelte.js` / `.svelte.ts`, runes outside components); `file` has no query. */
12
+ export declare function isSvelteModule(file: string): boolean;
13
+ /**
14
+ * Module-scope transform for one client Svelte module: signals created while
15
+ * its body runs (shared state, `export const cart = $state(...)`) are tracked
16
+ * under a scope named after the file. The body is bracketed by enter/leave
17
+ * calls; nothing is inserted as a new line. The bracket is plain JS, so it
18
+ * works before or after vite-plugin-svelte compiles the module (with
19
+ * `svelteDevtools()` listed before `sveltekit()`, a `.svelte.ts` module is
20
+ * compiled after this transform). `null` for a server-compiled module.
21
+ */
22
+ export declare function injectModuleTracking(code: string, id: string): string | null;
@@ -1,4 +1,7 @@
1
- import { CaptureInfoMap, CompilerWarning, ComponentInstance, FpsSample, LoadProfile, ReactiveGraph, ReactiveGraphRequest, ReactiveGraphResult, ReactiveSummary, ReactiveSummaryRequest, RenderProfile, RuntimeError, StateChange, StateTimelineDelta, StateTimelineEntry, DatasetVersions } from './types.js';
1
+ import { CaptureInfoMap, CompilerWarning, ComponentInstance, FpsSample, LoadProfile, ReactiveGraphRequest, ReactiveGraphResult, ReactiveSummary, ReactiveSummaryRequest, RenderProfile, RuntimeError, StateChange, StateTimelineDelta, StateTimelineEntry, DatasetVersions } from '../types.js';
2
+ import { Payload } from './payload.js';
3
+ import { TimelinePush } from './state-timeline.js';
4
+ export { STATE_TIMELINE_BYTES } from './state-timeline.js';
2
5
  export declare const LIMITS: {
3
6
  readonly liveComponents: 50000;
4
7
  readonly renderProfiles: 5000;
@@ -14,9 +17,8 @@ export declare const LIMITS: {
14
17
  export declare const RUNTIME_REQUEST_TIMEOUT = 1000;
15
18
  /** A pull answered within this window is reused instead of asking the runtime again. */
16
19
  export declare const PULL_FRESHNESS = 1000;
17
- /** Byte budget (JSON length, measured once at ingest) for the server-side state timeline. */
18
- export declare const STATE_TIMELINE_BYTES: number;
19
- export type DatasetKey = keyof DatasetVersions;
20
+ /** A consumer (DevTools UI tab, MCP agent) counts as watching until its lease expires. */
21
+ export declare const LEASE_TTL = 15000;
20
22
  /** App page loads (tabs / reloads) whose component tree + profiles are kept, LRU. */
21
23
  export declare const MAX_EPOCHS = 4;
22
24
  /** Hot-channel event names shared with `runtime.ts` (stable contract, see docs/devframe-migration.md §6). */
@@ -38,23 +40,13 @@ export declare const HOT_EVENTS: {
38
40
  /** server → runtime(s): `{ active: boolean }` — whether any consumer is watching. */
39
41
  readonly subscription: "svelte-devtools:subscription";
40
42
  };
41
- /** Defaults and bounds for `get-reactive-summary` (§6.7 I). */
42
- export declare const SUMMARY_DEFAULTS: {
43
- readonly topK: 50;
44
- readonly maxTopK: 200;
45
- readonly windowMs: 10000;
46
- readonly minWindowMs: 1000;
47
- readonly maxWindowMs: 60000;
48
- };
49
- /** A consumer (DevTools UI tab, MCP agent) counts as watching until its lease expires. */
50
- export declare const LEASE_TTL = 15000;
51
43
  export interface HotClient {
52
44
  send(event: string, payload: unknown): void;
53
45
  }
54
46
  export interface HotChannel {
55
47
  send(event: string, payload: unknown): void;
56
- on(event: string, listener: (payload: any, client: HotClient) => void): void;
57
- off?(event: string, listener: (payload: any, client: HotClient) => void): void;
48
+ on(event: string, listener: (payload: unknown, client: HotClient) => void): void;
49
+ off?(event: string, listener: (payload: unknown, client: HotClient) => void): void;
58
50
  }
59
51
  export interface CollectorHooks {
60
52
  onFpsSample?: (sample: FpsSample) => void;
@@ -66,49 +58,35 @@ export interface CollectorHooks {
66
58
  * feeds it, the devframe RPC layer and the MCP server read from it.
67
59
  */
68
60
  export declare class Collector {
69
- private readonly hooks;
70
61
  private epochs;
71
62
  private servedEpoch;
72
63
  private liveCache;
73
- loadProfiles: LoadProfile[];
74
- reactiveGraph: ReactiveGraph;
75
- compilerWarnings: CompilerWarning[];
76
- runtimeErrors: RuntimeError[];
77
- fpsSamples: FpsSample[];
64
+ /** Epochs we asked for a full snapshot (delta without a base); answered once per epoch. */
65
+ private resyncRequested;
66
+ private readonly fps;
67
+ private readonly errors;
68
+ private readonly loads;
69
+ private readonly warnings;
70
+ private readonly timeline;
78
71
  readonly versions: DatasetVersions;
79
- private bump;
80
- private timeline;
81
- /** Parallel to `timeline`: JSON size and source epoch (app page load) of each entry. */
82
- private timelineSizes;
83
- private timelineEpochs;
84
- private timelineBytes;
85
- /** Newest seq issued by this collector (= the current cursor). */
86
- private timelineSeq;
87
- /** Cursor value at the last removal; older cursors must start over. */
88
- private timelineResetAt;
89
- /** Seq of the newest entry trimmed by the caps; cursors below it missed entries. */
90
- private timelineTrimmedAt;
91
- private lastPull;
92
- private inflight;
93
72
  private pulls;
94
73
  private pullCache;
95
74
  private pullInflight;
96
75
  private requestSeq;
97
76
  /** The most recent graph reply, for capture info. */
98
77
  private lastGraph;
99
- private timelineDrops;
100
- /** Per epoch: whether the runtime has a first sample of every tracked $state yet. */
101
- private timelineBaseline;
102
- private timelineTooLarge;
103
- private received;
78
+ private lastTimelinePull;
79
+ private timelineInflight;
80
+ private timelineResolvers;
104
81
  private hot;
105
82
  private detachHot;
106
83
  private leases;
107
84
  private snapshotWaiters;
108
85
  private active;
109
86
  private sweepTimer;
110
- private stateTimelineResolvers;
87
+ private readonly hooks;
111
88
  constructor(hooks?: CollectorHooks);
89
+ private bump;
112
90
  /**
113
91
  * Subscribe to the runtime's hot-channel events. Re-attaching (dev server
114
92
  * restart) detaches the previous channel first so listeners never pile up.
@@ -120,8 +98,12 @@ export declare class Collector {
120
98
  active: boolean;
121
99
  componentDeltas: true;
122
100
  };
123
- /** Epochs we asked for a full snapshot (delta without a base); answered once per epoch. */
124
- private resyncRequested;
101
+ get fpsSamples(): FpsSample[];
102
+ get runtimeErrors(): RuntimeError[];
103
+ get loadProfiles(): LoadProfile[];
104
+ get compilerWarnings(): CompilerWarning[];
105
+ /** The server-side timeline (all tracked epochs, oldest first). */
106
+ get stateTimeline(): StateTimelineEntry[];
125
107
  /** Components of the served epoch, parents first, capped at {@link LIMITS.liveComponents}. */
126
108
  get liveComponents(): ComponentInstance[];
127
109
  /**
@@ -155,9 +137,10 @@ export declare class Collector {
155
137
  /**
156
138
  * Mark `id` as watching for `ttl` ms (renewed by heartbeats). The first
157
139
  * lease activates the runtime's polling/FPS sampling, the last expiry or
158
- * release pauses it.
140
+ * release pauses it. Returns whether this call activated it.
159
141
  */
160
142
  lease(id: string, ttl?: number): boolean;
143
+ release(id: string): void;
161
144
  /**
162
145
  * Resolve once the runtime has sent its activation snapshot (components,
163
146
  * profiles, then a `reset: true` timeline — the last part) or after
@@ -165,7 +148,6 @@ export declare class Collector {
165
148
  * the stale pre-activation state.
166
149
  */
167
150
  waitForSnapshot(timeout: number): Promise<void>;
168
- release(id: string): void;
169
151
  private updateSubscription;
170
152
  /**
171
153
  * Full form `{ epoch?, reset?, components }` replaces the epoch's tree;
@@ -175,56 +157,30 @@ export declare class Collector {
175
157
  * resync. Entries stay in registration order (parents first); an instance
176
158
  * is stored only while its parent is and the cap allows, otherwise only its
177
159
  * id is tracked, so the stored part is always a rooted, orphan-free tree.
160
+ * Entries that are not objects with a numeric `id` are ignored.
178
161
  */
179
- ingestComponents(data: {
180
- components?: unknown;
181
- epoch?: unknown;
182
- added?: unknown;
183
- removed?: unknown;
184
- } | undefined, client?: HotClient): void;
185
- ingestProfiles(data: {
186
- profiles?: unknown;
187
- epoch?: unknown;
188
- total?: unknown;
189
- } | undefined): void;
162
+ ingestComponents(data: Payload | undefined, client?: HotClient): void;
163
+ ingestProfiles(data?: Payload): void;
164
+ ingestStateTimeline(data: TimelinePush | undefined): void;
165
+ ingestFps(sample: FpsSample): void;
166
+ ingestRuntimeError(error: RuntimeError): void;
167
+ recordLoadProfile(profile: LoadProfile): void;
168
+ /**
169
+ * A warning identical to one held is not recorded again: a component is
170
+ * compiled once per environment (client and SSR), each time warning anew.
171
+ */
172
+ recordCompilerWarning(warning: CompilerWarning): void;
173
+ clearLoadProfiles(): void;
174
+ clearErrors(): void;
175
+ clearFps(): void;
176
+ clearStateTimeline(): void;
177
+ /** Changes after `since` (a previous `cursor`), or the whole buffer when the cursor is stale. */
178
+ getStateTimelineDelta(since?: number): StateTimelineDelta;
190
179
  /**
191
180
  * What the server holds versus what was reported, per dataset (§6.7 B).
192
181
  * `total: null` means unknown; nothing is estimated.
193
182
  */
194
183
  getCaptureInfo(): CaptureInfoMap;
195
- /** The server-side timeline (all tracked epochs, oldest first). */
196
- get stateTimeline(): StateTimelineEntry[];
197
- /**
198
- * Two payload shapes (docs/devframe-migration.md §6.4):
199
- * - delta: `{ epoch, changes, reset? }` — `changes` are new since the
200
- * previous push from that page load (`epoch`); `reset` replaces that
201
- * epoch's entries. Entries are kept per epoch, so several app tabs (or a
202
- * reload) interleave instead of wiping each other.
203
- * - legacy full snapshot: `{ changes }` — we append only the entries after
204
- * the newest one we already hold, so clients still get deltas.
205
- */
206
- ingestStateTimeline(data: {
207
- changes?: unknown;
208
- epoch?: unknown;
209
- reset?: unknown;
210
- dropped?: unknown;
211
- valueTooLarge?: unknown;
212
- baseline?: unknown;
213
- } | undefined): void;
214
- /**
215
- * Add the runtime's own losses (unsent entries it evicted, §6.7 C) and
216
- * too-large values to the epoch's counters. Only runtime reasons are
217
- * accepted from the runtime; server reasons are counted here.
218
- */
219
- private countRuntimeLosses;
220
- private addDrop;
221
- /** Changes after `since` (a previous `cursor`), or the whole buffer when the cursor is stale. */
222
- getStateTimelineDelta(since?: number): StateTimelineDelta;
223
- /** Invalidate every cursor issued so far (entries were removed, not just appended). */
224
- private markTimelineReset;
225
- private dropEpoch;
226
- private appendTimeline;
227
- private resolveSnapshotWaiters;
228
184
  /**
229
185
  * A graph reply. With a `requestId` (§6.7 A) it resolves only that request,
230
186
  * and only if its epoch matches the one asked for; a reply nobody waits for
@@ -232,27 +188,11 @@ export declare class Collector {
232
188
  * is a whole-app graph and answers every pending graph pull, scoped ones by
233
189
  * filtering here.
234
190
  */
235
- ingestReactiveGraph(data: Record<string, any> | undefined): void;
236
- /**
237
- * Shape a runtime reply into a {@link ReactiveGraphResult}: apply the
238
- * collector caps (nodes, then only edges between kept nodes, then the edge
239
- * cap) and report what was left out. Totals come from the runtime; an older
240
- * runtime's are the counts it sent (`nodesKind: 'sent'`), or unknown when
241
- * the server had to scope its whole-app graph.
242
- */
243
- private normalizeGraph;
244
- private storeGraph;
191
+ ingestReactiveGraph(data: Payload | undefined): void;
245
192
  /** A summary reply (§6.7 I): resolves only the matching request. */
246
- ingestReactiveSummary(data: Record<string, any> | undefined): void;
247
- private normalizeSummary;
248
- ingestFps(sample: FpsSample): void;
249
- ingestRuntimeError(error: RuntimeError): void;
250
- recordLoadProfile(profile: LoadProfile): void;
251
- recordCompilerWarning(warning: CompilerWarning): void;
252
- clearLoadProfiles(): void;
253
- clearErrors(): void;
254
- clearFps(): void;
255
- clearStateTimeline(): void;
193
+ ingestReactiveSummary(data: Payload | undefined): void;
194
+ /** The pending pull `requestId` names, if the reply is of its kind and from its epoch. */
195
+ private matchingPull;
256
196
  /**
257
197
  * Ask the browser runtime for the graph of one component instance (or the
258
198
  * whole app), built by the runtime within the caps (§6.7 A). Falls back to
@@ -268,17 +208,17 @@ export declare class Collector {
268
208
  * last result for the same key is returned with `stale: true`.
269
209
  */
270
210
  private keyedPull;
271
- /** Resolve a pending pull with a fresh result and cache it under its key. */
211
+ /**
212
+ * Resolve a pending pull: with a fresh result (cached under its key), or
213
+ * with its fallback when the runtime did not answer.
214
+ */
272
215
  private settle;
273
- /** Answer every pending keyed pull from its cache (or empty), marked stale. */
274
- private flushPulls;
275
- /** Ask the browser runtime for a fresh state timeline; falls back to the last one. */
276
- requestStateTimeline(): Promise<StateChange[]>;
277
216
  /**
278
- * Concurrent callers share one in-flight pull, and a result younger than
279
- * {@link PULL_FRESHNESS} is reused, so several polling clients never make
280
- * the user's app rebuild the same data more than once a second.
217
+ * Ask the browser runtime for a fresh state timeline; falls back to the
218
+ * last one. Concurrent callers share one in-flight pull, and a result
219
+ * younger than {@link PULL_FRESHNESS} is reused, so several polling clients
220
+ * never make the user's app rebuild the same data more than once a second.
281
221
  */
282
- private pull;
222
+ requestStateTimeline(): Promise<StateChange[]>;
283
223
  private flushStateTimeline;
284
224
  }
@@ -0,0 +1,13 @@
1
+ import { Plugin } from 'vite';
2
+ import { CompilerWarning } from '../types.js';
3
+ /**
4
+ * Report every Svelte compiler warning of the app to `record`, as the
5
+ * compiler's structured warning (vite-plugin-svelte prints dev warnings with
6
+ * `console.log`, past Vite's logger). The user's `onwarn` (or the default
7
+ * handler) still runs, so console output is unchanged. Dependencies'
8
+ * warnings are skipped, as vite-plugin-svelte does in dev.
9
+ *
10
+ * Must run after vite-plugin-svelte's own `configResolved`, which creates
11
+ * the options (a restart creates new ones, so wrappers never stack).
12
+ */
13
+ export declare function captureCompilerWarnings(plugins: readonly Plugin[], record: (warning: CompilerWarning) => void): void;