@webqit/webflo 0.11.61 → 0.20.2-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/.github/FUNDING.yml +12 -0
  2. package/.github/workflows/publish.yml +48 -0
  3. package/.gitignore +2 -0
  4. package/LICENSE +2 -2
  5. package/README.md +71 -2050
  6. package/package.json +28 -13
  7. package/site/-/_.md +139 -0
  8. package/site/-/docs.old.md +2010 -0
  9. package/site/.vitepress/cache/deps/@braintree_sanitize-url 2.js +93 -0
  10. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
  11. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js 2.map +7 -0
  12. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
  13. package/site/.vitepress/cache/deps/_metadata 2.json +85 -0
  14. package/site/.vitepress/cache/deps/_metadata.json +85 -0
  15. package/site/.vitepress/cache/deps/chunk-BUSYA2B4 2.js +9 -0
  16. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
  17. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js 2.map +7 -0
  18. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
  19. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK 2.js +9719 -0
  20. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js +9719 -0
  21. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js 2.map +7 -0
  22. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js.map +7 -0
  23. package/site/.vitepress/cache/deps/chunk-QAXAIFA7 2.js +12705 -0
  24. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js +12705 -0
  25. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js 2.map +7 -0
  26. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js.map +7 -0
  27. package/site/.vitepress/cache/deps/cytoscape 2.js +30278 -0
  28. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent 2.js +4710 -0
  29. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
  30. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js 2.map +7 -0
  31. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
  32. package/site/.vitepress/cache/deps/cytoscape.js +30278 -0
  33. package/site/.vitepress/cache/deps/cytoscape.js 2.map +7 -0
  34. package/site/.vitepress/cache/deps/cytoscape.js.map +7 -0
  35. package/site/.vitepress/cache/deps/dayjs 2.js +285 -0
  36. package/site/.vitepress/cache/deps/dayjs.js +285 -0
  37. package/site/.vitepress/cache/deps/dayjs.js 2.map +7 -0
  38. package/site/.vitepress/cache/deps/dayjs.js.map +7 -0
  39. package/site/.vitepress/cache/deps/debug 2.js +453 -0
  40. package/site/.vitepress/cache/deps/debug.js +453 -0
  41. package/site/.vitepress/cache/deps/debug.js 2.map +7 -0
  42. package/site/.vitepress/cache/deps/debug.js.map +7 -0
  43. package/site/.vitepress/cache/deps/package 2.json +3 -0
  44. package/site/.vitepress/cache/deps/package.json +3 -0
  45. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api 2.js +4507 -0
  46. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
  47. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js 2.map +7 -0
  48. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  49. package/site/.vitepress/cache/deps/vitepress___@vueuse_core 2.js +584 -0
  50. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
  51. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js 2.map +7 -0
  52. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  53. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap 2.js +1166 -0
  54. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1166 -0
  55. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js 2.map +7 -0
  56. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  57. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js 2.js +1667 -0
  58. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
  59. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js 2.map +7 -0
  60. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  61. package/site/.vitepress/cache/deps/vitepress___minisearch 2.js +1815 -0
  62. package/site/.vitepress/cache/deps/vitepress___minisearch.js +1815 -0
  63. package/site/.vitepress/cache/deps/vitepress___minisearch.js 2.map +7 -0
  64. package/site/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  65. package/site/.vitepress/cache/deps/vue 2.js +344 -0
  66. package/site/.vitepress/cache/deps/vue.js +344 -0
  67. package/site/.vitepress/cache/deps/vue.js 2.map +7 -0
  68. package/site/.vitepress/cache/deps/vue.js.map +7 -0
  69. package/site/.vitepress/config.ts +147 -0
  70. package/site/.vitepress/theme/custom.css +50 -0
  71. package/site/.vitepress/theme/index.ts +6 -0
  72. package/site/api/webflo-fetch/FormData.md +0 -0
  73. package/site/api/webflo-fetch/Headers.md +0 -0
  74. package/site/api/webflo-fetch/LiveResponse.md +0 -0
  75. package/site/api/webflo-fetch/Request.md +0 -0
  76. package/site/api/webflo-fetch/Response.md +0 -0
  77. package/site/api/webflo-fetch/fetch.md +0 -0
  78. package/site/api/webflo-routing/HttpCookies.md +0 -0
  79. package/site/api/webflo-routing/HttpEvent/respondWith.md +1 -0
  80. package/site/api/webflo-routing/HttpEvent/waitUntil.md +1 -0
  81. package/site/api/webflo-routing/HttpEvent/waitUntilNavigate.md +1 -0
  82. package/site/api/webflo-routing/HttpEvent.md +30 -0
  83. package/site/api/webflo-routing/HttpSession.md +0 -0
  84. package/site/api/webflo-routing/HttpState.md +0 -0
  85. package/site/api/webflo-routing/HttpUser.md +0 -0
  86. package/site/api/webflo-routing/handler/fetch.md +42 -0
  87. package/site/api/webflo-routing/handler/next.md +54 -0
  88. package/site/api/webflo-routing/handler.md +119 -0
  89. package/site/api.md +26 -0
  90. package/site/contributing.md +16 -0
  91. package/site/docs/advanced/lifecycles.md +20 -0
  92. package/site/docs/advanced/redirects.md +0 -0
  93. package/site/docs/advanced/routing.md +1 -0
  94. package/site/docs/advanced.md +9 -0
  95. package/site/docs/concepts/realtime.md +637 -0
  96. package/site/docs/concepts/rendering.md +60 -0
  97. package/site/docs/concepts/request-response.md +47 -0
  98. package/site/docs/concepts/routing.md +656 -0
  99. package/site/docs/concepts/state.md +44 -0
  100. package/site/docs/concepts/templates.md +48 -0
  101. package/site/docs/concepts.md +97 -0
  102. package/site/docs/getting-started.md +378 -0
  103. package/site/docs/tech-stack.md +56 -0
  104. package/site/docs.md +100 -0
  105. package/site/examples/pwa.md +10 -0
  106. package/site/examples/web.md +11 -0
  107. package/site/examples.md +10 -0
  108. package/site/faq.md +13 -0
  109. package/site/guides/guide-auth.md +13 -0
  110. package/site/guides/guide-file-upload.md +11 -0
  111. package/site/guides/guide-service-worker.md +10 -0
  112. package/site/guides/tutorial-1-todo.md +24 -0
  113. package/site/guides.md +15 -0
  114. package/site/index.md +39 -0
  115. package/site/public/img/brand/logo-670x670.png +0 -0
  116. package/site/recipes/realtime.md +11 -0
  117. package/site/recipes/streaming.md +15 -0
  118. package/site/reference/cli.md +11 -0
  119. package/site/reference/config.md +13 -0
  120. package/site/reference/tools.md +9 -0
  121. package/src/Context.js +3 -11
  122. package/src/config-pi/deployment/Env.js +6 -19
  123. package/src/config-pi/deployment/Layout.js +11 -3
  124. package/src/config-pi/runtime/Client.js +40 -48
  125. package/src/config-pi/runtime/Server.js +52 -20
  126. package/src/config-pi/runtime/client/Worker.js +22 -20
  127. package/src/config-pi/static/Init.js +57 -0
  128. package/src/config-pi/static/index.js +2 -0
  129. package/src/deployment-pi/origins/index.js +1 -1
  130. package/src/deployment-pi/util.js +161 -0
  131. package/src/index.js +3 -9
  132. package/src/init-pi/index.js +117 -0
  133. package/src/init-pi/templates/pwa/app/handler.server.js +8 -0
  134. package/src/init-pi/templates/pwa/app/page.html +7 -0
  135. package/src/init-pi/templates/pwa/package.json +19 -0
  136. package/src/init-pi/templates/pwa/public/assets/app.css +16 -0
  137. package/src/init-pi/templates/pwa/public/index.html +39 -0
  138. package/src/init-pi/templates/pwa/public/manifest.json +29 -0
  139. package/src/init-pi/templates/web/app/handler.server.js +8 -0
  140. package/src/init-pi/templates/web/app/page.html +7 -0
  141. package/src/init-pi/templates/web/package.json +19 -0
  142. package/src/init-pi/templates/web/public/assets/app.css +16 -0
  143. package/src/init-pi/templates/web/public/index.html +39 -0
  144. package/src/runtime-pi/WebfloRuntime.js +350 -0
  145. package/src/runtime-pi/index.js +3 -10
  146. package/src/runtime-pi/webflo-client/ClientSideCookies.js +17 -0
  147. package/src/runtime-pi/webflo-client/ClientSideWorkport.js +63 -0
  148. package/src/runtime-pi/webflo-client/DeviceCapabilities.js +213 -0
  149. package/src/runtime-pi/webflo-client/WebfloClient.js +500 -0
  150. package/src/runtime-pi/webflo-client/WebfloRootClient1.js +206 -0
  151. package/src/runtime-pi/webflo-client/WebfloRootClient2.js +113 -0
  152. package/src/runtime-pi/webflo-client/WebfloSubClient.js +118 -0
  153. package/src/runtime-pi/webflo-client/index.js +17 -0
  154. package/src/runtime-pi/webflo-client/webflo-codegen.js +469 -0
  155. package/src/runtime-pi/webflo-client/webflo-devmode.js +243 -0
  156. package/src/runtime-pi/webflo-client/webflo-embedded.js +50 -0
  157. package/src/runtime-pi/webflo-fetch/LiveResponse.js +437 -0
  158. package/src/runtime-pi/webflo-fetch/cookies.js +10 -0
  159. package/src/runtime-pi/webflo-fetch/fetch.js +16 -0
  160. package/src/runtime-pi/webflo-fetch/formdata.js +54 -0
  161. package/src/runtime-pi/webflo-fetch/headers.js +151 -0
  162. package/src/runtime-pi/webflo-fetch/index.js +5 -0
  163. package/src/runtime-pi/webflo-fetch/message.js +49 -0
  164. package/src/runtime-pi/webflo-fetch/request.js +62 -0
  165. package/src/runtime-pi/webflo-fetch/response.js +110 -0
  166. package/src/runtime-pi/webflo-fetch/util.js +28 -0
  167. package/src/runtime-pi/webflo-messaging/WQBroadcastChannel.js +10 -0
  168. package/src/runtime-pi/webflo-messaging/WQMessageChannel.js +26 -0
  169. package/src/runtime-pi/webflo-messaging/WQMessageEvent.js +87 -0
  170. package/src/runtime-pi/webflo-messaging/WQMessagePort.js +38 -0
  171. package/src/runtime-pi/webflo-messaging/WQRelayPort.js +47 -0
  172. package/src/runtime-pi/webflo-messaging/WQSockPort.js +113 -0
  173. package/src/runtime-pi/webflo-messaging/WQStarPort.js +104 -0
  174. package/src/runtime-pi/webflo-messaging/wq-message-port.js +404 -0
  175. package/src/runtime-pi/webflo-routing/HttpCookies.js +42 -0
  176. package/src/runtime-pi/webflo-routing/HttpEvent.js +112 -0
  177. package/src/runtime-pi/webflo-routing/HttpSession.js +11 -0
  178. package/src/runtime-pi/webflo-routing/HttpState.js +153 -0
  179. package/src/runtime-pi/webflo-routing/HttpUser.js +54 -0
  180. package/src/runtime-pi/webflo-routing/WebfloRouter.js +245 -0
  181. package/src/runtime-pi/webflo-server/ServerSideCookies.js +19 -0
  182. package/src/runtime-pi/webflo-server/ServerSideSession.js +38 -0
  183. package/src/runtime-pi/webflo-server/WebfloServer.js +937 -0
  184. package/src/runtime-pi/webflo-server/index.js +11 -0
  185. package/src/runtime-pi/webflo-server/messaging/Client.js +27 -0
  186. package/src/runtime-pi/webflo-server/messaging/ClientRequestRealtime.js +50 -0
  187. package/src/runtime-pi/webflo-server/messaging/Clients.js +25 -0
  188. package/src/runtime-pi/webflo-server/webflo-devmode.js +326 -0
  189. package/src/runtime-pi/{client → webflo-url}/Url.js +27 -76
  190. package/src/runtime-pi/webflo-url/index.js +1 -0
  191. package/src/runtime-pi/webflo-url/urlpattern.js +38 -0
  192. package/src/runtime-pi/{util-url.js → webflo-url/util.js} +5 -43
  193. package/src/runtime-pi/webflo-url/xURL.js +94 -0
  194. package/src/runtime-pi/webflo-worker/WebfloWorker.js +234 -0
  195. package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +19 -0
  196. package/src/runtime-pi/webflo-worker/WorkerSideWorkport.js +18 -0
  197. package/src/runtime-pi/webflo-worker/index.js +11 -0
  198. package/src/services-pi/index.js +2 -0
  199. package/src/services-pi/push/index.js +23 -0
  200. package/src/util.js +10 -0
  201. package/src/{webflo.js → webflo-cli.js} +4 -4
  202. package/src/runtime-pi/Application.js +0 -29
  203. package/src/runtime-pi/Cookies.js +0 -82
  204. package/src/runtime-pi/HttpEvent.js +0 -107
  205. package/src/runtime-pi/Router.js +0 -130
  206. package/src/runtime-pi/Runtime.js +0 -21
  207. package/src/runtime-pi/client/Application.js +0 -76
  208. package/src/runtime-pi/client/Context.js +0 -7
  209. package/src/runtime-pi/client/Router.js +0 -48
  210. package/src/runtime-pi/client/Runtime.js +0 -525
  211. package/src/runtime-pi/client/Workport.js +0 -190
  212. package/src/runtime-pi/client/createStorage.js +0 -58
  213. package/src/runtime-pi/client/generate.js +0 -481
  214. package/src/runtime-pi/client/index.js +0 -21
  215. package/src/runtime-pi/client/worker/Application.js +0 -44
  216. package/src/runtime-pi/client/worker/Context.js +0 -7
  217. package/src/runtime-pi/client/worker/Runtime.js +0 -275
  218. package/src/runtime-pi/client/worker/Workport.js +0 -78
  219. package/src/runtime-pi/client/worker/index.js +0 -21
  220. package/src/runtime-pi/server/Application.js +0 -101
  221. package/src/runtime-pi/server/Context.js +0 -16
  222. package/src/runtime-pi/server/Router.js +0 -159
  223. package/src/runtime-pi/server/Runtime.js +0 -558
  224. package/src/runtime-pi/server/index.js +0 -21
  225. package/src/runtime-pi/util-http.js +0 -86
  226. package/src/runtime-pi/xFormData.js +0 -24
  227. package/src/runtime-pi/xHeaders.js +0 -146
  228. package/src/runtime-pi/xRequest.js +0 -46
  229. package/src/runtime-pi/xRequestHeaders.js +0 -109
  230. package/src/runtime-pi/xResponse.js +0 -33
  231. package/src/runtime-pi/xResponseHeaders.js +0 -117
  232. package/src/runtime-pi/xURL.js +0 -105
  233. package/src/runtime-pi/xfetch.js +0 -23
  234. package/src/runtime-pi/xxHttpMessage.js +0 -102
  235. package/src/static-pi/index.js +0 -11
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "APP_TITLE",
3
+ "short_name": "APP_TITLE",
4
+ "description": "APP_DESCRIPTION",
5
+ "start_url": "/",
6
+ "display": "standalone",
7
+ "orientation": "portrait",
8
+ "background_color": "#4e40ce",
9
+ "theme_color": "#4e40ce",
10
+ "scope": "/",
11
+ "icons": [
12
+ {
13
+ "src": "/assets/...",
14
+ "sizes": "192x192",
15
+ "type": "image/png"
16
+ },
17
+ {
18
+ "src": "/assets/...",
19
+ "sizes": "512x512",
20
+ "type": "image/png",
21
+ "purpose": "maskable"
22
+ }
23
+ ],
24
+ "categories": [],
25
+ "related_applications": [],
26
+ "prefer_related_applications": false,
27
+ "lang": "en",
28
+ "dir": "ltr"
29
+ }
@@ -0,0 +1,8 @@
1
+ export default async function (event, next, fetch) {
2
+ if (next.stepname) return await next();
3
+ return {
4
+ title: 'Webflo Web',
5
+ greeting: 'Hello World!',
6
+ menu: [{ title: 'Home', href: '/' }],
7
+ };
8
+ }
@@ -0,0 +1,7 @@
1
+ <ul render="#items: (item) of data?.menu / 'menu'">
2
+ <template def="menu" scoped="">
3
+ <li>
4
+ <a render="~href: item?.href; #text: item?.title;"></a>
5
+ </li>
6
+ </template>
7
+ </ul>
@@ -0,0 +1,19 @@
1
+ {
2
+ "title": "",
3
+ "name": "",
4
+ "description": "",
5
+ "type": "module",
6
+ "scripts": {
7
+ "build:html": "oohtml bundle --recursive --outdir=public/assets --auto-embed=app",
8
+ "build:js": "webflo generate::client --recursive --outdir=public/assets --auto-embed",
9
+ "build": "npm run build:html && npm run build:js",
10
+ "dev": "webflo start --dev --build-sensitivity=2",
11
+ "start": "webflo start"
12
+ },
13
+ "dependencies": {
14
+ "@webqit/webflo": "file:../../webflo"
15
+ },
16
+ "devDependencies": {
17
+ "@webqit/oohtml-cli": "latest"
18
+ }
19
+ }
@@ -0,0 +1,16 @@
1
+ body {
2
+ background-color: #4e40ce;
3
+ margin: 0;
4
+ color: white;
5
+ }
6
+ h1 {
7
+ background-color: black;
8
+ padding: 2rem;
9
+ }
10
+ h1 span:first-of-type {
11
+ color: crimson;
12
+ }
13
+ ul {
14
+ padding: 2rem;
15
+ padding-inline: 3rem;
16
+ }
@@ -0,0 +1,39 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <title render="#text: data?.titleBar || data?.title">APP_TITLE</title>
8
+ <meta name="description" content="APP_DESCRIPTION">
9
+ <meta name="apple-mobile-web-app-title" content="APP_TITLE">
10
+ <meta name="color-scheme" content="dark">
11
+ <meta name="theme-color" content="#313131">
12
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
13
+ <meta name="apple-mobile-web-app-capable" content="yes">
14
+ <meta name="mobile-web-app-capable" content="yes">
15
+ <!--
16
+ <link rel="icon" href="/assets/..." type="image/png">
17
+ <link rel="apple-touch-icon" href="/assets/...">
18
+ <link rel="manifest" href="/manifest.json">
19
+ -->
20
+ <script crossorigin ssr src="https://unpkg.com/@webqit/oohtml@latest/dist/main.lite.js"></script>
21
+ <template def="app" ssr src="/assets/app.html" by="oohtml-cli"></template>
22
+ <script type="module" src="/assets/app.js" by="webflo"></script>
23
+ <link rel="stylesheet" href="/assets/app.css">
24
+ </head>
25
+
26
+ <body importscontext="/app">
27
+
28
+ <h1>
29
+ <span><?{ data.title }?></span><br>
30
+ <span><?{ data.greeting }?></span>
31
+ </h1>
32
+
33
+ <import ref="#page.html">
34
+ Import will show here...
35
+ </import>
36
+
37
+ </body>
38
+
39
+ </html>
@@ -0,0 +1,350 @@
1
+ import { Context } from '../Context.js';
2
+ import { WebfloRouter } from './webflo-routing/WebfloRouter.js';
3
+ import { _wq } from '../util.js';
4
+
5
+ export class WebfloRuntime {
6
+
7
+ #instanceController = new AbortController;
8
+ get $instanceController() { return this.#instanceController; }
9
+
10
+ static get Context() { return Context; }
11
+
12
+ static get Router() { return WebfloRouter; }
13
+
14
+ #cx;
15
+ get cx() { return this.#cx; }
16
+
17
+ #config;
18
+ get config() { return this.#config; }
19
+
20
+ #routes;
21
+ get routes() { return this.#routes; }
22
+
23
+ constructor(cx) {
24
+ if (!(cx instanceof this.constructor.Context)) {
25
+ throw new Error('Argument #1 must be a Webflo Context instance');
26
+ }
27
+ this.#cx = cx;
28
+ this.#config = this.#cx.config;
29
+ this.#routes = this.#cx.routes;
30
+ }
31
+
32
+ env(key) {
33
+ const { ENV } = this.config;
34
+ return key in ENV.mappings
35
+ ? ENV.data[ENV.mappings[key]]
36
+ : ENV.data[key];
37
+ }
38
+
39
+ async initialize() {
40
+ // Do init work
41
+ return this.#instanceController;
42
+ }
43
+
44
+ async setupCapabilities() {
45
+ // Do init work
46
+ return this.#instanceController;
47
+ }
48
+
49
+ async hydrate() {
50
+ // Do hydration work
51
+ return this.#instanceController;
52
+ }
53
+
54
+ control() {
55
+ // Do control work
56
+ return this.#instanceController;
57
+ }
58
+
59
+ createRequest(href, init = {}) {
60
+ return new Request(href, init);
61
+ }
62
+
63
+ createHttpCookies({ request, ...rest }) {
64
+ return this.constructor.HttpCookies.create({ request, ...rest });
65
+ }
66
+
67
+ createHttpSession({ store, request, ...rest }) {
68
+ return this.constructor.HttpSession.create({ store, request, ...rest });
69
+ }
70
+
71
+ createHttpUser({ store, request, session, realtime, ...rest }) {
72
+ return this.constructor.HttpUser.create({ store, request, session, realtime, ...rest });
73
+ }
74
+
75
+ createHttpEvent({ request, cookies, session, user, realtime, sdk, detail, signal, state, ...rest }) {
76
+ return this.constructor.HttpEvent.create(null, { request, cookies, session, user, realtime, sdk, detail, signal, state, ...rest });
77
+ }
78
+
79
+ async dispatchNavigationEvent({ httpEvent, crossLayerFetch, responseRealtime }) {
80
+ const { flags: FLAGS } = this.cx;
81
+ // Resolve rid before dispatching
82
+ if (httpEvent.request.method === 'GET' && httpEvent.url.query['_rid']) {
83
+ const requestMeta = _wq(httpEvent.request, 'meta');
84
+ requestMeta.set('redirectID', httpEvent.url.query['_rid']);
85
+ requestMeta.set('carries', [].concat(await httpEvent.session.get(`carry-store:${requestMeta.get('redirectID')}`) || []));
86
+ await httpEvent.session.delete(`carry-store:${requestMeta.get('redirectID')}`);
87
+ }
88
+ // Dispatch event
89
+ const router = new this.constructor.Router(this, httpEvent.url.pathname);
90
+ await router.route(['SETUP'], httpEvent);
91
+ // Do proper routing for respone
92
+ const response = await new Promise(async (resolve) => {
93
+ let autoLiveResponse, response;
94
+ httpEvent.realtime.wqLifecycle.messaging.then(() => {
95
+ autoLiveResponse = new LiveResponse(null, { status: 202, statusText: 'Accepted', done: false });
96
+ resolve(autoLiveResponse);
97
+ });
98
+ const route = async () => {
99
+ const routeMethods = [httpEvent.request.method, 'default'];
100
+ const remoteFetch = (...args) => this.remoteFetch(...args);
101
+ return await router.route(routeMethods, httpEvent, crossLayerFetch, remoteFetch);
102
+ };
103
+ const fullRoutingPipeline = (this.cx.middlewares || []).concat(route);
104
+ try {
105
+ response = await fullRoutingPipeline.reverse().reduce((next, fn) => {
106
+ return () => fn.call(this.cx, httpEvent, router, next);
107
+ }, null)()/*immediately calling the first*/;
108
+ } catch (e) {
109
+ console.error(e);
110
+ response = new Response(null, { status: 500, statusText: e.message });
111
+ }
112
+ if (!(response instanceof LiveResponse) && !(response instanceof Response)) {
113
+ response = LiveResponse.test(response) === 'Default'
114
+ ? Response.from(response)
115
+ : await LiveResponse.from(response, { responsesOK: true });
116
+ }
117
+ // Any "carry" data?
118
+ //await this.handleCarries(httpEvent, response);
119
+ // Resolve now...
120
+ if (autoLiveResponse) {
121
+ await autoLiveResponse.replaceWith(response, { done: true });
122
+ } else {
123
+ resolve(response);
124
+ }
125
+ });
126
+ // Commit data in the exact order. Reason: in how they depend on each other
127
+ for (const storage of [httpEvent.user, httpEvent.session, httpEvent.cookies]) {
128
+ await storage?.commit?.(response, FLAGS['dev']);
129
+ }
130
+ if (response instanceof LiveResponse && response.whileLive()) {
131
+ httpEvent.waitUntil(response.whileLive(true));
132
+ } else {
133
+ httpEvent.waitUntil(Promise.resolve());
134
+ await null; // We need the above resolved before we move on
135
+ }
136
+
137
+ // Send the X-Background-Messaging-Port header
138
+ // This server's event lifecycle management
139
+ if (!httpEvent.lifeCycleComplete()) {
140
+ if (this.isClientSide) {
141
+ const responseMeta = _wq(response, 'meta');
142
+ responseMeta.set('wqRealtime', responseRealtime);
143
+ } else {
144
+ const upstreamBackgroundMessagingPort = response.headers.get('X-Background-Messaging-Port');
145
+ response.headers.set('X-Background-Messaging-Port', responseRealtime);
146
+ }
147
+
148
+ // On navigation:
149
+ // Abort httpEvent.realtime and httpEvent itself
150
+ httpEvent.realtime.addEventListener('navigate', (e) => {
151
+ setTimeout(() => { // Allow for global handlers to see the events
152
+ if (e.defaultPrevented) {
153
+ console.log(`Client Messaging Port on ${httpEvent.request.url} not auto-closed on user navigation.`);
154
+ } else {
155
+ httpEvent.realtime.close();
156
+ httpEvent.abort();
157
+ }
158
+ }, 0);
159
+ });
160
+ // On close:
161
+ // Abort httpEvent itself
162
+ httpEvent.realtime.wqLifecycle.close.then(() => {
163
+ httpEvent.abort();
164
+ });
165
+
166
+ // On ROOT event complete:
167
+ // Close httpEvent.realtime
168
+ httpEvent.lifeCycleComplete(true).then(() => {
169
+ httpEvent.realtime.close();
170
+ });
171
+ }
172
+
173
+ if (!this.isClientSide && response instanceof LiveResponse) {
174
+ // Must convert to Response on the server-side before returning
175
+ return response.toResponse({ clientRequestRealtime: httpEvent.realtime });
176
+ }
177
+
178
+ return response;
179
+ }
180
+
181
+ async handleCarries(httpEvent, response) {
182
+ const requestMeta = _wq(httpEvent.request, 'meta');
183
+ const responseMeta = _wq(response, 'meta');
184
+ if (response.headers.get('Location')) {
185
+ // Don't emit the supposedly incoming "carries"
186
+ // Save back to URL
187
+ if (requestMeta.get('carries')?.length) {
188
+ await httpEvent.session.set(`carry-store:${requestMeta.get('redirectID')}`, requestMeta.get('carries'));
189
+ requestMeta.set('carries', []);
190
+ }
191
+ // Stash current byte of "carry"
192
+ if (responseMeta.has('carry')) {
193
+ const $url = new URL(response.headers.get('Location'), httpEvent.request.url);
194
+ if ($url.searchParams.has('_rid')) {
195
+ // If the URL already has a rid, append the new one
196
+ const existingRedirectID = $url.searchParams.get('_rid');
197
+ const existingData = await httpEvent.session.get(`carry-store:${existingRedirectID}`);
198
+ const combinedData = [].concat(responseMeta.get('carry'), existingData || []);
199
+ // Save the combined data back to the session
200
+ await httpEvent.session.set(`carry-store:${existingRedirectID}`, combinedData);
201
+ } else {
202
+ // If not, create a new rid
203
+ const redirectID = (0 | Math.random() * 9e6).toString(36);
204
+ $url.searchParams.set('_rid', redirectID);
205
+ await httpEvent.session.set(`carry-store:${redirectID}`, [].concat(responseMeta.get('carry')));
206
+ }
207
+ }
208
+ } else {
209
+ // Fire redirect message?
210
+ const flashResponses = requestMeta.get('carries')?.map((c) => c.response).filter((r) => r);
211
+ if (flashResponses?.length) {
212
+ httpEvent.waitUntil(new Promise((resolve) => {
213
+ httpEvent.realtime.wqLifecycle.open.then(() => {
214
+ httpEvent.realtime.postMessage(flashResponses, { wqEventOptions: { type: 'flash' } });
215
+ resolve();
216
+ }, { once: true });
217
+ }));
218
+ }
219
+ requestMeta.set('carries', []);
220
+ }
221
+ }
222
+
223
+ streamSlice(stream, { start, end }) {
224
+ let bytesRead = 0;
225
+ const reader = stream.getReader();
226
+ return new ReadableStream({
227
+ async pull(controller) {
228
+ while (true) {
229
+ const { done, value } = await reader.read();
230
+ if (done) {
231
+ controller.close();
232
+ break;
233
+ }
234
+ let chunk = value;
235
+ let chunkStart = bytesRead;
236
+ let chunkEnd = bytesRead + chunk.length;
237
+ if (chunkEnd <= start) {
238
+ // skip entire chunk
239
+ bytesRead += chunk.length;
240
+ continue;
241
+ }
242
+ if (chunkStart > end) {
243
+ // past requested range
244
+ controller.close();
245
+ break;
246
+ }
247
+ // slice relevant part
248
+ let sliceStart = Math.max(start - chunkStart, 0);
249
+ let sliceEnd = Math.min(end - chunkStart + 1, chunk.length);
250
+ controller.enqueue(chunk.subarray(sliceStart, sliceEnd));
251
+ bytesRead += chunk.length;
252
+ if (chunkEnd > end) {
253
+ controller.close();
254
+ break;
255
+ }
256
+ }
257
+ },
258
+ cancel(reason) {
259
+ reader.cancel(reason);
260
+ }
261
+ });
262
+ }
263
+
264
+ streamJoin(streams, contentType, totalLength) {
265
+ // Single stream?
266
+ if (streams.length === 1) {
267
+ return streams[0];
268
+ }
269
+ // Multipart!
270
+ const boundary = `WEBFLO_BOUNDARY_${Math.random().toString(36).slice(2)}`;
271
+ const encoder = new TextEncoder();
272
+ // Generator for multipart chunks
273
+ async function* generateMultipart() {
274
+ for (const { stream, start, end } of streams) {
275
+ // Boundary + headers for each part
276
+ yield encoder.encode(`--${boundary}\r\n`);
277
+ yield encoder.encode(
278
+ `Content-Type: ${contentType}\r\n` +
279
+ `Content-Range: bytes ${start}-${end}/${totalLength}\r\n\r\n`
280
+ );
281
+ // Stream the sliced body
282
+ const reader = stream.getReader();
283
+ while (true) {
284
+ const { done, value } = await reader.read();
285
+ if (done) break;
286
+ yield value;
287
+ }
288
+
289
+ yield encoder.encode('\r\n');
290
+ }
291
+ // Final boundary
292
+ yield encoder.encode(`--${boundary}--\r\n`);
293
+ }
294
+ // Create ReadableStream from async generator
295
+ return {
296
+ stream: new ReadableStream({
297
+ async pull(controller) {
298
+ const gen = generateMultipart();
299
+ while (true) {
300
+ const { done, value } = await gen.next();
301
+ if (done) {
302
+ controller.close();
303
+ break;
304
+ }
305
+ controller.enqueue(value);
306
+ }
307
+ },
308
+ cancel(reason) {
309
+ // Handle cancellation if needed
310
+ }
311
+ }),
312
+ boundary,
313
+ };
314
+ }
315
+
316
+ createStreamingResponse(httpEvent, readStream, stats) {
317
+ let response;
318
+ const requestRange = httpEvent.request.headers.get('Range', true); // Parses the Range header
319
+ if (requestRange.length) {
320
+ const streams = requestRange.reduce((streams, range) => {
321
+ if (!streams) return;
322
+ const [start, end] = range.render(stats.size); // Resolve offsets
323
+ const currentStart = (streams[streams.length - 1]?.end || -1) + 1;
324
+ if (!range.isValid(currentStart, stats.size)) return; // Only after rendering()
325
+ return streams.concat({ start, end, stream: readStream({ start, end }) });
326
+ }, []);
327
+ if (!streams) {
328
+ return new Response(null, {
329
+ status: 416, statusText: 'Requested Range Not Satisfiable', headers: {
330
+ 'Content-Range': `bytes */${stats.size}`,
331
+ }
332
+ });
333
+ }
334
+ const streamJoin = this.streamJoin(streams, stats.mime, stats.size);
335
+ response = new Response(streamJoin.stream, { status: 206, statusText: 'Partial Content' });
336
+ if (streamJoin.boundary) {
337
+ response.headers.set('Content-Type', `multipart/byteranges; boundary=${streamJoin.boundary}`);
338
+ } else {
339
+ response.headers.set('Content-Type', stats.mime);
340
+ response.headers.set('Content-Range', `bytes ${streamJoin.start}-${streamJoin.end}/${stats.size}`);
341
+ response.headers.set('Content-Length', streamJoin.end - streamJoin.start + 1);
342
+ }
343
+ } else {
344
+ response = new Response(readStream(), { status: 200, statusText: 'OK' });
345
+ response.headers.set('Content-Type', stats.mime);
346
+ response.headers.set('Content-Length', stats.size);
347
+ }
348
+ return response;
349
+ }
350
+ }
@@ -1,14 +1,7 @@
1
+ import * as server from './webflo-server/index.js';
2
+ import * as client from './webflo-client/webflo-codegen.js';
1
3
 
2
- /**
3
- * @imports
4
- */
5
- import * as server from './server/index.js';
6
- import * as client from './client/generate.js';
7
-
8
- /**
9
- * @exports
10
- */
11
4
  export {
12
5
  server,
13
- client,
6
+ client
14
7
  }
@@ -0,0 +1,17 @@
1
+ import { HttpCookies } from '../webflo-routing/HttpCookies.js';
2
+
3
+ export class ClientSideCookies extends HttpCookies {
4
+ static create({ request }) {
5
+ return new this({
6
+ request,
7
+ entries: document.cookie.split(';').map((c) => c.split('=').map((s) => s.trim()))
8
+ });
9
+ }
10
+
11
+ async commit(response) {
12
+ for (const cookieStr of await this.render()) {
13
+ document.cookie = cookieStr;
14
+ }
15
+ await super.commit();
16
+ }
17
+ }
@@ -0,0 +1,63 @@
1
+ export class ClientSideWorkport extends EventTarget {
2
+
3
+ #registration;
4
+ get registration() { return this.#registration; }
5
+
6
+ #ready;
7
+ get ready() { return this.#ready; }
8
+
9
+ #active;
10
+ get active() { return this.#active; }
11
+
12
+ static async initialize(parentNode, file, params = {}) {
13
+ const registration = (await navigator.serviceWorker.getRegistration())
14
+ || (await navigator.serviceWorker.register(file, { scope: '/', ...params }));
15
+ return new this(parentNode, registration, params);
16
+ }
17
+
18
+ #messageHandler;
19
+ constructor(parentNode, registration, params = {}) {
20
+ super(parentNode, params);
21
+ this.#registration = registration;
22
+ this.#ready = navigator.serviceWorker ? navigator.serviceWorker.ready : new Promise(() => {});
23
+ // Helper that updates instance's state
24
+ const stateChange = (target) => {
25
+ // target.state can be any of: "parsed", "installing", "installed", "activating", "activated", "redundant"
26
+ if (target.state === 'redundant') {
27
+ } else if (target.state === 'activated') {
28
+ const existing = this.#active;
29
+ this.#active = target;
30
+ if (!existing) {
31
+ this.dispatchEvent(new Event('open'));
32
+ }
33
+ }
34
+ }
35
+ // We're always installing at first for a new service worker.
36
+ // An existing service would immediately be active
37
+ const initial = this.#registration.active || this.#registration.waiting || this.#registration.installing;
38
+ if (initial) {
39
+ stateChange(initial);
40
+ initial.addEventListener('statechange', (e) => stateChange(e.target));
41
+ // "updatefound" event - a new worker that will control
42
+ // this page is installing somewhere
43
+ this.#registration.addEventListener('updatefound', () => {
44
+ // If updatefound is fired, it means that there's
45
+ // a new service worker being installed.
46
+ stateChange(this.#registration.installing);
47
+ this.#registration.installing.addEventListener('statechange', (e) => stateChange(e.target));
48
+ });
49
+ }
50
+ this.#messageHandler = (event) => {
51
+ this.dispatchEvent(event);
52
+ };
53
+ navigator.serviceWorker.addEventListener('message', this.#messageHandler);
54
+ }
55
+
56
+ postMessage(data, transferOrOptions = []) {
57
+ return this.#active?.postMessage(data, transferOrOptions);
58
+ }
59
+
60
+ close() {
61
+ navigator.serviceWorker.removeEventListener('message', this.#messageHandler);
62
+ }
63
+ }