@oddsquad/vite-plugin-lit 0.5.0 → 0.6.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.
@@ -32,7 +32,7 @@
32
32
  `prefers-color-scheme` @media owns it, following the host/OS; an explicit
33
33
  light/dark pins a `.color-scheme-*` class on :root.
34
34
  -->
35
- <script type="module" crossorigin src="./assets/index-Gn4Hk_9s.js"></script>
35
+ <script type="module" crossorigin src="./assets/index-DVr5EnyB.js"></script>
36
36
  </head>
37
37
  <body>
38
38
  <lit-devtools-panel></lit-devtools-panel>
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /**
7
+ * Mirrors timeline events into Chrome DevTools' Performance panel as custom
8
+ * tracks, via `console.timeStamp(label, start, end, track, group, color)`.
9
+ *
10
+ * Start/end are `performance.now()` values. Paired `:start`/`:end` events
11
+ * become a range; everything else becomes a zero-length marker.
12
+ */
13
+ import type { TimelineEvent } from '../../../types/timeline.js';
14
+ type TrackColor = 'primary' | 'primary-light' | 'primary-dark' | 'secondary' | 'secondary-light' | 'secondary-dark' | 'tertiary' | 'tertiary-light' | 'tertiary-dark' | 'error';
15
+ export type TimeStamp = (label: string, start: number, end: number, track: string, group: string, color: TrackColor) => void;
16
+ export interface ChromeTracksSink {
17
+ push(event: TimelineEvent): void;
18
+ reset(): void;
19
+ }
20
+ export declare const createChromeTracksSink: (stamp?: TimeStamp, toPerf?: (t: number) => number) => ChromeTracksSink;
21
+ export {};
22
+ //# sourceMappingURL=chrome-tracks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrome-tracks.d.ts","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/chrome-tracks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AAG9D,KAAK,UAAU,GACX,SAAS,GACT,eAAe,GACf,cAAc,GACd,WAAW,GACX,iBAAiB,GACjB,gBAAgB,GAChB,UAAU,GACV,gBAAgB,GAChB,eAAe,GACf,OAAO,CAAC;AAEZ,MAAM,MAAM,SAAS,GAAG,CACtB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,UAAU,KACd,IAAI,CAAC;AAEV,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,KAAK,IAAI,IAAI,CAAC;CACf;AAuBD,eAAO,MAAM,sBAAsB,WAC1B,SAAS,WACR,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,KAC5B,gBAgDF,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ import {toPerfTime} from './clock.js';
7
+ const GROUP = 'Lit';
8
+ const MAX_PENDING = 1000;
9
+ const TRACKS = {
10
+ 'lit-lifecycle': {track: 'Lifecycle', color: 'primary', lit: true},
11
+ 'lit-render': {track: 'Render', color: 'secondary', lit: true},
12
+ 'lit-render-verbose': {
13
+ track: 'Render (verbose)',
14
+ color: 'secondary-light',
15
+ lit: true,
16
+ },
17
+ mouse: {track: 'Input', color: 'tertiary', lit: false},
18
+ keyboard: {track: 'Input', color: 'tertiary', lit: false},
19
+ };
20
+ const consoleStamp = (...args) => {
21
+ const c = console;
22
+ if (typeof c.timeStamp === 'function') c.timeStamp(...args);
23
+ };
24
+ export const createChromeTracksSink = (
25
+ stamp = consoleStamp,
26
+ toPerf = toPerfTime
27
+ ) => {
28
+ // Start times are converted at receipt because the clock epoch can reset
29
+ // before the matching :end arrives.
30
+ const pending = new Map();
31
+ return {
32
+ push(event) {
33
+ const cfg = TRACKS[event.layerId];
34
+ if (cfg === undefined) return;
35
+ const title = event.title ?? '';
36
+ const isError = event.logType === 'error';
37
+ const isStart = title.endsWith(':start');
38
+ const isEnd = title.endsWith(':end');
39
+ const phase =
40
+ isStart || isEnd ? title.slice(0, title.lastIndexOf(':')) : title;
41
+ const tag = cfg.lit ? (event.meta?.tagName ?? event.subtitle) : undefined;
42
+ const label = tag ? `<${tag}> ${phase}` : phase;
43
+ if (isStart) {
44
+ const key = `${event.layerId}|${event.groupId}|${phase}`;
45
+ pending.delete(key);
46
+ pending.set(key, {start: toPerf(event.time), error: isError});
47
+ if (pending.size > MAX_PENDING) {
48
+ const oldest = pending.keys().next().value;
49
+ if (oldest !== undefined) pending.delete(oldest);
50
+ }
51
+ } else if (isEnd) {
52
+ const key = `${event.layerId}|${event.groupId}|${phase}`;
53
+ const p = pending.get(key);
54
+ if (p === undefined) return;
55
+ pending.delete(key);
56
+ stamp(
57
+ label,
58
+ p.start,
59
+ toPerf(event.time),
60
+ cfg.track,
61
+ GROUP,
62
+ p.error || isError ? 'error' : cfg.color
63
+ );
64
+ } else {
65
+ const t = toPerf(event.time);
66
+ stamp(label, t, t, cfg.track, GROUP, isError ? 'error' : cfg.color);
67
+ }
68
+ },
69
+ reset() {
70
+ pending.clear();
71
+ },
72
+ };
73
+ };
74
+ //# sourceMappingURL=chrome-tracks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrome-tracks.js","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/chrome-tracks.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Mirrors timeline events into Chrome DevTools' Performance panel as custom\n * tracks, via `console.timeStamp(label, start, end, track, group, color)`.\n *\n * Start/end are `performance.now()` values. Paired `:start`/`:end` events\n * become a range; everything else becomes a zero-length marker.\n */\n\nimport type {TimelineEvent} from '../../../types/timeline.js';\nimport {toPerfTime} from './clock.js';\n\ntype TrackColor =\n | 'primary'\n | 'primary-light'\n | 'primary-dark'\n | 'secondary'\n | 'secondary-light'\n | 'secondary-dark'\n | 'tertiary'\n | 'tertiary-light'\n | 'tertiary-dark'\n | 'error';\n\nexport type TimeStamp = (\n label: string,\n start: number,\n end: number,\n track: string,\n group: string,\n color: TrackColor\n) => void;\n\nexport interface ChromeTracksSink {\n push(event: TimelineEvent): void;\n reset(): void;\n}\n\nconst GROUP = 'Lit';\nconst MAX_PENDING = 1000;\n\nconst TRACKS: Record<string, {track: string; color: TrackColor; lit: boolean}> =\n {\n 'lit-lifecycle': {track: 'Lifecycle', color: 'primary', lit: true},\n 'lit-render': {track: 'Render', color: 'secondary', lit: true},\n 'lit-render-verbose': {\n track: 'Render (verbose)',\n color: 'secondary-light',\n lit: true,\n },\n mouse: {track: 'Input', color: 'tertiary', lit: false},\n keyboard: {track: 'Input', color: 'tertiary', lit: false},\n };\n\nconst consoleStamp: TimeStamp = (...args) => {\n const c = console as unknown as {timeStamp?: TimeStamp};\n if (typeof c.timeStamp === 'function') c.timeStamp(...args);\n};\n\nexport const createChromeTracksSink = (\n stamp: TimeStamp = consoleStamp,\n toPerf: (t: number) => number = toPerfTime\n): ChromeTracksSink => {\n // Start times are converted at receipt because the clock epoch can reset\n // before the matching :end arrives.\n const pending = new Map<string, {start: number; error: boolean}>();\n\n return {\n push(event) {\n const cfg = TRACKS[event.layerId];\n if (cfg === undefined) return;\n const title = event.title ?? '';\n const isError = event.logType === 'error';\n const isStart = title.endsWith(':start');\n const isEnd = title.endsWith(':end');\n const phase =\n isStart || isEnd ? title.slice(0, title.lastIndexOf(':')) : title;\n const tag = cfg.lit ? (event.meta?.tagName ?? event.subtitle) : undefined;\n const label = tag ? `<${tag}> ${phase}` : phase;\n\n if (isStart) {\n const key = `${event.layerId}|${event.groupId}|${phase}`;\n pending.delete(key);\n pending.set(key, {start: toPerf(event.time), error: isError});\n if (pending.size > MAX_PENDING) {\n const oldest = pending.keys().next().value;\n if (oldest !== undefined) pending.delete(oldest);\n }\n } else if (isEnd) {\n const key = `${event.layerId}|${event.groupId}|${phase}`;\n const p = pending.get(key);\n if (p === undefined) return;\n pending.delete(key);\n stamp(\n label,\n p.start,\n toPerf(event.time),\n cfg.track,\n GROUP,\n p.error || isError ? 'error' : cfg.color\n );\n } else {\n const t = toPerf(event.time);\n stamp(label, t, t, cfg.track, GROUP, isError ? 'error' : cfg.color);\n }\n },\n reset() {\n pending.clear();\n },\n };\n};\n"]}
@@ -7,4 +7,10 @@
7
7
  export declare const resetClock: () => void;
8
8
  /** Milliseconds since the last {@link resetClock}. */
9
9
  export declare const now: () => number;
10
+ /**
11
+ * Convert a recording-relative time (from {@link now}) back to a
12
+ * `performance.now()` value, i.e. milliseconds since `performance.timeOrigin`.
13
+ * Chrome DevTools' `console.timeStamp` expects that timebase.
14
+ */
15
+ export declare const toPerfTime: (t: number) => number;
10
16
  //# sourceMappingURL=clock.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/clock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,qEAAqE;AACrE,eAAO,MAAM,UAAU,QAAO,IAE7B,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,GAAG,QAAO,MAAmC,CAAC"}
1
+ {"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/clock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,qEAAqE;AACrE,eAAO,MAAM,UAAU,QAAO,IAE7B,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,GAAG,QAAO,MAAmC,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,UAAU,MAAO,MAAM,KAAG,MAAmB,CAAC"}
@@ -19,4 +19,10 @@ export const resetClock = () => {
19
19
  };
20
20
  /** Milliseconds since the last {@link resetClock}. */
21
21
  export const now = () => performance.now() - epoch;
22
+ /**
23
+ * Convert a recording-relative time (from {@link now}) back to a
24
+ * `performance.now()` value, i.e. milliseconds since `performance.timeOrigin`.
25
+ * Chrome DevTools' `console.timeStamp` expects that timebase.
26
+ */
27
+ export const toPerfTime = (t) => t + epoch;
22
28
  //# sourceMappingURL=clock.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clock.js","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/clock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH,IAAI,KAAK,GAAG,CAAC,CAAC;AAEd,qEAAqE;AACrE,MAAM,CAAC,MAAM,UAAU,GAAG,GAAS,EAAE;IACnC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;AAC5B,CAAC,CAAC;AAEF,sDAAsD;AACtD,MAAM,CAAC,MAAM,GAAG,GAAG,GAAW,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Recording-relative clock for the timeline.\n *\n * Built-in capture layers timestamp events with {@link now} rather than raw\n * `performance.now()`, so event times read as \"ms since recording started\"\n * (the first event is ~0) instead of \"ms since the app page loaded\" — which is\n * also meaningless to the panel, an iframe with its own time origin. The origin\n * is re-zeroed on each rising edge of recording via {@link resetClock}.\n */\n\nlet epoch = 0;\n\n/** Re-zero the clock; called when recording transitions off → on. */\nexport const resetClock = (): void => {\n epoch = performance.now();\n};\n\n/** Milliseconds since the last {@link resetClock}. */\nexport const now = (): number => performance.now() - epoch;\n"]}
1
+ {"version":3,"file":"clock.js","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/clock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH,IAAI,KAAK,GAAG,CAAC,CAAC;AAEd,qEAAqE;AACrE,MAAM,CAAC,MAAM,UAAU,GAAG,GAAS,EAAE;IACnC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;AAC5B,CAAC,CAAC;AAEF,sDAAsD;AACtD,MAAM,CAAC,MAAM,GAAG,GAAG,GAAW,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;AAE3D;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Recording-relative clock for the timeline.\n *\n * Built-in capture layers timestamp events with {@link now} rather than raw\n * `performance.now()`, so event times read as \"ms since recording started\"\n * (the first event is ~0) instead of \"ms since the app page loaded\" — which is\n * also meaningless to the panel, an iframe with its own time origin. The origin\n * is re-zeroed on each rising edge of recording via {@link resetClock}.\n */\n\nlet epoch = 0;\n\n/** Re-zero the clock; called when recording transitions off → on. */\nexport const resetClock = (): void => {\n epoch = performance.now();\n};\n\n/** Milliseconds since the last {@link resetClock}. */\nexport const now = (): number => performance.now() - epoch;\n\n/**\n * Convert a recording-relative time (from {@link now}) back to a\n * `performance.now()` value, i.e. milliseconds since `performance.timeOrigin`.\n * Chrome DevTools' `console.timeStamp` expects that timebase.\n */\nexport const toPerfTime = (t: number): number => t + epoch;\n"]}
@@ -11,10 +11,14 @@
11
11
  * transport.
12
12
  *
13
13
  * Recording starts off; the panel iframe toggles it via the Vite HMR channel
14
- * (Phase 0/1) or devframe shared state (Phase 2+).
14
+ * (Phase 0/1) or devframe shared state (Phase 2+). Layers capture while the
15
+ * panel is recording OR the "chrome performance tracks" preference is on; the
16
+ * panel transport only receives events while recording, the Chrome tracks sink
17
+ * only while the preference is on.
15
18
  */
16
19
  import {emit, setHotClient} from './transport.js';
17
20
  import {resetClock} from './clock.js';
21
+ import {createChromeTracksSink} from './chrome-tracks.js';
18
22
  import {installLifecycleLayer, setUpdateHook} from './lifecycle.js';
19
23
  import {installRenderLayer, setRenderDebugEnabled} from './render.js';
20
24
  import {installMouseLayer, installKeyboardLayer} from './input.js';
@@ -32,28 +36,36 @@ const state = {
32
36
  mouseEventEnabled: false,
33
37
  keyboardEventEnabled: false,
34
38
  };
35
- const recording = () => state.recordingState;
39
+ // Mirror to Chrome DevTools' Performance panel; a page-side preference driven
40
+ // by the settings override, independent of panel recording.
41
+ let chromeTracks = false;
42
+ const sink = createChromeTracksSink();
43
+ // Layers run when either consumer wants events.
44
+ const capturing = () => state.recordingState || chromeTracks;
45
+ const out = (e) => {
46
+ if (state.recordingState) emit(e);
47
+ if (chromeTracks) sink.push(e);
48
+ };
36
49
  const lifecycleEnabled = () => state.litLifecycleEnabled;
37
50
  const renderEnabled = () => state.litRenderEnabled;
38
51
  const renderVerboseEnabled = () => state.litRenderVerboseEnabled;
39
52
  const mouseEnabled = () => state.mouseEventEnabled;
40
53
  const keyboardEnabled = () => state.keyboardEventEnabled;
41
- // Drive Lit's debug event flag from recording × (render-layer-enabled OR
54
+ // Drive Lit's debug event flag from capturing × (render-layer-enabled OR
42
55
  // verbose-layer-enabled) so lit-html only pays the per-render CustomEvent
43
56
  // dispatch cost while we're actually capturing one of the two render layers.
44
57
  const syncRenderDebug = () => {
45
58
  setRenderDebugEnabled(
46
- state.recordingState &&
47
- (state.litRenderEnabled || state.litRenderVerboseEnabled)
59
+ capturing() && (state.litRenderEnabled || state.litRenderVerboseEnabled)
48
60
  );
49
61
  };
50
62
  // ---------------------------------------------------------------------------
51
63
  // Capture layer installation
52
64
  // ---------------------------------------------------------------------------
53
- installLifecycleLayer(emit, recording, lifecycleEnabled);
54
- installRenderLayer(emit, recording, renderEnabled, renderVerboseEnabled);
55
- installMouseLayer(emit, recording, mouseEnabled);
56
- installKeyboardLayer(emit, recording, keyboardEnabled);
65
+ installLifecycleLayer(out, capturing, lifecycleEnabled);
66
+ installRenderLayer(out, capturing, renderEnabled, renderVerboseEnabled);
67
+ installMouseLayer(out, capturing, mouseEnabled);
68
+ installKeyboardLayer(out, capturing, keyboardEnabled);
57
69
  // Flash-on-update rides the lifecycle wrappers but not the recording gate:
58
70
  // it's a page-side visual the panel toggles as a preference, so it follows the
59
71
  // settings override (read at boot, pushed live) rather than the layer state.
@@ -67,6 +79,12 @@ const hot = import.meta.hot;
67
79
  subscribeOverride(hot, (o) => {
68
80
  setFlashEnabled(o.flashUpdates ?? false);
69
81
  setFlashRamp(o.flashUpdatesRamp ?? false);
82
+ const next = o.chromeTracks ?? false;
83
+ if (next !== chromeTracks) {
84
+ chromeTracks = next;
85
+ if (!next) sink.reset();
86
+ syncRenderDebug();
87
+ }
70
88
  });
71
89
  if (hot !== undefined) {
72
90
  pageChannel.useViteHot(hot);
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/install.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Timeline runtime install entry point.\n *\n * Injected by the plugin into the host page via `transformIndexHtml` when\n * `timeline: true` is set. Sets up all capture layers and wires them to the\n * transport.\n *\n * Recording starts off; the panel iframe toggles it via the Vite HMR channel\n * (Phase 0/1) or devframe shared state (Phase 2+).\n */\n\nimport {emit, setHotClient} from './transport.js';\nimport {resetClock} from './clock.js';\nimport {installLifecycleLayer, setUpdateHook} from './lifecycle.js';\nimport {installRenderLayer, setRenderDebugEnabled} from './render.js';\nimport {installMouseLayer, installKeyboardLayer} from './input.js';\nimport {flashUpdate, setFlashEnabled, setFlashRamp} from './flash.js';\nimport {subscribeOverride} from '../overrides.js';\nimport {pageChannel} from '../page-channel.js';\nimport type {ViteHotLike} from '../page-channel.js';\nimport type {TimelineLayersState} from '../../../types/timeline.js';\n\n// ---------------------------------------------------------------------------\n// Recording state — written by the panel toggle, read by all capture layers.\n// ---------------------------------------------------------------------------\n\nconst state: TimelineLayersState = {\n recordingState: false,\n litLifecycleEnabled: true,\n litRenderEnabled: true,\n litRenderVerboseEnabled: false,\n mouseEventEnabled: false,\n keyboardEventEnabled: false,\n};\n\nconst recording = (): boolean => state.recordingState;\nconst lifecycleEnabled = (): boolean => state.litLifecycleEnabled;\nconst renderEnabled = (): boolean => state.litRenderEnabled;\nconst renderVerboseEnabled = (): boolean => state.litRenderVerboseEnabled;\nconst mouseEnabled = (): boolean => state.mouseEventEnabled;\nconst keyboardEnabled = (): boolean => state.keyboardEventEnabled;\n\n// Drive Lit's debug event flag from recording × (render-layer-enabled OR\n// verbose-layer-enabled) so lit-html only pays the per-render CustomEvent\n// dispatch cost while we're actually capturing one of the two render layers.\nconst syncRenderDebug = (): void => {\n setRenderDebugEnabled(\n state.recordingState &&\n (state.litRenderEnabled || state.litRenderVerboseEnabled)\n );\n};\n\n// ---------------------------------------------------------------------------\n// Capture layer installation\n// ---------------------------------------------------------------------------\n\ninstallLifecycleLayer(emit, recording, lifecycleEnabled);\ninstallRenderLayer(emit, recording, renderEnabled, renderVerboseEnabled);\ninstallMouseLayer(emit, recording, mouseEnabled);\ninstallKeyboardLayer(emit, recording, keyboardEnabled);\n\n// Flash-on-update rides the lifecycle wrappers but not the recording gate:\n// it's a page-side visual the panel toggles as a preference, so it follows the\n// settings override (read at boot, pushed live) rather than the layer state.\nsetUpdateHook(flashUpdate);\n\n// ---------------------------------------------------------------------------\n// Page channel wiring\n// ---------------------------------------------------------------------------\n\n// `import.meta.hot` exists in Vite dev builds; the tsconfig lib set doesn't\n// include it, so we access it through the un-typed global shape.\nconst hot = (import.meta as {hot?: ViteHotLike}).hot;\n\nsubscribeOverride(hot, (o) => {\n setFlashEnabled(o.flashUpdates ?? false);\n setFlashRamp(o.flashUpdatesRamp ?? false);\n});\n\nif (hot !== undefined) {\n pageChannel.useViteHot(hot);\n setHotClient(pageChannel);\n\n // Panel → app: toggle recording and per-layer flags.\n pageChannel.on('lit:timeline:recording-changed', (data) => {\n const next = (data as {recording: boolean}).recording;\n // Re-zero the timeline clock on the rising edge so event times read as\n // \"ms since recording started\" rather than since page load.\n if (next && !state.recordingState) resetClock();\n state.recordingState = next;\n syncRenderDebug();\n });\n\n pageChannel.on('lit:timeline:layers-changed', (data) => {\n Object.assign(state, data as Partial<TimelineLayersState>);\n syncRenderDebug();\n });\n\n // Announce readiness so the panel can detect the runtime.\n pageChannel.send('lit:timeline:runtime-ready', {});\n // A carrier attached later starts with no idea a runtime exists.\n pageChannel.onAttach(() =>\n pageChannel.send('lit:timeline:runtime-ready', {})\n );\n}\n"]}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/lib/runtime/timeline/install.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Timeline runtime install entry point.\n *\n * Injected by the plugin into the host page via `transformIndexHtml` when\n * `timeline: true` is set. Sets up all capture layers and wires them to the\n * transport.\n *\n * Recording starts off; the panel iframe toggles it via the Vite HMR channel\n * (Phase 0/1) or devframe shared state (Phase 2+). Layers capture while the\n * panel is recording OR the \"chrome performance tracks\" preference is on; the\n * panel transport only receives events while recording, the Chrome tracks sink\n * only while the preference is on.\n */\n\nimport {emit, setHotClient} from './transport.js';\nimport {resetClock} from './clock.js';\nimport {createChromeTracksSink} from './chrome-tracks.js';\nimport {installLifecycleLayer, setUpdateHook} from './lifecycle.js';\nimport {installRenderLayer, setRenderDebugEnabled} from './render.js';\nimport {installMouseLayer, installKeyboardLayer} from './input.js';\nimport {flashUpdate, setFlashEnabled, setFlashRamp} from './flash.js';\nimport {subscribeOverride} from '../overrides.js';\nimport {pageChannel} from '../page-channel.js';\nimport type {ViteHotLike} from '../page-channel.js';\nimport type {\n TimelineEvent,\n TimelineLayersState,\n} from '../../../types/timeline.js';\n\n// ---------------------------------------------------------------------------\n// Recording state — written by the panel toggle, read by all capture layers.\n// ---------------------------------------------------------------------------\n\nconst state: TimelineLayersState = {\n recordingState: false,\n litLifecycleEnabled: true,\n litRenderEnabled: true,\n litRenderVerboseEnabled: false,\n mouseEventEnabled: false,\n keyboardEventEnabled: false,\n};\n\n// Mirror to Chrome DevTools' Performance panel; a page-side preference driven\n// by the settings override, independent of panel recording.\nlet chromeTracks = false;\nconst sink = createChromeTracksSink();\n\n// Layers run when either consumer wants events.\nconst capturing = (): boolean => state.recordingState || chromeTracks;\nconst out = (e: TimelineEvent): void => {\n if (state.recordingState) emit(e);\n if (chromeTracks) sink.push(e);\n};\nconst lifecycleEnabled = (): boolean => state.litLifecycleEnabled;\nconst renderEnabled = (): boolean => state.litRenderEnabled;\nconst renderVerboseEnabled = (): boolean => state.litRenderVerboseEnabled;\nconst mouseEnabled = (): boolean => state.mouseEventEnabled;\nconst keyboardEnabled = (): boolean => state.keyboardEventEnabled;\n\n// Drive Lit's debug event flag from capturing × (render-layer-enabled OR\n// verbose-layer-enabled) so lit-html only pays the per-render CustomEvent\n// dispatch cost while we're actually capturing one of the two render layers.\nconst syncRenderDebug = (): void => {\n setRenderDebugEnabled(\n capturing() && (state.litRenderEnabled || state.litRenderVerboseEnabled)\n );\n};\n\n// ---------------------------------------------------------------------------\n// Capture layer installation\n// ---------------------------------------------------------------------------\n\ninstallLifecycleLayer(out, capturing, lifecycleEnabled);\ninstallRenderLayer(out, capturing, renderEnabled, renderVerboseEnabled);\ninstallMouseLayer(out, capturing, mouseEnabled);\ninstallKeyboardLayer(out, capturing, keyboardEnabled);\n\n// Flash-on-update rides the lifecycle wrappers but not the recording gate:\n// it's a page-side visual the panel toggles as a preference, so it follows the\n// settings override (read at boot, pushed live) rather than the layer state.\nsetUpdateHook(flashUpdate);\n\n// ---------------------------------------------------------------------------\n// Page channel wiring\n// ---------------------------------------------------------------------------\n\n// `import.meta.hot` exists in Vite dev builds; the tsconfig lib set doesn't\n// include it, so we access it through the un-typed global shape.\nconst hot = (import.meta as {hot?: ViteHotLike}).hot;\n\nsubscribeOverride(hot, (o) => {\n setFlashEnabled(o.flashUpdates ?? false);\n setFlashRamp(o.flashUpdatesRamp ?? false);\n const next = o.chromeTracks ?? false;\n if (next !== chromeTracks) {\n chromeTracks = next;\n if (!next) sink.reset();\n syncRenderDebug();\n }\n});\n\nif (hot !== undefined) {\n pageChannel.useViteHot(hot);\n setHotClient(pageChannel);\n\n // Panel → app: toggle recording and per-layer flags.\n pageChannel.on('lit:timeline:recording-changed', (data) => {\n const next = (data as {recording: boolean}).recording;\n // Re-zero the timeline clock on the rising edge so event times read as\n // \"ms since recording started\" rather than since page load.\n if (next && !state.recordingState) resetClock();\n state.recordingState = next;\n syncRenderDebug();\n });\n\n pageChannel.on('lit:timeline:layers-changed', (data) => {\n Object.assign(state, data as Partial<TimelineLayersState>);\n syncRenderDebug();\n });\n\n // Announce readiness so the panel can detect the runtime.\n pageChannel.send('lit:timeline:runtime-ready', {});\n // A carrier attached later starts with no idea a runtime exists.\n pageChannel.onAttach(() =>\n pageChannel.send('lit:timeline:runtime-ready', {})\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oddsquad/vite-plugin-lit",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Vite plugin providing true HMR for Lit components, plus CSS helpers and a DevTools panel",
5
5
  "license": "BSD-3-Clause",
6
6
  "author": "Oddsquad (based on @lit-labs/vite-hmr by Google LLC)",
@@ -128,6 +128,12 @@ export interface SettingsOverride {
128
128
  * {@link SettingsOverride.flashUpdates}.
129
129
  */
130
130
  flashUpdatesRamp?: boolean;
131
+ /**
132
+ * Mirror the timeline into Chrome DevTools' Performance panel as custom
133
+ * tracks (via `console.timeStamp`), independent of panel recording. Pure
134
+ * preference (no config-time baseline), so `undefined` reads as off.
135
+ */
136
+ chromeTracks?: boolean;
131
137
  }
132
138
  /**
133
139
  * Built-in editors the source overlay can open files in. Keep in sync with
@@ -1 +1 @@
1
- {"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/types/timeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/types/timeline.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"timeline.js","sourceRoot":"","sources":["../src/types/timeline.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkDH,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,EAAC,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAC;IAC9D,EAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAC;IACxD,EAAC,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,QAAQ,EAAC;IAC1E,EAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAC;IAC9C,EAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAC;CACrD,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAwB;IACvD,cAAc,EAAE,KAAK;IACrB,mBAAmB,EAAE,IAAI;IACzB,gBAAgB,EAAE,IAAI;IACtB,uBAAuB,EAAE,KAAK;IAC9B,iBAAiB,EAAE,KAAK;IACxB,oBAAoB,EAAE,KAAK;CAC5B,CAAC;AAkFF;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAG9B;IACH,EAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAC;IACnC,EAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAC;IAClC,EAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAC;IAC5B,EAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAC;IAClC,EAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAC;CACvC,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,MAAM,wBAAwB,GAAG,wBAAwB,CAAC;AAmBjE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,yBAAyB,GAAG,iCAAiC,CAAC;AAE3E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,yBAAyB,GAAG,gCAAgC,CAAC;AAE1E;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GACxC,oCAAoC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nexport interface TimelineLayer {\n id: string;\n label: string;\n color: number; // 0xRRGGBB\n}\n\nexport interface TimelineEvent<TData = unknown> {\n /**\n * Stable identity, stamped on the Node side (`${epoch}-${seq}`) when the\n * event is received, so it survives the stream, `recent-events` and a\n * snapshot export. Absent on events still in the page runtime.\n */\n id?: string;\n layerId: string;\n /**\n * Milliseconds since recording started, stamped in the browser page\n * (`performance.now()` re-zeroed on each recording start; see\n * `runtime/timeline/clock.ts`). Not comparable to any Node-side clock.\n */\n time: number;\n data: TData;\n title?: string;\n subtitle?: string;\n /** Pairs a start event with its matching end event in the same update group. */\n groupId?: number | string;\n logType?: 'default' | 'warning' | 'error';\n meta?: {\n elementId?: number;\n tagName?: string;\n source?: {file: string; line: number};\n };\n}\n\nexport interface TimelineLayersState {\n recordingState: boolean;\n litLifecycleEnabled: boolean;\n litRenderEnabled: boolean;\n /**\n * Per-part `lit-debug` events (`template updating`, `set part`, `commit\n * *`, …) — one per binding on *every* render, so a ticking clock or\n * animation floods the layer. Off by default; the `lit-render` layer's\n * begin/end render pair already covers the common case.\n */\n litRenderVerboseEnabled: boolean;\n mouseEventEnabled: boolean;\n keyboardEventEnabled: boolean;\n}\n\nexport const TIMELINE_LAYERS: readonly TimelineLayer[] = [\n {id: 'lit-lifecycle', label: 'Lit Lifecycle', color: 0x4d63ff},\n {id: 'lit-render', label: 'Lit Render', color: 0x325cff},\n {id: 'lit-render-verbose', label: 'Lit Render (verbose)', color: 0x99aeff},\n {id: 'mouse', label: 'Mouse', color: 0xa451af},\n {id: 'keyboard', label: 'Keyboard', color: 0x8151af},\n];\n\nexport const DEFAULT_LAYERS_STATE: TimelineLayersState = {\n recordingState: false,\n litLifecycleEnabled: true,\n litRenderEnabled: true,\n litRenderVerboseEnabled: false,\n mouseEventEnabled: false,\n keyboardEventEnabled: false,\n};\n\n/**\n * Snapshot of the plugin's resolved feature settings, surfaced in the panel's\n * Settings tab. The plugin produces this at config time (explicit options >\n * LIT_PLUGIN_* env > defaults) and serves it from the panel server. It's the\n * baseline the panel shows; some HMR settings can then be overridden live (see\n * {@link SettingsOverride}).\n */\nexport interface FeatureSettings {\n hmr: {\n enabled: boolean;\n reconnect: boolean;\n onIncompatible: 'reload' | 'warn';\n indicatorEnabled: boolean;\n indicatorCount: boolean;\n };\n sourceOverlay: {\n enabled: boolean;\n /** Hotkey letter combined with Ctrl+Shift to toggle the overlay. */\n key: string;\n editor: string;\n throttleMs: number;\n };\n timeline: boolean;\n /**\n * Which layer supplied each setting, keyed like {@link SettingsOverride}\n * (plus the read-only source-overlay rows). Lets the panel label a value\n * \"Zed (env)\" and name the baseline a panel override replaced. Optional so\n * older producers (and snapshots) without it still type-check.\n */\n sources?: SettingSources;\n}\n\n/**\n * Where a resolved setting came from, in precedence order after a panel\n * override: an explicit `litPlugin({...})` option, a `LIT_PLUGIN_*` env var,\n * or the built-in default.\n */\nexport type SettingSource = 'option' | 'env' | 'default';\n\n/** Per-setting {@link SettingSource}, as carried on {@link FeatureSettings}. */\nexport interface SettingSources {\n hmrReconnect?: SettingSource;\n hmrOnIncompatible?: SettingSource;\n hmrIndicatorVisible?: SettingSource;\n hmrIndicatorCount?: SettingSource;\n sourceOverlayEditor?: SettingSource;\n sourceOverlayKey?: SettingSource;\n sourceOverlayThrottleMs?: SettingSource;\n}\n\n/**\n * Runtime overrides the panel applies on top of the resolved env config, for\n * settings whose runtime is already injected (so they can change live). A\n * feature disabled at config time has no runtime, so it can't be enabled here\n * — only the behaviour of already-enabled features is overridable.\n *\n * Persisted under {@link SETTINGS_OVERRIDE_LS_KEY} (the panel and app share an\n * origin) so overrides survive reloads, and pushed live over\n * {@link SETTINGS_OVERRIDE_CHANNEL} via Vite HMR for immediate effect.\n */\nexport interface SettingsOverride {\n hmrReconnect?: boolean;\n hmrOnIncompatible?: 'reload' | 'warn';\n hmrIndicatorVisible?: boolean;\n hmrIndicatorCount?: boolean;\n /** Built-in editor key for the source overlay's open-in-editor target. */\n sourceOverlayEditor?: string;\n /**\n * Flash a short outline over every Lit element that completes an update.\n * Pure preference (no config-time baseline), so `undefined` reads as off.\n */\n flashUpdates?: boolean;\n /**\n * Colour the flash by how often the element updated in the last second,\n * calm to hot, instead of one flat colour. Only meaningful with\n * {@link SettingsOverride.flashUpdates}.\n */\n flashUpdatesRamp?: boolean;\n}\n\n/**\n * Built-in editors the source overlay can open files in. Keep in sync with\n * BUILTIN_EDITORS in lib/runtime/source-overlay/editors.ts.\n */\nexport const SOURCE_OVERLAY_EDITORS: ReadonlyArray<{\n value: string;\n label: string;\n}> = [\n {value: 'vscode', label: 'VS Code'},\n {value: 'cursor', label: 'Cursor'},\n {value: 'zed', label: 'Zed'},\n {value: 'idea', label: 'IntelliJ'},\n {value: 'windsurf', label: 'Windsurf'},\n];\n\n/** localStorage key holding the {@link SettingsOverride}. */\nexport const SETTINGS_OVERRIDE_LS_KEY = 'lit-devtools-overrides';\n\n/**\n * The resolved config value each overridden key was set against, recorded so\n * the Settings tab can notice when `.env` or plugin options moved on. Kept\n * beside the {@link SettingsOverride}, never inside it: the runtime applies and\n * receives the override as-is and has no use for these.\n */\nexport type OverrideBaselines = Partial<\n Record<\n | 'hmrReconnect'\n | 'hmrOnIncompatible'\n | 'hmrIndicatorVisible'\n | 'hmrIndicatorCount'\n | 'sourceOverlayEditor',\n unknown\n >\n>;\n\n/** localStorage key holding the {@link OverrideBaselines}. */\nexport const OVERRIDE_BASELINES_LS_KEY = 'lit-devtools-override-baselines';\n\n/** Vite HMR channel the server uses to push overrides to the app runtime. */\nexport const SETTINGS_OVERRIDE_CHANNEL = 'lit-devtools:settings-override';\n\n/**\n * Vite HMR channel the DevTools \"toggle source overlay\" command uses to tell\n * the app runtime to toggle the overlay (the command handler runs server-side).\n */\nexport const SOURCE_OVERLAY_TOGGLE_CHANNEL =\n 'lit-devtools:toggle-source-overlay';\n"]}
1
+ {"version":3,"file":"timeline.js","sourceRoot":"","sources":["../src/types/timeline.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkDH,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,EAAC,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAC;IAC9D,EAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAC;IACxD,EAAC,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,QAAQ,EAAC;IAC1E,EAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAC;IAC9C,EAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAC;CACrD,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAwB;IACvD,cAAc,EAAE,KAAK;IACrB,mBAAmB,EAAE,IAAI;IACzB,gBAAgB,EAAE,IAAI;IACtB,uBAAuB,EAAE,KAAK;IAC9B,iBAAiB,EAAE,KAAK;IACxB,oBAAoB,EAAE,KAAK;CAC5B,CAAC;AAwFF;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAG9B;IACH,EAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAC;IACnC,EAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAC;IAClC,EAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAC;IAC5B,EAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAC;IAClC,EAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAC;CACvC,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,MAAM,wBAAwB,GAAG,wBAAwB,CAAC;AAmBjE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,yBAAyB,GAAG,iCAAiC,CAAC;AAE3E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,yBAAyB,GAAG,gCAAgC,CAAC;AAE1E;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GACxC,oCAAoC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nexport interface TimelineLayer {\n id: string;\n label: string;\n color: number; // 0xRRGGBB\n}\n\nexport interface TimelineEvent<TData = unknown> {\n /**\n * Stable identity, stamped on the Node side (`${epoch}-${seq}`) when the\n * event is received, so it survives the stream, `recent-events` and a\n * snapshot export. Absent on events still in the page runtime.\n */\n id?: string;\n layerId: string;\n /**\n * Milliseconds since recording started, stamped in the browser page\n * (`performance.now()` re-zeroed on each recording start; see\n * `runtime/timeline/clock.ts`). Not comparable to any Node-side clock.\n */\n time: number;\n data: TData;\n title?: string;\n subtitle?: string;\n /** Pairs a start event with its matching end event in the same update group. */\n groupId?: number | string;\n logType?: 'default' | 'warning' | 'error';\n meta?: {\n elementId?: number;\n tagName?: string;\n source?: {file: string; line: number};\n };\n}\n\nexport interface TimelineLayersState {\n recordingState: boolean;\n litLifecycleEnabled: boolean;\n litRenderEnabled: boolean;\n /**\n * Per-part `lit-debug` events (`template updating`, `set part`, `commit\n * *`, …) — one per binding on *every* render, so a ticking clock or\n * animation floods the layer. Off by default; the `lit-render` layer's\n * begin/end render pair already covers the common case.\n */\n litRenderVerboseEnabled: boolean;\n mouseEventEnabled: boolean;\n keyboardEventEnabled: boolean;\n}\n\nexport const TIMELINE_LAYERS: readonly TimelineLayer[] = [\n {id: 'lit-lifecycle', label: 'Lit Lifecycle', color: 0x4d63ff},\n {id: 'lit-render', label: 'Lit Render', color: 0x325cff},\n {id: 'lit-render-verbose', label: 'Lit Render (verbose)', color: 0x99aeff},\n {id: 'mouse', label: 'Mouse', color: 0xa451af},\n {id: 'keyboard', label: 'Keyboard', color: 0x8151af},\n];\n\nexport const DEFAULT_LAYERS_STATE: TimelineLayersState = {\n recordingState: false,\n litLifecycleEnabled: true,\n litRenderEnabled: true,\n litRenderVerboseEnabled: false,\n mouseEventEnabled: false,\n keyboardEventEnabled: false,\n};\n\n/**\n * Snapshot of the plugin's resolved feature settings, surfaced in the panel's\n * Settings tab. The plugin produces this at config time (explicit options >\n * LIT_PLUGIN_* env > defaults) and serves it from the panel server. It's the\n * baseline the panel shows; some HMR settings can then be overridden live (see\n * {@link SettingsOverride}).\n */\nexport interface FeatureSettings {\n hmr: {\n enabled: boolean;\n reconnect: boolean;\n onIncompatible: 'reload' | 'warn';\n indicatorEnabled: boolean;\n indicatorCount: boolean;\n };\n sourceOverlay: {\n enabled: boolean;\n /** Hotkey letter combined with Ctrl+Shift to toggle the overlay. */\n key: string;\n editor: string;\n throttleMs: number;\n };\n timeline: boolean;\n /**\n * Which layer supplied each setting, keyed like {@link SettingsOverride}\n * (plus the read-only source-overlay rows). Lets the panel label a value\n * \"Zed (env)\" and name the baseline a panel override replaced. Optional so\n * older producers (and snapshots) without it still type-check.\n */\n sources?: SettingSources;\n}\n\n/**\n * Where a resolved setting came from, in precedence order after a panel\n * override: an explicit `litPlugin({...})` option, a `LIT_PLUGIN_*` env var,\n * or the built-in default.\n */\nexport type SettingSource = 'option' | 'env' | 'default';\n\n/** Per-setting {@link SettingSource}, as carried on {@link FeatureSettings}. */\nexport interface SettingSources {\n hmrReconnect?: SettingSource;\n hmrOnIncompatible?: SettingSource;\n hmrIndicatorVisible?: SettingSource;\n hmrIndicatorCount?: SettingSource;\n sourceOverlayEditor?: SettingSource;\n sourceOverlayKey?: SettingSource;\n sourceOverlayThrottleMs?: SettingSource;\n}\n\n/**\n * Runtime overrides the panel applies on top of the resolved env config, for\n * settings whose runtime is already injected (so they can change live). A\n * feature disabled at config time has no runtime, so it can't be enabled here\n * — only the behaviour of already-enabled features is overridable.\n *\n * Persisted under {@link SETTINGS_OVERRIDE_LS_KEY} (the panel and app share an\n * origin) so overrides survive reloads, and pushed live over\n * {@link SETTINGS_OVERRIDE_CHANNEL} via Vite HMR for immediate effect.\n */\nexport interface SettingsOverride {\n hmrReconnect?: boolean;\n hmrOnIncompatible?: 'reload' | 'warn';\n hmrIndicatorVisible?: boolean;\n hmrIndicatorCount?: boolean;\n /** Built-in editor key for the source overlay's open-in-editor target. */\n sourceOverlayEditor?: string;\n /**\n * Flash a short outline over every Lit element that completes an update.\n * Pure preference (no config-time baseline), so `undefined` reads as off.\n */\n flashUpdates?: boolean;\n /**\n * Colour the flash by how often the element updated in the last second,\n * calm to hot, instead of one flat colour. Only meaningful with\n * {@link SettingsOverride.flashUpdates}.\n */\n flashUpdatesRamp?: boolean;\n /**\n * Mirror the timeline into Chrome DevTools' Performance panel as custom\n * tracks (via `console.timeStamp`), independent of panel recording. Pure\n * preference (no config-time baseline), so `undefined` reads as off.\n */\n chromeTracks?: boolean;\n}\n\n/**\n * Built-in editors the source overlay can open files in. Keep in sync with\n * BUILTIN_EDITORS in lib/runtime/source-overlay/editors.ts.\n */\nexport const SOURCE_OVERLAY_EDITORS: ReadonlyArray<{\n value: string;\n label: string;\n}> = [\n {value: 'vscode', label: 'VS Code'},\n {value: 'cursor', label: 'Cursor'},\n {value: 'zed', label: 'Zed'},\n {value: 'idea', label: 'IntelliJ'},\n {value: 'windsurf', label: 'Windsurf'},\n];\n\n/** localStorage key holding the {@link SettingsOverride}. */\nexport const SETTINGS_OVERRIDE_LS_KEY = 'lit-devtools-overrides';\n\n/**\n * The resolved config value each overridden key was set against, recorded so\n * the Settings tab can notice when `.env` or plugin options moved on. Kept\n * beside the {@link SettingsOverride}, never inside it: the runtime applies and\n * receives the override as-is and has no use for these.\n */\nexport type OverrideBaselines = Partial<\n Record<\n | 'hmrReconnect'\n | 'hmrOnIncompatible'\n | 'hmrIndicatorVisible'\n | 'hmrIndicatorCount'\n | 'sourceOverlayEditor',\n unknown\n >\n>;\n\n/** localStorage key holding the {@link OverrideBaselines}. */\nexport const OVERRIDE_BASELINES_LS_KEY = 'lit-devtools-override-baselines';\n\n/** Vite HMR channel the server uses to push overrides to the app runtime. */\nexport const SETTINGS_OVERRIDE_CHANNEL = 'lit-devtools:settings-override';\n\n/**\n * Vite HMR channel the DevTools \"toggle source overlay\" command uses to tell\n * the app runtime to toggle the overlay (the command handler runs server-side).\n */\nexport const SOURCE_OVERLAY_TOGGLE_CHANNEL =\n 'lit-devtools:toggle-source-overlay';\n"]}