@api-client/core 0.6.1 → 0.6.4
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/build/browser.d.ts +1 -2
- package/build/browser.js +0 -1
- package/build/browser.js.map +1 -1
- package/build/index.d.ts +1 -2
- package/build/index.js +0 -1
- package/build/index.js.map +1 -1
- package/build/src/lib/transformers/PayloadSerializer.d.ts +85 -16
- package/build/src/lib/transformers/PayloadSerializer.js +171 -61
- package/build/src/lib/transformers/PayloadSerializer.js.map +1 -1
- package/build/src/mocking/lib/Request.js +1 -1
- package/build/src/mocking/lib/Request.js.map +1 -1
- package/build/src/mocking/lib/Response.js +4 -1
- package/build/src/mocking/lib/Response.js.map +1 -1
- package/build/src/models/RequestUiMeta.d.ts +2 -2
- package/build/src/runtime/http-engine/CoreEngine.js +3 -6
- package/build/src/runtime/http-engine/CoreEngine.js.map +1 -1
- package/build/src/runtime/http-engine/FormData.d.ts +36 -2
- package/build/src/runtime/http-engine/FormData.js +156 -55
- package/build/src/runtime/http-engine/FormData.js.map +1 -1
- package/build/src/runtime/http-engine/PayloadSupport.d.ts +4 -5
- package/build/src/runtime/http-engine/PayloadSupport.js +19 -12
- package/build/src/runtime/http-engine/PayloadSupport.js.map +1 -1
- package/package.json +3 -5
- package/src/lib/transformers/PayloadSerializer.ts +216 -70
- package/src/mocking/lib/Request.ts +1 -1
- package/src/mocking/lib/Response.ts +4 -1
- package/src/models/RequestUiMeta.ts +2 -2
- package/src/runtime/http-engine/CoreEngine.ts +3 -6
- package/src/runtime/http-engine/FormData.ts +184 -63
- package/src/runtime/http-engine/PayloadSupport.ts +23 -15
- package/build/src/lib/transformers/Utils.d.ts +0 -7
- package/build/src/lib/transformers/Utils.js +0 -19
- package/build/src/lib/transformers/Utils.js.map +0 -1
- package/src/lib/transformers/Utils.ts +0 -18
|
@@ -6,9 +6,8 @@ import { PayloadSerializer } from '../../lib/transformers/PayloadSerializer.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export class PayloadSupport {
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* https://
|
|
11
|
-
* platform/text/LineEnding.cpp&rcl=1458041387&l=101
|
|
9
|
+
* Normalizes line endings to CRLF
|
|
10
|
+
* https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/wtf/text/line_ending.cc;l=68
|
|
12
11
|
*
|
|
13
12
|
* @param string A string to be normalized.
|
|
14
13
|
* @return normalized string
|
|
@@ -40,26 +39,34 @@ export class PayloadSupport {
|
|
|
40
39
|
/**
|
|
41
40
|
* Transforms the request payload into a `Buffer`
|
|
42
41
|
*
|
|
43
|
-
* @param payload A payload message
|
|
44
42
|
* @param headers A headers object where to append headers when needed
|
|
43
|
+
* @param payload A payload message
|
|
45
44
|
* @returns A promise resolved to a `Buffer`.
|
|
46
45
|
*/
|
|
47
|
-
static
|
|
46
|
+
static payloadToBuffer(headers, payload) {
|
|
48
47
|
if (!payload) {
|
|
49
|
-
return;
|
|
48
|
+
return undefined;
|
|
50
49
|
}
|
|
51
50
|
if (typeof payload === 'string') {
|
|
52
51
|
payload = PayloadSupport.normalizeString(payload);
|
|
53
52
|
return Buffer.from(payload, 'utf8');
|
|
54
53
|
}
|
|
55
54
|
if (payload.type === 'string') {
|
|
56
|
-
return PayloadSupport.payloadToBuffer(payload.data
|
|
55
|
+
return PayloadSupport.payloadToBuffer(headers, payload.data);
|
|
56
|
+
}
|
|
57
|
+
if (payload.type === 'file') {
|
|
58
|
+
const meta = payload.meta;
|
|
59
|
+
if (!headers.has('content-type') && meta.mime) {
|
|
60
|
+
headers.set('content-type', meta.mime);
|
|
61
|
+
}
|
|
62
|
+
return PayloadSerializer.deserializeFileBuffer(payload);
|
|
57
63
|
}
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
if (payload.type === 'blob') {
|
|
65
|
+
const meta = payload.meta;
|
|
66
|
+
if (!headers.has('content-type') && meta.mime) {
|
|
67
|
+
headers.set('content-type', meta.mime);
|
|
61
68
|
}
|
|
62
|
-
return PayloadSerializer.deserializeBlobBuffer(payload
|
|
69
|
+
return PayloadSerializer.deserializeBlobBuffer(payload);
|
|
63
70
|
}
|
|
64
71
|
if (payload.type === 'buffer') {
|
|
65
72
|
return PayloadSerializer.deserializeBuffer(payload.data);
|
|
@@ -68,7 +75,7 @@ export class PayloadSupport {
|
|
|
68
75
|
return PayloadSerializer.deserializeArrayBufferBuffer(payload.data);
|
|
69
76
|
}
|
|
70
77
|
if (payload.type === 'formdata') {
|
|
71
|
-
const result =
|
|
78
|
+
const result = formDataConverter(payload.data);
|
|
72
79
|
headers.set('Content-Type', result.type);
|
|
73
80
|
return result.buffer;
|
|
74
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PayloadSupport.js","sourceRoot":"","sources":["../../../../src/runtime/http-engine/PayloadSupport.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAW,iBAAiB,
|
|
1
|
+
{"version":3,"file":"PayloadSupport.js","sourceRoot":"","sources":["../../../../src/runtime/http-engine/PayloadSupport.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@api-client/core",
|
|
3
3
|
"description": "The API Client's core client library. Works in NodeJS and in a ES enabled browser.",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.4",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"module": "build/index.js",
|
|
@@ -55,7 +55,6 @@
|
|
|
55
55
|
"lint-staged": "^12.3.4",
|
|
56
56
|
"mocha": "^9.1.3",
|
|
57
57
|
"oauth2-mock-server": "^4.3.1",
|
|
58
|
-
"shrink-ray-current": "^4.1.3",
|
|
59
58
|
"sinon": "^13.0.1",
|
|
60
59
|
"source-map-support": "^0.5.21",
|
|
61
60
|
"ssl-root-cas": "^1.3.1",
|
|
@@ -70,8 +69,8 @@
|
|
|
70
69
|
"tsc:watch": "tsc --watch",
|
|
71
70
|
"test:browser": "wtr --playwright --browsers chromium firefox webkit --coverage",
|
|
72
71
|
"test:browser:watch": "wtr --watch --playwright --browsers chromium",
|
|
73
|
-
"test:
|
|
74
|
-
"test": "npm run test:
|
|
72
|
+
"test:node": "npm run build-ts && mocha",
|
|
73
|
+
"test": "npm run test:node && npm run test:browser"
|
|
75
74
|
},
|
|
76
75
|
"husky": {
|
|
77
76
|
"hooks": {
|
|
@@ -90,7 +89,6 @@
|
|
|
90
89
|
"@pawel-up/jexl": "^3.0.0",
|
|
91
90
|
"@xmldom/xmldom": "^0.8.2",
|
|
92
91
|
"console-table-printer": "^2.11.0",
|
|
93
|
-
"form-data": "^4.0.0",
|
|
94
92
|
"ws": "^8.5.0",
|
|
95
93
|
"xpath": "^0.0.32"
|
|
96
94
|
},
|
|
@@ -1,35 +1,58 @@
|
|
|
1
|
-
import { blobToDataUrl } from './Utils.js';
|
|
2
|
-
|
|
3
1
|
export type PayloadTypes = 'string' | 'file' | 'blob' | 'buffer' | 'arraybuffer' | 'formdata' | 'x-www-form-urlencoded';
|
|
4
2
|
export type DeserializedPayload = string | Blob | File | FormData | Buffer | ArrayBuffer | undefined;
|
|
5
3
|
export const SupportedPayloadTypes: PayloadTypes[] = ['string', 'file', 'blob', 'buffer', 'arraybuffer', 'formdata', 'x-www-form-urlencoded'];
|
|
6
4
|
|
|
7
5
|
export interface IMultipartBody {
|
|
8
6
|
/**
|
|
9
|
-
*
|
|
7
|
+
* Whether the parameter is enabled. Default to true.
|
|
10
8
|
*/
|
|
11
|
-
|
|
9
|
+
enabled?: boolean;
|
|
12
10
|
/**
|
|
13
11
|
* The name of the filed
|
|
14
12
|
*/
|
|
15
13
|
name: string;
|
|
16
14
|
/**
|
|
17
|
-
* Converted value
|
|
15
|
+
* Converted value.
|
|
16
|
+
* When the part value was a string this is a string.
|
|
17
|
+
* When the previous value was a Blob or a Buffer, this will be a serialized payload.
|
|
18
|
+
*/
|
|
19
|
+
value: string | ISafePayload;
|
|
20
|
+
/**
|
|
21
|
+
* Aside from the `value` which is used to process the Payload, the purpose of this field to to keep
|
|
22
|
+
* the entered by the user string value for the "blob" item. This is primarily handled by the UI
|
|
23
|
+
* and ignored by the HTTP Engine.
|
|
24
|
+
*/
|
|
25
|
+
blobText?: string;
|
|
26
|
+
/**
|
|
27
|
+
* When `true` this entry represent a file part
|
|
28
|
+
* @deprecated This is only used for the compatibility with ARC. This information is encoded in the `value`.
|
|
18
29
|
*/
|
|
19
|
-
|
|
30
|
+
isFile?: boolean;
|
|
20
31
|
/**
|
|
21
32
|
* A content type entered by the user to the text part of the text part input.
|
|
22
33
|
* This can only be set when `isFile` is false.
|
|
34
|
+
* @deprecated This is only used for the compatibility with ARC. This information is encoded in the `value`.
|
|
23
35
|
*/
|
|
24
36
|
type?: string;
|
|
25
37
|
/**
|
|
26
38
|
* The original file name used with the part
|
|
39
|
+
* @deprecated This is only used for the compatibility with ARC. This information is encoded in the `value`.
|
|
27
40
|
*/
|
|
28
41
|
fileName?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface IBlobMeta {
|
|
29
45
|
/**
|
|
30
|
-
*
|
|
46
|
+
* The blob's mime type.
|
|
31
47
|
*/
|
|
32
|
-
|
|
48
|
+
mime: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface IFileMeta extends IBlobMeta {
|
|
52
|
+
/**
|
|
53
|
+
* The file name.
|
|
54
|
+
*/
|
|
55
|
+
name: string;
|
|
33
56
|
}
|
|
34
57
|
|
|
35
58
|
/**
|
|
@@ -43,13 +66,17 @@ export interface ISafePayload {
|
|
|
43
66
|
* The type od the originating payload object.
|
|
44
67
|
*/
|
|
45
68
|
type: PayloadTypes;
|
|
69
|
+
/**
|
|
70
|
+
* The payload contents. The data type depends on the `type`.
|
|
71
|
+
*/
|
|
46
72
|
data: string | number[] | IMultipartBody[];
|
|
47
73
|
/**
|
|
48
74
|
* Optionally the original mime type of the payload.
|
|
49
75
|
* This is used with files.
|
|
50
76
|
*/
|
|
51
|
-
|
|
77
|
+
meta?: IBlobMeta | IFileMeta;
|
|
52
78
|
}
|
|
79
|
+
|
|
53
80
|
/**
|
|
54
81
|
* The request payload. When not a string then it has to go through a
|
|
55
82
|
* transformation from a store safe object to the original data object.
|
|
@@ -84,6 +111,17 @@ export class PayloadSerializer {
|
|
|
84
111
|
return false;
|
|
85
112
|
}
|
|
86
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Tests whether the given input should be processed by the `serialize()`.
|
|
116
|
+
*/
|
|
117
|
+
static needsSerialization(input: unknown): boolean {
|
|
118
|
+
const typedSerialized = input as ISafePayload;
|
|
119
|
+
if (typedSerialized.type && SupportedPayloadTypes.includes(typedSerialized.type)) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
87
125
|
/**
|
|
88
126
|
* Transforms the payload into a data store safe object.
|
|
89
127
|
*/
|
|
@@ -100,6 +138,10 @@ export class PayloadSerializer {
|
|
|
100
138
|
// if (typeof payload === 'string') {
|
|
101
139
|
// return payload;
|
|
102
140
|
// }
|
|
141
|
+
|
|
142
|
+
if (hasBlob && payload instanceof File) {
|
|
143
|
+
return PayloadSerializer.stringifyFile(payload);
|
|
144
|
+
}
|
|
103
145
|
if (hasBlob && payload instanceof Blob) {
|
|
104
146
|
return PayloadSerializer.stringifyBlob(payload);
|
|
105
147
|
}
|
|
@@ -111,7 +153,7 @@ export class PayloadSerializer {
|
|
|
111
153
|
}
|
|
112
154
|
if (hasFormData && payload instanceof FormData) {
|
|
113
155
|
try {
|
|
114
|
-
const result = await PayloadSerializer.stringifyFormData(
|
|
156
|
+
const result = await PayloadSerializer.stringifyFormData(payload);
|
|
115
157
|
return result;
|
|
116
158
|
} catch (e: unknown) {
|
|
117
159
|
console.warn(`Unable to transform FormData: ${(e as Error).message}`);
|
|
@@ -121,18 +163,38 @@ export class PayloadSerializer {
|
|
|
121
163
|
}
|
|
122
164
|
|
|
123
165
|
/**
|
|
124
|
-
*
|
|
166
|
+
* Stringifies a file object.
|
|
167
|
+
*/
|
|
168
|
+
static async stringifyFile(file: File): Promise<ISafePayload> {
|
|
169
|
+
const buffer = await file.arrayBuffer();
|
|
170
|
+
const view = new Uint8Array(buffer);
|
|
171
|
+
const meta: IFileMeta = {
|
|
172
|
+
mime: file.type,
|
|
173
|
+
name: file.name,
|
|
174
|
+
};
|
|
175
|
+
const result: ISafePayload = {
|
|
176
|
+
type: 'file',
|
|
177
|
+
data: [...view],
|
|
178
|
+
meta,
|
|
179
|
+
};
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Stringifies a blob object.
|
|
125
185
|
*
|
|
126
|
-
* @param blob
|
|
127
|
-
* @return Promise resolved to a base64 string data from the file.
|
|
186
|
+
* @param blob Blob object to be translated to string
|
|
128
187
|
*/
|
|
129
188
|
static async stringifyBlob(blob: Blob): Promise<ISafePayload> {
|
|
130
|
-
const
|
|
131
|
-
const
|
|
189
|
+
const buffer = await blob.arrayBuffer();
|
|
190
|
+
const view = new Uint8Array(buffer);
|
|
191
|
+
const meta: IBlobMeta = {
|
|
192
|
+
mime: blob.type,
|
|
193
|
+
};
|
|
132
194
|
const result: ISafePayload = {
|
|
133
195
|
type: 'blob',
|
|
134
|
-
data,
|
|
135
|
-
|
|
196
|
+
data: [...view],
|
|
197
|
+
meta,
|
|
136
198
|
};
|
|
137
199
|
return result;
|
|
138
200
|
}
|
|
@@ -160,14 +222,11 @@ export class PayloadSerializer {
|
|
|
160
222
|
* @returns The buffer metadata or undefined if the passed argument is not an ArrayBuffer.
|
|
161
223
|
*/
|
|
162
224
|
static stringifyArrayBuffer(payload: ArrayBuffer): ISafePayload | undefined {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
return undefined;
|
|
225
|
+
const view = new Uint8Array(payload);
|
|
226
|
+
return {
|
|
227
|
+
type: 'arraybuffer',
|
|
228
|
+
data: Array.from(view),
|
|
229
|
+
};
|
|
171
230
|
}
|
|
172
231
|
|
|
173
232
|
/**
|
|
@@ -176,9 +235,11 @@ export class PayloadSerializer {
|
|
|
176
235
|
* @param payload A `FormData` object
|
|
177
236
|
* @return A promise resolved to a datastore safe entries.
|
|
178
237
|
*/
|
|
179
|
-
static async stringifyFormData(payload:
|
|
238
|
+
static async stringifyFormData(payload: FormData): Promise<ISafePayload> {
|
|
239
|
+
// TS apparently doesn't know that FormData is iterable.
|
|
240
|
+
const iterable = (payload as unknown) as Iterable<(string | File)[]>;
|
|
180
241
|
const promises: Promise<IMultipartBody>[] = [];
|
|
181
|
-
for (const part of
|
|
242
|
+
for (const part of iterable) {
|
|
182
243
|
promises.push(PayloadSerializer.serializeFormDataEntry(part[0] as string, part[1]));
|
|
183
244
|
}
|
|
184
245
|
const items = await Promise.all(promises);
|
|
@@ -195,33 +256,27 @@ export class PayloadSerializer {
|
|
|
195
256
|
* @param file The part value
|
|
196
257
|
* @returns Transformed FormData part to a datastore safe entry.
|
|
197
258
|
*/
|
|
198
|
-
static async serializeFormDataEntry(name: string, file: string | File): Promise<IMultipartBody> {
|
|
259
|
+
static async serializeFormDataEntry(name: string, file: string | File | Blob): Promise<IMultipartBody> {
|
|
199
260
|
if (typeof file === 'string') {
|
|
200
|
-
// when adding an item to the FormData object without 3rd parameter of the append function
|
|
201
|
-
// then the value is a string.
|
|
202
261
|
return {
|
|
203
|
-
isFile: false,
|
|
204
262
|
name,
|
|
205
263
|
value: file,
|
|
206
264
|
enabled: true,
|
|
207
265
|
};
|
|
208
266
|
}
|
|
209
|
-
|
|
210
|
-
|
|
267
|
+
let value: ISafePayload;
|
|
268
|
+
// API Client adds the "blob" when adding a text value with a mime type.
|
|
269
|
+
// This is recognized by the UI to restore the entry as the text and not a file.
|
|
270
|
+
if (file instanceof File && file.name !== 'blob') {
|
|
271
|
+
value = await PayloadSerializer.stringifyFile(file);
|
|
272
|
+
} else {
|
|
273
|
+
value = await PayloadSerializer.stringifyBlob(file);
|
|
274
|
+
}
|
|
211
275
|
const part: IMultipartBody = {
|
|
212
|
-
isFile: false,
|
|
213
276
|
name,
|
|
214
277
|
value,
|
|
215
278
|
enabled: true,
|
|
216
279
|
};
|
|
217
|
-
if (file.name === 'blob') {
|
|
218
|
-
// API Client adds the "blob" filename when the content type is set on the editor.
|
|
219
|
-
// otherwise it wouldn't be possible to set the content type value.
|
|
220
|
-
part.type = file.type;
|
|
221
|
-
} else {
|
|
222
|
-
part.isFile = true;
|
|
223
|
-
part.fileName = file.name;
|
|
224
|
-
}
|
|
225
280
|
return part;
|
|
226
281
|
}
|
|
227
282
|
|
|
@@ -240,8 +295,8 @@ export class PayloadSerializer {
|
|
|
240
295
|
// We mostly gonna return a Buffer here.
|
|
241
296
|
switch (payload.type) {
|
|
242
297
|
case 'string': return payload.data as string;
|
|
243
|
-
case 'file':
|
|
244
|
-
case 'blob': return PayloadSerializer.deserializeBlobBuffer(payload
|
|
298
|
+
case 'file': return PayloadSerializer.deserializeFileBuffer(payload);
|
|
299
|
+
case 'blob': return PayloadSerializer.deserializeBlobBuffer(payload);
|
|
245
300
|
case 'buffer': return PayloadSerializer.deserializeBuffer(payload.data as number[]);
|
|
246
301
|
case 'arraybuffer': return PayloadSerializer.deserializeArrayBufferBuffer(payload.data as number[]);
|
|
247
302
|
case 'formdata': return undefined;
|
|
@@ -250,9 +305,9 @@ export class PayloadSerializer {
|
|
|
250
305
|
}
|
|
251
306
|
switch (payload.type) {
|
|
252
307
|
case 'string': return payload.data as string;
|
|
253
|
-
case 'file':
|
|
254
|
-
case 'blob': return PayloadSerializer.deserializeBlob(payload
|
|
255
|
-
case 'buffer': return PayloadSerializer.
|
|
308
|
+
case 'file': return PayloadSerializer.deserializeFile(payload);
|
|
309
|
+
case 'blob': return PayloadSerializer.deserializeBlob(payload);
|
|
310
|
+
case 'buffer': return PayloadSerializer.deserializeArrayBuffer(payload.data as number[]);
|
|
256
311
|
case 'arraybuffer': return PayloadSerializer.deserializeArrayBuffer(payload.data as number[]);
|
|
257
312
|
case 'formdata': return PayloadSerializer.deserializeFormData(payload.data as IMultipartBody[]);
|
|
258
313
|
default: return undefined;
|
|
@@ -260,12 +315,47 @@ export class PayloadSerializer {
|
|
|
260
315
|
}
|
|
261
316
|
|
|
262
317
|
/**
|
|
263
|
-
*
|
|
318
|
+
* Deserializes previously serialized file object.
|
|
319
|
+
*
|
|
320
|
+
* @param payload The serialized payload with a file.
|
|
321
|
+
*/
|
|
322
|
+
static deserializeFile(payload: ISafePayload): File {
|
|
323
|
+
const data = payload.data as number[];
|
|
324
|
+
const meta = payload.meta as IFileMeta;
|
|
325
|
+
const { mime, name } = meta;
|
|
326
|
+
const { buffer } = new Uint8Array(data);
|
|
327
|
+
return new File([buffer], name, {
|
|
328
|
+
type: mime,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Deserializes previously serialized blob object.
|
|
334
|
+
*
|
|
335
|
+
* In previous versions of ARC the data was a string as data URL. In API client this is a buffer.
|
|
264
336
|
*
|
|
337
|
+
* @param payload The serialized payload.
|
|
338
|
+
* @return Restored blob value
|
|
339
|
+
*/
|
|
340
|
+
static deserializeBlob(payload: ISafePayload): Blob | undefined {
|
|
341
|
+
if (typeof payload.data === 'string') {
|
|
342
|
+
return this.deserializeBlobLegacy(payload.data);
|
|
343
|
+
}
|
|
344
|
+
const data = payload.data as number[];
|
|
345
|
+
const meta = payload.meta as IBlobMeta;
|
|
346
|
+
const { mime } = meta;
|
|
347
|
+
const { buffer } = new Uint8Array(data);
|
|
348
|
+
return new Blob([buffer], { type: mime });
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* The old implementation of the blob deserializer.
|
|
353
|
+
*
|
|
354
|
+
* @deprecated
|
|
265
355
|
* @param dataUrl Data url from blob value.
|
|
266
356
|
* @return Restored blob value
|
|
267
357
|
*/
|
|
268
|
-
static
|
|
358
|
+
static deserializeBlobLegacy(dataUrl: string): Blob | undefined {
|
|
269
359
|
const arr = dataUrl.split(',');
|
|
270
360
|
const matchedMime = arr[0].match(/:(.*?);/);
|
|
271
361
|
if (!matchedMime) {
|
|
@@ -282,12 +372,40 @@ export class PayloadSerializer {
|
|
|
282
372
|
}
|
|
283
373
|
|
|
284
374
|
/**
|
|
285
|
-
* Converts
|
|
375
|
+
* Converts previously serialized File to a Buffer.
|
|
376
|
+
*
|
|
377
|
+
* @param payload The serialized payload.
|
|
378
|
+
* @return Restored File value as Buffer
|
|
379
|
+
*/
|
|
380
|
+
static deserializeFileBuffer(payload: ISafePayload): Buffer {
|
|
381
|
+
const data = payload.data as number[];
|
|
382
|
+
const ab = this.deserializeArrayBuffer(data);
|
|
383
|
+
return Buffer.from(ab);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Converts data-url string to buffer
|
|
286
388
|
*
|
|
389
|
+
* @param payload The serialized payload.
|
|
390
|
+
* @return Restored blob value
|
|
391
|
+
*/
|
|
392
|
+
static deserializeBlobBuffer(payload: ISafePayload): Buffer {
|
|
393
|
+
if (typeof payload.data === 'string') {
|
|
394
|
+
return this.deserializeBlobBufferLegacy(payload.data);
|
|
395
|
+
}
|
|
396
|
+
const data = payload.data as number[];
|
|
397
|
+
const ab = this.deserializeArrayBuffer(data);
|
|
398
|
+
return Buffer.from(ab);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Converts data-url string to buffer
|
|
403
|
+
*
|
|
404
|
+
* @deprecated
|
|
287
405
|
* @param dataUrl Data url from blob value.
|
|
288
406
|
* @return Restored blob value
|
|
289
407
|
*/
|
|
290
|
-
static
|
|
408
|
+
static deserializeBlobBufferLegacy(dataUrl: string): Buffer {
|
|
291
409
|
const arr = dataUrl.split(',');
|
|
292
410
|
const value = arr[1];
|
|
293
411
|
return Buffer.from(value, 'base64url');
|
|
@@ -334,26 +452,54 @@ export class PayloadSerializer {
|
|
|
334
452
|
if (!Array.isArray(parts) || !parts.length) {
|
|
335
453
|
return fd;
|
|
336
454
|
}
|
|
337
|
-
parts.forEach(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
455
|
+
parts.forEach(part => this.deserializeFormDataPart(fd, part));
|
|
456
|
+
return fd;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private static deserializeFormDataPart(form: FormData, part: IMultipartBody): void {
|
|
460
|
+
if (part.enabled === false) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
// the compatibility with old ARC.
|
|
464
|
+
if (typeof part.isFile === 'boolean') {
|
|
465
|
+
this.deserializeFormDataLegacy(form, part);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const { name, value } = part;
|
|
469
|
+
if (typeof value === 'string') {
|
|
470
|
+
form.append(name, value);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (value.type === 'string') {
|
|
474
|
+
form.append(name, value.data as string);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
if (value.type === 'file') {
|
|
478
|
+
const file = this.deserializeFile(value);
|
|
479
|
+
form.append(name, file);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const blob = this.deserializeBlob(value) as Blob;
|
|
483
|
+
form.append(name, blob);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* @deprecated This is only for compatibility with ARC.
|
|
488
|
+
*/
|
|
489
|
+
private static deserializeFormDataLegacy(form: FormData, part: IMultipartBody): void {
|
|
490
|
+
let blob;
|
|
491
|
+
if (part.isFile) {
|
|
492
|
+
blob = PayloadSerializer.deserializeBlobLegacy(part.value as string);
|
|
493
|
+
if (blob) {
|
|
494
|
+
form.append(part.name, blob, part.fileName);
|
|
341
495
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
fd.append(name, blob, fileName);
|
|
347
|
-
}
|
|
348
|
-
} else if (type) {
|
|
349
|
-
blob = PayloadSerializer.deserializeBlob(value);
|
|
350
|
-
if (blob) {
|
|
351
|
-
fd.append(name, blob, 'blob');
|
|
352
|
-
}
|
|
353
|
-
} else {
|
|
354
|
-
fd.append(name, value);
|
|
496
|
+
} else if (part.type) {
|
|
497
|
+
blob = PayloadSerializer.deserializeBlobLegacy(part.value as string);
|
|
498
|
+
if (blob) {
|
|
499
|
+
form.append(part.name, blob, 'blob');
|
|
355
500
|
}
|
|
356
|
-
}
|
|
357
|
-
|
|
501
|
+
} else {
|
|
502
|
+
form.append(part.name, part.value as string);
|
|
503
|
+
}
|
|
358
504
|
}
|
|
359
505
|
}
|
|
@@ -83,7 +83,7 @@ export class Request {
|
|
|
83
83
|
result.response = await this.response.response(init.response);
|
|
84
84
|
}
|
|
85
85
|
if (init.redirects) {
|
|
86
|
-
result.redirects = await this.response.redirects();
|
|
86
|
+
result.redirects = await this.response.redirects(undefined, init.response);
|
|
87
87
|
}
|
|
88
88
|
if (!init.noSize) {
|
|
89
89
|
result.size = this.response.size();
|
|
@@ -87,7 +87,7 @@ export class Response {
|
|
|
87
87
|
return result;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
async redirect(init
|
|
90
|
+
async redirect(init: IResponseInit = {}): Promise<IResponseRedirect> {
|
|
91
91
|
const start = this.time.timestamp();
|
|
92
92
|
const end = this.time.timestamp({ min: start + 1 })
|
|
93
93
|
const info: IResponseRedirect = {
|
|
@@ -97,6 +97,9 @@ export class Response {
|
|
|
97
97
|
url: this.internet.uri(),
|
|
98
98
|
response: await this.httpResponse({ ...init, statusGroup: 3}),
|
|
99
99
|
};
|
|
100
|
+
if (init.timings) {
|
|
101
|
+
info.timings = this.har.timing(init);
|
|
102
|
+
}
|
|
100
103
|
return info;
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IProperty, Property } from './Property.js';
|
|
2
|
-
import { IMultipartBody } from '../lib/transformers/PayloadSerializer.js';
|
|
2
|
+
import { IMultipartBody, ISafePayload } from '../lib/transformers/PayloadSerializer.js';
|
|
3
3
|
import { RequestUiMeta as LegacyRequestUiMeta } from './legacy/request/ArcRequest.js';
|
|
4
4
|
|
|
5
5
|
export const Kind = 'Core#RequestUiMeta';
|
|
@@ -70,7 +70,7 @@ export interface IBodyMetaModel {
|
|
|
70
70
|
/**
|
|
71
71
|
* Generated view model.
|
|
72
72
|
*/
|
|
73
|
-
viewModel: (IProperty | IMultipartBody | IRawBody)[];
|
|
73
|
+
viewModel: (IProperty | ISafePayload | IMultipartBody | IRawBody)[];
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/**
|
|
@@ -134,12 +134,9 @@ export class CoreEngine extends HttpEngine {
|
|
|
134
134
|
if (auth) {
|
|
135
135
|
headers.set('proxy-authorization', auth);
|
|
136
136
|
}
|
|
137
|
-
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
if (buffer) {
|
|
141
|
-
addContentLength(this.request.method || 'GET', buffer, headers);
|
|
142
|
-
}
|
|
137
|
+
const buffer = PayloadSupport.payloadToBuffer(headers, payload);
|
|
138
|
+
if (buffer) {
|
|
139
|
+
addContentLength(this.request.method || 'GET', buffer, headers);
|
|
143
140
|
}
|
|
144
141
|
|
|
145
142
|
this._handleAuthorization(headers);
|