@webqit/webflo 0.11.39 → 0.11.40

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 (38) hide show
  1. package/package.json +2 -3
  2. package/src/Context.js +3 -3
  3. package/src/config-pi/deployment/Layout.js +0 -1
  4. package/src/runtime-pi/{RuntimeClient.js → Application.js} +2 -2
  5. package/src/runtime-pi/HttpEvent.js +106 -0
  6. package/src/runtime-pi/Router.js +2 -3
  7. package/src/runtime-pi/Runtime.js +3 -3
  8. package/src/runtime-pi/client/{RuntimeClient.js → Application.js} +12 -4
  9. package/src/runtime-pi/client/Router.js +4 -3
  10. package/src/runtime-pi/client/Runtime.js +37 -59
  11. package/src/runtime-pi/client/Url.js +3 -3
  12. package/src/runtime-pi/client/Workport.js +1 -1
  13. package/src/runtime-pi/client/{Storage.js → createStorage.js} +3 -3
  14. package/src/runtime-pi/client/generate.js +5 -3
  15. package/src/runtime-pi/client/index.js +4 -4
  16. package/src/runtime-pi/client/worker/{WorkerClient.js → Application.js} +12 -8
  17. package/src/runtime-pi/client/worker/{Worker.js → Runtime.js} +25 -27
  18. package/src/runtime-pi/client/worker/index.js +6 -6
  19. package/src/runtime-pi/server/{RuntimeClient.js → Application.js} +8 -8
  20. package/src/runtime-pi/server/Router.js +3 -2
  21. package/src/runtime-pi/server/Runtime.js +41 -98
  22. package/src/runtime-pi/server/index.js +4 -4
  23. package/src/runtime-pi/util-http.js +70 -0
  24. package/src/runtime-pi/util-url.js +147 -0
  25. package/src/runtime-pi/xFormData.js +10 -46
  26. package/src/runtime-pi/xHeaders.js +2 -11
  27. package/src/runtime-pi/xRequest.js +29 -42
  28. package/src/runtime-pi/xRequestHeaders.js +20 -23
  29. package/src/runtime-pi/xResponse.js +19 -15
  30. package/src/runtime-pi/xResponseHeaders.js +41 -43
  31. package/src/runtime-pi/xURL.js +71 -77
  32. package/src/runtime-pi/xfetch.js +15 -6
  33. package/src/runtime-pi/xxHttpMessage.js +102 -0
  34. package/src/runtime-pi/client/whatwag.js +0 -27
  35. package/src/runtime-pi/server/whatwag.js +0 -35
  36. package/src/runtime-pi/util.js +0 -162
  37. package/src/runtime-pi/xHttpEvent.js +0 -101
  38. package/src/runtime-pi/xHttpMessage.js +0 -171
@@ -3,9 +3,9 @@
3
3
  * @imports
4
4
  */
5
5
  import Router from '../Router.js';
6
- import _WorkerClient from '../../RuntimeClient.js';
6
+ import _Application from '../../Application.js';
7
7
 
8
- export default class RuntimeClient extends _WorkerClient {
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
- const httpMethodName = httpEvent.request.method.toUpperCase();
31
- let response = await router.route([httpMethodName, 'default'], httpEvent, {}, async event => {
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 { urlPattern } from '../../util.js';
7
- import { HttpEvent, Request, Response, fetch as xfetch, Observer } from '../Runtime.js';
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 _Worker from '../../Runtime.js';
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
- } from '../Runtime.js';
18
+ }
23
19
 
24
20
  /**
25
21
  * ---------------------------
26
- * The Worker Initializer
22
+ * The Runtime Initializer
27
23
  * ---------------------------
28
24
  */
29
25
 
30
- export default class Worker extends _Worker {
26
+ export default class Runtime extends _Runtime {
31
27
 
32
28
  /**
33
29
  * Runtime
34
30
  *
35
31
  * @param Object cx
36
- * @param Function clientCallback
32
+ * @param Function applicationInstance
37
33
  *
38
34
  * @return void
39
35
  */
40
- constructor(cx, clientCallback) {
41
- super(cx, clientCallback);
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 && !urlPattern(c, self.origin).isPattern());
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 Request.rip(req);
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.client.init) return;
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.client.init(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
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.client.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
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 Request(href, init);
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 => urlPattern(p, self.origin).test(url));
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 => Response.compat(_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 (!(response instanceof Response)) { response = Response.compat(response); }
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 WorkerClient from './WorkerClient.js';
7
- import Worker from './Worker.js';
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(clientCallback = null) {
12
+ export async function start(applicationInstance = null) {
13
13
  const cx = this || {};
14
- const defaultClientCallback = _cx => new WorkerClient(_cx);
15
- return new Worker(Context.create(cx), clientCallback || defaultClientCallback);
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 './Worker.js';
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 _RuntimeClient from '../RuntimeClient.js';
9
+ import _Application from '../Application.js';
10
10
 
11
- export default class RuntimeClient extends _RuntimeClient {
11
+ export default class Application extends _Application {
12
12
 
13
13
  /**
14
- * RuntimeClient
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
- const httpMethodName = httpEvent.request.method.toUpperCase();
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.bodyAttrs.inputType === 'object' && httpEvent.request.headers.accept.match('text/html')) {
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
- response = new httpEvent.Response(rendering.toString(), {
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.push(thisTick.currentSegment);
31
- thisTick.trailOnFile.push(thisTick.currentSegmentOnFile.seg);
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 = [];
@@ -6,44 +6,22 @@ import Fs from 'fs';
6
6
  import Path from 'path';
7
7
  import Http from 'http';
8
8
  import Https from 'https';
9
- import Formidable from 'formidable';
10
9
  import Sessions from 'client-sessions';
11
10
  import { Observer } from '@webqit/oohtml-ssr/apis.js';
12
11
  import { _each } from '@webqit/util/obj/index.js';
13
12
  import { _isEmpty } from '@webqit/util/js/index.js';
14
13
  import { _from as _arrFrom, _any } from '@webqit/util/arr/index.js';
15
14
  import { slice as _streamSlice } from 'stream-slice';
16
- import { urlPattern } from '../util.js';
17
- import * as whatwag from './whatwag.js';
18
- import xURL from '../xURL.js';
19
- import xFormData from "../xFormData.js";
20
- import xRequestHeaders from "../xRequestHeaders.js";
21
- import xResponseHeaders from "../xResponseHeaders.js";
15
+ import { Readable as _ReadableStream } from 'stream';
16
+ import { pattern } from '../util-url.js';
22
17
  import xRequest from "../xRequest.js";
23
18
  import xResponse from "../xResponse.js";
24
19
  import xfetch from '../xfetch.js';
25
- import xHttpEvent from '../xHttpEvent.js';
20
+ import HttpEvent from '../HttpEvent.js';
26
21
  import _Runtime from '../Runtime.js';
27
22
 
28
- const URL = xURL(whatwag.URL);
29
- const FormData = xFormData(whatwag.FormData);
30
- const ReadableStream = whatwag.ReadableStream;
31
- const RequestHeaders = xRequestHeaders(whatwag.Headers);
32
- const ResponseHeaders = xResponseHeaders(whatwag.Headers);
33
- const Request = xRequest(whatwag.Request, RequestHeaders, FormData, whatwag.Blob);
34
- const Response = xResponse(whatwag.Response, ResponseHeaders, FormData, whatwag.Blob);
35
- const fetch = xfetch(whatwag.fetch);
36
- const HttpEvent = xHttpEvent(Request, Response, URL);
37
-
38
23
  export {
39
- URL,
40
- FormData,
41
- ReadableStream,
42
- RequestHeaders,
43
- ResponseHeaders,
44
- Request,
45
- Response,
46
- fetch,
24
+ //fetch,
47
25
  HttpEvent,
48
26
  Observer,
49
27
  }
@@ -54,18 +32,18 @@ export default class Runtime extends _Runtime {
54
32
  * Runtime
55
33
  *
56
34
  * @param Object cx
57
- * @param Function clientCallback
35
+ * @param Function applicationInstance
58
36
  *
59
37
  * @return void
60
38
  */
61
- constructor(cx, clientCallback) {
62
- super(cx, clientCallback);
39
+ constructor(cx, applicationInstance) {
40
+ super(cx, applicationInstance);
63
41
  // ---------------
64
42
  this.ready = (async () => {
65
43
  // ---------------
66
44
  const resolveContextObj = async (cx, force = false) => {
67
- if (_isEmpty(cx.server) || force) { cx.server = await (new cx.config.runtime.Server(cx)).read(); }
68
45
  if (_isEmpty(cx.layout) || force) { cx.layout = await (new cx.config.deployment.Layout(cx)).read(); }
46
+ if (_isEmpty(cx.server) || force) { cx.server = await (new cx.config.runtime.Server(cx)).read(); }
69
47
  if (_isEmpty(cx.env) || force) { cx.env = await (new cx.config.deployment.Env(cx)).read(); }
70
48
  };
71
49
  await resolveContextObj(this.cx);
@@ -88,6 +66,7 @@ export default class Runtime extends _Runtime {
88
66
  if (vhost.path) {
89
67
  cx = this.cx.constructor.create(this.cx, Path.join(this.cx.CWD, vhost.path));
90
68
  await resolveContextObj(cx, true);
69
+ cx.dict.key = true;
91
70
  // From the server that's most likely to be active
92
71
  port || (port = cx.server.https.port || cx.server.port);
93
72
  // The domain list that corresponds to the specified resolved port
@@ -145,6 +124,7 @@ export default class Runtime extends _Runtime {
145
124
  }
146
125
  // ---------------
147
126
  const handleRequest = async (proto, request, response) => {
127
+ request[Symbol.toStringTag] = 'ReadableStream';
148
128
  const [ fullUrl, requestInit ] = await this.parseNodeRequest(proto, request);
149
129
  let clientResponse = await this.go(fullUrl, requestInit, { request, response });
150
130
  if (response.headersSent) return;
@@ -158,9 +138,12 @@ export default class Runtime extends _Runtime {
158
138
  if (clientResponse.headers.location) {
159
139
  return response.end();
160
140
  }
161
- if ((clientResponse.body instanceof ReadableStream)) {
141
+ if ((clientResponse.body instanceof _ReadableStream)) {
162
142
  return clientResponse.body.pipe(response);
163
143
  }
144
+ if ((clientResponse.body instanceof ReadableStream)) {
145
+ return _ReadableStream.from(clientResponse.body).pipe(response);
146
+ }
164
147
  let body = clientResponse.body;
165
148
  if (clientResponse.headers.contentType === 'application/json') {
166
149
  body += '';
@@ -195,12 +178,12 @@ export default class Runtime extends _Runtime {
195
178
  }
196
179
  this.cx.logger.info(``);
197
180
  }
198
- if (this.client && this.client.init) {
199
- const request = this.generateRequest('/');
181
+ if (this.app && this.app.init) {
182
+ const request = this.generateRequest('http://localhost/');
200
183
  const httpEvent = new HttpEvent(request, { srcType: 'initialization' }, (id = 'session', options = { duration: 60 * 60 * 24, activeDuration: 60 * 60 * 24 }, callback = null) => {
201
184
  return this.getSession(this.cx, httpEvent, id, options, callback);
202
185
  });
203
- await this.client.init(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
186
+ await this.app.init(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
204
187
  }
205
188
  })();
206
189
  // ---------------
@@ -220,55 +203,14 @@ export default class Runtime extends _Runtime {
220
203
  * @return Array
221
204
  */
222
205
  async parseNodeRequest(proto, request) {
223
- let url = request.url;
224
206
  // Detected when using manual proxy setting in a browser
225
- if (url.startsWith(`http://${ request.headers.host }`) || url.startsWith(`https://${ request.headers.host }`)) {
226
- url = url.split(request.headers.host)[1];
207
+ if (request.url.startsWith(`http://${ request.headers.host }`) || request.url.startsWith(`https://${ request.headers.host }`)) {
208
+ request.url = request.url.split(request.headers.host)[1];
227
209
  }
228
- const fullUrl = proto + '://' + request.headers.host + url;
210
+ const fullUrl = proto + '://' + request.headers.host + request.url;
229
211
  const requestInit = { method: request.method, headers: request.headers };
230
- if (request.method !== 'GET' && request.method !== 'HEAD') {
231
- requestInit.body = await new Promise((resolve, reject) => {
232
- var formidable = new Formidable.IncomingForm({ multiples: true, allowEmptyFiles: true, keepExtensions: true });
233
- formidable.parse(request, (error, fields, files) => {
234
- if (error) { return reject(error); }
235
- if (request.headers['content-type'] === 'application/json') {
236
- return resolve(fields);
237
- }
238
- const formData = new FormData;
239
- Object.keys(fields).forEach(name => {
240
- if (Array.isArray(fields[name])) {
241
- const values = Array.isArray(fields[name][0])
242
- ? fields[name][0]/* bugly a nested array when there are actually more than entry */
243
- : fields[name];
244
- values.forEach(value => {
245
- formData.append(!name.endsWith(']') ? name + '[]' : name, value);
246
- });
247
- } else {
248
- formData.append(name, fields[name]);
249
- }
250
- });
251
- Object.keys(files).forEach(name => {
252
- const fileCompat = file => {
253
- // IMPORTANT
254
- // Path up the "formidable" file in a way that "formdata-node"
255
- // to can translate it into its own file instance
256
- file[Symbol.toStringTag] = 'File';
257
- file.stream = () => Fs.createReadStream(file.path);
258
- // Done pathcing
259
- return file;
260
- }
261
- if (Array.isArray(files[name])) {
262
- files[name].forEach(value => {
263
- formData.append(name, fileCompat(value));
264
- });
265
- } else {
266
- formData.append(name, fileCompat(files[name]));
267
- }
268
- });
269
- resolve(formData);
270
- });
271
- });
212
+ if (!['GET', 'HEAD'].includes(request.method)) {
213
+ requestInit.body = request;
272
214
  }
273
215
  return [ fullUrl, requestInit ];
274
216
  }
@@ -286,7 +228,7 @@ export default class Runtime extends _Runtime {
286
228
  await this.ready;
287
229
 
288
230
  // ------------
289
- url = typeof url === 'string' ? new whatwag.URL(url) : url;
231
+ url = typeof url === 'string' ? new URL(url) : url;
290
232
  init = { referrer: this.location.href, ...init };
291
233
  // ------------
292
234
  const hosts = [];
@@ -309,10 +251,10 @@ export default class Runtime extends _Runtime {
309
251
  exit = { status: 302, headers: { Location: ( url.hostname = `www.${ url.hostname }`, url.href ) } };
310
252
  } else if (this.cx.config.runtime.server.Redirects) {
311
253
  exit = ((await (new this.cx.config.runtime.server.Redirects(this.cx)).read()).entries || []).reduce((_rdr, entry) => {
312
- return _rdr || ((_rdr = urlPattern(entry.from, url.origin).exec(url.href)) && { status: entry.code || 302, headers: { Location: _rdr.render(entry.to) } });
254
+ return _rdr || ((_rdr = pattern(entry.from, url.origin).exec(url.href)) && { status: entry.code || 302, headers: { Location: _rdr.render(entry.to) } });
313
255
  }, null);
314
256
  }
315
- if (exit) { return new Response(null, exit); }
257
+ if (exit) { return new xResponse(null, exit); }
316
258
  // ------------
317
259
 
318
260
  // ------------
@@ -323,7 +265,7 @@ export default class Runtime extends _Runtime {
323
265
  // ------------
324
266
  // Automatically-added headers
325
267
  const autoHeaders = this.cx.config.runtime.server.Headers
326
- ? ((await (new this.cx.config.runtime.server.Headers(this.cx)).read()).entries || []).filter(entry => urlPattern(entry.url, url.origin).exec(url.href))
268
+ ? ((await (new this.cx.config.runtime.server.Headers(this.cx)).read()).entries || []).filter(entry => pattern(entry.url, url.origin).exec(url.href))
327
269
  : [];
328
270
  // The request object
329
271
  const request = this.generateRequest(url.href, init, autoHeaders.filter(header => header.type === 'request'));
@@ -334,10 +276,10 @@ export default class Runtime extends _Runtime {
334
276
  // Response
335
277
  let response, finalResponse;
336
278
  try {
337
- response = await this.client.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
279
+ response = await this.app.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
338
280
  finalResponse = await this.handleResponse(this.cx, httpEvent, response, autoHeaders.filter(header => header.type === 'response'));
339
281
  } catch(e) {
340
- finalResponse = new Response(null, { status: 500, statusText: e.message });
282
+ finalResponse = new xResponse(null, { status: 500, statusText: e.message });
341
283
  console.error(e);
342
284
  }
343
285
  // Logging
@@ -353,19 +295,20 @@ export default class Runtime extends _Runtime {
353
295
  // Fetch from proxied host
354
296
  async proxyGo(vhost, url, init) {
355
297
  // ---------
356
- const url2 = new whatwag.URL(url);
298
+ const url2 = new URL(url);
357
299
  url2.port = vhost.port;
358
300
  if (vhost.proto) { url2.protocol = vhost.proto; }
359
301
  // ---------
360
- const init2 = { ...init, compress: false };
302
+ const init2 = { ...init, decompress: false/* honoured in xfetch() */ };
361
303
  if (!init2.headers) init2.headers = {};
362
304
  init2.headers.host = url2.host;
305
+ delete init2.headers.connection;
363
306
  // ---------
364
307
  let response;
365
308
  try {
366
309
  response = await this.remoteFetch(url2, init2);
367
310
  } catch(e) {
368
- response = new Response(null, { status: 500, statusText: e.message });
311
+ response = new xResponse(null, { status: 500, statusText: e.message });
369
312
  console.error(e);
370
313
  }
371
314
  if (this.cx.logger) {
@@ -378,7 +321,7 @@ export default class Runtime extends _Runtime {
378
321
 
379
322
  // Generates request object
380
323
  generateRequest(href, init = {}, autoHeaders = []) {
381
- const request = new Request(href, init);
324
+ const request = new xRequest(href, init);
382
325
  this._autoHeaders(request.headers, autoHeaders);
383
326
  return request;
384
327
  }
@@ -422,24 +365,24 @@ export default class Runtime extends _Runtime {
422
365
  let href = request;
423
366
  if (request instanceof Request) {
424
367
  href = request.url;
425
- } else if (request instanceof whatwag.URL) {
368
+ } else if (request instanceof URL) {
426
369
  href = request.href;
427
370
  }
428
371
  Observer.set(this.network, 'remote', href);
429
- const _response = fetch(request, ...args);
372
+ const _response = xfetch(request, ...args);
430
373
  // This catch() is NOT intended to handle failure of the fetch
431
374
  _response.catch(e => Observer.set(this.network, 'error', e.message));
432
375
  // Save a reference to this
433
376
  return _response.then(async response => {
434
377
  // Stop loading status
435
378
  Observer.set(this.network, 'remote', false);
436
- return new Response(response);
379
+ return new xResponse(response);
437
380
  });
438
381
  }
439
382
 
440
383
  // Handles response object
441
384
  async handleResponse(cx, e, response, autoHeaders = []) {
442
- if (!(response instanceof Response)) { response = new Response(response); }
385
+ if (!(response instanceof xResponse)) { response = new xResponse(response); }
443
386
  Observer.set(this.network, 'remote', false);
444
387
  Observer.set(this.network, 'error', null);
445
388
 
@@ -461,7 +404,7 @@ export default class Runtime extends _Runtime {
461
404
  if (response.headers.location) {
462
405
  const xRedirectPolicy = e.request.headers.get('X-Redirect-Policy');
463
406
  const xRedirectCode = e.request.headers.get('X-Redirect-Code') || 300;
464
- const destinationUrl = new whatwag.URL(response.headers.location, e.url.origin);
407
+ const destinationUrl = new URL(response.headers.location, e.url.origin);
465
408
  const isSameOriginRedirect = destinationUrl.origin === e.url.origin;
466
409
  let isSameSpaRedirect, sparootsFile = Path.join(cx.CWD, cx.layout.PUBLIC_DIR, 'sparoots.json');
467
410
  if (isSameOriginRedirect && xRedirectPolicy === 'manual-when-cross-spa' && Fs.existsSync(sparootsFile)) {
@@ -483,7 +426,7 @@ export default class Runtime extends _Runtime {
483
426
 
484
427
  // ----------------
485
428
  // 404
486
- if (response.bodyAttrs.input === undefined || response.bodyAttrs.input === null) {
429
+ if (response.meta.body === undefined || response.meta.body === null) {
487
430
  response.attrs.status = response.status !== 200 ? response.status : 404;
488
431
  response.attrs.statusText = `${e.request.url} not found!`;
489
432
  return response;
@@ -507,7 +450,7 @@ export default class Runtime extends _Runtime {
507
450
  // Body
508
451
  let rangeRequest, body = response.body;
509
452
  if ((rangeRequest = e.request.headers.range) && !response.headers.get('Content-Range')
510
- && ((body instanceof ReadableStream) || (ArrayBuffer.isView(body) && (body = ReadableStream.from(body))))) {
453
+ && ((body instanceof ReadableStream) || (ArrayBuffer.isView(body) && (body = _ReadableStream.from(body))))) {
511
454
  // ...in partials
512
455
  const totalLength = response.headers.contentLength || 0;
513
456
  const ranges = await rangeRequest.reduce(async (_ranges, range) => {
@@ -540,7 +483,7 @@ export default class Runtime extends _Runtime {
540
483
  });
541
484
  } else {
542
485
  // TODO: of ranges.parts is more than one, return multipart/byteranges
543
- response = new Response(ranges.parts[0].body, {
486
+ response = new xResponse(ranges.parts[0].body, {
544
487
  status: 206,
545
488
  statusText: response.statusText,
546
489
  headers: response.headers,
@@ -3,16 +3,16 @@
3
3
  * @imports
4
4
  */
5
5
  import Context from './Context.js';
6
- import RuntimeClient from './RuntimeClient.js';
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(clientCallback = null) {
12
+ export async function start(applicationInstance = null) {
13
13
  const cx = this || {};
14
- const defaultClientCallback = _cx => new RuntimeClient(_cx);
15
- return new Runtime(Context.create(cx), clientCallback || defaultClientCallback);
14
+ const defaultApplicationInstance = _cx => new Application(_cx);
15
+ return new Runtime(Context.create(cx), applicationInstance || defaultApplicationInstance);
16
16
  }
17
17
 
18
18
  /**