@webqit/webflo 0.11.61-0 → 0.20.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.
Files changed (274) hide show
  1. package/.github/FUNDING.yml +12 -0
  2. package/.github/workflows/publish.yml +48 -0
  3. package/.gitignore +9 -7
  4. package/LICENSE +21 -21
  5. package/README.md +100 -2074
  6. package/docker/Dockerfile +42 -42
  7. package/docker/README.md +91 -91
  8. package/docker/package.json +2 -2
  9. package/package.json +95 -81
  10. package/site/-/_.md +139 -0
  11. package/site/-/docs.old.md +2010 -0
  12. package/site/.vitepress/cache/deps/@braintree_sanitize-url 2.js +93 -0
  13. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
  14. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js 2.map +7 -0
  15. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
  16. package/site/.vitepress/cache/deps/_metadata 2.json +85 -0
  17. package/site/.vitepress/cache/deps/_metadata.json +85 -0
  18. package/site/.vitepress/cache/deps/chunk-BUSYA2B4 2.js +9 -0
  19. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
  20. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js 2.map +7 -0
  21. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
  22. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK 2.js +9719 -0
  23. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js +9719 -0
  24. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js 2.map +7 -0
  25. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js.map +7 -0
  26. package/site/.vitepress/cache/deps/chunk-QAXAIFA7 2.js +12705 -0
  27. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js +12705 -0
  28. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js 2.map +7 -0
  29. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js.map +7 -0
  30. package/site/.vitepress/cache/deps/cytoscape 2.js +30278 -0
  31. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent 2.js +4710 -0
  32. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
  33. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js 2.map +7 -0
  34. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
  35. package/site/.vitepress/cache/deps/cytoscape.js +30278 -0
  36. package/site/.vitepress/cache/deps/cytoscape.js 2.map +7 -0
  37. package/site/.vitepress/cache/deps/cytoscape.js.map +7 -0
  38. package/site/.vitepress/cache/deps/dayjs 2.js +285 -0
  39. package/site/.vitepress/cache/deps/dayjs.js +285 -0
  40. package/site/.vitepress/cache/deps/dayjs.js 2.map +7 -0
  41. package/site/.vitepress/cache/deps/dayjs.js.map +7 -0
  42. package/site/.vitepress/cache/deps/debug 2.js +453 -0
  43. package/site/.vitepress/cache/deps/debug.js +453 -0
  44. package/site/.vitepress/cache/deps/debug.js 2.map +7 -0
  45. package/site/.vitepress/cache/deps/debug.js.map +7 -0
  46. package/site/.vitepress/cache/deps/package 2.json +3 -0
  47. package/site/.vitepress/cache/deps/package.json +3 -0
  48. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api 2.js +4507 -0
  49. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
  50. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js 2.map +7 -0
  51. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  52. package/site/.vitepress/cache/deps/vitepress___@vueuse_core 2.js +584 -0
  53. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
  54. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js 2.map +7 -0
  55. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  56. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap 2.js +1166 -0
  57. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1166 -0
  58. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js 2.map +7 -0
  59. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  60. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js 2.js +1667 -0
  61. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
  62. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js 2.map +7 -0
  63. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  64. package/site/.vitepress/cache/deps/vitepress___minisearch 2.js +1815 -0
  65. package/site/.vitepress/cache/deps/vitepress___minisearch.js +1815 -0
  66. package/site/.vitepress/cache/deps/vitepress___minisearch.js 2.map +7 -0
  67. package/site/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  68. package/site/.vitepress/cache/deps/vue 2.js +344 -0
  69. package/site/.vitepress/cache/deps/vue.js +344 -0
  70. package/site/.vitepress/cache/deps/vue.js 2.map +7 -0
  71. package/site/.vitepress/cache/deps/vue.js.map +7 -0
  72. package/site/.vitepress/config.ts +147 -0
  73. package/site/.vitepress/theme/custom.css +50 -0
  74. package/site/.vitepress/theme/index.ts +6 -0
  75. package/site/api/webflo-fetch/FormData.md +0 -0
  76. package/site/api/webflo-fetch/Headers.md +0 -0
  77. package/site/api/webflo-fetch/LiveResponse.md +0 -0
  78. package/site/api/webflo-fetch/Request.md +0 -0
  79. package/site/api/webflo-fetch/Response.md +0 -0
  80. package/site/api/webflo-fetch/fetch.md +0 -0
  81. package/site/api/webflo-routing/HttpCookies.md +0 -0
  82. package/site/api/webflo-routing/HttpEvent/respondWith.md +1 -0
  83. package/site/api/webflo-routing/HttpEvent/waitUntil.md +1 -0
  84. package/site/api/webflo-routing/HttpEvent/waitUntilNavigate.md +1 -0
  85. package/site/api/webflo-routing/HttpEvent.md +30 -0
  86. package/site/api/webflo-routing/HttpSession.md +0 -0
  87. package/site/api/webflo-routing/HttpState.md +0 -0
  88. package/site/api/webflo-routing/HttpUser.md +0 -0
  89. package/site/api/webflo-routing/handler/fetch.md +42 -0
  90. package/site/api/webflo-routing/handler/next.md +54 -0
  91. package/site/api/webflo-routing/handler.md +119 -0
  92. package/site/api.md +26 -0
  93. package/site/contributing.md +16 -0
  94. package/site/docs/advanced/lifecycles.md +20 -0
  95. package/site/docs/advanced/redirects.md +0 -0
  96. package/site/docs/advanced/routing.md +1 -0
  97. package/site/docs/advanced.md +9 -0
  98. package/site/docs/concepts/realtime.md +637 -0
  99. package/site/docs/concepts/rendering.md +60 -0
  100. package/site/docs/concepts/request-response.md +47 -0
  101. package/site/docs/concepts/routing.md +656 -0
  102. package/site/docs/concepts/state.md +44 -0
  103. package/site/docs/concepts/templates.md +48 -0
  104. package/site/docs/concepts.md +97 -0
  105. package/site/docs/getting-started.md +378 -0
  106. package/site/docs/tech-stack.md +56 -0
  107. package/site/docs.md +100 -0
  108. package/site/examples/pwa.md +10 -0
  109. package/site/examples/web.md +11 -0
  110. package/site/examples.md +10 -0
  111. package/site/faq.md +13 -0
  112. package/site/guides/guide-auth.md +13 -0
  113. package/site/guides/guide-file-upload.md +11 -0
  114. package/site/guides/guide-service-worker.md +10 -0
  115. package/site/guides/tutorial-1-todo.md +24 -0
  116. package/site/guides.md +15 -0
  117. package/site/index.md +39 -0
  118. package/site/public/img/brand/logo-670x670.png +0 -0
  119. package/site/recipes/realtime.md +11 -0
  120. package/site/recipes/streaming.md +15 -0
  121. package/site/reference/cli.md +11 -0
  122. package/site/reference/config.md +13 -0
  123. package/site/reference/tools.md +9 -0
  124. package/src/Context.js +71 -79
  125. package/src/config-pi/deployment/Env.js +55 -68
  126. package/src/config-pi/deployment/Layout.js +71 -63
  127. package/src/config-pi/deployment/Origins.js +139 -139
  128. package/src/config-pi/deployment/Proxy.js +74 -74
  129. package/src/config-pi/deployment/index.js +17 -17
  130. package/src/config-pi/index.js +15 -15
  131. package/src/config-pi/runtime/Client.js +108 -98
  132. package/src/config-pi/runtime/Server.js +157 -125
  133. package/src/config-pi/runtime/client/Worker.js +111 -134
  134. package/src/config-pi/runtime/client/index.js +11 -11
  135. package/src/config-pi/runtime/index.js +17 -17
  136. package/src/config-pi/runtime/server/Headers.js +74 -74
  137. package/src/config-pi/runtime/server/Redirects.js +69 -69
  138. package/src/config-pi/runtime/server/index.js +13 -13
  139. package/src/config-pi/static/Init.js +57 -0
  140. package/src/config-pi/static/Manifest.js +319 -319
  141. package/src/config-pi/static/Ssg.js +49 -49
  142. package/src/config-pi/static/index.js +15 -13
  143. package/src/deployment-pi/index.js +10 -10
  144. package/src/deployment-pi/origins/index.js +216 -216
  145. package/src/deployment-pi/util.js +161 -0
  146. package/src/index.js +13 -19
  147. package/src/init-pi/index.js +117 -0
  148. package/src/init-pi/templates/pwa/app/handler.server.js +8 -0
  149. package/src/init-pi/templates/pwa/app/page.html +7 -0
  150. package/src/init-pi/templates/pwa/package.json +19 -0
  151. package/src/init-pi/templates/pwa/public/assets/app.css +16 -0
  152. package/src/init-pi/templates/pwa/public/index.html +39 -0
  153. package/src/init-pi/templates/pwa/public/manifest.json +29 -0
  154. package/src/init-pi/templates/web/app/handler.server.js +8 -0
  155. package/src/init-pi/templates/web/app/page.html +7 -0
  156. package/src/init-pi/templates/web/package.json +19 -0
  157. package/src/init-pi/templates/web/public/assets/app.css +16 -0
  158. package/src/init-pi/templates/web/public/index.html +39 -0
  159. package/src/runtime-pi/WebfloRuntime.js +350 -0
  160. package/src/runtime-pi/index.js +6 -13
  161. package/src/runtime-pi/webflo-client/ClientSideCookies.js +17 -0
  162. package/src/runtime-pi/webflo-client/ClientSideWorkport.js +63 -0
  163. package/src/runtime-pi/webflo-client/DeviceCapabilities.js +213 -0
  164. package/src/runtime-pi/webflo-client/WebfloClient.js +500 -0
  165. package/src/runtime-pi/webflo-client/WebfloRootClient1.js +206 -0
  166. package/src/runtime-pi/webflo-client/WebfloRootClient2.js +113 -0
  167. package/src/runtime-pi/webflo-client/WebfloSubClient.js +118 -0
  168. package/src/runtime-pi/webflo-client/index.js +17 -0
  169. package/src/runtime-pi/webflo-client/webflo-codegen.js +469 -0
  170. package/src/runtime-pi/webflo-client/webflo-devmode.js +243 -0
  171. package/src/runtime-pi/webflo-client/webflo-embedded.js +50 -0
  172. package/src/runtime-pi/webflo-fetch/LiveResponse.js +437 -0
  173. package/src/runtime-pi/webflo-fetch/cookies.js +10 -0
  174. package/src/runtime-pi/webflo-fetch/fetch.js +16 -0
  175. package/src/runtime-pi/webflo-fetch/formdata.js +54 -0
  176. package/src/runtime-pi/webflo-fetch/headers.js +151 -0
  177. package/src/runtime-pi/webflo-fetch/index.js +5 -0
  178. package/src/runtime-pi/webflo-fetch/message.js +49 -0
  179. package/src/runtime-pi/webflo-fetch/request.js +62 -0
  180. package/src/runtime-pi/webflo-fetch/response.js +110 -0
  181. package/src/runtime-pi/webflo-fetch/util.js +28 -0
  182. package/src/runtime-pi/webflo-messaging/WQBroadcastChannel.js +10 -0
  183. package/src/runtime-pi/webflo-messaging/WQMessageChannel.js +26 -0
  184. package/src/runtime-pi/webflo-messaging/WQMessageEvent.js +87 -0
  185. package/src/runtime-pi/webflo-messaging/WQMessagePort.js +38 -0
  186. package/src/runtime-pi/webflo-messaging/WQRelayPort.js +47 -0
  187. package/src/runtime-pi/webflo-messaging/WQSockPort.js +113 -0
  188. package/src/runtime-pi/webflo-messaging/WQStarPort.js +104 -0
  189. package/src/runtime-pi/webflo-messaging/wq-message-port.js +404 -0
  190. package/src/runtime-pi/webflo-routing/HttpCookies.js +42 -0
  191. package/src/runtime-pi/webflo-routing/HttpEvent.js +112 -0
  192. package/src/runtime-pi/webflo-routing/HttpSession.js +11 -0
  193. package/src/runtime-pi/webflo-routing/HttpState.js +153 -0
  194. package/src/runtime-pi/webflo-routing/HttpUser.js +54 -0
  195. package/src/runtime-pi/webflo-routing/WebfloRouter.js +245 -0
  196. package/src/runtime-pi/webflo-server/ServerSideCookies.js +19 -0
  197. package/src/runtime-pi/webflo-server/ServerSideSession.js +38 -0
  198. package/src/runtime-pi/webflo-server/WebfloServer.js +937 -0
  199. package/src/runtime-pi/webflo-server/index.js +11 -0
  200. package/src/runtime-pi/webflo-server/messaging/Client.js +27 -0
  201. package/src/runtime-pi/webflo-server/messaging/ClientRequestRealtime.js +50 -0
  202. package/src/runtime-pi/webflo-server/messaging/Clients.js +25 -0
  203. package/src/runtime-pi/webflo-server/webflo-devmode.js +326 -0
  204. package/src/runtime-pi/{client → webflo-url}/Url.js +155 -205
  205. package/src/runtime-pi/webflo-url/index.js +1 -0
  206. package/src/runtime-pi/webflo-url/urlpattern.js +38 -0
  207. package/src/runtime-pi/{util-url.js → webflo-url/util.js} +109 -147
  208. package/src/runtime-pi/webflo-url/xURL.js +94 -0
  209. package/src/runtime-pi/webflo-worker/WebfloWorker.js +234 -0
  210. package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +19 -0
  211. package/src/runtime-pi/webflo-worker/WorkerSideWorkport.js +18 -0
  212. package/src/runtime-pi/webflo-worker/index.js +11 -0
  213. package/src/services-pi/cert/http-auth-hook.js +22 -22
  214. package/src/services-pi/cert/http-cleanup-hook.js +22 -22
  215. package/src/services-pi/cert/index.js +79 -79
  216. package/src/services-pi/index.js +10 -8
  217. package/src/services-pi/push/index.js +23 -0
  218. package/src/util.js +10 -0
  219. package/src/{webflo.js → webflo-cli.js} +30 -30
  220. package/test/index.test.js +26 -26
  221. package/test/site/package.json +9 -9
  222. package/test/site/public/bundle.html +5 -5
  223. package/test/site/public/bundle.html.json +3 -3
  224. package/test/site/public/bundle.js +2 -2
  225. package/test/site/public/bundle.webflo.js +15 -15
  226. package/test/site/public/index.html +29 -29
  227. package/test/site/public/index1.html +34 -34
  228. package/test/site/public/page-2/bundle.html +4 -4
  229. package/test/site/public/page-2/bundle.js +2 -2
  230. package/test/site/public/page-2/index.html +45 -45
  231. package/test/site/public/page-2/main.html +2 -2
  232. package/test/site/public/page-4/subpage/bundle.js +2 -2
  233. package/test/site/public/page-4/subpage/index.html +30 -30
  234. package/test/site/public/sparoots.json +4 -4
  235. package/test/site/public/worker.js +3 -3
  236. package/test/site/server/index.js +15 -15
  237. package/src/runtime-pi/Application.js +0 -29
  238. package/src/runtime-pi/Cookies.js +0 -82
  239. package/src/runtime-pi/HttpEvent.js +0 -107
  240. package/src/runtime-pi/Router.js +0 -130
  241. package/src/runtime-pi/Runtime.js +0 -21
  242. package/src/runtime-pi/client/Application.js +0 -100
  243. package/src/runtime-pi/client/Context.js +0 -7
  244. package/src/runtime-pi/client/Router.js +0 -48
  245. package/src/runtime-pi/client/Runtime.js +0 -332
  246. package/src/runtime-pi/client/Workport.js +0 -178
  247. package/src/runtime-pi/client/createStorage.js +0 -57
  248. package/src/runtime-pi/client/generate.js +0 -472
  249. package/src/runtime-pi/client/index.js +0 -21
  250. package/src/runtime-pi/client/oohtml/full.js +0 -7
  251. package/src/runtime-pi/client/oohtml/namespacing.js +0 -7
  252. package/src/runtime-pi/client/oohtml/scripting.js +0 -8
  253. package/src/runtime-pi/client/oohtml/templating.js +0 -8
  254. package/src/runtime-pi/client/worker/Application.js +0 -44
  255. package/src/runtime-pi/client/worker/Context.js +0 -7
  256. package/src/runtime-pi/client/worker/Runtime.js +0 -269
  257. package/src/runtime-pi/client/worker/Workport.js +0 -86
  258. package/src/runtime-pi/client/worker/index.js +0 -21
  259. package/src/runtime-pi/server/Application.js +0 -116
  260. package/src/runtime-pi/server/Context.js +0 -16
  261. package/src/runtime-pi/server/Router.js +0 -159
  262. package/src/runtime-pi/server/Runtime.js +0 -557
  263. package/src/runtime-pi/server/index.js +0 -21
  264. package/src/runtime-pi/util-http.js +0 -86
  265. package/src/runtime-pi/xFormData.js +0 -24
  266. package/src/runtime-pi/xHeaders.js +0 -146
  267. package/src/runtime-pi/xRequest.js +0 -46
  268. package/src/runtime-pi/xRequestHeaders.js +0 -109
  269. package/src/runtime-pi/xResponse.js +0 -33
  270. package/src/runtime-pi/xResponseHeaders.js +0 -117
  271. package/src/runtime-pi/xURL.js +0 -105
  272. package/src/runtime-pi/xfetch.js +0 -23
  273. package/src/runtime-pi/xxHttpMessage.js +0 -102
  274. package/src/static-pi/index.js +0 -11
@@ -1,147 +1,109 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import { _isString, _isNumeric, _isArray, _isTypeObject } from '@webqit/util/js/index.js';
6
- if (typeof URLPattern === 'undefined') {
7
- await import('urlpattern-polyfill');
8
- }
9
-
10
- export const params = {
11
- // Parse a search params string into an object
12
- parse(str, delim = '&') {
13
- str = str || '';
14
- const target = {};
15
- (str.startsWith('?') ? str.substr(1) : str)
16
- .split(delim).filter(q => q).map(q => q.split('=').map(q => q.trim()))
17
- .forEach(q => this.set(target, q[0], decodeURIComponent(q[1])));
18
- return target;
19
- },
20
- // Stringify an object into a search params string
21
- stringify(targetObject, delim = '&') {
22
- const q = [];
23
- Object.keys(targetObject).forEach(key => {
24
- this.reduceValue(targetObject[key], key, (_value, _pathNotation, suggestedKeys = undefined) => {
25
- if (suggestedKeys) return suggestedKeys;
26
- q.push(`${_pathNotation}=${encodeURIComponent(_value)}`);
27
- });
28
- });
29
- return q.join(delim);
30
- },
31
-
32
- // Get value by path notation
33
- get(targetObject, pathNotation) {
34
- return this.reducePath(pathNotation, targetObject, (key, _targetObject) => {
35
- if (!_targetObject && _targetObject !== 0) return;
36
- return _targetObject[key];
37
- });
38
- },
39
- // Set value by path notation
40
- set(targetObject, pathNotation, value) {
41
- this.reducePath(pathNotation, targetObject, function(_key, _targetObject, suggestedBranch = undefined) {
42
- let _value = value;
43
- if (suggestedBranch) { _value = suggestedBranch; }
44
- if (_key === '' && _isArray(_targetObject)) {
45
- _targetObject.push(_value);
46
- } else {
47
- _targetObject[_key] = _value;
48
- }
49
- return _value;
50
- });
51
- },
52
-
53
- // Resolve a value to its leaf nodes
54
- reduceValue(value, contextPath, callback) {
55
- if (_isTypeObject(value)) {
56
- let suggestedKeys = Object.keys(value);
57
- let keys = callback(value, contextPath, suggestedKeys);
58
- if (_isArray(keys)) {
59
- return keys.forEach(key => {
60
- this.reduceValue(value[key], contextPath ? `${contextPath}[${key}]` : key, callback);
61
- });
62
- }
63
- }
64
- callback(value, contextPath);
65
- },
66
- // Resolve a path to its leaf index
67
- reducePath(pathNotation, contextObject, callback) {
68
- if (_isString(pathNotation) && pathNotation.endsWith(']') && _isTypeObject(contextObject)) {
69
- let [ key, ...rest ] = pathNotation.split('[');
70
- if (_isNumeric(key)) { key = parseInt(key); }
71
- rest = rest.join('[').replace(']', '');
72
- let branch;
73
- if (key in contextObject) {
74
- branch = contextObject[key];
75
- } else {
76
- let suggestedBranch = rest === '' || _isNumeric(rest.split('[')[0]) ? [] : {};
77
- branch = callback(key, contextObject, suggestedBranch);
78
- }
79
- return this.reducePath(rest, branch, callback);
80
- }
81
- if (_isNumeric(pathNotation)) { pathNotation = parseInt(pathNotation); }
82
- return callback(pathNotation, contextObject);
83
- },
84
- };
85
-
86
- export const path = {
87
- join(/* path segments */) {
88
- // Split the inputs into a list of path commands.
89
- var parts = [], backsteps = 0;
90
- for (var i = 0, l = arguments.length; i < l; i++) {
91
- parts = parts.concat(arguments[i].split("/"));
92
- }
93
- // Interpret the path commands to get the new resolved path.
94
- var newParts = [];
95
- for (i = 0, l = parts.length; i < l; i++) {
96
- var part = parts[i];
97
- // Remove leading and trailing slashes
98
- // Also remove "." segments
99
- if (!part || part === ".") continue;
100
- // Interpret ".." to pop the last segment
101
- if (part === "..") {
102
- if (!newParts.length) backsteps ++;
103
- else newParts.pop();
104
- }
105
- // Push new path segments.
106
- else newParts.push(part);
107
- }
108
- // Preserve the initial slash if there was one.
109
- if (parts[0] === "") newParts.unshift("");
110
- // Turn back into a single string path.
111
- return '../'.repeat(backsteps) + newParts.join("/") || (newParts.length ? "/" : ".");
112
- },
113
- // A simple function to get the dirname of a path
114
- // Trailing slashes are ignored. Leading slash is preserved.
115
- dirname(path) {
116
- return this.join(path, "..");
117
- }
118
- };
119
-
120
- export const pattern = (pattern, baseUrl = null) => ({
121
- pattern: new URLPattern(pattern, baseUrl),
122
- isPattern() {
123
- return Object.keys(this.pattern.keys || {}).some(compName => this.pattern.keys[compName].length);
124
- },
125
- test(...args) { return this.pattern.test(...args) },
126
- exec(...args) {
127
- let components = this.pattern.exec(...args);
128
- if (!components) return;
129
- components.vars = Object.keys(this.pattern.keys).reduce(({ named, unnamed }, compName) => {
130
- this.pattern.keys[compName].forEach(key => {
131
- let value = components[compName].groups[key.name];
132
- if (typeof key.name === 'number') {
133
- unnamed.push(value);
134
- } else {
135
- named[key.name] = value;
136
- }
137
- });
138
- return { named, unnamed };
139
- }, { named: {}, unnamed: [] });
140
- components.render = str => {
141
- return str.replace(/\$(\$|[0-9A-Z]+)/gi, (a, b) => {
142
- return b === '$' ? '$' : (_isNumeric(b) ? components.vars.unnamed[b - 1] : components.vars.named[b]) || '';
143
- });
144
- }
145
- return components;
146
- }
147
- });
1
+ import { _isString, _isNumeric, _isArray, _isTypeObject } from '@webqit/util/js/index.js';
2
+
3
+ export const DeepURLSearchParams = {
4
+ // Parse a search params string into an object
5
+ eval(targetObject, str, delim = '&') {
6
+ str = str || '';
7
+ (str.startsWith('?') ? str.substr(1) : str)
8
+ .split(delim).filter(q => q).map(q => q.split('=').map(q => q.trim()))
9
+ .forEach(q => this.set(targetObject, q[0], decodeURIComponent(q[1])));
10
+ return targetObject;
11
+ },
12
+ // Stringify an object into a search params string
13
+ stringify(targetObject, delim = '&') {
14
+ const q = [];
15
+ Object.keys(targetObject).forEach(key => {
16
+ this.reduceValue(targetObject[key], key, (_value, _pathNotation, suggestedKeys = undefined) => {
17
+ if (suggestedKeys) return suggestedKeys;
18
+ q.push(`${_pathNotation}=${encodeURIComponent(_value)}`);
19
+ });
20
+ });
21
+ return q.join(delim);
22
+ },
23
+ // Get value by path notation
24
+ get(targetObject, pathNotation) {
25
+ return this.reducePath(pathNotation, targetObject, (key, _targetObject) => {
26
+ if (!_targetObject && _targetObject !== 0) return;
27
+ return _targetObject[key];
28
+ });
29
+ },
30
+ // Set value by path notation
31
+ set(targetObject, pathNotation, value) {
32
+ this.reducePath(pathNotation, targetObject, function(_key, _targetObject, suggestedBranch = undefined) {
33
+ let _value = value;
34
+ if (suggestedBranch) { _value = suggestedBranch; }
35
+ if (_key === '' && _isArray(_targetObject)) {
36
+ _targetObject.push(_value);
37
+ } else {
38
+ _targetObject[_key] = _value;
39
+ }
40
+ return _value;
41
+ });
42
+ },
43
+
44
+ // Resolve a value to its leaf nodes
45
+ reduceValue(value, contextPath, callback) {
46
+ if (_isTypeObject(value)) {
47
+ let suggestedKeys = Object.keys(value);
48
+ let keys = callback(value, contextPath, suggestedKeys);
49
+ if (_isArray(keys)) {
50
+ return keys.forEach(key => {
51
+ this.reduceValue(value[key], contextPath ? `${contextPath}[${key}]` : key, callback);
52
+ });
53
+ }
54
+ }
55
+ callback(value, contextPath);
56
+ },
57
+ // Resolve a path to its leaf index
58
+ reducePath(pathNotation, contextObject, callback) {
59
+ if (_isString(pathNotation) && pathNotation.endsWith(']') && _isTypeObject(contextObject)) {
60
+ let [ key, ...rest ] = pathNotation.split('[');
61
+ if (_isNumeric(key)) { key = parseInt(key); }
62
+ rest = rest.join('[').replace(']', '');
63
+ let branch;
64
+ if (key in contextObject) {
65
+ branch = contextObject[key];
66
+ } else {
67
+ let suggestedBranch = rest === '' || _isNumeric(rest.split('[')[0]) ? [] : {};
68
+ branch = callback(key, contextObject, suggestedBranch);
69
+ }
70
+ return this.reducePath(rest, branch, callback);
71
+ }
72
+ if (_isNumeric(pathNotation)) { pathNotation = parseInt(pathNotation); }
73
+ return callback(pathNotation, contextObject);
74
+ },
75
+ };
76
+
77
+ export const path = {
78
+ join(/* path segments */) {
79
+ // Split the inputs into a list of path commands.
80
+ let parts = [], backsteps = 0;
81
+ for ( let i = 0, l = arguments.length; i < l; i++ ) {
82
+ parts = parts.concat( arguments[ i ].split( '/' ) );
83
+ }
84
+ // Interpret the path commands to get the new resolved path.
85
+ let newParts = [];
86
+ for ( let i = 0, l = parts.length; i < l; i++ ) {
87
+ let part = parts[ i ];
88
+ // Remove leading and trailing slashes
89
+ // Also remove "." segments
90
+ if ( !part || part === '.' ) continue;
91
+ // Interpret ".." to pop the last segment
92
+ if ( part === '..' ) {
93
+ if ( !newParts.length ) backsteps ++;
94
+ else newParts.pop();
95
+ }
96
+ // Push new path segments.
97
+ else newParts.push( part );
98
+ }
99
+ // Preserve the initial slash if there was one.
100
+ if ( parts[ 0 ] === '' ) newParts.unshift( '' );
101
+ // Turn back into a single string path.
102
+ return '../'.repeat( backsteps ) + newParts.join( '/' ) || ( newParts.length ? '/' : '.' );
103
+ },
104
+ // A simple function to get the dirname of a path
105
+ // Trailing slashes are ignored. Leading slash is preserved.
106
+ dirname( path ) {
107
+ return this.join( path, '..' );
108
+ }
109
+ };
@@ -0,0 +1,94 @@
1
+ import { _isObject } from '@webqit/util/js/index.js';
2
+ import { Observer } from '@webqit/quantum-js';
3
+ import { DeepURLSearchParams } from './util.js';
4
+
5
+ export class xURL extends URL {
6
+
7
+ // constructor
8
+ constructor(...args) {
9
+ super(...args);
10
+ const query = DeepURLSearchParams.eval({}, this.search);
11
+ const updateSearch = () => {
12
+ // "query" was updated. So we update "search"
13
+ let search = DeepURLSearchParams.stringify(query);
14
+ search = search ? '?' + search : '';
15
+ if (search !== this.search) {
16
+ this.search = search;
17
+ }
18
+ };
19
+ const $this = this;
20
+ this._query = new Proxy(query, {
21
+ set(t, k, v) {
22
+ t[k] = v;
23
+ if (!$this._updatingSearch) updateSearch();
24
+ return true;
25
+ },
26
+ deleteProperty(t, k) {
27
+ delete t[k];
28
+ if (!$this._updatingSearch) updateSearch();
29
+ return true;
30
+ }
31
+ });
32
+ }
33
+
34
+ // Set search
35
+ set search(value) {
36
+ super.search = value;
37
+ // "search" was updated. So we update "query"
38
+ this._updatingSearch = true;
39
+ const query = DeepURLSearchParams.eval({}, value);
40
+ const keys_a = Object.keys(query);
41
+ const keys_b = Object.keys(this._query);
42
+ for (const k of new Set([...keys_a,...keys_b])) {
43
+ if (!keys_a.includes(k)) delete this.query[k];
44
+ if (!keys_b.includes(k)) this.query[k] = query[k];
45
+ }
46
+ this._updatingSearch = false;
47
+ }
48
+
49
+ // Get search
50
+ get search() {
51
+ return super.search;
52
+ }
53
+
54
+ // Get query
55
+ get query() {
56
+ return this._query;
57
+ }
58
+
59
+ };
60
+
61
+ xURL.Observable = class extends xURL {
62
+
63
+ constructor() {
64
+ super(...arguments);
65
+ Observer.accessorize(this, [
66
+ 'protocol',
67
+ 'username',
68
+ 'password',
69
+ 'host',
70
+ 'hostname',
71
+ 'port',
72
+ 'origin',
73
+ 'pathname',
74
+ 'search',
75
+ 'query',
76
+ 'hash',
77
+ 'href',
78
+ ]);
79
+ }
80
+
81
+ };
82
+
83
+ const _strictEven = (a, b) => {
84
+ if (_isObject(a) && _isObject(b)) {
85
+ return _strictEven(Object.keys(a), Object.keys(b))
86
+ && _strictEven(Object.values(a), Object.values(b));
87
+ }
88
+ if (Array.isArray(a) && Array.isArray(b)) {
89
+ return a.length === b.length
90
+ && a.reduce((recieved, item, i) => recieved && item === b[i], true);
91
+ }
92
+ return a === b;
93
+ };
94
+
@@ -0,0 +1,234 @@
1
+ import { _any } from '@webqit/util/arr/index.js';
2
+ import { WebfloRuntime } from '../WebfloRuntime.js';
3
+ import { WQBroadcastChannel } from '../webflo-messaging/WQBroadcastChannel.js';
4
+ import { WorkerSideWorkport } from './WorkerSideWorkport.js';
5
+ import { WorkerSideCookies } from './WorkerSideCookies.js';
6
+ import { HttpSession } from '../webflo-routing/HttpSession.js';
7
+ import { HttpEvent } from '../webflo-routing/HttpEvent.js';
8
+ import { HttpUser } from '../webflo-routing/HttpUser.js';
9
+ import '../webflo-fetch/index.js';
10
+ import '../webflo-url/index.js';
11
+
12
+ export class WebfloWorker extends WebfloRuntime {
13
+
14
+ static get HttpEvent() { return HttpEvent; }
15
+
16
+ static get HttpCookies() { return WorkerSideCookies; }
17
+
18
+ static get HttpSession() { return HttpSession; }
19
+
20
+ static get HttpUser() { return HttpUser; }
21
+
22
+ static get Workport() { return WorkerSideWorkport; }
23
+
24
+ static create(cx) {
25
+ return new this(this.Context.create(cx));
26
+ }
27
+
28
+ #sdk = {};
29
+ get sdk() { return this.#sdk; }
30
+
31
+ async initialize() {
32
+ const instanceController = super.initialize();
33
+ // ONINSTALL
34
+ const installHandler = (event) => {
35
+ if (this.config.WORKER.skip_waiting) self.skipWaiting();
36
+ // Manage CACHE
37
+ if (this.config.WORKER.cache_name && (this.config.WORKER.cache_only_urls || []).length) {
38
+ // Add files to cache
39
+ event.waitUntil(self.caches.open(this.config.WORKER.cache_name).then(async cache => {
40
+ if (this.cx.logger) { this.cx.logger.log('[ServiceWorker] Pre-caching resources.'); }
41
+ for (const urls of ['cache_first_urls', 'cache_only_urls']) {
42
+ const _urls = (this.config.WORKER[urls] || []).map(c => c.trim()).filter(c => c && !(new URLPattern(c, self.origin)).isPattern());
43
+ await cache.addAll(_urls);
44
+ }
45
+ }));
46
+ }
47
+ };
48
+ // ONACTIVATE
49
+ const activateHandler = (event) => {
50
+ event.waitUntil(new Promise(async resolve => {
51
+ if (this.config.WORKER.skip_waiting) { await self.clients.claim(); }
52
+ // Manage CACHE
53
+ if (this.config.WORKER.cache_name) {
54
+ // Clear outdated CACHES
55
+ await self.caches.keys().then(keyList => {
56
+ return Promise.all(keyList.map(key => {
57
+ if (key !== this.config.WORKER.cache_name && key !== this.config.WORKER.cache_name + '_json') {
58
+ if (this.cx.logger) { this.cx.logger.log('[ServiceWorker] Removing old cache:', key); }
59
+ return self.caches.delete(key);
60
+ }
61
+ }));
62
+ })
63
+ }
64
+ resolve();
65
+ }));
66
+ };
67
+ self.addEventListener('install', installHandler, { signal: instanceController.signal });
68
+ self.addEventListener('activate', activateHandler, { signal: instanceController.signal });
69
+ this.control();
70
+ return instanceController;
71
+ }
72
+
73
+ control() {
74
+ const instanceController = super.control();
75
+ // ONFETCH
76
+ const fetchHandler = (event) => {
77
+ // Handle special requests
78
+ if (!event.request.url.startsWith('http') || event.request.mode === 'navigate') {
79
+ return event.respondWith(fetch(event.request));
80
+ }
81
+ // Handle external requests
82
+ if (!event.request.url.startsWith(self.origin)) {
83
+ return event.respondWith(this.remoteFetch(event.request));
84
+ }
85
+ event.respondWith((async (event) => {
86
+ const response = await this.navigate(event.request.url, event.request, { event });
87
+ return response;
88
+ })(event));
89
+ };
90
+ const webpushHandler = (event) => {
91
+ if (!(self.Notification && self.Notification.permission === 'granted')) return;
92
+ let data;
93
+ try {
94
+ data = event.data?.json() ?? {};
95
+ } catch(e) { return; }
96
+ const { type, title, ...params } = data;
97
+ if (type !== 'notification') return;
98
+ self.registration.showNotification(title, params);
99
+ };
100
+ self.addEventListener('fetch', fetchHandler, { signal: instanceController.signal });
101
+ self.addEventListener('push', webpushHandler, { signal: instanceController.signal });
102
+ return instanceController;
103
+ }
104
+
105
+ async navigate(url, init = {}, detail = {}) {
106
+ // Resolve inputs
107
+ const scopeObj = { url, init, detail };
108
+ if (typeof scopeObj.url === 'string') {
109
+ scopeObj.url = new URL(scopeObj.url, self.location.origin);
110
+ }
111
+ // Create and route request
112
+ scopeObj.request = this.createRequest(scopeObj.url, scopeObj.init);
113
+ scopeObj.cookies = this.createHttpCookies({
114
+ request: scopeObj.request
115
+ });
116
+ scopeObj.session = this.createHttpSession({
117
+ store: this.#sdk.storage?.('session'),
118
+ request: scopeObj.request
119
+ });
120
+ const requestID = crypto.randomUUID();
121
+ scopeObj.clientRequestRealtime = new WQBroadcastChannel(requestID);
122
+ scopeObj.user = this.createHttpUser({
123
+ store: this.#sdk.storage?.('user'),
124
+ request: scopeObj.request,
125
+ realtime: scopeObj.clientRequestRealtime,
126
+ session: scopeObj.session,
127
+ });
128
+ scopeObj.httpEvent = this.createHttpEvent({
129
+ request: scopeObj.request,
130
+ realtime: scopeObj.clientRequestRealtime,
131
+ cookies: scopeObj.cookies,
132
+ session: scopeObj.session,
133
+ user: scopeObj.user,
134
+ detail: scopeObj.detail,
135
+ sdk: {}
136
+ });
137
+ // Dispatch for response
138
+ scopeObj.response = await this.dispatchNavigationEvent({
139
+ httpEvent: scopeObj.httpEvent,
140
+ crossLayerFetch: async (event) => {
141
+ // Was this nexted()? Tell the next layer we're in JSON mode by default
142
+ if (event !== scopeObj.httpEvent && !event.request.headers.has('Accept')) {
143
+ event.request.headers.set('Accept', 'application/json');
144
+ }
145
+ return await this.remoteFetch(event.request);
146
+ },
147
+ responseRealtime: `br:${scopeObj.httpEvent.realtime.name}`
148
+ });
149
+ return scopeObj.response;
150
+ }
151
+
152
+ async remoteFetch(request, ...args) {
153
+ if (arguments.length > 1) {
154
+ request = this.createRequest(request, ...args);
155
+ }
156
+ const scopeObj = {};
157
+ const matchUrl = (patterns, url) => _any((patterns || []).map(p => p.trim()).filter(p => p), p => (new URLPattern(p, self.origin)).test(url));
158
+ if (matchUrl(this.config.WORKER.cache_only_urls, request.url)) {
159
+ scopeObj.strategy = 'cache-only';
160
+ scopeObj.response = this.cacheFetch(request, { networkFallback: false, cacheRefresh: false });
161
+ } else if (matchUrl(this.config.WORKER.network_only_urls, request.url)) {
162
+ scopeObj.strategy = 'network-only';
163
+ scopeObj.response = this.networkFetch(request, { cacheFallback: false, cacheRefresh: false });
164
+ } else if (matchUrl(this.config.WORKER.cache_first_urls, request.url)) {
165
+ scopeObj.strategy = 'cache-first';
166
+ scopeObj.response = this.cacheFetch(request, { networkFallback: true, cacheRefresh: true });
167
+ } else if (matchUrl(this.config.WORKER.network_first_urls, request.url) || !this.config.WORKER.default_fetching_strategy) {
168
+ scopeObj.strategy = 'network-first';
169
+ scopeObj.response = this.networkFetch(request, { cacheFallback: true, cacheRefresh: true });
170
+ } else {
171
+ scopeObj.strategy = this.config.WORKER.default_fetching_strategy;
172
+ switch (this.config.WORKER.default_fetching_strategy) {
173
+ case 'cache-only':
174
+ scopeObj.response = this.cacheFetch(request, { networkFallback: false, cacheRefresh: false });
175
+ break;
176
+ case 'network-only':
177
+ scopeObj.response = this.networkFetch(request, { cacheFallback: false, cacheRefresh: false });
178
+ break;
179
+ case 'cache-first':
180
+ scopeObj.response = this.cacheFetch(request, { networkFallback: true, cacheRefresh: true });
181
+ break;
182
+ case 'network-first':
183
+ scopeObj.response = this.networkFetch(request, { cacheFallback: true, cacheRefresh: true });
184
+ break;
185
+ }
186
+ }
187
+ return await scopeObj.response;
188
+ }
189
+
190
+ async networkFetch(request, params = {}) {
191
+ if (!params.cacheFallback) {
192
+ return fetch(request);
193
+ }
194
+ return fetch(request).then((response) => {
195
+ if (params.cacheRefresh) this.refreshCache(request, response);
196
+ return response;
197
+ }).catch((e) => this.getRequestCache(request).then(cache => {
198
+ return cache.match(request);
199
+ }));
200
+ }
201
+
202
+ async cacheFetch(request, params = {}) {
203
+ return this.getRequestCache(request).then(cache => cache.match(request).then((response) => {
204
+ // Nothing cache, use network
205
+ if (!response && params.networkFallback) return this.networkFetch(request, { ...params, cacheFallback: false });
206
+ // Note: fetch, but for refreshing purposes only... not the returned response
207
+ if (response && params.cacheRefresh) this.networkFetch(request, { ...params, justRefreshing: true });
208
+ return response;
209
+ }));
210
+ }
211
+
212
+ async refreshCache(request, response) {
213
+ // Check if we received a valid response
214
+ if (request.method !== 'GET' || !response || response.status !== 200 || (response.type !== 'basic' && response.type !== 'cors')) {
215
+ return response;
216
+ }
217
+ // IMPORTANT: Clone the response. A response is a stream
218
+ // and because we want the browser to consume the response
219
+ // as well as the cache consuming the response, we need
220
+ // to clone it so we have two streams.
221
+ var responseToCache = response.clone();
222
+ await this.getRequestCache(request).then(cache => {
223
+ cache.put(request, responseToCache);
224
+ });
225
+ return response;
226
+ }
227
+
228
+ async getRequestCache(request) {
229
+ const cacheName = request.headers.get('X-Powered-By') === '@webqit/webflo'
230
+ ? this.config.WORKER.cache_name + '_csr'
231
+ : this.config.WORKER.cache_name;
232
+ return self.caches.open(cacheName);
233
+ }
234
+ }
@@ -0,0 +1,19 @@
1
+ import { HttpCookies } from '../webflo-routing/HttpCookies.js';
2
+
3
+ export class WorkerSideCookies extends HttpCookies {
4
+ static create({ request }) {
5
+ return new this({
6
+ request,
7
+ entries: request.headers.get('Cookie', true).map((c) => [c.name, c])
8
+ });
9
+ }
10
+
11
+ async commit(response = null) {
12
+ if (response) {
13
+ for (const cookieStr of await this.render()) {
14
+ response.headers.append('Set-Cookie', cookieStr);
15
+ }
16
+ }
17
+ await super.commit();
18
+ }
19
+ }
@@ -0,0 +1,18 @@
1
+ export class WorkerSideWorkport {
2
+
3
+ showNotification(title, params = {}) {
4
+ return self.registration.showNotification(title, params);
5
+ }
6
+
7
+ handleNotificationClick(callback) {
8
+ const handler = (e) => e.waitUntil(callback(e));
9
+ self.addEventListener('notificationclick', handler);
10
+ return () => self.removeEventListener('notificationclick', handler);
11
+ }
12
+
13
+ handlePush(callback) {
14
+ const handler = (e) => e.waitUntil(callback(e));
15
+ self.addEventListener('push', handler);
16
+ return () => self.removeEventListener('notificationclick', handler);
17
+ }
18
+ }
@@ -0,0 +1,11 @@
1
+ import { WebfloWorker } from './WebfloWorker.js';
2
+
3
+ export async function start() {
4
+ const instance = WebfloWorker.create(this || {});
5
+ await instance.initialize();
6
+ return instance;
7
+ }
8
+
9
+ export {
10
+ WebfloWorker
11
+ }