@muhgholy/next-drive 4.7.0 → 4.9.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 +103 -78
- package/dist/{chunk-OWKTTRQC.js → chunk-C5CORNPP.js} +83 -49
- package/dist/chunk-C5CORNPP.js.map +1 -0
- package/dist/{chunk-YR4DEKWI.cjs → chunk-WZWJYN64.cjs} +83 -49
- package/dist/chunk-WZWJYN64.cjs.map +1 -0
- package/dist/server/controllers/drive.d.ts +3 -2
- 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 +17 -5
- package/dist/server/utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-OWKTTRQC.js.map +0 -1
- package/dist/chunk-YR4DEKWI.cjs.map +0 -1
|
@@ -370,75 +370,77 @@ 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, defaultFit: "inside" },
|
|
374
|
+
"article-image": { ratio: [16, 9], baseWidth: 800, qualityFactor: 0.85, defaultFit: "inside" },
|
|
375
|
+
"thumbnail": { ratio: [1, 1], baseWidth: 150, qualityFactor: 0.7, defaultFit: "cover" },
|
|
376
|
+
"avatar": { ratio: [1, 1], baseWidth: 128, qualityFactor: 0.8, defaultFit: "cover" },
|
|
377
|
+
"logo": { ratio: [2, 1], baseWidth: 200, qualityFactor: 0.95, defaultFit: "contain" },
|
|
378
|
+
"card": { ratio: [4, 3], baseWidth: 400, qualityFactor: 0.8, defaultFit: "cover" },
|
|
379
|
+
"gallery": { ratio: [1, 1], baseWidth: 600, qualityFactor: 0.85, defaultFit: "cover" },
|
|
380
|
+
"og": { ratio: [1200, 630], baseWidth: 1200, qualityFactor: 0.9, defaultFit: "cover" },
|
|
381
|
+
"icon": { ratio: [1, 1], baseWidth: 48, qualityFactor: 0.75, defaultFit: "cover" },
|
|
382
|
+
"cover": { ratio: [16, 9], baseWidth: 1920, qualityFactor: 0.9, defaultFit: "cover" },
|
|
383
|
+
"story": { ratio: [9, 16], baseWidth: 1080, qualityFactor: 0.85, defaultFit: "cover" },
|
|
384
|
+
"video": { ratio: [16, 9], baseWidth: 1280, qualityFactor: 0.85, defaultFit: "cover" },
|
|
385
|
+
"banner": { ratio: [3, 1], baseWidth: 1200, qualityFactor: 0.9, defaultFit: "cover" },
|
|
386
|
+
"portrait": { ratio: [3, 4], baseWidth: 600, qualityFactor: 0.85, defaultFit: "inside" },
|
|
387
|
+
"landscape": { ratio: [4, 3], baseWidth: 800, qualityFactor: 0.85, defaultFit: "inside" }
|
|
395
388
|
};
|
|
396
|
-
var
|
|
397
|
-
|
|
389
|
+
var VALID_FIT_OPTIONS = ["cover", "contain", "fill", "inside", "outside"];
|
|
390
|
+
var VALID_POSITION_OPTIONS = [
|
|
391
|
+
"center",
|
|
392
|
+
"top",
|
|
393
|
+
"right top",
|
|
394
|
+
"right",
|
|
395
|
+
"right bottom",
|
|
396
|
+
"bottom",
|
|
397
|
+
"left bottom",
|
|
398
|
+
"left",
|
|
399
|
+
"left top",
|
|
400
|
+
"attention",
|
|
401
|
+
"entropy"
|
|
402
|
+
];
|
|
403
|
+
var SIZE_SCALES = {
|
|
404
|
+
"xs": 0.25,
|
|
405
|
+
"sm": 0.5,
|
|
406
|
+
"md": 1,
|
|
407
|
+
"lg": 1.5,
|
|
408
|
+
"xl": 2,
|
|
409
|
+
"2xl": 2.5
|
|
410
|
+
};
|
|
411
|
+
var STANDALONE_SIZES = {
|
|
398
412
|
"xs": { width: 64, height: 64 },
|
|
399
413
|
"sm": { width: 128, height: 128 },
|
|
400
414
|
"md": { width: 256, height: 256 },
|
|
401
415
|
"lg": { width: 512, height: 512 },
|
|
402
416
|
"xl": { width: 1024, height: 1024 },
|
|
403
417
|
"2xl": { width: 1600, height: 1600 },
|
|
404
|
-
// Named squares
|
|
405
418
|
"icon": { width: 48, height: 48 },
|
|
406
419
|
"thumb": { width: 150, height: 150 },
|
|
407
420
|
"square": { width: 600, height: 600 },
|
|
408
421
|
"avatar-sm": { width: 64, height: 64 },
|
|
409
422
|
"avatar-md": { width: 128, height: 128 },
|
|
410
423
|
"avatar-lg": { width: 256, height: 256 },
|
|
411
|
-
// Landscape (16:9)
|
|
412
424
|
"landscape-sm": { width: 480, height: 270 },
|
|
413
425
|
"landscape": { width: 800, height: 450 },
|
|
414
426
|
"landscape-lg": { width: 1280, height: 720 },
|
|
415
427
|
"landscape-xl": { width: 1920, height: 1080 },
|
|
416
|
-
// Portrait (9:16)
|
|
417
428
|
"portrait-sm": { width: 270, height: 480 },
|
|
418
429
|
"portrait": { width: 450, height: 800 },
|
|
419
430
|
"portrait-lg": { width: 720, height: 1280 },
|
|
420
|
-
// Wide/Banner (OG, social)
|
|
421
431
|
"wide": { width: 1200, height: 630 },
|
|
422
|
-
// Open Graph standard
|
|
423
432
|
"banner": { width: 1200, height: 400 },
|
|
424
|
-
// Banner/header
|
|
425
433
|
"banner-sm": { width: 800, height: 200 },
|
|
426
|
-
// Classic photo ratios
|
|
427
434
|
"photo-4x3": { width: 800, height: 600 },
|
|
428
|
-
// 4:3
|
|
429
435
|
"photo-3x2": { width: 900, height: 600 },
|
|
430
|
-
// 3:2
|
|
431
|
-
// Story/vertical (9:16)
|
|
432
436
|
"story": { width: 1080, height: 1920 },
|
|
433
|
-
// Video thumbnails
|
|
434
437
|
"video": { width: 1280, height: 720 },
|
|
435
438
|
"video-sm": { width: 640, height: 360 },
|
|
436
|
-
// Card sizes
|
|
437
439
|
"card-sm": { width: 300, height: 200 },
|
|
438
440
|
"card": { width: 400, height: 300 },
|
|
439
441
|
"card-lg": { width: 600, height: 400 }
|
|
440
442
|
};
|
|
441
|
-
var getImageSettings = (fileSizeInBytes, qualityPreset, display, size) => {
|
|
443
|
+
var getImageSettings = (fileSizeInBytes, qualityPreset, display, size, fit, position) => {
|
|
442
444
|
let baseQuality = 80;
|
|
443
445
|
if (qualityPreset === "low") baseQuality = 30;
|
|
444
446
|
else if (qualityPreset === "medium") baseQuality = 50;
|
|
@@ -447,8 +449,28 @@ var getImageSettings = (fileSizeInBytes, qualityPreset, display, size) => {
|
|
|
447
449
|
const n = parseInt(qualityPreset, 10);
|
|
448
450
|
if (!isNaN(n)) baseQuality = Math.min(100, Math.max(1, n));
|
|
449
451
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
+
let width;
|
|
453
|
+
let height;
|
|
454
|
+
let qualityFactor = 1;
|
|
455
|
+
let defaultFit = "inside";
|
|
456
|
+
const displayPreset = display ? DISPLAY_PRESETS[display] : void 0;
|
|
457
|
+
if (displayPreset) {
|
|
458
|
+
qualityFactor = displayPreset.qualityFactor;
|
|
459
|
+
defaultFit = displayPreset.defaultFit;
|
|
460
|
+
const [ratioW, ratioH] = displayPreset.ratio;
|
|
461
|
+
const scale = size && SIZE_SCALES[size] ? SIZE_SCALES[size] : 1;
|
|
462
|
+
width = Math.round(displayPreset.baseWidth * scale);
|
|
463
|
+
height = Math.round(width * ratioH / ratioW);
|
|
464
|
+
} else if (size) {
|
|
465
|
+
const standalone = STANDALONE_SIZES[size];
|
|
466
|
+
if (standalone) {
|
|
467
|
+
width = standalone.width;
|
|
468
|
+
height = standalone.height;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
const resolvedFit = fit && VALID_FIT_OPTIONS.includes(fit) ? fit : defaultFit;
|
|
472
|
+
const resolvedPosition = position && VALID_POSITION_OPTIONS.includes(position) ? position : void 0;
|
|
473
|
+
baseQuality = Math.round(baseQuality * qualityFactor);
|
|
452
474
|
let quality = baseQuality;
|
|
453
475
|
let effort = 4;
|
|
454
476
|
let pngCompression = 6;
|
|
@@ -476,12 +498,12 @@ var getImageSettings = (fileSizeInBytes, qualityPreset, display, size) => {
|
|
|
476
498
|
pngCompression = 7;
|
|
477
499
|
}
|
|
478
500
|
}
|
|
479
|
-
const dimensions = size && SIZE_PRESETS[size] ? SIZE_PRESETS[size] : void 0;
|
|
480
501
|
return {
|
|
481
502
|
quality: Math.max(1, Math.min(100, quality)),
|
|
482
503
|
effort,
|
|
483
504
|
pngCompression,
|
|
484
|
-
...
|
|
505
|
+
...width && height && { width, height, fit: resolvedFit },
|
|
506
|
+
...resolvedPosition && { position: resolvedPosition }
|
|
485
507
|
};
|
|
486
508
|
};
|
|
487
509
|
var objectIdSchema = zod.z.string().refine((val) => mongoose.isValidObjectId(val), {
|
|
@@ -1560,9 +1582,9 @@ var driveUpload = async (source, key, options) => {
|
|
|
1560
1582
|
}
|
|
1561
1583
|
}
|
|
1562
1584
|
let resolvedParentId = null;
|
|
1563
|
-
if (options.folder
|
|
1585
|
+
if (options.folder && "path" in options.folder) {
|
|
1564
1586
|
resolvedParentId = await resolveFolderByPath(options.folder.path, key, accountId);
|
|
1565
|
-
} else if (options.folder
|
|
1587
|
+
} else if (options.folder && "id" in options.folder && options.folder.id !== "root") {
|
|
1566
1588
|
resolvedParentId = options.folder.id;
|
|
1567
1589
|
} else if (options.parentId && options.parentId !== "root") {
|
|
1568
1590
|
resolvedParentId = options.parentId;
|
|
@@ -1722,23 +1744,30 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1722
1744
|
const quality = req.query.quality;
|
|
1723
1745
|
const display = req.query.display;
|
|
1724
1746
|
const sizePreset = req.query.size;
|
|
1747
|
+
const fit = req.query.fit;
|
|
1748
|
+
const position = req.query.position;
|
|
1725
1749
|
const isImage = mime.startsWith("image/");
|
|
1726
|
-
const shouldTransform = isImage && (format || quality || display || sizePreset);
|
|
1750
|
+
const shouldTransform = isImage && (format || quality || display || sizePreset || fit);
|
|
1727
1751
|
res.setHeader("Content-Disposition", `inline; filename="${safeFilename}"`);
|
|
1728
1752
|
if (config.cors?.enabled) {
|
|
1729
1753
|
res.setHeader("Cross-Origin-Resource-Policy", "cross-origin");
|
|
1730
1754
|
}
|
|
1731
1755
|
if (shouldTransform) {
|
|
1732
1756
|
try {
|
|
1733
|
-
const settings = getImageSettings(fileSize, quality, display, sizePreset);
|
|
1757
|
+
const settings = getImageSettings(fileSize, quality, display, sizePreset, fit, position);
|
|
1734
1758
|
let targetFormat = format || mime.split("/")[1];
|
|
1735
1759
|
if (targetFormat === "jpg") targetFormat = "jpeg";
|
|
1760
|
+
if (!["jpeg", "png", "webp", "avif"].includes(targetFormat)) {
|
|
1761
|
+
targetFormat = format || "webp";
|
|
1762
|
+
}
|
|
1736
1763
|
const cacheDir = path__default.default.join(config.storage.path, "file", drive._id.toString(), "cache");
|
|
1737
1764
|
const cacheKey = [
|
|
1738
1765
|
"opt",
|
|
1739
1766
|
`q${settings.quality}`,
|
|
1740
1767
|
`e${settings.effort}`,
|
|
1741
1768
|
settings.width ? `${settings.width}x${settings.height}` : "orig",
|
|
1769
|
+
settings.fit || "none",
|
|
1770
|
+
settings.position || "c",
|
|
1742
1771
|
targetFormat
|
|
1743
1772
|
].join("_");
|
|
1744
1773
|
const cachePath = path__default.default.join(cacheDir, `${cacheKey}.bin`);
|
|
@@ -1758,7 +1787,8 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1758
1787
|
let pipeline = sharp__default.default();
|
|
1759
1788
|
if (settings.width && settings.height) {
|
|
1760
1789
|
pipeline = pipeline.resize(settings.width, settings.height, {
|
|
1761
|
-
fit: "inside",
|
|
1790
|
+
fit: settings.fit || "inside",
|
|
1791
|
+
position: settings.position || "center",
|
|
1762
1792
|
withoutEnlargement: true
|
|
1763
1793
|
});
|
|
1764
1794
|
}
|
|
@@ -1769,13 +1799,17 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1769
1799
|
pipeline = pipeline.png({ compressionLevel: settings.pngCompression, adaptiveFiltering: true });
|
|
1770
1800
|
res.setHeader("Content-Type", "image/png");
|
|
1771
1801
|
} else if (targetFormat === "webp") {
|
|
1772
|
-
|
|
1802
|
+
const webpEffort = Math.min(settings.effort, 6);
|
|
1803
|
+
pipeline = pipeline.webp({ quality: settings.quality, effort: webpEffort });
|
|
1773
1804
|
res.setHeader("Content-Type", "image/webp");
|
|
1774
1805
|
} else if (targetFormat === "avif") {
|
|
1775
1806
|
pipeline = pipeline.avif({ quality: settings.quality, effort: settings.effort });
|
|
1776
1807
|
res.setHeader("Content-Type", "image/avif");
|
|
1777
1808
|
}
|
|
1778
1809
|
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
1810
|
+
pipeline.on("error", (err) => {
|
|
1811
|
+
console.error("[next-drive] Pipeline error:", err);
|
|
1812
|
+
});
|
|
1779
1813
|
stream.pipe(pipeline);
|
|
1780
1814
|
pipeline.clone().toFile(cachePath).catch((e) => console.error("[next-drive] Cache write failed:", e));
|
|
1781
1815
|
pipeline.clone().pipe(res);
|
|
@@ -2330,5 +2364,5 @@ exports.driveReadFile = driveReadFile;
|
|
|
2330
2364
|
exports.driveUpload = driveUpload;
|
|
2331
2365
|
exports.getDriveConfig = getDriveConfig;
|
|
2332
2366
|
exports.getDriveInformation = getDriveInformation;
|
|
2333
|
-
//# sourceMappingURL=chunk-
|
|
2334
|
-
//# sourceMappingURL=chunk-
|
|
2367
|
+
//# sourceMappingURL=chunk-WZWJYN64.cjs.map
|
|
2368
|
+
//# sourceMappingURL=chunk-WZWJYN64.cjs.map
|