@sproux/media-sdk 0.1.0 → 0.1.1
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 +106 -114
- package/dist/index.cjs +110 -128
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +78 -94
- package/dist/index.d.ts +78 -94
- package/dist/index.js +103 -117
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -14,115 +14,99 @@ declare const MEDIA_STATUS: {
|
|
|
14
14
|
readonly READY: "ready";
|
|
15
15
|
readonly ERROR: "error";
|
|
16
16
|
};
|
|
17
|
-
declare
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
declare enum IMAGE_FORMAT {
|
|
18
|
+
WEBP = "webp",
|
|
19
|
+
AVIF = "avif",
|
|
20
|
+
JPEG = "jpeg",
|
|
21
|
+
PNG = "png",
|
|
22
|
+
GIF = "gif",
|
|
23
|
+
ICO = "ico",
|
|
24
|
+
SVG = "svg",
|
|
25
|
+
JPG = "jpg"
|
|
26
|
+
}
|
|
27
|
+
declare enum IMAGE_RESIZE_TYPE {
|
|
28
|
+
FIT = "fit",
|
|
29
|
+
FILL = "fill",
|
|
30
|
+
FORCE = "force",
|
|
31
|
+
FILL_DOWN = "fill-down",
|
|
32
|
+
AUTO = "auto"
|
|
33
|
+
}
|
|
29
34
|
declare const R2_PATH: {
|
|
30
35
|
readonly HLS_PLAYLIST: "playlist.m3u8";
|
|
31
36
|
readonly THUMBNAIL: "thumbnail.webp";
|
|
32
37
|
};
|
|
33
38
|
declare const MEDIA_DEFAULTS: {
|
|
34
|
-
readonly IMAGE_FORMAT:
|
|
39
|
+
readonly IMAGE_FORMAT: IMAGE_FORMAT.WEBP;
|
|
35
40
|
};
|
|
36
41
|
|
|
37
|
-
type
|
|
38
|
-
type
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
interface ParsedMediaUrl {
|
|
43
|
-
/** Full original URL */
|
|
44
|
-
originalUrl: string;
|
|
45
|
-
/** CDN base including protocol and host */
|
|
46
|
-
cdnBase: string;
|
|
47
|
-
/** Object key without CDN base */
|
|
48
|
-
objectKey: string;
|
|
49
|
-
/** Purpose segment: avatar, hero, gallery */
|
|
50
|
-
purpose: MediaPurpose;
|
|
51
|
-
/** Type segment: image, video */
|
|
52
|
-
type: MediaType;
|
|
53
|
-
/** User ID segment */
|
|
54
|
-
userId: string;
|
|
55
|
-
/** File name without extension */
|
|
56
|
-
name: string;
|
|
57
|
-
/** File extension without dot */
|
|
58
|
-
extension: string;
|
|
42
|
+
type ImageFormat = `${IMAGE_FORMAT}`;
|
|
43
|
+
type ImageResizeType = `${IMAGE_RESIZE_TYPE}`;
|
|
44
|
+
interface SprouxMediaConfig {
|
|
45
|
+
/** CDN base URL including protocol and host (e.g. "https://cdn.example.com") */
|
|
46
|
+
cdnUrl: string;
|
|
59
47
|
}
|
|
60
|
-
interface
|
|
48
|
+
interface ImageUrlOptions {
|
|
49
|
+
/** Output format extension (e.g. "webp", "avif") */
|
|
50
|
+
extension: ImageFormat;
|
|
61
51
|
/** Target width in pixels (1-4096) */
|
|
62
52
|
width: number;
|
|
63
53
|
/** Target height in pixels (1-4096) */
|
|
64
54
|
height: number;
|
|
65
55
|
/** Resize type: fit, fill, auto */
|
|
66
56
|
resizeType: ImageResizeType;
|
|
67
|
-
/**
|
|
68
|
-
format?: ImageFormat;
|
|
69
|
-
/** Quality 1-100 */
|
|
57
|
+
/** Quality 1-100 (optional) */
|
|
70
58
|
quality?: number;
|
|
71
59
|
}
|
|
72
60
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
* buildVideoThumbnailUrl("https://cdn.example.com/gallery/video/usr-1/xyz.mp4")
|
|
124
|
-
* → "https://cdn.example.com/gallery/video/usr-1/xyz/thumbnail.webp"
|
|
125
|
-
*/
|
|
126
|
-
declare function buildVideoThumbnailUrl(originalUrl: string): string;
|
|
61
|
+
declare class SprouxMedia {
|
|
62
|
+
private static instance;
|
|
63
|
+
private readonly cdnUrl;
|
|
64
|
+
private constructor();
|
|
65
|
+
/**
|
|
66
|
+
* Initialize the singleton with CDN configuration.
|
|
67
|
+
* Returns the singleton instance.
|
|
68
|
+
*/
|
|
69
|
+
static init(config: SprouxMediaConfig): SprouxMedia;
|
|
70
|
+
/**
|
|
71
|
+
* Returns the existing singleton instance.
|
|
72
|
+
* Throws if `init()` has not been called.
|
|
73
|
+
*/
|
|
74
|
+
static getInstance(): SprouxMedia;
|
|
75
|
+
/**
|
|
76
|
+
* Build a CDN URL for an image variant.
|
|
77
|
+
*
|
|
78
|
+
* @param objectKey - Object key without extension (e.g. "avatar/image/usr-1/abc")
|
|
79
|
+
* @param options - Image variant options including extension, dimensions, resize type, and optional quality
|
|
80
|
+
* @returns Full CDN URL for the image variant
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* media.getImageUrl('avatar/image/usr-1/abc', {
|
|
84
|
+
* extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,
|
|
85
|
+
* });
|
|
86
|
+
* // → "https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp"
|
|
87
|
+
*/
|
|
88
|
+
getImageUrl(objectKey: string, options: ImageUrlOptions): string;
|
|
89
|
+
/**
|
|
90
|
+
* Build a CDN URL for a video HLS playlist.
|
|
91
|
+
*
|
|
92
|
+
* @param objectKey - Object key without extension (e.g. "gallery/video/usr-1/xyz")
|
|
93
|
+
* @returns Full CDN URL for the HLS playlist
|
|
94
|
+
*/
|
|
95
|
+
getVideoHlsUrl(objectKey: string): string;
|
|
96
|
+
/**
|
|
97
|
+
* Build a CDN URL for a video thumbnail.
|
|
98
|
+
*
|
|
99
|
+
* @param objectKey - Object key without extension (e.g. "gallery/video/usr-1/xyz")
|
|
100
|
+
* @returns Full CDN URL for the thumbnail
|
|
101
|
+
*/
|
|
102
|
+
getVideoThumbnailUrl(objectKey: string): string;
|
|
103
|
+
/**
|
|
104
|
+
* Build a deterministic variant string from image options.
|
|
105
|
+
*
|
|
106
|
+
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
107
|
+
*/
|
|
108
|
+
private buildVariantString;
|
|
109
|
+
private validateImageOptions;
|
|
110
|
+
}
|
|
127
111
|
|
|
128
|
-
export { IMAGE_FORMAT, IMAGE_RESIZE_TYPE, type ImageFormat, type ImageResizeType, type
|
|
112
|
+
export { IMAGE_FORMAT, IMAGE_RESIZE_TYPE, type ImageFormat, type ImageResizeType, type ImageUrlOptions, MEDIA_DEFAULTS, MEDIA_PURPOSE, MEDIA_STATUS, MEDIA_TYPE, R2_PATH, SprouxMedia, type SprouxMediaConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,115 +14,99 @@ declare const MEDIA_STATUS: {
|
|
|
14
14
|
readonly READY: "ready";
|
|
15
15
|
readonly ERROR: "error";
|
|
16
16
|
};
|
|
17
|
-
declare
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
declare enum IMAGE_FORMAT {
|
|
18
|
+
WEBP = "webp",
|
|
19
|
+
AVIF = "avif",
|
|
20
|
+
JPEG = "jpeg",
|
|
21
|
+
PNG = "png",
|
|
22
|
+
GIF = "gif",
|
|
23
|
+
ICO = "ico",
|
|
24
|
+
SVG = "svg",
|
|
25
|
+
JPG = "jpg"
|
|
26
|
+
}
|
|
27
|
+
declare enum IMAGE_RESIZE_TYPE {
|
|
28
|
+
FIT = "fit",
|
|
29
|
+
FILL = "fill",
|
|
30
|
+
FORCE = "force",
|
|
31
|
+
FILL_DOWN = "fill-down",
|
|
32
|
+
AUTO = "auto"
|
|
33
|
+
}
|
|
29
34
|
declare const R2_PATH: {
|
|
30
35
|
readonly HLS_PLAYLIST: "playlist.m3u8";
|
|
31
36
|
readonly THUMBNAIL: "thumbnail.webp";
|
|
32
37
|
};
|
|
33
38
|
declare const MEDIA_DEFAULTS: {
|
|
34
|
-
readonly IMAGE_FORMAT:
|
|
39
|
+
readonly IMAGE_FORMAT: IMAGE_FORMAT.WEBP;
|
|
35
40
|
};
|
|
36
41
|
|
|
37
|
-
type
|
|
38
|
-
type
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
interface ParsedMediaUrl {
|
|
43
|
-
/** Full original URL */
|
|
44
|
-
originalUrl: string;
|
|
45
|
-
/** CDN base including protocol and host */
|
|
46
|
-
cdnBase: string;
|
|
47
|
-
/** Object key without CDN base */
|
|
48
|
-
objectKey: string;
|
|
49
|
-
/** Purpose segment: avatar, hero, gallery */
|
|
50
|
-
purpose: MediaPurpose;
|
|
51
|
-
/** Type segment: image, video */
|
|
52
|
-
type: MediaType;
|
|
53
|
-
/** User ID segment */
|
|
54
|
-
userId: string;
|
|
55
|
-
/** File name without extension */
|
|
56
|
-
name: string;
|
|
57
|
-
/** File extension without dot */
|
|
58
|
-
extension: string;
|
|
42
|
+
type ImageFormat = `${IMAGE_FORMAT}`;
|
|
43
|
+
type ImageResizeType = `${IMAGE_RESIZE_TYPE}`;
|
|
44
|
+
interface SprouxMediaConfig {
|
|
45
|
+
/** CDN base URL including protocol and host (e.g. "https://cdn.example.com") */
|
|
46
|
+
cdnUrl: string;
|
|
59
47
|
}
|
|
60
|
-
interface
|
|
48
|
+
interface ImageUrlOptions {
|
|
49
|
+
/** Output format extension (e.g. "webp", "avif") */
|
|
50
|
+
extension: ImageFormat;
|
|
61
51
|
/** Target width in pixels (1-4096) */
|
|
62
52
|
width: number;
|
|
63
53
|
/** Target height in pixels (1-4096) */
|
|
64
54
|
height: number;
|
|
65
55
|
/** Resize type: fit, fill, auto */
|
|
66
56
|
resizeType: ImageResizeType;
|
|
67
|
-
/**
|
|
68
|
-
format?: ImageFormat;
|
|
69
|
-
/** Quality 1-100 */
|
|
57
|
+
/** Quality 1-100 (optional) */
|
|
70
58
|
quality?: number;
|
|
71
59
|
}
|
|
72
60
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
* buildVideoThumbnailUrl("https://cdn.example.com/gallery/video/usr-1/xyz.mp4")
|
|
124
|
-
* → "https://cdn.example.com/gallery/video/usr-1/xyz/thumbnail.webp"
|
|
125
|
-
*/
|
|
126
|
-
declare function buildVideoThumbnailUrl(originalUrl: string): string;
|
|
61
|
+
declare class SprouxMedia {
|
|
62
|
+
private static instance;
|
|
63
|
+
private readonly cdnUrl;
|
|
64
|
+
private constructor();
|
|
65
|
+
/**
|
|
66
|
+
* Initialize the singleton with CDN configuration.
|
|
67
|
+
* Returns the singleton instance.
|
|
68
|
+
*/
|
|
69
|
+
static init(config: SprouxMediaConfig): SprouxMedia;
|
|
70
|
+
/**
|
|
71
|
+
* Returns the existing singleton instance.
|
|
72
|
+
* Throws if `init()` has not been called.
|
|
73
|
+
*/
|
|
74
|
+
static getInstance(): SprouxMedia;
|
|
75
|
+
/**
|
|
76
|
+
* Build a CDN URL for an image variant.
|
|
77
|
+
*
|
|
78
|
+
* @param objectKey - Object key without extension (e.g. "avatar/image/usr-1/abc")
|
|
79
|
+
* @param options - Image variant options including extension, dimensions, resize type, and optional quality
|
|
80
|
+
* @returns Full CDN URL for the image variant
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* media.getImageUrl('avatar/image/usr-1/abc', {
|
|
84
|
+
* extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,
|
|
85
|
+
* });
|
|
86
|
+
* // → "https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp"
|
|
87
|
+
*/
|
|
88
|
+
getImageUrl(objectKey: string, options: ImageUrlOptions): string;
|
|
89
|
+
/**
|
|
90
|
+
* Build a CDN URL for a video HLS playlist.
|
|
91
|
+
*
|
|
92
|
+
* @param objectKey - Object key without extension (e.g. "gallery/video/usr-1/xyz")
|
|
93
|
+
* @returns Full CDN URL for the HLS playlist
|
|
94
|
+
*/
|
|
95
|
+
getVideoHlsUrl(objectKey: string): string;
|
|
96
|
+
/**
|
|
97
|
+
* Build a CDN URL for a video thumbnail.
|
|
98
|
+
*
|
|
99
|
+
* @param objectKey - Object key without extension (e.g. "gallery/video/usr-1/xyz")
|
|
100
|
+
* @returns Full CDN URL for the thumbnail
|
|
101
|
+
*/
|
|
102
|
+
getVideoThumbnailUrl(objectKey: string): string;
|
|
103
|
+
/**
|
|
104
|
+
* Build a deterministic variant string from image options.
|
|
105
|
+
*
|
|
106
|
+
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
107
|
+
*/
|
|
108
|
+
private buildVariantString;
|
|
109
|
+
private validateImageOptions;
|
|
110
|
+
}
|
|
127
111
|
|
|
128
|
-
export { IMAGE_FORMAT, IMAGE_RESIZE_TYPE, type ImageFormat, type ImageResizeType, type
|
|
112
|
+
export { IMAGE_FORMAT, IMAGE_RESIZE_TYPE, type ImageFormat, type ImageResizeType, type ImageUrlOptions, MEDIA_DEFAULTS, MEDIA_PURPOSE, MEDIA_STATUS, MEDIA_TYPE, R2_PATH, SprouxMedia, type SprouxMediaConfig };
|
package/dist/index.js
CHANGED
|
@@ -15,136 +15,126 @@ var MEDIA_STATUS = {
|
|
|
15
15
|
READY: "ready",
|
|
16
16
|
ERROR: "error"
|
|
17
17
|
};
|
|
18
|
-
var IMAGE_FORMAT = {
|
|
19
|
-
WEBP
|
|
20
|
-
AVIF
|
|
21
|
-
JPEG
|
|
22
|
-
PNG
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
var IMAGE_FORMAT = /* @__PURE__ */ ((IMAGE_FORMAT2) => {
|
|
19
|
+
IMAGE_FORMAT2["WEBP"] = "webp";
|
|
20
|
+
IMAGE_FORMAT2["AVIF"] = "avif";
|
|
21
|
+
IMAGE_FORMAT2["JPEG"] = "jpeg";
|
|
22
|
+
IMAGE_FORMAT2["PNG"] = "png";
|
|
23
|
+
IMAGE_FORMAT2["GIF"] = "gif";
|
|
24
|
+
IMAGE_FORMAT2["ICO"] = "ico";
|
|
25
|
+
IMAGE_FORMAT2["SVG"] = "svg";
|
|
26
|
+
IMAGE_FORMAT2["JPG"] = "jpg";
|
|
27
|
+
return IMAGE_FORMAT2;
|
|
28
|
+
})(IMAGE_FORMAT || {});
|
|
29
|
+
var IMAGE_RESIZE_TYPE = /* @__PURE__ */ ((IMAGE_RESIZE_TYPE2) => {
|
|
30
|
+
IMAGE_RESIZE_TYPE2["FIT"] = "fit";
|
|
31
|
+
IMAGE_RESIZE_TYPE2["FILL"] = "fill";
|
|
32
|
+
IMAGE_RESIZE_TYPE2["FORCE"] = "force";
|
|
33
|
+
IMAGE_RESIZE_TYPE2["FILL_DOWN"] = "fill-down";
|
|
34
|
+
IMAGE_RESIZE_TYPE2["AUTO"] = "auto";
|
|
35
|
+
return IMAGE_RESIZE_TYPE2;
|
|
36
|
+
})(IMAGE_RESIZE_TYPE || {});
|
|
30
37
|
var R2_PATH = {
|
|
31
38
|
HLS_PLAYLIST: "playlist.m3u8",
|
|
32
39
|
THUMBNAIL: "thumbnail.webp"
|
|
33
40
|
};
|
|
34
41
|
var MEDIA_DEFAULTS = {
|
|
35
|
-
IMAGE_FORMAT:
|
|
42
|
+
IMAGE_FORMAT: "webp" /* WEBP */
|
|
36
43
|
};
|
|
37
44
|
|
|
38
|
-
// src/
|
|
39
|
-
var
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
url = new URL(originalUrl);
|
|
45
|
-
} catch {
|
|
46
|
-
throw new Error(`Invalid media URL: "${originalUrl}"`);
|
|
47
|
-
}
|
|
48
|
-
const pathname = url.pathname.startsWith("/") ? url.pathname.slice(1) : url.pathname;
|
|
49
|
-
const segments = pathname.split("/");
|
|
50
|
-
if (segments.length < 4) {
|
|
51
|
-
throw new Error(
|
|
52
|
-
`Invalid media URL path: expected at least 4 segments (purpose/type/userId/filename), got ${segments.length} in "${pathname}"`
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
const [purpose, type, userId, filename] = segments;
|
|
56
|
-
if (!VALID_PURPOSES.has(purpose)) {
|
|
57
|
-
throw new Error(
|
|
58
|
-
`Invalid media purpose: "${purpose}". Expected one of: ${[...VALID_PURPOSES].join(", ")}`
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
if (!VALID_TYPES.has(type)) {
|
|
62
|
-
throw new Error(
|
|
63
|
-
`Invalid media type: "${type}". Expected one of: ${[...VALID_TYPES].join(", ")}`
|
|
64
|
-
);
|
|
45
|
+
// src/sproux-media.ts
|
|
46
|
+
var SprouxMedia = class _SprouxMedia {
|
|
47
|
+
static instance = null;
|
|
48
|
+
cdnUrl;
|
|
49
|
+
constructor(config) {
|
|
50
|
+
this.cdnUrl = config.cdnUrl.replace(/\/+$/, "");
|
|
65
51
|
}
|
|
66
|
-
|
|
67
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Initialize the singleton with CDN configuration.
|
|
54
|
+
* Returns the singleton instance.
|
|
55
|
+
*/
|
|
56
|
+
static init(config) {
|
|
57
|
+
if (_SprouxMedia.instance) {
|
|
58
|
+
return _SprouxMedia.instance;
|
|
59
|
+
}
|
|
60
|
+
return _SprouxMedia.instance = new _SprouxMedia(config);
|
|
68
61
|
}
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Returns the existing singleton instance.
|
|
64
|
+
* Throws if `init()` has not been called.
|
|
65
|
+
*/
|
|
66
|
+
static getInstance() {
|
|
67
|
+
if (!_SprouxMedia.instance) {
|
|
68
|
+
throw new Error("SprouxMedia has not been initialized. Call SprouxMedia.init() first.");
|
|
69
|
+
}
|
|
70
|
+
return _SprouxMedia.instance;
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Build a CDN URL for an image variant.
|
|
74
|
+
*
|
|
75
|
+
* @param objectKey - Object key without extension (e.g. "avatar/image/usr-1/abc")
|
|
76
|
+
* @param options - Image variant options including extension, dimensions, resize type, and optional quality
|
|
77
|
+
* @returns Full CDN URL for the image variant
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* media.getImageUrl('avatar/image/usr-1/abc', {
|
|
81
|
+
* extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,
|
|
82
|
+
* });
|
|
83
|
+
* // → "https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp"
|
|
84
|
+
*/
|
|
85
|
+
getImageUrl(objectKey, options) {
|
|
86
|
+
this.validateImageOptions(options);
|
|
87
|
+
const variant = this.buildVariantString(options);
|
|
88
|
+
return `${this.cdnUrl}/${objectKey}-${variant}.${options.extension}`;
|
|
75
89
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Build a CDN URL for a video HLS playlist.
|
|
92
|
+
*
|
|
93
|
+
* @param objectKey - Object key without extension (e.g. "gallery/video/usr-1/xyz")
|
|
94
|
+
* @returns Full CDN URL for the HLS playlist
|
|
95
|
+
*/
|
|
96
|
+
getVideoHlsUrl(objectKey) {
|
|
97
|
+
return `${this.cdnUrl}/${objectKey}/${R2_PATH.HLS_PLAYLIST}`;
|
|
80
98
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
userId,
|
|
90
|
-
name,
|
|
91
|
-
extension
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// src/build-variant-string.ts
|
|
96
|
-
function buildVariantString(options) {
|
|
97
|
-
validateVariantOptions(options);
|
|
98
|
-
const parts = [`${options.width}x${options.height}`, options.resizeType];
|
|
99
|
-
if (options.quality != null) {
|
|
100
|
-
parts.push(`q${options.quality}`);
|
|
99
|
+
/**
|
|
100
|
+
* Build a CDN URL for a video thumbnail.
|
|
101
|
+
*
|
|
102
|
+
* @param objectKey - Object key without extension (e.g. "gallery/video/usr-1/xyz")
|
|
103
|
+
* @returns Full CDN URL for the thumbnail
|
|
104
|
+
*/
|
|
105
|
+
getVideoThumbnailUrl(objectKey) {
|
|
106
|
+
return `${this.cdnUrl}/${objectKey}/${R2_PATH.THUMBNAIL}`;
|
|
101
107
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Build a deterministic variant string from image options.
|
|
110
|
+
*
|
|
111
|
+
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
112
|
+
*/
|
|
113
|
+
buildVariantString(options) {
|
|
114
|
+
const parts = [`${options.width}x${options.height}`, options.resizeType];
|
|
115
|
+
if (options.quality != null) {
|
|
116
|
+
parts.push(`q${options.quality}`);
|
|
117
|
+
}
|
|
118
|
+
return parts.join("-");
|
|
110
119
|
}
|
|
111
|
-
|
|
112
|
-
if (!Number.isInteger(options.
|
|
120
|
+
validateImageOptions(options) {
|
|
121
|
+
if (!Number.isInteger(options.width) || options.width < 1 || options.width > 4096) {
|
|
122
|
+
throw new Error(`Invalid width: ${options.width}. Must be an integer between 1 and 4096.`);
|
|
123
|
+
}
|
|
124
|
+
if (!Number.isInteger(options.height) || options.height < 1 || options.height > 4096) {
|
|
113
125
|
throw new Error(
|
|
114
|
-
`Invalid
|
|
126
|
+
`Invalid height: ${options.height}. Must be an integer between 1 and 4096.`
|
|
115
127
|
);
|
|
116
128
|
}
|
|
129
|
+
if (options.quality != null) {
|
|
130
|
+
if (!Number.isInteger(options.quality) || options.quality < 1 || options.quality > 100) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Invalid quality: ${options.quality}. Must be an integer between 1 and 100.`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
117
136
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// src/build-image-variant-url.ts
|
|
121
|
-
function buildImageVariantUrl(originalUrl, options) {
|
|
122
|
-
const parsed = parseMediaUrl(originalUrl);
|
|
123
|
-
if (parsed.type !== "image") {
|
|
124
|
-
throw new Error(`Expected image URL, got type "${parsed.type}" in "${originalUrl}"`);
|
|
125
|
-
}
|
|
126
|
-
const variant = buildVariantString(options);
|
|
127
|
-
const format = options.format ?? MEDIA_DEFAULTS.IMAGE_FORMAT;
|
|
128
|
-
return `${parsed.cdnBase}/${parsed.purpose}/${parsed.type}/${parsed.userId}/${parsed.name}-${variant}.${format}`;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// src/build-video-hls-url.ts
|
|
132
|
-
function buildVideoHlsUrl(originalUrl) {
|
|
133
|
-
const parsed = parseMediaUrl(originalUrl);
|
|
134
|
-
if (parsed.type !== "video") {
|
|
135
|
-
throw new Error(`Expected video URL, got type "${parsed.type}" in "${originalUrl}"`);
|
|
136
|
-
}
|
|
137
|
-
return `${parsed.cdnBase}/${parsed.purpose}/video/${parsed.userId}/${parsed.name}/${R2_PATH.HLS_PLAYLIST}`;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// src/build-video-thumbnail-url.ts
|
|
141
|
-
function buildVideoThumbnailUrl(originalUrl) {
|
|
142
|
-
const parsed = parseMediaUrl(originalUrl);
|
|
143
|
-
if (parsed.type !== "video") {
|
|
144
|
-
throw new Error(`Expected video URL, got type "${parsed.type}" in "${originalUrl}"`);
|
|
145
|
-
}
|
|
146
|
-
return `${parsed.cdnBase}/${parsed.purpose}/video/${parsed.userId}/${parsed.name}/${R2_PATH.THUMBNAIL}`;
|
|
147
|
-
}
|
|
137
|
+
};
|
|
148
138
|
export {
|
|
149
139
|
IMAGE_FORMAT,
|
|
150
140
|
IMAGE_RESIZE_TYPE,
|
|
@@ -153,10 +143,6 @@ export {
|
|
|
153
143
|
MEDIA_STATUS,
|
|
154
144
|
MEDIA_TYPE,
|
|
155
145
|
R2_PATH,
|
|
156
|
-
|
|
157
|
-
buildVariantString,
|
|
158
|
-
buildVideoHlsUrl,
|
|
159
|
-
buildVideoThumbnailUrl,
|
|
160
|
-
parseMediaUrl
|
|
146
|
+
SprouxMedia
|
|
161
147
|
};
|
|
162
148
|
//# sourceMappingURL=index.js.map
|