@webqit/webflo 1.0.19 → 1.0.21
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 +7 -4
- package/src/config-pi/runtime/Client.js +50 -46
- package/src/config-pi/runtime/Server.js +77 -14
- package/src/config-pi/runtime/client/Worker.js +22 -20
- package/src/runtime-pi/HttpEvent.js +34 -19
- package/src/runtime-pi/HttpUser.js +8 -84
- package/src/runtime-pi/WebfloCookieStorage.js +28 -12
- package/src/runtime-pi/WebfloRouter.js +2 -2
- package/src/runtime-pi/WebfloRuntime.js +9 -4
- package/src/runtime-pi/WebfloStorage.js +91 -34
- package/src/runtime-pi/client/Capabilities.js +211 -0
- package/src/runtime-pi/client/CookieStorage.js +3 -3
- package/src/runtime-pi/client/SessionStorage.js +8 -25
- package/src/runtime-pi/client/WebfloClient.js +15 -23
- package/src/runtime-pi/client/WebfloRootClient1.js +55 -34
- package/src/runtime-pi/client/WebfloRootClient2.js +2 -2
- package/src/runtime-pi/client/WebfloSubClient.js +9 -5
- package/src/runtime-pi/client/Workport.js +64 -91
- package/src/runtime-pi/client/generate.js +25 -16
- package/src/runtime-pi/client/index.js +3 -2
- package/src/runtime-pi/client/worker/CookieStorage.js +6 -4
- package/src/runtime-pi/client/worker/SessionStorage.js +3 -7
- package/src/runtime-pi/client/worker/WebfloWorker.js +70 -56
- package/src/runtime-pi/client/worker/index.js +3 -2
- package/src/runtime-pi/server/CookieStorage.js +6 -4
- package/src/runtime-pi/server/SessionStorage.js +17 -19
- package/src/runtime-pi/server/WebfloServer.js +66 -12
- package/src/runtime-pi/server/index.js +1 -0
- package/src/runtime-pi/util-http.js +15 -2
- package/src/services-pi/index.js +2 -0
- package/src/services-pi/push/index.js +23 -0
- package/src/static-pi/index.js +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WebfloClient } from './WebfloClient.js';
|
|
2
2
|
import { Context } from './Context.js';
|
|
3
3
|
import { Workport } from './Workport.js';
|
|
4
|
+
import { Capabilities } from './Capabilities.js';
|
|
4
5
|
|
|
5
6
|
const { Observer } = webqit;
|
|
6
7
|
|
|
@@ -10,6 +11,8 @@ export class WebfloRootClient1 extends WebfloClient {
|
|
|
10
11
|
|
|
11
12
|
static get Workport() { return Workport; }
|
|
12
13
|
|
|
14
|
+
static get Capabilities() { return Capabilities; }
|
|
15
|
+
|
|
13
16
|
static create(host, cx = {}) {
|
|
14
17
|
return new this(host, this.Context.create(cx));
|
|
15
18
|
}
|
|
@@ -17,6 +20,15 @@ export class WebfloRootClient1 extends WebfloClient {
|
|
|
17
20
|
#cx;
|
|
18
21
|
get cx() { return this.#cx; }
|
|
19
22
|
|
|
23
|
+
#network;
|
|
24
|
+
get network() { return this.#network; }
|
|
25
|
+
|
|
26
|
+
#workport;
|
|
27
|
+
get workport() { return this.#workport; }
|
|
28
|
+
|
|
29
|
+
#capabilities;
|
|
30
|
+
get capabilities() { return this.#capabilities; }
|
|
31
|
+
|
|
20
32
|
constructor(host, cx) {
|
|
21
33
|
if (!(host instanceof Document)) {
|
|
22
34
|
throw new Error('Argument #1 must be a Document instance');
|
|
@@ -26,11 +38,42 @@ export class WebfloRootClient1 extends WebfloClient {
|
|
|
26
38
|
throw new Error('Argument #2 must be a Webflo Context instance');
|
|
27
39
|
}
|
|
28
40
|
this.#cx = cx;
|
|
41
|
+
this.#network = { status: window.navigator.onLine };
|
|
29
42
|
}
|
|
30
43
|
|
|
31
|
-
initialize() {
|
|
32
|
-
//
|
|
33
|
-
|
|
44
|
+
async initialize() {
|
|
45
|
+
// --------
|
|
46
|
+
// INITIALIZATIONS
|
|
47
|
+
const cleanups = [await super.initialize()];
|
|
48
|
+
// --------
|
|
49
|
+
// Service Worker && Capabilities
|
|
50
|
+
if (this.cx.params.capabilities?.service_worker?.filename) {
|
|
51
|
+
const { service_worker: { filename, ...restServiceWorkerParams } = {} } = this.cx.params.capabilities;
|
|
52
|
+
this.#workport = await this.constructor.Workport.initialize(null, (this.cx.params.public_base_url || '') + filename, restServiceWorkerParams);
|
|
53
|
+
cleanups.push(() => this.#workport.close());
|
|
54
|
+
}
|
|
55
|
+
this.#capabilities = await this.constructor.Capabilities.initialize({ ...this.cx.params.capabilities, env: this.cx.params.env });
|
|
56
|
+
cleanups.push(() => this.#capabilities.close());
|
|
57
|
+
// --------
|
|
58
|
+
// Bind network status handlers
|
|
59
|
+
const onlineHandler = () => Observer.set(this.network, 'status', window.navigator.onLine);
|
|
60
|
+
window.addEventListener('online', onlineHandler);
|
|
61
|
+
window.addEventListener('offline', onlineHandler);
|
|
62
|
+
cleanups.push(() => {
|
|
63
|
+
window.removeEventListener('online', onlineHandler);
|
|
64
|
+
window.removeEventListener('offline', onlineHandler);
|
|
65
|
+
});
|
|
66
|
+
// --------
|
|
67
|
+
// Window opener pinging
|
|
68
|
+
let beforeunloadCleanup;
|
|
69
|
+
if (window.opener) {
|
|
70
|
+
const beforeunloadHandler = () => window.opener.postMessage('close');
|
|
71
|
+
window.addEventListener('beforeunload', beforeunloadHandler);
|
|
72
|
+
cleanups.push(() => {
|
|
73
|
+
window.removeEventListener('beforeunload', beforeunloadHandler);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// --------
|
|
34
77
|
// Bind global prompt handlers
|
|
35
78
|
const promptsHandler = (e) => {
|
|
36
79
|
e.stopPropagation();
|
|
@@ -49,9 +92,10 @@ export class WebfloRootClient1 extends WebfloClient {
|
|
|
49
92
|
});
|
|
50
93
|
}, 10);
|
|
51
94
|
};
|
|
52
|
-
|
|
53
|
-
this.backgroundMessaging.handleMessages('prompt', promptsHandler);
|
|
54
|
-
//
|
|
95
|
+
cleanups.push(this.backgroundMessaging.handleMessages('confirm', promptsHandler));
|
|
96
|
+
cleanups.push(this.backgroundMessaging.handleMessages('prompt', promptsHandler));
|
|
97
|
+
// --------
|
|
98
|
+
// HYDRATION
|
|
55
99
|
const scope = {};
|
|
56
100
|
if (scope.backgroundMessagingMeta = document.querySelector('meta[name="X-Background-Messaging"]')) {
|
|
57
101
|
scope.backgroundMessaging = this.$createBackgroundMessagingFrom(scope.backgroundMessagingMeta.content);
|
|
@@ -66,32 +110,9 @@ export class WebfloRootClient1 extends WebfloClient {
|
|
|
66
110
|
});
|
|
67
111
|
} catch(e) {}
|
|
68
112
|
}
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const { vapid_key_env, push_registration_url_env, ..._restServiceWorkerParams } = restServiceWorkerParams;
|
|
73
|
-
const swParams = {
|
|
74
|
-
..._restServiceWorkerParams,
|
|
75
|
-
VAPID_PUBLIC_KEY: this.cx.params.env[vapid_key_env],
|
|
76
|
-
PUSH_REGISTRATION_PUBLIC_URL: this.cx.params.env[push_registration_url_env],
|
|
77
|
-
startMessages: true
|
|
78
|
-
};
|
|
79
|
-
this.workport = new this.constructor.Workport;
|
|
80
|
-
this.workport.registerServiceWorker(base + filename, swParams);
|
|
81
|
-
}
|
|
82
|
-
if (window.opener) {
|
|
83
|
-
// Window opener pinging
|
|
84
|
-
const $undoControl = undoControl;
|
|
85
|
-
const beforeunloadHandler = () => {
|
|
86
|
-
window.opener.postMessage('close');
|
|
87
|
-
};
|
|
88
|
-
window.addEventListener('beforeunload', beforeunloadHandler);
|
|
89
|
-
undoControl = () => {
|
|
90
|
-
window.removeEventListener('beforeunload', beforeunloadHandler);
|
|
91
|
-
$undoControl();
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
return undoControl
|
|
113
|
+
// --------
|
|
114
|
+
// CLEAN UP
|
|
115
|
+
return () => cleanups.forEach((c) => c());
|
|
95
116
|
}
|
|
96
117
|
|
|
97
118
|
/**
|
|
@@ -102,7 +123,7 @@ export class WebfloRootClient1 extends WebfloClient {
|
|
|
102
123
|
|
|
103
124
|
control() {
|
|
104
125
|
// IMPORTANT: we're calling super.controlClassic()
|
|
105
|
-
const
|
|
126
|
+
const cleanupSuper = super.controlClassic((newHref) => {
|
|
106
127
|
try {
|
|
107
128
|
// Save current scroll position
|
|
108
129
|
window.history.replaceState({
|
|
@@ -134,7 +155,7 @@ export class WebfloRootClient1 extends WebfloClient {
|
|
|
134
155
|
window.addEventListener('popstate', popstateHandler);
|
|
135
156
|
return () => {
|
|
136
157
|
this.host.removeEventListener('popstate', popstateHandler);
|
|
137
|
-
|
|
158
|
+
cleanupSuper();
|
|
138
159
|
};
|
|
139
160
|
}
|
|
140
161
|
|
|
@@ -9,14 +9,14 @@ export class WebfloRootClient2 extends WebfloRootClient1 {
|
|
|
9
9
|
let navigationOrigins = [];
|
|
10
10
|
// Capture all link-clicks
|
|
11
11
|
const clickHandler = (e) => {
|
|
12
|
-
if (!this._canIntercept(e)) return;
|
|
12
|
+
if (!this._canIntercept(e) || e.defaultPrevented) return;
|
|
13
13
|
let anchorEl = e.target.closest('a');
|
|
14
14
|
if (!anchorEl || !anchorEl.href || anchorEl.target) return;
|
|
15
15
|
navigationOrigins = [anchorEl, null, anchorEl.closest('[navigationcontext]')];
|
|
16
16
|
};
|
|
17
17
|
// Capture all form-submits
|
|
18
18
|
const submitHandler = (e) => {
|
|
19
|
-
if (!this._canIntercept(e)) return;
|
|
19
|
+
if (!this._canIntercept(e) || e.defaultPrevented) return;
|
|
20
20
|
navigationOrigins = [e.submitter, e.target.closest('form'), e.target.closest('[navigationcontext]')];
|
|
21
21
|
};
|
|
22
22
|
// Handle navigation event which happens after the above
|
|
@@ -50,9 +50,9 @@ export class WebfloSubClient extends WebfloClient {
|
|
|
50
50
|
this.location = newValue;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
connectedCallback() {
|
|
53
|
+
async connectedCallback() {
|
|
54
54
|
this.#superRuntime = (this.parentNode?.closest(embedTagNames) || document).webfloRuntime;
|
|
55
|
-
this.#webfloControllerUninitialize = WebfloSubClient.create(this, this.#superRuntime).initialize();
|
|
55
|
+
this.#webfloControllerUninitialize = await WebfloSubClient.create(this, this.#superRuntime).initialize();
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
disconnectedCallback() {
|
|
@@ -70,8 +70,12 @@ export class WebfloSubClient extends WebfloClient {
|
|
|
70
70
|
|
|
71
71
|
get cx() { return this.#superRuntime.cx; }
|
|
72
72
|
|
|
73
|
+
get network() { return this.#superRuntime.network; }
|
|
74
|
+
|
|
73
75
|
get workport() { return this.#superRuntime.workport; }
|
|
74
76
|
|
|
77
|
+
get capabilities() { return this.#superRuntime.capabilities; }
|
|
78
|
+
|
|
75
79
|
get withViewTransitions() { return this.host.hasAttribute('viewtransitions'); }
|
|
76
80
|
|
|
77
81
|
constructor(host, superRuntime) {
|
|
@@ -85,11 +89,11 @@ export class WebfloSubClient extends WebfloClient {
|
|
|
85
89
|
this.#superRuntime = superRuntime;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
initialize() {
|
|
92
|
+
async initialize() {
|
|
89
93
|
if (this.host.location.origin !== window.location.origin) {
|
|
90
94
|
throw new Error(`Webflo embeddable origin violation in "${window.location}"`);
|
|
91
95
|
}
|
|
92
|
-
const
|
|
96
|
+
const cleanupSuper = await super.initialize();
|
|
93
97
|
this.backgroundMessaging.setParent(this.#superRuntime.backgroundMessaging);
|
|
94
98
|
if (this.host.getAttribute('location')) {
|
|
95
99
|
this.navigate(this.location.href);
|
|
@@ -98,7 +102,7 @@ export class WebfloSubClient extends WebfloClient {
|
|
|
98
102
|
if (this.backgroundMessaging.parentNode === this.#superRuntime.backgroundMessaging) {
|
|
99
103
|
this.backgroundMessaging.setParent(null);
|
|
100
104
|
}
|
|
101
|
-
|
|
105
|
+
cleanupSuper();
|
|
102
106
|
};
|
|
103
107
|
}
|
|
104
108
|
|
|
@@ -1,118 +1,91 @@
|
|
|
1
|
-
|
|
1
|
+
import { _isObject } from '@webqit/util/js/index.js';
|
|
2
|
+
import { WebfloMessagingAPI } from '../WebfloMessagingAPI.js';
|
|
3
|
+
import { WebfloMessageEvent } from '../WebfloMessageEvent.js';
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
#swParams = {};
|
|
5
|
+
export class Workport extends WebfloMessagingAPI {
|
|
5
6
|
|
|
6
|
-
#
|
|
7
|
-
get
|
|
8
|
-
#swRegistration;
|
|
7
|
+
#registration;
|
|
8
|
+
get registration() { return this.#registration; }
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
#params;
|
|
11
|
+
get params() { return this.#params; }
|
|
12
|
+
|
|
13
|
+
#ready;
|
|
14
|
+
get ready() { return this.#ready; }
|
|
15
|
+
|
|
16
|
+
#active;
|
|
17
|
+
get active() { return this.#active; }
|
|
18
|
+
|
|
19
|
+
static async initialize(parentNode, file, params = {}) {
|
|
20
|
+
const registration = (await navigator.serviceWorker.getRegistration())
|
|
21
|
+
|| (await navigator.serviceWorker.register(file, { scope: '/', ...params }));
|
|
22
|
+
return new this(parentNode, registration, params);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#messageHandler;
|
|
26
|
+
constructor(parentNode, registration, params = {}) {
|
|
27
|
+
super(parentNode, params);
|
|
28
|
+
this.#registration = registration;
|
|
29
|
+
this.#params = params;
|
|
30
|
+
this.#ready = navigator.serviceWorker ? navigator.serviceWorker.ready : new Promise(() => {});
|
|
18
31
|
// Helper that updates instance's state
|
|
19
32
|
const stateChange = (target) => {
|
|
20
33
|
// target.state can be any of: "parsed", "installing", "installed", "activating", "activated", "redundant"
|
|
21
34
|
if (target.state === 'redundant') {
|
|
22
|
-
//this.remove(target);
|
|
23
35
|
} else if (target.state === 'activated') {
|
|
24
|
-
|
|
36
|
+
const existing = this.#active;
|
|
37
|
+
this.#active = target;
|
|
38
|
+
if (!existing) {
|
|
39
|
+
this.$emit('connected');
|
|
40
|
+
}
|
|
25
41
|
}
|
|
26
42
|
}
|
|
27
43
|
// We're always installing at first for a new service worker.
|
|
28
44
|
// An existing service would immediately be active
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
31
|
-
stateChange(
|
|
32
|
-
|
|
45
|
+
const initial = this.#registration.active || this.#registration.waiting || this.#registration.installing;
|
|
46
|
+
if (initial) {
|
|
47
|
+
stateChange(initial);
|
|
48
|
+
initial.addEventListener('statechange', (e) => stateChange(e.target));
|
|
33
49
|
// "updatefound" event - a new worker that will control
|
|
34
50
|
// this page is installing somewhere
|
|
35
|
-
this.#
|
|
51
|
+
this.#registration.addEventListener('updatefound', () => {
|
|
36
52
|
// If updatefound is fired, it means that there's
|
|
37
53
|
// a new service worker being installed.
|
|
38
|
-
stateChange(this.#
|
|
39
|
-
this.#
|
|
54
|
+
stateChange(this.#registration.installing);
|
|
55
|
+
this.#registration.installing.addEventListener('statechange', (e) => stateChange(e.target));
|
|
40
56
|
});
|
|
41
57
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return await new Promise(async (resolve, reject) => {
|
|
46
|
-
const permissionResult = Notification.requestPermission(resolve);
|
|
47
|
-
if (permissionResult) {
|
|
48
|
-
permissionResult.then(resolve, reject);
|
|
58
|
+
this.#messageHandler = async (event) => {
|
|
59
|
+
if (!_isObject(event.data) || !['messageType', 'message'].every((k) => k in event.data)) {
|
|
60
|
+
return;
|
|
49
61
|
}
|
|
50
|
-
|
|
62
|
+
this.dispatchEvent(new WorkerMessageEvent(
|
|
63
|
+
this,
|
|
64
|
+
event.data.messageType,
|
|
65
|
+
event.data.message,
|
|
66
|
+
event.ports
|
|
67
|
+
));
|
|
68
|
+
};
|
|
69
|
+
navigator.serviceWorker.addEventListener('message', this.#messageHandler);
|
|
51
70
|
}
|
|
52
71
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
return new Notification(title, params);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async pushSubscription(autoPrompt = true) {
|
|
62
|
-
if (!this.#swRegistration) {
|
|
63
|
-
throw new Error(`Service worker not registered`);
|
|
64
|
-
}
|
|
65
|
-
await this.#swReady;
|
|
66
|
-
const pushManager = (await this.#swRegistration).pushManager;
|
|
67
|
-
let subscription = await pushManager.getSubscription();
|
|
68
|
-
if (!subscription && autoPrompt && this.#swParams.VAPID_PUBLIC_KEY) {
|
|
69
|
-
subscription = await pushManager.subscribe({
|
|
70
|
-
userVisibleOnly: true,
|
|
71
|
-
applicationServerKey: urlBase64ToUint8Array(this.#swParams.VAPID_PUBLIC_KEY),
|
|
72
|
-
});
|
|
73
|
-
if (this.#swParams.PUSH_REGISTRATION_PUBLIC_URL) {
|
|
74
|
-
await fetch(this.#swParams.PUSH_REGISTRATION_PUBLIC_URL, {
|
|
75
|
-
method: 'POST',
|
|
76
|
-
headers: { 'Content-Type': 'application/json', },
|
|
77
|
-
body: JSON.stringify(subscription)
|
|
78
|
-
});
|
|
72
|
+
postMessage(message, transferOrOptions = []) {
|
|
73
|
+
this.on('connected', () => {
|
|
74
|
+
if (Array.isArray(transferOrOptions)) {
|
|
75
|
+
transferOrOptions = { transfer: transferOrOptions };
|
|
79
76
|
}
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
const { messageType = 'message', ...options } = transferOrOptions;
|
|
78
|
+
return this.#active.postMessage({
|
|
79
|
+
messageType,
|
|
80
|
+
message
|
|
81
|
+
}, options);
|
|
82
|
+
});
|
|
83
|
+
super.postMessage(message, transferOrOptions);
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
throw new Error(`Service worker not registered`);
|
|
87
|
-
}
|
|
88
|
-
await this.#swReady;
|
|
89
|
-
const pushManager = (await this.#swRegistration).pushManager;
|
|
90
|
-
const subscription = await pushManager.getSubscription();
|
|
91
|
-
if (subscription) {
|
|
92
|
-
subscription.unsubscribe();
|
|
93
|
-
if (subscription && this.#swParams.PUSH_REGISTRATION_PUBLIC_URL) {
|
|
94
|
-
await fetch(this.#swParams.PUSH_REGISTRATION_PUBLIC_URL, {
|
|
95
|
-
method: 'DELETE',
|
|
96
|
-
headers: { 'Content-Type': 'application/json', },
|
|
97
|
-
body: JSON.stringify(subscription)
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
}
|
|
86
|
+
close() {
|
|
87
|
+
navigator.serviceWorker.removeEventListener('message', this.#messageHandler);
|
|
101
88
|
}
|
|
102
89
|
}
|
|
103
90
|
|
|
104
|
-
|
|
105
|
-
function urlBase64ToUint8Array(base64String) {
|
|
106
|
-
var padding = '='.repeat((4 - base64String.length % 4) % 4);
|
|
107
|
-
var base64 = (base64String + padding)
|
|
108
|
-
.replace(/\-/g, '+')
|
|
109
|
-
.replace(/_/g, '/');
|
|
110
|
-
|
|
111
|
-
var rawData = window.atob(base64);
|
|
112
|
-
var outputArray = new Uint8Array(rawData.length);
|
|
113
|
-
|
|
114
|
-
for (var i = 0; i < rawData.length; ++i) {
|
|
115
|
-
outputArray[i] = rawData.charCodeAt(i);
|
|
116
|
-
}
|
|
117
|
-
return outputArray;
|
|
118
|
-
}
|
|
91
|
+
export class WorkerMessageEvent extends WebfloMessageEvent {}
|
|
@@ -25,13 +25,14 @@ export async function generate() {
|
|
|
25
25
|
if (!cx.config.deployment?.Layout) {
|
|
26
26
|
throw new Error(`The Client configurator "config.deployment.Layout" is required in context.`);
|
|
27
27
|
}
|
|
28
|
+
const env = {};
|
|
28
29
|
const clientConfig = await (new cx.config.runtime.Client(cx)).read();
|
|
29
|
-
clientConfig.env =
|
|
30
|
-
if (clientConfig.service_worker
|
|
30
|
+
clientConfig.env = env;
|
|
31
|
+
if (clientConfig.capabilities?.service_worker && !cx.config.runtime.client?.Worker) {
|
|
31
32
|
throw new Error(`The Service Worker configurator "config.runtime.client.Worker" is required in context.`);
|
|
32
33
|
}
|
|
33
34
|
const workerConfig = await (new cx.config.runtime.client.Worker(cx)).read();
|
|
34
|
-
workerConfig.env =
|
|
35
|
+
workerConfig.env = env;
|
|
35
36
|
// -----------
|
|
36
37
|
if (!cx.config.deployment?.Layout) {
|
|
37
38
|
throw new Error(`The Layout configurator "config.deployment.Layout" is required in context.`);
|
|
@@ -42,20 +43,15 @@ export async function generate() {
|
|
|
42
43
|
const dirClient = Path.resolve(cx.CWD || '', layoutConfig.CLIENT_DIR);
|
|
43
44
|
const dirWorker = Path.resolve(cx.CWD || '', layoutConfig.WORKER_DIR);
|
|
44
45
|
const dirSelf = Path.dirname(Url.fileURLToPath(import.meta.url)).replace(/\\/g, '/');
|
|
45
|
-
if (clientConfig.
|
|
46
|
+
if (clientConfig.copy_public_variables) {
|
|
46
47
|
if (!cx.config.deployment?.Env) {
|
|
47
48
|
throw new Error(`The Layout configurator "config.deployment.Env" is required in context to bundle public env.`);
|
|
48
49
|
}
|
|
49
50
|
const envConfig = await (new cx.config.deployment.Env(cx)).read();
|
|
50
|
-
const env = { ...envConfig.entries, ...process.env };
|
|
51
|
-
for (const key in env) {
|
|
51
|
+
const $env = { ...envConfig.entries, ...process.env };
|
|
52
|
+
for (const key in $env) {
|
|
52
53
|
if (!key.includes('PUBLIC_') && !key.includes('_PUBLIC')) continue;
|
|
53
|
-
|
|
54
|
-
clientConfig.env[key] = env[key];
|
|
55
|
-
}
|
|
56
|
-
if (workerConfig.bundle_public_env) {
|
|
57
|
-
workerConfig.env[key] = env[key];
|
|
58
|
-
}
|
|
54
|
+
env[key] = $env[key];
|
|
59
55
|
}
|
|
60
56
|
}
|
|
61
57
|
// -----------
|
|
@@ -114,7 +110,14 @@ export async function generate() {
|
|
|
114
110
|
gen.code.push(`const { start } = webqit.Webflo`);
|
|
115
111
|
// ------------------
|
|
116
112
|
// Bundle
|
|
117
|
-
|
|
113
|
+
const paramsObj = structuredClone(clientConfig);
|
|
114
|
+
if (paramsObj.capabilities?.service_worker) {
|
|
115
|
+
paramsObj.capabilities.service_worker = {
|
|
116
|
+
filename: workerConfig.filename,
|
|
117
|
+
scope: workerConfig.scope
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
declareStart.call(cx, gen, dirClient, dirPublic, paramsObj, spaRouting);
|
|
118
121
|
await bundle.call(cx, gen, Path.join(dirPublic, outfileMain), true/* asModule */);
|
|
119
122
|
// ------------------
|
|
120
123
|
// Embed/unembed
|
|
@@ -192,8 +195,14 @@ export async function generate() {
|
|
|
192
195
|
}
|
|
193
196
|
}
|
|
194
197
|
}
|
|
195
|
-
|
|
196
|
-
|
|
198
|
+
const paramsObj = structuredClone(workerConfig);
|
|
199
|
+
if (clientConfig.capabilities?.webpush) {
|
|
200
|
+
paramsObj.capabilities = {
|
|
201
|
+
webpush: true
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
declareStart.call(cx, gen, dirWorker, dirPublic, paramsObj, workerRouting);
|
|
205
|
+
await bundle.call(cx, gen, Path.join(dirPublic, workerroot, workerConfig.filename));
|
|
197
206
|
// ------------------
|
|
198
207
|
// Recurse
|
|
199
208
|
workerGraphCallback && workerGraphCallback(workerroot, subworkerroots);
|
|
@@ -214,7 +223,7 @@ export async function generate() {
|
|
|
214
223
|
await generateClient();
|
|
215
224
|
Fs.existsSync(sparootsFile) && Fs.unlinkSync(sparootsFile);
|
|
216
225
|
}
|
|
217
|
-
if (clientConfig.service_worker
|
|
226
|
+
if (clientConfig.capabilities?.service_worker) {
|
|
218
227
|
await generateWorker('/');
|
|
219
228
|
}
|
|
220
229
|
}
|
|
@@ -2,11 +2,12 @@ import { WebfloRootClient1 } from './WebfloRootClient1.js';
|
|
|
2
2
|
import { WebfloRootClient2 } from './WebfloRootClient2.js';
|
|
3
3
|
import { WebfloSubClient } from './WebfloSubClient.js';
|
|
4
4
|
|
|
5
|
-
export function start() {
|
|
5
|
+
export async function start() {
|
|
6
6
|
const WebfloRootClient = window.navigation ? WebfloRootClient2 : WebfloRootClient1;
|
|
7
7
|
const instance = WebfloRootClient.create(document, this || {});
|
|
8
|
-
instance.initialize();
|
|
8
|
+
await instance.initialize();
|
|
9
9
|
WebfloSubClient.defineElement();
|
|
10
|
+
return instance;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export { WebfloSubClient } from './WebfloSubClient.js';
|
|
@@ -8,10 +8,12 @@ export class CookieStorage extends WebfloCookieStorage {
|
|
|
8
8
|
);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
commit(response) {
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
async commit(response = null) {
|
|
12
|
+
if (response) {
|
|
13
|
+
for (const cookieStr of await this.render()) {
|
|
14
|
+
response.headers.append('Set-Cookie', cookieStr);
|
|
15
|
+
}
|
|
14
16
|
}
|
|
15
|
-
super.commit();
|
|
17
|
+
await super.commit();
|
|
16
18
|
}
|
|
17
19
|
}
|
|
@@ -2,14 +2,10 @@ import { WebfloStorage } from '../../WebfloStorage.js';
|
|
|
2
2
|
|
|
3
3
|
export class SessionStorage extends WebfloStorage {
|
|
4
4
|
static create(request) {
|
|
5
|
-
return new this(request);
|
|
5
|
+
return new this({}, null, request);
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
super(
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async commit(response) {
|
|
13
|
-
super.commit();
|
|
8
|
+
async commit(response = null) {
|
|
9
|
+
await super.commit();
|
|
14
10
|
}
|
|
15
11
|
}
|