@muhgholy/next-drive 4.6.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -87
- package/dist/{chunk-UT2XCOS7.js → chunk-AYHO6FSR.js} +102 -44
- package/dist/chunk-AYHO6FSR.js.map +1 -0
- package/dist/{chunk-I3AR7V7Z.cjs → chunk-TAG5UMWA.cjs} +102 -44
- package/dist/chunk-TAG5UMWA.cjs.map +1 -0
- package/dist/server/controllers/drive.d.ts +27 -3
- package/dist/server/controllers/drive.d.ts.map +1 -1
- package/dist/server/express.cjs +11 -11
- package/dist/server/express.js +2 -2
- package/dist/server/index.cjs +13 -13
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/utils.d.ts +2 -2
- package/dist/server/utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-I3AR7V7Z.cjs.map +0 -1
- package/dist/chunk-UT2XCOS7.js.map +0 -1
|
@@ -370,70 +370,58 @@ var extractImageMetadata = async (filePath) => {
|
|
|
370
370
|
}
|
|
371
371
|
};
|
|
372
372
|
var DISPLAY_PRESETS = {
|
|
373
|
-
"article-header": 0.9,
|
|
374
|
-
|
|
375
|
-
"
|
|
376
|
-
|
|
377
|
-
"
|
|
378
|
-
|
|
379
|
-
"
|
|
380
|
-
|
|
381
|
-
"
|
|
382
|
-
|
|
383
|
-
"
|
|
384
|
-
|
|
385
|
-
"
|
|
386
|
-
|
|
387
|
-
"
|
|
388
|
-
// Open Graph/social sharing
|
|
389
|
-
"icon": 0.75,
|
|
390
|
-
// Small icons
|
|
391
|
-
"cover": 0.9,
|
|
392
|
-
// Full-width covers
|
|
393
|
-
"story": 0.85
|
|
394
|
-
// Story/vertical format
|
|
373
|
+
"article-header": { ratio: [16, 9], baseWidth: 1200, qualityFactor: 0.9 },
|
|
374
|
+
"article-image": { ratio: [16, 9], baseWidth: 800, qualityFactor: 0.85 },
|
|
375
|
+
"thumbnail": { ratio: [1, 1], baseWidth: 150, qualityFactor: 0.7 },
|
|
376
|
+
"avatar": { ratio: [1, 1], baseWidth: 128, qualityFactor: 0.8 },
|
|
377
|
+
"logo": { ratio: [2, 1], baseWidth: 200, qualityFactor: 0.95 },
|
|
378
|
+
"card": { ratio: [4, 3], baseWidth: 400, qualityFactor: 0.8 },
|
|
379
|
+
"gallery": { ratio: [1, 1], baseWidth: 600, qualityFactor: 0.85 },
|
|
380
|
+
"og": { ratio: [1200, 630], baseWidth: 1200, qualityFactor: 0.9 },
|
|
381
|
+
"icon": { ratio: [1, 1], baseWidth: 48, qualityFactor: 0.75 },
|
|
382
|
+
"cover": { ratio: [16, 9], baseWidth: 1920, qualityFactor: 0.9 },
|
|
383
|
+
"story": { ratio: [9, 16], baseWidth: 1080, qualityFactor: 0.85 },
|
|
384
|
+
"video": { ratio: [16, 9], baseWidth: 1280, qualityFactor: 0.85 },
|
|
385
|
+
"banner": { ratio: [3, 1], baseWidth: 1200, qualityFactor: 0.9 },
|
|
386
|
+
"portrait": { ratio: [3, 4], baseWidth: 600, qualityFactor: 0.85 },
|
|
387
|
+
"landscape": { ratio: [4, 3], baseWidth: 800, qualityFactor: 0.85 }
|
|
395
388
|
};
|
|
396
|
-
var
|
|
397
|
-
|
|
389
|
+
var SIZE_SCALES = {
|
|
390
|
+
"xs": 0.25,
|
|
391
|
+
"sm": 0.5,
|
|
392
|
+
"md": 1,
|
|
393
|
+
"lg": 1.5,
|
|
394
|
+
"xl": 2,
|
|
395
|
+
"2xl": 2.5
|
|
396
|
+
};
|
|
397
|
+
var STANDALONE_SIZES = {
|
|
398
398
|
"xs": { width: 64, height: 64 },
|
|
399
399
|
"sm": { width: 128, height: 128 },
|
|
400
400
|
"md": { width: 256, height: 256 },
|
|
401
401
|
"lg": { width: 512, height: 512 },
|
|
402
402
|
"xl": { width: 1024, height: 1024 },
|
|
403
403
|
"2xl": { width: 1600, height: 1600 },
|
|
404
|
-
// Named squares
|
|
405
404
|
"icon": { width: 48, height: 48 },
|
|
406
405
|
"thumb": { width: 150, height: 150 },
|
|
407
406
|
"square": { width: 600, height: 600 },
|
|
408
407
|
"avatar-sm": { width: 64, height: 64 },
|
|
409
408
|
"avatar-md": { width: 128, height: 128 },
|
|
410
409
|
"avatar-lg": { width: 256, height: 256 },
|
|
411
|
-
// Landscape (16:9)
|
|
412
410
|
"landscape-sm": { width: 480, height: 270 },
|
|
413
411
|
"landscape": { width: 800, height: 450 },
|
|
414
412
|
"landscape-lg": { width: 1280, height: 720 },
|
|
415
413
|
"landscape-xl": { width: 1920, height: 1080 },
|
|
416
|
-
// Portrait (9:16)
|
|
417
414
|
"portrait-sm": { width: 270, height: 480 },
|
|
418
415
|
"portrait": { width: 450, height: 800 },
|
|
419
416
|
"portrait-lg": { width: 720, height: 1280 },
|
|
420
|
-
// Wide/Banner (OG, social)
|
|
421
417
|
"wide": { width: 1200, height: 630 },
|
|
422
|
-
// Open Graph standard
|
|
423
418
|
"banner": { width: 1200, height: 400 },
|
|
424
|
-
// Banner/header
|
|
425
419
|
"banner-sm": { width: 800, height: 200 },
|
|
426
|
-
// Classic photo ratios
|
|
427
420
|
"photo-4x3": { width: 800, height: 600 },
|
|
428
|
-
// 4:3
|
|
429
421
|
"photo-3x2": { width: 900, height: 600 },
|
|
430
|
-
// 3:2
|
|
431
|
-
// Story/vertical (9:16)
|
|
432
422
|
"story": { width: 1080, height: 1920 },
|
|
433
|
-
// Video thumbnails
|
|
434
423
|
"video": { width: 1280, height: 720 },
|
|
435
424
|
"video-sm": { width: 640, height: 360 },
|
|
436
|
-
// Card sizes
|
|
437
425
|
"card-sm": { width: 300, height: 200 },
|
|
438
426
|
"card": { width: 400, height: 300 },
|
|
439
427
|
"card-lg": { width: 600, height: 400 }
|
|
@@ -447,8 +435,24 @@ var getImageSettings = (fileSizeInBytes, qualityPreset, display, size) => {
|
|
|
447
435
|
const n = parseInt(qualityPreset, 10);
|
|
448
436
|
if (!isNaN(n)) baseQuality = Math.min(100, Math.max(1, n));
|
|
449
437
|
}
|
|
450
|
-
|
|
451
|
-
|
|
438
|
+
let width;
|
|
439
|
+
let height;
|
|
440
|
+
let qualityFactor = 1;
|
|
441
|
+
const displayPreset = display ? DISPLAY_PRESETS[display] : void 0;
|
|
442
|
+
if (displayPreset) {
|
|
443
|
+
qualityFactor = displayPreset.qualityFactor;
|
|
444
|
+
const [ratioW, ratioH] = displayPreset.ratio;
|
|
445
|
+
const scale = size && SIZE_SCALES[size] ? SIZE_SCALES[size] : 1;
|
|
446
|
+
width = Math.round(displayPreset.baseWidth * scale);
|
|
447
|
+
height = Math.round(width * ratioH / ratioW);
|
|
448
|
+
} else if (size) {
|
|
449
|
+
const standalone = STANDALONE_SIZES[size];
|
|
450
|
+
if (standalone) {
|
|
451
|
+
width = standalone.width;
|
|
452
|
+
height = standalone.height;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
baseQuality = Math.round(baseQuality * qualityFactor);
|
|
452
456
|
let quality = baseQuality;
|
|
453
457
|
let effort = 4;
|
|
454
458
|
let pngCompression = 6;
|
|
@@ -476,12 +480,11 @@ var getImageSettings = (fileSizeInBytes, qualityPreset, display, size) => {
|
|
|
476
480
|
pngCompression = 7;
|
|
477
481
|
}
|
|
478
482
|
}
|
|
479
|
-
const dimensions = size && SIZE_PRESETS[size] ? SIZE_PRESETS[size] : void 0;
|
|
480
483
|
return {
|
|
481
484
|
quality: Math.max(1, Math.min(100, quality)),
|
|
482
485
|
effort,
|
|
483
486
|
pngCompression,
|
|
484
|
-
...
|
|
487
|
+
...width && height && { width, height }
|
|
485
488
|
};
|
|
486
489
|
};
|
|
487
490
|
var objectIdSchema = zod.z.string().refine((val) => mongoose.isValidObjectId(val), {
|
|
@@ -1430,6 +1433,46 @@ var driveDelete = async (source, options) => {
|
|
|
1430
1433
|
const owner = drive.owner;
|
|
1431
1434
|
await provider.delete([driveId], owner, accountId);
|
|
1432
1435
|
};
|
|
1436
|
+
var resolveFolderByPath = async (folderPath, owner, accountId) => {
|
|
1437
|
+
const normalizedPath = folderPath.replace(/^\/+|\/+$/g, "");
|
|
1438
|
+
if (!normalizedPath) {
|
|
1439
|
+
throw new Error("Folder path cannot be empty");
|
|
1440
|
+
}
|
|
1441
|
+
const segments = normalizedPath.split("/").filter((s) => s.length > 0);
|
|
1442
|
+
if (segments.length === 0) {
|
|
1443
|
+
throw new Error("Invalid folder path");
|
|
1444
|
+
}
|
|
1445
|
+
let providerName = "LOCAL";
|
|
1446
|
+
if (accountId && accountId !== "LOCAL") {
|
|
1447
|
+
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner });
|
|
1448
|
+
if (!account) {
|
|
1449
|
+
throw new Error("Invalid Storage Account");
|
|
1450
|
+
}
|
|
1451
|
+
if (account.metadata.provider === "GOOGLE") {
|
|
1452
|
+
providerName = "GOOGLE";
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
let currentParentId = null;
|
|
1456
|
+
for (const segmentName of segments) {
|
|
1457
|
+
const existingFolder = await drive_default.findOne({
|
|
1458
|
+
owner,
|
|
1459
|
+
"provider.type": providerName,
|
|
1460
|
+
storageAccountId: accountId || null,
|
|
1461
|
+
parentId: currentParentId,
|
|
1462
|
+
name: segmentName,
|
|
1463
|
+
"information.type": "FOLDER",
|
|
1464
|
+
trashedAt: null
|
|
1465
|
+
});
|
|
1466
|
+
if (existingFolder) {
|
|
1467
|
+
currentParentId = String(existingFolder._id);
|
|
1468
|
+
} else {
|
|
1469
|
+
const provider = providerName === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
1470
|
+
const newFolder = await provider.createFolder(segmentName, currentParentId, owner, accountId);
|
|
1471
|
+
currentParentId = newFolder.id;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
return currentParentId;
|
|
1475
|
+
};
|
|
1433
1476
|
var driveUpload = async (source, key, options) => {
|
|
1434
1477
|
const config = getDriveConfig();
|
|
1435
1478
|
let provider = LocalStorageProvider;
|
|
@@ -1519,12 +1562,20 @@ var driveUpload = async (source, key, options) => {
|
|
|
1519
1562
|
throw new Error("Storage quota exceeded");
|
|
1520
1563
|
}
|
|
1521
1564
|
}
|
|
1565
|
+
let resolvedParentId = null;
|
|
1566
|
+
if (options.folder && "path" in options.folder) {
|
|
1567
|
+
resolvedParentId = await resolveFolderByPath(options.folder.path, key, accountId);
|
|
1568
|
+
} else if (options.folder && "id" in options.folder && options.folder.id !== "root") {
|
|
1569
|
+
resolvedParentId = options.folder.id;
|
|
1570
|
+
} else if (options.parentId && options.parentId !== "root") {
|
|
1571
|
+
resolvedParentId = options.parentId;
|
|
1572
|
+
}
|
|
1522
1573
|
const drive = new drive_default({
|
|
1523
1574
|
owner: key,
|
|
1524
1575
|
storageAccountId: accountId || null,
|
|
1525
1576
|
provider: { type: provider.name },
|
|
1526
1577
|
name: options.name,
|
|
1527
|
-
parentId:
|
|
1578
|
+
parentId: resolvedParentId,
|
|
1528
1579
|
order: await getNextOrderValue(key),
|
|
1529
1580
|
information: { type: "FILE", sizeInBytes: fileSize, mime: mimeType, path: "" },
|
|
1530
1581
|
status: "UPLOADING"
|
|
@@ -1685,6 +1736,9 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1685
1736
|
const settings = getImageSettings(fileSize, quality, display, sizePreset);
|
|
1686
1737
|
let targetFormat = format || mime.split("/")[1];
|
|
1687
1738
|
if (targetFormat === "jpg") targetFormat = "jpeg";
|
|
1739
|
+
if (!["jpeg", "png", "webp", "avif"].includes(targetFormat)) {
|
|
1740
|
+
targetFormat = format || "webp";
|
|
1741
|
+
}
|
|
1688
1742
|
const cacheDir = path__default.default.join(config.storage.path, "file", drive._id.toString(), "cache");
|
|
1689
1743
|
const cacheKey = [
|
|
1690
1744
|
"opt",
|
|
@@ -1721,13 +1775,17 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1721
1775
|
pipeline = pipeline.png({ compressionLevel: settings.pngCompression, adaptiveFiltering: true });
|
|
1722
1776
|
res.setHeader("Content-Type", "image/png");
|
|
1723
1777
|
} else if (targetFormat === "webp") {
|
|
1724
|
-
|
|
1778
|
+
const webpEffort = Math.min(settings.effort, 6);
|
|
1779
|
+
pipeline = pipeline.webp({ quality: settings.quality, effort: webpEffort });
|
|
1725
1780
|
res.setHeader("Content-Type", "image/webp");
|
|
1726
1781
|
} else if (targetFormat === "avif") {
|
|
1727
1782
|
pipeline = pipeline.avif({ quality: settings.quality, effort: settings.effort });
|
|
1728
1783
|
res.setHeader("Content-Type", "image/avif");
|
|
1729
1784
|
}
|
|
1730
1785
|
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
1786
|
+
pipeline.on("error", (err) => {
|
|
1787
|
+
console.error("[next-drive] Pipeline error:", err);
|
|
1788
|
+
});
|
|
1731
1789
|
stream.pipe(pipeline);
|
|
1732
1790
|
pipeline.clone().toFile(cachePath).catch((e) => console.error("[next-drive] Cache write failed:", e));
|
|
1733
1791
|
pipeline.clone().pipe(res);
|
|
@@ -2282,5 +2340,5 @@ exports.driveReadFile = driveReadFile;
|
|
|
2282
2340
|
exports.driveUpload = driveUpload;
|
|
2283
2341
|
exports.getDriveConfig = getDriveConfig;
|
|
2284
2342
|
exports.getDriveInformation = getDriveInformation;
|
|
2285
|
-
//# sourceMappingURL=chunk-
|
|
2286
|
-
//# sourceMappingURL=chunk-
|
|
2343
|
+
//# sourceMappingURL=chunk-TAG5UMWA.cjs.map
|
|
2344
|
+
//# sourceMappingURL=chunk-TAG5UMWA.cjs.map
|