sygnal 5.4.0 → 6.1.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 (360) hide show
  1. package/CHANGELOG.md +716 -0
  2. package/README.md +24 -9
  3. package/dist/ai.cjs.js +115 -0
  4. package/dist/ai.cjs.js.map +1 -0
  5. package/dist/ai.esm.js +2 -0
  6. package/dist/ai.esm.js.map +1 -0
  7. package/dist/astro/client.cjs.js +16 -9
  8. package/dist/astro/client.cjs.js.map +1 -1
  9. package/dist/astro/client.mjs +16 -9
  10. package/dist/astro/client.mjs.map +1 -1
  11. package/dist/astro/index.cjs.js +958 -92
  12. package/dist/astro/index.cjs.js.map +1 -1
  13. package/dist/astro/index.mjs +958 -93
  14. package/dist/astro/index.mjs.map +1 -1
  15. package/dist/astro/server.cjs.js +3396 -165
  16. package/dist/astro/server.cjs.js.map +1 -1
  17. package/dist/astro/server.mjs +3396 -165
  18. package/dist/astro/server.mjs.map +1 -1
  19. package/dist/devtools.cjs.js +1840 -0
  20. package/dist/devtools.cjs.js.map +1 -0
  21. package/dist/devtools.esm.js +1827 -0
  22. package/dist/devtools.esm.js.map +1 -0
  23. package/dist/diagnostics.cjs.js +3190 -296
  24. package/dist/diagnostics.cjs.js.map +1 -1
  25. package/dist/diagnostics.esm.js +3190 -296
  26. package/dist/diagnostics.esm.js.map +1 -1
  27. package/dist/element.cjs.js +230 -0
  28. package/dist/element.cjs.js.map +1 -0
  29. package/dist/element.esm.js +228 -0
  30. package/dist/element.esm.js.map +1 -0
  31. package/dist/guide/accessibility.md +310 -0
  32. package/dist/guide/adapters.md +221 -0
  33. package/dist/guide/agent.md +588 -0
  34. package/dist/guide/ai-chat.md +693 -0
  35. package/dist/guide/ai-decisions.md +330 -0
  36. package/dist/guide/behaviors.md +312 -0
  37. package/dist/guide/browser-sources.md +203 -0
  38. package/dist/guide/drag-and-drop.md +342 -0
  39. package/dist/guide/element-commands.md +306 -0
  40. package/dist/guide/error-boundaries.md +169 -0
  41. package/dist/guide/forms-reference.md +409 -0
  42. package/dist/guide/forms.md +251 -0
  43. package/dist/guide/http.md +301 -0
  44. package/dist/guide/inputs.md +173 -0
  45. package/dist/guide/mcp-apps.md +272 -0
  46. package/dist/guide/persistence.md +245 -0
  47. package/dist/guide/recipes/ai-form-fill.md +163 -0
  48. package/dist/guide/recipes/ai-summarize.md +155 -0
  49. package/dist/guide/recipes/ai-support-inbox.md +190 -0
  50. package/dist/guide/recipes/carousel.md +155 -0
  51. package/dist/guide/recipes/charts.md +177 -0
  52. package/dist/guide/recipes/code-editor.md +135 -0
  53. package/dist/guide/recipes/data-grid.md +155 -0
  54. package/dist/guide/recipes/data-table.md +196 -0
  55. package/dist/guide/recipes/i18n.md +222 -0
  56. package/dist/guide/recipes/icons.md +115 -0
  57. package/dist/guide/recipes/overview.md +43 -0
  58. package/dist/guide/recipes/rich-text.md +154 -0
  59. package/dist/guide/resources.md +471 -0
  60. package/dist/guide/ssr.md +255 -0
  61. package/dist/guide/timers.md +178 -0
  62. package/dist/guide/ui/accordion.md +93 -0
  63. package/dist/guide/ui/combobox.md +144 -0
  64. package/dist/guide/ui/dialog.md +124 -0
  65. package/dist/guide/ui/disclosure.md +60 -0
  66. package/dist/guide/ui/menu.md +125 -0
  67. package/dist/guide/ui/overview.md +166 -0
  68. package/dist/guide/ui/popover.md +101 -0
  69. package/dist/guide/ui/select.md +114 -0
  70. package/dist/guide/ui/tabs.md +161 -0
  71. package/dist/guide/ui/toaster.md +152 -0
  72. package/dist/guide/ui/tooltip.md +103 -0
  73. package/dist/guide/undo.md +178 -0
  74. package/dist/guide/virtual-collections.md +183 -0
  75. package/dist/guide/web-components.md +179 -0
  76. package/dist/guide/webmcp.md +226 -0
  77. package/dist/guide/widgets.md +217 -0
  78. package/dist/index.cjs.js +19288 -7408
  79. package/dist/index.cjs.js.map +1 -1
  80. package/dist/index.d.ts +4466 -552
  81. package/dist/index.esm.js +19274 -7461
  82. package/dist/index.esm.js.map +1 -1
  83. package/dist/jsx-dev-runtime.cjs.js +26 -334
  84. package/dist/jsx-dev-runtime.cjs.js.map +1 -1
  85. package/dist/jsx-dev-runtime.esm.js +19 -327
  86. package/dist/jsx-dev-runtime.esm.js.map +1 -1
  87. package/dist/jsx-runtime.cjs.js +26 -334
  88. package/dist/jsx-runtime.cjs.js.map +1 -1
  89. package/dist/jsx-runtime.esm.js +19 -327
  90. package/dist/jsx-runtime.esm.js.map +1 -1
  91. package/dist/jsx.cjs.js +10 -314
  92. package/dist/jsx.cjs.js.map +1 -1
  93. package/dist/jsx.esm.js +8 -315
  94. package/dist/jsx.esm.js.map +1 -1
  95. package/dist/react.cjs.js +117 -0
  96. package/dist/react.cjs.js.map +1 -0
  97. package/dist/react.esm.js +115 -0
  98. package/dist/react.esm.js.map +1 -0
  99. package/dist/shims/globalthis.cjs +20 -0
  100. package/dist/sygnal.min.js +1 -1
  101. package/dist/sygnal.min.js.map +1 -1
  102. package/dist/ui-combobox.cjs.js +169 -0
  103. package/dist/ui-combobox.cjs.js.map +1 -0
  104. package/dist/ui-combobox.esm.js +148 -0
  105. package/dist/ui-combobox.esm.js.map +1 -0
  106. package/dist/ui-menu.cjs.js +87 -0
  107. package/dist/ui-menu.cjs.js.map +1 -0
  108. package/dist/ui-menu.esm.js +66 -0
  109. package/dist/ui-menu.esm.js.map +1 -0
  110. package/dist/ui-select.cjs.js +104 -0
  111. package/dist/ui-select.cjs.js.map +1 -0
  112. package/dist/ui-select.esm.js +83 -0
  113. package/dist/ui-select.esm.js.map +1 -0
  114. package/dist/ui.cjs.js +738 -0
  115. package/dist/ui.cjs.js.map +1 -0
  116. package/dist/ui.esm.js +727 -0
  117. package/dist/ui.esm.js.map +1 -0
  118. package/dist/vike/ClientOnly.cjs.js +4 -14
  119. package/dist/vike/ClientOnly.cjs.js.map +1 -1
  120. package/dist/vike/ClientOnly.mjs +4 -14
  121. package/dist/vike/ClientOnly.mjs.map +1 -1
  122. package/dist/vike/{+config.js → config/+config.js} +9 -1
  123. package/dist/vike/config/+config.js.map +1 -0
  124. package/dist/vike/config/package.json +6 -0
  125. package/dist/vike/onRenderClient.cjs.js +165 -95
  126. package/dist/vike/onRenderClient.cjs.js.map +1 -1
  127. package/dist/vike/onRenderClient.mjs +165 -95
  128. package/dist/vike/onRenderClient.mjs.map +1 -1
  129. package/dist/vike/onRenderHtml.cjs.js +59 -24
  130. package/dist/vike/onRenderHtml.cjs.js.map +1 -1
  131. package/dist/vike/onRenderHtml.mjs +60 -25
  132. package/dist/vike/onRenderHtml.mjs.map +1 -1
  133. package/dist/vite/plugin.cjs.js +919 -89
  134. package/dist/vite/plugin.cjs.js.map +1 -1
  135. package/dist/vite/plugin.mjs +919 -90
  136. package/dist/vite/plugin.mjs.map +1 -1
  137. package/dist/zag.cjs.js +408 -0
  138. package/dist/zag.cjs.js.map +1 -0
  139. package/dist/zag.esm.js +405 -0
  140. package/dist/zag.esm.js.map +1 -0
  141. package/llms.txt +172 -103
  142. package/package.json +112 -14
  143. package/src/ai.d.ts +1186 -0
  144. package/src/ai.ts +23 -0
  145. package/src/astro/client.ts +27 -16
  146. package/src/astro/index.d.ts +24 -0
  147. package/src/astro/index.ts +69 -3
  148. package/src/astro/server.ts +8 -2
  149. package/src/collection.ts +6 -93
  150. package/src/core/actions.ts +134 -0
  151. package/src/core/cell.ts +202 -0
  152. package/src/core/debug.ts +23 -0
  153. package/src/core/define.ts +242 -0
  154. package/src/core/hooks.ts +314 -0
  155. package/src/core/hosts/collection.ts +325 -0
  156. package/src/core/hosts/switchable.ts +146 -0
  157. package/src/core/instance.ts +592 -0
  158. package/src/core/markers/clientonly.ts +13 -0
  159. package/src/core/markers/lazy.ts +40 -0
  160. package/src/core/markers/portal.ts +96 -0
  161. package/src/core/markers/suspense.ts +41 -0
  162. package/src/core/markers/transition.ts +70 -0
  163. package/src/core/registry.ts +25 -0
  164. package/src/core/runtime.ts +573 -0
  165. package/src/core/statics.ts +104 -0
  166. package/src/core/teardown.ts +60 -0
  167. package/src/core/view.ts +37 -0
  168. package/src/cycle/dom/DocumentDOMSource.ts +13 -8
  169. package/src/cycle/dom/ElementFinder.ts +7 -9
  170. package/src/cycle/dom/EventDelegator.ts +174 -223
  171. package/src/cycle/dom/IsolateModule.ts +65 -35
  172. package/src/cycle/dom/MainDOMSource.ts +9 -2
  173. package/src/cycle/dom/PriorityQueue.ts +4 -2
  174. package/src/cycle/dom/SymbolTree.ts +18 -47
  175. package/src/cycle/dom/classNameModule.ts +9 -7
  176. package/src/cycle/dom/controlledInputModule.ts +23 -6
  177. package/src/cycle/dom/enrichEventStream.ts +25 -47
  178. package/src/cycle/dom/fragment.ts +7 -0
  179. package/src/cycle/dom/isolate.ts +30 -27
  180. package/src/cycle/dom/makeDOMDriver.ts +115 -56
  181. package/src/cycle/dom/mockDOMSource.ts +21 -1
  182. package/src/cycle/dom/modules.ts +16 -3
  183. package/src/cycle/dom/propsModule.ts +65 -0
  184. package/src/cycle/dom/selectModule.ts +22 -17
  185. package/src/cycle/dom/snabbdom.ts +1 -6
  186. package/src/cycle/dom/thunk.ts +3 -0
  187. package/src/cycle/dom/utils.ts +98 -0
  188. package/src/cycle/dom/viewTransition.ts +43 -0
  189. package/src/cycle/state/StateSource.ts +19 -3
  190. package/src/cycle/state/objIsEqual.ts +50 -0
  191. package/src/cycle/state/types.ts +0 -10
  192. package/src/defineComponent.ts +34 -0
  193. package/src/devtools.d.ts +170 -0
  194. package/src/devtools.ts +37 -0
  195. package/src/element.d.ts +59 -0
  196. package/src/element.ts +235 -0
  197. package/src/extra/ai/agent/index.ts +484 -0
  198. package/src/extra/ai/answers.ts +115 -0
  199. package/src/extra/ai/chat/behavior.ts +336 -0
  200. package/src/extra/ai/chat/driver.ts +271 -0
  201. package/src/extra/ai/chat/memoryTransport.ts +61 -0
  202. package/src/extra/ai/chat/output.ts +37 -0
  203. package/src/extra/ai/commandBar.ts +281 -0
  204. package/src/extra/ai/decide.ts +104 -0
  205. package/src/extra/ai/index.ts +42 -0
  206. package/src/extra/ai/link.ts +90 -0
  207. package/src/extra/ai/mcpApp.ts +314 -0
  208. package/src/extra/ai/messages.ts +51 -0
  209. package/src/extra/ai/schema/index.ts +166 -0
  210. package/src/extra/ai/schema/jsonSchema.ts +72 -0
  211. package/src/extra/ai/schema/strict.ts +152 -0
  212. package/src/extra/ai/transports/agui.ts +177 -0
  213. package/src/extra/ai/transports/anthropicMessages.ts +175 -0
  214. package/src/extra/ai/transports/chatCompletions.ts +105 -0
  215. package/src/extra/ai/transports/chromePrompt.ts +77 -0
  216. package/src/extra/ai/transports/encodeOpenResponses.ts +87 -0
  217. package/src/extra/ai/transports/fromAISDK.ts +126 -0
  218. package/src/extra/ai/transports/openResponses.ts +105 -0
  219. package/src/extra/ai/transports/shared.ts +125 -0
  220. package/src/extra/ai/transports/tools.ts +59 -0
  221. package/src/extra/ai/transports/uiMessageStream.ts +107 -0
  222. package/src/extra/ai/webmcp.ts +260 -0
  223. package/src/extra/backoff.ts +9 -0
  224. package/src/extra/behaviors.ts +169 -0
  225. package/src/extra/browserSignals.ts +23 -0
  226. package/src/extra/browserSources.ts +326 -0
  227. package/src/extra/command.ts +3 -3
  228. package/src/extra/controls.ts +47 -0
  229. package/src/extra/copyAsTest.ts +286 -0
  230. package/src/extra/devMcp.ts +386 -0
  231. package/src/extra/devtools.ts +101 -31
  232. package/src/extra/devtoolsActions.ts +379 -0
  233. package/src/extra/devtoolsHook.ts +9 -0
  234. package/src/extra/devtoolsNext.ts +83 -0
  235. package/src/extra/diagnostics/checks/actionLog.ts +108 -0
  236. package/src/extra/diagnostics/checks/behaviors.ts +49 -0
  237. package/src/extra/diagnostics/checks/browserSources.ts +96 -0
  238. package/src/extra/diagnostics/checks/chat.ts +71 -0
  239. package/src/extra/diagnostics/checks/collections.ts +1 -1
  240. package/src/extra/diagnostics/checks/controls.ts +148 -0
  241. package/src/extra/diagnostics/checks/dataset.ts +57 -0
  242. package/src/extra/diagnostics/checks/dom.ts +20 -11
  243. package/src/extra/diagnostics/checks/elementCommands.ts +175 -0
  244. package/src/extra/diagnostics/checks/events.ts +17 -2
  245. package/src/extra/diagnostics/checks/fetch.ts +135 -0
  246. package/src/extra/diagnostics/checks/forms.ts +171 -0
  247. package/src/extra/diagnostics/checks/index.ts +103 -4
  248. package/src/extra/diagnostics/checks/inspect.ts +140 -32
  249. package/src/extra/diagnostics/checks/next.ts +417 -0
  250. package/src/extra/diagnostics/checks/persist.ts +54 -0
  251. package/src/extra/diagnostics/checks/props.ts +10 -5
  252. package/src/extra/diagnostics/checks/public.d.ts +115 -7
  253. package/src/extra/diagnostics/checks/replies.ts +128 -0
  254. package/src/extra/diagnostics/checks/router.ts +100 -0
  255. package/src/extra/diagnostics/checks/rxjsHints.ts +1 -1
  256. package/src/extra/diagnostics/checks/shared.ts +86 -2
  257. package/src/extra/diagnostics/checks/shorthand.ts +115 -0
  258. package/src/extra/diagnostics/checks/sortable.ts +129 -0
  259. package/src/extra/diagnostics/checks/state.ts +100 -7
  260. package/src/extra/diagnostics/checks/statics.ts +48 -0
  261. package/src/extra/diagnostics/checks/strict.ts +10 -67
  262. package/src/extra/diagnostics/checks/timers.ts +80 -0
  263. package/src/extra/diagnostics/checks/viewTransitions.ts +47 -0
  264. package/src/extra/diagnostics/checks/virtual.ts +73 -0
  265. package/src/extra/diagnostics/checks/widgets.ts +109 -0
  266. package/src/extra/diagnostics/checks/wiring.ts +69 -10
  267. package/src/extra/diagnostics/codes.ts +335 -23
  268. package/src/extra/diagnostics/index.ts +34 -9
  269. package/src/extra/diagnostics/legacy.ts +17 -0
  270. package/src/extra/driverFactories.ts +83 -19
  271. package/src/extra/elementCommands.ts +53 -0
  272. package/src/extra/fetchDriver.ts +519 -0
  273. package/src/extra/focusWithin.ts +27 -0
  274. package/src/extra/form.ts +284 -0
  275. package/src/extra/formHelpers.ts +139 -0
  276. package/src/extra/formTool.ts +150 -0
  277. package/src/extra/head.ts +106 -0
  278. package/src/extra/hmr.ts +2 -3
  279. package/src/extra/owned.ts +24 -0
  280. package/src/extra/pager.ts +50 -0
  281. package/src/extra/persist.ts +133 -0
  282. package/src/extra/pwa.ts +1 -1
  283. package/src/extra/queryCache.ts +107 -0
  284. package/src/extra/reducers.ts +1 -1
  285. package/src/extra/reduxDevtools.ts +92 -0
  286. package/src/extra/replies.ts +54 -0
  287. package/src/extra/router.ts +323 -0
  288. package/src/extra/run.ts +90 -217
  289. package/src/extra/selection.ts +76 -0
  290. package/src/extra/socketDriver.ts +265 -0
  291. package/src/extra/sortable.ts +377 -0
  292. package/src/extra/ssr.ts +427 -160
  293. package/src/extra/standardSchema.ts +27 -0
  294. package/src/extra/testing.ts +2550 -175
  295. package/src/extra/timers.ts +95 -0
  296. package/src/extra/undo.ts +261 -0
  297. package/src/extra/viewTransitions.ts +38 -0
  298. package/src/extra/virtual.ts +513 -0
  299. package/src/extra/widget.ts +201 -0
  300. package/src/index.d.ts +2754 -127
  301. package/src/index.ts +45 -4
  302. package/src/jsx-runtime.ts +15 -1
  303. package/src/jsx.ts +2 -1
  304. package/src/lazy.ts +50 -7
  305. package/src/portal.ts +3 -1
  306. package/src/pragma/index.ts +256 -133
  307. package/src/react-peers.d.ts +5 -0
  308. package/src/react.d.ts +43 -0
  309. package/src/react.ts +110 -0
  310. package/src/shared.ts +57 -0
  311. package/src/slot.ts +1 -1
  312. package/src/suspense.ts +3 -1
  313. package/src/switchable.ts +6 -121
  314. package/src/transition.ts +3 -1
  315. package/src/ui/accordion.ts +64 -0
  316. package/src/ui/dialog.ts +129 -0
  317. package/src/ui/disclosure.ts +35 -0
  318. package/src/ui/popover.ts +45 -0
  319. package/src/ui/shared.ts +94 -0
  320. package/src/ui/tabs.ts +82 -0
  321. package/src/ui/toaster.ts +198 -0
  322. package/src/ui/tooltip.ts +70 -0
  323. package/src/ui/zag/combobox.ts +115 -0
  324. package/src/ui/zag/menu.ts +40 -0
  325. package/src/ui/zag/select.ts +54 -0
  326. package/src/ui/zag/shared.ts +43 -0
  327. package/src/ui-combobox.d.ts +20 -0
  328. package/src/ui-combobox.ts +6 -0
  329. package/src/ui-menu.d.ts +30 -0
  330. package/src/ui-menu.ts +6 -0
  331. package/src/ui-select.d.ts +17 -0
  332. package/src/ui-select.ts +6 -0
  333. package/src/ui-zag-types.d.ts +42 -0
  334. package/src/ui.d.ts +208 -0
  335. package/src/ui.ts +15 -0
  336. package/src/vike/+config.ts +9 -1
  337. package/src/vike/ClientOnly.ts +1 -1
  338. package/src/vike/onRenderClient.ts +144 -96
  339. package/src/vike/onRenderHtml.ts +69 -26
  340. package/src/vike/types.ts +7 -1
  341. package/src/vite/globalthis-shim.ts +18 -0
  342. package/src/vite/globalthis.ts +56 -0
  343. package/src/vite/mcp.ts +568 -0
  344. package/src/vite/plugin.d.ts +47 -3
  345. package/src/vite/plugin.ts +262 -25
  346. package/src/zag.d.ts +64 -0
  347. package/src/zag.ts +238 -0
  348. package/dist/vike/+config.cjs.js +0 -66
  349. package/dist/vike/+config.cjs.js.map +0 -1
  350. package/dist/vike/+config.js.map +0 -1
  351. package/src/component.ts +0 -2301
  352. package/src/cycle/isolate/index.ts +0 -196
  353. package/src/cycle/run/index.ts +0 -151
  354. package/src/cycle/run/internals.ts +0 -143
  355. package/src/cycle/state/Collection.ts +0 -184
  356. package/src/cycle/state/index.ts +0 -5
  357. package/src/cycle/state/pickCombine.ts +0 -201
  358. package/src/cycle/state/pickMerge.ts +0 -122
  359. package/src/cycle/state/withState.ts +0 -47
  360. package/src/pragma/fn.ts +0 -55
package/src/ai.ts ADDED
@@ -0,0 +1,23 @@
1
+ // 'sygnal/ai' (PLAN-6, D240): LLM chat, decisions and the agent layer. The code lives in the main
2
+ // package (src/extra/ai/, D253); this entry re-exports it from the external 'sygnal' (rollup maps
3
+ // './index' to it), so an app has one copy of the internals (G-581) and the core bundle gains 0 B.
4
+ // Keep this list in sync with src/extra/ai/index.ts and src/ai.d.ts.
5
+ export {messageText, withToolResults} from './index'
6
+ export {decide, choice, noul, score} from './index'
7
+ export {agentTools, toJsonSchema, parseInput, jsonSchema} from './index'
8
+ // L-1 (1-L)
9
+ export {makeChatDriver, outputJsonSchema} from './index'
10
+ // A-2 (2-W)
11
+ export {experimentalExposeWebMcp} from './index'
12
+ // L-3 (2-C)
13
+ export {chat} from './index'
14
+ // L-2 (2-T)
15
+ export {openResponses, chatCompletions, uiMessageStream, chromePrompt, encodeOpenResponses} from './index'
16
+ // M-2 / M-3 (3-M)
17
+ export {answers, commandBar} from './index'
18
+ // L-2 (3-W2)
19
+ export {anthropicMessages, agui, fromAISDK, strictSchemas} from './index'
20
+ // X-1 (3-X)
21
+ export {makeMcpAppDriver} from './index'
22
+ // A-3 (3-A3, experimental, D291)
23
+ export {formTool} from './index'
@@ -1,21 +1,26 @@
1
1
  // The public entry (external in the build), so islands share the app's
2
2
  // Sygnal core instead of a bundled copy (B-019).
3
3
  import { run } from 'sygnal'
4
+ // PLAN-4 GS-11 / D120: the app-level error hook, the default export of the module the
5
+ // integration's `onError` option names (undefined without it); served by sygnal/astro's Vite plugin
6
+ // @ts-ignore — a virtual module
7
+ import onError from 'virtual:sygnal/astro-on-error'
4
8
 
5
9
  interface SygnalComponent {
6
10
  (args: any): any;
7
- isSygnalComponent?: boolean;
8
11
  model?: any;
9
12
  intent?: any;
10
- hmrActions?: any;
13
+ connections?: any;
14
+ resources?: any;
15
+ route?: any;
16
+ head?: any;
17
+ persist?: any;
18
+ uses?: any;
19
+ timers?: any;
20
+ viewTransitions?: any;
11
21
  context?: any;
12
- peers?: any;
13
- components?: any;
14
22
  initialState?: any;
15
23
  calculated?: any;
16
- storeCalculatedInState?: any;
17
- DOMSourceName?: string;
18
- stateSourceName?: string;
19
24
  onError?: (error: Error, info: { componentName: string }) => any;
20
25
  debug?: boolean;
21
26
  componentName?: string;
@@ -29,8 +34,7 @@ interface AstroMetadata {
29
34
  function looksLikeSygnalComponent(Component: any): Component is SygnalComponent {
30
35
  if (typeof Component !== 'function') return false
31
36
  return Boolean(
32
- Component.isSygnalComponent ||
33
- Component.model ||
37
+ Component.model ||
34
38
  Component.intent ||
35
39
  Component.initialState ||
36
40
  Component.componentName
@@ -61,23 +65,30 @@ export default (element: any) => {
61
65
  const Wrapped: any = (args: any) => Component({ ...islandProps, ...args, props: islandProps })
62
66
  Wrapped.model = Component.model
63
67
  Wrapped.intent = Component.intent
64
- Wrapped.hmrActions = Component.hmrActions
65
68
  Wrapped.context = Component.context
66
- Wrapped.peers = Component.peers
67
- Wrapped.components = Component.components
68
69
  Wrapped.initialState = Component.initialState
69
70
  Wrapped.calculated = Component.calculated
70
- Wrapped.storeCalculatedInState = Component.storeCalculatedInState
71
- Wrapped.DOMSourceName = Component.DOMSourceName
72
- Wrapped.stateSourceName = Component.stateSourceName
73
71
  Wrapped.onError = Component.onError
74
72
  Wrapped.debug = Component.debug
73
+ Wrapped.connections = Component.connections
74
+ Wrapped.resources = Component.resources
75
+ Wrapped.route = Component.route
76
+ Wrapped.head = Component.head
77
+ // PLAN-4 3-B2: more statics the core reads off the root view: persist (root only: the island
78
+ // is its app's root), uses, timers (they run only with a timer driver) and viewTransitions
79
+ Wrapped.persist = Component.persist
80
+ Wrapped.uses = Component.uses
81
+ Wrapped.timers = Component.timers
82
+ Wrapped.viewTransitions = Component.viewTransitions
75
83
  Wrapped.componentName = Component.componentName || Component.name
76
84
  // run() names the root by `name` first: diagnostics and devtools should
77
85
  // say 'Counter', not 'Wrapped'
78
86
  try { Object.defineProperty(Wrapped, 'name', { value: Wrapped.componentName, configurable: true }) } catch (_) {}
79
87
 
80
- const app = run(Wrapped, {}, { mountPoint })
88
+ // G-206: a `uid` island prop is the island's uid root (as on the server); the view's own
89
+ // uid() function wins over the prop (args are spread last)
90
+ // 3-B2: `__hydrate` tells persist() whether the island starts over the server's markup
91
+ const app = run(Wrapped, { __hydrate: () => client !== 'only' && canHydrate }, { mountPoint, onError, uid: islandProps.uid })
81
92
  element.__sygnal = app
82
93
  }
83
94
  }
@@ -12,6 +12,7 @@ declare type SygnalAstroIntegration = {
12
12
  updateConfig: (config: any) => void;
13
13
  command?: 'dev' | 'build' | 'preview' | 'sync';
14
14
  logger?: { warn: (message: string) => void };
15
+ config?: { root?: URL | string; vite?: any };
15
16
  }) => void;
16
17
  };
17
18
  };
@@ -29,6 +30,29 @@ export interface SygnalAstroOptions {
29
30
  * @default true
30
31
  */
31
32
  check?: boolean | CheckPluginOptions;
33
+ /**
34
+ * Resolve xstream's `globalthis` dependency to a stub returning the native
35
+ * `globalThis` (see the sygnal/vite `nativeGlobalThis` option), in
36
+ * `astro dev` and `astro build`. false: keep the polyfill package.
37
+ * @default true
38
+ */
39
+ nativeGlobalThis?: boolean;
40
+ /**
41
+ * Install the DevTools bridge for islands in `astro dev` (see the sygnal/vite
42
+ * `devtools` option). Never in `astro build`.
43
+ * @default true
44
+ */
45
+ devtools?: boolean;
46
+ /**
47
+ * The islands' app-level error hook (PLAN-4 GS-11): the path of a module, relative to the
48
+ * Astro project root, whose default export is called as run()'s and renderToString's
49
+ * `onError`, in the browser and during SSR. Reporting only, after a component's onError
50
+ * boundary chose the fallback.
51
+ * @example sygnal({ onError: './src/onError.js' })
52
+ * // src/onError.js
53
+ * export default (error, { componentName, action, phase }) => report(error)
54
+ */
55
+ onError?: string;
32
56
  }
33
57
 
34
58
  /**
@@ -1,8 +1,38 @@
1
1
  import sygnalVite from '../vite/plugin'
2
+ import { globalThisAlias } from '../vite/globalthis'
2
3
  import type { DiagnosticsMode, DiagnosticsPluginOptions, CheckPluginOptions } from '../vite/plugin'
4
+ // Node built-ins (the integration runs in Node). The package has no @types/node.
5
+ // @ts-ignore
6
+ import path from 'node:path'
7
+ // @ts-ignore
8
+ import { fileURLToPath } from 'node:url'
3
9
 
4
10
  const SYGNAL_RENDERER_NAME = '@sygnal/astro'
5
11
 
12
+ // PLAN-4 GS-11 / D120: both island entries import this; it re-exports the default export of the
13
+ // module the `onError` option names (undefined without it)
14
+ const ON_ERROR_ID = 'virtual:sygnal/astro-on-error'
15
+
16
+ /** The Vite plugin serving ON_ERROR_ID; `file` is absolute (undefined: no hook) */
17
+ function onErrorPlugin(file?: string) {
18
+ return {
19
+ name: 'sygnal:astro-on-error',
20
+ resolveId: (id: string) => id === ON_ERROR_ID ? '\0' + ON_ERROR_ID : undefined,
21
+ load: (id: string) => id === '\0' + ON_ERROR_ID
22
+ ? (file ? `export { default } from ${JSON.stringify(file)}` : 'export default undefined')
23
+ : undefined,
24
+ // Vite 6+ (Astro 6 renders in its own 'prerender' / 'ssr' environments): the island server
25
+ // entry imports the virtual module, so Vite must load it (not Node). `ssr.noExternal`
26
+ // below covers the 'ssr' environment and older Vite
27
+ configEnvironment: (name: string) => name === 'client' ? undefined : { resolve: { noExternal: ['sygnal'] } },
28
+ }
29
+ }
30
+
31
+ /** The project root as a directory path (Astro gives a file: URL) */
32
+ const rootDir = (root: any): string =>
33
+ // @ts-ignore — Node's process
34
+ !root ? process.cwd() : typeof root === 'string' ? root : fileURLToPath(root)
35
+
6
36
  interface AstroRenderer {
7
37
  name: string;
8
38
  clientEntrypoint: string;
@@ -14,6 +44,7 @@ interface AstroConfigSetupArgs {
14
44
  updateConfig: (config: any) => void;
15
45
  command?: 'dev' | 'build' | 'preview' | 'sync';
16
46
  logger?: { warn: (message: string) => void };
47
+ config?: { root?: URL | string; vite?: { resolve?: { alias?: any } } };
17
48
  }
18
49
 
19
50
  export interface SygnalAstroOptions {
@@ -26,13 +57,34 @@ export interface SygnalAstroOptions {
26
57
  diagnostics?: DiagnosticsMode | DiagnosticsPluginOptions;
27
58
  /** Run sygnal-check in `astro dev` (see the sygnal/vite `check` option). @default true */
28
59
  check?: boolean | CheckPluginOptions;
60
+ /**
61
+ * Resolve xstream's `globalthis` dependency to a stub returning the native
62
+ * `globalThis` (see the sygnal/vite `nativeGlobalThis` option), in
63
+ * `astro dev` and `astro build`. false: keep the polyfill package.
64
+ * @default true
65
+ */
66
+ nativeGlobalThis?: boolean;
67
+ /**
68
+ * Install the DevTools bridge for islands in `astro dev` (see the sygnal/vite
69
+ * `devtools` option). Never in `astro build`.
70
+ * @default true
71
+ */
72
+ devtools?: boolean;
73
+ /**
74
+ * PLAN-4 GS-11: the islands' app-level error hook: the path of a module (relative to the Astro
75
+ * project root) whose default export is called as run()'s / renderToString's `onError`
76
+ * (error, { componentName, action, phase }), in the browser and during SSR. Reporting only,
77
+ * after a component's onError boundary chose the fallback.
78
+ * @example sygnal({ onError: './src/onError.js' })
79
+ */
80
+ onError?: string;
29
81
  }
30
82
 
31
83
  export default function sygnalAstroIntegration(options: SygnalAstroOptions = {}) {
32
84
  return {
33
85
  name: SYGNAL_RENDERER_NAME,
34
86
  hooks: {
35
- 'astro:config:setup': ({ addRenderer, updateConfig, command }: AstroConfigSetupArgs) => {
87
+ 'astro:config:setup': ({ addRenderer, updateConfig, command, config }: AstroConfigSetupArgs) => {
36
88
  addRenderer({
37
89
  name: SYGNAL_RENDERER_NAME,
38
90
  clientEntrypoint: 'sygnal/astro/client',
@@ -44,12 +96,17 @@ export default function sygnalAstroIntegration(options: SygnalAstroOptions = {})
44
96
  jsx: 'automatic',
45
97
  jsxImportSource: 'sygnal',
46
98
  },
99
+ // D120: the island entries import the virtual onError module, so they stay on Vite:
100
+ // not pre-bundled with it, and not externalized (loaded by Node) during SSR
101
+ optimizeDeps: { exclude: [ON_ERROR_ID] },
102
+ ssr: { noExternal: ['sygnal'] },
47
103
  }
104
+ const hook = options.onError ? path.resolve(rootDir(config?.root), options.onError) : undefined
48
105
 
49
106
  // Dev mode (G-014): islands are started by sygnal/astro/client, which
50
107
  // user code never imports, so the sygnal Vite plugin wraps that entry
51
- // in dev to set the dev flag and load the runtime checks first. It
52
- // also runs sygnal-check. Nothing is added to `astro build`.
108
+ // in dev to install DevTools, set the dev flag and load the runtime checks first. It
109
+ // also runs sygnal-check. `astro build` only gets the `globalthis` alias.
53
110
  if (command === 'dev') {
54
111
  vite.plugins = [sygnalVite({
55
112
  disableJsx: true,
@@ -57,9 +114,18 @@ export default function sygnalAstroIntegration(options: SygnalAstroOptions = {})
57
114
  vitestSetup: false,
58
115
  diagnostics: options.diagnostics,
59
116
  check: options.check,
117
+ nativeGlobalThis: options.nativeGlobalThis,
118
+ devtools: options.devtools,
60
119
  })]
120
+ } else if (options.nativeGlobalThis !== false) {
121
+ // G-099: the same `globalthis` alias the plugin adds in dev (R2-7: unless the
122
+ // user's vite config already aliases `globalthis`)
123
+ const alias = globalThisAlias(config?.vite?.resolve?.alias)
124
+ if (alias.length) vite.resolve = { alias }
61
125
  }
62
126
 
127
+ vite.plugins = [...(vite.plugins || []), onErrorPlugin(hook)]
128
+
63
129
  updateConfig({ vite })
64
130
  },
65
131
  },
@@ -1,10 +1,12 @@
1
1
  import {renderToString} from '../extra/ssr'
2
+ // PLAN-4 GS-11 / D120: the integration's `onError` module (see client.ts)
3
+ // @ts-ignore — a virtual module
4
+ import onError from 'virtual:sygnal/astro-on-error'
2
5
 
3
6
  function looksLikeSygnalComponent(Component: any): boolean {
4
7
  if (typeof Component !== 'function') return false
5
8
  return Boolean(
6
- Component.isSygnalComponent ||
7
- Component.model ||
9
+ Component.model ||
8
10
  Component.intent ||
9
11
  Component.initialState ||
10
12
  Component.componentName
@@ -27,6 +29,10 @@ export function renderToStaticMarkup(
27
29
  const html = renderToString(Component, {
28
30
  state: props.initialState || Component.initialState,
29
31
  props: {...props, props},
32
+ // PLAN-4 GS-11: the app-level error hook (as the client's run() gets)
33
+ onError,
34
+ // G-206: a `uid` island prop is its uid root (as on the client), for two islands on a page
35
+ uid: props.uid,
30
36
  })
31
37
  return {html, attrs: {}}
32
38
  } catch (err: any) {
package/src/collection.ts CHANGED
@@ -1,101 +1,14 @@
1
- import isolate from './cycle/isolate/index';
2
- import {makeCollection} from './cycle/state/index';
3
- import {h} from './cycle/dom/index';
4
- import type {Lens} from './cycle/state/types';
5
- import {fail} from './extra/diagnostics/legacy';
6
-
7
- let COLLECTION_COUNT = 0;
8
-
9
- interface CollectionOptions {
10
- combineList?: string[];
11
- globalList?: string[];
12
- stateSourceName?: string;
13
- domSourceName?: string;
14
- container?: string;
15
- containerClass?: string;
16
- }
17
-
18
- export default function collection(
19
- component: (...args: any[]) => any,
20
- stateLense: string | Lens<any, any>,
21
- opts: CollectionOptions = {}
22
- ): (sources: any) => any {
23
- if (typeof component !== 'function') {
24
- fail('SYG411', 'collection', 'first argument (component) must be a function', 'Pass a component function');
25
- }
26
- const {
27
- combineList = ['DOM'],
28
- globalList = ['EVENTS'],
29
- stateSourceName = 'STATE',
30
- domSourceName = 'DOM',
31
- container = 'div',
32
- containerClass,
33
- } = opts;
34
-
35
- return (sources: any) => {
36
- const key = `sygnal-collection-${COLLECTION_COUNT++}`;
37
- const collectionOpts = {
38
- item: component,
39
- itemKey: (state: any, ind: number) =>
40
- typeof state.id !== 'undefined' ? state.id : ind,
41
- // B-009: prefix with the collection instance so two Collections in one parent whose
42
- // items share ids get different DOM isolation scopes
43
- itemScope: (itemKey: any) => `${key}-${itemKey}`,
44
- channel: stateSourceName,
45
- collectSinks: (instances: any) => {
46
- return Object.entries(sources).reduce<Record<string, any>>(
47
- (acc, [name]) => {
48
- if (combineList.includes(name)) {
49
- const combined = instances.pickCombine(name);
50
- if (name === domSourceName && container) {
51
- acc[domSourceName] = combined.map((children: any) => {
52
- const data = containerClass
53
- ? {props: {className: containerClass}}
54
- : {};
55
- return {
56
- sel: container,
57
- data,
58
- children,
59
- key,
60
- text: undefined,
61
- elm: undefined,
62
- };
63
- });
64
- } else {
65
- acc[name] = combined;
66
- }
67
- } else {
68
- acc[name] = instances.pickMerge(name);
69
- }
70
- return acc;
71
- },
72
- {}
73
- );
74
- },
75
- };
76
-
77
- const isolateOpts: Record<string, any> = {[stateSourceName]: stateLense};
78
-
79
- globalList.forEach((global) => (isolateOpts[global] = null));
80
- combineList.forEach((combine) => (isolateOpts[combine] = null));
81
-
82
- return makeIsolatedCollection(collectionOpts, isolateOpts, sources);
83
- };
84
- }
85
-
86
- function makeIsolatedCollection(
87
- collectionOpts: any,
88
- isolateOpts: any,
89
- sources: any
90
- ): any {
91
- return isolate(makeCollection(collectionOpts), isolateOpts)(sources);
92
- }
1
+ import {h} from './cycle/dom/snabbdom';
2
+ // the core's handler for this marker, registered on import (D157)
3
+ import './core/hosts/collection';
93
4
 
5
+ /** `<Collection of={Item} from="items" />`: a marker vnode the core's Collection host renders */
94
6
  const Collection = (props: any) => {
95
7
  const {children, ...sanitizedProps} = props;
96
8
  return h('collection', {props: sanitizedProps}, children);
97
9
  };
98
- (Collection as any).label = 'collection';
10
+ (Collection as any).componentName = 'collection';
99
11
  (Collection as any).preventInstantiation = true;
100
12
 
101
13
  export {Collection};
14
+ export default Collection;
@@ -0,0 +1,134 @@
1
+ /**
2
+ * PLAN-4.6 core: running one action (03-proposal §3, 04 §2.4.1).
3
+ *
4
+ * The action's handlers run in model order with (pre, data, next, props), where `pre` is the
5
+ * state (calculated fields included) from before the action, for every sink:
6
+ * - STATE: applied at once (D165). ABORT, or the object it was given (GS-4), is no change.
7
+ * D205: during an input / change event (an action triggered by typing in a field), no change
8
+ * still re-renders the instance, so a controlled field shows the model's value again
9
+ * - EFFECT: run synchronously (preventDefault on the live event still works); `props.signal`
10
+ * aborts on dispose; a returned value is SYG219, a rejected promise SYG214.
11
+ * - PARENT: straight to the parent's CHILD.select listeners as { name, component, value }.
12
+ * - READY: the instance's ready flag (the parent re-renders it with data-sygnal-ready).
13
+ * - ELEMENT: element commands, run after the next patch (extra/elementCommands).
14
+ * - any other sink (EVENTS, LOG, drivers): stamped and scoped (send), then the app's bus.
15
+ * A dispatch from a handler (a driver answering synchronously, an EFFECT) is queued (FIFO).
16
+ */
17
+ import type {Inst} from './instance'
18
+ import {isAbort} from '../shared'
19
+ import {isObj} from './define'
20
+ import {warn, error as logError, fail} from '../extra/diagnostics/legacy'
21
+ import {runElementCommands} from '../extra/elementCommands'
22
+ import {viewOf} from './view'
23
+ import {checkStatics} from './statics'
24
+ import {objIsEqual} from '../cycle/state/objIsEqual'
25
+ import {dbg} from './debug'
26
+
27
+ export function handle(inst: Inst, type: string, data: any, cause: any, src?: string) {
28
+ const hs = inst.def.handlers.get(type), app = inst.app, H = app.hooks
29
+ // (an action with no model entry is seen too: the action log lists it with no sinks)
30
+ if (H.onAction) H.onAction(viewOf(inst), {type, data, cause, target: viewOf(inst), source: src})
31
+ dbg(inst, () => `<${type}> Action triggered`)
32
+ if (!hs) return
33
+ const def = inst.def
34
+ const pre = inst.cell.get()
35
+ let props: any, outs: any[] | undefined
36
+ const next = (t: string, d?: any, ms: any = 10, effect?: boolean) => {
37
+ if (typeof ms !== 'number') fail('SYG215', inst, `next() delay in '${type}' must be a number`, "Use next('ACTION', data, ms)")
38
+ // G-300: none for an instance being disposed; dispose() clears the pending ones
39
+ if (inst.disposed || inst.dying) return dbg(inst, () => `next(${t}) ignored: disposed`)
40
+ H.onNext?.(viewOf(inst), t, d, ms)
41
+ dbg(inst, () => `<${type}> ${effect ? 'EFFECT triggered' : 'Triggered'} a next() action: <${t}> ${ms}ms delay`)
42
+ const ts = inst.timers ||= new Set()
43
+ const id = setTimeout(() => { ts.delete(id); inst.disposed || app.dispatch(inst, t, d, 'next') }, ms)
44
+ ts.add(id)
45
+ }
46
+ for (const [sink, h0] of hs) {
47
+ const h = H.wrapHandler ? H.wrapHandler(viewOf(inst), type, sink, h0) || h0 : h0
48
+ if (sink == 'EFFECT') {
49
+ if (typeof h != 'function') continue
50
+ const failed = (e: any) => app.caught(inst, 'SYG214', `EFFECT handler '${type}' threw`, e, 'effect', type)
51
+ try {
52
+ const p = {...(props ||= inst_props(inst, pre)), signal: (inst.ac ||= globalThis.AbortController && new AbortController())?.signal}
53
+ const r = h(pre, data, (t: string, d?: any, ms?: any) => next(t, d, ms, true), p)
54
+ if (r?.then) r.then(null, failed)
55
+ else if (r !== undefined && !isAbort(r)) warn('SYG219', inst, `EFFECT handler '${type}' returned a value, which is ignored`, 'Use a STATE or driver sink')
56
+ } catch (e) { failed(e) }
57
+ continue
58
+ }
59
+ let v: any
60
+ if (typeof h == 'function') {
61
+ try { v = h(pre, data, next, props ||= inst_props(inst, pre)) } catch (e) {
62
+ app.caught(inst, 'SYG216', `Reducer for '${type}' threw; ${sink == 'STATE' ? 'state unchanged' : 'nothing sent'}`, e, 'reducer', type)
63
+ continue
64
+ }
65
+ } else v = h === undefined || h === true ? data : h
66
+ if (sink == 'STATE' && (isAbort(v) || v === pre)) {
67
+ // D205: the DOM event being dispatched (window.event) is the one this action came from
68
+ if (/^(input|change)$/.test((globalThis as any).event?.type)) inst.refresh()
69
+ continue
70
+ }
71
+ if (isAbort(v)) continue
72
+ if (sink == 'STATE') {
73
+ H.onReducer?.(viewOf(inst), type, pre, v)
74
+ dbg(inst, () => `<${type}> State reducer added`)
75
+ inst.cell.set(v)
76
+ // GS-12: this app's DOM driver patches inside a View Transition (makeViewTransitionDOMDriver
77
+ // reads the flag on its IsolateModule); includes?.: a non-array static lists nothing (G-228).
78
+ // Only for a state that changed structurally: today an equal one renders nothing (its
79
+ // request expires unused); here it would re-render the same view, so it asks for nothing
80
+ if (def.view.viewTransitions?.includes?.(type) && (v === undefined || !objIsEqual(pre, inst.cell.get()))) { const m = inst.dom?._isolateModule; if (m) m.vt = 1 }
81
+ continue
82
+ }
83
+ if (typeof v == 'symbol') { logError('SYG218', inst, `Reducer for '${type}' returned a symbol; nothing sent`, 'Return a value, or ABORT to send nothing'); continue }
84
+ if (v === undefined) warn('SYG217', inst, `Reducer for '${type}' sent undefined to the driver`, 'Return a value, or ABORT to send nothing')
85
+ if (H.onSink) H.onSink(viewOf(inst), type, sink, v)
86
+ dbg(inst, () => `<${type}> Data sent to [${sink}]: ${JSON.stringify(v)}`)
87
+ if (sink == 'PARENT') {
88
+ const e = {name: def.name, component: def.view, value: v}
89
+ if (inst.parent) inst.parent.toChild(e)
90
+ else app.out('PARENT', e)
91
+ } else if (sink == 'READY') inst.setReady(!!v)
92
+ else if (sink == 'ELEMENT') {
93
+ // onElementCommand returning false: recorded, not run (renderComponent's mock DOM)
94
+ if (H.onElementCommand?.(viewOf(inst), v) !== false) runElementCommands(inst.el ||= {name: def.name, DOMSourceName: 'DOM', sources: {DOM: inst.dom}, get _disposed() { return inst.disposed }}, v)
95
+ } else if (inst.st) (outs ||= []).push(sink, v)
96
+ else send(inst, sink, v)
97
+ }
98
+ // G-158 (D170/Q21): a static this action changed reaches its driver before the action's own
99
+ // driver values (a connection the action opens exists before its first message)
100
+ if (inst.st) {
101
+ checkStatics(inst)
102
+ if (outs) for (let i = 0; i < outs.length; i += 2) send(inst, outs[i], outs[i + 1])
103
+ }
104
+ }
105
+
106
+ /** the handlers' 4th argument: the props, children, slots, context, uid and the pre-action state */
107
+ function inst_props(inst: Inst, pre: any) {
108
+ return {...inst.props, children: inst.children, slots: inst.slots, context: inst.context(), uid: inst.uid, state: pre}
109
+ }
110
+
111
+ /**
112
+ * A sink value of an instance: stamped with its sender (EVENTS; object values for a reply-capable
113
+ * source), scoped through every ancestor's isolation (a driver's value-level isolateValue, else
114
+ * one stream per instance and sink through isolateSink), then onto the app's bus for that sink.
115
+ */
116
+ export function send(inst: Inst, n: string, v: any) {
117
+ const app = inst.app, src = app.sources[n]
118
+ if (n == 'EVENTS' || (src?.__sygnalReplies && isObj(v))) {
119
+ v = Object.defineProperties({...v}, {__emitterId: {value: inst.id, configurable: true}, __emitterName: {value: inst.def.name, configurable: true}})
120
+ }
121
+ if (inst.parent && src && typeof src.isolateSink == 'function') {
122
+ let w = v
123
+ for (let i: Inst = inst; i.parent; i = i.parent) {
124
+ const o = i.parent.src(n)
125
+ if (typeof o?.isolateValue != 'function') return app.pipe(inst, n, v, (s$: any) => {
126
+ for (let j: Inst = inst; j.parent; j = j.parent) { const p = j.parent.src(n); if (typeof p?.isolateSink == 'function') s$ = p.isolateSink(s$, j.scope) }
127
+ return s$
128
+ }, (x: any) => app.out(n, x))
129
+ w = o.isolateValue(w, i.scope)
130
+ }
131
+ v = w
132
+ }
133
+ app.out(n, v)
134
+ }