@tstdl/base 0.90.7 → 0.90.9
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/http/utils.js +1 -1
- package/package.json +1 -1
- package/utils/binary.d.ts +2 -1
- package/utils/binary.js +9 -6
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/stream/index.d.ts +1 -0
- package/utils/stream/index.js +1 -0
- package/utils/stream/readable-stream-adapter.js +6 -7
- package/utils/stream/stream-reader.d.ts +8 -1
- package/utils/stream/stream-reader.js +65 -21
- package/utils/stream/to-bytes-stream.d.ts +4 -0
- package/utils/stream/to-bytes-stream.js +78 -0
- package/utils/type/extends.d.ts +2 -0
- package/utils/type/extends.js +3 -0
- package/utils/type/index.d.ts +1 -0
- package/utils/type/index.js +1 -0
package/http/utils.js
CHANGED
|
@@ -49,7 +49,7 @@ export async function readBodyAsBuffer(body, headers, options = {}) {
|
|
|
49
49
|
uint8Array = new Uint8Array(buffer);
|
|
50
50
|
}
|
|
51
51
|
else if (isReadableStream(body) || isAnyIterable(body)) {
|
|
52
|
-
uint8Array = await readBinaryStream(readBodyAsBinaryStream(body, headers, options), headers.contentLength);
|
|
52
|
+
uint8Array = await readBinaryStream(readBodyAsBinaryStream(body, headers, options), { length: headers.contentLength });
|
|
53
53
|
}
|
|
54
54
|
else {
|
|
55
55
|
throw new NotSupportedError('Unsupported body type.');
|
package/package.json
CHANGED
package/utils/binary.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BinaryData } from '../types.js';
|
|
1
|
+
import type { BinaryData, Type } from '../types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Get ArrayBuffer from binary data
|
|
4
4
|
* @param data data to get ArrayBuffer from
|
|
@@ -14,3 +14,4 @@ export declare function toArrayBuffer(data: BinaryData, clone?: boolean): ArrayB
|
|
|
14
14
|
export declare function toUint8Array(data: BinaryData, clone?: boolean): Uint8Array;
|
|
15
15
|
export declare function concatArrayBuffers(buffers: ArrayBufferLike[]): ArrayBuffer;
|
|
16
16
|
export declare function concatArrayBufferViews<T extends ArrayBufferView>(arrays: T[], totalLength?: number): T;
|
|
17
|
+
export declare function concatArrayBufferViews<T extends ArrayBufferView>(arrays: ArrayBufferView[], targetType: Type<T, [ArrayBufferLike, number, number]>, totalLength?: number): T;
|
package/utils/binary.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { supportsBuffer } from '../supports.js';
|
|
2
|
-
import {
|
|
2
|
+
import { typeExtends } from './index.js';
|
|
3
|
+
import { assert, isArrayBuffer, isFunction, isNumber } from './type-guards.js';
|
|
3
4
|
/**
|
|
4
5
|
* Get ArrayBuffer from binary data
|
|
5
6
|
* @param data data to get ArrayBuffer from
|
|
@@ -36,11 +37,13 @@ export function concatArrayBuffers(buffers) {
|
|
|
36
37
|
const bytes = concatArrayBufferViews(arrays);
|
|
37
38
|
return bytes.buffer;
|
|
38
39
|
}
|
|
39
|
-
export function concatArrayBufferViews(arrays,
|
|
40
|
+
export function concatArrayBufferViews(arrays, totalLengthOrTargetType, totalLengthOrNothing) {
|
|
40
41
|
assert(arrays.length > 0, 'No array provided.');
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
const totalLength = isNumber(totalLengthOrTargetType) ? totalLengthOrTargetType : totalLengthOrNothing;
|
|
43
|
+
const type = isFunction(totalLengthOrTargetType) ? totalLengthOrTargetType : arrays[0].constructor;
|
|
44
|
+
if (supportsBuffer && typeExtends(type, Uint8Array)) {
|
|
45
|
+
const merged = Buffer.concat(arrays, totalLength);
|
|
46
|
+
return new type(merged.buffer, merged.byteOffset, merged.byteLength);
|
|
44
47
|
}
|
|
45
48
|
const totalBytes = totalLength ?? arrays.reduce((sum, array) => sum + array.byteLength, 0);
|
|
46
49
|
const merged = new Uint8Array(totalBytes);
|
|
@@ -50,5 +53,5 @@ export function concatArrayBufferViews(arrays, totalLength) {
|
|
|
50
53
|
merged.set(uint8Array, currentIndex);
|
|
51
54
|
currentIndex += uint8Array.byteLength;
|
|
52
55
|
}
|
|
53
|
-
return new type(merged.buffer);
|
|
56
|
+
return new type(merged.buffer, merged.byteOffset, merged.byteLength);
|
|
54
57
|
}
|
package/utils/index.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export * from './timer.js';
|
|
|
49
49
|
export * from './timing.js';
|
|
50
50
|
export * from './type-guards.js';
|
|
51
51
|
export * from './type-of.js';
|
|
52
|
+
export * from './type/index.js';
|
|
52
53
|
export * from './units.js';
|
|
53
54
|
export * from './url-builder.js';
|
|
54
55
|
export * from './value-or-provider.js';
|
package/utils/index.js
CHANGED
|
@@ -49,6 +49,7 @@ export * from './timer.js';
|
|
|
49
49
|
export * from './timing.js';
|
|
50
50
|
export * from './type-guards.js';
|
|
51
51
|
export * from './type-of.js';
|
|
52
|
+
export * from './type/index.js';
|
|
52
53
|
export * from './units.js';
|
|
53
54
|
export * from './url-builder.js';
|
|
54
55
|
export * from './value-or-provider.js';
|
package/utils/stream/index.d.ts
CHANGED
package/utils/stream/index.js
CHANGED
|
@@ -14,15 +14,14 @@ export async function* getReadableStreamIterable(stream, options = {}) {
|
|
|
14
14
|
if (options.close != false) {
|
|
15
15
|
await reader.cancel();
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
else {
|
|
18
|
+
reader.releaseLock();
|
|
19
|
+
}
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
export function getReadableStreamFromIterable(iterable) {
|
|
21
|
-
|
|
23
|
+
const iterator = isAsyncIterable(iterable) ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
|
|
22
24
|
return new ReadableStream({
|
|
23
|
-
cancel: async (reason) => {
|
|
24
|
-
await iterator.return?.(reason);
|
|
25
|
-
},
|
|
26
25
|
pull: async (controller) => {
|
|
27
26
|
const result = await iterator.next();
|
|
28
27
|
if (result.done == true) {
|
|
@@ -32,8 +31,8 @@ export function getReadableStreamFromIterable(iterable) {
|
|
|
32
31
|
controller.enqueue(result.value);
|
|
33
32
|
}
|
|
34
33
|
},
|
|
35
|
-
|
|
36
|
-
iterator
|
|
34
|
+
cancel: async (reason) => {
|
|
35
|
+
await iterator.return?.(reason);
|
|
37
36
|
}
|
|
38
37
|
});
|
|
39
38
|
}
|
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
import type { AnyIterable } from '../any-iterable-iterator.js';
|
|
2
|
-
export
|
|
2
|
+
export type ReadBinaryStreamOptions = {
|
|
3
|
+
length?: number;
|
|
4
|
+
/** Action if source stream has more bytes than provided length */
|
|
5
|
+
onLengthExceed?: 'error' | 'close' | 'leave-open';
|
|
6
|
+
/** Action if source stream has less bytes than provided length */
|
|
7
|
+
onLengthSubceed?: 'error' | 'close' | 'leave-open';
|
|
8
|
+
};
|
|
9
|
+
export declare function readBinaryStream(iterableOrStream: AnyIterable<ArrayBufferView> | ReadableStream<ArrayBufferView>, { length, onLengthExceed, onLengthSubceed }?: ReadBinaryStreamOptions): Promise<Uint8Array>;
|
|
@@ -1,34 +1,78 @@
|
|
|
1
1
|
import { BadRequestError } from '../../errors/bad-request.error.js';
|
|
2
|
-
import {
|
|
2
|
+
import { MaxBytesExceededError } from '../../errors/max-bytes-exceeded.error.js';
|
|
3
|
+
import { NotSupportedError } from '../../errors/not-supported.error.js';
|
|
3
4
|
import { concatArrayBufferViews } from '../binary.js';
|
|
4
|
-
import { isDefined } from '../type-guards.js';
|
|
5
|
-
import {
|
|
5
|
+
import { isDefined, isReadableStream } from '../type-guards.js';
|
|
6
|
+
import { getReadableStreamFromIterable } from './readable-stream-adapter.js';
|
|
7
|
+
import { toBytesStream } from './to-bytes-stream.js';
|
|
6
8
|
// eslint-disable-next-line max-statements
|
|
7
|
-
export async function readBinaryStream(iterableOrStream, length) {
|
|
8
|
-
const
|
|
9
|
+
export async function readBinaryStream(iterableOrStream, { length, onLengthExceed = 'error', onLengthSubceed = 'error' } = {}) {
|
|
10
|
+
const stream = isReadableStream(iterableOrStream)
|
|
11
|
+
? isDefined(length)
|
|
12
|
+
? toBytesStream(iterableOrStream)
|
|
13
|
+
: iterableOrStream
|
|
14
|
+
: getReadableStreamFromIterable(iterableOrStream);
|
|
9
15
|
if (isDefined(length)) {
|
|
10
|
-
const
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
const reader = stream.getReader({ mode: 'byob' });
|
|
17
|
+
let buffer = new ArrayBuffer(length + 1);
|
|
18
|
+
let bytesRead = 0;
|
|
19
|
+
while (true) {
|
|
20
|
+
const result = await reader.read(new Uint8Array(buffer, bytesRead, buffer.byteLength - bytesRead));
|
|
21
|
+
buffer = result.value.buffer;
|
|
22
|
+
bytesRead += result.value.byteLength;
|
|
23
|
+
if (result.done) {
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
if (bytesRead > length) {
|
|
27
|
+
switch (onLengthExceed) {
|
|
28
|
+
case 'error':
|
|
29
|
+
await reader.cancel();
|
|
30
|
+
throw new MaxBytesExceededError('Size of stream is greater than provided length.');
|
|
31
|
+
case 'close':
|
|
32
|
+
await reader.cancel();
|
|
33
|
+
break;
|
|
34
|
+
case 'leave-open':
|
|
35
|
+
reader.releaseLock();
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
throw new NotSupportedError(`Action ${onLengthExceed} not supported.`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (bytesRead == length + 1) {
|
|
42
|
+
break;
|
|
15
43
|
}
|
|
16
|
-
array.set(chunk, bytesWritten);
|
|
17
|
-
bytesWritten += chunk.length;
|
|
18
44
|
}
|
|
19
|
-
if (
|
|
20
|
-
|
|
45
|
+
if (bytesRead < length) {
|
|
46
|
+
switch (onLengthSubceed) {
|
|
47
|
+
case 'error':
|
|
48
|
+
await reader.cancel();
|
|
49
|
+
throw new BadRequestError('Size of stream was less than provided length.');
|
|
50
|
+
case 'close':
|
|
51
|
+
await reader.cancel();
|
|
52
|
+
break;
|
|
53
|
+
case 'leave-open':
|
|
54
|
+
reader.releaseLock();
|
|
55
|
+
break;
|
|
56
|
+
default:
|
|
57
|
+
throw new NotSupportedError(`Action ${onLengthSubceed} not supported.`);
|
|
58
|
+
}
|
|
21
59
|
}
|
|
22
|
-
|
|
60
|
+
await reader.cancel();
|
|
61
|
+
return new Uint8Array(buffer, 0, Math.min(length, bytesRead));
|
|
23
62
|
}
|
|
24
63
|
let totalLength = 0;
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
64
|
+
const reader = stream.getReader();
|
|
65
|
+
const views = [];
|
|
66
|
+
while (true) {
|
|
67
|
+
const result = await reader.read();
|
|
68
|
+
if (result.done) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
views.push(result.value);
|
|
72
|
+
totalLength += result.value.byteLength;
|
|
29
73
|
}
|
|
30
|
-
if (
|
|
74
|
+
if (views.length == 0) {
|
|
31
75
|
return new Uint8Array(0);
|
|
32
76
|
}
|
|
33
|
-
return concatArrayBufferViews(
|
|
77
|
+
return concatArrayBufferViews(views, Uint8Array, totalLength);
|
|
34
78
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { isNotNull, isNull } from '../type-guards.js';
|
|
2
|
+
export function toBytesStream(stream, options) {
|
|
3
|
+
try { // try to use byob mode from source
|
|
4
|
+
let byobReader;
|
|
5
|
+
return new ReadableStream({
|
|
6
|
+
type: 'bytes',
|
|
7
|
+
autoAllocateChunkSize: 10240,
|
|
8
|
+
start() {
|
|
9
|
+
byobReader = stream.getReader({ mode: 'byob' });
|
|
10
|
+
},
|
|
11
|
+
async pull(controller) {
|
|
12
|
+
const readResult = await byobReader.read(controller.byobRequest.view);
|
|
13
|
+
if (readResult.done) {
|
|
14
|
+
controller.close();
|
|
15
|
+
controller.byobRequest.respond(0);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
controller.byobRequest.respondWithNewView(readResult.value);
|
|
19
|
+
},
|
|
20
|
+
async cancel(reason) {
|
|
21
|
+
if (options?.ignoreCancel == true) {
|
|
22
|
+
byobReader.releaseLock();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
await byobReader.cancel(reason);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch { /* ignore */ }
|
|
31
|
+
let reader;
|
|
32
|
+
let buffer = null;
|
|
33
|
+
return new ReadableStream({
|
|
34
|
+
type: 'bytes',
|
|
35
|
+
start() {
|
|
36
|
+
reader = stream.getReader();
|
|
37
|
+
},
|
|
38
|
+
async pull(controller) {
|
|
39
|
+
const isByobRequest = isNotNull(controller.byobRequest);
|
|
40
|
+
const bufferIsEmpty = isNull(buffer) || (buffer.byteLength == 0);
|
|
41
|
+
if (!isByobRequest && !bufferIsEmpty) {
|
|
42
|
+
// we stil have data left in buffer from previous pull which was byob
|
|
43
|
+
controller.enqueue(buffer);
|
|
44
|
+
buffer = null;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (bufferIsEmpty) {
|
|
48
|
+
const readResult = await reader.read();
|
|
49
|
+
if (readResult.done) {
|
|
50
|
+
controller.close();
|
|
51
|
+
controller.byobRequest?.respond(0);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
buffer = readResult.value; // eslint-disable-line require-atomic-updates
|
|
55
|
+
}
|
|
56
|
+
if (!isByobRequest) {
|
|
57
|
+
controller.enqueue(buffer);
|
|
58
|
+
buffer = null;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const targetView = controller.byobRequest.view;
|
|
62
|
+
const targetArray = new Uint8Array(targetView.buffer, targetView.byteOffset, targetView.byteLength);
|
|
63
|
+
const setLength = Math.min(buffer.byteLength, targetArray.byteLength);
|
|
64
|
+
const sourceArray = new Uint8Array(buffer.buffer, buffer.byteOffset, setLength);
|
|
65
|
+
targetArray.set(sourceArray);
|
|
66
|
+
buffer = new Uint8Array(buffer.buffer, buffer.byteOffset + setLength);
|
|
67
|
+
controller.byobRequest.respond(setLength);
|
|
68
|
+
},
|
|
69
|
+
async cancel(reason) {
|
|
70
|
+
if (options?.ignoreCancel == true) {
|
|
71
|
+
reader.releaseLock();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
await reader.cancel(reason);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './extends.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './extends.js';
|