@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.
- package/.github/FUNDING.yml +12 -0
- package/.github/workflows/publish.yml +48 -0
- package/.gitignore +2 -0
- package/LICENSE +2 -2
- package/README.md +71 -2050
- package/package.json +28 -13
- package/site/-/_.md +139 -0
- package/site/-/docs.old.md +2010 -0
- package/site/.vitepress/cache/deps/@braintree_sanitize-url 2.js +93 -0
- package/site/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
- package/site/.vitepress/cache/deps/@braintree_sanitize-url.js 2.map +7 -0
- package/site/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
- package/site/.vitepress/cache/deps/_metadata 2.json +85 -0
- package/site/.vitepress/cache/deps/_metadata.json +85 -0
- package/site/.vitepress/cache/deps/chunk-BUSYA2B4 2.js +9 -0
- package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
- package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js 2.map +7 -0
- package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
- package/site/.vitepress/cache/deps/chunk-Q2AYPHVK 2.js +9719 -0
- package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js +9719 -0
- package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js 2.map +7 -0
- package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js.map +7 -0
- package/site/.vitepress/cache/deps/chunk-QAXAIFA7 2.js +12705 -0
- package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js +12705 -0
- package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js 2.map +7 -0
- package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js.map +7 -0
- package/site/.vitepress/cache/deps/cytoscape 2.js +30278 -0
- package/site/.vitepress/cache/deps/cytoscape-cose-bilkent 2.js +4710 -0
- package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
- package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js 2.map +7 -0
- package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
- package/site/.vitepress/cache/deps/cytoscape.js +30278 -0
- package/site/.vitepress/cache/deps/cytoscape.js 2.map +7 -0
- package/site/.vitepress/cache/deps/cytoscape.js.map +7 -0
- package/site/.vitepress/cache/deps/dayjs 2.js +285 -0
- package/site/.vitepress/cache/deps/dayjs.js +285 -0
- package/site/.vitepress/cache/deps/dayjs.js 2.map +7 -0
- package/site/.vitepress/cache/deps/dayjs.js.map +7 -0
- package/site/.vitepress/cache/deps/debug 2.js +453 -0
- package/site/.vitepress/cache/deps/debug.js +453 -0
- package/site/.vitepress/cache/deps/debug.js 2.map +7 -0
- package/site/.vitepress/cache/deps/debug.js.map +7 -0
- package/site/.vitepress/cache/deps/package 2.json +3 -0
- package/site/.vitepress/cache/deps/package.json +3 -0
- package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api 2.js +4507 -0
- package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
- package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js 2.map +7 -0
- package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
- package/site/.vitepress/cache/deps/vitepress___@vueuse_core 2.js +584 -0
- package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
- package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js 2.map +7 -0
- package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
- package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap 2.js +1166 -0
- package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1166 -0
- package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js 2.map +7 -0
- package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
- package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js 2.js +1667 -0
- package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
- package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js 2.map +7 -0
- package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
- package/site/.vitepress/cache/deps/vitepress___minisearch 2.js +1815 -0
- package/site/.vitepress/cache/deps/vitepress___minisearch.js +1815 -0
- package/site/.vitepress/cache/deps/vitepress___minisearch.js 2.map +7 -0
- package/site/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
- package/site/.vitepress/cache/deps/vue 2.js +344 -0
- package/site/.vitepress/cache/deps/vue.js +344 -0
- package/site/.vitepress/cache/deps/vue.js 2.map +7 -0
- package/site/.vitepress/cache/deps/vue.js.map +7 -0
- package/site/.vitepress/config.ts +147 -0
- package/site/.vitepress/theme/custom.css +50 -0
- package/site/.vitepress/theme/index.ts +6 -0
- package/site/api/webflo-fetch/FormData.md +0 -0
- package/site/api/webflo-fetch/Headers.md +0 -0
- package/site/api/webflo-fetch/LiveResponse.md +0 -0
- package/site/api/webflo-fetch/Request.md +0 -0
- package/site/api/webflo-fetch/Response.md +0 -0
- package/site/api/webflo-fetch/fetch.md +0 -0
- package/site/api/webflo-routing/HttpCookies.md +0 -0
- package/site/api/webflo-routing/HttpEvent/respondWith.md +1 -0
- package/site/api/webflo-routing/HttpEvent/waitUntil.md +1 -0
- package/site/api/webflo-routing/HttpEvent/waitUntilNavigate.md +1 -0
- package/site/api/webflo-routing/HttpEvent.md +30 -0
- package/site/api/webflo-routing/HttpSession.md +0 -0
- package/site/api/webflo-routing/HttpState.md +0 -0
- package/site/api/webflo-routing/HttpUser.md +0 -0
- package/site/api/webflo-routing/handler/fetch.md +42 -0
- package/site/api/webflo-routing/handler/next.md +54 -0
- package/site/api/webflo-routing/handler.md +119 -0
- package/site/api.md +26 -0
- package/site/contributing.md +16 -0
- package/site/docs/advanced/lifecycles.md +20 -0
- package/site/docs/advanced/redirects.md +0 -0
- package/site/docs/advanced/routing.md +1 -0
- package/site/docs/advanced.md +9 -0
- package/site/docs/concepts/realtime.md +637 -0
- package/site/docs/concepts/rendering.md +60 -0
- package/site/docs/concepts/request-response.md +47 -0
- package/site/docs/concepts/routing.md +656 -0
- package/site/docs/concepts/state.md +44 -0
- package/site/docs/concepts/templates.md +48 -0
- package/site/docs/concepts.md +97 -0
- package/site/docs/getting-started.md +378 -0
- package/site/docs/tech-stack.md +56 -0
- package/site/docs.md +100 -0
- package/site/examples/pwa.md +10 -0
- package/site/examples/web.md +11 -0
- package/site/examples.md +10 -0
- package/site/faq.md +13 -0
- package/site/guides/guide-auth.md +13 -0
- package/site/guides/guide-file-upload.md +11 -0
- package/site/guides/guide-service-worker.md +10 -0
- package/site/guides/tutorial-1-todo.md +24 -0
- package/site/guides.md +15 -0
- package/site/index.md +39 -0
- package/site/public/img/brand/logo-670x670.png +0 -0
- package/site/recipes/realtime.md +11 -0
- package/site/recipes/streaming.md +15 -0
- package/site/reference/cli.md +11 -0
- package/site/reference/config.md +13 -0
- package/site/reference/tools.md +9 -0
- package/src/Context.js +3 -11
- package/src/config-pi/deployment/Env.js +6 -19
- package/src/config-pi/deployment/Layout.js +11 -3
- package/src/config-pi/runtime/Client.js +40 -48
- package/src/config-pi/runtime/Server.js +52 -20
- package/src/config-pi/runtime/client/Worker.js +22 -20
- package/src/config-pi/static/Init.js +57 -0
- package/src/config-pi/static/index.js +2 -0
- package/src/deployment-pi/origins/index.js +1 -1
- package/src/deployment-pi/util.js +161 -0
- package/src/index.js +3 -9
- package/src/init-pi/index.js +117 -0
- package/src/init-pi/templates/pwa/app/handler.server.js +8 -0
- package/src/init-pi/templates/pwa/app/page.html +7 -0
- package/src/init-pi/templates/pwa/package.json +19 -0
- package/src/init-pi/templates/pwa/public/assets/app.css +16 -0
- package/src/init-pi/templates/pwa/public/index.html +39 -0
- package/src/init-pi/templates/pwa/public/manifest.json +29 -0
- package/src/init-pi/templates/web/app/handler.server.js +8 -0
- package/src/init-pi/templates/web/app/page.html +7 -0
- package/src/init-pi/templates/web/package.json +19 -0
- package/src/init-pi/templates/web/public/assets/app.css +16 -0
- package/src/init-pi/templates/web/public/index.html +39 -0
- package/src/runtime-pi/WebfloRuntime.js +350 -0
- package/src/runtime-pi/index.js +3 -10
- package/src/runtime-pi/webflo-client/ClientSideCookies.js +17 -0
- package/src/runtime-pi/webflo-client/ClientSideWorkport.js +63 -0
- package/src/runtime-pi/webflo-client/DeviceCapabilities.js +213 -0
- package/src/runtime-pi/webflo-client/WebfloClient.js +500 -0
- package/src/runtime-pi/webflo-client/WebfloRootClient1.js +206 -0
- package/src/runtime-pi/webflo-client/WebfloRootClient2.js +113 -0
- package/src/runtime-pi/webflo-client/WebfloSubClient.js +118 -0
- package/src/runtime-pi/webflo-client/index.js +17 -0
- package/src/runtime-pi/webflo-client/webflo-codegen.js +469 -0
- package/src/runtime-pi/webflo-client/webflo-devmode.js +243 -0
- package/src/runtime-pi/webflo-client/webflo-embedded.js +50 -0
- package/src/runtime-pi/webflo-fetch/LiveResponse.js +437 -0
- package/src/runtime-pi/webflo-fetch/cookies.js +10 -0
- package/src/runtime-pi/webflo-fetch/fetch.js +16 -0
- package/src/runtime-pi/webflo-fetch/formdata.js +54 -0
- package/src/runtime-pi/webflo-fetch/headers.js +151 -0
- package/src/runtime-pi/webflo-fetch/index.js +5 -0
- package/src/runtime-pi/webflo-fetch/message.js +49 -0
- package/src/runtime-pi/webflo-fetch/request.js +62 -0
- package/src/runtime-pi/webflo-fetch/response.js +110 -0
- package/src/runtime-pi/webflo-fetch/util.js +28 -0
- package/src/runtime-pi/webflo-messaging/WQBroadcastChannel.js +10 -0
- package/src/runtime-pi/webflo-messaging/WQMessageChannel.js +26 -0
- package/src/runtime-pi/webflo-messaging/WQMessageEvent.js +87 -0
- package/src/runtime-pi/webflo-messaging/WQMessagePort.js +38 -0
- package/src/runtime-pi/webflo-messaging/WQRelayPort.js +47 -0
- package/src/runtime-pi/webflo-messaging/WQSockPort.js +113 -0
- package/src/runtime-pi/webflo-messaging/WQStarPort.js +104 -0
- package/src/runtime-pi/webflo-messaging/wq-message-port.js +404 -0
- package/src/runtime-pi/webflo-routing/HttpCookies.js +42 -0
- package/src/runtime-pi/webflo-routing/HttpEvent.js +112 -0
- package/src/runtime-pi/webflo-routing/HttpSession.js +11 -0
- package/src/runtime-pi/webflo-routing/HttpState.js +153 -0
- package/src/runtime-pi/webflo-routing/HttpUser.js +54 -0
- package/src/runtime-pi/webflo-routing/WebfloRouter.js +245 -0
- package/src/runtime-pi/webflo-server/ServerSideCookies.js +19 -0
- package/src/runtime-pi/webflo-server/ServerSideSession.js +38 -0
- package/src/runtime-pi/webflo-server/WebfloServer.js +937 -0
- package/src/runtime-pi/webflo-server/index.js +11 -0
- package/src/runtime-pi/webflo-server/messaging/Client.js +27 -0
- package/src/runtime-pi/webflo-server/messaging/ClientRequestRealtime.js +50 -0
- package/src/runtime-pi/webflo-server/messaging/Clients.js +25 -0
- package/src/runtime-pi/webflo-server/webflo-devmode.js +326 -0
- package/src/runtime-pi/{client → webflo-url}/Url.js +27 -76
- package/src/runtime-pi/webflo-url/index.js +1 -0
- package/src/runtime-pi/webflo-url/urlpattern.js +38 -0
- package/src/runtime-pi/{util-url.js → webflo-url/util.js} +5 -43
- package/src/runtime-pi/webflo-url/xURL.js +94 -0
- package/src/runtime-pi/webflo-worker/WebfloWorker.js +234 -0
- package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +19 -0
- package/src/runtime-pi/webflo-worker/WorkerSideWorkport.js +18 -0
- package/src/runtime-pi/webflo-worker/index.js +11 -0
- package/src/services-pi/index.js +2 -0
- package/src/services-pi/push/index.js +23 -0
- package/src/util.js +10 -0
- package/src/{webflo.js → webflo-cli.js} +4 -4
- package/src/runtime-pi/Application.js +0 -29
- package/src/runtime-pi/Cookies.js +0 -82
- package/src/runtime-pi/HttpEvent.js +0 -107
- package/src/runtime-pi/Router.js +0 -130
- package/src/runtime-pi/Runtime.js +0 -21
- package/src/runtime-pi/client/Application.js +0 -76
- package/src/runtime-pi/client/Context.js +0 -7
- package/src/runtime-pi/client/Router.js +0 -48
- package/src/runtime-pi/client/Runtime.js +0 -525
- package/src/runtime-pi/client/Workport.js +0 -190
- package/src/runtime-pi/client/createStorage.js +0 -58
- package/src/runtime-pi/client/generate.js +0 -481
- package/src/runtime-pi/client/index.js +0 -21
- package/src/runtime-pi/client/worker/Application.js +0 -44
- package/src/runtime-pi/client/worker/Context.js +0 -7
- package/src/runtime-pi/client/worker/Runtime.js +0 -275
- package/src/runtime-pi/client/worker/Workport.js +0 -78
- package/src/runtime-pi/client/worker/index.js +0 -21
- package/src/runtime-pi/server/Application.js +0 -101
- package/src/runtime-pi/server/Context.js +0 -16
- package/src/runtime-pi/server/Router.js +0 -159
- package/src/runtime-pi/server/Runtime.js +0 -558
- package/src/runtime-pi/server/index.js +0 -21
- package/src/runtime-pi/util-http.js +0 -86
- package/src/runtime-pi/xFormData.js +0 -24
- package/src/runtime-pi/xHeaders.js +0 -146
- package/src/runtime-pi/xRequest.js +0 -46
- package/src/runtime-pi/xRequestHeaders.js +0 -109
- package/src/runtime-pi/xResponse.js +0 -33
- package/src/runtime-pi/xResponseHeaders.js +0 -117
- package/src/runtime-pi/xURL.js +0 -105
- package/src/runtime-pi/xfetch.js +0 -23
- package/src/runtime-pi/xxHttpMessage.js +0 -102
- 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
|
+
}
|