@webqit/webflo 0.11.61 → 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 (66) hide show
  1. package/package.json +1 -1
  2. package/src/{Context.js → AbstractContext.js} +1 -9
  3. package/src/deployment-pi/origins/index.js +1 -1
  4. package/src/index.js +1 -9
  5. package/src/runtime-pi/HttpEvent.js +101 -81
  6. package/src/runtime-pi/HttpUser.js +126 -0
  7. package/src/runtime-pi/MessagingOverBroadcast.js +9 -0
  8. package/src/runtime-pi/MessagingOverChannel.js +85 -0
  9. package/src/runtime-pi/MessagingOverSocket.js +106 -0
  10. package/src/runtime-pi/MultiportMessagingAPI.js +81 -0
  11. package/src/runtime-pi/WebfloCookieStorage.js +27 -0
  12. package/src/runtime-pi/WebfloEventTarget.js +39 -0
  13. package/src/runtime-pi/WebfloMessageEvent.js +58 -0
  14. package/src/runtime-pi/WebfloMessagingAPI.js +69 -0
  15. package/src/runtime-pi/{Router.js → WebfloRouter.js} +3 -34
  16. package/src/runtime-pi/WebfloRuntime.js +52 -0
  17. package/src/runtime-pi/WebfloStorage.js +109 -0
  18. package/src/runtime-pi/client/ClientMessaging.js +5 -0
  19. package/src/runtime-pi/client/Context.js +2 -6
  20. package/src/runtime-pi/client/CookieStorage.js +17 -0
  21. package/src/runtime-pi/client/Router.js +3 -13
  22. package/src/runtime-pi/client/SessionStorage.js +33 -0
  23. package/src/runtime-pi/client/Url.js +24 -72
  24. package/src/runtime-pi/client/WebfloClient.js +544 -0
  25. package/src/runtime-pi/client/WebfloRootClient1.js +179 -0
  26. package/src/runtime-pi/client/WebfloRootClient2.js +109 -0
  27. package/src/runtime-pi/client/WebfloSubClient.js +165 -0
  28. package/src/runtime-pi/client/Workport.js +89 -161
  29. package/src/runtime-pi/client/generate.js +1 -1
  30. package/src/runtime-pi/client/index.js +13 -18
  31. package/src/runtime-pi/client/worker/ClientMessaging.js +5 -0
  32. package/src/runtime-pi/client/worker/Context.js +2 -6
  33. package/src/runtime-pi/client/worker/CookieStorage.js +17 -0
  34. package/src/runtime-pi/client/worker/SessionStorage.js +13 -0
  35. package/src/runtime-pi/client/worker/WebfloWorker.js +294 -0
  36. package/src/runtime-pi/client/worker/Workport.js +13 -73
  37. package/src/runtime-pi/client/worker/index.js +7 -18
  38. package/src/runtime-pi/index.js +1 -8
  39. package/src/runtime-pi/server/ClientMessaging.js +18 -0
  40. package/src/runtime-pi/server/ClientMessagingRegistry.js +57 -0
  41. package/src/runtime-pi/server/Context.js +2 -6
  42. package/src/runtime-pi/server/CookieStorage.js +17 -0
  43. package/src/runtime-pi/server/Router.js +2 -68
  44. package/src/runtime-pi/server/SessionStorage.js +53 -0
  45. package/src/runtime-pi/server/WebfloServer.js +755 -0
  46. package/src/runtime-pi/server/index.js +7 -18
  47. package/src/runtime-pi/util-http.js +268 -32
  48. package/src/runtime-pi/xURL.js +25 -22
  49. package/src/runtime-pi/xfetch.js +2 -2
  50. package/src/runtime-pi/Application.js +0 -29
  51. package/src/runtime-pi/Cookies.js +0 -82
  52. package/src/runtime-pi/Runtime.js +0 -21
  53. package/src/runtime-pi/client/Application.js +0 -76
  54. package/src/runtime-pi/client/Runtime.js +0 -525
  55. package/src/runtime-pi/client/createStorage.js +0 -58
  56. package/src/runtime-pi/client/worker/Application.js +0 -44
  57. package/src/runtime-pi/client/worker/Runtime.js +0 -275
  58. package/src/runtime-pi/server/Application.js +0 -101
  59. package/src/runtime-pi/server/Runtime.js +0 -558
  60. package/src/runtime-pi/xFormData.js +0 -24
  61. package/src/runtime-pi/xHeaders.js +0 -146
  62. package/src/runtime-pi/xRequest.js +0 -46
  63. package/src/runtime-pi/xRequestHeaders.js +0 -109
  64. package/src/runtime-pi/xResponse.js +0 -33
  65. package/src/runtime-pi/xResponseHeaders.js +0 -117
  66. package/src/runtime-pi/xxHttpMessage.js +0 -102
@@ -1,21 +1,10 @@
1
+ import { WebfloServer } from './WebfloServer.js';
1
2
 
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);
3
+ export async function start() {
4
+ const instance = WebfloServer.create(this || {});
5
+ await instance.initialize();
16
6
  }
17
7
 
18
- /**
19
- * @APIS
20
- */
21
- export * as APIS from './Runtime.js';
8
+ export {
9
+ WebfloServer
10
+ }
@@ -1,30 +1,40 @@
1
-
2
- /**
3
- * @imports
4
- */
5
1
  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';
2
+ import { _after, _before } from '@webqit/util/str/index.js';
3
+ import { _from as _arrFrom } from '@webqit/util/arr/index.js';
7
4
  import { params } from './util-url.js';
8
5
 
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] };
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] };
14
24
  }, {});
15
- let body = message.body, type = dataType(message.body);
16
- if ([ 'Blob', 'File' ].includes(type)) {
25
+ let body = httpMessageInit.body, type = dataType(httpMessageInit.body);
26
+ if (['Blob', 'File'].includes(type)) {
17
27
  !headers['content-type'] && (headers['content-type'] = body.type);
18
28
  !headers['content-length'] && (headers['content-length'] = body.size);
19
- } else if ([ 'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer' ].includes(type)) {
29
+ } else if (['Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer'].includes(type)) {
20
30
  !headers['content-length'] && (headers['content-length'] = body.byteLength);
21
31
  } else if (type === 'json' && _isTypeObject(body)) {
22
32
  if (!headers['content-type']) {
23
- const [ _body, isJsonfiable ] = formDatarizeJson(body);
33
+ const [_body, isJsonfiable] = createFormDataFromJson(body, true/*jsonfy*/, true/*getIsJsonfiable*/);
24
34
  if (isJsonfiable) {
25
35
  body = JSON.stringify(body, (k, v) => v instanceof Error ? { ...v, message: v.message } : v);
26
36
  headers['content-type'] = 'application/json';
27
- headers['content-length'] = (new Blob([ body ])).size;
37
+ headers['content-length'] = (new Blob([body])).size;
28
38
  } else {
29
39
  body = _body;
30
40
  type = 'FormData';
@@ -33,10 +43,24 @@ export function formatMessage(message) {
33
43
  } else if (type === 'json') {
34
44
  !headers['content-length'] && (headers['content-length'] = (body + '').length);
35
45
  }
36
- return [ body, headers, type ];
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;
37
61
  }
38
62
 
39
- export function formDatarizeJson(data = {}, jsonfy = true) {
63
+ export function createFormDataFromJson(data = {}, jsonfy = true, getIsJsonfiable = false) {
40
64
  const formData = new FormData;
41
65
  let isJsonfiable = true;
42
66
  params.reduceValue(data, '', (value, contextPath, suggestedKeys = undefined) => {
@@ -50,13 +74,14 @@ export function formDatarizeJson(data = {}, jsonfy = true) {
50
74
  }
51
75
  formData.append(contextPath, value);
52
76
  });
53
- return [ formData, isJsonfiable ];
77
+ if (getIsJsonfiable) return [formData, isJsonfiable];
78
+ return formData;
54
79
  }
55
80
 
56
- export async function jsonfyFormData(formData, jsonfy = true) {
81
+ export async function renderFormDataToJson(formData, jsonfy = true, getIsJsonfiable = false) {
57
82
  let isJsonfiable = true;
58
83
  let json;
59
- for (let [ name, value ] of formData.entries()) {
84
+ for (let [name, value] of formData.entries()) {
60
85
  if (!json) { json = _isNumeric(_before(name, '[')) ? [] : {}; }
61
86
  let type = dataType(value);
62
87
  if (jsonfy && ['Blob', 'File'].includes(type) && value.type === 'application/json' && [4, 5].includes(value.size)) {
@@ -69,18 +94,229 @@ export async function jsonfyFormData(formData, jsonfy = true) {
69
94
  isJsonfiable = isJsonfiable && type === 'json';
70
95
  params.set(json, name, value);
71
96
  }
72
- return [ json, isJsonfiable ];
97
+ if (getIsJsonfiable) return [json, isJsonfiable];
98
+ return json;
73
99
  }
74
100
 
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';
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
+ }
85
321
  }
86
- }
322
+ });
@@ -15,40 +15,43 @@ export default class xURL extends URL {
15
15
  // constructor
16
16
  constructor(...args) {
17
17
  super(...args);
18
- var query = params.parse(this.search);
19
- const updateSearch = query => {
18
+ const query = params.parse(this.search);
19
+ const updateSearch = () => {
20
20
  // "query" was updated. So we update "search"
21
- var search = params.stringify(query);
21
+ let search = params.stringify(query);
22
22
  search = search ? '?' + search : '';
23
23
  if (search !== this.search) {
24
24
  this.search = search;
25
25
  }
26
26
  };
27
- this.__query = {
28
- value: query,
29
- proxy: new Proxy(this, {
30
- set(t, n, v) {
31
- t.__query.value[n] = v;
32
- updateSearch(t.__query.value);
33
- return true;
34
- },
35
- deleteProperty(t, n) {
36
- delete t.__query.value[n];
37
- updateSearch(t.__query.value);
38
- return true;
39
- }
40
- })
41
- };
27
+ const $this = this;
28
+ this._query = new Proxy(query, {
29
+ set(t, k, v) {
30
+ t[k] = v;
31
+ if (!$this._updatingSearch) updateSearch();
32
+ return true;
33
+ },
34
+ deleteProperty(t, k) {
35
+ delete t[k];
36
+ if (!$this._updatingSearch) updateSearch();
37
+ return true;
38
+ }
39
+ });
42
40
  }
43
41
 
44
42
  // Set search
45
43
  set search(value) {
46
44
  super.search = value;
47
45
  // "search" was updated. So we update "query"
48
- var query = params.parse(value);
49
- if (!_strictEven(query, this.query)) {
50
- this.__query.value = query;
46
+ this._updatingSearch = true;
47
+ const query = params.parse(value);
48
+ const keys_a = Object.keys(query);
49
+ const keys_b = Object.keys(this._query);
50
+ for (const k of new Set([...keys_a,...keys_b])) {
51
+ if (!keys_a.includes(k)) delete this.query[k];
52
+ if (!keys_b.includes(k)) this.query[k] = query[k];
51
53
  }
54
+ this._updatingSearch = false;
52
55
  }
53
56
 
54
57
  // Get search
@@ -58,7 +61,7 @@ export default class xURL extends URL {
58
61
 
59
62
  // Get query
60
63
  get query() {
61
- return this.__query.proxy;
64
+ return this._query;
62
65
  }
63
66
 
64
67
  };
@@ -2,14 +2,14 @@
2
2
  /**
3
3
  * @imports
4
4
  */
5
- import { formatMessage } from './util-http.js';
5
+ import { renderHttpMessageInit } from './util-http.js';
6
6
 
7
7
  /**
8
8
  * The xfetch Mixin
9
9
  */
10
10
  const xfetch = async (url, init = {}) => {
11
11
  if (init.body) {
12
- const [ body, headers ] = formatMessage(init);
12
+ const { body, headers } = renderHttpMessageInit(init);
13
13
  init = { ...init, body, headers, };
14
14
  }
15
15
  let response = await fetch(url, init), encoding;
@@ -1,29 +0,0 @@
1
-
2
- /**
3
- * ---------------------------
4
- * The base Application class
5
- * ---------------------------
6
- */
7
-
8
- export default class Application {
9
-
10
- constructor(cx) {
11
- this.cx = cx;
12
- }
13
-
14
- /**
15
- * Initializes application itself.
16
- *
17
- * @param HttpEvent httpEvent
18
- * @param Function remoteFetch
19
- *
20
- * @return Boolean|undefined
21
- */
22
- async init(httpEvent, remoteFetch) {
23
- // The app router
24
- const router = new this.Router(this.cx, '/');
25
- return router.route(['init'], httpEvent, {}, async event => {
26
- }, remoteFetch);
27
- }
28
-
29
- }
@@ -1,82 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import { _isString, _isObject } from "@webqit/util/js/index.js";
6
-
7
- export default class Cookies extends Map {
8
-
9
- constructor(...args) {
10
- super(...args);
11
- Object.defineProperty(this, 'inLock', { value: false, writable: true });
12
- Object.defineProperty(this, 'outLock', { value: false, writable: true });
13
- }
14
-
15
- set(name, value) {
16
- if (this.inLock) return;
17
- if (this.has(name)) this.delete(name);
18
- this.inLock = true;
19
- // -----------------
20
- let valueObj = value, valueStr = value, retrn;
21
- if (_isString(value)) { valueObj = this.parseEntry(`=${ value }`)[1]; }
22
- retrn = super.set(name, valueObj);
23
- if (!this.outLock) {
24
- if (_isObject(value)) { valueStr = this.stringifyEntry(value); }
25
- append(this.headers, `${ name }=${ valueStr }`);
26
- }
27
- // -----------------
28
- this.inLock = false;
29
- return retrn;
30
- }
31
-
32
- delete(name) {
33
- if (this.inLock) return;
34
- this.inLock = true;
35
- // -----------------
36
- let retrn = super.delete(name);
37
- this.headers.delete(this.headers.cookieHeaderName);
38
- for (let [ name, definition ] of this) {
39
- append(this.headers, `${ name }=${ this.stringifyEntry(definition) }`);
40
- }
41
- // -----------------
42
- this.inLock = false;
43
- return retrn;
44
- }
45
-
46
- clear() {
47
- if (this.inLock) return;
48
- this.inLock = true;
49
- // -----------------
50
- let retrn = super.clear();
51
- this.headers.delete(this.headers.cookieHeaderName);
52
- // -----------------
53
- this.inLock = false;
54
- return retrn;
55
- }
56
-
57
- json(json = {}) {
58
- if (arguments.length) {
59
- this.clear();
60
- for (let name in json) {
61
- this.set(name, json[name])
62
- }
63
- return;
64
- }
65
- for (let [ name, definition ] of this) {
66
- json[name] = definition;
67
- }
68
- return json;
69
- }
70
-
71
- toString() {
72
- return this.headers.get(this.headers.cookieHeaderName);
73
- }
74
-
75
- }
76
-
77
- function append(headers, value) {
78
- let values = [value];
79
- let currentValue = headers.get(headers.cookieHeaderName);
80
- if (currentValue) { values.unshift(currentValue); }
81
- headers.set(headers.cookieHeaderName, values.join(headers.cookieHeaderSeparator));
82
- }
@@ -1,21 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
-
6
- import { _isFunction } from "@webqit/util/js/index.js";
7
-
8
- /**
9
- * ---------------------------
10
- * The base Runtime class
11
- * ---------------------------
12
- */
13
-
14
- export default class Runtime {
15
- constructor(cx, applicationInstance) {
16
- this.cx = cx;
17
- this.cx.runtime = this;
18
- this.app = _isFunction(applicationInstance) ? applicationInstance(this.cx) : applicationInstance;
19
- if (!this.app || !this.app.handle) throw new Error(`Application instance must define a ".handle()" method.`);
20
- }
21
- }
@@ -1,76 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import Router from './Router.js';
6
- import _Application from '../Application.js';
7
-
8
- export default class Application extends _Application {
9
-
10
- // Returns router class
11
- get Router() {
12
- return Router;
13
- }
14
-
15
- /**
16
- * Handles HTTP events.
17
- *
18
- * @param HttpEvent httpEvent
19
- * @param Function remoteFetch
20
- *
21
- * @return Response
22
- */
23
- async handle(httpEvent, remoteFetch) {
24
- // The app router
25
- const router = new this.Router(this.cx, httpEvent.url.pathname);
26
- const handle = async () => {
27
- let bindingsConfig;
28
- if (window.webqit?.oohtml?.configs) { ( { BINDINGS_API: { api: bindingsConfig } = {}, } = window.webqit.oohtml.configs ); }
29
- return router.route([httpEvent.request.method, 'default'], httpEvent, { ...( ( bindingsConfig && document[bindingsConfig.bindings] ) || {} ) }, async event => {
30
- if (event !== httpEvent) {
31
- // This was nexted()
32
- if (!event.request.headers.has('Accept')) {
33
- event.request.headers.set('Accept', 'application/json');
34
- }
35
- }
36
- return remoteFetch(event.request);
37
- }, remoteFetch);
38
- };
39
- return await (this.cx.middlewares || []).concat(handle).reverse().reduce((next, fn) => {
40
- return () => fn.call(this.cx, httpEvent, router, next);
41
- }, null)();
42
- }
43
-
44
- // Renderer
45
- async render(httpEvent, response) {
46
- let data = await response.jsonfy();
47
- const router = new this.Router(this.cx, httpEvent.url.pathname);
48
- return await router.route('render', httpEvent, data, async (httpEvent, data) => {
49
- if (window.webqit?.dom) { await new Promise(res => window.webqit.dom.ready(res)); }
50
- if (window.webqit?.oohtml?.configs) {
51
- const {
52
- CONTEXT_API: { attr: contextConfig } = {},
53
- BINDINGS_API: { api: bindingsConfig } = {},
54
- HTML_IMPORTS: { attr: modulesContextAttrs } = {},
55
- } = window.webqit.oohtml.configs;
56
- if ( bindingsConfig ) {
57
- window.document[ bindingsConfig.bind ]({
58
- env: 'client', state: this.cx.runtime, ...(data || {})
59
- }, { diff: true });
60
- }
61
- let routingContext;
62
- if ( modulesContextAttrs ) {
63
- routingContext = window.document.body.querySelector(`[${ window.CSS.escape( contextConfig.contextname ) }="app"]`) || window.document.body;
64
- const prevRoute = routingContext.getAttribute( modulesContextAttrs.importscontext );
65
- const newRoute = '/' + `routes/${ httpEvent.url.pathname }`.split('/').map(a => a.trim()).filter(a => a).join('/');
66
- const rel = prevRoute === newRoute ? 'same' : ( `${ prevRoute }/`.startsWith( `${ newRoute }/` ) ? 'parent' : ( `${ newRoute }/`.startsWith( `${ prevRoute }/` ) ? 'child' : 'unrelated' ) );
67
- routingContext.setAttribute( modulesContextAttrs.importscontext, newRoute);
68
- routingContext.setAttribute( `prev-${ modulesContextAttrs.importscontext }`, prevRoute );
69
- routingContext.setAttribute( 'importscontext-transition-type', rel );
70
- }
71
- }
72
- return window;
73
- });
74
- }
75
- }
76
-