@webqit/webflo 0.11.21 → 0.11.24
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/.gitignore +7 -7
- package/LICENSE +20 -20
- package/README.md +2074 -2071
- package/package.json +82 -82
- package/src/Context.js +79 -79
- package/src/config-pi/deployment/Env.js +69 -69
- package/src/config-pi/deployment/Layout.js +65 -65
- package/src/config-pi/deployment/Origins.js +133 -133
- package/src/config-pi/deployment/Virtualization.js +65 -65
- package/src/config-pi/deployment/index.js +17 -17
- package/src/config-pi/index.js +15 -15
- package/src/config-pi/runtime/Client.js +101 -101
- package/src/config-pi/runtime/Server.js +128 -128
- package/src/config-pi/runtime/client/Worker.js +135 -135
- package/src/config-pi/runtime/client/index.js +11 -11
- package/src/config-pi/runtime/index.js +17 -17
- package/src/config-pi/runtime/server/Headers.js +77 -77
- package/src/config-pi/runtime/server/Redirects.js +73 -73
- package/src/config-pi/runtime/server/index.js +13 -13
- package/src/config-pi/static/Manifest.js +321 -321
- package/src/config-pi/static/Ssg.js +51 -51
- package/src/config-pi/static/index.js +13 -13
- package/src/deployment-pi/index.js +10 -10
- package/src/deployment-pi/origins/index.js +215 -215
- package/src/index.js +19 -19
- package/src/runtime-pi/Router.js +131 -131
- package/src/runtime-pi/client/Context.js +6 -6
- package/src/runtime-pi/client/Router.js +47 -47
- package/src/runtime-pi/client/Runtime.js +357 -341
- package/src/runtime-pi/client/RuntimeClient.js +98 -98
- package/src/runtime-pi/client/Storage.js +56 -56
- package/src/runtime-pi/client/Url.js +205 -205
- package/src/runtime-pi/client/Workport.js +163 -163
- package/src/runtime-pi/client/generate.js +467 -467
- package/src/runtime-pi/client/index.js +23 -23
- package/src/runtime-pi/client/oohtml/full.js +6 -6
- package/src/runtime-pi/client/oohtml/namespacing.js +6 -6
- package/src/runtime-pi/client/oohtml/scripting.js +7 -7
- package/src/runtime-pi/client/oohtml/templating.js +7 -7
- package/src/runtime-pi/client/whatwag.js +27 -27
- package/src/runtime-pi/client/worker/Context.js +6 -6
- package/src/runtime-pi/client/worker/Worker.js +291 -291
- package/src/runtime-pi/client/worker/WorkerClient.js +46 -46
- package/src/runtime-pi/client/worker/Workport.js +79 -79
- package/src/runtime-pi/client/worker/index.js +23 -23
- package/src/runtime-pi/index.js +13 -13
- package/src/runtime-pi/server/Context.js +15 -15
- package/src/runtime-pi/server/Router.js +157 -157
- package/src/runtime-pi/server/Runtime.js +547 -547
- package/src/runtime-pi/server/RuntimeClient.js +112 -112
- package/src/runtime-pi/server/index.js +23 -23
- package/src/runtime-pi/server/whatwag.js +35 -35
- package/src/runtime-pi/util.js +162 -162
- package/src/runtime-pi/xFormData.js +59 -59
- package/src/runtime-pi/xHeaders.js +87 -87
- package/src/runtime-pi/xHttpEvent.js +92 -92
- package/src/runtime-pi/xHttpMessage.js +179 -179
- package/src/runtime-pi/xRequest.js +73 -73
- package/src/runtime-pi/xRequestHeaders.js +94 -94
- package/src/runtime-pi/xResponse.js +68 -68
- package/src/runtime-pi/xResponseHeaders.js +109 -109
- package/src/runtime-pi/xURL.js +110 -110
- package/src/runtime-pi/xfetch.js +6 -6
- package/src/services-pi/certbot/http-auth-hook.js +22 -22
- package/src/services-pi/certbot/http-cleanup-hook.js +22 -22
- package/src/services-pi/certbot/index.js +79 -79
- package/src/services-pi/index.js +8 -8
- package/src/static-pi/index.js +10 -10
- package/src/webflo.js +31 -31
- package/test/index.test.js +26 -25
- package/test/site/package.json +9 -9
- package/test/site/public/bundle.html +5 -5
- package/test/site/public/bundle.html.json +3 -3
- package/test/site/public/bundle.js +2 -2
- package/test/site/public/bundle.webflo.js +15 -15
- package/test/site/public/index.html +29 -29
- package/test/site/public/index1.html +34 -34
- package/test/site/public/page-2/bundle.html +4 -4
- package/test/site/public/page-2/bundle.js +2 -2
- package/test/site/public/page-2/index.html +45 -45
- package/test/site/public/page-2/main.html +2 -2
- package/test/site/public/page-4/subpage/bundle.js +2 -2
- package/test/site/public/page-4/subpage/index.html +30 -30
- package/test/site/public/sparoots.json +4 -4
- package/test/site/public/worker.js +3 -3
- package/test/site/server/index.js +15 -15
|
@@ -1,342 +1,358 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* @imports
|
|
4
|
-
*/
|
|
5
|
-
import { _before, _toTitle } from '@webqit/util/str/index.js';
|
|
6
|
-
import { Observer } from '@webqit/oohtml-ssr/apis.js';
|
|
7
|
-
import Storage from './Storage.js';
|
|
8
|
-
import Url from './Url.js';
|
|
9
|
-
import { wwwFormUnserialize, wwwFormSet, wwwFormSerialize } from '../util.js';
|
|
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";
|
|
15
|
-
import xRequest from "../xRequest.js";
|
|
16
|
-
import xResponse from "../xResponse.js";
|
|
17
|
-
import xfetch from '../xfetch.js';
|
|
18
|
-
import xHttpEvent from '../xHttpEvent.js';
|
|
19
|
-
import Workport from './Workport.js';
|
|
20
|
-
|
|
21
|
-
const URL = xURL(whatwag.URL);
|
|
22
|
-
const FormData = xFormData(whatwag.FormData);
|
|
23
|
-
const ReadableStream = whatwag.ReadableStream;
|
|
24
|
-
const RequestHeaders = xRequestHeaders(whatwag.Headers);
|
|
25
|
-
const ResponseHeaders = xResponseHeaders(whatwag.Headers);
|
|
26
|
-
const Request = xRequest(whatwag.Request, RequestHeaders, FormData, whatwag.Blob);
|
|
27
|
-
const Response = xResponse(whatwag.Response, ResponseHeaders, FormData, whatwag.Blob);
|
|
28
|
-
const fetch = xfetch(whatwag.fetch);
|
|
29
|
-
const HttpEvent = xHttpEvent(Request, Response, URL);
|
|
30
|
-
|
|
31
|
-
export {
|
|
32
|
-
URL,
|
|
33
|
-
FormData,
|
|
34
|
-
ReadableStream,
|
|
35
|
-
RequestHeaders,
|
|
36
|
-
ResponseHeaders,
|
|
37
|
-
Request,
|
|
38
|
-
Response,
|
|
39
|
-
fetch,
|
|
40
|
-
HttpEvent,
|
|
41
|
-
Observer,
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export default class Runtime {
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Runtime
|
|
48
|
-
*
|
|
49
|
-
* @param Object cx
|
|
50
|
-
* @param Function clientCallback
|
|
51
|
-
*
|
|
52
|
-
* @return void
|
|
53
|
-
*/
|
|
54
|
-
constructor(cx, clientCallback) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
this.cx
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
// the window.history.
|
|
86
|
-
// the window.history.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (!
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
params
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
submitParams.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
Observer.set(this, '
|
|
155
|
-
window.addEventListener('
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
let
|
|
165
|
-
let
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
//
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
// ------------
|
|
277
|
-
//
|
|
278
|
-
// ------------
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @imports
|
|
4
|
+
*/
|
|
5
|
+
import { _before, _toTitle } from '@webqit/util/str/index.js';
|
|
6
|
+
import { Observer } from '@webqit/oohtml-ssr/apis.js';
|
|
7
|
+
import Storage from './Storage.js';
|
|
8
|
+
import Url from './Url.js';
|
|
9
|
+
import { wwwFormUnserialize, wwwFormSet, wwwFormSerialize } from '../util.js';
|
|
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";
|
|
15
|
+
import xRequest from "../xRequest.js";
|
|
16
|
+
import xResponse from "../xResponse.js";
|
|
17
|
+
import xfetch from '../xfetch.js';
|
|
18
|
+
import xHttpEvent from '../xHttpEvent.js';
|
|
19
|
+
import Workport from './Workport.js';
|
|
20
|
+
|
|
21
|
+
const URL = xURL(whatwag.URL);
|
|
22
|
+
const FormData = xFormData(whatwag.FormData);
|
|
23
|
+
const ReadableStream = whatwag.ReadableStream;
|
|
24
|
+
const RequestHeaders = xRequestHeaders(whatwag.Headers);
|
|
25
|
+
const ResponseHeaders = xResponseHeaders(whatwag.Headers);
|
|
26
|
+
const Request = xRequest(whatwag.Request, RequestHeaders, FormData, whatwag.Blob);
|
|
27
|
+
const Response = xResponse(whatwag.Response, ResponseHeaders, FormData, whatwag.Blob);
|
|
28
|
+
const fetch = xfetch(whatwag.fetch);
|
|
29
|
+
const HttpEvent = xHttpEvent(Request, Response, URL);
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
URL,
|
|
33
|
+
FormData,
|
|
34
|
+
ReadableStream,
|
|
35
|
+
RequestHeaders,
|
|
36
|
+
ResponseHeaders,
|
|
37
|
+
Request,
|
|
38
|
+
Response,
|
|
39
|
+
fetch,
|
|
40
|
+
HttpEvent,
|
|
41
|
+
Observer,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default class Runtime {
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Runtime
|
|
48
|
+
*
|
|
49
|
+
* @param Object cx
|
|
50
|
+
* @param Function clientCallback
|
|
51
|
+
*
|
|
52
|
+
* @return void
|
|
53
|
+
*/
|
|
54
|
+
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
|
+
|
|
64
|
+
// -----------------------
|
|
65
|
+
// Initialize location
|
|
66
|
+
Observer.set(this, 'location', new Url(window.document.location));
|
|
67
|
+
// -----------------------
|
|
68
|
+
// Syndicate changes to the browser;s location bar
|
|
69
|
+
Observer.observe(this.location, [[ 'href' ]], ([e]) => {
|
|
70
|
+
if (e.value === 'http:' || (e.detail || {}).src === window.document.location) {
|
|
71
|
+
// Already from a "popstate" event as above, so don't push again
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (e.value === window.document.location.href || e.value + '/' === window.document.location.href) {
|
|
75
|
+
window.history.replaceState(window.history.state, '', this.location.href);
|
|
76
|
+
} else {
|
|
77
|
+
try { window.history.pushState(window.history.state, '', this.location.href); } catch(e) {}
|
|
78
|
+
}
|
|
79
|
+
}, { diff: true });
|
|
80
|
+
|
|
81
|
+
// -----------------------
|
|
82
|
+
// This event is triggered by
|
|
83
|
+
// either the browser back button,
|
|
84
|
+
// the window.history.back(),
|
|
85
|
+
// the window.history.forward(),
|
|
86
|
+
// or the window.history.go() action.
|
|
87
|
+
window.addEventListener('popstate', e => {
|
|
88
|
+
// Needed to allow window.document.location
|
|
89
|
+
// to update to window.location
|
|
90
|
+
window.setTimeout(() => {
|
|
91
|
+
this.go(Url.copy(window.document.location), {}, { src: window.document.location, srcType: 'history', });
|
|
92
|
+
}, 0);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// -----------------------
|
|
96
|
+
// Capture all link-clicks
|
|
97
|
+
// and fire to this router.
|
|
98
|
+
window.addEventListener('click', e => {
|
|
99
|
+
var anchorEl = e.target.closest('a');
|
|
100
|
+
if (!anchorEl || !anchorEl.href) return;
|
|
101
|
+
if (!anchorEl.target && !anchorEl.download && this.isSpaRoute(anchorEl, e)) {
|
|
102
|
+
// Publish everything, including hash
|
|
103
|
+
this.go(Url.copy(anchorEl), {}, { src: anchorEl, srcType: 'link', });
|
|
104
|
+
if (!this.isHashAction(anchorEl)) {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// -----------------------
|
|
111
|
+
// Capture all form-submit
|
|
112
|
+
// and fire to this router.
|
|
113
|
+
window.addEventListener('submit', e => {
|
|
114
|
+
const form = e.target.closest('form'), submitter = e.submitter;
|
|
115
|
+
const submitParams = [ 'action', 'enctype', 'method', 'noValidate', 'target' ].reduce((params, prop) => {
|
|
116
|
+
params[prop] = submitter && submitter.hasAttribute(`form${prop.toLowerCase()}`) ? submitter[`form${_toTitle(prop)}`] : form[prop];
|
|
117
|
+
return params;
|
|
118
|
+
}, {});
|
|
119
|
+
// We support method hacking
|
|
120
|
+
submitParams.method = (submitter && submitter.dataset.formmethod) || form.dataset.method || submitParams.method;
|
|
121
|
+
submitParams.submitter = submitter;
|
|
122
|
+
// ---------------
|
|
123
|
+
var actionEl = window.document.createElement('a');
|
|
124
|
+
actionEl.href = submitParams.action;
|
|
125
|
+
// ---------------
|
|
126
|
+
// If not targeted and same origin...
|
|
127
|
+
if (!submitParams.target && this.isSpaRoute(actionEl, e)) {
|
|
128
|
+
// Build data
|
|
129
|
+
var formData = new FormData(form);
|
|
130
|
+
if ((submitter || {}).name) {
|
|
131
|
+
formData.set(submitter.name, submitter.value);
|
|
132
|
+
}
|
|
133
|
+
if (submitParams.method.toUpperCase() === 'GET') {
|
|
134
|
+
var query = wwwFormUnserialize(actionEl.search);
|
|
135
|
+
Array.from(formData.entries()).forEach(_entry => {
|
|
136
|
+
wwwFormSet(query, _entry[0], _entry[1], false);
|
|
137
|
+
});
|
|
138
|
+
actionEl.search = wwwFormSerialize(query);
|
|
139
|
+
formData = null;
|
|
140
|
+
}
|
|
141
|
+
this.go(Url.copy(actionEl), {
|
|
142
|
+
method: submitParams.method,
|
|
143
|
+
body: formData,
|
|
144
|
+
}, { ...submitParams, src: form, srcType: 'form', });
|
|
145
|
+
if (!this.isHashAction(actionEl)) {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// -----------------------
|
|
152
|
+
// Initialize network
|
|
153
|
+
Observer.set(this, 'network', {});
|
|
154
|
+
window.addEventListener('online', () => Observer.set(this.network, 'connectivity', 'online'));
|
|
155
|
+
window.addEventListener('offline', () => Observer.set(this.network, 'connectivity', 'offline'));
|
|
156
|
+
|
|
157
|
+
// -----------------------
|
|
158
|
+
// Service Worker && COMM
|
|
159
|
+
if (this.cx.params.service_worker_support) {
|
|
160
|
+
let workport = new Workport(this.cx.params.worker_filename, { scope: this.cx.params.worker_scope, startMessages: true });
|
|
161
|
+
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
|
+
}
|
|
177
|
+
|
|
178
|
+
// ---------------
|
|
179
|
+
this.go(this.location, {}, { srcType: 'init' });
|
|
180
|
+
// ---------------
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* History object
|
|
185
|
+
*/
|
|
186
|
+
get history() {
|
|
187
|
+
return window.history;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Check is-hash-action
|
|
191
|
+
isHashAction(urlObj) {
|
|
192
|
+
const isHashNav = _before(window.document.location.href, '#') === _before(urlObj.href, '#') && urlObj.href.includes('#');
|
|
193
|
+
return isHashNav && urlObj.hash.length > 1 && document.querySelector(urlObj.hash);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Check is-spa-route
|
|
197
|
+
isSpaRoute(url, e = undefined) {
|
|
198
|
+
url = typeof url === 'string' ? new whatwag.URL(url) : url;
|
|
199
|
+
if (url.origin && url.origin !== this.location.origin) return false;
|
|
200
|
+
if (e && (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)) return false;
|
|
201
|
+
if (!this.cx.params.routing) return true;
|
|
202
|
+
if (this.cx.params.routing.targets === false/** explicit false means disabled */) return false;
|
|
203
|
+
let b = url.pathname.split('/').filter(s => s);
|
|
204
|
+
const match = a => {
|
|
205
|
+
a = a.split('/').filter(s => s);
|
|
206
|
+
return a.reduce((prev, s, i) => prev && (s === b[i] || [s, b[i]].includes('-')), true);
|
|
207
|
+
};
|
|
208
|
+
return match(this.cx.params.routing.root) && this.cx.params.routing.subroots.reduce((prev, subroot) => {
|
|
209
|
+
return prev && !match(subroot);
|
|
210
|
+
}, true);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Generates request object
|
|
214
|
+
generateRequest(href, init) {
|
|
215
|
+
return new Request(href, {
|
|
216
|
+
signal: this._abortController.signal,
|
|
217
|
+
...init,
|
|
218
|
+
headers: {
|
|
219
|
+
'Accept': 'application/json',
|
|
220
|
+
'X-Redirect-Policy': 'manual-when-cross-spa',
|
|
221
|
+
'X-Redirect-Code': this._xRedirectCode,
|
|
222
|
+
'X-Powered-By': '@webqit/webflo',
|
|
223
|
+
...(init.headers || {}),
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Generates session object
|
|
229
|
+
getSession(e, id = null, persistent = false) {
|
|
230
|
+
return Storage(id, persistent);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Performs a request.
|
|
235
|
+
*
|
|
236
|
+
* @param object|string href
|
|
237
|
+
* @param object init
|
|
238
|
+
* @param object src
|
|
239
|
+
*
|
|
240
|
+
* @return Response
|
|
241
|
+
*/
|
|
242
|
+
async go(url, init = {}, detail = {}) {
|
|
243
|
+
url = typeof url === 'string' ? new whatwag.URL(url) : url;
|
|
244
|
+
init = { referrer: this.location.href, ...init };
|
|
245
|
+
// ------------
|
|
246
|
+
// Put his forward before instantiating a request and aborting previous
|
|
247
|
+
// Same-page hash-links clicks on chrome recurse here from histroy popstate
|
|
248
|
+
if (detail.srcType !== 'init' && (_before(url.href, '#') === _before(init.referrer, '#') && (init.method || 'GET').toUpperCase() === 'GET')) {
|
|
249
|
+
return new Response(null, { status: 304 }); // Not Modified
|
|
250
|
+
}
|
|
251
|
+
// ------------
|
|
252
|
+
if (this._abortController) {
|
|
253
|
+
this._abortController.abort();
|
|
254
|
+
}
|
|
255
|
+
this._abortController = new AbortController();
|
|
256
|
+
this._xRedirectCode = 200;
|
|
257
|
+
// ------------
|
|
258
|
+
// States
|
|
259
|
+
// ------------
|
|
260
|
+
Observer.set(this.network, 'error', null);
|
|
261
|
+
Observer.set(this.network, 'requesting', { ...init, ...detail });
|
|
262
|
+
if (['link', 'form'].includes(detail.srcType)) {
|
|
263
|
+
detail.src.state && (detail.src.state.active = true);
|
|
264
|
+
detail.submitter && detail.submitter.state && (detail.submitter.state.active = true);
|
|
265
|
+
}
|
|
266
|
+
// ------------
|
|
267
|
+
// Run
|
|
268
|
+
// ------------
|
|
269
|
+
// The request object
|
|
270
|
+
let request = this.generateRequest(url.href, init);
|
|
271
|
+
// The navigation event
|
|
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;
|
|
275
|
+
try {
|
|
276
|
+
// ------------
|
|
277
|
+
// Response
|
|
278
|
+
// ------------
|
|
279
|
+
response = await client.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
|
|
280
|
+
finalResponse = this.handleResponse(httpEvent, response);
|
|
281
|
+
// ------------
|
|
282
|
+
// Address bar
|
|
283
|
+
// ------------
|
|
284
|
+
if (response.redirected) {
|
|
285
|
+
Observer.set(this.location, { href: response.url }, { detail: { redirected: true }, });
|
|
286
|
+
Observer.set(this.network, 'requesting', null);
|
|
287
|
+
} else if (![302, 301].includes(finalResponse.status)) {
|
|
288
|
+
Observer.set(this.location, Url.copy(url)/* copy() is important */);
|
|
289
|
+
Observer.set(this.network, 'requesting', null);
|
|
290
|
+
}
|
|
291
|
+
// ------------
|
|
292
|
+
// States
|
|
293
|
+
// ------------
|
|
294
|
+
if (['link', 'form'].includes(detail.srcType)) {
|
|
295
|
+
detail.src.state && (detail.src.state.active = false);
|
|
296
|
+
detail.submitter && detail.submitter.state && (detail.submitter.state.active = false);
|
|
297
|
+
}
|
|
298
|
+
// ------------
|
|
299
|
+
// Rendering
|
|
300
|
+
// ------------
|
|
301
|
+
if (finalResponse.ok && finalResponse.headers.contentType === 'application/json') {
|
|
302
|
+
client.render && await client.render(httpEvent, finalResponse);
|
|
303
|
+
} else if (!finalResponse.ok) {
|
|
304
|
+
if ([404, 500].includes(finalResponse.status)) {
|
|
305
|
+
Observer.set(this.network, 'error', new Error(finalResponse.statusText, { cause: finalResponse.status }));
|
|
306
|
+
}
|
|
307
|
+
client.unrender && await client.unrender(httpEvent);
|
|
308
|
+
}
|
|
309
|
+
} catch(e) {
|
|
310
|
+
console.error(e);
|
|
311
|
+
Observer.set(this.network, 'error', { ...e, retry: () => this.go(url, init = {}, detail) });
|
|
312
|
+
finalResponse = new Response(null, { status: 500, statusText: e.message });
|
|
313
|
+
}
|
|
314
|
+
// ------------
|
|
315
|
+
// Return value
|
|
316
|
+
return finalResponse;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Initiates remote fetch and sets the status
|
|
320
|
+
remoteFetch(request, ...args) {
|
|
321
|
+
let href = typeof request === 'string' ? request : (request.url || request.href);
|
|
322
|
+
Observer.set(this.network, 'remote', href);
|
|
323
|
+
let _response = fetch(request, ...args);
|
|
324
|
+
// This catch() is NOT intended to handle failure of the fetch
|
|
325
|
+
_response.catch(e => Observer.set(this.network, 'error', e));
|
|
326
|
+
// Return xResponse
|
|
327
|
+
return _response.then(async response => {
|
|
328
|
+
// Stop loading status
|
|
329
|
+
Observer.set(this.network, 'remote', null);
|
|
330
|
+
return new Response(response);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Handles response object
|
|
335
|
+
handleResponse(e, response) {
|
|
336
|
+
if (!(response instanceof Response)) { response = new Response(response); }
|
|
337
|
+
if (!response.redirected) {
|
|
338
|
+
let location = response.headers.get('Location');
|
|
339
|
+
if (location) {
|
|
340
|
+
let xActualRedirectCode = parseInt(response.headers.get('X-Redirect-Code'));
|
|
341
|
+
if (xActualRedirectCode && response.status === this._xRedirectCode) {
|
|
342
|
+
response.attrs.status = xActualRedirectCode;
|
|
343
|
+
Observer.set(this.network, 'redirecting', location);
|
|
344
|
+
window.location = location;
|
|
345
|
+
} else if ([302,301].includes(response.status)) {
|
|
346
|
+
if (!this.isSpaRoute(location)) {
|
|
347
|
+
Observer.set(this.network, 'redirecting', location);
|
|
348
|
+
window.location = location;
|
|
349
|
+
} else {
|
|
350
|
+
this.go(location, {}, { srcType: 'rdr' });
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return response;
|
|
356
|
+
}
|
|
357
|
+
|
|
342
358
|
}
|