Skip to content

Commit 8e8db46

Browse files
committed
feat(filestore): added getInfo method
1 parent fe6e944 commit 8e8db46

2 files changed

Lines changed: 97 additions & 6 deletions

File tree

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828
"LICENSE"
2929
],
3030
"dependencies": {
31-
"@aws-sdk/client-s3": "^3.800.0",
32-
"@aws-sdk/credential-provider-node": "^3.799.0",
33-
"@azure/identity": "^4.9.1",
31+
"@aws-sdk/client-s3": "^3.817.0",
32+
"@aws-sdk/credential-provider-node": "^3.817.0",
33+
"@azure/identity": "^4.10.0",
3434
"@azure/service-bus": "^7.9.5",
3535
"@azure/storage-blob": "^12.27.0",
3636
"@google-cloud/pubsub": "^5.0.0",
@@ -46,14 +46,14 @@
4646
"devDependencies": {
4747
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
4848
"@types/jest": "^29.5.14",
49-
"@types/node": "^22.15.3",
49+
"@types/node": "^22.15.21",
5050
"husky": "^9.1.7",
5151
"jest": "^29.7.0",
52-
"lint-staged": "^15.5.1",
52+
"lint-staged": "^16.0.0",
5353
"npm-run-all": "^4.1.5",
5454
"prettier": "^3.5.3",
5555
"rimraf": "^6.0.1",
56-
"ts-jest": "^29.3.2",
56+
"ts-jest": "^29.3.4",
5757
"ts-node": "^10.9.2",
5858
"typescript": "^5.8.3"
5959
}

src/file-store.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,16 @@ import { FastifyInstance, FastifyPluginAsync } from "fastify";
1111
import fp from "fastify-plugin";
1212
import { streamToBuffer } from "./utils";
1313

14+
export interface FileInfo {
15+
size: number;
16+
contentType: string;
17+
lastModified: Date;
18+
}
19+
1420
export interface FileStore {
1521
exists(filepath: string): Promise<boolean>;
22+
// return null if file does not exist
23+
getInfo(filepath: string): Promise<FileInfo | null>;
1624
save(
1725
filepath: string,
1826
contentType: string,
@@ -56,6 +64,23 @@ class LocalFileStore implements FileStore {
5664
const p = path.join(this.dir, filepath);
5765
return !!(await fs.promises.stat(p));
5866
}
67+
async getInfo(filepath: string): Promise<FileInfo | null> {
68+
try {
69+
const p = path.join(this.dir, filepath);
70+
const stat = await fs.promises.stat(p);
71+
return {
72+
size: stat.size,
73+
contentType: "application/octet-stream",
74+
lastModified: stat.mtime,
75+
};
76+
} catch (err) {
77+
if (err.code === "ENOENT") {
78+
return null;
79+
}
80+
throw err;
81+
}
82+
}
83+
5984
async save(
6085
filepath: string,
6186
_contentType: string,
@@ -179,6 +204,24 @@ class AzureFileStore implements FileStore {
179204
throw new Error(resp.errorCode);
180205
}
181206
}
207+
208+
async getInfo(filepath: string): Promise<FileInfo | null> {
209+
try {
210+
const blob = this.client.getBlobClient(filepath);
211+
const properties = await blob.getProperties();
212+
213+
return {
214+
size: properties.contentLength || 0,
215+
contentType: properties.contentType || "application/octet-stream",
216+
lastModified: properties.lastModified || new Date(),
217+
};
218+
} catch (err) {
219+
if (err.statusCode === 404) {
220+
return null;
221+
}
222+
throw err;
223+
}
224+
}
182225
}
183226

184227
class GCPFileStore implements FileStore {
@@ -239,6 +282,29 @@ class GCPFileStore implements FileStore {
239282
}),
240283
);
241284
}
285+
286+
async getInfo(filepath: string): Promise<FileInfo | null> {
287+
try {
288+
const gcsfile = this.storage.bucket(this.bucket).file(filepath);
289+
const [metadata] = await gcsfile.getMetadata();
290+
291+
return {
292+
size:
293+
typeof metadata.size === "number"
294+
? metadata.size
295+
: parseInt(metadata.size ?? "0", 10) || 0,
296+
contentType: metadata.contentType || "application/octet-stream",
297+
lastModified: metadata.updated
298+
? new Date(metadata.updated)
299+
: new Date(),
300+
};
301+
} catch (err) {
302+
if (err.code === 404) {
303+
return null;
304+
}
305+
throw err;
306+
}
307+
}
242308
}
243309

244310
class S3FileStore implements FileStore {
@@ -334,6 +400,31 @@ class S3FileStore implements FileStore {
334400
}),
335401
);
336402
}
403+
404+
async getInfo(filepath: string): Promise<FileInfo | null> {
405+
try {
406+
const data = await this.client.send(
407+
new S3.HeadObjectCommand({
408+
Bucket: this.bucket,
409+
Key: filepath,
410+
}),
411+
);
412+
413+
return {
414+
size: data.ContentLength || 0,
415+
contentType: data.ContentType || "application/octet-stream",
416+
lastModified: data.LastModified || new Date(),
417+
};
418+
} catch (err) {
419+
if (
420+
err instanceof S3.NoSuchKey ||
421+
err["$metadata"]?.httpStatusCode === 404
422+
) {
423+
return null;
424+
}
425+
throw err;
426+
}
427+
}
337428
}
338429

339430
async function ConfigureLocal(f: FastifyInstance) {

0 commit comments

Comments
 (0)