mbkbucket 1.5.1 → 2.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 CHANGED
@@ -1,9 +1,9 @@
1
- mbkautheVar={"APP_NAME":"mbkbucket","loginRedirectURL":"/dashboard","bucket":""}
1
+ mbkautheVar={"APP_NAME":"portal","loginRedirectURL":"/dashboard","bucket":"R2_Bucket"}
2
2
  mbkauthShared={"Main_SECRET_TOKEN": 123,"DOMAIN":"mbktech.org","IS_DEPLOYED":"false","EncPass":"false","DEVICE_TRUST_DURATION_DAYS":7,"SESSION_SECRET_KEY":"123","LOGIN_DB":"postgres://","MBKAUTH_TWO_FA_ENABLE":"true","COOKIE_EXPIRE_TIME":2,"GITHUB_LOGIN_ENABLED":"f","GITHUB_CLIENT_ID":"123","GITHUB_CLIENT_SECRET":"123","GOOGLE_LOGIN_ENABLED":"f","GOOGLE_CLIENT_ID":"123","GOOGLE_CLIENT_SECRET":"123"}
3
3
  # See @node_modules/mbkauthe/docs/env.md for more details
4
4
  NODE_ENV=development
5
5
 
6
- BucketConnection={"r2":{"BUCKET_NAME":"","ACCESS_KEY_ID":"","SECRET_ACCESS_KEY":"","ENDPOINT":""},"e2":{"BUCKET_NAME":"","ACCESS_KEY_ID":"","SECRET_ACCESS_KEY":"","ENDPOINT":"","Region":"ap-southeast-1"},"custom":{"BUCKET_NAME":"","ACCESS_KEY_ID":"","SECRET_ACCESS_KEY":"","ENDPOINT":"","Region":""}}
6
+ BucketConnection={"R2_Bucket":{"BUCKET_NAME":"my-r2-bucket","ACCESS_KEY_ID":"your-r2-access-key","SECRET_ACCESS_KEY":"your-r2-secret","ENDPOINT":"https://accountid.r2.cloudflarestorage.com"},"S3_Bucket":{"BUCKET_NAME":"my-s3-bucket","ACCESS_KEY_ID":"your-s3-access-key","SECRET_ACCESS_KEY":"your-s3-secret","ENDPOINT":"https://s3.ap-southeast-1.amazonaws.com"}}
7
7
  # Region is optional
8
8
 
9
9
  mbkbucketVar={"publiView_enabled":"true","p_view_inline":"true"}
package/README.md CHANGED
@@ -75,6 +75,78 @@ For complete API documentation, refer to the TypeScript declarations in [index.d
75
75
 
76
76
  ---
77
77
 
78
+ ## Environment Configuration
79
+
80
+ The package validates both `mbkbucketVar` and `BucketConnection` at startup.
81
+
82
+ ### 1 `mbkautheVar`
83
+
84
+ `mbkautheVar.bucket` is used as the default bucket.
85
+
86
+ Example:
87
+
88
+ ```env
89
+ mbkautheVar={"APP_NAME":"portal","loginRedirectURL":"/dashboard","bucket":"R2_Bucket"}
90
+ ```
91
+
92
+ Notes:
93
+
94
+ - If `APP_NAME` is `portal`, mbkbucket works from bucket root (no `portal/` folder prefix).
95
+ - If `bucket` is missing, mbkbucket falls back to the first bucket key in `BucketConnection`.
96
+
97
+ ### 2 `BucketConnection`
98
+
99
+ Use a JSON object where each key is a selectable connection name.
100
+
101
+ Example:
102
+
103
+ ```env
104
+ BucketConnection={"R2_Bucket":{"BUCKET_NAME":"my-r2-bucket","ACCESS_KEY_ID":"...","SECRET_ACCESS_KEY":"...","ENDPOINT":"https://<account-id>.r2.cloudflarestorage.com"},"S3_Bucket":{"BUCKET_NAME":"my-s3-bucket","ACCESS_KEY_ID":"...","SECRET_ACCESS_KEY":"...","ENDPOINT":"https://s3.ap-southeast-1.amazonaws.com"}}
105
+ ```
106
+
107
+ Required fields per bucket:
108
+
109
+ - `BUCKET_NAME`
110
+ - `ACCESS_KEY_ID`
111
+ - `SECRET_ACCESS_KEY`
112
+ - `ENDPOINT`
113
+
114
+ ### Common Configuration Mistakes
115
+
116
+ 1. Quoted inner object (invalid)
117
+
118
+ ```env
119
+ BucketConnection={"R2_Bucket":"{\"BUCKET_NAME\":\"...\"}"}
120
+ ```
121
+
122
+ 2. Correct inner object (valid)
123
+
124
+ ```env
125
+ BucketConnection={"R2_Bucket":{"BUCKET_NAME":"...","ACCESS_KEY_ID":"...","SECRET_ACCESS_KEY":"...","ENDPOINT":"https://..."}}
126
+ ```
127
+
128
+ ### Runtime Selection
129
+
130
+ - Admin page bucket selection: `/mbkbucket?bucket=R2_Bucket`
131
+ - Public view route `/mbkbucket/p_view/:key(*)` always uses the default bucket from `mbkautheVar.bucket`.
132
+
133
+ ---
134
+
135
+ ## Automated Tests
136
+
137
+ Run tests:
138
+
139
+ ```bash
140
+ npm test
141
+ ```
142
+
143
+ Current tests cover:
144
+
145
+ - `mbkbucketVar` parsing/defaults/boolean normalization
146
+ - `BucketConnection` shape validation and required fields
147
+
148
+ ---
149
+
78
150
  ## Contact & Support
79
151
 
80
152
  For questions, issues, or contributions, please reach out:
package/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- // Type definitions for mbkbucket 1.5.0
1
+ // Type definitions for mbkbucket
2
2
  // Project: https://github.com/MIbnEKhalid/mbkbucket
3
- // Definitions by: Muhammad Bin Khalid <https://github.com/MIbnEKhalid">
4
3
 
5
4
  import { Readable } from "stream";
6
5
  import { Router, Application } from "express";
@@ -17,6 +16,8 @@ export interface BucketConfig {
17
16
  [key: string]: any;
18
17
  }
19
18
 
19
+ export type BucketConnectionMap = Record<string, BucketConfig>;
20
+
20
21
  export interface S3ObjectResult {
21
22
  Body: Readable;
22
23
  ContentLength?: number;
@@ -26,18 +27,16 @@ export interface S3ObjectResult {
26
27
  [key: string]: any;
27
28
  }
28
29
 
29
- // Options passed to uploadFile
30
30
  export interface UploadOptions {
31
31
  metadata?: Record<string, string>;
32
32
  cacheControl?: string;
33
33
  storageClass?: string;
34
34
  serverSideEncryption?: string;
35
35
  bucketName?: string;
36
- preventOverwrite?: boolean; // added in 1.4.1
36
+ preventOverwrite?: boolean;
37
37
  [key: string]: any;
38
38
  }
39
39
 
40
- // Options for listing files
41
40
  export interface ListFilesOptions {
42
41
  maxKeys?: number;
43
42
  continuationToken?: string | null;
@@ -48,7 +47,6 @@ export interface ListFilesOptions {
48
47
  [key: string]: any;
49
48
  }
50
49
 
51
- // Result returned from listfiles calls
52
50
  export interface ListFilesResult extends Record<string, any> {
53
51
  requestedAt: string;
54
52
  totalFiles: number;
@@ -56,7 +54,6 @@ export interface ListFilesResult extends Record<string, any> {
56
54
  nextToken: string | null;
57
55
  }
58
56
 
59
- // Incomplete multipart upload descriptor returned by AWS
60
57
  export interface IncompleteMultipartUpload {
61
58
  Key?: string;
62
59
  UploadId?: string;
@@ -65,7 +62,6 @@ export interface IncompleteMultipartUpload {
65
62
  [key: string]: any;
66
63
  }
67
64
 
68
- // Result returned by cleanupIncompleteMultipartUploads
69
65
  export interface CleanupResult {
70
66
  abortedCount: number;
71
67
  uploads: Array<{ key: string; uploadId: string; initiated?: string }>;
@@ -73,23 +69,31 @@ export interface CleanupResult {
73
69
  [key: string]: any;
74
70
  }
75
71
 
72
+ export interface ConfigVars {
73
+ publiView_enabled: boolean;
74
+ p_view_inline: boolean;
75
+ [key: string]: any;
76
+ }
77
+
76
78
  /**
77
- * S3-related functions (available from `mbkbucket/lib/s3` and re-exported at package root)
79
+ * S3 exports (re-exported from lib/s3.js at package root)
78
80
  */
81
+ export function getAvailableBucketNames(): string[];
82
+ export function resolveBucketName(bucketName?: string | null): string;
79
83
  export function getBucketConfig(bucketName?: string): BucketConfig;
80
84
  export const bucketClient: any;
81
85
  export function getAppName(): string;
82
86
  export function ensureKeyHasAppPrefix(key?: string): string;
83
87
  export function ensurePrefix(prefix?: string): string;
84
88
  export function getBucketClient(bucketName?: string): any;
85
- export function checkHealth(): Promise<{ status: string; responseTime?: number; bucket?: string; error?: string; checkedAt: string; region?: string }>;
89
+ export function checkHealth(): Promise<{ status: string; responseTime?: number; bucket?: string; error?: string; checkedAt: string; region?: string; }>;
86
90
 
87
91
  export function uploadFile(
88
92
  key: string,
89
93
  fileBuffer: Buffer | Uint8Array,
90
94
  contentType: string,
91
95
  options?: UploadOptions
92
- ): Promise<{ fileSize?: number; key: string; contentType?: string; uploadedAt?: string } & Record<string, any>>;
96
+ ): Promise<{ fileSize?: number; key: string; contentType?: string; uploadedAt?: string; } & Record<string, any>>;
93
97
 
94
98
  export function downloadFile(
95
99
  key: string,
@@ -121,10 +125,7 @@ export function deleteFolder(prefix: string, bucketName?: string): Promise<{
121
125
  prefix?: string;
122
126
  }>;
123
127
 
124
- export function listfiles(
125
- prefix?: string,
126
- options?: ListFilesOptions
127
- ): Promise<ListFilesResult>;
128
+ export function listfiles(prefix?: string, options?: ListFilesOptions): Promise<ListFilesResult>;
128
129
 
129
130
  export function getFileMetadata(key: string, bucketName?: string): Promise<{
130
131
  key: string;
@@ -141,8 +142,9 @@ export function getFileSize(key: string, bucketName?: string): Promise<number |
141
142
 
142
143
  export function generateSignedUrl(
143
144
  key: string,
144
- operation?: 'getObject' | 'putObject' | string,
145
- expiresIn?: number
145
+ operation?: "getObject" | "putObject" | string,
146
+ expiresIn?: number,
147
+ bucketName?: string
146
148
  ): Promise<{
147
149
  url: string;
148
150
  key: string;
@@ -152,31 +154,32 @@ export function generateSignedUrl(
152
154
  generatedAt: string;
153
155
  }>;
154
156
 
155
- /**
156
- * S3 Multipart Upload Functions
157
- */
158
157
  export function createMultipartUpload(
159
158
  key: string,
160
159
  contentType?: string,
161
- metadata?: Record<string, string>
160
+ metadata?: Record<string, string>,
161
+ bucketName?: string
162
162
  ): Promise<{ uploadId: string; key: string }>;
163
163
 
164
164
  export function uploadPart(
165
165
  key: string,
166
166
  uploadId: string,
167
167
  partNumber: number,
168
- buffer: Buffer | Uint8Array
168
+ buffer: Buffer | Uint8Array,
169
+ bucketName?: string
169
170
  ): Promise<{ ETag: string; partNumber: number }>;
170
171
 
171
172
  export function completeMultipartUpload(
172
173
  key: string,
173
174
  uploadId: string,
174
- parts: Array<{ partNumber: number; ETag: string }>
175
+ parts: Array<{ partNumber: number; ETag: string }>,
176
+ bucketName?: string
175
177
  ): Promise<{ key: string }>;
176
178
 
177
179
  export function abortMultipartUpload(
178
180
  key: string,
179
- uploadId: string
181
+ uploadId: string,
182
+ bucketName?: string
180
183
  ): Promise<{ key: string; abortedAt: string }>;
181
184
 
182
185
  export function listIncompleteMultipartUploads(
@@ -191,35 +194,33 @@ export function cleanupIncompleteMultipartUploads(
191
194
  ): Promise<CleanupResult>;
192
195
 
193
196
  /**
194
- * Configuration variables from mbkbucket
197
+ * Config exports (re-exported from lib/config/index.js at package root)
195
198
  */
196
- export interface ConfigVars {
197
- publiView_enabled: boolean;
198
- p_view_inline: boolean;
199
- [key: string]: any;
200
- }
201
-
199
+ export const packageJson: Record<string, any>;
200
+ export const appVersion: string;
202
201
  export const mbkbucketVar: ConfigVars;
202
+ export function getLatestVersion(): Promise<string | null>;
203
+ export function checkVersion(): Promise<void>;
204
+ export function parseAndValidateMbkbucketVar(rawValue?: string): ConfigVars;
205
+ export function parseAndValidateBucketConnection(rawValue?: string): BucketConnectionMap | null;
203
206
 
204
207
  /**
205
- * Exported router from `lib/bucket` (re-exported at package root as `bucket`)
208
+ * Router export (re-exported from lib/routes/index.js at package root as `bucket`)
206
209
  */
207
210
  export const bucket: Router;
208
211
 
209
212
  /**
210
- * Root default export: the configured Express application
213
+ * Root default export from index.js: configured Express application
211
214
  */
212
215
  declare const server: Application;
213
216
  export default server;
214
217
 
215
218
  /**
216
- * Module declarations for subpath imports so TypeScript consumers can import:
217
- * import { uploadFile } from 'mbkbucket/lib/s3';
218
- * import { packageJson } from 'mbkbucket/lib/config/index';
219
- * import bucketRouter from 'mbkbucket/lib/bucket';
219
+ * Subpath module declarations
220
220
  */
221
221
  declare module "mbkbucket/lib/s3" {
222
222
  import { Readable } from "stream";
223
+
223
224
  export interface BucketConfig {
224
225
  BUCKET_NAME: string;
225
226
  ENDPOINT?: string;
@@ -228,6 +229,9 @@ declare module "mbkbucket/lib/s3" {
228
229
  region?: string;
229
230
  [key: string]: any;
230
231
  }
232
+
233
+ export type BucketConnectionMap = Record<string, BucketConfig>;
234
+
231
235
  export interface S3ObjectResult {
232
236
  Body: Readable;
233
237
  ContentLength?: number;
@@ -237,7 +241,6 @@ declare module "mbkbucket/lib/s3" {
237
241
  [key: string]: any;
238
242
  }
239
243
 
240
- // re-use shared interfaces defined at top of index.d.ts
241
244
  export interface UploadOptions {
242
245
  metadata?: Record<string, string>;
243
246
  cacheControl?: string;
@@ -247,6 +250,7 @@ declare module "mbkbucket/lib/s3" {
247
250
  preventOverwrite?: boolean;
248
251
  [key: string]: any;
249
252
  }
253
+
250
254
  export interface ListFilesOptions {
251
255
  maxKeys?: number;
252
256
  continuationToken?: string | null;
@@ -256,12 +260,14 @@ declare module "mbkbucket/lib/s3" {
256
260
  bucketName?: string;
257
261
  [key: string]: any;
258
262
  }
263
+
259
264
  export interface ListFilesResult extends Record<string, any> {
260
265
  requestedAt: string;
261
266
  totalFiles: number;
262
267
  hasMore: boolean;
263
268
  nextToken: string | null;
264
269
  }
270
+
265
271
  export interface IncompleteMultipartUpload {
266
272
  Key?: string;
267
273
  UploadId?: string;
@@ -269,6 +275,7 @@ declare module "mbkbucket/lib/s3" {
269
275
  Initiator?: { DisplayName?: string; [key: string]: any };
270
276
  [key: string]: any;
271
277
  }
278
+
272
279
  export interface CleanupResult {
273
280
  abortedCount: number;
274
281
  uploads: Array<{ key: string; uploadId: string; initiated?: string }>;
@@ -276,13 +283,15 @@ declare module "mbkbucket/lib/s3" {
276
283
  [key: string]: any;
277
284
  }
278
285
 
286
+ export function getAvailableBucketNames(): string[];
287
+ export function resolveBucketName(bucketName?: string | null): string;
279
288
  export function getBucketConfig(bucketName?: string): BucketConfig;
280
289
  export const bucketClient: any;
281
290
  export function getAppName(): string;
282
291
  export function ensureKeyHasAppPrefix(key?: string): string;
283
292
  export function ensurePrefix(prefix?: string): string;
284
293
  export function getBucketClient(bucketName?: string): any;
285
- export function checkHealth(): Promise<{ status: string; responseTime?: number; bucket?: string; error?: string; checkedAt: string; region?: string }>;
294
+ export function checkHealth(): Promise<{ status: string; responseTime?: number; bucket?: string; error?: string; checkedAt: string; region?: string; }>;
286
295
 
287
296
  export function uploadFile(
288
297
  key: string,
@@ -320,10 +329,7 @@ declare module "mbkbucket/lib/s3" {
320
329
  prefix?: string;
321
330
  }>;
322
331
 
323
- export function listfiles(
324
- prefix?: string,
325
- options?: ListFilesOptions
326
- ): Promise<ListFilesResult>;
332
+ export function listfiles(prefix?: string, options?: ListFilesOptions): Promise<ListFilesResult>;
327
333
 
328
334
  export function getFileMetadata(key: string, bucketName?: string): Promise<{
329
335
  key: string;
@@ -337,10 +343,12 @@ declare module "mbkbucket/lib/s3" {
337
343
 
338
344
  export function fileExists(key: string, bucketName?: string): Promise<boolean>;
339
345
  export function getFileSize(key: string, bucketName?: string): Promise<number | null>;
346
+
340
347
  export function generateSignedUrl(
341
348
  key: string,
342
- operation?: 'getObject' | 'putObject' | string,
343
- expiresIn?: number
349
+ operation?: "getObject" | "putObject" | string,
350
+ expiresIn?: number,
351
+ bucketName?: string
344
352
  ): Promise<{
345
353
  url: string;
346
354
  key: string;
@@ -353,25 +361,29 @@ declare module "mbkbucket/lib/s3" {
353
361
  export function createMultipartUpload(
354
362
  key: string,
355
363
  contentType?: string,
356
- metadata?: Record<string, string>
364
+ metadata?: Record<string, string>,
365
+ bucketName?: string
357
366
  ): Promise<{ uploadId: string; key: string }>;
358
367
 
359
368
  export function uploadPart(
360
369
  key: string,
361
370
  uploadId: string,
362
371
  partNumber: number,
363
- buffer: Buffer | Uint8Array
372
+ buffer: Buffer | Uint8Array,
373
+ bucketName?: string
364
374
  ): Promise<{ ETag: string; partNumber: number }>;
365
375
 
366
376
  export function completeMultipartUpload(
367
377
  key: string,
368
378
  uploadId: string,
369
- parts: Array<{ partNumber: number; ETag: string }>
379
+ parts: Array<{ partNumber: number; ETag: string }>,
380
+ bucketName?: string
370
381
  ): Promise<{ key: string }>;
371
382
 
372
383
  export function abortMultipartUpload(
373
384
  key: string,
374
- uploadId: string
385
+ uploadId: string,
386
+ bucketName?: string
375
387
  ): Promise<{ key: string; abortedAt: string }>;
376
388
 
377
389
  export function listIncompleteMultipartUploads(
@@ -392,11 +404,37 @@ declare module "mbkbucket/lib/config/index" {
392
404
  p_view_inline: boolean;
393
405
  [key: string]: any;
394
406
  }
407
+
408
+ export interface BucketConfig {
409
+ BUCKET_NAME: string;
410
+ ENDPOINT?: string;
411
+ ACCESS_KEY_ID?: string;
412
+ SECRET_ACCESS_KEY?: string;
413
+ region?: string;
414
+ [key: string]: any;
415
+ }
416
+
417
+ export type BucketConnectionMap = Record<string, BucketConfig>;
418
+
395
419
  export const packageJson: Record<string, any>;
396
420
  export const appVersion: string;
397
421
  export const mbkbucketVar: ConfigVars;
398
422
  export function getLatestVersion(): Promise<string | null>;
399
423
  export function checkVersion(): Promise<void>;
424
+ export function parseAndValidateMbkbucketVar(rawValue?: string): ConfigVars;
425
+ export function parseAndValidateBucketConnection(rawValue?: string): BucketConnectionMap | null;
426
+ }
427
+
428
+ declare module "mbkbucket/lib/config/validation" {
429
+ export function normalizeBooleanLike(value: any): any;
430
+ export function parseAndValidateMbkbucketVar(rawValue?: string): { [key: string]: any };
431
+ export function parseAndValidateBucketConnection(rawValue?: string): Record<string, any> | null;
432
+ }
433
+
434
+ declare module "mbkbucket/lib/routes/index" {
435
+ import { Router } from "express";
436
+ const router: Router;
437
+ export default router;
400
438
  }
401
439
 
402
440
  declare module "mbkbucket/lib/bucket" {
package/index.js CHANGED
@@ -8,22 +8,20 @@ import compression from "compression";
8
8
  import rateLimit from 'express-rate-limit';
9
9
  import bucketRoutes from "./lib/routes/index.js";
10
10
  import { checkVersion } from "./lib/config/index.js";
11
- import { appVersion } from "./lib/config/index.js";
11
+ import { packageJson } from "./lib/config/index.js";
12
+ import { createLogger } from "./lib/debug.js";
12
13
 
13
14
  dotenv.config();
15
+ const debugServer = createLogger('server');
14
16
 
15
17
  const __filename = fileURLToPath(import.meta.url);
16
18
  const __dirname = path.dirname(__filename);
17
- const assetVersion = appVersion;
19
+ const isDevMode = process.env.NODE_ENV === "dev";
18
20
 
19
21
  const server = express();
20
22
  server.set('trust proxy', 1);
21
23
 
22
24
  server.use(compression());
23
- server.use((req, res, next) => {
24
- res.locals.assetVersion = assetVersion;
25
- next();
26
- });
27
25
 
28
26
  // Rate limiting: general limiter for typical browsing/API usage and a stricter
29
27
  // limiter for dashboard (admin) routes.
@@ -42,18 +40,19 @@ const generalLimiter = rateLimit({
42
40
  server.use(express.json({ limit: '10mb' }));
43
41
  server.use(express.urlencoded({ extended: true, limit: '10mb' }));
44
42
 
45
- // Serve only specific static assets (limit exposure): CSS and JS used by the dashboard
46
- // This replaces serving the entire /public directory.
47
- const staticMaxAgeSeconds = 90 * 24 * 60 * 60; // 90 days
43
+ // Serve only specific static assets (limit exposure): CSS and JS used by the dashboard.
44
+ // Avoid immutable long cache here because dashboard routes change frequently and stale JS
45
+ // can keep writing old URLs in browser history.
46
+ const dashboardAssetCacheControl = 'public, max-age=300, must-revalidate';
48
47
  server.get('/mbkbucket/bucketadmin.css', (req, res) => {
49
- res.set('Cache-Control', `public, max-age=${staticMaxAgeSeconds}, immutable`);
48
+ res.set('Cache-Control', dashboardAssetCacheControl);
50
49
  res.sendFile(path.join(__dirname, 'public', 'bucketadmin.css'), (err) => {
51
50
  if (err) res.status(err.status || 404).end();
52
51
  });
53
52
  });
54
53
 
55
54
  server.get('/mbkbucket/bucketadmin.js', (req, res) => {
56
- res.set('Cache-Control', `public, max-age=${staticMaxAgeSeconds}, immutable`);
55
+ res.set('Cache-Control', dashboardAssetCacheControl);
57
56
  res.sendFile(path.join(__dirname, 'public', 'bucketadmin.js'), (err) => {
58
57
  if (err) res.status(err.status || 404).end();
59
58
  });
@@ -63,6 +62,7 @@ server.get('/mbkbucket/bucketadmin.js', (req, res) => {
63
62
  server.engine("handlebars", engine({
64
63
  extname: ".handlebars",
65
64
  defaultLayout: "main",
65
+ layoutsDir: path.join(__dirname, "../../views/layouts"),
66
66
  partialsDir: [
67
67
  path.join(__dirname, "views/templates"),
68
68
  path.join(__dirname, "views/templates/notice"),
@@ -75,6 +75,9 @@ server.engine("handlebars", engine({
75
75
  helpers: {
76
76
  eq: function (a, b) {
77
77
  return a === b;
78
+ },
79
+ mbkbucket_cachebuster: function () {
80
+ return "?v=" + packageJson.version;
78
81
  }
79
82
  }
80
83
  }));
@@ -89,11 +92,8 @@ server.set("views", [
89
92
  server.use(mbkautheRoutes);
90
93
  server.use(generalLimiter);
91
94
  server.use(bucketRoutes);
92
-
93
- if (process.env.mbkbucket_test === "dev") {
94
-
95
- console.log("[mbkbucket] Dev mode is enabled. Starting server in dev mode.");
96
-
95
+ if (isDevMode) {
96
+ debugServer("Dev mode is enabled. Starting server in dev mode.");
97
97
 
98
98
  // Request timing middleware: logs method, url, status and elapsed ms
99
99
  server.use((req, res, next) => {
@@ -101,7 +101,7 @@ if (process.env.mbkbucket_test === "dev") {
101
101
  res.on('finish', () => {
102
102
  const diff = process.hrtime(start);
103
103
  const ms = diff[0] * 1000 + diff[1] / 1e6;
104
- console.log(`[mbkbucket] [${new Date().toISOString()}] ${req.method} ${req.originalUrl} ${res.statusCode} - ${ms.toFixed(3)} ms`);
104
+ debugServer("[%s] %s %s %s - %s ms", new Date().toISOString(), req.method, req.originalUrl, res.statusCode, ms.toFixed(3));
105
105
  });
106
106
  next();
107
107
  });
@@ -112,7 +112,7 @@ if (process.env.mbkbucket_test === "dev") {
112
112
 
113
113
  // 404 handler
114
114
  server.use((req, res) => {
115
- console.log(`[mbkbucket] Path not found: ${req.method} ${req.url}`);
115
+ debugServer("Path not found: %s %s", req.method, req.url);
116
116
  return res.status(404).render("Error/dError.handlebars", {
117
117
  layout: false,
118
118
  code: 404,
@@ -138,8 +138,8 @@ if (process.env.mbkbucket_test === "dev") {
138
138
  });
139
139
 
140
140
  const port = process.env.PORT || 3004;
141
- server.listen(port, async () => {
142
- console.log(`[mbkbucket] Server running on http://localhost:${port}`);
141
+ server.listen(port, async() => {
142
+ debugServer("Server running on http://localhost:%s", port);
143
143
  });
144
144
 
145
145
  }