@syncular/server 0.0.1-110 → 0.0.1-112

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.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Filesystem blob storage adapter.
3
+ *
4
+ * Stores blobs as files on disk with 2-level hash-based subdirectories.
5
+ * Uploads/downloads go through the server's blob routes using signed tokens
6
+ * (same pattern as the database adapter).
7
+ */
8
+ import type { BlobStorageAdapter } from '@syncular/core';
9
+ import type { BlobTokenSigner } from './database';
10
+ export interface FilesystemBlobStorageAdapterOptions {
11
+ /** Directory root for blob files */
12
+ basePath: string;
13
+ /** Server base URL for upload/download routes (e.g. "/api/sync") */
14
+ baseUrl: string;
15
+ /** Token signer for authorization */
16
+ tokenSigner: BlobTokenSigner;
17
+ }
18
+ /**
19
+ * Create a filesystem blob storage adapter.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const adapter = createFilesystemBlobStorageAdapter({
24
+ * basePath: '/data/blobs',
25
+ * baseUrl: 'https://api.example.com/api/sync',
26
+ * tokenSigner: createHmacTokenSigner(process.env.BLOB_SECRET!),
27
+ * });
28
+ * ```
29
+ */
30
+ export declare function createFilesystemBlobStorageAdapter(options: FilesystemBlobStorageAdapterOptions): BlobStorageAdapter;
31
+ //# sourceMappingURL=filesystem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../../src/blobs/adapters/filesystem.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,mCAAmC;IAClD,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,WAAW,EAAE,eAAe,CAAC;CAC9B;AAeD;;;;;;;;;;;GAWG;AACH,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,mCAAmC,GAC3C,kBAAkB,CA8HpB"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Filesystem blob storage adapter.
3
+ *
4
+ * Stores blobs as files on disk with 2-level hash-based subdirectories.
5
+ * Uploads/downloads go through the server's blob routes using signed tokens
6
+ * (same pattern as the database adapter).
7
+ */
8
+ import { mkdir, open, readFile, rename, stat, unlink, writeFile, } from 'node:fs/promises';
9
+ import { dirname, join } from 'node:path';
10
+ /**
11
+ * Resolve hash to a 2-level subdirectory path:
12
+ * `{basePath}/{hex[0..2]}/{hex[2..4]}/{hex}`
13
+ */
14
+ function hashToFilePath(basePath, hash) {
15
+ const hex = hash.startsWith('sha256:') ? hash.slice(7) : hash;
16
+ return join(basePath, hex.slice(0, 2), hex.slice(2, 4), hex);
17
+ }
18
+ function tmpPath(filePath) {
19
+ return `${filePath}.${Date.now()}.tmp`;
20
+ }
21
+ /**
22
+ * Create a filesystem blob storage adapter.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const adapter = createFilesystemBlobStorageAdapter({
27
+ * basePath: '/data/blobs',
28
+ * baseUrl: 'https://api.example.com/api/sync',
29
+ * tokenSigner: createHmacTokenSigner(process.env.BLOB_SECRET!),
30
+ * });
31
+ * ```
32
+ */
33
+ export function createFilesystemBlobStorageAdapter(options) {
34
+ const { basePath, tokenSigner } = options;
35
+ const normalizedBaseUrl = options.baseUrl.replace(/\/$/, '');
36
+ return {
37
+ name: 'filesystem',
38
+ async signUpload(opts) {
39
+ const expiresAt = Date.now() + opts.expiresIn * 1000;
40
+ const token = await tokenSigner.sign({ hash: opts.hash, action: 'upload', expiresAt }, opts.expiresIn);
41
+ const url = `${normalizedBaseUrl}/blobs/${encodeURIComponent(opts.hash)}/upload?token=${encodeURIComponent(token)}`;
42
+ return {
43
+ url,
44
+ method: 'PUT',
45
+ headers: {
46
+ 'Content-Type': opts.mimeType,
47
+ 'Content-Length': String(opts.size),
48
+ },
49
+ };
50
+ },
51
+ async signDownload(opts) {
52
+ const expiresAt = Date.now() + opts.expiresIn * 1000;
53
+ const token = await tokenSigner.sign({ hash: opts.hash, action: 'download', expiresAt }, opts.expiresIn);
54
+ return `${normalizedBaseUrl}/blobs/${encodeURIComponent(opts.hash)}/download?token=${encodeURIComponent(token)}`;
55
+ },
56
+ async exists(hash) {
57
+ try {
58
+ await stat(hashToFilePath(basePath, hash));
59
+ return true;
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ },
65
+ async delete(hash) {
66
+ try {
67
+ await unlink(hashToFilePath(basePath, hash));
68
+ }
69
+ catch (err) {
70
+ if (err.code !== 'ENOENT')
71
+ throw err;
72
+ }
73
+ },
74
+ async getMetadata(hash) {
75
+ try {
76
+ const s = await stat(hashToFilePath(basePath, hash));
77
+ return { size: s.size };
78
+ }
79
+ catch {
80
+ return null;
81
+ }
82
+ },
83
+ async put(hash, data) {
84
+ const filePath = hashToFilePath(basePath, hash);
85
+ const tmp = tmpPath(filePath);
86
+ await mkdir(dirname(filePath), { recursive: true });
87
+ await writeFile(tmp, data);
88
+ await rename(tmp, filePath);
89
+ },
90
+ async putStream(hash, stream) {
91
+ const filePath = hashToFilePath(basePath, hash);
92
+ const tmp = tmpPath(filePath);
93
+ await mkdir(dirname(filePath), { recursive: true });
94
+ const fh = await open(tmp, 'w');
95
+ try {
96
+ const reader = stream.getReader();
97
+ while (true) {
98
+ const { done, value } = await reader.read();
99
+ if (done)
100
+ break;
101
+ await fh.write(value);
102
+ }
103
+ }
104
+ finally {
105
+ await fh.close();
106
+ }
107
+ await rename(tmp, filePath);
108
+ },
109
+ async get(hash) {
110
+ try {
111
+ const buf = await readFile(hashToFilePath(basePath, hash));
112
+ return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
113
+ }
114
+ catch (err) {
115
+ if (err.code === 'ENOENT')
116
+ return null;
117
+ throw err;
118
+ }
119
+ },
120
+ async getStream(hash) {
121
+ let data;
122
+ try {
123
+ data = await readFile(hashToFilePath(basePath, hash));
124
+ }
125
+ catch (err) {
126
+ if (err.code === 'ENOENT')
127
+ return null;
128
+ throw err;
129
+ }
130
+ const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
131
+ return new ReadableStream({
132
+ start(controller) {
133
+ controller.enqueue(bytes);
134
+ controller.close();
135
+ },
136
+ });
137
+ },
138
+ };
139
+ }
140
+ //# sourceMappingURL=filesystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../../src/blobs/adapters/filesystem.ts"],"names":[],"mappings":"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"}
@@ -27,9 +27,10 @@ export interface S3Commands {
27
27
  PutObjectCommand: new (input: {
28
28
  Bucket: string;
29
29
  Key: string;
30
- ContentLength: number;
31
- ContentType: string;
30
+ ContentLength?: number;
31
+ ContentType?: string;
32
32
  ChecksumSHA256?: string;
33
+ Body?: Uint8Array | ReadableStream<Uint8Array>;
33
34
  }) => unknown;
34
35
  GetObjectCommand: new (input: {
35
36
  Bucket: string;
@@ -1 +1 @@
1
- {"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../../src/blobs/adapters/s3.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,KAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,KAAK,KAAK,EAAE;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,KAAK,OAAO,CAAC;IACd,gBAAgB,EAAE,KAAK,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;IAC1E,iBAAiB,EAAE,KAAK,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;IAC3E,mBAAmB,EAAE,KAAK,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;CAC9E;AAED,MAAM,WAAW,2BAA2B;IAC1C,yBAAyB;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,QAAQ,EAAE,UAAU,CAAC;IACrB,+DAA+D;IAC/D,YAAY,EAAE,cAAc,CAAC;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,2BAA2B,GACnC,kBAAkB,CAiIpB"}
1
+ {"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../../src/blobs/adapters/s3.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,KAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,KAAK,KAAK,EAAE;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,IAAI,CAAC,EAAE,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;KAChD,KAAK,OAAO,CAAC;IACd,gBAAgB,EAAE,KAAK,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;IAC1E,iBAAiB,EAAE,KAAK,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;IAC3E,mBAAmB,EAAE,KAAK,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;CAC9E;AAED,MAAM,WAAW,2BAA2B;IAC1C,yBAAyB;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,QAAQ,EAAE,UAAU,CAAC;IACrB,+DAA+D;IAC/D,YAAY,EAAE,cAAc,CAAC;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,2BAA2B,GACnC,kBAAkB,CAqLpB"}
@@ -118,6 +118,55 @@ export function createS3BlobStorageAdapter(options) {
118
118
  throw err;
119
119
  }
120
120
  },
121
+ async put(hash, data) {
122
+ const key = getKey(hash);
123
+ const command = new commands.PutObjectCommand({
124
+ Bucket: bucket,
125
+ Key: key,
126
+ Body: data,
127
+ ContentLength: data.length,
128
+ ContentType: 'application/octet-stream',
129
+ });
130
+ await client.send(command);
131
+ },
132
+ async get(hash) {
133
+ const key = getKey(hash);
134
+ try {
135
+ const command = new commands.GetObjectCommand({
136
+ Bucket: bucket,
137
+ Key: key,
138
+ });
139
+ const response = (await client.send(command));
140
+ if (!response.Body)
141
+ return null;
142
+ return response.Body.transformToByteArray();
143
+ }
144
+ catch (err) {
145
+ if (isNotFoundError(err)) {
146
+ return null;
147
+ }
148
+ throw err;
149
+ }
150
+ },
151
+ async getStream(hash) {
152
+ const key = getKey(hash);
153
+ try {
154
+ const command = new commands.GetObjectCommand({
155
+ Bucket: bucket,
156
+ Key: key,
157
+ });
158
+ const response = (await client.send(command));
159
+ if (!response.Body)
160
+ return null;
161
+ return response.Body.transformToWebStream();
162
+ }
163
+ catch (err) {
164
+ if (isNotFoundError(err)) {
165
+ return null;
166
+ }
167
+ throw err;
168
+ }
169
+ },
121
170
  };
122
171
  }
123
172
  function isNotFoundError(err) {
@@ -1 +1 @@
1
- {"version":3,"file":"s3.js","sourceRoot":"","sources":["../../../src/blobs/adapters/s3.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8DH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAoC,EAChB;IACpB,MAAM,EACJ,MAAM,EACN,MAAM,EACN,SAAS,GAAG,EAAE,EACd,QAAQ,EACR,YAAY,EACZ,eAAe,GAAG,IAAI,GACvB,GAAG,OAAO,CAAC;IAEZ,SAAS,MAAM,CAAC,IAAY,EAAU;QACpC,6CAA6C;QAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9D,OAAO,GAAG,SAAS,GAAG,GAAG,EAAE,CAAC;IAAA,CAC7B;IAED,OAAO;QACL,IAAI,EAAE,IAAI;QAEV,KAAK,CAAC,UAAU,CAAC,IAA2B,EAA6B;YACvE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE9B,oEAAoE;YACpE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;gBAC7C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;gBACpB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YAEd,+CAA+C;YAC/C,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;YAE5C,MAAM,YAAY,GAMd;gBACF,MAAM,EAAE,MAAM;gBACd,GAAG,EAAE,GAAG;gBACR,aAAa,EAAE,IAAI,CAAC,IAAI;gBACxB,WAAW,EAAE,IAAI,CAAC,QAAQ;aAC3B,CAAC;YAEF,IAAI,eAAe,EAAE,CAAC;gBACpB,YAAY,CAAC,cAAc,GAAG,cAAc,CAAC;YAC/C,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;YAC5D,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE;gBAC9C,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC,CAAC;YAEH,MAAM,OAAO,GAA2B;gBACtC,cAAc,EAAE,IAAI,CAAC,QAAQ;gBAC7B,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;aACpC,CAAC;YAEF,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,CAAC,uBAAuB,CAAC,GAAG,cAAc,CAAC;YACpD,CAAC;YAED,OAAO;gBACL,GAAG;gBACH,MAAM,EAAE,KAAK;gBACb,OAAO;aACR,CAAC;QAAA,CACH;QAED,KAAK,CAAC,YAAY,CAAC,IAA6B,EAAmB;YACjE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9B,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAC,gBAAgB,CAAC;gBAC5C,MAAM,EAAE,MAAM;gBACd,GAAG,EAAE,GAAG;aACT,CAAC,CAAC;YACH,OAAO,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAAA,CACrE;QAED,KAAK,CAAC,MAAM,CAAC,IAAY,EAAoB;YAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAC,iBAAiB,CAAC;oBAC7C,MAAM,EAAE,MAAM;oBACd,GAAG,EAAE,GAAG;iBACT,CAAC,CAAC;gBACH,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC3B,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,2BAA2B;gBAC3B,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzB,OAAO,KAAK,CAAC;gBACf,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;QAAA,CACF;QAED,KAAK,CAAC,MAAM,CAAC,IAAY,EAAiB;YACxC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAC,mBAAmB,CAAC;gBAC/C,MAAM,EAAE,MAAM;gBACd,GAAG,EAAE,GAAG;aACT,CAAC,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAAA,CAC5B;QAED,KAAK,CAAC,WAAW,CACf,IAAY,EACyC;YACrD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAC,iBAAiB,CAAC;oBAC7C,MAAM,EAAE,MAAM;oBACd,GAAG,EAAE,GAAG;iBACT,CAAC,CAAC;gBACH,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAG3C,CAAC;gBACF,OAAO;oBACL,IAAI,EAAE,QAAQ,CAAC,aAAa,IAAI,CAAC;oBACjC,QAAQ,EAAE,QAAQ,CAAC,WAAW;iBAC/B,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzB,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;QAAA,CACF;KACF,CAAC;AAAA,CACH;AAED,SAAS,eAAe,CAAC,GAAY,EAAW;IAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,CAAC,GAAG,GAAiE,CAAC;IAC5E,OAAO,CACL,CAAC,CAAC,IAAI,KAAK,UAAU;QACrB,CAAC,CAAC,IAAI,KAAK,WAAW;QACtB,CAAC,CAAC,SAAS,EAAE,cAAc,KAAK,GAAG,CACpC,CAAC;AAAA,CACH;AAED,SAAS,WAAW,CAAC,GAAW,EAAU;IACxC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,8DAA8D;IAC9D,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,yBAAyB;IACzB,MAAM,KAAK,GACT,kEAAkE,CAAC;IACrE,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACzB,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC,CAAC;IAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACpB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;QACxB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;QACxB,MAAM;YACJ,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;gBAC7B,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;gBAC1C,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;gBAC1C,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;IACjF,CAAC;SAAM,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAE,CAAC;QAC1B,MAAM;YACJ,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;gBAC7B,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;gBAC1C,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;gBAC7B,GAAG,CAAC;IACR,CAAC;IAED,OAAO,MAAM,CAAC;AAAA,CACf"}
1
+ {"version":3,"file":"s3.js","sourceRoot":"","sources":["../../../src/blobs/adapters/s3.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
  * @syncular/server - Blob storage exports
3
3
  */
4
4
  export * from './adapters/database';
5
+ export * from './adapters/filesystem';
5
6
  export * from './adapters/s3';
6
7
  export * from './manager';
7
8
  export * from './migrate';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blobs/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blobs/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
@@ -2,6 +2,7 @@
2
2
  * @syncular/server - Blob storage exports
3
3
  */
4
4
  export * from './adapters/database.js';
5
+ export * from './adapters/filesystem.js';
5
6
  export * from './adapters/s3.js';
6
7
  export * from './manager.js';
7
8
  export * from './migrate.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/blobs/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/blobs/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
@@ -3,7 +3,6 @@
3
3
  *
4
4
  * Separates chunk metadata (database) from body content (blob storage).
5
5
  */
6
- export * from './adapters/s3';
7
6
  export * from './db-metadata';
8
7
  export * from './types';
9
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/snapshot-chunks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/snapshot-chunks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC"}
@@ -3,7 +3,6 @@
3
3
  *
4
4
  * Separates chunk metadata (database) from body content (blob storage).
5
5
  */
6
- export * from './adapters/s3.js';
7
6
  export * from './db-metadata.js';
8
7
  export * from './types.js';
9
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/snapshot-chunks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/snapshot-chunks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/server",
3
- "version": "0.0.1-110",
3
+ "version": "0.0.1-112",
4
4
  "description": "Server-side sync engine with push/pull, pruning, and snapshot support",
5
5
  "license": "MIT",
6
6
  "author": "Benjamin Kniffler",
@@ -62,7 +62,7 @@
62
62
  "release": "bunx syncular-publish"
63
63
  },
64
64
  "dependencies": {
65
- "@syncular/core": "0.0.1"
65
+ "@syncular/core": "0.0.1-112"
66
66
  },
67
67
  "peerDependencies": {
68
68
  "kysely": "^0.28.0",
@@ -0,0 +1,132 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
2
+ import { mkdtemp, readdir, rm } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import type { BlobStorageAdapter } from '@syncular/core';
6
+ import { createHmacTokenSigner } from './database';
7
+ import { createFilesystemBlobStorageAdapter } from './filesystem';
8
+
9
+ let basePath: string;
10
+ let adapter: BlobStorageAdapter;
11
+
12
+ beforeEach(async () => {
13
+ basePath = await mkdtemp(join(tmpdir(), 'syncular-blob-test-'));
14
+ adapter = createFilesystemBlobStorageAdapter({
15
+ basePath,
16
+ baseUrl: 'https://example.com/api/sync',
17
+ tokenSigner: createHmacTokenSigner('test-secret'),
18
+ });
19
+ });
20
+
21
+ afterEach(async () => {
22
+ await rm(basePath, { recursive: true, force: true });
23
+ });
24
+
25
+ const testHash =
26
+ 'sha256:abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890';
27
+ const testData = new TextEncoder().encode('hello world');
28
+
29
+ describe('createFilesystemBlobStorageAdapter', () => {
30
+ test('put + get round-trip', async () => {
31
+ await adapter.put!(testHash, testData);
32
+ const result = await adapter.get!(testHash);
33
+ expect(result).toEqual(testData);
34
+ });
35
+
36
+ test('putStream + getStream round-trip', async () => {
37
+ const inputStream = new ReadableStream<Uint8Array>({
38
+ start(controller) {
39
+ controller.enqueue(testData);
40
+ controller.close();
41
+ },
42
+ });
43
+
44
+ await adapter.putStream!(testHash, inputStream);
45
+
46
+ const outputStream = await adapter.getStream!(testHash);
47
+ expect(outputStream).not.toBeNull();
48
+
49
+ const reader = outputStream!.getReader();
50
+ const chunks: Uint8Array[] = [];
51
+ while (true) {
52
+ const { done, value } = await reader.read();
53
+ if (done) break;
54
+ chunks.push(value);
55
+ }
56
+ const result = new Uint8Array(chunks.reduce((acc, c) => acc + c.length, 0));
57
+ let offset = 0;
58
+ for (const chunk of chunks) {
59
+ result.set(chunk, offset);
60
+ offset += chunk.length;
61
+ }
62
+ expect(result).toEqual(testData);
63
+ });
64
+
65
+ test('get returns null for missing blob', async () => {
66
+ const result = await adapter.get!(testHash);
67
+ expect(result).toBeNull();
68
+ });
69
+
70
+ test('getStream returns null for missing blob', async () => {
71
+ const result = await adapter.getStream!(testHash);
72
+ expect(result).toBeNull();
73
+ });
74
+
75
+ test('exists returns true after put', async () => {
76
+ expect(await adapter.exists(testHash)).toBe(false);
77
+ await adapter.put!(testHash, testData);
78
+ expect(await adapter.exists(testHash)).toBe(true);
79
+ });
80
+
81
+ test('delete removes the blob', async () => {
82
+ await adapter.put!(testHash, testData);
83
+ expect(await adapter.exists(testHash)).toBe(true);
84
+ await adapter.delete(testHash);
85
+ expect(await adapter.exists(testHash)).toBe(false);
86
+ });
87
+
88
+ test('delete is idempotent for missing blob', async () => {
89
+ await adapter.delete(testHash);
90
+ });
91
+
92
+ test('getMetadata returns size', async () => {
93
+ await adapter.put!(testHash, testData);
94
+ const meta = await adapter.getMetadata!(testHash);
95
+ expect(meta).toEqual({ size: testData.length });
96
+ });
97
+
98
+ test('getMetadata returns null for missing blob', async () => {
99
+ const meta = await adapter.getMetadata!(testHash);
100
+ expect(meta).toBeNull();
101
+ });
102
+
103
+ test('creates hash-based subdirectories', async () => {
104
+ await adapter.put!(testHash, testData);
105
+ // hex = abcdef..., so subdirs should be "ab/cd"
106
+ const firstLevel = await readdir(basePath);
107
+ expect(firstLevel).toContain('ab');
108
+ const secondLevel = await readdir(join(basePath, 'ab'));
109
+ expect(secondLevel).toContain('cd');
110
+ });
111
+
112
+ test('signUpload returns a token URL', async () => {
113
+ const result = await adapter.signUpload({
114
+ hash: testHash,
115
+ size: 100,
116
+ mimeType: 'application/octet-stream',
117
+ expiresIn: 60,
118
+ });
119
+ expect(result.url).toContain('/blobs/');
120
+ expect(result.url).toContain('token=');
121
+ expect(result.method).toBe('PUT');
122
+ });
123
+
124
+ test('signDownload returns a token URL', async () => {
125
+ const url = await adapter.signDownload({
126
+ hash: testHash,
127
+ expiresIn: 60,
128
+ });
129
+ expect(url).toContain('/blobs/');
130
+ expect(url).toContain('token=');
131
+ });
132
+ });