@webqit/webflo 0.8.76 → 0.9.0

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} +143 -102
  29. package/src/runtime-pi/client/RuntimeClient.js +114 -0
  30. package/src/{runtime → runtime-pi}/client/Storage.js +8 -7
  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 +102 -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 -61
  82. package/src/runtime/_RequestHeaders.js +0 -72
  83. package/src/runtime/_Response.js +0 -56
  84. package/src/runtime/client/Cache.js +0 -38
  85. package/src/runtime/client/Http.js +0 -225
  86. package/src/runtime/client/NavigationEvent.js +0 -21
  87. package/src/runtime/client/Runtime.js +0 -126
  88. package/src/runtime/client/StdRequest.js +0 -74
  89. package/src/runtime/client/Worker.js +0 -312
  90. package/src/runtime/client/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
@@ -0,0 +1,102 @@
1
+
2
+ /**
3
+ * imports
4
+ */
5
+ import Fs from 'fs';
6
+ import Path from 'path';
7
+ import QueryString from 'querystring';
8
+ import Router from './Router.js';
9
+
10
+ export default class RuntimeClient {
11
+
12
+ /**
13
+ * RuntimeClient
14
+ *
15
+ * @param Context cx
16
+ */
17
+ constructor(cx) {
18
+ this.cx = cx;
19
+ this.renderFileCache = {};
20
+ }
21
+
22
+ /**
23
+ * Handles navigation events.
24
+ *
25
+ * @param NavigationEvent httpEvent
26
+ * @param Function remoteFetch
27
+ *
28
+ * @return Response
29
+ */
30
+ async handle(httpEvent, remoteFetch) {
31
+ // The app router
32
+ const router = new Router(this.cx, httpEvent.url.pathname);
33
+ const handle = async () => {
34
+ // --------
35
+ // ROUTE FOR DATA
36
+ // --------
37
+ let httpMethodName = httpEvent.request.method.toLowerCase();
38
+ let response = await router.route([httpMethodName === 'delete' ? 'del' : httpMethodName, 'default'], httpEvent, {}, async event => {
39
+ return router.file(event);
40
+ }, remoteFetch);
41
+ if (!(response instanceof httpEvent.Response)) {
42
+ response = new httpEvent.Response(response);
43
+ }
44
+
45
+ // --------
46
+ // Rendering
47
+ // --------
48
+ if (response.ok && response.bodyAttrs.inputType === 'object' && httpEvent.request.headers.accept.match('text/html')) {
49
+ let rendering = await this.render(httpEvent, router, response);
50
+ if (typeof rendering !== 'string') {
51
+ throw new Error('render() must return a window object or a string response.');
52
+ }
53
+ response = new httpEvent.Response(rendering, {
54
+ status: response.status,
55
+ headers: { ...response.headers.json(), contentType: 'text/html' },
56
+ });
57
+ }
58
+
59
+ return response;
60
+ };
61
+
62
+ // --------
63
+ // PIPE THROUGH MIDDLEWARES
64
+ // --------
65
+ return (this.cx.middlewares || []).concat(handle).reverse().reduce((next, fn) => {
66
+ return () => fn.call(this.cx, httpEvent, router, next);
67
+ }, null)();
68
+ }
69
+
70
+ // Renderer
71
+ async render(httpEvent, router, response) {
72
+ let data = await response.json();
73
+ return router.route('render', httpEvent, data, async (httpEvent, data) => {
74
+ var renderFile, pathnameSplit = httpEvent.url.pathname.split('/');
75
+ while ((renderFile = Path.join(this.cx.CWD, this.cx.layout.PUBLIC_DIR, './' + pathnameSplit.join('/'), 'index.html'))
76
+ && (this.renderFileCache[renderFile] === false/* false on previous runs */ || !Fs.existsSync(renderFile))) {
77
+ this.renderFileCache[renderFile] = false;
78
+ pathnameSplit.pop();
79
+ }
80
+ const instanceParams = QueryString.stringify({
81
+ SOURCE: renderFile,
82
+ URL: httpEvent.url.href,
83
+ ROOT: this.cx.CWD,
84
+ });
85
+ const { window } = await import('@webqit/oohtml-ssr/instance.js?' + instanceParams);
86
+ // --------
87
+ // OOHTML would waiting for DOM-ready in order to be initialized
88
+ await new Promise(res => window.WebQit.DOM.ready(res));
89
+ await new Promise(res => (window.document.templatesReadyState === 'complete' && res(), window.document.addEventListener('templatesreadystatechange', res)));
90
+ if (!window.document.state.env) {
91
+ window.document.setState({
92
+ env: 'server',
93
+ }, { update: true });
94
+ }
95
+ window.document.setState({ page: data, url: httpEvent.url }, { update: 'merge' });
96
+ window.document.body.setAttribute('template', 'page/' + httpEvent.url.pathname.split('/').filter(a => a).map(a => a + '+-').join('/'));
97
+ await new Promise(res => setTimeout(res, 10));
98
+ return window.print();
99
+ });
100
+ }
101
+
102
+ }
@@ -0,0 +1,41 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import Context from './Context.js';
6
+ import RuntimeClient from './RuntimeClient.js';
7
+ import Runtime from './Runtime.js';
8
+
9
+ /**
10
+ * @desc
11
+ */
12
+ export const desc = {
13
+ config: {
14
+ headers: 'Configure automatic http headers.',
15
+ prerendering: 'Configure prerendering.',
16
+ redirects: 'Configure automatic redirects.',
17
+ server: 'Configure server settings.',
18
+ vhosts: 'Configure virtual hosts.',
19
+ },
20
+ start: 'Starts the Webflo server.',
21
+ };
22
+
23
+ /**
24
+ * @start
25
+ */
26
+ export async function start(clientCallback = null) {
27
+ const cx = this || {};
28
+ const defaultClientCallback = _cx => new RuntimeClient(_cx);
29
+ return new Runtime(Context.create(cx), ( ...args ) => {
30
+ return clientCallback ? clientCallback( ...args.concat( defaultClientCallback ) ) : defaultClientCallback( ...args );
31
+ });
32
+ }
33
+
34
+ /**
35
+ * @exports
36
+ */
37
+ export {
38
+ Context,
39
+ RuntimeClient,
40
+ Runtime,
41
+ }
@@ -0,0 +1,35 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import { URL } from 'url';
6
+ import { FormData, File, Blob } from 'formdata-node';
7
+ import fetch, { Request, Response, Headers } from 'node-fetch';
8
+ import { FormDataEncoder } from 'form-data-encoder';
9
+ import { Readable } from "stream";
10
+
11
+ /**
12
+ * The NavigationEvent class
13
+ */
14
+ if (!Request.prototype.formData) {
15
+ Request.prototype.formData = async function() { return null }
16
+ }
17
+ if (!Response.prototype.formData) {
18
+ Response.prototype.formData = async function() { return null }
19
+ }
20
+ FormData.encode = formData => {
21
+ const encoder = new FormDataEncoder(formData);
22
+ return [ Readable.from(encoder.encode()), encoder.headers ];
23
+ };
24
+
25
+ export {
26
+ URL,
27
+ fetch,
28
+ Headers,
29
+ Request,
30
+ Response,
31
+ FormData,
32
+ Readable as ReadableStream,
33
+ File,
34
+ Blob,
35
+ }
File without changes
@@ -9,7 +9,7 @@ import { wwwFormSet, wwwFormPathSerializeCallback } from './util.js';
9
9
  /**
10
10
  * The _Headers Mixin
11
11
  */
12
- const _FormData = NativeFormData => class extends NativeFormData {
12
+ const xFormData = whatwagFormData => class extends whatwagFormData {
13
13
 
14
14
  tee(callback = null) {
15
15
  const formData1 = new this.constructor, formData2 = new this.constructor;
@@ -47,7 +47,7 @@ const _FormData = NativeFormData => class extends NativeFormData {
47
47
 
48
48
  }
49
49
 
50
- export default _FormData;
50
+ export default xFormData;
51
51
 
52
52
  export const formDataType = (value, list = null) => {
53
53
  if (!_isTypeObject(value)) {
@@ -7,13 +7,13 @@ import { _isString, _getType, _isObject, _isFunction } from "@webqit/util/js/ind
7
7
  import { _isTypeObject } from '@webqit/util/js/index.js';
8
8
 
9
9
  /**
10
- * The _Headers Mixin
10
+ * The xHeaders Mixin
11
11
  */
12
- const _Headers = NativeHeaders => class extends NativeHeaders {
12
+ const xHeaders = whatwagHeaders => class extends whatwagHeaders {
13
13
 
14
14
  // construct
15
15
  constructor(definition = {}) {
16
- if (definition instanceof NativeHeaders) {
16
+ if (definition instanceof whatwagHeaders) {
17
17
  // It's another Headers instance
18
18
  super(definition);
19
19
  } else {
@@ -73,7 +73,7 @@ const _Headers = NativeHeaders => class extends NativeHeaders {
73
73
 
74
74
  }
75
75
 
76
- export default _Headers;
76
+ export default xHeaders;
77
77
 
78
78
  function getAllPropertyDescriptors(obj) {
79
79
  if (!obj) {
@@ -0,0 +1,93 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import { _isEmpty } from '@webqit/util/js/index.js';
6
+
7
+ /**
8
+ * The xHttpEvent Mixin
9
+ */
10
+ const xHttpEvent = (Request, Response, URL) => {
11
+
12
+ const HttpEvent = class {
13
+
14
+ /**
15
+ * Initializes a new HttpEvent instance.
16
+ *
17
+ * @param Request _request
18
+ * @param Object _detail
19
+ * @param Object _sessionFactory
20
+ */
21
+ constructor(_request, _detail, _sessionFactory) {
22
+ this._request = _request;
23
+ this._detail = _detail || {};
24
+ this._sessionFactory = _sessionFactory;
25
+ // -------
26
+ this.Request = Request;
27
+ this.Response = Response;
28
+ this.URL = URL;
29
+ // -------
30
+ this.port = {
31
+ listeners: [],
32
+ post(message) {
33
+ const promises = this.listeners.map(listener => listener(message))
34
+ .filter(returnValue => returnValue instanceof Promise);
35
+ if (process.length) return Promise.all(promises);
36
+ },
37
+ listen(listener) { this.listeners.push(listener); },
38
+ }
39
+ }
40
+
41
+ // url
42
+ get url() {
43
+ if (!this._url) {
44
+ this._url = new this.URL(this._request.url);
45
+ }
46
+ return this._url;
47
+ }
48
+
49
+ // request
50
+ get request() {
51
+ return this._request;
52
+ }
53
+
54
+ // detail
55
+ get detail() {
56
+ return this._detail;
57
+ }
58
+
59
+ // Session
60
+ get session() {
61
+ if (!this._session) {
62
+ this._session = this.sessionFactory().get();
63
+ }
64
+ return this._session;
65
+ }
66
+
67
+ // Session factory
68
+ sessionFactory(...args) {
69
+ return this._sessionFactory(...args);
70
+ }
71
+
72
+ // RDR
73
+ retarget(url, init = {}) {
74
+ var request;
75
+ if (url instanceof Request) {
76
+ if (!_isEmpty(init)) {
77
+ request = new Request(url, init);
78
+ } else {
79
+ request = url;
80
+ }
81
+ } else {
82
+ request = new Request(this._request, init);
83
+ request.attrs.url = `${this.url.origin}${url}`;
84
+ request.attrs.referrer = this.request.url;
85
+ }
86
+ return new HttpEvent(request, this.detail);
87
+ }
88
+
89
+ }
90
+ return HttpEvent;
91
+ }
92
+
93
+ export default xHttpEvent;
@@ -0,0 +1,179 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import { _isArray, _isEmpty, _isNumber, _isObject, _isPlainArray, _isPlainObject, _isString } from '@webqit/util/js/index.js';
6
+ import { formDataType } from './xFormData.js';
7
+
8
+ /**
9
+ * The _Request Mixin
10
+ */
11
+ const xHttpMessage = (whatwagHttpMessage, Headers, FormData) => {
12
+ const HttpMessage = class extends whatwagHttpMessage {
13
+
14
+ constructor(input, init, bodyAttrs) {
15
+ if (('headers' in init) && !(init.headers instanceof Headers)) {
16
+ init = { ...init };
17
+ init.headers = new Headers(init.headers);
18
+ arguments[1] = init;
19
+ }
20
+ if (_isEmpty(init)) {
21
+ super(input);
22
+ } else {
23
+ super(input, init);
24
+ }
25
+ this._headers = init.headers;
26
+ if (bodyAttrs.headers) {
27
+ this.headers.json(bodyAttrs.headers);
28
+ }
29
+ let attrs = {};
30
+ Object.defineProperty(this, 'attrs', { get: () => attrs });
31
+ Object.defineProperty(this, 'bodyAttrs', { get: () => bodyAttrs });
32
+ }
33
+
34
+ clone() {
35
+ return new this.constructor(super.clone());
36
+ }
37
+
38
+ get headers() {
39
+ if (!this._headers) {
40
+ this._headers = new Headers(super.headers);
41
+ }
42
+ return this._headers;
43
+ }
44
+
45
+ get attrs() {
46
+ return this.attrs;
47
+ }
48
+
49
+ get url() {
50
+ return 'url' in this.attrs ? this.attrs.url : super.url;
51
+ }
52
+
53
+ async arrayBuffer() {
54
+ if (this.bodyAttrs.arrayBuffer) {
55
+ return this.bodyAttrs.arrayBuffer;
56
+ }
57
+ return super.arrayBuffer();
58
+ }
59
+
60
+ async blob() {
61
+ if (this.bodyAttrs.blob) {
62
+ return this.bodyAttrs.blob;
63
+ }
64
+ return super.blob();
65
+ }
66
+
67
+ async formData() {
68
+ if (this.bodyAttrs.formData) {
69
+ return this.bodyAttrs.formData;
70
+ }
71
+ const formData = await super.formData();
72
+ formData.tee = FormData.prototype.tee.bind(formData);
73
+ formData.json = FormData.prototype.json.bind(formData);
74
+ return formData;
75
+ }
76
+
77
+ async json() {
78
+ if (this.bodyAttrs.json) {
79
+ return this.bodyAttrs.json;
80
+ }
81
+ return super.json();
82
+ }
83
+
84
+ async text() {
85
+ if (this.bodyAttrs.text) {
86
+ return this.bodyAttrs.text;
87
+ }
88
+ return super.text();
89
+ }
90
+
91
+ // Resolve
92
+ resolve(force = false) {
93
+ if (!this.bodyAttrs.resolved || force) {
94
+ this.bodyAttrs.resolved = new Promise(async (resolve, reject) => {
95
+ var messageInstance = this, resolved, contentType = messageInstance.headers.get('content-type') || '';
96
+ var type = contentType === 'application/json' || this.bodyAttrs.json ? 'json' : (
97
+ contentType === 'application/x-www-form-urlencoded' || contentType.startsWith('multipart/') || this.bodyAttrs.formData ? 'formData' : (
98
+ contentType === 'text/plain' ? 'plain' : 'other'
99
+ )
100
+ );
101
+ try {
102
+ if (type === 'formData') {
103
+ resolved = (await messageInstance.formData()).json();
104
+ } else {
105
+ resolved = type === 'json' ? await messageInstance.json() : (
106
+ type === 'plain' ? await messageInstance.text() : messageInstance.body
107
+ );
108
+ }
109
+ resolve(resolved);
110
+ } catch(e) {
111
+ reject(e);
112
+ }
113
+ });
114
+ }
115
+ return this.bodyAttrs.resolved;
116
+ }
117
+
118
+ };
119
+ // ----------
120
+ HttpMessage.Headers = Headers;
121
+ // ----------
122
+ return HttpMessage;
123
+ }
124
+
125
+ export default xHttpMessage;
126
+ export function encodeBody(body, FormData) {
127
+ const detailsObj = { body, input: body };
128
+ const encodeFormData = (detailsObj, formData) => {
129
+ if (!FormData.encode) return;
130
+ let [ body, headers ] = FormData.encode(formData);
131
+ detailsObj.body = body;
132
+ detailsObj.headers = headers;
133
+ }
134
+ if (_isString(body) || _isNumber(body)) {
135
+ detailsObj.inputType = 'text';
136
+ detailsObj.text = body;
137
+ detailsObj.headers = {
138
+ contentLength: (body + '').length,
139
+ };
140
+ return detailsObj;
141
+ }
142
+ detailsObj.inputType = formDataType(body);
143
+ if ([ 'Blob', 'File' ].includes(detailsObj.inputType)) {
144
+ detailsObj.blob = body;
145
+ detailsObj.headers = {
146
+ contentType: body.type,
147
+ contentLength: body.size,
148
+ };
149
+ } else if ([ 'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer' ].includes(detailsObj.inputType)) {
150
+ detailsObj.arrayBuffer = body;
151
+ detailsObj.headers = {
152
+ contentLength: body.byteLength,
153
+ };
154
+ } else if (detailsObj.inputType === 'FormData') {
155
+ detailsObj.formData = body;
156
+ encodeFormData(detailsObj, body);
157
+ } else if ((_isObject(body) && _isPlainObject(body)) || (_isArray(body) && _isPlainArray(body))) {
158
+ detailsObj.inputType = 'object';
159
+ // Deserialize object while detecting if multipart
160
+ var hasBlobs, formData = new FormData;
161
+ formData.json(body, (path, value, objectType) => {
162
+ hasBlobs = hasBlobs || objectType;
163
+ return true;
164
+ });
165
+ if (hasBlobs) {
166
+ detailsObj.formData = formData;
167
+ encodeFormData(detailsObj, formData);
168
+ } else {
169
+ detailsObj.json = body;
170
+ detailsObj.body = JSON.stringify(body);
171
+ detailsObj.headers = {
172
+ contentType: 'application/json',
173
+ contentLength: Buffer.byteLength(detailsObj.body, 'utf8'), // Buffer.from(string).length
174
+ };
175
+ }
176
+ detailsObj.resolved = body;
177
+ }
178
+ return detailsObj;
179
+ }
@@ -0,0 +1,67 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import xHttpMessage, { encodeBody } from './xHttpMessage.js';
6
+
7
+ /**
8
+ * The xRequest Mixin
9
+ */
10
+ const xRequest = (whatwagRequest, Headers, FormData) => class extends xHttpMessage(whatwagRequest, Headers, FormData) {
11
+
12
+ constructor(input, init = {}) {
13
+ init = { ...init };
14
+ let bodyAttrs = {};
15
+ if ((input instanceof whatwagRequest)) {
16
+ // On method change...
17
+ if (init.method && input.method !== init.method.toUpperCase() && [ 'GET', 'HEAD' ].includes(init.method.toUpperCase())) {
18
+ // Body must not be inherited.
19
+ input = input.url;
20
+ // We should now simply copy attributes
21
+ [ 'headers', 'mode', 'credentials', 'cache', 'redirect', 'referrer', 'integrity' ].forEach(attr => {
22
+ if (!(attr in init)) {
23
+ init[attr] = input[attr];
24
+ }
25
+ });
26
+ } else {
27
+ // Inherit bodyAttrs
28
+ bodyAttrs = input.bodyAttrs || {};
29
+ }
30
+ }
31
+ // Init can contain "already-parsed request content"
32
+ if (('body' in init)) {
33
+ bodyAttrs = encodeBody(init.body, FormData);
34
+ init.body = bodyAttrs.body;
35
+ }
36
+ let isNavigateMode;
37
+ if (init.mode === 'navigate') {
38
+ isNavigateMode = true;
39
+ init = { ...init };
40
+ delete init.mode;
41
+ }
42
+ super(input, init, bodyAttrs);
43
+ if (isNavigateMode) {
44
+ // Through the backdoor
45
+ this.attrs.mode = 'navigate';
46
+ }
47
+ }
48
+
49
+ get mode() {
50
+ return 'mode' in this.attrs ? this.attrs.mode : super.mode;
51
+ }
52
+
53
+ get cache() {
54
+ return 'cache' in this.attrs ? this.attrs.cache : super.cache;
55
+ }
56
+
57
+ get destination() {
58
+ return 'destination' in this.attrs ? this.attrs.destination : super.destination;
59
+ }
60
+
61
+ get referrer() {
62
+ return 'referrer' in this.attrs ? this.attrs.referrer : super.referrer;
63
+ }
64
+
65
+ };
66
+
67
+ export default xRequest;
@@ -0,0 +1,95 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import { _after } from "@webqit/util/str/index.js";
6
+ import { _from as _arrFrom } from "@webqit/util/arr/index.js";
7
+ import { _getType, _isObject } from "@webqit/util/js/index.js";
8
+ import { wwwFormUnserialize, wwwFormSerialize } from './util.js';
9
+ import xHeaders from './xHeaders.js';
10
+
11
+ /**
12
+ * The xHeaders Mixin
13
+ */
14
+ const xRequestHeaders = NativeHeaders => class extends xHeaders(NativeHeaders) {
15
+
16
+ set accept(value) {
17
+ return this.set('Accept', value);
18
+ }
19
+
20
+ get accept() {
21
+ const accept = this.get('Accept');
22
+ const list = accept && accept.split(',').map(a => (a = a.trim().split(';').map(a => a.trim()), [a.shift(), parseFloat((a.pop() || '1').replace('q=', ''))]))
23
+ .sort((a, b) => a[1] > b[1] ? -1 : 1) || [];
24
+ return {
25
+ match(mime) {
26
+ mime = (mime + '').split('/');
27
+ return list.reduce((prev, entry) => prev || (
28
+ (entry = entry[0].split('/')) && [0, 1].every(i => ((mime[i] === entry[i]) || mime[i] === '*' || entry[i] === '*'))
29
+ ), false);
30
+ },
31
+ toString() {
32
+ return accept;
33
+ }
34
+ };
35
+ }
36
+
37
+ set cookies(cookieJar) {
38
+ if (!_isObject(cookieJar)) {
39
+ throw new Error(`Cookies must be of type object. Received type: ${_getType(cookieJar)}.`);
40
+ }
41
+ this.set('Cookie', wwwFormSerialize(cookieJar, ';'));
42
+ this._cookies = null;
43
+ return true;
44
+ }
45
+
46
+ get cookies() {
47
+ if (!this._cookies) {
48
+ this._cookies = wwwFormUnserialize(this.get('cookie'), {}, ';');
49
+ }
50
+ return this._cookies;
51
+ }
52
+
53
+ set range(value) {
54
+ let rangeArr = [];
55
+ _arrFrom(value).forEach((range, i) => {
56
+ let rangeStr = Array.isArray(range) ? range.join('-') : range + '';
57
+ if (i === 0 && !rangeStr.includes('bytes=')) {
58
+ rangeStr = `bytes=${rangeStr}`;
59
+ }
60
+ rangeArr.push(rangeStr);
61
+ });
62
+ return this.set('Range', rangeArr.join(', '));
63
+ }
64
+
65
+ get range() {
66
+ const value = this.get('Range');
67
+ if (!value) return;
68
+ const rangeArr = _after(value, 'bytes=').split(',').map(rangeStr => {
69
+ let range = rangeStr.trim().split('-');
70
+ range[0] = range[0] ? parseInt(range[0], 10) : undefined;
71
+ if (range[1]) {
72
+ range[1] = parseInt(range[1], 10);
73
+ }
74
+ range.clamp = max => {
75
+ if (range[1] > max - 1 || range[1] === undefined) {
76
+ range[1] = max - 1;
77
+ }
78
+ if (range[0] === undefined) range[0] = range[1] ? max - range[1] - 1 : 0;
79
+ };
80
+ return range;
81
+ });
82
+ return rangeArr;
83
+ }
84
+
85
+ set cors(value) {
86
+ return this.set('Access-Control-Allow-Origin', value === true ? '*' : (value === false ? '' : value));
87
+ }
88
+
89
+ get cors() {
90
+ return this.get('Access-Control-Allow-Origin');
91
+ }
92
+
93
+ }
94
+
95
+ export default xRequestHeaders;