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.
- package/.env.example +4 -3
- package/README.md +375 -167
- package/index.js +3 -1
- package/lib/cli.js +239 -239
- package/lib/public/bucketadmin.css +855 -521
- package/lib/public/bucketadmin.js +367 -31
- package/lib/public/mbkbucket-helper-demo.html +4 -24
- package/lib/public/mbkbucket-helper.css +28 -34
- package/lib/public/mbkbucket-helper.js +4 -3
- package/lib/src/config/validation.js +18 -5
- package/lib/src/controllers/api.controller.js +66 -17
- package/lib/src/controllers/dashboard.controller.js +30 -10
- package/lib/src/controllers/info.controller.js +34 -3
- package/lib/src/controllers/view.controller.js +16 -14
- package/lib/src/core/storage/errors.js +62 -0
- package/lib/src/core/storage/gdrive-auth.js +193 -0
- package/lib/src/core/storage/gdrive-provider.js +656 -0
- package/lib/src/core/storage/index.js +14 -0
- package/lib/src/core/storage/models.js +80 -0
- package/lib/src/core/storage/path-strategy.js +65 -0
- package/lib/src/core/storage/s3-provider.js +491 -0
- package/lib/src/core/storage/storage-manager.js +203 -0
- package/lib/src/core/storage/storage-provider.js +217 -0
- package/lib/src/middleware/bucket-resolver.js +6 -6
- package/lib/src/routes/api.routes.js +5 -1
- package/lib/src/routes/index.js +2 -2
- package/lib/src/routes/view.routes.js +5 -2
- package/lib/src/services/s3.service.js +16 -568
- package/lib/src/services/storage.service.js +213 -0
- package/lib/src/utils/errors.js +15 -5
- package/package.json +2 -3
- package/views/bucket.hbs +47 -71
- package/views/bucketadmin_move_modal.hbs +35 -0
- package/views/bucketadmin_preview_modal.hbs +81 -13
- package/views/bucketadmincontent.hbs +56 -7
- package/views/mbkbucket_info.hbs +109 -207
package/README.md
CHANGED
|
@@ -1,26 +1,57 @@
|
|
|
1
1
|
# mbkbucket
|
|
2
2
|
|
|
3
|
-
> Flexible S3
|
|
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
|
[](https://www.npmjs.com/package/mbkbucket)
|
|
6
6
|
[](https://www.npmjs.com/package/mbkbucket)
|
|
7
7
|
[](LICENSE)
|
|
8
|
-
[](https://nodejs.org/)
|
|
9
|
+
[](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
|
-
- [
|
|
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
|
-
- [
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
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,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
'
|
|
50
|
-
{
|
|
77
|
+
'application/pdf',
|
|
78
|
+
{ connectionName: 'R2_Bucket' }
|
|
51
79
|
);
|
|
52
80
|
|
|
53
|
-
// List files
|
|
54
|
-
const { Contents,
|
|
81
|
+
// List files and directories
|
|
82
|
+
const { Contents, CommonPrefixes } = await listfiles('documents/', {
|
|
55
83
|
delimiter: '/',
|
|
56
84
|
maxKeys: 100
|
|
57
85
|
});
|
|
58
86
|
|
|
59
|
-
//
|
|
60
|
-
|
|
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
|
-
//
|
|
63
|
-
|
|
64
|
-
```
|
|
91
|
+
// Create a folder marker
|
|
92
|
+
await createFolder('projects/2026');
|
|
65
93
|
|
|
66
|
-
|
|
94
|
+
// Download a file stream
|
|
95
|
+
const { Body, ContentType, ContentLength } = await downloadFile('archive/invoice-2026.pdf');
|
|
67
96
|
|
|
68
|
-
|
|
69
|
-
|
|
97
|
+
// Generate pre-signed URL (for S3-compatible providers)
|
|
98
|
+
const { url } = await generateSignedUrl('archive/invoice-2026.pdf', 'getObject', 3600);
|
|
70
99
|
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
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:
|
|
90
|
-
upload: sessPerm(
|
|
91
|
-
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
|
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
|
|
166
|
+
# Run with npx without installation
|
|
120
167
|
npx mbkbucket
|
|
121
168
|
|
|
122
|
-
# Or after installing globally
|
|
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
|
|
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
|
-
|
|
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,
|
|
163
|
-
| `deleteFiles(keys,
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
|
|
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?,
|
|
176
|
-
| `uploadPart(key, uploadId, partNumber, buffer,
|
|
177
|
-
| `completeMultipartUpload(key, uploadId, parts,
|
|
178
|
-
| `abortMultipartUpload(key, uploadId,
|
|
179
|
-
| `listIncompleteMultipartUploads(prefix?,
|
|
180
|
-
| `cleanupIncompleteMultipartUploads(olderThanDays?, prefix?,
|
|
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
|
-
###
|
|
239
|
+
### Storage & Connection Management
|
|
183
240
|
|
|
184
|
-
| Function | Description |
|
|
241
|
+
| Function / Export | Description |
|
|
185
242
|
|---|---|
|
|
186
|
-
| `getAvailableBucketNames()` | List configured
|
|
187
|
-
| `resolveBucketName(
|
|
188
|
-
| `
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
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
|
-
|
|
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
|
-
| `
|
|
197
|
-
| `
|
|
198
|
-
| `
|
|
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` |
|
|
205
|
-
| `appVersion` |
|
|
206
|
-
| `mbkbucketVar` | Parsed mbkbucketVar
|
|
207
|
-
| `checkVersion()` | Check for newer
|
|
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
|
|
214
|
-
| `
|
|
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
|
-
|
|
354
|
+
```js
|
|
355
|
+
import { createBucketRouter } from 'mbkbucket';
|
|
356
|
+
import { sessPerm } from 'mbkauthe';
|
|
357
|
+
import { Permissions } from './permissions.js';
|
|
221
358
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
|
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` |
|
|
247
|
-
| `bucketadmincontent.hbs` | File
|
|
248
|
-
| `bucketadmin_alerts.hbs` |
|
|
249
|
-
| `bucketadmin_delete_modal.hbs` |
|
|
250
|
-
| `
|
|
251
|
-
| `
|
|
252
|
-
| `
|
|
253
|
-
| `
|
|
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
|
|
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":"
|
|
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
|
|
271
|
-
| `SECRET_ACCESS_KEY` | Yes | Secret
|
|
272
|
-
| `ENDPOINT` | Yes | S3
|
|
273
|
-
| `region` | No |
|
|
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
|
-
|
|
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
|
-
| `
|
|
290
|
-
| `
|
|
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
|
-
|
|
488
|
+
#### Google Drive via Service Account Example
|
|
293
489
|
|
|
294
490
|
```env
|
|
295
|
-
|
|
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
|
-
|
|
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
|
-
|
|
504
|
+
### `mbkbucketVar` (optional)
|
|
307
505
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
- `
|
|
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
|