@syncular/server-cloudflare 0.0.1-98 → 0.0.2-126
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 +24 -0
- package/dist/r2.d.ts.map +1 -1
- package/dist/r2.js +58 -12
- package/dist/r2.js.map +1 -1
- package/package.json +1 -1
- package/src/r2.test.ts +120 -0
- package/src/r2.ts +69 -12
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @syncular/server-cloudflare
|
|
2
|
+
|
|
3
|
+
Cloudflare Workers and Durable Objects adapters for running Syncular on the edge, plus Cloudflare R2 blob storage helpers.
|
|
4
|
+
|
|
5
|
+
This package is intentionally dialect-agnostic. You pair it with a database dialect (e.g. D1/SQLite or Neon/Postgres) and the matching Syncular server dialect.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @syncular/server-cloudflare
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Documentation
|
|
14
|
+
|
|
15
|
+
- Cloudflare adapter: https://syncular.dev/docs/server/cloudflare-adapter
|
|
16
|
+
- Dialects: https://syncular.dev/docs/server/dialects
|
|
17
|
+
- Blob storage: https://syncular.dev/docs/build/blob-storage
|
|
18
|
+
|
|
19
|
+
## Links
|
|
20
|
+
|
|
21
|
+
- GitHub: https://github.com/syncular/syncular
|
|
22
|
+
- Issues: https://github.com/syncular/syncular/issues
|
|
23
|
+
|
|
24
|
+
> Status: Alpha. APIs and storage layouts may change between releases.
|
package/dist/r2.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"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"}
|
package/dist/r2.js
CHANGED
|
@@ -80,7 +80,15 @@ export function createR2BlobStorageAdapter(options) {
|
|
|
80
80
|
? metadata.mimeType
|
|
81
81
|
: 'application/octet-stream';
|
|
82
82
|
}
|
|
83
|
-
function resolveChecksum(hash) {
|
|
83
|
+
function resolveChecksum(hash, metadata) {
|
|
84
|
+
if (metadata?.disableChecksum === true) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
const explicitChecksum = metadata?.checksumSha256;
|
|
88
|
+
if (typeof explicitChecksum === 'string' &&
|
|
89
|
+
/^[0-9a-f]{64}$/i.test(explicitChecksum)) {
|
|
90
|
+
return explicitChecksum.toLowerCase();
|
|
91
|
+
}
|
|
84
92
|
return hash.startsWith('sha256:') ? hash.slice(7) : undefined;
|
|
85
93
|
}
|
|
86
94
|
function resolveContentLength(metadata) {
|
|
@@ -98,23 +106,61 @@ export function createR2BlobStorageAdapter(options) {
|
|
|
98
106
|
}
|
|
99
107
|
return undefined;
|
|
100
108
|
}
|
|
109
|
+
async function streamToBytes(stream) {
|
|
110
|
+
const reader = stream.getReader();
|
|
111
|
+
try {
|
|
112
|
+
const chunks = [];
|
|
113
|
+
let total = 0;
|
|
114
|
+
while (true) {
|
|
115
|
+
const { done, value } = await reader.read();
|
|
116
|
+
if (done)
|
|
117
|
+
break;
|
|
118
|
+
if (!value)
|
|
119
|
+
continue;
|
|
120
|
+
chunks.push(value);
|
|
121
|
+
total += value.length;
|
|
122
|
+
}
|
|
123
|
+
const output = new Uint8Array(total);
|
|
124
|
+
let offset = 0;
|
|
125
|
+
for (const chunk of chunks) {
|
|
126
|
+
output.set(chunk, offset);
|
|
127
|
+
offset += chunk.length;
|
|
128
|
+
}
|
|
129
|
+
return output;
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
reader.releaseLock();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
101
135
|
async function putStreamInternal(hash, stream, metadata) {
|
|
102
136
|
const key = getKey(hash);
|
|
103
137
|
const mimeType = resolveMimeType(metadata);
|
|
104
|
-
const checksum = resolveChecksum(hash);
|
|
138
|
+
const checksum = resolveChecksum(hash, metadata);
|
|
105
139
|
const contentLength = resolveContentLength(metadata);
|
|
106
140
|
if (typeof contentLength === 'number' && contentLength >= 0) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
141
|
+
if (typeof FixedLengthStream !== 'undefined') {
|
|
142
|
+
const fixedLength = new FixedLengthStream(contentLength);
|
|
143
|
+
await Promise.all([
|
|
144
|
+
stream.pipeTo(fixedLength.writable),
|
|
145
|
+
bucket.put(key, fixedLength.readable, {
|
|
146
|
+
httpMetadata: { contentType: mimeType },
|
|
147
|
+
sha256: checksum,
|
|
148
|
+
}),
|
|
149
|
+
]);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const bufferedBody = await streamToBytes(stream);
|
|
153
|
+
if (bufferedBody.byteLength !== contentLength) {
|
|
154
|
+
throw new Error(`Blob content length mismatch: expected ${contentLength}, got ${bufferedBody.byteLength}`);
|
|
155
|
+
}
|
|
156
|
+
await bucket.put(key, bufferedBody, {
|
|
157
|
+
httpMetadata: { contentType: mimeType },
|
|
158
|
+
sha256: checksum,
|
|
159
|
+
});
|
|
115
160
|
return;
|
|
116
161
|
}
|
|
117
|
-
await
|
|
162
|
+
const bufferedBody = await streamToBytes(stream);
|
|
163
|
+
await bucket.put(key, bufferedBody, {
|
|
118
164
|
httpMetadata: {
|
|
119
165
|
contentType: mimeType,
|
|
120
166
|
},
|
|
@@ -171,7 +217,7 @@ export function createR2BlobStorageAdapter(options) {
|
|
|
171
217
|
async put(hash, data, metadata) {
|
|
172
218
|
const key = getKey(hash);
|
|
173
219
|
const mimeType = resolveMimeType(metadata);
|
|
174
|
-
const checksum = resolveChecksum(hash);
|
|
220
|
+
const checksum = resolveChecksum(hash, metadata);
|
|
175
221
|
await bucket.put(key, data, {
|
|
176
222
|
httpMetadata: {
|
|
177
223
|
contentType: mimeType,
|
package/dist/r2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r2.js","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"r2.js","sourceRoot":"","sources":["../src/r2.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/r2.test.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import {
|
|
3
|
+
type BlobStorageAdapter,
|
|
4
|
+
type BlobTokenSigner,
|
|
5
|
+
createR2BlobStorageAdapter,
|
|
6
|
+
} from './r2';
|
|
7
|
+
|
|
8
|
+
function createBodyStream(
|
|
9
|
+
chunks: readonly Uint8Array[]
|
|
10
|
+
): ReadableStream<Uint8Array> {
|
|
11
|
+
return new ReadableStream<Uint8Array>({
|
|
12
|
+
start(controller) {
|
|
13
|
+
for (const chunk of chunks) {
|
|
14
|
+
controller.enqueue(chunk);
|
|
15
|
+
}
|
|
16
|
+
controller.close();
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function consumeStream(
|
|
22
|
+
stream: ReadableStream<Uint8Array>
|
|
23
|
+
): Promise<void> {
|
|
24
|
+
const reader = stream.getReader();
|
|
25
|
+
try {
|
|
26
|
+
while (true) {
|
|
27
|
+
const { done } = await reader.read();
|
|
28
|
+
if (done) break;
|
|
29
|
+
}
|
|
30
|
+
} finally {
|
|
31
|
+
reader.releaseLock();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function createTokenSigner(): BlobTokenSigner {
|
|
36
|
+
return {
|
|
37
|
+
async sign() {
|
|
38
|
+
return 'token';
|
|
39
|
+
},
|
|
40
|
+
async verify() {
|
|
41
|
+
return null;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function createAdapterWithCapturedPuts(
|
|
47
|
+
captured: Array<{ body: unknown; options: unknown }>
|
|
48
|
+
): BlobStorageAdapter {
|
|
49
|
+
const bucket = {
|
|
50
|
+
async put(_key: string, body: unknown, options?: unknown) {
|
|
51
|
+
captured.push({ body, options });
|
|
52
|
+
if (body instanceof ReadableStream) {
|
|
53
|
+
await consumeStream(body as ReadableStream<Uint8Array>);
|
|
54
|
+
}
|
|
55
|
+
return {} as R2Object;
|
|
56
|
+
},
|
|
57
|
+
async get() {
|
|
58
|
+
return null;
|
|
59
|
+
},
|
|
60
|
+
async head() {
|
|
61
|
+
return null;
|
|
62
|
+
},
|
|
63
|
+
async delete() {},
|
|
64
|
+
} as unknown as R2Bucket;
|
|
65
|
+
|
|
66
|
+
return createR2BlobStorageAdapter({
|
|
67
|
+
bucket,
|
|
68
|
+
baseUrl: '/api/sync',
|
|
69
|
+
tokenSigner: createTokenSigner(),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
describe('createR2BlobStorageAdapter.putStream', () => {
|
|
74
|
+
test('buffers unknown-length streams before upload', async () => {
|
|
75
|
+
const puts: Array<{ body: unknown; options: unknown }> = [];
|
|
76
|
+
const adapter = createAdapterWithCapturedPuts(puts);
|
|
77
|
+
|
|
78
|
+
await adapter.putStream?.(
|
|
79
|
+
'sha256:abc123',
|
|
80
|
+
createBodyStream([new Uint8Array([1, 2]), new Uint8Array([3, 4])])
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
expect(puts).toHaveLength(1);
|
|
84
|
+
expect(puts[0]?.body).toBeInstanceOf(Uint8Array);
|
|
85
|
+
expect(Array.from(puts[0]?.body as Uint8Array)).toEqual([1, 2, 3, 4]);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('uses fixed-length stream when byteLength is provided', async () => {
|
|
89
|
+
const puts: Array<{ body: unknown; options: unknown }> = [];
|
|
90
|
+
const adapter = createAdapterWithCapturedPuts(puts);
|
|
91
|
+
|
|
92
|
+
await adapter.putStream?.(
|
|
93
|
+
'sha256:def456',
|
|
94
|
+
createBodyStream([new Uint8Array([9, 8, 7, 6])]),
|
|
95
|
+
{ byteLength: 4 }
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
expect(puts).toHaveLength(1);
|
|
99
|
+
if (typeof FixedLengthStream !== 'undefined') {
|
|
100
|
+
expect(puts[0]?.body).toBeInstanceOf(ReadableStream);
|
|
101
|
+
} else {
|
|
102
|
+
expect(puts[0]?.body).toBeInstanceOf(Uint8Array);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('omits checksum when disableChecksum metadata is set', async () => {
|
|
107
|
+
const puts: Array<{ body: unknown; options: unknown }> = [];
|
|
108
|
+
const adapter = createAdapterWithCapturedPuts(puts);
|
|
109
|
+
|
|
110
|
+
await adapter.putStream?.(
|
|
111
|
+
'sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
|
|
112
|
+
createBodyStream([new Uint8Array([1, 2, 3])]),
|
|
113
|
+
{ disableChecksum: true }
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(puts).toHaveLength(1);
|
|
117
|
+
const options = puts[0]?.options as { sha256?: string };
|
|
118
|
+
expect(options.sha256).toBeUndefined();
|
|
119
|
+
});
|
|
120
|
+
});
|
package/src/r2.ts
CHANGED
|
@@ -248,7 +248,22 @@ export function createR2BlobStorageAdapter(
|
|
|
248
248
|
: 'application/octet-stream';
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
function resolveChecksum(
|
|
251
|
+
function resolveChecksum(
|
|
252
|
+
hash: string,
|
|
253
|
+
metadata?: Record<string, unknown>
|
|
254
|
+
): string | undefined {
|
|
255
|
+
if (metadata?.disableChecksum === true) {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const explicitChecksum = metadata?.checksumSha256;
|
|
260
|
+
if (
|
|
261
|
+
typeof explicitChecksum === 'string' &&
|
|
262
|
+
/^[0-9a-f]{64}$/i.test(explicitChecksum)
|
|
263
|
+
) {
|
|
264
|
+
return explicitChecksum.toLowerCase();
|
|
265
|
+
}
|
|
266
|
+
|
|
252
267
|
return hash.startsWith('sha256:') ? hash.slice(7) : undefined;
|
|
253
268
|
}
|
|
254
269
|
|
|
@@ -268,6 +283,33 @@ export function createR2BlobStorageAdapter(
|
|
|
268
283
|
return undefined;
|
|
269
284
|
}
|
|
270
285
|
|
|
286
|
+
async function streamToBytes(
|
|
287
|
+
stream: ReadableStream<Uint8Array>
|
|
288
|
+
): Promise<Uint8Array> {
|
|
289
|
+
const reader = stream.getReader();
|
|
290
|
+
try {
|
|
291
|
+
const chunks: Uint8Array[] = [];
|
|
292
|
+
let total = 0;
|
|
293
|
+
while (true) {
|
|
294
|
+
const { done, value } = await reader.read();
|
|
295
|
+
if (done) break;
|
|
296
|
+
if (!value) continue;
|
|
297
|
+
chunks.push(value);
|
|
298
|
+
total += value.length;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const output = new Uint8Array(total);
|
|
302
|
+
let offset = 0;
|
|
303
|
+
for (const chunk of chunks) {
|
|
304
|
+
output.set(chunk, offset);
|
|
305
|
+
offset += chunk.length;
|
|
306
|
+
}
|
|
307
|
+
return output;
|
|
308
|
+
} finally {
|
|
309
|
+
reader.releaseLock();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
271
313
|
async function putStreamInternal(
|
|
272
314
|
hash: string,
|
|
273
315
|
stream: ReadableStream<Uint8Array>,
|
|
@@ -275,22 +317,37 @@ export function createR2BlobStorageAdapter(
|
|
|
275
317
|
): Promise<void> {
|
|
276
318
|
const key = getKey(hash);
|
|
277
319
|
const mimeType = resolveMimeType(metadata);
|
|
278
|
-
const checksum = resolveChecksum(hash);
|
|
320
|
+
const checksum = resolveChecksum(hash, metadata);
|
|
279
321
|
const contentLength = resolveContentLength(metadata);
|
|
280
322
|
|
|
281
323
|
if (typeof contentLength === 'number' && contentLength >= 0) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
324
|
+
if (typeof FixedLengthStream !== 'undefined') {
|
|
325
|
+
const fixedLength = new FixedLengthStream(contentLength);
|
|
326
|
+
await Promise.all([
|
|
327
|
+
stream.pipeTo(fixedLength.writable),
|
|
328
|
+
bucket.put(key, fixedLength.readable, {
|
|
329
|
+
httpMetadata: { contentType: mimeType },
|
|
330
|
+
sha256: checksum,
|
|
331
|
+
}),
|
|
332
|
+
]);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const bufferedBody = await streamToBytes(stream);
|
|
337
|
+
if (bufferedBody.byteLength !== contentLength) {
|
|
338
|
+
throw new Error(
|
|
339
|
+
`Blob content length mismatch: expected ${contentLength}, got ${bufferedBody.byteLength}`
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
await bucket.put(key, bufferedBody, {
|
|
343
|
+
httpMetadata: { contentType: mimeType },
|
|
344
|
+
sha256: checksum,
|
|
345
|
+
});
|
|
290
346
|
return;
|
|
291
347
|
}
|
|
292
348
|
|
|
293
|
-
await
|
|
349
|
+
const bufferedBody = await streamToBytes(stream);
|
|
350
|
+
await bucket.put(key, bufferedBody, {
|
|
294
351
|
httpMetadata: {
|
|
295
352
|
contentType: mimeType,
|
|
296
353
|
},
|
|
@@ -371,7 +428,7 @@ export function createR2BlobStorageAdapter(
|
|
|
371
428
|
): Promise<void> {
|
|
372
429
|
const key = getKey(hash);
|
|
373
430
|
const mimeType = resolveMimeType(metadata);
|
|
374
|
-
const checksum = resolveChecksum(hash);
|
|
431
|
+
const checksum = resolveChecksum(hash, metadata);
|
|
375
432
|
await bucket.put(key, data, {
|
|
376
433
|
httpMetadata: {
|
|
377
434
|
contentType: mimeType,
|