@sproux/media-sdk 0.1.2 → 0.1.3
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 +20 -6
- package/dist/index.cjs +20 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -7
- package/dist/index.d.ts +8 -7
- package/dist/index.js +18 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,13 +113,14 @@ media.getImageUrl('avatar/image/usr-1/photo.jpg');
|
|
|
113
113
|
|
|
114
114
|
All fields are optional.
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
|
116
|
+
|
|
117
|
+
| Property | Type | Required | Description |
|
|
118
|
+
| -------------- | ------------------- | ---------- | --------------------------------------------------------------------------- |
|
|
118
119
|
| `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
|
|
122
|
-
| `quality` | `number` | No | Quality 1–100
|
|
120
|
+
| `width` | `number` | No | Target width in pixels (1–4096) |
|
|
121
|
+
| `height` | `number` | No | Target height in pixels (1–4096) |
|
|
122
|
+
| `resizeType` | `ImageResizeType` | No | Resize strategy:`fit`, `fill`, `force`, `fill-down`, `auto` |
|
|
123
|
+
| `quality` | `number` | No | Quality 1–100 |
|
|
123
124
|
|
|
124
125
|
### `media.getVideoHlsUrl(objectKey: string): string`
|
|
125
126
|
|
|
@@ -189,6 +190,19 @@ import type {
|
|
|
189
190
|
|
|
190
191
|
> `ImageFormat` and `ImageResizeType` are string union types derived from their respective enums. You can use either the enum values (`IMAGE_FORMAT.WEBP`) or raw strings (`'webp'`).
|
|
191
192
|
|
|
193
|
+
## Helper
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { buildVariantString } from '@sproux/media-sdk';
|
|
197
|
+
|
|
198
|
+
const variant = buildVariantString({
|
|
199
|
+
width: 200,
|
|
200
|
+
height: 200,
|
|
201
|
+
resizeType: IMAGE_RESIZE_TYPE.FIT,
|
|
202
|
+
quality: 80,
|
|
203
|
+
}); // 200x200-fit-q80
|
|
204
|
+
```
|
|
205
|
+
|
|
192
206
|
## URL Structure
|
|
193
207
|
|
|
194
208
|
### Image Variant URL
|
package/dist/index.cjs
CHANGED
|
@@ -27,7 +27,8 @@ __export(index_exports, {
|
|
|
27
27
|
MEDIA_STATUS: () => MEDIA_STATUS,
|
|
28
28
|
MEDIA_TYPE: () => MEDIA_TYPE,
|
|
29
29
|
R2_PATH: () => R2_PATH,
|
|
30
|
-
SprouxMedia: () => SprouxMedia
|
|
30
|
+
SprouxMedia: () => SprouxMedia,
|
|
31
|
+
buildVariantString: () => buildVariantString
|
|
31
32
|
});
|
|
32
33
|
module.exports = __toCommonJS(index_exports);
|
|
33
34
|
|
|
@@ -75,6 +76,21 @@ var MEDIA_DEFAULTS = {
|
|
|
75
76
|
IMAGE_FORMAT: "webp" /* WEBP */
|
|
76
77
|
};
|
|
77
78
|
|
|
79
|
+
// src/sproux-media.helper.ts
|
|
80
|
+
function buildVariantString(options) {
|
|
81
|
+
const parts = [];
|
|
82
|
+
if (options.width != null && options.height != null) {
|
|
83
|
+
parts.push(`${options.width}x${options.height}`);
|
|
84
|
+
}
|
|
85
|
+
if (options.resizeType != null) {
|
|
86
|
+
parts.push(options.resizeType);
|
|
87
|
+
}
|
|
88
|
+
if (options.quality != null) {
|
|
89
|
+
parts.push(`q${options.quality}`);
|
|
90
|
+
}
|
|
91
|
+
return parts.join("-");
|
|
92
|
+
}
|
|
93
|
+
|
|
78
94
|
// src/sproux-media.ts
|
|
79
95
|
var SprouxMedia = class _SprouxMedia {
|
|
80
96
|
static instance = null;
|
|
@@ -128,7 +144,7 @@ var SprouxMedia = class _SprouxMedia {
|
|
|
128
144
|
this.validateImageOptions(options);
|
|
129
145
|
const { name, extension: originalExt } = this.parseObjectKey(objectKey);
|
|
130
146
|
const ext = options.extension ?? originalExt;
|
|
131
|
-
const variant =
|
|
147
|
+
const variant = buildVariantString(options);
|
|
132
148
|
return variant ? `${this.cdnUrl}/${name}-${variant}.${ext}` : `${this.cdnUrl}/${objectKey}`;
|
|
133
149
|
}
|
|
134
150
|
/**
|
|
@@ -162,24 +178,6 @@ var SprouxMedia = class _SprouxMedia {
|
|
|
162
178
|
extension: objectKey.substring(lastDot + 1)
|
|
163
179
|
};
|
|
164
180
|
}
|
|
165
|
-
/**
|
|
166
|
-
* Build a deterministic variant string from image options.
|
|
167
|
-
*
|
|
168
|
-
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
169
|
-
*/
|
|
170
|
-
buildVariantString(options) {
|
|
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
|
-
}
|
|
178
|
-
if (options.quality != null) {
|
|
179
|
-
parts.push(`q${options.quality}`);
|
|
180
|
-
}
|
|
181
|
-
return parts.join("-");
|
|
182
|
-
}
|
|
183
181
|
validateImageOptions(options) {
|
|
184
182
|
if (options.width != null) {
|
|
185
183
|
if (!Number.isInteger(options.width) || options.width < 1 || options.width > 4096) {
|
|
@@ -211,6 +209,7 @@ var SprouxMedia = class _SprouxMedia {
|
|
|
211
209
|
MEDIA_STATUS,
|
|
212
210
|
MEDIA_TYPE,
|
|
213
211
|
R2_PATH,
|
|
214
|
-
SprouxMedia
|
|
212
|
+
SprouxMedia,
|
|
213
|
+
buildVariantString
|
|
215
214
|
});
|
|
216
215
|
//# sourceMappingURL=index.cjs.map
|
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, 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/sproux-media.helper.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// Helper functions\r\nexport { buildVariantString } from './sproux-media.helper';\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 { ImageUrlOptions } from \"./types\";\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 export function 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 }","import { R2_PATH } from './constants';\r\nimport { buildVariantString } from './sproux-media.helper';\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 = 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\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
|
@@ -110,13 +110,14 @@ declare class SprouxMedia {
|
|
|
110
110
|
* Parse an object key into name (path without extension) and extension.
|
|
111
111
|
*/
|
|
112
112
|
private parseObjectKey;
|
|
113
|
-
/**
|
|
114
|
-
* Build a deterministic variant string from image options.
|
|
115
|
-
*
|
|
116
|
-
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
117
|
-
*/
|
|
118
|
-
private buildVariantString;
|
|
119
113
|
private validateImageOptions;
|
|
120
114
|
}
|
|
121
115
|
|
|
122
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Build a deterministic variant string from image options.
|
|
118
|
+
*
|
|
119
|
+
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
120
|
+
*/
|
|
121
|
+
declare function buildVariantString(options: ImageUrlOptions): string;
|
|
122
|
+
|
|
123
|
+
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, buildVariantString };
|
package/dist/index.d.ts
CHANGED
|
@@ -110,13 +110,14 @@ declare class SprouxMedia {
|
|
|
110
110
|
* Parse an object key into name (path without extension) and extension.
|
|
111
111
|
*/
|
|
112
112
|
private parseObjectKey;
|
|
113
|
-
/**
|
|
114
|
-
* Build a deterministic variant string from image options.
|
|
115
|
-
*
|
|
116
|
-
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
117
|
-
*/
|
|
118
|
-
private buildVariantString;
|
|
119
113
|
private validateImageOptions;
|
|
120
114
|
}
|
|
121
115
|
|
|
122
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Build a deterministic variant string from image options.
|
|
118
|
+
*
|
|
119
|
+
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
120
|
+
*/
|
|
121
|
+
declare function buildVariantString(options: ImageUrlOptions): string;
|
|
122
|
+
|
|
123
|
+
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, buildVariantString };
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,21 @@ var MEDIA_DEFAULTS = {
|
|
|
42
42
|
IMAGE_FORMAT: "webp" /* WEBP */
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
// src/sproux-media.helper.ts
|
|
46
|
+
function buildVariantString(options) {
|
|
47
|
+
const parts = [];
|
|
48
|
+
if (options.width != null && options.height != null) {
|
|
49
|
+
parts.push(`${options.width}x${options.height}`);
|
|
50
|
+
}
|
|
51
|
+
if (options.resizeType != null) {
|
|
52
|
+
parts.push(options.resizeType);
|
|
53
|
+
}
|
|
54
|
+
if (options.quality != null) {
|
|
55
|
+
parts.push(`q${options.quality}`);
|
|
56
|
+
}
|
|
57
|
+
return parts.join("-");
|
|
58
|
+
}
|
|
59
|
+
|
|
45
60
|
// src/sproux-media.ts
|
|
46
61
|
var SprouxMedia = class _SprouxMedia {
|
|
47
62
|
static instance = null;
|
|
@@ -95,7 +110,7 @@ var SprouxMedia = class _SprouxMedia {
|
|
|
95
110
|
this.validateImageOptions(options);
|
|
96
111
|
const { name, extension: originalExt } = this.parseObjectKey(objectKey);
|
|
97
112
|
const ext = options.extension ?? originalExt;
|
|
98
|
-
const variant =
|
|
113
|
+
const variant = buildVariantString(options);
|
|
99
114
|
return variant ? `${this.cdnUrl}/${name}-${variant}.${ext}` : `${this.cdnUrl}/${objectKey}`;
|
|
100
115
|
}
|
|
101
116
|
/**
|
|
@@ -129,24 +144,6 @@ var SprouxMedia = class _SprouxMedia {
|
|
|
129
144
|
extension: objectKey.substring(lastDot + 1)
|
|
130
145
|
};
|
|
131
146
|
}
|
|
132
|
-
/**
|
|
133
|
-
* Build a deterministic variant string from image options.
|
|
134
|
-
*
|
|
135
|
-
* Format: {width}x{height}-{resizeType}[-q{quality}]
|
|
136
|
-
*/
|
|
137
|
-
buildVariantString(options) {
|
|
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
|
-
}
|
|
145
|
-
if (options.quality != null) {
|
|
146
|
-
parts.push(`q${options.quality}`);
|
|
147
|
-
}
|
|
148
|
-
return parts.join("-");
|
|
149
|
-
}
|
|
150
147
|
validateImageOptions(options) {
|
|
151
148
|
if (options.width != null) {
|
|
152
149
|
if (!Number.isInteger(options.width) || options.width < 1 || options.width > 4096) {
|
|
@@ -177,6 +174,7 @@ export {
|
|
|
177
174
|
MEDIA_STATUS,
|
|
178
175
|
MEDIA_TYPE,
|
|
179
176
|
R2_PATH,
|
|
180
|
-
SprouxMedia
|
|
177
|
+
SprouxMedia,
|
|
178
|
+
buildVariantString
|
|
181
179
|
};
|
|
182
180
|
//# sourceMappingURL=index.js.map
|
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, 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/sproux-media.helper.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 { ImageUrlOptions } from \"./types\";\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 export function 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 }","import { R2_PATH } from './constants';\r\nimport { buildVariantString } from './sproux-media.helper';\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 = 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\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":";AAIO,IAAM,aAAa;AAAA,EACxB,OAAO;AAAA,EACP,OAAO;AACT;AAMO,IAAM,gBAAgB;AAAA,EAC3B,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AACX;AAMO,IAAM,eAAe;AAAA,EAC1B,SAAS;AAAA,EACT,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,OAAO;AACT;AAMO,IAAK,eAAL,kBAAKA,kBAAL;AACL,EAAAA,cAAA,UAAO;AACP,EAAAA,cAAA,UAAO;AACP,EAAAA,cAAA,UAAO;AACP,EAAAA,cAAA,SAAM;AACN,EAAAA,cAAA,SAAM;AACN,EAAAA,cAAA,SAAM;AACN,EAAAA,cAAA,SAAM;AACN,EAAAA,cAAA,SAAM;AARI,SAAAA;AAAA,GAAA;AAeL,IAAK,oBAAL,kBAAKC,uBAAL;AACL,EAAAA,mBAAA,SAAM;AACN,EAAAA,mBAAA,UAAO;AACP,EAAAA,mBAAA,WAAQ;AACR,EAAAA,mBAAA,eAAY;AACZ,EAAAA,mBAAA,UAAO;AALG,SAAAA;AAAA,GAAA;AAYL,IAAM,UAAU;AAAA,EACrB,cAAc;AAAA,EACd,WAAW;AACb;AAMO,IAAM,iBAAiB;AAAA,EAC5B,cAAc;AAChB;;;AClES,SAAS,mBAAmB,SAAkC;AACnE,QAAM,QAAkB,CAAC;AAEzB,MAAI,QAAQ,SAAS,QAAQ,QAAQ,UAAU,MAAM;AACnD,UAAM,KAAK,GAAG,QAAQ,KAAK,IAAI,QAAQ,MAAM,EAAE;AAAA,EACjD;AAEA,MAAI,QAAQ,cAAc,MAAM;AAC9B,UAAM,KAAK,QAAQ,UAAU;AAAA,EAC/B;AAEA,MAAI,QAAQ,WAAW,MAAM;AAC3B,UAAM,KAAK,IAAI,QAAQ,OAAO,EAAE;AAAA,EAClC;AAEA,SAAO,MAAM,KAAK,GAAG;AACvB;;;ACnBK,IAAM,cAAN,MAAM,aAAY;AAAA,EACvB,OAAe,WAA+B;AAAA,EAE7B;AAAA,EAET,YAAY,QAA2B;AAC7C,SAAK,SAAS,OAAO,OAAO,QAAQ,QAAQ,EAAE;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAK,QAAwC;AAClD,QAAI,aAAY,UAAU;AACxB,aAAO,aAAY;AAAA,IACrB;AAEA,WAAQ,aAAY,WAAW,IAAI,aAAY,MAAM;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,cAA2B;AAChC,QAAI,CAAC,aAAY,UAAU;AACzB,YAAM,IAAI,MAAM,sEAAsE;AAAA,IACxF;AACA,WAAO,aAAY;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,YAAY,WAAmB,SAAmC;AAChE,QAAI,CAAC,WAAW,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACjD,aAAO,GAAG,KAAK,MAAM,IAAI,SAAS;AAAA,IACpC;AAEA,SAAK,qBAAqB,OAAO;AAEjC,UAAM,EAAE,MAAM,WAAW,YAAY,IAAI,KAAK,eAAe,SAAS;AACtE,UAAM,MAAM,QAAQ,aAAa;AACjC,UAAM,UAAU,mBAAmB,OAAO;AAE1C,WAAO,UACH,GAAG,KAAK,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,GAAG,KACxC,GAAG,KAAK,MAAM,IAAI,SAAS;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,WAA2B;AACxC,WAAO,GAAG,KAAK,MAAM,IAAI,SAAS,IAAI,QAAQ,YAAY;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,qBAAqB,WAA2B;AAC9C,WAAO,GAAG,KAAK,MAAM,IAAI,SAAS,IAAI,QAAQ,SAAS;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,WAAwD;AAC7E,UAAM,UAAU,UAAU,YAAY,GAAG;AACzC,QAAI,YAAY,IAAI;AAClB,aAAO,EAAE,MAAM,WAAW,WAAW,GAAG;AAAA,IAC1C;AACA,WAAO;AAAA,MACL,MAAM,UAAU,UAAU,GAAG,OAAO;AAAA,MACpC,WAAW,UAAU,UAAU,UAAU,CAAC;AAAA,IAC5C;AAAA,EACF;AAAA,EAIQ,qBAAqB,SAAgC;AAC3D,QAAI,QAAQ,SAAS,MAAM;AACzB,UAAI,CAAC,OAAO,UAAU,QAAQ,KAAK,KAAK,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,MAAM;AACjF,cAAM,IAAI,MAAM,kBAAkB,QAAQ,KAAK,0CAA0C;AAAA,MAC3F;AAAA,IACF;AAEA,QAAI,QAAQ,UAAU,MAAM;AAC1B,UAAI,CAAC,OAAO,UAAU,QAAQ,MAAM,KAAK,QAAQ,SAAS,KAAK,QAAQ,SAAS,MAAM;AACpF,cAAM,IAAI;AAAA,UACR,mBAAmB,QAAQ,MAAM;AAAA,QACnC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,MAAM;AAC3B,UAAI,CAAC,OAAO,UAAU,QAAQ,OAAO,KAAK,QAAQ,UAAU,KAAK,QAAQ,UAAU,KAAK;AACtF,cAAM,IAAI;AAAA,UACR,oBAAoB,QAAQ,OAAO;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","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.3",
|
|
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",
|