@webqit/webflo 0.11.61-0 → 1.0.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 (118) hide show
  1. package/.gitignore +7 -7
  2. package/LICENSE +20 -20
  3. package/README.md +2079 -2074
  4. package/docker/Dockerfile +42 -42
  5. package/docker/README.md +91 -91
  6. package/docker/package.json +2 -2
  7. package/package.json +80 -81
  8. package/src/{Context.js → AbstractContext.js} +71 -79
  9. package/src/config-pi/deployment/Env.js +68 -68
  10. package/src/config-pi/deployment/Layout.js +63 -63
  11. package/src/config-pi/deployment/Origins.js +139 -139
  12. package/src/config-pi/deployment/Proxy.js +74 -74
  13. package/src/config-pi/deployment/index.js +17 -17
  14. package/src/config-pi/index.js +15 -15
  15. package/src/config-pi/runtime/Client.js +116 -98
  16. package/src/config-pi/runtime/Server.js +125 -125
  17. package/src/config-pi/runtime/client/Worker.js +109 -134
  18. package/src/config-pi/runtime/client/index.js +11 -11
  19. package/src/config-pi/runtime/index.js +17 -17
  20. package/src/config-pi/runtime/server/Headers.js +74 -74
  21. package/src/config-pi/runtime/server/Redirects.js +69 -69
  22. package/src/config-pi/runtime/server/index.js +13 -13
  23. package/src/config-pi/static/Manifest.js +319 -319
  24. package/src/config-pi/static/Ssg.js +49 -49
  25. package/src/config-pi/static/index.js +13 -13
  26. package/src/deployment-pi/index.js +10 -10
  27. package/src/deployment-pi/origins/index.js +216 -216
  28. package/src/index.js +11 -19
  29. package/src/runtime-pi/HttpEvent.js +126 -106
  30. package/src/runtime-pi/HttpUser.js +126 -0
  31. package/src/runtime-pi/MessagingOverBroadcast.js +9 -0
  32. package/src/runtime-pi/MessagingOverChannel.js +85 -0
  33. package/src/runtime-pi/MessagingOverSocket.js +106 -0
  34. package/src/runtime-pi/MultiportMessagingAPI.js +81 -0
  35. package/src/runtime-pi/WebfloCookieStorage.js +27 -0
  36. package/src/runtime-pi/WebfloEventTarget.js +39 -0
  37. package/src/runtime-pi/WebfloMessageEvent.js +58 -0
  38. package/src/runtime-pi/WebfloMessagingAPI.js +69 -0
  39. package/src/runtime-pi/{Router.js → WebfloRouter.js} +99 -130
  40. package/src/runtime-pi/WebfloRuntime.js +52 -0
  41. package/src/runtime-pi/WebfloStorage.js +109 -0
  42. package/src/runtime-pi/client/ClientMessaging.js +5 -0
  43. package/src/runtime-pi/client/Context.js +3 -7
  44. package/src/runtime-pi/client/CookieStorage.js +17 -0
  45. package/src/runtime-pi/client/Router.js +38 -48
  46. package/src/runtime-pi/client/SessionStorage.js +33 -0
  47. package/src/runtime-pi/client/Url.js +156 -205
  48. package/src/runtime-pi/client/WebfloClient.js +544 -0
  49. package/src/runtime-pi/client/WebfloRootClient1.js +179 -0
  50. package/src/runtime-pi/client/WebfloRootClient2.js +109 -0
  51. package/src/runtime-pi/client/WebfloSubClient.js +165 -0
  52. package/src/runtime-pi/client/Workport.js +118 -178
  53. package/src/runtime-pi/client/generate.js +480 -471
  54. package/src/runtime-pi/client/index.js +16 -21
  55. package/src/runtime-pi/client/worker/ClientMessaging.js +5 -0
  56. package/src/runtime-pi/client/worker/Context.js +3 -7
  57. package/src/runtime-pi/client/worker/CookieStorage.js +17 -0
  58. package/src/runtime-pi/client/worker/SessionStorage.js +13 -0
  59. package/src/runtime-pi/client/worker/WebfloWorker.js +294 -0
  60. package/src/runtime-pi/client/worker/Workport.js +17 -85
  61. package/src/runtime-pi/client/worker/index.js +10 -21
  62. package/src/runtime-pi/index.js +6 -13
  63. package/src/runtime-pi/server/ClientMessaging.js +18 -0
  64. package/src/runtime-pi/server/ClientMessagingRegistry.js +57 -0
  65. package/src/runtime-pi/server/Context.js +11 -15
  66. package/src/runtime-pi/server/CookieStorage.js +17 -0
  67. package/src/runtime-pi/server/Router.js +93 -159
  68. package/src/runtime-pi/server/SessionStorage.js +53 -0
  69. package/src/runtime-pi/server/WebfloServer.js +755 -0
  70. package/src/runtime-pi/server/index.js +10 -21
  71. package/src/runtime-pi/util-http.js +322 -86
  72. package/src/runtime-pi/util-url.js +146 -146
  73. package/src/runtime-pi/xURL.js +108 -105
  74. package/src/runtime-pi/xfetch.js +22 -22
  75. package/src/services-pi/cert/http-auth-hook.js +22 -22
  76. package/src/services-pi/cert/http-cleanup-hook.js +22 -22
  77. package/src/services-pi/cert/index.js +79 -79
  78. package/src/services-pi/index.js +8 -8
  79. package/src/static-pi/index.js +10 -10
  80. package/src/webflo.js +30 -30
  81. package/test/index.test.js +26 -26
  82. package/test/site/package.json +9 -9
  83. package/test/site/public/bundle.html +5 -5
  84. package/test/site/public/bundle.html.json +3 -3
  85. package/test/site/public/bundle.js +2 -2
  86. package/test/site/public/bundle.webflo.js +15 -15
  87. package/test/site/public/index.html +29 -29
  88. package/test/site/public/index1.html +34 -34
  89. package/test/site/public/page-2/bundle.html +4 -4
  90. package/test/site/public/page-2/bundle.js +2 -2
  91. package/test/site/public/page-2/index.html +45 -45
  92. package/test/site/public/page-2/main.html +2 -2
  93. package/test/site/public/page-4/subpage/bundle.js +2 -2
  94. package/test/site/public/page-4/subpage/index.html +30 -30
  95. package/test/site/public/sparoots.json +4 -4
  96. package/test/site/public/worker.js +3 -3
  97. package/test/site/server/index.js +15 -15
  98. package/src/runtime-pi/Application.js +0 -29
  99. package/src/runtime-pi/Cookies.js +0 -82
  100. package/src/runtime-pi/Runtime.js +0 -21
  101. package/src/runtime-pi/client/Application.js +0 -100
  102. package/src/runtime-pi/client/Runtime.js +0 -332
  103. package/src/runtime-pi/client/createStorage.js +0 -57
  104. package/src/runtime-pi/client/oohtml/full.js +0 -7
  105. package/src/runtime-pi/client/oohtml/namespacing.js +0 -7
  106. package/src/runtime-pi/client/oohtml/scripting.js +0 -8
  107. package/src/runtime-pi/client/oohtml/templating.js +0 -8
  108. package/src/runtime-pi/client/worker/Application.js +0 -44
  109. package/src/runtime-pi/client/worker/Runtime.js +0 -269
  110. package/src/runtime-pi/server/Application.js +0 -116
  111. package/src/runtime-pi/server/Runtime.js +0 -557
  112. package/src/runtime-pi/xFormData.js +0 -24
  113. package/src/runtime-pi/xHeaders.js +0 -146
  114. package/src/runtime-pi/xRequest.js +0 -46
  115. package/src/runtime-pi/xRequestHeaders.js +0 -109
  116. package/src/runtime-pi/xResponse.js +0 -33
  117. package/src/runtime-pi/xResponseHeaders.js +0 -117
  118. package/src/runtime-pi/xxHttpMessage.js +0 -102
@@ -1,21 +1,10 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import Context from './Context.js';
6
- import Application from './Application.js';
7
- import Runtime from './Runtime.js';
8
-
9
- /**
10
- * @start
11
- */
12
- export async function start(applicationInstance = null) {
13
- const cx = this || {};
14
- const defaultApplicationInstance = _cx => new Application(_cx);
15
- return new Runtime(Context.create(cx), applicationInstance || defaultApplicationInstance);
16
- }
17
-
18
- /**
19
- * @APIS
20
- */
21
- export * as APIS from './Runtime.js';
1
+ import { WebfloServer } from './WebfloServer.js';
2
+
3
+ export async function start() {
4
+ const instance = WebfloServer.create(this || {});
5
+ await instance.initialize();
6
+ }
7
+
8
+ export {
9
+ WebfloServer
10
+ }
@@ -1,86 +1,322 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import { _isString, _isNumeric, _isObject, _isPlainObject, _isArray, _isPlainArray, _isTypeObject, _isNumber, _isBoolean } from '@webqit/util/js/index.js';
6
- import { _before } from '@webqit/util/str/index.js';
7
- import { params } from './util-url.js';
8
-
9
- export function formatMessage(message) {
10
- const headers = (message.headers instanceof Headers) ? [...message.headers.keys()].reduce((_headers, name) => {
11
- return { ..._headers, [name/* lower-cased */]: message.headers.get(name) };
12
- }, {}) : Object.keys(message.headers || {}).reduce((_headers, name) => {
13
- return { ..._headers, [name.toLowerCase()]: message.headers[name] };
14
- }, {});
15
- let body = message.body, type = dataType(message.body);
16
- if ([ 'Blob', 'File' ].includes(type)) {
17
- !headers['content-type'] && (headers['content-type'] = body.type);
18
- !headers['content-length'] && (headers['content-length'] = body.size);
19
- } else if ([ 'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer' ].includes(type)) {
20
- !headers['content-length'] && (headers['content-length'] = body.byteLength);
21
- } else if (type === 'json' && _isTypeObject(body)) {
22
- if (!headers['content-type']) {
23
- const [ _body, isJsonfiable ] = formDatarizeJson(body);
24
- if (isJsonfiable) {
25
- body = JSON.stringify(body, (k, v) => v instanceof Error ? { ...v, message: v.message } : v);
26
- headers['content-type'] = 'application/json';
27
- headers['content-length'] = (new Blob([ body ])).size;
28
- } else {
29
- body = _body;
30
- type = 'FormData';
31
- }
32
- }
33
- } else if (type === 'json') {
34
- !headers['content-length'] && (headers['content-length'] = (body + '').length);
35
- }
36
- return [ body, headers, type ];
37
- }
38
-
39
- export function formDatarizeJson(data = {}, jsonfy = true) {
40
- const formData = new FormData;
41
- let isJsonfiable = true;
42
- params.reduceValue(data, '', (value, contextPath, suggestedKeys = undefined) => {
43
- if (suggestedKeys) {
44
- const isJson = dataType(value) === 'json';
45
- isJsonfiable = isJsonfiable && isJson;
46
- return isJson && suggestedKeys;
47
- }
48
- if (jsonfy && [true, false, null].includes(value)) {
49
- value = new Blob([value], { type: 'application/json' });
50
- }
51
- formData.append(contextPath, value);
52
- });
53
- return [ formData, isJsonfiable ];
54
- }
55
-
56
- export async function jsonfyFormData(formData, jsonfy = true) {
57
- let isJsonfiable = true;
58
- let json;
59
- for (let [ name, value ] of formData.entries()) {
60
- if (!json) { json = _isNumeric(_before(name, '[')) ? [] : {}; }
61
- let type = dataType(value);
62
- if (jsonfy && ['Blob', 'File'].includes(type) && value.type === 'application/json' && [4, 5].includes(value.size)) {
63
- let _value = await value.text();
64
- if (['true', 'false', 'null'].includes(_value)) {
65
- type = 'json';
66
- value = JSON.parse(_value);
67
- }
68
- }
69
- isJsonfiable = isJsonfiable && type === 'json';
70
- params.set(json, name, value);
71
- }
72
- return [ json, isJsonfiable ];
73
- }
74
-
75
- export function dataType(value) {
76
- if (_isString(value) || _isNumber(value) || _isBoolean(value)) return 'json';
77
- if (!_isTypeObject(value)) return;
78
- const toStringTag = value[Symbol.toStringTag];
79
- const type = [
80
- 'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer', 'Blob', 'File', 'FormData', 'Stream', 'ReadableStream'
81
- ].reduce((_toStringTag, type) => _toStringTag || (toStringTag === type ? type : null), null);
82
- if (type) return type;
83
- if ((_isObject(value) && _isPlainObject(value)) || (_isArray(value) && _isPlainArray(value)) || 'toString' in value) {
84
- return 'json';
85
- }
86
- }
1
+ import { _isString, _isNumeric, _isObject, _isPlainObject, _isArray, _isPlainArray, _isTypeObject, _isNumber, _isBoolean } from '@webqit/util/js/index.js';
2
+ import { _after, _before } from '@webqit/util/str/index.js';
3
+ import { _from as _arrFrom } from '@webqit/util/arr/index.js';
4
+ import { params } from './util-url.js';
5
+
6
+ export function dataType(value) {
7
+ if (_isString(value) || _isNumber(value) || _isBoolean(value)) return 'json';
8
+ if (!_isTypeObject(value)) return;
9
+ const toStringTag = value[Symbol.toStringTag];
10
+ const type = [
11
+ 'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer', 'Blob', 'File', 'FormData', 'Stream', 'ReadableStream'
12
+ ].reduce((_toStringTag, type) => _toStringTag || (toStringTag === type ? type : null), null);
13
+ if (type) return type;
14
+ if ((_isObject(value) && _isPlainObject(value)) || (_isArray(value) && _isPlainArray(value)) || 'toString' in value) {
15
+ return 'json';
16
+ }
17
+ }
18
+
19
+ export function renderHttpMessageInit(httpMessageInit) {
20
+ const headers = (httpMessageInit.headers instanceof Headers) ? [...httpMessageInit.headers.keys()].reduce((_headers, name) => {
21
+ return { ..._headers, [name/* lower-cased */]: httpMessageInit.headers.get(name) };
22
+ }, {}) : Object.keys(httpMessageInit.headers || {}).reduce((_headers, name) => {
23
+ return { ..._headers, [name.toLowerCase()]: httpMessageInit.headers[name] };
24
+ }, {});
25
+ let body = httpMessageInit.body, type = dataType(httpMessageInit.body);
26
+ if (['Blob', 'File'].includes(type)) {
27
+ !headers['content-type'] && (headers['content-type'] = body.type);
28
+ !headers['content-length'] && (headers['content-length'] = body.size);
29
+ } else if (['Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer'].includes(type)) {
30
+ !headers['content-length'] && (headers['content-length'] = body.byteLength);
31
+ } else if (type === 'json' && _isTypeObject(body)) {
32
+ if (!headers['content-type']) {
33
+ const [_body, isJsonfiable] = createFormDataFromJson(body, true/*jsonfy*/, true/*getIsJsonfiable*/);
34
+ if (isJsonfiable) {
35
+ body = JSON.stringify(body, (k, v) => v instanceof Error ? { ...v, message: v.message } : v);
36
+ headers['content-type'] = 'application/json';
37
+ headers['content-length'] = (new Blob([body])).size;
38
+ } else {
39
+ body = _body;
40
+ type = 'FormData';
41
+ }
42
+ }
43
+ } else if (type === 'json') {
44
+ !headers['content-length'] && (headers['content-length'] = (body + '').length);
45
+ }
46
+ return { body, headers, $type: type };
47
+ }
48
+
49
+ export async function parseHttpMessage(httpMessage) {
50
+ let result;
51
+ const contentType = httpMessage.headers.get('Content-Type') || '';
52
+ if (contentType === 'application/x-www-form-urlencoded' || contentType.startsWith('multipart/form-data')) {
53
+ const formData = await httpMessage.formData();
54
+ result = await formData?.json();
55
+ } else if (contentType.startsWith('application/json')/*can include charset*/) {
56
+ result = await httpMessage.json();
57
+ } else /*if (contentType === 'text/plain')*/ {
58
+ result = await httpMessage.text();
59
+ }
60
+ return result;
61
+ }
62
+
63
+ export function createFormDataFromJson(data = {}, jsonfy = true, getIsJsonfiable = false) {
64
+ const formData = new FormData;
65
+ let isJsonfiable = true;
66
+ params.reduceValue(data, '', (value, contextPath, suggestedKeys = undefined) => {
67
+ if (suggestedKeys) {
68
+ const isJson = dataType(value) === 'json';
69
+ isJsonfiable = isJsonfiable && isJson;
70
+ return isJson && suggestedKeys;
71
+ }
72
+ if (jsonfy && [true, false, null].includes(value)) {
73
+ value = new Blob([value], { type: 'application/json' });
74
+ }
75
+ formData.append(contextPath, value);
76
+ });
77
+ if (getIsJsonfiable) return [formData, isJsonfiable];
78
+ return formData;
79
+ }
80
+
81
+ export async function renderFormDataToJson(formData, jsonfy = true, getIsJsonfiable = false) {
82
+ let isJsonfiable = true;
83
+ let json;
84
+ for (let [name, value] of formData.entries()) {
85
+ if (!json) { json = _isNumeric(_before(name, '[')) ? [] : {}; }
86
+ let type = dataType(value);
87
+ if (jsonfy && ['Blob', 'File'].includes(type) && value.type === 'application/json' && [4, 5].includes(value.size)) {
88
+ let _value = await value.text();
89
+ if (['true', 'false', 'null'].includes(_value)) {
90
+ type = 'json';
91
+ value = JSON.parse(_value);
92
+ }
93
+ }
94
+ isJsonfiable = isJsonfiable && type === 'json';
95
+ params.set(json, name, value);
96
+ }
97
+ if (getIsJsonfiable) return [json, isJsonfiable];
98
+ return json;
99
+ }
100
+
101
+ export function renderCookieObj(cookieObj) {
102
+ const attrsArr = [`${cookieObj.name}=${/*encodeURIComponent*/(cookieObj.value)}`];
103
+ for (const attrName in cookieObj) {
104
+ if (['name', 'value'].includes(attrName)) continue;
105
+ let _attrName = attrName[0].toUpperCase() + attrName.substring(1);
106
+ if (_attrName === 'MaxAge') { _attrName = 'Max-Age' };
107
+ attrsArr.push(cookieObj[attrName] === true ? _attrName : `${_attrName}=${cookieObj[attrName]}`);
108
+ }
109
+ return attrsArr.join(';');
110
+ }
111
+
112
+ /* Request */
113
+
114
+ Object.defineProperties(Request, {
115
+ create: {
116
+ value: function (url, init = {}) {
117
+ if (url instanceof Request) return url;
118
+ let $$type, $$body = init.body;
119
+ if ('body' in init) {
120
+ const { body, headers, $type } = renderHttpMessageInit(init);
121
+ init = { ...init, body, headers };
122
+ $$type = $type;
123
+ }
124
+ const instance = new Request(url, init);
125
+ instance.meta.body = $$body;
126
+ instance.meta.type = $$type;
127
+ return instance;
128
+ }
129
+ },
130
+
131
+ copy: {
132
+ value: async function (request, init = {}) {
133
+ const requestInit = [
134
+ 'method', 'headers', 'mode', 'credentials', 'cache', 'redirect', 'referrer', 'integrity',
135
+ ].reduce((init, prop) => ({ [prop]: request[prop], ...init }), {});
136
+ if (!['GET', 'HEAD'].includes(init.method?.toUpperCase() || request.method)) {
137
+ requestInit.body = await request.clone().arrayBuffer();
138
+ }
139
+ if (requestInit.mode === 'navigate') {
140
+ requestInit.mode = 'cors';
141
+ }
142
+ return { url: request.url, ...requestInit };
143
+ }
144
+ }
145
+ });
146
+
147
+ Object.defineProperties(Request.prototype, {
148
+ parse: { value: function() { return parseHttpMessage(this); } },
149
+ meta: { get: function() { if (!this._meta) this._meta = {}; return this._meta; } }
150
+ });
151
+
152
+ /* Response */
153
+
154
+ Object.defineProperties(Response, {
155
+ create: {
156
+ value: function (body, init = {}) {
157
+ if (body instanceof Response) return body;
158
+ let $type, $body = body;
159
+ if (body || body === 0) {
160
+ let headers;
161
+ ({ body, headers, $type } = renderHttpMessageInit({ body, headers: init.headers }));
162
+ init = { ...init, headers };
163
+ }
164
+ const instance = new Response(body, init);
165
+ instance.meta.body = $body;
166
+ instance.meta.type = $type;
167
+ return instance;
168
+ }
169
+ }
170
+ });
171
+
172
+ const statusGet = Object.getOwnPropertyDescriptor(Response.prototype, 'status');
173
+ Object.defineProperties(Response.prototype, {
174
+ parse: { value: function() { return parseHttpMessage(this); } },
175
+ meta: { get: function() { if (!this._meta) this._meta = {}; return this._meta; } },
176
+ status: { get: function() { return this.meta.status || statusGet.get.call(this); } }
177
+ });
178
+
179
+ /* Headers */
180
+
181
+ const { set: headerSet, append: headerAppend, get: headerGet } = Headers.prototype;
182
+ Object.defineProperties(Headers.prototype, {
183
+ set: {
184
+ value: function (name, value) {
185
+ // -------------------------
186
+ // Format "Set-Cookie" response header
187
+ if (/^Set-Cookie$/i.test(name) && _isObject(value)) {
188
+ value = renderCookieObj(value);
189
+ }
190
+ // -------------------------
191
+ // Format "Cookie" request header
192
+ if (/Cookie/i.test(name) && _isTypeObject(value)) {
193
+ value = [].concat(value).map(renderCookieObj).join(';');
194
+ }
195
+ // -------------------------
196
+ // Format "Content-Range" response header?
197
+ if (/^Content-Range$/i.test(name) && Array.isArray(value)) {
198
+ if (value.length < 2 || !value[0].includes('-')) {
199
+ throw new Error(`A Content-Range array must be in the format: [ 'start-end', 'total' ]`);
200
+ }
201
+ value = `bytes ${value.join('/')}`;
202
+ }
203
+ // -------------------------
204
+ // Format "Range" request header?
205
+ if (/^Range$/i.test(name)) {
206
+ let rangeArr = [];
207
+ _arrFrom(value).forEach((range, i) => {
208
+ let rangeStr = Array.isArray(range) ? range.join('-') : range + '';
209
+ if (i === 0 && !rangeStr.includes('bytes=')) {
210
+ rangeStr = `bytes=${rangeStr}`;
211
+ }
212
+ rangeArr.push(rangeStr);
213
+ });
214
+ value = rangeArr.join(', ');
215
+ }
216
+ // -------------------------
217
+ // Format "Accept" request header?
218
+ if (/^Accept$/i.test(name) && Array.isArray(value)) {
219
+ value = value.join(',');
220
+ }
221
+ // -------------------------
222
+ return headerSet.call(this, name, value);
223
+ }
224
+ },
225
+
226
+ append: {
227
+ value: function (name, value) {
228
+ // -------------------------
229
+ // Format "Set-Cookie" response header
230
+ if (/^Set-Cookie$/i.test(name) && _isObject(value)) {
231
+ value = renderCookieObj(value);
232
+ }
233
+ // -------------------------
234
+ return headerAppend.call(this, name, value);
235
+ }
236
+ },
237
+
238
+ get: {
239
+ value: function (name, parsed = false) {
240
+ let value = headerGet.call(this, name);
241
+ // -------------------------
242
+ // Parse "Set-Cookie" response header
243
+ if (/^Set-Cookie$/i.test(name) && parsed) {
244
+ value = this.getSetCookie()/*IMPORTANT*/.map((str) => {
245
+ const [cookieDefinition, attrsStr] = str.split(';');
246
+ const [name, value] = cookieDefinition.split('=').map((s) => s.trim());
247
+ const cookieObj = { name, value: /*decodeURIComponent*/(value), };
248
+ attrsStr && attrsStr.split(/\;/g).map(attrStr => attrStr.trim().split('=')).forEach(attrsArr => {
249
+ cookieObj[attrsArr[0][0].toLowerCase() + attrsArr[0].substring(1).replace('-', '')] = attrsArr.length === 1 ? true : attrsArr[1];
250
+ });
251
+ return cookieObj;
252
+ });
253
+ }
254
+ // -------------------------
255
+ // Parse "Cookie" request header
256
+ if (/^Cookie$/i.test(name) && parsed) {
257
+ value = value?.split(';').map((str) => {
258
+ const [name, value] = str.split('=').map((s) => s.trim());
259
+ return { name, value: /*decodeURIComponent*/(value), };
260
+ }) || [];
261
+ }
262
+ // -------------------------
263
+ // Parse "Content-Range" response header?
264
+ if (/^Content-Range$/i.test(name) && value && parsed) {
265
+ value = _after(value, 'bytes ').split('/');
266
+ }
267
+ // -------------------------
268
+ // Parse "Range" request header?
269
+ if (/^Range$/i.test(name) && parsed) {
270
+ value = !value ? [] : _after(value, 'bytes=').split(',').map((rangeStr) => {
271
+ let range = rangeStr.trim().split('-');
272
+ range[0] = range[0] ? parseInt(range[0], 10) : undefined;
273
+ if (range[1]) {
274
+ range[1] = parseInt(range[1], 10);
275
+ }
276
+ range.clamp = max => {
277
+ if (range[1] > max - 1 || range[1] === undefined) {
278
+ range[1] = max - 1;
279
+ }
280
+ if (range[0] === undefined) range[0] = range[1] ? max - range[1] - 1 : 0;
281
+ };
282
+ return range;
283
+ });
284
+ }
285
+ // -------------------------
286
+ // Parse "Accept" request header?
287
+ if (/^Accept$/i.test(name) && parsed) {
288
+ const list = value && value.split(',')
289
+ .map((a) => (a = a.trim().split(';').map(a => a.trim()), [a.shift(), parseFloat((a.pop() || '1').replace('q=', ''))]))
290
+ .sort((a, b) => a[1] > b[1] ? -1 : 1) || [];
291
+ value = {
292
+ match(mime) {
293
+ mime = (mime + '').split('/');
294
+ return list.reduce((prev, entry) => prev || (
295
+ (entry = entry[0].split('/')) && [0, 1].every(i => ((mime[i] === entry[i]) || mime[i] === '*' || entry[i] === '*'))
296
+ ), false);
297
+ },
298
+ toString() {
299
+ return value;
300
+ }
301
+ };
302
+ }
303
+ // -------------------------
304
+ return value;
305
+ }
306
+ }
307
+ });
308
+
309
+ /* FormData */
310
+
311
+ Object.defineProperties(FormData, {
312
+ json: { value: createFormDataFromJson }
313
+ });
314
+
315
+ Object.defineProperties(FormData.prototype, {
316
+ json: {
317
+ value: async function (data = {}) {
318
+ const result = await renderFormDataToJson(this, ...arguments);
319
+ return result;
320
+ }
321
+ }
322
+ });