@webqit/webflo 0.20.1 → 0.20.2-next.1
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/package.json +1 -1
- package/site/.vitepress/config.ts +1 -0
- package/site/.vitepress/dist/-/_.html +56 -0
- package/site/.vitepress/dist/-/docs.old.html +679 -0
- package/site/.vitepress/dist/404.html +23 -0
- package/site/.vitepress/dist/api/webflo-fetch/FormData.html +55 -0
- package/site/.vitepress/dist/api/webflo-fetch/Headers.html +55 -0
- package/site/.vitepress/dist/api/webflo-fetch/LiveResponse.html +55 -0
- package/site/.vitepress/dist/api/webflo-fetch/Request.html +55 -0
- package/site/.vitepress/dist/api/webflo-fetch/Response.html +55 -0
- package/site/.vitepress/dist/api/webflo-fetch/fetch.html +55 -0
- package/site/.vitepress/dist/api/webflo-routing/HttpCookies.html +55 -0
- package/site/.vitepress/dist/api/webflo-routing/HttpEvent/respondWith.html +55 -0
- package/site/.vitepress/dist/api/webflo-routing/HttpEvent/waitUntil.html +55 -0
- package/site/.vitepress/dist/api/webflo-routing/HttpEvent/waitUntilNavigate.html +55 -0
- package/site/.vitepress/dist/api/webflo-routing/HttpEvent.html +55 -0
- package/site/.vitepress/dist/api/webflo-routing/HttpSession.html +55 -0
- package/site/.vitepress/dist/api/webflo-routing/HttpState.html +55 -0
- package/site/.vitepress/dist/api/webflo-routing/HttpUser.html +55 -0
- package/site/.vitepress/dist/api/webflo-routing/handler/fetch.html +59 -0
- package/site/.vitepress/dist/api/webflo-routing/handler/next.html +61 -0
- package/site/.vitepress/dist/api/webflo-routing/handler.html +65 -0
- package/site/.vitepress/dist/api.html +55 -0
- package/site/.vitepress/dist/assets/-__.md.wD5kDRhS.js +1 -0
- package/site/.vitepress/dist/assets/-__.md.wD5kDRhS.lean.js +1 -0
- package/site/.vitepress/dist/assets/-_docs.old.md.CiqucE_1.js +625 -0
- package/site/.vitepress/dist/assets/-_docs.old.md.CiqucE_1.lean.js +1 -0
- package/site/.vitepress/dist/assets/api.md.C9KRNLi_.js +1 -0
- package/site/.vitepress/dist/assets/api.md.C9KRNLi_.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_FormData.md.CDuexUTz.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_FormData.md.CDuexUTz.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_Headers.md.Cl_4-FUP.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_Headers.md.Cl_4-FUP.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_LiveResponse.md.BMidKMB1.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_LiveResponse.md.BMidKMB1.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_Request.md.DPwZCPmi.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_Request.md.DPwZCPmi.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_Response.md.BaSyoOLE.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_Response.md.BaSyoOLE.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_fetch.md.Bc9r3Q9I.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-fetch_fetch.md.Bc9r3Q9I.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpCookies.md.B5ok3jrM.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpCookies.md.B5ok3jrM.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpEvent.md.DBkSQRTa.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpEvent.md.DBkSQRTa.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpEvent_respondWith.md.aAxq-5Ie.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpEvent_respondWith.md.aAxq-5Ie.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpEvent_waitUntil.md.DyQZLhPR.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpEvent_waitUntil.md.DyQZLhPR.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpEvent_waitUntilNavigate.md.DKLylwhl.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpEvent_waitUntilNavigate.md.DKLylwhl.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpSession.md.bkeCy7_Q.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpSession.md.bkeCy7_Q.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpState.md.DO53IAM1.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpState.md.DO53IAM1.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpUser.md.CfsaBFdl.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_HttpUser.md.CfsaBFdl.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_handler.md.B0eVFluL.js +11 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_handler.md.B0eVFluL.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_handler_fetch.md.CpwUMFMz.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_handler_fetch.md.CpwUMFMz.lean.js +1 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_handler_next.md.CA4tDXtV.js +7 -0
- package/site/.vitepress/dist/assets/api_webflo-routing_handler_next.md.CA4tDXtV.lean.js +1 -0
- package/site/.vitepress/dist/assets/app.B989j-Lw.js +256 -0
- package/site/.vitepress/dist/assets/chunks/@localSearchIndexroot.IcaIAE_s.js +1 -0
- package/site/.vitepress/dist/assets/chunks/VPLocalSearchBox.CxstEVOs.js +8 -0
- package/site/.vitepress/dist/assets/chunks/arc.CNNknwAo.js +1 -0
- package/site/.vitepress/dist/assets/chunks/architectureDiagram-VXUJARFQ.DCLYhNHD.js +36 -0
- package/site/.vitepress/dist/assets/chunks/basePickBy.Cxi84nlK.js +1 -0
- package/site/.vitepress/dist/assets/chunks/baseUniq.DDTOgUAc.js +1 -0
- package/site/.vitepress/dist/assets/chunks/blockDiagram-VD42YOAC.BcpiarhA.js +122 -0
- package/site/.vitepress/dist/assets/chunks/c4Diagram-YG6GDRKO.BI_5dKaW.js +10 -0
- package/site/.vitepress/dist/assets/chunks/channel.CxIJmpCu.js +1 -0
- package/site/.vitepress/dist/assets/chunks/chunk-4BX2VUAB.C6goADHj.js +1 -0
- package/site/.vitepress/dist/assets/chunks/chunk-55IACEB6.BLGj4Pud.js +1 -0
- package/site/.vitepress/dist/assets/chunks/chunk-B4BG7PRW.DsAzxoJ_.js +165 -0
- package/site/.vitepress/dist/assets/chunks/chunk-DI55MBZ5.BnE2NeEC.js +220 -0
- package/site/.vitepress/dist/assets/chunks/chunk-FMBD7UC4.DGeT8zu4.js +15 -0
- package/site/.vitepress/dist/assets/chunks/chunk-QN33PNHL.Bc78W0xn.js +1 -0
- package/site/.vitepress/dist/assets/chunks/chunk-QZHKN3VN.BFSSbGEs.js +1 -0
- package/site/.vitepress/dist/assets/chunks/chunk-TZMSLE5B.DyZR9PPb.js +1 -0
- package/site/.vitepress/dist/assets/chunks/classDiagram-2ON5EDUG._0fUH5ha.js +1 -0
- package/site/.vitepress/dist/assets/chunks/classDiagram-v2-WZHVMYZB._0fUH5ha.js +1 -0
- package/site/.vitepress/dist/assets/chunks/clone.BYyOtvOD.js +1 -0
- package/site/.vitepress/dist/assets/chunks/cose-bilkent-S5V4N54A.TlhUFBAR.js +1 -0
- package/site/.vitepress/dist/assets/chunks/cytoscape.esm.CyJtwmzi.js +331 -0
- package/site/.vitepress/dist/assets/chunks/dagre-6UL2VRFP.D__9IqfC.js +4 -0
- package/site/.vitepress/dist/assets/chunks/defaultLocale.C4B-KCzX.js +1 -0
- package/site/.vitepress/dist/assets/chunks/diagram-PSM6KHXK.DYSDWndU.js +24 -0
- package/site/.vitepress/dist/assets/chunks/diagram-QEK2KX5R.FZi2c8WB.js +43 -0
- package/site/.vitepress/dist/assets/chunks/diagram-S2PKOQOG.D-Xxss9Z.js +24 -0
- package/site/.vitepress/dist/assets/chunks/erDiagram-Q2GNP2WA.CNdrcxqE.js +60 -0
- package/site/.vitepress/dist/assets/chunks/flowDiagram-NV44I4VS.C_6PWuGm.js +162 -0
- package/site/.vitepress/dist/assets/chunks/framework.9Uv4PgnO.js +18 -0
- package/site/.vitepress/dist/assets/chunks/ganttDiagram-LVOFAZNH._TBJejxF.js +267 -0
- package/site/.vitepress/dist/assets/chunks/gitGraphDiagram-NY62KEGX.BmQODSWS.js +65 -0
- package/site/.vitepress/dist/assets/chunks/graph.BHWe3GDJ.js +1 -0
- package/site/.vitepress/dist/assets/chunks/infoDiagram-ER5ION4S.CbdOaGtv.js +2 -0
- package/site/.vitepress/dist/assets/chunks/init.Gi6I4Gst.js +1 -0
- package/site/.vitepress/dist/assets/chunks/journeyDiagram-XKPGCS4Q.B-PjYmDZ.js +139 -0
- package/site/.vitepress/dist/assets/chunks/kanban-definition-3W4ZIXB7.Bc_8e9KR.js +89 -0
- package/site/.vitepress/dist/assets/chunks/katex.BbEIqZs1.js +261 -0
- package/site/.vitepress/dist/assets/chunks/layout.hswMW8l0.js +1 -0
- package/site/.vitepress/dist/assets/chunks/linear.CUHYPplj.js +1 -0
- package/site/.vitepress/dist/assets/chunks/mindmap-definition-VGOIOE7T.CvIaZI8e.js +68 -0
- package/site/.vitepress/dist/assets/chunks/ordinal.BYWQX77i.js +1 -0
- package/site/.vitepress/dist/assets/chunks/pieDiagram-ADFJNKIX.BSTQM2Ms.js +30 -0
- package/site/.vitepress/dist/assets/chunks/quadrantDiagram-AYHSOK5B.CkEJjNYC.js +7 -0
- package/site/.vitepress/dist/assets/chunks/requirementDiagram-UZGBJVZJ.QsTahBza.js +64 -0
- package/site/.vitepress/dist/assets/chunks/sankeyDiagram-TZEHDZUN.NRsUNMzF.js +10 -0
- package/site/.vitepress/dist/assets/chunks/sequenceDiagram-WL72ISMW.rq-YLOb-.js +145 -0
- package/site/.vitepress/dist/assets/chunks/stateDiagram-FKZM4ZOC.BseVQjcW.js +1 -0
- package/site/.vitepress/dist/assets/chunks/stateDiagram-v2-4FDKWEC3.CH4mdaj_.js +1 -0
- package/site/.vitepress/dist/assets/chunks/theme.Jp0RA4YE.js +2 -0
- package/site/.vitepress/dist/assets/chunks/timeline-definition-IT6M3QCI.N8DNMk16.js +61 -0
- package/site/.vitepress/dist/assets/chunks/treemap-KMMF4GRG.CAwkr_aP.js +128 -0
- package/site/.vitepress/dist/assets/chunks/virtual_mermaid-config.DDnGl6nM.js +1 -0
- package/site/.vitepress/dist/assets/chunks/xychartDiagram-PRI3JC2R.CF4KVQhG.js +7 -0
- package/site/.vitepress/dist/assets/contributing.md.gqIMCtVI.js +1 -0
- package/site/.vitepress/dist/assets/contributing.md.gqIMCtVI.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs.md.hvbqYbFY.js +1 -0
- package/site/.vitepress/dist/assets/docs.md.hvbqYbFY.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_advanced.md.D048cxnq.js +1 -0
- package/site/.vitepress/dist/assets/docs_advanced.md.D048cxnq.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_advanced_lifecycles.md.BICPL-da.js +1 -0
- package/site/.vitepress/dist/assets/docs_advanced_lifecycles.md.BICPL-da.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_advanced_redirects.md.BMha6D3W.js +1 -0
- package/site/.vitepress/dist/assets/docs_advanced_redirects.md.BMha6D3W.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_advanced_routing.md.Cv63UDJF.js +1 -0
- package/site/.vitepress/dist/assets/docs_advanced_routing.md.Cv63UDJF.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_concepts.md.Clwx81Hz.js +3 -0
- package/site/.vitepress/dist/assets/docs_concepts.md.Clwx81Hz.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_concepts_realtime.md.CBrMq5Ln.js +218 -0
- package/site/.vitepress/dist/assets/docs_concepts_realtime.md.CBrMq5Ln.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_concepts_rendering.md.BWr5Lxgn.js +24 -0
- package/site/.vitepress/dist/assets/docs_concepts_rendering.md.BWr5Lxgn.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_concepts_request-response.md.DhplzNqt.js +4 -0
- package/site/.vitepress/dist/assets/docs_concepts_request-response.md.DhplzNqt.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_concepts_routing.md.C2KO1eAu.js +228 -0
- package/site/.vitepress/dist/assets/docs_concepts_routing.md.C2KO1eAu.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_concepts_state.md.CtbMVS_K.js +10 -0
- package/site/.vitepress/dist/assets/docs_concepts_state.md.CtbMVS_K.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_concepts_templates.md.4i6jQcYw.js +15 -0
- package/site/.vitepress/dist/assets/docs_concepts_templates.md.4i6jQcYw.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_getting-started.md.CNGtwB_L.js +75 -0
- package/site/.vitepress/dist/assets/docs_getting-started.md.CNGtwB_L.lean.js +1 -0
- package/site/.vitepress/dist/assets/docs_tech-stack.md.xiWGQstL.js +1 -0
- package/site/.vitepress/dist/assets/docs_tech-stack.md.xiWGQstL.lean.js +1 -0
- package/site/.vitepress/dist/assets/examples.md.BqDfJd4G.js +1 -0
- package/site/.vitepress/dist/assets/examples.md.BqDfJd4G.lean.js +1 -0
- package/site/.vitepress/dist/assets/examples_pwa.md.DREN7J2F.js +1 -0
- package/site/.vitepress/dist/assets/examples_pwa.md.DREN7J2F.lean.js +1 -0
- package/site/.vitepress/dist/assets/examples_web.md.DUhZ0IQL.js +1 -0
- package/site/.vitepress/dist/assets/examples_web.md.DUhZ0IQL.lean.js +1 -0
- package/site/.vitepress/dist/assets/faq.md.DtfXaXUI.js +1 -0
- package/site/.vitepress/dist/assets/faq.md.DtfXaXUI.lean.js +1 -0
- package/site/.vitepress/dist/assets/guides.md.BVdQyeU-.js +1 -0
- package/site/.vitepress/dist/assets/guides.md.BVdQyeU-.lean.js +1 -0
- package/site/.vitepress/dist/assets/guides_guide-auth.md.DNFuRudp.js +1 -0
- package/site/.vitepress/dist/assets/guides_guide-auth.md.DNFuRudp.lean.js +1 -0
- package/site/.vitepress/dist/assets/guides_guide-file-upload.md.DRbRLk7h.js +1 -0
- package/site/.vitepress/dist/assets/guides_guide-file-upload.md.DRbRLk7h.lean.js +1 -0
- package/site/.vitepress/dist/assets/guides_guide-service-worker.md.B0wEVcQw.js +1 -0
- package/site/.vitepress/dist/assets/guides_guide-service-worker.md.B0wEVcQw.lean.js +1 -0
- package/site/.vitepress/dist/assets/guides_tutorial-1-todo.md.D9ket3Re.js +3 -0
- package/site/.vitepress/dist/assets/guides_tutorial-1-todo.md.D9ket3Re.lean.js +1 -0
- package/site/.vitepress/dist/assets/index.md.DB-CsGEX.js +1 -0
- package/site/.vitepress/dist/assets/index.md.DB-CsGEX.lean.js +1 -0
- package/site/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/site/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/site/.vitepress/dist/assets/recipes_realtime.md.CX1Vs2FD.js +1 -0
- package/site/.vitepress/dist/assets/recipes_realtime.md.CX1Vs2FD.lean.js +1 -0
- package/site/.vitepress/dist/assets/recipes_streaming.md.C7GFShgF.js +5 -0
- package/site/.vitepress/dist/assets/recipes_streaming.md.C7GFShgF.lean.js +1 -0
- package/site/.vitepress/dist/assets/reference_cli.md.DERqaQJm.js +1 -0
- package/site/.vitepress/dist/assets/reference_cli.md.DERqaQJm.lean.js +1 -0
- package/site/.vitepress/dist/assets/reference_config.md.DI_yG-7N.js +1 -0
- package/site/.vitepress/dist/assets/reference_config.md.DI_yG-7N.lean.js +1 -0
- package/site/.vitepress/dist/assets/reference_tools.md.DZxjdVFX.js +1 -0
- package/site/.vitepress/dist/assets/reference_tools.md.DZxjdVFX.lean.js +1 -0
- package/site/.vitepress/dist/assets/style.BD0LzINo.css +1 -0
- package/site/.vitepress/dist/contributing.html +55 -0
- package/site/.vitepress/dist/docs/advanced/lifecycles.html +55 -0
- package/site/.vitepress/dist/docs/advanced/redirects.html +55 -0
- package/site/.vitepress/dist/docs/advanced/routing.html +55 -0
- package/site/.vitepress/dist/docs/advanced.html +55 -0
- package/site/.vitepress/dist/docs/concepts/realtime.html +272 -0
- package/site/.vitepress/dist/docs/concepts/rendering.html +78 -0
- package/site/.vitepress/dist/docs/concepts/request-response.html +58 -0
- package/site/.vitepress/dist/docs/concepts/routing.html +282 -0
- package/site/.vitepress/dist/docs/concepts/state.html +64 -0
- package/site/.vitepress/dist/docs/concepts/templates.html +69 -0
- package/site/.vitepress/dist/docs/concepts.html +57 -0
- package/site/.vitepress/dist/docs/getting-started.html +129 -0
- package/site/.vitepress/dist/docs/tech-stack.html +55 -0
- package/site/.vitepress/dist/docs.html +55 -0
- package/site/.vitepress/dist/examples/pwa.html +55 -0
- package/site/.vitepress/dist/examples/web.html +55 -0
- package/site/.vitepress/dist/examples.html +55 -0
- package/site/.vitepress/dist/faq.html +55 -0
- package/site/.vitepress/dist/guides/guide-auth.html +55 -0
- package/site/.vitepress/dist/guides/guide-file-upload.html +55 -0
- package/site/.vitepress/dist/guides/guide-service-worker.html +55 -0
- package/site/.vitepress/dist/guides/tutorial-1-todo.html +57 -0
- package/site/.vitepress/dist/guides.html +55 -0
- package/site/.vitepress/dist/hashmap.json +1 -0
- package/site/.vitepress/dist/img/brand/logo-670x670.png +0 -0
- package/site/.vitepress/dist/index.html +55 -0
- package/site/.vitepress/dist/recipes/realtime.html +55 -0
- package/site/.vitepress/dist/recipes/streaming.html +59 -0
- package/site/.vitepress/dist/reference/cli.html +55 -0
- package/site/.vitepress/dist/reference/config.html +55 -0
- package/site/.vitepress/dist/reference/tools.html +55 -0
- package/site/.vitepress/dist/vp-icons.css +1 -0
- package/site/.vitepress/cache/deps/@braintree_sanitize-url 2.js +0 -93
- package/site/.vitepress/cache/deps/@braintree_sanitize-url.js 2.map +0 -7
- package/site/.vitepress/cache/deps/_metadata 2.json +0 -85
- package/site/.vitepress/cache/deps/_metadata.json +0 -85
- package/site/.vitepress/cache/deps/chunk-BUSYA2B4 2.js +0 -9
- package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js 2.map +0 -7
- package/site/.vitepress/cache/deps/chunk-Q2AYPHVK 2.js +0 -9719
- package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js 2.map +0 -7
- package/site/.vitepress/cache/deps/chunk-QAXAIFA7 2.js +0 -12705
- package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js 2.map +0 -7
- package/site/.vitepress/cache/deps/cytoscape 2.js +0 -30278
- package/site/.vitepress/cache/deps/cytoscape-cose-bilkent 2.js +0 -4710
- package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js 2.map +0 -7
- package/site/.vitepress/cache/deps/cytoscape.js 2.map +0 -7
- package/site/.vitepress/cache/deps/dayjs 2.js +0 -285
- package/site/.vitepress/cache/deps/dayjs.js 2.map +0 -7
- package/site/.vitepress/cache/deps/debug 2.js +0 -453
- package/site/.vitepress/cache/deps/debug.js 2.map +0 -7
- package/site/.vitepress/cache/deps/package 2.json +0 -3
- package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api 2.js +0 -4507
- package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js 2.map +0 -7
- package/site/.vitepress/cache/deps/vitepress___@vueuse_core 2.js +0 -584
- package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js 2.map +0 -7
- package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap 2.js +0 -1166
- package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js 2.map +0 -7
- package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js 2.js +0 -1667
- package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js 2.map +0 -7
- package/site/.vitepress/cache/deps/vitepress___minisearch 2.js +0 -1815
- package/site/.vitepress/cache/deps/vitepress___minisearch.js 2.map +0 -7
- package/site/.vitepress/cache/deps/vue 2.js +0 -344
- package/site/.vitepress/cache/deps/vue.js 2.map +0 -7
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/@braintree_sanitize-url.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/@braintree_sanitize-url.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/chunk-BUSYA2B4.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/chunk-BUSYA2B4.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/chunk-Q2AYPHVK.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/chunk-Q2AYPHVK.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/chunk-QAXAIFA7.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/chunk-QAXAIFA7.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/cytoscape-cose-bilkent.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/cytoscape-cose-bilkent.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/cytoscape.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/cytoscape.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/dayjs.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/dayjs.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/debug.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/debug.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/package.json +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___@vue_devtools-api.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___@vue_devtools-api.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___@vueuse_core.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___@vueuse_core.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___@vueuse_integrations_useFocusTrap.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___@vueuse_integrations_useFocusTrap.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___mark__js_src_vanilla__js.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___mark__js_src_vanilla__js.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___minisearch.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vitepress___minisearch.js.map +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vue.js +0 -0
- /package/site/.vitepress/cache/{deps → deps_temp_9b107c53}/vue.js.map +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import{_ as F,C as i,c as y,o as e,a2 as p,b as t,j as a,w as n,a as l,G as c,a3 as r}from"./chunks/framework.9Uv4PgnO.js";const E=JSON.parse('{"title":"Webflo Realtime","description":"","frontmatter":{},"headers":[],"relativePath":"docs/concepts/realtime.md","filePath":"docs/concepts/realtime.md"}'),D={name:"docs/concepts/realtime.md"};function d(h,s,A,B,u,m){const o=i("Mermaid");return e(),y("div",null,[s[3]||(s[3]=p(`<h1 id="webflo-realtime" tabindex="-1">Webflo Realtime <a class="header-anchor" href="#webflo-realtime" aria-label="Permalink to "Webflo Realtime""></a></h1><p>Realtime experiences — collaborative documents, live dashboards, chat windows, streaming progress bars — are what make modern web apps feel <em>alive</em>. They’re also the difference between form submissions that make you wait and form submissions that feel like a live conversation.</p><p>Webflo apps work this way by default.</p><p>They're powered by a rich set of APIs designed for every use case:</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;"> new</span><span style="color:#82AAFF;"> LiveResponse</span><span style="color:#BABED8;">(data</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> false</span><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> progress</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 10</span><span style="color:#89DDFF;"> },</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> false</span><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">waitUntilNavigate</span><span style="color:#BABED8;">()</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">client</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addEventListener</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">message</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;"> handle)</span><span style="color:#89DDFF;">;</span></span>
|
|
2
|
+
<span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">client</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">postMessage</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> message</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">You seem to be typing something.</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#BABED8;"> result </span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">user</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">confirm</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> message</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Should we proceed?</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
3
|
+
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#BABED8;"> result </span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">user</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">prompt</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> message</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">What is your name?</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#89DDFF;"> {</span><span style="color:#BABED8;"> channel</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;"> leave </span><span style="color:#89DDFF;">}</span><span style="color:#89DDFF;"> =</span><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">client</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">enterChannel</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">test-channel</span><span style="color:#89DDFF;">'</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><h2 id="the-traditional-setup" tabindex="-1">The Traditional Setup <a class="header-anchor" href="#the-traditional-setup" aria-label="Permalink to "The Traditional Setup""></a></h2><p>Historically, building realtime applications required a significant amount of setup. It extended beyond the simple request–response model and into a world of parallel WebSocket connections and streaming protocols. It presented two protocols, two lifecycles, and an awkward choreography between them — keeping them in sync, closing them both cleanly, and rebuilding them on every reconnect.</p>`,12)),(e(),t(r,null,{default:n(()=>[c(o,{id:"mermaid-24",class:"mermaid",graph:"flowchart%20LR%0A%20%20%20%20subgraph%20Browser%0A%20%20%20%20%20%20%20%20B1%5BHTTP%20Client%5D%0A%20%20%20%20%20%20%20%20B2%5BWebSocket%20Client%5D%0A%20%20%20%20end%0A%20%20%20%20subgraph%20Server%0A%20%20%20%20%20%20%20%20S1%5BHTTP%20Handler%5D%0A%20%20%20%20%20%20%20%20S2%5BWebSocket%20Handler%5D%0A%20%20%20%20end%0A%20%20%20%20B1%20%3C--%3E%20%7CHTTP%20request%20%2F%20response%7C%20S1%0A%20%20%20%20B2%20%3C---%3E%20%7CRealtime%20messages%7C%20S2%0A"})]),fallback:n(()=>[...s[0]||(s[0]=[l(" Loading... ",-1)])]),_:1})),s[4]||(s[4]=a("p",null,"This works — but it’s hardly effortless. That’s requests on one channel, updates on another.",-1)),s[5]||(s[5]=a("h2",{id:"the-webflo-model",tabindex:"-1"},[l("The Webflo Model "),a("a",{class:"header-anchor",href:"#the-webflo-model","aria-label":'Permalink to "The Webflo Model"'},"")],-1)),s[6]||(s[6]=a("p",null,"In Webflo, this behavior is built in. The same request that starts over HTTP can seamlessly continue as a live, bidirectional exchange — with no moving parts or extra line of code at the application layer.",-1)),s[7]||(s[7]=a("p",null,[l("This is like the entire architecture above collapsed into one: an "),a("strong",null,"auto-upgrading connection"),l(" that can be used for many different things.")],-1)),(e(),t(r,null,{default:n(()=>[c(o,{id:"mermaid-37",class:"mermaid",graph:"flowchart%20LR%0A%20%20%20%20subgraph%20Browser%0A%20%20%20%20%20%20%20%20B1%5BWebflo%20Client%5D%0A%20%20%20%20end%0A%20%20%20%20subgraph%20Server%0A%20%20%20%20%20%20%20%20S1%5BWebflo%20Handler%5D%0A%20%20%20%20end%0A%20%20%20%20B1%20%3C--%3E%20%7CAuto-upgrading%0A%20%20%20%20HTTP%20request%20%2F%20response%7C%20S1%0A"})]),fallback:n(()=>[...s[1]||(s[1]=[l(" Loading... ",-1)])]),_:1})),s[8]||(s[8]=p(`<p>This is the same HTTP request / response lifecycle, only <strong>with "live" mode built-in</strong>.</p><h2 id="how-it-works" tabindex="-1">How It Works <a class="header-anchor" href="#how-it-works" aria-label="Permalink to "How It Works""></a></h2><p>In Webflo, you simply write route handlers that can talk for as long as they need to — without worrying about the transport layer or the lifecycle of the connection.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#82AAFF;"> GET</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;font-style:italic;"> next</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
4
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">next</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">stepname</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // The conventional delegation line</span></span>
|
|
5
|
+
<span class="line"></span>
|
|
6
|
+
<span class="line"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> step</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 1</span><span style="color:#89DDFF;"> },</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> false</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
7
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#89DDFF;"> new</span><span style="color:#FFCB6B;"> Promise</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">r</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#82AAFF;"> setTimeout</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">r</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;"> 500</span><span style="color:#F07178;">))</span><span style="color:#89DDFF;">;</span></span>
|
|
8
|
+
<span class="line"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> step</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 2</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
9
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>Here, the browser first renders <code>{ step: 1 }</code>, then <code>{ step: 2 }</code> half a second later — all within the same request.</p><p>When a handler continues sending responses or messages, Webflo transparently upgrades the underlying connection and handles the lifecycle behind the scenes.</p><h3 id="what-happens" tabindex="-1">What Happens <a class="header-anchor" href="#what-happens" aria-label="Permalink to "What Happens""></a></h3><ol><li>The first response is sent normally over HTTP.</li><li>Webflo detects that the handler hasn’t returned yet.</li><li>It silently upgrades the connection, tagging the initial response with a header that tells the client to connect in the background.</li><li>The client renders the first data and immediately joins the background channel.</li><li>A two-way line now exists — and either side can send or receive messages.</li><li>The handler pushes its next response, this time, it's delivered via the upgraded connection.</li><li>The client renders it instantly — replacing the previous rendered state.</li><li>Webflo closes automatically when the handler finishes or the user navigates away.</li></ol><div class="info custom-block"><p class="custom-block-title">Further Details</p><ul><li>Full handshake details are covered in <strong><a href="#appendix-a-–-the-realtime-lifecycle">Appendix A – The Realtime Lifecycle</a></strong>.</li></ul></div><h2 id="the-two-ends-of-the-line" tabindex="-1">The Two Ends of the Line <a class="header-anchor" href="#the-two-ends-of-the-line" aria-label="Permalink to "The Two Ends of the Line""></a></h2><p>A realtime conversation always has two sides — <em>Port A</em> and <em>Port B</em>.</p><h3 id="port-a-upstream-route-handlers" tabindex="-1"><em>Port A</em>: Upstream Route Handlers <a class="header-anchor" href="#port-a-upstream-route-handlers" aria-label="Permalink to "_Port A_: Upstream Route Handlers""></a></h3><p>Realtime conversations are initiated by route handlers — as part of responses to HTTP requests. These route handlers function as <em>Port A</em>.</p><p>The <strong>primary</strong> realtime API here is <code>event.client</code> — a Webflo <code>MessagePort</code> supporting things like: <code>.postMessage()</code>, <code>.addEventListener()</code>, etc.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#89DDFF;font-style:italic;"> default</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
10
|
+
<span class="line"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">client</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">postMessage</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> hello</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">world</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
11
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p><code>event.client</code> is the API that other APIs like <code>event.respondWith()</code>, <code>event.user.prompt()</code>, etc. use under the hood.</p><h3 id="port-b-downstream-clients" tabindex="-1"><em>Port B</em>: Downstream Clients <a class="header-anchor" href="#port-b-downstream-clients" aria-label="Permalink to "_Port B_: Downstream Clients""></a></h3><p>Realtime conversations are received downstream as part of responses to an initial HTTP request. These HTTP clients or handlers are the <em>Port B</em>.</p><p>The primary realtime API here is <code>liveResponse.background</code> — the same Webflo <code>MessagePort</code> interface as <code>event.client</code>, supporting things like: <code>.postMessage()</code>, <code>.addEventListener()</code>, etc.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#BABED8;"> response </span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> fetch</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">https://api.example.com/data</span><span style="color:#89DDFF;">'</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
12
|
+
<span class="line"><span style="color:#C792EA;">const</span><span style="color:#BABED8;"> liveResponse </span><span style="color:#89DDFF;">=</span><span style="color:#BABED8;"> LiveResponse</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">from</span><span style="color:#BABED8;">(response)</span><span style="color:#89DDFF;">;</span></span>
|
|
13
|
+
<span class="line"></span>
|
|
14
|
+
<span class="line"><span style="color:#BABED8;">liveResponse</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">background</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addEventListener</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">message</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">message</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
15
|
+
<span class="line"><span style="color:#BABED8;"> console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">message</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
16
|
+
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><p>Typical Port B clients in Webflo are:</p><ul><li>The App UI</li><li>Intermediate Route Handlers</li></ul><div class="info custom-block"><p class="custom-block-title">LiveResponse</p><p><code>LiveResponse</code> is the "live" version of the standard <code>Response</code> API. It extends the native <code>Response</code> object with a live body, headers, and status — all of which can be mutated in-place.</p></div><h4 id="the-app-ui" tabindex="-1">The App UI <a class="header-anchor" href="#the-app-ui" aria-label="Permalink to "The App UI""></a></h4><p>Every Webflo SPA has a client-side Webflo instance — <code>window.webqit.app</code>. It mounts via the <em>client</em> script that Webflo injects into the page at build time.</p><div class="language-html"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;"><</span><span style="color:#F07178;">script</span><span style="color:#C792EA;"> src</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">"</span><span style="color:#C3E88D;">/app.js</span><span style="color:#89DDFF;">"</span><span style="color:#89DDFF;">></</span><span style="color:#F07178;">script</span><span style="color:#89DDFF;">></span></span></code></pre></div><p>This client manages in-app navigations, turning them into seamless request–response flows — becoming a typical <em>Port B</em> in the realtime system. In each of those flows, the client occupies the top-most end of the line. It receives everything that handlers send as part of a response, applies live updates to the document, and manages any interactive exchanges.</p><p>The applicable realtime API here is <code>window.webqit.app.background</code> (<code>app.background</code>, for short) — an extension of Webflo <code>MessagePort</code> supporting things like: <code>.postMessage()</code>, <code>.addEventListener()</code>, etc.</p><p>The <code>app.background</code> port is also a <em>multi-port</em> hub housing all <em>active</em> background activities across page navigations. Every interaction on this API is thus an interaction over all active realtime conversations.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">app</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">background</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addEventListener</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">message</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">message</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
17
|
+
<span class="line"><span style="color:#BABED8;"> console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">message</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
18
|
+
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="info custom-block"><p class="custom-block-title">App-Level Background Activities</p><p>It is possible to listen to all background activities in the app via <code>app.background</code>. We'll use this API to drive a custom dialog UI just ahead.</p></div><h4 id="intermediate-route-handlers" tabindex="-1">Intermediate Route Handlers <a class="header-anchor" href="#intermediate-route-handlers" aria-label="Permalink to "Intermediate Route Handlers""></a></h4><p>With Webflo's realtime capabilities being an <strong>upgrade</strong> to the existing HTTP request/response model, realtime connections can be intercepted at <em>any point</em> along that flow just as routing in Webflo can happen at various layers along that flow. A client-side handler or service-worker-side handler, for example, can intercept the conversation at their level.</p><p>The background connection comes along with the upstream response obtained via <code>next()</code> or <code>fetch()</code>.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#89DDFF;font-style:italic;"> default</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;font-style:italic;"> next</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
19
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">next</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">stepname</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // The conventional delegation line</span></span>
|
|
20
|
+
<span class="line"></span>
|
|
21
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> response</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span></span>
|
|
22
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> liveResponse</span><span style="color:#89DDFF;"> =</span><span style="color:#BABED8;"> LiveResponse</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">from</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">response</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
23
|
+
<span class="line"><span style="color:#BABED8;"> liveResponse</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">background</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addEventListener</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">message</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">message</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
24
|
+
<span class="line"><span style="color:#BABED8;"> console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">message</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
25
|
+
<span class="line"><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
26
|
+
<span class="line"></span>
|
|
27
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> return</span><span style="color:#BABED8;"> liveResponse</span><span style="color:#89DDFF;">;</span></span>
|
|
28
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>This intermediate handler essentially talks to the upstream via <code>liveResponse.background</code> (the <em>Port B</em>) while letting the same response flow downstream.</p><p>The handler’s own <code>event.client</code> port remains its own <em>Port A</em> for communicating with the downstream.</p><hr><div class="tip custom-block"><p class="custom-block-title">TIP</p><p>While not explicitly mentioned, external Webflo servers are just as accessible and interactive as the local server. A server-to-server interaction, for example, is just a matter of <code>LiveResponse.from(await fetch('https://api.example.com/data'))</code>.</p></div><h2 id="entering-background-mode" tabindex="-1">Entering Background Mode <a class="header-anchor" href="#entering-background-mode" aria-label="Permalink to "Entering Background Mode""></a></h2><p>A handler <strong>enters background mode</strong> when it responds to a request interactively as any of the below scenarios. Webflo automatically upgrades the connection to a realtime connection — initiating the <em>handshake sequence</em> with the client and keeping the communication open until <em>termination</em> is triggered — as in <a href="#appendix-a-–-the-realtime-lifecycle">the Realtime Lifecycle</a>.</p><h3 id="handler-sends-a-message-at-any-point-in-its-lifecycle" tabindex="-1"><em>Handler sends a message at any point in its lifecycle</em> <a class="header-anchor" href="#handler-sends-a-message-at-any-point-in-its-lifecycle" aria-label="Permalink to "_Handler sends a message at any point in its lifecycle_""></a></h3><p>A handler may send a message at any point in its lifecycle by either:</p><ol><li>calling <code>event.client.postMessage()</code>:</li></ol><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">client</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">postMessage</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> progress</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 10</span><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><ol start="2"><li>or achieving the same through higher-level APIs like <code>event.user.confirm()</code>:</li></ol><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#C792EA;">const</span><span style="color:#BABED8;"> result </span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">user</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">confirm</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> message</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Are you sure?</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><h3 id="handler-returns-a-response-and-explicitly-marks-it-not-done" tabindex="-1"><em>Handler returns a response and explicitly marks it <strong>not done</strong></em> <a class="header-anchor" href="#handler-returns-a-response-and-explicitly-marks-it-not-done" aria-label="Permalink to "_Handler returns a response and explicitly marks it **not done**_""></a></h3><p>A handler may return a response and explicitly mark it <strong>not done</strong> by calling <code>event.respondWith()</code> (or returning <code>LiveResponse</code>) with <code>{ done: false }</code>:</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#BABED8;">(data</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> false</span><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;"> new</span><span style="color:#82AAFF;"> LiveResponse</span><span style="color:#BABED8;">(data</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> false</span><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><h3 id="handler-holds-down-the-event-lifecycle-via-promises" tabindex="-1"><em>Handler holds down the event lifecycle via promises</em> <a class="header-anchor" href="#handler-holds-down-the-event-lifecycle-via-promises" aria-label="Permalink to "_Handler holds down the event lifecycle via promises_""></a></h3><p>A handler may hold down the event lifecycle via promises by either:</p><ol><li>explicitly calling <code>event.waitUntil()</code> or <code>event.waitUntilNavigate()</code> before returning a response:</li></ol><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">waitUntilNavigate</span><span style="color:#BABED8;">()</span><span style="color:#89DDFF;">;</span></span>
|
|
29
|
+
<span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#BABED8;">(data)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">waitUntil</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">new</span><span style="color:#FFCB6B;"> Promise</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">()</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {}</span><span style="color:#BABED8;">))</span><span style="color:#89DDFF;">;</span></span>
|
|
30
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#BABED8;"> data</span><span style="color:#89DDFF;">;</span></span></code></pre></div><ol start="2"><li>or calling <code>event.respondWith()</code> (or returning <code>LiveResponse</code>) with a promise that resolves to a response:</li></ol><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#BABED8;">(</span></span>
|
|
31
|
+
<span class="line"><span style="color:#89DDFF;"> new</span><span style="color:#FFCB6B;"> Promise</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">resolve</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
32
|
+
<span class="line"><span style="color:#82AAFF;"> setTimeout</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">()</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
33
|
+
<span class="line"><span style="color:#82AAFF;"> resolve</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">data</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
34
|
+
<span class="line"><span style="color:#89DDFF;"> },</span><span style="color:#F78C6C;"> 1000</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
35
|
+
<span class="line"><span style="color:#89DDFF;"> }</span><span style="color:#BABED8;">)</span></span>
|
|
36
|
+
<span class="line"><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><ol start="3"><li>or calling <code>event.respondWith()</code> (or returning <code>LiveResponse</code>) with an async callback as second argument:</li></ol><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#BABED8;">event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#BABED8;">(data</span><span style="color:#89DDFF;">,</span><span style="color:#C792EA;"> async</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">$data</span><span style="color:#676E95;font-style:italic;"> /* reactive copy of data */</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
37
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#89DDFF;"> new</span><span style="color:#FFCB6B;"> Promise</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">resolve</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#82AAFF;"> setTimeout</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">resolve</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;"> 1000</span><span style="color:#F07178;">))</span><span style="color:#89DDFF;">;</span></span>
|
|
38
|
+
<span class="line"><span style="color:#BABED8;"> $data</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">someProp</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">someValue</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">;</span></span>
|
|
39
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#89DDFF;"> new</span><span style="color:#FFCB6B;"> Promise</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">resolve</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#82AAFF;"> setTimeout</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">resolve</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;"> 1000</span><span style="color:#F07178;">))</span><span style="color:#89DDFF;">;</span></span>
|
|
40
|
+
<span class="line"><span style="color:#BABED8;"> $data</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">someProp</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">someOtherValue</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">;</span></span>
|
|
41
|
+
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><h3 id="handler-returns-a-generator-object" tabindex="-1"><em>Handler returns a <code>Generator</code> object</em> <a class="header-anchor" href="#handler-returns-a-generator-object" aria-label="Permalink to "_Handler returns a \`Generator\` object_""></a></h3><p>A handler may return a <code>Generator</code> object by either:</p><ol><li>being itself a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*" target="_blank" rel="noreferrer"><code>generator function declaration</code></a>:</li></ol><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#89DDFF;font-style:italic;"> default</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#89DDFF;">*</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
42
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> yield</span><span style="color:#BABED8;"> data1</span><span style="color:#89DDFF;">;</span></span>
|
|
43
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> yield</span><span style="color:#89DDFF;"> new</span><span style="color:#82AAFF;"> Response</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">data2</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
44
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> yield</span><span style="color:#89DDFF;"> new</span><span style="color:#82AAFF;"> LiveResponse</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">null,</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> headers</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> Location</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">/</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> }</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
45
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><ol start="2"><li>or returning a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator" target="_blank" rel="noreferrer"><code>Generator</code> interface</a> as value:</li></ol><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#89DDFF;font-style:italic;"> default</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
46
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> return</span><span style="color:#89DDFF;"> {</span></span>
|
|
47
|
+
<span class="line"><span style="color:#82AAFF;"> next</span><span style="color:#89DDFF;">:</span><span style="color:#C792EA;"> async</span><span style="color:#89DDFF;"> ()</span><span style="color:#C792EA;"> =></span><span style="color:#F07178;"> (</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> true</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">,</span></span>
|
|
48
|
+
<span class="line"><span style="color:#82AAFF;"> return</span><span style="color:#89DDFF;">:</span><span style="color:#C792EA;"> async</span><span style="color:#89DDFF;"> ()</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> undefined,</span></span>
|
|
49
|
+
<span class="line"><span style="color:#82AAFF;"> throw</span><span style="color:#89DDFF;">:</span><span style="color:#C792EA;"> async</span><span style="color:#89DDFF;"> ()</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> undefined,</span></span>
|
|
50
|
+
<span class="line"><span style="color:#89DDFF;"> };</span></span>
|
|
51
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="handler-returns-a-state-object" tabindex="-1"><em>Handler returns a <code>State</code> object</em> <a class="header-anchor" href="#handler-returns-a-state-object" aria-label="Permalink to "_Handler returns a \`State\` object_""></a></h3><p>A handler may return a <code>State</code> object by declaring a <code>live</code> function:</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#89DDFF;font-style:italic;"> default</span><span style="color:#BABED8;"> async live </span><span style="color:#C792EA;">function</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
52
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> data</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> progress</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 0</span><span style="color:#89DDFF;"> };</span></span>
|
|
53
|
+
<span class="line"></span>
|
|
54
|
+
<span class="line"><span style="color:#82AAFF;"> setInterval</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">()</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
55
|
+
<span class="line"><span style="color:#BABED8;"> data</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">progress</span><span style="color:#89DDFF;"> +=</span><span style="color:#F78C6C;"> 10</span><span style="color:#89DDFF;">;</span></span>
|
|
56
|
+
<span class="line"><span style="color:#89DDFF;"> },</span><span style="color:#F78C6C;"> 1000</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
57
|
+
<span class="line"></span>
|
|
58
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> return</span><span style="color:#BABED8;"> data</span><span style="color:#89DDFF;">;</span></span>
|
|
59
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>The <code>live</code> keyword is a shorthand for defining a quantum function that returns a <code>State</code> object.</p><hr><p>Webflo knows to switch the connection to background mode in all the above cases.</p><div class="tip custom-block"><p class="custom-block-title">In Practice</p><ul><li>Entering or not entering background mode is often not something you need to be conscious of.</li><li>A handler just happens to be interactive or not interactive depending on request types and how they lend themselves to be handled.</li><li><strong>Webflo simply fulfills the intent of however a handler works</strong>.</li></ul></div><h2 id="real-world-examples" tabindex="-1">Real-world Examples <a class="header-anchor" href="#real-world-examples" aria-label="Permalink to "Real-world Examples""></a></h2><h3 id="live-responses" tabindex="-1">Live Responses <a class="header-anchor" href="#live-responses" aria-label="Permalink to "Live Responses""></a></h3><h4 id="example-—-replace-state" tabindex="-1">Example — Replace state <a class="header-anchor" href="#example-—-replace-state" aria-label="Permalink to "Example — Replace state""></a></h4><p>This handler returns a <code>LiveResponse</code> whose body starts as <code>{ step: 1 }</code> and is replaced with <code>{ step: 2 }</code> after ~200ms; the UI updates automatically.</p><p><strong><em>Result</em>:</strong> The page first renders step: 1, then updates to step: 2 after ~200ms.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#89DDFF;"> {</span><span style="color:#BABED8;"> LiveResponse</span><span style="color:#89DDFF;"> }</span><span style="color:#89DDFF;font-style:italic;"> from</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">@webqit/webflo</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight has-highlighted vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#82AAFF;"> GET</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;font-style:italic;"> next</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
60
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">next</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">stepname</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // The conventional delegation line</span></span>
|
|
61
|
+
<span class="line"></span>
|
|
62
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> res</span><span style="color:#89DDFF;"> =</span><span style="color:#BABED8;"> LiveResponse</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">from</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> step</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 1</span><span style="color:#89DDFF;"> },</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> false</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
63
|
+
<span class="line highlighted"><span style="color:#82AAFF;"> setTimeout</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">()</span><span style="color:#C792EA;"> =></span><span style="color:#BABED8;"> res</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">replaceWith</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> step</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 2</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;"> 200</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
64
|
+
<span class="line"></span>
|
|
65
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> return</span><span style="color:#BABED8;"> res</span><span style="color:#89DDFF;">;</span></span>
|
|
66
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="example-—-mutate-state-in-place" tabindex="-1">Example — Mutate state in place <a class="header-anchor" href="#example-—-mutate-state-in-place" aria-label="Permalink to "Example — Mutate state in place""></a></h4><p>This handler returns a skeleton object immediately for fast page load and then builds the object tree progressively as data arrives; the UI reflects every step of the object's construction.</p><p><strong><em>Result</em>:</strong> The UI renders a skeleton first, then progressively fills in as the object tree is built from the server.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">import</span><span style="color:#89DDFF;"> {</span><span style="color:#BABED8;"> Observer</span><span style="color:#89DDFF;"> }</span><span style="color:#89DDFF;font-style:italic;"> from</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">@webqit/observer</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#82AAFF;"> GET</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;font-style:italic;"> next</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
67
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">next</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">stepname</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // The conventional delegation line</span></span>
|
|
68
|
+
<span class="line"></span>
|
|
69
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> data</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;"> {</span></span>
|
|
70
|
+
<span class="line"><span style="color:#F07178;"> menu</span><span style="color:#89DDFF;">:</span><span style="color:#F07178;"> [</span></span>
|
|
71
|
+
<span class="line"><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> name</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Home</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> href</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">/</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> },</span></span>
|
|
72
|
+
<span class="line"><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> name</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">About</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> href</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">/about</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> },</span></span>
|
|
73
|
+
<span class="line"><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> name</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Contact</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> href</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">/contact</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> },</span></span>
|
|
74
|
+
<span class="line"><span style="color:#F07178;"> ]</span><span style="color:#89DDFF;">,</span></span>
|
|
75
|
+
<span class="line"><span style="color:#F07178;"> content</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> {</span></span>
|
|
76
|
+
<span class="line"><span style="color:#F07178;"> header</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Loading...</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span></span>
|
|
77
|
+
<span class="line"><span style="color:#F07178;"> body</span><span style="color:#89DDFF;">:</span><span style="color:#F07178;"> []</span><span style="color:#89DDFF;">,</span></span>
|
|
78
|
+
<span class="line"><span style="color:#89DDFF;"> },</span></span>
|
|
79
|
+
<span class="line"><span style="color:#89DDFF;"> };</span></span>
|
|
80
|
+
<span class="line"></span>
|
|
81
|
+
<span class="line"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">waitUntil</span><span style="color:#F07178;">(</span></span>
|
|
82
|
+
<span class="line"><span style="color:#89DDFF;"> new</span><span style="color:#FFCB6B;"> Promise</span><span style="color:#F07178;">(</span><span style="color:#C792EA;">async</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">resolve</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
83
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> someData</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> fetch</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">https://api.example.com/data</span><span style="color:#89DDFF;">'</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
84
|
+
<span class="line"><span style="color:#BABED8;"> Observer</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">set</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">data</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">content</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">header</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;"> someData</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">header</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
85
|
+
<span class="line"></span>
|
|
86
|
+
<span class="line"><span style="color:#BABED8;"> Observer</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">proxy</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">data</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">content</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">body</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">push</span><span style="color:#F07178;">(</span></span>
|
|
87
|
+
<span class="line"><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> text</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Inventory 1:</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> +</span><span style="color:#BABED8;"> someData</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">items</span><span style="color:#F07178;">[</span><span style="color:#F78C6C;">0</span><span style="color:#F07178;">] </span><span style="color:#89DDFF;">},</span></span>
|
|
88
|
+
<span class="line"><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> text</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Inventory 2:</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> +</span><span style="color:#BABED8;"> someData</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">items</span><span style="color:#F07178;">[</span><span style="color:#F78C6C;">1</span><span style="color:#F07178;">] </span><span style="color:#89DDFF;">}</span></span>
|
|
89
|
+
<span class="line"><span style="color:#F07178;"> )</span><span style="color:#89DDFF;">;</span></span>
|
|
90
|
+
<span class="line"></span>
|
|
91
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> someData2</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> fetch</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">https://api.example.com/data2</span><span style="color:#89DDFF;">'</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
92
|
+
<span class="line"><span style="color:#BABED8;"> Observer</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">proxy</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">data</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">content</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">body</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">push</span><span style="color:#F07178;">(</span></span>
|
|
93
|
+
<span class="line"><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> text</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Inventory 3:</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> +</span><span style="color:#BABED8;"> someData2</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">items</span><span style="color:#F07178;">[</span><span style="color:#F78C6C;">0</span><span style="color:#F07178;">] </span><span style="color:#89DDFF;">},</span></span>
|
|
94
|
+
<span class="line"><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> text</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Inventory 4:</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> +</span><span style="color:#BABED8;"> someData2</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">items</span><span style="color:#F07178;">[</span><span style="color:#F78C6C;">1</span><span style="color:#F07178;">] </span><span style="color:#89DDFF;">}</span></span>
|
|
95
|
+
<span class="line"><span style="color:#F07178;"> )</span><span style="color:#89DDFF;">;</span></span>
|
|
96
|
+
<span class="line"></span>
|
|
97
|
+
<span class="line"><span style="color:#82AAFF;"> resolve</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span></span>
|
|
98
|
+
<span class="line"><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span></span>
|
|
99
|
+
<span class="line"><span style="color:#F07178;"> )</span><span style="color:#89DDFF;">;</span></span>
|
|
100
|
+
<span class="line"></span>
|
|
101
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> return</span><span style="color:#BABED8;"> data</span><span style="color:#89DDFF;">;</span></span>
|
|
102
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="example-—-live-database-results-linkedql" tabindex="-1">Example — Live database results (LinkedQL) <a class="header-anchor" href="#example-—-live-database-results-linkedql" aria-label="Permalink to "Example — Live database results (LinkedQL)""></a></h4><p>This handler responds with a live posts list from the database using <a href="https://github.com/linked-db/linked-ql" target="_blank" rel="noreferrer">LinkedQL</a>; as upstream data changes, <code>rows</code> update continuously.</p><p><strong><em>Result</em>:</strong> On the UI, the list grows live as new posts are added upstream.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight has-highlighted vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#82AAFF;"> GET</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;font-style:italic;"> next</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
103
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">next</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">stepname</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // The conventional delegation line</span></span>
|
|
104
|
+
<span class="line"></span>
|
|
105
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> result</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#BABED8;"> client</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">query</span><span style="color:#F07178;">(</span></span>
|
|
106
|
+
<span class="line"><span style="color:#89DDFF;"> \`</span><span style="color:#C3E88D;">SELECT * FROM posts WHERE date_created > '2023-01-01'</span><span style="color:#89DDFF;">\`</span><span style="color:#89DDFF;">,</span></span>
|
|
107
|
+
<span class="line"><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> live</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> true</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> signal</span><span style="color:#89DDFF;">:</span><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">signal</span><span style="color:#89DDFF;"> }</span></span>
|
|
108
|
+
<span class="line"><span style="color:#F07178;"> )</span><span style="color:#89DDFF;">;</span></span>
|
|
109
|
+
<span class="line"></span>
|
|
110
|
+
<span class="line"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">waitUntilNavigate</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // Hold down the event lifecycle</span></span>
|
|
111
|
+
<span class="line"></span>
|
|
112
|
+
<span class="line highlighted"><span style="color:#89DDFF;font-style:italic;"> return</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> posts</span><span style="color:#89DDFF;">:</span><span style="color:#BABED8;"> result</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">rows</span><span style="color:#89DDFF;"> };</span></span>
|
|
113
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="example-—-redirect-after-work" tabindex="-1">Example — Redirect after work <a class="header-anchor" href="#example-—-redirect-after-work" aria-label="Permalink to "Example — Redirect after work""></a></h4><p>This handler emits progress and then issues a redirect when the work completes.</p><p><strong><em>Result</em>:</strong> The page shows intermediate progress, then redirects to <code>/done</code> when work completes.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight has-highlighted vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#82AAFF;"> POST</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;font-style:italic;"> next</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
114
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">next</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">stepname</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // The conventional delegation line</span></span>
|
|
115
|
+
<span class="line"></span>
|
|
116
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Initiate response</span></span>
|
|
117
|
+
<span class="line"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> step</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 1</span><span style="color:#89DDFF;"> },</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> false</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
118
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Make API call</span></span>
|
|
119
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> fetch</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">https://api.example.com/data</span><span style="color:#89DDFF;">'</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
120
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Update response</span></span>
|
|
121
|
+
<span class="line"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> step</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 2</span><span style="color:#89DDFF;"> },</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> false</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
122
|
+
<span class="line"></span>
|
|
123
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Redirect</span></span>
|
|
124
|
+
<span class="line highlighted"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">null,</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> status</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 302</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> headers</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> Location</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">/done</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> }</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
125
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="user-dialogs-server-↔-user-interaction" tabindex="-1">User Dialogs: Server ↔ User Interaction <a class="header-anchor" href="#user-dialogs-server-↔-user-interaction" aria-label="Permalink to "User Dialogs: Server ↔ User Interaction""></a></h3><h4 id="example-—-ask-for-confirmation" tabindex="-1">Example — Ask for confirmation <a class="header-anchor" href="#example-—-ask-for-confirmation" aria-label="Permalink to "Example — Ask for confirmation""></a></h4><p>This handler pauses request processing to interact with the user before proceeding, using realtime messaging.</p><p><strong><em>Result</em>:</strong> The user is prompted to confirm an action; on OK, the handler proceeds.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight has-highlighted vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#82AAFF;"> DELETE</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;font-style:italic;"> next</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
126
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">next</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">stepname</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // The conventional delegation line</span></span>
|
|
127
|
+
<span class="line"></span>
|
|
128
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> message</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">This item will be permanently deleted. Are you sure?</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">;</span></span>
|
|
129
|
+
<span class="line highlighted"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> answer</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">user</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">confirm</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">{</span><span style="color:#BABED8;"> message</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
130
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">answer</span><span style="color:#89DDFF;">?.</span><span style="color:#BABED8;">data</span><span style="color:#89DDFF;"> ===</span><span style="color:#FF9CAC;"> true</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;">{</span></span>
|
|
131
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // proceed</span></span>
|
|
132
|
+
<span class="line"><span style="color:#89DDFF;"> }</span></span>
|
|
133
|
+
<span class="line"></span>
|
|
134
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> return</span><span style="color:#BABED8;"> Response</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">json</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> ok</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> true</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
135
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>The Webflo UI client shows the dialog (native <code>confirm()/prompt()</code> or custom UI if configured) and returns the user's response.</p><p>Customization is as simple as intercepting these via <code>preventDefault()</code> to render your own modals.</p><div class="language-javascript"><button title="Copy Code" class="copy"></button><span class="lang">javascript</span><pre class="shiki material-theme-palenight has-highlighted vp-code" tabindex="0"><code><span class="line"><span style="color:#676E95;font-style:italic;">// Intercept at window.webqit.app.background</span></span>
|
|
136
|
+
<span class="line"><span style="color:#BABED8;">window</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">webqit</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">app</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">background</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addEventListener</span><span style="color:#BABED8;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">prompt</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">e</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
137
|
+
<span class="line highlighted"><span style="color:#BABED8;"> e</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">preventDefault</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span></span>
|
|
138
|
+
<span class="line"><span style="color:#82AAFF;"> customDialog</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">e</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">data</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">message</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">then</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">result</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
139
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Reply to the request on the provided port</span></span>
|
|
140
|
+
<span class="line highlighted"><span style="color:#BABED8;"> e</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">ports</span><span style="color:#F07178;">[</span><span style="color:#F78C6C;">0</span><span style="color:#F07178;">]</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">postMessage</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">result</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
141
|
+
<span class="line"><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
142
|
+
<span class="line"><span style="color:#89DDFF;">}</span><span style="color:#BABED8;">)</span><span style="color:#89DDFF;">;</span></span></code></pre></div><h3 id="message-channels" tabindex="-1">Message Channels <a class="header-anchor" href="#message-channels" aria-label="Permalink to "Message Channels""></a></h3><h4 id="example-—-channel-chat-server-client-ui" tabindex="-1">Example — Channel chat (server + client + UI) <a class="header-anchor" href="#example-—-channel-chat-server-client-ui" aria-label="Permalink to "Example — Channel chat (server + client + UI)""></a></h4><p>These handlers establish a chat channel and broadcast messages to all participants.</p><p><strong><em>Result</em>:</strong> Messages appear in the chat trail every few seconds; incoming vs outgoing messages are styled differently.</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#82AAFF;"> GET</span><span style="color:#89DDFF;">(</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;font-style:italic;"> next</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
143
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">next</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">stepname</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // The conventional delegation line</span></span>
|
|
144
|
+
<span class="line"></span>
|
|
145
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Channel ID - must tally with the client-side ID</span></span>
|
|
146
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> channelID</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">test-channel</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">;</span></span>
|
|
147
|
+
<span class="line"></span>
|
|
148
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#89DDFF;"> {</span><span style="color:#BABED8;"> channel</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;"> leave</span><span style="color:#89DDFF;"> }</span><span style="color:#89DDFF;"> =</span><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">client</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">enterChannel</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">channelID</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> {</span></span>
|
|
149
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Optionally annotate user's messages with user's name</span></span>
|
|
150
|
+
<span class="line"><span style="color:#82AAFF;"> resolveData</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">message</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#F07178;"> (</span><span style="color:#89DDFF;">{</span><span style="color:#89DDFF;"> ...</span><span style="color:#BABED8;">message</span><span style="color:#89DDFF;">,</span><span style="color:#F07178;"> user</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">sample name</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">,</span></span>
|
|
151
|
+
<span class="line"><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
152
|
+
<span class="line"></span>
|
|
153
|
+
<span class="line"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">waitUntilNavigate</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // keep open</span></span>
|
|
154
|
+
<span class="line"><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">client</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addEventListener</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">close</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">e</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
155
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> //e.preventDefault();</span></span>
|
|
156
|
+
<span class="line"><span style="color:#BABED8;"> console</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">log</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">'</span><span style="color:#C3E88D;">Chat closed</span><span style="color:#89DDFF;">'</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
157
|
+
<span class="line"><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
158
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>Then on the client:</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight has-highlighted vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;font-style:italic;">export</span><span style="color:#89DDFF;font-style:italic;"> default</span><span style="color:#C792EA;"> async</span><span style="color:#C792EA;"> function</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">event</span><span style="color:#89DDFF;">,</span><span style="color:#BABED8;font-style:italic;"> next</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
159
|
+
<span class="line"><span style="color:#89DDFF;font-style:italic;"> if</span><span style="color:#F07178;"> (</span><span style="color:#BABED8;">next</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">stepname</span><span style="color:#F07178;">) </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // The conventional delegation line</span></span>
|
|
160
|
+
<span class="line"></span>
|
|
161
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Initialize states</span></span>
|
|
162
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> data</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> messageTrail</span><span style="color:#89DDFF;">:</span><span style="color:#F07178;"> [</span><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> message</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">Beginning of chat...</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">] </span><span style="color:#89DDFF;">};</span></span>
|
|
163
|
+
<span class="line highlighted"><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#BABED8;"> event</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">respondWith</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">data</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> done</span><span style="color:#89DDFF;">:</span><span style="color:#FF9CAC;"> false</span><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
164
|
+
<span class="line"></span>
|
|
165
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // The messaging part</span></span>
|
|
166
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> response</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;font-style:italic;"> await</span><span style="color:#82AAFF;"> next</span><span style="color:#F07178;">()</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;"> // Call server</span></span>
|
|
167
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> chatPort</span><span style="color:#89DDFF;"> =</span><span style="color:#BABED8;"> LiveResponse</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">from</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">response</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">background</span><span style="color:#89DDFF;">;</span></span>
|
|
168
|
+
<span class="line"></span>
|
|
169
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Channel ID - must tally with the server-side ID</span></span>
|
|
170
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> channelID</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;"> '</span><span style="color:#C3E88D;">test-channel</span><span style="color:#89DDFF;">'</span><span style="color:#89DDFF;">;</span></span>
|
|
171
|
+
<span class="line"></span>
|
|
172
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Listen to upstream messages - from others in the same channel</span></span>
|
|
173
|
+
<span class="line"><span style="color:#BABED8;"> chatPort</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addEventListener</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">\`\${</span><span style="color:#BABED8;">channelID</span><span style="color:#89DDFF;">}</span><span style="color:#C3E88D;">:message</span><span style="color:#89DDFF;">\`</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> (</span><span style="color:#BABED8;font-style:italic;">e</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
174
|
+
<span class="line highlighted"><span style="color:#BABED8;"> Observer</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">proxy</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">data</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">messageTrail</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">push</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">e</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">data</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
175
|
+
<span class="line"><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
176
|
+
<span class="line"></span>
|
|
177
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Send messages to the chat</span></span>
|
|
178
|
+
<span class="line"><span style="color:#82AAFF;"> setInterval</span><span style="color:#F07178;">(</span><span style="color:#89DDFF;">()</span><span style="color:#C792EA;"> =></span><span style="color:#89DDFF;"> {</span></span>
|
|
179
|
+
<span class="line"><span style="color:#C792EA;"> const</span><span style="color:#BABED8;"> message</span><span style="color:#89DDFF;"> =</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> message</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> \`</span><span style="color:#C3E88D;">Hello from </span><span style="color:#89DDFF;">\${</span><span style="color:#BABED8;">navigator</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">userAgent</span><span style="color:#89DDFF;">}\`</span><span style="color:#89DDFF;"> };</span></span>
|
|
180
|
+
<span class="line"></span>
|
|
181
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Send to others in the same channel</span></span>
|
|
182
|
+
<span class="line"><span style="color:#BABED8;"> chatPort</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">postMessage</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">message</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;"> {</span></span>
|
|
183
|
+
<span class="line"><span style="color:#F07178;"> wqEventOptions</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> {</span><span style="color:#F07178;"> type</span><span style="color:#89DDFF;">:</span><span style="color:#89DDFF;"> \`\${</span><span style="color:#BABED8;">channelID</span><span style="color:#89DDFF;">}</span><span style="color:#C3E88D;">:message</span><span style="color:#89DDFF;">\`</span><span style="color:#89DDFF;"> },</span></span>
|
|
184
|
+
<span class="line highlighted"><span style="color:#89DDFF;"> }</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
185
|
+
<span class="line"></span>
|
|
186
|
+
<span class="line"><span style="color:#676E95;font-style:italic;"> // Add to the local trail</span></span>
|
|
187
|
+
<span class="line highlighted"><span style="color:#BABED8;"> Observer</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">proxy</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">data</span><span style="color:#89DDFF;">.</span><span style="color:#BABED8;">messageTrail</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">push</span><span style="color:#F07178;">(</span><span style="color:#BABED8;">message</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
188
|
+
<span class="line"><span style="color:#89DDFF;"> },</span><span style="color:#F78C6C;"> 6000</span><span style="color:#F07178;">)</span><span style="color:#89DDFF;">;</span></span>
|
|
189
|
+
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><details class="details custom-block"><summary>Then on the UI</summary><div class="language-html"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki material-theme-palenight vp-code" tabindex="0"><code><span class="line"><span style="color:#89DDFF;"><</span><span style="color:#F07178;">div</span><span style="color:#89DDFF;">></span></span>
|
|
190
|
+
<span class="line"><span style="color:#BABED8;"> Welcome to chat!</span></span>
|
|
191
|
+
<span class="line"><span style="color:#89DDFF;"> <</span><span style="color:#F07178;">ul</span><span style="color:#C792EA;"> render</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">"</span><span style="color:#C3E88D;">#items: (m) of data?.messageTrail / 'message'</span><span style="color:#89DDFF;">"</span><span style="color:#89DDFF;">></span></span>
|
|
192
|
+
<span class="line"><span style="color:#89DDFF;"> <</span><span style="color:#F07178;">template</span><span style="color:#C792EA;"> def</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">"</span><span style="color:#C3E88D;">message</span><span style="color:#89DDFF;">"</span><span style="color:#C792EA;"> scoped</span><span style="color:#89DDFF;">></span></span>
|
|
193
|
+
<span class="line"><span style="color:#89DDFF;"> <</span><span style="color:#F07178;">li</span></span>
|
|
194
|
+
<span class="line"><span style="color:#C792EA;"> class</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">"</span><span style="color:#C3E88D;">chat-message</span><span style="color:#89DDFF;">"</span></span>
|
|
195
|
+
<span class="line"><span style="color:#C792EA;"> render</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">"</span><span style="color:#C3E88D;">#text: m.event || m.message; ~type: m.user && 'incoming' || 'outgoing';</span><span style="color:#89DDFF;">"</span></span>
|
|
196
|
+
<span class="line"><span style="color:#89DDFF;"> ></</span><span style="color:#F07178;">li</span><span style="color:#89DDFF;">></span></span>
|
|
197
|
+
<span class="line"><span style="color:#89DDFF;"> </</span><span style="color:#F07178;">template</span><span style="color:#89DDFF;">></span></span>
|
|
198
|
+
<span class="line"><span style="color:#89DDFF;"> </</span><span style="color:#F07178;">ul</span><span style="color:#89DDFF;">></span></span>
|
|
199
|
+
<span class="line"><span style="color:#89DDFF;"> <</span><span style="color:#F07178;">style</span><span style="color:#C792EA;"> scoped</span><span style="color:#89DDFF;">></span></span>
|
|
200
|
+
<span class="line"><span style="color:#FFCB6B;"> ul</span><span style="color:#89DDFF;">:</span><span style="color:#C792EA;">has</span><span style="color:#89DDFF;">(.</span><span style="color:#FFCB6B;">chat-message</span><span style="color:#89DDFF;">)</span><span style="color:#89DDFF;"> {</span></span>
|
|
201
|
+
<span class="line"><span style="color:#B2CCD6;"> list-style</span><span style="color:#89DDFF;">:</span><span style="color:#BABED8;"> none</span><span style="color:#89DDFF;">;</span></span>
|
|
202
|
+
<span class="line"><span style="color:#B2CCD6;"> padding</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 0</span><span style="color:#89DDFF;">;</span></span>
|
|
203
|
+
<span class="line"><span style="color:#89DDFF;"> }</span></span>
|
|
204
|
+
<span class="line"><span style="color:#89DDFF;"> .</span><span style="color:#FFCB6B;">chat-message</span><span style="color:#89DDFF;"> {</span></span>
|
|
205
|
+
<span class="line"><span style="color:#B2CCD6;"> padding</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 20px</span><span style="color:#89DDFF;">;</span></span>
|
|
206
|
+
<span class="line"><span style="color:#B2CCD6;"> margin</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 10px</span><span style="color:#89DDFF;">;</span></span>
|
|
207
|
+
<span class="line"><span style="color:#89DDFF;"> }</span></span>
|
|
208
|
+
<span class="line"><span style="color:#89DDFF;"> .</span><span style="color:#FFCB6B;">chat-message</span><span style="color:#89DDFF;">[</span><span style="color:#C792EA;">type</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">"</span><span style="color:#C3E88D;">incoming</span><span style="color:#89DDFF;">"</span><span style="color:#89DDFF;">]</span><span style="color:#89DDFF;"> {</span></span>
|
|
209
|
+
<span class="line"><span style="color:#B2CCD6;"> margin-right</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 200px</span><span style="color:#89DDFF;">;</span></span>
|
|
210
|
+
<span class="line"><span style="color:#B2CCD6;"> background-color</span><span style="color:#89DDFF;">:</span><span style="color:#BABED8;"> blue</span><span style="color:#89DDFF;">;</span></span>
|
|
211
|
+
<span class="line"><span style="color:#89DDFF;"> }</span></span>
|
|
212
|
+
<span class="line"><span style="color:#89DDFF;"> .</span><span style="color:#FFCB6B;">chat-message</span><span style="color:#89DDFF;">[</span><span style="color:#C792EA;">type</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">"</span><span style="color:#C3E88D;">outgoing</span><span style="color:#89DDFF;">"</span><span style="color:#89DDFF;">]</span><span style="color:#89DDFF;"> {</span></span>
|
|
213
|
+
<span class="line"><span style="color:#B2CCD6;"> margin-left</span><span style="color:#89DDFF;">:</span><span style="color:#F78C6C;"> 200px</span><span style="color:#89DDFF;">;</span></span>
|
|
214
|
+
<span class="line"><span style="color:#B2CCD6;"> text-align</span><span style="color:#89DDFF;">:</span><span style="color:#BABED8;"> right</span><span style="color:#89DDFF;">;</span></span>
|
|
215
|
+
<span class="line"><span style="color:#B2CCD6;"> background-color</span><span style="color:#89DDFF;">:</span><span style="color:#BABED8;"> teal</span><span style="color:#89DDFF;">;</span></span>
|
|
216
|
+
<span class="line"><span style="color:#89DDFF;"> }</span></span>
|
|
217
|
+
<span class="line"><span style="color:#89DDFF;"> </</span><span style="color:#F07178;">style</span><span style="color:#89DDFF;">></span></span>
|
|
218
|
+
<span class="line"><span style="color:#89DDFF;"></</span><span style="color:#F07178;">div</span><span style="color:#89DDFF;">></span></span></code></pre></div></details><div class="warning custom-block"><p class="custom-block-title">WARNING</p><ul><li>Channel IDs must be unique and unguessable across the app.</li><li>Channels are not persistent and are only active for the duration of the request. A database is required to store channel data.</li></ul></div><h2 id="appendix-a-–-the-realtime-lifecycle" tabindex="-1">Appendix A – The Realtime Lifecycle <a class="header-anchor" href="#appendix-a-–-the-realtime-lifecycle" aria-label="Permalink to "Appendix A – The Realtime Lifecycle""></a></h2>`,111)),(e(),t(r,null,{default:n(()=>[c(o,{id:"mermaid-428",class:"mermaid",graph:"sequenceDiagram%0A%20%20participant%20Browser%0A%20%20participant%20Handler%0A%20%20Browser-%3E%3EHandler%3A%20HTTP%20request%0A%20%20Handler--%3E%3EBrowser%3A%20Initial%20Response%20(or%20a%20Temporary%20202%20Accepted)%20%3Cbr%3E%2B%20X-Background-Messaging-Port%0A%20%20Browser--%3E%3EHandler%3A%20Connect%20(WebSocket%20%2F%20Broadcast%20%2F%20MessageChannel)%0A%20%20Note%20over%20Browser%2CHandler%3A%20Background%20mode%20established%0A%20%20Handler--%3E%3EBrowser%3A%20Messages%2C%20updates%2C%20dialogs%2C%20etc.%0A%20%20Browser--%3E%3EHandler%3A%20Replies%2C%20requests%2C%20etc.%0A%20%20Browser%3C%3C--%3E%3EHandler%3A%20Termination%0A"})]),fallback:n(()=>[...s[2]||(s[2]=[l(" Loading... ",-1)])]),_:1})),s[9]||(s[9]=p('<h3 id="the-handshake" tabindex="-1">The Handshake <a class="header-anchor" href="#the-handshake" aria-label="Permalink to "The Handshake""></a></h3><p>On entering background mode, Webflo initiates a handshake sequence as follows:</p><ol><li>Webflo gives the initial response a unique <code>X-Background-Messaging-Port</code> header that tells the client to connect in the background after rendering the initial response. <blockquote><p>If the scenario is case <code>1.</code> above happening <em>before</em> yielding a response, Webflo sends a temporary <code>202 Accepted</code> response to the client carrying this header.</p></blockquote></li><li>The client reads that header and opens the background channel. <blockquote><p>If the client fails to connect within the handshake window, Webflo abandons the wait and concludes the request normally.</p></blockquote></li><li>On connecting, both sides resume the same request context — now in live mode.</li></ol><h3 id="termination" tabindex="-1">Termination <a class="header-anchor" href="#termination" aria-label="Permalink to "Termination""></a></h3><p>Communication remains active until one of three events occurs and triggers a controlled closure:</p><ol><li>The handler completes and no longer holds the event lifecycle.</li><li>The user navigates away, triggering a <code>navigate</code> event on the handler's <code>event.client</code> port. <blockquote><p>If the handler calls <code>event.preventDefault()</code> on the <code>navigate</code> event, Webflo knows to not close the connection. <strong>You must explicitly call <code>event.client.close()</code> when finished.</strong></p></blockquote></li><li>Either side explicitly calls <code>.close()</code> on its own port to end the conversation.</li></ol>',6))])}const f=F(D,[["render",d]]);export{E as __pageData,f as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as F,C as i,c as y,o as e,a2 as p,b as t,j as a,w as n,a as l,G as c,a3 as r}from"./chunks/framework.9Uv4PgnO.js";const E=JSON.parse('{"title":"Webflo Realtime","description":"","frontmatter":{},"headers":[],"relativePath":"docs/concepts/realtime.md","filePath":"docs/concepts/realtime.md"}'),D={name:"docs/concepts/realtime.md"};function d(h,s,A,B,u,m){const o=i("Mermaid");return e(),y("div",null,[s[3]||(s[3]=p("",12)),(e(),t(r,null,{default:n(()=>[c(o,{id:"mermaid-24",class:"mermaid",graph:"flowchart%20LR%0A%20%20%20%20subgraph%20Browser%0A%20%20%20%20%20%20%20%20B1%5BHTTP%20Client%5D%0A%20%20%20%20%20%20%20%20B2%5BWebSocket%20Client%5D%0A%20%20%20%20end%0A%20%20%20%20subgraph%20Server%0A%20%20%20%20%20%20%20%20S1%5BHTTP%20Handler%5D%0A%20%20%20%20%20%20%20%20S2%5BWebSocket%20Handler%5D%0A%20%20%20%20end%0A%20%20%20%20B1%20%3C--%3E%20%7CHTTP%20request%20%2F%20response%7C%20S1%0A%20%20%20%20B2%20%3C---%3E%20%7CRealtime%20messages%7C%20S2%0A"})]),fallback:n(()=>[...s[0]||(s[0]=[l(" Loading... ",-1)])]),_:1})),s[4]||(s[4]=a("p",null,"This works — but it’s hardly effortless. That’s requests on one channel, updates on another.",-1)),s[5]||(s[5]=a("h2",{id:"the-webflo-model",tabindex:"-1"},[l("The Webflo Model "),a("a",{class:"header-anchor",href:"#the-webflo-model","aria-label":'Permalink to "The Webflo Model"'},"")],-1)),s[6]||(s[6]=a("p",null,"In Webflo, this behavior is built in. The same request that starts over HTTP can seamlessly continue as a live, bidirectional exchange — with no moving parts or extra line of code at the application layer.",-1)),s[7]||(s[7]=a("p",null,[l("This is like the entire architecture above collapsed into one: an "),a("strong",null,"auto-upgrading connection"),l(" that can be used for many different things.")],-1)),(e(),t(r,null,{default:n(()=>[c(o,{id:"mermaid-37",class:"mermaid",graph:"flowchart%20LR%0A%20%20%20%20subgraph%20Browser%0A%20%20%20%20%20%20%20%20B1%5BWebflo%20Client%5D%0A%20%20%20%20end%0A%20%20%20%20subgraph%20Server%0A%20%20%20%20%20%20%20%20S1%5BWebflo%20Handler%5D%0A%20%20%20%20end%0A%20%20%20%20B1%20%3C--%3E%20%7CAuto-upgrading%0A%20%20%20%20HTTP%20request%20%2F%20response%7C%20S1%0A"})]),fallback:n(()=>[...s[1]||(s[1]=[l(" Loading... ",-1)])]),_:1})),s[8]||(s[8]=p("",111)),(e(),t(r,null,{default:n(()=>[c(o,{id:"mermaid-428",class:"mermaid",graph:"sequenceDiagram%0A%20%20participant%20Browser%0A%20%20participant%20Handler%0A%20%20Browser-%3E%3EHandler%3A%20HTTP%20request%0A%20%20Handler--%3E%3EBrowser%3A%20Initial%20Response%20(or%20a%20Temporary%20202%20Accepted)%20%3Cbr%3E%2B%20X-Background-Messaging-Port%0A%20%20Browser--%3E%3EHandler%3A%20Connect%20(WebSocket%20%2F%20Broadcast%20%2F%20MessageChannel)%0A%20%20Note%20over%20Browser%2CHandler%3A%20Background%20mode%20established%0A%20%20Handler--%3E%3EBrowser%3A%20Messages%2C%20updates%2C%20dialogs%2C%20etc.%0A%20%20Browser--%3E%3EHandler%3A%20Replies%2C%20requests%2C%20etc.%0A%20%20Browser%3C%3C--%3E%3EHandler%3A%20Termination%0A"})]),fallback:n(()=>[...s[2]||(s[2]=[l(" Loading... ",-1)])]),_:1})),s[9]||(s[9]=p("",6))])}const f=F(D,[["render",d]]);export{E as __pageData,f as default};
|