@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.
Files changed (97) hide show
  1. package/package.json +5 -12
  2. package/src/Cli.js +131 -0
  3. package/src/Configurator.js +97 -0
  4. package/src/Context.js +76 -0
  5. package/src/config-pi/deployment/Env.js +69 -0
  6. package/src/config-pi/deployment/Layout.js +65 -0
  7. package/src/config-pi/deployment/Origins.js +133 -0
  8. package/src/config-pi/deployment/Virtualization.js +65 -0
  9. package/src/config-pi/deployment/index.js +18 -0
  10. package/src/config-pi/index.js +16 -0
  11. package/src/config-pi/runtime/Client.js +59 -0
  12. package/src/config-pi/runtime/Server.js +174 -0
  13. package/src/config-pi/runtime/client/Worker.js +117 -0
  14. package/src/config-pi/runtime/client/index.js +12 -0
  15. package/src/config-pi/runtime/index.js +18 -0
  16. package/src/config-pi/runtime/server/Headers.js +90 -0
  17. package/src/config-pi/runtime/server/Redirects.js +108 -0
  18. package/src/config-pi/runtime/server/index.js +14 -0
  19. package/src/config-pi/static/Manifest.js +321 -0
  20. package/src/config-pi/static/Ssg.js +72 -0
  21. package/src/config-pi/static/index.js +14 -0
  22. package/src/deployment-pi/index.js +10 -0
  23. package/src/{services → deployment-pi}/origins/index.js +88 -58
  24. package/src/index.js +14 -147
  25. package/src/{runtime → runtime-pi}/Router.js +19 -19
  26. package/src/runtime-pi/client/Context.js +7 -0
  27. package/src/{runtime → runtime-pi}/client/Router.js +2 -2
  28. package/src/{runtime/client/Navigator.js → runtime-pi/client/Runtime.js} +148 -103
  29. package/src/runtime-pi/client/RuntimeClient.js +114 -0
  30. package/src/{runtime → runtime-pi}/client/Storage.js +1 -1
  31. package/src/{runtime → runtime-pi}/client/Url.js +2 -6
  32. package/src/{runtime/client/WorkerClient.js → runtime-pi/client/WorkerComm.js} +2 -2
  33. package/src/runtime-pi/client/generate.js +242 -0
  34. package/src/runtime-pi/client/generate.oohtml.js +7 -0
  35. package/src/runtime-pi/client/index.js +18 -0
  36. package/src/runtime-pi/client/whatwag.js +27 -0
  37. package/src/runtime-pi/client/worker/Context.js +7 -0
  38. package/src/runtime-pi/client/worker/Worker.js +243 -0
  39. package/src/runtime-pi/client/worker/WorkerClient.js +46 -0
  40. package/src/runtime-pi/client/worker/index.js +18 -0
  41. package/src/runtime-pi/index.js +14 -0
  42. package/src/runtime-pi/server/Context.js +16 -0
  43. package/src/{runtime → runtime-pi}/server/Router.js +6 -6
  44. package/src/runtime-pi/server/Runtime.js +531 -0
  45. package/src/runtime-pi/server/RuntimeClient.js +103 -0
  46. package/src/runtime-pi/server/index.js +41 -0
  47. package/src/runtime-pi/server/whatwag.js +35 -0
  48. package/src/{runtime → runtime-pi}/util.js +0 -0
  49. package/src/{runtime/_FormData.js → runtime-pi/xFormData.js} +2 -2
  50. package/src/{runtime/_Headers.js → runtime-pi/xHeaders.js} +4 -4
  51. package/src/runtime-pi/xHttpEvent.js +93 -0
  52. package/src/runtime-pi/xHttpMessage.js +179 -0
  53. package/src/runtime-pi/xRequest.js +67 -0
  54. package/src/runtime-pi/xRequestHeaders.js +95 -0
  55. package/src/runtime-pi/xResponse.js +62 -0
  56. package/src/{runtime/_ResponseHeaders.js → runtime-pi/xResponseHeaders.js} +38 -18
  57. package/src/{runtime/_URL.js → runtime-pi/xURL.js} +4 -4
  58. package/src/runtime-pi/xfetch.js +7 -0
  59. package/src/{services → services-pi}/certbot/http-auth-hook.js +0 -0
  60. package/src/{services → services-pi}/certbot/http-cleanup-hook.js +0 -0
  61. package/src/{services → services-pi}/certbot/index.js +21 -15
  62. package/src/services-pi/index.js +9 -0
  63. package/src/static-pi/index.js +11 -0
  64. package/src/webflo.js +33 -0
  65. package/test/index.test.js +26 -0
  66. package/src/build/client/index.js +0 -261
  67. package/src/build/index.js +0 -5
  68. package/src/config/client.js +0 -191
  69. package/src/config/headers.js +0 -121
  70. package/src/config/index.js +0 -14
  71. package/src/config/layout.js +0 -83
  72. package/src/config/manifest.js +0 -341
  73. package/src/config/origins.js +0 -165
  74. package/src/config/prerendering.js +0 -100
  75. package/src/config/redirects.js +0 -137
  76. package/src/config/server.js +0 -201
  77. package/src/config/variables.js +0 -102
  78. package/src/config/vhosts.js +0 -93
  79. package/src/runtime/_MessageStream.js +0 -195
  80. package/src/runtime/_NavigationEvent.js +0 -91
  81. package/src/runtime/_Request.js +0 -59
  82. package/src/runtime/_RequestHeaders.js +0 -72
  83. package/src/runtime/_Response.js +0 -56
  84. package/src/runtime/client/NavigationEvent.js +0 -21
  85. package/src/runtime/client/Runtime.js +0 -126
  86. package/src/runtime/client/Worker.js +0 -317
  87. package/src/runtime/client/archive/Cache.js +0 -38
  88. package/src/runtime/client/archive/Http.js +0 -225
  89. package/src/runtime/client/archive/StdRequest.js +0 -74
  90. package/src/runtime/client/archive/WorkerComm.js +0 -183
  91. package/src/runtime/client/effects/sounds.js +0 -64
  92. package/src/runtime/index.js +0 -5
  93. package/src/runtime/server/NavigationEvent.js +0 -39
  94. package/src/runtime/server/Runtime.js +0 -593
  95. package/src/runtime/server/index.js +0 -183
  96. package/src/runtime/server/index.mjs +0 -10
  97. 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 _isEmpty from '@webqit/util/js/isEmpty.js';
7
- import _merge from '@webqit/util/obj/merge.js';
8
- import parseArgs from '@webqit/backpack/src/cli/parseArgs.js';
9
- import Ui from '@webqit/backpack/src/cli/Ui.js';
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
- const commands = {
20
- config: 'Starts a configuration process.',
21
- build: build.client.desc.build,
22
- deploy: services.origins.desc.deploy,
23
- ...runtime.server.desc,
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/isString.js';
6
- import _isFunction from '@webqit/util/js/isFunction.js';
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 string|array path
23
- * @param object layout
24
- * @param object context
20
+ * @param Context cx
21
+ * @param String|Array path
25
22
  *
26
23
  * @return void
27
24
  */
28
- constructor(path, layout, context) {
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
- async route(method, event, arg, _default) {
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 _this = { ...$this.context };
49
+ const thisContext = {};
53
50
  if (!thisTick.trail || thisTick.trail.length < thisTick.destination.length) {
54
51
  thisTick = await $this.readTick(thisTick);
55
52
  // -------------
56
- _this.pathname = `/${thisTick.trail.join('/')}`;
57
- _this.stepname = thisTick.trail[thisTick.trail.length - 1];
58
- $this.finalizeHandlerContext(_this, thisTick);
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(_this, thisTick.event, thisTick.arg, _next/*next*/);
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(_this, thisTick.event, thisTick.arg);
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
+ }
@@ -0,0 +1,7 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import _Contex from '../../Context.js';
6
+
7
+ export default class Context extends _Contex {}
@@ -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/before.js';
6
- import _toTitle from '@webqit/util/str/toTitle.js';
7
- import { wwwFormUnserialize, wwwFormSet, wwwFormSerialize } from '../util.js';
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 Navigator {
43
+ export default class Runtime {
12
44
 
13
- constructor(client) {
14
- this.client = client;
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
- * Navigator location
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), { ...submitParams, body: formData, src: form, srcType: 'form', });
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
- * Initial navigation
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 params
184
+ * @param object init
185
+ * @param object src
149
186
  *
150
- * @return void
187
+ * @return Response
151
188
  */
152
- async go(url, params = {}) {
153
-
154
- // Generates request object
155
- const generateRequest = (url, params) => {
156
- return new Request(url, {
157
- ...params,
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
- Observer.set(this.location, url, { detail: params, });
212
- Observer.set(this.network, 'redirecting', null);
196
+ url = typeof url === 'string' ? new whatwag.URL(url) : url;
197
+ init = { referrer: this.location.href, ...init };
213
198
  // ------------
214
- if (['link', 'form'].includes(params.srcType)) {
215
- Observer.set(params.src, 'active', true);
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
- if (this._abortController) {
221
- this._abortController.abort();
222
- }
223
- this._abortController = new AbortController();
224
- let xRedirectCode = 300;
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
- if (params.srcType === 'init' || !(_before(url.href, '#') === _before(params.referrer, '#') && (params.method || 'GET').toUpperCase() === 'GET')) {
228
- handleResponse(this.client.call(this, generateRequest(url.href, params), params, remoteRequest), params);
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
- return this._abortController;
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.