@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
package/README.md
CHANGED
|
@@ -269,18 +269,28 @@ Upload files programmatically from server-side code:
|
|
|
269
269
|
```typescript
|
|
270
270
|
import { driveUpload } from "@muhgholy/next-drive/server";
|
|
271
271
|
|
|
272
|
-
// Upload
|
|
272
|
+
// Upload to specific folder by ID
|
|
273
273
|
const file = await driveUpload(
|
|
274
274
|
"/tmp/photo.jpg",
|
|
275
275
|
{ userId: "123" },
|
|
276
276
|
{
|
|
277
277
|
name: "photo.jpg",
|
|
278
|
-
|
|
278
|
+
folder: { id: "folderId" }, // Optional: folder ID
|
|
279
279
|
accountId: "LOCAL", // Optional: storage account ID
|
|
280
280
|
enforce: false, // Optional: bypass quota check
|
|
281
281
|
}
|
|
282
282
|
);
|
|
283
283
|
|
|
284
|
+
// Upload to folder by path (creates folders if not exist)
|
|
285
|
+
const file = await driveUpload(
|
|
286
|
+
"/tmp/photo.jpg",
|
|
287
|
+
{ userId: "123" },
|
|
288
|
+
{
|
|
289
|
+
name: "photo.jpg",
|
|
290
|
+
folder: { path: "images/2024/january" }, // Creates folders recursively
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
|
|
284
294
|
// Upload from stream
|
|
285
295
|
import fs from "fs";
|
|
286
296
|
const stream = fs.createReadStream("/tmp/video.mp4");
|
|
@@ -307,13 +317,14 @@ const file = await driveUpload(
|
|
|
307
317
|
|
|
308
318
|
**Options:**
|
|
309
319
|
|
|
310
|
-
| Option
|
|
311
|
-
|
|
|
312
|
-
| `name`
|
|
313
|
-
| `
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
316
|
-
| `
|
|
320
|
+
| Option | Type | Required | Description |
|
|
321
|
+
| ------------ | --------------------------------- | -------- | -------------------------------------------------------- |
|
|
322
|
+
| `name` | `string` | Yes | File name with extension |
|
|
323
|
+
| `folder.id` | `string` | No | Parent folder ID |
|
|
324
|
+
| `folder.path`| `string` | No | Folder path (e.g., `images/2024`) - creates if not exist |
|
|
325
|
+
| `accountId` | `string` | No | Storage account ID ('LOCAL' for local storage) |
|
|
326
|
+
| `mime` | `string` | No | MIME type (auto-detected from extension if not provided) |
|
|
327
|
+
| `enforce` | `boolean` | No | Bypass quota check (default: false) |
|
|
317
328
|
|
|
318
329
|
### Get Signed URL
|
|
319
330
|
|
|
@@ -579,7 +590,7 @@ Serve optimized images with dynamic compression, resizing, and format conversion
|
|
|
579
590
|
### URL Format
|
|
580
591
|
|
|
581
592
|
```
|
|
582
|
-
/api/drive?action=serve&id={fileId}&quality={preset}&display={context}&size={
|
|
593
|
+
/api/drive?action=serve&id={fileId}&quality={preset}&display={context}&size={scale}&format={format}
|
|
583
594
|
```
|
|
584
595
|
|
|
585
596
|
### Parameters
|
|
@@ -587,10 +598,22 @@ Serve optimized images with dynamic compression, resizing, and format conversion
|
|
|
587
598
|
| Parameter | Type | Description |
|
|
588
599
|
|-----------|------|-------------|
|
|
589
600
|
| `quality` | `low` / `medium` / `high` / `1-100` | Compression level |
|
|
590
|
-
| `display` | string |
|
|
591
|
-
| `size` | string |
|
|
601
|
+
| `display` | string | Sets aspect ratio, base dimensions, and quality factor |
|
|
602
|
+
| `size` | string | Scale factor (xs/sm/md/lg/xl) or standalone dimension preset |
|
|
592
603
|
| `format` | `jpeg` / `webp` / `avif` / `png` | Output format |
|
|
593
604
|
|
|
605
|
+
### How Display + Size Work Together
|
|
606
|
+
|
|
607
|
+
When **display** is specified, it defines the aspect ratio and base dimensions. The **size** parameter then scales those dimensions:
|
|
608
|
+
|
|
609
|
+
```
|
|
610
|
+
display=article-image + size=sm → 400×225 (16:9, half size)
|
|
611
|
+
display=article-image + size=md → 800×450 (16:9, default)
|
|
612
|
+
display=article-image + size=lg → 1200×675 (16:9, 1.5x)
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
When **no display** is specified, size uses standalone presets (fixed dimensions).
|
|
616
|
+
|
|
594
617
|
### Quality Presets
|
|
595
618
|
|
|
596
619
|
| Preset | Base Quality | Use Case |
|
|
@@ -602,88 +625,74 @@ Serve optimized images with dynamic compression, resizing, and format conversion
|
|
|
602
625
|
|
|
603
626
|
> Quality is dynamically adjusted based on file size. Larger files get more aggressive compression.
|
|
604
627
|
|
|
605
|
-
### Display Presets (
|
|
606
|
-
|
|
607
|
-
| Display |
|
|
608
|
-
|
|
609
|
-
| `article-header` |
|
|
610
|
-
| `article-image` |
|
|
611
|
-
| `thumbnail` |
|
|
612
|
-
| `avatar` |
|
|
613
|
-
| `logo` | 0.95 |
|
|
614
|
-
| `card` |
|
|
615
|
-
| `gallery` | 0.85 |
|
|
616
|
-
| `og` |
|
|
617
|
-
| `icon` |
|
|
618
|
-
| `cover` |
|
|
619
|
-
| `story` | 0.85 |
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
| `
|
|
630
|
-
|
|
631
|
-
| `
|
|
632
|
-
| `
|
|
633
|
-
| `
|
|
634
|
-
| `
|
|
635
|
-
| `
|
|
636
|
-
| `
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
|
643
|
-
|
|
644
|
-
| `landscape-
|
|
645
|
-
| `landscape
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
|
649
|
-
|
|
650
|
-
| `
|
|
651
|
-
| `
|
|
652
|
-
| `portrait-lg` | 720×1280 |
|
|
653
|
-
|
|
654
|
-
**Wide/Banner:**
|
|
655
|
-
| Size | Dimensions | Ratio |
|
|
656
|
-
|------|------------|-------|
|
|
657
|
-
| `wide` | 1200×630 | OG standard |
|
|
658
|
-
| `banner` | 1200×400 | 3:1 |
|
|
659
|
-
| `banner-sm` | 800×200 | 4:1 |
|
|
660
|
-
|
|
661
|
-
**Other:**
|
|
662
|
-
| Size | Dimensions | Ratio |
|
|
663
|
-
|------|------------|-------|
|
|
664
|
-
| `photo-4x3` | 800×600 | 4:3 |
|
|
665
|
-
| `photo-3x2` | 900×600 | 3:2 |
|
|
666
|
-
| `story` | 1080×1920 | 9:16 |
|
|
667
|
-
| `video` | 1280×720 | 16:9 |
|
|
668
|
-
| `video-sm` | 640×360 | 16:9 |
|
|
669
|
-
| `card-sm` | 300×200 | 3:2 |
|
|
670
|
-
| `card` | 400×300 | 4:3 |
|
|
671
|
-
| `card-lg` | 600×400 | 3:2 |
|
|
628
|
+
### Display Presets (Aspect Ratio + Dimensions)
|
|
629
|
+
|
|
630
|
+
| Display | Aspect Ratio | Base Size | Quality Factor |
|
|
631
|
+
|---------|--------------|-----------|----------------|
|
|
632
|
+
| `article-header` | 16:9 | 1200×675 | 0.9 |
|
|
633
|
+
| `article-image` | 16:9 | 800×450 | 0.85 |
|
|
634
|
+
| `thumbnail` | 1:1 | 150×150 | 0.7 |
|
|
635
|
+
| `avatar` | 1:1 | 128×128 | 0.8 |
|
|
636
|
+
| `logo` | 2:1 | 200×100 | 0.95 |
|
|
637
|
+
| `card` | 4:3 | 400×300 | 0.8 |
|
|
638
|
+
| `gallery` | 1:1 | 600×600 | 0.85 |
|
|
639
|
+
| `og` | ~1.9:1 | 1200×630 | 0.9 |
|
|
640
|
+
| `icon` | 1:1 | 48×48 | 0.75 |
|
|
641
|
+
| `cover` | 16:9 | 1920×1080 | 0.9 |
|
|
642
|
+
| `story` | 9:16 | 1080×1920 | 0.85 |
|
|
643
|
+
| `video` | 16:9 | 1280×720 | 0.85 |
|
|
644
|
+
| `banner` | 3:1 | 1200×400 | 0.9 |
|
|
645
|
+
| `portrait` | 3:4 | 600×800 | 0.85 |
|
|
646
|
+
| `landscape` | 4:3 | 800×600 | 0.85 |
|
|
647
|
+
|
|
648
|
+
### Size Scale (with Display)
|
|
649
|
+
|
|
650
|
+
When used with a display preset, size scales the dimensions:
|
|
651
|
+
|
|
652
|
+
| Size | Scale | Example with `article-image` (800×450) |
|
|
653
|
+
|------|-------|----------------------------------------|
|
|
654
|
+
| `xs` | 0.25× | 200×113 |
|
|
655
|
+
| `sm` | 0.5× | 400×225 |
|
|
656
|
+
| `md` | 1.0× | 800×450 |
|
|
657
|
+
| `lg` | 1.5× | 1200×675 |
|
|
658
|
+
| `xl` | 2.0× | 1600×900 |
|
|
659
|
+
| `2xl` | 2.5× | 2000×1125 |
|
|
660
|
+
|
|
661
|
+
### Standalone Size Presets (without Display)
|
|
662
|
+
|
|
663
|
+
When no display is specified, use these fixed dimension presets:
|
|
664
|
+
|
|
665
|
+
| Size | Dimensions | Size | Dimensions |
|
|
666
|
+
|------|------------|------|------------|
|
|
667
|
+
| `xs` | 64×64 | `landscape-sm` | 480×270 |
|
|
668
|
+
| `sm` | 128×128 | `landscape` | 800×450 |
|
|
669
|
+
| `md` | 256×256 | `landscape-lg` | 1280×720 |
|
|
670
|
+
| `lg` | 512×512 | `portrait-sm` | 270×480 |
|
|
671
|
+
| `xl` | 1024×1024 | `portrait` | 450×800 |
|
|
672
|
+
| `icon` | 48×48 | `wide` | 1200×630 |
|
|
673
|
+
| `thumb` | 150×150 | `banner` | 1200×400 |
|
|
674
|
+
| `video` | 1280×720 | `card` | 400×300 |
|
|
672
675
|
|
|
673
676
|
### Examples
|
|
674
677
|
|
|
675
678
|
```html
|
|
676
|
-
<!-- Article
|
|
677
|
-
<img src="/api/drive?action=serve&id=123&display=article-
|
|
679
|
+
<!-- Article image, smaller variant (400×225) -->
|
|
680
|
+
<img src="/api/drive?action=serve&id=123&display=article-image&size=sm&format=webp">
|
|
681
|
+
|
|
682
|
+
<!-- Article image, default size (800×450) -->
|
|
683
|
+
<img src="/api/drive?action=serve&id=123&display=article-image&format=webp">
|
|
684
|
+
|
|
685
|
+
<!-- Article image, larger variant (1200×675) -->
|
|
686
|
+
<img src="/api/drive?action=serve&id=123&display=article-image&size=lg&format=webp">
|
|
678
687
|
|
|
679
|
-
<!-- Thumbnail
|
|
680
|
-
<img src="/api/drive?action=serve&id=123&display=thumbnail&
|
|
688
|
+
<!-- Thumbnail (150×150 square) -->
|
|
689
|
+
<img src="/api/drive?action=serve&id=123&display=thumbnail&format=webp">
|
|
681
690
|
|
|
682
|
-
<!-- Avatar -->
|
|
683
|
-
<img src="/api/drive?action=serve&id=123&display=avatar&size=
|
|
691
|
+
<!-- Avatar, smaller (64×64) -->
|
|
692
|
+
<img src="/api/drive?action=serve&id=123&display=avatar&size=sm&format=webp">
|
|
684
693
|
|
|
685
|
-
<!--
|
|
686
|
-
<img src="/api/drive?action=serve&id=123&
|
|
694
|
+
<!-- Standalone size, no display -->
|
|
695
|
+
<img src="/api/drive?action=serve&id=123&size=landscape&format=webp">
|
|
687
696
|
|
|
688
697
|
<!-- Just quality, no resize -->
|
|
689
698
|
<img src="/api/drive?action=serve&id=123&quality=medium&format=webp">
|
|
@@ -357,70 +357,58 @@ var extractImageMetadata = async (filePath) => {
|
|
|
357
357
|
}
|
|
358
358
|
};
|
|
359
359
|
var DISPLAY_PRESETS = {
|
|
360
|
-
"article-header": 0.9,
|
|
361
|
-
|
|
362
|
-
"
|
|
363
|
-
|
|
364
|
-
"
|
|
365
|
-
|
|
366
|
-
"
|
|
367
|
-
|
|
368
|
-
"
|
|
369
|
-
|
|
370
|
-
"
|
|
371
|
-
|
|
372
|
-
"
|
|
373
|
-
|
|
374
|
-
"
|
|
375
|
-
// Open Graph/social sharing
|
|
376
|
-
"icon": 0.75,
|
|
377
|
-
// Small icons
|
|
378
|
-
"cover": 0.9,
|
|
379
|
-
// Full-width covers
|
|
380
|
-
"story": 0.85
|
|
381
|
-
// Story/vertical format
|
|
360
|
+
"article-header": { ratio: [16, 9], baseWidth: 1200, qualityFactor: 0.9 },
|
|
361
|
+
"article-image": { ratio: [16, 9], baseWidth: 800, qualityFactor: 0.85 },
|
|
362
|
+
"thumbnail": { ratio: [1, 1], baseWidth: 150, qualityFactor: 0.7 },
|
|
363
|
+
"avatar": { ratio: [1, 1], baseWidth: 128, qualityFactor: 0.8 },
|
|
364
|
+
"logo": { ratio: [2, 1], baseWidth: 200, qualityFactor: 0.95 },
|
|
365
|
+
"card": { ratio: [4, 3], baseWidth: 400, qualityFactor: 0.8 },
|
|
366
|
+
"gallery": { ratio: [1, 1], baseWidth: 600, qualityFactor: 0.85 },
|
|
367
|
+
"og": { ratio: [1200, 630], baseWidth: 1200, qualityFactor: 0.9 },
|
|
368
|
+
"icon": { ratio: [1, 1], baseWidth: 48, qualityFactor: 0.75 },
|
|
369
|
+
"cover": { ratio: [16, 9], baseWidth: 1920, qualityFactor: 0.9 },
|
|
370
|
+
"story": { ratio: [9, 16], baseWidth: 1080, qualityFactor: 0.85 },
|
|
371
|
+
"video": { ratio: [16, 9], baseWidth: 1280, qualityFactor: 0.85 },
|
|
372
|
+
"banner": { ratio: [3, 1], baseWidth: 1200, qualityFactor: 0.9 },
|
|
373
|
+
"portrait": { ratio: [3, 4], baseWidth: 600, qualityFactor: 0.85 },
|
|
374
|
+
"landscape": { ratio: [4, 3], baseWidth: 800, qualityFactor: 0.85 }
|
|
382
375
|
};
|
|
383
|
-
var
|
|
384
|
-
|
|
376
|
+
var SIZE_SCALES = {
|
|
377
|
+
"xs": 0.25,
|
|
378
|
+
"sm": 0.5,
|
|
379
|
+
"md": 1,
|
|
380
|
+
"lg": 1.5,
|
|
381
|
+
"xl": 2,
|
|
382
|
+
"2xl": 2.5
|
|
383
|
+
};
|
|
384
|
+
var STANDALONE_SIZES = {
|
|
385
385
|
"xs": { width: 64, height: 64 },
|
|
386
386
|
"sm": { width: 128, height: 128 },
|
|
387
387
|
"md": { width: 256, height: 256 },
|
|
388
388
|
"lg": { width: 512, height: 512 },
|
|
389
389
|
"xl": { width: 1024, height: 1024 },
|
|
390
390
|
"2xl": { width: 1600, height: 1600 },
|
|
391
|
-
// Named squares
|
|
392
391
|
"icon": { width: 48, height: 48 },
|
|
393
392
|
"thumb": { width: 150, height: 150 },
|
|
394
393
|
"square": { width: 600, height: 600 },
|
|
395
394
|
"avatar-sm": { width: 64, height: 64 },
|
|
396
395
|
"avatar-md": { width: 128, height: 128 },
|
|
397
396
|
"avatar-lg": { width: 256, height: 256 },
|
|
398
|
-
// Landscape (16:9)
|
|
399
397
|
"landscape-sm": { width: 480, height: 270 },
|
|
400
398
|
"landscape": { width: 800, height: 450 },
|
|
401
399
|
"landscape-lg": { width: 1280, height: 720 },
|
|
402
400
|
"landscape-xl": { width: 1920, height: 1080 },
|
|
403
|
-
// Portrait (9:16)
|
|
404
401
|
"portrait-sm": { width: 270, height: 480 },
|
|
405
402
|
"portrait": { width: 450, height: 800 },
|
|
406
403
|
"portrait-lg": { width: 720, height: 1280 },
|
|
407
|
-
// Wide/Banner (OG, social)
|
|
408
404
|
"wide": { width: 1200, height: 630 },
|
|
409
|
-
// Open Graph standard
|
|
410
405
|
"banner": { width: 1200, height: 400 },
|
|
411
|
-
// Banner/header
|
|
412
406
|
"banner-sm": { width: 800, height: 200 },
|
|
413
|
-
// Classic photo ratios
|
|
414
407
|
"photo-4x3": { width: 800, height: 600 },
|
|
415
|
-
// 4:3
|
|
416
408
|
"photo-3x2": { width: 900, height: 600 },
|
|
417
|
-
// 3:2
|
|
418
|
-
// Story/vertical (9:16)
|
|
419
409
|
"story": { width: 1080, height: 1920 },
|
|
420
|
-
// Video thumbnails
|
|
421
410
|
"video": { width: 1280, height: 720 },
|
|
422
411
|
"video-sm": { width: 640, height: 360 },
|
|
423
|
-
// Card sizes
|
|
424
412
|
"card-sm": { width: 300, height: 200 },
|
|
425
413
|
"card": { width: 400, height: 300 },
|
|
426
414
|
"card-lg": { width: 600, height: 400 }
|
|
@@ -434,8 +422,24 @@ var getImageSettings = (fileSizeInBytes, qualityPreset, display, size) => {
|
|
|
434
422
|
const n = parseInt(qualityPreset, 10);
|
|
435
423
|
if (!isNaN(n)) baseQuality = Math.min(100, Math.max(1, n));
|
|
436
424
|
}
|
|
437
|
-
|
|
438
|
-
|
|
425
|
+
let width;
|
|
426
|
+
let height;
|
|
427
|
+
let qualityFactor = 1;
|
|
428
|
+
const displayPreset = display ? DISPLAY_PRESETS[display] : void 0;
|
|
429
|
+
if (displayPreset) {
|
|
430
|
+
qualityFactor = displayPreset.qualityFactor;
|
|
431
|
+
const [ratioW, ratioH] = displayPreset.ratio;
|
|
432
|
+
const scale = size && SIZE_SCALES[size] ? SIZE_SCALES[size] : 1;
|
|
433
|
+
width = Math.round(displayPreset.baseWidth * scale);
|
|
434
|
+
height = Math.round(width * ratioH / ratioW);
|
|
435
|
+
} else if (size) {
|
|
436
|
+
const standalone = STANDALONE_SIZES[size];
|
|
437
|
+
if (standalone) {
|
|
438
|
+
width = standalone.width;
|
|
439
|
+
height = standalone.height;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
baseQuality = Math.round(baseQuality * qualityFactor);
|
|
439
443
|
let quality = baseQuality;
|
|
440
444
|
let effort = 4;
|
|
441
445
|
let pngCompression = 6;
|
|
@@ -463,12 +467,11 @@ var getImageSettings = (fileSizeInBytes, qualityPreset, display, size) => {
|
|
|
463
467
|
pngCompression = 7;
|
|
464
468
|
}
|
|
465
469
|
}
|
|
466
|
-
const dimensions = size && SIZE_PRESETS[size] ? SIZE_PRESETS[size] : void 0;
|
|
467
470
|
return {
|
|
468
471
|
quality: Math.max(1, Math.min(100, quality)),
|
|
469
472
|
effort,
|
|
470
473
|
pngCompression,
|
|
471
|
-
...
|
|
474
|
+
...width && height && { width, height }
|
|
472
475
|
};
|
|
473
476
|
};
|
|
474
477
|
var objectIdSchema = z.string().refine((val) => isValidObjectId(val), {
|
|
@@ -1417,6 +1420,46 @@ var driveDelete = async (source, options) => {
|
|
|
1417
1420
|
const owner = drive.owner;
|
|
1418
1421
|
await provider.delete([driveId], owner, accountId);
|
|
1419
1422
|
};
|
|
1423
|
+
var resolveFolderByPath = async (folderPath, owner, accountId) => {
|
|
1424
|
+
const normalizedPath = folderPath.replace(/^\/+|\/+$/g, "");
|
|
1425
|
+
if (!normalizedPath) {
|
|
1426
|
+
throw new Error("Folder path cannot be empty");
|
|
1427
|
+
}
|
|
1428
|
+
const segments = normalizedPath.split("/").filter((s) => s.length > 0);
|
|
1429
|
+
if (segments.length === 0) {
|
|
1430
|
+
throw new Error("Invalid folder path");
|
|
1431
|
+
}
|
|
1432
|
+
let providerName = "LOCAL";
|
|
1433
|
+
if (accountId && accountId !== "LOCAL") {
|
|
1434
|
+
const account = await drive_default.db.model("StorageAccount").findOne({ _id: accountId, owner });
|
|
1435
|
+
if (!account) {
|
|
1436
|
+
throw new Error("Invalid Storage Account");
|
|
1437
|
+
}
|
|
1438
|
+
if (account.metadata.provider === "GOOGLE") {
|
|
1439
|
+
providerName = "GOOGLE";
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
let currentParentId = null;
|
|
1443
|
+
for (const segmentName of segments) {
|
|
1444
|
+
const existingFolder = await drive_default.findOne({
|
|
1445
|
+
owner,
|
|
1446
|
+
"provider.type": providerName,
|
|
1447
|
+
storageAccountId: accountId || null,
|
|
1448
|
+
parentId: currentParentId,
|
|
1449
|
+
name: segmentName,
|
|
1450
|
+
"information.type": "FOLDER",
|
|
1451
|
+
trashedAt: null
|
|
1452
|
+
});
|
|
1453
|
+
if (existingFolder) {
|
|
1454
|
+
currentParentId = String(existingFolder._id);
|
|
1455
|
+
} else {
|
|
1456
|
+
const provider = providerName === "GOOGLE" ? GoogleDriveProvider : LocalStorageProvider;
|
|
1457
|
+
const newFolder = await provider.createFolder(segmentName, currentParentId, owner, accountId);
|
|
1458
|
+
currentParentId = newFolder.id;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return currentParentId;
|
|
1462
|
+
};
|
|
1420
1463
|
var driveUpload = async (source, key, options) => {
|
|
1421
1464
|
const config = getDriveConfig();
|
|
1422
1465
|
let provider = LocalStorageProvider;
|
|
@@ -1506,12 +1549,20 @@ var driveUpload = async (source, key, options) => {
|
|
|
1506
1549
|
throw new Error("Storage quota exceeded");
|
|
1507
1550
|
}
|
|
1508
1551
|
}
|
|
1552
|
+
let resolvedParentId = null;
|
|
1553
|
+
if (options.folder && "path" in options.folder) {
|
|
1554
|
+
resolvedParentId = await resolveFolderByPath(options.folder.path, key, accountId);
|
|
1555
|
+
} else if (options.folder && "id" in options.folder && options.folder.id !== "root") {
|
|
1556
|
+
resolvedParentId = options.folder.id;
|
|
1557
|
+
} else if (options.parentId && options.parentId !== "root") {
|
|
1558
|
+
resolvedParentId = options.parentId;
|
|
1559
|
+
}
|
|
1509
1560
|
const drive = new drive_default({
|
|
1510
1561
|
owner: key,
|
|
1511
1562
|
storageAccountId: accountId || null,
|
|
1512
1563
|
provider: { type: provider.name },
|
|
1513
1564
|
name: options.name,
|
|
1514
|
-
parentId:
|
|
1565
|
+
parentId: resolvedParentId,
|
|
1515
1566
|
order: await getNextOrderValue(key),
|
|
1516
1567
|
information: { type: "FILE", sizeInBytes: fileSize, mime: mimeType, path: "" },
|
|
1517
1568
|
status: "UPLOADING"
|
|
@@ -1672,6 +1723,9 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1672
1723
|
const settings = getImageSettings(fileSize, quality, display, sizePreset);
|
|
1673
1724
|
let targetFormat = format || mime.split("/")[1];
|
|
1674
1725
|
if (targetFormat === "jpg") targetFormat = "jpeg";
|
|
1726
|
+
if (!["jpeg", "png", "webp", "avif"].includes(targetFormat)) {
|
|
1727
|
+
targetFormat = format || "webp";
|
|
1728
|
+
}
|
|
1675
1729
|
const cacheDir = path.join(config.storage.path, "file", drive._id.toString(), "cache");
|
|
1676
1730
|
const cacheKey = [
|
|
1677
1731
|
"opt",
|
|
@@ -1708,13 +1762,17 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1708
1762
|
pipeline = pipeline.png({ compressionLevel: settings.pngCompression, adaptiveFiltering: true });
|
|
1709
1763
|
res.setHeader("Content-Type", "image/png");
|
|
1710
1764
|
} else if (targetFormat === "webp") {
|
|
1711
|
-
|
|
1765
|
+
const webpEffort = Math.min(settings.effort, 6);
|
|
1766
|
+
pipeline = pipeline.webp({ quality: settings.quality, effort: webpEffort });
|
|
1712
1767
|
res.setHeader("Content-Type", "image/webp");
|
|
1713
1768
|
} else if (targetFormat === "avif") {
|
|
1714
1769
|
pipeline = pipeline.avif({ quality: settings.quality, effort: settings.effort });
|
|
1715
1770
|
res.setHeader("Content-Type", "image/avif");
|
|
1716
1771
|
}
|
|
1717
1772
|
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
1773
|
+
pipeline.on("error", (err) => {
|
|
1774
|
+
console.error("[next-drive] Pipeline error:", err);
|
|
1775
|
+
});
|
|
1718
1776
|
stream.pipe(pipeline);
|
|
1719
1777
|
pipeline.clone().toFile(cachePath).catch((e) => console.error("[next-drive] Cache write failed:", e));
|
|
1720
1778
|
pipeline.clone().pipe(res);
|
|
@@ -2258,5 +2316,5 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2258
2316
|
};
|
|
2259
2317
|
|
|
2260
2318
|
export { driveAPIHandler, driveConfiguration, driveDelete, driveFilePath, driveFileSchemaZod, driveGetUrl, driveInfo, driveList, driveReadFile, driveUpload, getDriveConfig, getDriveInformation };
|
|
2261
|
-
//# sourceMappingURL=chunk-
|
|
2262
|
-
//# sourceMappingURL=chunk-
|
|
2319
|
+
//# sourceMappingURL=chunk-AYHO6FSR.js.map
|
|
2320
|
+
//# sourceMappingURL=chunk-AYHO6FSR.js.map
|