@muhgholy/next-drive 4.15.1 → 4.17.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.
@@ -4,7 +4,7 @@ var formidable = require('formidable');
4
4
  var path = require('path');
5
5
  var fs = require('fs');
6
6
  var os3 = require('os');
7
- var crypto3 = require('crypto');
7
+ var crypto2 = require('crypto');
8
8
  var mongoose = require('mongoose');
9
9
  var sharp2 = require('sharp');
10
10
  var zod = require('zod');
@@ -17,7 +17,7 @@ var formidable__default = /*#__PURE__*/_interopDefault(formidable);
17
17
  var path__default = /*#__PURE__*/_interopDefault(path);
18
18
  var fs__default = /*#__PURE__*/_interopDefault(fs);
19
19
  var os3__default = /*#__PURE__*/_interopDefault(os3);
20
- var crypto3__default = /*#__PURE__*/_interopDefault(crypto3);
20
+ var crypto2__default = /*#__PURE__*/_interopDefault(crypto2);
21
21
  var mongoose__default = /*#__PURE__*/_interopDefault(mongoose);
22
22
  var sharp2__default = /*#__PURE__*/_interopDefault(sharp2);
23
23
  var ffmpeg__default = /*#__PURE__*/_interopDefault(ffmpeg);
@@ -251,38 +251,49 @@ var runMigrations = async (storagePath) => {
251
251
  };
252
252
 
253
253
  // src/server/config.ts
254
- var globalConfig = null;
255
- var migrationPromise = null;
256
- var configInitialized = false;
254
+ var GLOBAL_KEY = "__nextDrive";
255
+ var getGlobal = () => {
256
+ if (!globalThis[GLOBAL_KEY]) {
257
+ globalThis[GLOBAL_KEY] = {
258
+ config: null,
259
+ migrationPromise: null,
260
+ initialized: false
261
+ };
262
+ }
263
+ return globalThis[GLOBAL_KEY];
264
+ };
257
265
  var driveConfiguration = async (config) => {
266
+ const g = getGlobal();
258
267
  if (mongoose__default.default.connection.readyState !== 1) {
259
268
  throw new Error("Database not connected. Please connect to Mongoose before initializing next-drive.");
260
269
  }
261
- if (configInitialized && globalConfig) {
262
- if (migrationPromise) await migrationPromise;
263
- return globalConfig;
270
+ if (g.initialized && g.config) {
271
+ if (g.migrationPromise) await g.migrationPromise;
272
+ return g.config;
264
273
  }
265
274
  const resolvedPath = config.storage?.path || path__default.default.join(os3__default.default.tmpdir(), "next-drive-data");
266
275
  const mode = config.mode || "NORMAL";
267
276
  if (mode === "ROOT") {
268
- globalConfig = {
277
+ g.config = {
269
278
  ...config,
270
279
  mode: "ROOT",
271
280
  storage: {
272
281
  ...config.storage,
273
282
  path: resolvedPath
274
283
  },
275
- security: config.security || {
276
- maxUploadSizeInBytes: 1024 * 1024 * 1024 * 10,
284
+ security: {
285
+ maxUploadSizeInBytes: config.security?.maxUploadSizeInBytes ?? 1024 * 1024 * 1024 * 10,
277
286
  // 10GB default for ROOT
278
- allowedMimeTypes: ["*/*"]
287
+ allowedMimeTypes: config.security?.allowedMimeTypes ?? ["*/*"],
288
+ signedUrls: config.security?.signedUrls,
289
+ trash: config.security?.trash
279
290
  }
280
291
  };
281
292
  } else {
282
293
  if (!config.information) {
283
294
  throw new Error("information callback is required in NORMAL mode");
284
295
  }
285
- globalConfig = {
296
+ g.config = {
286
297
  ...config,
287
298
  mode: "NORMAL",
288
299
  storage: {
@@ -298,16 +309,17 @@ var driveConfiguration = async (config) => {
298
309
  information: config.information
299
310
  };
300
311
  }
301
- configInitialized = true;
302
- if (!migrationPromise) {
303
- migrationPromise = runMigrations(resolvedPath);
312
+ g.initialized = true;
313
+ if (!g.migrationPromise) {
314
+ g.migrationPromise = runMigrations(resolvedPath);
304
315
  }
305
- await migrationPromise;
306
- return globalConfig;
316
+ await g.migrationPromise;
317
+ return g.config;
307
318
  };
308
319
  var getDriveConfig = () => {
309
- if (!globalConfig) throw new Error("Drive configuration not initialized");
310
- return globalConfig;
320
+ const g = getGlobal();
321
+ if (!g.config) throw new Error("Drive configuration not initialized");
322
+ return g.config;
311
323
  };
312
324
  var getDriveInformation = async (req) => {
313
325
  const config = getDriveConfig();
@@ -364,7 +376,7 @@ var validateMimeType = (mime, allowedTypes) => {
364
376
  });
365
377
  };
366
378
  var computeFileHash = (filePath) => new Promise((resolve, reject) => {
367
- const hash = crypto3__default.default.createHash("sha256");
379
+ const hash = crypto2__default.default.createHash("sha256");
368
380
  const stream = fs__default.default.createReadStream(filePath);
369
381
  stream.on("data", (data) => hash.update(data));
370
382
  stream.on("end", () => resolve(hash.digest("hex")));
@@ -1286,7 +1298,7 @@ var driveGetUrl = (fileId, options) => {
1286
1298
  } else {
1287
1299
  expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
1288
1300
  }
1289
- const signature = crypto3__default.default.createHmac("sha256", secret).update(`${fileId}:${expiryTimestamp}`).digest("hex");
1301
+ const signature = crypto2__default.default.createHmac("sha256", secret).update(`${fileId}:${expiryTimestamp}`).digest("hex");
1290
1302
  const token = Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url");
1291
1303
  return `/api/drive?action=serve&id=${fileId}&token=${token}`;
1292
1304
  };
@@ -1552,7 +1564,7 @@ var driveUpload = async (source, key, options) => {
1552
1564
  if (!fs__default.default.existsSync(tempDir)) {
1553
1565
  fs__default.default.mkdirSync(tempDir, { recursive: true });
1554
1566
  }
1555
- tempFilePath = path__default.default.join(tempDir, `upload-${crypto3__default.default.randomUUID()}.tmp`);
1567
+ tempFilePath = path__default.default.join(tempDir, `upload-${crypto2__default.default.randomUUID()}.tmp`);
1556
1568
  fs__default.default.writeFileSync(tempFilePath, source);
1557
1569
  sourceFilePath = tempFilePath;
1558
1570
  fileSize = source.length;
@@ -1561,7 +1573,7 @@ var driveUpload = async (source, key, options) => {
1561
1573
  if (!fs__default.default.existsSync(tempDir)) {
1562
1574
  fs__default.default.mkdirSync(tempDir, { recursive: true });
1563
1575
  }
1564
- tempFilePath = path__default.default.join(tempDir, `upload-${crypto3__default.default.randomUUID()}.tmp`);
1576
+ tempFilePath = path__default.default.join(tempDir, `upload-${crypto2__default.default.randomUUID()}.tmp`);
1565
1577
  const writeStream = fs__default.default.createWriteStream(tempFilePath);
1566
1578
  await new Promise((resolve, reject) => {
1567
1579
  source.pipe(writeStream);
@@ -1669,6 +1681,21 @@ var getProvider = async (req, owner) => {
1669
1681
  if (account.metadata.provider === "GOOGLE") return { provider: GoogleDriveProvider, accountId: account._id.toString() };
1670
1682
  return { provider: LocalStorageProvider };
1671
1683
  };
1684
+ var addSignedUrlToken = (item, config) => {
1685
+ if (!config.security?.signedUrls?.enabled || !config.security.signedUrls.secret) {
1686
+ return item;
1687
+ }
1688
+ const { secret, expiresIn } = config.security.signedUrls;
1689
+ const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
1690
+ const signature = crypto2__default.default.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
1691
+ return { ...item, token: Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url") };
1692
+ };
1693
+ var addSignedUrlTokens = (items, config) => {
1694
+ if (!config.security?.signedUrls?.enabled || !config.security.signedUrls.secret) {
1695
+ return items;
1696
+ }
1697
+ return items.map((item) => addSignedUrlToken(item, config));
1698
+ };
1672
1699
  var applyCorsHeaders = (req, res, config) => {
1673
1700
  const cors = config.cors;
1674
1701
  if (!cors?.enabled) return false;
@@ -1750,7 +1777,7 @@ var driveAPIHandler = async (req, res) => {
1750
1777
  return res.status(401).json({ status: 401, message: "Token expired" });
1751
1778
  }
1752
1779
  const { secret } = config.security.signedUrls;
1753
- const expectedSignature = crypto3__default.default.createHmac("sha256", secret).update(`${id}:${expiry}`).digest("hex");
1780
+ const expectedSignature = crypto2__default.default.createHmac("sha256", secret).update(`${id}:${expiry}`).digest("hex");
1754
1781
  if (signature !== expectedSignature) {
1755
1782
  return res.status(401).json({ status: 401, message: "Invalid token" });
1756
1783
  }
@@ -2024,15 +2051,7 @@ var driveAPIHandler = async (req, res) => {
2024
2051
  }
2025
2052
  if (afterId) query._id = { $lt: afterId };
2026
2053
  const items = await drive_default.find(query, {}, { sort: { order: 1, _id: -1 }, limit });
2027
- let plainItems = await Promise.all(items.map((item) => item.toClient()));
2028
- if (config.security?.signedUrls?.enabled && config.security.signedUrls.secret) {
2029
- const { secret, expiresIn } = config.security.signedUrls;
2030
- plainItems = plainItems.map((item) => {
2031
- const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
2032
- const signature = crypto3__default.default.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
2033
- return { ...item, token: Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url") };
2034
- });
2035
- }
2054
+ const plainItems = addSignedUrlTokens(await Promise.all(items.map((item) => item.toClient())), config);
2036
2055
  res.status(200).json({ status: 200, message: "Items retrieved", data: { items: plainItems, hasMore: items.length === limit } });
2037
2056
  return;
2038
2057
  }
@@ -2059,15 +2078,7 @@ var driveAPIHandler = async (req, res) => {
2059
2078
  }
2060
2079
  if (folderId && folderId !== "root") query.parentId = folderId;
2061
2080
  const items = await drive_default.find(query, {}, { limit, sort: { createdAt: -1 } });
2062
- let plainItems = await Promise.all(items.map((i) => i.toClient()));
2063
- if (config.security?.signedUrls?.enabled && config.security.signedUrls.secret) {
2064
- const { secret, expiresIn } = config.security.signedUrls;
2065
- plainItems = plainItems.map((item) => {
2066
- const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
2067
- const signature = crypto3__default.default.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
2068
- return { ...item, token: Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url") };
2069
- });
2070
- }
2081
+ const plainItems = addSignedUrlTokens(await Promise.all(items.map((i) => i.toClient())), config);
2071
2082
  return res.status(200).json({ status: 200, message: "Results", data: { items: plainItems } });
2072
2083
  }
2073
2084
  // ** 3. UPLOAD **
@@ -2125,7 +2136,7 @@ var driveAPIHandler = async (req, res) => {
2125
2136
  return res.status(413).json({ status: 413, message: "Storage quota exceeded" });
2126
2137
  }
2127
2138
  }
2128
- currentUploadId = crypto3__default.default.randomUUID();
2139
+ currentUploadId = crypto2__default.default.randomUUID();
2129
2140
  const uploadDir = path__default.default.join(tempBaseDir, currentUploadId);
2130
2141
  fs__default.default.mkdirSync(uploadDir, { recursive: true });
2131
2142
  const metadata = {
@@ -2230,7 +2241,7 @@ var driveAPIHandler = async (req, res) => {
2230
2241
  const item = await provider.uploadFile(drive, finalTempPath, meta.accountId);
2231
2242
  fs__default.default.rmSync(uploadDir, { recursive: true, force: true });
2232
2243
  const newQuota = await provider.getQuota(meta.owner, meta.accountId, information.storage.quotaInBytes);
2233
- res.status(200).json({ status: 200, message: "Upload complete", data: { type: "UPLOAD_COMPLETE", driveId: String(drive._id), item }, statistic: { storage: newQuota } });
2244
+ res.status(200).json({ status: 200, message: "Upload complete", data: { type: "UPLOAD_COMPLETE", driveId: String(drive._id), item: addSignedUrlToken(item, config) }, statistic: { storage: newQuota } });
2234
2245
  } catch (err) {
2235
2246
  await drive_default.deleteOne({ _id: drive._id });
2236
2247
  throw err;
@@ -2272,7 +2283,7 @@ var driveAPIHandler = async (req, res) => {
2272
2283
  const folderData = createFolderBodySchema.safeParse(req.body);
2273
2284
  if (!folderData.success) return res.status(400).json({ status: 400, message: folderData.error.errors[0].message });
2274
2285
  const { name, parentId } = folderData.data;
2275
- const item = await provider.createFolder(name, parentId ?? null, owner, accountId);
2286
+ const item = addSignedUrlToken(await provider.createFolder(name, parentId ?? null, owner, accountId), config);
2276
2287
  return res.status(201).json({ status: 201, message: "Folder created", data: { item } });
2277
2288
  }
2278
2289
  // ** 5. DELETE **
@@ -2327,15 +2338,7 @@ var driveAPIHandler = async (req, res) => {
2327
2338
  trashedAt: { $ne: null }
2328
2339
  };
2329
2340
  const items = await drive_default.find(query, {}, { sort: { trashedAt: -1 } });
2330
- let plainItems = await Promise.all(items.map((item) => item.toClient()));
2331
- if (config.security?.signedUrls?.enabled && config.security.signedUrls.secret) {
2332
- const { secret, expiresIn } = config.security.signedUrls;
2333
- plainItems = plainItems.map((item) => {
2334
- const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
2335
- const signature = crypto3__default.default.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
2336
- return { ...item, token: Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url") };
2337
- });
2338
- }
2341
+ const plainItems = addSignedUrlTokens(await Promise.all(items.map((item) => item.toClient())), config);
2339
2342
  return res.status(200).json({
2340
2343
  status: 200,
2341
2344
  message: "Trash items",
@@ -2390,14 +2393,14 @@ var driveAPIHandler = async (req, res) => {
2390
2393
  console.error(`Failed to move item ${id}`, e);
2391
2394
  }
2392
2395
  }
2393
- return res.status(200).json({ status: 200, message: "Moved", data: { items } });
2396
+ return res.status(200).json({ status: 200, message: "Moved", data: { items: addSignedUrlTokens(items, config) } });
2394
2397
  }
2395
2398
  // ** 8. RENAME **
2396
2399
  case "rename": {
2397
2400
  const renameData = renameBodySchema.safeParse({ id: req.query.id, ...req.body });
2398
2401
  if (!renameData.success) return res.status(400).json({ status: 400, message: "Invalid data" });
2399
2402
  const { id, newName } = renameData.data;
2400
- const item = await provider.rename(id, newName, owner, accountId);
2403
+ const item = addSignedUrlToken(await provider.rename(id, newName, owner, accountId), config);
2401
2404
  return res.status(200).json({ status: 200, message: "Renamed", data: { item } });
2402
2405
  }
2403
2406
  // ** 9. THUMBNAIL **
@@ -2422,5 +2425,5 @@ exports.driveReadFile = driveReadFile;
2422
2425
  exports.driveUpload = driveUpload;
2423
2426
  exports.getDriveConfig = getDriveConfig;
2424
2427
  exports.getDriveInformation = getDriveInformation;
2425
- //# sourceMappingURL=chunk-JZJKT2OS.cjs.map
2426
- //# sourceMappingURL=chunk-JZJKT2OS.cjs.map
2428
+ //# sourceMappingURL=chunk-XIUFYDVE.cjs.map
2429
+ //# sourceMappingURL=chunk-XIUFYDVE.cjs.map