@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
|
@@ -542,11 +542,11 @@ var LocalStorageProvider = {
|
|
|
542
542
|
return { usedInBytes, quotaInBytes: configuredQuotaInBytes ?? 0 };
|
|
543
543
|
},
|
|
544
544
|
openStream: async (item, accountId) => {
|
|
545
|
-
if (item.information.type !== "FILE") throw new Error("
|
|
545
|
+
if (item.information.type !== "FILE") throw new Error("Could not open local file: folders cannot be streamed");
|
|
546
546
|
const storagePath = getDriveConfig().storage.path;
|
|
547
547
|
const filePath = path__default.default.join(storagePath, "file", item._id.toString(), "data.bin");
|
|
548
548
|
if (!fs__default.default.existsSync(filePath)) {
|
|
549
|
-
throw new Error("
|
|
549
|
+
throw new Error("Could not open local file: it is missing from disk");
|
|
550
550
|
}
|
|
551
551
|
const stat = fs__default.default.statSync(filePath);
|
|
552
552
|
const stream = fs__default.default.createReadStream(filePath);
|
|
@@ -557,13 +557,13 @@ var LocalStorageProvider = {
|
|
|
557
557
|
};
|
|
558
558
|
},
|
|
559
559
|
getThumbnail: async (item, accountId) => {
|
|
560
|
-
if (item.information.type !== "FILE") throw new Error("No
|
|
560
|
+
if (item.information.type !== "FILE") throw new Error("No preview available: folders do not have thumbnails");
|
|
561
561
|
const storagePath = getDriveConfig().storage.path;
|
|
562
562
|
const fileDir = path__default.default.join(storagePath, "file", item._id.toString());
|
|
563
563
|
const originalPath = path__default.default.join(fileDir, "data.bin");
|
|
564
564
|
const thumbDir = path__default.default.join(fileDir, "cache");
|
|
565
565
|
const thumbPath = path__default.default.join(thumbDir, "thumbnail.webp");
|
|
566
|
-
if (!fs__default.default.existsSync(originalPath)) throw new Error("
|
|
566
|
+
if (!fs__default.default.existsSync(originalPath)) throw new Error("Could not generate preview: the original file is missing");
|
|
567
567
|
if (fs__default.default.existsSync(thumbPath)) {
|
|
568
568
|
return fs__default.default.createReadStream(thumbPath);
|
|
569
569
|
}
|
|
@@ -612,12 +612,12 @@ var LocalStorageProvider = {
|
|
|
612
612
|
return folder.toClient();
|
|
613
613
|
},
|
|
614
614
|
uploadFile: async (drive, filePath, accountId) => {
|
|
615
|
-
if (drive.information.type !== "FILE") throw new Error("
|
|
615
|
+
if (drive.information.type !== "FILE") throw new Error("Could not save local file: invalid file record");
|
|
616
616
|
const storagePath = getDriveConfig().storage.path;
|
|
617
617
|
const destDir = path__default.default.join(storagePath, "file", String(drive._id));
|
|
618
618
|
const destPath = path__default.default.join(destDir, "data.bin");
|
|
619
619
|
if (!fs__default.default.existsSync(filePath)) {
|
|
620
|
-
throw new Error("
|
|
620
|
+
throw new Error("Could not save local file: the uploaded data is missing");
|
|
621
621
|
}
|
|
622
622
|
if (!fs__default.default.existsSync(destDir)) {
|
|
623
623
|
fs__default.default.mkdirSync(destDir, { recursive: true });
|
|
@@ -633,12 +633,12 @@ var LocalStorageProvider = {
|
|
|
633
633
|
}
|
|
634
634
|
}
|
|
635
635
|
if (!fs__default.default.existsSync(destPath)) {
|
|
636
|
-
throw new Error("
|
|
636
|
+
throw new Error("Could not save local file: writing to storage failed");
|
|
637
637
|
}
|
|
638
638
|
const destStats = fs__default.default.statSync(destPath);
|
|
639
639
|
if (destStats.size !== drive.information.sizeInBytes) {
|
|
640
640
|
fs__default.default.unlinkSync(destPath);
|
|
641
|
-
throw new Error(
|
|
641
|
+
throw new Error("Could not save local file: the stored data was incomplete (size mismatch)");
|
|
642
642
|
}
|
|
643
643
|
drive.status = "READY";
|
|
644
644
|
drive.information.path = path__default.default.join("file", String(drive._id), "data.bin");
|
|
@@ -683,12 +683,12 @@ var LocalStorageProvider = {
|
|
|
683
683
|
},
|
|
684
684
|
rename: async (id, newName, owner, accountId) => {
|
|
685
685
|
const item = await drive_default.findOneAndUpdate({ _id: id, owner }, { name: newName }, { new: true });
|
|
686
|
-
if (!item) throw new Error("
|
|
686
|
+
if (!item) throw new Error("Could not rename: the item no longer exists");
|
|
687
687
|
return item.toClient();
|
|
688
688
|
},
|
|
689
689
|
move: async (id, newParentId, owner, accountId) => {
|
|
690
690
|
const item = await drive_default.findOne({ _id: id, owner });
|
|
691
|
-
if (!item) throw new Error("
|
|
691
|
+
if (!item) throw new Error("Could not move: the item no longer exists");
|
|
692
692
|
item.parentId = newParentId === "root" || !newParentId ? null : new mongoose__default.default.Types.ObjectId(newParentId);
|
|
693
693
|
await item.save();
|
|
694
694
|
return item.toClient();
|
|
@@ -731,13 +731,13 @@ var createAuthClient = async (owner, accountId) => {
|
|
|
731
731
|
const query = { owner, "metadata.provider": "GOOGLE" };
|
|
732
732
|
if (accountId) query._id = accountId;
|
|
733
733
|
const account = await account_default.findOne(query);
|
|
734
|
-
if (!account) throw new Error("Google Drive account not connected");
|
|
734
|
+
if (!account) throw new Error("Could not reach Google Drive: account not connected");
|
|
735
735
|
const config = getDriveConfig();
|
|
736
736
|
const { clientId, clientSecret, redirectUri } = config.storage?.google || {};
|
|
737
|
-
if (!clientId || !clientSecret) throw new Error("Google credentials not configured on server");
|
|
737
|
+
if (!clientId || !clientSecret) throw new Error("Could not reach Google Drive: Google credentials are not configured on the server");
|
|
738
738
|
const oAuth2Client = new googleapis.google.auth.OAuth2(clientId, clientSecret, redirectUri);
|
|
739
739
|
if (account.metadata.provider !== "GOOGLE" || !account.metadata.google) {
|
|
740
|
-
throw new Error("
|
|
740
|
+
throw new Error("Could not reach Google Drive: account data is invalid, please reconnect");
|
|
741
741
|
}
|
|
742
742
|
oAuth2Client.setCredentials(account.metadata.google.credentials);
|
|
743
743
|
oAuth2Client.on("tokens", async (tokens) => {
|
|
@@ -959,8 +959,8 @@ var GoogleDriveProvider = {
|
|
|
959
959
|
openStream: async (item, accountId) => {
|
|
960
960
|
const { client } = await createAuthClient(item.owner, accountId || item.storageAccountId?.toString());
|
|
961
961
|
const drive = googleapis.google.drive({ version: "v3", auth: client });
|
|
962
|
-
if (!item.provider?.google?.id) throw new Error("
|
|
963
|
-
if (item.information.type === "FOLDER") throw new Error("
|
|
962
|
+
if (!item.provider?.google?.id) throw new Error("Could not open Google Drive file: its Google file ID is missing");
|
|
963
|
+
if (item.information.type === "FOLDER") throw new Error("Could not open Google Drive file: folders cannot be streamed");
|
|
964
964
|
const res = await drive.files.get(
|
|
965
965
|
{ fileId: item.provider.google.id, alt: "media" },
|
|
966
966
|
{ responseType: "stream" }
|
|
@@ -980,7 +980,7 @@ var GoogleDriveProvider = {
|
|
|
980
980
|
return fs__default.default.createReadStream(thumbPath);
|
|
981
981
|
}
|
|
982
982
|
const { client } = await createAuthClient(item.owner, accountId || item.storageAccountId?.toString());
|
|
983
|
-
if (!item.provider?.google?.thumbnailLink) throw new Error("No
|
|
983
|
+
if (!item.provider?.google?.thumbnailLink) throw new Error("No preview available for this Google Drive file");
|
|
984
984
|
const res = await client.request({ url: item.provider.google.thumbnailLink, responseType: "stream" });
|
|
985
985
|
if (!fs__default.default.existsSync(thumbDir)) {
|
|
986
986
|
fs__default.default.mkdirSync(thumbDir, { recursive: true });
|
|
@@ -1020,7 +1020,7 @@ var GoogleDriveProvider = {
|
|
|
1020
1020
|
fields: "id, name, mimeType, webViewLink, iconLink"
|
|
1021
1021
|
});
|
|
1022
1022
|
const file = res.data;
|
|
1023
|
-
if (!file.id) throw new Error("
|
|
1023
|
+
if (!file.id) throw new Error("Could not create folder on Google Drive");
|
|
1024
1024
|
const folder = new drive_default({
|
|
1025
1025
|
owner,
|
|
1026
1026
|
name: file.name,
|
|
@@ -1041,7 +1041,7 @@ var GoogleDriveProvider = {
|
|
|
1041
1041
|
return folder.toClient();
|
|
1042
1042
|
},
|
|
1043
1043
|
uploadFile: async (drive, filePath, accountId) => {
|
|
1044
|
-
if (drive.information.type !== "FILE") throw new Error("
|
|
1044
|
+
if (drive.information.type !== "FILE") throw new Error("Could not upload to Google Drive: invalid file record");
|
|
1045
1045
|
const { client } = await createAuthClient(drive.owner, accountId || drive.storageAccountId?.toString());
|
|
1046
1046
|
const googleDrive = googleapis.google.drive({ version: "v3", auth: client });
|
|
1047
1047
|
let googleParentId = "root";
|
|
@@ -1063,7 +1063,7 @@ var GoogleDriveProvider = {
|
|
|
1063
1063
|
fields: "id, name, mimeType, webViewLink, iconLink, thumbnailLink, size"
|
|
1064
1064
|
});
|
|
1065
1065
|
const gFile = res.data;
|
|
1066
|
-
if (!gFile.id) throw new Error("
|
|
1066
|
+
if (!gFile.id) throw new Error("Could not upload to Google Drive: no file was created");
|
|
1067
1067
|
drive.status = "READY";
|
|
1068
1068
|
drive.provider = {
|
|
1069
1069
|
type: "GOOGLE",
|
|
@@ -1135,7 +1135,7 @@ var GoogleDriveProvider = {
|
|
|
1135
1135
|
const { client } = await createAuthClient(owner, accountId);
|
|
1136
1136
|
const drive = googleapis.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 rename on Google Drive: item not found or not synced");
|
|
1139
1139
|
await drive.files.update({
|
|
1140
1140
|
fileId: item.provider.google.id,
|
|
1141
1141
|
requestBody: { name: newName }
|
|
@@ -1148,7 +1148,7 @@ var GoogleDriveProvider = {
|
|
|
1148
1148
|
const { client, accountId: foundAccountId } = await createAuthClient(owner, accountId);
|
|
1149
1149
|
const drive = googleapis.google.drive({ version: "v3", auth: client });
|
|
1150
1150
|
const item = await drive_default.findOne({ _id: id, owner });
|
|
1151
|
-
if (!item || !item.provider?.google?.id) throw new Error("
|
|
1151
|
+
if (!item || !item.provider?.google?.id) throw new Error("Could not move on Google Drive: item not found or not synced");
|
|
1152
1152
|
let previousGoogleParentId = void 0;
|
|
1153
1153
|
if (item.parentId) {
|
|
1154
1154
|
const oldParent = await drive_default.findOne({ _id: item.parentId, owner });
|
|
@@ -1168,7 +1168,7 @@ var GoogleDriveProvider = {
|
|
|
1168
1168
|
let newGoogleParentId = "root";
|
|
1169
1169
|
if (newParentId && newParentId !== "root") {
|
|
1170
1170
|
const newParent = await drive_default.findOne({ _id: newParentId, owner });
|
|
1171
|
-
if (!newParent || !newParent.provider?.google?.id) throw new Error("
|
|
1171
|
+
if (!newParent || !newParent.provider?.google?.id) throw new Error("Could not move on Google Drive: target folder not found");
|
|
1172
1172
|
newGoogleParentId = newParent.provider.google.id;
|
|
1173
1173
|
}
|
|
1174
1174
|
await drive.files.update({
|
|
@@ -1236,15 +1236,15 @@ var driveReadFile = async (file) => {
|
|
|
1236
1236
|
let drive;
|
|
1237
1237
|
if (typeof file === "string") {
|
|
1238
1238
|
const doc = await drive_default.findById(file);
|
|
1239
|
-
if (!doc) throw new Error(
|
|
1239
|
+
if (!doc) throw new Error("Could not read file: the file no longer exists");
|
|
1240
1240
|
drive = doc;
|
|
1241
1241
|
} else if ("toClient" in file) {
|
|
1242
1242
|
drive = file;
|
|
1243
1243
|
} else {
|
|
1244
|
-
throw new Error("
|
|
1244
|
+
throw new Error("Could not read file: invalid file reference provided");
|
|
1245
1245
|
}
|
|
1246
1246
|
if (drive.information.type !== "FILE") {
|
|
1247
|
-
throw new Error("
|
|
1247
|
+
throw new Error("Could not read file: this item is a folder, not a file");
|
|
1248
1248
|
}
|
|
1249
1249
|
const provider = drive.provider?.type === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
1250
1250
|
const accountId = drive.storageAccountId?.toString();
|
|
@@ -1253,7 +1253,7 @@ var driveReadFile = async (file) => {
|
|
|
1253
1253
|
var driveInfo = async (source) => {
|
|
1254
1254
|
const fileId = typeof source === "string" ? source : source.id;
|
|
1255
1255
|
const drive = await drive_default.findById(fileId);
|
|
1256
|
-
if (!drive) throw new Error(
|
|
1256
|
+
if (!drive) throw new Error("Could not load file details: the file no longer exists");
|
|
1257
1257
|
let parentName;
|
|
1258
1258
|
if (drive.parentId) {
|
|
1259
1259
|
const parent = await drive_default.findById(drive.parentId);
|
|
@@ -1292,15 +1292,15 @@ var driveFilePath = async (file) => {
|
|
|
1292
1292
|
let drive;
|
|
1293
1293
|
if (typeof file === "string") {
|
|
1294
1294
|
const doc = await drive_default.findById(file);
|
|
1295
|
-
if (!doc) throw new Error(
|
|
1295
|
+
if (!doc) throw new Error("Could not locate file: the file no longer exists");
|
|
1296
1296
|
drive = doc;
|
|
1297
1297
|
} else if ("toClient" in file) {
|
|
1298
1298
|
drive = file;
|
|
1299
1299
|
} else {
|
|
1300
|
-
throw new Error("
|
|
1300
|
+
throw new Error("Could not locate file: invalid file reference provided");
|
|
1301
1301
|
}
|
|
1302
1302
|
if (drive.information.type !== "FILE") {
|
|
1303
|
-
throw new Error("
|
|
1303
|
+
throw new Error("Could not locate file: this item is a folder, not a file");
|
|
1304
1304
|
}
|
|
1305
1305
|
const config = getDriveConfig();
|
|
1306
1306
|
const STORAGE_PATH = config.storage.path;
|
|
@@ -1308,7 +1308,7 @@ var driveFilePath = async (file) => {
|
|
|
1308
1308
|
if (providerType === "LOCAL") {
|
|
1309
1309
|
const filePath = path__default.default.join(STORAGE_PATH, "file", String(drive._id), "data.bin");
|
|
1310
1310
|
if (!fs__default.default.existsSync(filePath)) {
|
|
1311
|
-
throw new Error(
|
|
1311
|
+
throw new Error("Could not locate file: the stored file is missing from disk");
|
|
1312
1312
|
}
|
|
1313
1313
|
return Object.freeze({
|
|
1314
1314
|
path: filePath,
|
|
@@ -1365,7 +1365,7 @@ var driveFilePath = async (file) => {
|
|
|
1365
1365
|
provider: "GOOGLE"
|
|
1366
1366
|
});
|
|
1367
1367
|
}
|
|
1368
|
-
throw new Error(`
|
|
1368
|
+
throw new Error(`Could not locate file: unsupported storage provider "${providerType}"`);
|
|
1369
1369
|
};
|
|
1370
1370
|
var driveList = async (options) => {
|
|
1371
1371
|
const { key, folderId, accountId, limit = 100, afterId } = options;
|
|
@@ -1373,7 +1373,7 @@ var driveList = async (options) => {
|
|
|
1373
1373
|
if (accountId && accountId !== "LOCAL") {
|
|
1374
1374
|
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner: key });
|
|
1375
1375
|
if (!account) {
|
|
1376
|
-
throw new Error("
|
|
1376
|
+
throw new Error("Could not list files: storage account not found or access denied");
|
|
1377
1377
|
}
|
|
1378
1378
|
if (account.metadata.provider === "GOOGLE") {
|
|
1379
1379
|
providerName = "GOOGLE";
|
|
@@ -1401,7 +1401,7 @@ var driveListFiles = async (options) => {
|
|
|
1401
1401
|
if (accountId && accountId !== "LOCAL") {
|
|
1402
1402
|
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner: key });
|
|
1403
1403
|
if (!account) {
|
|
1404
|
-
throw new Error("
|
|
1404
|
+
throw new Error("Could not load files: storage account not found or access denied");
|
|
1405
1405
|
}
|
|
1406
1406
|
if (account.metadata.provider === "GOOGLE") {
|
|
1407
1407
|
providerName = "GOOGLE";
|
|
@@ -1445,7 +1445,7 @@ var driveDelete = async (source, options) => {
|
|
|
1445
1445
|
let driveId;
|
|
1446
1446
|
if (typeof source === "string") {
|
|
1447
1447
|
const doc = await drive_default.findById(source);
|
|
1448
|
-
if (!doc) throw new Error(
|
|
1448
|
+
if (!doc) throw new Error("Could not delete: the file no longer exists");
|
|
1449
1449
|
drive = doc;
|
|
1450
1450
|
driveId = source;
|
|
1451
1451
|
} else if ("toClient" in source) {
|
|
@@ -1453,7 +1453,7 @@ var driveDelete = async (source, options) => {
|
|
|
1453
1453
|
driveId = String(drive._id);
|
|
1454
1454
|
} else {
|
|
1455
1455
|
const doc = await drive_default.findById(source.id);
|
|
1456
|
-
if (!doc) throw new Error(
|
|
1456
|
+
if (!doc) throw new Error("Could not delete: the selected file no longer exists");
|
|
1457
1457
|
drive = doc;
|
|
1458
1458
|
driveId = source.id;
|
|
1459
1459
|
}
|
|
@@ -1465,7 +1465,7 @@ var driveDelete = async (source, options) => {
|
|
|
1465
1465
|
trashedAt: null
|
|
1466
1466
|
});
|
|
1467
1467
|
if (childCount > 0) {
|
|
1468
|
-
throw new Error(`
|
|
1468
|
+
throw new Error(`Could not delete folder: it still contains ${childCount} item(s). Enable recursive delete to remove the folder and everything inside it.`);
|
|
1469
1469
|
}
|
|
1470
1470
|
}
|
|
1471
1471
|
const provider = drive.provider?.type === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
@@ -1476,17 +1476,17 @@ var driveDelete = async (source, options) => {
|
|
|
1476
1476
|
var resolveFolderByPath = async (folderPath, owner, accountId) => {
|
|
1477
1477
|
const normalizedPath = folderPath.replace(/^\/+|\/+$/g, "");
|
|
1478
1478
|
if (!normalizedPath) {
|
|
1479
|
-
throw new Error("
|
|
1479
|
+
throw new Error("Could not resolve folder: the folder path is empty");
|
|
1480
1480
|
}
|
|
1481
1481
|
const segments = normalizedPath.split("/").filter((s) => s.length > 0);
|
|
1482
1482
|
if (segments.length === 0) {
|
|
1483
|
-
throw new Error("
|
|
1483
|
+
throw new Error("Could not resolve folder: the folder path is invalid");
|
|
1484
1484
|
}
|
|
1485
1485
|
let providerName = "LOCAL";
|
|
1486
1486
|
if (accountId && accountId !== "LOCAL") {
|
|
1487
1487
|
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner });
|
|
1488
1488
|
if (!account) {
|
|
1489
|
-
throw new Error("
|
|
1489
|
+
throw new Error("Could not resolve folder: storage account not found or access denied");
|
|
1490
1490
|
}
|
|
1491
1491
|
if (account.metadata.provider === "GOOGLE") {
|
|
1492
1492
|
providerName = "GOOGLE";
|
|
@@ -1520,7 +1520,7 @@ var driveUpload = async (source, key, options) => {
|
|
|
1520
1520
|
if (accountId && accountId !== "LOCAL") {
|
|
1521
1521
|
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner: key });
|
|
1522
1522
|
if (!account) {
|
|
1523
|
-
throw new Error("
|
|
1523
|
+
throw new Error("Could not upload: storage account not found or access denied");
|
|
1524
1524
|
}
|
|
1525
1525
|
if (account.metadata.provider === "GOOGLE") {
|
|
1526
1526
|
provider = GoogleDriveProvider;
|
|
@@ -1531,7 +1531,7 @@ var driveUpload = async (source, key, options) => {
|
|
|
1531
1531
|
let fileSize;
|
|
1532
1532
|
if (typeof source === "string") {
|
|
1533
1533
|
if (!fs__default.default.existsSync(source)) {
|
|
1534
|
-
throw new Error(
|
|
1534
|
+
throw new Error("Could not upload: source file not found");
|
|
1535
1535
|
}
|
|
1536
1536
|
sourceFilePath = source;
|
|
1537
1537
|
const stats = fs__default.default.statSync(source);
|
|
@@ -1590,17 +1590,17 @@ var driveUpload = async (source, key, options) => {
|
|
|
1590
1590
|
mimeType = mimeTypes[ext] || "application/octet-stream";
|
|
1591
1591
|
}
|
|
1592
1592
|
if (config.security && !validateMimeType(mimeType, config.security.allowedMimeTypes)) {
|
|
1593
|
-
throw new Error(`
|
|
1593
|
+
throw new Error(`Could not upload: file type "${mimeType}" is not allowed`);
|
|
1594
1594
|
}
|
|
1595
1595
|
if (config.security && fileSize > config.security.maxUploadSizeInBytes) {
|
|
1596
|
-
throw new Error(
|
|
1596
|
+
throw new Error("Could not upload: file is larger than the maximum allowed size");
|
|
1597
1597
|
}
|
|
1598
1598
|
const isRootMode = config.mode === "ROOT";
|
|
1599
1599
|
if (!options.enforce && !isRootMode) {
|
|
1600
1600
|
const information = await getDriveInformation({ method: "KEY", key });
|
|
1601
1601
|
const quota = await provider.getQuota(key, accountId, information.storage.quotaInBytes);
|
|
1602
1602
|
if (quota.usedInBytes + fileSize > quota.quotaInBytes) {
|
|
1603
|
-
throw new Error("
|
|
1603
|
+
throw new Error("Could not upload: you have run out of storage space");
|
|
1604
1604
|
}
|
|
1605
1605
|
}
|
|
1606
1606
|
let resolvedParentId = null;
|
|
@@ -1819,7 +1819,7 @@ var getProvider = async (req, owner) => {
|
|
|
1819
1819
|
}
|
|
1820
1820
|
const account = await account_default.findOne({ _id: accountId, owner });
|
|
1821
1821
|
if (!account) {
|
|
1822
|
-
throw new Error("
|
|
1822
|
+
throw new Error("Storage account not found or access denied");
|
|
1823
1823
|
}
|
|
1824
1824
|
if (account.metadata.provider === "GOOGLE") return { provider: GoogleDriveProvider, accountId: account._id.toString() };
|
|
1825
1825
|
return { provider: LocalStorageProvider };
|
|
@@ -1882,41 +1882,41 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1882
1882
|
config = getDriveConfig();
|
|
1883
1883
|
} catch (error) {
|
|
1884
1884
|
console.error("[next-drive] Configuration error:", error);
|
|
1885
|
-
res.status(500).json({ status: 500, message: "
|
|
1885
|
+
res.status(500).json({ status: 500, message: "Drive is not ready: failed to initialize configuration" });
|
|
1886
1886
|
return;
|
|
1887
1887
|
}
|
|
1888
1888
|
const isPreflightHandled = applyCorsHeaders(req, res, config);
|
|
1889
1889
|
if (isPreflightHandled) return;
|
|
1890
1890
|
if (!action) {
|
|
1891
|
-
res.status(400).json({ status: 400, message:
|
|
1891
|
+
res.status(400).json({ status: 400, message: 'Missing "action" parameter in request' });
|
|
1892
1892
|
return;
|
|
1893
1893
|
}
|
|
1894
1894
|
if (action === "serve" || action === "thumbnail") {
|
|
1895
1895
|
try {
|
|
1896
1896
|
const { id, token } = req.query;
|
|
1897
1897
|
if (!id || typeof id !== "string") {
|
|
1898
|
-
return res.status(400).json({ status: 400, message: "
|
|
1898
|
+
return res.status(400).json({ status: 400, message: "Could not open file: missing or invalid file ID" });
|
|
1899
1899
|
}
|
|
1900
1900
|
const drive = await drive_default.findById(id);
|
|
1901
|
-
if (!drive) return res.status(404).json({ status: 404, message: "File not found" });
|
|
1901
|
+
if (!drive) return res.status(404).json({ status: 404, message: "File not found or no longer available" });
|
|
1902
1902
|
if (config.security?.signedUrls?.enabled) {
|
|
1903
1903
|
if (!token || typeof token !== "string") {
|
|
1904
|
-
return res.status(401).json({ status: 401, message: "
|
|
1904
|
+
return res.status(401).json({ status: 401, message: "Access denied: this link is missing its access token" });
|
|
1905
1905
|
}
|
|
1906
1906
|
try {
|
|
1907
1907
|
const decoded = Buffer.from(token, "base64url").toString();
|
|
1908
1908
|
const [expiryStr, signature] = decoded.split(":");
|
|
1909
1909
|
const expiry = parseInt(expiryStr, 10);
|
|
1910
1910
|
if (Date.now() / 1e3 > expiry) {
|
|
1911
|
-
return res.status(401).json({ status: 401, message: "
|
|
1911
|
+
return res.status(401).json({ status: 401, message: "Access denied: this link has expired" });
|
|
1912
1912
|
}
|
|
1913
1913
|
const { secret } = config.security.signedUrls;
|
|
1914
1914
|
const expectedSignature = crypto2__default.default.createHmac("sha256", secret).update(`${id}:${expiry}`).digest("hex");
|
|
1915
1915
|
if (signature !== expectedSignature) {
|
|
1916
|
-
return res.status(401).json({ status: 401, message: "
|
|
1916
|
+
return res.status(401).json({ status: 401, message: "Access denied: this link's access token is invalid" });
|
|
1917
1917
|
}
|
|
1918
1918
|
} catch (err) {
|
|
1919
|
-
return res.status(401).json({ status: 401, message: "
|
|
1919
|
+
return res.status(401).json({ status: 401, message: "Access denied: this link's access token is malformed" });
|
|
1920
1920
|
}
|
|
1921
1921
|
}
|
|
1922
1922
|
const itemProvider = drive.provider?.type === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
@@ -2022,7 +2022,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2022
2022
|
console.error(`[next-drive] Error in ${action}:`, error);
|
|
2023
2023
|
return res.status(500).json({
|
|
2024
2024
|
status: 500,
|
|
2025
|
-
message: error instanceof Error ? error.message : "
|
|
2025
|
+
message: error instanceof Error ? error.message : "Something went wrong while serving the file"
|
|
2026
2026
|
});
|
|
2027
2027
|
}
|
|
2028
2028
|
}
|
|
@@ -2052,7 +2052,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2052
2052
|
const { provider: provider2 } = req.query;
|
|
2053
2053
|
if (provider2 === "GOOGLE") {
|
|
2054
2054
|
const { clientId, clientSecret, redirectUri } = config.storage?.google || {};
|
|
2055
|
-
if (!clientId || !clientSecret || !redirectUri) return res.status(500).json({ status: 500, message: "Google not configured" });
|
|
2055
|
+
if (!clientId || !clientSecret || !redirectUri) return res.status(500).json({ status: 500, message: "Google Drive is not configured on the server" });
|
|
2056
2056
|
const callbackUri = new URL(redirectUri);
|
|
2057
2057
|
callbackUri.searchParams.set("action", "callback");
|
|
2058
2058
|
const oAuth2Client = new googleapis.google.auth.OAuth2(clientId, clientSecret, callbackUri.toString());
|
|
@@ -2066,13 +2066,13 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2066
2066
|
});
|
|
2067
2067
|
return res.status(200).json({ status: 200, message: "Auth URL generated", data: { url } });
|
|
2068
2068
|
}
|
|
2069
|
-
return res.status(400).json({ status: 400, message: "Unknown provider" });
|
|
2069
|
+
return res.status(400).json({ status: 400, message: "Unknown storage provider requested" });
|
|
2070
2070
|
}
|
|
2071
2071
|
case "callback": {
|
|
2072
2072
|
const { code, state } = req.query;
|
|
2073
|
-
if (!code) return res.status(400).json({ status: 400, message: "
|
|
2073
|
+
if (!code) return res.status(400).json({ status: 400, message: "Google sign-in failed: authorization code missing" });
|
|
2074
2074
|
const { clientId, clientSecret, redirectUri } = config.storage?.google || {};
|
|
2075
|
-
if (!clientId || !clientSecret || !redirectUri) return res.status(500).json({ status: 500, message: "Google not configured" });
|
|
2075
|
+
if (!clientId || !clientSecret || !redirectUri) return res.status(500).json({ status: 500, message: "Google Drive sign-in is not configured on the server" });
|
|
2076
2076
|
const callbackUri = new URL(redirectUri);
|
|
2077
2077
|
callbackUri.searchParams.set("action", "callback");
|
|
2078
2078
|
const oAuth2Client = new googleapis.google.auth.OAuth2(clientId, clientSecret, callbackUri.toString());
|
|
@@ -2147,7 +2147,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2147
2147
|
case "removeAccount": {
|
|
2148
2148
|
const { id } = req.query;
|
|
2149
2149
|
const account = await account_default.findOne({ _id: id, owner });
|
|
2150
|
-
if (!account) return res.status(404).json({ status: 404, message: "
|
|
2150
|
+
if (!account) return res.status(404).json({ status: 404, message: "Could not disconnect: account not found" });
|
|
2151
2151
|
if (account.metadata.provider === "GOOGLE") {
|
|
2152
2152
|
try {
|
|
2153
2153
|
await GoogleDriveProvider.revokeToken(owner, account._id.toString());
|
|
@@ -2165,9 +2165,9 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2165
2165
|
switch (action) {
|
|
2166
2166
|
// ** 1. LIST **
|
|
2167
2167
|
case "list": {
|
|
2168
|
-
if (req.method !== "GET") return res.status(405).json({ status: 405, message: "
|
|
2168
|
+
if (req.method !== "GET") return res.status(405).json({ status: 405, message: "Listing files requires a GET request" });
|
|
2169
2169
|
const listQuery = listQuerySchema.safeParse(req.query);
|
|
2170
|
-
if (!listQuery.success) return res.status(400).json({ status: 400, message: "
|
|
2170
|
+
if (!listQuery.success) return res.status(400).json({ status: 400, message: "Could not list files: invalid request parameters" });
|
|
2171
2171
|
const { folderId, limit, afterId } = listQuery.data;
|
|
2172
2172
|
try {
|
|
2173
2173
|
await provider.sync(folderId || "root", owner, accountId);
|
|
@@ -2192,7 +2192,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2192
2192
|
// ** 2. SEARCH **
|
|
2193
2193
|
case "search": {
|
|
2194
2194
|
const searchData = searchQuerySchema.safeParse(req.query);
|
|
2195
|
-
if (!searchData.success) return res.status(400).json({ status: 400, message: "
|
|
2195
|
+
if (!searchData.success) return res.status(400).json({ status: 400, message: "Could not search: invalid request parameters" });
|
|
2196
2196
|
const { q, folderId, limit, trashed } = searchData.data;
|
|
2197
2197
|
if (!trashed) {
|
|
2198
2198
|
try {
|
|
@@ -2217,7 +2217,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2217
2217
|
}
|
|
2218
2218
|
// ** 3. UPLOAD **
|
|
2219
2219
|
case "upload": {
|
|
2220
|
-
if (req.method !== "POST") return res.status(405).json({ status: 405, message: "
|
|
2220
|
+
if (req.method !== "POST") return res.status(405).json({ status: 405, message: "Uploading requires a POST request" });
|
|
2221
2221
|
const systemTmpDir = path__default.default.join(os2__default.default.tmpdir(), "next-drive-uploads");
|
|
2222
2222
|
if (!fs__default.default.existsSync(systemTmpDir)) fs__default.default.mkdirSync(systemTmpDir, { recursive: true });
|
|
2223
2223
|
const form = formidable__default.default({
|
|
@@ -2256,18 +2256,18 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2256
2256
|
let currentUploadId = driveId;
|
|
2257
2257
|
const tempBaseDir = path__default.default.join(os2__default.default.tmpdir(), "next-drive-uploads");
|
|
2258
2258
|
if (!currentUploadId) {
|
|
2259
|
-
if (chunkIndex !== 0) return res.status(400).json({ message: "
|
|
2259
|
+
if (chunkIndex !== 0) return res.status(400).json({ message: "Could not upload: missing upload session for this chunk" });
|
|
2260
2260
|
if (fileType && config.security) {
|
|
2261
2261
|
if (!validateMimeType(fileType, config.security.allowedMimeTypes)) {
|
|
2262
2262
|
cleanupTempFiles(files);
|
|
2263
|
-
return res.status(400).json({ status: 400, message: `
|
|
2263
|
+
return res.status(400).json({ status: 400, message: `Could not upload: file type "${fileType}" is not allowed` });
|
|
2264
2264
|
}
|
|
2265
2265
|
}
|
|
2266
2266
|
if (!isRootMode) {
|
|
2267
2267
|
const quota = await provider.getQuota(owner, accountId, information.storage.quotaInBytes);
|
|
2268
2268
|
if (quota.usedInBytes + fileSizeInBytes > quota.quotaInBytes) {
|
|
2269
2269
|
cleanupTempFiles(files);
|
|
2270
|
-
return res.status(413).json({ status: 413, message: "
|
|
2270
|
+
return res.status(413).json({ status: 413, message: "Could not upload: you have run out of storage space" });
|
|
2271
2271
|
}
|
|
2272
2272
|
}
|
|
2273
2273
|
currentUploadId = crypto2__default.default.randomUUID();
|
|
@@ -2289,11 +2289,11 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2289
2289
|
const uploadDir = path__default.default.join(tempBaseDir, currentUploadId);
|
|
2290
2290
|
if (!fs__default.default.existsSync(uploadDir)) {
|
|
2291
2291
|
cleanupTempFiles(files);
|
|
2292
|
-
return res.status(404).json({ status: 404, message: "
|
|
2292
|
+
return res.status(404).json({ status: 404, message: "Could not upload: this upload session was not found or has expired" });
|
|
2293
2293
|
}
|
|
2294
2294
|
try {
|
|
2295
2295
|
const chunkFile = Array.isArray(files.chunk) ? files.chunk[0] : files.chunk;
|
|
2296
|
-
if (!chunkFile) throw new Error("
|
|
2296
|
+
if (!chunkFile) throw new Error("Could not upload: no file chunk was received");
|
|
2297
2297
|
const partPath = path__default.default.join(uploadDir, `part_${chunkIndex}`);
|
|
2298
2298
|
try {
|
|
2299
2299
|
fs__default.default.renameSync(chunkFile.filepath, partPath);
|
|
@@ -2327,7 +2327,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2327
2327
|
const pPath = path__default.default.join(uploadDir, `part_${i}`);
|
|
2328
2328
|
if (!fs__default.default.existsSync(pPath)) {
|
|
2329
2329
|
writeStream.destroy();
|
|
2330
|
-
throw new Error(`
|
|
2330
|
+
throw new Error(`Could not finish upload: chunk ${i} is missing`);
|
|
2331
2331
|
}
|
|
2332
2332
|
const data = fs__default.default.readFileSync(pPath);
|
|
2333
2333
|
const canContinue = writeStream.write(data);
|
|
@@ -2348,11 +2348,11 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2348
2348
|
writeStream.once("error", reject);
|
|
2349
2349
|
});
|
|
2350
2350
|
if (!fs__default.default.existsSync(finalTempPath)) {
|
|
2351
|
-
throw new Error("
|
|
2351
|
+
throw new Error("Could not finish upload: failed to assemble the file");
|
|
2352
2352
|
}
|
|
2353
2353
|
const finalStats = fs__default.default.statSync(finalTempPath);
|
|
2354
2354
|
if (finalStats.size !== meta.fileSize) {
|
|
2355
|
-
throw new Error(
|
|
2355
|
+
throw new Error("Could not finish upload: the assembled file is incomplete (size mismatch)");
|
|
2356
2356
|
}
|
|
2357
2357
|
const drive = new drive_default({
|
|
2358
2358
|
owner: meta.owner,
|
|
@@ -2395,12 +2395,12 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2395
2395
|
return;
|
|
2396
2396
|
}
|
|
2397
2397
|
cleanupTempFiles(files);
|
|
2398
|
-
return res.status(400).json({ status: 400, message: "
|
|
2398
|
+
return res.status(400).json({ status: 400, message: "Could not upload: invalid upload request" });
|
|
2399
2399
|
}
|
|
2400
2400
|
// ** 4. CANCEL UPLOAD **
|
|
2401
2401
|
case "cancel": {
|
|
2402
2402
|
const cancelData = cancelQuerySchema.safeParse(req.query);
|
|
2403
|
-
if (!cancelData.success) return res.status(400).json({ status: 400, message: "
|
|
2403
|
+
if (!cancelData.success) return res.status(400).json({ status: 400, message: "Could not cancel upload: invalid ID" });
|
|
2404
2404
|
const { id } = cancelData.data;
|
|
2405
2405
|
const tempUploadDir = path__default.default.join(os2__default.default.tmpdir(), "next-drive-uploads", id);
|
|
2406
2406
|
if (fs__default.default.existsSync(tempUploadDir)) {
|
|
@@ -2423,10 +2423,10 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2423
2423
|
// ** 5. DELETE **
|
|
2424
2424
|
case "delete": {
|
|
2425
2425
|
const deleteData = deleteQuerySchema.safeParse(req.query);
|
|
2426
|
-
if (!deleteData.success) return res.status(400).json({ status: 400, message: "
|
|
2426
|
+
if (!deleteData.success) return res.status(400).json({ status: 400, message: "Could not move to trash: invalid ID" });
|
|
2427
2427
|
const { id } = deleteData.data;
|
|
2428
2428
|
const drive = await drive_default.findById(id);
|
|
2429
|
-
if (!drive) return res.status(404).json({ status: 404, message: "
|
|
2429
|
+
if (!drive) return res.status(404).json({ status: 404, message: "Could not move to trash: item not found" });
|
|
2430
2430
|
const itemProvider = drive.provider?.type === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
2431
2431
|
const itemAccountId = drive.storageAccountId ? drive.storageAccountId.toString() : void 0;
|
|
2432
2432
|
try {
|
|
@@ -2441,7 +2441,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2441
2441
|
// ** 6. HARD DELETE **
|
|
2442
2442
|
case "deletePermanent": {
|
|
2443
2443
|
const deleteData = deleteQuerySchema.safeParse(req.query);
|
|
2444
|
-
if (!deleteData.success) return res.status(400).json({ status: 400, message: "
|
|
2444
|
+
if (!deleteData.success) return res.status(400).json({ status: 400, message: "Could not delete: invalid ID" });
|
|
2445
2445
|
const { id } = deleteData.data;
|
|
2446
2446
|
await provider.delete([id], owner, accountId);
|
|
2447
2447
|
const quota = await provider.getQuota(owner, accountId, information.storage.quotaInBytes);
|
|
@@ -2482,10 +2482,10 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2482
2482
|
// ** 7C. RESTORE **
|
|
2483
2483
|
case "restore": {
|
|
2484
2484
|
const restoreData = deleteQuerySchema.safeParse(req.query);
|
|
2485
|
-
if (!restoreData.success) return res.status(400).json({ status: 400, message: "
|
|
2485
|
+
if (!restoreData.success) return res.status(400).json({ status: 400, message: "Could not restore: invalid ID" });
|
|
2486
2486
|
const { id } = restoreData.data;
|
|
2487
2487
|
const drive = await drive_default.findById(id);
|
|
2488
|
-
if (!drive) return res.status(404).json({ status: 404, message: "
|
|
2488
|
+
if (!drive) return res.status(404).json({ status: 404, message: "Could not restore: item not found" });
|
|
2489
2489
|
let targetParentId = drive.parentId;
|
|
2490
2490
|
if (targetParentId) {
|
|
2491
2491
|
const parent = await drive_default.findById(targetParentId);
|
|
@@ -2515,7 +2515,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2515
2515
|
// ** 7D. MOVE **
|
|
2516
2516
|
case "move": {
|
|
2517
2517
|
const moveData = moveBodySchema.safeParse(req.body);
|
|
2518
|
-
if (!moveData.success) return res.status(400).json({ status: 400, message: "
|
|
2518
|
+
if (!moveData.success) return res.status(400).json({ status: 400, message: "Could not move: invalid request data" });
|
|
2519
2519
|
const { ids, targetFolderId } = moveData.data;
|
|
2520
2520
|
const items = [];
|
|
2521
2521
|
const effectiveTargetId = targetFolderId === "root" || !targetFolderId ? null : targetFolderId;
|
|
@@ -2532,18 +2532,18 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2532
2532
|
// ** 8. RENAME **
|
|
2533
2533
|
case "rename": {
|
|
2534
2534
|
const renameData = renameBodySchema.safeParse({ id: req.query.id, ...req.body });
|
|
2535
|
-
if (!renameData.success) return res.status(400).json({ status: 400, message: "
|
|
2535
|
+
if (!renameData.success) return res.status(400).json({ status: 400, message: "Could not rename: invalid request data" });
|
|
2536
2536
|
const { id, newName } = renameData.data;
|
|
2537
2537
|
const item = addSignedUrlToken(await provider.rename(id, newName, owner, accountId), config);
|
|
2538
2538
|
return res.status(200).json({ status: 200, message: "Renamed", data: { item } });
|
|
2539
2539
|
}
|
|
2540
2540
|
// ** 9. THUMBNAIL **
|
|
2541
2541
|
default:
|
|
2542
|
-
res.status(400).json({ status: 400, message: `Unknown action: ${action}` });
|
|
2542
|
+
res.status(400).json({ status: 400, message: `Unknown action requested: "${action}"` });
|
|
2543
2543
|
}
|
|
2544
2544
|
} catch (error) {
|
|
2545
2545
|
console.error(`[next-drive] Error handling action ${action}:`, error);
|
|
2546
|
-
res.status(500).json({ status: 500, message: error instanceof Error ? error.message : "
|
|
2546
|
+
res.status(500).json({ status: 500, message: error instanceof Error ? error.message : "Something went wrong while processing your request" });
|
|
2547
2547
|
}
|
|
2548
2548
|
};
|
|
2549
2549
|
|
|
@@ -2562,5 +2562,5 @@ exports.driveUpload = driveUpload;
|
|
|
2562
2562
|
exports.drive_default = drive_default;
|
|
2563
2563
|
exports.getDriveConfig = getDriveConfig;
|
|
2564
2564
|
exports.getDriveInformation = getDriveInformation;
|
|
2565
|
-
//# sourceMappingURL=chunk-
|
|
2566
|
-
//# sourceMappingURL=chunk-
|
|
2565
|
+
//# sourceMappingURL=chunk-LAKT7IJJ.cjs.map
|
|
2566
|
+
//# sourceMappingURL=chunk-LAKT7IJJ.cjs.map
|