mbkbucket 3.8.3 → 4.0.1

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.
Files changed (36) hide show
  1. package/.env.example +4 -3
  2. package/README.md +375 -167
  3. package/index.js +3 -1
  4. package/lib/cli.js +239 -239
  5. package/lib/public/bucketadmin.css +855 -521
  6. package/lib/public/bucketadmin.js +367 -31
  7. package/lib/public/mbkbucket-helper-demo.html +4 -24
  8. package/lib/public/mbkbucket-helper.css +28 -34
  9. package/lib/public/mbkbucket-helper.js +4 -3
  10. package/lib/src/config/validation.js +18 -5
  11. package/lib/src/controllers/api.controller.js +66 -17
  12. package/lib/src/controllers/dashboard.controller.js +30 -10
  13. package/lib/src/controllers/info.controller.js +34 -3
  14. package/lib/src/controllers/view.controller.js +16 -14
  15. package/lib/src/core/storage/errors.js +62 -0
  16. package/lib/src/core/storage/gdrive-auth.js +193 -0
  17. package/lib/src/core/storage/gdrive-provider.js +656 -0
  18. package/lib/src/core/storage/index.js +14 -0
  19. package/lib/src/core/storage/models.js +80 -0
  20. package/lib/src/core/storage/path-strategy.js +65 -0
  21. package/lib/src/core/storage/s3-provider.js +491 -0
  22. package/lib/src/core/storage/storage-manager.js +203 -0
  23. package/lib/src/core/storage/storage-provider.js +217 -0
  24. package/lib/src/middleware/bucket-resolver.js +6 -6
  25. package/lib/src/routes/api.routes.js +5 -1
  26. package/lib/src/routes/index.js +2 -2
  27. package/lib/src/routes/view.routes.js +5 -2
  28. package/lib/src/services/s3.service.js +16 -568
  29. package/lib/src/services/storage.service.js +213 -0
  30. package/lib/src/utils/errors.js +15 -5
  31. package/package.json +2 -3
  32. package/views/bucket.hbs +47 -71
  33. package/views/bucketadmin_move_modal.hbs +35 -0
  34. package/views/bucketadmin_preview_modal.hbs +81 -13
  35. package/views/bucketadmincontent.hbs +56 -7
  36. package/views/mbkbucket_info.hbs +109 -207
package/README.md CHANGED
@@ -1,26 +1,57 @@
1
1
  # mbkbucket
2
2
 
3
- > Flexible S3/R2 bucket management — library, Express router, and CLI for mbktech.org applications.
3
+ > Flexible S3, Cloudflare R2, and Google Drive cloud storage management — library, Express router, dashboard, and standalone server CLI for mbktech.org applications.
4
4
 
5
5
  [![Version](https://img.shields.io/npm/v/mbkbucket.svg)](https://www.npmjs.com/package/mbkbucket)
6
6
  [![Downloads](https://img.shields.io/npm/dm/mbkbucket.svg)](https://www.npmjs.com/package/mbkbucket)
7
7
  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
- [![Node.js](https://img.shields.io/badge/node-%3E%3D14.0.0-brightgreen.svg)](https://nodejs.org/)
9
- [![Check npm version](https://github.com/MIbnEKhalid/mbkbucket/actions/workflows/checkLatestVersion.yml/badge.svg)]
8
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/)
9
+ [![Tests](https://img.shields.io/badge/tests-passing-brightgreen.svg)](tests)
10
10
 
11
11
  ---
12
12
 
13
13
  ## Table of Contents
14
14
 
15
+ - [What's New in v4.0.0](#whats-new-in-v400-)
15
16
  - [Installation](#installation-)
16
17
  - [Quick Start](#quick-start-)
18
+ - [Supported Storage Providers](#supported-storage-providers-)
17
19
  - [CLI Usage](#cli-usage-)
18
20
  - [Library API](#library-api-)
19
- - [Express Router](#express-router-)
21
+ - [File Operations](#file-operations)
22
+ - [Folder, Copy & Move Operations](#folder-copy--move-operations)
23
+ - [Multipart Upload](#multipart-upload)
24
+ - [Storage & Connection Management](#storage--connection-management)
25
+ - [Storage Core & Custom Drivers](#storage-core--custom-drivers)
26
+ - [Google Drive Authentication Helpers](#google-drive-authentication-helpers)
27
+ - [Key Prefixing & App Isolation](#key-prefixing--app-isolation)
28
+ - [Config & Diagnostics](#config--diagnostics)
29
+ - [Express Integration](#express-integration)
30
+ - [Express Router & HTTP API](#express-router--http-api-)
31
+ - [Endpoints](#endpoints)
32
+ - [Host-Controlled Permissions](#host-controlled-permissions)
33
+ - [Templates & Views](#templates--views)
34
+ - [Frontend Helper Client](#frontend-helper-client-)
20
35
  - [Environment Configuration](#environment-configuration-)
21
- - [Supported Storage Providers](#supported-storage-providers-)
22
- - [Tests](#automated-tests-)
23
- - [Support](#contact--support)
36
+ - [BucketConnection](#bucketconnection-required)
37
+ - [mbkautheVar](#mbkauthevar-required)
38
+ - [mbkbucketVar](#mbkbucketvar-optional)
39
+ - [Automated Tests](#automated-tests-)
40
+ - [Contact & Support](#contact--support)
41
+ - [License](#license)
42
+
43
+ ---
44
+
45
+ ## What's New in v4.0.0 🌟
46
+
47
+ - **Provider-Independent Storage Architecture**: Unified `StorageProvider` base class and dynamic `StorageManager` registry. Seamlessly switch between or combine multiple storage backends.
48
+ - **Native Google Drive Support**: First-class Google Drive provider supporting both OAuth 2.0 (user authorization code / refresh token flow) and Google Cloud Service Account credentials with folder-level targeting (`folder_id`).
49
+ - **File Move & Copy Operations**: Built-in `moveFile` and `copyFile` operations across both library functions, REST APIs, and UI modals.
50
+ - **Native Folder Creation**: Create directory markers and structure via `createFolder` with automatic folder marker resolution.
51
+ - **Redesigned Admin Dashboard**: Clean modern UI with connection health badges, provider tags, storage connection switcher dropdown, dedicated Move/Rename modal, and enhanced media previews (video range streaming, PDF, audio, and code view).
52
+ - **Frontend Drop-in Client Library (`mbkbucket-helper.js`)**: Bundled client helper with a modal gallery browser, input file picker, drag-and-drop chunked uploader, URL builders, and toast notifications. Demo page included at `/mbkbucket/helper-demo`.
53
+ - **Custom Storage Drivers**: Register custom storage engines via `storageManager.registerDriver('custom', factory)`.
54
+ - **Full Backward Compatibility**: All legacy S3 helper methods remain available and map cleanly to the underlying storage provider.
24
55
 
25
56
  ---
26
57
 
@@ -37,89 +68,105 @@ npm install mbkbucket
37
68
  ### As a Library
38
69
 
39
70
  ```js
40
- import { uploadFile, downloadFile, listfiles, deleteFile, deleteFolder, getFileMetadata, generateSignedUrl,
41
- bucket, // Express router
42
- packageJson // Package metadata
43
- } from 'mbkbucket';
44
-
45
- // Upload a file
46
- const result = await uploadFile(
47
- 'photos/sunset.jpg',
71
+ import { uploadFile, downloadFile, listfiles, copyFile, moveFile, createFolder, deleteFile, generateSignedUrl, storageManager } from 'mbkbucket';
72
+
73
+ // Upload a file to default storage (or specify connectionName / bucketName)
74
+ const upload = await uploadFile(
75
+ 'documents/invoice.pdf',
48
76
  fileBuffer,
49
- 'image/jpeg',
50
- { bucketName: 'R2_Bucket' }
77
+ 'application/pdf',
78
+ { connectionName: 'R2_Bucket' }
51
79
  );
52
80
 
53
- // List files
54
- const { Contents, hasMore } = await listfiles('photos/', {
81
+ // List files and directories
82
+ const { Contents, CommonPrefixes } = await listfiles('documents/', {
55
83
  delimiter: '/',
56
84
  maxKeys: 100
57
85
  });
58
86
 
59
- // Download a file
60
- const { Body, ContentType } = await downloadFile('photos/sunset.jpg');
87
+ // Copy or move files
88
+ await copyFile('documents/invoice.pdf', 'backup/invoice.pdf');
89
+ await moveFile('documents/invoice.pdf', 'archive/invoice-2026.pdf');
61
90
 
62
- // Generate a pre-signed URL (valid for 1 hour)
63
- const { url } = await generateSignedUrl('photos/sunset.jpg', 'getObject', 3600);
64
- ```
91
+ // Create a folder marker
92
+ await createFolder('projects/2026');
65
93
 
66
- ### As Express Middleware
94
+ // Download a file stream
95
+ const { Body, ContentType, ContentLength } = await downloadFile('archive/invoice-2026.pdf');
67
96
 
68
- ```js
69
- import mbkbucket from 'mbkbucket';
97
+ // Generate pre-signed URL (for S3-compatible providers)
98
+ const { url } = await generateSignedUrl('archive/invoice-2026.pdf', 'getObject', 3600);
70
99
 
71
- // mbkbucket is a fully configured Express app with auth, sessions, and bucket routes
72
- mbkbucket.listen(3004, () => {
73
- console.log('mbkbucket server running on http://localhost:3004');
74
- });
100
+ // Check health across active connections
101
+ const health = await storageManager.checkHealth('Google_Drive');
102
+ console.log('Google Drive status:', health.status);
75
103
  ```
76
104
 
77
- ### Host-controlled permissions
78
-
79
- The default `bucket` router remains superadmin-only. A host application can
80
- provide its own mbkauthe permission instead:
105
+ ### As Express Middleware
81
106
 
82
107
  ```js
108
+ import express from 'express';
83
109
  import { createBucketRouter } from 'mbkbucket';
84
- import { sessPerm } from 'mbkauthe';
85
- import { Permissions } from './permissions.js';
110
+ import { sessRole, sessPerm } from 'mbkauthe';
111
+
112
+ const app = express();
86
113
 
114
+ // Mount the bucket dashboard and API under /mbkbucket
87
115
  app.use(createBucketRouter({
88
116
  authorization: {
89
- view: sessPerm(Permissions.storage.view),
90
- upload: sessPerm(Permissions.storage.upload),
91
- delete: sessPerm(Permissions.storage.delete),
117
+ view: sessRole('admin'),
118
+ upload: sessPerm('storage.upload'),
119
+ delete: sessRole('superadmin'),
92
120
  },
121
+ publiViewEnabled: true,
93
122
  }));
123
+
124
+ app.listen(3004, () => {
125
+ console.log('Server running on http://localhost:3004');
126
+ });
94
127
  ```
95
128
 
96
- Define `Permissions.storage.view`, `Permissions.storage.upload`, and
97
- `Permissions.storage.delete` in the host application's permission manifest and
98
- sync that manifest with mbkauthe. The supplied middleware controls the
99
- dashboard, private views, and bucket APIs; public views and info endpoints keep
100
- their existing behavior. When no middleware is supplied, mbkbucket uses
101
- `sessRole('superadmin')` for every private operation. A single middleware may
102
- also be passed as `authorization` to protect all three operations uniformly.
129
+ ### As a Standalone Application
130
+
131
+ ```js
132
+ import mbkbucket from 'mbkbucket';
103
133
 
104
- The Express app includes:
105
- - **`/mbkbucket`** — Admin dashboard (superadmin only)
106
- - **`/mbkbucket/api/*`** — REST API for file operations
107
- - **`/mbkbucket/p_view/:key(*)`** — Public file view
108
- - **`/mbkbucket/info`** — Health & config info
134
+ // mbkbucket is a pre-configured Express app with mbkauthe sessions, views, and routes
135
+ mbkbucket.listen(3004, () => {
136
+ console.log('mbkbucket running on http://localhost:3004/mbkbucket');
137
+ });
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Supported Storage Providers 🗄️
143
+
144
+ mbkbucket v4.0.0 supports multiple object and file storage providers simultaneously:
145
+
146
+ | Provider | Type Identifier | Features / Capabilities |
147
+ |---|---|---|
148
+ | **AWS S3** | `s3` | Multipart upload, signed URLs, range streaming, server-side copy/move |
149
+ | **Cloudflare R2** | `s3` / `r2` | S3-compatible, zero egress fees, signed URLs, multipart upload |
150
+ | **Google Drive** | `gdrive` / `google-drive` | OAuth 2.0 & Service Account auth, native folder hierarchy, direct download URLs, range requests |
151
+ | **MinIO** | `s3` / `minio` | Self-hosted S3-compatible storage, multipart, signed URLs |
152
+ | **IDrive e2** | `s3` | S3-compatible high-performance object storage |
153
+ | **Backblaze B2** | `s3` | S3-compatible API endpoints |
154
+ | **DigitalOcean Spaces** | `s3` | S3-compatible object storage |
155
+ | **Custom Drivers** | Any custom name | Register via `storageManager.registerDriver(type, factory)` |
109
156
 
110
157
  ---
111
158
 
112
159
  ## CLI Usage 💻
113
160
 
114
- mbkbucket includes a CLI for running the dashboard and API as a standalone Node.js server application.
161
+ mbkbucket includes a standalone CLI server runner with built-in configuration verification, port binding, and browser launching.
115
162
 
116
163
  ### Run Standalone Server
117
164
 
118
165
  ```bash
119
- # Run using npx
166
+ # Run with npx without installation
120
167
  npx mbkbucket
121
168
 
122
- # Or after installing globally / locally
169
+ # Or after installing globally or in your repository
123
170
  mbkbucket
124
171
  ```
125
172
 
@@ -130,127 +177,279 @@ mbkbucket
130
177
  | `--port <number>` | `-p` | Port to listen on (default: `3004` or `$PORT`) |
131
178
  | `--host <host>` | `-H` | Host address to bind to (default: `0.0.0.0` or `$HOST`) |
132
179
  | `--app <name>` | `-a` | Override `APP_NAME` for bucket key prefix isolation |
133
- | `--bucket <name>` | `-b` | Override default bucket name |
180
+ | `--bucket <name>` | `-b` | Override default bucket / storage connection name |
134
181
  | `--env <path>` | `-e` | Load environment variables from a custom `.env` file |
135
182
  | `--dev` | `-d` | Run in development mode (`NODE_ENV=dev`) |
136
183
  | `--open` | `-o` | Automatically open dashboard in default browser |
137
184
  | `--version` | `-v` | Show version number |
138
185
  | `--help` | `-h` | Show help text |
139
186
 
140
- ### Examples
187
+ ### CLI Examples
141
188
 
142
189
  ```bash
143
190
  # Start server on custom port and open browser
144
191
  mbkbucket -p 8080 --open
145
192
 
146
- # Start with a specific .env file and application prefix
147
- mbkbucket --env ./configs/.env.prod -a myapp
193
+ # Start with a specific production .env file and application prefix
194
+ mbkbucket --env ./configs/.env.prod -a portalapp
148
195
  ```
149
196
 
150
197
  ---
151
198
 
152
199
  ## Library API 📚
153
200
 
154
- All functions are exported from the package root. Full TypeScript declarations in [index.d.ts](index.d.ts).
201
+ Full TypeScript declarations are available in [index.d.ts](index.d.ts).
155
202
 
156
203
  ### File Operations
157
204
 
158
205
  | Function | Description |
159
206
  |---|---|
160
- | `uploadFile(key, buffer, contentType, options?)` | Upload a file |
161
- | `downloadFile(key, options?)` | Download a file |
162
- | `deleteFile(key, bucketName?)` | Delete a single file |
163
- | `deleteFiles(keys, bucketName?)` | Batch delete up to 1000 files |
164
- | `deleteFolder(prefix, bucketName?)` | Recursively delete all files under a prefix |
165
- | `listfiles(prefix?, options?)` | List files with pagination and filtering |
166
- | `getFileMetadata(key, bucketName?)` | Get file metadata without downloading |
167
- | `fileExists(key, bucketName?)` | Check if a file exists |
168
- | `getFileSize(key, bucketName?)` | Get file size in bytes |
169
- | `generateSignedUrl(key, operation?, expiresIn?, bucketName?)` | Generate a pre-signed URL |
207
+ | `uploadFile(key, buffer, contentType, options?)` | Upload a file buffer/stream with options (`preventOverwrite`, `metadata`, `bucketName`/`connectionName`) |
208
+ | `downloadFile(key, options?)` | Download a file as a readable stream with metadata and headers |
209
+ | `deleteFile(key, connectionName?)` | Delete a single file |
210
+ | `deleteFiles(keys, connectionName?)` | Batch delete an array of files |
211
+ | `listfiles(prefix?, options?)` | List files and folders with pagination, search, or delimiter filtering |
212
+ | `getFileMetadata(key, connectionName?)` | Retrieve file metadata without downloading content |
213
+ | `fileExists(key, connectionName?)` | Check if a file exists |
214
+ | `getFileSize(key, connectionName?)` | Get file size in bytes (returns `number` or `null`) |
215
+ | `generateSignedUrl(key, operation?, expiresIn?, connectionName?)` | Generate a pre-signed URL (`getObject` or `putObject`) |
216
+
217
+ ### Folder, Copy & Move Operations
218
+
219
+ | Function | Description |
220
+ |---|---|
221
+ | `createFolder(prefix, connectionName?, options?)` | Create a folder / directory marker |
222
+ | `copyFile(sourceKey, destKey, options?, connectionName?)` | Copy a file within storage |
223
+ | `moveFile(sourceKey, destKey, options?, connectionName?)` | Move or rename a file within storage |
224
+ | `deleteFolder(prefix, connectionName?)` | Recursively delete all files under a folder prefix |
170
225
 
171
226
  ### Multipart Upload
172
227
 
228
+ *(Supported on S3-compatible providers)*
229
+
173
230
  | Function | Description |
174
231
  |---|---|
175
- | `createMultipartUpload(key, contentType?, metadata?, bucketName?)` | Start a multipart upload |
176
- | `uploadPart(key, uploadId, partNumber, buffer, bucketName?)` | Upload a single part |
177
- | `completeMultipartUpload(key, uploadId, parts, bucketName?)` | Complete a multipart upload |
178
- | `abortMultipartUpload(key, uploadId, bucketName?)` | Abort a multipart upload |
179
- | `listIncompleteMultipartUploads(prefix?, bucketName?)` | List incomplete uploads |
180
- | `cleanupIncompleteMultipartUploads(olderThanDays?, prefix?, bucketName?)` | Clean up stale uploads |
232
+ | `createMultipartUpload(key, contentType?, metadata?, connectionName?)` | Initialize a multipart upload session |
233
+ | `uploadPart(key, uploadId, partNumber, buffer, connectionName?)` | Upload an individual chunk part |
234
+ | `completeMultipartUpload(key, uploadId, parts, connectionName?)` | Finalize and assemble multipart upload |
235
+ | `abortMultipartUpload(key, uploadId, connectionName?)` | Abort and cancel a multipart upload |
236
+ | `listIncompleteMultipartUploads(prefix?, connectionName?)` | List pending / incomplete multipart uploads |
237
+ | `cleanupIncompleteMultipartUploads(olderThanDays?, prefix?, connectionName?)` | Clean up abandoned multipart chunks |
181
238
 
182
- ### Bucket Management
239
+ ### Storage & Connection Management
183
240
 
184
- | Function | Description |
241
+ | Function / Export | Description |
185
242
  |---|---|
186
- | `getAvailableBucketNames()` | List configured bucket names |
187
- | `resolveBucketName(bucketName?)` | Resolve and validate a bucket name |
188
- | `getBucketConfig(bucketName?)` | Get bucket credentials/config |
189
- | `getBucketClient(bucketName?)` | Get an S3 client instance |
190
- | `checkHealth()` | Check S3 connectivity |
243
+ | `getAvailableStorageNames()` / `getAvailableBucketNames()` | List all configured storage connection identifiers |
244
+ | `resolveStorageName(name?)` / `resolveBucketName(name?)` | Resolve and validate target connection name (falls back to default) |
245
+ | `getStorageProvider(name?)` | Get the initialized `StorageProvider` instance for a connection |
246
+ | `getStorageConfig(name?)` / `getBucketConfig(name?)` | Retrieve connection credentials and configuration object |
247
+ | `getBucketClient(bucketName?)` | Get the underlying AWS SDK S3Client instance (for S3 connections) |
248
+ | `checkHealth(name?)` | Execute health and connectivity check on a storage connection |
249
+ | `runHealthCheck(name?)` | Run diagnostic health check with console / debug output |
250
+
251
+ ### Storage Core & Custom Drivers
252
+
253
+ mbkbucket exposes its core abstraction classes so you can extend or inspect providers programmatically:
254
+
255
+ ```js
256
+ import { StorageProvider, StorageManager, storageManager } from 'mbkbucket';
191
257
 
192
- ### Key Prefixing
258
+ // Register a custom storage driver
259
+ storageManager.registerDriver('local-disk', (name, config) => {
260
+ return new MyCustomLocalStorageProvider(name, config);
261
+ });
262
+
263
+ // Register a runtime connection using the driver
264
+ storageManager.registerConnection('local_backup', {
265
+ type: 'local-disk',
266
+ basePath: '/var/storage'
267
+ });
268
+ ```
269
+
270
+ Exported classes:
271
+ - `StorageProvider`: Abstract base class with required contracts (`uploadFile`, `downloadFile`, `listFiles`, `deleteFile`, `copyFile`, `moveFile`, `createFolder`, etc.) and `capabilities` flags.
272
+ - `S3StorageProvider`: S3, Cloudflare R2, MinIO implementation.
273
+ - `GoogleDriveStorageProvider`: Google Drive implementation.
274
+ - `StorageManager` / `storageManager`: Connection registry, driver repository, and health orchestrator.
275
+ - `StorageFile`, `StorageFolder`, `StorageListResult`: Standardized metadata models.
276
+ - Custom Errors: `StorageError`, `StorageNotFoundError`, `StorageAccessDeniedError`, `StorageConflictError`, `StorageValidationError`, `StorageConfigError`, `StorageQuotaExceededError`, `StorageUnsupportedOperationError`.
277
+
278
+ ### Google Drive Authentication Helpers
279
+
280
+ mbkbucket exports helper functions for handling Google Drive OAuth 2.0 flows:
281
+
282
+ | Export | Description |
283
+ |---|---|
284
+ | `getGoogleAuthUrl(options)` | Generate Google OAuth 2.0 consent URL (`clientId`, `redirectUri`, `state`) |
285
+ | `exchangeCodeForTokens(options)` | Exchange authorization code for access and refresh tokens |
286
+ | `refreshGoogleAccessToken(options)` | Refresh an expired access token using a refresh token |
287
+ | `getServiceAccountAccessToken(options)` | Generate access token using Google Cloud Service Account credentials |
288
+ | `GOOGLE_DRIVE_SCOPES` | Standard OAuth scope strings for Google Drive (`drive.file`, `drive`, etc.) |
289
+
290
+ ### Key Prefixing & App Isolation
193
291
 
194
292
  | Function | Description |
195
293
  |---|---|
196
- | `ensureKeyHasAppPrefix(key?)` | Prefix a key with the app name |
197
- | `ensurePrefix(prefix?)` | Prefix a folder path with the app name |
198
- | `getAppName()` | Get the current app name |
294
+ | `getAppName()` | Retrieve the active application namespace from `mbkautheVar.APP_NAME` |
295
+ | `ensureKeyHasAppPrefix(key?)` | Prefix a file key with the app prefix to enforce tenant isolation |
296
+ | `ensurePrefix(prefix?)` | Prefix a folder path with the app prefix |
297
+ | `validateKeySafety(str, isKey?)` | Guard against path traversal attacks (`..`, null bytes, illegal characters) |
199
298
 
200
- ### Config
299
+ ### Config & Diagnostics
201
300
 
202
301
  | Export | Description |
203
302
  |---|---|
204
- | `packageJson` | Package metadata (version, etc.) |
205
- | `appVersion` | Parent project version |
206
- | `mbkbucketVar` | Parsed mbkbucketVar config |
207
- | `checkVersion()` | Check for newer package versions |
303
+ | `packageJson` | mbkbucket package metadata (version, license, etc.) |
304
+ | `appVersion` | Detected version of the host application |
305
+ | `mbkbucketVar` | Parsed and validated `mbkbucketVar` configuration |
306
+ | `checkVersion()` | Check GitHub releases for newer versions of mbkbucket |
307
+ | `validateConfiguration()` | Validate `mbkbucketVar` settings |
308
+ | `validateBucketConnection()` | Validate `BucketConnection` syntax and provider schemas |
309
+ | `validateAllConfiguration()` | Run all configuration validations |
208
310
 
209
- ### Express
311
+ ### Express Integration
210
312
 
211
313
  | Export | Description |
212
314
  |---|---|
213
- | `bucket` (named) | Express Router with all bucket routes |
214
- | `default` | Fully configured Express application |
315
+ | `bucket` (named) | Pre-configured Express router with superadmin protection |
316
+ | `createBucketRouter(options)` | Configurable router factory with custom permission middleware |
317
+ | `default` | Standalone Express server application ready for `.listen()` |
215
318
 
216
319
  ---
217
320
 
218
- ## Express Router 🖥️
321
+ ## Express Router & HTTP API 🖥️
322
+
323
+ ### Endpoints
324
+
325
+ All routes are mounted relative to the router path (typically `/mbkbucket`):
326
+
327
+ | Endpoint | Method | Default Access | Description |
328
+ |---|---|---|---|
329
+ | `/mbkbucket` | `GET` | `view` auth | Admin file manager dashboard UI |
330
+ | `/mbkbucket/info` | `GET` | Public / Any | Health check, provider capabilities, and runtime config info |
331
+ | `/mbkbucket/view/*key` | `GET` | `view` auth | Inline viewer with byte-range streaming for video, audio, PDF, images, text |
332
+ | `/mbkbucket/player/*key` | `GET` | `view` auth | Dedicated media player page for video and audio playback |
333
+ | `/mbkbucket/p_view/*key` | `GET` | Public | Public file viewer (enabled when `publiView_enabled` is `"true"`) |
334
+ | `/mbkbucket/download/*key` | `GET` | `view` auth | Download file with `Content-Disposition: attachment` headers |
335
+ | `/mbkbucket/api/files` | `GET` | `view` auth | List files and folders with pagination, search, and continuation tokens |
336
+ | `/mbkbucket/api/file-info/*key`| `GET` | `view` auth | Get metadata (Content-Type, size, ETag, last modified) for a key |
337
+ | `/mbkbucket/api/health` | `GET` | `view` auth | Check connectivity for active storage connection |
338
+ | `/mbkbucket/api/incomplete-uploads` | `GET` | `view` auth | List incomplete multipart uploads |
339
+ | `/mbkbucket/api/cleanup-uploads` | `POST` | `delete` auth | Clean up incomplete multipart uploads older than specified days |
340
+ | `/mbkbucket/upload` | `POST` | `upload` auth | Upload a single file via `multipart/form-data` with conflict detection |
341
+ | `/mbkbucket/upload-init` | `POST` | `upload` auth | Initiate multipart upload session |
342
+ | `/mbkbucket/upload-chunk` | `POST` | `upload` auth | Upload individual multipart chunk (up to 50MB) |
343
+ | `/mbkbucket/upload-complete` | `POST` | `upload` auth | Assemble and complete multipart upload |
344
+ | `/mbkbucket/upload-abort` | `POST` | `delete` auth | Abort pending multipart upload session |
345
+ | `/mbkbucket/create-folder` | `POST` | `upload` auth | Create a new directory folder marker |
346
+ | `/mbkbucket/delete` | `POST` | `delete` auth | Delete a single file, batch array of keys, or folder |
347
+ | `/mbkbucket/move` | `POST` | `upload` auth | Move or rename a file (`sourceKey` to `destKey`) |
348
+ | `/mbkbucket/copy` | `POST` | `upload` auth | Copy or duplicate a file (`sourceKey` to `destKey`) |
349
+
350
+ ### Host-Controlled Permissions
351
+
352
+ You can configure granular authorization per operation using `createBucketRouter`:
219
353
 
220
- ### Routes
354
+ ```js
355
+ import { createBucketRouter } from 'mbkbucket';
356
+ import { sessPerm } from 'mbkauthe';
357
+ import { Permissions } from './permissions.js';
221
358
 
222
- | Route | Auth | Description |
223
- |---|---|---|
224
- | `GET /mbkbucket` | superadmin | Admin dashboard |
225
- | `GET /mbkbucket/info` | Any | Health check & config info |
226
- | `GET /mbkbucket/p_view/:key(*)` | Public | Public file viewer |
227
- | `POST /mbkbucket/api/list` | superadmin | List files (JSON) |
228
- | `POST /mbkbucket/api/upload` | superadmin | Upload file(s) |
229
- | `POST /mbkbucket/api/delete` | superadmin | Delete file(s) |
230
- | `POST /mbkbucket/api/delete-folder` | superadmin | Delete folder |
231
- | `POST /mbkbucket/api/create-folder` | superadmin | Create folder marker |
232
- | `POST /mbkbucket/api/rename` | superadmin | Rename/move a file |
233
- | `GET /mbkbucket/api/download/:key(*)` | superadmin | Download a file |
234
- | `GET /mbkbucket/api/metadata/:key(*)` | superadmin | Get file metadata |
235
- | `POST /mbkbucket/api/multipart/init` | superadmin | Init multipart upload |
236
- | `POST /mbkbucket/api/multipart/part` | superadmin | Upload multipart chunk |
237
- | `POST /mbkbucket/api/multipart/complete` | superadmin | Complete multipart |
238
- | `POST /mbkbucket/api/multipart/abort` | superadmin | Abort multipart |
239
- | `GET /mbkbucket/api/multipart/list` | superadmin | List incomplete uploads |
240
- | `POST /mbkbucket/api/multipart/cleanup` | superadmin | Clean up stale uploads |
241
-
242
- ### Views
243
-
244
- | Template | Description |
359
+ app.use(createBucketRouter({
360
+ authorization: {
361
+ view: sessPerm(Permissions.storage.view),
362
+ upload: sessPerm(Permissions.storage.upload),
363
+ delete: sessPerm(Permissions.storage.delete),
364
+ },
365
+ publiViewEnabled: false,
366
+ }));
367
+ ```
368
+
369
+ - When no custom authorization is passed, `sessRole('superadmin')` protects all private endpoints by default.
370
+ - Passing a single middleware function to `authorization` applies that guard across all three operations.
371
+
372
+ ### Templates & Views
373
+
374
+ The Express router renders Handlebars (`.hbs`) views located in `views/`:
375
+
376
+ | Template / Partial | Description |
245
377
  |---|---|
246
- | `bucketportal.hbs` | Admin dashboard shell |
247
- | `bucketadmincontent.hbs` | File listing & management UI |
248
- | `bucketadmin_alerts.hbs` | Alert/notification partial |
249
- | `bucketadmin_delete_modal.hbs` | Delete confirmation modal |
250
- | `bucketadmin_preview_modal.hbs` | File preview modal |
251
- | `bucketadmin_filelist_skeleton.hbs` | Loading skeleton |
252
- | `bucket.hbs` | Public file viewer |
253
- | `mbkbucket_info.hbs` | Info/health page |
378
+ | `bucketportal.hbs` | Dashboard shell layout |
379
+ | `bucketadmincontent.hbs` | File manager interface with tree sidebar and storage switcher |
380
+ | `bucketadmin_alerts.hbs` | UI alerts and toast partial |
381
+ | `bucketadmin_delete_modal.hbs` | Item and folder deletion confirmation modal |
382
+ | `bucketadmin_move_modal.hbs` | File move and rename modal with destination selection |
383
+ | `bucketadmin_newfolder_modal.hbs` | New folder creation modal |
384
+ | `bucketadmin_preview_modal.hbs` | Full-screen media preview modal (images, video, audio, code, PDF) |
385
+ | `bucketadmin_upload_modal.hbs` | Chunked file upload modal with progress bars |
386
+ | `bucketadmin_filelist_skeleton.hbs`| Loading state placeholder skeleton |
387
+ | `bucket.hbs` | Public file viewer page |
388
+ | `mbkbucket_info.hbs` | Diagnostics, active connections, and environment info page |
389
+
390
+ ---
391
+
392
+ ## Frontend Helper Client 🎨
393
+
394
+ mbkbucket bundles a lightweight, zero-dependency client library served directly from your app:
395
+
396
+ - Script: `/mbkbucket/mbkbucket-helper.js`
397
+ - Styles: `/mbkbucket/mbkbucket-helper.css`
398
+ - Live interactive demo: `/mbkbucket/helper-demo`
399
+
400
+ ### Including the Helper
401
+
402
+ ```html
403
+ <link rel="stylesheet" href="/mbkbucket/mbkbucket-helper.css">
404
+ <script src="/mbkbucket/mbkbucket-helper.js"></script>
405
+ ```
406
+
407
+ ### Features
408
+
409
+ #### 1. Gallery Browser Modal
410
+ Open a rich modal browser to allow users to select one or multiple files directly from storage:
411
+
412
+ ```js
413
+ MBKBucket.openGallery({
414
+ title: 'Choose Profile Banner',
415
+ filter: 'image', // 'image' | 'video' | 'audio' | 'pdf' | 'all'
416
+ multiple: false,
417
+ onSelect: (selectedFiles) => {
418
+ console.log('Selected:', selectedFiles[0].url, selectedFiles[0].key);
419
+ }
420
+ });
421
+ ```
422
+
423
+ #### 2. File Picker Inputs
424
+ Bind an existing `<input>` element with auto-attached browse buttons and live thumbnail previews:
425
+
426
+ ```html
427
+ <input type="text" data-mbk-picker data-filter="image" data-preview="#avatar-preview">
428
+ <img id="avatar-preview" src="/placeholder.png" alt="Preview">
429
+ ```
430
+
431
+ Or programmatically:
432
+ ```js
433
+ MBKBucket.createPicker(document.getElementById('my-input'), {
434
+ filter: 'image',
435
+ onSelect: (file) => console.log('Picked:', file)
436
+ });
437
+ ```
438
+
439
+ #### 3. Upload Widget
440
+ Add a drag-and-drop uploader with automatic chunking for large files:
441
+
442
+ ```html
443
+ <div data-mbk-uploader data-prefix="uploads/users" data-allowed="image/*,video/*"></div>
444
+ ```
445
+
446
+ #### 4. Client URL Builders
447
+ ```js
448
+ MBKBucket.url.view('photos/cover.jpg'); // -> /mbkbucket/view/photos/cover.jpg
449
+ MBKBucket.url.download('reports/data.xlsx'); // -> /mbkbucket/download/reports/data.xlsx
450
+ MBKBucket.url.publicView('public/logo.png'); // -> /mbkbucket/p_view/public/logo.png
451
+ MBKBucket.url.player('media/intro.mp4'); // -> /mbkbucket/player/media/intro.mp4
452
+ ```
254
453
 
255
454
  ---
256
455
 
@@ -258,71 +457,81 @@ All functions are exported from the package root. Full TypeScript declarations i
258
457
 
259
458
  ### `BucketConnection` (required)
260
459
 
261
- JSON mapping of bucket names to S3-compatible credentials:
460
+ A JSON string defining one or more storage connections. You can configure **S3/R2** connections and **Google Drive** connections together:
262
461
 
263
462
  ```env
264
- BucketConnection={"R2_Bucket":{"BUCKET_NAME":"my-bucket","ACCESS_KEY_ID":"...","SECRET_ACCESS_KEY":"...","ENDPOINT":"https://<id>.r2.cloudflarestorage.com"}}
463
+ BucketConnection={"R2_Bucket":{"BUCKET_NAME":"my-bucket","ACCESS_KEY_ID":"your-key","SECRET_ACCESS_KEY":"your-secret","ENDPOINT":"https://<account-id>.r2.cloudflarestorage.com"},"Google_Drive":{"type":"gdrive","client_id":"your-client-id.apps.googleusercontent.com","client_secret":"your-client-secret","refresh_token":"your-refresh-token","folder_id":"root"}}
265
464
  ```
266
465
 
466
+ #### S3 / Cloudflare R2 Connection Fields
467
+
267
468
  | Field | Required | Description |
268
469
  |---|---|---|
269
470
  | `BUCKET_NAME` | Yes | Target bucket name |
270
- | `ACCESS_KEY_ID` | Yes | Access key |
271
- | `SECRET_ACCESS_KEY` | Yes | Secret key |
272
- | `ENDPOINT` | Yes | S3-compatible endpoint URL |
273
- | `region` | No | AWS region (default: `auto`) |
274
-
275
- ### `mbkautheVar` (required)
471
+ | `ACCESS_KEY_ID` | Yes | S3 Access Key ID |
472
+ | `SECRET_ACCESS_KEY` | Yes | S3 Secret Access Key |
473
+ | `ENDPOINT` | Yes | S3 API endpoint URL (e.g. `https://<id>.r2.cloudflarestorage.com` or `https://s3.us-east-1.amazonaws.com`) |
474
+ | `region` | No | Region (defaults to `'auto'` for Cloudflare R2 / custom endpoints) |
276
475
 
277
- Standard mbkauthe configuration. Key fields for mbkbucket:
476
+ #### Google Drive Connection Fields
278
477
 
279
- | Field | Description |
280
- |---|---|
281
- | `APP_NAME` | App name used for key prefix isolation |
282
- | `bucket` | Default bucket name (falls back to first in `BucketConnection`) |
283
- | `CLI_AUTH_ENABLED` | Enable CLI device-flow login (`"true"` / `"false"`) |
284
-
285
- ### `mbkbucketVar` (optional)
286
-
287
- | Field | Default | Description |
478
+ | Field | Required | Description |
288
479
  |---|---|---|
289
- | `publiView_enabled` | `"false"` | Enable public file viewer |
290
- | `p_view_inline` | `"false"` | Show files inline vs download |
480
+ | `type` | Yes | Provider tag: `"gdrive"` or `"google-drive"` |
481
+ | `client_id` | OAuth | Google OAuth 2.0 Client ID |
482
+ | `client_secret` | OAuth | Google OAuth 2.0 Client Secret |
483
+ | `refresh_token` | OAuth | Long-lived Google OAuth 2.0 refresh token |
484
+ | `folder_id` | No | Target root folder ID in Google Drive (defaults to `"root"`) |
485
+ | `client_email` | Service Account | Service Account client email (alternative to OAuth) |
486
+ | `private_key` | Service Account | Service Account PEM private key (alternative to OAuth) |
291
487
 
292
- ### Common Mistakes
488
+ #### Google Drive via Service Account Example
293
489
 
294
490
  ```env
295
- # ❌ Wrong — inner object quoted as string
296
- BucketConnection={"R2_Bucket":"{\"BUCKET_NAME\":\"...\"}"}
297
-
298
- # ✅ Correct — proper JSON nesting
299
- BucketConnection={"R2_Bucket":{"BUCKET_NAME":"...","ACCESS_KEY_ID":"...","SECRET_ACCESS_KEY":"...","ENDPOINT":"https://..."}}
491
+ BucketConnection={"Google_Drive_SA":{"type":"gdrive","client_email":"storage-sa@project.iam.gserviceaccount.com","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----","folder_id":"1A2B3C4D5E6F"}}
300
492
  ```
301
493
 
302
- ---
494
+ ### `mbkautheVar` (required)
303
495
 
304
- ## Supported Storage Providers 🗄️
496
+ Standard mbkauthe configuration. Key fields relevant to storage:
497
+
498
+ | Field | Required | Description |
499
+ |---|---|---|
500
+ | `APP_NAME` | Yes | Namespace used for automatic key prefix isolation |
501
+ | `bucket` | No | Default active connection name (falls back to first key in `BucketConnection`) |
502
+ | `loginRedirectURL` | No | URL to redirect upon authentication |
305
503
 
306
- Any S3-compatible object storage:
504
+ ### `mbkbucketVar` (optional)
307
505
 
308
- - **AWS S3**
309
- - **Cloudflare R2**
310
- - **IDrive e2**
311
- - **MinIO**
312
- - **Backblaze B2** (via S3-compatible API)
313
- - **DigitalOcean Spaces**
506
+ Optional behavioral toggles for viewers and streaming:
507
+
508
+ ```env
509
+ mbkbucketVar={"publiView_enabled":"true","p_view_inline":"true"}
510
+ ```
511
+
512
+ | Field | Default | Description |
513
+ |---|---|---|
514
+ | `publiView_enabled` | `false` | Enable or disable unauthenticated public file access under `/mbkbucket/p_view/*` |
515
+ | `p_view_inline` | `true` | Stream files inline in browser response (vs redirecting to external signed URLs) |
314
516
 
315
517
  ---
316
518
 
317
519
  ## Automated Tests 🧪
318
520
 
521
+ mbkbucket uses [Vitest](https://vitest.dev/) for unit and integration testing:
522
+
319
523
  ```bash
320
524
  npm test
321
525
  ```
322
526
 
323
- Covers:
324
- - `mbkbucketVar` parsing, defaults, and boolean normalization
325
- - `BucketConnection` shape validation and required fields
527
+ ### Test Suites Covered
528
+
529
+ - **Storage Provider & Core Abstractions**: `StorageProvider` interface contracts, capability inspection, `PathStrategy` traversal security, `StorageError` hierarchy, Google Drive consent URL generation.
530
+ - **S3 & Google Drive Drivers**: Health checks, mock provider operations, connection switching, custom driver registration.
531
+ - **API Routes Logic**: File listing, single and chunked multipart uploads, conflict detection (409), folder creation, single/batch deletion, move and copy operations, health endpoint, metadata inspection.
532
+ - **View Controller & Streaming**: Inline viewer, video byte-range streaming (`206 Partial Content`), unsupported MIME rejection (`415`), public file viewing.
533
+ - **Configuration Validation**: S3 and Google Drive connection validation, malformed JSON recovery, boolean normalization, and error messaging.
534
+ - **Public API Exports**: Verification of all exported functions, classes, and proxy objects from package root.
326
535
 
327
536
  ---
328
537
 
@@ -345,7 +554,6 @@ Part of [MBK Tech](https://mbktech.org/)
345
554
 
346
555
  Licensed under the MIT License. See [LICENSE](LICENSE) for details.
347
556
 
348
-
349
557
  <!--
350
558
  * MBKBucket
351
559
  * Copyright (c) 2026 Muhammad Bin Khalid, MBKTech.org and contributors