@api-client/core 0.6.2 → 0.6.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/build/browser.d.ts +0 -1
- package/build/browser.js +0 -1
- package/build/browser.js.map +1 -1
- package/build/index.d.ts +0 -1
- package/build/index.js +0 -1
- package/build/index.js.map +1 -1
- package/build/src/lib/transformers/PayloadSerializer.d.ts +79 -16
- package/build/src/lib/transformers/PayloadSerializer.js +167 -61
- package/build/src/lib/transformers/PayloadSerializer.js.map +1 -1
- 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 +1 -3
- package/src/lib/transformers/PayloadSerializer.ts +206 -70
- 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
|
@@ -1,35 +1,52 @@
|
|
|
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
18
|
*/
|
|
19
|
-
value: string;
|
|
19
|
+
value: string | ISafePayload;
|
|
20
|
+
/**
|
|
21
|
+
* When `true` this entry represent a file part
|
|
22
|
+
* @deprecated This is only used for the compatibility with ARC. This information is encoded in the `value`.
|
|
23
|
+
*/
|
|
24
|
+
isFile?: boolean;
|
|
20
25
|
/**
|
|
21
26
|
* A content type entered by the user to the text part of the text part input.
|
|
22
27
|
* This can only be set when `isFile` is false.
|
|
28
|
+
* @deprecated This is only used for the compatibility with ARC. This information is encoded in the `value`.
|
|
23
29
|
*/
|
|
24
30
|
type?: string;
|
|
25
31
|
/**
|
|
26
32
|
* The original file name used with the part
|
|
33
|
+
* @deprecated This is only used for the compatibility with ARC. This information is encoded in the `value`.
|
|
27
34
|
*/
|
|
28
35
|
fileName?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface IBlobMeta {
|
|
29
39
|
/**
|
|
30
|
-
*
|
|
40
|
+
* The blob's mime type.
|
|
31
41
|
*/
|
|
32
|
-
|
|
42
|
+
mime: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface IFileMeta extends IBlobMeta {
|
|
46
|
+
/**
|
|
47
|
+
* The file name.
|
|
48
|
+
*/
|
|
49
|
+
name: string;
|
|
33
50
|
}
|
|
34
51
|
|
|
35
52
|
/**
|
|
@@ -43,13 +60,17 @@ export interface ISafePayload {
|
|
|
43
60
|
* The type od the originating payload object.
|
|
44
61
|
*/
|
|
45
62
|
type: PayloadTypes;
|
|
63
|
+
/**
|
|
64
|
+
* The payload contents. The data type depends on the `type`.
|
|
65
|
+
*/
|
|
46
66
|
data: string | number[] | IMultipartBody[];
|
|
47
67
|
/**
|
|
48
68
|
* Optionally the original mime type of the payload.
|
|
49
69
|
* This is used with files.
|
|
50
70
|
*/
|
|
51
|
-
|
|
71
|
+
meta?: IBlobMeta | IFileMeta;
|
|
52
72
|
}
|
|
73
|
+
|
|
53
74
|
/**
|
|
54
75
|
* The request payload. When not a string then it has to go through a
|
|
55
76
|
* transformation from a store safe object to the original data object.
|
|
@@ -84,6 +105,17 @@ export class PayloadSerializer {
|
|
|
84
105
|
return false;
|
|
85
106
|
}
|
|
86
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Tests whether the given input should be processed by the `serialize()`.
|
|
110
|
+
*/
|
|
111
|
+
static needsSerialization(input: unknown): boolean {
|
|
112
|
+
const typedSerialized = input as ISafePayload;
|
|
113
|
+
if (typedSerialized.type && SupportedPayloadTypes.includes(typedSerialized.type)) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
87
119
|
/**
|
|
88
120
|
* Transforms the payload into a data store safe object.
|
|
89
121
|
*/
|
|
@@ -100,6 +132,10 @@ export class PayloadSerializer {
|
|
|
100
132
|
// if (typeof payload === 'string') {
|
|
101
133
|
// return payload;
|
|
102
134
|
// }
|
|
135
|
+
|
|
136
|
+
if (hasBlob && payload instanceof File) {
|
|
137
|
+
return PayloadSerializer.stringifyFile(payload);
|
|
138
|
+
}
|
|
103
139
|
if (hasBlob && payload instanceof Blob) {
|
|
104
140
|
return PayloadSerializer.stringifyBlob(payload);
|
|
105
141
|
}
|
|
@@ -111,7 +147,7 @@ export class PayloadSerializer {
|
|
|
111
147
|
}
|
|
112
148
|
if (hasFormData && payload instanceof FormData) {
|
|
113
149
|
try {
|
|
114
|
-
const result = await PayloadSerializer.stringifyFormData(
|
|
150
|
+
const result = await PayloadSerializer.stringifyFormData(payload);
|
|
115
151
|
return result;
|
|
116
152
|
} catch (e: unknown) {
|
|
117
153
|
console.warn(`Unable to transform FormData: ${(e as Error).message}`);
|
|
@@ -121,18 +157,38 @@ export class PayloadSerializer {
|
|
|
121
157
|
}
|
|
122
158
|
|
|
123
159
|
/**
|
|
124
|
-
*
|
|
160
|
+
* Stringifies a file object.
|
|
161
|
+
*/
|
|
162
|
+
static async stringifyFile(file: File): Promise<ISafePayload> {
|
|
163
|
+
const buffer = await file.arrayBuffer();
|
|
164
|
+
const view = new Uint8Array(buffer);
|
|
165
|
+
const meta: IFileMeta = {
|
|
166
|
+
mime: file.type,
|
|
167
|
+
name: file.name,
|
|
168
|
+
};
|
|
169
|
+
const result: ISafePayload = {
|
|
170
|
+
type: 'file',
|
|
171
|
+
data: [...view],
|
|
172
|
+
meta,
|
|
173
|
+
};
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Stringifies a blob object.
|
|
125
179
|
*
|
|
126
|
-
* @param blob
|
|
127
|
-
* @return Promise resolved to a base64 string data from the file.
|
|
180
|
+
* @param blob Blob object to be translated to string
|
|
128
181
|
*/
|
|
129
182
|
static async stringifyBlob(blob: Blob): Promise<ISafePayload> {
|
|
130
|
-
const
|
|
131
|
-
const
|
|
183
|
+
const buffer = await blob.arrayBuffer();
|
|
184
|
+
const view = new Uint8Array(buffer);
|
|
185
|
+
const meta: IBlobMeta = {
|
|
186
|
+
mime: blob.type,
|
|
187
|
+
};
|
|
132
188
|
const result: ISafePayload = {
|
|
133
189
|
type: 'blob',
|
|
134
|
-
data,
|
|
135
|
-
|
|
190
|
+
data: [...view],
|
|
191
|
+
meta,
|
|
136
192
|
};
|
|
137
193
|
return result;
|
|
138
194
|
}
|
|
@@ -160,14 +216,11 @@ export class PayloadSerializer {
|
|
|
160
216
|
* @returns The buffer metadata or undefined if the passed argument is not an ArrayBuffer.
|
|
161
217
|
*/
|
|
162
218
|
static stringifyArrayBuffer(payload: ArrayBuffer): ISafePayload | undefined {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
return undefined;
|
|
219
|
+
const view = new Uint8Array(payload);
|
|
220
|
+
return {
|
|
221
|
+
type: 'arraybuffer',
|
|
222
|
+
data: Array.from(view),
|
|
223
|
+
};
|
|
171
224
|
}
|
|
172
225
|
|
|
173
226
|
/**
|
|
@@ -176,9 +229,11 @@ export class PayloadSerializer {
|
|
|
176
229
|
* @param payload A `FormData` object
|
|
177
230
|
* @return A promise resolved to a datastore safe entries.
|
|
178
231
|
*/
|
|
179
|
-
static async stringifyFormData(payload:
|
|
232
|
+
static async stringifyFormData(payload: FormData): Promise<ISafePayload> {
|
|
233
|
+
// TS apparently doesn't know that FormData is iterable.
|
|
234
|
+
const iterable = (payload as unknown) as Iterable<(string | File)[]>;
|
|
180
235
|
const promises: Promise<IMultipartBody>[] = [];
|
|
181
|
-
for (const part of
|
|
236
|
+
for (const part of iterable) {
|
|
182
237
|
promises.push(PayloadSerializer.serializeFormDataEntry(part[0] as string, part[1]));
|
|
183
238
|
}
|
|
184
239
|
const items = await Promise.all(promises);
|
|
@@ -195,33 +250,27 @@ export class PayloadSerializer {
|
|
|
195
250
|
* @param file The part value
|
|
196
251
|
* @returns Transformed FormData part to a datastore safe entry.
|
|
197
252
|
*/
|
|
198
|
-
static async serializeFormDataEntry(name: string, file: string | File): Promise<IMultipartBody> {
|
|
253
|
+
static async serializeFormDataEntry(name: string, file: string | File | Blob): Promise<IMultipartBody> {
|
|
199
254
|
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
255
|
return {
|
|
203
|
-
isFile: false,
|
|
204
256
|
name,
|
|
205
257
|
value: file,
|
|
206
258
|
enabled: true,
|
|
207
259
|
};
|
|
208
260
|
}
|
|
209
|
-
|
|
210
|
-
|
|
261
|
+
let value: ISafePayload;
|
|
262
|
+
// API Client adds the "blob" when adding a text value with a mime type.
|
|
263
|
+
// This is recognized by the UI to restore the entry as the text and not a file.
|
|
264
|
+
if (file instanceof File && file.name !== 'blob') {
|
|
265
|
+
value = await PayloadSerializer.stringifyFile(file);
|
|
266
|
+
} else {
|
|
267
|
+
value = await PayloadSerializer.stringifyBlob(file);
|
|
268
|
+
}
|
|
211
269
|
const part: IMultipartBody = {
|
|
212
|
-
isFile: false,
|
|
213
270
|
name,
|
|
214
271
|
value,
|
|
215
272
|
enabled: true,
|
|
216
273
|
};
|
|
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
274
|
return part;
|
|
226
275
|
}
|
|
227
276
|
|
|
@@ -240,8 +289,8 @@ export class PayloadSerializer {
|
|
|
240
289
|
// We mostly gonna return a Buffer here.
|
|
241
290
|
switch (payload.type) {
|
|
242
291
|
case 'string': return payload.data as string;
|
|
243
|
-
case 'file':
|
|
244
|
-
case 'blob': return PayloadSerializer.deserializeBlobBuffer(payload
|
|
292
|
+
case 'file': return PayloadSerializer.deserializeFileBuffer(payload);
|
|
293
|
+
case 'blob': return PayloadSerializer.deserializeBlobBuffer(payload);
|
|
245
294
|
case 'buffer': return PayloadSerializer.deserializeBuffer(payload.data as number[]);
|
|
246
295
|
case 'arraybuffer': return PayloadSerializer.deserializeArrayBufferBuffer(payload.data as number[]);
|
|
247
296
|
case 'formdata': return undefined;
|
|
@@ -250,9 +299,9 @@ export class PayloadSerializer {
|
|
|
250
299
|
}
|
|
251
300
|
switch (payload.type) {
|
|
252
301
|
case 'string': return payload.data as string;
|
|
253
|
-
case 'file':
|
|
254
|
-
case 'blob': return PayloadSerializer.deserializeBlob(payload
|
|
255
|
-
case 'buffer': return PayloadSerializer.
|
|
302
|
+
case 'file': return PayloadSerializer.deserializeFile(payload);
|
|
303
|
+
case 'blob': return PayloadSerializer.deserializeBlob(payload);
|
|
304
|
+
case 'buffer': return PayloadSerializer.deserializeArrayBuffer(payload.data as number[]);
|
|
256
305
|
case 'arraybuffer': return PayloadSerializer.deserializeArrayBuffer(payload.data as number[]);
|
|
257
306
|
case 'formdata': return PayloadSerializer.deserializeFormData(payload.data as IMultipartBody[]);
|
|
258
307
|
default: return undefined;
|
|
@@ -260,12 +309,47 @@ export class PayloadSerializer {
|
|
|
260
309
|
}
|
|
261
310
|
|
|
262
311
|
/**
|
|
263
|
-
*
|
|
312
|
+
* Deserializes previously serialized file object.
|
|
313
|
+
*
|
|
314
|
+
* @param payload The serialized payload with a file.
|
|
315
|
+
*/
|
|
316
|
+
static deserializeFile(payload: ISafePayload): File {
|
|
317
|
+
const data = payload.data as number[];
|
|
318
|
+
const meta = payload.meta as IFileMeta;
|
|
319
|
+
const { mime, name } = meta;
|
|
320
|
+
const { buffer } = new Uint8Array(data);
|
|
321
|
+
return new File([buffer], name, {
|
|
322
|
+
type: mime,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Deserializes previously serialized blob object.
|
|
328
|
+
*
|
|
329
|
+
* In previous versions of ARC the data was a string as data URL. In API client this is a buffer.
|
|
264
330
|
*
|
|
331
|
+
* @param payload The serialized payload.
|
|
332
|
+
* @return Restored blob value
|
|
333
|
+
*/
|
|
334
|
+
static deserializeBlob(payload: ISafePayload): Blob | undefined {
|
|
335
|
+
if (typeof payload.data === 'string') {
|
|
336
|
+
return this.deserializeBlobLegacy(payload.data);
|
|
337
|
+
}
|
|
338
|
+
const data = payload.data as number[];
|
|
339
|
+
const meta = payload.meta as IBlobMeta;
|
|
340
|
+
const { mime } = meta;
|
|
341
|
+
const { buffer } = new Uint8Array(data);
|
|
342
|
+
return new Blob([buffer], { type: mime });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* The old implementation of the blob deserializer.
|
|
347
|
+
*
|
|
348
|
+
* @deprecated
|
|
265
349
|
* @param dataUrl Data url from blob value.
|
|
266
350
|
* @return Restored blob value
|
|
267
351
|
*/
|
|
268
|
-
static
|
|
352
|
+
static deserializeBlobLegacy(dataUrl: string): Blob | undefined {
|
|
269
353
|
const arr = dataUrl.split(',');
|
|
270
354
|
const matchedMime = arr[0].match(/:(.*?);/);
|
|
271
355
|
if (!matchedMime) {
|
|
@@ -282,12 +366,40 @@ export class PayloadSerializer {
|
|
|
282
366
|
}
|
|
283
367
|
|
|
284
368
|
/**
|
|
285
|
-
* Converts
|
|
369
|
+
* Converts previously serialized File to a Buffer.
|
|
286
370
|
*
|
|
371
|
+
* @param payload The serialized payload.
|
|
372
|
+
* @return Restored File value as Buffer
|
|
373
|
+
*/
|
|
374
|
+
static deserializeFileBuffer(payload: ISafePayload): Buffer {
|
|
375
|
+
const data = payload.data as number[];
|
|
376
|
+
const ab = this.deserializeArrayBuffer(data);
|
|
377
|
+
return Buffer.from(ab);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Converts data-url string to buffer
|
|
382
|
+
*
|
|
383
|
+
* @param payload The serialized payload.
|
|
384
|
+
* @return Restored blob value
|
|
385
|
+
*/
|
|
386
|
+
static deserializeBlobBuffer(payload: ISafePayload): Buffer {
|
|
387
|
+
if (typeof payload.data === 'string') {
|
|
388
|
+
return this.deserializeBlobBufferLegacy(payload.data);
|
|
389
|
+
}
|
|
390
|
+
const data = payload.data as number[];
|
|
391
|
+
const ab = this.deserializeArrayBuffer(data);
|
|
392
|
+
return Buffer.from(ab);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Converts data-url string to buffer
|
|
397
|
+
*
|
|
398
|
+
* @deprecated
|
|
287
399
|
* @param dataUrl Data url from blob value.
|
|
288
400
|
* @return Restored blob value
|
|
289
401
|
*/
|
|
290
|
-
static
|
|
402
|
+
static deserializeBlobBufferLegacy(dataUrl: string): Buffer {
|
|
291
403
|
const arr = dataUrl.split(',');
|
|
292
404
|
const value = arr[1];
|
|
293
405
|
return Buffer.from(value, 'base64url');
|
|
@@ -334,26 +446,50 @@ export class PayloadSerializer {
|
|
|
334
446
|
if (!Array.isArray(parts) || !parts.length) {
|
|
335
447
|
return fd;
|
|
336
448
|
}
|
|
337
|
-
parts.forEach(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
449
|
+
parts.forEach(part => this.deserializeFormDataPart(fd, part));
|
|
450
|
+
return fd;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
private static deserializeFormDataPart(form: FormData, part: IMultipartBody): void {
|
|
454
|
+
if (part.enabled === false) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
// the compatibility with old ARC.
|
|
458
|
+
if (typeof part.isFile === 'boolean') {
|
|
459
|
+
this.deserializeFormDataLegacy(form, part);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const { name, value } = part;
|
|
463
|
+
if (typeof value === 'string') {
|
|
464
|
+
form.append(name, value);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (value.type === 'file') {
|
|
468
|
+
const file = this.deserializeFile(value);
|
|
469
|
+
form.append(name, file);
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const blob = this.deserializeBlob(value) as Blob;
|
|
473
|
+
form.append(name, blob);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* @deprecated This is only for compatibility with ARC.
|
|
478
|
+
*/
|
|
479
|
+
private static deserializeFormDataLegacy(form: FormData, part: IMultipartBody): void {
|
|
480
|
+
let blob;
|
|
481
|
+
if (part.isFile) {
|
|
482
|
+
blob = PayloadSerializer.deserializeBlobLegacy(part.value as string);
|
|
483
|
+
if (blob) {
|
|
484
|
+
form.append(part.name, blob, part.fileName);
|
|
341
485
|
}
|
|
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);
|
|
486
|
+
} else if (part.type) {
|
|
487
|
+
blob = PayloadSerializer.deserializeBlobLegacy(part.value as string);
|
|
488
|
+
if (blob) {
|
|
489
|
+
form.append(part.name, blob, 'blob');
|
|
355
490
|
}
|
|
356
|
-
}
|
|
357
|
-
|
|
491
|
+
} else {
|
|
492
|
+
form.append(part.name, part.value as string);
|
|
493
|
+
}
|
|
358
494
|
}
|
|
359
495
|
}
|
|
@@ -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);
|