@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
@@ -1,21 +1,13 @@
1
-
2
- /**
3
- * @imports
4
- */
5
1
  import { _isString, _isNumeric, _isArray, _isTypeObject } from '@webqit/util/js/index.js';
6
- if (typeof URLPattern === 'undefined') {
7
- await import('urlpattern-polyfill');
8
- }
9
2
 
10
- export const params = {
3
+ export const DeepURLSearchParams = {
11
4
  // Parse a search params string into an object
12
- parse(str, delim = '&') {
5
+ eval(targetObject, str, delim = '&') {
13
6
  str = str || '';
14
- const target = {};
15
7
  (str.startsWith('?') ? str.substr(1) : str)
16
8
  .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;
9
+ .forEach(q => this.set(targetObject, q[0], decodeURIComponent(q[1])));
10
+ return targetObject;
19
11
  },
20
12
  // Stringify an object into a search params string
21
13
  stringify(targetObject, delim = '&') {
@@ -28,7 +20,6 @@ export const params = {
28
20
  });
29
21
  return q.join(delim);
30
22
  },
31
-
32
23
  // Get value by path notation
33
24
  get(targetObject, pathNotation) {
34
25
  return this.reducePath(pathNotation, targetObject, (key, _targetObject) => {
@@ -115,33 +106,4 @@ export const path = {
115
106
  dirname( path ) {
116
107
  return this.join( path, '..' );
117
108
  }
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
- });
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
+ }
@@ -3,7 +3,9 @@
3
3
  * @imports
4
4
  */
5
5
  import * as cert from './cert/index.js';
6
+ import * as push from './push/index.js';
6
7
 
7
8
  export {
8
9
  cert,
10
+ push,
9
11
  }
@@ -0,0 +1,23 @@
1
+
2
+ /**
3
+ * imports
4
+ */
5
+ import webpush from 'web-push';
6
+
7
+ /**
8
+ * @description
9
+ */
10
+ export const desc = {
11
+ generate: 'Generate a set of VAPID keys for push notifications.',
12
+ };
13
+
14
+ /**
15
+ * Reads SSL from file.
16
+ *
17
+ * @return object
18
+ */
19
+ export async function generate() {
20
+ const cx = this || {};
21
+ const vapidKeys = webpush.generateVAPIDKeys();
22
+ cx.logger.log(vapidKeys);
23
+ }
package/src/util.js ADDED
@@ -0,0 +1,10 @@
1
+ import { _wq as __wq } from '@webqit/util/js/index.js';
2
+
3
+ export const _wq = (target, ...args) => __wq(target, 'webflo', ...args);
4
+
5
+ export const _await = (value, callback) => {
6
+ if (value instanceof Promise) {
7
+ return value.then(callback);
8
+ }
9
+ return callback(value);
10
+ };
@@ -10,15 +10,15 @@ import { Logger, Cli } from '@webqit/backpack';
10
10
  import * as WebfloPI from './index.js';
11
11
 
12
12
  const dirSelf = Path.dirname(Url.fileURLToPath(import.meta.url));
13
- const webfloJson = jsonFile.read(Path.join(dirSelf, '../package.json'));
14
- const appJson = jsonFile.read('./package.json');
13
+ const webfloMeta = jsonFile.read(Path.join(dirSelf, '../package.json'));
14
+ const appMeta = jsonFile.read('./package.json');
15
15
 
16
16
  /**
17
17
  * @cx
18
18
  */
19
19
  const cx = WebfloPI.Context.create({
20
- meta: { title: webfloJson.title, version: webfloJson.version },
21
- app: { title: appJson.title, version: appJson.version },
20
+ meta: { title: webfloMeta.title, version: webfloMeta.version },
21
+ appMeta: { ...appMeta },
22
22
  logger: Logger,
23
23
  config: WebfloPI.config,
24
24
  middlewares: [ WebfloPI.deployment.origins.webhook ],
@@ -1,29 +0,0 @@
1
-
2
- /**
3
- * ---------------------------
4
- * The base Application class
5
- * ---------------------------
6
- */
7
-
8
- export default class Application {
9
-
10
- constructor(cx) {
11
- this.cx = cx;
12
- }
13
-
14
- /**
15
- * Initializes application itself.
16
- *
17
- * @param HttpEvent httpEvent
18
- * @param Function remoteFetch
19
- *
20
- * @return Boolean|undefined
21
- */
22
- async init(httpEvent, remoteFetch) {
23
- // The app router
24
- const router = new this.Router(this.cx, '/');
25
- return router.route(['init'], httpEvent, {}, async event => {
26
- }, remoteFetch);
27
- }
28
-
29
- }
@@ -1,82 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import { _isString, _isObject } from "@webqit/util/js/index.js";
6
-
7
- export default class Cookies extends Map {
8
-
9
- constructor(...args) {
10
- super(...args);
11
- Object.defineProperty(this, 'inLock', { value: false, writable: true });
12
- Object.defineProperty(this, 'outLock', { value: false, writable: true });
13
- }
14
-
15
- set(name, value) {
16
- if (this.inLock) return;
17
- if (this.has(name)) this.delete(name);
18
- this.inLock = true;
19
- // -----------------
20
- let valueObj = value, valueStr = value, retrn;
21
- if (_isString(value)) { valueObj = this.parseEntry(`=${ value }`)[1]; }
22
- retrn = super.set(name, valueObj);
23
- if (!this.outLock) {
24
- if (_isObject(value)) { valueStr = this.stringifyEntry(value); }
25
- append(this.headers, `${ name }=${ valueStr }`);
26
- }
27
- // -----------------
28
- this.inLock = false;
29
- return retrn;
30
- }
31
-
32
- delete(name) {
33
- if (this.inLock) return;
34
- this.inLock = true;
35
- // -----------------
36
- let retrn = super.delete(name);
37
- this.headers.delete(this.headers.cookieHeaderName);
38
- for (let [ name, definition ] of this) {
39
- append(this.headers, `${ name }=${ this.stringifyEntry(definition) }`);
40
- }
41
- // -----------------
42
- this.inLock = false;
43
- return retrn;
44
- }
45
-
46
- clear() {
47
- if (this.inLock) return;
48
- this.inLock = true;
49
- // -----------------
50
- let retrn = super.clear();
51
- this.headers.delete(this.headers.cookieHeaderName);
52
- // -----------------
53
- this.inLock = false;
54
- return retrn;
55
- }
56
-
57
- json(json = {}) {
58
- if (arguments.length) {
59
- this.clear();
60
- for (let name in json) {
61
- this.set(name, json[name])
62
- }
63
- return;
64
- }
65
- for (let [ name, definition ] of this) {
66
- json[name] = definition;
67
- }
68
- return json;
69
- }
70
-
71
- toString() {
72
- return this.headers.get(this.headers.cookieHeaderName);
73
- }
74
-
75
- }
76
-
77
- function append(headers, value) {
78
- let values = [value];
79
- let currentValue = headers.get(headers.cookieHeaderName);
80
- if (currentValue) { values.unshift(currentValue); }
81
- headers.set(headers.cookieHeaderName, values.join(headers.cookieHeaderSeparator));
82
- }