@pierre/storage 0.9.2 → 1.0.0

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.
@@ -2,254 +2,271 @@ import type { BlobLike, FileLike, ReadableStreamLike } from './types';
2
2
 
3
3
  type NodeBuffer = Uint8Array & { toString(encoding?: string): string };
4
4
  interface NodeBufferConstructor {
5
- from(data: Uint8Array): NodeBuffer;
6
- from(data: string, encoding?: string): NodeBuffer;
7
- isBuffer(value: unknown): value is NodeBuffer;
5
+ from(data: Uint8Array): NodeBuffer;
6
+ from(data: string, encoding?: string): NodeBuffer;
7
+ isBuffer(value: unknown): value is NodeBuffer;
8
8
  }
9
9
 
10
10
  const BufferCtor: NodeBufferConstructor | undefined = (
11
- globalThis as { Buffer?: NodeBufferConstructor }
11
+ globalThis as { Buffer?: NodeBufferConstructor }
12
12
  ).Buffer;
13
13
 
14
14
  export const MAX_CHUNK_BYTES = 4 * 1024 * 1024;
15
15
 
16
16
  export type ChunkSegment = {
17
- chunk: Uint8Array;
18
- eof: boolean;
17
+ chunk: Uint8Array;
18
+ eof: boolean;
19
19
  };
20
20
 
21
- export async function* chunkify(source: AsyncIterable<Uint8Array>): AsyncIterable<ChunkSegment> {
22
- let pending: Uint8Array | null = null;
23
- let produced = false;
24
-
25
- for await (const value of source) {
26
- const bytes = value;
27
-
28
- if (pending && pending.byteLength === MAX_CHUNK_BYTES) {
29
- yield { chunk: pending, eof: false };
30
- produced = true;
31
- pending = null;
32
- }
33
-
34
- const merged: Uint8Array = pending ? concatChunks(pending, bytes) : bytes;
35
- pending = null;
36
-
37
- let cursor: Uint8Array = merged;
38
- while (cursor.byteLength > MAX_CHUNK_BYTES) {
39
- const chunk: Uint8Array = cursor.slice(0, MAX_CHUNK_BYTES);
40
- cursor = cursor.slice(MAX_CHUNK_BYTES);
41
- yield { chunk, eof: false };
42
- produced = true;
43
- }
44
-
45
- pending = cursor;
46
- }
47
-
48
- if (pending) {
49
- yield { chunk: pending, eof: true };
50
- produced = true;
51
- }
52
-
53
- if (!produced) {
54
- yield { chunk: new Uint8Array(0), eof: true };
55
- }
21
+ export async function* chunkify(
22
+ source: AsyncIterable<Uint8Array>
23
+ ): AsyncIterable<ChunkSegment> {
24
+ let pending: Uint8Array | null = null;
25
+ let produced = false;
26
+
27
+ for await (const value of source) {
28
+ const bytes = value;
29
+
30
+ if (pending && pending.byteLength === MAX_CHUNK_BYTES) {
31
+ yield { chunk: pending, eof: false };
32
+ produced = true;
33
+ pending = null;
34
+ }
35
+
36
+ const merged: Uint8Array = pending ? concatChunks(pending, bytes) : bytes;
37
+ pending = null;
38
+
39
+ let cursor: Uint8Array = merged;
40
+ while (cursor.byteLength > MAX_CHUNK_BYTES) {
41
+ const chunk: Uint8Array = cursor.slice(0, MAX_CHUNK_BYTES);
42
+ cursor = cursor.slice(MAX_CHUNK_BYTES);
43
+ yield { chunk, eof: false };
44
+ produced = true;
45
+ }
46
+
47
+ pending = cursor;
48
+ }
49
+
50
+ if (pending) {
51
+ yield { chunk: pending, eof: true };
52
+ produced = true;
53
+ }
54
+
55
+ if (!produced) {
56
+ yield { chunk: new Uint8Array(0), eof: true };
57
+ }
56
58
  }
57
59
 
58
60
  export async function* toAsyncIterable(
59
- source:
60
- | string
61
- | Uint8Array
62
- | ArrayBuffer
63
- | BlobLike
64
- | FileLike
65
- | ReadableStreamLike<Uint8Array | ArrayBuffer | ArrayBufferView | string>
66
- | AsyncIterable<Uint8Array | ArrayBuffer | ArrayBufferView | string>
67
- | Iterable<Uint8Array | ArrayBuffer | ArrayBufferView | string>,
61
+ source:
62
+ | string
63
+ | Uint8Array
64
+ | ArrayBuffer
65
+ | BlobLike
66
+ | FileLike
67
+ | ReadableStreamLike<Uint8Array | ArrayBuffer | ArrayBufferView | string>
68
+ | AsyncIterable<Uint8Array | ArrayBuffer | ArrayBufferView | string>
69
+ | Iterable<Uint8Array | ArrayBuffer | ArrayBufferView | string>
68
70
  ): AsyncIterable<Uint8Array> {
69
- if (typeof source === 'string') {
70
- yield new TextEncoder().encode(source);
71
- return;
72
- }
73
- if (source instanceof Uint8Array) {
74
- yield source;
75
- return;
76
- }
77
- if (source instanceof ArrayBuffer) {
78
- yield new Uint8Array(source);
79
- return;
80
- }
81
- if (ArrayBuffer.isView(source)) {
82
- yield new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
83
- return;
84
- }
85
- if (isBlobLike(source)) {
86
- const stream = source.stream();
87
- if (isAsyncIterable(stream)) {
88
- for await (const chunk of stream as AsyncIterable<unknown>) {
89
- yield ensureUint8Array(chunk);
90
- }
91
- return;
92
- }
93
- if (isReadableStreamLike(stream)) {
94
- yield* readReadableStream(stream);
95
- return;
96
- }
97
- }
98
- if (isReadableStreamLike(source)) {
99
- yield* readReadableStream(source);
100
- return;
101
- }
102
- if (isAsyncIterable(source)) {
103
- for await (const chunk of source as AsyncIterable<unknown>) {
104
- yield ensureUint8Array(chunk);
105
- }
106
- return;
107
- }
108
- if (isIterable(source)) {
109
- for (const chunk of source as Iterable<unknown>) {
110
- yield ensureUint8Array(chunk);
111
- }
112
- return;
113
- }
114
- throw new Error('Unsupported content source; expected binary data');
71
+ if (typeof source === 'string') {
72
+ yield new TextEncoder().encode(source);
73
+ return;
74
+ }
75
+ if (source instanceof Uint8Array) {
76
+ yield source;
77
+ return;
78
+ }
79
+ if (source instanceof ArrayBuffer) {
80
+ yield new Uint8Array(source);
81
+ return;
82
+ }
83
+ if (ArrayBuffer.isView(source)) {
84
+ yield new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
85
+ return;
86
+ }
87
+ if (isBlobLike(source)) {
88
+ const stream = source.stream();
89
+ if (isAsyncIterable(stream)) {
90
+ for await (const chunk of stream as AsyncIterable<unknown>) {
91
+ yield ensureUint8Array(chunk);
92
+ }
93
+ return;
94
+ }
95
+ if (isReadableStreamLike(stream)) {
96
+ yield* readReadableStream(stream);
97
+ return;
98
+ }
99
+ }
100
+ if (isReadableStreamLike(source)) {
101
+ yield* readReadableStream(source);
102
+ return;
103
+ }
104
+ if (isAsyncIterable(source)) {
105
+ for await (const chunk of source as AsyncIterable<unknown>) {
106
+ yield ensureUint8Array(chunk);
107
+ }
108
+ return;
109
+ }
110
+ if (isIterable(source)) {
111
+ for (const chunk of source as Iterable<unknown>) {
112
+ yield ensureUint8Array(chunk);
113
+ }
114
+ return;
115
+ }
116
+ throw new Error('Unsupported content source; expected binary data');
115
117
  }
116
118
 
117
119
  export function base64Encode(bytes: Uint8Array): string {
118
- if (BufferCtor) {
119
- return BufferCtor.from(bytes).toString('base64');
120
- }
121
- let binary = '';
122
- for (let i = 0; i < bytes.byteLength; i++) {
123
- binary += String.fromCharCode(bytes[i]);
124
- }
125
- const btoaFn = (globalThis as { btoa?: (data: string) => string }).btoa;
126
- if (typeof btoaFn === 'function') {
127
- return btoaFn(binary);
128
- }
129
- throw new Error('Base64 encoding is not supported in this environment');
120
+ if (BufferCtor) {
121
+ return BufferCtor.from(bytes).toString('base64');
122
+ }
123
+ let binary = '';
124
+ for (let i = 0; i < bytes.byteLength; i++) {
125
+ binary += String.fromCharCode(bytes[i]);
126
+ }
127
+ const btoaFn = (globalThis as { btoa?: (data: string) => string }).btoa;
128
+ if (typeof btoaFn === 'function') {
129
+ return btoaFn(binary);
130
+ }
131
+ throw new Error('Base64 encoding is not supported in this environment');
130
132
  }
131
133
 
132
134
  export function requiresDuplex(body: unknown): boolean {
133
- if (!body || typeof body !== 'object') {
134
- return false;
135
- }
136
-
137
- if (typeof (body as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === 'function') {
138
- return true;
139
- }
140
-
141
- const readableStreamCtor = (
142
- globalThis as {
143
- ReadableStream?: new (...args: unknown[]) => unknown;
144
- }
145
- ).ReadableStream;
146
- if (readableStreamCtor && body instanceof readableStreamCtor) {
147
- return true;
148
- }
149
-
150
- return false;
135
+ if (!body || typeof body !== 'object') {
136
+ return false;
137
+ }
138
+
139
+ if (
140
+ typeof (body as { [Symbol.asyncIterator]?: unknown })[
141
+ Symbol.asyncIterator
142
+ ] === 'function'
143
+ ) {
144
+ return true;
145
+ }
146
+
147
+ const readableStreamCtor = (
148
+ globalThis as {
149
+ ReadableStream?: new (...args: unknown[]) => unknown;
150
+ }
151
+ ).ReadableStream;
152
+ if (readableStreamCtor && body instanceof readableStreamCtor) {
153
+ return true;
154
+ }
155
+
156
+ return false;
151
157
  }
152
158
 
153
159
  export function toRequestBody(iterable: AsyncIterable<Uint8Array>): unknown {
154
- const readableStreamCtor = (
155
- globalThis as { ReadableStream?: new (underlyingSource: unknown) => unknown }
156
- ).ReadableStream;
157
- if (typeof readableStreamCtor === 'function') {
158
- const iterator = iterable[Symbol.asyncIterator]();
159
- return new readableStreamCtor({
160
- async pull(controller: { enqueue(chunk: Uint8Array): void; close(): void }) {
161
- const { value, done } = await iterator.next();
162
- if (done) {
163
- controller.close();
164
- return;
165
- }
166
- controller.enqueue(value!);
167
- },
168
- async cancel(reason: unknown) {
169
- if (typeof iterator.return === 'function') {
170
- await iterator.return(reason);
171
- }
172
- },
173
- });
174
- }
175
- return iterable;
160
+ const readableStreamCtor = (
161
+ globalThis as {
162
+ ReadableStream?: new (underlyingSource: unknown) => unknown;
163
+ }
164
+ ).ReadableStream;
165
+ if (typeof readableStreamCtor === 'function') {
166
+ const iterator = iterable[Symbol.asyncIterator]();
167
+ return new readableStreamCtor({
168
+ async pull(controller: {
169
+ enqueue(chunk: Uint8Array): void;
170
+ close(): void;
171
+ }) {
172
+ const { value, done } = await iterator.next();
173
+ if (done) {
174
+ controller.close();
175
+ return;
176
+ }
177
+ controller.enqueue(value!);
178
+ },
179
+ async cancel(reason: unknown) {
180
+ if (typeof iterator.return === 'function') {
181
+ await iterator.return(reason);
182
+ }
183
+ },
184
+ });
185
+ }
186
+ return iterable;
176
187
  }
177
188
 
178
- async function* readReadableStream(stream: ReadableStreamLike<unknown>): AsyncIterable<Uint8Array> {
179
- const reader = stream.getReader();
180
- try {
181
- while (true) {
182
- const { value, done } = await reader.read();
183
- if (done) {
184
- break;
185
- }
186
- if (value !== undefined) {
187
- yield ensureUint8Array(value);
188
- }
189
- }
190
- } finally {
191
- reader.releaseLock?.();
192
- }
189
+ async function* readReadableStream(
190
+ stream: ReadableStreamLike<unknown>
191
+ ): AsyncIterable<Uint8Array> {
192
+ const reader = stream.getReader();
193
+ try {
194
+ while (true) {
195
+ const { value, done } = await reader.read();
196
+ if (done) {
197
+ break;
198
+ }
199
+ if (value !== undefined) {
200
+ yield ensureUint8Array(value);
201
+ }
202
+ }
203
+ } finally {
204
+ reader.releaseLock?.();
205
+ }
193
206
  }
194
207
 
195
208
  function ensureUint8Array(value: unknown): Uint8Array {
196
- if (value instanceof Uint8Array) {
197
- return value;
198
- }
199
- if (value instanceof ArrayBuffer) {
200
- return new Uint8Array(value);
201
- }
202
- if (ArrayBuffer.isView(value)) {
203
- return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
204
- }
205
- if (typeof value === 'string') {
206
- return new TextEncoder().encode(value);
207
- }
208
- if (BufferCtor && BufferCtor.isBuffer(value)) {
209
- return value as Uint8Array;
210
- }
211
- throw new Error('Unsupported chunk type; expected binary data');
209
+ if (value instanceof Uint8Array) {
210
+ return value;
211
+ }
212
+ if (value instanceof ArrayBuffer) {
213
+ return new Uint8Array(value);
214
+ }
215
+ if (ArrayBuffer.isView(value)) {
216
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
217
+ }
218
+ if (typeof value === 'string') {
219
+ return new TextEncoder().encode(value);
220
+ }
221
+ if (BufferCtor && BufferCtor.isBuffer(value)) {
222
+ return value as Uint8Array;
223
+ }
224
+ throw new Error('Unsupported chunk type; expected binary data');
212
225
  }
213
226
 
214
227
  function isBlobLike(value: unknown): value is BlobLike {
215
- return (
216
- typeof value === 'object' && value !== null && typeof (value as BlobLike).stream === 'function'
217
- );
228
+ return (
229
+ typeof value === 'object' &&
230
+ value !== null &&
231
+ typeof (value as BlobLike).stream === 'function'
232
+ );
218
233
  }
219
234
 
220
- function isReadableStreamLike<T>(value: unknown): value is ReadableStreamLike<T> {
221
- return (
222
- typeof value === 'object' &&
223
- value !== null &&
224
- typeof (value as ReadableStreamLike<T>).getReader === 'function'
225
- );
235
+ function isReadableStreamLike<T>(
236
+ value: unknown
237
+ ): value is ReadableStreamLike<T> {
238
+ return (
239
+ typeof value === 'object' &&
240
+ value !== null &&
241
+ typeof (value as ReadableStreamLike<T>).getReader === 'function'
242
+ );
226
243
  }
227
244
 
228
245
  function isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {
229
- return (
230
- typeof value === 'object' &&
231
- value !== null &&
232
- Symbol.asyncIterator in (value as Record<string, unknown>)
233
- );
246
+ return (
247
+ typeof value === 'object' &&
248
+ value !== null &&
249
+ Symbol.asyncIterator in (value as Record<string, unknown>)
250
+ );
234
251
  }
235
252
 
236
253
  function isIterable(value: unknown): value is Iterable<unknown> {
237
- return (
238
- typeof value === 'object' &&
239
- value !== null &&
240
- Symbol.iterator in (value as Record<string, unknown>)
241
- );
254
+ return (
255
+ typeof value === 'object' &&
256
+ value !== null &&
257
+ Symbol.iterator in (value as Record<string, unknown>)
258
+ );
242
259
  }
243
260
 
244
261
  function concatChunks(a: Uint8Array, b: Uint8Array): Uint8Array {
245
- if (a.byteLength === 0) {
246
- return b;
247
- }
248
- if (b.byteLength === 0) {
249
- return a;
250
- }
251
- const merged = new Uint8Array(a.byteLength + b.byteLength);
252
- merged.set(a, 0);
253
- merged.set(b, a.byteLength);
254
- return merged;
262
+ if (a.byteLength === 0) {
263
+ return b;
264
+ }
265
+ if (b.byteLength === 0) {
266
+ return a;
267
+ }
268
+ const merged = new Uint8Array(a.byteLength + b.byteLength);
269
+ merged.set(a, 0);
270
+ merged.set(b, a.byteLength);
271
+ return merged;
255
272
  }