@oddsquad/vite-plugin-lit 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/LICENSE +1 -1
  3. package/README.md +40 -17
  4. package/bin.mjs +89 -13
  5. package/client.d.ts +0 -6
  6. package/dist/client/assets/{browser-agent-rpc-BXhoSh1z-F2EfZsFX.js → browser-agent-rpc-BXhoSh1z-ybEeG-x9.js} +2 -2
  7. package/dist/client/assets/{browser-agent-rpc-BXhoSh1z-F2EfZsFX.js.map → browser-agent-rpc-BXhoSh1z-ybEeG-x9.js.map} +1 -1
  8. package/dist/client/assets/{index-B2HYO7lk.js → index-CgkhETVR.js} +22 -145
  9. package/dist/client/assets/index-CgkhETVR.js.map +1 -0
  10. package/dist/client/index.html +1 -1
  11. package/dist/standalone/lit-devtools.js +6717 -0
  12. package/index.d.ts +0 -5
  13. package/index.d.ts.map +1 -1
  14. package/index.js +1 -5
  15. package/index.js.map +1 -1
  16. package/lib/color-scheme.d.ts +0 -5
  17. package/lib/color-scheme.d.ts.map +1 -1
  18. package/lib/color-scheme.js +0 -5
  19. package/lib/color-scheme.js.map +1 -1
  20. package/lib/confine.d.ts +0 -5
  21. package/lib/confine.d.ts.map +1 -1
  22. package/lib/confine.js +0 -5
  23. package/lib/confine.js.map +1 -1
  24. package/lib/devframe/allowed-origins.d.ts +21 -0
  25. package/lib/devframe/allowed-origins.d.ts.map +1 -0
  26. package/lib/devframe/allowed-origins.js +58 -0
  27. package/lib/devframe/allowed-origins.js.map +1 -0
  28. package/lib/devframe/definition.d.ts +7 -3
  29. package/lib/devframe/definition.d.ts.map +1 -1
  30. package/lib/devframe/definition.js +1 -6
  31. package/lib/devframe/definition.js.map +1 -1
  32. package/lib/devframe/icon.d.ts +0 -5
  33. package/lib/devframe/icon.d.ts.map +1 -1
  34. package/lib/devframe/icon.js +0 -5
  35. package/lib/devframe/icon.js.map +1 -1
  36. package/lib/devframe/launch-editor.d.ts +0 -5
  37. package/lib/devframe/launch-editor.d.ts.map +1 -1
  38. package/lib/devframe/launch-editor.js +0 -5
  39. package/lib/devframe/launch-editor.js.map +1 -1
  40. package/lib/devframe/paths.d.ts +8 -3
  41. package/lib/devframe/paths.d.ts.map +1 -1
  42. package/lib/devframe/paths.js +0 -5
  43. package/lib/devframe/paths.js.map +1 -1
  44. package/lib/devframe/protocol.d.ts +6 -3
  45. package/lib/devframe/protocol.d.ts.map +1 -1
  46. package/lib/devframe/protocol.js +0 -5
  47. package/lib/devframe/protocol.js.map +1 -1
  48. package/lib/devframe/rpc-source.d.ts +15 -3
  49. package/lib/devframe/rpc-source.d.ts.map +1 -1
  50. package/lib/devframe/rpc-source.js +0 -5
  51. package/lib/devframe/rpc-source.js.map +1 -1
  52. package/lib/devframe/source.d.ts +0 -5
  53. package/lib/devframe/source.d.ts.map +1 -1
  54. package/lib/devframe/source.js +7 -3
  55. package/lib/devframe/source.js.map +1 -1
  56. package/lib/devframe/vite.d.ts +0 -5
  57. package/lib/devframe/vite.d.ts.map +1 -1
  58. package/lib/devframe/vite.js +16 -3
  59. package/lib/devframe/vite.js.map +1 -1
  60. package/lib/http.d.ts +0 -5
  61. package/lib/http.d.ts.map +1 -1
  62. package/lib/http.js +0 -5
  63. package/lib/http.js.map +1 -1
  64. package/lib/icons.d.ts +0 -5
  65. package/lib/icons.d.ts.map +1 -1
  66. package/lib/icons.js +0 -5
  67. package/lib/icons.js.map +1 -1
  68. package/lib/options.d.ts +26 -5
  69. package/lib/options.d.ts.map +1 -1
  70. package/lib/options.js +19 -5
  71. package/lib/options.js.map +1 -1
  72. package/lib/override-baselines.d.ts +0 -5
  73. package/lib/override-baselines.d.ts.map +1 -1
  74. package/lib/override-baselines.js +0 -5
  75. package/lib/override-baselines.js.map +1 -1
  76. package/lib/plugin.d.ts +0 -5
  77. package/lib/plugin.d.ts.map +1 -1
  78. package/lib/plugin.js +3 -5
  79. package/lib/plugin.js.map +1 -1
  80. package/lib/plugins/css-literals.d.ts +0 -5
  81. package/lib/plugins/css-literals.d.ts.map +1 -1
  82. package/lib/plugins/css-literals.js +0 -5
  83. package/lib/plugins/css-literals.js.map +1 -1
  84. package/lib/plugins/css-queries.d.ts +0 -5
  85. package/lib/plugins/css-queries.d.ts.map +1 -1
  86. package/lib/plugins/css-queries.js +0 -5
  87. package/lib/plugins/css-queries.js.map +1 -1
  88. package/lib/plugins/open-in-editor.d.ts +0 -5
  89. package/lib/plugins/open-in-editor.d.ts.map +1 -1
  90. package/lib/plugins/open-in-editor.js +0 -5
  91. package/lib/plugins/open-in-editor.js.map +1 -1
  92. package/lib/plugins/private-fields.d.ts +22 -0
  93. package/lib/plugins/private-fields.d.ts.map +1 -0
  94. package/lib/plugins/private-fields.js +254 -0
  95. package/lib/plugins/private-fields.js.map +1 -0
  96. package/lib/plugins/shared.d.ts +0 -5
  97. package/lib/plugins/shared.d.ts.map +1 -1
  98. package/lib/plugins/shared.js +0 -5
  99. package/lib/plugins/shared.js.map +1 -1
  100. package/lib/plugins/timeline-virtual.d.ts +0 -5
  101. package/lib/plugins/timeline-virtual.d.ts.map +1 -1
  102. package/lib/plugins/timeline-virtual.js +0 -5
  103. package/lib/plugins/timeline-virtual.js.map +1 -1
  104. package/lib/runtime/child-state.d.ts +95 -0
  105. package/lib/runtime/child-state.d.ts.map +1 -0
  106. package/lib/runtime/child-state.js +461 -0
  107. package/lib/runtime/child-state.js.map +1 -0
  108. package/lib/runtime/css.d.ts +14 -3
  109. package/lib/runtime/css.d.ts.map +1 -1
  110. package/lib/runtime/css.js +3 -5
  111. package/lib/runtime/css.js.map +1 -1
  112. package/lib/runtime/edge-panel.d.ts +8 -3
  113. package/lib/runtime/edge-panel.d.ts.map +1 -1
  114. package/lib/runtime/edge-panel.js +0 -5
  115. package/lib/runtime/edge-panel.js.map +1 -1
  116. package/lib/runtime/fonts.d.ts +0 -5
  117. package/lib/runtime/fonts.d.ts.map +1 -1
  118. package/lib/runtime/fonts.js +0 -5
  119. package/lib/runtime/fonts.js.map +1 -1
  120. package/lib/runtime/indicator.d.ts +3 -3
  121. package/lib/runtime/indicator.js +0 -5
  122. package/lib/runtime/indicator.js.map +1 -1
  123. package/lib/runtime/inspector/collect.d.ts +3 -3
  124. package/lib/runtime/inspector/collect.d.ts.map +1 -1
  125. package/lib/runtime/inspector/collect.js +0 -5
  126. package/lib/runtime/inspector/collect.js.map +1 -1
  127. package/lib/runtime/inspector/highlight.d.ts +10 -3
  128. package/lib/runtime/inspector/highlight.d.ts.map +1 -1
  129. package/lib/runtime/inspector/highlight.js +0 -5
  130. package/lib/runtime/inspector/highlight.js.map +1 -1
  131. package/lib/runtime/inspector/install.d.ts +6 -3
  132. package/lib/runtime/inspector/install.d.ts.map +1 -1
  133. package/lib/runtime/inspector/install.js +4 -6
  134. package/lib/runtime/inspector/install.js.map +1 -1
  135. package/lib/runtime/inspector/serialize.d.ts +4 -3
  136. package/lib/runtime/inspector/serialize.d.ts.map +1 -1
  137. package/lib/runtime/inspector/serialize.js +0 -5
  138. package/lib/runtime/inspector/serialize.js.map +1 -1
  139. package/lib/runtime/intern.d.ts +11 -3
  140. package/lib/runtime/intern.d.ts.map +1 -1
  141. package/lib/runtime/intern.js +11 -3
  142. package/lib/runtime/intern.js.map +1 -1
  143. package/lib/runtime/overrides.d.ts +3 -3
  144. package/lib/runtime/overrides.d.ts.map +1 -1
  145. package/lib/runtime/overrides.js +0 -5
  146. package/lib/runtime/overrides.js.map +1 -1
  147. package/lib/runtime/page-channel.d.ts +0 -5
  148. package/lib/runtime/page-channel.d.ts.map +1 -1
  149. package/lib/runtime/page-channel.js +13 -3
  150. package/lib/runtime/page-channel.js.map +1 -1
  151. package/lib/runtime/patch.d.ts +22 -3
  152. package/lib/runtime/patch.d.ts.map +1 -1
  153. package/lib/runtime/patch.js +22 -6
  154. package/lib/runtime/patch.js.map +1 -1
  155. package/lib/runtime/rpc-transport.d.ts +21 -3
  156. package/lib/runtime/rpc-transport.d.ts.map +1 -1
  157. package/lib/runtime/rpc-transport.js +4 -5
  158. package/lib/runtime/rpc-transport.js.map +1 -1
  159. package/lib/runtime/source-meta.d.ts +0 -5
  160. package/lib/runtime/source-meta.d.ts.map +1 -1
  161. package/lib/runtime/source-meta.js +0 -5
  162. package/lib/runtime/source-meta.js.map +1 -1
  163. package/lib/runtime/source-overlay/editors.d.ts +0 -5
  164. package/lib/runtime/source-overlay/editors.d.ts.map +1 -1
  165. package/lib/runtime/source-overlay/editors.js +9 -9
  166. package/lib/runtime/source-overlay/editors.js.map +1 -1
  167. package/lib/runtime/source-overlay/mask-path.d.ts +0 -5
  168. package/lib/runtime/source-overlay/mask-path.d.ts.map +1 -1
  169. package/lib/runtime/source-overlay/mask-path.js +0 -5
  170. package/lib/runtime/source-overlay/mask-path.js.map +1 -1
  171. package/lib/runtime/source-overlay/overlay-element.d.ts +0 -5
  172. package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -1
  173. package/lib/runtime/source-overlay/overlay-element.js +0 -5
  174. package/lib/runtime/source-overlay/overlay-element.js.map +1 -1
  175. package/lib/runtime/source-overlay/source-host.d.ts +0 -5
  176. package/lib/runtime/source-overlay/source-host.d.ts.map +1 -1
  177. package/lib/runtime/source-overlay/source-host.js +0 -5
  178. package/lib/runtime/source-overlay/source-host.js.map +1 -1
  179. package/lib/runtime/source-overlay/template.d.ts +0 -5
  180. package/lib/runtime/source-overlay/template.d.ts.map +1 -1
  181. package/lib/runtime/source-overlay/template.js +0 -5
  182. package/lib/runtime/source-overlay/template.js.map +1 -1
  183. package/lib/runtime/source-overlay.d.ts +0 -5
  184. package/lib/runtime/source-overlay.d.ts.map +1 -1
  185. package/lib/runtime/source-overlay.js +0 -5
  186. package/lib/runtime/source-overlay.js.map +1 -1
  187. package/lib/runtime/standalone.d.ts +22 -0
  188. package/lib/runtime/standalone.d.ts.map +1 -0
  189. package/lib/runtime/standalone.js +45 -0
  190. package/lib/runtime/standalone.js.map +1 -0
  191. package/lib/runtime/timeline/chrome-tracks.d.ts +0 -5
  192. package/lib/runtime/timeline/chrome-tracks.d.ts.map +1 -1
  193. package/lib/runtime/timeline/chrome-tracks.js +5 -3
  194. package/lib/runtime/timeline/chrome-tracks.js.map +1 -1
  195. package/lib/runtime/timeline/clock.d.ts +7 -3
  196. package/lib/runtime/timeline/clock.d.ts.map +1 -1
  197. package/lib/runtime/timeline/clock.js +0 -5
  198. package/lib/runtime/timeline/clock.js.map +1 -1
  199. package/lib/runtime/timeline/flash.d.ts +0 -5
  200. package/lib/runtime/timeline/flash.d.ts.map +1 -1
  201. package/lib/runtime/timeline/flash.js +15 -3
  202. package/lib/runtime/timeline/flash.js.map +1 -1
  203. package/lib/runtime/timeline/identity.d.ts +0 -5
  204. package/lib/runtime/timeline/identity.d.ts.map +1 -1
  205. package/lib/runtime/timeline/identity.js +9 -3
  206. package/lib/runtime/timeline/identity.js.map +1 -1
  207. package/lib/runtime/timeline/input.d.ts +0 -5
  208. package/lib/runtime/timeline/input.d.ts.map +1 -1
  209. package/lib/runtime/timeline/input.js +2 -3
  210. package/lib/runtime/timeline/input.js.map +1 -1
  211. package/lib/runtime/timeline/install.d.ts +11 -3
  212. package/lib/runtime/timeline/install.d.ts.map +1 -1
  213. package/lib/runtime/timeline/install.js +4 -7
  214. package/lib/runtime/timeline/install.js.map +1 -1
  215. package/lib/runtime/timeline/lifecycle.d.ts +13 -3
  216. package/lib/runtime/timeline/lifecycle.d.ts.map +1 -1
  217. package/lib/runtime/timeline/lifecycle.js +5 -6
  218. package/lib/runtime/timeline/lifecycle.js.map +1 -1
  219. package/lib/runtime/timeline/public-api.d.ts +6 -3
  220. package/lib/runtime/timeline/public-api.d.ts.map +1 -1
  221. package/lib/runtime/timeline/public-api.js +0 -5
  222. package/lib/runtime/timeline/public-api.js.map +1 -1
  223. package/lib/runtime/timeline/render.d.ts +0 -5
  224. package/lib/runtime/timeline/render.d.ts.map +1 -1
  225. package/lib/runtime/timeline/render.js +21 -3
  226. package/lib/runtime/timeline/render.js.map +1 -1
  227. package/lib/runtime/timeline/transport.d.ts +0 -5
  228. package/lib/runtime/timeline/transport.d.ts.map +1 -1
  229. package/lib/runtime/timeline/transport.js +10 -3
  230. package/lib/runtime/timeline/transport.js.map +1 -1
  231. package/lib/segmented-tabs.d.ts +0 -5
  232. package/lib/segmented-tabs.d.ts.map +1 -1
  233. package/lib/segmented-tabs.js +0 -5
  234. package/lib/segmented-tabs.js.map +1 -1
  235. package/lib/snapshot.d.ts +11 -3
  236. package/lib/snapshot.d.ts.map +1 -1
  237. package/lib/snapshot.js +0 -5
  238. package/lib/snapshot.js.map +1 -1
  239. package/lib/source-meta.d.ts +0 -5
  240. package/lib/source-meta.d.ts.map +1 -1
  241. package/lib/source-meta.js +0 -5
  242. package/lib/source-meta.js.map +1 -1
  243. package/lib/timeline/derive.d.ts +0 -5
  244. package/lib/timeline/derive.d.ts.map +1 -1
  245. package/lib/timeline/derive.js +22 -3
  246. package/lib/timeline/derive.js.map +1 -1
  247. package/lib/timeline/filter.d.ts +0 -5
  248. package/lib/timeline/filter.d.ts.map +1 -1
  249. package/lib/timeline/filter.js +6 -3
  250. package/lib/timeline/filter.js.map +1 -1
  251. package/lib/timeline/tracks.d.ts +0 -5
  252. package/lib/timeline/tracks.d.ts.map +1 -1
  253. package/lib/timeline/tracks.js +12 -3
  254. package/lib/timeline/tracks.js.map +1 -1
  255. package/lib/tokens.d.ts +0 -5
  256. package/lib/tokens.d.ts.map +1 -1
  257. package/lib/tokens.js +0 -5
  258. package/lib/tokens.js.map +1 -1
  259. package/lib/transform.d.ts +0 -5
  260. package/lib/transform.d.ts.map +1 -1
  261. package/lib/transform.js +0 -5
  262. package/lib/transform.js.map +1 -1
  263. package/lib/types.d.ts +10 -5
  264. package/lib/types.d.ts.map +1 -1
  265. package/lib/types.js +0 -5
  266. package/lib/types.js.map +1 -1
  267. package/lib/wrap-table.d.ts +0 -5
  268. package/lib/wrap-table.d.ts.map +1 -1
  269. package/lib/wrap-table.js +12 -3
  270. package/lib/wrap-table.js.map +1 -1
  271. package/package.json +14 -10
  272. package/types/hmr-incompatibility.d.ts +0 -5
  273. package/types/hmr-incompatibility.d.ts.map +1 -1
  274. package/types/hmr-incompatibility.js +13 -3
  275. package/types/hmr-incompatibility.js.map +1 -1
  276. package/types/in-page.d.ts +0 -5
  277. package/types/in-page.d.ts.map +1 -1
  278. package/types/in-page.js +0 -5
  279. package/types/in-page.js.map +1 -1
  280. package/types/inspector.d.ts +0 -5
  281. package/types/inspector.d.ts.map +1 -1
  282. package/types/inspector.js +13 -3
  283. package/types/inspector.js.map +1 -1
  284. package/types/snapshot.d.ts +0 -5
  285. package/types/snapshot.d.ts.map +1 -1
  286. package/types/snapshot.js +12 -3
  287. package/types/snapshot.js.map +1 -1
  288. package/types/timeline.d.ts +4 -6
  289. package/types/timeline.d.ts.map +1 -1
  290. package/types/timeline.js +0 -5
  291. package/types/timeline.js.map +1 -1
  292. package/dist/client/assets/index-B2HYO7lk.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,74 @@
3
3
  Notable changes per release. Versions before 0.3.0 predate this file; see the
4
4
  git history for those.
5
5
 
6
+ ## 0.8.0 — 2026-09-30
7
+
8
+ The plugin is now on JSR as well as npm: every release publishes the same
9
+ build to jsr.io/@oddsquad/vite-plugin-lit. The documentation site gets a page
10
+ per release, the StackBlitz playground starts again, and the licence now names
11
+ oddcelot as the copyright holder.
12
+
13
+ ### Added
14
+
15
+ - **Also on JSR.** Releases now publish to jsr.io/@oddsquad/vite-plugin-lit
16
+ alongside npm, so `npx jsr add @oddsquad/vite-plugin-lit` installs the same
17
+ build.
18
+ - **The docs have a page per release.** The changelog on the documentation
19
+ site now lists every version with its date and links to a page for each
20
+ one, plus a page with everything that changed since a given version.
21
+
22
+ ### Changed
23
+
24
+ - **The licence names the right copyright holder.** The package's LICENSE,
25
+ author field and source headers credited Google LLC; they now credit
26
+ oddcelot. The licence terms (BSD-3-Clause) are unchanged.
27
+
28
+ ### Fixed
29
+
30
+ - **The StackBlitz playground starts.** Opening the playground on StackBlitz,
31
+ in dev or with `npm run standalone`, no longer stops at "Cannot find native
32
+ binding", and the dev server prints where to open the Lit DevTools panel in
33
+ its own tab.
34
+
35
+ ## 0.7.0 — 2026-09-29
36
+
37
+ Hot-patching covers two cases it used to get wrong: components with native
38
+ `#private` members, which threw, and child elements whose parent template you
39
+ edit, which lost their state. The standalone `lit-devtools dev` server also
40
+ gets pages to feed it: one script tag connects any page running Lit, whether
41
+ Vite serves it or not, directly or through a proxy. Two fixes ride along:
42
+ open-in-editor links lose a stray slash, and the timeline no longer misses the
43
+ first component's connect and disconnect.
44
+
45
+ ### Added
46
+
47
+ - **Components with `#private` fields keep hot-patching.** Editing an element
48
+ that uses native `#private` fields or methods now updates it in place and
49
+ keeps its private state, instead of throwing "Cannot read private member".
50
+ Set `hmr.privateFields: false` to keep real brand checks in dev.
51
+ - **Child components keep their state when you edit the parent.** Changing the
52
+ template a child element sits in no longer resets its `@state` and
53
+ `#private` fields; `hmr.childState: 'reuse'` keeps the original element
54
+ where it has no bindings, and `'reset'` restores the old behaviour. The
55
+ DevTools Settings tab can switch the mode live; the next edit uses it.
56
+ - **Pages outside Vite can feed the standalone panel.** `lit-devtools dev` now
57
+ prints a `<script src=".../lit-devtools.js">` tag; a page that loads it shows
58
+ its component tree, inspector and timeline in the panel, even when Vite
59
+ doesn't serve it or it's reached through a proxy or tunnel. Pages on
60
+ localhost connect on any port, and `--allow-origin` admits others, with `*`
61
+ for any subdomain (`--allow-origin 'https://*.webcontainer-api.io'` for
62
+ StackBlitz). HMR, source locations and open-in-editor still need Vite.
63
+
64
+ ### Fixed
65
+
66
+ - **Open-in-editor links use the documented URL form.** Links to VS Code,
67
+ Cursor, Zed and Windsurf no longer carry a double slash before absolute
68
+ paths like `/Users/...`.
69
+ - **The timeline records the first component's connect and disconnect.** On a
70
+ page with no Lit element when the DevTools runtime starts, the first
71
+ component defined afterwards now shows its `connectedCallback` and
72
+ `disconnectedCallback` events like the rest.
73
+
6
74
  ## 0.6.1 — 2026-09-29
7
75
 
8
76
  A fix release. Components whose `extends` clause holds braces load in dev
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  BSD 3-Clause License
2
2
 
3
- Copyright (c) 2017 Google LLC. All rights reserved.
3
+ Copyright (c) 2026 oddcelot. All rights reserved.
4
4
 
5
5
  Redistribution and use in source and binary forms, with or without
6
6
  modification, are permitted provided that the following conditions are met:
package/README.md CHANGED
@@ -7,10 +7,17 @@ https://github.com/user-attachments/assets/bacc7649-746a-4ecf-a017-0370b5af23ca
7
7
 
8
8
  **[Documentation →](https://oddcelot.github.io/vite-plugin-lit/)**
9
9
 
10
- Based on `@lit-labs/vite-plugin-lit` (formerly `@lit-labs/vite-hmr`) from the
11
- [lit monorepo](https://github.com/lit/lit), which is kept checked out as a
12
- read-only [submodule](./lit) here for reference and opt-in canary testing
13
- against lit `main`.
10
+ **[Try it on StackBlitz →](https://stackblitz.com/github/oddcelot/vite-plugin-lit/tree/main/playground?startScript=stackblitz)**
11
+ The playground with HMR and the Vite DevTools dock: click the counter, edit
12
+ `src/hmr-counter.ts`, and the count stays.
13
+ [Standalone mode](https://stackblitz.com/github/oddcelot/vite-plugin-lit/tree/main/playground?file=package.json&startScript=standalone)
14
+ runs the same page as static files, without Vite, next to the DevTools panel
15
+ on its own port.
16
+
17
+ Started life in a fork of the [lit monorepo](https://github.com/lit/lit) as a
18
+ proposed `@lit-labs/vite-hmr` package, and now lives here on its own. Lit is
19
+ kept checked out as a read-only [submodule](./lit) for reference and opt-in
20
+ canary testing against lit `main`.
14
21
 
15
22
  ## Why
16
23
 
@@ -121,33 +128,49 @@ The two differ in how the server is found, not in what it can do:
121
128
  plugin logs a warning saying so at startup, naming the reason.
122
129
 
123
130
  The CLI also has `lit-devtools dev`, a standalone devframe server. Started on
124
- its own it shows an empty panel, because it has no page of its own. A page
125
- served by a Vite dev server that loads this plugin's runtime can point itself
126
- at it and feed it the live component tree, inspector and timeline:
131
+ its own it shows an empty panel, because it has no page of its own. Add the
132
+ script tag it prints at startup to any page, including one that Vite does not
133
+ serve and one on another origin, and the page feeds it the live component tree,
134
+ inspector and timeline:
127
135
 
128
- ```ts
129
- import {connectToDevServer} from '@oddsquad/vite-plugin-lit/connect.js';
130
-
131
- await connectToDevServer('http://localhost:5180/');
136
+ ```html
137
+ <script src="http://localhost:5180/lit-devtools.js"></script>
132
138
  ```
133
139
 
134
- The server asks for its one-time code unless you start it with `--no-auth`. What
135
- this does not do yet: put the runtime into a page that is not on a Vite dev
136
- server, and set up the cross-origin access and authentication a page on another
137
- origin needs. The dev server's `__connection.json` sends no CORS headers today,
138
- so from a different origin the connection is blocked by the browser.
140
+ Put it before the scripts that define your components. The server asks for its
141
+ one-time code unless you start it with `--no-auth`: type the code into the
142
+ prompt the page shows, open the page once with `#devframe_otp=<code>` on its
143
+ URL, or skip the gate on a loopback host with `--no-auth`. Pages on a loopback
144
+ origin (any port) may connect; for any other origin, pass it to the server with
145
+ `--allow-origin https://myapp.test:8443` (repeatable). A `*` in the host
146
+ matches any subdomain, e.g. `--allow-origin 'https://*.webcontainer-api.io'`
147
+ for StackBlitz, where every port gets its own origin.
148
+
149
+ Outside Vite the page has no build-time transforms, so HMR patching, source
150
+ locations and open-in-editor do not work there; the tree, inspector and timeline
151
+ do. A page that Vite serves can instead call `connectToDevServer()` from
152
+ `@oddsquad/vite-plugin-lit/connect.js`.
153
+
154
+ To try it from this repo, run `pnpm run standalone:demo`; see
155
+ [Playground](#playground).
139
156
 
140
157
  ## Playground
141
158
 
142
159
  A manually inspectable fixture app (also the source for the e2e fixtures), and
143
160
  self-contained enough to open on
144
- [StackBlitz](https://stackblitz.com/github/oddcelot/vite-plugin-lit/tree/main/playground)
161
+ [StackBlitz](https://stackblitz.com/github/oddcelot/vite-plugin-lit/tree/main/playground?startScript=stackblitz)
145
162
  straight from the repo URL. Run it locally from the repo root:
146
163
 
147
164
  ```sh
148
165
  pnpm dev # builds the plugin, then serves http://localhost:5179
149
166
  ```
150
167
 
168
+ The same playground runs in standalone mode, built to static files and fed to
169
+ a `lit-devtools dev` panel on another port: `pnpm run standalone:demo` here, or
170
+ [on StackBlitz](https://stackblitz.com/github/oddcelot/vite-plugin-lit/tree/main/playground?file=package.json&startScript=standalone)
171
+ with `?startScript=standalone`. StackBlitz installs the published plugin, so
172
+ both links run the latest release of the plugin against the playground on `main`.
173
+
151
174
  ## Development
152
175
 
153
176
  Requires Node 26 and pnpm 12 (`corepack enable` picks up the pinned version).
package/bin.mjs CHANGED
@@ -1,10 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * @license
4
- * Copyright 2026 Google LLC
5
- * SPDX-License-Identifier: BSD-3-Clause
6
- */
7
-
8
2
  /**
9
3
  * `lit-devtools` — the package's command line.
10
4
  *
@@ -27,10 +21,14 @@
27
21
  * and only on the path that needs them, so installing this package without
28
22
  * them stays supported.
29
23
  *
30
- * @see plans/roadmap/03-cli-and-stdio-mcp.md
24
+ * @see plans/devtools-features.md (CLI and stdio MCP)
31
25
  */
32
26
 
27
+ import {readFile} from 'node:fs/promises';
28
+ import {createRequire} from 'node:module';
33
29
  import process from 'node:process';
30
+ import {pathToFileURL} from 'node:url';
31
+ import {resolveAllowedOrigins} from './lib/devframe/allowed-origins.js';
34
32
  import {createStandaloneLitDevframe} from './lib/devframe/rpc-source.js';
35
33
  import {PACKAGE_VERSION} from './lib/devframe/paths.js';
36
34
 
@@ -43,6 +41,12 @@ import {PACKAGE_VERSION} from './lib/devframe/paths.js';
43
41
  */
44
42
  const DEFAULT_DEV_PORT = 5180;
45
43
 
44
+ /** The script pages outside Vite load; built by `build:standalone`. */
45
+ const STANDALONE_SCRIPT = new URL(
46
+ './dist/standalone/lit-devtools.js',
47
+ import.meta.url
48
+ );
49
+
46
50
  /** True for a host only this machine can reach. */
47
51
  const isLoopbackHost = (host) =>
48
52
  host === 'localhost' ||
@@ -75,6 +79,13 @@ const main = async () => {
75
79
  .option('--port <port>', 'Port to listen on', {default: DEFAULT_DEV_PORT})
76
80
  .option('--host <host>', 'Host to bind to', {default: 'localhost'})
77
81
  .option('--open', 'Open the browser on start')
82
+ .option(
83
+ '--allow-origin <origin>',
84
+ 'Also let pages served from this origin connect, e.g. ' +
85
+ 'https://myapp.test:8443, or https://*.webcontainer-api.io for any ' +
86
+ 'host under a domain. Loopback origins on any port are always ' +
87
+ 'allowed. Repeatable.'
88
+ )
78
89
  .option(
79
90
  '--no-auth',
80
91
  'Skip the one-time-code gate, so a page can connect without a token'
@@ -95,16 +106,81 @@ const main = async () => {
95
106
  }
96
107
  const {createDevServer} = await import('devframe/adapters/dev');
97
108
  // A standalone server has no Vite, so it has no page of its own: the
98
- // panel stays empty until a page dials in with `connectToDevServer()`
99
- // (see `lib/runtime/rpc-transport.ts`), which carries the runtime's
100
- // usual channels over devframe RPC. Injecting the runtime into a page
101
- // that is not on a Vite dev server is not something this command does.
102
- await createDevServer(
109
+ // panel stays empty until a page dials in. It gets there by loading
110
+ // `/lit-devtools.js` (served below), which starts the runtime and calls
111
+ // `connectToDevServer()` (see `lib/runtime/rpc-transport.ts`). HMR
112
+ // patching and source metadata need Vite's transforms and are not part
113
+ // of it.
114
+ let allowedOrigins;
115
+ try {
116
+ allowedOrigins = resolveAllowedOrigins(
117
+ [flags.allowOrigin]
118
+ .flat()
119
+ .filter((origin) => origin != null)
120
+ .map(String)
121
+ );
122
+ } catch (error) {
123
+ console.error(`[lit-devtools] ${error.message}`);
124
+ process.exit(1);
125
+ }
126
+ let server;
127
+ const serveScript = async () => {
128
+ const headers = {
129
+ 'content-type': 'text/javascript; charset=utf-8',
130
+ 'cache-control': 'no-store',
131
+ };
132
+ let bundle;
133
+ try {
134
+ bundle = await readFile(STANDALONE_SCRIPT, 'utf8');
135
+ } catch {
136
+ return new Response(
137
+ '// lit-devtools: the standalone script is not built. ' +
138
+ 'Run `pnpm run build` in the package and restart.\n',
139
+ {status: 500, headers}
140
+ );
141
+ }
142
+ // The descriptor `__connection.json` would answer with, inlined so the
143
+ // page never fetches it: that request is cross-origin from a page
144
+ // that is not on this server, and gets no CORS headers. Picked, not
145
+ // spread, so nothing else devframe puts in it rides along to any page
146
+ // that can load a script tag.
147
+ const {backend, websocket, sse} = server.connectionMeta();
148
+ const config = {
149
+ url: server.origin + '/',
150
+ connectionMeta: {backend, websocket, sse},
151
+ };
152
+ return new Response(
153
+ `globalThis.__LIT_DEVTOOLS_CONNECT__ = ${JSON.stringify(config)};\n${bundle}`,
154
+ {headers}
155
+ );
156
+ };
157
+ // devframe mounts a static catch-all that answers 404 for paths it
158
+ // does not know, so a route added to its app in `onReady` would never be
159
+ // reached. The route has to go on the app *before* devframe's, which
160
+ // means handing it one -- built from the copy of h3 devframe itself
161
+ // resolves, so the two agree on the class.
162
+ const devframeRequire = createRequire(
163
+ import.meta.resolve('devframe/adapters/dev')
164
+ );
165
+ const {H3} = await import(
166
+ pathToFileURL(devframeRequire.resolve('h3')).href
167
+ );
168
+ const app = new H3();
169
+ app.use('/lit-devtools.js', serveScript);
170
+ server = await createDevServer(
103
171
  createStandaloneLitDevframe({version: PACKAGE_VERSION}),
104
172
  {
105
173
  host: flags.host,
106
174
  port: Number(flags.port),
107
175
  flags: {open: Boolean(flags.open), auth: flags.auth},
176
+ app,
177
+ ...(allowedOrigins !== undefined ? {allowedOrigins} : {}),
178
+ onReady({origin}) {
179
+ console.log(
180
+ `\n[lit-devtools] Add this to a page to connect it:\n\n` +
181
+ ` <script src="${origin}/lit-devtools.js"></script>\n`
182
+ );
183
+ },
108
184
  }
109
185
  );
110
186
  });
@@ -117,7 +193,7 @@ const main = async () => {
117
193
  // dev server's memory -- a fresh CLI process has no page, no timeline
118
194
  // and no component tree, so anything it could build would be an empty
119
195
  // shell. The export therefore runs inside the dev server that holds
120
- // the data; see plans/roadmap/08-static-snapshot.md.
196
+ // the data; see plans/devtools-features.md.
121
197
  console.error(
122
198
  `[lit-devtools] A static snapshot is exported from a running ` +
123
199
  `session, not from this CLI.\n` +
package/client.d.ts CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * @license
3
- * Copyright 2026 Google LLC
4
- * SPDX-License-Identifier: BSD-3-Clause
5
- */
6
-
7
1
  /**
8
2
  * Ambient types for the import queries provided by the Lit Vite plugin.
9
3
  *
@@ -1,4 +1,4 @@
1
- import { n as onBrowserAgentToolsChanged, r as nanoid, t as listBrowserAgentTools } from "./index-B2HYO7lk.js";
1
+ import { n as onBrowserAgentToolsChanged, r as nanoid, t as listBrowserAgentTools } from "./index-CgkhETVR.js";
2
2
  //#region node_modules/.pnpm/devframe@1.1.0_@devframes+agentic@1.1.0_cac@7.0.0_srvx@1.0.5/node_modules/devframe/dist/browser-agent-rpc-BXhoSh1z.mjs
3
3
  var CLIENT_ID_STORAGE_KEY = "devframe:client-id";
4
4
  var memoryClientId;
@@ -66,4 +66,4 @@ function setupBrowserAgentRpcBridge(rpc) {
66
66
  //#endregion
67
67
  export { setupBrowserAgentRpcBridge };
68
68
 
69
- //# sourceMappingURL=browser-agent-rpc-BXhoSh1z-F2EfZsFX.js.map
69
+ //# sourceMappingURL=browser-agent-rpc-BXhoSh1z-ybEeG-x9.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser-agent-rpc-BXhoSh1z-F2EfZsFX.js","names":[],"sources":["../../../node_modules/.pnpm/devframe@1.1.0_@devframes+agentic@1.1.0_cac@7.0.0_srvx@1.0.5/node_modules/devframe/dist/browser-agent-rpc-BXhoSh1z.mjs"],"sourcesContent":["import { nanoid } from \"./utils/nanoid.mjs\";\nimport { n as onBrowserAgentToolsChanged, t as listBrowserAgentTools } from \"./browser-agent-Pu-FLk6I.mjs\";\n//#region src/client/client-id.ts\nconst CLIENT_ID_STORAGE_KEY = \"devframe:client-id\";\nlet memoryClientId;\n/**\n* This browser tab's stable client id: one nanoid per tab, persisted in\n* `sessionStorage` so it survives page reloads and RPC reconnects. The node\n* side uses it to tell connected tabs apart across reconnects (see #394).\n*\n* Tab duplication copies `sessionStorage`, so two tabs can briefly share an id\n* until per-tab disambiguation lands with the wider tab-metadata work.\n*/\nfunction resolveClientId(win = globalThis.window) {\n\ttry {\n\t\tconst storage = win?.sessionStorage;\n\t\tif (storage) {\n\t\t\tlet id = storage.getItem(CLIENT_ID_STORAGE_KEY);\n\t\t\tif (!id) {\n\t\t\t\tid = nanoid();\n\t\t\t\tstorage.setItem(CLIENT_ID_STORAGE_KEY, id);\n\t\t\t}\n\t\t\treturn id;\n\t\t}\n\t} catch {}\n\tmemoryClientId ??= nanoid();\n\treturn memoryClientId;\n}\n//#endregion\n//#region src/client/browser-agent-rpc.ts\n/** Mirror this document's browser-agent registry over its existing RPC connection. */\nfunction setupBrowserAgentRpcBridge(rpc) {\n\trpc.client.register({\n\t\tname: \"devframe:agent:invoke-client-tool\",\n\t\ttype: \"action\",\n\t\tjsonSerializable: true,\n\t\thandler: async (id, args) => {\n\t\t\tconst tool = listBrowserAgentTools().find((tool) => tool.id === id);\n\t\t\tif (!tool) throw new Error(`[devframe/agent] browser tool \"${id}\" not found`);\n\t\t\treturn await tool.invoke(args);\n\t\t}\n\t});\n\tlet queued = false;\n\tlet disposed = false;\n\tlet lastSyncedCount = 0;\n\tconst sync = () => {\n\t\tif (queued || disposed) return;\n\t\tqueued = true;\n\t\tqueueMicrotask(async () => {\n\t\t\tqueued = false;\n\t\t\tif (disposed) return;\n\t\t\tconst manifests = listBrowserAgentTools().map(({ invoke: _, ...manifest }) => manifest);\n\t\t\tif (manifests.length === 0 && lastSyncedCount === 0) return;\n\t\t\tlastSyncedCount = manifests.length;\n\t\t\tawait rpc.callOptional(\"devframe:agent:sync-client-tools\", resolveClientId(), manifests).catch(() => {});\n\t\t});\n\t};\n\tconst stopTools = onBrowserAgentToolsChanged(sync);\n\tconst stopConnection = rpc.events.on(\"connection:status\", (status) => {\n\t\tif (status === \"connected\") sync();\n\t});\n\tsync();\n\treturn () => {\n\t\tdisposed = true;\n\t\tstopTools();\n\t\tstopConnection();\n\t};\n}\n//#endregion\nexport { setupBrowserAgentRpcBridge };\n"],"x_google_ignoreList":[0],"mappings":";;AAGA,IAAM,wBAAwB;AAC9B,IAAI;;;;;;;;;AASJ,SAAS,gBAAgB,MAAM,WAAW,QAAQ;CACjD,IAAI;EACH,MAAM,UAAU,KAAK;EACrB,IAAI,SAAS;GACZ,IAAI,KAAK,QAAQ,QAAQ,qBAAqB;GAC9C,IAAI,CAAC,IAAI;IACR,KAAK,OAAO;IACZ,QAAQ,QAAQ,uBAAuB,EAAE;GAC1C;GACA,OAAO;EACR;CACD,QAAQ,CAAC;CACT,mBAAmB,OAAO;CAC1B,OAAO;AACR;;AAIA,SAAS,2BAA2B,KAAK;CACxC,IAAI,OAAO,SAAS;EACnB,MAAM;EACN,MAAM;EACN,kBAAkB;EAClB,SAAS,OAAO,IAAI,SAAS;GAC5B,MAAM,OAAO,sBAAsB,CAAC,CAAC,MAAM,SAAS,KAAK,OAAO,EAAE;GAClE,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,kCAAkC,GAAG,YAAY;GAC5E,OAAO,MAAM,KAAK,OAAO,IAAI;EAC9B;CACD,CAAC;CACD,IAAI,SAAS;CACb,IAAI,WAAW;CACf,IAAI,kBAAkB;CACtB,MAAM,aAAa;EAClB,IAAI,UAAU,UAAU;EACxB,SAAS;EACT,eAAe,YAAY;GAC1B,SAAS;GACT,IAAI,UAAU;GACd,MAAM,YAAY,sBAAsB,CAAC,CAAC,KAAK,EAAE,QAAQ,GAAG,GAAG,eAAe,QAAQ;GACtF,IAAI,UAAU,WAAW,KAAK,oBAAoB,GAAG;GACrD,kBAAkB,UAAU;GAC5B,MAAM,IAAI,aAAa,oCAAoC,gBAAgB,GAAG,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC;EACxG,CAAC;CACF;CACA,MAAM,YAAY,2BAA2B,IAAI;CACjD,MAAM,iBAAiB,IAAI,OAAO,GAAG,sBAAsB,WAAW;EACrE,IAAI,WAAW,aAAa,KAAK;CAClC,CAAC;CACD,KAAK;CACL,aAAa;EACZ,WAAW;EACX,UAAU;EACV,eAAe;CAChB;AACD"}
1
+ {"version":3,"file":"browser-agent-rpc-BXhoSh1z-ybEeG-x9.js","names":[],"sources":["../../../node_modules/.pnpm/devframe@1.1.0_@devframes+agentic@1.1.0_cac@7.0.0_srvx@1.0.5/node_modules/devframe/dist/browser-agent-rpc-BXhoSh1z.mjs"],"sourcesContent":["import { nanoid } from \"./utils/nanoid.mjs\";\nimport { n as onBrowserAgentToolsChanged, t as listBrowserAgentTools } from \"./browser-agent-Pu-FLk6I.mjs\";\n//#region src/client/client-id.ts\nconst CLIENT_ID_STORAGE_KEY = \"devframe:client-id\";\nlet memoryClientId;\n/**\n* This browser tab's stable client id: one nanoid per tab, persisted in\n* `sessionStorage` so it survives page reloads and RPC reconnects. The node\n* side uses it to tell connected tabs apart across reconnects (see #394).\n*\n* Tab duplication copies `sessionStorage`, so two tabs can briefly share an id\n* until per-tab disambiguation lands with the wider tab-metadata work.\n*/\nfunction resolveClientId(win = globalThis.window) {\n\ttry {\n\t\tconst storage = win?.sessionStorage;\n\t\tif (storage) {\n\t\t\tlet id = storage.getItem(CLIENT_ID_STORAGE_KEY);\n\t\t\tif (!id) {\n\t\t\t\tid = nanoid();\n\t\t\t\tstorage.setItem(CLIENT_ID_STORAGE_KEY, id);\n\t\t\t}\n\t\t\treturn id;\n\t\t}\n\t} catch {}\n\tmemoryClientId ??= nanoid();\n\treturn memoryClientId;\n}\n//#endregion\n//#region src/client/browser-agent-rpc.ts\n/** Mirror this document's browser-agent registry over its existing RPC connection. */\nfunction setupBrowserAgentRpcBridge(rpc) {\n\trpc.client.register({\n\t\tname: \"devframe:agent:invoke-client-tool\",\n\t\ttype: \"action\",\n\t\tjsonSerializable: true,\n\t\thandler: async (id, args) => {\n\t\t\tconst tool = listBrowserAgentTools().find((tool) => tool.id === id);\n\t\t\tif (!tool) throw new Error(`[devframe/agent] browser tool \"${id}\" not found`);\n\t\t\treturn await tool.invoke(args);\n\t\t}\n\t});\n\tlet queued = false;\n\tlet disposed = false;\n\tlet lastSyncedCount = 0;\n\tconst sync = () => {\n\t\tif (queued || disposed) return;\n\t\tqueued = true;\n\t\tqueueMicrotask(async () => {\n\t\t\tqueued = false;\n\t\t\tif (disposed) return;\n\t\t\tconst manifests = listBrowserAgentTools().map(({ invoke: _, ...manifest }) => manifest);\n\t\t\tif (manifests.length === 0 && lastSyncedCount === 0) return;\n\t\t\tlastSyncedCount = manifests.length;\n\t\t\tawait rpc.callOptional(\"devframe:agent:sync-client-tools\", resolveClientId(), manifests).catch(() => {});\n\t\t});\n\t};\n\tconst stopTools = onBrowserAgentToolsChanged(sync);\n\tconst stopConnection = rpc.events.on(\"connection:status\", (status) => {\n\t\tif (status === \"connected\") sync();\n\t});\n\tsync();\n\treturn () => {\n\t\tdisposed = true;\n\t\tstopTools();\n\t\tstopConnection();\n\t};\n}\n//#endregion\nexport { setupBrowserAgentRpcBridge };\n"],"x_google_ignoreList":[0],"mappings":";;AAGA,IAAM,wBAAwB;AAC9B,IAAI;;;;;;;;;AASJ,SAAS,gBAAgB,MAAM,WAAW,QAAQ;CACjD,IAAI;EACH,MAAM,UAAU,KAAK;EACrB,IAAI,SAAS;GACZ,IAAI,KAAK,QAAQ,QAAQ,qBAAqB;GAC9C,IAAI,CAAC,IAAI;IACR,KAAK,OAAO;IACZ,QAAQ,QAAQ,uBAAuB,EAAE;GAC1C;GACA,OAAO;EACR;CACD,QAAQ,CAAC;CACT,mBAAmB,OAAO;CAC1B,OAAO;AACR;;AAIA,SAAS,2BAA2B,KAAK;CACxC,IAAI,OAAO,SAAS;EACnB,MAAM;EACN,MAAM;EACN,kBAAkB;EAClB,SAAS,OAAO,IAAI,SAAS;GAC5B,MAAM,OAAO,sBAAsB,CAAC,CAAC,MAAM,SAAS,KAAK,OAAO,EAAE;GAClE,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,kCAAkC,GAAG,YAAY;GAC5E,OAAO,MAAM,KAAK,OAAO,IAAI;EAC9B;CACD,CAAC;CACD,IAAI,SAAS;CACb,IAAI,WAAW;CACf,IAAI,kBAAkB;CACtB,MAAM,aAAa;EAClB,IAAI,UAAU,UAAU;EACxB,SAAS;EACT,eAAe,YAAY;GAC1B,SAAS;GACT,IAAI,UAAU;GACd,MAAM,YAAY,sBAAsB,CAAC,CAAC,KAAK,EAAE,QAAQ,GAAG,GAAG,eAAe,QAAQ;GACtF,IAAI,UAAU,WAAW,KAAK,oBAAoB,GAAG;GACrD,kBAAkB,UAAU;GAC5B,MAAM,IAAI,aAAa,oCAAoC,gBAAgB,GAAG,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC;EACxG,CAAC;CACF;CACA,MAAM,YAAY,2BAA2B,IAAI;CACjD,MAAM,iBAAiB,IAAI,OAAO,GAAG,sBAAsB,WAAW;EACrE,IAAI,WAAW,aAAa,KAAK;CAClC,CAAC;CACD,KAAK;CACL,aAAa;EACZ,WAAW;EACX,UAAU;EACV,eAAe;CAChB;AACD"}