@muhgholy/next-drive 4.6.0 → 4.7.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/README.md CHANGED
@@ -269,18 +269,28 @@ Upload files programmatically from server-side code:
269
269
  ```typescript
270
270
  import { driveUpload } from "@muhgholy/next-drive/server";
271
271
 
272
- // Upload from file path
272
+ // Upload to specific folder by ID
273
273
  const file = await driveUpload(
274
274
  "/tmp/photo.jpg",
275
275
  { userId: "123" },
276
276
  {
277
277
  name: "photo.jpg",
278
- parentId: "folderId", // Optional: folder ID or null for root
278
+ folder: { id: "folderId" }, // Optional: folder ID
279
279
  accountId: "LOCAL", // Optional: storage account ID
280
280
  enforce: false, // Optional: bypass quota check
281
281
  }
282
282
  );
283
283
 
284
+ // Upload to folder by path (creates folders if not exist)
285
+ const file = await driveUpload(
286
+ "/tmp/photo.jpg",
287
+ { userId: "123" },
288
+ {
289
+ name: "photo.jpg",
290
+ folder: { path: "images/2024/january" }, // Creates folders recursively
291
+ }
292
+ );
293
+
284
294
  // Upload from stream
285
295
  import fs from "fs";
286
296
  const stream = fs.createReadStream("/tmp/video.mp4");
@@ -307,13 +317,14 @@ const file = await driveUpload(
307
317
 
308
318
  **Options:**
309
319
 
310
- | Option | Type | Required | Description |
311
- | ----------- | ---------------- | -------- | -------------------------------------------------------- |
312
- | `name` | `string` | Yes | File name with extension |
313
- | `parentId` | `string \| null` | No | Parent folder ID (null or 'root' for root) |
314
- | `accountId` | `string` | No | Storage account ID ('LOCAL' for local storage) |
315
- | `mime` | `string` | No | MIME type (auto-detected from extension if not provided) |
316
- | `enforce` | `boolean` | No | Bypass quota check (default: false) |
320
+ | Option | Type | Required | Description |
321
+ | ------------ | --------------------------------- | -------- | -------------------------------------------------------- |
322
+ | `name` | `string` | Yes | File name with extension |
323
+ | `folder.id` | `string` | No | Parent folder ID |
324
+ | `folder.path`| `string` | No | Folder path (e.g., `images/2024`) - creates if not exist |
325
+ | `accountId` | `string` | No | Storage account ID ('LOCAL' for local storage) |
326
+ | `mime` | `string` | No | MIME type (auto-detected from extension if not provided) |
327
+ | `enforce` | `boolean` | No | Bypass quota check (default: false) |
317
328
 
318
329
  ### Get Signed URL
319
330
 
@@ -1417,6 +1417,46 @@ var driveDelete = async (source, options) => {
1417
1417
  const owner = drive.owner;
1418
1418
  await provider.delete([driveId], owner, accountId);
1419
1419
  };
1420
+ var resolveFolderByPath = async (folderPath, owner, accountId) => {
1421
+ const normalizedPath = folderPath.replace(/^\/+|\/+$/g, "");
1422
+ if (!normalizedPath) {
1423
+ throw new Error("Folder path cannot be empty");
1424
+ }
1425
+ const segments = normalizedPath.split("/").filter((s) => s.length > 0);
1426
+ if (segments.length === 0) {
1427
+ throw new Error("Invalid folder path");
1428
+ }
1429
+ let providerName = "LOCAL";
1430
+ if (accountId && accountId !== "LOCAL") {
1431
+ const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner });
1432
+ if (!account) {
1433
+ throw new Error("Invalid Storage Account");
1434
+ }
1435
+ if (account.metadata.provider === "GOOGLE") {
1436
+ providerName = "GOOGLE";
1437
+ }
1438
+ }
1439
+ let currentParentId = null;
1440
+ for (const segmentName of segments) {
1441
+ const existingFolder = await drive_default.findOne({
1442
+ owner,
1443
+ "provider.type": providerName,
1444
+ storageAccountId: accountId || null,
1445
+ parentId: currentParentId,
1446
+ name: segmentName,
1447
+ "information.type": "FOLDER",
1448
+ trashedAt: null
1449
+ });
1450
+ if (existingFolder) {
1451
+ currentParentId = String(existingFolder._id);
1452
+ } else {
1453
+ const provider = providerName === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
1454
+ const newFolder = await provider.createFolder(segmentName, currentParentId, owner, accountId);
1455
+ currentParentId = newFolder.id;
1456
+ }
1457
+ }
1458
+ return currentParentId;
1459
+ };
1420
1460
  var driveUpload = async (source, key, options) => {
1421
1461
  const config = getDriveConfig();
1422
1462
  let provider = LocalStorageProvider;
@@ -1506,12 +1546,20 @@ var driveUpload = async (source, key, options) => {
1506
1546
  throw new Error("Storage quota exceeded");
1507
1547
  }
1508
1548
  }
1549
+ let resolvedParentId = null;
1550
+ if (options.folder?.path) {
1551
+ resolvedParentId = await resolveFolderByPath(options.folder.path, key, accountId);
1552
+ } else if (options.folder?.id && options.folder.id !== "root") {
1553
+ resolvedParentId = options.folder.id;
1554
+ } else if (options.parentId && options.parentId !== "root") {
1555
+ resolvedParentId = options.parentId;
1556
+ }
1509
1557
  const drive = new drive_default({
1510
1558
  owner: key,
1511
1559
  storageAccountId: accountId || null,
1512
1560
  provider: { type: provider.name },
1513
1561
  name: options.name,
1514
- parentId: options.parentId === "root" || !options.parentId ? null : options.parentId,
1562
+ parentId: resolvedParentId,
1515
1563
  order: await getNextOrderValue(key),
1516
1564
  information: { type: "FILE", sizeInBytes: fileSize, mime: mimeType, path: "" },
1517
1565
  status: "UPLOADING"
@@ -2258,5 +2306,5 @@ var driveAPIHandler = async (req, res) => {
2258
2306
  };
2259
2307
 
2260
2308
  export { driveAPIHandler, driveConfiguration, driveDelete, driveFilePath, driveFileSchemaZod, driveGetUrl, driveInfo, driveList, driveReadFile, driveUpload, getDriveConfig, getDriveInformation };
2261
- //# sourceMappingURL=chunk-UT2XCOS7.js.map
2262
- //# sourceMappingURL=chunk-UT2XCOS7.js.map
2309
+ //# sourceMappingURL=chunk-OWKTTRQC.js.map
2310
+ //# sourceMappingURL=chunk-OWKTTRQC.js.map