@webqit/webflo 0.8.77 → 0.9.1
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 +5 -12
- package/src/Cli.js +131 -0
- package/src/Configurator.js +97 -0
- package/src/Context.js +76 -0
- package/src/config-pi/deployment/Env.js +69 -0
- package/src/config-pi/deployment/Layout.js +65 -0
- package/src/config-pi/deployment/Origins.js +133 -0
- package/src/config-pi/deployment/Virtualization.js +65 -0
- package/src/config-pi/deployment/index.js +18 -0
- package/src/config-pi/index.js +16 -0
- package/src/config-pi/runtime/Client.js +59 -0
- package/src/config-pi/runtime/Server.js +174 -0
- package/src/config-pi/runtime/client/Worker.js +117 -0
- package/src/config-pi/runtime/client/index.js +12 -0
- package/src/config-pi/runtime/index.js +18 -0
- package/src/config-pi/runtime/server/Headers.js +90 -0
- package/src/config-pi/runtime/server/Redirects.js +108 -0
- package/src/config-pi/runtime/server/index.js +14 -0
- package/src/config-pi/static/Manifest.js +321 -0
- package/src/config-pi/static/Ssg.js +72 -0
- package/src/config-pi/static/index.js +14 -0
- package/src/deployment-pi/index.js +10 -0
- package/src/{services → deployment-pi}/origins/index.js +88 -58
- package/src/index.js +14 -147
- package/src/{runtime → runtime-pi}/Router.js +19 -19
- package/src/runtime-pi/client/Context.js +7 -0
- package/src/{runtime → runtime-pi}/client/Router.js +2 -2
- package/src/{runtime/client/Navigator.js → runtime-pi/client/Runtime.js} +148 -103
- package/src/runtime-pi/client/RuntimeClient.js +114 -0
- package/src/{runtime → runtime-pi}/client/Storage.js +1 -1
- package/src/{runtime → runtime-pi}/client/Url.js +2 -6
- package/src/{runtime/client/WorkerClient.js → runtime-pi/client/WorkerComm.js} +2 -2
- package/src/runtime-pi/client/generate.js +242 -0
- package/src/runtime-pi/client/generate.oohtml.js +7 -0
- package/src/runtime-pi/client/index.js +18 -0
- package/src/runtime-pi/client/whatwag.js +27 -0
- package/src/runtime-pi/client/worker/Context.js +7 -0
- package/src/runtime-pi/client/worker/Worker.js +243 -0
- package/src/runtime-pi/client/worker/WorkerClient.js +46 -0
- package/src/runtime-pi/client/worker/index.js +18 -0
- package/src/runtime-pi/index.js +14 -0
- package/src/runtime-pi/server/Context.js +16 -0
- package/src/{runtime → runtime-pi}/server/Router.js +6 -6
- package/src/runtime-pi/server/Runtime.js +531 -0
- package/src/runtime-pi/server/RuntimeClient.js +103 -0
- package/src/runtime-pi/server/index.js +41 -0
- package/src/runtime-pi/server/whatwag.js +35 -0
- package/src/{runtime → runtime-pi}/util.js +0 -0
- package/src/{runtime/_FormData.js → runtime-pi/xFormData.js} +2 -2
- package/src/{runtime/_Headers.js → runtime-pi/xHeaders.js} +4 -4
- package/src/runtime-pi/xHttpEvent.js +93 -0
- package/src/runtime-pi/xHttpMessage.js +179 -0
- package/src/runtime-pi/xRequest.js +67 -0
- package/src/runtime-pi/xRequestHeaders.js +95 -0
- package/src/runtime-pi/xResponse.js +62 -0
- package/src/{runtime/_ResponseHeaders.js → runtime-pi/xResponseHeaders.js} +38 -18
- package/src/{runtime/_URL.js → runtime-pi/xURL.js} +4 -4
- package/src/runtime-pi/xfetch.js +7 -0
- package/src/{services → services-pi}/certbot/http-auth-hook.js +0 -0
- package/src/{services → services-pi}/certbot/http-cleanup-hook.js +0 -0
- package/src/{services → services-pi}/certbot/index.js +21 -15
- package/src/services-pi/index.js +9 -0
- package/src/static-pi/index.js +11 -0
- package/src/webflo.js +33 -0
- package/test/index.test.js +26 -0
- package/src/build/client/index.js +0 -261
- package/src/build/index.js +0 -5
- package/src/config/client.js +0 -191
- package/src/config/headers.js +0 -121
- package/src/config/index.js +0 -14
- package/src/config/layout.js +0 -83
- package/src/config/manifest.js +0 -341
- package/src/config/origins.js +0 -165
- package/src/config/prerendering.js +0 -100
- package/src/config/redirects.js +0 -137
- package/src/config/server.js +0 -201
- package/src/config/variables.js +0 -102
- package/src/config/vhosts.js +0 -93
- package/src/runtime/_MessageStream.js +0 -195
- package/src/runtime/_NavigationEvent.js +0 -91
- package/src/runtime/_Request.js +0 -59
- package/src/runtime/_RequestHeaders.js +0 -72
- package/src/runtime/_Response.js +0 -56
- package/src/runtime/client/NavigationEvent.js +0 -21
- package/src/runtime/client/Runtime.js +0 -126
- package/src/runtime/client/Worker.js +0 -317
- package/src/runtime/client/archive/Cache.js +0 -38
- package/src/runtime/client/archive/Http.js +0 -225
- package/src/runtime/client/archive/StdRequest.js +0 -74
- package/src/runtime/client/archive/WorkerComm.js +0 -183
- package/src/runtime/client/effects/sounds.js +0 -64
- package/src/runtime/index.js +0 -5
- package/src/runtime/server/NavigationEvent.js +0 -39
- package/src/runtime/server/Runtime.js +0 -593
- package/src/runtime/server/index.js +0 -183
- package/src/runtime/server/index.mjs +0 -10
- package/src/services/index.js +0 -6
package/src/index.js
CHANGED
|
@@ -1,151 +1,18 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
|
|
3
2
|
/**
|
|
4
|
-
* imports
|
|
3
|
+
* @imports
|
|
5
4
|
*/
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import * as DotJson from '@webqit/backpack/src/dotfiles/DotJson.js';
|
|
11
|
-
import { Promptx } from '@webqit/backpack/src/cli/Promptx.js';
|
|
12
|
-
import * as build from './build/index.js';
|
|
13
|
-
import * as config from './config/index.js';
|
|
14
|
-
import * as runtime from './runtime/index.js';
|
|
15
|
-
import * as services from './services/index.js';
|
|
5
|
+
import * as config from './config-pi/index.js';
|
|
6
|
+
import * as deployment from './deployment-pi/index.js';
|
|
7
|
+
import * as runtime from './runtime-pi/index.js';
|
|
8
|
+
import * as services from './services-pi/index.js';
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// ------------------------------------------
|
|
27
|
-
|
|
28
|
-
const { command, keywords, flags, options, ellipsis } = parseArgs(process.argv);
|
|
29
|
-
|
|
30
|
-
// ------------------------------------------
|
|
31
|
-
|
|
32
|
-
console.log('');
|
|
33
|
-
|
|
34
|
-
(async function() {
|
|
35
|
-
const layout = await config.layout.read({});
|
|
36
|
-
layout.PKG = DotJson.read('./package.json');
|
|
37
|
-
switch(command) {
|
|
38
|
-
|
|
39
|
-
// --------------------------
|
|
40
|
-
|
|
41
|
-
case 'build':
|
|
42
|
-
build.client.build(Ui, flags, layout);
|
|
43
|
-
break;
|
|
44
|
-
|
|
45
|
-
// --------------------------
|
|
46
|
-
|
|
47
|
-
case 'config':
|
|
48
|
-
|
|
49
|
-
var domain = Object.keys(keywords)[0];
|
|
50
|
-
// ----------------
|
|
51
|
-
if (!domain && ellipsis) {
|
|
52
|
-
domain = await Promptx({
|
|
53
|
-
name: 'domain',
|
|
54
|
-
type: 'select',
|
|
55
|
-
choices: Object.keys(config).map(c => ({value: c})),
|
|
56
|
-
message: 'Please select a configuration domain',
|
|
57
|
-
}).then(d => d.domain);
|
|
58
|
-
}
|
|
59
|
-
if (!domain || !config[domain]) {
|
|
60
|
-
Ui.log(Ui.f`Please add a configuration domain to the ${command} command. For options, use the ellipsis ${'...'}`);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
// ----------------
|
|
64
|
-
const data = await config[domain].read(flags, layout);
|
|
65
|
-
Promptx(await config[domain].questions(data, {}, layout)).then(async _data => {
|
|
66
|
-
await config[domain].write(_merge(data, _data), flags, layout);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
break;
|
|
70
|
-
|
|
71
|
-
// --------------------------
|
|
72
|
-
|
|
73
|
-
case 'start':
|
|
74
|
-
runtime.server.start(Ui, flags, layout);
|
|
75
|
-
break;
|
|
76
|
-
|
|
77
|
-
case 'stop':
|
|
78
|
-
case 'restart':
|
|
79
|
-
var _runtime = Object.keys(keywords)[0];
|
|
80
|
-
// ----------------
|
|
81
|
-
if (!_runtime && ellipsis) {
|
|
82
|
-
_runtime = await Promptx({
|
|
83
|
-
name: 'runtime',
|
|
84
|
-
type: 'select',
|
|
85
|
-
choices: (await runtime.server.processes(Ui)).map(r => ({title: r.name, description: r.status, value: r.name})).concat({description: 'All of the above', value: 'all'}),
|
|
86
|
-
message: 'Please select a runtime name',
|
|
87
|
-
}).then(d => d.runtime);
|
|
88
|
-
}
|
|
89
|
-
// ----------------
|
|
90
|
-
await runtime.server[command](Ui, _runtime || 'all', flags);
|
|
91
|
-
process.exit();
|
|
92
|
-
break;
|
|
93
|
-
|
|
94
|
-
case 'processes':
|
|
95
|
-
const processes = await runtime.server.processes(Ui, flags);
|
|
96
|
-
Ui.title(`SERVERS`);
|
|
97
|
-
if (processes.length) {
|
|
98
|
-
processes.forEach(service => {
|
|
99
|
-
Ui.log(Ui.f`> ${service}`);
|
|
100
|
-
});
|
|
101
|
-
} else {
|
|
102
|
-
Ui.log(Ui.f`> (empty)`);
|
|
103
|
-
}
|
|
104
|
-
process.exit();
|
|
105
|
-
break;
|
|
106
|
-
|
|
107
|
-
// --------------------------
|
|
108
|
-
|
|
109
|
-
case 'deploy':
|
|
110
|
-
var origin = Object.keys(keywords)[0],
|
|
111
|
-
options;
|
|
112
|
-
// ----------------
|
|
113
|
-
if (!origin && ellipsis) {
|
|
114
|
-
if (!(options = (await config.origins.read(flags, layout)).REPOS) || _isEmpty(options)) {
|
|
115
|
-
Ui.log(Ui.f`Please configure an origin (${'webflo config ...'}) to use the ${'deploy'} command.`);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
origin = await Promptx({
|
|
119
|
-
name: 'origin',
|
|
120
|
-
type: 'select',
|
|
121
|
-
choices: options.map(r => ({value: r.TAG})),
|
|
122
|
-
message: 'Please select a origin',
|
|
123
|
-
}).then(d => d.origin);
|
|
124
|
-
}
|
|
125
|
-
if (!origin) {
|
|
126
|
-
Ui.log(Ui.f`Please add an origin name to the ${command} command. For options, use the ellipsis ${'...'}`);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
// ----------------
|
|
130
|
-
services.origins.deploy(Ui, origin, flags, layout);
|
|
131
|
-
break;
|
|
132
|
-
|
|
133
|
-
// --------------------------
|
|
134
|
-
|
|
135
|
-
case 'cert':
|
|
136
|
-
var domains = Object.keys(keywords);
|
|
137
|
-
services.certbot.generate(Ui, domains, flags, layout);
|
|
138
|
-
break;
|
|
139
|
-
|
|
140
|
-
case 'help':
|
|
141
|
-
default:
|
|
142
|
-
Ui.title(`NAVIGATOR HELP`);
|
|
143
|
-
Ui.log('');
|
|
144
|
-
Ui.log(Ui.f`Say ${'webflo'} <${'command'}>`);
|
|
145
|
-
Ui.log('');
|
|
146
|
-
Ui.log(Ui.f`Where <${'command'}> is one of:`);
|
|
147
|
-
Ui.log(Ui.f`${commands}`);
|
|
148
|
-
Ui.log('');
|
|
149
|
-
Ui.log(Ui.f`You may also refer to the Webflo DOCS as ${'https://webqit.io/tooling/webflo'}`);
|
|
150
|
-
}
|
|
151
|
-
})();
|
|
10
|
+
/**
|
|
11
|
+
* @exports
|
|
12
|
+
*/
|
|
13
|
+
export {
|
|
14
|
+
config,
|
|
15
|
+
deployment,
|
|
16
|
+
runtime,
|
|
17
|
+
services,
|
|
18
|
+
}
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
|
-
import _isString from '@webqit/util/js/
|
|
6
|
-
import
|
|
7
|
-
import _isArray from '@webqit/util/js/isArray.js';
|
|
8
|
-
import _arrFrom from '@webqit/util/arr/from.js';
|
|
5
|
+
import { _isString, _isFunction, _isArray } from '@webqit/util/js/index.js';
|
|
6
|
+
import { _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
9
7
|
|
|
10
8
|
/**
|
|
11
9
|
* ---------------------------
|
|
@@ -19,16 +17,14 @@ export default class Router {
|
|
|
19
17
|
* Constructs a new Router instance
|
|
20
18
|
* over route definitions.
|
|
21
19
|
*
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
24
|
-
* @param object context
|
|
20
|
+
* @param Context cx
|
|
21
|
+
* @param String|Array path
|
|
25
22
|
*
|
|
26
23
|
* @return void
|
|
27
24
|
*/
|
|
28
|
-
constructor(
|
|
25
|
+
constructor(cx, path) {
|
|
26
|
+
this.cx = cx;
|
|
29
27
|
this.path = _isArray(path) ? path : (path + '').split('/').filter(a => a);
|
|
30
|
-
this.layout = layout;
|
|
31
|
-
this.context = context;
|
|
32
28
|
}
|
|
33
29
|
|
|
34
30
|
/**
|
|
@@ -38,10 +34,11 @@ export default class Router {
|
|
|
38
34
|
* @param Object event
|
|
39
35
|
* @param any arg
|
|
40
36
|
* @param function _default
|
|
37
|
+
* @param function remoteFetch
|
|
41
38
|
*
|
|
42
39
|
* @return object
|
|
43
40
|
*/
|
|
44
|
-
|
|
41
|
+
async route(method, event, arg, _default, remoteFetch = null) {
|
|
45
42
|
|
|
46
43
|
const $this = this;
|
|
47
44
|
|
|
@@ -49,15 +46,17 @@ export default class Router {
|
|
|
49
46
|
// The loop
|
|
50
47
|
// ----------------
|
|
51
48
|
const next = async function(thisTick) {
|
|
52
|
-
const
|
|
49
|
+
const thisContext = {};
|
|
53
50
|
if (!thisTick.trail || thisTick.trail.length < thisTick.destination.length) {
|
|
54
51
|
thisTick = await $this.readTick(thisTick);
|
|
55
52
|
// -------------
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
$this.finalizeHandlerContext(
|
|
53
|
+
thisContext.pathname = `/${thisTick.trail.join('/')}`;
|
|
54
|
+
thisContext.stepname = thisTick.trail[thisTick.trail.length - 1];
|
|
55
|
+
$this.finalizeHandlerContext(thisContext, thisTick);
|
|
59
56
|
// -------------
|
|
60
57
|
if (thisTick.exports) {
|
|
58
|
+
// Broadcast any hints exported by handler
|
|
59
|
+
if (thisTick.exports.hints) { await event.port.post({ ...thisTick.exports.hints, $type: 'handler:hints' }); }
|
|
61
60
|
const methods = _arrFrom(thisTick.method);
|
|
62
61
|
const handler = _isFunction(thisTick.exports) && methods.includes('default') ? thisTick.exports : methods.reduce((_handler, name) => _handler || thisTick.exports[name.toLowerCase()], null);
|
|
63
62
|
if (handler) {
|
|
@@ -102,7 +101,7 @@ export default class Router {
|
|
|
102
101
|
_next.pathname = nextPathname.join('/');
|
|
103
102
|
_next.stepname = nextPathname[0];
|
|
104
103
|
// -------------
|
|
105
|
-
return await handler.call(
|
|
104
|
+
return await handler.call(thisContext, thisTick.event, thisTick.arg, _next/*next*/, remoteFetch);
|
|
106
105
|
}
|
|
107
106
|
// Handler not found but exports found
|
|
108
107
|
return next(thisTick);
|
|
@@ -115,7 +114,7 @@ export default class Router {
|
|
|
115
114
|
// Local file
|
|
116
115
|
// -------------
|
|
117
116
|
if (_default) {
|
|
118
|
-
return await _default.call(
|
|
117
|
+
return await _default.call(thisContext, thisTick.event, thisTick.arg, remoteFetch);
|
|
119
118
|
}
|
|
120
119
|
};
|
|
121
120
|
|
|
@@ -126,5 +125,6 @@ export default class Router {
|
|
|
126
125
|
arg,
|
|
127
126
|
});
|
|
128
127
|
|
|
129
|
-
}
|
|
130
|
-
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
}
|
|
@@ -14,8 +14,8 @@ import _Router from '../Router.js';
|
|
|
14
14
|
export default class Router extends _Router {
|
|
15
15
|
|
|
16
16
|
async readTick(thisTick) {
|
|
17
|
-
var routeTree = this.layout;
|
|
18
|
-
var routePaths = Object.keys(this.layout);
|
|
17
|
+
var routeTree = this.cx.layout;
|
|
18
|
+
var routePaths = Object.keys(this.cx.layout);
|
|
19
19
|
if (thisTick.trail) {
|
|
20
20
|
thisTick.currentSegment = thisTick.destination[thisTick.trail.length];
|
|
21
21
|
thisTick.currentSegmentOnFile = [ thisTick.currentSegment, '-' ].reduce((_segmentOnFile, _seg) => {
|
|
@@ -2,22 +2,64 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
|
-
import _before from '@webqit/util/str/
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import { Observer } from './Runtime.js';
|
|
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';
|
|
9
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
|
+
|
|
20
|
+
const URL = xURL(whatwag.URL);
|
|
21
|
+
const FormData = xFormData(whatwag.FormData);
|
|
22
|
+
const ReadableStream = whatwag.ReadableStream;
|
|
23
|
+
const RequestHeaders = xRequestHeaders(whatwag.Headers);
|
|
24
|
+
const ResponseHeaders = xResponseHeaders(whatwag.Headers);
|
|
25
|
+
const Request = xRequest(whatwag.Request, RequestHeaders, FormData, whatwag.Blob);
|
|
26
|
+
const Response = xResponse(whatwag.Response, ResponseHeaders, FormData, whatwag.Blob);
|
|
27
|
+
const fetch = xfetch(whatwag.fetch);
|
|
28
|
+
const HttpEvent = xHttpEvent(Request, Response, URL);
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
URL,
|
|
32
|
+
FormData,
|
|
33
|
+
ReadableStream,
|
|
34
|
+
RequestHeaders,
|
|
35
|
+
ResponseHeaders,
|
|
36
|
+
Request,
|
|
37
|
+
Response,
|
|
38
|
+
fetch,
|
|
39
|
+
HttpEvent,
|
|
40
|
+
Observer,
|
|
41
|
+
}
|
|
10
42
|
|
|
11
|
-
export default class
|
|
43
|
+
export default class Runtime {
|
|
12
44
|
|
|
13
|
-
|
|
14
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Runtime
|
|
47
|
+
*
|
|
48
|
+
* @param Object cx
|
|
49
|
+
* @param Function clientCallback
|
|
50
|
+
*
|
|
51
|
+
* @return void
|
|
52
|
+
*/
|
|
53
|
+
constructor(cx, clientCallback) {
|
|
15
54
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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);
|
|
21
63
|
|
|
22
64
|
// -----------------------
|
|
23
65
|
// Initialize location
|
|
@@ -59,7 +101,7 @@ export default class Navigator {
|
|
|
59
101
|
if (!anchor.target && !anchor.download && (!anchor.origin || anchor.origin === this.location.origin)) {
|
|
60
102
|
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return;
|
|
61
103
|
// Publish everything, including hash
|
|
62
|
-
this.go(Url.copy(anchor), { src: anchor, srcType: 'link', });
|
|
104
|
+
this.go(Url.copy(anchor), {}, { src: anchor, srcType: 'link', });
|
|
63
105
|
// URLs with # will cause a natural navigation
|
|
64
106
|
// even if pointing to a different page, a natural navigation will still happen
|
|
65
107
|
// because with the Observer.set() above, window.document.location.href would have become
|
|
@@ -102,7 +144,11 @@ export default class Navigator {
|
|
|
102
144
|
actionEl.search = wwwFormSerialize(query);
|
|
103
145
|
formData = null;
|
|
104
146
|
}
|
|
105
|
-
this.go(Url.copy(actionEl), {
|
|
147
|
+
this.go(Url.copy(actionEl), {
|
|
148
|
+
method: submitParams.method,
|
|
149
|
+
body: formData,
|
|
150
|
+
headers: { contentType: submitParams.enctype },
|
|
151
|
+
}, { ...submitParams, src: form, srcType: 'form', });
|
|
106
152
|
// URLs with # will cause a natural navigation
|
|
107
153
|
// even if pointing to a different page, a natural navigation will still happen
|
|
108
154
|
// because with the Observer.set() above, window.document.location.href would have become
|
|
@@ -113,26 +159,16 @@ export default class Navigator {
|
|
|
113
159
|
}
|
|
114
160
|
});
|
|
115
161
|
|
|
116
|
-
/**
|
|
117
|
-
* ----------------
|
|
118
|
-
* Navigator network
|
|
119
|
-
* ----------------
|
|
120
|
-
*/
|
|
121
|
-
|
|
122
162
|
// -----------------------
|
|
123
163
|
// Initialize network
|
|
124
164
|
Observer.set(this, 'network', {});
|
|
125
165
|
window.addEventListener('online', () => Observer.set(this.network, 'online', navigator.onLine));
|
|
126
166
|
window.addEventListener('offline', () => Observer.set(this.network, 'online', navigator.onLine));
|
|
127
167
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
*/
|
|
133
|
-
|
|
134
|
-
this.go(this.location, { srcType: 'init' });
|
|
135
|
-
}
|
|
168
|
+
// ---------------
|
|
169
|
+
this.go(this.location, {}, { srcType: 'init' });
|
|
170
|
+
// ---------------
|
|
171
|
+
}
|
|
136
172
|
|
|
137
173
|
/**
|
|
138
174
|
* History object
|
|
@@ -145,91 +181,100 @@ export default class Navigator {
|
|
|
145
181
|
* Performs a request.
|
|
146
182
|
*
|
|
147
183
|
* @param object|string href
|
|
148
|
-
* @param object
|
|
184
|
+
* @param object init
|
|
185
|
+
* @param object src
|
|
149
186
|
*
|
|
150
|
-
* @return
|
|
187
|
+
* @return Response
|
|
151
188
|
*/
|
|
152
|
-
async go(url,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
headers: {
|
|
159
|
-
'Accept': 'application/json',
|
|
160
|
-
'X-Redirect-Policy': 'manual-when-cross-origin',
|
|
161
|
-
'X-Redirect-Code': xRedirectCode,
|
|
162
|
-
'X-Powered-By': '@webqit/webflo',
|
|
163
|
-
...(params.headers || {}),
|
|
164
|
-
},
|
|
165
|
-
referrer: window.document.location.href,
|
|
166
|
-
signal: this._abortController.signal,
|
|
167
|
-
});
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
// Initiates remote fetch and sets the status
|
|
171
|
-
const remoteRequest = request => {
|
|
172
|
-
Observer.set(this.network, 'remote', true);
|
|
173
|
-
let _response = fetch(request);
|
|
174
|
-
// This catch() is NOT intended to handle failure of the fetch
|
|
175
|
-
_response.catch(e => Observer.set(this.network, 'error', e.message));
|
|
176
|
-
// Save a reference to this
|
|
177
|
-
return _response.then(async response => {
|
|
178
|
-
// Stop loading status
|
|
179
|
-
Observer.set(this.network, 'remote', false);
|
|
180
|
-
return response;
|
|
181
|
-
});
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// Handles response object
|
|
185
|
-
const handleResponse = async (response, params) => {
|
|
186
|
-
response = await response;
|
|
187
|
-
Observer.set(this.network, 'remote', false);
|
|
188
|
-
Observer.set(this.network, 'error', null);
|
|
189
|
-
if (['link', 'form'].includes(params.srcType)) {
|
|
190
|
-
Observer.set(params.src, 'active', false);
|
|
191
|
-
Observer.set(params.submitter || {}, 'active', false);
|
|
192
|
-
}
|
|
193
|
-
if (!response) return;
|
|
194
|
-
if (response.redirected && this.isSameOrigin(response.url)) {
|
|
195
|
-
Observer.set(this.location, { href: response.url }, {
|
|
196
|
-
detail: { isRedirect: true },
|
|
197
|
-
});
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
let location = response.headers.get('Location');
|
|
201
|
-
if (location && response.status === xRedirectCode) {
|
|
202
|
-
Observer.set(this.network, 'redirecting', location);
|
|
203
|
-
window.location = location;
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
// ------------
|
|
208
|
-
url = typeof url === 'string' ? { href: url } : url;
|
|
209
|
-
params = { referrer: this.location.href, ...params };
|
|
189
|
+
async go(url, init = {}, detail = {}) {
|
|
190
|
+
if (this._abortController) {
|
|
191
|
+
this._abortController.abort();
|
|
192
|
+
}
|
|
193
|
+
this._abortController = new AbortController();
|
|
194
|
+
this._xRedirectCode = 300;
|
|
210
195
|
// ------------
|
|
211
|
-
|
|
212
|
-
|
|
196
|
+
url = typeof url === 'string' ? new whatwag.URL(url) : url;
|
|
197
|
+
init = { referrer: this.location.href, ...init };
|
|
213
198
|
// ------------
|
|
214
|
-
if (
|
|
215
|
-
|
|
216
|
-
Observer.set(params.submitter || {}, 'active', true);
|
|
199
|
+
if (detail.srcType !== 'init' && (_before(url.href, '#') === _before(init.referrer, '#') && (init.method || 'GET').toUpperCase() === 'GET')) {
|
|
200
|
+
return;
|
|
217
201
|
}
|
|
202
|
+
// ------------
|
|
203
|
+
if (['link', 'form'].includes(detail.srcType)) {
|
|
204
|
+
Observer.set(detail.src, 'active', true);
|
|
205
|
+
Observer.set(detail.submitter || {}, 'active', true);
|
|
206
|
+
}
|
|
207
|
+
// ------------
|
|
208
|
+
Observer.set(this.location, url, { detail: { ...init, ...detail }, });
|
|
209
|
+
Observer.set(this.network, 'redirecting', null);
|
|
218
210
|
// ------------
|
|
211
|
+
// The request object
|
|
212
|
+
let request = this.generateRequest(url.href, init);
|
|
213
|
+
// The navigation event
|
|
214
|
+
let httpEvent = new HttpEvent(request, detail, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
|
|
215
|
+
// Response
|
|
216
|
+
let response = await this.clients.get('*').handle(httpEvent, (...args) => this.remoteFetch(...args));
|
|
217
|
+
let finalResponse = this.handleResponse(httpEvent, response);
|
|
218
|
+
// Return value
|
|
219
|
+
return finalResponse;
|
|
220
|
+
}
|
|
219
221
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
// Generates request object
|
|
223
|
+
generateRequest(href, init) {
|
|
224
|
+
return new Request(href, {
|
|
225
|
+
signal: this._abortController.signal,
|
|
226
|
+
...init,
|
|
227
|
+
headers: {
|
|
228
|
+
'Accept': 'application/json',
|
|
229
|
+
'X-Redirect-Policy': 'manual-when-cross-origin',
|
|
230
|
+
'X-Redirect-Code': this._xRedirectCode,
|
|
231
|
+
'X-Powered-By': '@webqit/webflo',
|
|
232
|
+
...(init.headers || {}),
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
}
|
|
225
236
|
|
|
237
|
+
// Generates session object
|
|
238
|
+
getSession(e, id = null, persistent = false) {
|
|
239
|
+
return Storage(id, persistent);
|
|
240
|
+
}
|
|
226
241
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
242
|
+
// Initiates remote fetch and sets the status
|
|
243
|
+
remoteFetch(request) {
|
|
244
|
+
Observer.set(this.network, 'remote', true);
|
|
245
|
+
let _response = fetch(request);
|
|
246
|
+
// This catch() is NOT intended to handle failure of the fetch
|
|
247
|
+
_response.catch(e => Observer.set(this.network, 'error', e.message));
|
|
248
|
+
// Return xResponse
|
|
249
|
+
return _response.then(async response => {
|
|
250
|
+
// Stop loading status
|
|
251
|
+
Observer.set(this.network, 'remote', false);
|
|
252
|
+
return new Response(response);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
230
255
|
|
|
231
|
-
|
|
232
|
-
|
|
256
|
+
// Handles response object
|
|
257
|
+
handleResponse(e, response) {
|
|
258
|
+
if (!(response instanceof Response)) { response = new Response(response); }
|
|
259
|
+
Observer.set(this.network, 'remote', false);
|
|
260
|
+
Observer.set(this.network, 'error', null);
|
|
261
|
+
if (['link', 'form'].includes(e.detail.srcType)) {
|
|
262
|
+
Observer.set(e.detail.src, 'active', false);
|
|
263
|
+
Observer.set(e.detail.submitter || {}, 'active', false);
|
|
264
|
+
}
|
|
265
|
+
if (response.redirected && this.isSameOrigin(response.url)) {
|
|
266
|
+
Observer.set(this.location, { href: response.url }, {
|
|
267
|
+
detail: { isRedirect: true },
|
|
268
|
+
});
|
|
269
|
+
} else {
|
|
270
|
+
let location = response.headers.get('Location');
|
|
271
|
+
if (location && response.status === this._xRedirectCode) {
|
|
272
|
+
Observer.set(this.network, 'redirecting', location);
|
|
273
|
+
window.location = location;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return response;
|
|
277
|
+
}
|
|
233
278
|
|
|
234
279
|
/**
|
|
235
280
|
* Checks if an URL is same origin.
|