@syncular/server-storage-filesystem 0.0.6-159 → 0.0.6-165
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/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +81 -23
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,14 @@ import type { BlobStorageAdapter } from '@syncular/core';
|
|
|
9
9
|
export interface BlobTokenSigner {
|
|
10
10
|
sign(payload: {
|
|
11
11
|
hash: string;
|
|
12
|
-
|
|
12
|
+
partitionId: string;
|
|
13
|
+
action: 'upload';
|
|
14
|
+
size: number;
|
|
15
|
+
expiresAt: number;
|
|
16
|
+
} | {
|
|
17
|
+
hash: string;
|
|
18
|
+
partitionId: string;
|
|
19
|
+
action: 'download';
|
|
13
20
|
expiresAt: number;
|
|
14
21
|
}, expiresInSeconds: number): Promise<string>;
|
|
15
22
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,eAAe;IAC9B,IAAI,CACF,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,eAAe;IAC9B,IAAI,CACF,OAAO,EACH;QACE,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,QAAQ,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,GACD;QACE,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,UAAU,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;KACnB,EACL,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,CAAC;CACpB;AAOD,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;AA8BD;;;;;;;;;;;GAWG;AACH,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,mCAAmC,GAC3C,kBAAkB,CAgKpB"}
|
package/dist/index.js
CHANGED
|
@@ -16,9 +16,20 @@ function hasErrnoCode(error, code) {
|
|
|
16
16
|
* Resolve hash to a 2-level subdirectory path:
|
|
17
17
|
* `{basePath}/{hex[0..2]}/{hex[2..4]}/{hex}`
|
|
18
18
|
*/
|
|
19
|
-
function
|
|
19
|
+
function normalizePartitionId(partitionId) {
|
|
20
|
+
const raw = partitionId?.trim();
|
|
21
|
+
if (!raw)
|
|
22
|
+
return 'default';
|
|
23
|
+
return raw;
|
|
24
|
+
}
|
|
25
|
+
function hashToFilePath(basePath, hash, partitionId) {
|
|
20
26
|
const hex = hash.startsWith('sha256:') ? hash.slice(7) : hash;
|
|
21
|
-
|
|
27
|
+
const normalizedPartition = normalizePartitionId(partitionId);
|
|
28
|
+
if (!partitionId || normalizedPartition === 'default') {
|
|
29
|
+
return join(basePath, hex.slice(0, 2), hex.slice(2, 4), hex);
|
|
30
|
+
}
|
|
31
|
+
const partitionPath = encodeURIComponent(normalizedPartition);
|
|
32
|
+
return join(basePath, partitionPath, hex.slice(0, 2), hex.slice(2, 4), hex);
|
|
22
33
|
}
|
|
23
34
|
function tmpPath(filePath) {
|
|
24
35
|
return `${filePath}.${Date.now()}.tmp`;
|
|
@@ -41,8 +52,15 @@ export function createFilesystemBlobStorageAdapter(options) {
|
|
|
41
52
|
return {
|
|
42
53
|
name: 'filesystem',
|
|
43
54
|
async signUpload(opts) {
|
|
55
|
+
const partitionId = normalizePartitionId(opts.partitionId);
|
|
44
56
|
const expiresAt = Date.now() + opts.expiresIn * 1000;
|
|
45
|
-
const token = await tokenSigner.sign({
|
|
57
|
+
const token = await tokenSigner.sign({
|
|
58
|
+
hash: opts.hash,
|
|
59
|
+
partitionId,
|
|
60
|
+
action: 'upload',
|
|
61
|
+
size: opts.size,
|
|
62
|
+
expiresAt,
|
|
63
|
+
}, opts.expiresIn);
|
|
46
64
|
const url = `${normalizedBaseUrl}/blobs/${encodeURIComponent(opts.hash)}/upload?token=${encodeURIComponent(token)}`;
|
|
47
65
|
return {
|
|
48
66
|
url,
|
|
@@ -54,46 +72,47 @@ export function createFilesystemBlobStorageAdapter(options) {
|
|
|
54
72
|
};
|
|
55
73
|
},
|
|
56
74
|
async signDownload(opts) {
|
|
75
|
+
const partitionId = normalizePartitionId(opts.partitionId);
|
|
57
76
|
const expiresAt = Date.now() + opts.expiresIn * 1000;
|
|
58
|
-
const token = await tokenSigner.sign({ hash: opts.hash, action: 'download', expiresAt }, opts.expiresIn);
|
|
77
|
+
const token = await tokenSigner.sign({ hash: opts.hash, partitionId, action: 'download', expiresAt }, opts.expiresIn);
|
|
59
78
|
return `${normalizedBaseUrl}/blobs/${encodeURIComponent(opts.hash)}/download?token=${encodeURIComponent(token)}`;
|
|
60
79
|
},
|
|
61
|
-
async exists(hash) {
|
|
80
|
+
async exists(hash, options) {
|
|
62
81
|
try {
|
|
63
|
-
await stat(hashToFilePath(basePath, hash));
|
|
82
|
+
await stat(hashToFilePath(basePath, hash, options?.partitionId));
|
|
64
83
|
return true;
|
|
65
84
|
}
|
|
66
85
|
catch {
|
|
67
86
|
return false;
|
|
68
87
|
}
|
|
69
88
|
},
|
|
70
|
-
async delete(hash) {
|
|
89
|
+
async delete(hash, options) {
|
|
71
90
|
try {
|
|
72
|
-
await unlink(hashToFilePath(basePath, hash));
|
|
91
|
+
await unlink(hashToFilePath(basePath, hash, options?.partitionId));
|
|
73
92
|
}
|
|
74
93
|
catch (err) {
|
|
75
94
|
if (!hasErrnoCode(err, 'ENOENT'))
|
|
76
95
|
throw err;
|
|
77
96
|
}
|
|
78
97
|
},
|
|
79
|
-
async getMetadata(hash) {
|
|
98
|
+
async getMetadata(hash, options) {
|
|
80
99
|
try {
|
|
81
|
-
const fileStats = await stat(hashToFilePath(basePath, hash));
|
|
100
|
+
const fileStats = await stat(hashToFilePath(basePath, hash, options?.partitionId));
|
|
82
101
|
return { size: fileStats.size };
|
|
83
102
|
}
|
|
84
103
|
catch {
|
|
85
104
|
return null;
|
|
86
105
|
}
|
|
87
106
|
},
|
|
88
|
-
async put(hash, data) {
|
|
89
|
-
const filePath = hashToFilePath(basePath, hash);
|
|
107
|
+
async put(hash, data, _metadata, options) {
|
|
108
|
+
const filePath = hashToFilePath(basePath, hash, options?.partitionId);
|
|
90
109
|
const tmp = tmpPath(filePath);
|
|
91
110
|
await mkdir(dirname(filePath), { recursive: true });
|
|
92
111
|
await writeFile(tmp, data);
|
|
93
112
|
await rename(tmp, filePath);
|
|
94
113
|
},
|
|
95
|
-
async putStream(hash, stream) {
|
|
96
|
-
const filePath = hashToFilePath(basePath, hash);
|
|
114
|
+
async putStream(hash, stream, _metadata, options) {
|
|
115
|
+
const filePath = hashToFilePath(basePath, hash, options?.partitionId);
|
|
97
116
|
const tmp = tmpPath(filePath);
|
|
98
117
|
await mkdir(dirname(filePath), { recursive: true });
|
|
99
118
|
const fh = await open(tmp, 'w');
|
|
@@ -111,9 +130,9 @@ export function createFilesystemBlobStorageAdapter(options) {
|
|
|
111
130
|
}
|
|
112
131
|
await rename(tmp, filePath);
|
|
113
132
|
},
|
|
114
|
-
async get(hash) {
|
|
133
|
+
async get(hash, options) {
|
|
115
134
|
try {
|
|
116
|
-
const data = await readFile(hashToFilePath(basePath, hash));
|
|
135
|
+
const data = await readFile(hashToFilePath(basePath, hash, options?.partitionId));
|
|
117
136
|
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
118
137
|
}
|
|
119
138
|
catch (err) {
|
|
@@ -122,10 +141,10 @@ export function createFilesystemBlobStorageAdapter(options) {
|
|
|
122
141
|
throw err;
|
|
123
142
|
}
|
|
124
143
|
},
|
|
125
|
-
async getStream(hash) {
|
|
144
|
+
async getStream(hash, options) {
|
|
126
145
|
let data;
|
|
127
146
|
try {
|
|
128
|
-
data = await readFile(hashToFilePath(basePath, hash));
|
|
147
|
+
data = await readFile(hashToFilePath(basePath, hash, options?.partitionId));
|
|
129
148
|
}
|
|
130
149
|
catch (err) {
|
|
131
150
|
if (hasErrnoCode(err, 'ENOENT'))
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,MAAM,EACN,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/server-storage-filesystem",
|
|
3
|
-
"version": "0.0.6-
|
|
3
|
+
"version": "0.0.6-165",
|
|
4
4
|
"description": "Filesystem blob storage adapter for Syncular server",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
"release": "bunx syncular-publish"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@syncular/core": "0.0.6-
|
|
44
|
+
"@syncular/core": "0.0.6-165"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@syncular/config": "0.0.0",
|
|
48
|
-
"@syncular/server": "0.0.6-
|
|
48
|
+
"@syncular/server": "0.0.6-165"
|
|
49
49
|
},
|
|
50
50
|
"files": [
|
|
51
51
|
"dist",
|
package/src/index.ts
CHANGED
|
@@ -25,11 +25,20 @@ import type {
|
|
|
25
25
|
|
|
26
26
|
export interface BlobTokenSigner {
|
|
27
27
|
sign(
|
|
28
|
-
payload:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
payload:
|
|
29
|
+
| {
|
|
30
|
+
hash: string;
|
|
31
|
+
partitionId: string;
|
|
32
|
+
action: 'upload';
|
|
33
|
+
size: number;
|
|
34
|
+
expiresAt: number;
|
|
35
|
+
}
|
|
36
|
+
| {
|
|
37
|
+
hash: string;
|
|
38
|
+
partitionId: string;
|
|
39
|
+
action: 'download';
|
|
40
|
+
expiresAt: number;
|
|
41
|
+
},
|
|
33
42
|
expiresInSeconds: number
|
|
34
43
|
): Promise<string>;
|
|
35
44
|
}
|
|
@@ -52,9 +61,24 @@ export interface FilesystemBlobStorageAdapterOptions {
|
|
|
52
61
|
* Resolve hash to a 2-level subdirectory path:
|
|
53
62
|
* `{basePath}/{hex[0..2]}/{hex[2..4]}/{hex}`
|
|
54
63
|
*/
|
|
55
|
-
function
|
|
64
|
+
function normalizePartitionId(partitionId?: string): string {
|
|
65
|
+
const raw = partitionId?.trim();
|
|
66
|
+
if (!raw) return 'default';
|
|
67
|
+
return raw;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hashToFilePath(
|
|
71
|
+
basePath: string,
|
|
72
|
+
hash: string,
|
|
73
|
+
partitionId?: string
|
|
74
|
+
): string {
|
|
56
75
|
const hex = hash.startsWith('sha256:') ? hash.slice(7) : hash;
|
|
57
|
-
|
|
76
|
+
const normalizedPartition = normalizePartitionId(partitionId);
|
|
77
|
+
if (!partitionId || normalizedPartition === 'default') {
|
|
78
|
+
return join(basePath, hex.slice(0, 2), hex.slice(2, 4), hex);
|
|
79
|
+
}
|
|
80
|
+
const partitionPath = encodeURIComponent(normalizedPartition);
|
|
81
|
+
return join(basePath, partitionPath, hex.slice(0, 2), hex.slice(2, 4), hex);
|
|
58
82
|
}
|
|
59
83
|
|
|
60
84
|
function tmpPath(filePath: string): string {
|
|
@@ -83,9 +107,16 @@ export function createFilesystemBlobStorageAdapter(
|
|
|
83
107
|
name: 'filesystem',
|
|
84
108
|
|
|
85
109
|
async signUpload(opts: BlobSignUploadOptions): Promise<BlobSignedUpload> {
|
|
110
|
+
const partitionId = normalizePartitionId(opts.partitionId);
|
|
86
111
|
const expiresAt = Date.now() + opts.expiresIn * 1000;
|
|
87
112
|
const token = await tokenSigner.sign(
|
|
88
|
-
{
|
|
113
|
+
{
|
|
114
|
+
hash: opts.hash,
|
|
115
|
+
partitionId,
|
|
116
|
+
action: 'upload',
|
|
117
|
+
size: opts.size,
|
|
118
|
+
expiresAt,
|
|
119
|
+
},
|
|
89
120
|
opts.expiresIn
|
|
90
121
|
);
|
|
91
122
|
|
|
@@ -102,45 +133,60 @@ export function createFilesystemBlobStorageAdapter(
|
|
|
102
133
|
},
|
|
103
134
|
|
|
104
135
|
async signDownload(opts: BlobSignDownloadOptions): Promise<string> {
|
|
136
|
+
const partitionId = normalizePartitionId(opts.partitionId);
|
|
105
137
|
const expiresAt = Date.now() + opts.expiresIn * 1000;
|
|
106
138
|
const token = await tokenSigner.sign(
|
|
107
|
-
{ hash: opts.hash, action: 'download', expiresAt },
|
|
139
|
+
{ hash: opts.hash, partitionId, action: 'download', expiresAt },
|
|
108
140
|
opts.expiresIn
|
|
109
141
|
);
|
|
110
142
|
|
|
111
143
|
return `${normalizedBaseUrl}/blobs/${encodeURIComponent(opts.hash)}/download?token=${encodeURIComponent(token)}`;
|
|
112
144
|
},
|
|
113
145
|
|
|
114
|
-
async exists(
|
|
146
|
+
async exists(
|
|
147
|
+
hash: string,
|
|
148
|
+
options?: { partitionId?: string }
|
|
149
|
+
): Promise<boolean> {
|
|
115
150
|
try {
|
|
116
|
-
await stat(hashToFilePath(basePath, hash));
|
|
151
|
+
await stat(hashToFilePath(basePath, hash, options?.partitionId));
|
|
117
152
|
return true;
|
|
118
153
|
} catch {
|
|
119
154
|
return false;
|
|
120
155
|
}
|
|
121
156
|
},
|
|
122
157
|
|
|
123
|
-
async delete(
|
|
158
|
+
async delete(
|
|
159
|
+
hash: string,
|
|
160
|
+
options?: { partitionId?: string }
|
|
161
|
+
): Promise<void> {
|
|
124
162
|
try {
|
|
125
|
-
await unlink(hashToFilePath(basePath, hash));
|
|
163
|
+
await unlink(hashToFilePath(basePath, hash, options?.partitionId));
|
|
126
164
|
} catch (err) {
|
|
127
165
|
if (!hasErrnoCode(err, 'ENOENT')) throw err;
|
|
128
166
|
}
|
|
129
167
|
},
|
|
130
168
|
|
|
131
169
|
async getMetadata(
|
|
132
|
-
hash: string
|
|
170
|
+
hash: string,
|
|
171
|
+
options?: { partitionId?: string }
|
|
133
172
|
): Promise<{ size: number; mimeType?: string } | null> {
|
|
134
173
|
try {
|
|
135
|
-
const fileStats = await stat(
|
|
174
|
+
const fileStats = await stat(
|
|
175
|
+
hashToFilePath(basePath, hash, options?.partitionId)
|
|
176
|
+
);
|
|
136
177
|
return { size: fileStats.size };
|
|
137
178
|
} catch {
|
|
138
179
|
return null;
|
|
139
180
|
}
|
|
140
181
|
},
|
|
141
182
|
|
|
142
|
-
async put(
|
|
143
|
-
|
|
183
|
+
async put(
|
|
184
|
+
hash: string,
|
|
185
|
+
data: Uint8Array,
|
|
186
|
+
_metadata?: Record<string, unknown>,
|
|
187
|
+
options?: { partitionId?: string }
|
|
188
|
+
): Promise<void> {
|
|
189
|
+
const filePath = hashToFilePath(basePath, hash, options?.partitionId);
|
|
144
190
|
const tmp = tmpPath(filePath);
|
|
145
191
|
await mkdir(dirname(filePath), { recursive: true });
|
|
146
192
|
await writeFile(tmp, data);
|
|
@@ -149,9 +195,11 @@ export function createFilesystemBlobStorageAdapter(
|
|
|
149
195
|
|
|
150
196
|
async putStream(
|
|
151
197
|
hash: string,
|
|
152
|
-
stream: ReadableStream<Uint8Array
|
|
198
|
+
stream: ReadableStream<Uint8Array>,
|
|
199
|
+
_metadata?: Record<string, unknown>,
|
|
200
|
+
options?: { partitionId?: string }
|
|
153
201
|
): Promise<void> {
|
|
154
|
-
const filePath = hashToFilePath(basePath, hash);
|
|
202
|
+
const filePath = hashToFilePath(basePath, hash, options?.partitionId);
|
|
155
203
|
const tmp = tmpPath(filePath);
|
|
156
204
|
await mkdir(dirname(filePath), { recursive: true });
|
|
157
205
|
|
|
@@ -170,9 +218,14 @@ export function createFilesystemBlobStorageAdapter(
|
|
|
170
218
|
await rename(tmp, filePath);
|
|
171
219
|
},
|
|
172
220
|
|
|
173
|
-
async get(
|
|
221
|
+
async get(
|
|
222
|
+
hash: string,
|
|
223
|
+
options?: { partitionId?: string }
|
|
224
|
+
): Promise<Uint8Array | null> {
|
|
174
225
|
try {
|
|
175
|
-
const data = await readFile(
|
|
226
|
+
const data = await readFile(
|
|
227
|
+
hashToFilePath(basePath, hash, options?.partitionId)
|
|
228
|
+
);
|
|
176
229
|
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
177
230
|
} catch (err) {
|
|
178
231
|
if (hasErrnoCode(err, 'ENOENT')) return null;
|
|
@@ -180,10 +233,15 @@ export function createFilesystemBlobStorageAdapter(
|
|
|
180
233
|
}
|
|
181
234
|
},
|
|
182
235
|
|
|
183
|
-
async getStream(
|
|
236
|
+
async getStream(
|
|
237
|
+
hash: string,
|
|
238
|
+
options?: { partitionId?: string }
|
|
239
|
+
): Promise<ReadableStream<Uint8Array> | null> {
|
|
184
240
|
let data: Uint8Array;
|
|
185
241
|
try {
|
|
186
|
-
data = await readFile(
|
|
242
|
+
data = await readFile(
|
|
243
|
+
hashToFilePath(basePath, hash, options?.partitionId)
|
|
244
|
+
);
|
|
187
245
|
} catch (err) {
|
|
188
246
|
if (hasErrnoCode(err, 'ENOENT')) return null;
|
|
189
247
|
throw err;
|