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.
- package/CHANGELOG.md +646 -0
- package/README.md +77 -47
- package/dist/astro/client.cjs.js +33 -8114
- package/dist/astro/client.cjs.js.map +1 -0
- package/dist/astro/client.mjs +33 -8114
- package/dist/astro/client.mjs.map +1 -0
- package/dist/astro/index.cjs.js +1039 -9
- package/dist/astro/index.cjs.js.map +1 -0
- package/dist/astro/index.mjs +1038 -9
- package/dist/astro/index.mjs.map +1 -0
- package/dist/astro/server.cjs.js +3400 -166
- package/dist/astro/server.cjs.js.map +1 -0
- package/dist/astro/server.mjs +3400 -166
- package/dist/astro/server.mjs.map +1 -0
- package/dist/devtools.cjs.js +1431 -0
- package/dist/devtools.cjs.js.map +1 -0
- package/dist/devtools.esm.js +1419 -0
- package/dist/devtools.esm.js.map +1 -0
- package/dist/diagnostics.cjs.js +4033 -0
- package/dist/diagnostics.cjs.js.map +1 -0
- package/dist/diagnostics.esm.js +4003 -0
- package/dist/diagnostics.esm.js.map +1 -0
- package/dist/element.cjs.js +230 -0
- package/dist/element.cjs.js.map +1 -0
- package/dist/element.esm.js +228 -0
- package/dist/element.esm.js.map +1 -0
- package/dist/guide/accessibility.md +257 -0
- package/dist/guide/adapters.md +221 -0
- package/dist/guide/behaviors.md +312 -0
- package/dist/guide/browser-sources.md +203 -0
- package/dist/guide/drag-and-drop.md +342 -0
- package/dist/guide/element-commands.md +306 -0
- package/dist/guide/error-boundaries.md +169 -0
- package/dist/guide/forms-reference.md +381 -0
- package/dist/guide/forms.md +250 -0
- package/dist/guide/http.md +299 -0
- package/dist/guide/inputs.md +173 -0
- package/dist/guide/persistence.md +245 -0
- package/dist/guide/recipes/carousel.md +155 -0
- package/dist/guide/recipes/charts.md +177 -0
- package/dist/guide/recipes/code-editor.md +135 -0
- package/dist/guide/recipes/data-grid.md +155 -0
- package/dist/guide/recipes/data-table.md +196 -0
- package/dist/guide/recipes/i18n.md +222 -0
- package/dist/guide/recipes/icons.md +115 -0
- package/dist/guide/recipes/overview.md +33 -0
- package/dist/guide/recipes/rich-text.md +154 -0
- package/dist/guide/resources.md +471 -0
- package/dist/guide/ssr.md +255 -0
- package/dist/guide/timers.md +178 -0
- package/dist/guide/ui/accordion.md +93 -0
- package/dist/guide/ui/combobox.md +144 -0
- package/dist/guide/ui/dialog.md +124 -0
- package/dist/guide/ui/disclosure.md +60 -0
- package/dist/guide/ui/menu.md +125 -0
- package/dist/guide/ui/overview.md +166 -0
- package/dist/guide/ui/popover.md +101 -0
- package/dist/guide/ui/select.md +114 -0
- package/dist/guide/ui/tabs.md +161 -0
- package/dist/guide/ui/toaster.md +152 -0
- package/dist/guide/ui/tooltip.md +103 -0
- package/dist/guide/undo.md +178 -0
- package/dist/guide/virtual-collections.md +183 -0
- package/dist/guide/web-components.md +179 -0
- package/dist/guide/widgets.md +217 -0
- package/dist/index.cjs.js +15283 -6279
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +3739 -370
- package/dist/index.esm.js +15230 -6274
- package/dist/index.esm.js.map +1 -0
- package/dist/jsx-dev-runtime.cjs.js +27 -329
- package/dist/jsx-dev-runtime.cjs.js.map +1 -0
- package/dist/jsx-dev-runtime.esm.js +20 -322
- package/dist/jsx-dev-runtime.esm.js.map +1 -0
- package/dist/jsx-runtime.cjs.js +27 -329
- package/dist/jsx-runtime.cjs.js.map +1 -0
- package/dist/jsx-runtime.esm.js +20 -322
- package/dist/jsx-runtime.esm.js.map +1 -0
- package/dist/jsx.cjs.js +11 -309
- package/dist/jsx.cjs.js.map +1 -0
- package/dist/jsx.esm.js +9 -310
- package/dist/jsx.esm.js.map +1 -0
- package/dist/react.cjs.js +117 -0
- package/dist/react.cjs.js.map +1 -0
- package/dist/react.esm.js +115 -0
- package/dist/react.esm.js.map +1 -0
- package/dist/shims/globalthis.cjs +20 -0
- package/dist/sygnal.min.js +2 -1
- package/dist/sygnal.min.js.map +1 -0
- package/dist/ui-combobox.cjs.js +169 -0
- package/dist/ui-combobox.cjs.js.map +1 -0
- package/dist/ui-combobox.esm.js +148 -0
- package/dist/ui-combobox.esm.js.map +1 -0
- package/dist/ui-menu.cjs.js +87 -0
- package/dist/ui-menu.cjs.js.map +1 -0
- package/dist/ui-menu.esm.js +66 -0
- package/dist/ui-menu.esm.js.map +1 -0
- package/dist/ui-select.cjs.js +104 -0
- package/dist/ui-select.cjs.js.map +1 -0
- package/dist/ui-select.esm.js +83 -0
- package/dist/ui-select.esm.js.map +1 -0
- package/dist/ui.cjs.js +738 -0
- package/dist/ui.cjs.js.map +1 -0
- package/dist/ui.esm.js +727 -0
- package/dist/ui.esm.js.map +1 -0
- package/dist/vike/ClientOnly.cjs.js +5 -14
- package/dist/vike/ClientOnly.cjs.js.map +1 -0
- package/dist/vike/ClientOnly.mjs +5 -14
- package/dist/vike/ClientOnly.mjs.map +1 -0
- package/dist/vike/{+config.js → config/+config.js} +10 -1
- package/dist/vike/config/+config.js.map +1 -0
- package/dist/vike/config/package.json +6 -0
- package/dist/vike/onRenderClient.cjs.js +166 -95
- package/dist/vike/onRenderClient.cjs.js.map +1 -0
- package/dist/vike/onRenderClient.mjs +166 -95
- package/dist/vike/onRenderClient.mjs.map +1 -0
- package/dist/vike/onRenderHtml.cjs.js +60 -24
- package/dist/vike/onRenderHtml.cjs.js.map +1 -0
- package/dist/vike/onRenderHtml.mjs +61 -25
- package/dist/vike/onRenderHtml.mjs.map +1 -0
- package/dist/vite/plugin.cjs.js +926 -65
- package/dist/vite/plugin.cjs.js.map +1 -0
- package/dist/vite/plugin.mjs +925 -65
- package/dist/vite/plugin.mjs.map +1 -0
- package/dist/zag.cjs.js +408 -0
- package/dist/zag.cjs.js.map +1 -0
- package/dist/zag.esm.js +405 -0
- package/dist/zag.esm.js.map +1 -0
- package/llms.txt +313 -0
- package/package.json +109 -16
- package/src/astro/client.ts +40 -18
- package/src/astro/index.d.ts +48 -1
- package/src/astro/index.ts +106 -9
- package/src/astro/server.ts +11 -3
- package/src/collection.ts +6 -90
- package/src/core/actions.ts +134 -0
- package/src/core/cell.ts +202 -0
- package/src/core/debug.ts +23 -0
- package/src/core/define.ts +242 -0
- package/src/core/hooks.ts +314 -0
- package/src/core/hosts/collection.ts +325 -0
- package/src/core/hosts/switchable.ts +146 -0
- package/src/core/instance.ts +592 -0
- package/src/core/markers/clientonly.ts +13 -0
- package/src/core/markers/lazy.ts +40 -0
- package/src/core/markers/portal.ts +96 -0
- package/src/core/markers/suspense.ts +41 -0
- package/src/core/markers/transition.ts +70 -0
- package/src/core/registry.ts +25 -0
- package/src/core/runtime.ts +573 -0
- package/src/core/statics.ts +104 -0
- package/src/core/teardown.ts +60 -0
- package/src/core/view.ts +37 -0
- package/src/cycle/dom/DocumentDOMSource.ts +13 -8
- package/src/cycle/dom/ElementFinder.ts +7 -9
- package/src/cycle/dom/EventDelegator.ts +174 -223
- package/src/cycle/dom/IsolateModule.ts +65 -35
- package/src/cycle/dom/MainDOMSource.ts +13 -2
- package/src/cycle/dom/PriorityQueue.ts +4 -2
- package/src/cycle/dom/SymbolTree.ts +18 -47
- package/src/cycle/dom/classNameModule.ts +76 -0
- package/src/cycle/dom/controlledInputModule.ts +50 -0
- package/src/cycle/dom/enrichEventStream.ts +29 -45
- package/src/cycle/dom/fragment.ts +7 -0
- package/src/cycle/dom/isolate.ts +30 -27
- package/src/cycle/dom/makeDOMDriver.ts +115 -57
- package/src/cycle/dom/mockDOMSource.ts +83 -9
- package/src/cycle/dom/modules.ts +21 -4
- package/src/cycle/dom/propsModule.ts +65 -0
- package/src/cycle/dom/selectModule.ts +22 -17
- package/src/cycle/dom/snabbdom.ts +1 -6
- package/src/cycle/dom/thunk.ts +3 -0
- package/src/cycle/dom/utils.ts +98 -0
- package/src/cycle/dom/viewTransition.ts +43 -0
- package/src/cycle/state/StateSource.ts +20 -4
- package/src/cycle/state/objIsEqual.ts +50 -0
- package/src/cycle/state/types.ts +0 -10
- package/src/defineComponent.ts +34 -0
- package/src/devtools.d.ts +151 -0
- package/src/devtools.ts +34 -0
- package/src/element.d.ts +59 -0
- package/src/element.ts +235 -0
- package/src/extra/backoff.ts +9 -0
- package/src/extra/behaviors.ts +169 -0
- package/src/extra/browserSignals.ts +23 -0
- package/src/extra/browserSources.ts +326 -0
- package/src/extra/command.ts +3 -3
- package/src/extra/controls.ts +47 -0
- package/src/extra/copyAsTest.ts +286 -0
- package/src/extra/devtools.ts +109 -31
- package/src/extra/devtoolsActions.ts +379 -0
- package/src/extra/devtoolsHook.ts +9 -0
- package/src/extra/devtoolsNext.ts +83 -0
- package/src/extra/diagnostics/checks/actionLog.ts +108 -0
- package/src/extra/diagnostics/checks/behaviors.ts +49 -0
- package/src/extra/diagnostics/checks/browserSources.ts +96 -0
- package/src/extra/diagnostics/checks/collections.ts +67 -0
- package/src/extra/diagnostics/checks/controls.ts +148 -0
- package/src/extra/diagnostics/checks/dataset.ts +57 -0
- package/src/extra/diagnostics/checks/dom.ts +250 -0
- package/src/extra/diagnostics/checks/elementCommands.ts +175 -0
- package/src/extra/diagnostics/checks/events.ts +83 -0
- package/src/extra/diagnostics/checks/fetch.ts +135 -0
- package/src/extra/diagnostics/checks/forms.ts +163 -0
- package/src/extra/diagnostics/checks/index.ts +202 -0
- package/src/extra/diagnostics/checks/inspect.ts +427 -0
- package/src/extra/diagnostics/checks/next.ts +417 -0
- package/src/extra/diagnostics/checks/persist.ts +54 -0
- package/src/extra/diagnostics/checks/props.ts +56 -0
- package/src/extra/diagnostics/checks/public.d.ts +302 -0
- package/src/extra/diagnostics/checks/replies.ts +128 -0
- package/src/extra/diagnostics/checks/router.ts +100 -0
- package/src/extra/diagnostics/checks/rxjsHints.ts +88 -0
- package/src/extra/diagnostics/checks/shared.ts +203 -0
- package/src/extra/diagnostics/checks/shorthand.ts +115 -0
- package/src/extra/diagnostics/checks/sortable.ts +129 -0
- package/src/extra/diagnostics/checks/state.ts +148 -0
- package/src/extra/diagnostics/checks/statics.ts +48 -0
- package/src/extra/diagnostics/checks/strict.ts +55 -0
- package/src/extra/diagnostics/checks/timers.ts +80 -0
- package/src/extra/diagnostics/checks/viewTransitions.ts +47 -0
- package/src/extra/diagnostics/checks/virtual.ts +73 -0
- package/src/extra/diagnostics/checks/widgets.ts +109 -0
- package/src/extra/diagnostics/checks/wiring.ts +121 -0
- package/src/extra/diagnostics/codes.ts +477 -0
- package/src/extra/diagnostics/index.ts +353 -0
- package/src/extra/diagnostics/legacy.ts +76 -0
- package/src/extra/driverFactories.ts +172 -60
- package/src/extra/elementCommands.ts +53 -0
- package/src/extra/eventDriver.ts +4 -0
- package/src/extra/fetchDriver.ts +519 -0
- package/src/extra/flatten.ts +75 -0
- package/src/extra/focusWithin.ts +27 -0
- package/src/extra/form.ts +268 -0
- package/src/extra/formHelpers.ts +139 -0
- package/src/extra/head.ts +106 -0
- package/src/extra/hmr.ts +2 -3
- package/src/extra/owned.ts +24 -0
- package/src/extra/pager.ts +50 -0
- package/src/extra/persist.ts +133 -0
- package/src/extra/pwa.ts +1 -1
- package/src/extra/queryCache.ts +107 -0
- package/src/extra/reducers.ts +13 -6
- package/src/extra/reduxDevtools.ts +92 -0
- package/src/extra/replies.ts +54 -0
- package/src/extra/router.ts +323 -0
- package/src/extra/run.ts +94 -210
- package/src/extra/selection.ts +76 -0
- package/src/extra/socketDriver.ts +265 -0
- package/src/extra/sortable.ts +377 -0
- package/src/extra/ssr.ts +427 -160
- package/src/extra/standardSchema.ts +27 -0
- package/src/extra/testing.ts +3158 -190
- package/src/extra/timers.ts +95 -0
- package/src/extra/undo.ts +261 -0
- package/src/extra/viewTransitions.ts +38 -0
- package/src/extra/virtual.ts +513 -0
- package/src/extra/widget.ts +201 -0
- package/src/extra/xstreamExtras.ts +269 -0
- package/src/index.d.ts +3012 -87
- package/src/index.ts +32 -10
- package/src/jsx-runtime.ts +15 -1
- package/src/jsx.ts +2 -1
- package/src/lazy.ts +50 -7
- package/src/portal.ts +3 -1
- package/src/pragma/index.ts +262 -134
- package/src/react-peers.d.ts +5 -0
- package/src/react.d.ts +43 -0
- package/src/react.ts +110 -0
- package/src/shared.ts +48 -0
- package/src/slot.ts +1 -1
- package/src/suspense.ts +3 -1
- package/src/switchable.ts +6 -119
- package/src/transition.ts +3 -1
- package/src/ui/accordion.ts +64 -0
- package/src/ui/dialog.ts +129 -0
- package/src/ui/disclosure.ts +35 -0
- package/src/ui/popover.ts +45 -0
- package/src/ui/shared.ts +94 -0
- package/src/ui/tabs.ts +82 -0
- package/src/ui/toaster.ts +198 -0
- package/src/ui/tooltip.ts +70 -0
- package/src/ui/zag/combobox.ts +115 -0
- package/src/ui/zag/menu.ts +40 -0
- package/src/ui/zag/select.ts +54 -0
- package/src/ui/zag/shared.ts +43 -0
- package/src/ui-combobox.d.ts +20 -0
- package/src/ui-combobox.ts +6 -0
- package/src/ui-menu.d.ts +30 -0
- package/src/ui-menu.ts +6 -0
- package/src/ui-select.d.ts +17 -0
- package/src/ui-select.ts +6 -0
- package/src/ui-zag-types.d.ts +42 -0
- package/src/ui.d.ts +208 -0
- package/src/ui.ts +15 -0
- package/src/vike/+config.ts +9 -1
- package/src/vike/ClientOnly.ts +1 -1
- package/src/vike/onRenderClient.ts +144 -96
- package/src/vike/onRenderHtml.ts +69 -26
- package/src/vike/types.ts +27 -4
- package/src/vite/globalthis-shim.ts +18 -0
- package/src/vite/globalthis.ts +56 -0
- package/src/vite/plugin.d.ts +114 -2
- package/src/vite/plugin.ts +920 -56
- package/src/zag.d.ts +64 -0
- package/src/zag.ts +238 -0
- package/dist/astro/astro/client.d.ts +0 -5
- package/dist/astro/astro/index.d.ts +0 -16
- package/dist/astro/astro/server.d.ts +0 -12
- package/dist/astro/client.d.ts +0 -5
- package/dist/astro/client.esm.js +0 -4665
- package/dist/astro/collection.d.ts +0 -12
- package/dist/astro/component.d.ts +0 -22
- package/dist/astro/cycle/dom/BodyDOMSource.d.ts +0 -10
- package/dist/astro/cycle/dom/DOMSource.d.ts +0 -11
- package/dist/astro/cycle/dom/DocumentDOMSource.d.ts +0 -12
- package/dist/astro/cycle/dom/ElementFinder.d.ts +0 -8
- package/dist/astro/cycle/dom/EventDelegator.d.ts +0 -34
- package/dist/astro/cycle/dom/IsolateModule.d.ts +0 -23
- package/dist/astro/cycle/dom/MainDOMSource.d.ts +0 -32
- package/dist/astro/cycle/dom/PriorityQueue.d.ts +0 -7
- package/dist/astro/cycle/dom/ScopeChecker.d.ts +0 -9
- package/dist/astro/cycle/dom/SymbolTree.d.ts +0 -9
- package/dist/astro/cycle/dom/VNodeWrapper.d.ts +0 -8
- package/dist/astro/cycle/dom/enrichEventStream.d.ts +0 -24
- package/dist/astro/cycle/dom/fromEvent.d.ts +0 -6
- package/dist/astro/cycle/dom/index.d.ts +0 -8
- package/dist/astro/cycle/dom/isolate.d.ts +0 -9
- package/dist/astro/cycle/dom/makeDOMDriver.d.ts +0 -11
- package/dist/astro/cycle/dom/mockDOMSource.d.ts +0 -17
- package/dist/astro/cycle/dom/modules.d.ts +0 -5
- package/dist/astro/cycle/dom/snabbdom.d.ts +0 -22
- package/dist/astro/cycle/dom/styleModule.d.ts +0 -13
- package/dist/astro/cycle/dom/thunk.d.ts +0 -11
- package/dist/astro/cycle/dom/utils.d.ts +0 -8
- package/dist/astro/cycle/isolate/index.d.ts +0 -42
- package/dist/astro/cycle/run/adapt.d.ts +0 -6
- package/dist/astro/cycle/run/index.d.ts +0 -36
- package/dist/astro/cycle/run/internals.d.ts +0 -8
- package/dist/astro/cycle/run/types.d.ts +0 -49
- package/dist/astro/cycle/state/Collection.d.ts +0 -29
- package/dist/astro/cycle/state/StateSource.d.ts +0 -20
- package/dist/astro/cycle/state/index.d.ts +0 -5
- package/dist/astro/cycle/state/pickCombine.d.ts +0 -3
- package/dist/astro/cycle/state/pickMerge.d.ts +0 -3
- package/dist/astro/cycle/state/types.d.ts +0 -18
- package/dist/astro/cycle/state/withState.d.ts +0 -17
- package/dist/astro/extra/classes.d.ts +0 -7
- package/dist/astro/extra/devtools.d.ts +0 -78
- package/dist/astro/extra/dragDriver.d.ts +0 -20
- package/dist/astro/extra/driverFactories.d.ts +0 -12
- package/dist/astro/extra/eventDriver.d.ts +0 -9
- package/dist/astro/extra/exactState.d.ts +0 -1
- package/dist/astro/extra/hmr.d.ts +0 -17
- package/dist/astro/extra/logDriver.d.ts +0 -2
- package/dist/astro/extra/processDrag.d.ts +0 -19
- package/dist/astro/extra/processForm.d.ts +0 -15
- package/dist/astro/extra/run.d.ts +0 -13
- package/dist/astro/extra/xstreamCompat.d.ts +0 -5
- package/dist/astro/index.d.ts +0 -19
- package/dist/astro/index.esm.js +0 -27
- package/dist/astro/jsx-dev-runtime.d.ts +0 -1
- package/dist/astro/jsx-runtime.d.ts +0 -4
- package/dist/astro/jsx.d.ts +0 -2
- package/dist/astro/pragma/fn.d.ts +0 -7
- package/dist/astro/pragma/index.d.ts +0 -7
- package/dist/astro/pragma/is.d.ts +0 -10
- package/dist/astro/server.d.ts +0 -12
- package/dist/astro/server.esm.js +0 -25
- package/dist/astro/switchable.d.ts +0 -7
- package/dist/collection.d.ts +0 -12
- package/dist/component.d.ts +0 -22
- package/dist/cycle/dom/BodyDOMSource.d.ts +0 -10
- package/dist/cycle/dom/DOMSource.d.ts +0 -11
- package/dist/cycle/dom/DocumentDOMSource.d.ts +0 -12
- package/dist/cycle/dom/ElementFinder.d.ts +0 -8
- package/dist/cycle/dom/EventDelegator.d.ts +0 -34
- package/dist/cycle/dom/IsolateModule.d.ts +0 -23
- package/dist/cycle/dom/MainDOMSource.d.ts +0 -32
- package/dist/cycle/dom/PriorityQueue.d.ts +0 -7
- package/dist/cycle/dom/ScopeChecker.d.ts +0 -9
- package/dist/cycle/dom/SymbolTree.d.ts +0 -9
- package/dist/cycle/dom/VNodeWrapper.d.ts +0 -8
- package/dist/cycle/dom/enrichEventStream.d.ts +0 -24
- package/dist/cycle/dom/fromEvent.d.ts +0 -6
- package/dist/cycle/dom/index.d.ts +0 -8
- package/dist/cycle/dom/isolate.d.ts +0 -9
- package/dist/cycle/dom/makeDOMDriver.d.ts +0 -11
- package/dist/cycle/dom/mockDOMSource.d.ts +0 -17
- package/dist/cycle/dom/modules.d.ts +0 -5
- package/dist/cycle/dom/snabbdom.d.ts +0 -22
- package/dist/cycle/dom/styleModule.d.ts +0 -13
- package/dist/cycle/dom/thunk.d.ts +0 -11
- package/dist/cycle/dom/utils.d.ts +0 -8
- package/dist/cycle/isolate/index.d.ts +0 -42
- package/dist/cycle/run/adapt.d.ts +0 -6
- package/dist/cycle/run/index.d.ts +0 -36
- package/dist/cycle/run/internals.d.ts +0 -8
- package/dist/cycle/run/types.d.ts +0 -49
- package/dist/cycle/state/Collection.d.ts +0 -29
- package/dist/cycle/state/StateSource.d.ts +0 -20
- package/dist/cycle/state/index.d.ts +0 -5
- package/dist/cycle/state/pickCombine.d.ts +0 -3
- package/dist/cycle/state/pickMerge.d.ts +0 -3
- package/dist/cycle/state/types.d.ts +0 -18
- package/dist/cycle/state/withState.d.ts +0 -17
- package/dist/extra/classes.d.ts +0 -7
- package/dist/extra/devtools.d.ts +0 -78
- package/dist/extra/dragDriver.d.ts +0 -20
- package/dist/extra/driverFactories.d.ts +0 -12
- package/dist/extra/eventDriver.d.ts +0 -9
- package/dist/extra/exactState.d.ts +0 -1
- package/dist/extra/hmr.d.ts +0 -17
- package/dist/extra/logDriver.d.ts +0 -2
- package/dist/extra/processDrag.d.ts +0 -19
- package/dist/extra/processForm.d.ts +0 -15
- package/dist/extra/run.d.ts +0 -13
- package/dist/extra/xstreamCompat.d.ts +0 -5
- package/dist/jsx-dev-runtime.d.ts +0 -1
- package/dist/jsx-dev-runtime.js +0 -224
- package/dist/jsx-runtime.d.ts +0 -4
- package/dist/jsx-runtime.js +0 -224
- package/dist/jsx.d.ts +0 -2
- package/dist/pragma/fn.d.ts +0 -7
- package/dist/pragma/index.d.ts +0 -7
- package/dist/pragma/is.d.ts +0 -10
- package/dist/switchable.d.ts +0 -7
- package/dist/vike/+config.cjs.js +0 -65
- package/src/component.ts +0 -2256
- package/src/cycle/isolate/index.ts +0 -196
- package/src/cycle/run/index.ts +0 -151
- package/src/cycle/run/internals.ts +0 -143
- package/src/cycle/state/Collection.ts +0 -174
- package/src/cycle/state/index.ts +0 -5
- package/src/cycle/state/pickCombine.ts +0 -167
- package/src/cycle/state/pickMerge.ts +0 -122
- package/src/cycle/state/withState.ts +0 -47
- package/src/pragma/fn.ts +0 -55
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {warn} from './diagnostics/legacy';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* PLAN-4 GS-5 (D114): state persistence for the root component, as a helper value:
|
|
5
|
+
*
|
|
6
|
+
* TodoApp.persist = persist({ key: 'todo-app', pick: ['todos', 'filter'], version: 2, migrate })
|
|
7
|
+
*
|
|
8
|
+
* The core has no persistence code: a root component calls `persist.setup(this)` once, in its
|
|
9
|
+
* root setup (src/core/runtime.ts rootShim); an app that never imports persist() pays 0 B.
|
|
10
|
+
*
|
|
11
|
+
* - Stored as JSON `{ version, state }` under `key`; `state` has the picked top-level keys
|
|
12
|
+
* (`pick`), or all but `omit` and the calculated fields. A `uses` key whose behavior is marked
|
|
13
|
+
* `persist: false` (sortable: drag state) is left out of both the save and the restore (the root's own
|
|
14
|
+
* `uses` only: a sub-component's or Collection item's behavior slice is part of its data, 3-L G-476). `format: 'plain'` (4-G1, D143) stores
|
|
15
|
+
* that object itself, with no envelope; `version` / `migrate` then don't apply (a type error;
|
|
16
|
+
* ignored here), and a stored value that isn't an object is ignored.
|
|
17
|
+
* - Restore: a synchronous read before INITIALIZE, merged into initialState, so the restore is
|
|
18
|
+
* part of the initial-state action. A stored `version` other than `version` (default 1) goes
|
|
19
|
+
* through `migrate(old, fromVersion)`; without migrate, or when it returns nothing, the entry
|
|
20
|
+
* is ignored. Hydrating server HTML, the restore is a RESTORE action after the first state
|
|
21
|
+
* instead, so the first render matches the server's. Hydrating: the `hydrate` option when given,
|
|
22
|
+
* else the integration's `__hydrate` source (Astro: a server-rendered island; Vike: a hydration),
|
|
23
|
+
* else whether run()'s mount point (its `__m` source) starts with renderToString's markup (the
|
|
24
|
+
* root element carries `data-sygnal-ssr`; 3-R).
|
|
25
|
+
* - Writes: debounced (`debounceMs`, default 100), skipped when the stored text is the same,
|
|
26
|
+
* flushed on `pagehide` and on dispose.
|
|
27
|
+
* - `PERSIST: { clear: true }` in any model entry's object form (a value or a function of
|
|
28
|
+
* (state, data)) removes the stored copy; the state that same action produces isn't written
|
|
29
|
+
* (later changes are). The entry's PERSIST sink is turned into an EFFECT here, so it needs no
|
|
30
|
+
* driver. An 'ACTION | PERSIST' key (non-canonical) isn't handled (3-B2).
|
|
31
|
+
* - `sync: true`: another tab's write is applied through RESTORE (the `storage` event, or an
|
|
32
|
+
* adapter's `subscribe(fn)`).
|
|
33
|
+
* - `storage`: 'local' (default), 'session', or a synchronous { getItem, setItem, removeItem }
|
|
34
|
+
* adapter (optionally with subscribe). renderComponent passes its fake stores as the
|
|
35
|
+
* `__storage` source ({ local, session, f: flush functions t.settle() calls }).
|
|
36
|
+
* - Failures (unreadable entry, migrate throws, quota) are SYG642 (warn, printed in production
|
|
37
|
+
* too), once per kind (restore / save / clear; a save that works again re-arms it); the app
|
|
38
|
+
* continues on initialState / unsaved, and a failed save is retried at the next change.
|
|
39
|
+
*/
|
|
40
|
+
const g: any = globalThis;
|
|
41
|
+
|
|
42
|
+
export const setupPersist = (c: any, o: any): void => {
|
|
43
|
+
const {key, pick, omit, version = 1, migrate, sync, debounceMs = 100} = o, plain = o.format == 'plain', src = c.sources, m = src.__m;
|
|
44
|
+
const env = src.__storage, calc = c.calculated || {};
|
|
45
|
+
// hydrating: the option, else the integration's signal (__hydrate: Astro, Vike), else whether
|
|
46
|
+
// run()'s mount point starts with renderToString's markup (its root element is marked; a
|
|
47
|
+
// client-only app's loading placeholder isn't server markup)
|
|
48
|
+
const hydrate = o.hydrate ?? src.__hydrate ?? !!(typeof m == 'string' ? g.document?.querySelector(m) : m)?.firstElementChild?.hasAttribute('data-sygnal-ssr');
|
|
49
|
+
let S: any, t: any, last: any, raw: any, skip: any, off: any;
|
|
50
|
+
// (the docs link the message ends with explains the causes and fixes). Once per kind (restore,
|
|
51
|
+
// save, clear): a storage that throws on every write must not warn on every change; a save that
|
|
52
|
+
// works again re-arms the save report
|
|
53
|
+
const bad: any = {};
|
|
54
|
+
const fail = (what: string, e?: any) => bad[what] || (bad[what] = 1, warn('SYG642', c, `persist '${key}': ${what} failed`, undefined, e));
|
|
55
|
+
// a behavior's slice marked `persist: false` (UI state: sortable's drag) is never saved or restored (3-H G-452)
|
|
56
|
+
const uses = c.view?.uses || {};
|
|
57
|
+
const only = (s: any) => {
|
|
58
|
+
const out: any = {};
|
|
59
|
+
for (const k in s) if ((pick ? pick.includes(k) : !omit?.includes(k)) && !(k in calc) && uses[k]?.persist !== false) out[k] = s[k];
|
|
60
|
+
return out;
|
|
61
|
+
};
|
|
62
|
+
const read = (r: any) => {
|
|
63
|
+
try {
|
|
64
|
+
if (r == null) return;
|
|
65
|
+
const j = JSON.parse(r);
|
|
66
|
+
if (plain) return j && typeof j == 'object' && !Array.isArray(j) ? only(j) : undefined;
|
|
67
|
+
const {version: v = 1, state} = j, s = v === version ? state : migrate && migrate(state, v);
|
|
68
|
+
return s && only(s);
|
|
69
|
+
} catch (e) { fail('restore', e); }
|
|
70
|
+
};
|
|
71
|
+
const write = () => {
|
|
72
|
+
clearTimeout(t); t = 0;
|
|
73
|
+
const r = JSON.stringify(plain ? only(last) : {version, state: only(last)}), p = raw;
|
|
74
|
+
// a failed save is retried at the next change (raw stays the stored text)
|
|
75
|
+
if (r != raw) try { raw = r; S.setItem(key, r); bad.save = 0; } catch (e) { raw = p; fail('save', e); }
|
|
76
|
+
};
|
|
77
|
+
const clear = () => {
|
|
78
|
+
clearTimeout(t); t = 0; skip = 1; raw = null;
|
|
79
|
+
setTimeout(() => skip = 0);
|
|
80
|
+
try { S?.removeItem(key); } catch (e) { fail('clear', e); }
|
|
81
|
+
};
|
|
82
|
+
const send = (d: any) => d && c.action$.shamefullySendNext({type: 'RESTORE', data: d});
|
|
83
|
+
// PERSIST sinks become EFFECTs (no driver); a model RESTORE entry replaces the built-in one
|
|
84
|
+
const wrap = (p: any, e?: any) => (...a: any[]) => { const r = e?.(...a), v = typeof p == 'function' ? p(...a) : p; v?.clear && clear(); return r; };
|
|
85
|
+
const model: any = {RESTORE: (s: any, d: any) => ({...s, ...d})};
|
|
86
|
+
for (const k in c.model) {
|
|
87
|
+
let v = c.model[k];
|
|
88
|
+
if (v && typeof v == 'object' && 'PERSIST' in v) { const {PERSIST, ...rest} = v; v = {...rest, EFFECT: wrap(PERSIST, rest.EFFECT)}; }
|
|
89
|
+
model[k] = v;
|
|
90
|
+
}
|
|
91
|
+
c.model = model;
|
|
92
|
+
try { S = typeof o.storage == 'object' ? o.storage : (env || g)[(o.storage || 'local') + (env ? '' : 'Storage')]; } catch (_) {}
|
|
93
|
+
if (!S) return;
|
|
94
|
+
try {
|
|
95
|
+
raw = S.getItem(key);
|
|
96
|
+
if (!hydrate) { const r = read(raw); if (r) c.initialState = {...c.initialState, ...r}; }
|
|
97
|
+
} catch (e) { fail('restore', e); }
|
|
98
|
+
const state$ = c.sources[c.stateSourceName].stream;
|
|
99
|
+
let first = 1;
|
|
100
|
+
const L = {next: (s: any) => {
|
|
101
|
+
last = s;
|
|
102
|
+
// the initial state (restored or not) isn't written back. hydrate: it is the server's; restore
|
|
103
|
+
// once it has rendered (the DOM driver patches before this listener hears the vtree)
|
|
104
|
+
if (first) {
|
|
105
|
+
first = 0;
|
|
106
|
+
let once = hydrate;
|
|
107
|
+
const v$ = c.vdom$, l = {next: () => once && setTimeout(() => (v$.removeListener(l), send(read(raw))), once = 0)};
|
|
108
|
+
return hydrate && v$.addListener(l);
|
|
109
|
+
}
|
|
110
|
+
if (!skip) clearTimeout(t), t = setTimeout(write, debounceMs);
|
|
111
|
+
}};
|
|
112
|
+
state$.addListener(L);
|
|
113
|
+
const flush = () => t && write();
|
|
114
|
+
const onSync = (k: any, v: any) => { if (k == key && v != raw) send(read(raw = v)); };
|
|
115
|
+
const onStorage = (e: any) => (!e.storageArea || e.storageArea == S) && onSync(e.key, e.newValue);
|
|
116
|
+
if (sync) off = S.subscribe ? S.subscribe(onSync) : (g.addEventListener?.('storage', onStorage), () => g.removeEventListener?.('storage', onStorage));
|
|
117
|
+
g.addEventListener?.('pagehide', flush);
|
|
118
|
+
env?.f.add(flush);
|
|
119
|
+
c._dispose$.addListener({next: () => {
|
|
120
|
+
flush();
|
|
121
|
+
state$.removeListener(L);
|
|
122
|
+
off?.();
|
|
123
|
+
g.removeEventListener?.('pagehide', flush);
|
|
124
|
+
env?.f.delete(flush);
|
|
125
|
+
}});
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* `App.persist = persist({ key, pick | omit, version, migrate, format, storage, sync, hydrate, debounceMs })`:
|
|
130
|
+
* the root component's state, saved to localStorage (or sessionStorage, or an adapter) and
|
|
131
|
+
* restored at startup. Only an app that imports it pays for it.
|
|
132
|
+
*/
|
|
133
|
+
export const persist = (o: any) => ({options: o, setup: (c: any) => setupPersist(c, o)});
|
package/src/extra/pwa.ts
CHANGED
|
@@ -118,7 +118,7 @@ export function makeServiceWorkerDriver(
|
|
|
118
118
|
|
|
119
119
|
let _onlineCleanup: (() => void) | undefined;
|
|
120
120
|
|
|
121
|
-
export const onlineStatus$: Stream<boolean> = xs.create<boolean>({
|
|
121
|
+
export const onlineStatus$: Stream<boolean> = /*#__PURE__*/ xs.create<boolean>({
|
|
122
122
|
start(listener: Listener<boolean>) {
|
|
123
123
|
if (typeof window === 'undefined') {
|
|
124
124
|
listener.next(true);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {onBrowserSignals} from './browserSignals';
|
|
2
|
+
import {withQuery, hit} from './fetchDriver';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* queryCache(options?) (PLAN-3 D88, 5-5): the opt-in query cache of makeFetchDriver, in its own
|
|
6
|
+
* export so apps that only make requests don't pay for it:
|
|
7
|
+
*
|
|
8
|
+
* makeFetchDriver({ cache: queryCache({ staleTime, gcTime, refetchOnFocus, refetchOnReconnect, initial }) })
|
|
9
|
+
*
|
|
10
|
+
* It owns the entries (key → { k, q (the request), v (data), at (fetched at), s (marked stale),
|
|
11
|
+
* n (resources using it), g (gc timer) }), gc, freshness (the stale-while-revalidate decision),
|
|
12
|
+
* the fetches identical requests share (de-duplication, `f`), entry invalidation, the focus /
|
|
13
|
+
* reconnect trigger and SSR seeding. The driver calls its hooks (key, fresh, get, put, use,
|
|
14
|
+
* inval, on, list) and keeps resources, polling, retries and validation.
|
|
15
|
+
*
|
|
16
|
+
* - Keys: method + URL as written (the driver's baseUrl left out, query sorted) + body + parse.
|
|
17
|
+
* Cacheable: a resource's GET/HEAD request, and any request with `cache: true` or `staleTime`
|
|
18
|
+
* (`cache: false` opts out; a `parse` function / 'response' or a non-string body never is).
|
|
19
|
+
* - SSR seeding (H-7): `dehydrate()` returns a JSON-safe snapshot `[{ key, data, updatedAt, tags }]`
|
|
20
|
+
* of the entries with data; `hydrate(snapshot)` / `queryCache({ initial })` write it back (an
|
|
21
|
+
* entry newer than the snapshot's is kept). `set(request, data)` writes one entry (a loader on
|
|
22
|
+
* the server). Entries keep their `updatedAt`, so a seeded entry is fresh for `staleTime`.
|
|
23
|
+
* - `prefetch(request)`: the attached driver (the last makeFetchDriver given this cache) fetches
|
|
24
|
+
* the request into the cache without a reply, like the `{ prefetch }` sink command.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const IDEMPOTENT = /^(GET|HEAD)$/i;
|
|
28
|
+
|
|
29
|
+
export function queryCache(o: any = {}): any {
|
|
30
|
+
const map = new Map<string, any>();
|
|
31
|
+
const now = () => Date.now();
|
|
32
|
+
const gc = (E: any) => {
|
|
33
|
+
clearTimeout(E.g);
|
|
34
|
+
const ms = o.gcTime ?? 3e5;
|
|
35
|
+
// unref: a server's seeded cache never keeps Node alive
|
|
36
|
+
if (ms < 1 / 0) (E.g = setTimeout(() => E.n || map.delete(E.k), ms) as any).unref?.();
|
|
37
|
+
};
|
|
38
|
+
const entry = (k: string, q: any) => {
|
|
39
|
+
let E = map.get(k);
|
|
40
|
+
if (!E) map.set(k, (E = {k, q, n: 0}));
|
|
41
|
+
return E;
|
|
42
|
+
};
|
|
43
|
+
// the key of a cacheable request (else undefined); `res`: a resource's
|
|
44
|
+
const key = (q: any, res?: any) => {
|
|
45
|
+
if (typeof q == 'string') q = {url: q};
|
|
46
|
+
const {method, json, body, parse, query} = q;
|
|
47
|
+
const m = (method || (json !== undefined || body !== undefined ? 'POST' : 'GET')).toUpperCase();
|
|
48
|
+
const b = json !== undefined ? JSON.stringify(json) : body ?? '';
|
|
49
|
+
if (q.cache === false || typeof b != 'string' || typeof parse == 'function' || parse == 'response' ||
|
|
50
|
+
!(q.cache || q.staleTime != null || (res && IDEMPOTENT.test(m)))) return;
|
|
51
|
+
return [m, withQuery(q.url ?? '', query, 1), b, parse].join(' ').trim();
|
|
52
|
+
};
|
|
53
|
+
const fresh = (k: any, q: any) => {
|
|
54
|
+
const E = map.get(k);
|
|
55
|
+
return E?.at > 0 && !E.s && now() - E.at < (q?.staleTime ?? o.staleTime ?? 0);
|
|
56
|
+
};
|
|
57
|
+
const put = (k: string, q: any, v: any, at = now()) => {
|
|
58
|
+
const E = entry(k, q);
|
|
59
|
+
E.v = v;
|
|
60
|
+
E.at = at;
|
|
61
|
+
E.s = 0;
|
|
62
|
+
E.q = q;
|
|
63
|
+
E.n || gc(E);
|
|
64
|
+
};
|
|
65
|
+
const C: any = {
|
|
66
|
+
key,
|
|
67
|
+
fresh,
|
|
68
|
+
put,
|
|
69
|
+
get: (k: any) => map.get(k),
|
|
70
|
+
// the fetches identical cacheable requests share (the driver's flight records), key → flight
|
|
71
|
+
f: new Map(),
|
|
72
|
+
// resource R now uses key k (or none): the entries' subscriber counts, gc when unused
|
|
73
|
+
use: (R: any, k?: string) => {
|
|
74
|
+
if (R.k === k) return;
|
|
75
|
+
const O = map.get(R.k);
|
|
76
|
+
if (O && !--O.n) gc(O);
|
|
77
|
+
if ((R.k = k) !== undefined) {
|
|
78
|
+
const E = entry(k as string, R.q);
|
|
79
|
+
E.n++;
|
|
80
|
+
clearTimeout(E.g);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
// D80: marks the matching entries stale (`dry`: only counts them)
|
|
84
|
+
inval: (x: any, dry?: any) => {
|
|
85
|
+
let n = 0;
|
|
86
|
+
map.forEach(E => { if (hit(x, E.q)) { n++; dry || (E.s = 1); } });
|
|
87
|
+
return n;
|
|
88
|
+
},
|
|
89
|
+
// focus / reconnect call `fn` (the driver refetches its stale mounted resources); `on`: the
|
|
90
|
+
// test fake's signal source
|
|
91
|
+
on: (on: any, fn: () => void) => (on || onBrowserSignals)((sig: string) => {
|
|
92
|
+
o[sig == 'focus' ? 'refetchOnFocus' : 'refetchOnReconnect'] === false || fn();
|
|
93
|
+
}),
|
|
94
|
+
list: () => [...map.values()].map(E => ({key: E.k, age: E.at && now() - E.at, stale: !fresh(E.k, E.q), subscribers: E.n, data: E.v, tags: E.q?.tags})),
|
|
95
|
+
dehydrate: () => [...map.values()].filter(E => E.at > 0).map(E => ({key: E.k, data: E.v, updatedAt: E.at, tags: E.q?.tags})),
|
|
96
|
+
hydrate: (snap: any) => snap?.forEach?.((e: any) => {
|
|
97
|
+
if (!(map.get(e.key)?.at >= e.updatedAt)) put(e.key, {url: e.key.split(' ')[1], tags: e.tags}, e.data, e.updatedAt);
|
|
98
|
+
}),
|
|
99
|
+
set: (q: any, data: any) => {
|
|
100
|
+
const k = key(q, 1);
|
|
101
|
+
if (k !== undefined) put(k, typeof q == 'string' ? {url: q} : q, data);
|
|
102
|
+
},
|
|
103
|
+
prefetch: (q: any) => C.d?.({prefetch: q}),
|
|
104
|
+
};
|
|
105
|
+
C.hydrate(o.initial);
|
|
106
|
+
return C;
|
|
107
|
+
}
|
package/src/extra/reducers.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* set((state, title) => ({ title }))
|
|
18
18
|
*/
|
|
19
19
|
export function set<S = any>(
|
|
20
|
-
partial: Partial<S> | ((state: S, data: any, next: Function, props: any) => Partial<S>)
|
|
20
|
+
partial: (Partial<S> & object) | ((state: S, data: any, next: Function, props: any) => Partial<S>)
|
|
21
21
|
): (state: S, data: any, next: Function, props: any) => S {
|
|
22
22
|
if (typeof partial === 'function') {
|
|
23
23
|
return (state, data, next, props) => ({
|
|
@@ -39,6 +39,17 @@ export function toggle<S = any>(field: keyof S & string): (state: S) => S {
|
|
|
39
39
|
return (state) => ({ ...state, [field]: !state[field] })
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// event(type, payload?) → EVENTS sink fn for the object form:
|
|
43
|
+
// `ACTION: { EVENTS: event('TYPE', (state, data) => payload) }` (static payloads allowed)
|
|
44
|
+
export function event(
|
|
45
|
+
type: string,
|
|
46
|
+
payload?: any | ((state: any, data: any, next: Function, props: any) => any)
|
|
47
|
+
): (state: any, data: any, next: Function, props: any) => { type: string; data: any } {
|
|
48
|
+
return typeof payload === 'function'
|
|
49
|
+
? (state, data, next, props) => ({ type, data: payload(state, data, next, props) })
|
|
50
|
+
: () => ({ type, data: payload })
|
|
51
|
+
}
|
|
52
|
+
|
|
42
53
|
// ── emit() ─────────────────────────────────────────────────────────
|
|
43
54
|
/**
|
|
44
55
|
* Create a model entry that emits an EVENTS bus event.
|
|
@@ -56,9 +67,5 @@ export function emit(
|
|
|
56
67
|
type: string,
|
|
57
68
|
data?: any | ((state: any, actionData: any, next: Function, props: any) => any)
|
|
58
69
|
): { EVENTS: (state: any, actionData: any, next: Function, props: any) => { type: string; data: any } } {
|
|
59
|
-
return {
|
|
60
|
-
EVENTS: typeof data === 'function'
|
|
61
|
-
? (state, actionData, next, props) => ({ type, data: data(state, actionData, next, props) })
|
|
62
|
-
: () => ({ type, data }),
|
|
63
|
-
}
|
|
70
|
+
return { EVENTS: event(type, data) }
|
|
64
71
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PLAN-4 3-E (GS-10 stretch): a dev-only bridge to the Redux DevTools extension
|
|
3
|
+
* (window.__REDUX_DEVTOOLS_EXTENSION__), in 'sygnal/devtools'. Sends each recorded action
|
|
4
|
+
* (./devtoolsActions; built-in ones left out) with the root's state after it, as
|
|
5
|
+
* `{ type: '<Component>/<ACTION>', payload, cause, instance }`. Jump to state / action in the
|
|
6
|
+
* extension replaces the root's state (the Sygnal DevTools time-travel path). sygnal/vite calls it
|
|
7
|
+
* in dev with sygnal({ devtools: { redux: true } }).
|
|
8
|
+
*/
|
|
9
|
+
import {recordActions, onAction, resolveInstance, preview} from './devtoolsActions'
|
|
10
|
+
import type {DevtoolsAction} from './devtoolsActions'
|
|
11
|
+
|
|
12
|
+
export interface ReduxDevtoolsOptions {
|
|
13
|
+
/** the instance name in the extension (default 'Sygnal') */
|
|
14
|
+
name?: string
|
|
15
|
+
/** which actions to send (default: all but 'built-in' ones) */
|
|
16
|
+
filter?: (action: DevtoolsAction) => boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const clone = (s: any) => preview(s)
|
|
20
|
+
|
|
21
|
+
let shared: (() => void) | undefined
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Connect the app's root (run()'s result, a component, an instance id; default: the newest root)
|
|
25
|
+
* to the Redux DevTools extension. Returns a disconnect function; does nothing without the
|
|
26
|
+
* extension.
|
|
27
|
+
*/
|
|
28
|
+
export function connectReduxDevtools(target?: any, options?: ReduxDevtoolsOptions): () => void {
|
|
29
|
+
// the default connection (sygnal/vite may inject the call in several files) is made once
|
|
30
|
+
if (target === undefined && options === undefined) {
|
|
31
|
+
if (!shared) {
|
|
32
|
+
const off = connect(undefined, {})
|
|
33
|
+
shared = () => { off(); shared = undefined }
|
|
34
|
+
}
|
|
35
|
+
return shared
|
|
36
|
+
}
|
|
37
|
+
return connect(target, options || {})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function connect(target: any, options: ReduxDevtoolsOptions): () => void {
|
|
41
|
+
const ext = typeof window != 'undefined' && (window as any).__REDUX_DEVTOOLS_EXTENSION__
|
|
42
|
+
if (!ext || typeof ext.connect != 'function') return () => {}
|
|
43
|
+
recordActions()
|
|
44
|
+
const conn = ext.connect({name: options.name || 'Sygnal', features: {jump: true, pause: true, export: true}})
|
|
45
|
+
const keep = options.filter || ((a: DevtoolsAction) => a.cause != 'built-in')
|
|
46
|
+
let root: any, started = false, timer: any = null
|
|
47
|
+
const queue: DevtoolsAction[] = []
|
|
48
|
+
|
|
49
|
+
const rootOf = () => {
|
|
50
|
+
if (!root || root.disposed || !root.c) root = resolveInstance(target)
|
|
51
|
+
return root
|
|
52
|
+
}
|
|
53
|
+
const flush = () => {
|
|
54
|
+
timer = null
|
|
55
|
+
const r = start()
|
|
56
|
+
if (!r) return
|
|
57
|
+
for (const a of queue.splice(0)) {
|
|
58
|
+
const state = a.instance === r.id && 'after' in a ? a.after : r.c.currentState
|
|
59
|
+
conn.send({type: `${a.component}/${a.type}`, payload: preview(a.data), cause: a.cause, instance: a.instance}, clone(state))
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const start = () => {
|
|
63
|
+
const r = rootOf()
|
|
64
|
+
if (r && !started) { started = true; conn.init(clone(r.c.currentState)) }
|
|
65
|
+
return r
|
|
66
|
+
}
|
|
67
|
+
start()
|
|
68
|
+
const off = onAction((a, kind) => {
|
|
69
|
+
if (kind == 'reset') { queue.length = 0; started = false; start(); return }
|
|
70
|
+
if (kind != 'add') return
|
|
71
|
+
// connected before run() (sygnal/vite): the root's first action, its state still the initial one
|
|
72
|
+
if (!started) start()
|
|
73
|
+
if (!keep(a!)) return
|
|
74
|
+
queue.push(a!)
|
|
75
|
+
if (timer === null) timer = setTimeout(flush, 0)
|
|
76
|
+
})
|
|
77
|
+
const unsubscribe = conn.subscribe((msg: any) => {
|
|
78
|
+
if (msg?.type !== 'DISPATCH' || !msg.state) return
|
|
79
|
+
const t = msg.payload?.type
|
|
80
|
+
if (t !== 'JUMP_TO_STATE' && t !== 'JUMP_TO_ACTION') return
|
|
81
|
+
const r = rootOf()
|
|
82
|
+
const dt = (window as any).__SYGNAL_DEVTOOLS__
|
|
83
|
+
if (!r || !dt || typeof dt._timeTravel != 'function') return
|
|
84
|
+
try { dt._timeTravel({componentId: Number(r.id), componentName: r.name, state: JSON.parse(msg.state)}) } catch (_) { /* a bad state from the extension */ }
|
|
85
|
+
})
|
|
86
|
+
return () => {
|
|
87
|
+
off()
|
|
88
|
+
if (timer !== null) clearTimeout(timer)
|
|
89
|
+
if (typeof unsubscribe == 'function') unsubscribe()
|
|
90
|
+
try { ext.disconnect?.() } catch (_) { /* ignore */ }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import xs from 'xstream';
|
|
2
|
+
import {error as logError} from './diagnostics/legacy';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* PLAN-3 reply actions: the shared part of every driver that answers a request
|
|
6
|
+
* with the sender's own actions (makeFetchDriver, driverFromAsync, the socket driver).
|
|
7
|
+
*
|
|
8
|
+
* - The core stamps each object a component sends to a source marked
|
|
9
|
+
* `__sygnalReplies: true` with the sending instance (`__emitterId`, the same
|
|
10
|
+
* non-enumerable stamp EVENTS gets), and merges `source.replies(instance)` into
|
|
11
|
+
* that instance's actions.
|
|
12
|
+
* - A request that names `ok` / `error` actions from a stamped sender gets reply actions:
|
|
13
|
+
* the driver answers it with `reply(sender, type, data)`, which reaches exactly
|
|
14
|
+
* that instance (never select()/errors()).
|
|
15
|
+
* - When the instance stops listening (disposed), `onStop(sender)` lets the
|
|
16
|
+
* driver abort what it still has in flight for it.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const SENDER = '__emitterId';
|
|
20
|
+
|
|
21
|
+
/** the instance that sent a request (undefined when it wasn't sent by a component) */
|
|
22
|
+
export const senderOf = (req: any) => req[SENDER];
|
|
23
|
+
|
|
24
|
+
/** `to` (a copy of `from`) with `from`'s sender stamp (a spread drops non-enumerables) */
|
|
25
|
+
export const keepSender = (from: any, to: any) => {
|
|
26
|
+
if (from[SENDER] !== undefined) Object.defineProperty(to, SENDER, {value: from[SENDER]});
|
|
27
|
+
return to;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* D57: a request object with a `then` / `catch` key is a thenable (it breaks `await`), so
|
|
32
|
+
* reply-action drivers refuse it (SYG610). True when the request may be sent.
|
|
33
|
+
*/
|
|
34
|
+
export const allowed = (req: any, driver: string) =>
|
|
35
|
+
!('then' in req || 'catch' in req) ||
|
|
36
|
+
logError('SYG610', req.__emitterName, `${driver}: request not sent: it has a 'then'/'catch' key`, "Use ok: 'ACTION' / error: 'ACTION'", req);
|
|
37
|
+
|
|
38
|
+
/** the reply-action half of a driver's source */
|
|
39
|
+
export const makeReplies = (onStop?: (sender: any) => void) => {
|
|
40
|
+
const to = new Map<any, any>();
|
|
41
|
+
return {
|
|
42
|
+
replies: {
|
|
43
|
+
__sygnalReplies: true,
|
|
44
|
+
replies: (sender: any) => xs.create<any>({
|
|
45
|
+
start: l => { to.set(sender, l); },
|
|
46
|
+
stop: () => { to.delete(sender); onStop?.(sender); },
|
|
47
|
+
}),
|
|
48
|
+
},
|
|
49
|
+
/** deliver `{ type, data }` to the sender's actions (dropped when it's gone) */
|
|
50
|
+
reply: (sender: any, type: any, data: any) => { to.get(sender)?.next({type, data}); },
|
|
51
|
+
/** whether the sender listens to its replies now (a reply to it would not be dropped) */
|
|
52
|
+
listening: (sender: any) => to.has(sender),
|
|
53
|
+
};
|
|
54
|
+
};
|