sygnal 5.3.7 → 6.0.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 (438) hide show
  1. package/CHANGELOG.md +646 -0
  2. package/README.md +77 -47
  3. package/dist/astro/client.cjs.js +33 -8114
  4. package/dist/astro/client.cjs.js.map +1 -0
  5. package/dist/astro/client.mjs +33 -8114
  6. package/dist/astro/client.mjs.map +1 -0
  7. package/dist/astro/index.cjs.js +1039 -9
  8. package/dist/astro/index.cjs.js.map +1 -0
  9. package/dist/astro/index.mjs +1038 -9
  10. package/dist/astro/index.mjs.map +1 -0
  11. package/dist/astro/server.cjs.js +3400 -166
  12. package/dist/astro/server.cjs.js.map +1 -0
  13. package/dist/astro/server.mjs +3400 -166
  14. package/dist/astro/server.mjs.map +1 -0
  15. package/dist/devtools.cjs.js +1431 -0
  16. package/dist/devtools.cjs.js.map +1 -0
  17. package/dist/devtools.esm.js +1419 -0
  18. package/dist/devtools.esm.js.map +1 -0
  19. package/dist/diagnostics.cjs.js +4033 -0
  20. package/dist/diagnostics.cjs.js.map +1 -0
  21. package/dist/diagnostics.esm.js +4003 -0
  22. package/dist/diagnostics.esm.js.map +1 -0
  23. package/dist/element.cjs.js +230 -0
  24. package/dist/element.cjs.js.map +1 -0
  25. package/dist/element.esm.js +228 -0
  26. package/dist/element.esm.js.map +1 -0
  27. package/dist/guide/accessibility.md +257 -0
  28. package/dist/guide/adapters.md +221 -0
  29. package/dist/guide/behaviors.md +312 -0
  30. package/dist/guide/browser-sources.md +203 -0
  31. package/dist/guide/drag-and-drop.md +342 -0
  32. package/dist/guide/element-commands.md +306 -0
  33. package/dist/guide/error-boundaries.md +169 -0
  34. package/dist/guide/forms-reference.md +381 -0
  35. package/dist/guide/forms.md +250 -0
  36. package/dist/guide/http.md +299 -0
  37. package/dist/guide/inputs.md +173 -0
  38. package/dist/guide/persistence.md +245 -0
  39. package/dist/guide/recipes/carousel.md +155 -0
  40. package/dist/guide/recipes/charts.md +177 -0
  41. package/dist/guide/recipes/code-editor.md +135 -0
  42. package/dist/guide/recipes/data-grid.md +155 -0
  43. package/dist/guide/recipes/data-table.md +196 -0
  44. package/dist/guide/recipes/i18n.md +222 -0
  45. package/dist/guide/recipes/icons.md +115 -0
  46. package/dist/guide/recipes/overview.md +33 -0
  47. package/dist/guide/recipes/rich-text.md +154 -0
  48. package/dist/guide/resources.md +471 -0
  49. package/dist/guide/ssr.md +255 -0
  50. package/dist/guide/timers.md +178 -0
  51. package/dist/guide/ui/accordion.md +93 -0
  52. package/dist/guide/ui/combobox.md +144 -0
  53. package/dist/guide/ui/dialog.md +124 -0
  54. package/dist/guide/ui/disclosure.md +60 -0
  55. package/dist/guide/ui/menu.md +125 -0
  56. package/dist/guide/ui/overview.md +166 -0
  57. package/dist/guide/ui/popover.md +101 -0
  58. package/dist/guide/ui/select.md +114 -0
  59. package/dist/guide/ui/tabs.md +161 -0
  60. package/dist/guide/ui/toaster.md +152 -0
  61. package/dist/guide/ui/tooltip.md +103 -0
  62. package/dist/guide/undo.md +178 -0
  63. package/dist/guide/virtual-collections.md +183 -0
  64. package/dist/guide/web-components.md +179 -0
  65. package/dist/guide/widgets.md +217 -0
  66. package/dist/index.cjs.js +15283 -6279
  67. package/dist/index.cjs.js.map +1 -0
  68. package/dist/index.d.ts +3739 -370
  69. package/dist/index.esm.js +15230 -6274
  70. package/dist/index.esm.js.map +1 -0
  71. package/dist/jsx-dev-runtime.cjs.js +27 -329
  72. package/dist/jsx-dev-runtime.cjs.js.map +1 -0
  73. package/dist/jsx-dev-runtime.esm.js +20 -322
  74. package/dist/jsx-dev-runtime.esm.js.map +1 -0
  75. package/dist/jsx-runtime.cjs.js +27 -329
  76. package/dist/jsx-runtime.cjs.js.map +1 -0
  77. package/dist/jsx-runtime.esm.js +20 -322
  78. package/dist/jsx-runtime.esm.js.map +1 -0
  79. package/dist/jsx.cjs.js +11 -309
  80. package/dist/jsx.cjs.js.map +1 -0
  81. package/dist/jsx.esm.js +9 -310
  82. package/dist/jsx.esm.js.map +1 -0
  83. package/dist/react.cjs.js +117 -0
  84. package/dist/react.cjs.js.map +1 -0
  85. package/dist/react.esm.js +115 -0
  86. package/dist/react.esm.js.map +1 -0
  87. package/dist/shims/globalthis.cjs +20 -0
  88. package/dist/sygnal.min.js +2 -1
  89. package/dist/sygnal.min.js.map +1 -0
  90. package/dist/ui-combobox.cjs.js +169 -0
  91. package/dist/ui-combobox.cjs.js.map +1 -0
  92. package/dist/ui-combobox.esm.js +148 -0
  93. package/dist/ui-combobox.esm.js.map +1 -0
  94. package/dist/ui-menu.cjs.js +87 -0
  95. package/dist/ui-menu.cjs.js.map +1 -0
  96. package/dist/ui-menu.esm.js +66 -0
  97. package/dist/ui-menu.esm.js.map +1 -0
  98. package/dist/ui-select.cjs.js +104 -0
  99. package/dist/ui-select.cjs.js.map +1 -0
  100. package/dist/ui-select.esm.js +83 -0
  101. package/dist/ui-select.esm.js.map +1 -0
  102. package/dist/ui.cjs.js +738 -0
  103. package/dist/ui.cjs.js.map +1 -0
  104. package/dist/ui.esm.js +727 -0
  105. package/dist/ui.esm.js.map +1 -0
  106. package/dist/vike/ClientOnly.cjs.js +5 -14
  107. package/dist/vike/ClientOnly.cjs.js.map +1 -0
  108. package/dist/vike/ClientOnly.mjs +5 -14
  109. package/dist/vike/ClientOnly.mjs.map +1 -0
  110. package/dist/vike/{+config.js → config/+config.js} +10 -1
  111. package/dist/vike/config/+config.js.map +1 -0
  112. package/dist/vike/config/package.json +6 -0
  113. package/dist/vike/onRenderClient.cjs.js +166 -95
  114. package/dist/vike/onRenderClient.cjs.js.map +1 -0
  115. package/dist/vike/onRenderClient.mjs +166 -95
  116. package/dist/vike/onRenderClient.mjs.map +1 -0
  117. package/dist/vike/onRenderHtml.cjs.js +60 -24
  118. package/dist/vike/onRenderHtml.cjs.js.map +1 -0
  119. package/dist/vike/onRenderHtml.mjs +61 -25
  120. package/dist/vike/onRenderHtml.mjs.map +1 -0
  121. package/dist/vite/plugin.cjs.js +926 -65
  122. package/dist/vite/plugin.cjs.js.map +1 -0
  123. package/dist/vite/plugin.mjs +925 -65
  124. package/dist/vite/plugin.mjs.map +1 -0
  125. package/dist/zag.cjs.js +408 -0
  126. package/dist/zag.cjs.js.map +1 -0
  127. package/dist/zag.esm.js +405 -0
  128. package/dist/zag.esm.js.map +1 -0
  129. package/llms.txt +313 -0
  130. package/package.json +109 -16
  131. package/src/astro/client.ts +40 -18
  132. package/src/astro/index.d.ts +48 -1
  133. package/src/astro/index.ts +106 -9
  134. package/src/astro/server.ts +11 -3
  135. package/src/collection.ts +6 -90
  136. package/src/core/actions.ts +134 -0
  137. package/src/core/cell.ts +202 -0
  138. package/src/core/debug.ts +23 -0
  139. package/src/core/define.ts +242 -0
  140. package/src/core/hooks.ts +314 -0
  141. package/src/core/hosts/collection.ts +325 -0
  142. package/src/core/hosts/switchable.ts +146 -0
  143. package/src/core/instance.ts +592 -0
  144. package/src/core/markers/clientonly.ts +13 -0
  145. package/src/core/markers/lazy.ts +40 -0
  146. package/src/core/markers/portal.ts +96 -0
  147. package/src/core/markers/suspense.ts +41 -0
  148. package/src/core/markers/transition.ts +70 -0
  149. package/src/core/registry.ts +25 -0
  150. package/src/core/runtime.ts +573 -0
  151. package/src/core/statics.ts +104 -0
  152. package/src/core/teardown.ts +60 -0
  153. package/src/core/view.ts +37 -0
  154. package/src/cycle/dom/DocumentDOMSource.ts +13 -8
  155. package/src/cycle/dom/ElementFinder.ts +7 -9
  156. package/src/cycle/dom/EventDelegator.ts +174 -223
  157. package/src/cycle/dom/IsolateModule.ts +65 -35
  158. package/src/cycle/dom/MainDOMSource.ts +13 -2
  159. package/src/cycle/dom/PriorityQueue.ts +4 -2
  160. package/src/cycle/dom/SymbolTree.ts +18 -47
  161. package/src/cycle/dom/classNameModule.ts +76 -0
  162. package/src/cycle/dom/controlledInputModule.ts +50 -0
  163. package/src/cycle/dom/enrichEventStream.ts +29 -45
  164. package/src/cycle/dom/fragment.ts +7 -0
  165. package/src/cycle/dom/isolate.ts +30 -27
  166. package/src/cycle/dom/makeDOMDriver.ts +115 -57
  167. package/src/cycle/dom/mockDOMSource.ts +83 -9
  168. package/src/cycle/dom/modules.ts +21 -4
  169. package/src/cycle/dom/propsModule.ts +65 -0
  170. package/src/cycle/dom/selectModule.ts +22 -17
  171. package/src/cycle/dom/snabbdom.ts +1 -6
  172. package/src/cycle/dom/thunk.ts +3 -0
  173. package/src/cycle/dom/utils.ts +98 -0
  174. package/src/cycle/dom/viewTransition.ts +43 -0
  175. package/src/cycle/state/StateSource.ts +20 -4
  176. package/src/cycle/state/objIsEqual.ts +50 -0
  177. package/src/cycle/state/types.ts +0 -10
  178. package/src/defineComponent.ts +34 -0
  179. package/src/devtools.d.ts +151 -0
  180. package/src/devtools.ts +34 -0
  181. package/src/element.d.ts +59 -0
  182. package/src/element.ts +235 -0
  183. package/src/extra/backoff.ts +9 -0
  184. package/src/extra/behaviors.ts +169 -0
  185. package/src/extra/browserSignals.ts +23 -0
  186. package/src/extra/browserSources.ts +326 -0
  187. package/src/extra/command.ts +3 -3
  188. package/src/extra/controls.ts +47 -0
  189. package/src/extra/copyAsTest.ts +286 -0
  190. package/src/extra/devtools.ts +109 -31
  191. package/src/extra/devtoolsActions.ts +379 -0
  192. package/src/extra/devtoolsHook.ts +9 -0
  193. package/src/extra/devtoolsNext.ts +83 -0
  194. package/src/extra/diagnostics/checks/actionLog.ts +108 -0
  195. package/src/extra/diagnostics/checks/behaviors.ts +49 -0
  196. package/src/extra/diagnostics/checks/browserSources.ts +96 -0
  197. package/src/extra/diagnostics/checks/collections.ts +67 -0
  198. package/src/extra/diagnostics/checks/controls.ts +148 -0
  199. package/src/extra/diagnostics/checks/dataset.ts +57 -0
  200. package/src/extra/diagnostics/checks/dom.ts +250 -0
  201. package/src/extra/diagnostics/checks/elementCommands.ts +175 -0
  202. package/src/extra/diagnostics/checks/events.ts +83 -0
  203. package/src/extra/diagnostics/checks/fetch.ts +135 -0
  204. package/src/extra/diagnostics/checks/forms.ts +163 -0
  205. package/src/extra/diagnostics/checks/index.ts +202 -0
  206. package/src/extra/diagnostics/checks/inspect.ts +427 -0
  207. package/src/extra/diagnostics/checks/next.ts +417 -0
  208. package/src/extra/diagnostics/checks/persist.ts +54 -0
  209. package/src/extra/diagnostics/checks/props.ts +56 -0
  210. package/src/extra/diagnostics/checks/public.d.ts +302 -0
  211. package/src/extra/diagnostics/checks/replies.ts +128 -0
  212. package/src/extra/diagnostics/checks/router.ts +100 -0
  213. package/src/extra/diagnostics/checks/rxjsHints.ts +88 -0
  214. package/src/extra/diagnostics/checks/shared.ts +203 -0
  215. package/src/extra/diagnostics/checks/shorthand.ts +115 -0
  216. package/src/extra/diagnostics/checks/sortable.ts +129 -0
  217. package/src/extra/diagnostics/checks/state.ts +148 -0
  218. package/src/extra/diagnostics/checks/statics.ts +48 -0
  219. package/src/extra/diagnostics/checks/strict.ts +55 -0
  220. package/src/extra/diagnostics/checks/timers.ts +80 -0
  221. package/src/extra/diagnostics/checks/viewTransitions.ts +47 -0
  222. package/src/extra/diagnostics/checks/virtual.ts +73 -0
  223. package/src/extra/diagnostics/checks/widgets.ts +109 -0
  224. package/src/extra/diagnostics/checks/wiring.ts +121 -0
  225. package/src/extra/diagnostics/codes.ts +477 -0
  226. package/src/extra/diagnostics/index.ts +353 -0
  227. package/src/extra/diagnostics/legacy.ts +76 -0
  228. package/src/extra/driverFactories.ts +172 -60
  229. package/src/extra/elementCommands.ts +53 -0
  230. package/src/extra/eventDriver.ts +4 -0
  231. package/src/extra/fetchDriver.ts +519 -0
  232. package/src/extra/flatten.ts +75 -0
  233. package/src/extra/focusWithin.ts +27 -0
  234. package/src/extra/form.ts +268 -0
  235. package/src/extra/formHelpers.ts +139 -0
  236. package/src/extra/head.ts +106 -0
  237. package/src/extra/hmr.ts +2 -3
  238. package/src/extra/owned.ts +24 -0
  239. package/src/extra/pager.ts +50 -0
  240. package/src/extra/persist.ts +133 -0
  241. package/src/extra/pwa.ts +1 -1
  242. package/src/extra/queryCache.ts +107 -0
  243. package/src/extra/reducers.ts +13 -6
  244. package/src/extra/reduxDevtools.ts +92 -0
  245. package/src/extra/replies.ts +54 -0
  246. package/src/extra/router.ts +323 -0
  247. package/src/extra/run.ts +94 -210
  248. package/src/extra/selection.ts +76 -0
  249. package/src/extra/socketDriver.ts +265 -0
  250. package/src/extra/sortable.ts +377 -0
  251. package/src/extra/ssr.ts +427 -160
  252. package/src/extra/standardSchema.ts +27 -0
  253. package/src/extra/testing.ts +3158 -190
  254. package/src/extra/timers.ts +95 -0
  255. package/src/extra/undo.ts +261 -0
  256. package/src/extra/viewTransitions.ts +38 -0
  257. package/src/extra/virtual.ts +513 -0
  258. package/src/extra/widget.ts +201 -0
  259. package/src/extra/xstreamExtras.ts +269 -0
  260. package/src/index.d.ts +3012 -87
  261. package/src/index.ts +32 -10
  262. package/src/jsx-runtime.ts +15 -1
  263. package/src/jsx.ts +2 -1
  264. package/src/lazy.ts +50 -7
  265. package/src/portal.ts +3 -1
  266. package/src/pragma/index.ts +262 -134
  267. package/src/react-peers.d.ts +5 -0
  268. package/src/react.d.ts +43 -0
  269. package/src/react.ts +110 -0
  270. package/src/shared.ts +48 -0
  271. package/src/slot.ts +1 -1
  272. package/src/suspense.ts +3 -1
  273. package/src/switchable.ts +6 -119
  274. package/src/transition.ts +3 -1
  275. package/src/ui/accordion.ts +64 -0
  276. package/src/ui/dialog.ts +129 -0
  277. package/src/ui/disclosure.ts +35 -0
  278. package/src/ui/popover.ts +45 -0
  279. package/src/ui/shared.ts +94 -0
  280. package/src/ui/tabs.ts +82 -0
  281. package/src/ui/toaster.ts +198 -0
  282. package/src/ui/tooltip.ts +70 -0
  283. package/src/ui/zag/combobox.ts +115 -0
  284. package/src/ui/zag/menu.ts +40 -0
  285. package/src/ui/zag/select.ts +54 -0
  286. package/src/ui/zag/shared.ts +43 -0
  287. package/src/ui-combobox.d.ts +20 -0
  288. package/src/ui-combobox.ts +6 -0
  289. package/src/ui-menu.d.ts +30 -0
  290. package/src/ui-menu.ts +6 -0
  291. package/src/ui-select.d.ts +17 -0
  292. package/src/ui-select.ts +6 -0
  293. package/src/ui-zag-types.d.ts +42 -0
  294. package/src/ui.d.ts +208 -0
  295. package/src/ui.ts +15 -0
  296. package/src/vike/+config.ts +9 -1
  297. package/src/vike/ClientOnly.ts +1 -1
  298. package/src/vike/onRenderClient.ts +144 -96
  299. package/src/vike/onRenderHtml.ts +69 -26
  300. package/src/vike/types.ts +27 -4
  301. package/src/vite/globalthis-shim.ts +18 -0
  302. package/src/vite/globalthis.ts +56 -0
  303. package/src/vite/plugin.d.ts +114 -2
  304. package/src/vite/plugin.ts +920 -56
  305. package/src/zag.d.ts +64 -0
  306. package/src/zag.ts +238 -0
  307. package/dist/astro/astro/client.d.ts +0 -5
  308. package/dist/astro/astro/index.d.ts +0 -16
  309. package/dist/astro/astro/server.d.ts +0 -12
  310. package/dist/astro/client.d.ts +0 -5
  311. package/dist/astro/client.esm.js +0 -4665
  312. package/dist/astro/collection.d.ts +0 -12
  313. package/dist/astro/component.d.ts +0 -22
  314. package/dist/astro/cycle/dom/BodyDOMSource.d.ts +0 -10
  315. package/dist/astro/cycle/dom/DOMSource.d.ts +0 -11
  316. package/dist/astro/cycle/dom/DocumentDOMSource.d.ts +0 -12
  317. package/dist/astro/cycle/dom/ElementFinder.d.ts +0 -8
  318. package/dist/astro/cycle/dom/EventDelegator.d.ts +0 -34
  319. package/dist/astro/cycle/dom/IsolateModule.d.ts +0 -23
  320. package/dist/astro/cycle/dom/MainDOMSource.d.ts +0 -32
  321. package/dist/astro/cycle/dom/PriorityQueue.d.ts +0 -7
  322. package/dist/astro/cycle/dom/ScopeChecker.d.ts +0 -9
  323. package/dist/astro/cycle/dom/SymbolTree.d.ts +0 -9
  324. package/dist/astro/cycle/dom/VNodeWrapper.d.ts +0 -8
  325. package/dist/astro/cycle/dom/enrichEventStream.d.ts +0 -24
  326. package/dist/astro/cycle/dom/fromEvent.d.ts +0 -6
  327. package/dist/astro/cycle/dom/index.d.ts +0 -8
  328. package/dist/astro/cycle/dom/isolate.d.ts +0 -9
  329. package/dist/astro/cycle/dom/makeDOMDriver.d.ts +0 -11
  330. package/dist/astro/cycle/dom/mockDOMSource.d.ts +0 -17
  331. package/dist/astro/cycle/dom/modules.d.ts +0 -5
  332. package/dist/astro/cycle/dom/snabbdom.d.ts +0 -22
  333. package/dist/astro/cycle/dom/styleModule.d.ts +0 -13
  334. package/dist/astro/cycle/dom/thunk.d.ts +0 -11
  335. package/dist/astro/cycle/dom/utils.d.ts +0 -8
  336. package/dist/astro/cycle/isolate/index.d.ts +0 -42
  337. package/dist/astro/cycle/run/adapt.d.ts +0 -6
  338. package/dist/astro/cycle/run/index.d.ts +0 -36
  339. package/dist/astro/cycle/run/internals.d.ts +0 -8
  340. package/dist/astro/cycle/run/types.d.ts +0 -49
  341. package/dist/astro/cycle/state/Collection.d.ts +0 -29
  342. package/dist/astro/cycle/state/StateSource.d.ts +0 -20
  343. package/dist/astro/cycle/state/index.d.ts +0 -5
  344. package/dist/astro/cycle/state/pickCombine.d.ts +0 -3
  345. package/dist/astro/cycle/state/pickMerge.d.ts +0 -3
  346. package/dist/astro/cycle/state/types.d.ts +0 -18
  347. package/dist/astro/cycle/state/withState.d.ts +0 -17
  348. package/dist/astro/extra/classes.d.ts +0 -7
  349. package/dist/astro/extra/devtools.d.ts +0 -78
  350. package/dist/astro/extra/dragDriver.d.ts +0 -20
  351. package/dist/astro/extra/driverFactories.d.ts +0 -12
  352. package/dist/astro/extra/eventDriver.d.ts +0 -9
  353. package/dist/astro/extra/exactState.d.ts +0 -1
  354. package/dist/astro/extra/hmr.d.ts +0 -17
  355. package/dist/astro/extra/logDriver.d.ts +0 -2
  356. package/dist/astro/extra/processDrag.d.ts +0 -19
  357. package/dist/astro/extra/processForm.d.ts +0 -15
  358. package/dist/astro/extra/run.d.ts +0 -13
  359. package/dist/astro/extra/xstreamCompat.d.ts +0 -5
  360. package/dist/astro/index.d.ts +0 -19
  361. package/dist/astro/index.esm.js +0 -27
  362. package/dist/astro/jsx-dev-runtime.d.ts +0 -1
  363. package/dist/astro/jsx-runtime.d.ts +0 -4
  364. package/dist/astro/jsx.d.ts +0 -2
  365. package/dist/astro/pragma/fn.d.ts +0 -7
  366. package/dist/astro/pragma/index.d.ts +0 -7
  367. package/dist/astro/pragma/is.d.ts +0 -10
  368. package/dist/astro/server.d.ts +0 -12
  369. package/dist/astro/server.esm.js +0 -25
  370. package/dist/astro/switchable.d.ts +0 -7
  371. package/dist/collection.d.ts +0 -12
  372. package/dist/component.d.ts +0 -22
  373. package/dist/cycle/dom/BodyDOMSource.d.ts +0 -10
  374. package/dist/cycle/dom/DOMSource.d.ts +0 -11
  375. package/dist/cycle/dom/DocumentDOMSource.d.ts +0 -12
  376. package/dist/cycle/dom/ElementFinder.d.ts +0 -8
  377. package/dist/cycle/dom/EventDelegator.d.ts +0 -34
  378. package/dist/cycle/dom/IsolateModule.d.ts +0 -23
  379. package/dist/cycle/dom/MainDOMSource.d.ts +0 -32
  380. package/dist/cycle/dom/PriorityQueue.d.ts +0 -7
  381. package/dist/cycle/dom/ScopeChecker.d.ts +0 -9
  382. package/dist/cycle/dom/SymbolTree.d.ts +0 -9
  383. package/dist/cycle/dom/VNodeWrapper.d.ts +0 -8
  384. package/dist/cycle/dom/enrichEventStream.d.ts +0 -24
  385. package/dist/cycle/dom/fromEvent.d.ts +0 -6
  386. package/dist/cycle/dom/index.d.ts +0 -8
  387. package/dist/cycle/dom/isolate.d.ts +0 -9
  388. package/dist/cycle/dom/makeDOMDriver.d.ts +0 -11
  389. package/dist/cycle/dom/mockDOMSource.d.ts +0 -17
  390. package/dist/cycle/dom/modules.d.ts +0 -5
  391. package/dist/cycle/dom/snabbdom.d.ts +0 -22
  392. package/dist/cycle/dom/styleModule.d.ts +0 -13
  393. package/dist/cycle/dom/thunk.d.ts +0 -11
  394. package/dist/cycle/dom/utils.d.ts +0 -8
  395. package/dist/cycle/isolate/index.d.ts +0 -42
  396. package/dist/cycle/run/adapt.d.ts +0 -6
  397. package/dist/cycle/run/index.d.ts +0 -36
  398. package/dist/cycle/run/internals.d.ts +0 -8
  399. package/dist/cycle/run/types.d.ts +0 -49
  400. package/dist/cycle/state/Collection.d.ts +0 -29
  401. package/dist/cycle/state/StateSource.d.ts +0 -20
  402. package/dist/cycle/state/index.d.ts +0 -5
  403. package/dist/cycle/state/pickCombine.d.ts +0 -3
  404. package/dist/cycle/state/pickMerge.d.ts +0 -3
  405. package/dist/cycle/state/types.d.ts +0 -18
  406. package/dist/cycle/state/withState.d.ts +0 -17
  407. package/dist/extra/classes.d.ts +0 -7
  408. package/dist/extra/devtools.d.ts +0 -78
  409. package/dist/extra/dragDriver.d.ts +0 -20
  410. package/dist/extra/driverFactories.d.ts +0 -12
  411. package/dist/extra/eventDriver.d.ts +0 -9
  412. package/dist/extra/exactState.d.ts +0 -1
  413. package/dist/extra/hmr.d.ts +0 -17
  414. package/dist/extra/logDriver.d.ts +0 -2
  415. package/dist/extra/processDrag.d.ts +0 -19
  416. package/dist/extra/processForm.d.ts +0 -15
  417. package/dist/extra/run.d.ts +0 -13
  418. package/dist/extra/xstreamCompat.d.ts +0 -5
  419. package/dist/jsx-dev-runtime.d.ts +0 -1
  420. package/dist/jsx-dev-runtime.js +0 -224
  421. package/dist/jsx-runtime.d.ts +0 -4
  422. package/dist/jsx-runtime.js +0 -224
  423. package/dist/jsx.d.ts +0 -2
  424. package/dist/pragma/fn.d.ts +0 -7
  425. package/dist/pragma/index.d.ts +0 -7
  426. package/dist/pragma/is.d.ts +0 -10
  427. package/dist/switchable.d.ts +0 -7
  428. package/dist/vike/+config.cjs.js +0 -65
  429. package/src/component.ts +0 -2256
  430. package/src/cycle/isolate/index.ts +0 -196
  431. package/src/cycle/run/index.ts +0 -151
  432. package/src/cycle/run/internals.ts +0 -143
  433. package/src/cycle/state/Collection.ts +0 -174
  434. package/src/cycle/state/index.ts +0 -5
  435. package/src/cycle/state/pickCombine.ts +0 -167
  436. package/src/cycle/state/pickMerge.ts +0 -122
  437. package/src/cycle/state/withState.ts +0 -47
  438. package/src/pragma/fn.ts +0 -55
@@ -0,0 +1,286 @@
1
+ /**
2
+ * PLAN-4 3-E (GS-10): "Copy as test". Turns a recorded session (./devtoolsActions getSession())
3
+ * into a Vitest + renderComponent test that replays it:
4
+ *
5
+ * renderComponent(C, { initialState?, drivers? }) the session's initial state (left out when
6
+ * it is the component's own initialState)
7
+ * await t.ready()
8
+ * t.simulateAction(type, data) each action caused by 'intent' | 'simulateAction' | 'behavior'
9
+ * await t.respond(sink, body, OK) a reply action from a makeFetchDriver source (renderComponent's
10
+ * await t.fail(sink, status, ...) HTTP fake answers the request the replayed actions send again)
11
+ * await t.settle()
12
+ * expect(t.state).toEqual(final)
13
+ *
14
+ * 'next' and 'built-in' actions are consequences (the replay produces them again), never replayed;
15
+ * nor is an intent action whose data is the component's own state (an intent over STATE.stream).
16
+ * A t.respond / t.fail that follows simulateAction calls waits for the request they send (G-218).
17
+ * Data is written as JS literals: JSON values, Date, Map, Set, NaN / Infinity / -0, bigint. A DOM
18
+ * event or element becomes a stub ({ type, key, target: { dataset, value, checked, id } }), with a
19
+ * comment. Anything else (functions, class instances, cycles) is left out with a comment.
20
+ *
21
+ * The final-state assertion is written only when the replay is complete: every state-changing
22
+ * action could be replayed with its data, no descendant instance changed the state on its own
23
+ * (a child's intent: copy the test from that instance instead), the session wasn't truncated,
24
+ * and the final state is JSON-safe. Otherwise a comment says why. A test written with the
25
+ * assertion passes unchanged (for drivers the session's app had, pass `drivers`).
26
+ */
27
+ import type {SessionRecording, SessionAction} from './devtoolsActions'
28
+ import {isElement, isEvent, deepEqual} from './devtoolsActions'
29
+
30
+ export interface CopyAsTestOptions {
31
+ /** the import line(s) for the component, e.g. "import App from './App.jsx'" (default: `import <Name> from './<Name>.js'`) */
32
+ componentImport?: string
33
+ /** the identifier the component has in the test (default: the recorded component name) */
34
+ componentName?: string
35
+ /** more import lines (drivers, helpers) */
36
+ imports?: string[]
37
+ /** drivers for renderComponent, as source code by sink name: { DND: 'mockDragDriver().driver' } */
38
+ drivers?: Record<string, string>
39
+ /** more renderComponent options, as source code: "strict: true" */
40
+ renderOptions?: string
41
+ /** the test's name (default: '<Component> session (copied from sygnal/devtools)') */
42
+ testName?: string
43
+ /** adds a `// @vitest-environment <env>` first line (e.g. 'jsdom') */
44
+ environment?: string
45
+ }
46
+
47
+ export interface CopyAsTestResult {
48
+ /** the test file */
49
+ code: string
50
+ /** true when the test asserts the final state */
51
+ complete: boolean
52
+ /** what was left out, and why (also comments in the code) */
53
+ warnings: string[]
54
+ /** actions written as simulateAction / respond / fail */
55
+ replayed: number
56
+ }
57
+
58
+ const REPLAY = new Set(['intent', 'simulateAction', 'behavior'])
59
+ const IDENT = /^[A-Za-z_$][\w$]*$/
60
+
61
+ class Unserializable extends Error {}
62
+
63
+ /** a single-quoted JS string literal */
64
+ const str = (s: string) => `'${JSON.stringify(s).slice(1, -1).replace(/\\"/g, '"').replace(/'/g, "\\'")}'`
65
+
66
+ interface Lit { code: string; stubbed: boolean }
67
+
68
+ /** `v` as a JS literal. mode 'data' turns DOM events / elements into stubs; 'state' refuses them. */
69
+ export function literal(v: any, mode: 'data' | 'state' = 'data', indent = ''): Lit {
70
+ const flag = {stubbed: false}
71
+ const code = lit(v, mode, indent, new Set(), flag)
72
+ return {code, stubbed: flag.stubbed}
73
+ }
74
+
75
+ function elementStub(el: any): any {
76
+ const out: any = {}
77
+ const ds = el.dataset && typeof el.dataset == 'object' ? {...el.dataset} : {}
78
+ if (Object.keys(ds).length) out.dataset = ds
79
+ if (el.id) out.id = el.id
80
+ const tag = String(el.tagName).toUpperCase()
81
+ if (/^(INPUT|SELECT|TEXTAREA)$/.test(tag) && typeof el.value == 'string') out.value = el.value
82
+ if (tag == 'INPUT' && /^(checkbox|radio)$/i.test(el.type || '')) out.checked = !!el.checked
83
+ return out
84
+ }
85
+
86
+ function eventStub(e: any): any {
87
+ const out: any = {type: e.type}
88
+ if (typeof e.key == 'string') out.key = e.key
89
+ if (isElement(e.target)) {
90
+ const t = elementStub(e.target)
91
+ if (Object.keys(t).length) out.target = t
92
+ }
93
+ return out
94
+ }
95
+
96
+ function lit(v: any, mode: 'data' | 'state', ind: string, seen: Set<any>, flag: {stubbed: boolean}): string {
97
+ if (v === null) return 'null'
98
+ switch (typeof v) {
99
+ case 'undefined': return 'undefined'
100
+ case 'boolean': return String(v)
101
+ case 'string': return str(v)
102
+ case 'number': return Object.is(v, -0) ? '-0' : String(v)
103
+ case 'bigint': return `${v}n`
104
+ case 'function': throw new Unserializable(`a function (${v.name || 'anonymous'})`)
105
+ case 'symbol': throw new Unserializable(`a symbol (${String(v)})`)
106
+ }
107
+ if (seen.has(v)) throw new Unserializable('a circular reference')
108
+ if (isEvent(v) || isElement(v)) {
109
+ if (mode == 'state') throw new Unserializable(isEvent(v) ? `a DOM ${v.type} event` : 'a DOM element')
110
+ flag.stubbed = true
111
+ return lit(isEvent(v) ? eventStub(v) : elementStub(v), mode, ind, seen, flag)
112
+ }
113
+ seen.add(v)
114
+ try {
115
+ const inner = ind + ' '
116
+ const list = (items: string[], open: string, close: string) => {
117
+ if (!items.length) return open + close
118
+ const one = open + (open == '{' ? ' ' : '') + items.join(', ') + (open == '{' ? ' ' : '') + close
119
+ if (one.length + ind.length <= 100 && !one.includes('\n')) return one
120
+ return open + '\n' + items.map(s => inner + s).join(',\n') + ',\n' + ind + close
121
+ }
122
+ if (Array.isArray(v)) return list(Array.from(v, x => lit(x, mode, inner, seen, flag)), '[', ']')
123
+ if (v instanceof Date) return `new Date(${str(isNaN(+v) ? 'Invalid Date' : v.toISOString())})`
124
+ if (v instanceof Map) return `new Map(${list([...v].map(([k, x]) => list([lit(k, mode, inner + ' ', seen, flag), lit(x, mode, inner + ' ', seen, flag)], '[', ']')), '[', ']')})`
125
+ if (v instanceof Set) return `new Set(${list([...v].map(x => lit(x, mode, inner, seen, flag)), '[', ']')})`
126
+ const proto = Object.getPrototypeOf(v)
127
+ // G-265: a vnode of the JSX pragma (its own constructor, flagged $p) is a plain object
128
+ if (proto !== Object.prototype && proto !== null && !v.$p) throw new Unserializable(`a ${(v.constructor && v.constructor.name) || 'class instance'}`)
129
+ const items: string[] = []
130
+ for (const k of Object.keys(v)) {
131
+ if (v[k] === undefined) continue
132
+ items.push(`${IDENT.test(k) ? k : str(k)}: ${lit(v[k], mode, inner, seen, flag)}`)
133
+ }
134
+ return list(items, '{', '}')
135
+ } finally {
136
+ seen.delete(v)
137
+ }
138
+ }
139
+
140
+ const q = str
141
+ const tryLit = (v: any, mode: 'data' | 'state', ind: string): Lit | {error: string} => {
142
+ try { return literal(v, mode, ind) } catch (e: any) {
143
+ if (e instanceof Unserializable) return {error: e.message}
144
+ throw e
145
+ }
146
+ }
147
+
148
+ /** an error reply from makeFetchDriver: { error, request, status?, body? } for the request's `error` action */
149
+ const isErrorReply = (a: SessionAction) =>
150
+ a.data && typeof a.data == 'object' && 'error' in a.data && a.data.request && typeof a.data.request == 'object' && a.data.request.error === a.type
151
+
152
+ /** The test for a recorded session (see the module comment), with what it left out. */
153
+ export function sessionToTest(rec: SessionRecording, options: CopyAsTestOptions = {}): CopyAsTestResult {
154
+ const name = options.componentName || (IDENT.test(rec.component) ? rec.component : 'Component')
155
+ const warnings: string[] = []
156
+ const incomplete: string[] = []
157
+ const body: string[] = []
158
+ const I = ' '
159
+ const drivers = options.drivers || {}
160
+ let replayed = 0
161
+
162
+ if (rec.truncated) incomplete.push('the session lost its oldest actions (clear the log, then record a shorter session)')
163
+
164
+ // render options
165
+ const opts: string[] = []
166
+ if (rec.initialState !== undefined && !deepEqual(rec.initialState, rec.definitionInitialState)) {
167
+ const l = tryLit(rec.initialState, 'state', I)
168
+ if ('error' in l) {
169
+ warnings.push(`the initial state holds ${l.error}: rendering with the component's own initialState`)
170
+ incomplete.push('the initial state could not be written')
171
+ } else opts.push(`initialState: ${l.code}`)
172
+ }
173
+ const fakeable = new Set(rec.fakeable)
174
+ const driverNames = [...new Set([...rec.drivers.filter(n => !fakeable.has(n)), ...Object.keys(drivers)])]
175
+ const given = driverNames.filter(n => drivers[n] !== undefined)
176
+ const missing = driverNames.filter(n => drivers[n] === undefined)
177
+ if (given.length) opts.push(`drivers: { ${given.map(n => `${IDENT.test(n) ? n : q(n)}: ${drivers[n]}`).join(', ')} }`)
178
+ if (missing.length) warnings.push(`the app had ${missing.length == 1 ? 'a driver' : 'drivers'} for ${missing.join(', ')}: pass ${missing.length == 1 ? 'it' : 'them'} with copyAsTest(..., { drivers: { ${missing[0]}: '...' } }) if the component reads ${missing.length == 1 ? 'it' : 'them'}`)
179
+ if (options.renderOptions) opts.push(options.renderOptions)
180
+
181
+ const names = rec.actionNames && new Set(rec.actionNames)
182
+ // (G-218: t.respond / t.fail right after queued simulateAction calls wait for the request
183
+ // those calls send, so no settle() is needed before them)
184
+ const answer = (line: string) => body.push(line)
185
+ for (const a of rec.actions) {
186
+ const changes = a.sinks.includes('STATE') || a.sinks.includes('state')
187
+ if (REPLAY.has(a.cause)) {
188
+ // an intent over the component's own STATE stream: the replay produces it again
189
+ if (a.echo) continue
190
+ // an intent action with no model entry does nothing (renderComponent can't send it)
191
+ if (names && !names.has(a.type) && a.cause != 'behavior') continue
192
+ replayed++
193
+ if (a.data === undefined) { body.push(`${I}t.simulateAction(${q(a.type)})`); continue }
194
+ const l = tryLit(a.data, 'data', I)
195
+ if ('error' in l) {
196
+ body.push(`${I}t.simulateAction(${q(a.type)}) // data left out: it held ${l.error}`)
197
+ if (changes) incomplete.push(`${a.type}'s data could not be written (${l.error})`)
198
+ continue
199
+ }
200
+ if (l.stubbed) body.push(`${I}// ${a.type}: DOM event/element data as a stub (type, key, target dataset/value/checked/id)`)
201
+ body.push(`${I}t.simulateAction(${q(a.type)}, ${l.code})`)
202
+ } else if (a.cause == 'reply') {
203
+ const sink = a.replySink
204
+ if (!sink || a.replyKind != 'fetch' || drivers[sink] !== undefined) {
205
+ body.push(`${I}// reply ${a.type}${sink ? ` from ${sink}` : ''}: not replayed (renderComponent fakes makeFetchDriver sources only)`)
206
+ if (changes) incomplete.push(`the ${a.type} reply could not be replayed`)
207
+ continue
208
+ }
209
+ if (isErrorReply(a)) {
210
+ const err = a.data.error, status = a.data.status ?? (err && err.status), errBody = a.data.body ?? (err && err.body)
211
+ if (typeof status == 'number') {
212
+ if (errBody === undefined) answer(`${I}await t.fail(${q(sink)}, ${status}, ${q(a.type)})`)
213
+ else {
214
+ const l = tryLit(errBody, 'state', I)
215
+ if ('error' in l) { answer(`${I}await t.fail(${q(sink)}, ${status}, ${q(a.type)}) // body left out: it held ${l.error}`); if (changes) incomplete.push(`the ${a.type} error body could not be written`) }
216
+ else answer(`${I}await t.fail(${q(sink)}, ${status}, { request: (r) => r.error === ${q(a.type)}, body: ${l.code} })`)
217
+ }
218
+ } else if (a.data.issues) {
219
+ body.push(`${I}// reply ${a.type}: a validation failure, not replayed`)
220
+ if (changes) incomplete.push(`the ${a.type} validation failure could not be replayed`)
221
+ continue
222
+ } else {
223
+ answer(`${I}await t.fail(${q(sink)}, new Error(${str(String(err && err.message || err))}), ${q(a.type)})`)
224
+ }
225
+ replayed++
226
+ continue
227
+ }
228
+ const l = tryLit(a.data, 'state', I)
229
+ if ('error' in l) {
230
+ body.push(`${I}// reply ${a.type} from ${sink}: its data held ${l.error}, not replayed`)
231
+ if (changes) incomplete.push(`the ${a.type} reply's data could not be written`)
232
+ continue
233
+ }
234
+ answer(`${I}await t.respond(${q(sink)}, ${l.code}, ${q(a.type)})`)
235
+ replayed++
236
+ } else if (a.type == 'RESOURCE' && a.data && (a.data.status == 'success' || a.data.status == 'error')) {
237
+ body.push(`${I}// RESOURCE ${a.data.name}: ${a.data.status}, not replayed (answer it with t.respond / t.fail)`)
238
+ if (changes) incomplete.push(`resource '${a.data.name}' was answered`)
239
+ }
240
+ // 'next' and 'built-in': consequences, produced again by the replay
241
+ }
242
+
243
+ if (rec.foreign.length) {
244
+ const list = rec.foreign.slice(0, 5).map(f => `${f.component}#${f.instance} ${f.type}`).join(', ') + (rec.foreign.length > 5 ? ', ...' : '')
245
+ incomplete.push(`child components changed the state through their own actions (${list}): copy the test from that component instance instead`)
246
+ }
247
+
248
+ let assertion: string[]
249
+ if (!incomplete.length) {
250
+ const l = tryLit(rec.finalState, 'state', I)
251
+ if ('error' in l) incomplete.push(`the final state holds ${l.error}`)
252
+ else assertion = [`${I}expect(t.state).toEqual(${l.code})`]
253
+ }
254
+ if (incomplete.length) {
255
+ warnings.push(...incomplete.map(s => 'no final-state assertion: ' + s))
256
+ assertion = [`${I}// No final-state assertion: ${incomplete.join('; ')}`]
257
+ }
258
+
259
+ const head: string[] = []
260
+ if (options.environment) head.push(`// @vitest-environment ${options.environment}`)
261
+ head.push(`// Copied from a sygnal/devtools session of ${rec.component} (${rec.actions.length} recorded actions, ${replayed} replayed)`)
262
+ for (const w of warnings) head.push(`// NOTE: ${w}`)
263
+ head.push(`import { it, expect } from 'vitest'`, `import { renderComponent } from 'sygnal'`)
264
+ head.push(...(options.imports || []))
265
+ head.push(options.componentImport || `import ${name} from './${name}.js'`)
266
+
267
+ const testName = options.testName || `${rec.component} session (copied from sygnal/devtools)`
268
+ const render = opts.length ? `renderComponent(${name}, {\n${opts.map(o => `${I}${o},`).join('\n')}\n })` : `renderComponent(${name})`
269
+ const code = [
270
+ ...head,
271
+ '',
272
+ `it(${q(testName)}, async () => {`,
273
+ ` const t = ${render}`,
274
+ ' try {',
275
+ `${I}await t.ready()`,
276
+ ...body,
277
+ `${I}await t.settle()`,
278
+ ...assertion!,
279
+ ' } finally {',
280
+ `${I}t.dispose()`,
281
+ ' }',
282
+ '})',
283
+ '',
284
+ ].join('\n')
285
+ return {code, complete: !incomplete.length, warnings, replayed}
286
+ }
@@ -1,3 +1,12 @@
1
+ import {getDiagnostics} from './diagnostics/index';
2
+ import type {Diagnostic} from './diagnostics/index';
3
+ import {recordActions, clearActions, getActions, onAction, getSession, preview} from './devtoolsActions';
4
+ import type {DevtoolsAction, SessionRecording} from './devtoolsActions';
5
+ import {sessionToTest} from './copyAsTest';
6
+ import type {CopyAsTestOptions, CopyAsTestResult} from './copyAsTest';
7
+
8
+ import {addLayer, devtoolsHooks} from './devtoolsNext';
9
+
1
10
  const DEVTOOLS_SOURCE = '__SYGNAL_DEVTOOLS_PAGE__';
2
11
  const EXTENSION_SOURCE = '__SYGNAL_DEVTOOLS_EXTENSION__';
3
12
  const DEFAULT_MAX_HISTORY = 200;
@@ -6,13 +15,10 @@ declare global {
6
15
  interface Window {
7
16
  __SYGNAL_DEVTOOLS__?: SygnalDevTools;
8
17
  __SYGNAL_DEVTOOLS_APP__?: {
9
- sinks?: { STATE?: { shamefullySendNext: (fn: any) => void } };
18
+ __runtime?: { setState: (id: any, fn: (s: any) => any) => void };
10
19
  };
11
20
  __SYGNAL_DEVTOOLS_PAGE__?: boolean;
12
21
  SYGNAL_DEBUG?: string | false;
13
- __SYGNAL_HMR_UPDATING?: boolean;
14
- __SYGNAL_HMR_STATE?: unknown;
15
- __SYGNAL_HMR_PERSISTED_STATE?: unknown;
16
22
  __SYGNAL_HMR_LAST_CAPTURED_STATE?: unknown;
17
23
  Cyclejs?: { sinks?: any };
18
24
  CyclejsDevTool_startGraphSerializer?: (sinks: any) => void;
@@ -55,11 +61,16 @@ interface ExtensionMessage {
55
61
  source?: string;
56
62
  }
57
63
 
58
- class SygnalDevTools {
64
+ export class SygnalDevTools {
59
65
  _connected: boolean;
66
+ _initialized = false;
60
67
  _components: Map<number, ComponentMeta>;
61
68
  _stateHistory: StateHistoryEntry[];
62
69
  _maxHistory: number;
70
+ /** PLAN-4 3-E: actions changed since the last ACTIONS post (flushed on a timeout) */
71
+ _dirty = new Set<DevtoolsAction>();
72
+ _flush: any = null;
73
+ _copyOptions: CopyAsTestOptions = {};
63
74
 
64
75
  constructor() {
65
76
  this._connected = false;
@@ -68,15 +79,33 @@ class SygnalDevTools {
68
79
  this._maxHistory = DEFAULT_MAX_HISTORY;
69
80
  }
70
81
 
82
+ /** Diagnostics collected by the shared diagnostics core (see src/extra/diagnostics). */
83
+ getDiagnostics(): Diagnostic[] {
84
+ return getDiagnostics();
85
+ }
86
+
71
87
  get connected(): boolean {
72
88
  return this._connected && typeof window !== 'undefined';
73
89
  }
74
90
 
91
+ /** Publish the bridge on window and listen for the extension. Idempotent (D77: called once, by 'sygnal/devtools'). */
75
92
  init(): void {
76
- if (typeof window === 'undefined') return;
93
+ if (typeof window === 'undefined' || this._initialized) return;
94
+ this._initialized = true;
77
95
 
78
96
  window.__SYGNAL_DEVTOOLS__ = this;
79
97
 
98
+ // PLAN-4 3-E (GS-10): the action log (recorded from now on, connected or not)
99
+ recordActions();
100
+ // PLAN-4.6 R4: the apps read this bridge's hooks (devtoolsNext.ts)
101
+ addLayer((api: any) => devtoolsHooks(this, api));
102
+ onAction((a, kind) => {
103
+ if (!this.connected) return;
104
+ if (kind == 'reset') { this._dirty.clear(); this._post('ACTIONS_RESET', {actions: []}); return; }
105
+ this._dirty.add(a!);
106
+ if (this._flush === null) this._flush = setTimeout(() => this._flushActions(), 0);
107
+ });
108
+
80
109
  window.addEventListener('message', (event: MessageEvent) => {
81
110
  if (event.source !== window) return;
82
111
  if (event.data?.source === EXTENSION_SOURCE) {
@@ -91,6 +120,13 @@ class SygnalDevTools {
91
120
  this._connected = true;
92
121
  if (msg.payload?.maxHistory) this._maxHistory = msg.payload.maxHistory;
93
122
  this._sendFullTree();
123
+ this._post('ACTIONS_RESET', {actions: getActions().slice(-500).map(a => this._serializeAction(a))});
124
+ break;
125
+ case 'CLEAR_ACTIONS':
126
+ clearActions();
127
+ break;
128
+ case 'COPY_AS_TEST':
129
+ this._post('COPY_AS_TEST_RESULT', this._copyAsTest(msg.payload?.instance));
94
130
  break;
95
131
  case 'DISCONNECT':
96
132
  this._connected = false;
@@ -122,7 +158,7 @@ class SygnalDevTools {
122
158
  hasIntent: !!instance.intent,
123
159
  hasContext: !!instance.context,
124
160
  hasCalculated: !!instance.calculated,
125
- components: Object.keys(instance.components || {}),
161
+ components: [],
126
162
  parentId: null,
127
163
  children: [],
128
164
  debug: instance._debug,
@@ -275,6 +311,42 @@ class SygnalDevTools {
275
311
  });
276
312
  }
277
313
 
314
+ /** PLAN-4 3-E: post the actions added or changed since the last flush */
315
+ _flushActions(): void {
316
+ this._flush = null;
317
+ if (!this.connected || !this._dirty.size) { this._dirty.clear(); return; }
318
+ const list = [...this._dirty].sort((a, b) => a.seq - b.seq).map(a => this._serializeAction(a));
319
+ this._dirty.clear();
320
+ this._post('ACTIONS', {actions: list});
321
+ }
322
+
323
+ _serializeAction(a: DevtoolsAction): any {
324
+ return {
325
+ seq: a.seq, type: a.type, data: preview(a.data), component: a.component, instance: a.instance, parent: a.parent,
326
+ sinks: [...a.sinks], cause: a.cause, at: a.at,
327
+ ...('after' in a ? {before: this._safeClone(a.before), after: this._safeClone(a.after)} : {}),
328
+ };
329
+ }
330
+
331
+ /** "Copy as test" for the panel: the session of `instance` (default: the root) */
332
+ _copyAsTest(instance?: string | number): CopyAsTestResult | {error: string} {
333
+ try {
334
+ return sessionToTest(getSession(instance ?? undefined), this._copyOptions);
335
+ } catch (e: any) {
336
+ return {error: String(e?.message || e)};
337
+ }
338
+ }
339
+
340
+ /** Defaults for "Copy as test" from the panel (componentImport, drivers, imports, ...) */
341
+ configureCopyAsTest(options: CopyAsTestOptions): void {
342
+ this._copyOptions = {...this._copyOptions, ...options};
343
+ }
344
+
345
+ /** The recorded session of an instance (see sygnal/devtools getSession) */
346
+ getSession(target?: any): SessionRecording {
347
+ return getSession(target);
348
+ }
349
+
278
350
  _setDebug({componentId, enabled}: {componentId?: number; enabled: boolean}): void {
279
351
  if (typeof componentId === 'undefined' || componentId === null) {
280
352
  if (typeof window !== 'undefined') window.SYGNAL_DEBUG = enabled ? 'true' : false;
@@ -286,7 +358,8 @@ class SygnalDevTools {
286
358
  if (meta && meta._instanceRef) {
287
359
  const instance = meta._instanceRef.deref();
288
360
  if (instance) {
289
- instance._debug = enabled;
361
+ // (through the app's runtime API)
362
+ instance.__api?.setDebug(componentId, enabled);
290
363
  meta.debug = enabled;
291
364
  this._post('DEBUG_TOGGLED', {componentId, enabled});
292
365
  }
@@ -303,40 +376,27 @@ class SygnalDevTools {
303
376
 
304
377
  const newState = this._safeClone(state);
305
378
 
306
- // Try per-component time-travel via the component's STATE sink (reducer stream)
379
+ // Per-component time travel through the app's runtime API
307
380
  const meta = this._components.get(componentId);
308
381
  if (meta) {
309
382
  const instance = meta._instanceRef?.deref();
310
383
  if (!instance) {
311
384
  console.warn(`[Sygnal DevTools] _timeTravel: WeakRef for component #${componentId} (${componentName}) has been GC'd`);
312
- } else {
313
- // sinks[stateSourceName] is the reducer stream — push a reducer that replaces state
314
- const stateSinkName = instance.stateSourceName || 'STATE';
315
- const stateSink = instance.sinks?.[stateSinkName];
316
- if (stateSink?.shamefullySendNext) {
317
- stateSink.shamefullySendNext(() => ({...newState}));
318
- this._post('TIME_TRAVEL_APPLIED', {
319
- componentId,
320
- componentName,
321
- state: newState,
322
- });
323
- return;
324
- }
325
- console.warn(`[Sygnal DevTools] _timeTravel: component #${componentId} (${componentName}) has no STATE sink with shamefullySendNext. sinkName=${stateSinkName}, hasSinks=${!!instance.sinks}, sinkKeys=${instance.sinks ? Object.keys(instance.sinks).join(',') : 'none'}`);
385
+ } else if (instance.__api) {
386
+ // the runtime's setState (a queued action, one patch)
387
+ instance.__api.setState(componentId, () => ({...newState}));
388
+ this._post('TIME_TRAVEL_APPLIED', {componentId, componentName, state: newState});
389
+ return;
326
390
  }
327
391
  } else {
328
392
  console.warn(`[Sygnal DevTools] _timeTravel: no meta for componentId ${componentId}`);
329
393
  }
330
394
 
331
- // Fall back to root STATE sink for root-level components
395
+ // Fall back to the root's state
332
396
  const app = window.__SYGNAL_DEVTOOLS_APP__;
333
- if (app?.sinks?.STATE?.shamefullySendNext) {
334
- app.sinks.STATE.shamefullySendNext(() => ({...newState}));
335
- this._post('TIME_TRAVEL_APPLIED', {
336
- componentId,
337
- componentName,
338
- state: newState,
339
- });
397
+ if (app?.__runtime) {
398
+ app.__runtime.setState('root', () => ({...newState}));
399
+ this._post('TIME_TRAVEL_APPLIED', {componentId, componentName, state: newState});
340
400
  } else {
341
401
  console.warn(`[Sygnal DevTools] _timeTravel: no fallback root STATE sink available`);
342
402
  }
@@ -498,9 +558,27 @@ class SygnalDevTools {
498
558
 
499
559
  let instance: SygnalDevTools | null = null;
500
560
 
561
+ /**
562
+ * The bridge singleton of the 'sygnal/devtools' entry. Not part of the core
563
+ * (D77): the core only calls the hooks of window.__SYGNAL_DEVTOOLS__ when it exists.
564
+ */
501
565
  export function getDevTools(): SygnalDevTools {
502
566
  if (!instance) instance = new SygnalDevTools();
503
567
  return instance;
504
568
  }
505
569
 
570
+ /**
571
+ * Install the bridge (what run() did before 6.0): window.__SYGNAL_DEVTOOLS__ is
572
+ * set and the extension can connect. A bridge already on window (e.g. a second
573
+ * copy of this entry) is kept. Nothing happens outside a browser.
574
+ */
575
+ export function installDevTools(): SygnalDevTools | undefined {
576
+ if (typeof window === 'undefined') return undefined;
577
+ const existing = window.__SYGNAL_DEVTOOLS__;
578
+ if (existing) return existing;
579
+ const dt = getDevTools();
580
+ dt.init();
581
+ return dt;
582
+ }
583
+
506
584
  export default getDevTools;