@sproux/media-sdk
v0.1.15
Published
Media URL builder library for Sproux — build image variant URLs, video HLS playlist URLs, and thumbnails from original media URLs.
Downloads
437
Maintainers
Readme
@sproux/media-sdk
Media URL builder library for Sproux — build image variant URLs, video HLS playlist URLs, thumbnails, and document URLs from object keys using a singleton pattern.
Installation
# npm
npm install @sproux/media-sdk
# pnpm
pnpm add @sproux/media-sdk
# yarn
yarn add @sproux/media-sdkObject Key Format
All object keys follow the format:
{purpose}/{asset-type}/{user-id}/{asset-id}/{sanitized-fileName}.{extension}Variant keys follow the format:
{purpose}/{asset-type}/{user-id}/{asset-id}/{sanitized-fileName}-{variant-key}.{extension}Examples:
avatar/image/usr-1/abc/my-photo.jpggallery/video/usr-1/abc/intro.mp4contract/document/usr-1/abc/contract-v2.pdfavatar/image/usr-1/abc/my-photo-w200-h200-fit-q80.webp(variant)
Quick Start
import { SprouxMedia, IMAGE_FORMAT, IMAGE_RESIZE_TYPE } from '@sproux/media-sdk';
// Initialize once (e.g. at app startup)
const media = SprouxMedia.init({ cdnUrl: 'https://cdn.example.com' });
// Build an image variant URL with all options
const imageUrl = media.getImageUrl('avatar/image/usr-1/abc/my-photo.jpg', {
format: IMAGE_FORMAT.WEBP,
width: 200,
height: 200,
resizeType: IMAGE_RESIZE_TYPE.FIT,
quality: 80,
});
// → "https://cdn.example.com/avatar/image/usr-1/abc/my-photo-w200-h200-fit-q80.webp"
// Width-only (height auto-scaled)
const widthOnly = media.getImageUrl('avatar/image/usr-1/abc/my-photo.jpg', {
format: IMAGE_FORMAT.WEBP,
width: 200,
resizeType: IMAGE_RESIZE_TYPE.FIT,
});
// → "https://cdn.example.com/avatar/image/usr-1/abc/my-photo-w200-fit.webp"
// Height-only (width auto-scaled)
const heightOnly = media.getImageUrl('avatar/image/usr-1/abc/my-photo.jpg', {
format: IMAGE_FORMAT.WEBP,
height: 300,
resizeType: IMAGE_RESIZE_TYPE.FIT,
});
// → "https://cdn.example.com/avatar/image/usr-1/abc/my-photo-h300-fit.webp"
// Or with just the object key (no variant transformation)
const originalUrl = media.getImageUrl('avatar/image/usr-1/abc/my-photo.jpg');
// → "https://cdn.example.com/avatar/image/usr-1/abc/my-photo.jpg"
// Determine the asset type from an object key
const imageType = SprouxMedia.determineObjectType('avatar/image/usr-1/abc/my-photo.jpg');
// → "image"
const videoType = SprouxMedia.determineObjectType('gallery/video/usr-1/abc/intro.mp4');
// → "video"
const documentType = SprouxMedia.determineObjectType('contract/document/usr-1/abc/contract-v2.pdf');
// → "document"
// Extract the asset ID
const assetId = SprouxMedia.getAssetId('avatar/image/usr-1/abc/my-photo.jpg');
// → "abc"
// Extract the file name
const fileName = SprouxMedia.getFileName('avatar/image/usr-1/abc/my-photo.jpg');
// → "my-photo.jpg"
// Build a document URL
const docUrl = media.getDocumentUrl('contract/document/usr-1/abc/contract-v2.pdf');
// → "https://cdn.example.com/contract/document/usr-1/abc/contract-v2.pdf"
// Build a video original URL
const videoUrl = media.getVideoOriginalUrl('gallery/video/usr-1/abc/intro.mp4');
// → "https://cdn.example.com/gallery/video/usr-1/abc/intro.mp4"
// Build a video HLS playlist URL
const hlsUrl = media.getVideoHlsUrl('gallery/video/usr-1/abc/intro.mp4');
// → "https://cdn.example.com/gallery/video/usr-1/abc/intro/playlist.m3u8"
// Build a video thumbnail URL
const thumbUrl = media.getVideoThumbnailUrl('gallery/video/usr-1/abc/intro.mp4');
// → "https://cdn.example.com/gallery/video/usr-1/abc/intro/thumbnail_5_0.jpg"Singleton Usage
import { SprouxMedia, IMAGE_FORMAT, IMAGE_RESIZE_TYPE } from '@sproux/media-sdk';
// Initialize once at startup
SprouxMedia.init({ cdnUrl: 'https://cdn.example.com' });
// Access from anywhere via getInstance()
const media = SprouxMedia.getInstance();
// With variant options (both dimensions)
const url = media.getImageUrl('avatar/image/usr-1/abc/photo.jpg', {
format: IMAGE_FORMAT.WEBP,
width: 400,
height: 300,
resizeType: IMAGE_RESIZE_TYPE.FILL,
});
// Without options — returns the original URL
const original = media.getImageUrl('avatar/image/usr-1/abc/photo.jpg');Calling
getInstance()beforeinit()will throw an error.
API Reference
SprouxMedia.init(config: SprouxMediaConfig): SprouxMedia
Initialize the singleton with CDN configuration. Returns the singleton instance.
const media = SprouxMedia.init({ cdnUrl: 'https://cdn.example.com' });SprouxMedia.getInstance(): SprouxMedia
Returns the existing singleton instance. Throws if init() has not been called.
media.getImageUrl(objectKey: string, options?: ImageUrlOptions): string
Build a CDN URL for an image variant. When options is omitted, returns the original CDN URL for the object key as-is.
objectKey— Object key with format (e.g."avatar/image/usr-1/abc/my-photo.jpg")options— Optional variant transformation options
import { IMAGE_FORMAT, IMAGE_RESIZE_TYPE } from '@sproux/media-sdk';
// With variant options (both dimensions)
media.getImageUrl('avatar/image/usr-1/abc/photo.jpg', {
format: IMAGE_FORMAT.WEBP,
width: 400,
height: 300,
resizeType: IMAGE_RESIZE_TYPE.FILL,
quality: 85,
});
// → "https://cdn.example.com/avatar/image/usr-1/abc/photo-w400-h300-fill-q85.webp"
// Width-only (height auto-scaled)
media.getImageUrl('avatar/image/usr-1/abc/photo.jpg', {
format: IMAGE_FORMAT.WEBP,
width: 400,
resizeType: IMAGE_RESIZE_TYPE.FIT,
});
// → "https://cdn.example.com/avatar/image/usr-1/abc/photo-w400-fit.webp"
// Height-only (width auto-scaled)
media.getImageUrl('avatar/image/usr-1/abc/photo.jpg', {
format: IMAGE_FORMAT.WEBP,
height: 300,
resizeType: IMAGE_RESIZE_TYPE.FIT,
});
// → "https://cdn.example.com/avatar/image/usr-1/abc/photo-h300-fit.webp"
// Without options — returns the original URL
media.getImageUrl('avatar/image/usr-1/abc/photo.jpg');
// → "https://cdn.example.com/avatar/image/usr-1/abc/photo.jpg"ImageUrlOptions
All fields are optional.
| Property | Type | Required | Description |
| -------------- | ------------------- | ---------- | --------------------------------------------------------------------------- |
| format | ImageFormat | No | Output format (webp, avif, jpeg, png, gif, ico, svg, jpg) |
| width | number | No | Target width in pixels (1–4096) |
| height | number | No | Target height in pixels (1–4096) |
| resizeType | ImageResizeType | No | Resize strategy:fit, fill, force, fill-down, auto |
| quality | number | No | Quality 1–100 |
media.getDocumentUrl(objectKey: string): string
Build a CDN URL for a document file from an object key.
media.getDocumentUrl('contract/document/usr-1/abc/contract-v2.pdf');
// → "https://cdn.example.com/contract/document/usr-1/abc/contract-v2.pdf"media.getVideoOriginalUrl(objectKey: string): string
Build the original CDN URL for a video from an object key.
media.getVideoOriginalUrl('gallery/video/usr-1/abc/intro.mp4');
// → "https://cdn.example.com/gallery/video/usr-1/abc/intro.mp4"media.getVideoHlsUrl(objectKey: string): string
Build an HLS playlist URL from an object key.
media.getVideoHlsUrl('gallery/video/usr-1/abc/intro.mp4');
// → "https://cdn.example.com/gallery/video/usr-1/abc/intro/playlist.m3u8"media.getVideoThumbnailUrl(objectKey: string): string
Build a thumbnail URL from an object key.
media.getVideoThumbnailUrl('gallery/video/usr-1/abc/intro.mp4');
// → "https://cdn.example.com/gallery/video/usr-1/abc/intro/thumbnail_5_0.jpg"SprouxMedia.determineObjectType(objectKey: string): AssetType | null
Determine the asset type ('image', 'video', or 'document') from an object key. Returns null if the asset-type segment is missing or does not match a known type.
Object key format: {purpose}/{asset-type}/{user-id}/{asset-id}/{sanitized-fileName}.{extension}
SprouxMedia.determineObjectType('avatar/image/usr-1/abc/my-photo.jpg');
// → "image"
SprouxMedia.determineObjectType('gallery/video/usr-1/abc/intro.mp4');
// → "video"
SprouxMedia.determineObjectType('invalid');
// → nullSprouxMedia.getAssetId(objectKey: string): string | null
Extract the asset ID from an object key. Returns null if the object key has fewer than 5 segments.
Object key format: {purpose}/{asset-type}/{user-id}/{asset-id}/{sanitized-fileName}.{extension}
SprouxMedia.getAssetId('avatar/image/usr-1/abc/my-photo.jpg');
// → "abc"
SprouxMedia.getAssetId('gallery/video/019b7297-f2da-702f-aaa3-612498436e02/019ca305-abe5-7b31-929b-4a1999aeaca1/intro.mp4');
// → "019ca305-abe5-7b31-929b-4a1999aeaca1"
SprouxMedia.getAssetId('invalid/key');
// → nullSprouxMedia.getFileName(objectKey: string): string | null
Extract the sanitized file name (with extension) from an object key. Returns null if the object key has fewer than 5 segments.
Object key format: {purpose}/{asset-type}/{user-id}/{asset-id}/{sanitized-fileName}.{extension}
SprouxMedia.getFileName('avatar/image/usr-1/abc/my-photo.jpg');
// → "my-photo.jpg"
SprouxMedia.getFileName('invalid/key');
// → nullEnums
Use the provided enums for type-safe image options:
import { ASSET_TYPE, IMAGE_FORMAT, IMAGE_RESIZE_TYPE, MEDIA_PURPOSE } from '@sproux/media-sdk';
// MEDIA_PURPOSE
MEDIA_PURPOSE.AVATAR // 'avatar'
MEDIA_PURPOSE.HERO // 'hero'
MEDIA_PURPOSE.GALLERY // 'gallery'
MEDIA_PURPOSE.DELIVERY_PROOF // 'delivery_proof'
MEDIA_PURPOSE.RESPONSE_DISPUTE_EVIDENCE // 'response_dispute_evidence'
MEDIA_PURPOSE.REPORT_EVIDENCE // 'report_evidence'
MEDIA_PURPOSE.DELIERY_UPDATE // 'delivery_update'
// ASSET_TYPE
ASSET_TYPE.IMAGE // 'image'
ASSET_TYPE.VIDEO // 'video'
ASSET_TYPE.DOCUMENT // 'document'
// IMAGE_FORMAT
IMAGE_FORMAT.WEBP // 'webp'
IMAGE_FORMAT.AVIF // 'avif'
IMAGE_FORMAT.JPEG // 'jpeg'
IMAGE_FORMAT.PNG // 'png'
IMAGE_FORMAT.GIF // 'gif'
IMAGE_FORMAT.ICO // 'ico'
IMAGE_FORMAT.SVG // 'svg'
IMAGE_FORMAT.JPG // 'jpg'
// IMAGE_RESIZE_TYPE
IMAGE_RESIZE_TYPE.FIT // 'fit'
IMAGE_RESIZE_TYPE.FILL // 'fill'
IMAGE_RESIZE_TYPE.FORCE // 'force'
IMAGE_RESIZE_TYPE.FILL_DOWN // 'fill-down'
IMAGE_RESIZE_TYPE.AUTO // 'auto'Types
import type {
AssetType, // 'image' | 'video' | 'document'
ImageFormat, // 'webp' | 'avif' | 'jpeg' | 'png' | 'gif' | 'ico' | 'svg' | 'jpg'
ImageResizeType, // 'fit' | 'fill' | 'force' | 'fill-down' | 'auto'
SprouxMediaConfig, // { cdnUrl: string }
ImageUrlOptions, // { format?, width?, height?, resizeType?, quality? }
} from '@sproux/media-sdk';
ImageFormatandImageResizeTypeare string union types derived from their respective enums. You can use either the enum values (IMAGE_FORMAT.WEBP) or raw strings ('webp').
Helper
buildVariantString(options: ImageUrlOptions): string | null
Build a deterministic variant string from image options. Returns null if no options are provided.
import { buildVariantString } from '@sproux/media-sdk';
const variant = buildVariantString({
width: 200,
height: 200,
resizeType: IMAGE_RESIZE_TYPE.FIT,
quality: 80,
}); // "w200-h200-fit-q80"
// Width-only
buildVariantString({ width: 200, resizeType: IMAGE_RESIZE_TYPE.FIT }); // "w200-fit"
// Height-only
buildVariantString({ height: 300, resizeType: IMAGE_RESIZE_TYPE.FIT }); // "h300-fit"
// Empty options
buildVariantString({}); // nullURL Structure
Object Key
{purpose}/{asset-type}/{user-id}/{asset-id}/{sanitized-fileName}.{extension}Image Variant URL
{cdnUrl}/{purpose}/{asset-type}/{user-id}/{asset-id}/{sanitized-fileName}-{variant-key}.{format}Examples:
- Both dimensions:
https://cdn.example.com/avatar/image/usr-1/abc/photo-w200-h200-fit-q80.webp - Width-only:
https://cdn.example.com/avatar/image/usr-1/abc/photo-w200-fit.webp - Height-only:
https://cdn.example.com/avatar/image/usr-1/abc/photo-h300-fit.webp
Document URL
{cdnUrl}/{objectKey}Video Original URL
{cdnUrl}/{objectKey}Video HLS URL
{cdnUrl}/{purpose}/{asset-type}/{user-id}/{asset-id}/{sanitized-fileName}/playlist.m3u8Video Thumbnail URL
{cdnUrl}/{purpose}/{asset-type}/{user-id}/{asset-id}/{sanitized-fileName}/thumbnail_5_0.jpgLicense
MIT
