@muhgholy/next-drive 4.23.30 → 4.23.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/{chunk-J2OYAYYA.js → chunk-2DCZENJ2.js} +116 -10
  2. package/dist/chunk-2DCZENJ2.js.map +1 -0
  3. package/dist/{chunk-LTWWPQJA.cjs → chunk-HWNIRA6Y.cjs} +49 -6
  4. package/dist/chunk-HWNIRA6Y.cjs.map +1 -0
  5. package/dist/{chunk-DNJRZKAF.js → chunk-IWV6G7HQ.js} +49 -7
  6. package/dist/chunk-IWV6G7HQ.js.map +1 -0
  7. package/dist/{chunk-QE5EHVVA.cjs → chunk-WUG4ATLH.cjs} +150 -44
  8. package/dist/chunk-WUG4ATLH.cjs.map +1 -0
  9. package/dist/server/actions/public.d.ts.map +1 -1
  10. package/dist/server/config.d.ts.map +1 -1
  11. package/dist/server/express.cjs +12 -12
  12. package/dist/server/express.js +4 -4
  13. package/dist/server/hono.cjs +12 -12
  14. package/dist/server/hono.js +4 -4
  15. package/dist/server/index.cjs +19 -19
  16. package/dist/server/index.d.ts.map +1 -1
  17. package/dist/server/index.js +2 -2
  18. package/dist/server/storage-adapters/google.d.ts.map +1 -1
  19. package/dist/server/tus.d.ts +5 -1
  20. package/dist/server/tus.d.ts.map +1 -1
  21. package/dist/tus-5LLFMVQK.cjs +20 -0
  22. package/dist/tus-5LLFMVQK.cjs.map +1 -0
  23. package/dist/tus-C4T5ZDTG.js +3 -0
  24. package/dist/tus-C4T5ZDTG.js.map +1 -0
  25. package/dist/types/server/config.d.ts +8 -0
  26. package/dist/types/server/config.d.ts.map +1 -1
  27. package/dist/types/server/express.d.ts +3 -24
  28. package/dist/types/server/express.d.ts.map +1 -1
  29. package/dist/types/server/hono.d.ts +3 -24
  30. package/dist/types/server/hono.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/dist/chunk-DNJRZKAF.js.map +0 -1
  33. package/dist/chunk-J2OYAYYA.js.map +0 -1
  34. package/dist/chunk-LTWWPQJA.cjs.map +0 -1
  35. package/dist/chunk-QE5EHVVA.cjs.map +0 -1
  36. package/dist/tus-35IUZMFV.js +0 -3
  37. package/dist/tus-35IUZMFV.js.map +0 -1
  38. package/dist/tus-PK6UHGE4.cjs +0 -16
  39. package/dist/tus-PK6UHGE4.cjs.map +0 -1
@@ -251,7 +251,7 @@ var getGlobal = () => {
251
251
  config: null,
252
252
  migrationPromise: null,
253
253
  initialized: false,
254
- abuse: { ipHits: /* @__PURE__ */ new Map(), active: /* @__PURE__ */ new Map(), lastSweep: 0 }
254
+ abuse: { ipHits: /* @__PURE__ */ new Map(), active: /* @__PURE__ */ new Map(), lastSweep: 0, transformActive: 0 }
255
255
  };
256
256
  }
257
257
  return globalThis[GLOBAL_KEY];
@@ -281,6 +281,9 @@ var driveConfiguration = async (config) => {
281
281
  allowedMimeTypes: config.security?.allowedMimeTypes ?? ["*/*"],
282
282
  signedUrls: config.security?.signedUrls,
283
283
  trash: config.security?.trash,
284
+ publicRateLimit: config.security?.publicRateLimit,
285
+ transformConcurrency: config.security?.transformConcurrency,
286
+ cacheMaxAgeDays: config.security?.cacheMaxAgeDays,
284
287
  unauthenticated: config.security?.unauthenticated
285
288
  }
286
289
  };
@@ -300,11 +303,19 @@ var driveConfiguration = async (config) => {
300
303
  allowedMimeTypes: config.security?.allowedMimeTypes ?? ["*/*"],
301
304
  signedUrls: config.security?.signedUrls,
302
305
  trash: config.security?.trash,
306
+ publicRateLimit: config.security?.publicRateLimit,
307
+ transformConcurrency: config.security?.transformConcurrency,
308
+ cacheMaxAgeDays: config.security?.cacheMaxAgeDays,
303
309
  unauthenticated: config.security?.unauthenticated
304
310
  },
305
311
  information: config.information
306
312
  };
307
313
  }
314
+ if (!g.config.security?.signedUrls?.enabled && !g.config.security?.publicRateLimit) {
315
+ console.warn(
316
+ '[next-drive] security.signedUrls is disabled and security.publicRateLimit is unset - "?action=serve"/"thumbnail" will serve any valid file id to anyone, with no rate limit. Enable security.signedUrls (recommended) and/or set security.publicRateLimit if these files should not be fully public.'
317
+ );
318
+ }
308
319
  g.initialized = true;
309
320
  if (!g.migrationPromise) {
310
321
  g.migrationPromise = runMigrations(resolvedPath);
@@ -951,14 +962,36 @@ var GoogleDriveProvider = {
951
962
  }
952
963
  },
953
964
  openStream: async (item, accountId) => {
965
+ if (item.information.type === "FOLDER") throw new Error("Could not open Google Drive file: folders cannot be streamed");
966
+ const cachePath = path.join(getDriveConfig().storage.path, "file", item._id.toString(), "data.bin");
967
+ if (fs.existsSync(cachePath)) {
968
+ return {
969
+ stream: fs.createReadStream(cachePath),
970
+ mime: item.information.mime,
971
+ size: fs.statSync(cachePath).size
972
+ };
973
+ }
954
974
  const { client } = await createAuthClient(item.owner, accountId || item.storageAccountId?.toString());
955
975
  const drive = google.drive({ version: "v3", auth: client });
956
976
  if (!item.provider?.google?.id) throw new Error("Could not open Google Drive file: its Google file ID is missing");
957
- if (item.information.type === "FOLDER") throw new Error("Could not open Google Drive file: folders cannot be streamed");
958
977
  const res = await drive.files.get(
959
978
  { fileId: item.provider.google.id, alt: "media" },
960
979
  { responseType: "stream" }
961
980
  );
981
+ const fileDir = path.dirname(cachePath);
982
+ if (!fs.existsSync(fileDir)) fs.mkdirSync(fileDir, { recursive: true });
983
+ const tempPath = `${cachePath}.tmp`;
984
+ const writeStream = fs.createWriteStream(tempPath);
985
+ res.data.pipe(writeStream);
986
+ writeStream.on("finish", () => {
987
+ try {
988
+ fs.renameSync(tempPath, cachePath);
989
+ } catch {
990
+ fs.unlinkSync(tempPath);
991
+ }
992
+ });
993
+ writeStream.on("error", () => fs.unlink(tempPath, () => {
994
+ }));
962
995
  return {
963
996
  stream: res.data,
964
997
  mime: item.information.mime,
@@ -1706,7 +1739,7 @@ var driveCleanup = async () => {
1706
1739
  }
1707
1740
  }
1708
1741
  try {
1709
- const { getTusServer: getTusServer2 } = await import('./tus-35IUZMFV.js');
1742
+ const { getTusServer: getTusServer2 } = await import('./tus-C4T5ZDTG.js');
1710
1743
  await getTusServer2().cleanUpExpiredUploads();
1711
1744
  } catch (e) {
1712
1745
  console.error("[next-drive] Failed to clean up expired tus uploads:", e);
@@ -1766,6 +1799,12 @@ var countActiveAnon = (store) => {
1766
1799
  return store.active.size;
1767
1800
  };
1768
1801
  var releaseSlot = (id) => abuseStore()?.active.delete(id);
1802
+ var resolveTusCorsOptions = (cors) => {
1803
+ if (!cors?.enabled) return { allowedCredentials: false };
1804
+ const { origins, credentials = false } = cors;
1805
+ if (!origins || origins === "*") return { allowedCredentials: credentials };
1806
+ return { allowedOrigins: Array.isArray(origins) ? origins : [origins], allowedCredentials: credentials };
1807
+ };
1769
1808
  var getTusServer = () => {
1770
1809
  const g = globalThis;
1771
1810
  g.__nextDrive = g.__nextDrive ?? {};
@@ -1774,6 +1813,7 @@ var getTusServer = () => {
1774
1813
  const tusDir = path.join(config.storage.path, "tus");
1775
1814
  fs.mkdirSync(tusDir, { recursive: true });
1776
1815
  const apiPath = new URL(config.apiUrl || "/api/drive", "http://x").pathname;
1816
+ const { allowedOrigins, allowedCredentials } = resolveTusCorsOptions(config.cors);
1777
1817
  const server = new Server({
1778
1818
  path: apiPath,
1779
1819
  datastore: new FileStore({ directory: tusDir, expirationPeriodInMilliseconds: UPLOAD_EXPIRATION_MS }),
@@ -1781,6 +1821,8 @@ var getTusServer = () => {
1781
1821
  // ** must be declared here to survive cross-origin requests.
1782
1822
  allowedHeaders: ["X-Drive-Account"],
1783
1823
  exposedHeaders: ["X-Drive-Item"],
1824
+ allowedOrigins,
1825
+ allowedCredentials,
1784
1826
  maxSize: (req) => {
1785
1827
  const ctx = getCtx(req);
1786
1828
  if (!ctx) return Number.MAX_SAFE_INTEGER;
@@ -1820,7 +1862,7 @@ var getTusServer = () => {
1820
1862
  }
1821
1863
  }
1822
1864
  const nreq = req.__nodeReq;
1823
- const ip = (nreq && abuse.clientId?.(nreq)) ?? (abuse.trustedHeaders ?? ["cf-connecting-ip", "x-forwarded-for"]).map((h) => req.headers.get(h)).find(Boolean)?.split(",")[0].trim() ?? nreq?.socket?.remoteAddress ?? "unknown";
1865
+ const ip = (nreq && abuse.clientId?.(nreq)) ?? (abuse.trustedHeaders ?? ["cf-connecting-ip", "x-real-ip", "x-forwarded-for"]).map((h) => req.headers.get(h)).find(Boolean)?.split(",")[0].trim() ?? nreq?.socket?.remoteAddress ?? "unknown";
1824
1866
  const hits = (store.ipHits.get(ip) ?? []).filter((t) => now - t < 36e5);
1825
1867
  const perIp = abuse.perIp;
1826
1868
  if (perIp && hits.filter((t) => now - t < perIp.windowMinutes * 6e4).length >= perIp.max) throw { status_code: 429, body: "Too many uploads, please try again later" };
@@ -1942,6 +1984,6 @@ var handleUpload = async (req, res, ctx) => {
1942
1984
  res.end(response.body ? Buffer.from(await response.arrayBuffer()) : void 0);
1943
1985
  };
1944
1986
 
1945
- export { GoogleDriveProvider, LocalStorageProvider, account_default, driveCleanup, driveConfiguration, driveConfirm, driveDelete, driveFilePath, driveGetUrl, driveInfo, driveList, driveListFiles, drivePurgeExpired, driveReadFile, driveUpload, drive_default, getDriveConfig, getDriveInformation, getImageSettings, getTusServer, handleUpload, resolveProvider, withSignedUrl, withSignedUrls };
1946
- //# sourceMappingURL=chunk-DNJRZKAF.js.map
1947
- //# sourceMappingURL=chunk-DNJRZKAF.js.map
1987
+ export { GoogleDriveProvider, LocalStorageProvider, account_default, driveCleanup, driveConfiguration, driveConfirm, driveDelete, driveFilePath, driveGetUrl, driveInfo, driveList, driveListFiles, drivePurgeExpired, driveReadFile, driveUpload, drive_default, getDriveConfig, getDriveInformation, getImageSettings, getTusServer, handleUpload, resolveProvider, resolveTusCorsOptions, withSignedUrl, withSignedUrls };
1988
+ //# sourceMappingURL=chunk-IWV6G7HQ.js.map
1989
+ //# sourceMappingURL=chunk-IWV6G7HQ.js.map