@webqit/webflo 0.11.33 → 0.11.35
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 +1 -1
- package/src/config-pi/deployment/Virtualization.js +10 -4
- package/src/config-pi/runtime/Server.js +18 -20
- package/src/runtime-pi/Router.js +3 -3
- package/src/runtime-pi/Runtime.js +21 -0
- package/src/runtime-pi/RuntimeClient.js +29 -0
- package/src/runtime-pi/client/Runtime.js +30 -41
- package/src/runtime-pi/client/RuntimeClient.js +10 -13
- package/src/runtime-pi/client/Workport.js +14 -2
- package/src/runtime-pi/client/index.js +1 -3
- package/src/runtime-pi/client/worker/Worker.js +21 -36
- package/src/runtime-pi/client/worker/WorkerClient.js +8 -11
- package/src/runtime-pi/client/worker/Workport.js +11 -1
- package/src/runtime-pi/client/worker/index.js +1 -3
- package/src/runtime-pi/server/Router.js +1 -0
- package/src/runtime-pi/server/Runtime.js +253 -216
- package/src/runtime-pi/server/RuntimeClient.js +10 -7
- package/src/runtime-pi/server/index.js +1 -3
- package/src/services-pi/cert/http-auth-hook.js +1 -1
- package/src/services-pi/cert/http-cleanup-hook.js +1 -1
- package/src/webflo.js +1 -1
package/package.json
CHANGED
|
@@ -46,15 +46,21 @@ export default class Virtualization extends Dotfile {
|
|
|
46
46
|
initial: config.entries,
|
|
47
47
|
questions: [
|
|
48
48
|
{
|
|
49
|
-
name: '
|
|
49
|
+
name: 'path',
|
|
50
50
|
type: 'text',
|
|
51
|
-
message: 'Enter
|
|
51
|
+
message: 'Enter local pathname to target server if exists. (Leave empty to explicitly specify hostnames and port number.)',
|
|
52
52
|
validation: ['important'],
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
|
-
name: '
|
|
55
|
+
name: 'hostnames',
|
|
56
|
+
type: 'text',
|
|
57
|
+
message: 'Enter host names. (Leave empty to automatically derive hostnames from the config of the target server specified above.)',
|
|
58
|
+
validation: ['important'],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'port',
|
|
56
62
|
type: 'text',
|
|
57
|
-
message: 'Enter
|
|
63
|
+
message: 'Enter target port. (Leave empty to automatically derive port number from the config of the target server specified above.)',
|
|
58
64
|
validation: ['important'],
|
|
59
65
|
},
|
|
60
66
|
],
|
|
@@ -21,16 +21,16 @@ export default class Server extends Dotfile {
|
|
|
21
21
|
withDefaults(config) {
|
|
22
22
|
return _merge(true, {
|
|
23
23
|
port: process.env.port || 3000,
|
|
24
|
+
domains: [],
|
|
25
|
+
force_www: '',
|
|
24
26
|
https: {
|
|
25
27
|
port: 0,
|
|
26
28
|
keyfile: '',
|
|
27
29
|
certfile: '',
|
|
28
|
-
|
|
30
|
+
domains: [],
|
|
29
31
|
force: false,
|
|
30
32
|
},
|
|
31
|
-
force_www: '',
|
|
32
33
|
oohtml_support: 'full',
|
|
33
|
-
shared: false,
|
|
34
34
|
}, config);
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -60,6 +60,19 @@ export default class Server extends Dotfile {
|
|
|
60
60
|
initial: config.port,
|
|
61
61
|
validation: ['important'],
|
|
62
62
|
},
|
|
63
|
+
{
|
|
64
|
+
name: 'domains',
|
|
65
|
+
type: 'list',
|
|
66
|
+
message: '[domains]: Enter a list of allowed domains if necessary (comma-separated)',
|
|
67
|
+
validation: ['important'],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'force_www',
|
|
71
|
+
type: 'select',
|
|
72
|
+
message: '[force_www]: Force add/remove "www" on hostname?',
|
|
73
|
+
choices: CHOICES.force_www,
|
|
74
|
+
initial: this.indexOfInitial(CHOICES.force_www, config.force_www),
|
|
75
|
+
},
|
|
63
76
|
{
|
|
64
77
|
name: 'https',
|
|
65
78
|
controls: {
|
|
@@ -86,9 +99,9 @@ export default class Server extends Dotfile {
|
|
|
86
99
|
validation: ['important'],
|
|
87
100
|
},
|
|
88
101
|
{
|
|
89
|
-
name: '
|
|
102
|
+
name: 'domains',
|
|
90
103
|
type: 'list',
|
|
91
|
-
message: '[
|
|
104
|
+
message: '[domains]: Enter the CERT domains (comma-separated)',
|
|
92
105
|
validation: ['important'],
|
|
93
106
|
},
|
|
94
107
|
{
|
|
@@ -100,13 +113,6 @@ export default class Server extends Dotfile {
|
|
|
100
113
|
},
|
|
101
114
|
],
|
|
102
115
|
},
|
|
103
|
-
{
|
|
104
|
-
name: 'force_www',
|
|
105
|
-
type: 'select',
|
|
106
|
-
message: '[force_www]: Force add/remove "www" on hostname?',
|
|
107
|
-
choices: CHOICES.force_www,
|
|
108
|
-
initial: this.indexOfInitial(CHOICES.force_www, config.force_www),
|
|
109
|
-
},
|
|
110
116
|
{
|
|
111
117
|
name: 'oohtml_support',
|
|
112
118
|
type: 'select',
|
|
@@ -115,14 +121,6 @@ export default class Server extends Dotfile {
|
|
|
115
121
|
initial: this.indexOfInitial(CHOICES.oohtml_support, config.oohtml_support),
|
|
116
122
|
validation: ['important'],
|
|
117
123
|
},
|
|
118
|
-
{
|
|
119
|
-
name: 'shared',
|
|
120
|
-
type: 'toggle',
|
|
121
|
-
message: '[shared]: Shared server?',
|
|
122
|
-
active: 'YES',
|
|
123
|
-
inactive: 'NO',
|
|
124
|
-
initial: config.shared,
|
|
125
|
-
},
|
|
126
124
|
];
|
|
127
125
|
}
|
|
128
126
|
}
|
package/src/runtime-pi/Router.js
CHANGED
|
@@ -22,13 +22,13 @@ export default class Router {
|
|
|
22
22
|
*
|
|
23
23
|
* @return void
|
|
24
24
|
*/
|
|
25
|
-
constructor(cx, path) {
|
|
25
|
+
constructor(cx, path = []) {
|
|
26
26
|
this.cx = cx;
|
|
27
27
|
this.path = _isArray(path) ? path : (path + '').split('/').filter(a => a);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* Performs dynamic routing
|
|
31
|
+
* Performs dynamic routing
|
|
32
32
|
*
|
|
33
33
|
* @param array|string method
|
|
34
34
|
* @param Object event
|
|
@@ -59,7 +59,7 @@ export default class Router {
|
|
|
59
59
|
// Broadcast any hints exported by handler
|
|
60
60
|
if (thisTick.exports.hints) { await event.port.post({ ...thisTick.exports.hints, $type: 'handler:hints' }); }
|
|
61
61
|
const methods = _arrFrom(thisTick.method);
|
|
62
|
-
const handler = _isFunction(thisTick.exports) && methods.includes('default') ? thisTick.exports : methods.reduce((_handler, name) => _handler || thisTick.exports[name
|
|
62
|
+
const handler = _isFunction(thisTick.exports) && methods.includes('default') ? thisTick.exports : methods.reduce((_handler, name) => _handler || thisTick.exports[name], null);
|
|
63
63
|
if (handler) {
|
|
64
64
|
// -------------
|
|
65
65
|
// Dynamic response
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @imports
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { _isFunction } from "@webqit/util/js/index.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ---------------------------
|
|
10
|
+
* The base Runtime class
|
|
11
|
+
* ---------------------------
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export default class Runtime {
|
|
15
|
+
constructor(cx, client) {
|
|
16
|
+
this.cx = cx;
|
|
17
|
+
this.cx.runtime = this;
|
|
18
|
+
this.client = _isFunction(client) ? client(this.cx) : client;
|
|
19
|
+
if (!this.client || !this.client.handle) throw new Error(`Application instance must define a ".handle()" method.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* ---------------------------
|
|
4
|
+
* The base RuntimeClient class
|
|
5
|
+
* ---------------------------
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export default class RuntimeClient {
|
|
9
|
+
|
|
10
|
+
constructor(cx) {
|
|
11
|
+
this.cx = cx;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Initializes application itself.
|
|
16
|
+
*
|
|
17
|
+
* @param HttpEvent httpEvent
|
|
18
|
+
* @param Function remoteFetch
|
|
19
|
+
*
|
|
20
|
+
* @return Boolean|undefined
|
|
21
|
+
*/
|
|
22
|
+
async init(httpEvent, remoteFetch) {
|
|
23
|
+
// The app router
|
|
24
|
+
const router = new this.Router(this.cx, '/');
|
|
25
|
+
return router.route(['init'], httpEvent, {}, async event => {
|
|
26
|
+
}, remoteFetch);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
@@ -17,6 +17,7 @@ import xResponse from "../xResponse.js";
|
|
|
17
17
|
import xfetch from '../xfetch.js';
|
|
18
18
|
import xHttpEvent from '../xHttpEvent.js';
|
|
19
19
|
import Workport from './Workport.js';
|
|
20
|
+
import _Runtime from '../Runtime.js';
|
|
20
21
|
|
|
21
22
|
const URL = xURL(whatwag.URL);
|
|
22
23
|
const FormData = xFormData(whatwag.FormData);
|
|
@@ -41,7 +42,7 @@ export {
|
|
|
41
42
|
Observer,
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
export default class Runtime {
|
|
45
|
+
export default class Runtime extends _Runtime {
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
48
|
* Runtime
|
|
@@ -52,15 +53,7 @@ export default class Runtime {
|
|
|
52
53
|
* @return void
|
|
53
54
|
*/
|
|
54
55
|
constructor(cx, clientCallback) {
|
|
55
|
-
|
|
56
|
-
this.cx = cx;
|
|
57
|
-
this.clients = new Map;
|
|
58
|
-
// ---------------
|
|
59
|
-
this.cx.runtime = this;
|
|
60
|
-
let client = clientCallback(this.cx, '*');
|
|
61
|
-
if (!client || !client.handle) throw new Error(`Application instance must define a ".handle()" method.`);
|
|
62
|
-
this.clients.set('*', client);
|
|
63
|
-
|
|
56
|
+
super(cx, clientCallback);
|
|
64
57
|
// -----------------------
|
|
65
58
|
// Initialize location
|
|
66
59
|
Observer.set(this, 'location', new Url(window.document.location));
|
|
@@ -157,27 +150,24 @@ export default class Runtime {
|
|
|
157
150
|
// -----------------------
|
|
158
151
|
// Service Worker && COMM
|
|
159
152
|
if (this.cx.params.service_worker_support) {
|
|
160
|
-
|
|
153
|
+
const workport = new Workport(this.cx.params.worker_filename, { scope: this.cx.params.worker_scope, startMessages: true });
|
|
161
154
|
Observer.set(this, 'workport', workport);
|
|
162
|
-
workport.messaging.listen(async evt => {
|
|
163
|
-
let responsePort = evt.ports[0];
|
|
164
|
-
let client = this.clients.get('*');
|
|
165
|
-
let response = client.alert && await client.alert(evt);
|
|
166
|
-
if (responsePort) {
|
|
167
|
-
if (response instanceof Promise) {
|
|
168
|
-
response.then(data => {
|
|
169
|
-
responsePort.postMessage(data);
|
|
170
|
-
});
|
|
171
|
-
} else {
|
|
172
|
-
responsePort.postMessage(response);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
155
|
}
|
|
177
156
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
157
|
+
// -----------------------
|
|
158
|
+
// Initialize and Hydration
|
|
159
|
+
(async () => {
|
|
160
|
+
let shouldHydrate;
|
|
161
|
+
if (this.client.init) {
|
|
162
|
+
const request = this.generateRequest(this.location);
|
|
163
|
+
const httpEvent = new HttpEvent(request, { srcType: 'initialization' }, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
|
|
164
|
+
shouldHydrate = await this.client.init(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
165
|
+
}
|
|
166
|
+
if (shouldHydrate !== false) {
|
|
167
|
+
this.go(this.location, {}, { srcType: 'hydration' });
|
|
168
|
+
}
|
|
169
|
+
})();
|
|
170
|
+
|
|
181
171
|
}
|
|
182
172
|
|
|
183
173
|
/**
|
|
@@ -211,9 +201,9 @@ export default class Runtime {
|
|
|
211
201
|
}
|
|
212
202
|
|
|
213
203
|
// Generates request object
|
|
214
|
-
generateRequest(href, init) {
|
|
204
|
+
generateRequest(href, init = {}) {
|
|
215
205
|
return new Request(href, {
|
|
216
|
-
signal: this._abortController.signal,
|
|
206
|
+
signal: this._abortController && this._abortController.signal,
|
|
217
207
|
...init,
|
|
218
208
|
headers: {
|
|
219
209
|
'Accept': 'application/json',
|
|
@@ -245,7 +235,7 @@ export default class Runtime {
|
|
|
245
235
|
// ------------
|
|
246
236
|
// Put his forward before instantiating a request and aborting previous
|
|
247
237
|
// Same-page hash-links clicks on chrome recurse here from histroy popstate
|
|
248
|
-
if (detail.srcType !== '
|
|
238
|
+
if (detail.srcType !== 'hydration' && (_before(url.href, '#') === _before(init.referrer, '#') && (init.method || 'GET').toUpperCase() === 'GET')) {
|
|
249
239
|
return new Response(null, { status: 304 }); // Not Modified
|
|
250
240
|
}
|
|
251
241
|
// ------------
|
|
@@ -266,17 +256,14 @@ export default class Runtime {
|
|
|
266
256
|
// ------------
|
|
267
257
|
// Run
|
|
268
258
|
// ------------
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
let httpEvent = new HttpEvent(request, detail, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
|
|
273
|
-
// Response
|
|
274
|
-
let client = this.clients.get('*'), response, finalResponse;
|
|
259
|
+
const request = this.generateRequest(url.href, init);
|
|
260
|
+
const httpEvent = new HttpEvent(request, detail, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
|
|
261
|
+
let response, finalResponse;
|
|
275
262
|
try {
|
|
276
263
|
// ------------
|
|
277
264
|
// Response
|
|
278
265
|
// ------------
|
|
279
|
-
response = await client.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
266
|
+
response = await this.client.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
280
267
|
finalResponse = this.handleResponse(httpEvent, response);
|
|
281
268
|
// ------------
|
|
282
269
|
// Address bar
|
|
@@ -299,12 +286,14 @@ export default class Runtime {
|
|
|
299
286
|
// Rendering
|
|
300
287
|
// ------------
|
|
301
288
|
if (finalResponse.ok && (finalResponse.headers.contentType === 'application/json' || finalResponse.headers.contentType.startsWith('multipart/form-data'))) {
|
|
302
|
-
client.render && await client.render(httpEvent, finalResponse);
|
|
289
|
+
this.client.render && await this.client.render(httpEvent, finalResponse);
|
|
303
290
|
} else if (!finalResponse.ok) {
|
|
304
291
|
if ([404, 500].includes(finalResponse.status)) {
|
|
305
292
|
Observer.set(this.network, 'error', new Error(finalResponse.statusText, { cause: finalResponse.status }));
|
|
306
293
|
}
|
|
307
|
-
|
|
294
|
+
if (!finalResponse.headers.get('Location')) {
|
|
295
|
+
this.client.unrender && await this.client.unrender(httpEvent);
|
|
296
|
+
}
|
|
308
297
|
}
|
|
309
298
|
} catch(e) {
|
|
310
299
|
console.error(e);
|
|
@@ -321,7 +310,7 @@ export default class Runtime {
|
|
|
321
310
|
let href = request;
|
|
322
311
|
if (request instanceof Request) {
|
|
323
312
|
href = request.url;
|
|
324
|
-
} else if (request instanceof
|
|
313
|
+
} else if (request instanceof whatwag.URL) {
|
|
325
314
|
href = request.href;
|
|
326
315
|
}
|
|
327
316
|
Observer.set(this.network, 'remote', href);
|
|
@@ -3,19 +3,16 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import Router from './Router.js';
|
|
6
|
+
import _RuntimeClient from '../RuntimeClient.js';
|
|
6
7
|
|
|
7
|
-
export default class RuntimeClient {
|
|
8
|
+
export default class RuntimeClient extends _RuntimeClient {
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* @param Context cx
|
|
13
|
-
*/
|
|
14
|
-
constructor(cx) {
|
|
15
|
-
this.cx = cx;
|
|
10
|
+
// Returns router class
|
|
11
|
+
get Router() {
|
|
12
|
+
return Router;
|
|
16
13
|
}
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
/**
|
|
19
16
|
* Handles HTTP events.
|
|
20
17
|
*
|
|
21
18
|
* @param HttpEvent httpEvent
|
|
@@ -25,12 +22,12 @@ export default class RuntimeClient {
|
|
|
25
22
|
*/
|
|
26
23
|
async handle(httpEvent, remoteFetch) {
|
|
27
24
|
// The app router
|
|
28
|
-
const router = new Router(this.cx, httpEvent.url.pathname);
|
|
25
|
+
const router = new this.Router(this.cx, httpEvent.url.pathname);
|
|
29
26
|
const handle = async () => {
|
|
30
27
|
// --------
|
|
31
28
|
// ROUTE FOR DATA
|
|
32
29
|
// --------
|
|
33
|
-
|
|
30
|
+
const httpMethodName = httpEvent.request.method.toUpperCase();
|
|
34
31
|
return router.route([httpMethodName, 'default'], httpEvent, {}, async event => {
|
|
35
32
|
return remoteFetch(event.request);
|
|
36
33
|
}, remoteFetch);
|
|
@@ -46,7 +43,7 @@ export default class RuntimeClient {
|
|
|
46
43
|
// Renderer
|
|
47
44
|
async render(httpEvent, response) {
|
|
48
45
|
let data = await response.jsonfy();
|
|
49
|
-
const router = new Router(this.cx, httpEvent.url.pathname);
|
|
46
|
+
const router = new this.Router(this.cx, httpEvent.url.pathname);
|
|
50
47
|
return router.route('render', httpEvent, data, async (httpEvent, data) => {
|
|
51
48
|
// --------
|
|
52
49
|
// OOHTML would waiting for DOM-ready in order to be initialized
|
|
@@ -57,7 +54,7 @@ export default class RuntimeClient {
|
|
|
57
54
|
if (!window.document.state.env) {
|
|
58
55
|
window.document.setState({
|
|
59
56
|
env: 'client',
|
|
60
|
-
onHydration: (httpEvent.detail || {}).srcType === '
|
|
57
|
+
onHydration: (httpEvent.detail || {}).srcType === 'hydration',
|
|
61
58
|
network: this.cx.runtime.network,
|
|
62
59
|
url: this.cx.runtime.location,
|
|
63
60
|
}, { update: true });
|
|
@@ -9,7 +9,7 @@ import { Observer } from './Runtime.js';
|
|
|
9
9
|
export default class Workport {
|
|
10
10
|
|
|
11
11
|
constructor(file, params = {}) {
|
|
12
|
-
this.ready = navigator.serviceWorker ? navigator.serviceWorker.ready : new Promise;
|
|
12
|
+
this.ready = navigator.serviceWorker ? navigator.serviceWorker.ready : new Promise(() => {});
|
|
13
13
|
|
|
14
14
|
// --------
|
|
15
15
|
// Registration and lifecycle
|
|
@@ -83,7 +83,19 @@ export default class Workport {
|
|
|
83
83
|
},
|
|
84
84
|
listen: callback => {
|
|
85
85
|
if (navigator.serviceWorker) {
|
|
86
|
-
navigator.serviceWorker.addEventListener('message',
|
|
86
|
+
navigator.serviceWorker.addEventListener('message', evt => {
|
|
87
|
+
const response = callback(evt);
|
|
88
|
+
let responsePort = evt.ports[0];
|
|
89
|
+
if (responsePort) {
|
|
90
|
+
if (response instanceof Promise) {
|
|
91
|
+
response.then(data => {
|
|
92
|
+
responsePort.postMessage(data);
|
|
93
|
+
});
|
|
94
|
+
} else {
|
|
95
|
+
responsePort.postMessage(response);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
87
99
|
}
|
|
88
100
|
return this.post;
|
|
89
101
|
},
|
|
@@ -12,9 +12,7 @@ import Runtime from './Runtime.js';
|
|
|
12
12
|
export async function start(clientCallback = null) {
|
|
13
13
|
const cx = this || {};
|
|
14
14
|
const defaultClientCallback = _cx => new RuntimeClient(_cx);
|
|
15
|
-
return new Runtime(Context.create(cx),
|
|
16
|
-
return clientCallback ? clientCallback( ...args.concat( defaultClientCallback ) ) : defaultClientCallback( ...args );
|
|
17
|
-
});
|
|
15
|
+
return new Runtime(Context.create(cx), clientCallback || defaultClientCallback);
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
/**
|
|
@@ -6,6 +6,8 @@ import { _any } from '@webqit/util/arr/index.js';
|
|
|
6
6
|
import { urlPattern } from '../../util.js';
|
|
7
7
|
import { HttpEvent, Request, Response, fetch as xfetch, Observer } from '../Runtime.js';
|
|
8
8
|
import Workport from './Workport.js';
|
|
9
|
+
import _Worker from '../../Runtime.js';
|
|
10
|
+
|
|
9
11
|
export {
|
|
10
12
|
URL,
|
|
11
13
|
FormData,
|
|
@@ -25,7 +27,7 @@ export {
|
|
|
25
27
|
* ---------------------------
|
|
26
28
|
*/
|
|
27
29
|
|
|
28
|
-
export default class Worker {
|
|
30
|
+
export default class Worker extends _Worker {
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
33
|
* Runtime
|
|
@@ -36,18 +38,10 @@ export default class Worker {
|
|
|
36
38
|
* @return void
|
|
37
39
|
*/
|
|
38
40
|
constructor(cx, clientCallback) {
|
|
39
|
-
|
|
41
|
+
super(cx, clientCallback);
|
|
40
42
|
// ---------------
|
|
41
|
-
this.cx = cx;
|
|
42
|
-
this.clients = new Map;
|
|
43
43
|
this.mockSessionStore = {};
|
|
44
|
-
//
|
|
45
|
-
this.cx.runtime = this;
|
|
46
|
-
let client = clientCallback(this.cx, '*');
|
|
47
|
-
if (!client || !client.handle) throw new Error(`Application instance must define a ".handle()" method.`);
|
|
48
|
-
this.clients.set('*', client);
|
|
49
|
-
|
|
50
|
-
// -------------
|
|
44
|
+
// --------------
|
|
51
45
|
// ONINSTALL
|
|
52
46
|
self.addEventListener('install', evt => {
|
|
53
47
|
if (this.cx.params.skip_waiting) { self.skipWaiting(); }
|
|
@@ -113,26 +107,17 @@ export default class Worker {
|
|
|
113
107
|
|
|
114
108
|
// -------------
|
|
115
109
|
// Workport
|
|
116
|
-
|
|
110
|
+
const workport = new Workport();
|
|
117
111
|
Observer.set(this, 'workport', workport);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
} else {
|
|
128
|
-
responsePort.postMessage(response);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
workport.push.listen(async evt => {
|
|
133
|
-
let client = this.clients.get('*');
|
|
134
|
-
client.alert && await client.alert(evt);
|
|
135
|
-
});
|
|
112
|
+
|
|
113
|
+
// -------------
|
|
114
|
+
// Initialize
|
|
115
|
+
(async () => {
|
|
116
|
+
if (!this.client.init) return;
|
|
117
|
+
const request = this.generateRequest('/');
|
|
118
|
+
const httpEvent = new HttpEvent(request, { srcType: 'initialization' }, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
|
|
119
|
+
await this.client.init(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
120
|
+
})();
|
|
136
121
|
|
|
137
122
|
}
|
|
138
123
|
|
|
@@ -151,12 +136,12 @@ export default class Worker {
|
|
|
151
136
|
init = { referrer: this.location.href, ...init };
|
|
152
137
|
// ------------
|
|
153
138
|
// The request object
|
|
154
|
-
|
|
139
|
+
const request = await this.generateRequest(url.href, init);
|
|
155
140
|
if (detail.event) {
|
|
156
141
|
Object.defineProperty(detail.event, 'request', { value: request });
|
|
157
142
|
}
|
|
158
143
|
// The navigation event
|
|
159
|
-
|
|
144
|
+
const httpEvent = new HttpEvent(request, detail, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
|
|
160
145
|
httpEvent.port.listen(message => {
|
|
161
146
|
if (message.$type === 'handler:hints' && message.session) {
|
|
162
147
|
// TODO: Sync session data from client
|
|
@@ -166,18 +151,18 @@ export default class Worker {
|
|
|
166
151
|
// Response
|
|
167
152
|
let response;
|
|
168
153
|
if (httpEvent.request.url.startsWith(self.origin)/* && httpEvent.request.mode === 'navigate'*/) {
|
|
169
|
-
response = await this.
|
|
154
|
+
response = await this.client.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
170
155
|
} else {
|
|
171
156
|
response = await this.remoteFetch(httpEvent.request);
|
|
172
157
|
}
|
|
173
|
-
|
|
158
|
+
const finalResponse = this.handleResponse(httpEvent, response);
|
|
174
159
|
// Return value
|
|
175
160
|
return finalResponse;
|
|
176
161
|
}
|
|
177
162
|
|
|
178
163
|
// Generates request object
|
|
179
|
-
generateRequest(href, init) {
|
|
180
|
-
|
|
164
|
+
generateRequest(href, init = {}) {
|
|
165
|
+
const request = new Request(href, init);
|
|
181
166
|
return request;
|
|
182
167
|
}
|
|
183
168
|
|
|
@@ -3,19 +3,16 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import Router from '../Router.js';
|
|
6
|
+
import _WorkerClient from '../../RuntimeClient.js';
|
|
6
7
|
|
|
7
|
-
export default class
|
|
8
|
+
export default class RuntimeClient extends _WorkerClient {
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* @param Context cx
|
|
13
|
-
*/
|
|
14
|
-
constructor(cx) {
|
|
15
|
-
this.cx = cx;
|
|
10
|
+
// Returns router class
|
|
11
|
+
get Router() {
|
|
12
|
+
return Router;
|
|
16
13
|
}
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
/**
|
|
19
16
|
* Handles HTTP events.
|
|
20
17
|
*
|
|
21
18
|
* @param HttpEvent httpEvent
|
|
@@ -25,12 +22,12 @@ export default class WorkerClient {
|
|
|
25
22
|
*/
|
|
26
23
|
async handle(httpEvent, remoteFetch) {
|
|
27
24
|
// The app router
|
|
28
|
-
const router = new Router(this.cx, httpEvent.url.pathname);
|
|
25
|
+
const router = new this.Router(this.cx, httpEvent.url.pathname);
|
|
29
26
|
const handle = async () => {
|
|
30
27
|
// --------
|
|
31
28
|
// ROUTE FOR DATA
|
|
32
29
|
// --------
|
|
33
|
-
|
|
30
|
+
const httpMethodName = httpEvent.request.method.toUpperCase();
|
|
34
31
|
let response = await router.route([httpMethodName, 'default'], httpEvent, {}, async event => {
|
|
35
32
|
return remoteFetch(event.request);
|
|
36
33
|
}, remoteFetch);
|
|
@@ -15,7 +15,17 @@ export default class Workport {
|
|
|
15
15
|
if (!client) {
|
|
16
16
|
self.addEventListener('message', evt => {
|
|
17
17
|
this.client = evt.source;
|
|
18
|
-
callback(evt);
|
|
18
|
+
const response = callback(evt);
|
|
19
|
+
let responsePort = evt.ports[0];
|
|
20
|
+
if (responsePort) {
|
|
21
|
+
if (response instanceof Promise) {
|
|
22
|
+
response.then(data => {
|
|
23
|
+
responsePort.postMessage(data);
|
|
24
|
+
});
|
|
25
|
+
} else {
|
|
26
|
+
responsePort.postMessage(response);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
19
29
|
});
|
|
20
30
|
return this.post;
|
|
21
31
|
}
|
|
@@ -12,9 +12,7 @@ import Worker from './Worker.js';
|
|
|
12
12
|
export async function start(clientCallback = null) {
|
|
13
13
|
const cx = this || {};
|
|
14
14
|
const defaultClientCallback = _cx => new WorkerClient(_cx);
|
|
15
|
-
return new Worker(Context.create(cx),
|
|
16
|
-
return clientCallback ? clientCallback( ...args.concat( defaultClientCallback ) ) : defaultClientCallback( ...args );
|
|
17
|
-
});
|
|
15
|
+
return new Worker(Context.create(cx), clientCallback || defaultClientCallback);
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
/**
|