@digibuffer/file-manager-core 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.
package/README.md ADDED
@@ -0,0 +1,240 @@
1
+ # @digibuffer/file-manager-core
2
+
3
+ Complete file management library for cloud storage (R2/S3) with optional PostgreSQL database integration.
4
+
5
+ ## Features
6
+
7
+ - ✅ **Full CRUD Operations**: List, Move, Rename, Copy, Delete files
8
+ - ✅ **Dual Mode**: Storage-only or Database-backed operations
9
+ - ✅ **PostgreSQL Integration**: Store file metadata in database
10
+ - ✅ **Auto-Sync**: Automatic synchronization between cloud and database
11
+ - ✅ **Batch Operations**: Efficient batch delete and operations
12
+ - ✅ **Presigned URLs**: Generate secure download links
13
+ - ✅ **Pagination**: Built-in cursor-based pagination
14
+ - ✅ **TypeScript**: Full type safety
15
+ - ✅ **Next.js Adapter**: Easy integration with Next.js
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @digibuffer/file-manager-core
21
+ # Optional: for database support
22
+ npm install postgres
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ### Storage-Only Mode
28
+
29
+ ```typescript
30
+ import { FileManager } from '@digibuffer/file-manager-core';
31
+
32
+ const fileManager = new FileManager({
33
+ storage: {
34
+ bucket: 'my-bucket',
35
+ accessKeyId: process.env.R2_ACCESS_KEY_ID!,
36
+ secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
37
+ endpoint: process.env.R2_ENDPOINT!,
38
+ },
39
+ });
40
+
41
+ // List files
42
+ const files = await fileManager.list({ prefix: 'uploads/' });
43
+
44
+ // Move file
45
+ await fileManager.move({
46
+ sourceKey: 'old/path/file.pdf',
47
+ destinationKey: 'new/path/file.pdf',
48
+ });
49
+
50
+ // Copy file
51
+ await fileManager.copy({
52
+ sourceKey: 'original.pdf',
53
+ destinationKey: 'copy.pdf',
54
+ });
55
+
56
+ // Delete file
57
+ await fileManager.delete('file-to-delete.pdf');
58
+ ```
59
+
60
+ ### Database Mode (with PostgreSQL)
61
+
62
+ ```typescript
63
+ import { FileManager } from '@digibuffer/file-manager-core';
64
+
65
+ const fileManager = new FileManager({
66
+ storage: {
67
+ bucket: 'my-bucket',
68
+ accessKeyId: process.env.R2_ACCESS_KEY_ID!,
69
+ secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
70
+ endpoint: process.env.R2_ENDPOINT!,
71
+ },
72
+ database: {
73
+ connectionString: process.env.DATABASE_URL,
74
+ tableName: 'files', // optional, defaults to 'files'
75
+ },
76
+ defaultSource: 'database', // 'storage' | 'database' | 'both'
77
+ autoSync: true, // auto-sync storage changes to database
78
+ });
79
+
80
+ // List from database (faster)
81
+ const files = await fileManager.list({ prefix: 'uploads/' });
82
+
83
+ // List from both and merge
84
+ const allFiles = await fileManager.list({}, 'both');
85
+
86
+ // Sync storage to database
87
+ await fileManager.syncToDatabase();
88
+ ```
89
+
90
+ ## API Reference
91
+
92
+ ### Core Methods
93
+
94
+ #### `list(options, source?)`
95
+ List files with pagination and filtering.
96
+
97
+ ```typescript
98
+ const result = await fileManager.list({
99
+ prefix: 'folder/',
100
+ maxKeys: 100,
101
+ sortBy: 'lastModified',
102
+ sortOrder: 'desc',
103
+ });
104
+ ```
105
+
106
+ #### `move(options)`
107
+ Move a file to a new location.
108
+
109
+ ```typescript
110
+ await fileManager.move({
111
+ sourceKey: 'old/file.pdf',
112
+ destinationKey: 'new/file.pdf',
113
+ });
114
+ ```
115
+
116
+ #### `copy(options)`
117
+ Copy a file to a new location.
118
+
119
+ ```typescript
120
+ await fileManager.copy({
121
+ sourceKey: 'original.pdf',
122
+ destinationKey: 'copy.pdf',
123
+ metadata: { copied: 'true' },
124
+ });
125
+ ```
126
+
127
+ #### `rename(oldKey, newKey)`
128
+ Rename a file (alias for move).
129
+
130
+ ```typescript
131
+ await fileManager.rename('old-name.pdf', 'new-name.pdf');
132
+ ```
133
+
134
+ #### `delete(key)`
135
+ Delete a single file.
136
+
137
+ ```typescript
138
+ await fileManager.delete('file.pdf');
139
+ ```
140
+
141
+ #### `deleteBatch(keys)`
142
+ Delete multiple files.
143
+
144
+ ```typescript
145
+ await fileManager.deleteBatch(['file1.pdf', 'file2.pdf']);
146
+ ```
147
+
148
+ #### `getDownloadUrl(key, options?)`
149
+ Generate presigned download URL.
150
+
151
+ ```typescript
152
+ const url = await fileManager.getDownloadUrl('file.pdf', {
153
+ expiresIn: 3600,
154
+ disposition: 'attachment',
155
+ filename: 'download.pdf',
156
+ });
157
+ ```
158
+
159
+ #### `exists(key, source?)`
160
+ Check if file exists.
161
+
162
+ ```typescript
163
+ const exists = await fileManager.exists('file.pdf');
164
+ ```
165
+
166
+ #### `getMetadata(key, source?)`
167
+ Get file metadata.
168
+
169
+ ```typescript
170
+ const metadata = await fileManager.getMetadata('file.pdf');
171
+ ```
172
+
173
+ ### Next.js Integration
174
+
175
+ ```typescript
176
+ // app/api/files/route.ts
177
+ import { FileManager, createFileManagerRouter } from '@digibuffer/file-manager-core';
178
+ import { toRouteHandler, withCors } from '@digibuffer/file-manager-core/adapters/next';
179
+
180
+ const fileManager = new FileManager({
181
+ storage: { /* config */ },
182
+ database: { /* config */ },
183
+ });
184
+
185
+ const router = createFileManagerRouter({
186
+ fileManager,
187
+ authorize: async (context, operation, resource) => {
188
+ // Your authorization logic
189
+ return true;
190
+ },
191
+ getAuthContext: async (request) => {
192
+ // Extract user from session/token
193
+ return { userId: 'user-123' };
194
+ },
195
+ });
196
+
197
+ export const POST = withCors(toRouteHandler(router));
198
+ ```
199
+
200
+ ### Operation Hooks
201
+
202
+ ```typescript
203
+ const fileManager = new FileManager(config, {
204
+ beforeDelete: async (keys) => {
205
+ console.log('About to delete:', keys);
206
+ },
207
+ afterDelete: async (keys) => {
208
+ console.log('Deleted:', keys);
209
+ },
210
+ beforeMove: async (options) => {
211
+ console.log('Moving:', options);
212
+ },
213
+ afterMove: async (options) => {
214
+ console.log('Moved:', options);
215
+ },
216
+ });
217
+ ```
218
+
219
+ ## Database Schema
220
+
221
+ The library automatically creates this table:
222
+
223
+ ```sql
224
+ CREATE TABLE files (
225
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
226
+ key TEXT NOT NULL UNIQUE,
227
+ size BIGINT NOT NULL,
228
+ content_type TEXT,
229
+ etag TEXT,
230
+ user_id TEXT,
231
+ custom_metadata JSONB,
232
+ last_modified TIMESTAMP NOT NULL,
233
+ uploaded_at TIMESTAMP NOT NULL DEFAULT NOW(),
234
+ updated_at TIMESTAMP NOT NULL DEFAULT NOW()
235
+ );
236
+ ```
237
+
238
+ ## License
239
+
240
+ MIT
@@ -0,0 +1,24 @@
1
+ import { t as FileManagerRouter } from "../router-CY6g7nWy.js";
2
+ import { NextRequest } from "next/server";
3
+
4
+ //#region src/adapters/next.d.ts
5
+
6
+ /**
7
+ * Convert FileManagerRouter to Next.js App Router handler
8
+ */
9
+ declare function toRouteHandler(router: FileManagerRouter): (request: NextRequest) => Promise<Response>;
10
+ /**
11
+ * CORS options
12
+ */
13
+ interface CorsOptions {
14
+ origin?: string | string[];
15
+ methods?: string[];
16
+ allowedHeaders?: string[];
17
+ credentials?: boolean;
18
+ }
19
+ /**
20
+ * Add CORS headers to handler
21
+ */
22
+ declare function withCors<T extends Request = Request>(handler: (request: T) => Promise<Response>, options?: CorsOptions): (request: T) => Promise<Response>;
23
+ //#endregion
24
+ export { toRouteHandler, withCors };
@@ -0,0 +1,46 @@
1
+ import "../router-De_vaLLo.js";
2
+
3
+ //#region src/adapters/next.ts
4
+ /**
5
+ * Convert FileManagerRouter to Next.js App Router handler
6
+ */
7
+ function toRouteHandler(router) {
8
+ return async (request) => {
9
+ return router.handle(request);
10
+ };
11
+ }
12
+ /**
13
+ * Add CORS headers to handler
14
+ */
15
+ function withCors(handler, options = {}) {
16
+ const { origin = "*", methods = [
17
+ "GET",
18
+ "POST",
19
+ "PUT",
20
+ "DELETE",
21
+ "OPTIONS"
22
+ ], allowedHeaders = ["Content-Type", "Authorization"], credentials = false } = options;
23
+ return async (request) => {
24
+ if (request.method === "OPTIONS") return new Response(null, {
25
+ status: 204,
26
+ headers: {
27
+ "Access-Control-Allow-Origin": Array.isArray(origin) ? origin[0] : origin,
28
+ "Access-Control-Allow-Methods": methods.join(", "),
29
+ "Access-Control-Allow-Headers": allowedHeaders.join(", "),
30
+ ...credentials && { "Access-Control-Allow-Credentials": "true" }
31
+ }
32
+ });
33
+ const response = await handler(request);
34
+ const corsHeaders = new Headers(response.headers);
35
+ corsHeaders.set("Access-Control-Allow-Origin", Array.isArray(origin) ? origin[0] : origin);
36
+ if (credentials) corsHeaders.set("Access-Control-Allow-Credentials", "true");
37
+ return new Response(response.body, {
38
+ status: response.status,
39
+ statusText: response.statusText,
40
+ headers: corsHeaders
41
+ });
42
+ };
43
+ }
44
+
45
+ //#endregion
46
+ export { toRouteHandler, withCors };
@@ -0,0 +1,123 @@
1
+ import { C as PaginatedResponse, D as StorageFile, E as StorageConfig, O as StorageProvider, S as OperationResult, T as RequestAction, _ as FileOperationResponse, a as AuthorizationCallback, b as MoveOptions, c as DataSource, d as DatabaseProvider, f as DownloadUrlOptions, g as FileOperationRequest, h as FileMetadata, i as AuthContext, l as DatabaseConfig, m as FileManagerError, n as createFileManagerRouter, o as BatchOperationResult, p as FileManagerConfig, r as FileManager, s as CopyOptions, t as FileManagerRouter, u as DatabaseFile, v as ListOptions, w as PaginationCursor, x as OperationHooks, y as ManagedFile } from "./router-CY6g7nWy.js";
2
+
3
+ //#region src/storage/s3-provider.d.ts
4
+
5
+ /**
6
+ * S3/R2 Storage Provider Implementation
7
+ */
8
+ declare class S3StorageProvider implements StorageProvider {
9
+ private config;
10
+ constructor(config: StorageConfig);
11
+ /**
12
+ * List files from S3/R2 storage
13
+ */
14
+ list(options?: ListOptions): Promise<PaginatedResponse<StorageFile>>;
15
+ /**
16
+ * Delete a single file
17
+ */
18
+ delete(key: string): Promise<OperationResult>;
19
+ /**
20
+ * Delete multiple files in batch
21
+ */
22
+ deleteBatch(keys: string[]): Promise<BatchOperationResult>;
23
+ /**
24
+ * Check if file exists
25
+ */
26
+ exists(key: string): Promise<boolean>;
27
+ /**
28
+ * Get file metadata
29
+ */
30
+ getMetadata(key: string): Promise<StorageFile | null>;
31
+ /**
32
+ * Generate presigned download URL
33
+ */
34
+ getDownloadUrl(key: string, options?: DownloadUrlOptions): Promise<string>;
35
+ /**
36
+ * Move a file (copy + delete source)
37
+ */
38
+ move(options: MoveOptions): Promise<OperationResult>;
39
+ /**
40
+ * Copy a file to a new location
41
+ */
42
+ copy(options: CopyOptions): Promise<OperationResult>;
43
+ /**
44
+ * Rename a file (same as move)
45
+ */
46
+ rename(oldKey: string, newKey: string): Promise<OperationResult>;
47
+ /**
48
+ * Parse XML list response
49
+ */
50
+ private parseListResponse;
51
+ /**
52
+ * Extract continuation token from XML
53
+ */
54
+ private extractContinuationToken;
55
+ /**
56
+ * Extract value from XML tag
57
+ */
58
+ private extractXmlValue;
59
+ /**
60
+ * Sort files by specified field
61
+ */
62
+ private sortFiles;
63
+ }
64
+ //#endregion
65
+ //#region src/database/postgres-provider.d.ts
66
+ /**
67
+ * PostgreSQL Database Provider Implementation
68
+ */
69
+ declare class PostgresDatabaseProvider implements DatabaseProvider {
70
+ private sql;
71
+ private tableName;
72
+ constructor(config: DatabaseConfig);
73
+ /**
74
+ * Initialize PostgreSQL connection
75
+ */
76
+ private initializeConnection;
77
+ /**
78
+ * Create files table if it doesn't exist
79
+ */
80
+ private ensureTableExists;
81
+ /**
82
+ * List files from database
83
+ */
84
+ list(options?: ListOptions): Promise<PaginatedResponse<DatabaseFile>>;
85
+ /**
86
+ * Get a single file by key
87
+ */
88
+ get(key: string): Promise<DatabaseFile | null>;
89
+ /**
90
+ * Create a new file record
91
+ */
92
+ create(file: Omit<DatabaseFile, 'id' | 'uploadedAt' | 'updatedAt'>): Promise<DatabaseFile>;
93
+ /**
94
+ * Update file metadata
95
+ */
96
+ update(key: string, data: Partial<DatabaseFile>): Promise<DatabaseFile | null>;
97
+ /**
98
+ * Delete a file record
99
+ */
100
+ delete(key: string): Promise<OperationResult>;
101
+ /**
102
+ * Delete multiple file records
103
+ */
104
+ deleteBatch(keys: string[]): Promise<BatchOperationResult>;
105
+ /**
106
+ * Check if file exists
107
+ */
108
+ exists(key: string): Promise<boolean>;
109
+ /**
110
+ * Sync storage files to database
111
+ */
112
+ sync(storageFiles: StorageFile[]): Promise<void>;
113
+ /**
114
+ * Get sort column for SQL query
115
+ */
116
+ private getSortColumn;
117
+ /**
118
+ * Close database connection
119
+ */
120
+ close(): Promise<void>;
121
+ }
122
+ //#endregion
123
+ export { type AuthContext, type AuthorizationCallback, type BatchOperationResult, type CopyOptions, type DataSource, type DatabaseConfig, type DatabaseFile, type DatabaseProvider, type DownloadUrlOptions, FileManager, type FileManagerConfig, FileManagerError, FileManagerRouter, type FileMetadata, type FileOperationRequest, type FileOperationResponse, type ListOptions, type ManagedFile, type MoveOptions, type OperationHooks, type OperationResult, type PaginatedResponse, type PaginationCursor, PostgresDatabaseProvider, type RequestAction, S3StorageProvider, type StorageConfig, type StorageFile, type StorageProvider, createFileManagerRouter };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { a as S3StorageProvider, i as PostgresDatabaseProvider, n as createFileManagerRouter, o as FileManagerError, r as FileManager, t as FileManagerRouter } from "./router-De_vaLLo.js";
2
+
3
+ export { FileManager, FileManagerError, FileManagerRouter, PostgresDatabaseProvider, S3StorageProvider, createFileManagerRouter };