@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,49 @@
1
+ import { _isTypeObject } from '@webqit/util/js/index.js';
2
+ import { createFormDataFromJson } from './formdata.js';
3
+ import { dataType } from './util.js';
4
+
5
+ export function renderHttpMessageInit(httpMessageInit) {
6
+ // JSONfy headers
7
+ const headers = (httpMessageInit.headers instanceof Headers) ? [...httpMessageInit.headers.entries()].reduce((_headers, [name, value]) => {
8
+ return { ..._headers, [name/* lower-cased */]: _headers[name] ? [].concat(_headers[name], value) : value };
9
+ }, {}) : Object.keys(httpMessageInit.headers || {}).reduce((_headers, name) => {
10
+ return { ..._headers, [name.toLowerCase()]: httpMessageInit.headers[name] };
11
+ }, {});
12
+ // Process body
13
+ let body = httpMessageInit.body, type = dataType(httpMessageInit.body);
14
+ if (['Blob', 'File'].includes(type)) {
15
+ !headers['content-type'] && (headers['content-type'] = body.type);
16
+ !headers['content-length'] && (headers['content-length'] = body.size);
17
+ } else if (['Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer'].includes(type)) {
18
+ !headers['content-length'] && (headers['content-length'] = body.byteLength);
19
+ } else if (type === 'json' && _isTypeObject(body)/*JSON object*/) {
20
+ if (!headers['content-type']) {
21
+ const [_body, isJsonfiable] = createFormDataFromJson(body, true/*jsonfy*/, true/*getIsJsonfiable*/);
22
+ if (isJsonfiable) {
23
+ body = JSON.stringify(body, (k, v) => v instanceof Error ? { ...v, message: v.message } : v);
24
+ headers['content-type'] = 'application/json';
25
+ headers['content-length'] = (new Blob([body])).size;
26
+ } else {
27
+ body = _body;
28
+ type = 'FormData';
29
+ }
30
+ }
31
+ } else if (type === 'json'/*JSON string*/ && !headers['content-length']) {
32
+ (headers['content-length'] = (body + '').length);
33
+ }
34
+ return { body, headers, $type: type };
35
+ }
36
+
37
+ export async function parseHttpMessage(httpMessage) {
38
+ let result;
39
+ const contentType = httpMessage.headers.get('Content-Type') || '';
40
+ if (contentType === 'application/x-www-form-urlencoded' || contentType.startsWith('multipart/form-data')) {
41
+ const formData = await httpMessage.formData();
42
+ result = await formData?.json();
43
+ } else if (contentType.startsWith('application/json')/*can include charset*/) {
44
+ result = await httpMessage.json();
45
+ } else /*if (contentType === 'text/plain')*/ {
46
+ result = httpMessage.body;
47
+ }
48
+ return result;
49
+ }
@@ -0,0 +1,62 @@
1
+ import { _wq } from '../../util.js';
2
+ import { renderHttpMessageInit } from './message.js';
3
+
4
+ const prototypeOriginals = { clone: Request.prototype.clone };
5
+ const prototypeExtensions = {
6
+ carries: { get: function () { return new Set(_wq(this, 'meta').get('carries') || []); } },
7
+ clone: {
8
+ value: function (init = {}) {
9
+ const clone = prototypeOriginals.clone.call(this, init);
10
+ const requestMeta = _wq(this, 'meta');
11
+ _wq(clone).set('meta', requestMeta);
12
+ return clone;
13
+ }
14
+ },
15
+ parse: { value: function () { return parseHttpMessage(this); } },
16
+ };
17
+
18
+ const staticExtensions = {
19
+ from: {
20
+ value: function (url, init = {}) {
21
+ if (url instanceof Request) return url;
22
+ let $$type, $$body = init.body;
23
+ if ('body' in init) {
24
+ const { body, headers, $type } = renderHttpMessageInit(init);
25
+ init = { ...init, body, headers };
26
+ $$type = $type;
27
+ }
28
+ const instance = new Request(url, init);
29
+ const responseMeta = _wq(instance, 'meta');
30
+ responseMeta.set('body', $$body);
31
+ responseMeta.set('type', $$type);
32
+ return instance;
33
+ }
34
+ },
35
+ copy: {
36
+ value: async function (request, init = {}) {
37
+ const requestInit = [
38
+ 'method', 'headers', 'mode', 'credentials', 'cache', 'redirect', 'referrer', 'integrity',
39
+ ].reduce(($init, prop) => (
40
+ { ...$init, [prop]: prop in init ? init[prop] : (prop === 'headers' ? new Headers(request[prop]) : request[prop]) }
41
+ ), {});
42
+ if (!['GET', 'HEAD'].includes(init.method?.toUpperCase() || request.method)) {
43
+ if ('body' in init) {
44
+ requestInit.body = init.body
45
+ if (!('headers' in init)) {
46
+ requestInit.headers.delete('Content-Type');
47
+ requestInit.headers.delete('Content-Length');
48
+ }
49
+ } else {
50
+ requestInit.body = await request.clone().arrayBuffer();
51
+ }
52
+ }
53
+ if (requestInit.mode === 'navigate') {
54
+ requestInit.mode = 'cors';
55
+ }
56
+ return { url: request.url, ...requestInit };
57
+ }
58
+ }
59
+ };
60
+
61
+ Object.defineProperties(Request.prototype, prototypeExtensions);
62
+ Object.defineProperties(Request, staticExtensions);
@@ -0,0 +1,110 @@
1
+
2
+ import { _isObject } from '@webqit/util/js/index.js';
3
+ import { parseHttpMessage, renderHttpMessageInit } from './message.js';
4
+ import { WQBroadcastChannel } from '../webflo-messaging/WQBroadcastChannel.js';
5
+ import { WQSockPort } from '../webflo-messaging/WQSockPort.js';
6
+ import { _wq } from '../../util.js';
7
+
8
+ export function responseRealtimeConnect(url) {
9
+ const [proto, portID] = url.split(':');
10
+ if (proto === 'br') {
11
+ return new WQBroadcastChannel(portID);
12
+ }
13
+ if (proto !== 'ws') {
14
+ throw new Error(`Unknown background messaging protocol: ${proto}`);
15
+ }
16
+ return new WQSockPort(portID);
17
+ }
18
+
19
+ export function responseRealtime() {
20
+ const responseMeta = _wq(this, 'meta');
21
+ if (!responseMeta.has('wqRealtime')) {
22
+ const value = this.headers.get('X-Background-Messaging-Port')?.trim();
23
+ if (value) {
24
+ responseMeta.set('wqRealtime', responseRealtimeConnect(value));
25
+ }
26
+ }
27
+ return responseMeta.get('wqRealtime');
28
+ }
29
+
30
+ const staticOriginals = { json: Response.json };
31
+ const staticExtensions = {
32
+ from: {
33
+ value: function (body, init = {}) {
34
+ if (body instanceof Response) return body;
35
+ let $type, $body = body;
36
+ if (body || body === 0) {
37
+ let headers;
38
+ ({ body, headers, $type } = renderHttpMessageInit({ body, headers: init.headers }));
39
+ init = { ...init, headers };
40
+ }
41
+ const instance = new Response(body, init);
42
+ const responseMeta = _wq(instance, 'meta');
43
+ responseMeta.set('body', $body);
44
+ responseMeta.set('type', $type);
45
+ return instance;
46
+ }
47
+ },
48
+ json: {
49
+ value: function (data, options = {}) {
50
+ const instance = staticOriginals.json(data, options);
51
+ const responseMeta = _wq(instance, 'meta');
52
+ responseMeta.set('body', data);
53
+ responseMeta.set('type', 'json');
54
+ return instance;
55
+ }
56
+ },
57
+ redirectWith: {
58
+ value: function (url, { status = 302, request = null, response = null }) {
59
+ if (typeof status !== 'string') {
60
+ throw new Error('Redirect code must be an object!');
61
+ }
62
+ if (request && !_isObject(request) || response && !_isObject(response)) {
63
+ throw new Error('Carries (redirect requests and responses) must be an object!');
64
+ }
65
+ const responseInstance = this.redirect(url, status);
66
+ if (request || response) {
67
+ const responseMeta = _wq(responseInstance, 'meta');
68
+ responseMeta.set('carry', { request, response });
69
+ }
70
+ return responseInstance;
71
+ }
72
+ }
73
+ };
74
+
75
+ const prototypeOriginals = {
76
+ clone: Response.prototype.clone,
77
+ status: Object.getOwnPropertyDescriptor(Response.prototype, 'status'),
78
+ };
79
+ const prototypeExtensions = {
80
+ status: { get: function () { return _wq(this, 'meta').get('status') || prototypeOriginals.status.get.call(this); } },
81
+ carry: { get: function () { return _wq(this, 'meta').get('carry'); } },
82
+ clone: {
83
+ value: function (init = {}) {
84
+ const clone = prototypeOriginals.clone.call(this, init);
85
+ const responseMeta = _wq(this, 'meta');
86
+ _wq(clone).set('meta', responseMeta);
87
+ return clone;
88
+ }
89
+ },
90
+ isLive: {
91
+ value: function () {
92
+ let liveLevel = (this.headers.get('X-Background-Messaging-Port')?.trim() || _wq(this, 'meta').has('wqRealtime')) && 1 || 0;
93
+ liveLevel += this.headers.get('X-Live-Response-Message-ID')?.trim() && 1 || 0;
94
+ return liveLevel;
95
+ }
96
+ },
97
+ wqRealtime: {
98
+ get: function () {
99
+ return responseRealtime.call(this);
100
+ }
101
+ },
102
+ parse: {
103
+ value: async function () {
104
+ return await parseHttpMessage(this);
105
+ }
106
+ }
107
+ };
108
+
109
+ Object.defineProperties(Response.prototype, prototypeExtensions);
110
+ Object.defineProperties(Response, staticExtensions);
@@ -0,0 +1,28 @@
1
+ import { _isString, _isObject, _isPlainObject, _isPlainArray, _isTypeObject, _isNumber, _isBoolean } from '@webqit/util/js/index.js';
2
+
3
+ export function isTypeStream(obj) {
4
+ return obj instanceof ReadableStream || isTypeReadable(obj);
5
+ }
6
+
7
+ export function isTypeReadable(obj) {
8
+ return (
9
+ obj !== null &&
10
+ typeof obj === 'object' &&
11
+ typeof obj.read === 'function' && // streams have .read()
12
+ typeof obj.pipe === 'function' && // streams have .pipe()
13
+ typeof obj.on === 'function' // streams have event listeners
14
+ );
15
+ }
16
+
17
+ export function dataType(value) {
18
+ if (_isString(value) || _isNumber(value) || _isBoolean(value)) return 'json';
19
+ if (!_isTypeObject(value)) return;
20
+ const toStringTag = value[Symbol.toStringTag];
21
+ const type = [
22
+ 'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer', 'Blob', 'File', 'FormData', 'Stream', 'ReadableStream'
23
+ ].reduce((_toStringTag, type) => _toStringTag || (toStringTag === type ? type : null), null);
24
+ if (type) return type;
25
+ if ((_isObject(value) && _isPlainObject(value)) || (Array.isArray(value) && _isPlainArray(value)) || 'toString' in value) {
26
+ return 'json';
27
+ }
28
+ }
@@ -0,0 +1,10 @@
1
+ import { toWQPort} from './wq-message-port.js';
2
+
3
+ export class WQBroadcastChannel extends BroadcastChannel {
4
+ constructor(channelName) {
5
+ super(channelName);
6
+ toWQPort(this);
7
+ }
8
+ }
9
+
10
+ globalThis.WQBroadcastChannel = WQBroadcastChannel;
@@ -0,0 +1,26 @@
1
+ import { toWQPort } from './wq-message-port.js';
2
+
3
+ export class WQMessageChannel extends MessageChannel {
4
+
5
+ #port1;
6
+ get port1() {
7
+ if (!this.#port1) {
8
+ this.#port1 = super.port1;
9
+ this.#port1.start();
10
+ toWQPort(this.#port1);
11
+ }
12
+ return this.#port1;
13
+ }
14
+
15
+ #port2;
16
+ get port2() {
17
+ if (!this.#port2) {
18
+ this.#port2 = super.port2;
19
+ this.#port2.start();
20
+ toWQPort(this.#port2);
21
+ }
22
+ return this.#port2;
23
+ }
24
+ }
25
+
26
+ globalThis.WQMessageChannel = WQMessageChannel;
@@ -0,0 +1,87 @@
1
+ import { _isTypeObject } from '@webqit/util/js/index.js';
2
+ import { toWQPort, applyMutations } from './wq-message-port.js';
3
+ import { _wq } from '../../util.js';
4
+
5
+ export class WQMessageEvent extends Event {
6
+
7
+ #originalTarget;
8
+ get originalTarget() { return this.#originalTarget; }
9
+
10
+ #eventID;
11
+ get eventID() { return this.#eventID; }
12
+
13
+ #data;
14
+ get data() { return this.#data; }
15
+
16
+ #live;
17
+ get live() { return this.#live; }
18
+
19
+ #bubbles;
20
+ get bubbles() { return this.#bubbles; }
21
+
22
+ #forwarded;
23
+ get forwarded() { return this.#forwarded; }
24
+
25
+ #ports = [];
26
+ get ports() { return this.#ports; }
27
+
28
+ constructor(originalTarget, {
29
+ data = null,
30
+ wqEventOptions: { eventID, type = 'message', live = false, bubbles = false, forwarded = false } = {},
31
+ wqProcessingOptions: {} = {},
32
+ ports = []
33
+ } = {}) {
34
+ if (typeof eventID !== 'string') {
35
+ throw new TypeError('eventID must be a non-empty string');
36
+ }
37
+ if (type && typeof type !== 'string') {
38
+ throw new TypeError('Where specified, wqEventOptions.type must be a string');
39
+ }
40
+ super(type);
41
+ this.#originalTarget = originalTarget;
42
+ this.#eventID = eventID;
43
+ this.#data = data;
44
+ this.#live = live;
45
+ this.#bubbles = bubbles;
46
+ this.#forwarded = forwarded;
47
+ this.#ports = ports.map(toWQPort);
48
+ if (_isTypeObject(this.#data) && this.#live) {
49
+ // If the data is a live object, we can apply mutations to it
50
+ applyMutations.call(originalTarget, this.#data, this.#eventID);
51
+ }
52
+ }
53
+
54
+ #immediatePropagationStopped = false;
55
+ get immediatePropagationStopped() { return this.#immediatePropagationStopped; }
56
+
57
+ stopImmediatePropagation() {
58
+ this.#immediatePropagationStopped = true;
59
+ this.#propagationStopped = true;
60
+ super.stopImmediatePropagation();
61
+ }
62
+
63
+ #propagationStopped = false;
64
+ get propagationStopped() { return this.#propagationStopped; }
65
+
66
+ stopPropagation() {
67
+ this.#propagationStopped = true;
68
+ super.stopPropagation();
69
+ }
70
+
71
+ #defaultPrevented = false;
72
+ get defaultPrevented() { return this.#defaultPrevented; }
73
+
74
+ preventDefault() {
75
+ this.#defaultPrevented = true;
76
+ super.preventDefault();
77
+ }
78
+
79
+ wqRespondWith(data, transferOrOptions = []) {
80
+ for (const port of this.#ports) {
81
+ port.postMessage(data, transferOrOptions);
82
+ }
83
+ return !!this.#ports.length;
84
+ }
85
+ }
86
+
87
+ globalThis.WQMessageEvent = WQMessageEvent;
@@ -0,0 +1,38 @@
1
+ import { internalAddEventListener, postRequest, handleRequests, forwardPort, forwardEvent } from './wq-message-port.js';
2
+ import { _wq } from '../../util.js';
3
+
4
+ export const WQMessagePortInstanceTag = Symbol('WQMessagePortInstanceTag');
5
+
6
+ export class WQMessagePort extends EventTarget {
7
+
8
+ [WQMessagePortInstanceTag] = true;
9
+
10
+ static [Symbol.hasInstance](instance) {
11
+ return !!instance?.[WQMessagePortInstanceTag];
12
+ }
13
+
14
+ addEventListener(...args) {
15
+ internalAddEventListener.call(this, args);
16
+ return super.addEventListener(...args);
17
+ }
18
+
19
+ dispatchEvent(event) {
20
+ const returnValue = super.dispatchEvent(event);
21
+ forwardEvent.call(this, event);
22
+ return returnValue;
23
+ }
24
+
25
+ postRequest(data, callback, options = {}) {
26
+ return postRequest.call(this, data, callback, options);
27
+ }
28
+
29
+ handleRequests(type, listener, options = {}) {
30
+ return handleRequests.call(this, type, listener, options);
31
+ }
32
+
33
+ wqForwardPort(eventTypes, eventTarget, { resolveData = null, bidirectional = false, namespace1 = null, namespace2 = null } = {}) {
34
+ return forwardPort.call(this, eventTypes, eventTarget, { resolveData, bidirectional, namespace1, namespace2 });
35
+ }
36
+ }
37
+
38
+ globalThis.WQMessagePort = WQMessagePort;
@@ -0,0 +1,47 @@
1
+ import { forwardPort } from './wq-message-port.js';
2
+ import { WQStarPort } from './WQStarPort.js';
3
+
4
+ export class WQRelayPort extends WQStarPort {
5
+
6
+ #namespace;
7
+ get namespace() { return this.#namespace; }
8
+
9
+ constructor(namespace = null) {
10
+ super();
11
+ this.#namespace = namespace;
12
+ }
13
+
14
+ addPort(port, { resolveData = null } = {}) {
15
+ const $resolveData = (data, ...args) => {
16
+ if (resolveData) {
17
+ return resolveData(data, ...args);
18
+ }
19
+ return data;
20
+ };
21
+ // Setup
22
+ const superCleanup = super.addPort(port, { enableBubbling: false });
23
+ const forwardingCleanup = forwardPort.call(port, '*', this, { bidirectional: false, resolveData: $resolveData, namespace1: this.namespace, namespace2: this.namespace });
24
+ const messageType_ping = this.namespace && `${this.namespace}:message` || 'message';
25
+ this.postMessage(
26
+ $resolveData({
27
+ event: 'joins',
28
+ }, port, this),
29
+ { wqEventOptions: { type: messageType_ping }, wqProcessingOptions: { except: port } }
30
+ );
31
+ // Teardown
32
+ const leaves = () => {
33
+ forwardingCleanup();
34
+ this.postMessage(
35
+ $resolveData({
36
+ event: 'leaves',
37
+ }, port, this),
38
+ { wqEventOptions: { type: messageType_ping }, wqProcessingOptions: { except: port } }
39
+ );
40
+ };
41
+ port.wqLifecycle.close.then(leaves);
42
+ return () => {
43
+ superCleanup(); // Cascade to super
44
+ leaves();
45
+ };
46
+ }
47
+ }
@@ -0,0 +1,113 @@
1
+ import { _isObject } from '@webqit/util/js/index.js';
2
+ import { toWQPort, portIsMessaging, forwardPort, preProcessPostMessage, portHooksCleanup } from './wq-message-port.js';
3
+ import { WQMessageEvent } from './WQMessageEvent.js';
4
+ import { WQMessagePort } from './WQMessagePort.js';
5
+ import { _wq } from '../../util.js';
6
+
7
+ export class WQSockPort extends WQMessagePort {
8
+
9
+ static WebSocket = typeof WebSocket !== 'undefined' ? WebSocket : null;
10
+
11
+ #socket;
12
+ #cleanups = [];
13
+
14
+ constructor(instanceOrConnectionID) {
15
+ super();
16
+ this.#socket = typeof instanceOrConnectionID === 'string' ? new this.constructor.WebSocket(`/${instanceOrConnectionID}`) : instanceOrConnectionID;
17
+ const meta = _wq(this, 'meta');
18
+ Object.defineProperty(this, 'wqLifecycle', {
19
+ value: {
20
+ open: new Promise((resolve) => {
21
+ if (meta.get('open')) return resolve();
22
+ meta.set('onlineCallback', resolve);
23
+ }),
24
+ close: new Promise((resolve) => {
25
+ if (meta.get('close')) return resolve();
26
+ meta.set('offlineCallback', resolve);
27
+ }),
28
+ messaging: new Promise((resolve) => {
29
+ if (meta.get('messaging')) return resolve();
30
+ meta.set('messagingCallback', resolve);
31
+ }),
32
+ },
33
+ configurable: true
34
+ });
35
+ const fireOpen = () => {
36
+ this.dispatchEvent(new Event('open'));
37
+ meta.get('onlineCallback')();
38
+ };
39
+ const fireClose = () => {
40
+ this.dispatchEvent(new Event('close'));
41
+ meta.get('offlineCallback')();
42
+ };
43
+ if (this.#socket.readyState === this.#socket.constructor.OPEN) {
44
+ fireOpen();
45
+ }
46
+ const fireError = () => {
47
+ this.dispatchEvent(new Event('error'));
48
+ };
49
+ // --------
50
+ const handleMessage = async (event) => {
51
+ let json;
52
+ try {
53
+ if (!(json = JSON.parse(event.data))
54
+ || !json['.wq']
55
+ || !('data' in json)
56
+ || !['wqEventOptions', 'wqProcessingOptions'].every((k) => _isObject(json[k]))) {
57
+ return;
58
+ }
59
+ } catch (e) {
60
+ // throw a better error
61
+ }
62
+ // Build event details...
63
+ const { data, wqEventOptions, wqProcessingOptions } = json;
64
+ const eventInit = { data, wqEventOptions, ports: [] };
65
+ if (wqProcessingOptions.dataOriginallyUndefined) {
66
+ eventInit.data = undefined;
67
+ }
68
+ for (let i = 0; i < (wqProcessingOptions.numPorts || 0); i++) {
69
+ const channel = new MessageChannel;
70
+ channel.port1.start();
71
+ toWQPort(channel.port1);
72
+ this.#cleanups.push(forwardPort.call(this, '*', channel.port1, { bidirectional: true, namespace1: `${wqEventOptions.eventID}:${i}` }));
73
+ eventInit.ports.push(channel.port2);
74
+ }
75
+ this.dispatchEvent(new WQMessageEvent(this, eventInit));
76
+ };
77
+ const handleClose = (e) => {
78
+ this.#socket.removeEventListener('message', handleMessage);
79
+ this.#socket.removeEventListener('open', fireOpen);
80
+ this.#socket.removeEventListener('error', fireError);
81
+ this.#socket.removeEventListener('close', handleClose);
82
+ for (const c of this.#cleanups) {
83
+ c();
84
+ }
85
+ portHooksCleanup.call(this);
86
+ fireClose();
87
+ };
88
+ this.#socket.addEventListener('message', handleMessage);
89
+ this.#socket.addEventListener('open', fireOpen);
90
+ this.#socket.addEventListener('error', fireError);
91
+ this.#socket.addEventListener('close', handleClose);
92
+ }
93
+
94
+ postMessage(data, transferOrOptions = []) {
95
+ const { transfer = [], wqEventOptions = {}, wqProcessingOptions: _, ...portOptions } = preProcessPostMessage.call(this, data, transferOrOptions);
96
+ const messagePorts = transfer.filter((t) => t instanceof MessagePort);
97
+ portIsMessaging.call(this);
98
+ this.#socket.send(JSON.stringify({
99
+ data: data === undefined ? null : data,
100
+ wqEventOptions,
101
+ wqProcessingOptions: { numPorts: messagePorts.length, dataOriginallyUndefined: data === undefined },
102
+ ['.wq']: true,
103
+ }), portOptions);
104
+ for (let i = 0; i < messagePorts.length; i++) {
105
+ toWQPort(messagePorts[i]);
106
+ this.#cleanups.push(forwardPort.call(this, '*', messagePorts[i], { bidirectional: true, namespace1: `${wqEventOptions.eventID}:${i}` }));
107
+ }
108
+ }
109
+
110
+ close() {
111
+ return this.#socket.close();
112
+ }
113
+ }
@@ -0,0 +1,104 @@
1
+ import { preProcessPostMessage, portIsMessaging, portHooksCleanup } from './wq-message-port.js';
2
+ import { WQMessagePort } from './WQMessagePort.js';
3
+ import { _wq } from '../../util.js';
4
+
5
+ export class WQStarPort extends WQMessagePort {
6
+
7
+ #ports = new Set;
8
+
9
+ get length() { return this.#ports.size; }
10
+
11
+ [Symbol.iterator]() { return this.#ports[Symbol.iterator](); }
12
+
13
+ constructor() {
14
+ super();
15
+ this.#startWQLifecycle();
16
+ }
17
+
18
+ #startWQLifecycle() {
19
+ const meta = _wq(this, 'meta');
20
+ Object.defineProperty(this, 'wqLifecycle', {
21
+ value: {
22
+ open: new Promise((resolve) => {
23
+ if (meta.get('open')) return resolve();
24
+ meta.set('onlineCallback', resolve);
25
+ }),
26
+ close: new Promise((resolve) => {
27
+ if (meta.get('close')) return resolve();
28
+ meta.set('offlineCallback', resolve);
29
+ }),
30
+ messaging: new Promise((resolve) => {
31
+ if (meta.get('messaging')) return resolve();
32
+ meta.set('messagingCallback', resolve);
33
+ }),
34
+ },
35
+ configurable: true
36
+ });
37
+ }
38
+
39
+ addPort(port, { enableBubbling = true } = {}) {
40
+ if (!(port instanceof WQMessagePort)) {
41
+ throw new TypeError('Port must be a WQMessagePort instance.');
42
+ }
43
+ if (this.#ports.has(port)) return;
44
+ this.#ports.add(port); // @ORDER: 1
45
+ const meta = _wq(this, 'meta');
46
+ const portMeta = _wq(port, 'meta');
47
+ if (enableBubbling) {
48
+ if (portMeta.get('parentNode')) {
49
+ throw new TypeError('Incoming port already has a parent node.');
50
+ }
51
+ portMeta.set('parentNode', this); // @ORDER: 2
52
+ }
53
+ // Lifecycle management
54
+ port.wqLifecycle.open.then(() => {
55
+ if (meta.get('open')) return;
56
+ this.dispatchEvent(new Event('open'));
57
+ meta.get('onlineCallback')();
58
+ });
59
+ const cleanup = () => {
60
+ if (!this.#ports.has(port)) return;
61
+ this.#ports.delete(port);
62
+ if (enableBubbling) {
63
+ portMeta.set('parentNode', null);
64
+ }
65
+ if (this.#ports.size === 0) {
66
+ this.dispatchEvent(new Event('close'));
67
+ meta.get('offlineCallback')();
68
+ this.#startWQLifecycle();
69
+ }
70
+ };
71
+ port.wqLifecycle.close.then(cleanup);
72
+ return cleanup;
73
+ }
74
+
75
+ findPort(callback) {
76
+ for (const port of this.#ports) {
77
+ if (callback(port)) {
78
+ return port;
79
+ }
80
+ }
81
+ }
82
+
83
+ // --------
84
+
85
+ postMessage(data, transferOrOptions = []) {
86
+ portIsMessaging.call(this);
87
+ this.wqLifecycle.open.then(() => {
88
+ const { wqProcessingOptions, ...resstOptions } = preProcessPostMessage.call(this, data, transferOrOptions);
89
+ for (const port of this.#ports) {
90
+ if (port === wqProcessingOptions.except) continue;
91
+ port.postMessage(data, { wqProcessingOptions, ...resstOptions });
92
+ }
93
+ });
94
+ }
95
+
96
+ close(destroy = false) {
97
+ for (const port of this.#ports) {
98
+ port.close?.();
99
+ }
100
+ if (destroy) {
101
+ portHooksCleanup.call(this);
102
+ }
103
+ }
104
+ }