@webqit/webflo 0.20.26 → 0.20.28

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 (57) hide show
  1. package/package.json +8 -5
  2. package/src/build-pi/index.js +6 -4
  3. package/src/init-pi/index.js +0 -1
  4. package/src/runtime-pi/{WebfloRuntime.js → AppRuntime.js} +57 -113
  5. package/src/runtime-pi/webflo-client/DeviceCapabilities.js +1 -1
  6. package/src/runtime-pi/webflo-client/WebfloClient.js +163 -103
  7. package/src/runtime-pi/webflo-client/{WebfloRootClient1.js → WebfloRootClientA.js} +39 -56
  8. package/src/runtime-pi/webflo-client/{WebfloRootClient2.js → WebfloRootClientB.js} +3 -3
  9. package/src/runtime-pi/webflo-client/WebfloSubClient.js +28 -15
  10. package/src/runtime-pi/webflo-client/index.js +3 -3
  11. package/src/runtime-pi/webflo-messaging/ClientPortMixin.js +13 -0
  12. package/src/runtime-pi/{webflo-server/messaging/ClientRequestRealtime.js → webflo-messaging/ClientRequestPort001.js} +13 -9
  13. package/src/runtime-pi/webflo-messaging/ClientRequestPort010.js +4 -0
  14. package/src/runtime-pi/webflo-messaging/ClientRequestPort100.js +17 -0
  15. package/src/runtime-pi/webflo-messaging/WebfloTenancy001.js +27 -0
  16. package/src/runtime-pi/webflo-messaging/WebfloTenant001.js +27 -0
  17. package/src/runtime-pi/webflo-routing/HttpCookies101.js +53 -0
  18. package/src/runtime-pi/webflo-routing/HttpCookies110.js +3 -0
  19. package/src/runtime-pi/webflo-routing/{HttpEvent.js → HttpEvent111.js} +95 -73
  20. package/src/runtime-pi/webflo-routing/HttpKeyvalInterface.js +120 -0
  21. package/src/runtime-pi/webflo-routing/HttpSession001.js +24 -0
  22. package/src/runtime-pi/webflo-routing/HttpSession110.js +3 -0
  23. package/src/runtime-pi/webflo-routing/{HttpThread.js → HttpThread111.js} +54 -13
  24. package/src/runtime-pi/webflo-routing/{HttpUser.js → HttpUser111.js} +10 -23
  25. package/src/runtime-pi/webflo-routing/KeyvalsFactory001.js +53 -0
  26. package/src/runtime-pi/webflo-routing/KeyvalsFactory110.js +48 -0
  27. package/src/runtime-pi/webflo-routing/KeyvalsFactoryInterface.js +56 -0
  28. package/src/runtime-pi/webflo-routing/{WebfloRouter.js → WebfloRouter111.js} +5 -6
  29. package/src/runtime-pi/webflo-server/WebfloServer.js +262 -269
  30. package/src/runtime-pi/webflo-worker/WebfloWorker.js +97 -44
  31. package/src/util.js +3 -2
  32. package/src/runtime-pi/apis.js +0 -9
  33. package/src/runtime-pi/webflo-client/ClientSideCookies.js +0 -18
  34. package/src/runtime-pi/webflo-fetch/LiveResponse.js +0 -476
  35. package/src/runtime-pi/webflo-fetch/index.js +0 -419
  36. package/src/runtime-pi/webflo-fetch/util.js +0 -28
  37. package/src/runtime-pi/webflo-messaging/WQBroadcastChannel.js +0 -10
  38. package/src/runtime-pi/webflo-messaging/WQMessageChannel.js +0 -26
  39. package/src/runtime-pi/webflo-messaging/WQMessageEvent.js +0 -87
  40. package/src/runtime-pi/webflo-messaging/WQMessagePort.js +0 -38
  41. package/src/runtime-pi/webflo-messaging/WQRelayPort.js +0 -47
  42. package/src/runtime-pi/webflo-messaging/WQSockPort.js +0 -111
  43. package/src/runtime-pi/webflo-messaging/WQStarPort.js +0 -112
  44. package/src/runtime-pi/webflo-messaging/wq-message-port.js +0 -413
  45. package/src/runtime-pi/webflo-routing/HttpCookies.js +0 -43
  46. package/src/runtime-pi/webflo-routing/HttpSession.js +0 -11
  47. package/src/runtime-pi/webflo-routing/HttpState.js +0 -182
  48. package/src/runtime-pi/webflo-server/ServerSideCookies.js +0 -22
  49. package/src/runtime-pi/webflo-server/ServerSideSession.js +0 -40
  50. package/src/runtime-pi/webflo-server/messaging/Client.js +0 -27
  51. package/src/runtime-pi/webflo-server/messaging/Clients.js +0 -25
  52. package/src/runtime-pi/webflo-url/Url.js +0 -156
  53. package/src/runtime-pi/webflo-url/index.js +0 -1
  54. package/src/runtime-pi/webflo-url/urlpattern.js +0 -38
  55. package/src/runtime-pi/webflo-url/util.js +0 -109
  56. package/src/runtime-pi/webflo-url/xURL.js +0 -94
  57. package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +0 -21
@@ -1,111 +0,0 @@
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
- #socket;
10
- #cleanups = [];
11
-
12
- constructor(instanceOrConnectionID) {
13
- super();
14
- this.#socket = typeof instanceOrConnectionID === 'string' ? new WebSocket(`/${instanceOrConnectionID}`) : instanceOrConnectionID;
15
- const meta = _wq(this, 'meta');
16
- Object.defineProperty(this, 'wqLifecycle', {
17
- value: {
18
- open: new Promise((resolve) => {
19
- if (meta.get('open')) return resolve();
20
- meta.set('onlineCallback', resolve);
21
- }),
22
- close: new Promise((resolve) => {
23
- if (meta.get('close')) return resolve();
24
- meta.set('offlineCallback', resolve);
25
- }),
26
- messaging: new Promise((resolve) => {
27
- if (meta.get('messaging')) return resolve();
28
- meta.set('messagingCallback', resolve);
29
- }),
30
- },
31
- configurable: true
32
- });
33
- const fireOpen = () => {
34
- this.dispatchEvent(new Event('open'));
35
- meta.get('onlineCallback')();
36
- };
37
- const fireClose = () => {
38
- this.dispatchEvent(new Event('close'));
39
- meta.get('offlineCallback')();
40
- };
41
- if (this.#socket.readyState === this.#socket.constructor.OPEN) {
42
- fireOpen();
43
- }
44
- const fireError = () => {
45
- this.dispatchEvent(new Event('error'));
46
- };
47
- // --------
48
- const handleMessage = async (event) => {
49
- let json;
50
- try {
51
- if (!(json = JSON.parse(event.data))
52
- || !json['.wq']
53
- || !('data' in json)
54
- || !['wqEventOptions', 'wqProcessingOptions'].every((k) => _isObject(json[k]))) {
55
- return;
56
- }
57
- } catch (e) {
58
- // throw a better error
59
- }
60
- // Build event details...
61
- const { data, wqEventOptions, wqProcessingOptions } = json;
62
- const eventInit = { data, wqEventOptions, ports: [] };
63
- if (wqProcessingOptions.dataOriginallyUndefined) {
64
- eventInit.data = undefined;
65
- }
66
- for (let i = 0; i < (wqProcessingOptions.numPorts || 0); i++) {
67
- const channel = new MessageChannel;
68
- channel.port1.start();
69
- toWQPort(channel.port1);
70
- this.#cleanups.push(forwardPort.call(this, '*', channel.port1, { bidirectional: true, namespace1: `${wqEventOptions.eventID}:${i}` }));
71
- eventInit.ports.push(channel.port2);
72
- }
73
- this.dispatchEvent(new WQMessageEvent(this, eventInit));
74
- };
75
- const handleClose = (e) => {
76
- this.#socket.removeEventListener('message', handleMessage);
77
- this.#socket.removeEventListener('open', fireOpen);
78
- this.#socket.removeEventListener('error', fireError);
79
- this.#socket.removeEventListener('close', handleClose);
80
- for (const c of this.#cleanups) {
81
- c();
82
- }
83
- portHooksCleanup.call(this);
84
- fireClose();
85
- };
86
- this.#socket.addEventListener('message', handleMessage);
87
- this.#socket.addEventListener('open', fireOpen);
88
- this.#socket.addEventListener('error', fireError);
89
- this.#socket.addEventListener('close', handleClose);
90
- }
91
-
92
- postMessage(data, transferOrOptions = []) {
93
- const { transfer = [], wqEventOptions = {}, wqProcessingOptions: _, ...portOptions } = preProcessPostMessage.call(this, data, transferOrOptions);
94
- const messagePorts = transfer.filter((t) => t instanceof MessagePort);
95
- portIsMessaging.call(this);
96
- this.#socket.send(JSON.stringify({
97
- data: data === undefined ? null : data,
98
- wqEventOptions,
99
- wqProcessingOptions: { numPorts: messagePorts.length, dataOriginallyUndefined: data === undefined },
100
- ['.wq']: true,
101
- }), portOptions);
102
- for (let i = 0; i < messagePorts.length; i++) {
103
- toWQPort(messagePorts[i]);
104
- this.#cleanups.push(forwardPort.call(this, '*', messagePorts[i], { bidirectional: true, namespace1: `${wqEventOptions.eventID}:${i}` }));
105
- }
106
- }
107
-
108
- close() {
109
- return this.#socket.close();
110
- }
111
- }
@@ -1,112 +0,0 @@
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
- let isMessaging = false;
21
- Object.defineProperty(this, 'wqLifecycle', {
22
- value: {
23
- open: new Promise((resolve) => {
24
- if (meta.get('open')) return resolve();
25
- meta.set('onlineCallback', resolve);
26
- }),
27
- close: new Promise((resolve) => {
28
- if (meta.get('close')) return resolve();
29
- meta.set('offlineCallback', resolve);
30
- }),
31
- messaging: new Promise((resolve) => {
32
- if (meta.get('messaging')) {
33
- isMessaging = true;
34
- return resolve();
35
- }
36
- meta.set('messagingCallback', () => {
37
- isMessaging = true;
38
- resolve()
39
- });
40
- }),
41
- isMessaging: (() => isMessaging),
42
- },
43
- configurable: true
44
- });
45
- }
46
-
47
- addPort(port, { enableBubbling = true } = {}) {
48
- if (!(port instanceof WQMessagePort)) {
49
- throw new TypeError('Port must be a WQMessagePort instance.');
50
- }
51
- if (this.#ports.has(port)) return;
52
- this.#ports.add(port); // @ORDER: 1
53
- const meta = _wq(this, 'meta');
54
- const portMeta = _wq(port, 'meta');
55
- if (enableBubbling) {
56
- if (portMeta.get('parentNode')) {
57
- throw new TypeError('Incoming port already has a parent node.');
58
- }
59
- portMeta.set('parentNode', this); // @ORDER: 2
60
- }
61
- // Lifecycle management
62
- port.wqLifecycle.open.then(() => {
63
- if (meta.get('open')) return;
64
- this.dispatchEvent(new Event('open'));
65
- meta.get('onlineCallback')();
66
- });
67
- const cleanup = () => {
68
- if (!this.#ports.has(port)) return;
69
- this.#ports.delete(port);
70
- if (enableBubbling) {
71
- portMeta.set('parentNode', null);
72
- }
73
- if (this.#ports.size === 0) {
74
- this.dispatchEvent(new Event('close'));
75
- meta.get('offlineCallback')();
76
- this.#startWQLifecycle();
77
- }
78
- };
79
- port.wqLifecycle.close.then(cleanup);
80
- return cleanup;
81
- }
82
-
83
- findPort(callback) {
84
- for (const port of this.#ports) {
85
- if (callback(port)) {
86
- return port;
87
- }
88
- }
89
- }
90
-
91
- // --------
92
-
93
- postMessage(data, transferOrOptions = []) {
94
- portIsMessaging.call(this);
95
- this.wqLifecycle.open.then(() => {
96
- const { wqProcessingOptions, ...resstOptions } = preProcessPostMessage.call(this, data, transferOrOptions);
97
- for (const port of this.#ports) {
98
- if (port === wqProcessingOptions.except) continue;
99
- port.postMessage(data, { wqProcessingOptions, ...resstOptions });
100
- }
101
- });
102
- }
103
-
104
- close(destroy = false) {
105
- for (const port of this.#ports) {
106
- port.close?.();
107
- }
108
- if (destroy) {
109
- portHooksCleanup.call(this);
110
- }
111
- }
112
- }
@@ -1,413 +0,0 @@
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/use-live';
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
- let isMessaging = false;
265
- Object.defineProperty(port, 'wqLifecycle', {
266
- value: {
267
- open: new Promise((resolve) => {
268
- if (portMeta.get('open')) return resolve();
269
- portMeta.set('onlineCallback', resolve);
270
- }),
271
- close: new Promise((resolve) => {
272
- if (portMeta.get('close')) return resolve();
273
- portMeta.set('offlineCallback', resolve);
274
- }),
275
- messaging: new Promise((resolve) => {
276
- if (portMeta.get('messaging')) {
277
- isMessaging = true;
278
- return resolve();
279
- }
280
- portMeta.set('messagingCallback', () => {
281
- isMessaging = true;
282
- resolve()
283
- });
284
- }),
285
- isMessaging: (() => isMessaging),
286
- }
287
- });
288
- Object.defineProperties(port, prototypeExtensions);
289
- // Set the tag
290
- port[WQMessagePortInstanceTag] = true;
291
- return port;
292
- }
293
-
294
- export function internalAddEventListener(args) {
295
- const meta = _wq(this, 'meta');
296
- meta.set('listenersRegistry', meta.get('listenersRegistry') || new Set);
297
- meta.get('listenersRegistry').add(args);
298
- }
299
-
300
- export function postRequest(data, callback, options = {}) {
301
- const { eventOptions2 = {}, transfer = [], ...$options } = options;
302
- const { signal, once } = eventOptions2;
303
- const messageChannel = new MessageChannel;
304
- messageChannel.port1.start();
305
- toWQPort(messageChannel.port1);
306
- messageChannel.port1.addEventListener('message', (e) => callback(e), { signal, once });
307
- return this.postMessage(data, { ...$options, transfer: [messageChannel.port2].concat(transfer) });
308
- }
309
-
310
- export function handleRequests(type, listener, options = {}) {
311
- const $listener = async (e) => {
312
- const response = await listener(e);
313
- for (const port of e.ports) {
314
- port.postMessage(response);
315
- }
316
- };
317
- this.addEventListener(type, $listener, options);
318
- return () => {
319
- this.removeEventListener(type, $listener, options);
320
- };
321
- }
322
-
323
- export function portIsMessaging() {
324
- const meta = _wq(this, 'meta');
325
- if (!meta.get('messaging')) {
326
- meta.set('messaging', true);
327
- meta.get('messagingCallback')?.();
328
- }
329
- }
330
-
331
- function autoPortOpen() {
332
- const meta = _wq(this, 'meta');
333
- if (!meta.get('open')) {
334
- meta.set('open', true);
335
- this.postMessage({
336
- ['.wq']: true,
337
- ping: 'open',
338
- });
339
- }
340
- }
341
-
342
- function portClose() {
343
- // Unregister custom event rewrites
344
- const meta = _wq(this, 'meta');
345
- this.removeEventListener('message', meta.get('messageHandler'));
346
- meta.set('close', true);
347
- meta.get('offlineCallback')?.();
348
- portHooksCleanup.call(this);
349
- this.dispatchEvent(new Event('close'));
350
- // Unset the tag
351
- this[WQMessagePortInstanceTag] = false;
352
- }
353
-
354
- const prototypeOriginals = {
355
- addEventListener: MessagePort.prototype.addEventListener,
356
- postMessage: MessagePort.prototype.postMessage,
357
- close: MessagePort.prototype.close,
358
- onmessage: Object.getOwnPropertyDescriptor(MessagePort.prototype, 'onmessage'),
359
- };
360
-
361
- const prototypeExtensions = {
362
- wqForwardPort: {
363
- value: function (eventTypes, eventTarget, { resolveData = null, bidirectional = false, namespace1 = null, namespace2 = null } = {}) {
364
- return forwardPort.call(this, eventTypes, eventTarget, { resolveData, bidirectional, namespace1, namespace2 });
365
- }
366
- },
367
- // --------
368
- addEventListener: {
369
- value: function (...args) {
370
- // On first interaction,
371
- // ping the other end with "open"
372
- autoPortOpen.call(this);
373
- internalAddEventListener.call(this, args);
374
- return prototypeOriginals.addEventListener.call(this, ...args);
375
- },
376
- },
377
- onmessage: {
378
- get: function () {
379
- return prototypeOriginals.onmessage.get.call(this);
380
- },
381
- set: function (value) {
382
- this.start();
383
- autoPortOpen.call(this);
384
- return prototypeOriginals.onmessage.set.call(this, value);
385
- },
386
- },
387
- postMessage: {
388
- value: function (data, transferOrOptions = {}) {
389
- portIsMessaging.call(this);
390
- const { wqEventOptions, wqProcessingOptions: _, ...portOptions } = preProcessPostMessage.call(this, data, transferOrOptions);
391
- return prototypeOriginals.postMessage.call(this, {
392
- data,
393
- wqEventOptions,
394
- wqProcessingOptions: {},
395
- ['.wq']: true,
396
- }, portOptions);
397
- }
398
- },
399
- postRequest: { value: postRequest },
400
- handleRequests: { value: handleRequests },
401
- close: {
402
- value: function () {
403
- // On close, tear down and fire "close" event on self
404
- // and ping the other end with "close"
405
- portClose.call(this);
406
- this.postMessage({
407
- ['.wq']: true,
408
- ping: 'close',
409
- });
410
- return prototypeOriginals.close.call(this);
411
- }
412
- },
413
- };
@@ -1,43 +0,0 @@
1
- import { _even } from '@webqit/util/obj/index.js';
2
- import { _isObject } from '@webqit/util/js/index.js';
3
- import { renderCookieObjToString } from '../webflo-fetch/index.js';
4
- import { HttpState } from './HttpState.js';
5
-
6
- export class HttpCookies extends HttpState {
7
-
8
- #originals;
9
-
10
- constructor({ request, thread = null, entries = [] }) {
11
- entries = [...entries].map(([key, value]) => [key, !_isObject(value) ? { name: key, value } : value]);
12
- super({ store: new Map(entries), request, thread });
13
- this.#originals = new Map(entries);
14
- }
15
-
16
- async set(key, value) {
17
- if (!_isObject(value)) { value = { name: key, value }; }
18
- return await super.set(key, value);
19
- }
20
-
21
- async get(key, withDetail = false) {
22
- if (!withDetail) return (await super.get(key))?.value;
23
- return await super.get(key);
24
- }
25
-
26
- async render() {
27
- const entries = await Promise.all((await this.keys()).concat(this.#originals.keys()).map(async (key) => {
28
- const a = this.#originals.get(key);
29
- const b = await this.get(key, true);
30
- if (a === b || (_isObject(a) && _isObject(b) && _even(a, b))) {
31
- // Same
32
- return;
33
- }
34
- if ([undefined, null].includes(b)) {
35
- // Deleted
36
- return { name: key, value: '', maxAge: 0 };
37
- }
38
- // Added or modified
39
- return { name: key, ...(await this.get(key, true)) };
40
- })).then((entries) => entries.filter((e) => e));
41
- return entries.map((e) => renderCookieObjToString(e));
42
- }
43
- }
@@ -1,11 +0,0 @@
1
- import { HttpState } from './HttpState.js';
2
-
3
- export class HttpSession extends HttpState {
4
- static create({ store, request, thread }) {
5
- return new this({
6
- store,
7
- request,
8
- thread
9
- });
10
- }
11
- }