@soulbatical/tetra-core 0.1.49 → 0.1.50
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/frontend/storage/index.d.ts +1 -1
- package/dist/frontend/storage/index.d.ts.map +1 -1
- package/dist/frontend/storage/storageUrl.d.ts +31 -5
- package/dist/frontend/storage/storageUrl.d.ts.map +1 -1
- package/dist/frontend/storage/storageUrl.js +40 -6
- package/dist/frontend/storage/storageUrl.js.map +1 -1
- package/dist/shared/storage/StorageProxyService.d.ts +23 -2
- package/dist/shared/storage/StorageProxyService.d.ts.map +1 -1
- package/dist/shared/storage/StorageProxyService.js +122 -6
- package/dist/shared/storage/StorageProxyService.js.map +1 -1
- package/dist/shared/storage/routes.d.ts.map +1 -1
- package/dist/shared/storage/routes.js +3 -1
- package/dist/shared/storage/routes.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { configureStorageUrls } from './storageUrl.js';
|
|
2
|
-
export type { StorageUrlHelpers, PhotoSize, Photo } from './storageUrl.js';
|
|
2
|
+
export type { StorageUrlHelpers, PhotoSize, Photo, ImageTransformParams } from './storageUrl.js';
|
|
3
3
|
export { useStorageUpload } from './useStorageUpload.js';
|
|
4
4
|
export type { UseStorageUploadOptions, UseStorageUploadReturn, UploadResult } from './useStorageUpload.js';
|
|
5
5
|
export { StorageDropzone } from './StorageDropzone.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/frontend/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/frontend/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC3G,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Storage URL Builders — construct proxy URLs for stored images
|
|
3
3
|
*
|
|
4
|
+
* Supports on-the-fly image transforms via query parameters:
|
|
5
|
+
* ?w=400 — resize to max width
|
|
6
|
+
* ?h=300 — resize to max height
|
|
7
|
+
* ?q=80 — quality 1-100
|
|
8
|
+
* ?f=webp — output format
|
|
9
|
+
*
|
|
4
10
|
* Usage:
|
|
5
11
|
* ```typescript
|
|
6
12
|
* import { configureStorageUrls } from '@soulbatical/tetra-core/frontend';
|
|
7
13
|
*
|
|
8
14
|
* const storage = configureStorageUrls('https://api.myapp.com');
|
|
9
|
-
*
|
|
10
|
-
* //
|
|
15
|
+
*
|
|
16
|
+
* // Original size
|
|
17
|
+
* storage.buildStorageUrl('images', orgId, 'photo.png');
|
|
18
|
+
*
|
|
19
|
+
* // Thumbnail (400px wide, webp)
|
|
20
|
+
* storage.buildStorageUrl('images', orgId, 'photo.png', { w: 400, f: 'webp' });
|
|
21
|
+
*
|
|
22
|
+
* // Responsive srcset with on-the-fly resize
|
|
23
|
+
* storage.buildImageSrcSet('images', orgId, 'photo.png');
|
|
24
|
+
* // → ".../photo.png?w=150&f=webp 150w, .../photo.png?w=600&f=webp 600w, ..."
|
|
11
25
|
* ```
|
|
12
26
|
*/
|
|
13
27
|
export type PhotoSize = 'thumb' | 'medium' | 'large' | 'original';
|
|
@@ -16,13 +30,25 @@ export interface Photo {
|
|
|
16
30
|
storage_prefix?: string;
|
|
17
31
|
storage_path?: string;
|
|
18
32
|
}
|
|
33
|
+
export interface ImageTransformParams {
|
|
34
|
+
/** Max width in pixels */
|
|
35
|
+
w?: number;
|
|
36
|
+
/** Max height in pixels */
|
|
37
|
+
h?: number;
|
|
38
|
+
/** Quality 1-100 (default: 80) */
|
|
39
|
+
q?: number;
|
|
40
|
+
/** Output format */
|
|
41
|
+
f?: 'webp' | 'jpeg' | 'png';
|
|
42
|
+
}
|
|
19
43
|
export interface StorageUrlHelpers {
|
|
20
|
-
/** Build a proxy URL for any stored file */
|
|
21
|
-
buildStorageUrl(bucket: string, orgId: string, fileId: string): string;
|
|
44
|
+
/** Build a proxy URL for any stored file, with optional image transforms */
|
|
45
|
+
buildStorageUrl(bucket: string, orgId: string, fileId: string, transform?: ImageTransformParams): string;
|
|
22
46
|
/** Build a photo URL for a specific size (expects {size}_{filename} convention) */
|
|
23
47
|
buildPhotoUrl(bucket: string, photo: Photo, size: PhotoSize): string;
|
|
24
|
-
/** Build a srcSet string for
|
|
48
|
+
/** Build a srcSet string for multi-size photos (pre-generated sizes) */
|
|
25
49
|
buildPhotoSrcSet(bucket: string, photo: Photo): string;
|
|
50
|
+
/** Build a srcSet string using on-the-fly resize (no pre-generated sizes needed) */
|
|
51
|
+
buildImageSrcSet(bucket: string, orgId: string, fileId: string, widths?: number[]): string;
|
|
26
52
|
}
|
|
27
53
|
/**
|
|
28
54
|
* Configure storage URL helpers with a base API URL.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageUrl.d.ts","sourceRoot":"","sources":["../../../src/frontend/storage/storageUrl.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"storageUrl.d.ts","sourceRoot":"","sources":["../../../src/frontend/storage/storageUrl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAElE,MAAM,WAAW,KAAK;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,0BAA0B;IAC1B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,kCAAkC;IAClC,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,oBAAoB;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAAC;IACzG,mFAAmF;IACnF,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IACrE,wEAAwE;IACxE,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC;IACvD,oFAAoF;IACpF,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;CAC5F;AAsBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,CAiC1E"}
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Storage URL Builders — construct proxy URLs for stored images
|
|
3
3
|
*
|
|
4
|
+
* Supports on-the-fly image transforms via query parameters:
|
|
5
|
+
* ?w=400 — resize to max width
|
|
6
|
+
* ?h=300 — resize to max height
|
|
7
|
+
* ?q=80 — quality 1-100
|
|
8
|
+
* ?f=webp — output format
|
|
9
|
+
*
|
|
4
10
|
* Usage:
|
|
5
11
|
* ```typescript
|
|
6
12
|
* import { configureStorageUrls } from '@soulbatical/tetra-core/frontend';
|
|
7
13
|
*
|
|
8
14
|
* const storage = configureStorageUrls('https://api.myapp.com');
|
|
9
|
-
*
|
|
10
|
-
* //
|
|
15
|
+
*
|
|
16
|
+
* // Original size
|
|
17
|
+
* storage.buildStorageUrl('images', orgId, 'photo.png');
|
|
18
|
+
*
|
|
19
|
+
* // Thumbnail (400px wide, webp)
|
|
20
|
+
* storage.buildStorageUrl('images', orgId, 'photo.png', { w: 400, f: 'webp' });
|
|
21
|
+
*
|
|
22
|
+
* // Responsive srcset with on-the-fly resize
|
|
23
|
+
* storage.buildImageSrcSet('images', orgId, 'photo.png');
|
|
24
|
+
* // → ".../photo.png?w=150&f=webp 150w, .../photo.png?w=600&f=webp 600w, ..."
|
|
11
25
|
* ```
|
|
12
26
|
*/
|
|
13
27
|
const SIZE_WIDTHS = {
|
|
@@ -16,18 +30,33 @@ const SIZE_WIDTHS = {
|
|
|
16
30
|
large: 1200,
|
|
17
31
|
original: 2000,
|
|
18
32
|
};
|
|
33
|
+
const DEFAULT_SRCSET_WIDTHS = [150, 400, 800, 1200, 2000];
|
|
34
|
+
function buildTransformQuery(transform) {
|
|
35
|
+
if (!transform)
|
|
36
|
+
return '';
|
|
37
|
+
const params = new URLSearchParams();
|
|
38
|
+
if (transform.w)
|
|
39
|
+
params.set('w', String(transform.w));
|
|
40
|
+
if (transform.h)
|
|
41
|
+
params.set('h', String(transform.h));
|
|
42
|
+
if (transform.q)
|
|
43
|
+
params.set('q', String(transform.q));
|
|
44
|
+
if (transform.f)
|
|
45
|
+
params.set('f', transform.f);
|
|
46
|
+
const str = params.toString();
|
|
47
|
+
return str ? `?${str}` : '';
|
|
48
|
+
}
|
|
19
49
|
/**
|
|
20
50
|
* Configure storage URL helpers with a base API URL.
|
|
21
51
|
* Call once at app startup, use the returned helpers everywhere.
|
|
22
52
|
*/
|
|
23
53
|
export function configureStorageUrls(apiBaseUrl) {
|
|
24
54
|
const base = apiBaseUrl.replace(/\/$/, '');
|
|
25
|
-
function buildStorageUrl(bucket, orgId, fileId) {
|
|
26
|
-
return `${base}/api/public/storage/${bucket}/${orgId}/${fileId}`;
|
|
55
|
+
function buildStorageUrl(bucket, orgId, fileId, transform) {
|
|
56
|
+
return `${base}/api/public/storage/${bucket}/${orgId}/${fileId}${buildTransformQuery(transform)}`;
|
|
27
57
|
}
|
|
28
58
|
function buildPhotoUrl(bucket, photo, size) {
|
|
29
59
|
if (photo.storage_path) {
|
|
30
|
-
// Full path provided — use directly
|
|
31
60
|
return `${base}/api/public/storage/${bucket}/${photo.storage_path}`;
|
|
32
61
|
}
|
|
33
62
|
const prefix = photo.storage_prefix || '';
|
|
@@ -41,6 +70,11 @@ export function configureStorageUrls(apiBaseUrl) {
|
|
|
41
70
|
.map((size) => `${buildPhotoUrl(bucket, photo, size)} ${SIZE_WIDTHS[size]}w`)
|
|
42
71
|
.join(', ');
|
|
43
72
|
}
|
|
44
|
-
|
|
73
|
+
function buildImageSrcSet(bucket, orgId, fileId, widths) {
|
|
74
|
+
return (widths || DEFAULT_SRCSET_WIDTHS)
|
|
75
|
+
.map((w) => `${buildStorageUrl(bucket, orgId, fileId, { w, f: 'webp', q: 80 })} ${w}w`)
|
|
76
|
+
.join(', ');
|
|
77
|
+
}
|
|
78
|
+
return { buildStorageUrl, buildPhotoUrl, buildPhotoSrcSet, buildImageSrcSet };
|
|
45
79
|
}
|
|
46
80
|
//# sourceMappingURL=storageUrl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageUrl.js","sourceRoot":"","sources":["../../../src/frontend/storage/storageUrl.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"storageUrl.js","sourceRoot":"","sources":["../../../src/frontend/storage/storageUrl.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,17 +3,38 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Sets proper CORS/CORP/Cache headers so images work cross-origin.
|
|
5
5
|
* Never exposes Supabase URLs to the client.
|
|
6
|
+
*
|
|
7
|
+
* Supports on-the-fly image transforms via query parameters:
|
|
8
|
+
* ?w=400 — resize to max width 400px (aspect ratio preserved)
|
|
9
|
+
* ?h=300 — resize to max height 300px
|
|
10
|
+
* ?q=80 — quality 1-100 (default: 80)
|
|
11
|
+
* ?f=webp — output format: webp, jpeg, png (default: auto from original)
|
|
12
|
+
*
|
|
13
|
+
* Transforms require sharp as optional peer dependency.
|
|
14
|
+
* Without sharp, images are served at original size.
|
|
6
15
|
*/
|
|
7
16
|
import type { Response } from 'express';
|
|
8
17
|
import type { StorageConfig } from './types.js';
|
|
18
|
+
export interface ImageTransformOptions {
|
|
19
|
+
width?: number;
|
|
20
|
+
height?: number;
|
|
21
|
+
quality?: number;
|
|
22
|
+
format?: 'webp' | 'jpeg' | 'png';
|
|
23
|
+
}
|
|
9
24
|
export declare class StorageProxyService {
|
|
10
25
|
private readonly supabaseUrl;
|
|
11
26
|
private readonly cacheMaxAge;
|
|
12
27
|
constructor(config: StorageConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Parse transform options from query parameters.
|
|
30
|
+
*/
|
|
31
|
+
static parseTransformOptions(query: Record<string, any>): ImageTransformOptions | null;
|
|
13
32
|
/**
|
|
14
33
|
* Stream a file from Supabase storage to the response.
|
|
15
|
-
*
|
|
34
|
+
* Optionally transforms images on-the-fly with sharp.
|
|
16
35
|
*/
|
|
17
|
-
streamFile(bucket: string, orgId: string, fileId: string, res: Response): Promise<void>;
|
|
36
|
+
streamFile(bucket: string, orgId: string, fileId: string, res: Response, transform?: ImageTransformOptions | null): Promise<void>;
|
|
37
|
+
private setHeaders;
|
|
38
|
+
private transformImage;
|
|
18
39
|
}
|
|
19
40
|
//# sourceMappingURL=StorageProxyService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageProxyService.d.ts","sourceRoot":"","sources":["../../../src/shared/storage/StorageProxyService.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"StorageProxyService.d.ts","sourceRoot":"","sources":["../../../src/shared/storage/StorageProxyService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKhD,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;CAClC;AA0BD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,MAAM,EAAE,aAAa;IAKjC;;OAEG;IACH,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,qBAAqB,GAAG,IAAI;IAgBtF;;;OAGG;IACG,UAAU,CACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,QAAQ,EACb,SAAS,CAAC,EAAE,qBAAqB,GAAG,IAAI,GACvC,OAAO,CAAC,IAAI,CAAC;IAoFhB,OAAO,CAAC,UAAU;YAOJ,cAAc;CAiC7B"}
|
|
@@ -3,9 +3,41 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Sets proper CORS/CORP/Cache headers so images work cross-origin.
|
|
5
5
|
* Never exposes Supabase URLs to the client.
|
|
6
|
+
*
|
|
7
|
+
* Supports on-the-fly image transforms via query parameters:
|
|
8
|
+
* ?w=400 — resize to max width 400px (aspect ratio preserved)
|
|
9
|
+
* ?h=300 — resize to max height 300px
|
|
10
|
+
* ?q=80 — quality 1-100 (default: 80)
|
|
11
|
+
* ?f=webp — output format: webp, jpeg, png (default: auto from original)
|
|
12
|
+
*
|
|
13
|
+
* Transforms require sharp as optional peer dependency.
|
|
14
|
+
* Without sharp, images are served at original size.
|
|
6
15
|
*/
|
|
7
16
|
import { createLogger } from '../../utils/logger.js';
|
|
8
17
|
const logger = createLogger('storage:proxy');
|
|
18
|
+
// Simple LRU-ish in-memory cache for transformed images
|
|
19
|
+
const transformCache = new Map();
|
|
20
|
+
const MAX_CACHE_SIZE = 200;
|
|
21
|
+
const CACHE_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
22
|
+
function getCached(key) {
|
|
23
|
+
const entry = transformCache.get(key);
|
|
24
|
+
if (!entry)
|
|
25
|
+
return null;
|
|
26
|
+
if (Date.now() - entry.timestamp > CACHE_TTL_MS) {
|
|
27
|
+
transformCache.delete(key);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return entry;
|
|
31
|
+
}
|
|
32
|
+
function setCache(key, buffer, contentType) {
|
|
33
|
+
// Evict oldest if at capacity
|
|
34
|
+
if (transformCache.size >= MAX_CACHE_SIZE) {
|
|
35
|
+
const oldest = transformCache.keys().next().value;
|
|
36
|
+
if (oldest)
|
|
37
|
+
transformCache.delete(oldest);
|
|
38
|
+
}
|
|
39
|
+
transformCache.set(key, { buffer, contentType, timestamp: Date.now() });
|
|
40
|
+
}
|
|
9
41
|
export class StorageProxyService {
|
|
10
42
|
supabaseUrl;
|
|
11
43
|
cacheMaxAge;
|
|
@@ -13,16 +45,45 @@ export class StorageProxyService {
|
|
|
13
45
|
this.supabaseUrl = config.supabaseUrl || process.env.SUPABASE_URL || '';
|
|
14
46
|
this.cacheMaxAge = config.cacheMaxAge ?? 3600;
|
|
15
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Parse transform options from query parameters.
|
|
50
|
+
*/
|
|
51
|
+
static parseTransformOptions(query) {
|
|
52
|
+
const w = query.w ? parseInt(query.w, 10) : undefined;
|
|
53
|
+
const h = query.h ? parseInt(query.h, 10) : undefined;
|
|
54
|
+
const q = query.q ? parseInt(query.q, 10) : undefined;
|
|
55
|
+
const f = query.f;
|
|
56
|
+
if (!w && !h && !q && !f)
|
|
57
|
+
return null;
|
|
58
|
+
return {
|
|
59
|
+
width: w && w > 0 && w <= 4000 ? w : undefined,
|
|
60
|
+
height: h && h > 0 && h <= 4000 ? h : undefined,
|
|
61
|
+
quality: q && q > 0 && q <= 100 ? q : 80,
|
|
62
|
+
format: f && ['webp', 'jpeg', 'png'].includes(f) ? f : undefined,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
16
65
|
/**
|
|
17
66
|
* Stream a file from Supabase storage to the response.
|
|
18
|
-
*
|
|
67
|
+
* Optionally transforms images on-the-fly with sharp.
|
|
19
68
|
*/
|
|
20
|
-
async streamFile(bucket, orgId, fileId, res) {
|
|
69
|
+
async streamFile(bucket, orgId, fileId, res, transform) {
|
|
21
70
|
if (!this.supabaseUrl) {
|
|
22
71
|
res.status(503).json({ success: false, error: 'Storage not configured' });
|
|
23
72
|
return;
|
|
24
73
|
}
|
|
25
74
|
const url = `${this.supabaseUrl}/storage/v1/object/public/${bucket}/${orgId}/${fileId}`;
|
|
75
|
+
// Check transform cache
|
|
76
|
+
if (transform) {
|
|
77
|
+
const cacheKey = `${url}:w${transform.width || ''}:h${transform.height || ''}:q${transform.quality || ''}:f${transform.format || ''}`;
|
|
78
|
+
const cached = getCached(cacheKey);
|
|
79
|
+
if (cached) {
|
|
80
|
+
this.setHeaders(res, cached.contentType);
|
|
81
|
+
res.setHeader('Content-Length', cached.buffer.length.toString());
|
|
82
|
+
res.setHeader('X-Transform-Cache', 'hit');
|
|
83
|
+
res.end(cached.buffer);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
26
87
|
try {
|
|
27
88
|
const upstream = await fetch(url);
|
|
28
89
|
if (!upstream.ok) {
|
|
@@ -33,10 +94,31 @@ export class StorageProxyService {
|
|
|
33
94
|
return;
|
|
34
95
|
}
|
|
35
96
|
const contentType = upstream.headers.get('content-type') || 'application/octet-stream';
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
97
|
+
const isImage = contentType.startsWith('image/');
|
|
98
|
+
// If transform requested and it's an image, try sharp
|
|
99
|
+
if (transform && isImage) {
|
|
100
|
+
try {
|
|
101
|
+
const buffer = Buffer.from(await upstream.arrayBuffer());
|
|
102
|
+
const transformed = await this.transformImage(buffer, transform);
|
|
103
|
+
const outType = transform.format
|
|
104
|
+
? `image/${transform.format}`
|
|
105
|
+
: contentType;
|
|
106
|
+
// Cache the result
|
|
107
|
+
const cacheKey = `${url}:w${transform.width || ''}:h${transform.height || ''}:q${transform.quality || ''}:f${transform.format || ''}`;
|
|
108
|
+
setCache(cacheKey, transformed, outType);
|
|
109
|
+
this.setHeaders(res, outType);
|
|
110
|
+
res.setHeader('Content-Length', transformed.length.toString());
|
|
111
|
+
res.setHeader('X-Transform', 'applied');
|
|
112
|
+
res.end(transformed);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
catch (transformError) {
|
|
116
|
+
// Sharp not available or transform failed — fall through to stream original
|
|
117
|
+
logger.debug({ error: transformError }, 'Transform failed, streaming original');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Stream original
|
|
121
|
+
this.setHeaders(res, contentType);
|
|
40
122
|
const contentLength = upstream.headers.get('content-length');
|
|
41
123
|
if (contentLength) {
|
|
42
124
|
res.setHeader('Content-Length', contentLength);
|
|
@@ -59,5 +141,39 @@ export class StorageProxyService {
|
|
|
59
141
|
res.status(502).json({ success: false, error: 'Failed to fetch from storage' });
|
|
60
142
|
}
|
|
61
143
|
}
|
|
144
|
+
setHeaders(res, contentType) {
|
|
145
|
+
res.setHeader('Content-Type', contentType);
|
|
146
|
+
res.setHeader('Cache-Control', `public, max-age=${this.cacheMaxAge}, immutable`);
|
|
147
|
+
res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');
|
|
148
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
149
|
+
}
|
|
150
|
+
async transformImage(buffer, options) {
|
|
151
|
+
// Dynamic import — sharp is optional peer dep
|
|
152
|
+
const sharp = (await import('sharp')).default;
|
|
153
|
+
let pipeline = sharp(buffer);
|
|
154
|
+
if (options.width || options.height) {
|
|
155
|
+
pipeline = pipeline.resize(options.width, options.height, {
|
|
156
|
+
fit: 'inside',
|
|
157
|
+
withoutEnlargement: true,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const quality = options.quality || 80;
|
|
161
|
+
switch (options.format) {
|
|
162
|
+
case 'webp':
|
|
163
|
+
pipeline = pipeline.webp({ quality });
|
|
164
|
+
break;
|
|
165
|
+
case 'jpeg':
|
|
166
|
+
pipeline = pipeline.jpeg({ quality, progressive: true });
|
|
167
|
+
break;
|
|
168
|
+
case 'png':
|
|
169
|
+
pipeline = pipeline.png({ quality });
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
// Auto-detect from original — apply quality
|
|
173
|
+
pipeline = pipeline.jpeg({ quality, progressive: true });
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
return pipeline.toBuffer();
|
|
177
|
+
}
|
|
62
178
|
}
|
|
63
179
|
//# sourceMappingURL=StorageProxyService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageProxyService.js","sourceRoot":"","sources":["../../../src/shared/storage/StorageProxyService.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"StorageProxyService.js","sourceRoot":"","sources":["../../../src/shared/storage/StorageProxyService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/shared/storage/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAGpD,OAAO,KAAK,EAAiB,mBAAmB,EAAE,oBAAoB,EAAgB,MAAM,YAAY,CAAC;AAKzG;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/shared/storage/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAGpD,OAAO,KAAK,EAAiB,mBAAmB,EAAE,oBAAoB,EAAgB,MAAM,YAAY,CAAC;AAKzG;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,CA2BxF;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,IAAI,CA8F1F"}
|
|
@@ -47,7 +47,9 @@ export function addStorageProxyRoutes(router, options) {
|
|
|
47
47
|
res.status(400).json({ success: false, error: 'Invalid bucket' });
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
// Parse optional image transform params: ?w=400&h=300&q=80&f=webp
|
|
51
|
+
const transform = StorageProxyService.parseTransformOptions(req.query);
|
|
52
|
+
await service.streamFile(bucket, orgId, fileId, res, transform);
|
|
51
53
|
});
|
|
52
54
|
logger.info({ buckets: config.allowedBuckets }, 'Storage proxy routes mounted');
|
|
53
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/shared/storage/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAc,EAAE,OAA4B;IAChF,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAE3B,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAElD,MAAM,CAAC,GAAG,CAAC,yBAAyB,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAC1E,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,MAAgB,CAAC;QAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,KAAe,CAAC;QACzC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,MAAgB,CAAC;QAE3C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;YAClE,OAAO;QACT,CAAC;QAED,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/shared/storage/routes.ts"],"names":[],"mappings":"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"}
|