@webqit/webflo 0.20.26 → 0.20.28
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.
- package/package.json +8 -5
- package/src/build-pi/index.js +6 -4
- package/src/init-pi/index.js +0 -1
- package/src/runtime-pi/{WebfloRuntime.js → AppRuntime.js} +57 -113
- package/src/runtime-pi/webflo-client/DeviceCapabilities.js +1 -1
- package/src/runtime-pi/webflo-client/WebfloClient.js +163 -103
- package/src/runtime-pi/webflo-client/{WebfloRootClient1.js → WebfloRootClientA.js} +39 -56
- package/src/runtime-pi/webflo-client/{WebfloRootClient2.js → WebfloRootClientB.js} +3 -3
- package/src/runtime-pi/webflo-client/WebfloSubClient.js +28 -15
- package/src/runtime-pi/webflo-client/index.js +3 -3
- package/src/runtime-pi/webflo-messaging/ClientPortMixin.js +13 -0
- package/src/runtime-pi/{webflo-server/messaging/ClientRequestRealtime.js → webflo-messaging/ClientRequestPort001.js} +13 -9
- package/src/runtime-pi/webflo-messaging/ClientRequestPort010.js +4 -0
- package/src/runtime-pi/webflo-messaging/ClientRequestPort100.js +17 -0
- package/src/runtime-pi/webflo-messaging/WebfloTenancy001.js +27 -0
- package/src/runtime-pi/webflo-messaging/WebfloTenant001.js +27 -0
- package/src/runtime-pi/webflo-routing/HttpCookies101.js +53 -0
- package/src/runtime-pi/webflo-routing/HttpCookies110.js +3 -0
- package/src/runtime-pi/webflo-routing/{HttpEvent.js → HttpEvent111.js} +95 -73
- package/src/runtime-pi/webflo-routing/HttpKeyvalInterface.js +120 -0
- package/src/runtime-pi/webflo-routing/HttpSession001.js +24 -0
- package/src/runtime-pi/webflo-routing/HttpSession110.js +3 -0
- package/src/runtime-pi/webflo-routing/{HttpThread.js → HttpThread111.js} +54 -13
- package/src/runtime-pi/webflo-routing/{HttpUser.js → HttpUser111.js} +10 -23
- package/src/runtime-pi/webflo-routing/KeyvalsFactory001.js +53 -0
- package/src/runtime-pi/webflo-routing/KeyvalsFactory110.js +48 -0
- package/src/runtime-pi/webflo-routing/KeyvalsFactoryInterface.js +56 -0
- package/src/runtime-pi/webflo-routing/{WebfloRouter.js → WebfloRouter111.js} +5 -6
- package/src/runtime-pi/webflo-server/WebfloServer.js +262 -269
- package/src/runtime-pi/webflo-worker/WebfloWorker.js +97 -44
- package/src/util.js +3 -2
- package/src/runtime-pi/apis.js +0 -9
- package/src/runtime-pi/webflo-client/ClientSideCookies.js +0 -18
- package/src/runtime-pi/webflo-fetch/LiveResponse.js +0 -476
- package/src/runtime-pi/webflo-fetch/index.js +0 -419
- package/src/runtime-pi/webflo-fetch/util.js +0 -28
- package/src/runtime-pi/webflo-messaging/WQBroadcastChannel.js +0 -10
- package/src/runtime-pi/webflo-messaging/WQMessageChannel.js +0 -26
- package/src/runtime-pi/webflo-messaging/WQMessageEvent.js +0 -87
- package/src/runtime-pi/webflo-messaging/WQMessagePort.js +0 -38
- package/src/runtime-pi/webflo-messaging/WQRelayPort.js +0 -47
- package/src/runtime-pi/webflo-messaging/WQSockPort.js +0 -111
- package/src/runtime-pi/webflo-messaging/WQStarPort.js +0 -112
- package/src/runtime-pi/webflo-messaging/wq-message-port.js +0 -413
- package/src/runtime-pi/webflo-routing/HttpCookies.js +0 -43
- package/src/runtime-pi/webflo-routing/HttpSession.js +0 -11
- package/src/runtime-pi/webflo-routing/HttpState.js +0 -182
- package/src/runtime-pi/webflo-server/ServerSideCookies.js +0 -22
- package/src/runtime-pi/webflo-server/ServerSideSession.js +0 -40
- package/src/runtime-pi/webflo-server/messaging/Client.js +0 -27
- package/src/runtime-pi/webflo-server/messaging/Clients.js +0 -25
- package/src/runtime-pi/webflo-url/Url.js +0 -156
- package/src/runtime-pi/webflo-url/index.js +0 -1
- package/src/runtime-pi/webflo-url/urlpattern.js +0 -38
- package/src/runtime-pi/webflo-url/util.js +0 -109
- package/src/runtime-pi/webflo-url/xURL.js +0 -94
- package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +0 -21
|
@@ -1,419 +0,0 @@
|
|
|
1
|
-
import { _isObject, _isTypeObject, _isNumeric } from '@webqit/util/js/index.js';
|
|
2
|
-
import { _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
3
|
-
import { _before, _after } from '@webqit/util/str/index.js';
|
|
4
|
-
import { DeepURLSearchParams } from '../webflo-url/util.js';
|
|
5
|
-
import { dataType } from './util.js';
|
|
6
|
-
import { _wq } from '../../util.js';
|
|
7
|
-
import { Observer } from '@webqit/use-live';
|
|
8
|
-
import { LiveResponse } from './LiveResponse.js';
|
|
9
|
-
|
|
10
|
-
// ----- env & globalize
|
|
11
|
-
|
|
12
|
-
export const env = {};
|
|
13
|
-
|
|
14
|
-
export function shim(prefix = 'wq') {
|
|
15
|
-
const apis = [Request, Response, Headers, FormData];
|
|
16
|
-
const descs = [request, response, headers, formData];
|
|
17
|
-
const patch = (api, desc) => {
|
|
18
|
-
const _descs = Object.fromEntries(Object.entries(desc).map(([key, value]) => {
|
|
19
|
-
if (prefix && key in api) {
|
|
20
|
-
key = `${prefix}${key[0].toUpperCase()}${key.slice(1)}`;
|
|
21
|
-
}
|
|
22
|
-
return [key, value];
|
|
23
|
-
}));
|
|
24
|
-
Object.defineProperties(api, _descs);
|
|
25
|
-
};
|
|
26
|
-
for (let i = 0; i < apis.length; i++) {
|
|
27
|
-
const api = apis[i];
|
|
28
|
-
const { prototype, ...statics } = descs[i];
|
|
29
|
-
patch(api, statics);
|
|
30
|
-
if (prototype) {
|
|
31
|
-
patch(api.prototype, prototype);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
globalThis.LiveResponse = LiveResponse;
|
|
35
|
-
globalThis.Observer = Observer;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// ----- request
|
|
39
|
-
|
|
40
|
-
const requestOriginals = { prototype: { clone: Request.prototype.clone } };
|
|
41
|
-
|
|
42
|
-
export const request = {
|
|
43
|
-
from: {
|
|
44
|
-
value: function (url, init = {}) {
|
|
45
|
-
if (url instanceof Request) return url;
|
|
46
|
-
let $$type, $$body = init.body;
|
|
47
|
-
if ('body' in init) {
|
|
48
|
-
const { body, headers, $type } = renderHttpMessageInit(init);
|
|
49
|
-
init = { ...init, body, headers };
|
|
50
|
-
$$type = $type;
|
|
51
|
-
}
|
|
52
|
-
const instance = new Request(url, init);
|
|
53
|
-
const responseMeta = _wq(instance, 'meta');
|
|
54
|
-
responseMeta.set('body', $$body);
|
|
55
|
-
responseMeta.set('type', $$type);
|
|
56
|
-
return instance;
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
copy: {
|
|
60
|
-
value: async function (request, init = {}) {
|
|
61
|
-
const attrs = ['method', 'headers', 'mode', 'credentials', 'cache', 'redirect', 'referrer', 'integrity'];
|
|
62
|
-
const requestInit = attrs.reduce(($init, prop) => (
|
|
63
|
-
{
|
|
64
|
-
...$init,
|
|
65
|
-
[prop]: prop in init
|
|
66
|
-
? init[prop]
|
|
67
|
-
: (prop === 'headers'
|
|
68
|
-
? new Headers(request[prop])
|
|
69
|
-
: request[prop])
|
|
70
|
-
}
|
|
71
|
-
), {});
|
|
72
|
-
if (!['GET', 'HEAD'].includes(init.method?.toUpperCase() || request.method)) {
|
|
73
|
-
if ('body' in init) {
|
|
74
|
-
requestInit.body = init.body
|
|
75
|
-
if (!('headers' in init)) {
|
|
76
|
-
requestInit.headers.delete('Content-Type');
|
|
77
|
-
requestInit.headers.delete('Content-Length');
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
requestInit.body = await request.clone().arrayBuffer();
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (requestInit.mode === 'navigate') {
|
|
84
|
-
requestInit.mode = 'cors';
|
|
85
|
-
}
|
|
86
|
-
return { url: request.url, ...requestInit };
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
prototype: {
|
|
90
|
-
parse: { value: async function () { return await parseHttpMessage(this); } },
|
|
91
|
-
clone: {
|
|
92
|
-
value: function (init = {}) {
|
|
93
|
-
const clone = requestOriginals.prototype.clone.call(this, init);
|
|
94
|
-
const requestMeta = _wq(this, 'meta');
|
|
95
|
-
_wq(clone).set('meta', requestMeta);
|
|
96
|
-
return clone;
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// ----- response
|
|
103
|
-
|
|
104
|
-
const responseOriginals = {
|
|
105
|
-
json: Response.json,
|
|
106
|
-
prototype: {
|
|
107
|
-
status: Object.getOwnPropertyDescriptor(Response.prototype, 'status'),
|
|
108
|
-
clone: Response.prototype.clone,
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
export const response = {
|
|
113
|
-
json: {
|
|
114
|
-
value: function (data, options = {}) {
|
|
115
|
-
const instance = responseOriginals.json(data, options);
|
|
116
|
-
const responseMeta = _wq(instance, 'meta');
|
|
117
|
-
responseMeta.set('body', data);
|
|
118
|
-
responseMeta.set('type', 'json');
|
|
119
|
-
return instance;
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
from: {
|
|
123
|
-
value: function (body, init = {}) {
|
|
124
|
-
if (body instanceof Response) return body;
|
|
125
|
-
let $type, $body = body;
|
|
126
|
-
if (body || body === 0) {
|
|
127
|
-
let headers;
|
|
128
|
-
({ body, headers, $type } = renderHttpMessageInit({ body, headers: init.headers }));
|
|
129
|
-
init = { ...init, headers };
|
|
130
|
-
}
|
|
131
|
-
const instance = new Response(body, init);
|
|
132
|
-
const responseMeta = _wq(instance, 'meta');
|
|
133
|
-
responseMeta.set('body', $body);
|
|
134
|
-
responseMeta.set('type', $type);
|
|
135
|
-
return instance;
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
prototype: {
|
|
139
|
-
status: {
|
|
140
|
-
get: function () {
|
|
141
|
-
return _wq(this, 'meta').get('status')
|
|
142
|
-
|| (this instanceof Response
|
|
143
|
-
? responseOriginals.prototype.status.get.call(this)
|
|
144
|
-
: this.status);
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
|
-
parse: { value: async function () { return await parseHttpMessage(this); } },
|
|
148
|
-
clone: {
|
|
149
|
-
value: function (init = {}) {
|
|
150
|
-
const clone = responseOriginals.prototype.clone.call(this, init);
|
|
151
|
-
const responseMeta = _wq(this, 'meta');
|
|
152
|
-
_wq(clone).set('meta', responseMeta);
|
|
153
|
-
return clone;
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
// ----- headers
|
|
160
|
-
|
|
161
|
-
const headersOriginals = {
|
|
162
|
-
set: Headers.prototype.set,
|
|
163
|
-
get: Headers.prototype.get,
|
|
164
|
-
append: Headers.prototype.append,
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
export const headers = {
|
|
168
|
-
set: {
|
|
169
|
-
value: function (name, value) {
|
|
170
|
-
|
|
171
|
-
// Format "Set-Cookie" response header
|
|
172
|
-
if (/^Set-Cookie$/i.test(name) && _isObject(value)) {
|
|
173
|
-
value = renderCookieObjToString(value);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Format "Cookie" request header
|
|
177
|
-
if (/Cookie/i.test(name) && _isTypeObject(value)) {
|
|
178
|
-
value = [].concat(value).map(renderCookieObjToString).join(';');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Format "Content-Range" response header?
|
|
182
|
-
if (/^Content-Range$/i.test(name) && Array.isArray(value)) {
|
|
183
|
-
if (value.length < 2 || !value[0].includes('-')) {
|
|
184
|
-
throw new Error(`A Content-Range array must be in the format: [ 'start-end', 'total' ]`);
|
|
185
|
-
}
|
|
186
|
-
value = `bytes ${value.join('/')}`;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Format "Range" request header?
|
|
190
|
-
if (/^Range$/i.test(name)) {
|
|
191
|
-
let rangeArr = [];
|
|
192
|
-
_arrFrom(value).forEach((range, i) => {
|
|
193
|
-
let rangeStr = Array.isArray(range) ? range.join('-') : range + '';
|
|
194
|
-
if (i === 0 && !rangeStr.includes('bytes=')) {
|
|
195
|
-
rangeStr = `bytes=${rangeStr}`;
|
|
196
|
-
}
|
|
197
|
-
rangeArr.push(rangeStr);
|
|
198
|
-
});
|
|
199
|
-
value = rangeArr.join(', ');
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Format "Accept" request header?
|
|
203
|
-
if (/^Accept$/i.test(name) && Array.isArray(value)) {
|
|
204
|
-
value = value.join(',');
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return headersOriginals.set.call(this, name, value);
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
append: {
|
|
211
|
-
value: function (name, value) {
|
|
212
|
-
|
|
213
|
-
// Format "Set-Cookie" response header
|
|
214
|
-
if (/^Set-Cookie$/i.test(name) && _isObject(value)) {
|
|
215
|
-
value = renderCookieObjToString(value);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return headersOriginals.append.call(this, name, value);
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
|
-
get: {
|
|
222
|
-
value: function (name, parsed = false) {
|
|
223
|
-
let value = headersOriginals.get.call(this, name);
|
|
224
|
-
|
|
225
|
-
// Parse "Set-Cookie" response header
|
|
226
|
-
if (/^Set-Cookie$/i.test(name) && parsed) {
|
|
227
|
-
value = this.getSetCookie()/*IMPORTANT*/.map((str) => {
|
|
228
|
-
const [cookieDefinition, attrsStr] = str.split(';');
|
|
229
|
-
const [name, value] = cookieDefinition.split('=').map((s) => s.trim());
|
|
230
|
-
const cookieObj = { name, value: /*decodeURIComponent*/(value), };
|
|
231
|
-
attrsStr && attrsStr.split(/\;/g).map(attrStr => attrStr.trim().split('=')).forEach(attrsArr => {
|
|
232
|
-
cookieObj[attrsArr[0][0].toLowerCase() + attrsArr[0].substring(1).replace('-', '')] = attrsArr.length === 1 ? true : attrsArr[1];
|
|
233
|
-
});
|
|
234
|
-
return cookieObj;
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Parse "Cookie" request header
|
|
239
|
-
if (/^Cookie$/i.test(name) && parsed) {
|
|
240
|
-
value = value?.split(';').map((str) => {
|
|
241
|
-
const [name, value] = str.split('=').map((s) => s.trim());
|
|
242
|
-
return { name, value: /*decodeURIComponent*/(value), };
|
|
243
|
-
}) || [];
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Parse "Content-Range" response header?
|
|
247
|
-
if (/^Content-Range$/i.test(name) && value && parsed) {
|
|
248
|
-
value = _after(value, 'bytes ').split('/');
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Parse "Range" request header?
|
|
252
|
-
if (/^Range$/i.test(name) && parsed) {
|
|
253
|
-
value = !value ? [] : _after(value, 'bytes=').split(',').map((rangeStr) => {
|
|
254
|
-
const range = rangeStr.trim().split('-').map((s) => s ? parseInt(s, 10) : null);
|
|
255
|
-
range.render = (totalLength) => {
|
|
256
|
-
if (range[1] === null) {
|
|
257
|
-
range[1] = totalLength - 1;
|
|
258
|
-
}
|
|
259
|
-
if (range[0] === null) {
|
|
260
|
-
range[0] = range[1] ? totalLength - range[1] - 1 : 0;
|
|
261
|
-
}
|
|
262
|
-
return range
|
|
263
|
-
};
|
|
264
|
-
range.isValid = (currentStart, totalLength) => {
|
|
265
|
-
// Start higher than end or vice versa?
|
|
266
|
-
if (range[0] > range[1] || range[1] < range[0]) return false;
|
|
267
|
-
// Stretching beyond valid start/end?
|
|
268
|
-
if (range[0] < currentStart || range[1] > totalLength) return false;
|
|
269
|
-
return true;
|
|
270
|
-
};
|
|
271
|
-
return range;
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// Parse "Accept" request header?
|
|
276
|
-
if (/^Accept$/i.test(name) && value && parsed) {
|
|
277
|
-
const parseSpec = (spec) => {
|
|
278
|
-
const [mime, q] = spec.trim().split(';').map((s) => s.trim());
|
|
279
|
-
return [mime, parseFloat((q || 'q=1').replace('q=', ''))];
|
|
280
|
-
};
|
|
281
|
-
const list = value.split(',')
|
|
282
|
-
.map((spec) => parseSpec(spec))
|
|
283
|
-
.sort((a, b) => a[1] > b[1] ? -1 : 1) || [];
|
|
284
|
-
const $value = value;
|
|
285
|
-
value = {
|
|
286
|
-
match(mime) {
|
|
287
|
-
if (!mime) return 0;
|
|
288
|
-
const splitMime = (mime) => mime.split('/').map((s) => s.trim());
|
|
289
|
-
const $mime = splitMime(mime + '');
|
|
290
|
-
return list.reduce((prev, [entry, q]) => {
|
|
291
|
-
if (prev) return prev;
|
|
292
|
-
const $entry = splitMime(entry);
|
|
293
|
-
return [0, 1].every((i) => (($mime[i] === $entry[i]) || $mime[i] === '*' || $entry[i] === '*')) ? q : 0;
|
|
294
|
-
}, 0);
|
|
295
|
-
},
|
|
296
|
-
toString() {
|
|
297
|
-
return $value;
|
|
298
|
-
}
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return value;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
// ----- formData
|
|
308
|
-
|
|
309
|
-
export const formData = {
|
|
310
|
-
json: { value: createFormDataFromJson },
|
|
311
|
-
prototype: {
|
|
312
|
-
json: {
|
|
313
|
-
value: async function (data = {}) {
|
|
314
|
-
const result = await renderFormDataToJson(this, ...arguments);
|
|
315
|
-
return result;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
// ----- Utils
|
|
322
|
-
|
|
323
|
-
export function renderHttpMessageInit(httpMessageInit) {
|
|
324
|
-
// JSONfy headers
|
|
325
|
-
const headers = (httpMessageInit.headers instanceof Headers) ? [...httpMessageInit.headers.entries()].reduce((_headers, [name, value]) => {
|
|
326
|
-
return { ..._headers, [name/* lower-cased */]: _headers[name] ? [].concat(_headers[name], value) : value };
|
|
327
|
-
}, {}) : Object.keys(httpMessageInit.headers || {}).reduce((_headers, name) => {
|
|
328
|
-
return { ..._headers, [name.toLowerCase()]: httpMessageInit.headers[name] };
|
|
329
|
-
}, {});
|
|
330
|
-
// Process body
|
|
331
|
-
let body = httpMessageInit.body,
|
|
332
|
-
type = dataType(httpMessageInit.body);
|
|
333
|
-
|
|
334
|
-
if (['Blob', 'File'].includes(type)) {
|
|
335
|
-
!headers['content-type'] && (headers['content-type'] = body.type);
|
|
336
|
-
!headers['content-length'] && (headers['content-length'] = body.size);
|
|
337
|
-
} else if (['Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer'].includes(type)) {
|
|
338
|
-
!headers['content-length'] && (headers['content-length'] = body.byteLength);
|
|
339
|
-
} else if (type === 'json' && _isTypeObject(body)/*JSON object*/) {
|
|
340
|
-
const [_body, isJsonfiable] = createFormDataFromJson(body, true/*jsonfy*/, true/*getIsJsonfiable*/);
|
|
341
|
-
if (isJsonfiable) {
|
|
342
|
-
body = JSON.stringify(body, (k, v) => v instanceof Error ? { ...v, message: v.message } : v);
|
|
343
|
-
headers['content-type'] = 'application/json';
|
|
344
|
-
headers['content-length'] = (new Blob([body])).size;
|
|
345
|
-
} else {
|
|
346
|
-
body = _body;
|
|
347
|
-
type = 'FormData';
|
|
348
|
-
}
|
|
349
|
-
} else if (type === 'json'/*JSON string*/ && !headers['content-length']) {
|
|
350
|
-
(headers['content-length'] = (body + '').length);
|
|
351
|
-
}
|
|
352
|
-
return { body, headers, $type: type };
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
export async function parseHttpMessage(httpMessage) {
|
|
356
|
-
if (!httpMessage.body) return null;
|
|
357
|
-
let result;
|
|
358
|
-
const contentType = httpMessage.headers.get('Content-Type') || '';
|
|
359
|
-
if (contentType === 'application/x-www-form-urlencoded' || contentType.startsWith('multipart/form-data')) {
|
|
360
|
-
const fd = await httpMessage.formData();
|
|
361
|
-
result = fd && await formData.prototype.json.value.call(fd);
|
|
362
|
-
} else if (contentType.startsWith('application/json')/*can include charset*/) {
|
|
363
|
-
result = await httpMessage.json();
|
|
364
|
-
} else /*if (contentType === 'text/plain')*/ {
|
|
365
|
-
result = httpMessage.body;
|
|
366
|
-
}
|
|
367
|
-
return result;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// -----
|
|
371
|
-
|
|
372
|
-
export function createFormDataFromJson(data = {}, jsonfy = true, getIsJsonfiable = false) {
|
|
373
|
-
const formData = new FormData;
|
|
374
|
-
let isJsonfiable = true;
|
|
375
|
-
DeepURLSearchParams.reduceValue(data, '', (value, contextPath, suggestedKeys = undefined) => {
|
|
376
|
-
if (suggestedKeys) {
|
|
377
|
-
const isJson = dataType(value) === 'json';
|
|
378
|
-
isJsonfiable = isJsonfiable && isJson;
|
|
379
|
-
return isJson && suggestedKeys;
|
|
380
|
-
}
|
|
381
|
-
if (jsonfy && [true, false, null].includes(value)) {
|
|
382
|
-
value = new Blob([value], { type: 'application/json' });
|
|
383
|
-
}
|
|
384
|
-
formData.append(contextPath, value);
|
|
385
|
-
});
|
|
386
|
-
if (getIsJsonfiable) return [formData, isJsonfiable];
|
|
387
|
-
return formData;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
export async function renderFormDataToJson(formData, jsonfy = true, getIsJsonfiable = false) {
|
|
391
|
-
let isJsonfiable = true;
|
|
392
|
-
let json;
|
|
393
|
-
for (let [name, value] of formData.entries()) {
|
|
394
|
-
if (!json) { json = _isNumeric(_before(name, '[')) ? [] : {}; }
|
|
395
|
-
let type = dataType(value);
|
|
396
|
-
if (jsonfy && ['Blob', 'File'].includes(type) && value.type === 'application/json') {
|
|
397
|
-
let _value = await value.text();
|
|
398
|
-
value = JSON.parse(_value);
|
|
399
|
-
type = 'json';
|
|
400
|
-
}
|
|
401
|
-
isJsonfiable = isJsonfiable && type === 'json';
|
|
402
|
-
DeepURLSearchParams.set(json, name, value);
|
|
403
|
-
}
|
|
404
|
-
if (getIsJsonfiable) return [json, isJsonfiable];
|
|
405
|
-
return json;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// -----
|
|
409
|
-
|
|
410
|
-
export function renderCookieObjToString(cookieObj) {
|
|
411
|
-
const attrsArr = [`${cookieObj.name}=${/*encodeURIComponent*/(cookieObj.value)}`];
|
|
412
|
-
for (const attrName in cookieObj) {
|
|
413
|
-
if (['name', 'value'].includes(attrName)) continue;
|
|
414
|
-
let _attrName = attrName[0].toUpperCase() + attrName.substring(1);
|
|
415
|
-
if (_attrName === 'MaxAge') { _attrName = 'Max-Age' };
|
|
416
|
-
attrsArr.push(cookieObj[attrName] === true ? _attrName : `${_attrName}=${cookieObj[attrName]}`);
|
|
417
|
-
}
|
|
418
|
-
return attrsArr.join('; ');
|
|
419
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { _isString, _isObject, _isPlainObject, _isPlainArray, _isTypeObject, _isNumber, _isBoolean } from '@webqit/util/js/index.js';
|
|
2
|
-
|
|
3
|
-
export function isTypeStream(obj) {
|
|
4
|
-
return obj instanceof ReadableStream || isTypeReadable(obj);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function isTypeReadable(obj) {
|
|
8
|
-
return (
|
|
9
|
-
obj !== null &&
|
|
10
|
-
typeof obj === 'object' &&
|
|
11
|
-
typeof obj.read === 'function' && // streams have .read()
|
|
12
|
-
typeof obj.pipe === 'function' && // streams have .pipe()
|
|
13
|
-
typeof obj.on === 'function' // streams have event listeners
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function dataType(value) {
|
|
18
|
-
if (_isString(value) || _isNumber(value) || _isBoolean(value)) return 'json';
|
|
19
|
-
if (!_isTypeObject(value)) return;
|
|
20
|
-
const toStringTag = value[Symbol.toStringTag];
|
|
21
|
-
const type = [
|
|
22
|
-
'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer', 'Blob', 'File', 'FormData', 'Stream', 'ReadableStream'
|
|
23
|
-
].reduce((_toStringTag, type) => _toStringTag || (toStringTag === type ? type : null), null);
|
|
24
|
-
if (type) return type;
|
|
25
|
-
if ((_isObject(value)) || (Array.isArray(value) && _isPlainArray(value)) || 'toString' in value) {
|
|
26
|
-
return 'json';
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { toWQPort } from './wq-message-port.js';
|
|
2
|
-
|
|
3
|
-
export class WQMessageChannel extends MessageChannel {
|
|
4
|
-
|
|
5
|
-
#port1;
|
|
6
|
-
get port1() {
|
|
7
|
-
if (!this.#port1) {
|
|
8
|
-
this.#port1 = super.port1;
|
|
9
|
-
this.#port1.start();
|
|
10
|
-
toWQPort(this.#port1);
|
|
11
|
-
}
|
|
12
|
-
return this.#port1;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
#port2;
|
|
16
|
-
get port2() {
|
|
17
|
-
if (!this.#port2) {
|
|
18
|
-
this.#port2 = super.port2;
|
|
19
|
-
this.#port2.start();
|
|
20
|
-
toWQPort(this.#port2);
|
|
21
|
-
}
|
|
22
|
-
return this.#port2;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
globalThis.WQMessageChannel = WQMessageChannel;
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { _isTypeObject } from '@webqit/util/js/index.js';
|
|
2
|
-
import { toWQPort, applyMutations } from './wq-message-port.js';
|
|
3
|
-
import { _wq } from '../../util.js';
|
|
4
|
-
|
|
5
|
-
export class WQMessageEvent extends Event {
|
|
6
|
-
|
|
7
|
-
#originalTarget;
|
|
8
|
-
get originalTarget() { return this.#originalTarget; }
|
|
9
|
-
|
|
10
|
-
#eventID;
|
|
11
|
-
get eventID() { return this.#eventID; }
|
|
12
|
-
|
|
13
|
-
#data;
|
|
14
|
-
get data() { return this.#data; }
|
|
15
|
-
|
|
16
|
-
#live;
|
|
17
|
-
get live() { return this.#live; }
|
|
18
|
-
|
|
19
|
-
#bubbles;
|
|
20
|
-
get bubbles() { return this.#bubbles; }
|
|
21
|
-
|
|
22
|
-
#forwarded;
|
|
23
|
-
get forwarded() { return this.#forwarded; }
|
|
24
|
-
|
|
25
|
-
#ports = [];
|
|
26
|
-
get ports() { return this.#ports; }
|
|
27
|
-
|
|
28
|
-
constructor(originalTarget, {
|
|
29
|
-
data = null,
|
|
30
|
-
wqEventOptions: { eventID, type = 'message', live = false, bubbles = false, forwarded = false } = {},
|
|
31
|
-
wqProcessingOptions: {} = {},
|
|
32
|
-
ports = []
|
|
33
|
-
} = {}) {
|
|
34
|
-
if (typeof eventID !== 'string') {
|
|
35
|
-
throw new TypeError('eventID must be a non-empty string');
|
|
36
|
-
}
|
|
37
|
-
if (type && typeof type !== 'string') {
|
|
38
|
-
throw new TypeError('Where specified, wqEventOptions.type must be a string');
|
|
39
|
-
}
|
|
40
|
-
super(type);
|
|
41
|
-
this.#originalTarget = originalTarget;
|
|
42
|
-
this.#eventID = eventID;
|
|
43
|
-
this.#data = data;
|
|
44
|
-
this.#live = live;
|
|
45
|
-
this.#bubbles = bubbles;
|
|
46
|
-
this.#forwarded = forwarded;
|
|
47
|
-
this.#ports = ports.map(toWQPort);
|
|
48
|
-
if (_isTypeObject(this.#data) && this.#live) {
|
|
49
|
-
// If the data is a live object, we can apply mutations to it
|
|
50
|
-
applyMutations.call(originalTarget, this.#data, this.#eventID);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
#immediatePropagationStopped = false;
|
|
55
|
-
get immediatePropagationStopped() { return this.#immediatePropagationStopped; }
|
|
56
|
-
|
|
57
|
-
stopImmediatePropagation() {
|
|
58
|
-
this.#immediatePropagationStopped = true;
|
|
59
|
-
this.#propagationStopped = true;
|
|
60
|
-
super.stopImmediatePropagation();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
#propagationStopped = false;
|
|
64
|
-
get propagationStopped() { return this.#propagationStopped; }
|
|
65
|
-
|
|
66
|
-
stopPropagation() {
|
|
67
|
-
this.#propagationStopped = true;
|
|
68
|
-
super.stopPropagation();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
#defaultPrevented = false;
|
|
72
|
-
get defaultPrevented() { return this.#defaultPrevented; }
|
|
73
|
-
|
|
74
|
-
preventDefault() {
|
|
75
|
-
this.#defaultPrevented = true;
|
|
76
|
-
super.preventDefault();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
wqRespondWith(data, transferOrOptions = []) {
|
|
80
|
-
for (const port of this.#ports) {
|
|
81
|
-
port.postMessage(data, transferOrOptions);
|
|
82
|
-
}
|
|
83
|
-
return !!this.#ports.length;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
globalThis.WQMessageEvent = WQMessageEvent;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { internalAddEventListener, postRequest, handleRequests, forwardPort, forwardEvent } from './wq-message-port.js';
|
|
2
|
-
import { _wq } from '../../util.js';
|
|
3
|
-
|
|
4
|
-
export const WQMessagePortInstanceTag = Symbol('WQMessagePortInstanceTag');
|
|
5
|
-
|
|
6
|
-
export class WQMessagePort extends EventTarget {
|
|
7
|
-
|
|
8
|
-
[WQMessagePortInstanceTag] = true;
|
|
9
|
-
|
|
10
|
-
static [Symbol.hasInstance](instance) {
|
|
11
|
-
return !!instance?.[WQMessagePortInstanceTag];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
addEventListener(...args) {
|
|
15
|
-
internalAddEventListener.call(this, args);
|
|
16
|
-
return super.addEventListener(...args);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
dispatchEvent(event) {
|
|
20
|
-
const returnValue = super.dispatchEvent(event);
|
|
21
|
-
forwardEvent.call(this, event);
|
|
22
|
-
return returnValue;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
postRequest(data, callback, options = {}) {
|
|
26
|
-
return postRequest.call(this, data, callback, options);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
handleRequests(type, listener, options = {}) {
|
|
30
|
-
return handleRequests.call(this, type, listener, options);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
wqForwardPort(eventTypes, eventTarget, { resolveData = null, bidirectional = false, namespace1 = null, namespace2 = null } = {}) {
|
|
34
|
-
return forwardPort.call(this, eventTypes, eventTarget, { resolveData, bidirectional, namespace1, namespace2 });
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
globalThis.WQMessagePort = WQMessagePort;
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { forwardPort } from './wq-message-port.js';
|
|
2
|
-
import { WQStarPort } from './WQStarPort.js';
|
|
3
|
-
|
|
4
|
-
export class WQRelayPort extends WQStarPort {
|
|
5
|
-
|
|
6
|
-
#namespace;
|
|
7
|
-
get namespace() { return this.#namespace; }
|
|
8
|
-
|
|
9
|
-
constructor(namespace = null) {
|
|
10
|
-
super();
|
|
11
|
-
this.#namespace = namespace;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
addPort(port, { resolveData = null } = {}) {
|
|
15
|
-
const $resolveData = (data, ...args) => {
|
|
16
|
-
if (resolveData) {
|
|
17
|
-
return resolveData(data, ...args);
|
|
18
|
-
}
|
|
19
|
-
return data;
|
|
20
|
-
};
|
|
21
|
-
// Setup
|
|
22
|
-
const superCleanup = super.addPort(port, { enableBubbling: false });
|
|
23
|
-
const forwardingCleanup = forwardPort.call(port, '*', this, { bidirectional: false, resolveData: $resolveData, namespace1: this.namespace, namespace2: this.namespace });
|
|
24
|
-
const messageType_ping = this.namespace && `${this.namespace}:message` || 'message';
|
|
25
|
-
this.postMessage(
|
|
26
|
-
$resolveData({
|
|
27
|
-
event: 'joins',
|
|
28
|
-
}, port, this),
|
|
29
|
-
{ wqEventOptions: { type: messageType_ping }, wqProcessingOptions: { except: port } }
|
|
30
|
-
);
|
|
31
|
-
// Teardown
|
|
32
|
-
const leaves = () => {
|
|
33
|
-
forwardingCleanup();
|
|
34
|
-
this.postMessage(
|
|
35
|
-
$resolveData({
|
|
36
|
-
event: 'leaves',
|
|
37
|
-
}, port, this),
|
|
38
|
-
{ wqEventOptions: { type: messageType_ping }, wqProcessingOptions: { except: port } }
|
|
39
|
-
);
|
|
40
|
-
};
|
|
41
|
-
port.wqLifecycle.close.then(leaves);
|
|
42
|
-
return () => {
|
|
43
|
-
superCleanup(); // Cascade to super
|
|
44
|
-
leaves();
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
}
|