@webqit/webflo 0.11.39 → 0.11.41
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/README.md +1 -1
- package/docker/Dockerfile +43 -0
- package/docker/README.md +91 -0
- package/docker/package.json +3 -0
- package/package.json +2 -3
- package/src/Context.js +3 -3
- package/src/config-pi/deployment/Layout.js +0 -1
- package/src/config-pi/deployment/Origins.js +7 -0
- package/src/config-pi/deployment/{Virtualization.js → Proxy.js} +3 -3
- package/src/config-pi/deployment/index.js +2 -2
- package/src/config-pi/runtime/Server.js +2 -2
- package/src/deployment-pi/origins/index.js +3 -2
- package/src/runtime-pi/{RuntimeClient.js → Application.js} +2 -2
- package/src/runtime-pi/HttpEvent.js +106 -0
- package/src/runtime-pi/Router.js +2 -3
- package/src/runtime-pi/Runtime.js +3 -3
- package/src/runtime-pi/client/{RuntimeClient.js → Application.js} +12 -4
- package/src/runtime-pi/client/Router.js +4 -3
- package/src/runtime-pi/client/Runtime.js +37 -59
- package/src/runtime-pi/client/Url.js +3 -3
- package/src/runtime-pi/client/Workport.js +1 -1
- package/src/runtime-pi/client/{Storage.js → createStorage.js} +3 -3
- package/src/runtime-pi/client/generate.js +5 -3
- package/src/runtime-pi/client/index.js +4 -4
- package/src/runtime-pi/client/worker/{WorkerClient.js → Application.js} +12 -8
- package/src/runtime-pi/client/worker/{Worker.js → Runtime.js} +25 -27
- package/src/runtime-pi/client/worker/index.js +6 -6
- package/src/runtime-pi/server/{RuntimeClient.js → Application.js} +8 -8
- package/src/runtime-pi/server/Router.js +3 -2
- package/src/runtime-pi/server/Runtime.js +50 -107
- package/src/runtime-pi/server/index.js +4 -4
- package/src/runtime-pi/util-http.js +70 -0
- package/src/runtime-pi/util-url.js +147 -0
- package/src/runtime-pi/xFormData.js +10 -46
- package/src/runtime-pi/xHeaders.js +2 -11
- package/src/runtime-pi/xRequest.js +29 -42
- package/src/runtime-pi/xRequestHeaders.js +20 -23
- package/src/runtime-pi/xResponse.js +19 -15
- package/src/runtime-pi/xResponseHeaders.js +41 -43
- package/src/runtime-pi/xURL.js +71 -77
- package/src/runtime-pi/xfetch.js +15 -6
- package/src/runtime-pi/xxHttpMessage.js +102 -0
- package/src/runtime-pi/client/whatwag.js +0 -27
- package/src/runtime-pi/server/whatwag.js +0 -35
- package/src/runtime-pi/util.js +0 -162
- package/src/runtime-pi/xHttpEvent.js +0 -101
- package/src/runtime-pi/xHttpMessage.js +0 -171
|
@@ -4,40 +4,17 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { _before, _toTitle } from '@webqit/util/str/index.js';
|
|
6
6
|
import { Observer } from '@webqit/oohtml-ssr/apis.js';
|
|
7
|
-
import
|
|
7
|
+
import createStorage from './createStorage.js';
|
|
8
8
|
import Url from './Url.js';
|
|
9
|
-
import
|
|
10
|
-
import * as whatwag from './whatwag.js';
|
|
11
|
-
import xURL from '../xURL.js';
|
|
12
|
-
import xFormData from "../xFormData.js";
|
|
13
|
-
import xRequestHeaders from "../xRequestHeaders.js";
|
|
14
|
-
import xResponseHeaders from "../xResponseHeaders.js";
|
|
9
|
+
import Workport from './Workport.js';
|
|
15
10
|
import xRequest from "../xRequest.js";
|
|
16
11
|
import xResponse from "../xResponse.js";
|
|
17
12
|
import xfetch from '../xfetch.js';
|
|
18
|
-
import
|
|
19
|
-
import Workport from './Workport.js';
|
|
13
|
+
import HttpEvent from '../HttpEvent.js';
|
|
20
14
|
import _Runtime from '../Runtime.js';
|
|
21
|
-
|
|
22
|
-
const URL = xURL(whatwag.URL);
|
|
23
|
-
const FormData = xFormData(whatwag.FormData);
|
|
24
|
-
const ReadableStream = whatwag.ReadableStream;
|
|
25
|
-
const RequestHeaders = xRequestHeaders(whatwag.Headers);
|
|
26
|
-
const ResponseHeaders = xResponseHeaders(whatwag.Headers);
|
|
27
|
-
const Request = xRequest(whatwag.Request, RequestHeaders, FormData, whatwag.Blob);
|
|
28
|
-
const Response = xResponse(whatwag.Response, ResponseHeaders, FormData, whatwag.Blob);
|
|
29
|
-
const fetch = xfetch(whatwag.fetch, Request);
|
|
30
|
-
const HttpEvent = xHttpEvent(Request, Response, URL);
|
|
15
|
+
import { params } from '../util-url.js';
|
|
31
16
|
|
|
32
17
|
export {
|
|
33
|
-
URL,
|
|
34
|
-
FormData,
|
|
35
|
-
ReadableStream,
|
|
36
|
-
RequestHeaders,
|
|
37
|
-
ResponseHeaders,
|
|
38
|
-
Request,
|
|
39
|
-
Response,
|
|
40
|
-
fetch,
|
|
41
18
|
HttpEvent,
|
|
42
19
|
Observer,
|
|
43
20
|
}
|
|
@@ -48,12 +25,12 @@ export default class Runtime extends _Runtime {
|
|
|
48
25
|
* Runtime
|
|
49
26
|
*
|
|
50
27
|
* @param Object cx
|
|
51
|
-
* @param Function
|
|
28
|
+
* @param Function applicationInstance
|
|
52
29
|
*
|
|
53
30
|
* @return void
|
|
54
31
|
*/
|
|
55
|
-
constructor(cx,
|
|
56
|
-
super(cx,
|
|
32
|
+
constructor(cx, applicationInstance) {
|
|
33
|
+
super(cx, applicationInstance);
|
|
57
34
|
// -----------------------
|
|
58
35
|
// Initialize location
|
|
59
36
|
Observer.set(this, 'location', new Url(window.document.location));
|
|
@@ -124,11 +101,11 @@ export default class Runtime extends _Runtime {
|
|
|
124
101
|
formData.set(submitter.name, submitter.value);
|
|
125
102
|
}
|
|
126
103
|
if (submitParams.method.toUpperCase() === 'GET') {
|
|
127
|
-
var query =
|
|
104
|
+
var query = params.parse(actionEl.search);
|
|
128
105
|
Array.from(formData.entries()).forEach(_entry => {
|
|
129
|
-
|
|
106
|
+
params.set(query, _entry[0], _entry[1]);
|
|
130
107
|
});
|
|
131
|
-
actionEl.search =
|
|
108
|
+
actionEl.search = params.stringify(query);
|
|
132
109
|
formData = null;
|
|
133
110
|
}
|
|
134
111
|
this.go(Url.copy(actionEl), {
|
|
@@ -150,7 +127,8 @@ export default class Runtime extends _Runtime {
|
|
|
150
127
|
// -----------------------
|
|
151
128
|
// Service Worker && COMM
|
|
152
129
|
if (this.cx.params.service_worker_support) {
|
|
153
|
-
const
|
|
130
|
+
const { public_base_url: base, worker_filename: filename, worker_scope: scope } = this.cx.params;
|
|
131
|
+
const workport = new Workport(base + filename, { scope, startMessages: true });
|
|
154
132
|
Observer.set(this, 'workport', workport);
|
|
155
133
|
}
|
|
156
134
|
|
|
@@ -158,10 +136,10 @@ export default class Runtime extends _Runtime {
|
|
|
158
136
|
// Initialize and Hydration
|
|
159
137
|
(async () => {
|
|
160
138
|
let shouldHydrate;
|
|
161
|
-
if (this.
|
|
139
|
+
if (this.app.init) {
|
|
162
140
|
const request = this.generateRequest(this.location);
|
|
163
141
|
const httpEvent = new HttpEvent(request, { srcType: 'initialization' }, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
|
|
164
|
-
shouldHydrate = await this.
|
|
142
|
+
shouldHydrate = await this.app.init(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
165
143
|
}
|
|
166
144
|
if (shouldHydrate !== false) {
|
|
167
145
|
this.go(this.location, {}, { srcType: 'hydration' });
|
|
@@ -185,7 +163,7 @@ export default class Runtime extends _Runtime {
|
|
|
185
163
|
|
|
186
164
|
// Check is-spa-route
|
|
187
165
|
isSpaRoute(url, e = undefined) {
|
|
188
|
-
url = typeof url === 'string' ? new
|
|
166
|
+
url = typeof url === 'string' ? new URL(url, this.location.origin) : url;
|
|
189
167
|
if (url.origin && url.origin !== this.location.origin) return false;
|
|
190
168
|
if (e && (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)) return false;
|
|
191
169
|
if (!this.cx.params.routing) return true;
|
|
@@ -202,7 +180,7 @@ export default class Runtime extends _Runtime {
|
|
|
202
180
|
|
|
203
181
|
// Generates request object
|
|
204
182
|
generateRequest(href, init = {}) {
|
|
205
|
-
return new
|
|
183
|
+
return new xRequest(href, {
|
|
206
184
|
signal: this._abortController && this._abortController.signal,
|
|
207
185
|
...init,
|
|
208
186
|
headers: {
|
|
@@ -216,8 +194,8 @@ export default class Runtime extends _Runtime {
|
|
|
216
194
|
}
|
|
217
195
|
|
|
218
196
|
// Generates session object
|
|
219
|
-
|
|
220
|
-
return
|
|
197
|
+
createStorage(e, id = null, persistent = false) {
|
|
198
|
+
return createStorage(id, persistent);
|
|
221
199
|
}
|
|
222
200
|
|
|
223
201
|
/**
|
|
@@ -230,13 +208,13 @@ export default class Runtime extends _Runtime {
|
|
|
230
208
|
* @return Response
|
|
231
209
|
*/
|
|
232
210
|
async go(url, init = {}, detail = {}) {
|
|
233
|
-
url = typeof url === 'string' ? new
|
|
211
|
+
url = typeof url === 'string' ? new URL(url, this.location.origin) : url;
|
|
234
212
|
init = { referrer: this.location.href, ...init };
|
|
235
213
|
// ------------
|
|
236
214
|
// Put his forward before instantiating a request and aborting previous
|
|
237
215
|
// Same-page hash-links clicks on chrome recurse here from histroy popstate
|
|
238
|
-
if (
|
|
239
|
-
return new
|
|
216
|
+
if (![ 'hydration', 'rdr' ].includes(detail.srcType) && (_before(url.href, '#') === _before(init.referrer, '#') && (init.method || 'GET').toUpperCase() === 'GET')) {
|
|
217
|
+
return new xResponse(null, { status: 304 }); // Not Modified
|
|
240
218
|
}
|
|
241
219
|
// ------------
|
|
242
220
|
if (this._abortController) {
|
|
@@ -257,23 +235,21 @@ export default class Runtime extends _Runtime {
|
|
|
257
235
|
// Run
|
|
258
236
|
// ------------
|
|
259
237
|
const request = this.generateRequest(url.href, init);
|
|
260
|
-
const httpEvent = new HttpEvent(request, detail, (id = null, persistent = false) => this.
|
|
238
|
+
const httpEvent = new HttpEvent(request, detail, (id = null, persistent = false) => this.createStorage(httpEvent, id, persistent));
|
|
261
239
|
let response, finalResponse;
|
|
262
240
|
try {
|
|
263
241
|
// ------------
|
|
264
242
|
// Response
|
|
265
243
|
// ------------
|
|
266
|
-
response = await this.
|
|
244
|
+
response = await this.app.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
267
245
|
finalResponse = this.handleResponse(httpEvent, response);
|
|
268
246
|
// ------------
|
|
269
247
|
// Address bar
|
|
270
248
|
// ------------
|
|
271
|
-
if (response.redirected) {
|
|
272
|
-
Observer.set(this.location, { href: response.url }, { detail: { redirected: true }, });
|
|
273
|
-
Observer.set(this.network, 'requesting', null);
|
|
249
|
+
if (response && response.redirected) {
|
|
250
|
+
Observer.set(this.location, { href: response.url }, { detail: { redirected: true, ...detail }, });
|
|
274
251
|
} else if (![302, 301].includes(finalResponse.status)) {
|
|
275
|
-
Observer.set(this.location, Url.copy(url)/* copy() is important
|
|
276
|
-
Observer.set(this.network, 'requesting', null);
|
|
252
|
+
Observer.set(this.location, Url.copy(url)/* copy() is important */, { detail });
|
|
277
253
|
}
|
|
278
254
|
// ------------
|
|
279
255
|
// States
|
|
@@ -286,19 +262,19 @@ export default class Runtime extends _Runtime {
|
|
|
286
262
|
// Rendering
|
|
287
263
|
// ------------
|
|
288
264
|
if (finalResponse.ok && (finalResponse.headers.contentType === 'application/json' || finalResponse.headers.contentType.startsWith('multipart/form-data'))) {
|
|
289
|
-
this.
|
|
265
|
+
this.app.render && await this.app.render(httpEvent, finalResponse);
|
|
290
266
|
} else if (!finalResponse.ok) {
|
|
291
267
|
if ([404, 500].includes(finalResponse.status)) {
|
|
292
268
|
Observer.set(this.network, 'error', new Error(finalResponse.statusText, { cause: finalResponse.status }));
|
|
293
269
|
}
|
|
294
270
|
if (!finalResponse.headers.get('Location')) {
|
|
295
|
-
this.
|
|
271
|
+
this.app.unrender && await this.app.unrender(httpEvent);
|
|
296
272
|
}
|
|
297
273
|
}
|
|
298
274
|
} catch(e) {
|
|
299
275
|
console.error(e);
|
|
300
276
|
Observer.set(this.network, 'error', { ...e, retry: () => this.go(url, init = {}, detail) });
|
|
301
|
-
finalResponse = new
|
|
277
|
+
finalResponse = new xResponse(null, { status: 500, statusText: e.message });
|
|
302
278
|
}
|
|
303
279
|
// ------------
|
|
304
280
|
// Return value
|
|
@@ -310,35 +286,37 @@ export default class Runtime extends _Runtime {
|
|
|
310
286
|
let href = request;
|
|
311
287
|
if (request instanceof Request) {
|
|
312
288
|
href = request.url;
|
|
313
|
-
} else if (request instanceof
|
|
289
|
+
} else if (request instanceof URL) {
|
|
314
290
|
href = request.href;
|
|
315
291
|
}
|
|
316
292
|
Observer.set(this.network, 'remote', href);
|
|
317
|
-
let _response =
|
|
293
|
+
let _response = xfetch(request, ...args);
|
|
318
294
|
// This catch() is NOT intended to handle failure of the fetch
|
|
319
295
|
_response.catch(e => Observer.set(this.network, 'error', e));
|
|
320
296
|
// Return xResponse
|
|
321
297
|
return _response.then(async response => {
|
|
322
298
|
// Stop loading status
|
|
323
299
|
Observer.set(this.network, 'remote', null);
|
|
324
|
-
return new
|
|
300
|
+
return new xResponse(response);
|
|
325
301
|
});
|
|
326
302
|
}
|
|
327
303
|
|
|
328
304
|
// Handles response object
|
|
329
305
|
handleResponse(e, response) {
|
|
330
|
-
if (
|
|
306
|
+
if (typeof response === 'undefined') { response = new xResponse(undefined, { status: 404 }); }
|
|
307
|
+
else if (!(response instanceof xResponse)) { response = new xResponse(response); }
|
|
308
|
+
Observer.set(this.network, 'requesting', null);
|
|
309
|
+
Observer.set(this.network, 'redirecting', null);
|
|
331
310
|
if (!response.redirected) {
|
|
332
311
|
let location = response.headers.get('Location');
|
|
333
312
|
if (location) {
|
|
334
313
|
let xActualRedirectCode = parseInt(response.headers.get('X-Redirect-Code'));
|
|
314
|
+
Observer.set(this.network, 'redirecting', location);
|
|
335
315
|
if (xActualRedirectCode && response.status === this._xRedirectCode) {
|
|
336
316
|
response.attrs.status = xActualRedirectCode;
|
|
337
|
-
Observer.set(this.network, 'redirecting', location);
|
|
338
317
|
window.location = location;
|
|
339
318
|
} else if ([302,301].includes(response.status)) {
|
|
340
319
|
if (!this.isSpaRoute(location)) {
|
|
341
|
-
Observer.set(this.network, 'redirecting', location);
|
|
342
320
|
window.location = location;
|
|
343
321
|
} else {
|
|
344
322
|
this.go(location, {}, { srcType: 'rdr' });
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { _with } from '@webqit/util/obj/index.js';
|
|
6
6
|
import { _isArray, _isObject, _isTypeObject, _isString, _isEmpty } from '@webqit/util/js/index.js';
|
|
7
|
-
import { wwwFormUnserialize, wwwFormSerialize } from '../util.js';
|
|
8
7
|
import { Observer } from './Runtime.js';
|
|
8
|
+
import { params } from '../util-url.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* ---------------------------
|
|
@@ -169,7 +169,7 @@ export default class Url {
|
|
|
169
169
|
* @return object
|
|
170
170
|
*/
|
|
171
171
|
static toQuery(search) {
|
|
172
|
-
return
|
|
172
|
+
return params.parse(search);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
/**
|
|
@@ -180,7 +180,7 @@ export default class Url {
|
|
|
180
180
|
* @return string
|
|
181
181
|
*/
|
|
182
182
|
static toSearch(query) {
|
|
183
|
-
var search =
|
|
183
|
+
var search = params.stringify(query);
|
|
184
184
|
return search ? '?' + search : '';
|
|
185
185
|
}}
|
|
186
186
|
|
|
@@ -29,7 +29,7 @@ export default function(namespace = null, persistent = false) {
|
|
|
29
29
|
return true;
|
|
30
30
|
}
|
|
31
31
|
if (event.type === 'has') {
|
|
32
|
-
for(
|
|
32
|
+
for(let i = 0; i < window[storeType].length; i ++){
|
|
33
33
|
if (window[storeType].key(i) === key) {
|
|
34
34
|
return true;
|
|
35
35
|
}
|
|
@@ -37,8 +37,8 @@ export default function(namespace = null, persistent = false) {
|
|
|
37
37
|
return false;
|
|
38
38
|
}
|
|
39
39
|
if (event.type === 'ownKeys') {
|
|
40
|
-
|
|
41
|
-
for(
|
|
40
|
+
const keys = [];
|
|
41
|
+
for(let i = 0; i < window[storeType].length; i ++){
|
|
42
42
|
keys.push(window[storeType].key(i));
|
|
43
43
|
};
|
|
44
44
|
return keys;
|
|
@@ -11,7 +11,7 @@ import { _afterLast, _beforeLast } from '@webqit/util/str/index.js';
|
|
|
11
11
|
import { _isObject, _isArray } from '@webqit/util/js/index.js';
|
|
12
12
|
import { jsFile } from '@webqit/backpack/src/dotfile/index.js';
|
|
13
13
|
import { gzipSync, brotliCompressSync } from 'zlib';
|
|
14
|
-
import {
|
|
14
|
+
import { pattern } from '../util-url.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* @generate
|
|
@@ -152,12 +152,14 @@ export async function generate() {
|
|
|
152
152
|
// >> Modules import
|
|
153
153
|
gen.imports[`${dirSelf}/worker/index.js`] = `{ start }`;
|
|
154
154
|
gen.code.push(``);
|
|
155
|
+
gen.code.push(`self.WebQit = {}`);
|
|
156
|
+
gen.code.push(``);
|
|
155
157
|
// ------------------
|
|
156
158
|
// Bundle
|
|
157
159
|
if (workerConfig.cache_only_urls.length) {
|
|
158
160
|
// Separate URLs from patterns
|
|
159
161
|
let [ urls, patterns ] = workerConfig.cache_only_urls.reduce(([ urls, patterns ], url) => {
|
|
160
|
-
let patternInstance =
|
|
162
|
+
let patternInstance = pattern(url, 'http://localhost'),
|
|
161
163
|
isPattern = patternInstance.isPattern();
|
|
162
164
|
if (isPattern && (patternInstance.pattern.pattern.hostname !== 'localhost' || patternInstance.pattern.pattern.port)) {
|
|
163
165
|
throw new Error(`Pattern URLs must have no origin part. Recieved "${url}".`);
|
|
@@ -233,7 +235,7 @@ function declareStart(gen, routesDir, targetDir, paramsObj, routing) {
|
|
|
233
235
|
// ------------------
|
|
234
236
|
// >> Startup
|
|
235
237
|
gen.code.push(`// >> Startup`);
|
|
236
|
-
gen.code.push(`start.call({ layout, params })`);
|
|
238
|
+
gen.code.push(`WebQit.app = await start.call({ layout, params })`);
|
|
237
239
|
}
|
|
238
240
|
|
|
239
241
|
/**
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import Context from './Context.js';
|
|
6
|
-
import
|
|
6
|
+
import Application from './Application.js';
|
|
7
7
|
import Runtime from './Runtime.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @start
|
|
11
11
|
*/
|
|
12
|
-
export async function start(
|
|
12
|
+
export async function start(applicationInstance = null) {
|
|
13
13
|
const cx = this || {};
|
|
14
|
-
const
|
|
15
|
-
return new Runtime(Context.create(cx),
|
|
14
|
+
const defaultApplicationInstance = _cx => new Application(_cx);
|
|
15
|
+
return new Runtime(Context.create(cx), applicationInstance || defaultApplicationInstance);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import Router from '../Router.js';
|
|
6
|
-
import
|
|
6
|
+
import _Application from '../../Application.js';
|
|
7
7
|
|
|
8
|
-
export default class
|
|
8
|
+
export default class Application extends _Application {
|
|
9
9
|
|
|
10
10
|
// Returns router class
|
|
11
11
|
get Router() {
|
|
@@ -27,14 +27,18 @@ export default class RuntimeClient extends _WorkerClient {
|
|
|
27
27
|
// --------
|
|
28
28
|
// ROUTE FOR DATA
|
|
29
29
|
// --------
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
return router.route([httpEvent.request.method, 'default'], httpEvent, {}, async event => {
|
|
31
|
+
if (event !== httpEvent) {
|
|
32
|
+
// This was nexted()
|
|
33
|
+
if (!event.request.headers.has('Accept')) {
|
|
34
|
+
event.request.headers.set('Accept', 'application/json');
|
|
35
|
+
}
|
|
36
|
+
if (event.request.body && !event.request.headers.has('Content-Type')) {
|
|
37
|
+
event.request.headers.set('Content-Type', 'application/json');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
32
40
|
return remoteFetch(event.request);
|
|
33
41
|
}, remoteFetch);
|
|
34
|
-
if (!(response instanceof httpEvent.Response)) {
|
|
35
|
-
response = httpEvent.Response.compat(response);
|
|
36
|
-
}
|
|
37
|
-
return response;
|
|
38
42
|
};
|
|
39
43
|
return handle();
|
|
40
44
|
}
|
|
@@ -3,42 +3,38 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import { _any } from '@webqit/util/arr/index.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { Observer } from '@webqit/oohtml-ssr/apis.js';
|
|
7
|
+
import { pattern } from '../../util-url.js';
|
|
8
8
|
import Workport from './Workport.js';
|
|
9
|
-
import
|
|
9
|
+
import _Runtime from '../../Runtime.js';
|
|
10
|
+
import xRequest from "../../xRequest.js";
|
|
11
|
+
import xResponse from "../../xResponse.js";
|
|
12
|
+
import xfetch from '../../xfetch.js';
|
|
13
|
+
import HttpEvent from '../../HttpEvent.js';
|
|
10
14
|
|
|
11
15
|
export {
|
|
12
|
-
URL,
|
|
13
|
-
FormData,
|
|
14
|
-
ReadableStream,
|
|
15
|
-
RequestHeaders,
|
|
16
|
-
ResponseHeaders,
|
|
17
|
-
Request,
|
|
18
|
-
Response,
|
|
19
|
-
fetch,
|
|
20
16
|
HttpEvent,
|
|
21
17
|
Observer,
|
|
22
|
-
}
|
|
18
|
+
}
|
|
23
19
|
|
|
24
20
|
/**
|
|
25
21
|
* ---------------------------
|
|
26
|
-
* The
|
|
22
|
+
* The Runtime Initializer
|
|
27
23
|
* ---------------------------
|
|
28
24
|
*/
|
|
29
25
|
|
|
30
|
-
export default class
|
|
26
|
+
export default class Runtime extends _Runtime {
|
|
31
27
|
|
|
32
28
|
/**
|
|
33
29
|
* Runtime
|
|
34
30
|
*
|
|
35
31
|
* @param Object cx
|
|
36
|
-
* @param Function
|
|
32
|
+
* @param Function applicationInstance
|
|
37
33
|
*
|
|
38
34
|
* @return void
|
|
39
35
|
*/
|
|
40
|
-
constructor(cx,
|
|
41
|
-
super(cx,
|
|
36
|
+
constructor(cx, applicationInstance) {
|
|
37
|
+
super(cx, applicationInstance);
|
|
42
38
|
// ---------------
|
|
43
39
|
this.mockSessionStore = {};
|
|
44
40
|
// --------------
|
|
@@ -50,7 +46,7 @@ export default class Worker extends _Worker {
|
|
|
50
46
|
// Add files to cache
|
|
51
47
|
evt.waitUntil( self.caches.open(this.cx.params.cache_name).then(cache => {
|
|
52
48
|
if (this.cx.logger) { this.cx.logger.log('[ServiceWorker] Pre-caching resources.'); }
|
|
53
|
-
const cache_only_urls = (this.cx.params.cache_only_urls || []).map(c => c.trim()).filter(c => c && !
|
|
49
|
+
const cache_only_urls = (this.cx.params.cache_only_urls || []).map(c => c.trim()).filter(c => c && !pattern(c, self.origin).isPattern());
|
|
54
50
|
return cache.addAll(cache_only_urls);
|
|
55
51
|
}) );
|
|
56
52
|
}
|
|
@@ -93,7 +89,7 @@ export default class Worker extends _Worker {
|
|
|
93
89
|
event.respondWith((async (req, evt) => {
|
|
94
90
|
let requestingClient = await self.clients.get(event.clientId);
|
|
95
91
|
this.workport.setCurrentClient(requestingClient);
|
|
96
|
-
const [ url, requestInit ] = await
|
|
92
|
+
const [ url, requestInit ] = await xRequest.rip(req);
|
|
97
93
|
// Now, the following is key:
|
|
98
94
|
// The browser likes to use "force-cache" for "navigate" requests, when, e.g: re-entering your site with the back button
|
|
99
95
|
// Problem here, force-cache forces out JSON not HTML as per webflo's design.
|
|
@@ -113,10 +109,10 @@ export default class Worker extends _Worker {
|
|
|
113
109
|
// -------------
|
|
114
110
|
// Initialize
|
|
115
111
|
(async () => {
|
|
116
|
-
if (!this.
|
|
112
|
+
if (!this.app.init) return;
|
|
117
113
|
const request = this.generateRequest('/');
|
|
118
114
|
const httpEvent = new HttpEvent(request, { srcType: 'initialization' }, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
|
|
119
|
-
await this.
|
|
115
|
+
await this.app.init(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
120
116
|
})();
|
|
121
117
|
|
|
122
118
|
}
|
|
@@ -132,11 +128,12 @@ export default class Worker extends _Worker {
|
|
|
132
128
|
*/
|
|
133
129
|
async go(url, init = {}, detail = {}) {
|
|
134
130
|
// ------------
|
|
135
|
-
url = typeof url === 'string' ? new URL(url) : url;
|
|
131
|
+
url = typeof url === 'string' ? new URL(url, self.location.origin) : url;
|
|
136
132
|
init = { referrer: this.location.href, ...init };
|
|
137
133
|
// ------------
|
|
138
134
|
// The request object
|
|
139
135
|
const request = await this.generateRequest(url.href, init);
|
|
136
|
+
|
|
140
137
|
if (detail.event) {
|
|
141
138
|
Object.defineProperty(detail.event, 'request', { value: request });
|
|
142
139
|
}
|
|
@@ -151,7 +148,7 @@ export default class Worker extends _Worker {
|
|
|
151
148
|
// Response
|
|
152
149
|
let response;
|
|
153
150
|
if (httpEvent.request.url.startsWith(self.origin)/* && httpEvent.request.mode === 'navigate'*/) {
|
|
154
|
-
response = await this.
|
|
151
|
+
response = await this.app.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
155
152
|
} else {
|
|
156
153
|
response = await this.remoteFetch(httpEvent.request);
|
|
157
154
|
}
|
|
@@ -162,7 +159,7 @@ export default class Worker extends _Worker {
|
|
|
162
159
|
|
|
163
160
|
// Generates request object
|
|
164
161
|
generateRequest(href, init = {}) {
|
|
165
|
-
const request = new
|
|
162
|
+
const request = new xRequest(href, init);
|
|
166
163
|
return request;
|
|
167
164
|
}
|
|
168
165
|
|
|
@@ -179,7 +176,7 @@ export default class Worker extends _Worker {
|
|
|
179
176
|
if (arguments.length > 1) {
|
|
180
177
|
request = this.generateRequest(request, ...args);
|
|
181
178
|
}
|
|
182
|
-
const matchUrl = (patterns, url) => _any((patterns || []).map(p => p.trim()).filter(p => p), p =>
|
|
179
|
+
const matchUrl = (patterns, url) => _any((patterns || []).map(p => p.trim()).filter(p => p), p => pattern(p, self.origin).test(url));
|
|
183
180
|
const execFetch = () => {
|
|
184
181
|
// network_first_urls
|
|
185
182
|
if (!this.cx.params.default_fetching_strategy || this.cx.params.default_fetching_strategy === 'network-first' || matchUrl(this.cx.params.network_first_urls, request.url)) {
|
|
@@ -206,7 +203,7 @@ export default class Worker extends _Worker {
|
|
|
206
203
|
// This catch() is NOT intended to handle failure of the fetch
|
|
207
204
|
response.catch(e => Observer.set(this.network, 'error', e.message));
|
|
208
205
|
// Return xResponse
|
|
209
|
-
return response.then(_response =>
|
|
206
|
+
return response.then(_response => xResponse.compat(_response));
|
|
210
207
|
}
|
|
211
208
|
|
|
212
209
|
// Caching strategy: network_first
|
|
@@ -265,7 +262,8 @@ export default class Worker extends _Worker {
|
|
|
265
262
|
|
|
266
263
|
// Handles response object
|
|
267
264
|
handleResponse(e, response) {
|
|
268
|
-
if (
|
|
265
|
+
if (typeof response === 'undefined') { response = new xResponse(undefined, { status: 404 }); }
|
|
266
|
+
else if (!(response instanceof xResponse)) { response = xResponse.compat(response); }
|
|
269
267
|
return response;
|
|
270
268
|
}
|
|
271
269
|
|
|
@@ -3,19 +3,19 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import Context from './Context.js';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import Application from './Application.js';
|
|
7
|
+
import Runtime from './Runtime.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @start
|
|
11
11
|
*/
|
|
12
|
-
export async function start(
|
|
12
|
+
export async function start(applicationInstance = null) {
|
|
13
13
|
const cx = this || {};
|
|
14
|
-
const
|
|
15
|
-
return new
|
|
14
|
+
const defaultApplicationInstance = _cx => new Application(_cx);
|
|
15
|
+
return new Runtime(Context.create(cx), applicationInstance || defaultApplicationInstance);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* @APIS
|
|
20
20
|
*/
|
|
21
|
-
export * as APIS from './
|
|
21
|
+
export * as APIS from './Runtime.js';
|
|
@@ -6,12 +6,12 @@ import Fs from 'fs';
|
|
|
6
6
|
import Path from 'path';
|
|
7
7
|
import QueryString from 'querystring';
|
|
8
8
|
import Router from './Router.js';
|
|
9
|
-
import
|
|
9
|
+
import _Application from '../Application.js';
|
|
10
10
|
|
|
11
|
-
export default class
|
|
11
|
+
export default class Application extends _Application {
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* Application
|
|
15
15
|
*
|
|
16
16
|
* @param Context cx
|
|
17
17
|
*/
|
|
@@ -40,8 +40,7 @@ export default class RuntimeClient extends _RuntimeClient {
|
|
|
40
40
|
// --------
|
|
41
41
|
// ROUTE FOR DATA
|
|
42
42
|
// --------
|
|
43
|
-
|
|
44
|
-
let response = await router.route([httpMethodName, 'default'], httpEvent, {}, async event => {
|
|
43
|
+
let response = await router.route([httpEvent.request.method, 'default'], httpEvent, {}, async event => {
|
|
45
44
|
return router.file(event);
|
|
46
45
|
}, remoteFetch);
|
|
47
46
|
if (!(response instanceof httpEvent.Response)) {
|
|
@@ -50,14 +49,15 @@ export default class RuntimeClient extends _RuntimeClient {
|
|
|
50
49
|
// --------
|
|
51
50
|
// Rendering
|
|
52
51
|
// --------
|
|
53
|
-
if (response.ok && response.
|
|
52
|
+
if (response.ok && response.meta.type === 'json' && typeof response.meta.body === 'object' && response.meta.body && httpEvent.request.headers.accept.match('text/html')) {
|
|
54
53
|
let rendering = await this.render(httpEvent, router, response);
|
|
55
54
|
if (typeof rendering !== 'string' && !(typeof rendering === 'object' && rendering && typeof rendering.toString === 'function')) {
|
|
56
55
|
throw new Error('render() must return a string response or an object that implements toString()..');
|
|
57
56
|
}
|
|
58
|
-
|
|
57
|
+
rendering = rendering.toString();
|
|
58
|
+
response = new httpEvent.Response(rendering, {
|
|
59
|
+
headers: { ...response.headers.json(), contentType: 'text/html', contentLength: (new Blob([rendering]).size) },
|
|
59
60
|
status: response.status,
|
|
60
|
-
headers: { ...response.headers.json(), contentType: 'text/html' },
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -17,6 +17,7 @@ import _Router from '../Router.js';
|
|
|
17
17
|
export default class Router extends _Router {
|
|
18
18
|
|
|
19
19
|
async readTick(thisTick) {
|
|
20
|
+
thisTick = { ...thisTick };
|
|
20
21
|
if (thisTick.trail) {
|
|
21
22
|
thisTick.currentSegment = thisTick.destination[thisTick.trail.length];
|
|
22
23
|
thisTick.currentSegmentOnFile = [ thisTick.currentSegment, '-' ].reduce((_segmentOnFile, _seg) => {
|
|
@@ -27,8 +28,8 @@ export default class Router extends _Router {
|
|
|
27
28
|
Fs.existsSync(Path.join(this.cx.CWD, this.cx.layout.SERVER_DIR, _currentPath)) ? { seg: _seg, dirExists: true } : _segmentOnFile
|
|
28
29
|
);
|
|
29
30
|
}, { seg: null });
|
|
30
|
-
thisTick.trail.
|
|
31
|
-
thisTick.trailOnFile.
|
|
31
|
+
thisTick.trail = thisTick.trail.concat(thisTick.currentSegment);
|
|
32
|
+
thisTick.trailOnFile = thisTick.trailOnFile.concat(thisTick.currentSegmentOnFile.seg);
|
|
32
33
|
thisTick.exports = thisTick.currentSegmentOnFile.index ? await import(Url.pathToFileURL(thisTick.currentSegmentOnFile.index)) : undefined;
|
|
33
34
|
} else {
|
|
34
35
|
thisTick.trail = [];
|