@pixelfiddler/core 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -58,7 +58,7 @@ function calculatesCandidateWidths(params) {
58
58
  descriptor: "w"
59
59
  };
60
60
  }
61
- var createResponsiveAttributes = (config, options = {}) => {
61
+ var createResponsiveAttributes = (imageSrc, baseUrl, options) => {
62
62
  const {
63
63
  sizes,
64
64
  width,
@@ -67,7 +67,7 @@ var createResponsiveAttributes = (config, options = {}) => {
67
67
  transformations = {},
68
68
  mode = "short",
69
69
  maxDpr = DEFAULT_MAX_DPR
70
- } = options;
70
+ } = options || {};
71
71
  const baseWidth = transformations.width ?? width;
72
72
  const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);
73
73
  const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);
@@ -80,14 +80,20 @@ var createResponsiveAttributes = (config, options = {}) => {
80
80
  maxDpr
81
81
  });
82
82
  if (candidates.length === 0) {
83
- return { src: config.baseUrl };
83
+ return { src: getFinalUrl(imageSrc, baseUrl) };
84
84
  }
85
- const srcSetEntries = candidates.map((w, index) => buildSrcEntries(w, index, config, transformations, mode, descriptor));
85
+ const srcSetEntries = candidates.map((w, index) => buildSrcEntries(imageSrc, w, index, transformations, mode, descriptor, baseUrl));
86
86
  const largestWidth = candidates[candidates.length - 1];
87
87
  const src = buildTransformationUrl(
88
- config,
89
- { ...transformations, width: largestWidth },
90
- mode
88
+ {
89
+ src: imageSrc,
90
+ baseUrl,
91
+ transformations: {
92
+ ...transformations,
93
+ width: largestWidth
94
+ },
95
+ mode
96
+ }
91
97
  );
92
98
  const endSizes = sizes ?? (descriptor === "w" ? "100vw" : void 0);
93
99
  return {
@@ -97,11 +103,14 @@ var createResponsiveAttributes = (config, options = {}) => {
97
103
  ...width !== void 0 ? { width } : {}
98
104
  };
99
105
  };
100
- function buildSrcEntries(width, index, config, transformations, mode, descriptor) {
106
+ function buildSrcEntries(imageSrc, width, index, transformations, mode, descriptor, baseUrl) {
101
107
  const url = buildTransformationUrl(
102
- config,
103
- { ...transformations, width },
104
- mode
108
+ {
109
+ src: imageSrc,
110
+ baseUrl,
111
+ transformations: { ...transformations, width },
112
+ mode
113
+ }
105
114
  );
106
115
  const desc = descriptor === "w" ? `${width}w` : `${index + 1}x`;
107
116
  return `${url} ${desc}`;
@@ -123,6 +132,38 @@ var parseVW = (sizes) => {
123
132
  const foundSizes = sizes.match(/(\d+(?:\.\d+)?)vw/g) || [];
124
133
  return foundSizes.map((size) => parseInt(size, 10));
125
134
  };
135
+ var getBaseUrlWithoutQuery = (url) => {
136
+ if (!url) return "";
137
+ const queryIndex = url.indexOf("?");
138
+ return queryIndex === -1 ? url : url.slice(0, queryIndex);
139
+ };
140
+ var isAbsoluteUrl = (url) => {
141
+ if (!url) return false;
142
+ return url.startsWith("http://") || url.startsWith("https://");
143
+ };
144
+ function getFinalUrl(src, baseUrl) {
145
+ const cleanSrc = getBaseUrlWithoutQuery(src);
146
+ if (isAbsoluteUrl(cleanSrc)) {
147
+ return removeTrailingSlash(cleanSrc);
148
+ } else {
149
+ const base = removeTrailingSlash(getBaseUrlWithoutQuery(baseUrl));
150
+ const normalizedPath = normalizePath(cleanSrc);
151
+ return `${base}${normalizedPath}`;
152
+ }
153
+ }
154
+ function normalizePath(src) {
155
+ return src && !src.startsWith("/") ? `/${src}` : src;
156
+ }
157
+ var parseNumberLikeParam = (width) => {
158
+ if (typeof width === "number") {
159
+ return width;
160
+ }
161
+ const parsed = Number(width);
162
+ if (!Number.isFinite(parsed)) {
163
+ throw new Error(`Invalid width value: ${width}`);
164
+ }
165
+ return parsed;
166
+ };
126
167
 
127
168
  // src/config.ts
128
169
  var PARAMS = [
@@ -208,21 +249,18 @@ var buildTransformationQueryParams = (options, mode = "short") => {
208
249
  params.map(([k, v]) => [k, v])
209
250
  ).toString();
210
251
  };
211
- var getBaseUrlWithoutQuery = (url) => {
212
- const queryIndex = url.indexOf("?");
213
- return queryIndex === -1 ? url : url.slice(0, queryIndex);
214
- };
215
- var buildTransformationUrl = (config, options, mode = "short") => {
216
- const baseUrl = removeTrailingSlash(getBaseUrlWithoutQuery(config.baseUrl));
217
- if (options.original) {
218
- return `${baseUrl}?original`;
252
+ var buildTransformationUrl = ({ src, transformations = {}, baseUrl, mode = "short" }) => {
253
+ const url = getFinalUrl(src, baseUrl);
254
+ if (transformations.original) {
255
+ return `${url}?original`;
219
256
  }
220
- const query = buildTransformationQueryParams(options, mode);
221
- return `${baseUrl}?${query}`;
257
+ const query = buildTransformationQueryParams(transformations, mode);
258
+ return `${url}?${query}`;
222
259
  };
223
260
 
224
261
  exports.buildTransformationQueryParams = buildTransformationQueryParams;
225
262
  exports.buildTransformationUrl = buildTransformationUrl;
226
263
  exports.createResponsiveAttributes = createResponsiveAttributes;
264
+ exports.parseNumberLikeParam = parseNumberLikeParam;
227
265
  //# sourceMappingURL=index.cjs.map
228
266
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/src-set.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import { buildTransformationUrl, NameMode } from './url-builder';\r\nimport { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { clampMax, nearest, parseVW } from './utils';\r\n\r\n/**\r\n * Maximum supported image width\r\n */\r\nexport const MAX_IMAGE_WIDTH = 4096;\r\n\r\n/**\r\n * Default device breakpoints for responsive srcset generation\r\n */\r\nexport const DEFAULT_DEVICE_BREAKPOINTS = [\r\n 320,\r\n 375,\r\n 640,\r\n 768,\r\n 1024,\r\n 1280,\r\n 1536,\r\n 1920,\r\n 2048,\r\n 3840\r\n] as const;\r\n\r\n/**\r\n * Default image breakpoints for smaller images (icons, thumbnails)\r\n */\r\nexport const DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384] as const;\r\n\r\n/**\r\n * Options for responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageOptions {\r\n /**\r\n * The `sizes` attribute value (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * When provided, generates width descriptors (`w`) for responsive layouts.\r\n */\r\n sizes?: string;\r\n /**\r\n * Fixed display width in CSS pixels.\r\n * When provided without `sizes`, generates DPR descriptors (`x`).\r\n */\r\n width?: number;\r\n /** Device breakpoints for viewport-based sizing (default: DEFAULT_DEVICE_BREAKPOINTS) */\r\n deviceBreakpoints?: number[];\r\n /** Image breakpoints for smaller images (default: DEFAULT_IMAGE_BREAKPOINTS) */\r\n imageBreakpoints?: number[];\r\n /** Base transformation options to apply to all variants */\r\n transformations?: TransformationOptions;\r\n /** Whether to use short or long parameter names (default: 'short') */\r\n mode?: NameMode;\r\n maxDpr?: number\r\n}\r\n\r\n/**\r\n * Result of responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageResult {\r\n /** The src attribute value (largest/default variant) */\r\n src: string;\r\n /** The srcset attribute value */\r\n srcSet?: string;\r\n /** The sizes attribute value (for width descriptors) */\r\n sizes?: string;\r\n /** The width attribute value (when explicitly provided) */\r\n width?: number;\r\n}\r\n\r\n/**\r\n * Calculates candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction calculatesCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n maxDpr: number\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr,\r\n maxDpr\r\n } = params;\r\n\r\n if (!allBreakpoints.length || !deviceBreakpoints.length) {\r\n return { candidates: [], descriptor: 'w' };\r\n }\r\n\r\n const minDevice = deviceBreakpoints[0]!;\r\n const maxDevice = deviceBreakpoints[deviceBreakpoints.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n\r\n // When no sizes with vw definition is provided go for x descriptor\r\n if (explicitWidth && !hasVW) {\r\n const DPRs = [1, 2, 3, 4].filter(item => item <= maxDpr);\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(allBreakpoints, explicitWidth * dpr))\r\n .map(clampMax)\r\n )\r\n ).filter(w => w <= MAX_IMAGE_WIDTH);\r\n\r\n return {\r\n candidates,\r\n descriptor: 'x'\r\n };\r\n }\r\n\r\n\r\n // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const lowestRatio = Math.min(...vwRatios) / 100;\r\n const minRequiredPx = minDevice * lowestRatio;\r\n\r\n\r\n return {\r\n // Responsive layout only uses device breakpoints\r\n candidates: deviceBreakpoints.filter(w => w >= minRequiredPx && w <= MAX_IMAGE_WIDTH),\r\n descriptor: 'w',\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const upperLimit = maxDevice * maxDpr;\r\n\r\n return {\r\n candidates: allBreakpoints.filter(w => w <= upperLimit),\r\n descriptor: 'w'\r\n };\r\n}\r\n\r\n/**\r\n * Generates responsive image attributes (src, srcSet, sizes) for optimal loading.\r\n *\r\n * Supports two strategies:\r\n * 1. **Responsive (with `sizes`)**: Uses width descriptors (`w`) for fluid layouts\r\n * where image size varies with viewport.\r\n * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size\r\n * images that need high-DPI support.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - Options for responsive image generation\r\n * @returns Object containing src, srcSet, and optionally sizes attributes\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/photo.jpg' };\r\n *\r\n * // Responsive image with sizes attribute (uses `w` descriptors)\r\n * createResponsiveAttributes(config, { sizes: '(max-width: 768px) 100vw, 50vw' });\r\n * // => {\r\n * // src: '...?w=3840',\r\n * // srcSet: '...?w=640 640w, ...?w=750 750w, ..., ...?w=3840 3840w',\r\n * // sizes: '(max-width: 768px) 100vw, 50vw'\r\n * // }\r\n *\r\n * // Fixed-width image (uses `x` descriptors)\r\n * createResponsiveAttributes(config, { width: 400 });\r\n * // => {\r\n * // src: '...?w=384',\r\n * // srcSet: '...?w=384 1x, ...?w=828 2x',\r\n * // width: 400\r\n * // }\r\n *\r\n * // With transformations\r\n * createResponsiveAttributes(config, {\r\n * sizes: '100vw',\r\n * transformations: { format: 'WEBP', quality: 80 }\r\n * });\r\n * ```\r\n */\r\nexport const createResponsiveAttributes = (\r\n config: UrlBuilderConfig,\r\n options: ResponsiveImageOptions = {}\r\n): ResponsiveImageResult => {\r\n const {\r\n sizes,\r\n width,\r\n deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],\r\n imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],\r\n transformations = {},\r\n mode = 'short',\r\n maxDpr = DEFAULT_MAX_DPR\r\n } = options;\r\n\r\n // If transformations.width is set, it takes precedence as the base width\r\n const baseWidth = transformations.width ?? width;\r\n\r\n const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);\r\n const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);\r\n\r\n const allBreakpoints = [...new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);\r\n\r\n const { candidates, descriptor } = calculatesCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(baseWidth !== undefined && { explicitWidth: baseWidth }),\r\n ...(sizes !== undefined && { sizesAttr: sizes }),\r\n maxDpr\r\n });\r\n\r\n if (candidates.length === 0) {\r\n // Fallback: no valid candidates, return base URL\r\n return { src: config.baseUrl };\r\n }\r\n\r\n // Build srcSet entries\r\n const srcSetEntries = candidates.map((w, index,) => buildSrcEntries(w, index, config, transformations, mode, descriptor));\r\n\r\n // Default src is the largest candidate\r\n const largestWidth = candidates[candidates.length - 1]!;\r\n const src = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: largestWidth },\r\n mode\r\n );\r\n\r\n const endSizes = sizes ?? (descriptor === 'w' ? '100vw' : undefined);\r\n\r\n return {\r\n src,\r\n ...(endSizes ? { sizes: endSizes } : {}),\r\n srcSet: srcSetEntries.join(', '),\r\n ...(width !== undefined ? { width } : {}),\r\n };\r\n};\r\n\r\nfunction buildSrcEntries(width: number, index: number, config: UrlBuilderConfig, transformations: TransformationOptions, mode: NameMode, descriptor: 'w' | 'x'): string {\r\n const url = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: width },\r\n mode\r\n );\r\n\r\n const desc = descriptor === 'w' ? `${width}w` : `${index + 1}x`;\r\n\r\n return `${url} ${desc}`;\r\n}\r\n","import { Path, PathValue } from './util-types';\r\nimport { MAX_IMAGE_WIDTH } from './src-set';\r\n\r\nexport const normalizeHex = (value: string) => value.replace('#', '')\r\n\r\n\r\nexport const removeTrailingSlash = (baseUrl: string) => {\r\n return baseUrl.endsWith('/')\r\n ? baseUrl.slice(0, -1)\r\n : baseUrl;\r\n}\r\n\r\nexport const getNestedValue = <\r\n T,\r\n P extends Path<T>\r\n>(\r\n obj: T,\r\n path: P\r\n): PathValue<T, P> | undefined =>\r\n path.reduce<any>(\r\n (acc, key) => (acc == null ? undefined : acc[key]),\r\n obj\r\n );\r\n\r\n\r\nexport const clampMax = (v: number) => Math.min(v, MAX_IMAGE_WIDTH);\r\n\r\nexport const nearest = (sortedBreakpoints: number[],target: number) =>\r\n sortedBreakpoints.find(w => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1]!;\r\n\r\nexport const parseVW = (sizes?: string): number[] => {\r\n if (!sizes) return [];\r\n const foundSizes = sizes.match(/(\\d+(?:\\.\\d+)?)vw/g) || []\r\n\r\n return foundSizes.map((size) => parseInt(size, 10))\r\n};\r\n\r\n","import { ParamSpec, Path } from './util-types';\r\nimport { TransformationOptions } from './types';\r\nimport { normalizeHex } from './utils';\r\n\r\nexport const PARAMS = [\r\n {path: ['width'], long: 'width', short: 'w'},\r\n {path: ['height'], long: 'height', short: 'h'},\r\n {path: ['dpr'], long: 'dpr', short: 'dpr'},\r\n {path: ['mode'], long: 'mode', short: 'rm'},\r\n {\r\n path: ['background'],\r\n long: 'background',\r\n short: 'bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n\r\n {path: ['format'], long: 'format', short: 'f'},\r\n {path: ['quality'], long: 'quality', short: 'q'},\r\n {path: ['stripMetadata'], long: 'stripMetadata', short: 'st'},\r\n\r\n {path: ['blur'], long: 'blur', short: 'bl'},\r\n {path: ['brightness'], long: 'brightness', short: 'br'},\r\n {path: ['contrast'], long: 'contrast', short: 'ct'},\r\n {path: ['grayscale'], long: 'grayscale', short: 'gs'},\r\n {path: ['saturation'], long: 'saturation', short: 'sa'},\r\n {path: ['sepia'], long: 'sepia', short: 'sp'},\r\n {path: ['sharpen'], long: 'sharpen', short: 'sh'},\r\n {path: ['noise'], long: 'noise', short: 'ns'},\r\n {path: ['rotate'], long: 'rotate', short: 'rt'},\r\n\r\n {path: ['border', 'width'], long: 'border.width', short: 'bo.w'},\r\n {\r\n path: ['border', 'color'],\r\n long: 'border.color',\r\n short: 'bo.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['border', 'radius'], long: 'border.radius', short: 'bo.r'},\r\n\r\n {path: ['crop', 'type'], long: 'crop.type', short: 'cr.t'},\r\n {path: ['crop', 'objectType'], long: 'crop.objectType', short: 'cr.o'},\r\n {path: ['crop', 'focus', 'position', 'x'], long: 'crop.x', short: 'cr.x'},\r\n {path: ['crop', 'focus', 'position', 'y'], long: 'crop.y', short: 'cr.y'},\r\n {path: ['crop', 'focus', 'strategy'], long: 'crop', short: 'cr'},\r\n {path: ['crop', 'width'], long: 'crop.width', short: 'cr.w'},\r\n {path: ['crop', 'height'], long: 'crop.height', short: 'cr.h'},\r\n {path: ['crop', 'afterResize'], long: 'crop.afterResize', short: 'cr.ar'},\r\n\r\n {path: ['text', 'text'], long: 'text', short: 'tx'},\r\n {\r\n path: ['text', 'color'],\r\n long: 'text.color',\r\n short: 'tx.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'opacity'], long: 'text.opacity', short: 'tx.o'},\r\n {path: ['text', 'size'], long: 'text.size', short: 'tx.s'},\r\n {path: ['text', 'font'], long: 'text.font', short: 'tx.f'},\r\n {path: ['text', 'fontSize'], long: 'text.fontSize', short: 'tx.fs'},\r\n {path: ['text', 'position'], long: 'text.position', short: 'tx.p'},\r\n {\r\n path: ['text', 'background'],\r\n long: 'text.background',\r\n short: 'tx.bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'backgroundOpacity'], long: 'text.backgroundOpacity', short: 'tx.bg.o'},\r\n\r\n {path: ['watermark', 'name'], long: 'watermark', short: 'wm'},\r\n {path: ['watermark', 'opacity'], long: 'watermark.opacity', short: 'wm.o'},\r\n {path: ['watermark', 'size'], long: 'watermark.size', short: 'wm.s'},\r\n {path: ['watermark', 'width'], long: 'watermark.width', short: 'wm.w'},\r\n {path: ['watermark', 'height'], long: 'watermark.height', short: 'wm.h'},\r\n {path: ['watermark', 'position'], long: 'watermark.position', short: 'wm.p'},\r\n] as const satisfies readonly ParamSpec<\r\n TransformationOptions,\r\n Path<TransformationOptions>\r\n>[];\r\n","import { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { getNestedValue, removeTrailingSlash } from './utils';\r\nimport { PARAMS } from './config';\r\n\r\n/**\r\n * Determines which parameter names to use in the query string.\r\n * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)\r\n * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)\r\n */\r\nexport type NameMode = 'short' | 'long';\r\n\r\n/**\r\n * Converts transformation options into a URL-encoded query string.\r\n *\r\n * Iterates through all defined parameters in the PARAMS config, extracts values\r\n * from the options object using their paths, applies any normalization functions\r\n * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.\r\n *\r\n * @param options - The transformation options object\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns URL-encoded query string (without leading `?`)\r\n *\r\n * @example\r\n * ```ts\r\n * // Using short aliases (default)\r\n * buildQueryParams({ width: 800, height: 600, quality: 80 });\r\n * // => 'w=800&h=600&q=80'\r\n *\r\n * // Using long parameter names\r\n * buildQueryParams({ width: 800, format: 'webp' }, 'long');\r\n * // => 'width=800&format=webp'\r\n *\r\n * // Nested options\r\n * buildQueryParams({ border: { width: 2, color: '#ff0000' } });\r\n * // => 'bo.w=2&bo.c=ff0000'\r\n * ```\r\n */\r\nexport const buildTransformationQueryParams = (\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n): string => {\r\n const params: Array<[string, string]> = [];\r\n\r\n for (const spec of PARAMS) {\r\n const value = getNestedValue(options, spec.path);\r\n if (value == null) continue;\r\n\r\n const name =\r\n mode === 'short' && spec.short ? spec.short : spec.long;\r\n\r\n let normalized = value\r\n if ('normalize' in spec) {\r\n normalized = spec.normalize(value)\r\n }\r\n\r\n params.push([name, String(normalized)]);\r\n }\r\n\r\n\r\n return new URLSearchParams(\r\n params.map(([k, v]) => [k, v])\r\n ).toString();\r\n\r\n};\r\n\r\n/**\r\n * Builds a complete transformation URL from a base URL and transformation options.\r\n *\r\n * Combines the configured base URL with query parameters generated from the\r\n * transformation options. Handles the special `original` flag which returns\r\n * the unmodified source image.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - The transformation options to apply\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns The complete URL string with query parameters\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://example.com/images/photo.jpg?w=400&h=300'\r\n *\r\n * // Multiple transformations\r\n * buildTransformationUrl(config, {\r\n * width: 800,\r\n * format: 'webp',\r\n * quality: 85,\r\n * blur: 5\r\n * });\r\n * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'\r\n *\r\n * // Request original image (no transformations)\r\n * buildTransformationUrl(config, { original: true });\r\n * // => 'https://example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://example.com/images/photo.jpg?width=400'\r\n * ```\r\n */\r\n/**\r\n * Extracts the base URL path without query parameters\r\n */\r\nconst getBaseUrlWithoutQuery = (url: string): string => {\r\n const queryIndex = url.indexOf('?');\r\n return queryIndex === -1 ? url : url.slice(0, queryIndex);\r\n};\r\n\r\nexport const buildTransformationUrl = (\r\n config: UrlBuilderConfig,\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n) => {\r\n // Strip any existing query params from baseUrl - transformations replace them\r\n const baseUrl = removeTrailingSlash(getBaseUrlWithoutQuery(config.baseUrl));\r\n\r\n if (options.original) {\r\n return `${baseUrl}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(options, mode);\r\n\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
1
+ {"version":3,"sources":["../src/src-set.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import { buildTransformationUrl, NameMode } from './url-builder';\r\nimport { TransformationOptions } from './types';\r\nimport { clampMax, getFinalUrl, nearest, parseVW } from './utils';\r\n\r\n/**\r\n * Maximum supported image width\r\n */\r\nexport const MAX_IMAGE_WIDTH = 4096;\r\n\r\n/**\r\n * Default device breakpoints for responsive srcset generation\r\n */\r\nexport const DEFAULT_DEVICE_BREAKPOINTS = [\r\n 320,\r\n 375,\r\n 640,\r\n 768,\r\n 1024,\r\n 1280,\r\n 1536,\r\n 1920,\r\n 2048,\r\n 3840\r\n] as const;\r\n\r\n/**\r\n * Default image breakpoints for smaller images (icons, thumbnails)\r\n */\r\nexport const DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384] as const;\r\n\r\n/**\r\n * Options for responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageOptions {\r\n /**\r\n * The `sizes` attribute value (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * When provided, generates width descriptors (`w`) for responsive layouts.\r\n */\r\n sizes?: string;\r\n /**\r\n * Fixed display width in CSS pixels.\r\n * When provided without `sizes`, generates DPR descriptors (`x`).\r\n */\r\n width?: number;\r\n /** Device breakpoints for viewport-based sizing (default: DEFAULT_DEVICE_BREAKPOINTS) */\r\n deviceBreakpoints?: number[];\r\n /** Image breakpoints for smaller images (default: DEFAULT_IMAGE_BREAKPOINTS) */\r\n imageBreakpoints?: number[];\r\n /** Base transformation options to apply to all variants */\r\n transformations?: TransformationOptions;\r\n /** Whether to use short or long parameter names (default: 'short') */\r\n mode?: NameMode;\r\n maxDpr?: number\r\n}\r\n\r\n/**\r\n * Result of responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageResult {\r\n /** The src attribute value (largest/default variant) */\r\n src: string;\r\n /** The srcset attribute value */\r\n srcSet?: string;\r\n /** The sizes attribute value (for width descriptors) */\r\n sizes?: string;\r\n /** The width attribute value (when explicitly provided) */\r\n width?: number;\r\n}\r\n\r\n/**\r\n * Calculates candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction calculatesCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n maxDpr: number\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr,\r\n maxDpr\r\n } = params;\r\n\r\n if (!allBreakpoints.length || !deviceBreakpoints.length) {\r\n return {candidates: [], descriptor: 'w'};\r\n }\r\n\r\n const minDevice = deviceBreakpoints[0]!;\r\n const maxDevice = deviceBreakpoints[deviceBreakpoints.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n\r\n // When no sizes with vw definition is provided go for x descriptor\r\n if (explicitWidth && !hasVW) {\r\n const DPRs = [1, 2, 3, 4].filter(item => item <= maxDpr);\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(allBreakpoints, explicitWidth * dpr))\r\n .map(clampMax)\r\n )\r\n ).filter(w => w <= MAX_IMAGE_WIDTH);\r\n\r\n return {\r\n candidates,\r\n descriptor: 'x'\r\n };\r\n }\r\n\r\n\r\n // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const lowestRatio = Math.min(...vwRatios) / 100;\r\n const minRequiredPx = minDevice * lowestRatio;\r\n\r\n\r\n return {\r\n // Responsive layout only uses device breakpoints\r\n candidates: deviceBreakpoints.filter(w => w >= minRequiredPx && w <= MAX_IMAGE_WIDTH),\r\n descriptor: 'w',\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const upperLimit = maxDevice * maxDpr;\r\n\r\n return {\r\n candidates: allBreakpoints.filter(w => w <= upperLimit),\r\n descriptor: 'w'\r\n };\r\n}\r\n\r\n/**\r\n * Generates responsive image attributes (src, srcSet, sizes) for optimal loading.\r\n *\r\n * Supports two strategies:\r\n * 1. **Responsive (with `sizes`)**: Uses width descriptors (`w`) for fluid layouts\r\n * where image size varies with viewport.\r\n * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size\r\n * images that need high-DPI support.\r\n *\r\n * @param imageSrc - Relative or an absolute path to the image\r\n * @param baseUrl - This should be your baseURL endpoint for the source from PixelFiddle Dashboard.\r\n * @param options - Options for responsive image generation\r\n * @returns Object containing src, srcSet, and optionally sizes attributes\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/photo.jpg' };\r\n *\r\n * // Responsive image with sizes attribute (uses `w` descriptors)\r\n * createResponsiveAttributes(config, { sizes: '(max-width: 768px) 100vw, 50vw' });\r\n * // => {\r\n * // src: '...?w=3840',\r\n * // srcSet: '...?w=640 640w, ...?w=750 750w, ..., ...?w=3840 3840w',\r\n * // sizes: '(max-width: 768px) 100vw, 50vw'\r\n * // }\r\n *\r\n * // Fixed-width image (uses `x` descriptors)\r\n * createResponsiveAttributes(config, { width: 400 });\r\n * // => {\r\n * // src: '...?w=384',\r\n * // srcSet: '...?w=384 1x, ...?w=828 2x',\r\n * // width: 400\r\n * // }\r\n *\r\n * // With transformations\r\n * createResponsiveAttributes(config, {\r\n * sizes: '100vw',\r\n * transformations: { format: 'WEBP', quality: 80 }\r\n * });\r\n * ```\r\n */\r\nexport const createResponsiveAttributes = (\r\n imageSrc: string,\r\n baseUrl?: string,\r\n options?: ResponsiveImageOptions\r\n): ResponsiveImageResult => {\r\n const {\r\n sizes,\r\n width,\r\n deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],\r\n imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],\r\n transformations = {},\r\n mode = 'short',\r\n maxDpr = DEFAULT_MAX_DPR\r\n } = options || {}\r\n\r\n // If transformations.width is set, it takes precedence as the base width\r\n const baseWidth = transformations.width ?? width;\r\n\r\n const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);\r\n const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);\r\n\r\n const allBreakpoints = [...new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);\r\n\r\n const {candidates, descriptor} = calculatesCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(baseWidth !== undefined && {explicitWidth: baseWidth}),\r\n ...(sizes !== undefined && {sizesAttr: sizes}),\r\n maxDpr\r\n });\r\n\r\n if (candidates.length === 0) {\r\n // Fallback: no valid candidates, return base URL\r\n return {src: getFinalUrl(imageSrc, baseUrl)};\r\n }\r\n\r\n // Build srcSet entries\r\n const srcSetEntries = candidates.map((w, index,) => buildSrcEntries(imageSrc, w, index, transformations, mode, descriptor, baseUrl));\r\n\r\n // Default src is the largest candidate\r\n const largestWidth = candidates[candidates.length - 1]!;\r\n const src = buildTransformationUrl({\r\n src: imageSrc,\r\n baseUrl,\r\n transformations: {\r\n ...transformations,\r\n width: largestWidth\r\n },\r\n mode\r\n }\r\n );\r\n\r\n const endSizes = sizes ?? (descriptor === 'w' ? '100vw' : undefined);\r\n\r\n return {\r\n src,\r\n ...(endSizes ? {sizes: endSizes} : {}),\r\n srcSet: srcSetEntries.join(', '),\r\n ...(width !== undefined ? {width} : {}),\r\n };\r\n};\r\n\r\nfunction buildSrcEntries(imageSrc: string, width: number, index: number, transformations: TransformationOptions, mode: NameMode, descriptor: 'w' | 'x', baseUrl?: string,): string {\r\n const url = buildTransformationUrl({\r\n src: imageSrc,\r\n baseUrl,\r\n transformations: {...transformations, width: width},\r\n mode\r\n }\r\n );\r\n\r\n const desc = descriptor === 'w' ? `${width}w` : `${index + 1}x`;\r\n\r\n return `${url} ${desc}`;\r\n}\r\n","import { Path, PathValue } from './util-types';\r\nimport { MAX_IMAGE_WIDTH } from './src-set';\r\n\r\nexport const normalizeHex = (value: string) => value.replace('#', '')\r\n\r\n\r\nexport const removeTrailingSlash = (baseUrl: string) => {\r\n return baseUrl.endsWith('/')\r\n ? baseUrl.slice(0, -1)\r\n : baseUrl;\r\n}\r\n\r\nexport const getNestedValue = <\r\n T,\r\n P extends Path<T>\r\n>(\r\n obj: T,\r\n path: P\r\n): PathValue<T, P> | undefined =>\r\n path.reduce<any>(\r\n (acc, key) => (acc == null ? undefined : acc[key]),\r\n obj\r\n );\r\n\r\n\r\nexport const clampMax = (v: number) => Math.min(v, MAX_IMAGE_WIDTH);\r\n\r\nexport const nearest = (sortedBreakpoints: number[],target: number) =>\r\n sortedBreakpoints.find(w => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1]!;\r\n\r\nexport const parseVW = (sizes?: string): number[] => {\r\n if (!sizes) return [];\r\n const foundSizes = sizes.match(/(\\d+(?:\\.\\d+)?)vw/g) || []\r\n\r\n return foundSizes.map((size) => parseInt(size, 10))\r\n};\r\n\r\n/**\r\n * Extracts the base URL path without query parameters\r\n */\r\nconst getBaseUrlWithoutQuery = (url: string | undefined): string => {\r\n if (!url) return '';\r\n const queryIndex = url.indexOf('?');\r\n return queryIndex === -1 ? url : url.slice(0, queryIndex);\r\n};\r\n\r\n/**\r\n * Checks if a URL is absolute (starts with http:// or https://)\r\n */\r\nconst isAbsoluteUrl = (url: string | undefined): boolean => {\r\n if (!url) return false;\r\n return url.startsWith('http://') || url.startsWith('https://');\r\n};\r\n\r\n\r\nexport function getFinalUrl(src: string, baseUrl?: string): string {\r\n const cleanSrc = getBaseUrlWithoutQuery(src);\r\n\r\n if (isAbsoluteUrl(cleanSrc)) {\r\n return removeTrailingSlash(cleanSrc);\r\n } else {\r\n // Relative path - combine with baseUrl\r\n const base = removeTrailingSlash(getBaseUrlWithoutQuery(baseUrl));\r\n\r\n // Ensure path has leading slash for proper URL construction\r\n const normalizedPath = normalizePath(cleanSrc)\r\n return `${base}${normalizedPath}`;\r\n }\r\n\r\n}\r\n\r\nexport function normalizePath(src: string): string {\r\n return src && !src.startsWith('/') ? `/${src}` : src;\r\n}\r\n\r\n\r\nexport const parseNumberLikeParam = (\r\n width: number | `${number}`\r\n): number => {\r\n if (typeof width === 'number') {\r\n return width;\r\n }\r\n\r\n const parsed = Number(width);\r\n\r\n if (!Number.isFinite(parsed)) {\r\n throw new Error(`Invalid width value: ${width}`);\r\n }\r\n\r\n return parsed;\r\n};\r\n","import { ParamSpec, Path } from './util-types';\r\nimport { TransformationOptions } from './types';\r\nimport { normalizeHex } from './utils';\r\n\r\nexport const PARAMS = [\r\n {path: ['width'], long: 'width', short: 'w'},\r\n {path: ['height'], long: 'height', short: 'h'},\r\n {path: ['dpr'], long: 'dpr', short: 'dpr'},\r\n {path: ['mode'], long: 'mode', short: 'rm'},\r\n {\r\n path: ['background'],\r\n long: 'background',\r\n short: 'bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n\r\n {path: ['format'], long: 'format', short: 'f'},\r\n {path: ['quality'], long: 'quality', short: 'q'},\r\n {path: ['stripMetadata'], long: 'stripMetadata', short: 'st'},\r\n\r\n {path: ['blur'], long: 'blur', short: 'bl'},\r\n {path: ['brightness'], long: 'brightness', short: 'br'},\r\n {path: ['contrast'], long: 'contrast', short: 'ct'},\r\n {path: ['grayscale'], long: 'grayscale', short: 'gs'},\r\n {path: ['saturation'], long: 'saturation', short: 'sa'},\r\n {path: ['sepia'], long: 'sepia', short: 'sp'},\r\n {path: ['sharpen'], long: 'sharpen', short: 'sh'},\r\n {path: ['noise'], long: 'noise', short: 'ns'},\r\n {path: ['rotate'], long: 'rotate', short: 'rt'},\r\n\r\n {path: ['border', 'width'], long: 'border.width', short: 'bo.w'},\r\n {\r\n path: ['border', 'color'],\r\n long: 'border.color',\r\n short: 'bo.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['border', 'radius'], long: 'border.radius', short: 'bo.r'},\r\n\r\n {path: ['crop', 'type'], long: 'crop.type', short: 'cr.t'},\r\n {path: ['crop', 'objectType'], long: 'crop.objectType', short: 'cr.o'},\r\n {path: ['crop', 'focus', 'position', 'x'], long: 'crop.x', short: 'cr.x'},\r\n {path: ['crop', 'focus', 'position', 'y'], long: 'crop.y', short: 'cr.y'},\r\n {path: ['crop', 'focus', 'strategy'], long: 'crop', short: 'cr'},\r\n {path: ['crop', 'width'], long: 'crop.width', short: 'cr.w'},\r\n {path: ['crop', 'height'], long: 'crop.height', short: 'cr.h'},\r\n {path: ['crop', 'afterResize'], long: 'crop.afterResize', short: 'cr.ar'},\r\n\r\n {path: ['text', 'text'], long: 'text', short: 'tx'},\r\n {\r\n path: ['text', 'color'],\r\n long: 'text.color',\r\n short: 'tx.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'opacity'], long: 'text.opacity', short: 'tx.o'},\r\n {path: ['text', 'size'], long: 'text.size', short: 'tx.s'},\r\n {path: ['text', 'font'], long: 'text.font', short: 'tx.f'},\r\n {path: ['text', 'fontSize'], long: 'text.fontSize', short: 'tx.fs'},\r\n {path: ['text', 'position'], long: 'text.position', short: 'tx.p'},\r\n {\r\n path: ['text', 'background'],\r\n long: 'text.background',\r\n short: 'tx.bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'backgroundOpacity'], long: 'text.backgroundOpacity', short: 'tx.bg.o'},\r\n\r\n {path: ['watermark', 'name'], long: 'watermark', short: 'wm'},\r\n {path: ['watermark', 'opacity'], long: 'watermark.opacity', short: 'wm.o'},\r\n {path: ['watermark', 'size'], long: 'watermark.size', short: 'wm.s'},\r\n {path: ['watermark', 'width'], long: 'watermark.width', short: 'wm.w'},\r\n {path: ['watermark', 'height'], long: 'watermark.height', short: 'wm.h'},\r\n {path: ['watermark', 'position'], long: 'watermark.position', short: 'wm.p'},\r\n] as const satisfies readonly ParamSpec<\r\n TransformationOptions,\r\n Path<TransformationOptions>\r\n>[];\r\n","import { BuildTransformationConfig, TransformationOptions } from './types';\r\nimport { getFinalUrl, getNestedValue } from './utils';\r\nimport { PARAMS } from './config';\r\n\r\n/**\r\n * Determines which parameter names to use in the query string.\r\n * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)\r\n * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)\r\n */\r\nexport type NameMode = 'short' | 'long';\r\n\r\n/**\r\n * Converts transformation options into a URL-encoded query string.\r\n *\r\n * Iterates through all defined parameters in the PARAMS config, extracts values\r\n * from the options object using their paths, applies any normalization functions\r\n * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.\r\n *\r\n * @param options - The transformation options object\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns URL-encoded query string (without leading `?`)\r\n *\r\n * @example\r\n * ```ts\r\n * // Using short aliases (default)\r\n * buildQueryParams({ width: 800, height: 600, quality: 80 });\r\n * // => 'w=800&h=600&q=80'\r\n *\r\n * // Using long parameter names\r\n * buildQueryParams({ width: 800, format: 'webp' }, 'long');\r\n * // => 'width=800&format=webp'\r\n *\r\n * // Nested options\r\n * buildQueryParams({ border: { width: 2, color: '#ff0000' } });\r\n * // => 'bo.w=2&bo.c=ff0000'\r\n * ```\r\n */\r\nexport const buildTransformationQueryParams = (\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n): string => {\r\n const params: Array<[string, string]> = [];\r\n\r\n for (const spec of PARAMS) {\r\n const value = getNestedValue(options, spec.path);\r\n if (value == null) continue;\r\n\r\n const name =\r\n mode === 'short' && spec.short ? spec.short : spec.long;\r\n\r\n let normalized = value\r\n if ('normalize' in spec) {\r\n normalized = spec.normalize(value)\r\n }\r\n\r\n params.push([name, String(normalized)]);\r\n }\r\n\r\n\r\n return new URLSearchParams(\r\n params.map(([k, v]) => [k, v])\r\n ).toString();\r\n\r\n};\r\n\r\n/**\r\n * Builds a complete transformation URL from a base URL and transformation options.\r\n *\r\n * Combines the configured base URL with query parameters generated from the\r\n * transformation options. Handles the special `original` flag which returns\r\n * the unmodified source image.\r\n *\r\n * @param src - Absolute or relative path to your image\r\n * @param config - Configuration containing the base URL for the image\r\n * @param transformations - The transformation options to apply\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns The complete URL string with query parameters\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://example.com/images/photo.jpg?w=400&h=300'\r\n *\r\n * // Multiple transformations\r\n * buildTransformationUrl(config, {\r\n * width: 800,\r\n * format: 'webp',\r\n * quality: 85,\r\n * blur: 5\r\n * });\r\n * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'\r\n *\r\n * // Request original image (no transformations)\r\n * buildTransformationUrl(config, { original: true });\r\n * // => 'https://example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://example.com/images/photo.jpg?width=400'\r\n * ```\r\n */\r\nexport const buildTransformationUrl = (\r\n {src, transformations = {}, baseUrl, mode = 'short'}: BuildTransformationConfig\r\n) => {\r\n const url = getFinalUrl(src, baseUrl)\r\n\r\n if (transformations.original) {\r\n return `${url}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(transformations, mode);\r\n\r\n return `${url}?${query}`;\r\n};\r\n"]}
package/dist/index.d.cts CHANGED
@@ -1,3 +1,77 @@
1
+ /**
2
+ * Determines which parameter names to use in the query string.
3
+ * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)
4
+ * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)
5
+ */
6
+ type NameMode = 'short' | 'long';
7
+ /**
8
+ * Converts transformation options into a URL-encoded query string.
9
+ *
10
+ * Iterates through all defined parameters in the PARAMS config, extracts values
11
+ * from the options object using their paths, applies any normalization functions
12
+ * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.
13
+ *
14
+ * @param options - The transformation options object
15
+ * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)
16
+ * @returns URL-encoded query string (without leading `?`)
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * // Using short aliases (default)
21
+ * buildQueryParams({ width: 800, height: 600, quality: 80 });
22
+ * // => 'w=800&h=600&q=80'
23
+ *
24
+ * // Using long parameter names
25
+ * buildQueryParams({ width: 800, format: 'webp' }, 'long');
26
+ * // => 'width=800&format=webp'
27
+ *
28
+ * // Nested options
29
+ * buildQueryParams({ border: { width: 2, color: '#ff0000' } });
30
+ * // => 'bo.w=2&bo.c=ff0000'
31
+ * ```
32
+ */
33
+ declare const buildTransformationQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
34
+ /**
35
+ * Builds a complete transformation URL from a base URL and transformation options.
36
+ *
37
+ * Combines the configured base URL with query parameters generated from the
38
+ * transformation options. Handles the special `original` flag which returns
39
+ * the unmodified source image.
40
+ *
41
+ * @param src - Absolute or relative path to your image
42
+ * @param config - Configuration containing the base URL for the image
43
+ * @param transformations - The transformation options to apply
44
+ * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)
45
+ * @returns The complete URL string with query parameters
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const config = { baseUrl: 'https://example.com/images/photo.jpg' };
50
+ *
51
+ * // Basic resize
52
+ * buildTransformationUrl(config, { width: 400, height: 300 });
53
+ * // => 'https://example.com/images/photo.jpg?w=400&h=300'
54
+ *
55
+ * // Multiple transformations
56
+ * buildTransformationUrl(config, {
57
+ * width: 800,
58
+ * format: 'webp',
59
+ * quality: 85,
60
+ * blur: 5
61
+ * });
62
+ * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'
63
+ *
64
+ * // Request original image (no transformations)
65
+ * buildTransformationUrl(config, { original: true });
66
+ * // => 'https://example.com/images/photo.jpg?original'
67
+ *
68
+ * // Using long parameter names
69
+ * buildTransformationUrl(config, { width: 400 }, 'long');
70
+ * // => 'https://example.com/images/photo.jpg?width=400'
71
+ * ```
72
+ */
73
+ declare const buildTransformationUrl: ({ src, transformations, baseUrl, mode }: BuildTransformationConfig) => string;
74
+
1
75
  /**
2
76
  * Helper type to extract values from const objects
3
77
  */
@@ -237,8 +311,6 @@ interface TransformationOptions extends ResizeOptions, FormatOptions, EffectOpti
237
311
  interface PixelFiddlerConfig {
238
312
  /** Base URL for the CDN (defaults to https://cdn.pixel-fiddler.com) */
239
313
  baseUrl?: string;
240
- /** Secret key for URL signing */
241
- signatureKey?: string;
242
314
  /** Max DPR that you want responsive srcSet to support, defaults to 2 */
243
315
  maxDpr?: number;
244
316
  }
@@ -249,41 +321,12 @@ interface UrlBuilderConfig extends PixelFiddlerConfig {
249
321
  /** Resolved base URL */
250
322
  baseUrl: string;
251
323
  }
252
-
253
- /**
254
- * Determines which parameter names to use in the query string.
255
- * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)
256
- * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)
257
- */
258
- type NameMode = 'short' | 'long';
259
- /**
260
- * Converts transformation options into a URL-encoded query string.
261
- *
262
- * Iterates through all defined parameters in the PARAMS config, extracts values
263
- * from the options object using their paths, applies any normalization functions
264
- * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.
265
- *
266
- * @param options - The transformation options object
267
- * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)
268
- * @returns URL-encoded query string (without leading `?`)
269
- *
270
- * @example
271
- * ```ts
272
- * // Using short aliases (default)
273
- * buildQueryParams({ width: 800, height: 600, quality: 80 });
274
- * // => 'w=800&h=600&q=80'
275
- *
276
- * // Using long parameter names
277
- * buildQueryParams({ width: 800, format: 'webp' }, 'long');
278
- * // => 'width=800&format=webp'
279
- *
280
- * // Nested options
281
- * buildQueryParams({ border: { width: 2, color: '#ff0000' } });
282
- * // => 'bo.w=2&bo.c=ff0000'
283
- * ```
284
- */
285
- declare const buildTransformationQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
286
- declare const buildTransformationUrl: (config: UrlBuilderConfig, options: TransformationOptions, mode?: NameMode) => string;
324
+ type BuildTransformationConfig = {
325
+ src: string;
326
+ transformations?: TransformationOptions;
327
+ baseUrl?: string;
328
+ mode?: NameMode;
329
+ };
287
330
 
288
331
  /**
289
332
  * Options for responsive image attributes generation
@@ -331,7 +374,8 @@ interface ResponsiveImageResult {
331
374
  * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size
332
375
  * images that need high-DPI support.
333
376
  *
334
- * @param config - Configuration containing the base URL for the image
377
+ * @param imageSrc - Relative or an absolute path to the image
378
+ * @param baseUrl - This should be your baseURL endpoint for the source from PixelFiddle Dashboard.
335
379
  * @param options - Options for responsive image generation
336
380
  * @returns Object containing src, srcSet, and optionally sizes attributes
337
381
  *
@@ -362,6 +406,8 @@ interface ResponsiveImageResult {
362
406
  * });
363
407
  * ```
364
408
  */
365
- declare const createResponsiveAttributes: (config: UrlBuilderConfig, options?: ResponsiveImageOptions) => ResponsiveImageResult;
409
+ declare const createResponsiveAttributes: (imageSrc: string, baseUrl?: string, options?: ResponsiveImageOptions) => ResponsiveImageResult;
410
+
411
+ declare const parseNumberLikeParam: (width: number | `${number}`) => number;
366
412
 
367
- export { type AutoCropFocus, type BorderOptions, type CropFocus, type CropFocusOptions, type CropFocusPosition, type CropFocusStrategy, type CropObjectType, type CropOptions, type CropType, type DevicePixelRatio, type EffectOptions, type FormatOptions, type HexColor, type ImageFormat, type ObjectCropOptions, type PixelFiddlerConfig, type Position, type ResizeMode, type ResizeOptions, type RotationAngle, type SimpleCropOptions, type SpecifiedCropFocus, type TextOptions, type TransformationOptions, type UrlBuilderConfig, type WatermarkOptions, buildTransformationQueryParams, buildTransformationUrl, createResponsiveAttributes };
413
+ export { type AutoCropFocus, type BorderOptions, type BuildTransformationConfig, type CropFocus, type CropFocusOptions, type CropFocusPosition, type CropFocusStrategy, type CropObjectType, type CropOptions, type CropType, type DevicePixelRatio, type EffectOptions, type FormatOptions, type HexColor, type ImageFormat, type ObjectCropOptions, type PixelFiddlerConfig, type Position, type ResizeMode, type ResizeOptions, type RotationAngle, type SimpleCropOptions, type SpecifiedCropFocus, type TextOptions, type TransformationOptions, type UrlBuilderConfig, type WatermarkOptions, buildTransformationQueryParams, buildTransformationUrl, createResponsiveAttributes, parseNumberLikeParam };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,77 @@
1
+ /**
2
+ * Determines which parameter names to use in the query string.
3
+ * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)
4
+ * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)
5
+ */
6
+ type NameMode = 'short' | 'long';
7
+ /**
8
+ * Converts transformation options into a URL-encoded query string.
9
+ *
10
+ * Iterates through all defined parameters in the PARAMS config, extracts values
11
+ * from the options object using their paths, applies any normalization functions
12
+ * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.
13
+ *
14
+ * @param options - The transformation options object
15
+ * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)
16
+ * @returns URL-encoded query string (without leading `?`)
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * // Using short aliases (default)
21
+ * buildQueryParams({ width: 800, height: 600, quality: 80 });
22
+ * // => 'w=800&h=600&q=80'
23
+ *
24
+ * // Using long parameter names
25
+ * buildQueryParams({ width: 800, format: 'webp' }, 'long');
26
+ * // => 'width=800&format=webp'
27
+ *
28
+ * // Nested options
29
+ * buildQueryParams({ border: { width: 2, color: '#ff0000' } });
30
+ * // => 'bo.w=2&bo.c=ff0000'
31
+ * ```
32
+ */
33
+ declare const buildTransformationQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
34
+ /**
35
+ * Builds a complete transformation URL from a base URL and transformation options.
36
+ *
37
+ * Combines the configured base URL with query parameters generated from the
38
+ * transformation options. Handles the special `original` flag which returns
39
+ * the unmodified source image.
40
+ *
41
+ * @param src - Absolute or relative path to your image
42
+ * @param config - Configuration containing the base URL for the image
43
+ * @param transformations - The transformation options to apply
44
+ * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)
45
+ * @returns The complete URL string with query parameters
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const config = { baseUrl: 'https://example.com/images/photo.jpg' };
50
+ *
51
+ * // Basic resize
52
+ * buildTransformationUrl(config, { width: 400, height: 300 });
53
+ * // => 'https://example.com/images/photo.jpg?w=400&h=300'
54
+ *
55
+ * // Multiple transformations
56
+ * buildTransformationUrl(config, {
57
+ * width: 800,
58
+ * format: 'webp',
59
+ * quality: 85,
60
+ * blur: 5
61
+ * });
62
+ * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'
63
+ *
64
+ * // Request original image (no transformations)
65
+ * buildTransformationUrl(config, { original: true });
66
+ * // => 'https://example.com/images/photo.jpg?original'
67
+ *
68
+ * // Using long parameter names
69
+ * buildTransformationUrl(config, { width: 400 }, 'long');
70
+ * // => 'https://example.com/images/photo.jpg?width=400'
71
+ * ```
72
+ */
73
+ declare const buildTransformationUrl: ({ src, transformations, baseUrl, mode }: BuildTransformationConfig) => string;
74
+
1
75
  /**
2
76
  * Helper type to extract values from const objects
3
77
  */
@@ -237,8 +311,6 @@ interface TransformationOptions extends ResizeOptions, FormatOptions, EffectOpti
237
311
  interface PixelFiddlerConfig {
238
312
  /** Base URL for the CDN (defaults to https://cdn.pixel-fiddler.com) */
239
313
  baseUrl?: string;
240
- /** Secret key for URL signing */
241
- signatureKey?: string;
242
314
  /** Max DPR that you want responsive srcSet to support, defaults to 2 */
243
315
  maxDpr?: number;
244
316
  }
@@ -249,41 +321,12 @@ interface UrlBuilderConfig extends PixelFiddlerConfig {
249
321
  /** Resolved base URL */
250
322
  baseUrl: string;
251
323
  }
252
-
253
- /**
254
- * Determines which parameter names to use in the query string.
255
- * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)
256
- * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)
257
- */
258
- type NameMode = 'short' | 'long';
259
- /**
260
- * Converts transformation options into a URL-encoded query string.
261
- *
262
- * Iterates through all defined parameters in the PARAMS config, extracts values
263
- * from the options object using their paths, applies any normalization functions
264
- * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.
265
- *
266
- * @param options - The transformation options object
267
- * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)
268
- * @returns URL-encoded query string (without leading `?`)
269
- *
270
- * @example
271
- * ```ts
272
- * // Using short aliases (default)
273
- * buildQueryParams({ width: 800, height: 600, quality: 80 });
274
- * // => 'w=800&h=600&q=80'
275
- *
276
- * // Using long parameter names
277
- * buildQueryParams({ width: 800, format: 'webp' }, 'long');
278
- * // => 'width=800&format=webp'
279
- *
280
- * // Nested options
281
- * buildQueryParams({ border: { width: 2, color: '#ff0000' } });
282
- * // => 'bo.w=2&bo.c=ff0000'
283
- * ```
284
- */
285
- declare const buildTransformationQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
286
- declare const buildTransformationUrl: (config: UrlBuilderConfig, options: TransformationOptions, mode?: NameMode) => string;
324
+ type BuildTransformationConfig = {
325
+ src: string;
326
+ transformations?: TransformationOptions;
327
+ baseUrl?: string;
328
+ mode?: NameMode;
329
+ };
287
330
 
288
331
  /**
289
332
  * Options for responsive image attributes generation
@@ -331,7 +374,8 @@ interface ResponsiveImageResult {
331
374
  * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size
332
375
  * images that need high-DPI support.
333
376
  *
334
- * @param config - Configuration containing the base URL for the image
377
+ * @param imageSrc - Relative or an absolute path to the image
378
+ * @param baseUrl - This should be your baseURL endpoint for the source from PixelFiddle Dashboard.
335
379
  * @param options - Options for responsive image generation
336
380
  * @returns Object containing src, srcSet, and optionally sizes attributes
337
381
  *
@@ -362,6 +406,8 @@ interface ResponsiveImageResult {
362
406
  * });
363
407
  * ```
364
408
  */
365
- declare const createResponsiveAttributes: (config: UrlBuilderConfig, options?: ResponsiveImageOptions) => ResponsiveImageResult;
409
+ declare const createResponsiveAttributes: (imageSrc: string, baseUrl?: string, options?: ResponsiveImageOptions) => ResponsiveImageResult;
410
+
411
+ declare const parseNumberLikeParam: (width: number | `${number}`) => number;
366
412
 
367
- export { type AutoCropFocus, type BorderOptions, type CropFocus, type CropFocusOptions, type CropFocusPosition, type CropFocusStrategy, type CropObjectType, type CropOptions, type CropType, type DevicePixelRatio, type EffectOptions, type FormatOptions, type HexColor, type ImageFormat, type ObjectCropOptions, type PixelFiddlerConfig, type Position, type ResizeMode, type ResizeOptions, type RotationAngle, type SimpleCropOptions, type SpecifiedCropFocus, type TextOptions, type TransformationOptions, type UrlBuilderConfig, type WatermarkOptions, buildTransformationQueryParams, buildTransformationUrl, createResponsiveAttributes };
413
+ export { type AutoCropFocus, type BorderOptions, type BuildTransformationConfig, type CropFocus, type CropFocusOptions, type CropFocusPosition, type CropFocusStrategy, type CropObjectType, type CropOptions, type CropType, type DevicePixelRatio, type EffectOptions, type FormatOptions, type HexColor, type ImageFormat, type ObjectCropOptions, type PixelFiddlerConfig, type Position, type ResizeMode, type ResizeOptions, type RotationAngle, type SimpleCropOptions, type SpecifiedCropFocus, type TextOptions, type TransformationOptions, type UrlBuilderConfig, type WatermarkOptions, buildTransformationQueryParams, buildTransformationUrl, createResponsiveAttributes, parseNumberLikeParam };
package/dist/index.js CHANGED
@@ -56,7 +56,7 @@ function calculatesCandidateWidths(params) {
56
56
  descriptor: "w"
57
57
  };
58
58
  }
59
- var createResponsiveAttributes = (config, options = {}) => {
59
+ var createResponsiveAttributes = (imageSrc, baseUrl, options) => {
60
60
  const {
61
61
  sizes,
62
62
  width,
@@ -65,7 +65,7 @@ var createResponsiveAttributes = (config, options = {}) => {
65
65
  transformations = {},
66
66
  mode = "short",
67
67
  maxDpr = DEFAULT_MAX_DPR
68
- } = options;
68
+ } = options || {};
69
69
  const baseWidth = transformations.width ?? width;
70
70
  const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);
71
71
  const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);
@@ -78,14 +78,20 @@ var createResponsiveAttributes = (config, options = {}) => {
78
78
  maxDpr
79
79
  });
80
80
  if (candidates.length === 0) {
81
- return { src: config.baseUrl };
81
+ return { src: getFinalUrl(imageSrc, baseUrl) };
82
82
  }
83
- const srcSetEntries = candidates.map((w, index) => buildSrcEntries(w, index, config, transformations, mode, descriptor));
83
+ const srcSetEntries = candidates.map((w, index) => buildSrcEntries(imageSrc, w, index, transformations, mode, descriptor, baseUrl));
84
84
  const largestWidth = candidates[candidates.length - 1];
85
85
  const src = buildTransformationUrl(
86
- config,
87
- { ...transformations, width: largestWidth },
88
- mode
86
+ {
87
+ src: imageSrc,
88
+ baseUrl,
89
+ transformations: {
90
+ ...transformations,
91
+ width: largestWidth
92
+ },
93
+ mode
94
+ }
89
95
  );
90
96
  const endSizes = sizes ?? (descriptor === "w" ? "100vw" : void 0);
91
97
  return {
@@ -95,11 +101,14 @@ var createResponsiveAttributes = (config, options = {}) => {
95
101
  ...width !== void 0 ? { width } : {}
96
102
  };
97
103
  };
98
- function buildSrcEntries(width, index, config, transformations, mode, descriptor) {
104
+ function buildSrcEntries(imageSrc, width, index, transformations, mode, descriptor, baseUrl) {
99
105
  const url = buildTransformationUrl(
100
- config,
101
- { ...transformations, width },
102
- mode
106
+ {
107
+ src: imageSrc,
108
+ baseUrl,
109
+ transformations: { ...transformations, width },
110
+ mode
111
+ }
103
112
  );
104
113
  const desc = descriptor === "w" ? `${width}w` : `${index + 1}x`;
105
114
  return `${url} ${desc}`;
@@ -121,6 +130,38 @@ var parseVW = (sizes) => {
121
130
  const foundSizes = sizes.match(/(\d+(?:\.\d+)?)vw/g) || [];
122
131
  return foundSizes.map((size) => parseInt(size, 10));
123
132
  };
133
+ var getBaseUrlWithoutQuery = (url) => {
134
+ if (!url) return "";
135
+ const queryIndex = url.indexOf("?");
136
+ return queryIndex === -1 ? url : url.slice(0, queryIndex);
137
+ };
138
+ var isAbsoluteUrl = (url) => {
139
+ if (!url) return false;
140
+ return url.startsWith("http://") || url.startsWith("https://");
141
+ };
142
+ function getFinalUrl(src, baseUrl) {
143
+ const cleanSrc = getBaseUrlWithoutQuery(src);
144
+ if (isAbsoluteUrl(cleanSrc)) {
145
+ return removeTrailingSlash(cleanSrc);
146
+ } else {
147
+ const base = removeTrailingSlash(getBaseUrlWithoutQuery(baseUrl));
148
+ const normalizedPath = normalizePath(cleanSrc);
149
+ return `${base}${normalizedPath}`;
150
+ }
151
+ }
152
+ function normalizePath(src) {
153
+ return src && !src.startsWith("/") ? `/${src}` : src;
154
+ }
155
+ var parseNumberLikeParam = (width) => {
156
+ if (typeof width === "number") {
157
+ return width;
158
+ }
159
+ const parsed = Number(width);
160
+ if (!Number.isFinite(parsed)) {
161
+ throw new Error(`Invalid width value: ${width}`);
162
+ }
163
+ return parsed;
164
+ };
124
165
 
125
166
  // src/config.ts
126
167
  var PARAMS = [
@@ -206,19 +247,15 @@ var buildTransformationQueryParams = (options, mode = "short") => {
206
247
  params.map(([k, v]) => [k, v])
207
248
  ).toString();
208
249
  };
209
- var getBaseUrlWithoutQuery = (url) => {
210
- const queryIndex = url.indexOf("?");
211
- return queryIndex === -1 ? url : url.slice(0, queryIndex);
212
- };
213
- var buildTransformationUrl = (config, options, mode = "short") => {
214
- const baseUrl = removeTrailingSlash(getBaseUrlWithoutQuery(config.baseUrl));
215
- if (options.original) {
216
- return `${baseUrl}?original`;
250
+ var buildTransformationUrl = ({ src, transformations = {}, baseUrl, mode = "short" }) => {
251
+ const url = getFinalUrl(src, baseUrl);
252
+ if (transformations.original) {
253
+ return `${url}?original`;
217
254
  }
218
- const query = buildTransformationQueryParams(options, mode);
219
- return `${baseUrl}?${query}`;
255
+ const query = buildTransformationQueryParams(transformations, mode);
256
+ return `${url}?${query}`;
220
257
  };
221
258
 
222
- export { buildTransformationQueryParams, buildTransformationUrl, createResponsiveAttributes };
259
+ export { buildTransformationQueryParams, buildTransformationUrl, createResponsiveAttributes, parseNumberLikeParam };
223
260
  //# sourceMappingURL=index.js.map
224
261
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/src-set.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { buildTransformationUrl, NameMode } from './url-builder';\r\nimport { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { clampMax, nearest, parseVW } from './utils';\r\n\r\n/**\r\n * Maximum supported image width\r\n */\r\nexport const MAX_IMAGE_WIDTH = 4096;\r\n\r\n/**\r\n * Default device breakpoints for responsive srcset generation\r\n */\r\nexport const DEFAULT_DEVICE_BREAKPOINTS = [\r\n 320,\r\n 375,\r\n 640,\r\n 768,\r\n 1024,\r\n 1280,\r\n 1536,\r\n 1920,\r\n 2048,\r\n 3840\r\n] as const;\r\n\r\n/**\r\n * Default image breakpoints for smaller images (icons, thumbnails)\r\n */\r\nexport const DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384] as const;\r\n\r\n/**\r\n * Options for responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageOptions {\r\n /**\r\n * The `sizes` attribute value (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * When provided, generates width descriptors (`w`) for responsive layouts.\r\n */\r\n sizes?: string;\r\n /**\r\n * Fixed display width in CSS pixels.\r\n * When provided without `sizes`, generates DPR descriptors (`x`).\r\n */\r\n width?: number;\r\n /** Device breakpoints for viewport-based sizing (default: DEFAULT_DEVICE_BREAKPOINTS) */\r\n deviceBreakpoints?: number[];\r\n /** Image breakpoints for smaller images (default: DEFAULT_IMAGE_BREAKPOINTS) */\r\n imageBreakpoints?: number[];\r\n /** Base transformation options to apply to all variants */\r\n transformations?: TransformationOptions;\r\n /** Whether to use short or long parameter names (default: 'short') */\r\n mode?: NameMode;\r\n maxDpr?: number\r\n}\r\n\r\n/**\r\n * Result of responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageResult {\r\n /** The src attribute value (largest/default variant) */\r\n src: string;\r\n /** The srcset attribute value */\r\n srcSet?: string;\r\n /** The sizes attribute value (for width descriptors) */\r\n sizes?: string;\r\n /** The width attribute value (when explicitly provided) */\r\n width?: number;\r\n}\r\n\r\n/**\r\n * Calculates candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction calculatesCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n maxDpr: number\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr,\r\n maxDpr\r\n } = params;\r\n\r\n if (!allBreakpoints.length || !deviceBreakpoints.length) {\r\n return { candidates: [], descriptor: 'w' };\r\n }\r\n\r\n const minDevice = deviceBreakpoints[0]!;\r\n const maxDevice = deviceBreakpoints[deviceBreakpoints.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n\r\n // When no sizes with vw definition is provided go for x descriptor\r\n if (explicitWidth && !hasVW) {\r\n const DPRs = [1, 2, 3, 4].filter(item => item <= maxDpr);\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(allBreakpoints, explicitWidth * dpr))\r\n .map(clampMax)\r\n )\r\n ).filter(w => w <= MAX_IMAGE_WIDTH);\r\n\r\n return {\r\n candidates,\r\n descriptor: 'x'\r\n };\r\n }\r\n\r\n\r\n // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const lowestRatio = Math.min(...vwRatios) / 100;\r\n const minRequiredPx = minDevice * lowestRatio;\r\n\r\n\r\n return {\r\n // Responsive layout only uses device breakpoints\r\n candidates: deviceBreakpoints.filter(w => w >= minRequiredPx && w <= MAX_IMAGE_WIDTH),\r\n descriptor: 'w',\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const upperLimit = maxDevice * maxDpr;\r\n\r\n return {\r\n candidates: allBreakpoints.filter(w => w <= upperLimit),\r\n descriptor: 'w'\r\n };\r\n}\r\n\r\n/**\r\n * Generates responsive image attributes (src, srcSet, sizes) for optimal loading.\r\n *\r\n * Supports two strategies:\r\n * 1. **Responsive (with `sizes`)**: Uses width descriptors (`w`) for fluid layouts\r\n * where image size varies with viewport.\r\n * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size\r\n * images that need high-DPI support.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - Options for responsive image generation\r\n * @returns Object containing src, srcSet, and optionally sizes attributes\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/photo.jpg' };\r\n *\r\n * // Responsive image with sizes attribute (uses `w` descriptors)\r\n * createResponsiveAttributes(config, { sizes: '(max-width: 768px) 100vw, 50vw' });\r\n * // => {\r\n * // src: '...?w=3840',\r\n * // srcSet: '...?w=640 640w, ...?w=750 750w, ..., ...?w=3840 3840w',\r\n * // sizes: '(max-width: 768px) 100vw, 50vw'\r\n * // }\r\n *\r\n * // Fixed-width image (uses `x` descriptors)\r\n * createResponsiveAttributes(config, { width: 400 });\r\n * // => {\r\n * // src: '...?w=384',\r\n * // srcSet: '...?w=384 1x, ...?w=828 2x',\r\n * // width: 400\r\n * // }\r\n *\r\n * // With transformations\r\n * createResponsiveAttributes(config, {\r\n * sizes: '100vw',\r\n * transformations: { format: 'WEBP', quality: 80 }\r\n * });\r\n * ```\r\n */\r\nexport const createResponsiveAttributes = (\r\n config: UrlBuilderConfig,\r\n options: ResponsiveImageOptions = {}\r\n): ResponsiveImageResult => {\r\n const {\r\n sizes,\r\n width,\r\n deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],\r\n imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],\r\n transformations = {},\r\n mode = 'short',\r\n maxDpr = DEFAULT_MAX_DPR\r\n } = options;\r\n\r\n // If transformations.width is set, it takes precedence as the base width\r\n const baseWidth = transformations.width ?? width;\r\n\r\n const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);\r\n const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);\r\n\r\n const allBreakpoints = [...new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);\r\n\r\n const { candidates, descriptor } = calculatesCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(baseWidth !== undefined && { explicitWidth: baseWidth }),\r\n ...(sizes !== undefined && { sizesAttr: sizes }),\r\n maxDpr\r\n });\r\n\r\n if (candidates.length === 0) {\r\n // Fallback: no valid candidates, return base URL\r\n return { src: config.baseUrl };\r\n }\r\n\r\n // Build srcSet entries\r\n const srcSetEntries = candidates.map((w, index,) => buildSrcEntries(w, index, config, transformations, mode, descriptor));\r\n\r\n // Default src is the largest candidate\r\n const largestWidth = candidates[candidates.length - 1]!;\r\n const src = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: largestWidth },\r\n mode\r\n );\r\n\r\n const endSizes = sizes ?? (descriptor === 'w' ? '100vw' : undefined);\r\n\r\n return {\r\n src,\r\n ...(endSizes ? { sizes: endSizes } : {}),\r\n srcSet: srcSetEntries.join(', '),\r\n ...(width !== undefined ? { width } : {}),\r\n };\r\n};\r\n\r\nfunction buildSrcEntries(width: number, index: number, config: UrlBuilderConfig, transformations: TransformationOptions, mode: NameMode, descriptor: 'w' | 'x'): string {\r\n const url = buildTransformationUrl(\r\n config,\r\n { ...transformations, width: width },\r\n mode\r\n );\r\n\r\n const desc = descriptor === 'w' ? `${width}w` : `${index + 1}x`;\r\n\r\n return `${url} ${desc}`;\r\n}\r\n","import { Path, PathValue } from './util-types';\r\nimport { MAX_IMAGE_WIDTH } from './src-set';\r\n\r\nexport const normalizeHex = (value: string) => value.replace('#', '')\r\n\r\n\r\nexport const removeTrailingSlash = (baseUrl: string) => {\r\n return baseUrl.endsWith('/')\r\n ? baseUrl.slice(0, -1)\r\n : baseUrl;\r\n}\r\n\r\nexport const getNestedValue = <\r\n T,\r\n P extends Path<T>\r\n>(\r\n obj: T,\r\n path: P\r\n): PathValue<T, P> | undefined =>\r\n path.reduce<any>(\r\n (acc, key) => (acc == null ? undefined : acc[key]),\r\n obj\r\n );\r\n\r\n\r\nexport const clampMax = (v: number) => Math.min(v, MAX_IMAGE_WIDTH);\r\n\r\nexport const nearest = (sortedBreakpoints: number[],target: number) =>\r\n sortedBreakpoints.find(w => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1]!;\r\n\r\nexport const parseVW = (sizes?: string): number[] => {\r\n if (!sizes) return [];\r\n const foundSizes = sizes.match(/(\\d+(?:\\.\\d+)?)vw/g) || []\r\n\r\n return foundSizes.map((size) => parseInt(size, 10))\r\n};\r\n\r\n","import { ParamSpec, Path } from './util-types';\r\nimport { TransformationOptions } from './types';\r\nimport { normalizeHex } from './utils';\r\n\r\nexport const PARAMS = [\r\n {path: ['width'], long: 'width', short: 'w'},\r\n {path: ['height'], long: 'height', short: 'h'},\r\n {path: ['dpr'], long: 'dpr', short: 'dpr'},\r\n {path: ['mode'], long: 'mode', short: 'rm'},\r\n {\r\n path: ['background'],\r\n long: 'background',\r\n short: 'bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n\r\n {path: ['format'], long: 'format', short: 'f'},\r\n {path: ['quality'], long: 'quality', short: 'q'},\r\n {path: ['stripMetadata'], long: 'stripMetadata', short: 'st'},\r\n\r\n {path: ['blur'], long: 'blur', short: 'bl'},\r\n {path: ['brightness'], long: 'brightness', short: 'br'},\r\n {path: ['contrast'], long: 'contrast', short: 'ct'},\r\n {path: ['grayscale'], long: 'grayscale', short: 'gs'},\r\n {path: ['saturation'], long: 'saturation', short: 'sa'},\r\n {path: ['sepia'], long: 'sepia', short: 'sp'},\r\n {path: ['sharpen'], long: 'sharpen', short: 'sh'},\r\n {path: ['noise'], long: 'noise', short: 'ns'},\r\n {path: ['rotate'], long: 'rotate', short: 'rt'},\r\n\r\n {path: ['border', 'width'], long: 'border.width', short: 'bo.w'},\r\n {\r\n path: ['border', 'color'],\r\n long: 'border.color',\r\n short: 'bo.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['border', 'radius'], long: 'border.radius', short: 'bo.r'},\r\n\r\n {path: ['crop', 'type'], long: 'crop.type', short: 'cr.t'},\r\n {path: ['crop', 'objectType'], long: 'crop.objectType', short: 'cr.o'},\r\n {path: ['crop', 'focus', 'position', 'x'], long: 'crop.x', short: 'cr.x'},\r\n {path: ['crop', 'focus', 'position', 'y'], long: 'crop.y', short: 'cr.y'},\r\n {path: ['crop', 'focus', 'strategy'], long: 'crop', short: 'cr'},\r\n {path: ['crop', 'width'], long: 'crop.width', short: 'cr.w'},\r\n {path: ['crop', 'height'], long: 'crop.height', short: 'cr.h'},\r\n {path: ['crop', 'afterResize'], long: 'crop.afterResize', short: 'cr.ar'},\r\n\r\n {path: ['text', 'text'], long: 'text', short: 'tx'},\r\n {\r\n path: ['text', 'color'],\r\n long: 'text.color',\r\n short: 'tx.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'opacity'], long: 'text.opacity', short: 'tx.o'},\r\n {path: ['text', 'size'], long: 'text.size', short: 'tx.s'},\r\n {path: ['text', 'font'], long: 'text.font', short: 'tx.f'},\r\n {path: ['text', 'fontSize'], long: 'text.fontSize', short: 'tx.fs'},\r\n {path: ['text', 'position'], long: 'text.position', short: 'tx.p'},\r\n {\r\n path: ['text', 'background'],\r\n long: 'text.background',\r\n short: 'tx.bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'backgroundOpacity'], long: 'text.backgroundOpacity', short: 'tx.bg.o'},\r\n\r\n {path: ['watermark', 'name'], long: 'watermark', short: 'wm'},\r\n {path: ['watermark', 'opacity'], long: 'watermark.opacity', short: 'wm.o'},\r\n {path: ['watermark', 'size'], long: 'watermark.size', short: 'wm.s'},\r\n {path: ['watermark', 'width'], long: 'watermark.width', short: 'wm.w'},\r\n {path: ['watermark', 'height'], long: 'watermark.height', short: 'wm.h'},\r\n {path: ['watermark', 'position'], long: 'watermark.position', short: 'wm.p'},\r\n] as const satisfies readonly ParamSpec<\r\n TransformationOptions,\r\n Path<TransformationOptions>\r\n>[];\r\n","import { TransformationOptions, UrlBuilderConfig } from './types';\r\nimport { getNestedValue, removeTrailingSlash } from './utils';\r\nimport { PARAMS } from './config';\r\n\r\n/**\r\n * Determines which parameter names to use in the query string.\r\n * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)\r\n * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)\r\n */\r\nexport type NameMode = 'short' | 'long';\r\n\r\n/**\r\n * Converts transformation options into a URL-encoded query string.\r\n *\r\n * Iterates through all defined parameters in the PARAMS config, extracts values\r\n * from the options object using their paths, applies any normalization functions\r\n * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.\r\n *\r\n * @param options - The transformation options object\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns URL-encoded query string (without leading `?`)\r\n *\r\n * @example\r\n * ```ts\r\n * // Using short aliases (default)\r\n * buildQueryParams({ width: 800, height: 600, quality: 80 });\r\n * // => 'w=800&h=600&q=80'\r\n *\r\n * // Using long parameter names\r\n * buildQueryParams({ width: 800, format: 'webp' }, 'long');\r\n * // => 'width=800&format=webp'\r\n *\r\n * // Nested options\r\n * buildQueryParams({ border: { width: 2, color: '#ff0000' } });\r\n * // => 'bo.w=2&bo.c=ff0000'\r\n * ```\r\n */\r\nexport const buildTransformationQueryParams = (\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n): string => {\r\n const params: Array<[string, string]> = [];\r\n\r\n for (const spec of PARAMS) {\r\n const value = getNestedValue(options, spec.path);\r\n if (value == null) continue;\r\n\r\n const name =\r\n mode === 'short' && spec.short ? spec.short : spec.long;\r\n\r\n let normalized = value\r\n if ('normalize' in spec) {\r\n normalized = spec.normalize(value)\r\n }\r\n\r\n params.push([name, String(normalized)]);\r\n }\r\n\r\n\r\n return new URLSearchParams(\r\n params.map(([k, v]) => [k, v])\r\n ).toString();\r\n\r\n};\r\n\r\n/**\r\n * Builds a complete transformation URL from a base URL and transformation options.\r\n *\r\n * Combines the configured base URL with query parameters generated from the\r\n * transformation options. Handles the special `original` flag which returns\r\n * the unmodified source image.\r\n *\r\n * @param config - Configuration containing the base URL for the image\r\n * @param options - The transformation options to apply\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns The complete URL string with query parameters\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://example.com/images/photo.jpg?w=400&h=300'\r\n *\r\n * // Multiple transformations\r\n * buildTransformationUrl(config, {\r\n * width: 800,\r\n * format: 'webp',\r\n * quality: 85,\r\n * blur: 5\r\n * });\r\n * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'\r\n *\r\n * // Request original image (no transformations)\r\n * buildTransformationUrl(config, { original: true });\r\n * // => 'https://example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://example.com/images/photo.jpg?width=400'\r\n * ```\r\n */\r\n/**\r\n * Extracts the base URL path without query parameters\r\n */\r\nconst getBaseUrlWithoutQuery = (url: string): string => {\r\n const queryIndex = url.indexOf('?');\r\n return queryIndex === -1 ? url : url.slice(0, queryIndex);\r\n};\r\n\r\nexport const buildTransformationUrl = (\r\n config: UrlBuilderConfig,\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n) => {\r\n // Strip any existing query params from baseUrl - transformations replace them\r\n const baseUrl = removeTrailingSlash(getBaseUrlWithoutQuery(config.baseUrl));\r\n\r\n if (options.original) {\r\n return `${baseUrl}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(options, mode);\r\n\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
1
+ {"version":3,"sources":["../src/src-set.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { buildTransformationUrl, NameMode } from './url-builder';\r\nimport { TransformationOptions } from './types';\r\nimport { clampMax, getFinalUrl, nearest, parseVW } from './utils';\r\n\r\n/**\r\n * Maximum supported image width\r\n */\r\nexport const MAX_IMAGE_WIDTH = 4096;\r\n\r\n/**\r\n * Default device breakpoints for responsive srcset generation\r\n */\r\nexport const DEFAULT_DEVICE_BREAKPOINTS = [\r\n 320,\r\n 375,\r\n 640,\r\n 768,\r\n 1024,\r\n 1280,\r\n 1536,\r\n 1920,\r\n 2048,\r\n 3840\r\n] as const;\r\n\r\n/**\r\n * Default image breakpoints for smaller images (icons, thumbnails)\r\n */\r\nexport const DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384] as const;\r\n\r\n/**\r\n * Options for responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageOptions {\r\n /**\r\n * The `sizes` attribute value (e.g., \"100vw\", \"(max-width: 768px) 100vw, 50vw\").\r\n * When provided, generates width descriptors (`w`) for responsive layouts.\r\n */\r\n sizes?: string;\r\n /**\r\n * Fixed display width in CSS pixels.\r\n * When provided without `sizes`, generates DPR descriptors (`x`).\r\n */\r\n width?: number;\r\n /** Device breakpoints for viewport-based sizing (default: DEFAULT_DEVICE_BREAKPOINTS) */\r\n deviceBreakpoints?: number[];\r\n /** Image breakpoints for smaller images (default: DEFAULT_IMAGE_BREAKPOINTS) */\r\n imageBreakpoints?: number[];\r\n /** Base transformation options to apply to all variants */\r\n transformations?: TransformationOptions;\r\n /** Whether to use short or long parameter names (default: 'short') */\r\n mode?: NameMode;\r\n maxDpr?: number\r\n}\r\n\r\n/**\r\n * Result of responsive image attributes generation\r\n */\r\nexport interface ResponsiveImageResult {\r\n /** The src attribute value (largest/default variant) */\r\n src: string;\r\n /** The srcset attribute value */\r\n srcSet?: string;\r\n /** The sizes attribute value (for width descriptors) */\r\n sizes?: string;\r\n /** The width attribute value (when explicitly provided) */\r\n width?: number;\r\n}\r\n\r\n/**\r\n * Calculates candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction calculatesCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n maxDpr: number\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr,\r\n maxDpr\r\n } = params;\r\n\r\n if (!allBreakpoints.length || !deviceBreakpoints.length) {\r\n return {candidates: [], descriptor: 'w'};\r\n }\r\n\r\n const minDevice = deviceBreakpoints[0]!;\r\n const maxDevice = deviceBreakpoints[deviceBreakpoints.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n\r\n // When no sizes with vw definition is provided go for x descriptor\r\n if (explicitWidth && !hasVW) {\r\n const DPRs = [1, 2, 3, 4].filter(item => item <= maxDpr);\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(allBreakpoints, explicitWidth * dpr))\r\n .map(clampMax)\r\n )\r\n ).filter(w => w <= MAX_IMAGE_WIDTH);\r\n\r\n return {\r\n candidates,\r\n descriptor: 'x'\r\n };\r\n }\r\n\r\n\r\n // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const lowestRatio = Math.min(...vwRatios) / 100;\r\n const minRequiredPx = minDevice * lowestRatio;\r\n\r\n\r\n return {\r\n // Responsive layout only uses device breakpoints\r\n candidates: deviceBreakpoints.filter(w => w >= minRequiredPx && w <= MAX_IMAGE_WIDTH),\r\n descriptor: 'w',\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const upperLimit = maxDevice * maxDpr;\r\n\r\n return {\r\n candidates: allBreakpoints.filter(w => w <= upperLimit),\r\n descriptor: 'w'\r\n };\r\n}\r\n\r\n/**\r\n * Generates responsive image attributes (src, srcSet, sizes) for optimal loading.\r\n *\r\n * Supports two strategies:\r\n * 1. **Responsive (with `sizes`)**: Uses width descriptors (`w`) for fluid layouts\r\n * where image size varies with viewport.\r\n * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size\r\n * images that need high-DPI support.\r\n *\r\n * @param imageSrc - Relative or an absolute path to the image\r\n * @param baseUrl - This should be your baseURL endpoint for the source from PixelFiddle Dashboard.\r\n * @param options - Options for responsive image generation\r\n * @returns Object containing src, srcSet, and optionally sizes attributes\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/photo.jpg' };\r\n *\r\n * // Responsive image with sizes attribute (uses `w` descriptors)\r\n * createResponsiveAttributes(config, { sizes: '(max-width: 768px) 100vw, 50vw' });\r\n * // => {\r\n * // src: '...?w=3840',\r\n * // srcSet: '...?w=640 640w, ...?w=750 750w, ..., ...?w=3840 3840w',\r\n * // sizes: '(max-width: 768px) 100vw, 50vw'\r\n * // }\r\n *\r\n * // Fixed-width image (uses `x` descriptors)\r\n * createResponsiveAttributes(config, { width: 400 });\r\n * // => {\r\n * // src: '...?w=384',\r\n * // srcSet: '...?w=384 1x, ...?w=828 2x',\r\n * // width: 400\r\n * // }\r\n *\r\n * // With transformations\r\n * createResponsiveAttributes(config, {\r\n * sizes: '100vw',\r\n * transformations: { format: 'WEBP', quality: 80 }\r\n * });\r\n * ```\r\n */\r\nexport const createResponsiveAttributes = (\r\n imageSrc: string,\r\n baseUrl?: string,\r\n options?: ResponsiveImageOptions\r\n): ResponsiveImageResult => {\r\n const {\r\n sizes,\r\n width,\r\n deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],\r\n imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],\r\n transformations = {},\r\n mode = 'short',\r\n maxDpr = DEFAULT_MAX_DPR\r\n } = options || {}\r\n\r\n // If transformations.width is set, it takes precedence as the base width\r\n const baseWidth = transformations.width ?? width;\r\n\r\n const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);\r\n const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);\r\n\r\n const allBreakpoints = [...new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);\r\n\r\n const {candidates, descriptor} = calculatesCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(baseWidth !== undefined && {explicitWidth: baseWidth}),\r\n ...(sizes !== undefined && {sizesAttr: sizes}),\r\n maxDpr\r\n });\r\n\r\n if (candidates.length === 0) {\r\n // Fallback: no valid candidates, return base URL\r\n return {src: getFinalUrl(imageSrc, baseUrl)};\r\n }\r\n\r\n // Build srcSet entries\r\n const srcSetEntries = candidates.map((w, index,) => buildSrcEntries(imageSrc, w, index, transformations, mode, descriptor, baseUrl));\r\n\r\n // Default src is the largest candidate\r\n const largestWidth = candidates[candidates.length - 1]!;\r\n const src = buildTransformationUrl({\r\n src: imageSrc,\r\n baseUrl,\r\n transformations: {\r\n ...transformations,\r\n width: largestWidth\r\n },\r\n mode\r\n }\r\n );\r\n\r\n const endSizes = sizes ?? (descriptor === 'w' ? '100vw' : undefined);\r\n\r\n return {\r\n src,\r\n ...(endSizes ? {sizes: endSizes} : {}),\r\n srcSet: srcSetEntries.join(', '),\r\n ...(width !== undefined ? {width} : {}),\r\n };\r\n};\r\n\r\nfunction buildSrcEntries(imageSrc: string, width: number, index: number, transformations: TransformationOptions, mode: NameMode, descriptor: 'w' | 'x', baseUrl?: string,): string {\r\n const url = buildTransformationUrl({\r\n src: imageSrc,\r\n baseUrl,\r\n transformations: {...transformations, width: width},\r\n mode\r\n }\r\n );\r\n\r\n const desc = descriptor === 'w' ? `${width}w` : `${index + 1}x`;\r\n\r\n return `${url} ${desc}`;\r\n}\r\n","import { Path, PathValue } from './util-types';\r\nimport { MAX_IMAGE_WIDTH } from './src-set';\r\n\r\nexport const normalizeHex = (value: string) => value.replace('#', '')\r\n\r\n\r\nexport const removeTrailingSlash = (baseUrl: string) => {\r\n return baseUrl.endsWith('/')\r\n ? baseUrl.slice(0, -1)\r\n : baseUrl;\r\n}\r\n\r\nexport const getNestedValue = <\r\n T,\r\n P extends Path<T>\r\n>(\r\n obj: T,\r\n path: P\r\n): PathValue<T, P> | undefined =>\r\n path.reduce<any>(\r\n (acc, key) => (acc == null ? undefined : acc[key]),\r\n obj\r\n );\r\n\r\n\r\nexport const clampMax = (v: number) => Math.min(v, MAX_IMAGE_WIDTH);\r\n\r\nexport const nearest = (sortedBreakpoints: number[],target: number) =>\r\n sortedBreakpoints.find(w => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1]!;\r\n\r\nexport const parseVW = (sizes?: string): number[] => {\r\n if (!sizes) return [];\r\n const foundSizes = sizes.match(/(\\d+(?:\\.\\d+)?)vw/g) || []\r\n\r\n return foundSizes.map((size) => parseInt(size, 10))\r\n};\r\n\r\n/**\r\n * Extracts the base URL path without query parameters\r\n */\r\nconst getBaseUrlWithoutQuery = (url: string | undefined): string => {\r\n if (!url) return '';\r\n const queryIndex = url.indexOf('?');\r\n return queryIndex === -1 ? url : url.slice(0, queryIndex);\r\n};\r\n\r\n/**\r\n * Checks if a URL is absolute (starts with http:// or https://)\r\n */\r\nconst isAbsoluteUrl = (url: string | undefined): boolean => {\r\n if (!url) return false;\r\n return url.startsWith('http://') || url.startsWith('https://');\r\n};\r\n\r\n\r\nexport function getFinalUrl(src: string, baseUrl?: string): string {\r\n const cleanSrc = getBaseUrlWithoutQuery(src);\r\n\r\n if (isAbsoluteUrl(cleanSrc)) {\r\n return removeTrailingSlash(cleanSrc);\r\n } else {\r\n // Relative path - combine with baseUrl\r\n const base = removeTrailingSlash(getBaseUrlWithoutQuery(baseUrl));\r\n\r\n // Ensure path has leading slash for proper URL construction\r\n const normalizedPath = normalizePath(cleanSrc)\r\n return `${base}${normalizedPath}`;\r\n }\r\n\r\n}\r\n\r\nexport function normalizePath(src: string): string {\r\n return src && !src.startsWith('/') ? `/${src}` : src;\r\n}\r\n\r\n\r\nexport const parseNumberLikeParam = (\r\n width: number | `${number}`\r\n): number => {\r\n if (typeof width === 'number') {\r\n return width;\r\n }\r\n\r\n const parsed = Number(width);\r\n\r\n if (!Number.isFinite(parsed)) {\r\n throw new Error(`Invalid width value: ${width}`);\r\n }\r\n\r\n return parsed;\r\n};\r\n","import { ParamSpec, Path } from './util-types';\r\nimport { TransformationOptions } from './types';\r\nimport { normalizeHex } from './utils';\r\n\r\nexport const PARAMS = [\r\n {path: ['width'], long: 'width', short: 'w'},\r\n {path: ['height'], long: 'height', short: 'h'},\r\n {path: ['dpr'], long: 'dpr', short: 'dpr'},\r\n {path: ['mode'], long: 'mode', short: 'rm'},\r\n {\r\n path: ['background'],\r\n long: 'background',\r\n short: 'bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n\r\n {path: ['format'], long: 'format', short: 'f'},\r\n {path: ['quality'], long: 'quality', short: 'q'},\r\n {path: ['stripMetadata'], long: 'stripMetadata', short: 'st'},\r\n\r\n {path: ['blur'], long: 'blur', short: 'bl'},\r\n {path: ['brightness'], long: 'brightness', short: 'br'},\r\n {path: ['contrast'], long: 'contrast', short: 'ct'},\r\n {path: ['grayscale'], long: 'grayscale', short: 'gs'},\r\n {path: ['saturation'], long: 'saturation', short: 'sa'},\r\n {path: ['sepia'], long: 'sepia', short: 'sp'},\r\n {path: ['sharpen'], long: 'sharpen', short: 'sh'},\r\n {path: ['noise'], long: 'noise', short: 'ns'},\r\n {path: ['rotate'], long: 'rotate', short: 'rt'},\r\n\r\n {path: ['border', 'width'], long: 'border.width', short: 'bo.w'},\r\n {\r\n path: ['border', 'color'],\r\n long: 'border.color',\r\n short: 'bo.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['border', 'radius'], long: 'border.radius', short: 'bo.r'},\r\n\r\n {path: ['crop', 'type'], long: 'crop.type', short: 'cr.t'},\r\n {path: ['crop', 'objectType'], long: 'crop.objectType', short: 'cr.o'},\r\n {path: ['crop', 'focus', 'position', 'x'], long: 'crop.x', short: 'cr.x'},\r\n {path: ['crop', 'focus', 'position', 'y'], long: 'crop.y', short: 'cr.y'},\r\n {path: ['crop', 'focus', 'strategy'], long: 'crop', short: 'cr'},\r\n {path: ['crop', 'width'], long: 'crop.width', short: 'cr.w'},\r\n {path: ['crop', 'height'], long: 'crop.height', short: 'cr.h'},\r\n {path: ['crop', 'afterResize'], long: 'crop.afterResize', short: 'cr.ar'},\r\n\r\n {path: ['text', 'text'], long: 'text', short: 'tx'},\r\n {\r\n path: ['text', 'color'],\r\n long: 'text.color',\r\n short: 'tx.c',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'opacity'], long: 'text.opacity', short: 'tx.o'},\r\n {path: ['text', 'size'], long: 'text.size', short: 'tx.s'},\r\n {path: ['text', 'font'], long: 'text.font', short: 'tx.f'},\r\n {path: ['text', 'fontSize'], long: 'text.fontSize', short: 'tx.fs'},\r\n {path: ['text', 'position'], long: 'text.position', short: 'tx.p'},\r\n {\r\n path: ['text', 'background'],\r\n long: 'text.background',\r\n short: 'tx.bg',\r\n normalize: (v) => typeof v === 'string' ? normalizeHex(v) : v\r\n },\r\n {path: ['text', 'backgroundOpacity'], long: 'text.backgroundOpacity', short: 'tx.bg.o'},\r\n\r\n {path: ['watermark', 'name'], long: 'watermark', short: 'wm'},\r\n {path: ['watermark', 'opacity'], long: 'watermark.opacity', short: 'wm.o'},\r\n {path: ['watermark', 'size'], long: 'watermark.size', short: 'wm.s'},\r\n {path: ['watermark', 'width'], long: 'watermark.width', short: 'wm.w'},\r\n {path: ['watermark', 'height'], long: 'watermark.height', short: 'wm.h'},\r\n {path: ['watermark', 'position'], long: 'watermark.position', short: 'wm.p'},\r\n] as const satisfies readonly ParamSpec<\r\n TransformationOptions,\r\n Path<TransformationOptions>\r\n>[];\r\n","import { BuildTransformationConfig, TransformationOptions } from './types';\r\nimport { getFinalUrl, getNestedValue } from './utils';\r\nimport { PARAMS } from './config';\r\n\r\n/**\r\n * Determines which parameter names to use in the query string.\r\n * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)\r\n * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)\r\n */\r\nexport type NameMode = 'short' | 'long';\r\n\r\n/**\r\n * Converts transformation options into a URL-encoded query string.\r\n *\r\n * Iterates through all defined parameters in the PARAMS config, extracts values\r\n * from the options object using their paths, applies any normalization functions\r\n * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.\r\n *\r\n * @param options - The transformation options object\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns URL-encoded query string (without leading `?`)\r\n *\r\n * @example\r\n * ```ts\r\n * // Using short aliases (default)\r\n * buildQueryParams({ width: 800, height: 600, quality: 80 });\r\n * // => 'w=800&h=600&q=80'\r\n *\r\n * // Using long parameter names\r\n * buildQueryParams({ width: 800, format: 'webp' }, 'long');\r\n * // => 'width=800&format=webp'\r\n *\r\n * // Nested options\r\n * buildQueryParams({ border: { width: 2, color: '#ff0000' } });\r\n * // => 'bo.w=2&bo.c=ff0000'\r\n * ```\r\n */\r\nexport const buildTransformationQueryParams = (\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n): string => {\r\n const params: Array<[string, string]> = [];\r\n\r\n for (const spec of PARAMS) {\r\n const value = getNestedValue(options, spec.path);\r\n if (value == null) continue;\r\n\r\n const name =\r\n mode === 'short' && spec.short ? spec.short : spec.long;\r\n\r\n let normalized = value\r\n if ('normalize' in spec) {\r\n normalized = spec.normalize(value)\r\n }\r\n\r\n params.push([name, String(normalized)]);\r\n }\r\n\r\n\r\n return new URLSearchParams(\r\n params.map(([k, v]) => [k, v])\r\n ).toString();\r\n\r\n};\r\n\r\n/**\r\n * Builds a complete transformation URL from a base URL and transformation options.\r\n *\r\n * Combines the configured base URL with query parameters generated from the\r\n * transformation options. Handles the special `original` flag which returns\r\n * the unmodified source image.\r\n *\r\n * @param src - Absolute or relative path to your image\r\n * @param config - Configuration containing the base URL for the image\r\n * @param transformations - The transformation options to apply\r\n * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)\r\n * @returns The complete URL string with query parameters\r\n *\r\n * @example\r\n * ```ts\r\n * const config = { baseUrl: 'https://example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://example.com/images/photo.jpg?w=400&h=300'\r\n *\r\n * // Multiple transformations\r\n * buildTransformationUrl(config, {\r\n * width: 800,\r\n * format: 'webp',\r\n * quality: 85,\r\n * blur: 5\r\n * });\r\n * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'\r\n *\r\n * // Request original image (no transformations)\r\n * buildTransformationUrl(config, { original: true });\r\n * // => 'https://example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://example.com/images/photo.jpg?width=400'\r\n * ```\r\n */\r\nexport const buildTransformationUrl = (\r\n {src, transformations = {}, baseUrl, mode = 'short'}: BuildTransformationConfig\r\n) => {\r\n const url = getFinalUrl(src, baseUrl)\r\n\r\n if (transformations.original) {\r\n return `${url}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(transformations, mode);\r\n\r\n return `${url}?${query}`;\r\n};\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixelfiddler/core",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Core utilities for PixelFiddler image transformation SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",