mbkbucket 4.0.0 → 4.1.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/.env.example +16 -15
- package/README.md +613 -561
- package/index.js +36 -33
- package/lib/cli.js +239 -239
- package/lib/public/bucketadmin.css +2042 -2042
- package/lib/public/bucketadmin.js +1844 -1622
- package/lib/public/mbkbucket-helper-demo.html +0 -58
- package/lib/public/mbkbucket-helper.js +1 -9
- package/lib/src/config/validation.js +91 -86
- package/lib/src/controllers/api.controller.js +486 -459
- package/lib/src/controllers/dashboard.controller.js +69 -69
- package/lib/src/controllers/info.controller.js +13 -13
- package/lib/src/controllers/view.controller.js +234 -233
- package/lib/src/core/metrics.js +134 -0
- package/lib/src/core/storage/capabilities.js +58 -0
- package/lib/src/core/storage/errors.js +0 -5
- package/lib/src/core/storage/gdrive-auth.js +0 -36
- package/lib/src/core/storage/gdrive-provider.js +101 -43
- package/lib/src/core/storage/index.js +4 -1
- package/lib/src/core/storage/local-provider.js +507 -0
- package/lib/src/core/storage/models.js +90 -50
- package/lib/src/core/storage/path-strategy.js +14 -1
- package/lib/src/core/storage/s3-provider.js +17 -37
- package/lib/src/core/storage/storage-manager.js +70 -50
- package/lib/src/core/storage/storage-provider.js +49 -120
- package/lib/src/middleware/bucket-resolver.js +37 -37
- package/lib/src/routes/api.routes.js +4 -1
- package/lib/src/routes/index.js +60 -60
- package/lib/src/routes/view.routes.js +28 -28
- package/lib/src/services/s3.service.js +42 -42
- package/lib/src/services/storage.service.js +311 -213
- package/lib/src/utils/cleanup-scheduler.js +91 -0
- package/lib/src/utils/errors.js +56 -56
- package/lib/src/utils/helpers.js +6 -6
- package/package.json +3 -5
- package/views/bucket.hbs +0 -5
- package/views/bucketadmin_move_modal.hbs +35 -35
- package/views/bucketadmin_preview_modal.hbs +108 -108
- package/views/bucketadmincontent.hbs +193 -193
- package/views/mbkbucket_info.hbs +134 -134
package/index.js
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MBKBucket
|
|
3
|
-
* Copyright (c) 2026 Muhammad Bin Khalid, MBKTech.org and contributors
|
|
4
|
-
* Licensed under the MIT License.
|
|
5
|
-
* Source: https://github.com/MIbnEKhalid/mbkbucket
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import dotenv from "dotenv";
|
|
9
|
-
import { createApp } from "./lib/src/app.js";
|
|
10
|
-
import { checkVersion } from "./lib/src/config/index.js";
|
|
11
|
-
import { runHealthCheck } from "./lib/src/services/storage.service.js";
|
|
12
|
-
import { createLogger } from "#logger";
|
|
13
|
-
|
|
14
|
-
dotenv.config();
|
|
15
|
-
|
|
16
|
-
const debugServer = createLogger('server');
|
|
17
|
-
const port = process.env.PORT || 3004;
|
|
18
|
-
const server = createApp();
|
|
19
|
-
|
|
20
|
-
if (process.env.NODE_ENV === "dev") {
|
|
21
|
-
await checkVersion();
|
|
22
|
-
await runHealthCheck();
|
|
23
|
-
server.listen(port, () => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
export * from "./lib/src/
|
|
30
|
-
export * from "./lib/src/
|
|
31
|
-
export * from "./lib/src/
|
|
32
|
-
export
|
|
33
|
-
export
|
|
1
|
+
/**
|
|
2
|
+
* MBKBucket
|
|
3
|
+
* Copyright (c) 2026 Muhammad Bin Khalid, MBKTech.org and contributors
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
* Source: https://github.com/MIbnEKhalid/mbkbucket
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import dotenv from "dotenv";
|
|
9
|
+
import { createApp } from "./lib/src/app.js";
|
|
10
|
+
import { checkVersion } from "./lib/src/config/index.js";
|
|
11
|
+
import { runHealthCheck } from "./lib/src/services/storage.service.js";
|
|
12
|
+
import { createLogger } from "#logger";
|
|
13
|
+
|
|
14
|
+
dotenv.config();
|
|
15
|
+
|
|
16
|
+
const debugServer = createLogger('server');
|
|
17
|
+
const port = process.env.PORT || 3004;
|
|
18
|
+
const server = createApp();
|
|
19
|
+
|
|
20
|
+
if (process.env.NODE_ENV === "dev") {
|
|
21
|
+
await checkVersion();
|
|
22
|
+
await runHealthCheck();
|
|
23
|
+
server.listen(port, () => {
|
|
24
|
+
console.log(`[mbkbucket] 🚀 Server running on http://localhost:${port}`);
|
|
25
|
+
debugServer("Server running on http://localhost:%s", port);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export * from "./lib/src/core/storage/index.js";
|
|
30
|
+
export * from "./lib/src/core/metrics.js";
|
|
31
|
+
export * from "./lib/src/utils/cleanup-scheduler.js";
|
|
32
|
+
export * from "./lib/src/services/storage.service.js";
|
|
33
|
+
export * from "./lib/src/services/s3.service.js";
|
|
34
|
+
export * from "./lib/src/config/index.js";
|
|
35
|
+
export { default as bucket, createBucketRouter } from "./lib/src/routes/index.js";
|
|
36
|
+
export default server;
|
package/lib/cli.js
CHANGED
|
@@ -1,239 +1,239 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* MBKBucket
|
|
5
|
-
* Copyright (c) 2026 Muhammad Bin Khalid, MBKTech.org and contributors
|
|
6
|
-
* Licensed under the MIT License.
|
|
7
|
-
* Source: https://github.com/MIbnEKhalid/mbkbucket
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* mbkbucket CLI — Standalone server runner for MBKBucket web application.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import dotenv from 'dotenv';
|
|
15
|
-
import path from 'node:path';
|
|
16
|
-
import os from 'node:os';
|
|
17
|
-
import { createApp } from './src/app.js';
|
|
18
|
-
import { packageJson, checkVersion } from './src/config/index.js';
|
|
19
|
-
import { checkHealth, getAvailableBucketNames } from './src/services/s3.service.js';
|
|
20
|
-
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
// ANSI Color helpers
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
const c = {
|
|
25
|
-
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
26
|
-
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
27
|
-
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
28
|
-
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
29
|
-
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
30
|
-
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
// Parse CLI arguments
|
|
35
|
-
// ---------------------------------------------------------------------------
|
|
36
|
-
const args = process.argv.slice(2);
|
|
37
|
-
|
|
38
|
-
function findFlag(name, shortChar) {
|
|
39
|
-
const long = `--${name}`;
|
|
40
|
-
const short = shortChar ? `-${shortChar}` : `-${name[0]}`;
|
|
41
|
-
for (let i = 0; i < args.length; i++) {
|
|
42
|
-
if (args[i] === long || args[i] === short) {
|
|
43
|
-
if (args[i + 1] !== undefined && !args[i + 1].startsWith('-')) {
|
|
44
|
-
return args[i + 1];
|
|
45
|
-
}
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return undefined;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const hasFlag = (name, shortChar) => {
|
|
53
|
-
const long = `--${name}`;
|
|
54
|
-
const short = shortChar ? `-${shortChar}` : `-${name[0]}`;
|
|
55
|
-
return args.includes(long) || args.includes(short);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
// Help & Version
|
|
60
|
-
// ---------------------------------------------------------------------------
|
|
61
|
-
function showHelp() {
|
|
62
|
-
console.log(`
|
|
63
|
-
${c.cyan(c.bold('⚡ mbkbucket'))} ${c.dim(`v${packageJson.version}`)}
|
|
64
|
-
Standalone S3/R2 Bucket Management Server
|
|
65
|
-
|
|
66
|
-
${c.bold('USAGE:')}
|
|
67
|
-
mbkbucket [options]
|
|
68
|
-
npx mbkbucket [options]
|
|
69
|
-
|
|
70
|
-
${c.bold('OPTIONS:')}
|
|
71
|
-
-p, --port <number> Port to listen on (default: 3004 or $PORT)
|
|
72
|
-
-H, --host <host> Host address to bind (default: 0.0.0.0 or $HOST)
|
|
73
|
-
-a, --app <name> Override APP_NAME for bucket key prefix isolation
|
|
74
|
-
-b, --bucket <name> Override default bucket name (MBKAUTHE_BUCKET)
|
|
75
|
-
-e, --env <path> Load environment variables from a custom .env file
|
|
76
|
-
-d, --dev Run in development mode (NODE_ENV=dev)
|
|
77
|
-
-o, --open Automatically open the dashboard in default browser
|
|
78
|
-
-v, --version Show version number
|
|
79
|
-
-h, --help Show this help message
|
|
80
|
-
|
|
81
|
-
${c.bold('ENVIRONMENT VARIABLES:')}
|
|
82
|
-
PORT Server port (default: 3004)
|
|
83
|
-
HOST Server host (default: 0.0.0.0)
|
|
84
|
-
NODE_ENV Environment mode ('production' | 'dev')
|
|
85
|
-
BucketConnection JSON mapping of bucket name -> S3 credentials
|
|
86
|
-
mbkautheVar mbkauthe configuration JSON
|
|
87
|
-
mbkbucketVar mbkbucket configuration JSON
|
|
88
|
-
|
|
89
|
-
${c.bold('EXAMPLES:')}
|
|
90
|
-
$ mbkbucket
|
|
91
|
-
$ mbkbucket -p 8080 --open
|
|
92
|
-
$ mbkbucket --env ./configs/.env.prod -a myapp
|
|
93
|
-
`);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function showVersion() {
|
|
97
|
-
console.log(`mbkbucket v${packageJson.version}`);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function getNetworkIp() {
|
|
101
|
-
try {
|
|
102
|
-
const nets = os.networkInterfaces();
|
|
103
|
-
for (const name of Object.keys(nets)) {
|
|
104
|
-
for (const net of nets[name] ?? []) {
|
|
105
|
-
if (net.family === 'IPv4' && !net.internal) return net.address;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
} catch {}
|
|
109
|
-
return undefined;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function openBrowser(url) {
|
|
113
|
-
const platform = process.platform;
|
|
114
|
-
let cmd = '';
|
|
115
|
-
if (platform === 'darwin') cmd = `open "${url}"`;
|
|
116
|
-
else if (platform === 'win32') cmd = `start "" "${url}"`;
|
|
117
|
-
else cmd = `xdg-open "${url}"`;
|
|
118
|
-
import('node:child_process').then(({ exec }) => {
|
|
119
|
-
exec(cmd, () => {});
|
|
120
|
-
}).catch(() => {});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ---------------------------------------------------------------------------
|
|
124
|
-
// Main Runner
|
|
125
|
-
// ---------------------------------------------------------------------------
|
|
126
|
-
async function main() {
|
|
127
|
-
if (hasFlag('help', 'h')) {
|
|
128
|
-
showHelp();
|
|
129
|
-
process.exit(0);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (hasFlag('version', 'v')) {
|
|
133
|
-
showVersion();
|
|
134
|
-
process.exit(0);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Load custom or default .env
|
|
138
|
-
const envPath = findFlag('env', 'e');
|
|
139
|
-
if (typeof envPath === 'string') {
|
|
140
|
-
dotenv.config({ path: path.resolve(process.cwd(), envPath) });
|
|
141
|
-
} else {
|
|
142
|
-
dotenv.config();
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Handle environment overrides from flags
|
|
146
|
-
const appFlag = findFlag('app', 'a');
|
|
147
|
-
if (typeof appFlag === 'string') {
|
|
148
|
-
process.env.APP_NAME = appFlag;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const bucketFlag = findFlag('bucket', 'b');
|
|
152
|
-
if (typeof bucketFlag === 'string') {
|
|
153
|
-
process.env.MBKAUTHE_BUCKET = bucketFlag;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (hasFlag('dev', 'd')) {
|
|
157
|
-
process.env.NODE_ENV = 'dev';
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const port = parseInt(findFlag('port', 'p') || process.env.PORT || '3004', 10);
|
|
161
|
-
const host = findFlag('host', 'H') || process.env.HOST || '0.0.0.0';
|
|
162
|
-
const shouldOpen = hasFlag('open', 'o');
|
|
163
|
-
|
|
164
|
-
// Check version in background
|
|
165
|
-
await checkVersion();
|
|
166
|
-
|
|
167
|
-
// Test S3 connectivity
|
|
168
|
-
let healthResult = null;
|
|
169
|
-
try {
|
|
170
|
-
healthResult = await checkHealth();
|
|
171
|
-
} catch (err) {
|
|
172
|
-
healthResult = { status: 'unhealthy', error: err.message };
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Create express application
|
|
176
|
-
const app = createApp();
|
|
177
|
-
|
|
178
|
-
const server = app.listen(port, host, () => {
|
|
179
|
-
const isAnyHost = host === '0.0.0.0' || host === '::' || host === '';
|
|
180
|
-
const displayHost = isAnyHost ? 'localhost' : host;
|
|
181
|
-
const localUrl = `http://${displayHost}:${port}/mbkbucket`;
|
|
182
|
-
|
|
183
|
-
console.log();
|
|
184
|
-
console.log(` ${c.cyan(c.bold('⚡ MBKBucket'))} ${c.dim(`v${packageJson.version}`)}`);
|
|
185
|
-
console.log();
|
|
186
|
-
console.log(` ${c.green('➜')} ${c.bold('Local:')} ${c.cyan(localUrl)}`);
|
|
187
|
-
|
|
188
|
-
if (isAnyHost) {
|
|
189
|
-
const netIp = getNetworkIp();
|
|
190
|
-
if (netIp) {
|
|
191
|
-
console.log(` ${c.green('➜')} ${c.bold('Network:')} ${c.cyan(`http://${netIp}:${port}/mbkbucket`)}`);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const appName = process.env.APP_NAME || 'root';
|
|
196
|
-
console.log(` ${c.green('➜')} ${c.bold('App Name:')} ${appName}`);
|
|
197
|
-
|
|
198
|
-
let bucketNames = [];
|
|
199
|
-
try {
|
|
200
|
-
bucketNames = getAvailableBucketNames();
|
|
201
|
-
} catch {}
|
|
202
|
-
|
|
203
|
-
if (bucketNames.length > 0) {
|
|
204
|
-
console.log(` ${c.green('➜')} ${c.bold('Buckets:')} ${bucketNames.join(', ')}`);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (healthResult?.status === 'healthy') {
|
|
208
|
-
console.log(` ${c.green('➜')} ${c.bold('Storage:')} ${c.green('✓ Connected')} (${healthResult.bucket} in ${healthResult.responseTime}ms)`);
|
|
209
|
-
} else if (healthResult?.error) {
|
|
210
|
-
console.log(` ${c.yellow('➜')} ${c.bold('Storage:')} ${c.yellow('⚠ Connection warning')} (${healthResult.error})`);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
console.log();
|
|
214
|
-
console.log(` ${c.dim('Press Ctrl+C to stop the server')}`);
|
|
215
|
-
console.log();
|
|
216
|
-
|
|
217
|
-
if (shouldOpen) {
|
|
218
|
-
openBrowser(localUrl);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
const shutdown = (signal) => {
|
|
223
|
-
console.log(`\n ${c.dim(`Received ${signal}, shutting down...`)}`);
|
|
224
|
-
server.close(() => {
|
|
225
|
-
console.log(` ${c.green('✓')} ${c.dim('MBKBucket server stopped.')}\n`);
|
|
226
|
-
process.exit(0);
|
|
227
|
-
});
|
|
228
|
-
setTimeout(() => process.exit(0), 2000).unref();
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
232
|
-
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
main().catch((err) => {
|
|
236
|
-
console.error(`\n${c.red(c.bold('Error starting mbkbucket:'))} ${err.message}`);
|
|
237
|
-
if (process.env.DEBUG) console.error(err);
|
|
238
|
-
process.exit(1);
|
|
239
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MBKBucket
|
|
5
|
+
* Copyright (c) 2026 Muhammad Bin Khalid, MBKTech.org and contributors
|
|
6
|
+
* Licensed under the MIT License.
|
|
7
|
+
* Source: https://github.com/MIbnEKhalid/mbkbucket
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* mbkbucket CLI — Standalone server runner for MBKBucket web application.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import dotenv from 'dotenv';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
import { createApp } from './src/app.js';
|
|
18
|
+
import { packageJson, checkVersion } from './src/config/index.js';
|
|
19
|
+
import { checkHealth, getAvailableBucketNames } from './src/services/s3.service.js';
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// ANSI Color helpers
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const c = {
|
|
25
|
+
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
26
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
27
|
+
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
28
|
+
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
29
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
30
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Parse CLI arguments
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
const args = process.argv.slice(2);
|
|
37
|
+
|
|
38
|
+
function findFlag(name, shortChar) {
|
|
39
|
+
const long = `--${name}`;
|
|
40
|
+
const short = shortChar ? `-${shortChar}` : `-${name[0]}`;
|
|
41
|
+
for (let i = 0; i < args.length; i++) {
|
|
42
|
+
if (args[i] === long || args[i] === short) {
|
|
43
|
+
if (args[i + 1] !== undefined && !args[i + 1].startsWith('-')) {
|
|
44
|
+
return args[i + 1];
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const hasFlag = (name, shortChar) => {
|
|
53
|
+
const long = `--${name}`;
|
|
54
|
+
const short = shortChar ? `-${shortChar}` : `-${name[0]}`;
|
|
55
|
+
return args.includes(long) || args.includes(short);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Help & Version
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
function showHelp() {
|
|
62
|
+
console.log(`
|
|
63
|
+
${c.cyan(c.bold('⚡ mbkbucket'))} ${c.dim(`v${packageJson.version}`)}
|
|
64
|
+
Standalone S3/R2 Bucket Management Server
|
|
65
|
+
|
|
66
|
+
${c.bold('USAGE:')}
|
|
67
|
+
mbkbucket [options]
|
|
68
|
+
npx mbkbucket [options]
|
|
69
|
+
|
|
70
|
+
${c.bold('OPTIONS:')}
|
|
71
|
+
-p, --port <number> Port to listen on (default: 3004 or $PORT)
|
|
72
|
+
-H, --host <host> Host address to bind (default: 0.0.0.0 or $HOST)
|
|
73
|
+
-a, --app <name> Override APP_NAME for bucket key prefix isolation
|
|
74
|
+
-b, --bucket <name> Override default bucket name (MBKAUTHE_BUCKET)
|
|
75
|
+
-e, --env <path> Load environment variables from a custom .env file
|
|
76
|
+
-d, --dev Run in development mode (NODE_ENV=dev)
|
|
77
|
+
-o, --open Automatically open the dashboard in default browser
|
|
78
|
+
-v, --version Show version number
|
|
79
|
+
-h, --help Show this help message
|
|
80
|
+
|
|
81
|
+
${c.bold('ENVIRONMENT VARIABLES:')}
|
|
82
|
+
PORT Server port (default: 3004)
|
|
83
|
+
HOST Server host (default: 0.0.0.0)
|
|
84
|
+
NODE_ENV Environment mode ('production' | 'dev')
|
|
85
|
+
BucketConnection JSON mapping of bucket name -> S3 credentials
|
|
86
|
+
mbkautheVar mbkauthe configuration JSON
|
|
87
|
+
mbkbucketVar mbkbucket configuration JSON
|
|
88
|
+
|
|
89
|
+
${c.bold('EXAMPLES:')}
|
|
90
|
+
$ mbkbucket
|
|
91
|
+
$ mbkbucket -p 8080 --open
|
|
92
|
+
$ mbkbucket --env ./configs/.env.prod -a myapp
|
|
93
|
+
`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function showVersion() {
|
|
97
|
+
console.log(`mbkbucket v${packageJson.version}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getNetworkIp() {
|
|
101
|
+
try {
|
|
102
|
+
const nets = os.networkInterfaces();
|
|
103
|
+
for (const name of Object.keys(nets)) {
|
|
104
|
+
for (const net of nets[name] ?? []) {
|
|
105
|
+
if (net.family === 'IPv4' && !net.internal) return net.address;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch {}
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function openBrowser(url) {
|
|
113
|
+
const platform = process.platform;
|
|
114
|
+
let cmd = '';
|
|
115
|
+
if (platform === 'darwin') cmd = `open "${url}"`;
|
|
116
|
+
else if (platform === 'win32') cmd = `start "" "${url}"`;
|
|
117
|
+
else cmd = `xdg-open "${url}"`;
|
|
118
|
+
import('node:child_process').then(({ exec }) => {
|
|
119
|
+
exec(cmd, () => {});
|
|
120
|
+
}).catch(() => {});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// Main Runner
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
async function main() {
|
|
127
|
+
if (hasFlag('help', 'h')) {
|
|
128
|
+
showHelp();
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (hasFlag('version', 'v')) {
|
|
133
|
+
showVersion();
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Load custom or default .env
|
|
138
|
+
const envPath = findFlag('env', 'e');
|
|
139
|
+
if (typeof envPath === 'string') {
|
|
140
|
+
dotenv.config({ path: path.resolve(process.cwd(), envPath) });
|
|
141
|
+
} else {
|
|
142
|
+
dotenv.config();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Handle environment overrides from flags
|
|
146
|
+
const appFlag = findFlag('app', 'a');
|
|
147
|
+
if (typeof appFlag === 'string') {
|
|
148
|
+
process.env.APP_NAME = appFlag;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const bucketFlag = findFlag('bucket', 'b');
|
|
152
|
+
if (typeof bucketFlag === 'string') {
|
|
153
|
+
process.env.MBKAUTHE_BUCKET = bucketFlag;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (hasFlag('dev', 'd')) {
|
|
157
|
+
process.env.NODE_ENV = 'dev';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const port = parseInt(findFlag('port', 'p') || process.env.PORT || '3004', 10);
|
|
161
|
+
const host = findFlag('host', 'H') || process.env.HOST || '0.0.0.0';
|
|
162
|
+
const shouldOpen = hasFlag('open', 'o');
|
|
163
|
+
|
|
164
|
+
// Check version in background
|
|
165
|
+
await checkVersion();
|
|
166
|
+
|
|
167
|
+
// Test S3 connectivity
|
|
168
|
+
let healthResult = null;
|
|
169
|
+
try {
|
|
170
|
+
healthResult = await checkHealth();
|
|
171
|
+
} catch (err) {
|
|
172
|
+
healthResult = { status: 'unhealthy', error: err.message };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Create express application
|
|
176
|
+
const app = createApp();
|
|
177
|
+
|
|
178
|
+
const server = app.listen(port, host, () => {
|
|
179
|
+
const isAnyHost = host === '0.0.0.0' || host === '::' || host === '';
|
|
180
|
+
const displayHost = isAnyHost ? 'localhost' : host;
|
|
181
|
+
const localUrl = `http://${displayHost}:${port}/mbkbucket`;
|
|
182
|
+
|
|
183
|
+
console.log();
|
|
184
|
+
console.log(` ${c.cyan(c.bold('⚡ MBKBucket'))} ${c.dim(`v${packageJson.version}`)}`);
|
|
185
|
+
console.log();
|
|
186
|
+
console.log(` ${c.green('➜')} ${c.bold('Local:')} ${c.cyan(localUrl)}`);
|
|
187
|
+
|
|
188
|
+
if (isAnyHost) {
|
|
189
|
+
const netIp = getNetworkIp();
|
|
190
|
+
if (netIp) {
|
|
191
|
+
console.log(` ${c.green('➜')} ${c.bold('Network:')} ${c.cyan(`http://${netIp}:${port}/mbkbucket`)}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const appName = process.env.APP_NAME || 'root';
|
|
196
|
+
console.log(` ${c.green('➜')} ${c.bold('App Name:')} ${appName}`);
|
|
197
|
+
|
|
198
|
+
let bucketNames = [];
|
|
199
|
+
try {
|
|
200
|
+
bucketNames = getAvailableBucketNames();
|
|
201
|
+
} catch {}
|
|
202
|
+
|
|
203
|
+
if (bucketNames.length > 0) {
|
|
204
|
+
console.log(` ${c.green('➜')} ${c.bold('Buckets:')} ${bucketNames.join(', ')}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (healthResult?.status === 'healthy') {
|
|
208
|
+
console.log(` ${c.green('➜')} ${c.bold('Storage:')} ${c.green('✓ Connected')} (${healthResult.bucket} in ${healthResult.responseTime}ms)`);
|
|
209
|
+
} else if (healthResult?.error) {
|
|
210
|
+
console.log(` ${c.yellow('➜')} ${c.bold('Storage:')} ${c.yellow('⚠ Connection warning')} (${healthResult.error})`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
console.log();
|
|
214
|
+
console.log(` ${c.dim('Press Ctrl+C to stop the server')}`);
|
|
215
|
+
console.log();
|
|
216
|
+
|
|
217
|
+
if (shouldOpen) {
|
|
218
|
+
openBrowser(localUrl);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const shutdown = (signal) => {
|
|
223
|
+
console.log(`\n ${c.dim(`Received ${signal}, shutting down...`)}`);
|
|
224
|
+
server.close(() => {
|
|
225
|
+
console.log(` ${c.green('✓')} ${c.dim('MBKBucket server stopped.')}\n`);
|
|
226
|
+
process.exit(0);
|
|
227
|
+
});
|
|
228
|
+
setTimeout(() => process.exit(0), 2000).unref();
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
232
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
main().catch((err) => {
|
|
236
|
+
console.error(`\n${c.red(c.bold('Error starting mbkbucket:'))} ${err.message}`);
|
|
237
|
+
if (process.env.DEBUG) console.error(err);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
});
|