@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.
- package/README.md +77 -43
- package/dist/index.cjs +148 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -7
- package/dist/index.d.ts +12 -7
- package/dist/index.js +148 -43
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/commit-pack.ts +103 -99
- package/src/commit.ts +373 -365
- package/src/diff-commit.ts +272 -259
- package/src/errors.ts +34 -34
- package/src/fetch.ts +146 -141
- package/src/index.ts +1400 -1249
- package/src/schemas.ts +120 -114
- package/src/stream-utils.ts +225 -208
- package/src/types.ts +378 -354
- package/src/util.ts +41 -34
- package/src/version.ts +1 -1
- package/src/webhook.ts +244 -239
package/src/stream-utils.ts
CHANGED
|
@@ -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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
17
|
+
chunk: Uint8Array;
|
|
18
|
+
eof: boolean;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
export async function* chunkify(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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(
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
216
|
-
|
|
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>(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
}
|