@webqit/fetch-plus 0.1.2 → 0.1.3
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/README.md +2050 -2
- package/dist/main.js +1 -1
- package/dist/main.js.map +4 -4
- package/package.json +8 -8
- package/src/FormDataPlus.js +23 -15
- package/src/HeadersPlus.js +128 -56
- package/src/LiveResponse.js +233 -155
- package/src/RequestPlus.js +9 -7
- package/src/ResponsePlus.js +6 -6
- package/src/index.js +0 -1
- package/src/messageParserMixin.js +217 -0
- package/test/1.basic.test.js +314 -0
- package/test/2.LiveResponse.test.js +261 -0
- package/test/3.LiveResponse.integration.test.js +459 -0
- package/src/URLSearchParamsPlus.js +0 -80
- package/src/core.js +0 -172
- package/test/basic.test.js +0 -0
package/src/core.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { _isString, _isObject, _isTypeObject, _isNumber, _isBoolean } from '@webqit/util/js/index.js';
|
|
2
|
-
import { _wq as $wq } from '@webqit/util/js/index.js';
|
|
3
|
-
import { FormDataPlus } from './FormDataPlus.js';
|
|
4
|
-
|
|
5
|
-
export const _wq = (target, ...args) => $wq(target, 'fetch+', ...args);
|
|
6
|
-
export const _meta = (target, ...args) => $wq(target, 'fetch+', 'meta', ...args);
|
|
7
|
-
|
|
8
|
-
export function messageParserMixin(superClass) {
|
|
9
|
-
return class extends superClass {
|
|
10
|
-
|
|
11
|
-
static from(httpMessageInit) {
|
|
12
|
-
const headers = (httpMessageInit.headers instanceof Headers)
|
|
13
|
-
|
|
14
|
-
? [...httpMessageInit.headers.entries()].reduce((_headers, [name, value]) => {
|
|
15
|
-
const key = name.toLowerCase();
|
|
16
|
-
_headers[key] = _headers[key] ? [].concat(_headers[key], value) : value;
|
|
17
|
-
return _headers;
|
|
18
|
-
}, {})
|
|
19
|
-
|
|
20
|
-
: Object.keys(httpMessageInit.headers || {}).reduce((_headers, name) => {
|
|
21
|
-
_headers[name.toLowerCase()] = httpMessageInit.headers[name];
|
|
22
|
-
return _headers;
|
|
23
|
-
}, {});
|
|
24
|
-
|
|
25
|
-
// Process body
|
|
26
|
-
let body = httpMessageInit.body;
|
|
27
|
-
let type = dataType(body);
|
|
28
|
-
|
|
29
|
-
// Binary bodies
|
|
30
|
-
if (['Blob', 'File'].includes(type)) {
|
|
31
|
-
|
|
32
|
-
headers['content-type'] ??= body.type;
|
|
33
|
-
headers['content-length'] ??= body.size;
|
|
34
|
-
|
|
35
|
-
} else if (['Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer'].includes(type)) {
|
|
36
|
-
headers['content-length'] ??= body.byteLength;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// JSON objects
|
|
40
|
-
else if (type === 'json' && _isTypeObject(body)) {
|
|
41
|
-
const [_body, isJsonfiable] = FormDataPlus.json(body, { recursive: true, getIsJsonfiable: true });
|
|
42
|
-
if (isJsonfiable) {
|
|
43
|
-
|
|
44
|
-
body = JSON.stringify(body, (k, v) => v instanceof Error ? { ...v, message: v.message } : v);
|
|
45
|
-
headers['content-type'] = 'application/json';
|
|
46
|
-
headers['content-length'] = (new Blob([body])).size;
|
|
47
|
-
|
|
48
|
-
} else {
|
|
49
|
-
body = _body;
|
|
50
|
-
type = 'FormData';
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// JSON strings
|
|
55
|
-
else if (type === 'json' && !headers['content-length']) {
|
|
56
|
-
headers['content-length'] = (body + '').length;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Return canonical init object with type info
|
|
60
|
-
return { body, headers, $type: type };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async parse({ to = null, memoize = false } = {}) {
|
|
64
|
-
const cache = _meta(this, 'cache');
|
|
65
|
-
const toOther = ['text', 'arrayBuffer', 'blob', 'bytes'].includes(to);
|
|
66
|
-
|
|
67
|
-
const contentType = (this.headers.get('Content-Type') || '').split(';')[0].trim();
|
|
68
|
-
let result;
|
|
69
|
-
|
|
70
|
-
const throw_cantConvert = () => {
|
|
71
|
-
throw new Error(`Can't convert response of type ${contentType} to: ${to}`);
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
if (!toOther
|
|
75
|
-
&& ['multipart/form-data', 'application/x-www-form-urlencoded'].includes(contentType)) {
|
|
76
|
-
if (to && !['formData', 'json'].includes(to)) throw_cantConvert();
|
|
77
|
-
|
|
78
|
-
if (memoize && cache.has(to || 'formData')) {
|
|
79
|
-
return cache.get(to || 'formData');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
let fd = await this.formData();
|
|
83
|
-
if (fd) {
|
|
84
|
-
fd = FormDataPlus.upgradeInPlace(fd);
|
|
85
|
-
if (memoize) cache.set('formData', fd);
|
|
86
|
-
|
|
87
|
-
if (to === 'json') {
|
|
88
|
-
fd = await fd.json({ recursive: true });
|
|
89
|
-
if (memoize) cache.set('json', { ...fd });
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
result = fd;
|
|
94
|
-
} else if (!toOther
|
|
95
|
-
&& contentType === 'application/json') {
|
|
96
|
-
if (to && !['json', 'formData'].includes(to)) throw_cantConvert();
|
|
97
|
-
|
|
98
|
-
if (memoize && cache.has(to || 'json')) {
|
|
99
|
-
return cache.get(to || 'json');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
let json = await this.json();
|
|
103
|
-
if (json) {
|
|
104
|
-
if (memoize) cache.set('json', { ...json });
|
|
105
|
-
|
|
106
|
-
if (to === 'formData') {
|
|
107
|
-
json = FormDataPlus.json(json, { recursive: true });
|
|
108
|
-
if (memoize) cache.set('formData', json);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
result = json;
|
|
113
|
-
} else /*if (contentType === 'text/plain')*/ {
|
|
114
|
-
if (to && !toOther) throw_cantConvert();
|
|
115
|
-
|
|
116
|
-
if (memoize) {
|
|
117
|
-
const result = cache.get(to || 'text') || cache.get('original');
|
|
118
|
-
if (result) return result;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
result = await this[to || 'text']();
|
|
122
|
-
|
|
123
|
-
if (memoize) cache.set(to || 'text', result);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return result;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ------ Util
|
|
132
|
-
|
|
133
|
-
export function dataType(value) {
|
|
134
|
-
if (value instanceof FormData) {
|
|
135
|
-
return 'FormData';
|
|
136
|
-
}
|
|
137
|
-
if (value === null || _isNumber(value) || _isBoolean(value)) {
|
|
138
|
-
return 'json';
|
|
139
|
-
}
|
|
140
|
-
if (_isString(value)
|
|
141
|
-
|| _isTypeObject(value) && 'toString' in value) {
|
|
142
|
-
return 'text';
|
|
143
|
-
}
|
|
144
|
-
if (!_isTypeObject(value)) return null;
|
|
145
|
-
|
|
146
|
-
const toStringTag = value[Symbol.toStringTag];
|
|
147
|
-
const type = [
|
|
148
|
-
'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer', 'Blob', 'File', 'FormData', 'Stream', 'ReadableStream'
|
|
149
|
-
].reduce((_toStringTag, type) => _toStringTag || (toStringTag === type ? type : null), null);
|
|
150
|
-
|
|
151
|
-
if (type) return type;
|
|
152
|
-
|
|
153
|
-
if ((_isObject(value)) || Array.isArray(value)) {
|
|
154
|
-
return 'json';
|
|
155
|
-
}
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function isTypeReadable(obj) {
|
|
160
|
-
return (
|
|
161
|
-
obj !== null &&
|
|
162
|
-
typeof obj === 'object' &&
|
|
163
|
-
typeof obj.read === 'function' && // streams have .read()
|
|
164
|
-
typeof obj.pipe === 'function' && // streams have .pipe()
|
|
165
|
-
typeof obj.on === 'function' // streams have event listeners
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export function isTypeStream(obj) {
|
|
170
|
-
return obj instanceof ReadableStream
|
|
171
|
-
|| isTypeReadable(obj);
|
|
172
|
-
}
|
package/test/basic.test.js
DELETED
|
File without changes
|