@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,404 @@
1
+ import { _isObject, _isTypeObject } from '@webqit/util/js/index.js';
2
+ import { WQMessagePort, WQMessagePortInstanceTag } from './WQMessagePort.js';
3
+ import { isTypeStream } from '../webflo-fetch/util.js';
4
+ import { WQMessageEvent } from './WQMessageEvent.js';
5
+ import { Observer } from '@webqit/quantum-js';
6
+ import { _wq } from '../../util.js';
7
+
8
+ /**
9
+ * transferOrOptions has the following structure:
10
+ * {
11
+ * transfer: Array<Transferable>,
12
+ * wqEventOptions: {
13
+ * eventID: String, // Optional, this is the ID of the event
14
+ * type: String, // The type of the event, e.g. 'message', 'request', 'mutations'
15
+ * live: Boolean, // If true, the data is to be transmitted as a live object
16
+ * bubbles: Boolean, // If true, the message bubbles up through the event system
17
+ * forwarded: Boolean, // Added at this.dispatchEvent() when forwarding messages
18
+ * },
19
+ * wqProcessingOptions: { // Eventually added while processing
20
+ * except, // Addable by anyone but added at this.dispatchEvent() when forwarding messages
21
+ * observing, // Added at the outermost postMessage() call when actually publishingMutations
22
+ * },
23
+ * wqObserverOptions: { // Stripped at the outermost postMessage() call
24
+ * signal: AbortSignal, // Optional signal to abort the live object
25
+ * withArrayMethodDescriptors: Boolean, // If true, array method descriptors are included in mutations
26
+ * },
27
+ * ...restOptions // Any other options that should be passed to the postMessage method
28
+ * }
29
+ */
30
+ export function preProcessPostMessage(data, transferOrOptions) {
31
+ if (Array.isArray(transferOrOptions)) {
32
+ transferOrOptions = { transfer: transferOrOptions };
33
+ } else if (!transferOrOptions || typeof transferOrOptions !== 'object') {
34
+ throw new TypeError('transferOrOptions must be an array or an object');
35
+ }
36
+ let {
37
+ wqEventOptions = {}, // Remove and re-add after normalization
38
+ wqProcessingOptions = {}, // Remove and re-add after normalization
39
+ wqObserverOptions = {}, // Remove for use here
40
+ ...options
41
+ } = transferOrOptions;
42
+ if (!wqEventOptions.type) {
43
+ // Set wqEventOptions.type
44
+ wqEventOptions = { ...wqEventOptions, type: 'message' };
45
+ }
46
+ if (!wqEventOptions.eventID) {
47
+ // Set wqEventOptions.eventID
48
+ wqEventOptions = { ...wqEventOptions, eventID: `${wqEventOptions.type}-${(0 | Math.random() * 9e6).toString(36)}` };
49
+ }
50
+ if (!wqProcessingOptions.observing && !wqEventOptions.forwarded && _isTypeObject(data) && wqEventOptions.live && !wqEventOptions.type?.endsWith('.mutate')) {
51
+ wqProcessingOptions = { ...wqProcessingOptions, observing: true }; // Set wqProcessingOptions.observing
52
+ publishMutations.call(this, data, wqEventOptions.eventID, wqObserverOptions);
53
+ }
54
+ // Re-combine
55
+ return { ...options, wqEventOptions, wqProcessingOptions };
56
+ }
57
+
58
+ export function publishMutations(data, originalEventID, { signal, withArrayMethodDescriptors = true, honourDoneMutationFlags = false } = {}) {
59
+ if (isTypeStream(data) || !_isTypeObject(data)) {
60
+ throw new TypeError('data must be a plain object and not a stream');
61
+ }
62
+ if (typeof originalEventID !== 'string') {
63
+ throw new TypeError('originalEventID must be a non-empty string');
64
+ }
65
+ const meta = _wq(this, 'meta');
66
+ meta.set('mutationListeners', meta.get('mutationListeners') || new Set);
67
+ const mutationListeners = meta.get('mutationListeners');
68
+ const liveStreamController = Observer.observe(data, Observer.subtree(), (mutations) => {
69
+ // Ignore individual mutations made by array operations
70
+ if (withArrayMethodDescriptors && Array.isArray(mutations[0].target) && !mutations[0].argumentsList && !['set', 'defineProperty', 'deleteProperty'].includes(mutations[0].operation)) {
71
+ return;
72
+ }
73
+ // Push events. Exclude the reference to target
74
+ let mutationsDone;
75
+ this.postMessage(
76
+ mutations.map((m) => {
77
+ mutationsDone = honourDoneMutationFlags && !mutationsDone && m.detail?.done;
78
+ return { ...m, target: undefined };
79
+ }),
80
+ { wqEventOptions: { type: `${originalEventID}.mutate` } }
81
+ );
82
+ if (mutationsDone) {
83
+ liveStreamController.abort();
84
+ }
85
+ }, { signal, withArrayMethodDescriptors });
86
+ mutationListeners.add(liveStreamController);
87
+ return liveStreamController;
88
+ }
89
+
90
+ export function applyMutations(data, originalEventID, { signal, honourDoneMutationFlags = false } = {}) {
91
+ if (isTypeStream(data) || !_isTypeObject(data)) {
92
+ throw new TypeError('data must be a plain object and not a stream');
93
+ }
94
+ if (typeof originalEventID !== 'string') {
95
+ throw new TypeError('originalEventID must be a non-empty string');
96
+ }
97
+ const meta = _wq(this, 'meta');
98
+ meta.set('mutationListeners', meta.get('mutationListeners') || new Set);
99
+ const mutationListeners = meta.get('mutationListeners');
100
+ return new Promise((resolve) => {
101
+ const messageHandler = (e) => {
102
+ if (!e.data?.length) return;
103
+ let mutationsDone;
104
+ Observer.batch(data, () => {
105
+ for (const mutation of e.data) {
106
+ if (mutation.argumentsList) {
107
+ const target = !mutation.path.length ? data : Observer.get(data, Observer.path(...mutation.path));
108
+ Observer.proxy(target)[mutation.operation](...mutation.argumentsList);
109
+ } else if (mutation.key !== 'length' || ['set', 'defineProperty', 'deleteProperty'].includes(mutation.operation)) {
110
+ const target = mutation.path.length === 1 ? data : Observer.get(data, Observer.path(...mutation.path.slice(0, -1)));
111
+ if (mutation.type === 'delete') {
112
+ Observer.deleteProperty(target, mutation.key);
113
+ } else {
114
+ Observer.set(target, mutation.key, mutation.value);
115
+ }
116
+ }
117
+ mutationsDone = honourDoneMutationFlags && !mutationsDone && mutation.detail?.done;
118
+ }
119
+ });
120
+ if (mutationsDone) {
121
+ cleanup();
122
+ }
123
+ };
124
+ this.addEventListener(`${originalEventID}.mutate`, messageHandler, { signal });
125
+ const cleanup = () => {
126
+ this.removeEventListener(`${originalEventID}.mutate`, messageHandler);
127
+ resolve();
128
+ };
129
+ mutationListeners.add(cleanup);
130
+ });
131
+ }
132
+
133
+ export function forwardPort(eventTypes, eventTarget, { resolveData = null, bidirectional = false, namespace1 = null, namespace2 = null } = {}) {
134
+ if (!(this instanceof WQMessagePort) || !(eventTarget instanceof WQMessagePort)) {
135
+ throw new Error('Both ports must be instance of WQMessagePort.');
136
+ }
137
+ if (!eventTypes) {
138
+ throw new Error('Event types must be specified.');
139
+ }
140
+ const meta = _wq(this, 'meta');
141
+ meta.set('downstreamRegistry', meta.get('downstreamRegistry') || new Set);
142
+ const downstreamRegistry = meta.get('downstreamRegistry');
143
+ const registration = { eventTarget, eventTypes, options: { resolveData, namespace1, namespace2 } };
144
+ downstreamRegistry.add(registration);
145
+ let cleanup2;
146
+ if (bidirectional) {
147
+ cleanup2 = forwardPort.call(
148
+ eventTarget,
149
+ typeof eventTypes === 'function' ? eventTypes : [].concat(eventTypes).filter((s) => s !== 'close'),
150
+ this,
151
+ { resolveData, bidirectional: false, namespace1: namespace2, namespace2: namespace1 }
152
+ );
153
+ }
154
+ return () => {
155
+ downstreamRegistry.delete(registration);
156
+ cleanup2?.();
157
+ };
158
+ }
159
+
160
+ export function forwardEvent(event) {
161
+ if (event.propagationStopped) return;
162
+ const meta = _wq(this, 'meta');
163
+ if (meta.get('parentNode') instanceof EventTarget && (
164
+ event.bubbles || meta.get('parentNode').findPort?.((port) => port === this) && event instanceof WQMessageEvent)
165
+ ) {
166
+ meta.get('parentNode').dispatchEvent(event);
167
+ }
168
+ if (!meta.has('downstreamRegistry')) return;
169
+ const downstreamRegistry = meta.get('downstreamRegistry');
170
+ if (event instanceof WQMessageEvent || event.type === 'close' || event.type.endsWith(':close')) {
171
+ const { type, eventID, data, live, bubbles, ports } = event;
172
+ const called = new WeakSet;
173
+ for (const { eventTarget, eventTypes, options } of downstreamRegistry) {
174
+ if (called.has(eventTarget)) continue;
175
+ let matches, $type = type;
176
+ if (options.namespace1) {
177
+ [, $type] = (new RegExp(`^${options.namespace1.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}:([^:]+)$`)).exec(type) || [];
178
+ if (!$type) continue;
179
+ }
180
+ if (typeof eventTypes === 'function') {
181
+ matches = eventTypes($type, this, eventTarget, options);
182
+ } else {
183
+ matches = [].concat(eventTypes).find((t) => {
184
+ return t === $type || ($type !== 'close' && t === '*'); // Star shouldn't imply close
185
+ });
186
+ }
187
+ if (!matches) continue;
188
+ called.add(eventTarget);
189
+ if ($type === 'close') {
190
+ eventTarget.close?.();
191
+ } else {
192
+ eventTarget.postMessage(options.resolveData ? options.resolveData(data, this, eventTarget, options) : data, {
193
+ transfers: ports,
194
+ wqEventOptions: { type: options.namespace2 ? `${options.namespace2}:${$type}` : $type, eventID, bubbles, live, forwarded: true },
195
+ wqProcessingOptions: { except: this } // IMPORTANT, in BroadcastChannel scenarios
196
+ });
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ export function portHooksCleanup() {
203
+ const meta = _wq(this, 'meta');
204
+ // 1. Destry listenersRegistry
205
+ for (const args of meta.get('listenersRegistry') || []) {
206
+ this.removeEventListener(...args);
207
+ }
208
+ meta.get('listenersRegistry')?.clear();
209
+ // 2. Destroy downstreamRegistry
210
+ meta.get('downstreamRegistry')?.clear();
211
+ // 3. Destroy mutationListeners
212
+ for (const mutationListener of meta.get('mutationListeners') || []) {
213
+ if (typeof mutationListener === 'function') {
214
+ mutationListener();
215
+ } else if (mutationListener instanceof AbortController) {
216
+ mutationListener.abort();
217
+ }
218
+ }
219
+ meta.get('mutationListeners')?.clear();
220
+ }
221
+
222
+ export function toWQPort(port) {
223
+ if (WQMessagePortInstanceTag in port) {
224
+ return port;
225
+ }
226
+ const portMeta = _wq(port, 'meta');
227
+ const messageHandler = (e) => {
228
+ if (!_isObject(e.data) || !e.data['.wq']) return;
229
+ // Handle lifecycle events from the other end
230
+ if (!portMeta.get('open')) {
231
+ // On first message, whether just an "open" ping or not...
232
+ // Fire an "open" event on self
233
+ portMeta.set('open', true);
234
+ port.dispatchEvent(new Event('open'));
235
+ portMeta.get('onlineCallback')?.();
236
+ }
237
+ if (!portMeta.get('close') && e.data.ping === 'close') {
238
+ // On receiving a "close" ping
239
+ // Fire a "close" event on self
240
+ portClose.call(port);
241
+ }
242
+ // Stop here if just a ping event
243
+ if (['open', 'close'].includes(e.data.ping)) {
244
+ e.stopImmediatePropagation();
245
+ return;
246
+ }
247
+ // Do event rewrites and the Webflo live object magic
248
+ if (e.type === 'message' && 'data' in e.data && ['wqEventOptions', 'wqProcessingOptions'].every((k) => _isObject(e.data[k]))) {
249
+ e.stopImmediatePropagation();
250
+ const event = new WQMessageEvent(port, {
251
+ data: e.data.data,
252
+ wqEventOptions: e.data.wqEventOptions,
253
+ wqProcessingOptions: e.data.wqProcessingOptions,
254
+ ports: e.ports,
255
+ });
256
+ port.dispatchEvent(event);
257
+ forwardEvent.call(port, event);
258
+ return;
259
+ }
260
+ };
261
+ port.addEventListener('message', messageHandler);
262
+ portMeta.set('messageHandler', messageHandler);
263
+ // Only after the above native methods usages...
264
+ Object.defineProperty(port, 'wqLifecycle', {
265
+ value: {
266
+ open: new Promise((resolve) => {
267
+ if (portMeta.get('open')) return resolve();
268
+ portMeta.set('onlineCallback', resolve);
269
+ }),
270
+ close: new Promise((resolve) => {
271
+ if (portMeta.get('close')) return resolve();
272
+ portMeta.set('offlineCallback', resolve);
273
+ }),
274
+ messaging: new Promise((resolve) => {
275
+ if (portMeta.get('messaging')) return resolve();
276
+ portMeta.set('messagingCallback', resolve);
277
+ }),
278
+ }
279
+ });
280
+ Object.defineProperties(port, prototypeExtensions);
281
+ // Set the tag
282
+ port[WQMessagePortInstanceTag] = true;
283
+ return port;
284
+ }
285
+
286
+ export function internalAddEventListener(args) {
287
+ const meta = _wq(this, 'meta');
288
+ meta.set('listenersRegistry', meta.get('listenersRegistry') || new Set);
289
+ meta.get('listenersRegistry').add(args);
290
+ }
291
+
292
+ export function postRequest(data, callback, options = {}) {
293
+ const { eventOptions2 = {}, transfer = [], ...$options } = options;
294
+ const { signal, once } = eventOptions2;
295
+ const messageChannel = new MessageChannel;
296
+ messageChannel.port1.start();
297
+ messageChannel.port1.addEventListener('message', (e) => callback(e), { signal, once });
298
+ return this.postMessage(data, { ...$options, transfer: [messageChannel.port2].concat(transfer) });
299
+ }
300
+
301
+ export function handleRequests(type, listener, options = {}) {
302
+ const $listener = async (e) => {
303
+ const response = await listener(e);
304
+ for (const port of e.ports) {
305
+ port.postMessage(response);
306
+ }
307
+ };
308
+ this.addEventListener(type, $listener, options);
309
+ return () => {
310
+ this.removeEventListener(type, $listener, options);
311
+ };
312
+ }
313
+
314
+ export function portIsMessaging() {
315
+ const meta = _wq(this, 'meta');
316
+ if (!meta.get('messaging')) {
317
+ meta.set('messaging', true);
318
+ meta.get('messagingCallback')?.();
319
+ }
320
+ }
321
+
322
+ function autoPortOpen() {
323
+ const meta = _wq(this, 'meta');
324
+ if (!meta.get('open')) {
325
+ meta.set('open', true);
326
+ this.postMessage({
327
+ ['.wq']: true,
328
+ ping: 'open',
329
+ });
330
+ }
331
+ }
332
+
333
+ function portClose() {
334
+ // Unregister custom event rewrites
335
+ const meta = _wq(this, 'meta');
336
+ this.removeEventListener('message', meta.get('messageHandler'));
337
+ meta.set('close', true);
338
+ meta.get('offlineCallback')?.();
339
+ portHooksCleanup.call(this);
340
+ this.dispatchEvent(new Event('close'));
341
+ // Unset the tag
342
+ this[WQMessagePortInstanceTag] = false;
343
+ }
344
+
345
+ const prototypeOriginals = {
346
+ addEventListener: MessagePort.prototype.addEventListener,
347
+ postMessage: MessagePort.prototype.postMessage,
348
+ close: MessagePort.prototype.close,
349
+ onmessage: Object.getOwnPropertyDescriptor(MessagePort.prototype, 'onmessage'),
350
+ };
351
+
352
+ const prototypeExtensions = {
353
+ wqForwardPort: {
354
+ value: function (eventTypes, eventTarget, { resolveData = null, bidirectional = false, namespace1 = null, namespace2 = null } = {}) {
355
+ return forwardPort.call(this, eventTypes, eventTarget, { resolveData, bidirectional, namespace1, namespace2 });
356
+ }
357
+ },
358
+ // --------
359
+ addEventListener: {
360
+ value: function (...args) {
361
+ // On first interaction,
362
+ // ping the other end with "open"
363
+ autoPortOpen.call(this);
364
+ internalAddEventListener.call(this, args);
365
+ return prototypeOriginals.addEventListener.call(this, ...args);
366
+ },
367
+ },
368
+ onmessage: {
369
+ get: function () {
370
+ return prototypeOriginals.onmessage.get.call(this);
371
+ },
372
+ set: function (value) {
373
+ this.start();
374
+ autoPortOpen.call(this);
375
+ return prototypeOriginals.onmessage.set.call(this, value);
376
+ },
377
+ },
378
+ postMessage: {
379
+ value: function (data, transferOrOptions = {}) {
380
+ portIsMessaging.call(this);
381
+ const { wqEventOptions, wqProcessingOptions: _, ...portOptions } = preProcessPostMessage.call(this, data, transferOrOptions);
382
+ return prototypeOriginals.postMessage.call(this, {
383
+ data,
384
+ wqEventOptions,
385
+ wqProcessingOptions: {},
386
+ ['.wq']: true,
387
+ }, portOptions);
388
+ }
389
+ },
390
+ postRequest: { value: postRequest },
391
+ handleRequests: { value: handleRequests },
392
+ close: {
393
+ value: function () {
394
+ // On close, tear down and fire "close" event on self
395
+ // and ping the other end with "close"
396
+ portClose.call(this);
397
+ this.postMessage({
398
+ ['.wq']: true,
399
+ ping: 'close',
400
+ });
401
+ return prototypeOriginals.close.call(this);
402
+ }
403
+ },
404
+ };
@@ -0,0 +1,42 @@
1
+ import { _isObject } from '@webqit/util/js/index.js';
2
+ import { renderCookieObjToString } from '../webflo-fetch/cookies.js';
3
+ import { HttpState } from './HttpState.js';
4
+
5
+ export class HttpCookies extends HttpState {
6
+
7
+ #originals;
8
+
9
+ constructor({ request, entries = [] }) {
10
+ entries = [...entries].map(([key, value]) => [key, !_isObject(value) ? { name: key, value } : value]);
11
+ super({ store: new Map(entries), request, session: null });
12
+ this.#originals = new Map(entries);
13
+ }
14
+
15
+ async set(key, value) {
16
+ if (!_isObject(value)) { value = { name: key, value }; }
17
+ return await super.set(key, value);
18
+ }
19
+
20
+ async get(key, withDetail = false) {
21
+ if (!withDetail) return (await super.get(key))?.value;
22
+ return await super.get(key);
23
+ }
24
+
25
+ async render() {
26
+ const entries = await Promise.all((await this.keys()).concat(this.#originals.keys()).map(async (key) => {
27
+ const a = this.#originals.get(key);
28
+ const b = await this.get(key, true);
29
+ if (a === b || (_isObject(a) && _isObject(b) && _even(a, b))) {
30
+ // Same
31
+ return;
32
+ }
33
+ if ([undefined, null].includes(b)) {
34
+ // Deleted
35
+ return { name: key, value: '', maxAge: 0 };
36
+ }
37
+ // Added or modified
38
+ return { name: key, ...(await this.get(key, true)) };
39
+ })).then((entries) => entries.filter((e) => e));
40
+ return entries.map((e) => renderCookieObjToString(e));
41
+ }
42
+ }
@@ -0,0 +1,112 @@
1
+ import { _difference } from '@webqit/util/arr/index.js';
2
+ import { _isObject } from '@webqit/util/js/index.js';
3
+ import { xURL } from '../webflo-url/xURL.js';
4
+ import { _wq } from '../../util.js';
5
+
6
+ export class HttpEvent {
7
+
8
+ static create(parentEvent, init = {}) {
9
+ return new this(parentEvent, init);
10
+ }
11
+
12
+ #parentEvent;
13
+ #url;
14
+ #init;
15
+ #abortController = new AbortController;
16
+
17
+ constructor(parentEvent, { request, cookies, session, user, realtime, sdk, detail, signal, state, ...rest }) {
18
+ this.#parentEvent = parentEvent;
19
+ this.#init = { request, cookies, session, user, realtime, sdk, detail, signal, state, ...rest };
20
+ this.#url = new xURL(this.#init.request.url);
21
+ this.#parentEvent?.signal.addEventListener('abort', () => this.#abortController.abort(), { once: true });
22
+ this.#init.request.signal?.addEventListener('abort', () => this.#abortController.abort(), { once: true });
23
+ this.#lifeCycleResolutionPromise.finally(() => {
24
+ this.#abortController.abort();
25
+ });
26
+ }
27
+
28
+ get url() { return this.#url; }
29
+
30
+ get request() { return this.#init.request; }
31
+
32
+ get realtime() { return this.#init.realtime; }
33
+
34
+ get cookies() { return this.#init.cookies; }
35
+
36
+ get session() { return this.#init.session; }
37
+
38
+ get user() { return this.#init.user; }
39
+
40
+ get sdk() { return this.#init.sdk; }
41
+
42
+ get detail() { return this.#init.detail; }
43
+
44
+ get signal() { return this.#abortController.signal; }
45
+
46
+ get state() { return { ...(this.#init.state || {}) }; }
47
+
48
+ #lifecyclePromises = new Set;
49
+ #lifeCycleResolve;
50
+ #lifeCycleReject;
51
+ #lifeCycleResolutionPromise = new Promise((resolve, reject) => {
52
+ this.#lifeCycleResolve = resolve;
53
+ this.#lifeCycleReject = reject;
54
+ });
55
+
56
+ #extendLifecycle(promise) {
57
+ if (this.#lifecyclePromises.dirty && !this.#lifecyclePromises.size) {
58
+ throw new Error('Event lifecycle already complete.');
59
+ }
60
+ promise = Promise.resolve(promise);
61
+ this.#lifecyclePromises.add(promise);
62
+ this.#lifecyclePromises.dirty = true;
63
+ return promise.then((value) => {
64
+ this.#lifecyclePromises.delete(promise);
65
+ if (!this.#lifecyclePromises.size) {
66
+ this.#lifeCycleResolve(value);
67
+ }
68
+ }).catch(() => {
69
+ this.#lifecyclePromises.delete(promise);
70
+ if (!this.#lifecyclePromises.size) {
71
+ this.#lifeCycleReject();
72
+ }
73
+ });
74
+ }
75
+
76
+ lifeCycleComplete(returningThePromise = false) {
77
+ if (returningThePromise) {
78
+ return this.#lifeCycleResolutionPromise;
79
+ }
80
+ return this.#lifecyclePromises.dirty // IMPORTANT
81
+ && !this.#lifecyclePromises.size;
82
+ }
83
+
84
+ waitUntil(promise) {
85
+ return this.#extendLifecycle(promise);
86
+ }
87
+
88
+ waitUntilNavigate() {
89
+ return this.waitUntil(new Promise(() => { }));
90
+ }
91
+
92
+ #internalLiveResponse = new LiveResponse(null, { done: false });
93
+ get internalLiveResponse() { return this.#internalLiveResponse; }
94
+
95
+ async respondWith(data, ...args) {
96
+ await this.#internalLiveResponse.replaceWith(data, ...args);
97
+ }
98
+
99
+ clone(init = {}) {
100
+ return this.constructor.create(this.#parentEvent, { ...this.#init, ...init });
101
+ }
102
+
103
+ extend(init = {}) {
104
+ const instance = this.constructor.create(this/*Main difference from clone*/, { ...this.#init, ...init });
105
+ this.#extendLifecycle(instance.lifeCycleComplete(true));
106
+ return instance;
107
+ }
108
+
109
+ abort() {
110
+ this.#abortController.abort();
111
+ }
112
+ }
@@ -0,0 +1,11 @@
1
+ import { HttpState } from './HttpState.js';
2
+
3
+ export class HttpSession extends HttpState {
4
+ static create({ store, request }) {
5
+ return new this({
6
+ store,
7
+ request,
8
+ session: true
9
+ });
10
+ }
11
+ }