@syncular/server-cloudflare 0.0.1-92 → 0.0.1-95
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/dist/r2.d.ts +8 -0
- package/dist/r2.d.ts.map +1 -1
- package/dist/r2.js +115 -8
- package/dist/r2.js.map +1 -1
- package/package.json +1 -1
- package/src/r2.ts +145 -10
package/dist/r2.d.ts
CHANGED
|
@@ -73,10 +73,18 @@ export interface BlobStorageAdapter {
|
|
|
73
73
|
* Store blob data directly (for adapters that support direct storage).
|
|
74
74
|
*/
|
|
75
75
|
put?(hash: string, data: Uint8Array, metadata?: Record<string, unknown>): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Store blob data directly from a stream.
|
|
78
|
+
*/
|
|
79
|
+
putStream?(hash: string, stream: ReadableStream<Uint8Array>, metadata?: Record<string, unknown>): Promise<void>;
|
|
76
80
|
/**
|
|
77
81
|
* Get blob data directly (for adapters that support direct retrieval).
|
|
78
82
|
*/
|
|
79
83
|
get?(hash: string): Promise<Uint8Array | null>;
|
|
84
|
+
/**
|
|
85
|
+
* Get blob data directly as a stream.
|
|
86
|
+
*/
|
|
87
|
+
getStream?(hash: string): Promise<ReadableStream<Uint8Array> | null>;
|
|
80
88
|
}
|
|
81
89
|
/**
|
|
82
90
|
* Token signer interface for creating/verifying upload/download tokens.
|
package/dist/r2.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,kBAAkB;IAClB,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAEtE;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEhE;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEvC;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC;;OAEG;IACH,WAAW,CAAC,CACV,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAEvD;;OAEG;IACH,GAAG,CAAC,CACF,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;OAEG;IACH,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"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"}
|
package/dist/r2.js
CHANGED
|
@@ -75,6 +75,86 @@ export function createR2BlobStorageAdapter(options) {
|
|
|
75
75
|
const hex = hash.startsWith('sha256:') ? hash.slice(7) : hash;
|
|
76
76
|
return `${keyPrefix}${hex}`;
|
|
77
77
|
}
|
|
78
|
+
function resolveMimeType(metadata) {
|
|
79
|
+
return typeof metadata?.mimeType === 'string'
|
|
80
|
+
? metadata.mimeType
|
|
81
|
+
: 'application/octet-stream';
|
|
82
|
+
}
|
|
83
|
+
function resolveChecksum(hash) {
|
|
84
|
+
return hash.startsWith('sha256:') ? hash.slice(7) : undefined;
|
|
85
|
+
}
|
|
86
|
+
function resolveContentLength(metadata) {
|
|
87
|
+
const candidates = [
|
|
88
|
+
metadata?.contentLength,
|
|
89
|
+
metadata?.byteLength,
|
|
90
|
+
metadata?.size,
|
|
91
|
+
];
|
|
92
|
+
for (const candidate of candidates) {
|
|
93
|
+
if (typeof candidate !== 'number')
|
|
94
|
+
continue;
|
|
95
|
+
if (!Number.isFinite(candidate) || candidate < 0)
|
|
96
|
+
continue;
|
|
97
|
+
return candidate;
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
async function readStreamToBytes(stream) {
|
|
102
|
+
const reader = stream.getReader();
|
|
103
|
+
try {
|
|
104
|
+
const chunks = [];
|
|
105
|
+
let total = 0;
|
|
106
|
+
while (true) {
|
|
107
|
+
const { done, value } = await reader.read();
|
|
108
|
+
if (done)
|
|
109
|
+
break;
|
|
110
|
+
if (!value)
|
|
111
|
+
continue;
|
|
112
|
+
chunks.push(value);
|
|
113
|
+
total += value.length;
|
|
114
|
+
}
|
|
115
|
+
const out = new Uint8Array(total);
|
|
116
|
+
let offset = 0;
|
|
117
|
+
for (const chunk of chunks) {
|
|
118
|
+
out.set(chunk, offset);
|
|
119
|
+
offset += chunk.length;
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
reader.releaseLock();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function putStreamInternal(hash, stream, metadata) {
|
|
128
|
+
const key = getKey(hash);
|
|
129
|
+
const mimeType = resolveMimeType(metadata);
|
|
130
|
+
const checksum = resolveChecksum(hash);
|
|
131
|
+
const contentLength = resolveContentLength(metadata);
|
|
132
|
+
if (typeof contentLength === 'number' && contentLength >= 0) {
|
|
133
|
+
const fixedLength = new FixedLengthStream(contentLength);
|
|
134
|
+
await Promise.all([
|
|
135
|
+
stream.pipeTo(fixedLength.writable),
|
|
136
|
+
bucket.put(key, fixedLength.readable, {
|
|
137
|
+
httpMetadata: { contentType: mimeType },
|
|
138
|
+
sha256: checksum,
|
|
139
|
+
}),
|
|
140
|
+
]);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const bytes = await readStreamToBytes(stream);
|
|
144
|
+
await bucket.put(key, bytes, {
|
|
145
|
+
httpMetadata: {
|
|
146
|
+
contentType: mimeType,
|
|
147
|
+
},
|
|
148
|
+
sha256: checksum,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
async function getStreamInternal(hash) {
|
|
152
|
+
const key = getKey(hash);
|
|
153
|
+
const object = await bucket.get(key);
|
|
154
|
+
if (!object)
|
|
155
|
+
return null;
|
|
156
|
+
return object.body;
|
|
157
|
+
}
|
|
78
158
|
return {
|
|
79
159
|
name: 'r2',
|
|
80
160
|
async signUpload(opts) {
|
|
@@ -117,22 +197,49 @@ export function createR2BlobStorageAdapter(options) {
|
|
|
117
197
|
},
|
|
118
198
|
async put(hash, data, metadata) {
|
|
119
199
|
const key = getKey(hash);
|
|
120
|
-
const mimeType =
|
|
121
|
-
|
|
122
|
-
: 'application/octet-stream';
|
|
200
|
+
const mimeType = resolveMimeType(metadata);
|
|
201
|
+
const checksum = resolveChecksum(hash);
|
|
123
202
|
await bucket.put(key, data, {
|
|
124
203
|
httpMetadata: {
|
|
125
204
|
contentType: mimeType,
|
|
126
205
|
},
|
|
127
|
-
sha256:
|
|
206
|
+
sha256: checksum,
|
|
128
207
|
});
|
|
129
208
|
},
|
|
209
|
+
async putStream(hash, stream, metadata) {
|
|
210
|
+
await putStreamInternal(hash, stream, metadata);
|
|
211
|
+
},
|
|
130
212
|
async get(hash) {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
if (!object)
|
|
213
|
+
const stream = await getStreamInternal(hash);
|
|
214
|
+
if (!stream)
|
|
134
215
|
return null;
|
|
135
|
-
|
|
216
|
+
const reader = stream.getReader();
|
|
217
|
+
try {
|
|
218
|
+
const chunks = [];
|
|
219
|
+
let total = 0;
|
|
220
|
+
while (true) {
|
|
221
|
+
const { done, value } = await reader.read();
|
|
222
|
+
if (done)
|
|
223
|
+
break;
|
|
224
|
+
if (!value)
|
|
225
|
+
continue;
|
|
226
|
+
chunks.push(value);
|
|
227
|
+
total += value.length;
|
|
228
|
+
}
|
|
229
|
+
const out = new Uint8Array(total);
|
|
230
|
+
let offset = 0;
|
|
231
|
+
for (const chunk of chunks) {
|
|
232
|
+
out.set(chunk, offset);
|
|
233
|
+
offset += chunk.length;
|
|
234
|
+
}
|
|
235
|
+
return out;
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
reader.releaseLock();
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
async getStream(hash) {
|
|
242
|
+
return getStreamInternal(hash);
|
|
136
243
|
},
|
|
137
244
|
};
|
|
138
245
|
}
|
package/dist/r2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r2.js","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"r2.js","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/r2.ts
CHANGED
|
@@ -92,10 +92,24 @@ export interface BlobStorageAdapter {
|
|
|
92
92
|
metadata?: Record<string, unknown>
|
|
93
93
|
): Promise<void>;
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Store blob data directly from a stream.
|
|
97
|
+
*/
|
|
98
|
+
putStream?(
|
|
99
|
+
hash: string,
|
|
100
|
+
stream: ReadableStream<Uint8Array>,
|
|
101
|
+
metadata?: Record<string, unknown>
|
|
102
|
+
): Promise<void>;
|
|
103
|
+
|
|
95
104
|
/**
|
|
96
105
|
* Get blob data directly (for adapters that support direct retrieval).
|
|
97
106
|
*/
|
|
98
107
|
get?(hash: string): Promise<Uint8Array | null>;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get blob data directly as a stream.
|
|
111
|
+
*/
|
|
112
|
+
getStream?(hash: string): Promise<ReadableStream<Uint8Array> | null>;
|
|
99
113
|
}
|
|
100
114
|
|
|
101
115
|
/**
|
|
@@ -228,6 +242,99 @@ export function createR2BlobStorageAdapter(
|
|
|
228
242
|
return `${keyPrefix}${hex}`;
|
|
229
243
|
}
|
|
230
244
|
|
|
245
|
+
function resolveMimeType(metadata?: Record<string, unknown>): string {
|
|
246
|
+
return typeof metadata?.mimeType === 'string'
|
|
247
|
+
? metadata.mimeType
|
|
248
|
+
: 'application/octet-stream';
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function resolveChecksum(hash: string): string | undefined {
|
|
252
|
+
return hash.startsWith('sha256:') ? hash.slice(7) : undefined;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function resolveContentLength(
|
|
256
|
+
metadata?: Record<string, unknown>
|
|
257
|
+
): number | undefined {
|
|
258
|
+
const candidates = [
|
|
259
|
+
metadata?.contentLength,
|
|
260
|
+
metadata?.byteLength,
|
|
261
|
+
metadata?.size,
|
|
262
|
+
];
|
|
263
|
+
for (const candidate of candidates) {
|
|
264
|
+
if (typeof candidate !== 'number') continue;
|
|
265
|
+
if (!Number.isFinite(candidate) || candidate < 0) continue;
|
|
266
|
+
return candidate;
|
|
267
|
+
}
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async function readStreamToBytes(
|
|
272
|
+
stream: ReadableStream<Uint8Array>
|
|
273
|
+
): Promise<Uint8Array> {
|
|
274
|
+
const reader = stream.getReader();
|
|
275
|
+
try {
|
|
276
|
+
const chunks: Uint8Array[] = [];
|
|
277
|
+
let total = 0;
|
|
278
|
+
while (true) {
|
|
279
|
+
const { done, value } = await reader.read();
|
|
280
|
+
if (done) break;
|
|
281
|
+
if (!value) continue;
|
|
282
|
+
chunks.push(value);
|
|
283
|
+
total += value.length;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const out = new Uint8Array(total);
|
|
287
|
+
let offset = 0;
|
|
288
|
+
for (const chunk of chunks) {
|
|
289
|
+
out.set(chunk, offset);
|
|
290
|
+
offset += chunk.length;
|
|
291
|
+
}
|
|
292
|
+
return out;
|
|
293
|
+
} finally {
|
|
294
|
+
reader.releaseLock();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
async function putStreamInternal(
|
|
299
|
+
hash: string,
|
|
300
|
+
stream: ReadableStream<Uint8Array>,
|
|
301
|
+
metadata?: Record<string, unknown>
|
|
302
|
+
): Promise<void> {
|
|
303
|
+
const key = getKey(hash);
|
|
304
|
+
const mimeType = resolveMimeType(metadata);
|
|
305
|
+
const checksum = resolveChecksum(hash);
|
|
306
|
+
const contentLength = resolveContentLength(metadata);
|
|
307
|
+
|
|
308
|
+
if (typeof contentLength === 'number' && contentLength >= 0) {
|
|
309
|
+
const fixedLength = new FixedLengthStream(contentLength);
|
|
310
|
+
await Promise.all([
|
|
311
|
+
stream.pipeTo(fixedLength.writable),
|
|
312
|
+
bucket.put(key, fixedLength.readable, {
|
|
313
|
+
httpMetadata: { contentType: mimeType },
|
|
314
|
+
sha256: checksum,
|
|
315
|
+
}),
|
|
316
|
+
]);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const bytes = await readStreamToBytes(stream);
|
|
321
|
+
await bucket.put(key, bytes, {
|
|
322
|
+
httpMetadata: {
|
|
323
|
+
contentType: mimeType,
|
|
324
|
+
},
|
|
325
|
+
sha256: checksum,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async function getStreamInternal(
|
|
330
|
+
hash: string
|
|
331
|
+
): Promise<ReadableStream<Uint8Array> | null> {
|
|
332
|
+
const key = getKey(hash);
|
|
333
|
+
const object = await bucket.get(key);
|
|
334
|
+
if (!object) return null;
|
|
335
|
+
return object.body as ReadableStream<Uint8Array> | null;
|
|
336
|
+
}
|
|
337
|
+
|
|
231
338
|
return {
|
|
232
339
|
name: 'r2',
|
|
233
340
|
|
|
@@ -291,25 +398,53 @@ export function createR2BlobStorageAdapter(
|
|
|
291
398
|
metadata?: Record<string, unknown>
|
|
292
399
|
): Promise<void> {
|
|
293
400
|
const key = getKey(hash);
|
|
294
|
-
const mimeType =
|
|
295
|
-
|
|
296
|
-
? metadata.mimeType
|
|
297
|
-
: 'application/octet-stream';
|
|
298
|
-
|
|
401
|
+
const mimeType = resolveMimeType(metadata);
|
|
402
|
+
const checksum = resolveChecksum(hash);
|
|
299
403
|
await bucket.put(key, data, {
|
|
300
404
|
httpMetadata: {
|
|
301
405
|
contentType: mimeType,
|
|
302
406
|
},
|
|
303
|
-
sha256:
|
|
407
|
+
sha256: checksum,
|
|
304
408
|
});
|
|
305
409
|
},
|
|
306
410
|
|
|
411
|
+
async putStream(
|
|
412
|
+
hash: string,
|
|
413
|
+
stream: ReadableStream<Uint8Array>,
|
|
414
|
+
metadata?: Record<string, unknown>
|
|
415
|
+
): Promise<void> {
|
|
416
|
+
await putStreamInternal(hash, stream, metadata);
|
|
417
|
+
},
|
|
418
|
+
|
|
307
419
|
async get(hash: string): Promise<Uint8Array | null> {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
420
|
+
const stream = await getStreamInternal(hash);
|
|
421
|
+
if (!stream) return null;
|
|
422
|
+
|
|
423
|
+
const reader = stream.getReader();
|
|
424
|
+
try {
|
|
425
|
+
const chunks: Uint8Array[] = [];
|
|
426
|
+
let total = 0;
|
|
427
|
+
while (true) {
|
|
428
|
+
const { done, value } = await reader.read();
|
|
429
|
+
if (done) break;
|
|
430
|
+
if (!value) continue;
|
|
431
|
+
chunks.push(value);
|
|
432
|
+
total += value.length;
|
|
433
|
+
}
|
|
434
|
+
const out = new Uint8Array(total);
|
|
435
|
+
let offset = 0;
|
|
436
|
+
for (const chunk of chunks) {
|
|
437
|
+
out.set(chunk, offset);
|
|
438
|
+
offset += chunk.length;
|
|
439
|
+
}
|
|
440
|
+
return out;
|
|
441
|
+
} finally {
|
|
442
|
+
reader.releaseLock();
|
|
443
|
+
}
|
|
444
|
+
},
|
|
311
445
|
|
|
312
|
-
|
|
446
|
+
async getStream(hash: string): Promise<ReadableStream<Uint8Array> | null> {
|
|
447
|
+
return getStreamInternal(hash);
|
|
313
448
|
},
|
|
314
449
|
};
|
|
315
450
|
}
|