@sproux/media-sdk 0.1.1 → 0.1.2
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 +28 -12
- package/dist/index.cjs +47 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -10
- package/dist/index.d.ts +20 -10
- package/dist/index.js +47 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,8 +23,8 @@ import { SprouxMedia, IMAGE_FORMAT, IMAGE_RESIZE_TYPE } from '@sproux/media-sdk'
|
|
|
23
23
|
// Initialize once (e.g. at app startup)
|
|
24
24
|
const media = SprouxMedia.init({ cdnUrl: 'https://cdn.example.com' });
|
|
25
25
|
|
|
26
|
-
// Build an image variant URL
|
|
27
|
-
const imageUrl = media.getImageUrl('avatar/image/usr-1/abc', {
|
|
26
|
+
// Build an image variant URL with all options
|
|
27
|
+
const imageUrl = media.getImageUrl('avatar/image/usr-1/abc.jpg', {
|
|
28
28
|
extension: IMAGE_FORMAT.WEBP,
|
|
29
29
|
width: 200,
|
|
30
30
|
height: 200,
|
|
@@ -33,6 +33,10 @@ const imageUrl = media.getImageUrl('avatar/image/usr-1/abc', {
|
|
|
33
33
|
});
|
|
34
34
|
// → "https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp"
|
|
35
35
|
|
|
36
|
+
// Or with just the object key (no variant transformation)
|
|
37
|
+
const originalUrl = media.getImageUrl('avatar/image/usr-1/abc.jpg');
|
|
38
|
+
// → "https://cdn.example.com/avatar/image/usr-1/abc.jpg"
|
|
39
|
+
|
|
36
40
|
// Build a video HLS playlist URL
|
|
37
41
|
const hlsUrl = media.getVideoHlsUrl('gallery/video/usr-1/intro');
|
|
38
42
|
// → "https://cdn.example.com/gallery/video/usr-1/intro/playlist.m3u8"
|
|
@@ -52,12 +56,16 @@ SprouxMedia.init({ cdnUrl: 'https://cdn.example.com' });
|
|
|
52
56
|
|
|
53
57
|
// Access from anywhere via getInstance()
|
|
54
58
|
const media = SprouxMedia.getInstance();
|
|
55
|
-
|
|
59
|
+
// With variant options
|
|
60
|
+
const url = media.getImageUrl('avatar/image/usr-1/photo.jpg', {
|
|
56
61
|
extension: IMAGE_FORMAT.WEBP,
|
|
57
62
|
width: 400,
|
|
58
63
|
height: 300,
|
|
59
64
|
resizeType: IMAGE_RESIZE_TYPE.FILL,
|
|
60
65
|
});
|
|
66
|
+
|
|
67
|
+
// Without options — returns the original URL
|
|
68
|
+
const original = media.getImageUrl('avatar/image/usr-1/photo.jpg');
|
|
61
69
|
```
|
|
62
70
|
|
|
63
71
|
> Calling `getInstance()` before `init()` will throw an error.
|
|
@@ -76,16 +84,18 @@ const media = SprouxMedia.init({ cdnUrl: 'https://cdn.example.com' });
|
|
|
76
84
|
|
|
77
85
|
Returns the existing singleton instance. Throws if `init()` has not been called.
|
|
78
86
|
|
|
79
|
-
### `media.getImageUrl(objectKey: string, options
|
|
87
|
+
### `media.getImageUrl(objectKey: string, options?: ImageUrlOptions): string`
|
|
80
88
|
|
|
81
|
-
Build a CDN URL for an image variant
|
|
89
|
+
Build a CDN URL for an image variant. When `options` is omitted, returns the original CDN URL for the object key as-is.
|
|
82
90
|
|
|
83
|
-
- `objectKey` — Object key **
|
|
91
|
+
- `objectKey` — Object key **with** extension (e.g. `"avatar/image/usr-1/abc.jpg"`)
|
|
92
|
+
- `options` — Optional variant transformation options
|
|
84
93
|
|
|
85
94
|
```typescript
|
|
86
95
|
import { IMAGE_FORMAT, IMAGE_RESIZE_TYPE } from '@sproux/media-sdk';
|
|
87
96
|
|
|
88
|
-
|
|
97
|
+
// With variant options
|
|
98
|
+
media.getImageUrl('avatar/image/usr-1/photo.jpg', {
|
|
89
99
|
extension: IMAGE_FORMAT.WEBP,
|
|
90
100
|
width: 400,
|
|
91
101
|
height: 300,
|
|
@@ -93,16 +103,22 @@ media.getImageUrl('avatar/image/usr-1/photo', {
|
|
|
93
103
|
quality: 85,
|
|
94
104
|
});
|
|
95
105
|
// → "https://cdn.example.com/avatar/image/usr-1/photo-400x300-fill-q85.webp"
|
|
106
|
+
|
|
107
|
+
// Without options — returns the original URL
|
|
108
|
+
media.getImageUrl('avatar/image/usr-1/photo.jpg');
|
|
109
|
+
// → "https://cdn.example.com/avatar/image/usr-1/photo.jpg"
|
|
96
110
|
```
|
|
97
111
|
|
|
98
112
|
#### ImageUrlOptions
|
|
99
113
|
|
|
114
|
+
All fields are optional.
|
|
115
|
+
|
|
100
116
|
| Property | Type | Required | Description |
|
|
101
117
|
| ------------ | ----------------- | -------- | -------------------------------------- |
|
|
102
|
-
| `extension` | `ImageFormat` |
|
|
103
|
-
| `width` | `number` |
|
|
104
|
-
| `height` | `number` |
|
|
105
|
-
| `resizeType` | `ImageResizeType` |
|
|
118
|
+
| `extension` | `ImageFormat` | No | Output format (`webp`, `avif`, `jpeg`, `png`, `gif`, `ico`, `svg`, `jpg`) |
|
|
119
|
+
| `width` | `number` | No | Target width in pixels (1–4096) |
|
|
120
|
+
| `height` | `number` | No | Target height in pixels (1–4096) |
|
|
121
|
+
| `resizeType` | `ImageResizeType` | No | Resize strategy: `fit`, `fill`, `force`, `fill-down`, `auto` |
|
|
106
122
|
| `quality` | `number` | No | Quality 1–100 |
|
|
107
123
|
|
|
108
124
|
### `media.getVideoHlsUrl(objectKey: string): string`
|
|
@@ -167,7 +183,7 @@ import type {
|
|
|
167
183
|
ImageFormat, // 'webp' | 'avif' | 'jpeg' | 'png' | 'gif' | 'ico' | 'svg' | 'jpg'
|
|
168
184
|
ImageResizeType, // 'fit' | 'fill' | 'force' | 'fill-down' | 'auto'
|
|
169
185
|
SprouxMediaConfig, // { cdnUrl: string }
|
|
170
|
-
ImageUrlOptions, // { extension
|
|
186
|
+
ImageUrlOptions, // { extension?, width?, height?, resizeType?, quality? }
|
|
171
187
|
} from '@sproux/media-sdk';
|
|
172
188
|
```
|
|
173
189
|
|
package/dist/index.cjs
CHANGED
|
@@ -103,22 +103,33 @@ var SprouxMedia = class _SprouxMedia {
|
|
|
103
103
|
return _SprouxMedia.instance;
|
|
104
104
|
}
|
|
105
105
|
/**
|
|
106
|
-
* Build a CDN URL for an image variant.
|
|
106
|
+
* Build a CDN URL for an image, optionally with variant transformation.
|
|
107
107
|
*
|
|
108
|
-
* @param objectKey - Object key
|
|
109
|
-
* @param options -
|
|
110
|
-
* @returns Full CDN URL
|
|
108
|
+
* @param objectKey - Object key with extension (e.g. "avatar/image/usr-1/abc.jpg")
|
|
109
|
+
* @param options - Optional image variant options (extension, dimensions, resize type, quality)
|
|
110
|
+
* @returns Full CDN URL — variant URL if options are provided, original URL otherwise
|
|
111
111
|
*
|
|
112
112
|
* @example
|
|
113
|
-
*
|
|
113
|
+
* // With variant options
|
|
114
|
+
* media.getImageUrl('avatar/image/usr-1/abc.jpg', {
|
|
114
115
|
* extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,
|
|
115
116
|
* });
|
|
116
117
|
* // → "https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp"
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* // Without options — returns the original URL
|
|
121
|
+
* media.getImageUrl('avatar/image/usr-1/abc.jpg');
|
|
122
|
+
* // → "https://cdn.example.com/avatar/image/usr-1/abc.jpg"
|
|
117
123
|
*/
|
|
118
124
|
getImageUrl(objectKey, options) {
|
|
125
|
+
if (!options || Object.keys(options).length === 0) {
|
|
126
|
+
return `${this.cdnUrl}/${objectKey}`;
|
|
127
|
+
}
|
|
119
128
|
this.validateImageOptions(options);
|
|
129
|
+
const { name, extension: originalExt } = this.parseObjectKey(objectKey);
|
|
130
|
+
const ext = options.extension ?? originalExt;
|
|
120
131
|
const variant = this.buildVariantString(options);
|
|
121
|
-
return `${this.cdnUrl}/${
|
|
132
|
+
return variant ? `${this.cdnUrl}/${name}-${variant}.${ext}` : `${this.cdnUrl}/${objectKey}`;
|
|
122
133
|
}
|
|
123
134
|
/**
|
|
124
135
|
* Build a CDN URL for a video HLS playlist.
|
|
@@ -138,26 +149,49 @@ var SprouxMedia = class _SprouxMedia {
|
|
|
138
149
|
getVideoThumbnailUrl(objectKey) {
|
|
139
150
|
return `${this.cdnUrl}/${objectKey}/${R2_PATH.THUMBNAIL}`;
|
|
140
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Parse an object key into name (path without extension) and extension.
|
|
154
|
+
*/
|
|
155
|
+
parseObjectKey(objectKey) {
|
|
156
|
+
const lastDot = objectKey.lastIndexOf(".");
|
|
157
|
+
if (lastDot === -1) {
|
|
158
|
+
return { name: objectKey, extension: "" };
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
name: objectKey.substring(0, lastDot),
|
|
162
|
+
extension: objectKey.substring(lastDot + 1)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
141
165
|
/**
|
|
142
166
|
* Build a deterministic variant string from image options.
|
|
143
167
|
*
|
|
144
168
|
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
145
169
|
*/
|
|
146
170
|
buildVariantString(options) {
|
|
147
|
-
const parts = [
|
|
171
|
+
const parts = [];
|
|
172
|
+
if (options.width != null && options.height != null) {
|
|
173
|
+
parts.push(`${options.width}x${options.height}`);
|
|
174
|
+
}
|
|
175
|
+
if (options.resizeType != null) {
|
|
176
|
+
parts.push(options.resizeType);
|
|
177
|
+
}
|
|
148
178
|
if (options.quality != null) {
|
|
149
179
|
parts.push(`q${options.quality}`);
|
|
150
180
|
}
|
|
151
181
|
return parts.join("-");
|
|
152
182
|
}
|
|
153
183
|
validateImageOptions(options) {
|
|
154
|
-
if (
|
|
155
|
-
|
|
184
|
+
if (options.width != null) {
|
|
185
|
+
if (!Number.isInteger(options.width) || options.width < 1 || options.width > 4096) {
|
|
186
|
+
throw new Error(`Invalid width: ${options.width}. Must be an integer between 1 and 4096.`);
|
|
187
|
+
}
|
|
156
188
|
}
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
189
|
+
if (options.height != null) {
|
|
190
|
+
if (!Number.isInteger(options.height) || options.height < 1 || options.height > 4096) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`Invalid height: ${options.height}. Must be an integer between 1 and 4096.`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
161
195
|
}
|
|
162
196
|
if (options.quality != null) {
|
|
163
197
|
if (!Number.isInteger(options.quality) || options.quality < 1 || options.quality > 100) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/sproux-media.ts"],"sourcesContent":["// Constants\r\nexport {\r\n MEDIA_TYPE,\r\n MEDIA_PURPOSE,\r\n MEDIA_STATUS,\r\n IMAGE_FORMAT,\r\n IMAGE_RESIZE_TYPE,\r\n R2_PATH,\r\n MEDIA_DEFAULTS,\r\n} from './constants';\r\n\r\n// Types\r\nexport type { ImageFormat, ImageResizeType, SprouxMediaConfig, ImageUrlOptions } from './types';\r\n\r\n// Singleton class\r\nexport { SprouxMedia } from './sproux-media';\r\n","// ============================================================================\r\n// MEDIA TYPE\r\n// ============================================================================\r\n\r\nexport const MEDIA_TYPE = {\r\n IMAGE: 'image',\r\n VIDEO: 'video',\r\n} as const;\r\n\r\n// ============================================================================\r\n// MEDIA PURPOSE\r\n// ============================================================================\r\n\r\nexport const MEDIA_PURPOSE = {\r\n AVATAR: 'avatar',\r\n HERO: 'hero',\r\n GALLERY: 'gallery',\r\n} as const;\r\n\r\n// ============================================================================\r\n// MEDIA STATUS\r\n// ============================================================================\r\n\r\nexport const MEDIA_STATUS = {\r\n PENDING: 'pending',\r\n UPLOADED: 'uploaded',\r\n PROCESSING: 'processing',\r\n READY: 'ready',\r\n ERROR: 'error',\r\n} as const;\r\n\r\n// ============================================================================\r\n// IMAGE FORMAT\r\n// ============================================================================\r\n\r\nexport enum IMAGE_FORMAT {\r\n WEBP = 'webp',\r\n AVIF = 'avif',\r\n JPEG = 'jpeg',\r\n PNG = 'png',\r\n GIF = 'gif',\r\n ICO = 'ico',\r\n SVG = 'svg',\r\n JPG = 'jpg',\r\n}\r\n\r\n// ============================================================================\r\n// IMAGE RESIZE TYPE\r\n// ============================================================================\r\n\r\nexport enum IMAGE_RESIZE_TYPE {\r\n FIT = 'fit',\r\n FILL = 'fill',\r\n FORCE = 'force',\r\n FILL_DOWN = 'fill-down',\r\n AUTO = 'auto',\r\n}\r\n\r\n// ============================================================================\r\n// R2/CDN PATH CONSTANTS\r\n// ============================================================================\r\n\r\nexport const R2_PATH = {\r\n HLS_PLAYLIST: 'playlist.m3u8',\r\n THUMBNAIL: 'thumbnail.webp',\r\n} as const;\r\n\r\n// ============================================================================\r\n// DEFAULTS\r\n// ============================================================================\r\n\r\nexport const MEDIA_DEFAULTS = {\r\n IMAGE_FORMAT: IMAGE_FORMAT.WEBP,\r\n} as const;\r\n","import { R2_PATH } from './constants';\r\nimport type { SprouxMediaConfig, ImageUrlOptions } from './types';\r\n\r\nexport class SprouxMedia {\r\n private static instance: SprouxMedia | null = null;\r\n\r\n private readonly cdnUrl: string;\r\n\r\n private constructor(config: SprouxMediaConfig) {\r\n this.cdnUrl = config.cdnUrl.replace(/\\/+$/, '');\r\n }\r\n\r\n /**\r\n * Initialize the singleton with CDN configuration.\r\n * Returns the singleton instance.\r\n */\r\n static init(config: SprouxMediaConfig): SprouxMedia {\r\n if (SprouxMedia.instance) {\r\n return SprouxMedia.instance;\r\n }\r\n \r\n return (SprouxMedia.instance = new SprouxMedia(config));\r\n }\r\n\r\n /**\r\n * Returns the existing singleton instance.\r\n * Throws if `init()` has not been called.\r\n */\r\n static getInstance(): SprouxMedia {\r\n if (!SprouxMedia.instance) {\r\n throw new Error('SprouxMedia has not been initialized. Call SprouxMedia.init() first.');\r\n }\r\n return SprouxMedia.instance;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for an image variant.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"avatar/image/usr-1/abc\")\r\n * @param options - Image variant options including extension, dimensions, resize type, and optional quality\r\n * @returns Full CDN URL for the image variant\r\n *\r\n * @example\r\n * media.getImageUrl('avatar/image/usr-1/abc', {\r\n * extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,\r\n * });\r\n * // → \"https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp\"\r\n */\r\n getImageUrl(objectKey: string, options: ImageUrlOptions): string {\r\n this.validateImageOptions(options);\r\n const variant = this.buildVariantString(options);\r\n return `${this.cdnUrl}/${objectKey}-${variant}.${options.extension}`;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for a video HLS playlist.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"gallery/video/usr-1/xyz\")\r\n * @returns Full CDN URL for the HLS playlist\r\n */\r\n getVideoHlsUrl(objectKey: string): string {\r\n return `${this.cdnUrl}/${objectKey}/${R2_PATH.HLS_PLAYLIST}`;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for a video thumbnail.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"gallery/video/usr-1/xyz\")\r\n * @returns Full CDN URL for the thumbnail\r\n */\r\n getVideoThumbnailUrl(objectKey: string): string {\r\n return `${this.cdnUrl}/${objectKey}/${R2_PATH.THUMBNAIL}`;\r\n }\r\n\r\n /**\r\n * Build a deterministic variant string from image options.\r\n *\r\n * Format: {width}x{height}-{resizeType}[-q{quality}]\r\n */\r\n private buildVariantString(options: ImageUrlOptions): string {\r\n const parts: string[] = [`${options.width}x${options.height}`, options.resizeType];\r\n\r\n if (options.quality != null) {\r\n parts.push(`q${options.quality}`);\r\n }\r\n\r\n return parts.join('-');\r\n }\r\n\r\n private validateImageOptions(options: ImageUrlOptions): void {\r\n if (!Number.isInteger(options.width) || options.width < 1 || options.width > 4096) {\r\n throw new Error(`Invalid width: ${options.width}. Must be an integer between 1 and 4096.`);\r\n }\r\n\r\n if (!Number.isInteger(options.height) || options.height < 1 || options.height > 4096) {\r\n throw new Error(\r\n `Invalid height: ${options.height}. Must be an integer between 1 and 4096.`,\r\n );\r\n }\r\n\r\n if (options.quality != null) {\r\n if (!Number.isInteger(options.quality) || options.quality < 1 || options.quality > 100) {\r\n throw new Error(\r\n `Invalid quality: ${options.quality}. Must be an integer between 1 and 100.`,\r\n );\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["IMAGE_FORMAT","IMAGE_RESIZE_TYPE"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/sproux-media.ts"],"sourcesContent":["// Constants\r\nexport {\r\n MEDIA_TYPE,\r\n MEDIA_PURPOSE,\r\n MEDIA_STATUS,\r\n IMAGE_FORMAT,\r\n IMAGE_RESIZE_TYPE,\r\n R2_PATH,\r\n MEDIA_DEFAULTS,\r\n} from './constants';\r\n\r\n// Types\r\nexport type { ImageFormat, ImageResizeType, SprouxMediaConfig, ImageUrlOptions } from './types';\r\n\r\n// Singleton class\r\nexport { SprouxMedia } from './sproux-media';\r\n","// ============================================================================\r\n// MEDIA TYPE\r\n// ============================================================================\r\n\r\nexport const MEDIA_TYPE = {\r\n IMAGE: 'image',\r\n VIDEO: 'video',\r\n} as const;\r\n\r\n// ============================================================================\r\n// MEDIA PURPOSE\r\n// ============================================================================\r\n\r\nexport const MEDIA_PURPOSE = {\r\n AVATAR: 'avatar',\r\n HERO: 'hero',\r\n GALLERY: 'gallery',\r\n} as const;\r\n\r\n// ============================================================================\r\n// MEDIA STATUS\r\n// ============================================================================\r\n\r\nexport const MEDIA_STATUS = {\r\n PENDING: 'pending',\r\n UPLOADED: 'uploaded',\r\n PROCESSING: 'processing',\r\n READY: 'ready',\r\n ERROR: 'error',\r\n} as const;\r\n\r\n// ============================================================================\r\n// IMAGE FORMAT\r\n// ============================================================================\r\n\r\nexport enum IMAGE_FORMAT {\r\n WEBP = 'webp',\r\n AVIF = 'avif',\r\n JPEG = 'jpeg',\r\n PNG = 'png',\r\n GIF = 'gif',\r\n ICO = 'ico',\r\n SVG = 'svg',\r\n JPG = 'jpg',\r\n}\r\n\r\n// ============================================================================\r\n// IMAGE RESIZE TYPE\r\n// ============================================================================\r\n\r\nexport enum IMAGE_RESIZE_TYPE {\r\n FIT = 'fit',\r\n FILL = 'fill',\r\n FORCE = 'force',\r\n FILL_DOWN = 'fill-down',\r\n AUTO = 'auto',\r\n}\r\n\r\n// ============================================================================\r\n// R2/CDN PATH CONSTANTS\r\n// ============================================================================\r\n\r\nexport const R2_PATH = {\r\n HLS_PLAYLIST: 'playlist.m3u8',\r\n THUMBNAIL: 'thumbnail.webp',\r\n} as const;\r\n\r\n// ============================================================================\r\n// DEFAULTS\r\n// ============================================================================\r\n\r\nexport const MEDIA_DEFAULTS = {\r\n IMAGE_FORMAT: IMAGE_FORMAT.WEBP,\r\n} as const;\r\n","import { R2_PATH } from './constants';\r\nimport type { SprouxMediaConfig, ImageUrlOptions } from './types';\r\n\r\nexport class SprouxMedia {\r\n private static instance: SprouxMedia | null = null;\r\n\r\n private readonly cdnUrl: string;\r\n\r\n private constructor(config: SprouxMediaConfig) {\r\n this.cdnUrl = config.cdnUrl.replace(/\\/+$/, '');\r\n }\r\n\r\n /**\r\n * Initialize the singleton with CDN configuration.\r\n * Returns the singleton instance.\r\n */\r\n static init(config: SprouxMediaConfig): SprouxMedia {\r\n if (SprouxMedia.instance) {\r\n return SprouxMedia.instance;\r\n }\r\n \r\n return (SprouxMedia.instance = new SprouxMedia(config));\r\n }\r\n\r\n /**\r\n * Returns the existing singleton instance.\r\n * Throws if `init()` has not been called.\r\n */\r\n static getInstance(): SprouxMedia {\r\n if (!SprouxMedia.instance) {\r\n throw new Error('SprouxMedia has not been initialized. Call SprouxMedia.init() first.');\r\n }\r\n return SprouxMedia.instance;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for an image, optionally with variant transformation.\r\n *\r\n * @param objectKey - Object key with extension (e.g. \"avatar/image/usr-1/abc.jpg\")\r\n * @param options - Optional image variant options (extension, dimensions, resize type, quality)\r\n * @returns Full CDN URL — variant URL if options are provided, original URL otherwise\r\n *\r\n * @example\r\n * // With variant options\r\n * media.getImageUrl('avatar/image/usr-1/abc.jpg', {\r\n * extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,\r\n * });\r\n * // → \"https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp\"\r\n *\r\n * @example\r\n * // Without options — returns the original URL\r\n * media.getImageUrl('avatar/image/usr-1/abc.jpg');\r\n * // → \"https://cdn.example.com/avatar/image/usr-1/abc.jpg\"\r\n */\r\n getImageUrl(objectKey: string, options?: ImageUrlOptions): string {\r\n if (!options || Object.keys(options).length === 0) {\r\n return `${this.cdnUrl}/${objectKey}`;\r\n }\r\n\r\n this.validateImageOptions(options);\r\n\r\n const { name, extension: originalExt } = this.parseObjectKey(objectKey);\r\n const ext = options.extension ?? originalExt;\r\n const variant = this.buildVariantString(options);\r\n\r\n return variant\r\n ? `${this.cdnUrl}/${name}-${variant}.${ext}`\r\n : `${this.cdnUrl}/${objectKey}`;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for a video HLS playlist.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"gallery/video/usr-1/xyz\")\r\n * @returns Full CDN URL for the HLS playlist\r\n */\r\n getVideoHlsUrl(objectKey: string): string {\r\n return `${this.cdnUrl}/${objectKey}/${R2_PATH.HLS_PLAYLIST}`;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for a video thumbnail.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"gallery/video/usr-1/xyz\")\r\n * @returns Full CDN URL for the thumbnail\r\n */\r\n getVideoThumbnailUrl(objectKey: string): string {\r\n return `${this.cdnUrl}/${objectKey}/${R2_PATH.THUMBNAIL}`;\r\n }\r\n\r\n /**\r\n * Parse an object key into name (path without extension) and extension.\r\n */\r\n private parseObjectKey(objectKey: string): { name: string; extension: string } {\r\n const lastDot = objectKey.lastIndexOf('.');\r\n if (lastDot === -1) {\r\n return { name: objectKey, extension: '' };\r\n }\r\n return {\r\n name: objectKey.substring(0, lastDot),\r\n extension: objectKey.substring(lastDot + 1),\r\n };\r\n }\r\n\r\n /**\r\n * Build a deterministic variant string from image options.\r\n *\r\n * Format: {width}x{height}-{resizeType}[-q{quality}]\r\n */\r\n private buildVariantString(options: ImageUrlOptions): string {\r\n const parts: string[] = [];\r\n\r\n if (options.width != null && options.height != null) {\r\n parts.push(`${options.width}x${options.height}`);\r\n }\r\n\r\n if (options.resizeType != null) {\r\n parts.push(options.resizeType);\r\n }\r\n\r\n if (options.quality != null) {\r\n parts.push(`q${options.quality}`);\r\n }\r\n\r\n return parts.join('-');\r\n }\r\n\r\n private validateImageOptions(options: ImageUrlOptions): void {\r\n if (options.width != null) {\r\n if (!Number.isInteger(options.width) || options.width < 1 || options.width > 4096) {\r\n throw new Error(`Invalid width: ${options.width}. Must be an integer between 1 and 4096.`);\r\n }\r\n }\r\n\r\n if (options.height != null) {\r\n if (!Number.isInteger(options.height) || options.height < 1 || options.height > 4096) {\r\n throw new Error(\r\n `Invalid height: ${options.height}. Must be an integer between 1 and 4096.`,\r\n );\r\n }\r\n }\r\n\r\n if (options.quality != null) {\r\n if (!Number.isInteger(options.quality) || options.quality < 1 || options.quality > 100) {\r\n throw new Error(\r\n `Invalid quality: ${options.quality}. Must be an integer between 1 and 100.`,\r\n );\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["IMAGE_FORMAT","IMAGE_RESIZE_TYPE"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -47,13 +47,13 @@ interface SprouxMediaConfig {
|
|
|
47
47
|
}
|
|
48
48
|
interface ImageUrlOptions {
|
|
49
49
|
/** Output format extension (e.g. "webp", "avif") */
|
|
50
|
-
extension
|
|
50
|
+
extension?: ImageFormat;
|
|
51
51
|
/** Target width in pixels (1-4096) */
|
|
52
|
-
width
|
|
52
|
+
width?: number;
|
|
53
53
|
/** Target height in pixels (1-4096) */
|
|
54
|
-
height
|
|
54
|
+
height?: number;
|
|
55
55
|
/** Resize type: fit, fill, auto */
|
|
56
|
-
resizeType
|
|
56
|
+
resizeType?: ImageResizeType;
|
|
57
57
|
/** Quality 1-100 (optional) */
|
|
58
58
|
quality?: number;
|
|
59
59
|
}
|
|
@@ -73,19 +73,25 @@ declare class SprouxMedia {
|
|
|
73
73
|
*/
|
|
74
74
|
static getInstance(): SprouxMedia;
|
|
75
75
|
/**
|
|
76
|
-
* Build a CDN URL for an image variant.
|
|
76
|
+
* Build a CDN URL for an image, optionally with variant transformation.
|
|
77
77
|
*
|
|
78
|
-
* @param objectKey - Object key
|
|
79
|
-
* @param options -
|
|
80
|
-
* @returns Full CDN URL
|
|
78
|
+
* @param objectKey - Object key with extension (e.g. "avatar/image/usr-1/abc.jpg")
|
|
79
|
+
* @param options - Optional image variant options (extension, dimensions, resize type, quality)
|
|
80
|
+
* @returns Full CDN URL — variant URL if options are provided, original URL otherwise
|
|
81
81
|
*
|
|
82
82
|
* @example
|
|
83
|
-
*
|
|
83
|
+
* // With variant options
|
|
84
|
+
* media.getImageUrl('avatar/image/usr-1/abc.jpg', {
|
|
84
85
|
* extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,
|
|
85
86
|
* });
|
|
86
87
|
* // → "https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp"
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* // Without options — returns the original URL
|
|
91
|
+
* media.getImageUrl('avatar/image/usr-1/abc.jpg');
|
|
92
|
+
* // → "https://cdn.example.com/avatar/image/usr-1/abc.jpg"
|
|
87
93
|
*/
|
|
88
|
-
getImageUrl(objectKey: string, options
|
|
94
|
+
getImageUrl(objectKey: string, options?: ImageUrlOptions): string;
|
|
89
95
|
/**
|
|
90
96
|
* Build a CDN URL for a video HLS playlist.
|
|
91
97
|
*
|
|
@@ -100,6 +106,10 @@ declare class SprouxMedia {
|
|
|
100
106
|
* @returns Full CDN URL for the thumbnail
|
|
101
107
|
*/
|
|
102
108
|
getVideoThumbnailUrl(objectKey: string): string;
|
|
109
|
+
/**
|
|
110
|
+
* Parse an object key into name (path without extension) and extension.
|
|
111
|
+
*/
|
|
112
|
+
private parseObjectKey;
|
|
103
113
|
/**
|
|
104
114
|
* Build a deterministic variant string from image options.
|
|
105
115
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -47,13 +47,13 @@ interface SprouxMediaConfig {
|
|
|
47
47
|
}
|
|
48
48
|
interface ImageUrlOptions {
|
|
49
49
|
/** Output format extension (e.g. "webp", "avif") */
|
|
50
|
-
extension
|
|
50
|
+
extension?: ImageFormat;
|
|
51
51
|
/** Target width in pixels (1-4096) */
|
|
52
|
-
width
|
|
52
|
+
width?: number;
|
|
53
53
|
/** Target height in pixels (1-4096) */
|
|
54
|
-
height
|
|
54
|
+
height?: number;
|
|
55
55
|
/** Resize type: fit, fill, auto */
|
|
56
|
-
resizeType
|
|
56
|
+
resizeType?: ImageResizeType;
|
|
57
57
|
/** Quality 1-100 (optional) */
|
|
58
58
|
quality?: number;
|
|
59
59
|
}
|
|
@@ -73,19 +73,25 @@ declare class SprouxMedia {
|
|
|
73
73
|
*/
|
|
74
74
|
static getInstance(): SprouxMedia;
|
|
75
75
|
/**
|
|
76
|
-
* Build a CDN URL for an image variant.
|
|
76
|
+
* Build a CDN URL for an image, optionally with variant transformation.
|
|
77
77
|
*
|
|
78
|
-
* @param objectKey - Object key
|
|
79
|
-
* @param options -
|
|
80
|
-
* @returns Full CDN URL
|
|
78
|
+
* @param objectKey - Object key with extension (e.g. "avatar/image/usr-1/abc.jpg")
|
|
79
|
+
* @param options - Optional image variant options (extension, dimensions, resize type, quality)
|
|
80
|
+
* @returns Full CDN URL — variant URL if options are provided, original URL otherwise
|
|
81
81
|
*
|
|
82
82
|
* @example
|
|
83
|
-
*
|
|
83
|
+
* // With variant options
|
|
84
|
+
* media.getImageUrl('avatar/image/usr-1/abc.jpg', {
|
|
84
85
|
* extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,
|
|
85
86
|
* });
|
|
86
87
|
* // → "https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp"
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* // Without options — returns the original URL
|
|
91
|
+
* media.getImageUrl('avatar/image/usr-1/abc.jpg');
|
|
92
|
+
* // → "https://cdn.example.com/avatar/image/usr-1/abc.jpg"
|
|
87
93
|
*/
|
|
88
|
-
getImageUrl(objectKey: string, options
|
|
94
|
+
getImageUrl(objectKey: string, options?: ImageUrlOptions): string;
|
|
89
95
|
/**
|
|
90
96
|
* Build a CDN URL for a video HLS playlist.
|
|
91
97
|
*
|
|
@@ -100,6 +106,10 @@ declare class SprouxMedia {
|
|
|
100
106
|
* @returns Full CDN URL for the thumbnail
|
|
101
107
|
*/
|
|
102
108
|
getVideoThumbnailUrl(objectKey: string): string;
|
|
109
|
+
/**
|
|
110
|
+
* Parse an object key into name (path without extension) and extension.
|
|
111
|
+
*/
|
|
112
|
+
private parseObjectKey;
|
|
103
113
|
/**
|
|
104
114
|
* Build a deterministic variant string from image options.
|
|
105
115
|
*
|
package/dist/index.js
CHANGED
|
@@ -70,22 +70,33 @@ var SprouxMedia = class _SprouxMedia {
|
|
|
70
70
|
return _SprouxMedia.instance;
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
|
-
* Build a CDN URL for an image variant.
|
|
73
|
+
* Build a CDN URL for an image, optionally with variant transformation.
|
|
74
74
|
*
|
|
75
|
-
* @param objectKey - Object key
|
|
76
|
-
* @param options -
|
|
77
|
-
* @returns Full CDN URL
|
|
75
|
+
* @param objectKey - Object key with extension (e.g. "avatar/image/usr-1/abc.jpg")
|
|
76
|
+
* @param options - Optional image variant options (extension, dimensions, resize type, quality)
|
|
77
|
+
* @returns Full CDN URL — variant URL if options are provided, original URL otherwise
|
|
78
78
|
*
|
|
79
79
|
* @example
|
|
80
|
-
*
|
|
80
|
+
* // With variant options
|
|
81
|
+
* media.getImageUrl('avatar/image/usr-1/abc.jpg', {
|
|
81
82
|
* extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,
|
|
82
83
|
* });
|
|
83
84
|
* // → "https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp"
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* // Without options — returns the original URL
|
|
88
|
+
* media.getImageUrl('avatar/image/usr-1/abc.jpg');
|
|
89
|
+
* // → "https://cdn.example.com/avatar/image/usr-1/abc.jpg"
|
|
84
90
|
*/
|
|
85
91
|
getImageUrl(objectKey, options) {
|
|
92
|
+
if (!options || Object.keys(options).length === 0) {
|
|
93
|
+
return `${this.cdnUrl}/${objectKey}`;
|
|
94
|
+
}
|
|
86
95
|
this.validateImageOptions(options);
|
|
96
|
+
const { name, extension: originalExt } = this.parseObjectKey(objectKey);
|
|
97
|
+
const ext = options.extension ?? originalExt;
|
|
87
98
|
const variant = this.buildVariantString(options);
|
|
88
|
-
return `${this.cdnUrl}/${
|
|
99
|
+
return variant ? `${this.cdnUrl}/${name}-${variant}.${ext}` : `${this.cdnUrl}/${objectKey}`;
|
|
89
100
|
}
|
|
90
101
|
/**
|
|
91
102
|
* Build a CDN URL for a video HLS playlist.
|
|
@@ -105,26 +116,49 @@ var SprouxMedia = class _SprouxMedia {
|
|
|
105
116
|
getVideoThumbnailUrl(objectKey) {
|
|
106
117
|
return `${this.cdnUrl}/${objectKey}/${R2_PATH.THUMBNAIL}`;
|
|
107
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Parse an object key into name (path without extension) and extension.
|
|
121
|
+
*/
|
|
122
|
+
parseObjectKey(objectKey) {
|
|
123
|
+
const lastDot = objectKey.lastIndexOf(".");
|
|
124
|
+
if (lastDot === -1) {
|
|
125
|
+
return { name: objectKey, extension: "" };
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
name: objectKey.substring(0, lastDot),
|
|
129
|
+
extension: objectKey.substring(lastDot + 1)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
108
132
|
/**
|
|
109
133
|
* Build a deterministic variant string from image options.
|
|
110
134
|
*
|
|
111
135
|
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
112
136
|
*/
|
|
113
137
|
buildVariantString(options) {
|
|
114
|
-
const parts = [
|
|
138
|
+
const parts = [];
|
|
139
|
+
if (options.width != null && options.height != null) {
|
|
140
|
+
parts.push(`${options.width}x${options.height}`);
|
|
141
|
+
}
|
|
142
|
+
if (options.resizeType != null) {
|
|
143
|
+
parts.push(options.resizeType);
|
|
144
|
+
}
|
|
115
145
|
if (options.quality != null) {
|
|
116
146
|
parts.push(`q${options.quality}`);
|
|
117
147
|
}
|
|
118
148
|
return parts.join("-");
|
|
119
149
|
}
|
|
120
150
|
validateImageOptions(options) {
|
|
121
|
-
if (
|
|
122
|
-
|
|
151
|
+
if (options.width != null) {
|
|
152
|
+
if (!Number.isInteger(options.width) || options.width < 1 || options.width > 4096) {
|
|
153
|
+
throw new Error(`Invalid width: ${options.width}. Must be an integer between 1 and 4096.`);
|
|
154
|
+
}
|
|
123
155
|
}
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
156
|
+
if (options.height != null) {
|
|
157
|
+
if (!Number.isInteger(options.height) || options.height < 1 || options.height > 4096) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Invalid height: ${options.height}. Must be an integer between 1 and 4096.`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
128
162
|
}
|
|
129
163
|
if (options.quality != null) {
|
|
130
164
|
if (!Number.isInteger(options.quality) || options.quality < 1 || options.quality > 100) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/sproux-media.ts"],"sourcesContent":["// ============================================================================\r\n// MEDIA TYPE\r\n// ============================================================================\r\n\r\nexport const MEDIA_TYPE = {\r\n IMAGE: 'image',\r\n VIDEO: 'video',\r\n} as const;\r\n\r\n// ============================================================================\r\n// MEDIA PURPOSE\r\n// ============================================================================\r\n\r\nexport const MEDIA_PURPOSE = {\r\n AVATAR: 'avatar',\r\n HERO: 'hero',\r\n GALLERY: 'gallery',\r\n} as const;\r\n\r\n// ============================================================================\r\n// MEDIA STATUS\r\n// ============================================================================\r\n\r\nexport const MEDIA_STATUS = {\r\n PENDING: 'pending',\r\n UPLOADED: 'uploaded',\r\n PROCESSING: 'processing',\r\n READY: 'ready',\r\n ERROR: 'error',\r\n} as const;\r\n\r\n// ============================================================================\r\n// IMAGE FORMAT\r\n// ============================================================================\r\n\r\nexport enum IMAGE_FORMAT {\r\n WEBP = 'webp',\r\n AVIF = 'avif',\r\n JPEG = 'jpeg',\r\n PNG = 'png',\r\n GIF = 'gif',\r\n ICO = 'ico',\r\n SVG = 'svg',\r\n JPG = 'jpg',\r\n}\r\n\r\n// ============================================================================\r\n// IMAGE RESIZE TYPE\r\n// ============================================================================\r\n\r\nexport enum IMAGE_RESIZE_TYPE {\r\n FIT = 'fit',\r\n FILL = 'fill',\r\n FORCE = 'force',\r\n FILL_DOWN = 'fill-down',\r\n AUTO = 'auto',\r\n}\r\n\r\n// ============================================================================\r\n// R2/CDN PATH CONSTANTS\r\n// ============================================================================\r\n\r\nexport const R2_PATH = {\r\n HLS_PLAYLIST: 'playlist.m3u8',\r\n THUMBNAIL: 'thumbnail.webp',\r\n} as const;\r\n\r\n// ============================================================================\r\n// DEFAULTS\r\n// ============================================================================\r\n\r\nexport const MEDIA_DEFAULTS = {\r\n IMAGE_FORMAT: IMAGE_FORMAT.WEBP,\r\n} as const;\r\n","import { R2_PATH } from './constants';\r\nimport type { SprouxMediaConfig, ImageUrlOptions } from './types';\r\n\r\nexport class SprouxMedia {\r\n private static instance: SprouxMedia | null = null;\r\n\r\n private readonly cdnUrl: string;\r\n\r\n private constructor(config: SprouxMediaConfig) {\r\n this.cdnUrl = config.cdnUrl.replace(/\\/+$/, '');\r\n }\r\n\r\n /**\r\n * Initialize the singleton with CDN configuration.\r\n * Returns the singleton instance.\r\n */\r\n static init(config: SprouxMediaConfig): SprouxMedia {\r\n if (SprouxMedia.instance) {\r\n return SprouxMedia.instance;\r\n }\r\n \r\n return (SprouxMedia.instance = new SprouxMedia(config));\r\n }\r\n\r\n /**\r\n * Returns the existing singleton instance.\r\n * Throws if `init()` has not been called.\r\n */\r\n static getInstance(): SprouxMedia {\r\n if (!SprouxMedia.instance) {\r\n throw new Error('SprouxMedia has not been initialized. Call SprouxMedia.init() first.');\r\n }\r\n return SprouxMedia.instance;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for an image variant.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"avatar/image/usr-1/abc\")\r\n * @param options - Image variant options including extension, dimensions, resize type, and optional quality\r\n * @returns Full CDN URL for the image variant\r\n *\r\n * @example\r\n * media.getImageUrl('avatar/image/usr-1/abc', {\r\n * extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,\r\n * });\r\n * // → \"https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp\"\r\n */\r\n getImageUrl(objectKey: string, options: ImageUrlOptions): string {\r\n this.validateImageOptions(options);\r\n const variant = this.buildVariantString(options);\r\n return `${this.cdnUrl}/${objectKey}-${variant}.${options.extension}`;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for a video HLS playlist.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"gallery/video/usr-1/xyz\")\r\n * @returns Full CDN URL for the HLS playlist\r\n */\r\n getVideoHlsUrl(objectKey: string): string {\r\n return `${this.cdnUrl}/${objectKey}/${R2_PATH.HLS_PLAYLIST}`;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for a video thumbnail.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"gallery/video/usr-1/xyz\")\r\n * @returns Full CDN URL for the thumbnail\r\n */\r\n getVideoThumbnailUrl(objectKey: string): string {\r\n return `${this.cdnUrl}/${objectKey}/${R2_PATH.THUMBNAIL}`;\r\n }\r\n\r\n /**\r\n * Build a deterministic variant string from image options.\r\n *\r\n * Format: {width}x{height}-{resizeType}[-q{quality}]\r\n */\r\n private buildVariantString(options: ImageUrlOptions): string {\r\n const parts: string[] = [`${options.width}x${options.height}`, options.resizeType];\r\n\r\n if (options.quality != null) {\r\n parts.push(`q${options.quality}`);\r\n }\r\n\r\n return parts.join('-');\r\n }\r\n\r\n private validateImageOptions(options: ImageUrlOptions): void {\r\n if (!Number.isInteger(options.width) || options.width < 1 || options.width > 4096) {\r\n throw new Error(`Invalid width: ${options.width}. Must be an integer between 1 and 4096.`);\r\n }\r\n\r\n if (!Number.isInteger(options.height) || options.height < 1 || options.height > 4096) {\r\n throw new Error(\r\n `Invalid height: ${options.height}. Must be an integer between 1 and 4096.`,\r\n );\r\n }\r\n\r\n if (options.quality != null) {\r\n if (!Number.isInteger(options.quality) || options.quality < 1 || options.quality > 100) {\r\n throw new Error(\r\n `Invalid quality: ${options.quality}. Must be an integer between 1 and 100.`,\r\n );\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["IMAGE_FORMAT","IMAGE_RESIZE_TYPE"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/sproux-media.ts"],"sourcesContent":["// ============================================================================\r\n// MEDIA TYPE\r\n// ============================================================================\r\n\r\nexport const MEDIA_TYPE = {\r\n IMAGE: 'image',\r\n VIDEO: 'video',\r\n} as const;\r\n\r\n// ============================================================================\r\n// MEDIA PURPOSE\r\n// ============================================================================\r\n\r\nexport const MEDIA_PURPOSE = {\r\n AVATAR: 'avatar',\r\n HERO: 'hero',\r\n GALLERY: 'gallery',\r\n} as const;\r\n\r\n// ============================================================================\r\n// MEDIA STATUS\r\n// ============================================================================\r\n\r\nexport const MEDIA_STATUS = {\r\n PENDING: 'pending',\r\n UPLOADED: 'uploaded',\r\n PROCESSING: 'processing',\r\n READY: 'ready',\r\n ERROR: 'error',\r\n} as const;\r\n\r\n// ============================================================================\r\n// IMAGE FORMAT\r\n// ============================================================================\r\n\r\nexport enum IMAGE_FORMAT {\r\n WEBP = 'webp',\r\n AVIF = 'avif',\r\n JPEG = 'jpeg',\r\n PNG = 'png',\r\n GIF = 'gif',\r\n ICO = 'ico',\r\n SVG = 'svg',\r\n JPG = 'jpg',\r\n}\r\n\r\n// ============================================================================\r\n// IMAGE RESIZE TYPE\r\n// ============================================================================\r\n\r\nexport enum IMAGE_RESIZE_TYPE {\r\n FIT = 'fit',\r\n FILL = 'fill',\r\n FORCE = 'force',\r\n FILL_DOWN = 'fill-down',\r\n AUTO = 'auto',\r\n}\r\n\r\n// ============================================================================\r\n// R2/CDN PATH CONSTANTS\r\n// ============================================================================\r\n\r\nexport const R2_PATH = {\r\n HLS_PLAYLIST: 'playlist.m3u8',\r\n THUMBNAIL: 'thumbnail.webp',\r\n} as const;\r\n\r\n// ============================================================================\r\n// DEFAULTS\r\n// ============================================================================\r\n\r\nexport const MEDIA_DEFAULTS = {\r\n IMAGE_FORMAT: IMAGE_FORMAT.WEBP,\r\n} as const;\r\n","import { R2_PATH } from './constants';\r\nimport type { SprouxMediaConfig, ImageUrlOptions } from './types';\r\n\r\nexport class SprouxMedia {\r\n private static instance: SprouxMedia | null = null;\r\n\r\n private readonly cdnUrl: string;\r\n\r\n private constructor(config: SprouxMediaConfig) {\r\n this.cdnUrl = config.cdnUrl.replace(/\\/+$/, '');\r\n }\r\n\r\n /**\r\n * Initialize the singleton with CDN configuration.\r\n * Returns the singleton instance.\r\n */\r\n static init(config: SprouxMediaConfig): SprouxMedia {\r\n if (SprouxMedia.instance) {\r\n return SprouxMedia.instance;\r\n }\r\n \r\n return (SprouxMedia.instance = new SprouxMedia(config));\r\n }\r\n\r\n /**\r\n * Returns the existing singleton instance.\r\n * Throws if `init()` has not been called.\r\n */\r\n static getInstance(): SprouxMedia {\r\n if (!SprouxMedia.instance) {\r\n throw new Error('SprouxMedia has not been initialized. Call SprouxMedia.init() first.');\r\n }\r\n return SprouxMedia.instance;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for an image, optionally with variant transformation.\r\n *\r\n * @param objectKey - Object key with extension (e.g. \"avatar/image/usr-1/abc.jpg\")\r\n * @param options - Optional image variant options (extension, dimensions, resize type, quality)\r\n * @returns Full CDN URL — variant URL if options are provided, original URL otherwise\r\n *\r\n * @example\r\n * // With variant options\r\n * media.getImageUrl('avatar/image/usr-1/abc.jpg', {\r\n * extension: 'webp', width: 200, height: 200, resizeType: 'fit', quality: 80,\r\n * });\r\n * // → \"https://cdn.example.com/avatar/image/usr-1/abc-200x200-fit-q80.webp\"\r\n *\r\n * @example\r\n * // Without options — returns the original URL\r\n * media.getImageUrl('avatar/image/usr-1/abc.jpg');\r\n * // → \"https://cdn.example.com/avatar/image/usr-1/abc.jpg\"\r\n */\r\n getImageUrl(objectKey: string, options?: ImageUrlOptions): string {\r\n if (!options || Object.keys(options).length === 0) {\r\n return `${this.cdnUrl}/${objectKey}`;\r\n }\r\n\r\n this.validateImageOptions(options);\r\n\r\n const { name, extension: originalExt } = this.parseObjectKey(objectKey);\r\n const ext = options.extension ?? originalExt;\r\n const variant = this.buildVariantString(options);\r\n\r\n return variant\r\n ? `${this.cdnUrl}/${name}-${variant}.${ext}`\r\n : `${this.cdnUrl}/${objectKey}`;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for a video HLS playlist.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"gallery/video/usr-1/xyz\")\r\n * @returns Full CDN URL for the HLS playlist\r\n */\r\n getVideoHlsUrl(objectKey: string): string {\r\n return `${this.cdnUrl}/${objectKey}/${R2_PATH.HLS_PLAYLIST}`;\r\n }\r\n\r\n /**\r\n * Build a CDN URL for a video thumbnail.\r\n *\r\n * @param objectKey - Object key without extension (e.g. \"gallery/video/usr-1/xyz\")\r\n * @returns Full CDN URL for the thumbnail\r\n */\r\n getVideoThumbnailUrl(objectKey: string): string {\r\n return `${this.cdnUrl}/${objectKey}/${R2_PATH.THUMBNAIL}`;\r\n }\r\n\r\n /**\r\n * Parse an object key into name (path without extension) and extension.\r\n */\r\n private parseObjectKey(objectKey: string): { name: string; extension: string } {\r\n const lastDot = objectKey.lastIndexOf('.');\r\n if (lastDot === -1) {\r\n return { name: objectKey, extension: '' };\r\n }\r\n return {\r\n name: objectKey.substring(0, lastDot),\r\n extension: objectKey.substring(lastDot + 1),\r\n };\r\n }\r\n\r\n /**\r\n * Build a deterministic variant string from image options.\r\n *\r\n * Format: {width}x{height}-{resizeType}[-q{quality}]\r\n */\r\n private buildVariantString(options: ImageUrlOptions): string {\r\n const parts: string[] = [];\r\n\r\n if (options.width != null && options.height != null) {\r\n parts.push(`${options.width}x${options.height}`);\r\n }\r\n\r\n if (options.resizeType != null) {\r\n parts.push(options.resizeType);\r\n }\r\n\r\n if (options.quality != null) {\r\n parts.push(`q${options.quality}`);\r\n }\r\n\r\n return parts.join('-');\r\n }\r\n\r\n private validateImageOptions(options: ImageUrlOptions): void {\r\n if (options.width != null) {\r\n if (!Number.isInteger(options.width) || options.width < 1 || options.width > 4096) {\r\n throw new Error(`Invalid width: ${options.width}. Must be an integer between 1 and 4096.`);\r\n }\r\n }\r\n\r\n if (options.height != null) {\r\n if (!Number.isInteger(options.height) || options.height < 1 || options.height > 4096) {\r\n throw new Error(\r\n `Invalid height: ${options.height}. Must be an integer between 1 and 4096.`,\r\n );\r\n }\r\n }\r\n\r\n if (options.quality != null) {\r\n if (!Number.isInteger(options.quality) || options.quality < 1 || options.quality > 100) {\r\n throw new Error(\r\n `Invalid quality: ${options.quality}. Must be an integer between 1 and 100.`,\r\n );\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["IMAGE_FORMAT","IMAGE_RESIZE_TYPE"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sproux/media-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Media URL builder library for Sproux — build image variant URLs, video HLS playlist URLs, and thumbnails from original media URLs.",
|
|
5
5
|
"author": "Sproux",
|
|
6
6
|
"license": "MIT",
|