@muhgholy/next-drive 2.2.5 → 3.0.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/dist/{chunk-EV3BVXQN.js → chunk-KCDI2FBD.js} +96 -52
- package/dist/chunk-KCDI2FBD.js.map +1 -0
- package/dist/client/components/ui/dialog-fullscreen.d.ts.map +1 -1
- package/dist/client/index.css +59 -0
- package/dist/client/index.css.map +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -66
- package/dist/client/index.js.map +1 -1
- package/dist/client/styles.css +0 -4
- package/dist/server/controllers/drive.d.ts.map +1 -1
- package/dist/server/express.js +2 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/providers/local.d.ts.map +1 -1
- package/dist/server/utils.d.ts +0 -5
- package/dist/server/utils.d.ts.map +1 -1
- package/package.json +102 -107
- package/dist/chunk-EV3BVXQN.js.map +0 -1
- package/dist/client/styles.js +0 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __require } from './chunk-DGUM43GV.js';
|
|
2
2
|
import formidable from 'formidable';
|
|
3
3
|
import path3 from 'path';
|
|
4
|
-
import
|
|
4
|
+
import fs2 from 'fs';
|
|
5
5
|
import os from 'os';
|
|
6
6
|
import mongoose2, { Schema, isValidObjectId } from 'mongoose';
|
|
7
7
|
import crypto2 from 'crypto';
|
|
@@ -126,18 +126,6 @@ StorageAccountSchema.method("toClient", async function() {
|
|
|
126
126
|
});
|
|
127
127
|
var StorageAccount = mongoose2.models.StorageAccount || mongoose2.model("StorageAccount", StorageAccountSchema);
|
|
128
128
|
var account_default = StorageAccount;
|
|
129
|
-
var moveFile = (src, dest) => {
|
|
130
|
-
try {
|
|
131
|
-
fs5.renameSync(src, dest);
|
|
132
|
-
} catch (err) {
|
|
133
|
-
if (err.code === "EXDEV") {
|
|
134
|
-
fs5.copyFileSync(src, dest);
|
|
135
|
-
fs5.unlinkSync(src);
|
|
136
|
-
} else {
|
|
137
|
-
throw err;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
129
|
var validateMimeType = (mime, allowedTypes) => {
|
|
142
130
|
if (allowedTypes.includes("*/*")) return true;
|
|
143
131
|
return allowedTypes.some((pattern) => {
|
|
@@ -151,7 +139,7 @@ var validateMimeType = (mime, allowedTypes) => {
|
|
|
151
139
|
};
|
|
152
140
|
var computeFileHash = (filePath) => new Promise((resolve, reject) => {
|
|
153
141
|
const hash = crypto2.createHash("sha256");
|
|
154
|
-
const stream =
|
|
142
|
+
const stream = fs2.createReadStream(filePath);
|
|
155
143
|
stream.on("data", (data) => hash.update(data));
|
|
156
144
|
stream.on("end", () => resolve(hash.digest("hex")));
|
|
157
145
|
stream.on("error", reject);
|
|
@@ -271,11 +259,11 @@ var LocalStorageProvider = {
|
|
|
271
259
|
openStream: async (item, accountId) => {
|
|
272
260
|
if (item.information.type !== "FILE") throw new Error("Cannot stream folder");
|
|
273
261
|
const filePath = path3.join(getDriveConfig().storage.path, item.information.path);
|
|
274
|
-
if (!
|
|
262
|
+
if (!fs2.existsSync(filePath)) {
|
|
275
263
|
throw new Error("File not found on disk");
|
|
276
264
|
}
|
|
277
|
-
const stat =
|
|
278
|
-
const stream =
|
|
265
|
+
const stat = fs2.statSync(filePath);
|
|
266
|
+
const stream = fs2.createReadStream(filePath);
|
|
279
267
|
return {
|
|
280
268
|
stream,
|
|
281
269
|
mime: item.information.mime,
|
|
@@ -287,11 +275,11 @@ var LocalStorageProvider = {
|
|
|
287
275
|
const storagePath = getDriveConfig().storage.path;
|
|
288
276
|
const originalPath = path3.join(storagePath, item.information.path);
|
|
289
277
|
const thumbPath = path3.join(storagePath, "cache", "thumbnails", `${item._id.toString()}.webp`);
|
|
290
|
-
if (!
|
|
291
|
-
if (
|
|
292
|
-
return
|
|
278
|
+
if (!fs2.existsSync(originalPath)) throw new Error("Original file not found");
|
|
279
|
+
if (fs2.existsSync(thumbPath)) {
|
|
280
|
+
return fs2.createReadStream(thumbPath);
|
|
293
281
|
}
|
|
294
|
-
if (!
|
|
282
|
+
if (!fs2.existsSync(path3.dirname(thumbPath))) fs2.mkdirSync(path3.dirname(thumbPath), { recursive: true });
|
|
295
283
|
if (item.information.mime.startsWith("image/")) {
|
|
296
284
|
await sharp(originalPath).resize(300, 300, { fit: "inside" }).toFormat("webp", { quality: 80 }).toFile(thumbPath);
|
|
297
285
|
} else if (item.information.mime.startsWith("video/")) {
|
|
@@ -306,7 +294,7 @@ var LocalStorageProvider = {
|
|
|
306
294
|
} else {
|
|
307
295
|
throw new Error("Unsupported mime type for thumbnail");
|
|
308
296
|
}
|
|
309
|
-
return
|
|
297
|
+
return fs2.createReadStream(thumbPath);
|
|
310
298
|
},
|
|
311
299
|
createFolder: async (name, parentId, owner, accountId) => {
|
|
312
300
|
const getNextOrderValue = async (owner2) => {
|
|
@@ -327,10 +315,33 @@ var LocalStorageProvider = {
|
|
|
327
315
|
},
|
|
328
316
|
uploadFile: async (drive, filePath, accountId) => {
|
|
329
317
|
if (drive.information.type !== "FILE") throw new Error("Invalid drive type");
|
|
330
|
-
const
|
|
318
|
+
const storagePath = getDriveConfig().storage.path;
|
|
319
|
+
const destPath = path3.join(storagePath, drive.information.path);
|
|
331
320
|
const dirPath = path3.dirname(destPath);
|
|
332
|
-
if (!
|
|
333
|
-
|
|
321
|
+
if (!fs2.existsSync(filePath)) {
|
|
322
|
+
throw new Error("Source file not found");
|
|
323
|
+
}
|
|
324
|
+
if (!fs2.existsSync(dirPath)) {
|
|
325
|
+
fs2.mkdirSync(dirPath, { recursive: true });
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
fs2.renameSync(filePath, destPath);
|
|
329
|
+
} catch (err) {
|
|
330
|
+
if (err instanceof Error && "code" in err && err.code === "EXDEV") {
|
|
331
|
+
fs2.copyFileSync(filePath, destPath);
|
|
332
|
+
fs2.unlinkSync(filePath);
|
|
333
|
+
} else {
|
|
334
|
+
throw err;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (!fs2.existsSync(destPath)) {
|
|
338
|
+
throw new Error("Failed to write file to destination");
|
|
339
|
+
}
|
|
340
|
+
const destStats = fs2.statSync(destPath);
|
|
341
|
+
if (destStats.size !== drive.information.sizeInBytes) {
|
|
342
|
+
fs2.unlinkSync(destPath);
|
|
343
|
+
throw new Error(`Destination file size mismatch: expected ${drive.information.sizeInBytes}, got ${destStats.size}`);
|
|
344
|
+
}
|
|
334
345
|
drive.status = "READY";
|
|
335
346
|
drive.information.hash = await computeFileHash(destPath);
|
|
336
347
|
if (drive.information.mime.startsWith("image/")) {
|
|
@@ -359,8 +370,8 @@ var LocalStorageProvider = {
|
|
|
359
370
|
if (item.information.type === "FILE" && item.information.path) {
|
|
360
371
|
const fullPath = path3.join(getDriveConfig().storage.path, item.information.path);
|
|
361
372
|
const dirPath = path3.dirname(fullPath);
|
|
362
|
-
if (
|
|
363
|
-
|
|
373
|
+
if (fs2.existsSync(dirPath)) {
|
|
374
|
+
fs2.rmSync(dirPath, { recursive: true, force: true });
|
|
364
375
|
}
|
|
365
376
|
}
|
|
366
377
|
}
|
|
@@ -669,7 +680,7 @@ var GoogleDriveProvider = {
|
|
|
669
680
|
},
|
|
670
681
|
media: {
|
|
671
682
|
mimeType: drive.information.mime,
|
|
672
|
-
body:
|
|
683
|
+
body: fs2.createReadStream(filePath)
|
|
673
684
|
},
|
|
674
685
|
fields: "id, name, mimeType, webViewLink, iconLink, thumbnailLink, size"
|
|
675
686
|
});
|
|
@@ -859,7 +870,7 @@ var driveFilePath = async (file) => {
|
|
|
859
870
|
const providerType = drive.provider?.type || "LOCAL";
|
|
860
871
|
if (providerType === "LOCAL") {
|
|
861
872
|
const filePath = path3.join(STORAGE_PATH, drive.information.path);
|
|
862
|
-
if (!
|
|
873
|
+
if (!fs2.existsSync(filePath)) {
|
|
863
874
|
throw new Error(`Local file not found on disk: ${filePath}`);
|
|
864
875
|
}
|
|
865
876
|
return Object.freeze({
|
|
@@ -874,8 +885,8 @@ var driveFilePath = async (file) => {
|
|
|
874
885
|
const libraryDir = path3.join(STORAGE_PATH, "library", "google");
|
|
875
886
|
const fileName = `${drive._id}${path3.extname(drive.name)}`;
|
|
876
887
|
const cachedFilePath = path3.join(libraryDir, fileName);
|
|
877
|
-
if (
|
|
878
|
-
const stats =
|
|
888
|
+
if (fs2.existsSync(cachedFilePath)) {
|
|
889
|
+
const stats = fs2.statSync(cachedFilePath);
|
|
879
890
|
if (stats.size === drive.information.sizeInBytes) {
|
|
880
891
|
return Object.freeze({
|
|
881
892
|
path: cachedFilePath,
|
|
@@ -885,22 +896,31 @@ var driveFilePath = async (file) => {
|
|
|
885
896
|
provider: "GOOGLE"
|
|
886
897
|
});
|
|
887
898
|
}
|
|
888
|
-
|
|
899
|
+
fs2.unlinkSync(cachedFilePath);
|
|
889
900
|
}
|
|
890
901
|
const accountId = drive.storageAccountId?.toString();
|
|
891
902
|
const { stream } = await GoogleDriveProvider.openStream(drive, accountId);
|
|
892
|
-
if (!
|
|
893
|
-
|
|
903
|
+
if (!fs2.existsSync(libraryDir)) {
|
|
904
|
+
fs2.mkdirSync(libraryDir, { recursive: true });
|
|
894
905
|
}
|
|
895
906
|
const tempPath = `${cachedFilePath}.tmp`;
|
|
896
|
-
const writeStream =
|
|
907
|
+
const writeStream = fs2.createWriteStream(tempPath);
|
|
897
908
|
await new Promise((resolve, reject) => {
|
|
898
909
|
stream.pipe(writeStream);
|
|
899
910
|
writeStream.on("finish", resolve);
|
|
900
911
|
writeStream.on("error", reject);
|
|
901
912
|
stream.on("error", reject);
|
|
902
913
|
});
|
|
903
|
-
|
|
914
|
+
try {
|
|
915
|
+
fs2.renameSync(tempPath, cachedFilePath);
|
|
916
|
+
} catch (err) {
|
|
917
|
+
if (err instanceof Error && "code" in err && err.code === "EXDEV") {
|
|
918
|
+
fs2.copyFileSync(tempPath, cachedFilePath);
|
|
919
|
+
fs2.unlinkSync(tempPath);
|
|
920
|
+
} else {
|
|
921
|
+
throw err;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
904
924
|
return Object.freeze({
|
|
905
925
|
path: cachedFilePath,
|
|
906
926
|
name: drive.name,
|
|
@@ -1173,7 +1193,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1173
1193
|
case "upload": {
|
|
1174
1194
|
if (req.method !== "POST") return res.status(405).json({ status: 405, message: "Only POST allowed" });
|
|
1175
1195
|
const systemTmpDir = path3.join(os.tmpdir(), "next-drive-uploads");
|
|
1176
|
-
if (!
|
|
1196
|
+
if (!fs2.existsSync(systemTmpDir)) fs2.mkdirSync(systemTmpDir, { recursive: true });
|
|
1177
1197
|
const form = formidable({
|
|
1178
1198
|
multiples: false,
|
|
1179
1199
|
maxFileSize: config.security.maxUploadSizeInBytes * 2,
|
|
@@ -1188,7 +1208,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1188
1208
|
});
|
|
1189
1209
|
const cleanupTempFiles = (files2) => {
|
|
1190
1210
|
Object.values(files2).flat().forEach((file) => {
|
|
1191
|
-
if (file &&
|
|
1211
|
+
if (file && fs2.existsSync(file.filepath)) fs2.rmSync(file.filepath, { force: true });
|
|
1192
1212
|
});
|
|
1193
1213
|
};
|
|
1194
1214
|
const getString = (f) => Array.isArray(f) ? f[0] : f || "";
|
|
@@ -1222,7 +1242,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1222
1242
|
}
|
|
1223
1243
|
currentUploadId = crypto.randomUUID();
|
|
1224
1244
|
const uploadDir = path3.join(tempBaseDir, currentUploadId);
|
|
1225
|
-
|
|
1245
|
+
fs2.mkdirSync(uploadDir, { recursive: true });
|
|
1226
1246
|
const metadata = {
|
|
1227
1247
|
owner,
|
|
1228
1248
|
accountId,
|
|
@@ -1233,11 +1253,11 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1233
1253
|
mimeType: fileType,
|
|
1234
1254
|
totalChunks
|
|
1235
1255
|
};
|
|
1236
|
-
|
|
1256
|
+
fs2.writeFileSync(path3.join(uploadDir, "metadata.json"), JSON.stringify(metadata));
|
|
1237
1257
|
}
|
|
1238
1258
|
if (currentUploadId) {
|
|
1239
1259
|
const uploadDir = path3.join(tempBaseDir, currentUploadId);
|
|
1240
|
-
if (!
|
|
1260
|
+
if (!fs2.existsSync(uploadDir)) {
|
|
1241
1261
|
cleanupTempFiles(files);
|
|
1242
1262
|
return res.status(404).json({ status: 404, message: "Upload session not found or expired" });
|
|
1243
1263
|
}
|
|
@@ -1245,23 +1265,47 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1245
1265
|
const chunkFile = Array.isArray(files.chunk) ? files.chunk[0] : files.chunk;
|
|
1246
1266
|
if (!chunkFile) throw new Error("No chunk file received");
|
|
1247
1267
|
const partPath = path3.join(uploadDir, `part_${chunkIndex}`);
|
|
1248
|
-
|
|
1249
|
-
|
|
1268
|
+
try {
|
|
1269
|
+
fs2.renameSync(chunkFile.filepath, partPath);
|
|
1270
|
+
} catch (err) {
|
|
1271
|
+
if (err instanceof Error && "code" in err && err.code === "EXDEV") {
|
|
1272
|
+
fs2.copyFileSync(chunkFile.filepath, partPath);
|
|
1273
|
+
fs2.unlinkSync(chunkFile.filepath);
|
|
1274
|
+
} else {
|
|
1275
|
+
throw err;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
const uploadedParts = fs2.readdirSync(uploadDir).filter((f) => f.startsWith("part_"));
|
|
1250
1279
|
if (uploadedParts.length === totalChunks) {
|
|
1251
1280
|
const metaPath = path3.join(uploadDir, "metadata.json");
|
|
1252
|
-
const meta = JSON.parse(
|
|
1281
|
+
const meta = JSON.parse(fs2.readFileSync(metaPath, "utf-8"));
|
|
1253
1282
|
const finalTempPath = path3.join(uploadDir, "final.bin");
|
|
1254
|
-
const writeStream =
|
|
1283
|
+
const writeStream = fs2.createWriteStream(finalTempPath);
|
|
1284
|
+
await new Promise((resolve, reject) => {
|
|
1285
|
+
writeStream.on("open", () => resolve());
|
|
1286
|
+
writeStream.on("error", reject);
|
|
1287
|
+
});
|
|
1255
1288
|
for (let i = 0; i < totalChunks; i++) {
|
|
1256
1289
|
const pPath = path3.join(uploadDir, `part_${i}`);
|
|
1257
|
-
|
|
1290
|
+
if (!fs2.existsSync(pPath)) {
|
|
1291
|
+
writeStream.destroy();
|
|
1292
|
+
throw new Error(`Missing chunk part: ${i}`);
|
|
1293
|
+
}
|
|
1294
|
+
const data = fs2.readFileSync(pPath);
|
|
1258
1295
|
writeStream.write(data);
|
|
1259
1296
|
}
|
|
1260
1297
|
await new Promise((resolve, reject) => {
|
|
1298
|
+
writeStream.end();
|
|
1261
1299
|
writeStream.on("finish", resolve);
|
|
1262
1300
|
writeStream.on("error", reject);
|
|
1263
|
-
writeStream.end();
|
|
1264
1301
|
});
|
|
1302
|
+
if (!fs2.existsSync(finalTempPath)) {
|
|
1303
|
+
throw new Error("Failed to create merged file");
|
|
1304
|
+
}
|
|
1305
|
+
const finalStats = fs2.statSync(finalTempPath);
|
|
1306
|
+
if (finalStats.size !== meta.fileSize) {
|
|
1307
|
+
throw new Error(`File size mismatch: expected ${meta.fileSize}, got ${finalStats.size}`);
|
|
1308
|
+
}
|
|
1265
1309
|
const drive = new drive_default({
|
|
1266
1310
|
owner: meta.owner,
|
|
1267
1311
|
storageAccountId: meta.accountId || null,
|
|
@@ -1284,7 +1328,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1284
1328
|
await drive.save();
|
|
1285
1329
|
try {
|
|
1286
1330
|
const item = await provider.uploadFile(drive, finalTempPath, meta.accountId);
|
|
1287
|
-
|
|
1331
|
+
fs2.rmSync(uploadDir, { recursive: true, force: true });
|
|
1288
1332
|
const newQuota = await provider.getQuota(meta.owner, meta.accountId, information.storage.quotaInBytes);
|
|
1289
1333
|
res.status(200).json({ status: 200, message: "Upload complete", data: { type: "UPLOAD_COMPLETE", driveId: String(drive._id), item }, statistic: { storage: newQuota } });
|
|
1290
1334
|
} catch (err) {
|
|
@@ -1314,9 +1358,9 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1314
1358
|
if (!cancelData.success) return res.status(400).json({ status: 400, message: "Invalid ID" });
|
|
1315
1359
|
const { id } = cancelData.data;
|
|
1316
1360
|
const tempUploadDir = path3.join(os.tmpdir(), "next-drive-uploads", id);
|
|
1317
|
-
if (
|
|
1361
|
+
if (fs2.existsSync(tempUploadDir)) {
|
|
1318
1362
|
try {
|
|
1319
|
-
|
|
1363
|
+
fs2.rmSync(tempUploadDir, { recursive: true, force: true });
|
|
1320
1364
|
} catch (e) {
|
|
1321
1365
|
console.error("Failed to cleanup temp upload:", e);
|
|
1322
1366
|
}
|
|
@@ -1495,5 +1539,5 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1495
1539
|
};
|
|
1496
1540
|
|
|
1497
1541
|
export { driveAPIHandler, driveConfiguration, driveFilePath, driveFileSchemaZod, driveGetUrl, driveReadFile, getDriveConfig, getDriveInformation };
|
|
1498
|
-
//# sourceMappingURL=chunk-
|
|
1499
|
-
//# sourceMappingURL=chunk-
|
|
1542
|
+
//# sourceMappingURL=chunk-KCDI2FBD.js.map
|
|
1543
|
+
//# sourceMappingURL=chunk-KCDI2FBD.js.map
|