@muhgholy/next-drive 4.23.5 → 4.23.7
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/dist/{chunk-TA6L5FYG.cjs → chunk-HQTC3554.cjs} +47 -2
- package/dist/chunk-HQTC3554.cjs.map +1 -0
- package/dist/{chunk-VIB7R4JN.cjs → chunk-LAKT7IJJ.cjs} +84 -84
- package/dist/chunk-LAKT7IJJ.cjs.map +1 -0
- package/dist/{chunk-GV4HB2G6.js → chunk-MVYNW56R.js} +84 -84
- package/dist/chunk-MVYNW56R.js.map +1 -0
- package/dist/{chunk-TMSG5WJZ.js → chunk-OSYRIHH4.js} +47 -3
- package/dist/chunk-OSYRIHH4.js.map +1 -0
- package/dist/client/file-chooser.d.ts.map +1 -1
- package/dist/client/index.cjs +126 -117
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.css +2 -1
- package/dist/client/index.js +20 -11
- package/dist/client/index.js.map +1 -1
- package/dist/client/utils.d.ts +1 -0
- package/dist/client/utils.d.ts.map +1 -1
- package/dist/server/express.cjs +12 -12
- package/dist/server/express.js +3 -3
- package/dist/server/hono.cjs +12 -12
- package/dist/server/hono.js +3 -3
- package/dist/server/index.cjs +18 -18
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-GV4HB2G6.js.map +0 -1
- package/dist/chunk-TA6L5FYG.cjs.map +0 -1
- package/dist/chunk-TMSG5WJZ.js.map +0 -1
- package/dist/chunk-VIB7R4JN.cjs.map +0 -1
|
@@ -529,11 +529,11 @@ var LocalStorageProvider = {
|
|
|
529
529
|
return { usedInBytes, quotaInBytes: configuredQuotaInBytes ?? 0 };
|
|
530
530
|
},
|
|
531
531
|
openStream: async (item, accountId) => {
|
|
532
|
-
if (item.information.type !== "FILE") throw new Error("
|
|
532
|
+
if (item.information.type !== "FILE") throw new Error("Could not open local file: folders cannot be streamed");
|
|
533
533
|
const storagePath = getDriveConfig().storage.path;
|
|
534
534
|
const filePath = path.join(storagePath, "file", item._id.toString(), "data.bin");
|
|
535
535
|
if (!fs.existsSync(filePath)) {
|
|
536
|
-
throw new Error("
|
|
536
|
+
throw new Error("Could not open local file: it is missing from disk");
|
|
537
537
|
}
|
|
538
538
|
const stat = fs.statSync(filePath);
|
|
539
539
|
const stream = fs.createReadStream(filePath);
|
|
@@ -544,13 +544,13 @@ var LocalStorageProvider = {
|
|
|
544
544
|
};
|
|
545
545
|
},
|
|
546
546
|
getThumbnail: async (item, accountId) => {
|
|
547
|
-
if (item.information.type !== "FILE") throw new Error("No
|
|
547
|
+
if (item.information.type !== "FILE") throw new Error("No preview available: folders do not have thumbnails");
|
|
548
548
|
const storagePath = getDriveConfig().storage.path;
|
|
549
549
|
const fileDir = path.join(storagePath, "file", item._id.toString());
|
|
550
550
|
const originalPath = path.join(fileDir, "data.bin");
|
|
551
551
|
const thumbDir = path.join(fileDir, "cache");
|
|
552
552
|
const thumbPath = path.join(thumbDir, "thumbnail.webp");
|
|
553
|
-
if (!fs.existsSync(originalPath)) throw new Error("
|
|
553
|
+
if (!fs.existsSync(originalPath)) throw new Error("Could not generate preview: the original file is missing");
|
|
554
554
|
if (fs.existsSync(thumbPath)) {
|
|
555
555
|
return fs.createReadStream(thumbPath);
|
|
556
556
|
}
|
|
@@ -599,12 +599,12 @@ var LocalStorageProvider = {
|
|
|
599
599
|
return folder.toClient();
|
|
600
600
|
},
|
|
601
601
|
uploadFile: async (drive, filePath, accountId) => {
|
|
602
|
-
if (drive.information.type !== "FILE") throw new Error("
|
|
602
|
+
if (drive.information.type !== "FILE") throw new Error("Could not save local file: invalid file record");
|
|
603
603
|
const storagePath = getDriveConfig().storage.path;
|
|
604
604
|
const destDir = path.join(storagePath, "file", String(drive._id));
|
|
605
605
|
const destPath = path.join(destDir, "data.bin");
|
|
606
606
|
if (!fs.existsSync(filePath)) {
|
|
607
|
-
throw new Error("
|
|
607
|
+
throw new Error("Could not save local file: the uploaded data is missing");
|
|
608
608
|
}
|
|
609
609
|
if (!fs.existsSync(destDir)) {
|
|
610
610
|
fs.mkdirSync(destDir, { recursive: true });
|
|
@@ -620,12 +620,12 @@ var LocalStorageProvider = {
|
|
|
620
620
|
}
|
|
621
621
|
}
|
|
622
622
|
if (!fs.existsSync(destPath)) {
|
|
623
|
-
throw new Error("
|
|
623
|
+
throw new Error("Could not save local file: writing to storage failed");
|
|
624
624
|
}
|
|
625
625
|
const destStats = fs.statSync(destPath);
|
|
626
626
|
if (destStats.size !== drive.information.sizeInBytes) {
|
|
627
627
|
fs.unlinkSync(destPath);
|
|
628
|
-
throw new Error(
|
|
628
|
+
throw new Error("Could not save local file: the stored data was incomplete (size mismatch)");
|
|
629
629
|
}
|
|
630
630
|
drive.status = "READY";
|
|
631
631
|
drive.information.path = path.join("file", String(drive._id), "data.bin");
|
|
@@ -670,12 +670,12 @@ var LocalStorageProvider = {
|
|
|
670
670
|
},
|
|
671
671
|
rename: async (id, newName, owner, accountId) => {
|
|
672
672
|
const item = await drive_default.findOneAndUpdate({ _id: id, owner }, { name: newName }, { new: true });
|
|
673
|
-
if (!item) throw new Error("
|
|
673
|
+
if (!item) throw new Error("Could not rename: the item no longer exists");
|
|
674
674
|
return item.toClient();
|
|
675
675
|
},
|
|
676
676
|
move: async (id, newParentId, owner, accountId) => {
|
|
677
677
|
const item = await drive_default.findOne({ _id: id, owner });
|
|
678
|
-
if (!item) throw new Error("
|
|
678
|
+
if (!item) throw new Error("Could not move: the item no longer exists");
|
|
679
679
|
item.parentId = newParentId === "root" || !newParentId ? null : new mongoose.Types.ObjectId(newParentId);
|
|
680
680
|
await item.save();
|
|
681
681
|
return item.toClient();
|
|
@@ -718,13 +718,13 @@ var createAuthClient = async (owner, accountId) => {
|
|
|
718
718
|
const query = { owner, "metadata.provider": "GOOGLE" };
|
|
719
719
|
if (accountId) query._id = accountId;
|
|
720
720
|
const account = await account_default.findOne(query);
|
|
721
|
-
if (!account) throw new Error("Google Drive account not connected");
|
|
721
|
+
if (!account) throw new Error("Could not reach Google Drive: account not connected");
|
|
722
722
|
const config = getDriveConfig();
|
|
723
723
|
const { clientId, clientSecret, redirectUri } = config.storage?.google || {};
|
|
724
|
-
if (!clientId || !clientSecret) throw new Error("Google credentials not configured on server");
|
|
724
|
+
if (!clientId || !clientSecret) throw new Error("Could not reach Google Drive: Google credentials are not configured on the server");
|
|
725
725
|
const oAuth2Client = new google.auth.OAuth2(clientId, clientSecret, redirectUri);
|
|
726
726
|
if (account.metadata.provider !== "GOOGLE" || !account.metadata.google) {
|
|
727
|
-
throw new Error("
|
|
727
|
+
throw new Error("Could not reach Google Drive: account data is invalid, please reconnect");
|
|
728
728
|
}
|
|
729
729
|
oAuth2Client.setCredentials(account.metadata.google.credentials);
|
|
730
730
|
oAuth2Client.on("tokens", async (tokens) => {
|
|
@@ -946,8 +946,8 @@ var GoogleDriveProvider = {
|
|
|
946
946
|
openStream: async (item, accountId) => {
|
|
947
947
|
const { client } = await createAuthClient(item.owner, accountId || item.storageAccountId?.toString());
|
|
948
948
|
const drive = google.drive({ version: "v3", auth: client });
|
|
949
|
-
if (!item.provider?.google?.id) throw new Error("
|
|
950
|
-
if (item.information.type === "FOLDER") throw new Error("
|
|
949
|
+
if (!item.provider?.google?.id) throw new Error("Could not open Google Drive file: its Google file ID is missing");
|
|
950
|
+
if (item.information.type === "FOLDER") throw new Error("Could not open Google Drive file: folders cannot be streamed");
|
|
951
951
|
const res = await drive.files.get(
|
|
952
952
|
{ fileId: item.provider.google.id, alt: "media" },
|
|
953
953
|
{ responseType: "stream" }
|
|
@@ -967,7 +967,7 @@ var GoogleDriveProvider = {
|
|
|
967
967
|
return fs.createReadStream(thumbPath);
|
|
968
968
|
}
|
|
969
969
|
const { client } = await createAuthClient(item.owner, accountId || item.storageAccountId?.toString());
|
|
970
|
-
if (!item.provider?.google?.thumbnailLink) throw new Error("No
|
|
970
|
+
if (!item.provider?.google?.thumbnailLink) throw new Error("No preview available for this Google Drive file");
|
|
971
971
|
const res = await client.request({ url: item.provider.google.thumbnailLink, responseType: "stream" });
|
|
972
972
|
if (!fs.existsSync(thumbDir)) {
|
|
973
973
|
fs.mkdirSync(thumbDir, { recursive: true });
|
|
@@ -1007,7 +1007,7 @@ var GoogleDriveProvider = {
|
|
|
1007
1007
|
fields: "id, name, mimeType, webViewLink, iconLink"
|
|
1008
1008
|
});
|
|
1009
1009
|
const file = res.data;
|
|
1010
|
-
if (!file.id) throw new Error("
|
|
1010
|
+
if (!file.id) throw new Error("Could not create folder on Google Drive");
|
|
1011
1011
|
const folder = new drive_default({
|
|
1012
1012
|
owner,
|
|
1013
1013
|
name: file.name,
|
|
@@ -1028,7 +1028,7 @@ var GoogleDriveProvider = {
|
|
|
1028
1028
|
return folder.toClient();
|
|
1029
1029
|
},
|
|
1030
1030
|
uploadFile: async (drive, filePath, accountId) => {
|
|
1031
|
-
if (drive.information.type !== "FILE") throw new Error("
|
|
1031
|
+
if (drive.information.type !== "FILE") throw new Error("Could not upload to Google Drive: invalid file record");
|
|
1032
1032
|
const { client } = await createAuthClient(drive.owner, accountId || drive.storageAccountId?.toString());
|
|
1033
1033
|
const googleDrive = google.drive({ version: "v3", auth: client });
|
|
1034
1034
|
let googleParentId = "root";
|
|
@@ -1050,7 +1050,7 @@ var GoogleDriveProvider = {
|
|
|
1050
1050
|
fields: "id, name, mimeType, webViewLink, iconLink, thumbnailLink, size"
|
|
1051
1051
|
});
|
|
1052
1052
|
const gFile = res.data;
|
|
1053
|
-
if (!gFile.id) throw new Error("
|
|
1053
|
+
if (!gFile.id) throw new Error("Could not upload to Google Drive: no file was created");
|
|
1054
1054
|
drive.status = "READY";
|
|
1055
1055
|
drive.provider = {
|
|
1056
1056
|
type: "GOOGLE",
|
|
@@ -1122,7 +1122,7 @@ var GoogleDriveProvider = {
|
|
|
1122
1122
|
const { client } = await createAuthClient(owner, accountId);
|
|
1123
1123
|
const drive = google.drive({ version: "v3", auth: client });
|
|
1124
1124
|
const item = await drive_default.findOne({ _id: id, owner });
|
|
1125
|
-
if (!item || !item.provider?.google?.id) throw new Error("
|
|
1125
|
+
if (!item || !item.provider?.google?.id) throw new Error("Could not rename on Google Drive: item not found or not synced");
|
|
1126
1126
|
await drive.files.update({
|
|
1127
1127
|
fileId: item.provider.google.id,
|
|
1128
1128
|
requestBody: { name: newName }
|
|
@@ -1135,7 +1135,7 @@ var GoogleDriveProvider = {
|
|
|
1135
1135
|
const { client, accountId: foundAccountId } = await createAuthClient(owner, accountId);
|
|
1136
1136
|
const drive = google.drive({ version: "v3", auth: client });
|
|
1137
1137
|
const item = await drive_default.findOne({ _id: id, owner });
|
|
1138
|
-
if (!item || !item.provider?.google?.id) throw new Error("
|
|
1138
|
+
if (!item || !item.provider?.google?.id) throw new Error("Could not move on Google Drive: item not found or not synced");
|
|
1139
1139
|
let previousGoogleParentId = void 0;
|
|
1140
1140
|
if (item.parentId) {
|
|
1141
1141
|
const oldParent = await drive_default.findOne({ _id: item.parentId, owner });
|
|
@@ -1155,7 +1155,7 @@ var GoogleDriveProvider = {
|
|
|
1155
1155
|
let newGoogleParentId = "root";
|
|
1156
1156
|
if (newParentId && newParentId !== "root") {
|
|
1157
1157
|
const newParent = await drive_default.findOne({ _id: newParentId, owner });
|
|
1158
|
-
if (!newParent || !newParent.provider?.google?.id) throw new Error("
|
|
1158
|
+
if (!newParent || !newParent.provider?.google?.id) throw new Error("Could not move on Google Drive: target folder not found");
|
|
1159
1159
|
newGoogleParentId = newParent.provider.google.id;
|
|
1160
1160
|
}
|
|
1161
1161
|
await drive.files.update({
|
|
@@ -1223,15 +1223,15 @@ var driveReadFile = async (file) => {
|
|
|
1223
1223
|
let drive;
|
|
1224
1224
|
if (typeof file === "string") {
|
|
1225
1225
|
const doc = await drive_default.findById(file);
|
|
1226
|
-
if (!doc) throw new Error(
|
|
1226
|
+
if (!doc) throw new Error("Could not read file: the file no longer exists");
|
|
1227
1227
|
drive = doc;
|
|
1228
1228
|
} else if ("toClient" in file) {
|
|
1229
1229
|
drive = file;
|
|
1230
1230
|
} else {
|
|
1231
|
-
throw new Error("
|
|
1231
|
+
throw new Error("Could not read file: invalid file reference provided");
|
|
1232
1232
|
}
|
|
1233
1233
|
if (drive.information.type !== "FILE") {
|
|
1234
|
-
throw new Error("
|
|
1234
|
+
throw new Error("Could not read file: this item is a folder, not a file");
|
|
1235
1235
|
}
|
|
1236
1236
|
const provider = drive.provider?.type === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
1237
1237
|
const accountId = drive.storageAccountId?.toString();
|
|
@@ -1240,7 +1240,7 @@ var driveReadFile = async (file) => {
|
|
|
1240
1240
|
var driveInfo = async (source) => {
|
|
1241
1241
|
const fileId = typeof source === "string" ? source : source.id;
|
|
1242
1242
|
const drive = await drive_default.findById(fileId);
|
|
1243
|
-
if (!drive) throw new Error(
|
|
1243
|
+
if (!drive) throw new Error("Could not load file details: the file no longer exists");
|
|
1244
1244
|
let parentName;
|
|
1245
1245
|
if (drive.parentId) {
|
|
1246
1246
|
const parent = await drive_default.findById(drive.parentId);
|
|
@@ -1279,15 +1279,15 @@ var driveFilePath = async (file) => {
|
|
|
1279
1279
|
let drive;
|
|
1280
1280
|
if (typeof file === "string") {
|
|
1281
1281
|
const doc = await drive_default.findById(file);
|
|
1282
|
-
if (!doc) throw new Error(
|
|
1282
|
+
if (!doc) throw new Error("Could not locate file: the file no longer exists");
|
|
1283
1283
|
drive = doc;
|
|
1284
1284
|
} else if ("toClient" in file) {
|
|
1285
1285
|
drive = file;
|
|
1286
1286
|
} else {
|
|
1287
|
-
throw new Error("
|
|
1287
|
+
throw new Error("Could not locate file: invalid file reference provided");
|
|
1288
1288
|
}
|
|
1289
1289
|
if (drive.information.type !== "FILE") {
|
|
1290
|
-
throw new Error("
|
|
1290
|
+
throw new Error("Could not locate file: this item is a folder, not a file");
|
|
1291
1291
|
}
|
|
1292
1292
|
const config = getDriveConfig();
|
|
1293
1293
|
const STORAGE_PATH = config.storage.path;
|
|
@@ -1295,7 +1295,7 @@ var driveFilePath = async (file) => {
|
|
|
1295
1295
|
if (providerType === "LOCAL") {
|
|
1296
1296
|
const filePath = path.join(STORAGE_PATH, "file", String(drive._id), "data.bin");
|
|
1297
1297
|
if (!fs.existsSync(filePath)) {
|
|
1298
|
-
throw new Error(
|
|
1298
|
+
throw new Error("Could not locate file: the stored file is missing from disk");
|
|
1299
1299
|
}
|
|
1300
1300
|
return Object.freeze({
|
|
1301
1301
|
path: filePath,
|
|
@@ -1352,7 +1352,7 @@ var driveFilePath = async (file) => {
|
|
|
1352
1352
|
provider: "GOOGLE"
|
|
1353
1353
|
});
|
|
1354
1354
|
}
|
|
1355
|
-
throw new Error(`
|
|
1355
|
+
throw new Error(`Could not locate file: unsupported storage provider "${providerType}"`);
|
|
1356
1356
|
};
|
|
1357
1357
|
var driveList = async (options) => {
|
|
1358
1358
|
const { key, folderId, accountId, limit = 100, afterId } = options;
|
|
@@ -1360,7 +1360,7 @@ var driveList = async (options) => {
|
|
|
1360
1360
|
if (accountId && accountId !== "LOCAL") {
|
|
1361
1361
|
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner: key });
|
|
1362
1362
|
if (!account) {
|
|
1363
|
-
throw new Error("
|
|
1363
|
+
throw new Error("Could not list files: storage account not found or access denied");
|
|
1364
1364
|
}
|
|
1365
1365
|
if (account.metadata.provider === "GOOGLE") {
|
|
1366
1366
|
providerName = "GOOGLE";
|
|
@@ -1388,7 +1388,7 @@ var driveListFiles = async (options) => {
|
|
|
1388
1388
|
if (accountId && accountId !== "LOCAL") {
|
|
1389
1389
|
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner: key });
|
|
1390
1390
|
if (!account) {
|
|
1391
|
-
throw new Error("
|
|
1391
|
+
throw new Error("Could not load files: storage account not found or access denied");
|
|
1392
1392
|
}
|
|
1393
1393
|
if (account.metadata.provider === "GOOGLE") {
|
|
1394
1394
|
providerName = "GOOGLE";
|
|
@@ -1432,7 +1432,7 @@ var driveDelete = async (source, options) => {
|
|
|
1432
1432
|
let driveId;
|
|
1433
1433
|
if (typeof source === "string") {
|
|
1434
1434
|
const doc = await drive_default.findById(source);
|
|
1435
|
-
if (!doc) throw new Error(
|
|
1435
|
+
if (!doc) throw new Error("Could not delete: the file no longer exists");
|
|
1436
1436
|
drive = doc;
|
|
1437
1437
|
driveId = source;
|
|
1438
1438
|
} else if ("toClient" in source) {
|
|
@@ -1440,7 +1440,7 @@ var driveDelete = async (source, options) => {
|
|
|
1440
1440
|
driveId = String(drive._id);
|
|
1441
1441
|
} else {
|
|
1442
1442
|
const doc = await drive_default.findById(source.id);
|
|
1443
|
-
if (!doc) throw new Error(
|
|
1443
|
+
if (!doc) throw new Error("Could not delete: the selected file no longer exists");
|
|
1444
1444
|
drive = doc;
|
|
1445
1445
|
driveId = source.id;
|
|
1446
1446
|
}
|
|
@@ -1452,7 +1452,7 @@ var driveDelete = async (source, options) => {
|
|
|
1452
1452
|
trashedAt: null
|
|
1453
1453
|
});
|
|
1454
1454
|
if (childCount > 0) {
|
|
1455
|
-
throw new Error(`
|
|
1455
|
+
throw new Error(`Could not delete folder: it still contains ${childCount} item(s). Enable recursive delete to remove the folder and everything inside it.`);
|
|
1456
1456
|
}
|
|
1457
1457
|
}
|
|
1458
1458
|
const provider = drive.provider?.type === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
@@ -1463,17 +1463,17 @@ var driveDelete = async (source, options) => {
|
|
|
1463
1463
|
var resolveFolderByPath = async (folderPath, owner, accountId) => {
|
|
1464
1464
|
const normalizedPath = folderPath.replace(/^\/+|\/+$/g, "");
|
|
1465
1465
|
if (!normalizedPath) {
|
|
1466
|
-
throw new Error("
|
|
1466
|
+
throw new Error("Could not resolve folder: the folder path is empty");
|
|
1467
1467
|
}
|
|
1468
1468
|
const segments = normalizedPath.split("/").filter((s) => s.length > 0);
|
|
1469
1469
|
if (segments.length === 0) {
|
|
1470
|
-
throw new Error("
|
|
1470
|
+
throw new Error("Could not resolve folder: the folder path is invalid");
|
|
1471
1471
|
}
|
|
1472
1472
|
let providerName = "LOCAL";
|
|
1473
1473
|
if (accountId && accountId !== "LOCAL") {
|
|
1474
1474
|
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner });
|
|
1475
1475
|
if (!account) {
|
|
1476
|
-
throw new Error("
|
|
1476
|
+
throw new Error("Could not resolve folder: storage account not found or access denied");
|
|
1477
1477
|
}
|
|
1478
1478
|
if (account.metadata.provider === "GOOGLE") {
|
|
1479
1479
|
providerName = "GOOGLE";
|
|
@@ -1507,7 +1507,7 @@ var driveUpload = async (source, key, options) => {
|
|
|
1507
1507
|
if (accountId && accountId !== "LOCAL") {
|
|
1508
1508
|
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner: key });
|
|
1509
1509
|
if (!account) {
|
|
1510
|
-
throw new Error("
|
|
1510
|
+
throw new Error("Could not upload: storage account not found or access denied");
|
|
1511
1511
|
}
|
|
1512
1512
|
if (account.metadata.provider === "GOOGLE") {
|
|
1513
1513
|
provider = GoogleDriveProvider;
|
|
@@ -1518,7 +1518,7 @@ var driveUpload = async (source, key, options) => {
|
|
|
1518
1518
|
let fileSize;
|
|
1519
1519
|
if (typeof source === "string") {
|
|
1520
1520
|
if (!fs.existsSync(source)) {
|
|
1521
|
-
throw new Error(
|
|
1521
|
+
throw new Error("Could not upload: source file not found");
|
|
1522
1522
|
}
|
|
1523
1523
|
sourceFilePath = source;
|
|
1524
1524
|
const stats = fs.statSync(source);
|
|
@@ -1577,17 +1577,17 @@ var driveUpload = async (source, key, options) => {
|
|
|
1577
1577
|
mimeType = mimeTypes[ext] || "application/octet-stream";
|
|
1578
1578
|
}
|
|
1579
1579
|
if (config.security && !validateMimeType(mimeType, config.security.allowedMimeTypes)) {
|
|
1580
|
-
throw new Error(`
|
|
1580
|
+
throw new Error(`Could not upload: file type "${mimeType}" is not allowed`);
|
|
1581
1581
|
}
|
|
1582
1582
|
if (config.security && fileSize > config.security.maxUploadSizeInBytes) {
|
|
1583
|
-
throw new Error(
|
|
1583
|
+
throw new Error("Could not upload: file is larger than the maximum allowed size");
|
|
1584
1584
|
}
|
|
1585
1585
|
const isRootMode = config.mode === "ROOT";
|
|
1586
1586
|
if (!options.enforce && !isRootMode) {
|
|
1587
1587
|
const information = await getDriveInformation({ method: "KEY", key });
|
|
1588
1588
|
const quota = await provider.getQuota(key, accountId, information.storage.quotaInBytes);
|
|
1589
1589
|
if (quota.usedInBytes + fileSize > quota.quotaInBytes) {
|
|
1590
|
-
throw new Error("
|
|
1590
|
+
throw new Error("Could not upload: you have run out of storage space");
|
|
1591
1591
|
}
|
|
1592
1592
|
}
|
|
1593
1593
|
let resolvedParentId = null;
|
|
@@ -1806,7 +1806,7 @@ var getProvider = async (req, owner) => {
|
|
|
1806
1806
|
}
|
|
1807
1807
|
const account = await account_default.findOne({ _id: accountId, owner });
|
|
1808
1808
|
if (!account) {
|
|
1809
|
-
throw new Error("
|
|
1809
|
+
throw new Error("Storage account not found or access denied");
|
|
1810
1810
|
}
|
|
1811
1811
|
if (account.metadata.provider === "GOOGLE") return { provider: GoogleDriveProvider, accountId: account._id.toString() };
|
|
1812
1812
|
return { provider: LocalStorageProvider };
|
|
@@ -1869,41 +1869,41 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1869
1869
|
config = getDriveConfig();
|
|
1870
1870
|
} catch (error) {
|
|
1871
1871
|
console.error("[next-drive] Configuration error:", error);
|
|
1872
|
-
res.status(500).json({ status: 500, message: "
|
|
1872
|
+
res.status(500).json({ status: 500, message: "Drive is not ready: failed to initialize configuration" });
|
|
1873
1873
|
return;
|
|
1874
1874
|
}
|
|
1875
1875
|
const isPreflightHandled = applyCorsHeaders(req, res, config);
|
|
1876
1876
|
if (isPreflightHandled) return;
|
|
1877
1877
|
if (!action) {
|
|
1878
|
-
res.status(400).json({ status: 400, message:
|
|
1878
|
+
res.status(400).json({ status: 400, message: 'Missing "action" parameter in request' });
|
|
1879
1879
|
return;
|
|
1880
1880
|
}
|
|
1881
1881
|
if (action === "serve" || action === "thumbnail") {
|
|
1882
1882
|
try {
|
|
1883
1883
|
const { id, token } = req.query;
|
|
1884
1884
|
if (!id || typeof id !== "string") {
|
|
1885
|
-
return res.status(400).json({ status: 400, message: "
|
|
1885
|
+
return res.status(400).json({ status: 400, message: "Could not open file: missing or invalid file ID" });
|
|
1886
1886
|
}
|
|
1887
1887
|
const drive = await drive_default.findById(id);
|
|
1888
|
-
if (!drive) return res.status(404).json({ status: 404, message: "File not found" });
|
|
1888
|
+
if (!drive) return res.status(404).json({ status: 404, message: "File not found or no longer available" });
|
|
1889
1889
|
if (config.security?.signedUrls?.enabled) {
|
|
1890
1890
|
if (!token || typeof token !== "string") {
|
|
1891
|
-
return res.status(401).json({ status: 401, message: "
|
|
1891
|
+
return res.status(401).json({ status: 401, message: "Access denied: this link is missing its access token" });
|
|
1892
1892
|
}
|
|
1893
1893
|
try {
|
|
1894
1894
|
const decoded = Buffer.from(token, "base64url").toString();
|
|
1895
1895
|
const [expiryStr, signature] = decoded.split(":");
|
|
1896
1896
|
const expiry = parseInt(expiryStr, 10);
|
|
1897
1897
|
if (Date.now() / 1e3 > expiry) {
|
|
1898
|
-
return res.status(401).json({ status: 401, message: "
|
|
1898
|
+
return res.status(401).json({ status: 401, message: "Access denied: this link has expired" });
|
|
1899
1899
|
}
|
|
1900
1900
|
const { secret } = config.security.signedUrls;
|
|
1901
1901
|
const expectedSignature = crypto2.createHmac("sha256", secret).update(`${id}:${expiry}`).digest("hex");
|
|
1902
1902
|
if (signature !== expectedSignature) {
|
|
1903
|
-
return res.status(401).json({ status: 401, message: "
|
|
1903
|
+
return res.status(401).json({ status: 401, message: "Access denied: this link's access token is invalid" });
|
|
1904
1904
|
}
|
|
1905
1905
|
} catch (err) {
|
|
1906
|
-
return res.status(401).json({ status: 401, message: "
|
|
1906
|
+
return res.status(401).json({ status: 401, message: "Access denied: this link's access token is malformed" });
|
|
1907
1907
|
}
|
|
1908
1908
|
}
|
|
1909
1909
|
const itemProvider = drive.provider?.type === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
@@ -2009,7 +2009,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2009
2009
|
console.error(`[next-drive] Error in ${action}:`, error);
|
|
2010
2010
|
return res.status(500).json({
|
|
2011
2011
|
status: 500,
|
|
2012
|
-
message: error instanceof Error ? error.message : "
|
|
2012
|
+
message: error instanceof Error ? error.message : "Something went wrong while serving the file"
|
|
2013
2013
|
});
|
|
2014
2014
|
}
|
|
2015
2015
|
}
|
|
@@ -2039,7 +2039,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2039
2039
|
const { provider: provider2 } = req.query;
|
|
2040
2040
|
if (provider2 === "GOOGLE") {
|
|
2041
2041
|
const { clientId, clientSecret, redirectUri } = config.storage?.google || {};
|
|
2042
|
-
if (!clientId || !clientSecret || !redirectUri) return res.status(500).json({ status: 500, message: "Google not configured" });
|
|
2042
|
+
if (!clientId || !clientSecret || !redirectUri) return res.status(500).json({ status: 500, message: "Google Drive is not configured on the server" });
|
|
2043
2043
|
const callbackUri = new URL(redirectUri);
|
|
2044
2044
|
callbackUri.searchParams.set("action", "callback");
|
|
2045
2045
|
const oAuth2Client = new google.auth.OAuth2(clientId, clientSecret, callbackUri.toString());
|
|
@@ -2053,13 +2053,13 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2053
2053
|
});
|
|
2054
2054
|
return res.status(200).json({ status: 200, message: "Auth URL generated", data: { url } });
|
|
2055
2055
|
}
|
|
2056
|
-
return res.status(400).json({ status: 400, message: "Unknown provider" });
|
|
2056
|
+
return res.status(400).json({ status: 400, message: "Unknown storage provider requested" });
|
|
2057
2057
|
}
|
|
2058
2058
|
case "callback": {
|
|
2059
2059
|
const { code, state } = req.query;
|
|
2060
|
-
if (!code) return res.status(400).json({ status: 400, message: "
|
|
2060
|
+
if (!code) return res.status(400).json({ status: 400, message: "Google sign-in failed: authorization code missing" });
|
|
2061
2061
|
const { clientId, clientSecret, redirectUri } = config.storage?.google || {};
|
|
2062
|
-
if (!clientId || !clientSecret || !redirectUri) return res.status(500).json({ status: 500, message: "Google not configured" });
|
|
2062
|
+
if (!clientId || !clientSecret || !redirectUri) return res.status(500).json({ status: 500, message: "Google Drive sign-in is not configured on the server" });
|
|
2063
2063
|
const callbackUri = new URL(redirectUri);
|
|
2064
2064
|
callbackUri.searchParams.set("action", "callback");
|
|
2065
2065
|
const oAuth2Client = new google.auth.OAuth2(clientId, clientSecret, callbackUri.toString());
|
|
@@ -2134,7 +2134,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2134
2134
|
case "removeAccount": {
|
|
2135
2135
|
const { id } = req.query;
|
|
2136
2136
|
const account = await account_default.findOne({ _id: id, owner });
|
|
2137
|
-
if (!account) return res.status(404).json({ status: 404, message: "
|
|
2137
|
+
if (!account) return res.status(404).json({ status: 404, message: "Could not disconnect: account not found" });
|
|
2138
2138
|
if (account.metadata.provider === "GOOGLE") {
|
|
2139
2139
|
try {
|
|
2140
2140
|
await GoogleDriveProvider.revokeToken(owner, account._id.toString());
|
|
@@ -2152,9 +2152,9 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2152
2152
|
switch (action) {
|
|
2153
2153
|
// ** 1. LIST **
|
|
2154
2154
|
case "list": {
|
|
2155
|
-
if (req.method !== "GET") return res.status(405).json({ status: 405, message: "
|
|
2155
|
+
if (req.method !== "GET") return res.status(405).json({ status: 405, message: "Listing files requires a GET request" });
|
|
2156
2156
|
const listQuery = listQuerySchema.safeParse(req.query);
|
|
2157
|
-
if (!listQuery.success) return res.status(400).json({ status: 400, message: "
|
|
2157
|
+
if (!listQuery.success) return res.status(400).json({ status: 400, message: "Could not list files: invalid request parameters" });
|
|
2158
2158
|
const { folderId, limit, afterId } = listQuery.data;
|
|
2159
2159
|
try {
|
|
2160
2160
|
await provider.sync(folderId || "root", owner, accountId);
|
|
@@ -2179,7 +2179,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2179
2179
|
// ** 2. SEARCH **
|
|
2180
2180
|
case "search": {
|
|
2181
2181
|
const searchData = searchQuerySchema.safeParse(req.query);
|
|
2182
|
-
if (!searchData.success) return res.status(400).json({ status: 400, message: "
|
|
2182
|
+
if (!searchData.success) return res.status(400).json({ status: 400, message: "Could not search: invalid request parameters" });
|
|
2183
2183
|
const { q, folderId, limit, trashed } = searchData.data;
|
|
2184
2184
|
if (!trashed) {
|
|
2185
2185
|
try {
|
|
@@ -2204,7 +2204,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2204
2204
|
}
|
|
2205
2205
|
// ** 3. UPLOAD **
|
|
2206
2206
|
case "upload": {
|
|
2207
|
-
if (req.method !== "POST") return res.status(405).json({ status: 405, message: "
|
|
2207
|
+
if (req.method !== "POST") return res.status(405).json({ status: 405, message: "Uploading requires a POST request" });
|
|
2208
2208
|
const systemTmpDir = path.join(os2.tmpdir(), "next-drive-uploads");
|
|
2209
2209
|
if (!fs.existsSync(systemTmpDir)) fs.mkdirSync(systemTmpDir, { recursive: true });
|
|
2210
2210
|
const form = formidable({
|
|
@@ -2243,18 +2243,18 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2243
2243
|
let currentUploadId = driveId;
|
|
2244
2244
|
const tempBaseDir = path.join(os2.tmpdir(), "next-drive-uploads");
|
|
2245
2245
|
if (!currentUploadId) {
|
|
2246
|
-
if (chunkIndex !== 0) return res.status(400).json({ message: "
|
|
2246
|
+
if (chunkIndex !== 0) return res.status(400).json({ message: "Could not upload: missing upload session for this chunk" });
|
|
2247
2247
|
if (fileType && config.security) {
|
|
2248
2248
|
if (!validateMimeType(fileType, config.security.allowedMimeTypes)) {
|
|
2249
2249
|
cleanupTempFiles(files);
|
|
2250
|
-
return res.status(400).json({ status: 400, message: `
|
|
2250
|
+
return res.status(400).json({ status: 400, message: `Could not upload: file type "${fileType}" is not allowed` });
|
|
2251
2251
|
}
|
|
2252
2252
|
}
|
|
2253
2253
|
if (!isRootMode) {
|
|
2254
2254
|
const quota = await provider.getQuota(owner, accountId, information.storage.quotaInBytes);
|
|
2255
2255
|
if (quota.usedInBytes + fileSizeInBytes > quota.quotaInBytes) {
|
|
2256
2256
|
cleanupTempFiles(files);
|
|
2257
|
-
return res.status(413).json({ status: 413, message: "
|
|
2257
|
+
return res.status(413).json({ status: 413, message: "Could not upload: you have run out of storage space" });
|
|
2258
2258
|
}
|
|
2259
2259
|
}
|
|
2260
2260
|
currentUploadId = crypto2.randomUUID();
|
|
@@ -2276,11 +2276,11 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2276
2276
|
const uploadDir = path.join(tempBaseDir, currentUploadId);
|
|
2277
2277
|
if (!fs.existsSync(uploadDir)) {
|
|
2278
2278
|
cleanupTempFiles(files);
|
|
2279
|
-
return res.status(404).json({ status: 404, message: "
|
|
2279
|
+
return res.status(404).json({ status: 404, message: "Could not upload: this upload session was not found or has expired" });
|
|
2280
2280
|
}
|
|
2281
2281
|
try {
|
|
2282
2282
|
const chunkFile = Array.isArray(files.chunk) ? files.chunk[0] : files.chunk;
|
|
2283
|
-
if (!chunkFile) throw new Error("
|
|
2283
|
+
if (!chunkFile) throw new Error("Could not upload: no file chunk was received");
|
|
2284
2284
|
const partPath = path.join(uploadDir, `part_${chunkIndex}`);
|
|
2285
2285
|
try {
|
|
2286
2286
|
fs.renameSync(chunkFile.filepath, partPath);
|
|
@@ -2314,7 +2314,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2314
2314
|
const pPath = path.join(uploadDir, `part_${i}`);
|
|
2315
2315
|
if (!fs.existsSync(pPath)) {
|
|
2316
2316
|
writeStream.destroy();
|
|
2317
|
-
throw new Error(`
|
|
2317
|
+
throw new Error(`Could not finish upload: chunk ${i} is missing`);
|
|
2318
2318
|
}
|
|
2319
2319
|
const data = fs.readFileSync(pPath);
|
|
2320
2320
|
const canContinue = writeStream.write(data);
|
|
@@ -2335,11 +2335,11 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2335
2335
|
writeStream.once("error", reject);
|
|
2336
2336
|
});
|
|
2337
2337
|
if (!fs.existsSync(finalTempPath)) {
|
|
2338
|
-
throw new Error("
|
|
2338
|
+
throw new Error("Could not finish upload: failed to assemble the file");
|
|
2339
2339
|
}
|
|
2340
2340
|
const finalStats = fs.statSync(finalTempPath);
|
|
2341
2341
|
if (finalStats.size !== meta.fileSize) {
|
|
2342
|
-
throw new Error(
|
|
2342
|
+
throw new Error("Could not finish upload: the assembled file is incomplete (size mismatch)");
|
|
2343
2343
|
}
|
|
2344
2344
|
const drive = new drive_default({
|
|
2345
2345
|
owner: meta.owner,
|
|
@@ -2382,12 +2382,12 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2382
2382
|
return;
|
|
2383
2383
|
}
|
|
2384
2384
|
cleanupTempFiles(files);
|
|
2385
|
-
return res.status(400).json({ status: 400, message: "
|
|
2385
|
+
return res.status(400).json({ status: 400, message: "Could not upload: invalid upload request" });
|
|
2386
2386
|
}
|
|
2387
2387
|
// ** 4. CANCEL UPLOAD **
|
|
2388
2388
|
case "cancel": {
|
|
2389
2389
|
const cancelData = cancelQuerySchema.safeParse(req.query);
|
|
2390
|
-
if (!cancelData.success) return res.status(400).json({ status: 400, message: "
|
|
2390
|
+
if (!cancelData.success) return res.status(400).json({ status: 400, message: "Could not cancel upload: invalid ID" });
|
|
2391
2391
|
const { id } = cancelData.data;
|
|
2392
2392
|
const tempUploadDir = path.join(os2.tmpdir(), "next-drive-uploads", id);
|
|
2393
2393
|
if (fs.existsSync(tempUploadDir)) {
|
|
@@ -2410,10 +2410,10 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2410
2410
|
// ** 5. DELETE **
|
|
2411
2411
|
case "delete": {
|
|
2412
2412
|
const deleteData = deleteQuerySchema.safeParse(req.query);
|
|
2413
|
-
if (!deleteData.success) return res.status(400).json({ status: 400, message: "
|
|
2413
|
+
if (!deleteData.success) return res.status(400).json({ status: 400, message: "Could not move to trash: invalid ID" });
|
|
2414
2414
|
const { id } = deleteData.data;
|
|
2415
2415
|
const drive = await drive_default.findById(id);
|
|
2416
|
-
if (!drive) return res.status(404).json({ status: 404, message: "
|
|
2416
|
+
if (!drive) return res.status(404).json({ status: 404, message: "Could not move to trash: item not found" });
|
|
2417
2417
|
const itemProvider = drive.provider?.type === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
2418
2418
|
const itemAccountId = drive.storageAccountId ? drive.storageAccountId.toString() : void 0;
|
|
2419
2419
|
try {
|
|
@@ -2428,7 +2428,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2428
2428
|
// ** 6. HARD DELETE **
|
|
2429
2429
|
case "deletePermanent": {
|
|
2430
2430
|
const deleteData = deleteQuerySchema.safeParse(req.query);
|
|
2431
|
-
if (!deleteData.success) return res.status(400).json({ status: 400, message: "
|
|
2431
|
+
if (!deleteData.success) return res.status(400).json({ status: 400, message: "Could not delete: invalid ID" });
|
|
2432
2432
|
const { id } = deleteData.data;
|
|
2433
2433
|
await provider.delete([id], owner, accountId);
|
|
2434
2434
|
const quota = await provider.getQuota(owner, accountId, information.storage.quotaInBytes);
|
|
@@ -2469,10 +2469,10 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2469
2469
|
// ** 7C. RESTORE **
|
|
2470
2470
|
case "restore": {
|
|
2471
2471
|
const restoreData = deleteQuerySchema.safeParse(req.query);
|
|
2472
|
-
if (!restoreData.success) return res.status(400).json({ status: 400, message: "
|
|
2472
|
+
if (!restoreData.success) return res.status(400).json({ status: 400, message: "Could not restore: invalid ID" });
|
|
2473
2473
|
const { id } = restoreData.data;
|
|
2474
2474
|
const drive = await drive_default.findById(id);
|
|
2475
|
-
if (!drive) return res.status(404).json({ status: 404, message: "
|
|
2475
|
+
if (!drive) return res.status(404).json({ status: 404, message: "Could not restore: item not found" });
|
|
2476
2476
|
let targetParentId = drive.parentId;
|
|
2477
2477
|
if (targetParentId) {
|
|
2478
2478
|
const parent = await drive_default.findById(targetParentId);
|
|
@@ -2502,7 +2502,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2502
2502
|
// ** 7D. MOVE **
|
|
2503
2503
|
case "move": {
|
|
2504
2504
|
const moveData = moveBodySchema.safeParse(req.body);
|
|
2505
|
-
if (!moveData.success) return res.status(400).json({ status: 400, message: "
|
|
2505
|
+
if (!moveData.success) return res.status(400).json({ status: 400, message: "Could not move: invalid request data" });
|
|
2506
2506
|
const { ids, targetFolderId } = moveData.data;
|
|
2507
2507
|
const items = [];
|
|
2508
2508
|
const effectiveTargetId = targetFolderId === "root" || !targetFolderId ? null : targetFolderId;
|
|
@@ -2519,21 +2519,21 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2519
2519
|
// ** 8. RENAME **
|
|
2520
2520
|
case "rename": {
|
|
2521
2521
|
const renameData = renameBodySchema.safeParse({ id: req.query.id, ...req.body });
|
|
2522
|
-
if (!renameData.success) return res.status(400).json({ status: 400, message: "
|
|
2522
|
+
if (!renameData.success) return res.status(400).json({ status: 400, message: "Could not rename: invalid request data" });
|
|
2523
2523
|
const { id, newName } = renameData.data;
|
|
2524
2524
|
const item = addSignedUrlToken(await provider.rename(id, newName, owner, accountId), config);
|
|
2525
2525
|
return res.status(200).json({ status: 200, message: "Renamed", data: { item } });
|
|
2526
2526
|
}
|
|
2527
2527
|
// ** 9. THUMBNAIL **
|
|
2528
2528
|
default:
|
|
2529
|
-
res.status(400).json({ status: 400, message: `Unknown action: ${action}` });
|
|
2529
|
+
res.status(400).json({ status: 400, message: `Unknown action requested: "${action}"` });
|
|
2530
2530
|
}
|
|
2531
2531
|
} catch (error) {
|
|
2532
2532
|
console.error(`[next-drive] Error handling action ${action}:`, error);
|
|
2533
|
-
res.status(500).json({ status: 500, message: error instanceof Error ? error.message : "
|
|
2533
|
+
res.status(500).json({ status: 500, message: error instanceof Error ? error.message : "Something went wrong while processing your request" });
|
|
2534
2534
|
}
|
|
2535
2535
|
};
|
|
2536
2536
|
|
|
2537
2537
|
export { driveAPIHandler, driveCleanup, driveConfiguration, driveDelete, driveFilePath, driveFileSchemaZod, driveGetUrl, driveInfo, driveList, driveListFiles, driveReadFile, driveUpload, drive_default, getDriveConfig, getDriveInformation };
|
|
2538
|
-
//# sourceMappingURL=chunk-
|
|
2539
|
-
//# sourceMappingURL=chunk-
|
|
2538
|
+
//# sourceMappingURL=chunk-MVYNW56R.js.map
|
|
2539
|
+
//# sourceMappingURL=chunk-MVYNW56R.js.map
|