bun-gridfs-storage 1.0.0

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,91 @@
1
+ /**
2
+ * BunGridFSStorage - Multer storage engine for GridFS
3
+ * Works with both Bun and Node.js
4
+ *
5
+ * @module bun-gridfs-storage/storage
6
+ * @author Aissam Irhir <aissamirhir@gmail.com>
7
+ */
8
+ import { EventEmitter } from "events";
9
+ import type { Request } from "express";
10
+ import { GridFSBucket } from "mongodb";
11
+ import type { BunGridFSStorageOptions, GridFSFile, MulterFile } from "./types";
12
+ /**
13
+ * Custom Bun-compatible GridFS Storage Engine for Multer
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { BunGridFSStorage } from 'bun-gridfs-storage';
18
+ * import multer from 'multer';
19
+ * import mongoose from 'mongoose';
20
+ *
21
+ * const storage = new BunGridFSStorage({
22
+ * db: mongoose.connection.db,
23
+ * file: (req, file) => ({
24
+ * filename: `${Date.now()}-${file.originalname}`,
25
+ * bucketName: 'uploads',
26
+ * }),
27
+ * });
28
+ *
29
+ * const upload = multer({ storage });
30
+ * ```
31
+ */
32
+ export declare class BunGridFSStorage extends EventEmitter {
33
+ private dbPromise;
34
+ private db;
35
+ private bucket;
36
+ private fileConfig;
37
+ private connected;
38
+ private defaultBucketName;
39
+ private defaultChunkSize;
40
+ constructor(options: BunGridFSStorageOptions);
41
+ /**
42
+ * Initialize database connection and GridFS bucket
43
+ * @private
44
+ */
45
+ private initConnection;
46
+ /**
47
+ * Multer storage engine _handleFile method
48
+ * Called when a file needs to be stored
49
+ *
50
+ * @param req - Express request object
51
+ * @param file - Multer file object
52
+ * @param cb - Callback to invoke when done
53
+ */
54
+ _handleFile(req: Request, file: MulterFile, cb: (error?: Error | null, info?: Partial<GridFSFile>) => void): Promise<void>;
55
+ /**
56
+ * Multer storage engine _removeFile method
57
+ * Called when a file needs to be removed
58
+ *
59
+ * @param _req - Express request object (unused)
60
+ * @param file - GridFS file object to remove
61
+ * @param cb - Callback to invoke when done
62
+ */
63
+ _removeFile(_req: Request, file: GridFSFile, cb: (error?: Error | null) => void): Promise<void>;
64
+ /**
65
+ * Wait for the storage to be connected
66
+ * @private
67
+ * @param maxWaitMs - Maximum time to wait in milliseconds (default: 10000)
68
+ */
69
+ private waitForConnection;
70
+ /**
71
+ * Check if storage is ready
72
+ * @returns True if connected and bucket is initialized
73
+ */
74
+ isReady(): boolean;
75
+ /**
76
+ * Get the GridFS bucket instance
77
+ * @returns GridFSBucket instance or null if not initialized
78
+ */
79
+ getBucket(): GridFSBucket | null;
80
+ /**
81
+ * Set default bucket name for new instances
82
+ * @param name - Bucket name
83
+ */
84
+ setDefaultBucketName(name: string): void;
85
+ /**
86
+ * Set default chunk size for new instances
87
+ * @param size - Chunk size in bytes
88
+ */
89
+ setDefaultChunkSize(size: number): void;
90
+ }
91
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,YAAY,EAAY,MAAM,SAAS,CAAC;AAEjD,OAAO,KAAK,EACV,uBAAuB,EAGvB,UAAU,EACV,UAAU,EACX,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,EAAE,CAAmB;IAC7B,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,gBAAgB,CAAsB;gBAElC,OAAO,EAAE,uBAAuB;IAsB5C;;;OAGG;YACW,cAAc;IA6B5B;;;;;;;OAOG;IACG,WAAW,CACf,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,UAAU,EAChB,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,GAC7D,OAAO,CAAC,IAAI,CAAC;IAkEhB;;;;;;;OAOG;IACG,WAAW,CACf,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,UAAU,EAChB,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,GACjC,OAAO,CAAC,IAAI,CAAC;IAiBhB;;;;OAIG;YACW,iBAAiB;IAsB/B;;;OAGG;IACH,OAAO,IAAI,OAAO;IAIlB;;;OAGG;IACH,SAAS,IAAI,YAAY,GAAG,IAAI;IAIhC;;;OAGG;IACH,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIxC;;;OAGG;IACH,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAGxC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * TypeScript type definitions for bun-gridfs-storage
3
+ *
4
+ * @module bun-gridfs-storage/types
5
+ * @author Aissam Irhir <aissamirhir@gmail.com>
6
+ */
7
+ import type { Request } from "express";
8
+ import type { ObjectId } from "mongodb";
9
+ /**
10
+ * GridFS file information returned after upload
11
+ */
12
+ export interface GridFSFile {
13
+ /** MongoDB ObjectId of the uploaded file */
14
+ id: ObjectId;
15
+ /** Filename used in GridFS */
16
+ filename: string;
17
+ /** Original filename from the upload */
18
+ originalname: string;
19
+ /** File encoding (e.g., "7bit", "base64") */
20
+ encoding: string;
21
+ /** MIME type of the file */
22
+ mimetype: string;
23
+ /** File size in bytes */
24
+ size: number;
25
+ /** GridFS bucket name where file is stored */
26
+ bucketName: string;
27
+ /** Custom metadata stored with the file */
28
+ metadata?: Record<string, any>;
29
+ /** Content type of the file */
30
+ contentType?: string;
31
+ /** Date when the file was uploaded */
32
+ uploadDate?: Date;
33
+ }
34
+ /**
35
+ * Configuration for storing a file in GridFS
36
+ */
37
+ export interface FileConfig {
38
+ /** Filename to use in GridFS */
39
+ filename: string;
40
+ /** GridFS bucket name */
41
+ bucketName: string;
42
+ /** Chunk size in bytes (default: 255KB) */
43
+ chunkSize?: number;
44
+ /** Custom metadata to store with the file */
45
+ metadata?: Record<string, any>;
46
+ /** Content type of the file */
47
+ contentType?: string;
48
+ }
49
+ /**
50
+ * Multer file type
51
+ */
52
+ export interface MulterFile {
53
+ fieldname: string;
54
+ originalname: string;
55
+ encoding: string;
56
+ mimetype: string;
57
+ size: number;
58
+ stream: NodeJS.ReadableStream;
59
+ destination: string;
60
+ filename: string;
61
+ path: string;
62
+ buffer: Buffer;
63
+ }
64
+ /**
65
+ * Callback function to configure file storage
66
+ * Can return a promise or the configuration directly
67
+ */
68
+ export type FileConfigCallback = (req: Request, file: MulterFile) => Promise<FileConfig> | FileConfig;
69
+ /**
70
+ * Options for initializing BunGridFSStorage
71
+ */
72
+ export interface BunGridFSStorageOptions {
73
+ /**
74
+ * MongoDB database connection
75
+ * Can be a Promise (for deferred connection) or direct Db instance
76
+ */
77
+ db: Promise<import("mongodb").Db> | import("mongodb").Db;
78
+ /**
79
+ * Optional callback to configure file storage
80
+ * If not provided, uses original filename and default bucket
81
+ */
82
+ file?: FileConfigCallback;
83
+ }
84
+ /**
85
+ * Events emitted by BunGridFSStorage
86
+ */
87
+ export interface BunGridFSStorageEvents {
88
+ /** Emitted when database connection is established */
89
+ connection: (db: import("mongodb").Db) => void;
90
+ /** Emitted when a file is successfully stored */
91
+ file: (file: GridFSFile) => void;
92
+ /** Emitted when a stream error occurs */
93
+ streamError: (error: Error, fileConfig: Partial<FileConfig>) => void;
94
+ /** Emitted when database connection fails */
95
+ connectionFailed: (error: Error) => void;
96
+ }
97
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,EAAE,EAAE,QAAQ,CAAC;IAEb,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IAEjB,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;IAErB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IAEjB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IAEjB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IAEb,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IAEnB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE/B,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,sCAAsC;IACtC,UAAU,CAAC,EAAE,IAAI,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IAEjB,yBAAyB;IACzB,UAAU,EAAE,MAAM,CAAC;IAEnB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE/B,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,UAAU,KACb,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,EAAE,EAAE,OAAO,CAAC,OAAO,SAAS,EAAE,EAAE,CAAC,GAAG,OAAO,SAAS,EAAE,EAAE,CAAC;IAEzD;;;OAGG;IACH,IAAI,CAAC,EAAE,kBAAkB,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,sDAAsD;IACtD,UAAU,EAAE,CAAC,EAAE,EAAE,OAAO,SAAS,EAAE,EAAE,KAAK,IAAI,CAAC;IAE/C,iDAAiD;IACjD,IAAI,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IAEjC,yCAAyC;IACzC,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAErE,6CAA6C;IAC7C,gBAAgB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC1C"}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "bun-gridfs-storage",
3
+ "version": "1.0.0",
4
+ "description": "A Multer storage engine for GridFS that works with both Bun and Node.js",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "src",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "scripts": {
22
+ "build": "bun run build:cjs && bun run build:esm && bun run build:types",
23
+ "build:cjs": "bun build ./src/index.ts --outfile ./dist/index.js --target node --format cjs",
24
+ "build:esm": "bun build ./src/index.ts --outfile ./dist/index.mjs --target node --format esm",
25
+ "build:types": "tsc --emitDeclarationOnly --outDir dist",
26
+ "test": "bun test",
27
+ "test:watch": "bun test --watch",
28
+ "prepublishOnly": "bun run build",
29
+ "clean": "rm -rf dist"
30
+ },
31
+ "keywords": [
32
+ "multer",
33
+ "gridfs",
34
+ "mongodb",
35
+ "storage",
36
+ "bun",
37
+ "nodejs",
38
+ "file-upload",
39
+ "mongoose"
40
+ ],
41
+ "author": "Aissam Irhir <aissamirhir@gmail.com>",
42
+ "license": "MIT",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/aissamirhir/bun-gridfs-storage.git"
46
+ },
47
+ "bugs": {
48
+ "url": "https://github.com/aissamirhir/bun-gridfs-storage/issues"
49
+ },
50
+ "homepage": "https://github.com/aissamirhir/bun-gridfs-storage#readme",
51
+ "peerDependencies": {
52
+ "mongodb": "^6.0.0",
53
+ "mongoose": "^8.0.0",
54
+ "multer": "^1.4.0"
55
+ },
56
+ "devDependencies": {
57
+ "@types/express": "^5.0.0",
58
+ "@types/multer": "^1.4.12",
59
+ "bun-types": "latest",
60
+ "typescript": "^5.9.0"
61
+ },
62
+ "engines": {
63
+ "node": ">=18.0.0",
64
+ "bun": ">=1.0.0"
65
+ }
66
+ }
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * bun-gridfs-storage - A Multer storage engine for GridFS
3
+ * Works with both Bun and Node.js
4
+ *
5
+ * @module bun-gridfs-storage
6
+ * @author Aissam Irhir <aissamirhir@gmail.com>
7
+ * @license MIT
8
+ */
9
+
10
+ export { BunGridFSStorage } from "./storage";
11
+ export type {
12
+ GridFSFile,
13
+ FileConfig,
14
+ FileConfigCallback,
15
+ BunGridFSStorageOptions,
16
+ BunGridFSStorageEvents,
17
+ MulterFile,
18
+ } from "./types";
package/src/storage.ts ADDED
@@ -0,0 +1,270 @@
1
+ /**
2
+ * BunGridFSStorage - Multer storage engine for GridFS
3
+ * Works with both Bun and Node.js
4
+ *
5
+ * @module bun-gridfs-storage/storage
6
+ * @author Aissam Irhir <aissamirhir@gmail.com>
7
+ */
8
+
9
+ import { EventEmitter } from "events";
10
+ import type { Request } from "express";
11
+ import { GridFSBucket, ObjectId } from "mongodb";
12
+ import type { Db } from "mongodb";
13
+ import type {
14
+ BunGridFSStorageOptions,
15
+ FileConfig,
16
+ FileConfigCallback,
17
+ GridFSFile,
18
+ MulterFile,
19
+ } from "./types";
20
+
21
+ /**
22
+ * Custom Bun-compatible GridFS Storage Engine for Multer
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * import { BunGridFSStorage } from 'bun-gridfs-storage';
27
+ * import multer from 'multer';
28
+ * import mongoose from 'mongoose';
29
+ *
30
+ * const storage = new BunGridFSStorage({
31
+ * db: mongoose.connection.db,
32
+ * file: (req, file) => ({
33
+ * filename: `${Date.now()}-${file.originalname}`,
34
+ * bucketName: 'uploads',
35
+ * }),
36
+ * });
37
+ *
38
+ * const upload = multer({ storage });
39
+ * ```
40
+ */
41
+ export class BunGridFSStorage extends EventEmitter {
42
+ private dbPromise: Promise<Db>;
43
+ private db: Db | null = null;
44
+ private bucket: GridFSBucket | null = null;
45
+ private fileConfig: FileConfigCallback;
46
+ private connected: boolean = false;
47
+ private defaultBucketName: string = "fs";
48
+ private defaultChunkSize: number = 255 * 1024; // 255KB
49
+
50
+ constructor(options: BunGridFSStorageOptions) {
51
+ super();
52
+
53
+ // Handle db as promise or direct value
54
+ if (options.db instanceof Promise) {
55
+ this.dbPromise = options.db;
56
+ } else {
57
+ this.dbPromise = Promise.resolve(options.db);
58
+ }
59
+
60
+ // Default file config function
61
+ this.fileConfig =
62
+ options.file ||
63
+ ((_req: Request, file: MulterFile): FileConfig => ({
64
+ filename: file.originalname,
65
+ bucketName: this.defaultBucketName,
66
+ }));
67
+
68
+ // Initialize connection
69
+ this.initConnection();
70
+ }
71
+
72
+ /**
73
+ * Initialize database connection and GridFS bucket
74
+ * @private
75
+ */
76
+ private async initConnection(): Promise<void> {
77
+ try {
78
+ this.db = await this.dbPromise;
79
+
80
+ if (!this.db) {
81
+ throw new Error("Database connection is null");
82
+ }
83
+
84
+ // Only create bucket if db.collection method exists
85
+ if (typeof this.db.collection === "function") {
86
+ this.bucket = new GridFSBucket(this.db, {
87
+ bucketName: this.defaultBucketName,
88
+ chunkSizeBytes: this.defaultChunkSize,
89
+ });
90
+
91
+ this.connected = true;
92
+ this.emit("connection", this.db);
93
+ } else {
94
+ throw new Error("Invalid database instance: missing collection method");
95
+ }
96
+ } catch (error) {
97
+ this.emit("connectionFailed", error);
98
+ // Only log in non-test environments
99
+ if (process.env.NODE_ENV !== "test") {
100
+ console.error("GridFS storage connection failed:", error);
101
+ }
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Multer storage engine _handleFile method
107
+ * Called when a file needs to be stored
108
+ *
109
+ * @param req - Express request object
110
+ * @param file - Multer file object
111
+ * @param cb - Callback to invoke when done
112
+ */
113
+ async _handleFile(
114
+ req: Request,
115
+ file: MulterFile,
116
+ cb: (error?: Error | null, info?: Partial<GridFSFile>) => void
117
+ ): Promise<void> {
118
+ try {
119
+ // Wait for connection if not ready
120
+ if (!this.connected || !this.bucket) {
121
+ await this.waitForConnection();
122
+ }
123
+
124
+ if (!this.bucket) {
125
+ throw new Error("GridFS bucket not initialized");
126
+ }
127
+
128
+ // Get file configuration
129
+ const fileConfig = await this.fileConfig(req, file);
130
+
131
+ // Create upload stream
132
+ const uploadStream = this.bucket.openUploadStream(fileConfig.filename, {
133
+ chunkSizeBytes: fileConfig.chunkSize || this.defaultChunkSize,
134
+ metadata: fileConfig.metadata,
135
+ contentType: fileConfig.contentType || file.mimetype,
136
+ });
137
+
138
+ // Track uploaded size
139
+ let size = 0;
140
+
141
+ // Handle stream events
142
+ file.stream.on("data", (chunk: Buffer) => {
143
+ size += chunk.length;
144
+ });
145
+
146
+ file.stream.on("error", (error: Error) => {
147
+ this.emit("streamError", error, fileConfig);
148
+ uploadStream.destroy(error);
149
+ cb(error);
150
+ });
151
+
152
+ uploadStream.on("error", (error: Error) => {
153
+ this.emit("streamError", error, fileConfig);
154
+ cb(error);
155
+ });
156
+
157
+ uploadStream.on("finish", () => {
158
+ const storedFile: GridFSFile = {
159
+ id: uploadStream.id as ObjectId,
160
+ filename: fileConfig.filename,
161
+ originalname: file.originalname,
162
+ encoding: file.encoding,
163
+ mimetype: file.mimetype,
164
+ size: size,
165
+ bucketName: fileConfig.bucketName,
166
+ metadata: fileConfig.metadata,
167
+ contentType: fileConfig.contentType || file.mimetype,
168
+ uploadDate: new Date(),
169
+ };
170
+
171
+ this.emit("file", storedFile);
172
+ cb(null, storedFile);
173
+ });
174
+
175
+ // Pipe the file stream to GridFS
176
+ file.stream.pipe(uploadStream);
177
+ } catch (error: any) {
178
+ this.emit("streamError", error, {});
179
+ cb(error);
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Multer storage engine _removeFile method
185
+ * Called when a file needs to be removed
186
+ *
187
+ * @param _req - Express request object (unused)
188
+ * @param file - GridFS file object to remove
189
+ * @param cb - Callback to invoke when done
190
+ */
191
+ async _removeFile(
192
+ _req: Request,
193
+ file: GridFSFile,
194
+ cb: (error?: Error | null) => void
195
+ ): Promise<void> {
196
+ try {
197
+ if (!this.bucket) {
198
+ await this.waitForConnection();
199
+ }
200
+
201
+ if (!this.bucket) {
202
+ throw new Error("GridFS bucket not initialized");
203
+ }
204
+
205
+ await this.bucket.delete(file.id);
206
+ cb(null);
207
+ } catch (error: any) {
208
+ cb(error);
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Wait for the storage to be connected
214
+ * @private
215
+ * @param maxWaitMs - Maximum time to wait in milliseconds (default: 10000)
216
+ */
217
+ private async waitForConnection(maxWaitMs: number = 10000): Promise<void> {
218
+ if (this.connected && this.bucket) {
219
+ return;
220
+ }
221
+
222
+ return new Promise((resolve, reject) => {
223
+ const startTime = Date.now();
224
+
225
+ const checkConnection = () => {
226
+ if (this.connected && this.bucket) {
227
+ resolve();
228
+ } else if (Date.now() - startTime > maxWaitMs) {
229
+ reject(new Error("Timeout waiting for GridFS connection"));
230
+ } else {
231
+ setTimeout(checkConnection, 100);
232
+ }
233
+ };
234
+
235
+ checkConnection();
236
+ });
237
+ }
238
+
239
+ /**
240
+ * Check if storage is ready
241
+ * @returns True if connected and bucket is initialized
242
+ */
243
+ isReady(): boolean {
244
+ return this.connected && this.bucket !== null;
245
+ }
246
+
247
+ /**
248
+ * Get the GridFS bucket instance
249
+ * @returns GridFSBucket instance or null if not initialized
250
+ */
251
+ getBucket(): GridFSBucket | null {
252
+ return this.bucket;
253
+ }
254
+
255
+ /**
256
+ * Set default bucket name for new instances
257
+ * @param name - Bucket name
258
+ */
259
+ setDefaultBucketName(name: string): void {
260
+ this.defaultBucketName = name;
261
+ }
262
+
263
+ /**
264
+ * Set default chunk size for new instances
265
+ * @param size - Chunk size in bytes
266
+ */
267
+ setDefaultChunkSize(size: number): void {
268
+ this.defaultChunkSize = size;
269
+ }
270
+ }
package/src/types.ts ADDED
@@ -0,0 +1,123 @@
1
+ /**
2
+ * TypeScript type definitions for bun-gridfs-storage
3
+ *
4
+ * @module bun-gridfs-storage/types
5
+ * @author Aissam Irhir <aissamirhir@gmail.com>
6
+ */
7
+
8
+ import type { Request } from "express";
9
+ import type { ObjectId } from "mongodb";
10
+
11
+ /**
12
+ * GridFS file information returned after upload
13
+ */
14
+ export interface GridFSFile {
15
+ /** MongoDB ObjectId of the uploaded file */
16
+ id: ObjectId;
17
+
18
+ /** Filename used in GridFS */
19
+ filename: string;
20
+
21
+ /** Original filename from the upload */
22
+ originalname: string;
23
+
24
+ /** File encoding (e.g., "7bit", "base64") */
25
+ encoding: string;
26
+
27
+ /** MIME type of the file */
28
+ mimetype: string;
29
+
30
+ /** File size in bytes */
31
+ size: number;
32
+
33
+ /** GridFS bucket name where file is stored */
34
+ bucketName: string;
35
+
36
+ /** Custom metadata stored with the file */
37
+ metadata?: Record<string, any>;
38
+
39
+ /** Content type of the file */
40
+ contentType?: string;
41
+
42
+ /** Date when the file was uploaded */
43
+ uploadDate?: Date;
44
+ }
45
+
46
+ /**
47
+ * Configuration for storing a file in GridFS
48
+ */
49
+ export interface FileConfig {
50
+ /** Filename to use in GridFS */
51
+ filename: string;
52
+
53
+ /** GridFS bucket name */
54
+ bucketName: string;
55
+
56
+ /** Chunk size in bytes (default: 255KB) */
57
+ chunkSize?: number;
58
+
59
+ /** Custom metadata to store with the file */
60
+ metadata?: Record<string, any>;
61
+
62
+ /** Content type of the file */
63
+ contentType?: string;
64
+ }
65
+
66
+ /**
67
+ * Multer file type
68
+ */
69
+ export interface MulterFile {
70
+ fieldname: string;
71
+ originalname: string;
72
+ encoding: string;
73
+ mimetype: string;
74
+ size: number;
75
+ stream: NodeJS.ReadableStream;
76
+ destination: string;
77
+ filename: string;
78
+ path: string;
79
+ buffer: Buffer;
80
+ }
81
+
82
+ /**
83
+ * Callback function to configure file storage
84
+ * Can return a promise or the configuration directly
85
+ */
86
+ export type FileConfigCallback = (
87
+ req: Request,
88
+ file: MulterFile
89
+ ) => Promise<FileConfig> | FileConfig;
90
+
91
+ /**
92
+ * Options for initializing BunGridFSStorage
93
+ */
94
+ export interface BunGridFSStorageOptions {
95
+ /**
96
+ * MongoDB database connection
97
+ * Can be a Promise (for deferred connection) or direct Db instance
98
+ */
99
+ db: Promise<import("mongodb").Db> | import("mongodb").Db;
100
+
101
+ /**
102
+ * Optional callback to configure file storage
103
+ * If not provided, uses original filename and default bucket
104
+ */
105
+ file?: FileConfigCallback;
106
+ }
107
+
108
+ /**
109
+ * Events emitted by BunGridFSStorage
110
+ */
111
+ export interface BunGridFSStorageEvents {
112
+ /** Emitted when database connection is established */
113
+ connection: (db: import("mongodb").Db) => void;
114
+
115
+ /** Emitted when a file is successfully stored */
116
+ file: (file: GridFSFile) => void;
117
+
118
+ /** Emitted when a stream error occurs */
119
+ streamError: (error: Error, fileConfig: Partial<FileConfig>) => void;
120
+
121
+ /** Emitted when database connection fails */
122
+ connectionFailed: (error: Error) => void;
123
+ }