@pixelfiddler/core 0.1.5 → 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
@@ -10,31 +10,32 @@ var DEFAULT_DEVICE_BREAKPOINTS = [
10
10
  1024,
11
11
  1280,
12
12
  1536,
13
- 1920
13
+ 1920,
14
+ 2048,
15
+ 3840
14
16
  ];
15
17
  var DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384];
16
18
  var DEFAULT_MAX_DPR = 2;
17
- function computeCandidateWidths(params) {
19
+ function calculatesCandidateWidths(params) {
18
20
  const {
19
21
  allBreakpoints,
20
22
  deviceBreakpoints,
21
23
  explicitWidth,
22
- sizesAttr
24
+ sizesAttr,
25
+ maxDpr
23
26
  } = params;
24
- const sortedAll = [...new Set(allBreakpoints)].sort((a, b) => a - b);
25
- const sortedDevice = [...new Set(deviceBreakpoints)].sort((a, b) => a - b);
26
- if (!sortedAll.length || !sortedDevice.length) {
27
+ if (!allBreakpoints.length || !deviceBreakpoints.length) {
27
28
  return { candidates: [], descriptor: "w" };
28
29
  }
29
- const minDevice = sortedDevice[0];
30
- const maxDevice = sortedDevice[sortedDevice.length - 1];
30
+ const minDevice = deviceBreakpoints[0];
31
+ const maxDevice = deviceBreakpoints[deviceBreakpoints.length - 1];
31
32
  const vwRatios = parseVW(sizesAttr);
32
33
  const hasVW = vwRatios.length > 0;
33
- if (typeof explicitWidth === "number" && !hasVW) {
34
- const DPRs = [1, 2, 3];
34
+ if (explicitWidth && !hasVW) {
35
+ const DPRs = [1, 2, 3, 4].filter((item) => item <= maxDpr);
35
36
  const candidates = Array.from(
36
37
  new Set(
37
- DPRs.map((dpr) => nearest(sortedAll, explicitWidth * dpr)).map(clampMax)
38
+ DPRs.map((dpr) => nearest(allBreakpoints, explicitWidth * dpr)).map(clampMax)
38
39
  )
39
40
  ).filter((w) => w <= MAX_IMAGE_WIDTH);
40
41
  return {
@@ -43,52 +44,56 @@ function computeCandidateWidths(params) {
43
44
  };
44
45
  }
45
46
  if (hasVW) {
46
- const minRatio = Math.min(...vwRatios);
47
- const maxRatio = Math.max(...vwRatios);
48
- const minPx = minDevice * minRatio;
49
- const maxPx = maxDevice * maxRatio * DEFAULT_MAX_DPR;
50
- const candidates = sortedAll.filter(
51
- (w) => w >= minPx && w <= clampMax(maxPx)
52
- );
47
+ const lowestRatio = Math.min(...vwRatios) / 100;
48
+ const minRequiredPx = minDevice * lowestRatio;
53
49
  return {
54
- candidates,
50
+ // Responsive layout only uses device breakpoints
51
+ candidates: deviceBreakpoints.filter((w) => w >= minRequiredPx && w <= MAX_IMAGE_WIDTH),
55
52
  descriptor: "w"
56
53
  };
57
54
  }
58
- const maxUseful = maxDevice * DEFAULT_MAX_DPR;
55
+ const upperLimit = maxDevice * maxDpr;
59
56
  return {
60
- candidates: sortedAll.filter((w) => w <= clampMax(maxUseful)),
57
+ candidates: allBreakpoints.filter((w) => w <= upperLimit),
61
58
  descriptor: "w"
62
59
  };
63
60
  }
64
- var createResponsiveAttributes = (config, options = {}) => {
61
+ var createResponsiveAttributes = (imageSrc, baseUrl, options) => {
65
62
  const {
66
63
  sizes,
67
64
  width,
68
65
  deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],
69
66
  imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],
70
67
  transformations = {},
71
- mode = "short"
72
- } = options;
68
+ mode = "short",
69
+ maxDpr = DEFAULT_MAX_DPR
70
+ } = options || {};
73
71
  const baseWidth = transformations.width ?? width;
74
72
  const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);
75
73
  const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);
76
74
  const allBreakpoints = [.../* @__PURE__ */ new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);
77
- const { candidates, descriptor } = computeCandidateWidths({
75
+ const { candidates, descriptor } = calculatesCandidateWidths({
78
76
  allBreakpoints,
79
77
  deviceBreakpoints: sortedDeviceBreakpoints,
80
78
  ...baseWidth !== void 0 && { explicitWidth: baseWidth },
81
- ...sizes !== void 0 && { sizesAttr: sizes }
79
+ ...sizes !== void 0 && { sizesAttr: sizes },
80
+ maxDpr
82
81
  });
83
82
  if (candidates.length === 0) {
84
- return { src: config.baseUrl };
83
+ return { src: getFinalUrl(imageSrc, baseUrl) };
85
84
  }
86
- 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));
87
86
  const largestWidth = candidates[candidates.length - 1];
88
87
  const src = buildTransformationUrl(
89
- config,
90
- { ...transformations, width: largestWidth },
91
- mode
88
+ {
89
+ src: imageSrc,
90
+ baseUrl,
91
+ transformations: {
92
+ ...transformations,
93
+ width: largestWidth
94
+ },
95
+ mode
96
+ }
92
97
  );
93
98
  const endSizes = sizes ?? (descriptor === "w" ? "100vw" : void 0);
94
99
  return {
@@ -98,11 +103,14 @@ var createResponsiveAttributes = (config, options = {}) => {
98
103
  ...width !== void 0 ? { width } : {}
99
104
  };
100
105
  };
101
- function buildSrcEntries(width, index, config, transformations, mode, descriptor) {
106
+ function buildSrcEntries(imageSrc, width, index, transformations, mode, descriptor, baseUrl) {
102
107
  const url = buildTransformationUrl(
103
- config,
104
- { ...transformations, width },
105
- mode
108
+ {
109
+ src: imageSrc,
110
+ baseUrl,
111
+ transformations: { ...transformations, width },
112
+ mode
113
+ }
106
114
  );
107
115
  const desc = descriptor === "w" ? `${width}w` : `${index + 1}x`;
108
116
  return `${url} ${desc}`;
@@ -121,9 +129,40 @@ var clampMax = (v) => Math.min(v, MAX_IMAGE_WIDTH);
121
129
  var nearest = (sortedBreakpoints, target) => sortedBreakpoints.find((w) => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1];
122
130
  var parseVW = (sizes) => {
123
131
  if (!sizes) return [];
124
- return [...sizes.matchAll(/(\d+(?:\.\d+)?)vw/g)].map(
125
- (m) => Number(m[1]) / 100
126
- );
132
+ const foundSizes = sizes.match(/(\d+(?:\.\d+)?)vw/g) || [];
133
+ return foundSizes.map((size) => parseInt(size, 10));
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;
127
166
  };
128
167
 
129
168
  // src/config.ts
@@ -210,21 +249,18 @@ var buildTransformationQueryParams = (options, mode = "short") => {
210
249
  params.map(([k, v]) => [k, v])
211
250
  ).toString();
212
251
  };
213
- var getBaseUrlWithoutQuery = (url) => {
214
- const queryIndex = url.indexOf("?");
215
- return queryIndex === -1 ? url : url.slice(0, queryIndex);
216
- };
217
- var buildTransformationUrl = (config, options, mode = "short") => {
218
- const baseUrl = removeTrailingSlash(getBaseUrlWithoutQuery(config.baseUrl));
219
- if (options.original) {
220
- 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`;
221
256
  }
222
- const query = buildTransformationQueryParams(options, mode);
223
- return `${baseUrl}?${query}`;
257
+ const query = buildTransformationQueryParams(transformations, mode);
258
+ return `${url}?${query}`;
224
259
  };
225
260
 
226
261
  exports.buildTransformationQueryParams = buildTransformationQueryParams;
227
262
  exports.buildTransformationUrl = buildTransformationUrl;
228
263
  exports.createResponsiveAttributes = createResponsiveAttributes;
264
+ exports.parseNumberLikeParam = parseNumberLikeParam;
229
265
  //# sourceMappingURL=index.cjs.map
230
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] 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}\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 * Computes candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction computeCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr\r\n } = params;\r\n\r\n // ---- Normalize & guard ----\r\n const sortedAll = [...new Set(allBreakpoints)].sort((a, b) => a - b);\r\n const sortedDevice = [...new Set(deviceBreakpoints)].sort((a, b) => a - b);\r\n\r\n if (!sortedAll.length || !sortedDevice.length) {\r\n return { candidates: [], descriptor: 'w' };\r\n }\r\n\r\n const minDevice = sortedDevice[0]!;\r\n const maxDevice = sortedDevice[sortedDevice.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n // Explicit width (fixed layout) → x descriptors ----\r\n // Prefer this when layout width is known and sizes does NOT imply vw scaling\r\n if (typeof explicitWidth === 'number' && !hasVW) {\r\n const DPRs = [1, 2, 3];\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(sortedAll, 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 // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const minRatio = Math.min(...vwRatios);\r\n const maxRatio = Math.max(...vwRatios);\r\n\r\n const minPx = minDevice * minRatio;\r\n const maxPx = maxDevice * maxRatio * DEFAULT_MAX_DPR;\r\n\r\n const candidates = sortedAll.filter(\r\n w => w >= minPx && w <= clampMax(maxPx)\r\n );\r\n\r\n return {\r\n candidates,\r\n descriptor: 'w'\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const maxUseful = maxDevice * DEFAULT_MAX_DPR;\r\n\r\n return {\r\n candidates: sortedAll.filter(w => w <= clampMax(maxUseful)),\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 } = 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 } = computeCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(baseWidth !== undefined && { explicitWidth: baseWidth }),\r\n ...(sizes !== undefined && { sizesAttr: sizes }),\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 return [...sizes.matchAll(/(\\d+(?:\\.\\d+)?)vw/g)].map(\r\n m => Number(m[1]) / 100\r\n );\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,8 @@ 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;
314
+ /** Max DPR that you want responsive srcSet to support, defaults to 2 */
315
+ maxDpr?: number;
242
316
  }
243
317
  /**
244
318
  * URL builder configuration (internal)
@@ -247,41 +321,12 @@ interface UrlBuilderConfig extends PixelFiddlerConfig {
247
321
  /** Resolved base URL */
248
322
  baseUrl: string;
249
323
  }
250
-
251
- /**
252
- * Determines which parameter names to use in the query string.
253
- * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)
254
- * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)
255
- */
256
- type NameMode = 'short' | 'long';
257
- /**
258
- * Converts transformation options into a URL-encoded query string.
259
- *
260
- * Iterates through all defined parameters in the PARAMS config, extracts values
261
- * from the options object using their paths, applies any normalization functions
262
- * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.
263
- *
264
- * @param options - The transformation options object
265
- * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)
266
- * @returns URL-encoded query string (without leading `?`)
267
- *
268
- * @example
269
- * ```ts
270
- * // Using short aliases (default)
271
- * buildQueryParams({ width: 800, height: 600, quality: 80 });
272
- * // => 'w=800&h=600&q=80'
273
- *
274
- * // Using long parameter names
275
- * buildQueryParams({ width: 800, format: 'webp' }, 'long');
276
- * // => 'width=800&format=webp'
277
- *
278
- * // Nested options
279
- * buildQueryParams({ border: { width: 2, color: '#ff0000' } });
280
- * // => 'bo.w=2&bo.c=ff0000'
281
- * ```
282
- */
283
- declare const buildTransformationQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
284
- 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
+ };
285
330
 
286
331
  /**
287
332
  * Options for responsive image attributes generation
@@ -305,6 +350,7 @@ interface ResponsiveImageOptions {
305
350
  transformations?: TransformationOptions;
306
351
  /** Whether to use short or long parameter names (default: 'short') */
307
352
  mode?: NameMode;
353
+ maxDpr?: number;
308
354
  }
309
355
  /**
310
356
  * Result of responsive image attributes generation
@@ -328,7 +374,8 @@ interface ResponsiveImageResult {
328
374
  * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size
329
375
  * images that need high-DPI support.
330
376
  *
331
- * @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.
332
379
  * @param options - Options for responsive image generation
333
380
  * @returns Object containing src, srcSet, and optionally sizes attributes
334
381
  *
@@ -359,6 +406,8 @@ interface ResponsiveImageResult {
359
406
  * });
360
407
  * ```
361
408
  */
362
- 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;
363
412
 
364
- 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,8 @@ 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;
314
+ /** Max DPR that you want responsive srcSet to support, defaults to 2 */
315
+ maxDpr?: number;
242
316
  }
243
317
  /**
244
318
  * URL builder configuration (internal)
@@ -247,41 +321,12 @@ interface UrlBuilderConfig extends PixelFiddlerConfig {
247
321
  /** Resolved base URL */
248
322
  baseUrl: string;
249
323
  }
250
-
251
- /**
252
- * Determines which parameter names to use in the query string.
253
- * - `'short'` - Use abbreviated aliases (e.g., `w`, `h`, `q`)
254
- * - `'long'` - Use full parameter names (e.g., `width`, `height`, `quality`)
255
- */
256
- type NameMode = 'short' | 'long';
257
- /**
258
- * Converts transformation options into a URL-encoded query string.
259
- *
260
- * Iterates through all defined parameters in the PARAMS config, extracts values
261
- * from the options object using their paths, applies any normalization functions
262
- * (e.g., stripping `#` from hex colors), and returns a URL-encoded query string.
263
- *
264
- * @param options - The transformation options object
265
- * @param mode - Whether to use short aliases or long parameter names (default: `'short'`)
266
- * @returns URL-encoded query string (without leading `?`)
267
- *
268
- * @example
269
- * ```ts
270
- * // Using short aliases (default)
271
- * buildQueryParams({ width: 800, height: 600, quality: 80 });
272
- * // => 'w=800&h=600&q=80'
273
- *
274
- * // Using long parameter names
275
- * buildQueryParams({ width: 800, format: 'webp' }, 'long');
276
- * // => 'width=800&format=webp'
277
- *
278
- * // Nested options
279
- * buildQueryParams({ border: { width: 2, color: '#ff0000' } });
280
- * // => 'bo.w=2&bo.c=ff0000'
281
- * ```
282
- */
283
- declare const buildTransformationQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
284
- 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
+ };
285
330
 
286
331
  /**
287
332
  * Options for responsive image attributes generation
@@ -305,6 +350,7 @@ interface ResponsiveImageOptions {
305
350
  transformations?: TransformationOptions;
306
351
  /** Whether to use short or long parameter names (default: 'short') */
307
352
  mode?: NameMode;
353
+ maxDpr?: number;
308
354
  }
309
355
  /**
310
356
  * Result of responsive image attributes generation
@@ -328,7 +374,8 @@ interface ResponsiveImageResult {
328
374
  * 2. **Fixed width (with `width`)**: Uses DPR descriptors (`x`) for fixed-size
329
375
  * images that need high-DPI support.
330
376
  *
331
- * @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.
332
379
  * @param options - Options for responsive image generation
333
380
  * @returns Object containing src, srcSet, and optionally sizes attributes
334
381
  *
@@ -359,6 +406,8 @@ interface ResponsiveImageResult {
359
406
  * });
360
407
  * ```
361
408
  */
362
- 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;
363
412
 
364
- 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
@@ -8,31 +8,32 @@ var DEFAULT_DEVICE_BREAKPOINTS = [
8
8
  1024,
9
9
  1280,
10
10
  1536,
11
- 1920
11
+ 1920,
12
+ 2048,
13
+ 3840
12
14
  ];
13
15
  var DEFAULT_IMAGE_BREAKPOINTS = [16, 32, 48, 64, 96, 128, 256, 384];
14
16
  var DEFAULT_MAX_DPR = 2;
15
- function computeCandidateWidths(params) {
17
+ function calculatesCandidateWidths(params) {
16
18
  const {
17
19
  allBreakpoints,
18
20
  deviceBreakpoints,
19
21
  explicitWidth,
20
- sizesAttr
22
+ sizesAttr,
23
+ maxDpr
21
24
  } = params;
22
- const sortedAll = [...new Set(allBreakpoints)].sort((a, b) => a - b);
23
- const sortedDevice = [...new Set(deviceBreakpoints)].sort((a, b) => a - b);
24
- if (!sortedAll.length || !sortedDevice.length) {
25
+ if (!allBreakpoints.length || !deviceBreakpoints.length) {
25
26
  return { candidates: [], descriptor: "w" };
26
27
  }
27
- const minDevice = sortedDevice[0];
28
- const maxDevice = sortedDevice[sortedDevice.length - 1];
28
+ const minDevice = deviceBreakpoints[0];
29
+ const maxDevice = deviceBreakpoints[deviceBreakpoints.length - 1];
29
30
  const vwRatios = parseVW(sizesAttr);
30
31
  const hasVW = vwRatios.length > 0;
31
- if (typeof explicitWidth === "number" && !hasVW) {
32
- const DPRs = [1, 2, 3];
32
+ if (explicitWidth && !hasVW) {
33
+ const DPRs = [1, 2, 3, 4].filter((item) => item <= maxDpr);
33
34
  const candidates = Array.from(
34
35
  new Set(
35
- DPRs.map((dpr) => nearest(sortedAll, explicitWidth * dpr)).map(clampMax)
36
+ DPRs.map((dpr) => nearest(allBreakpoints, explicitWidth * dpr)).map(clampMax)
36
37
  )
37
38
  ).filter((w) => w <= MAX_IMAGE_WIDTH);
38
39
  return {
@@ -41,52 +42,56 @@ function computeCandidateWidths(params) {
41
42
  };
42
43
  }
43
44
  if (hasVW) {
44
- const minRatio = Math.min(...vwRatios);
45
- const maxRatio = Math.max(...vwRatios);
46
- const minPx = minDevice * minRatio;
47
- const maxPx = maxDevice * maxRatio * DEFAULT_MAX_DPR;
48
- const candidates = sortedAll.filter(
49
- (w) => w >= minPx && w <= clampMax(maxPx)
50
- );
45
+ const lowestRatio = Math.min(...vwRatios) / 100;
46
+ const minRequiredPx = minDevice * lowestRatio;
51
47
  return {
52
- candidates,
48
+ // Responsive layout only uses device breakpoints
49
+ candidates: deviceBreakpoints.filter((w) => w >= minRequiredPx && w <= MAX_IMAGE_WIDTH),
53
50
  descriptor: "w"
54
51
  };
55
52
  }
56
- const maxUseful = maxDevice * DEFAULT_MAX_DPR;
53
+ const upperLimit = maxDevice * maxDpr;
57
54
  return {
58
- candidates: sortedAll.filter((w) => w <= clampMax(maxUseful)),
55
+ candidates: allBreakpoints.filter((w) => w <= upperLimit),
59
56
  descriptor: "w"
60
57
  };
61
58
  }
62
- var createResponsiveAttributes = (config, options = {}) => {
59
+ var createResponsiveAttributes = (imageSrc, baseUrl, options) => {
63
60
  const {
64
61
  sizes,
65
62
  width,
66
63
  deviceBreakpoints = [...DEFAULT_DEVICE_BREAKPOINTS],
67
64
  imageBreakpoints = [...DEFAULT_IMAGE_BREAKPOINTS],
68
65
  transformations = {},
69
- mode = "short"
70
- } = options;
66
+ mode = "short",
67
+ maxDpr = DEFAULT_MAX_DPR
68
+ } = options || {};
71
69
  const baseWidth = transformations.width ?? width;
72
70
  const sortedDeviceBreakpoints = [...deviceBreakpoints].sort((a, b) => a - b);
73
71
  const sortedImageBreakpoints = [...imageBreakpoints].sort((a, b) => a - b);
74
72
  const allBreakpoints = [.../* @__PURE__ */ new Set([...sortedImageBreakpoints, ...sortedDeviceBreakpoints])].sort((a, b) => a - b);
75
- const { candidates, descriptor } = computeCandidateWidths({
73
+ const { candidates, descriptor } = calculatesCandidateWidths({
76
74
  allBreakpoints,
77
75
  deviceBreakpoints: sortedDeviceBreakpoints,
78
76
  ...baseWidth !== void 0 && { explicitWidth: baseWidth },
79
- ...sizes !== void 0 && { sizesAttr: sizes }
77
+ ...sizes !== void 0 && { sizesAttr: sizes },
78
+ maxDpr
80
79
  });
81
80
  if (candidates.length === 0) {
82
- return { src: config.baseUrl };
81
+ return { src: getFinalUrl(imageSrc, baseUrl) };
83
82
  }
84
- 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));
85
84
  const largestWidth = candidates[candidates.length - 1];
86
85
  const src = buildTransformationUrl(
87
- config,
88
- { ...transformations, width: largestWidth },
89
- mode
86
+ {
87
+ src: imageSrc,
88
+ baseUrl,
89
+ transformations: {
90
+ ...transformations,
91
+ width: largestWidth
92
+ },
93
+ mode
94
+ }
90
95
  );
91
96
  const endSizes = sizes ?? (descriptor === "w" ? "100vw" : void 0);
92
97
  return {
@@ -96,11 +101,14 @@ var createResponsiveAttributes = (config, options = {}) => {
96
101
  ...width !== void 0 ? { width } : {}
97
102
  };
98
103
  };
99
- function buildSrcEntries(width, index, config, transformations, mode, descriptor) {
104
+ function buildSrcEntries(imageSrc, width, index, transformations, mode, descriptor, baseUrl) {
100
105
  const url = buildTransformationUrl(
101
- config,
102
- { ...transformations, width },
103
- mode
106
+ {
107
+ src: imageSrc,
108
+ baseUrl,
109
+ transformations: { ...transformations, width },
110
+ mode
111
+ }
104
112
  );
105
113
  const desc = descriptor === "w" ? `${width}w` : `${index + 1}x`;
106
114
  return `${url} ${desc}`;
@@ -119,9 +127,40 @@ var clampMax = (v) => Math.min(v, MAX_IMAGE_WIDTH);
119
127
  var nearest = (sortedBreakpoints, target) => sortedBreakpoints.find((w) => w >= target) ?? sortedBreakpoints[sortedBreakpoints.length - 1];
120
128
  var parseVW = (sizes) => {
121
129
  if (!sizes) return [];
122
- return [...sizes.matchAll(/(\d+(?:\.\d+)?)vw/g)].map(
123
- (m) => Number(m[1]) / 100
124
- );
130
+ const foundSizes = sizes.match(/(\d+(?:\.\d+)?)vw/g) || [];
131
+ return foundSizes.map((size) => parseInt(size, 10));
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;
125
164
  };
126
165
 
127
166
  // src/config.ts
@@ -208,19 +247,15 @@ var buildTransformationQueryParams = (options, mode = "short") => {
208
247
  params.map(([k, v]) => [k, v])
209
248
  ).toString();
210
249
  };
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`;
250
+ var buildTransformationUrl = ({ src, transformations = {}, baseUrl, mode = "short" }) => {
251
+ const url = getFinalUrl(src, baseUrl);
252
+ if (transformations.original) {
253
+ return `${url}?original`;
219
254
  }
220
- const query = buildTransformationQueryParams(options, mode);
221
- return `${baseUrl}?${query}`;
255
+ const query = buildTransformationQueryParams(transformations, mode);
256
+ return `${url}?${query}`;
222
257
  };
223
258
 
224
- export { buildTransformationQueryParams, buildTransformationUrl, createResponsiveAttributes };
259
+ export { buildTransformationQueryParams, buildTransformationUrl, createResponsiveAttributes, parseNumberLikeParam };
225
260
  //# sourceMappingURL=index.js.map
226
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":";AAOO,IAAM,eAAA,GAAkB,IAAA;AAKxB,IAAM,0BAAA,GAA6B;AAAA,EACtC,GAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA;AACJ,CAAA;AAKO,IAAM,yBAAA,GAA4B,CAAC,EAAA,EAAI,EAAA,EAAI,IAAI,EAAA,EAAI,EAAA,EAAI,GAAA,EAAK,GAAA,EAAK,GAAG,CAAA;AA2C3E,IAAM,eAAA,GAAkB,CAAA;AAExB,SAAS,uBAAuB,MAAA,EAKoB;AAChD,EAAA,MAAM;AAAA,IACF,cAAA;AAAA,IACA,iBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACJ,GAAI,MAAA;AAGJ,EAAA,MAAM,SAAA,GAAY,CAAC,GAAG,IAAI,GAAA,CAAI,cAAc,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AACnE,EAAA,MAAM,YAAA,GAAe,CAAC,GAAG,IAAI,GAAA,CAAI,iBAAiB,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AAEzE,EAAA,IAAI,CAAC,SAAA,CAAU,MAAA,IAAU,CAAC,aAAa,MAAA,EAAQ;AAC3C,IAAA,OAAO,EAAE,UAAA,EAAY,EAAC,EAAG,YAAY,GAAA,EAAI;AAAA,EAC7C;AAEA,EAAA,MAAM,SAAA,GAAY,aAAa,CAAC,CAAA;AAChC,EAAA,MAAM,SAAA,GAAY,YAAA,CAAa,YAAA,CAAa,MAAA,GAAS,CAAC,CAAA;AAEtD,EAAA,MAAM,QAAA,GAAW,QAAQ,SAAS,CAAA;AAClC,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,GAAS,CAAA;AAIhC,EAAA,IAAI,OAAO,aAAA,KAAkB,QAAA,IAAY,CAAC,KAAA,EAAO;AAC7C,IAAA,MAAM,IAAA,GAAO,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAErB,IAAA,MAAM,aAAa,KAAA,CAAM,IAAA;AAAA,MACrB,IAAI,GAAA;AAAA,QACA,IAAA,CACK,GAAA,CAAI,CAAA,GAAA,KAAO,OAAA,CAAQ,SAAA,EAAW,gBAAgB,GAAG,CAAC,CAAA,CAClD,GAAA,CAAI,QAAQ;AAAA;AACrB,KACJ,CAAE,MAAA,CAAO,CAAA,CAAA,KAAK,CAAA,IAAK,eAAe,CAAA;AAElC,IAAA,OAAO;AAAA,MACH,UAAA;AAAA,MACA,UAAA,EAAY;AAAA,KAChB;AAAA,EACJ;AAGA,EAAA,IAAI,KAAA,EAAO;AACP,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,GAAG,QAAQ,CAAA;AACrC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,GAAG,QAAQ,CAAA;AAErC,IAAA,MAAM,QAAQ,SAAA,GAAY,QAAA;AAC1B,IAAA,MAAM,KAAA,GAAQ,YAAY,QAAA,GAAW,eAAA;AAErC,IAAA,MAAM,aAAa,SAAA,CAAU,MAAA;AAAA,MACzB,CAAA,CAAA,KAAK,CAAA,IAAK,KAAA,IAAS,CAAA,IAAK,SAAS,KAAK;AAAA,KAC1C;AAEA,IAAA,OAAO;AAAA,MACH,UAAA;AAAA,MACA,UAAA,EAAY;AAAA,KAChB;AAAA,EACJ;AAGA,EAAA,MAAM,YAAY,SAAA,GAAY,eAAA;AAE9B,EAAA,OAAO;AAAA,IACH,YAAY,SAAA,CAAU,MAAA,CAAO,OAAK,CAAA,IAAK,QAAA,CAAS,SAAS,CAAC,CAAA;AAAA,IAC1D,UAAA,EAAY;AAAA,GAChB;AACJ;AA0CO,IAAM,0BAAA,GAA6B,CACtC,MAAA,EACA,OAAA,GAAkC,EAAC,KACX;AACxB,EAAA,MAAM;AAAA,IACF,KAAA;AAAA,IACA,KAAA;AAAA,IACA,iBAAA,GAAoB,CAAC,GAAG,0BAA0B,CAAA;AAAA,IAClD,gBAAA,GAAmB,CAAC,GAAG,yBAAyB,CAAA;AAAA,IAChD,kBAAkB,EAAC;AAAA,IACnB,IAAA,GAAO;AAAA,GACX,GAAI,OAAA;AAGJ,EAAA,MAAM,SAAA,GAAY,gBAAgB,KAAA,IAAS,KAAA;AAE3C,EAAA,MAAM,uBAAA,GAA0B,CAAC,GAAG,iBAAiB,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAC3E,EAAA,MAAM,sBAAA,GAAyB,CAAC,GAAG,gBAAgB,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAEzE,EAAA,MAAM,iBAAiB,CAAC,uBAAO,GAAA,CAAI,CAAC,GAAG,sBAAA,EAAwB,GAAG,uBAAuB,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA;AAEjH,EAAA,MAAM,EAAE,UAAA,EAAY,UAAA,EAAW,GAAI,sBAAA,CAAuB;AAAA,IACtD,cAAA;AAAA,IACA,iBAAA,EAAmB,uBAAA;AAAA,IACnB,GAAI,SAAA,KAAc,MAAA,IAAa,EAAE,eAAe,SAAA,EAAU;AAAA,IAC1D,GAAI,KAAA,KAAU,MAAA,IAAa,EAAE,WAAW,KAAA;AAAM,GACjD,CAAA;AAED,EAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAEzB,IAAA,OAAO,EAAE,GAAA,EAAK,MAAA,CAAO,OAAA,EAAQ;AAAA,EACjC;AAGA,EAAA,MAAM,aAAA,GAAgB,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,EAAG,KAAA,KAAW,eAAA,CAAgB,CAAA,EAAG,KAAA,EAAO,MAAA,EAAQ,eAAA,EAAiB,IAAA,EAAM,UAAU,CAAC,CAAA;AAGxH,EAAA,MAAM,YAAA,GAAe,UAAA,CAAW,UAAA,CAAW,MAAA,GAAS,CAAC,CAAA;AACrD,EAAA,MAAM,GAAA,GAAM,sBAAA;AAAA,IACR,MAAA;AAAA,IACA,EAAE,GAAG,eAAA,EAAiB,KAAA,EAAO,YAAA,EAAa;AAAA,IAC1C;AAAA,GACJ;AAEA,EAAA,MAAM,QAAA,GAAW,KAAA,KAAU,UAAA,KAAe,GAAA,GAAM,OAAA,GAAU,MAAA,CAAA;AAE1D,EAAA,OAAO;AAAA,IACH,GAAA;AAAA,IACA,GAAI,QAAA,GAAW,EAAE,KAAA,EAAO,QAAA,KAAa,EAAC;AAAA,IACtC,MAAA,EAAQ,aAAA,CAAc,IAAA,CAAK,IAAI,CAAA;AAAA,IAC/B,GAAI,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,KAAU;AAAC,GAC3C;AACJ;AAEA,SAAS,gBAAgB,KAAA,EAAe,KAAA,EAAe,MAAA,EAA0B,eAAA,EAAwC,MAAgB,UAAA,EAA+B;AACpK,EAAA,MAAM,GAAA,GAAM,sBAAA;AAAA,IACR,MAAA;AAAA,IACA,EAAE,GAAG,eAAA,EAAiB,KAAA,EAAa;AAAA,IACnC;AAAA,GACJ;AAEA,EAAA,MAAM,IAAA,GAAO,eAAe,GAAA,GAAM,CAAA,EAAG,KAAK,CAAA,CAAA,CAAA,GAAM,CAAA,EAAG,QAAQ,CAAC,CAAA,CAAA,CAAA;AAE5D,EAAA,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AACzB;;;ACrPO,IAAM,eAAe,CAAC,KAAA,KAAkB,KAAA,CAAM,OAAA,CAAQ,KAAK,EAAE,CAAA;AAG7D,IAAM,mBAAA,GAAsB,CAAC,OAAA,KAAoB;AACpD,EAAA,OAAO,OAAA,CAAQ,SAAS,GAAG,CAAA,GACrB,QAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GACnB,OAAA;AACV,CAAA;AAEO,IAAM,cAAA,GAAiB,CAI1B,GAAA,EACA,IAAA,KAEA,IAAA,CAAK,MAAA;AAAA,EACD,CAAC,GAAA,EAAK,GAAA,KAAS,OAAO,IAAA,GAAO,MAAA,GAAY,IAAI,GAAG,CAAA;AAAA,EAChD;AACJ,CAAA;AAGG,IAAM,WAAW,CAAC,CAAA,KAAc,IAAA,CAAK,GAAA,CAAI,GAAG,eAAe,CAAA;AAE3D,IAAM,OAAA,GAAU,CAAC,iBAAA,EAA4B,MAAA,KAChD,iBAAA,CAAkB,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,IAAK,MAAM,CAAA,IAAK,iBAAA,CAAkB,iBAAA,CAAkB,SAAS,CAAC,CAAA;AAEvF,IAAM,OAAA,GAAU,CAAC,KAAA,KAA6B;AACjD,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AACpB,EAAA,OAAO,CAAC,GAAG,KAAA,CAAM,QAAA,CAAS,oBAAoB,CAAC,CAAA,CAAE,GAAA;AAAA,IAC7C,CAAA,CAAA,KAAK,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI;AAAA,GACxB;AACJ,CAAA;;;AC/BO,IAAM,MAAA,GAAS;AAAA,EAClB,EAAC,MAAM,CAAC,OAAO,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,GAAA,EAAG;AAAA,EAC3C,EAAC,MAAM,CAAC,QAAQ,GAAG,IAAA,EAAM,QAAA,EAAU,OAAO,GAAA,EAAG;AAAA,EAC7C,EAAC,MAAM,CAAC,KAAK,GAAG,IAAA,EAAM,KAAA,EAAO,OAAO,KAAA,EAAK;AAAA,EACzC,EAAC,MAAM,CAAC,MAAM,GAAG,IAAA,EAAM,MAAA,EAAQ,OAAO,IAAA,EAAI;AAAA,EAC1C;AAAA,IACI,IAAA,EAAM,CAAC,YAAY,CAAA;AAAA,IACnB,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAO,IAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EAEA,EAAC,MAAM,CAAC,QAAQ,GAAG,IAAA,EAAM,QAAA,EAAU,OAAO,GAAA,EAAG;AAAA,EAC7C,EAAC,MAAM,CAAC,SAAS,GAAG,IAAA,EAAM,SAAA,EAAW,OAAO,GAAA,EAAG;AAAA,EAC/C,EAAC,MAAM,CAAC,eAAe,GAAG,IAAA,EAAM,eAAA,EAAiB,OAAO,IAAA,EAAI;AAAA,EAE5D,EAAC,MAAM,CAAC,MAAM,GAAG,IAAA,EAAM,MAAA,EAAQ,OAAO,IAAA,EAAI;AAAA,EAC1C,EAAC,MAAM,CAAC,YAAY,GAAG,IAAA,EAAM,YAAA,EAAc,OAAO,IAAA,EAAI;AAAA,EACtD,EAAC,MAAM,CAAC,UAAU,GAAG,IAAA,EAAM,UAAA,EAAY,OAAO,IAAA,EAAI;AAAA,EAClD,EAAC,MAAM,CAAC,WAAW,GAAG,IAAA,EAAM,WAAA,EAAa,OAAO,IAAA,EAAI;AAAA,EACpD,EAAC,MAAM,CAAC,YAAY,GAAG,IAAA,EAAM,YAAA,EAAc,OAAO,IAAA,EAAI;AAAA,EACtD,EAAC,MAAM,CAAC,OAAO,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,IAAA,EAAI;AAAA,EAC5C,EAAC,MAAM,CAAC,SAAS,GAAG,IAAA,EAAM,SAAA,EAAW,OAAO,IAAA,EAAI;AAAA,EAChD,EAAC,MAAM,CAAC,OAAO,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,IAAA,EAAI;AAAA,EAC5C,EAAC,MAAM,CAAC,QAAQ,GAAG,IAAA,EAAM,QAAA,EAAU,OAAO,IAAA,EAAI;AAAA,EAE9C,EAAC,MAAM,CAAC,QAAA,EAAU,OAAO,CAAA,EAAG,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAO,MAAA,EAAM;AAAA,EAC/D;AAAA,IACI,IAAA,EAAM,CAAC,QAAA,EAAU,OAAO,CAAA;AAAA,IACxB,IAAA,EAAM,cAAA;AAAA,IACN,KAAA,EAAO,MAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EACA,EAAC,MAAM,CAAC,QAAA,EAAU,QAAQ,CAAA,EAAG,IAAA,EAAM,eAAA,EAAiB,KAAA,EAAO,MAAA,EAAM;AAAA,EAEjE,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAA,EAAM;AAAA,EACzD,EAAC,MAAM,CAAC,MAAA,EAAQ,YAAY,CAAA,EAAG,IAAA,EAAM,iBAAA,EAAmB,KAAA,EAAO,MAAA,EAAM;AAAA,EACrE,EAAC,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAA,EAAS,UAAA,EAAY,GAAG,CAAA,EAAG,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,MAAA,EAAM;AAAA,EACxE,EAAC,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAA,EAAS,UAAA,EAAY,GAAG,CAAA,EAAG,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,MAAA,EAAM;AAAA,EACxE,EAAC,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAA,EAAS,UAAU,CAAA,EAAG,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAI;AAAA,EAC/D,EAAC,MAAM,CAAC,MAAA,EAAQ,OAAO,CAAA,EAAG,IAAA,EAAM,YAAA,EAAc,KAAA,EAAO,MAAA,EAAM;AAAA,EAC3D,EAAC,MAAM,CAAC,MAAA,EAAQ,QAAQ,CAAA,EAAG,IAAA,EAAM,aAAA,EAAe,KAAA,EAAO,MAAA,EAAM;AAAA,EAC7D,EAAC,MAAM,CAAC,MAAA,EAAQ,aAAa,CAAA,EAAG,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,OAAA,EAAO;AAAA,EAExE,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAI;AAAA,EAClD;AAAA,IACI,IAAA,EAAM,CAAC,MAAA,EAAQ,OAAO,CAAA;AAAA,IACtB,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAO,MAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EACA,EAAC,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,EAAG,IAAA,EAAM,cAAA,EAAgB,KAAA,EAAO,MAAA,EAAM;AAAA,EAC/D,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAA,EAAM;AAAA,EACzD,EAAC,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,MAAA,EAAM;AAAA,EACzD,EAAC,MAAM,CAAC,MAAA,EAAQ,UAAU,CAAA,EAAG,IAAA,EAAM,eAAA,EAAiB,KAAA,EAAO,OAAA,EAAO;AAAA,EAClE,EAAC,MAAM,CAAC,MAAA,EAAQ,UAAU,CAAA,EAAG,IAAA,EAAM,eAAA,EAAiB,KAAA,EAAO,MAAA,EAAM;AAAA,EACjE;AAAA,IACI,IAAA,EAAM,CAAC,MAAA,EAAQ,YAAY,CAAA;AAAA,IAC3B,IAAA,EAAM,iBAAA;AAAA,IACN,KAAA,EAAO,OAAA;AAAA,IACP,SAAA,EAAW,CAAC,CAAA,KAAM,OAAO,MAAM,QAAA,GAAW,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAChE;AAAA,EACA,EAAC,MAAM,CAAC,MAAA,EAAQ,mBAAmB,CAAA,EAAG,IAAA,EAAM,wBAAA,EAA0B,KAAA,EAAO,SAAA,EAAS;AAAA,EAEtF,EAAC,MAAM,CAAC,WAAA,EAAa,MAAM,CAAA,EAAG,IAAA,EAAM,WAAA,EAAa,KAAA,EAAO,IAAA,EAAI;AAAA,EAC5D,EAAC,MAAM,CAAC,WAAA,EAAa,SAAS,CAAA,EAAG,IAAA,EAAM,mBAAA,EAAqB,KAAA,EAAO,MAAA,EAAM;AAAA,EACzE,EAAC,MAAM,CAAC,WAAA,EAAa,MAAM,CAAA,EAAG,IAAA,EAAM,gBAAA,EAAkB,KAAA,EAAO,MAAA,EAAM;AAAA,EACnE,EAAC,MAAM,CAAC,WAAA,EAAa,OAAO,CAAA,EAAG,IAAA,EAAM,iBAAA,EAAmB,KAAA,EAAO,MAAA,EAAM;AAAA,EACrE,EAAC,MAAM,CAAC,WAAA,EAAa,QAAQ,CAAA,EAAG,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,MAAA,EAAM;AAAA,EACvE,EAAC,MAAM,CAAC,WAAA,EAAa,UAAU,CAAA,EAAG,IAAA,EAAM,oBAAA,EAAsB,KAAA,EAAO,MAAA;AACzE,CAAA;;;ACrCO,IAAM,8BAAA,GAAiC,CAC1C,OAAA,EACA,IAAA,GAAiB,OAAA,KACR;AACT,EAAA,MAAM,SAAkC,EAAC;AAEzC,EAAA,KAAA,MAAW,QAAQ,MAAA,EAAQ;AACvB,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,OAAA,EAAS,IAAA,CAAK,IAAI,CAAA;AAC/C,IAAA,IAAI,SAAS,IAAA,EAAM;AAEnB,IAAA,MAAM,OACF,IAAA,KAAS,OAAA,IAAW,KAAK,KAAA,GAAQ,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA;AAEvD,IAAA,IAAI,UAAA,GAAa,KAAA;AACjB,IAAA,IAAI,eAAe,IAAA,EAAM;AACrB,MAAA,UAAA,GAAa,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,IACrC;AAEA,IAAA,MAAA,CAAO,KAAK,CAAC,IAAA,EAAM,MAAA,CAAO,UAAU,CAAC,CAAC,CAAA;AAAA,EAC1C;AAGA,EAAA,OAAO,IAAI,eAAA;AAAA,IACP,MAAA,CAAO,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,CAAC,CAAA,EAAG,CAAC,CAAC;AAAA,IAC/B,QAAA,EAAS;AAEf;AA2CA,IAAM,sBAAA,GAAyB,CAAC,GAAA,KAAwB;AACpD,EAAA,MAAM,UAAA,GAAa,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAClC,EAAA,OAAO,eAAe,EAAA,GAAK,GAAA,GAAM,GAAA,CAAI,KAAA,CAAM,GAAG,UAAU,CAAA;AAC5D,CAAA;AAEO,IAAM,sBAAA,GAAyB,CAClC,MAAA,EACA,OAAA,EACA,OAAiB,OAAA,KAChB;AAED,EAAA,MAAM,OAAA,GAAU,mBAAA,CAAoB,sBAAA,CAAuB,MAAA,CAAO,OAAO,CAAC,CAAA;AAE1E,EAAA,IAAI,QAAQ,QAAA,EAAU;AAClB,IAAA,OAAO,GAAG,OAAO,CAAA,SAAA,CAAA;AAAA,EACrB;AAEA,EAAA,MAAM,KAAA,GAAQ,8BAAA,CAA+B,OAAA,EAAS,IAAI,CAAA;AAE1D,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAC9B","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] 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}\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 * Computes candidate widths and descriptor type based on input options.\r\n */\r\nconst DEFAULT_MAX_DPR = 2;\r\n\r\nfunction computeCandidateWidths(params: {\r\n allBreakpoints: number[];\r\n deviceBreakpoints: number[];\r\n explicitWidth?: number;\r\n sizesAttr?: string;\r\n}): { candidates: number[]; descriptor: 'w' | 'x' } {\r\n const {\r\n allBreakpoints,\r\n deviceBreakpoints,\r\n explicitWidth,\r\n sizesAttr\r\n } = params;\r\n\r\n // ---- Normalize & guard ----\r\n const sortedAll = [...new Set(allBreakpoints)].sort((a, b) => a - b);\r\n const sortedDevice = [...new Set(deviceBreakpoints)].sort((a, b) => a - b);\r\n\r\n if (!sortedAll.length || !sortedDevice.length) {\r\n return { candidates: [], descriptor: 'w' };\r\n }\r\n\r\n const minDevice = sortedDevice[0]!;\r\n const maxDevice = sortedDevice[sortedDevice.length - 1]!;\r\n\r\n const vwRatios = parseVW(sizesAttr);\r\n const hasVW = vwRatios.length > 0;\r\n\r\n // Explicit width (fixed layout) → x descriptors ----\r\n // Prefer this when layout width is known and sizes does NOT imply vw scaling\r\n if (typeof explicitWidth === 'number' && !hasVW) {\r\n const DPRs = [1, 2, 3];\r\n\r\n const candidates = Array.from(\r\n new Set(\r\n DPRs\r\n .map(dpr => nearest(sortedAll, 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 // Sizes with vw → w descriptors ----\r\n if (hasVW) {\r\n const minRatio = Math.min(...vwRatios);\r\n const maxRatio = Math.max(...vwRatios);\r\n\r\n const minPx = minDevice * minRatio;\r\n const maxPx = maxDevice * maxRatio * DEFAULT_MAX_DPR;\r\n\r\n const candidates = sortedAll.filter(\r\n w => w >= minPx && w <= clampMax(maxPx)\r\n );\r\n\r\n return {\r\n candidates,\r\n descriptor: 'w'\r\n };\r\n }\r\n\r\n // No sizes & no explicit width → device-based w ----\r\n const maxUseful = maxDevice * DEFAULT_MAX_DPR;\r\n\r\n return {\r\n candidates: sortedAll.filter(w => w <= clampMax(maxUseful)),\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 } = 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 } = computeCandidateWidths({\r\n allBreakpoints,\r\n deviceBreakpoints: sortedDeviceBreakpoints,\r\n ...(baseWidth !== undefined && { explicitWidth: baseWidth }),\r\n ...(sizes !== undefined && { sizesAttr: sizes }),\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 return [...sizes.matchAll(/(\\d+(?:\\.\\d+)?)vw/g)].map(\r\n m => Number(m[1]) / 100\r\n );\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.5",
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",