@webqit/webflo 0.20.27 → 0.20.29
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/package.json +2 -2
- package/src/runtime-pi/AppRuntime.js +4 -4
- package/src/runtime-pi/webflo-client/WebfloClient.js +55 -35
- package/src/runtime-pi/webflo-client/WebfloRootClientA.js +3 -3
- package/src/runtime-pi/webflo-client/WebfloSubClient.js +18 -21
- package/src/runtime-pi/webflo-client/index.js +6 -2
- package/src/runtime-pi/webflo-client/webflo-elements.js +1500 -0
- package/src/runtime-pi/webflo-client/webflo-embedded.js +7 -3
- package/src/runtime-pi/webflo-routing/HttpCookies101.js +4 -1
- package/src/runtime-pi/webflo-routing/HttpEvent111.js +7 -4
- package/src/runtime-pi/webflo-routing/HttpKeyvalInterface.js +5 -4
- package/src/runtime-pi/webflo-routing/HttpSession001.js +1 -4
- package/src/runtime-pi/webflo-routing/HttpThread111.js +26 -38
- package/src/runtime-pi/webflo-routing/KeyvalsFactory001.js +2 -2
- package/src/runtime-pi/webflo-routing/KeyvalsFactory110.js +2 -2
- package/src/runtime-pi/webflo-server/WebfloServer.js +10 -9
- package/src/runtime-pi/webflo-worker/WebfloWorker.js +1 -1
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"vanila-javascript"
|
|
13
13
|
],
|
|
14
14
|
"homepage": "https://webqit.io/tooling/webflo",
|
|
15
|
-
"version": "0.20.
|
|
15
|
+
"version": "0.20.29",
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@octokit/webhooks": "^7.15.1",
|
|
43
43
|
"@webqit/backpack": "^0.1.12",
|
|
44
|
-
"@webqit/fetch-plus": "^0.1.
|
|
44
|
+
"@webqit/fetch-plus": "^0.1.23",
|
|
45
45
|
"@webqit/keyval": "^0.2.17",
|
|
46
46
|
"@webqit/observer": "^3.8.14",
|
|
47
47
|
"@webqit/oohtml-ssr": "^2.2.2",
|
|
@@ -155,7 +155,7 @@ export class AppRuntime {
|
|
|
155
155
|
if (!this.isClientSide
|
|
156
156
|
&& response instanceof LiveResponse) {
|
|
157
157
|
// Must convert to Response on the server-side before returning
|
|
158
|
-
const outgoingResponse = response.toResponse({ port: httpEvent.client });
|
|
158
|
+
const outgoingResponse = response.toResponse({ port: httpEvent.client, signal: httpEvent.signal });
|
|
159
159
|
return outgoingResponse;
|
|
160
160
|
}
|
|
161
161
|
|
|
@@ -168,11 +168,11 @@ export class AppRuntime {
|
|
|
168
168
|
&& response.headers.get('Location')) return;
|
|
169
169
|
|
|
170
170
|
const status = await httpEvent.thread.consume('status', true);
|
|
171
|
-
if (!status
|
|
171
|
+
if (!status) return;
|
|
172
172
|
|
|
173
173
|
httpEvent.waitUntil(httpEvent.client.readyStateChange('open').then(async () => {
|
|
174
|
-
await new Promise((r) => setTimeout(r,
|
|
175
|
-
httpEvent.client.postMessage(status, { type: '
|
|
174
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
175
|
+
httpEvent.client.postMessage(status, { type: 'status' });
|
|
176
176
|
await new Promise((r) => setTimeout(r, 100));
|
|
177
177
|
}));
|
|
178
178
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { _before, _toTitle } from '@webqit/util/str/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { Observer } from '@webqit/observer';
|
|
3
|
+
import { URLPlus } from '@webqit/url-plus';
|
|
3
4
|
import { StarPort } from '@webqit/port-plus';
|
|
5
|
+
import { LiveResponse, RequestPlus } from '@webqit/fetch-plus';
|
|
4
6
|
import { HttpThread111 } from '../webflo-routing/HttpThread111.js';
|
|
5
7
|
import { HttpCookies101 } from '../webflo-routing/HttpCookies101.js';
|
|
6
8
|
import { HttpCookies110 } from '../webflo-routing/HttpCookies110.js';
|
|
@@ -11,8 +13,6 @@ import { WebfloRouter111 } from '../webflo-routing/WebfloRouter111.js';
|
|
|
11
13
|
import { KeyvalsFactory110 } from '../webflo-routing/KeyvalsFactory110.js';
|
|
12
14
|
import { ClientRequestPort100 } from '../webflo-messaging/ClientRequestPort100.js';
|
|
13
15
|
import { AppRuntime } from '../AppRuntime.js';
|
|
14
|
-
import { Observer } from '@webqit/observer';
|
|
15
|
-
import { URLPlus } from '@webqit/url-plus';
|
|
16
16
|
import { _meta } from '../../util.js';
|
|
17
17
|
|
|
18
18
|
export class WebfloClient extends AppRuntime {
|
|
@@ -69,29 +69,52 @@ export class WebfloClient extends AppRuntime {
|
|
|
69
69
|
|
|
70
70
|
// ----------
|
|
71
71
|
// Bind prompt handlers
|
|
72
|
-
const
|
|
72
|
+
const dialogHandler = (e) => {
|
|
73
73
|
window.queueMicrotask(() => {
|
|
74
74
|
if (e.defaultPrevented) return;
|
|
75
|
+
|
|
75
76
|
if (e.type === 'confirm') {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const dialogElement = document.createElement('wq-confirm');
|
|
78
|
+
dialogElement.toggleAttribute('wq-default', true);
|
|
79
|
+
|
|
80
|
+
dialogElement.render(e.data);
|
|
81
|
+
document.body.append(dialogElement);
|
|
82
|
+
dialogElement.showPopover();
|
|
83
|
+
|
|
84
|
+
dialogElement.addEventListener('response', (r) => {
|
|
85
|
+
e.respondWith(r.data);
|
|
86
|
+
setTimeout(() => dialogElement.remove(), 300);
|
|
87
|
+
}, { once: true });
|
|
79
88
|
} else if (e.type === 'prompt') {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
const dialogElement = document.createElement('wq-prompt');
|
|
90
|
+
dialogElement.toggleAttribute('wq-default', true);
|
|
91
|
+
|
|
92
|
+
dialogElement.render(e.data);
|
|
93
|
+
document.body.append(dialogElement);
|
|
94
|
+
dialogElement.showPopover();
|
|
95
|
+
|
|
96
|
+
dialogElement.addEventListener('response', (r) => {
|
|
97
|
+
e.respondWith(r.data);
|
|
98
|
+
setTimeout(() => dialogElement.remove(), 300);
|
|
99
|
+
}, { once: true });
|
|
100
|
+
} else if (e.type === 'status') {
|
|
101
|
+
const dialogElement = document.createElement('wq-toast');
|
|
102
|
+
dialogElement.toggleAttribute('wq-default', true);
|
|
103
|
+
|
|
104
|
+
dialogElement.render(e.data);
|
|
105
|
+
document.body.append(dialogElement);
|
|
106
|
+
dialogElement.showPopover();
|
|
107
|
+
|
|
108
|
+
dialogElement.addEventListener('toggle', (t) => {
|
|
109
|
+
if (t.newState !== 'closed') return;
|
|
110
|
+
dialogElement.remove();
|
|
111
|
+
}, { once: true });
|
|
89
112
|
}
|
|
90
113
|
});
|
|
91
114
|
};
|
|
92
|
-
this.background.addEventListener('confirm',
|
|
93
|
-
this.background.addEventListener('prompt',
|
|
94
|
-
this.background.addEventListener('
|
|
115
|
+
this.background.addEventListener('confirm', dialogHandler, { signal: instanceController.signal });
|
|
116
|
+
this.background.addEventListener('prompt', dialogHandler, { signal: instanceController.signal });
|
|
117
|
+
this.background.addEventListener('status', dialogHandler, { signal: instanceController.signal });
|
|
95
118
|
|
|
96
119
|
// ----------
|
|
97
120
|
// Call default-init
|
|
@@ -237,8 +260,6 @@ export class WebfloClient extends AppRuntime {
|
|
|
237
260
|
|
|
238
261
|
_canIntercept(e) { return !(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey); }
|
|
239
262
|
|
|
240
|
-
#xRedirectCode = 200;
|
|
241
|
-
|
|
242
263
|
isHashChange(urlObj) { return _before(this.location.href, '#') === _before(urlObj.href, '#') && (this.location.href.includes('#') || urlObj.href.includes('#')); }
|
|
243
264
|
|
|
244
265
|
isSpaRoute(urlObj) {
|
|
@@ -269,7 +290,6 @@ export class WebfloClient extends AppRuntime {
|
|
|
269
290
|
const request = super.createRequest(href, init);
|
|
270
291
|
request.headers.set('Accept', 'application/json');
|
|
271
292
|
request.headers.set('X-Redirect-Policy', 'manual-when-cross-spa');
|
|
272
|
-
request.headers.set('X-Redirect-Code', this.#xRedirectCode);
|
|
273
293
|
request.headers.set('X-Powered-By', '@webqit/webflo');
|
|
274
294
|
return request;
|
|
275
295
|
}
|
|
@@ -308,7 +328,7 @@ export class WebfloClient extends AppRuntime {
|
|
|
308
328
|
if (typeof cookieStore === 'undefined') {
|
|
309
329
|
const entries = document.cookie.split(';').map((c) => c.split('=').map((s) => s.trim()));
|
|
310
330
|
const store = this.#keyvals.create({ type: 'inmemory', path: ['cookies', scopeObj.tenantID], origins });
|
|
311
|
-
entries.forEach(([key, value]) => store.set(key,
|
|
331
|
+
entries.forEach(([key, value]) => store.set({ key, value }));
|
|
312
332
|
const initial = Object.fromEntries(entries);
|
|
313
333
|
scopeObj.cookies = HttpCookies101.create({
|
|
314
334
|
context: { handlersRegistry: this.#keyvals.getHandlers('cookies', true) },
|
|
@@ -443,23 +463,28 @@ export class WebfloClient extends AppRuntime {
|
|
|
443
463
|
let response = await super.dispatchNavigationEvent({ httpEvent, crossLayerFetch, clientPortB });
|
|
444
464
|
|
|
445
465
|
// Extract interactive. mode handling
|
|
446
|
-
const handleInteractiveMode = () => {
|
|
466
|
+
const handleInteractiveMode = (returnImmediate = false) => {
|
|
447
467
|
return new Promise(async (resolve) => {
|
|
448
468
|
// Must come as first thing
|
|
449
469
|
const backgroundPort = LiveResponse.getPort(response);
|
|
450
470
|
this.background.addPort(backgroundPort);
|
|
451
|
-
|
|
471
|
+
|
|
452
472
|
const liveResponse = response instanceof LiveResponse
|
|
453
473
|
? response
|
|
454
474
|
: LiveResponse.from(response);
|
|
455
475
|
|
|
456
|
-
liveResponse.
|
|
476
|
+
await liveResponse.readyStateChange('live');
|
|
477
|
+
// IMPORTANT: ensures we're listening to subsequent changes.
|
|
478
|
+
|
|
479
|
+
liveResponse.addEventListener('replace', () => {
|
|
457
480
|
if (liveResponse.headers.get('Location')) {
|
|
458
481
|
this.processRedirect(liveResponse);
|
|
459
482
|
} else {
|
|
460
483
|
resolve(liveResponse);
|
|
461
484
|
}
|
|
462
485
|
}, { signal: httpEvent.signal });
|
|
486
|
+
|
|
487
|
+
if (returnImmediate) resolve(liveResponse);
|
|
463
488
|
});
|
|
464
489
|
};
|
|
465
490
|
|
|
@@ -498,7 +523,7 @@ export class WebfloClient extends AppRuntime {
|
|
|
498
523
|
|
|
499
524
|
// Obtain and connect clientPortB as first thing
|
|
500
525
|
if (LiveResponse.hasPort(response)) {
|
|
501
|
-
response = await handleInteractiveMode();
|
|
526
|
+
response = await handleInteractiveMode(true);
|
|
502
527
|
}
|
|
503
528
|
}
|
|
504
529
|
|
|
@@ -507,14 +532,9 @@ export class WebfloClient extends AppRuntime {
|
|
|
507
532
|
|
|
508
533
|
async processRedirect(response) {
|
|
509
534
|
// Normalize redirect
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
if (xActualRedirectCode && statusCode === this.#xRedirectCode) {
|
|
514
|
-
const responseMeta = _meta(response);
|
|
515
|
-
responseMeta.set('status', xActualRedirectCode); // @NOTE 1
|
|
516
|
-
statusCode = xActualRedirectCode;
|
|
517
|
-
}
|
|
535
|
+
const statusCode = response.headers.has('X-Redirect-Code')
|
|
536
|
+
? parseInt(response.headers.get('X-Redirect-Code'))
|
|
537
|
+
: response.status;
|
|
518
538
|
|
|
519
539
|
// Trigger redirect
|
|
520
540
|
if ([302, 301].includes(statusCode)) {
|
|
@@ -100,9 +100,9 @@ export class WebfloRootClientA extends WebfloClient {
|
|
|
100
100
|
scopeObj.response.headers.set(name, metaElement.content?.trim() || '');
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
// Must come as first thing
|
|
104
|
+
const backgroundPort = LiveResponse.getPort(scopeObj.response);
|
|
105
|
+
if (backgroundPort) this.background.addPort(backgroundPort);
|
|
106
106
|
|
|
107
107
|
if (scopeObj.response.body || scopeObj.response.port) {
|
|
108
108
|
const httpEvent = HttpEvent111.create({ request: this.createRequest(this.location.href) }, true);
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { Observer } from '@webqit/observer';
|
|
2
2
|
import { LiveResponse } from '@webqit/fetch-plus';
|
|
3
3
|
import { WebfloClient } from './WebfloClient.js';
|
|
4
|
-
import { defineElement } from './webflo-embedded.js';
|
|
5
4
|
import { _meta } from '../../util.js';
|
|
6
5
|
|
|
7
6
|
export class WebfloSubClient extends WebfloClient {
|
|
8
7
|
|
|
9
|
-
static defineElement() {
|
|
10
|
-
defineElement(this);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
8
|
static create(superRuntime, host) {
|
|
14
9
|
return new this(superRuntime, host);
|
|
15
10
|
}
|
|
@@ -67,7 +62,7 @@ export class WebfloSubClient extends WebfloClient {
|
|
|
67
62
|
const locationCallback = (newHref) => {
|
|
68
63
|
this.host.reflectLocation(newHref);
|
|
69
64
|
};
|
|
70
|
-
|
|
65
|
+
|
|
71
66
|
return super.controlClassic/*IMPORTANT*/(locationCallback);
|
|
72
67
|
}
|
|
73
68
|
|
|
@@ -99,33 +94,35 @@ export class WebfloSubClient extends WebfloClient {
|
|
|
99
94
|
|
|
100
95
|
async redirect(location, response = null) {
|
|
101
96
|
location = typeof location === 'string' ? new URL(location, this.location.origin) : location;
|
|
102
|
-
|
|
97
|
+
|
|
103
98
|
const width = Math.min(800, window.innerWidth);
|
|
104
99
|
const height = Math.min(600, window.innerHeight);
|
|
105
100
|
const left = (window.outerWidth - width) / 2;
|
|
106
101
|
const top = (window.outerHeight - height) / 2;
|
|
107
102
|
const popup = window.open(location, '_blank', `popup=true,width=${width},height=${height},left=${left},top=${top}`);
|
|
108
|
-
|
|
109
|
-
const backgroundPort = response instanceof LiveResponse
|
|
103
|
+
|
|
104
|
+
const backgroundPort = response instanceof LiveResponse
|
|
110
105
|
? response.port
|
|
111
106
|
: LiveResponse.getPort(response);
|
|
107
|
+
|
|
112
108
|
if (backgroundPort) {
|
|
113
109
|
Observer.set(this.navigator, 'redirecting', new URL(location), { diff: true });
|
|
114
|
-
|
|
115
|
-
backgroundPort.readyStateChange('close').then((e) => {
|
|
116
|
-
window.removeEventListener('message', windowMessageHandler);
|
|
117
|
-
|
|
110
|
+
backgroundPort.readyStateChange('close').then(() => {
|
|
118
111
|
Observer.set(this.navigator, 'redirecting', null);
|
|
119
|
-
popup.postMessage('timeout:5');
|
|
120
|
-
|
|
121
|
-
setTimeout(() => {
|
|
122
|
-
popup.close();
|
|
123
|
-
}, 5000);
|
|
124
112
|
});
|
|
125
|
-
|
|
113
|
+
|
|
126
114
|
const windowMessageHandler = (e) => {
|
|
127
|
-
if (e.source === popup
|
|
128
|
-
|
|
115
|
+
if (e.source === popup) {
|
|
116
|
+
window.removeEventListener('message', windowMessageHandler);
|
|
117
|
+
if (e.data === 'canclose') {
|
|
118
|
+
popup.postMessage('timeout:5');
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
popup.close();
|
|
121
|
+
}, 5000);
|
|
122
|
+
}
|
|
123
|
+
if (e.data === 'closed') {
|
|
124
|
+
backgroundPort.close();
|
|
125
|
+
}
|
|
129
126
|
}
|
|
130
127
|
};
|
|
131
128
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { WebfloRootClientA } from './WebfloRootClientA.js';
|
|
2
2
|
import { WebfloRootClientB } from './WebfloRootClientB.js';
|
|
3
|
-
import {
|
|
3
|
+
import { defineElement } from './webflo-embedded.js';
|
|
4
|
+
import { defineElements } from './webflo-elements.js';
|
|
4
5
|
|
|
5
6
|
export async function start(bootstrap) {
|
|
6
7
|
const WebfloRootClient = window.navigation ? WebfloRootClientB : WebfloRootClientA;
|
|
7
8
|
const instance = WebfloRootClient.create(bootstrap, document);
|
|
8
9
|
await instance.initialize();
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
defineElement();
|
|
12
|
+
defineElements();
|
|
13
|
+
|
|
10
14
|
return instance;
|
|
11
15
|
}
|