@pixelfiddler/core 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,7 @@ import { buildTransformationUrl, buildQueryParams } from '@pixelfiddler/core';
19
19
 
20
20
  // Build a complete transformation URL
21
21
  const url = buildTransformationUrl(
22
- { baseUrl: 'https://cdn.pixelfiddler.com/images/photo.jpg' },
22
+ { baseUrl: 'https://example-media.com/images/photo.jpg' },
23
23
  {
24
24
  width: 800,
25
25
  height: 600,
@@ -27,7 +27,7 @@ const url = buildTransformationUrl(
27
27
  quality: 85,
28
28
  }
29
29
  );
30
- // => 'https://cdn.pixelfiddler.com/images/photo.jpg?w=800&h=600&f=webp&q=85'
30
+ // => 'https://example-media.com/images/photo.jpg?w=800&h=600&f=webp&q=85'
31
31
 
32
32
  // Or just get the query string
33
33
  const params = buildQueryParams({
package/dist/index.cjs CHANGED
@@ -1,24 +1,5 @@
1
1
  'use strict';
2
2
 
3
- // src/types.ts
4
- var CROP_FOCUS = {
5
- SPECIFIED: "SPECIFIED",
6
- AUTO: "AUTO"
7
- };
8
- var CROP_FOCUS_STRATEGY = {
9
- CENTER: "CENTER",
10
- SMART: "SMART",
11
- DETAIL: "DETAIL"
12
- };
13
- var CROP_TYPE = {
14
- SIMPLE: "SIMPLE",
15
- OBJECT: "OBJECT"
16
- };
17
- var CROP_OBJECT_TYPE = {
18
- FACE: "FACE",
19
- UPPER_BODY: "UPPER_BODY"
20
- };
21
-
22
3
  // src/utils.ts
23
4
  var normalizeHex = (value) => value.replace("#", "");
24
5
  var removeTrailingSlash = (baseUrl) => {
@@ -97,7 +78,7 @@ var PARAMS = [
97
78
  ];
98
79
 
99
80
  // src/url-builder.ts
100
- var buildQueryParams = (options, mode = "short") => {
81
+ var buildTransformationQueryParams = (options, mode = "short") => {
101
82
  const params = [];
102
83
  for (const spec of PARAMS) {
103
84
  const value = getNestedValue(options, spec.path);
@@ -117,16 +98,12 @@ var buildTransformationUrl = (config, options, mode = "short") => {
117
98
  if (options.original) {
118
99
  return `${config.baseUrl}?original`;
119
100
  }
120
- const query = buildQueryParams(options, mode);
101
+ const query = buildTransformationQueryParams(options, mode);
121
102
  const baseUrl = removeTrailingSlash(config.baseUrl);
122
103
  return `${baseUrl}?${query}`;
123
104
  };
124
105
 
125
- exports.CROP_FOCUS = CROP_FOCUS;
126
- exports.CROP_FOCUS_STRATEGY = CROP_FOCUS_STRATEGY;
127
- exports.CROP_OBJECT_TYPE = CROP_OBJECT_TYPE;
128
- exports.CROP_TYPE = CROP_TYPE;
129
- exports.buildQueryParams = buildQueryParams;
106
+ exports.buildTransformationQueryParams = buildTransformationQueryParams;
130
107
  exports.buildTransformationUrl = buildTransformationUrl;
131
108
  //# sourceMappingURL=index.cjs.map
132
109
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * Helper type to extract values from const objects\r\n */\r\ntype ObjectValue<T> = T[keyof T];\r\n\r\n/**\r\n * Resize mode for image transformations\r\n */\r\nexport type ResizeMode = 'FILL' | 'FIT' | 'PAD' | 'FORCE' | 'COVER';\r\n\r\n/**\r\n * Output image format - null or empty means AUTO\r\n */\r\nexport type ImageFormat = 'jpeg' | 'png' | 'webp' | 'avif' | 'gif'\r\n\r\n/**\r\n * Position for text overlays and watermarks\r\n */\r\nexport type Position =\r\n | 'TOP_LEFT'\r\n | 'TOP_CENTER'\r\n | 'TOP_RIGHT'\r\n | 'CENTER_LEFT'\r\n | 'CENTER'\r\n | 'CENTER_RIGHT'\r\n | 'BOTTOM_LEFT'\r\n | 'BOTTOM_CENTER'\r\n | 'BOTTOM_RIGHT';\r\n\r\n/**\r\n * Crop focus type\r\n */\r\nexport const CROP_FOCUS = {\r\n SPECIFIED: 'SPECIFIED',\r\n AUTO: 'AUTO',\r\n} as const;\r\n\r\nexport type CropFocus = ObjectValue<typeof CROP_FOCUS>;\r\n\r\n/**\r\n * Crop focus strategy for AUTO focus\r\n */\r\nexport const CROP_FOCUS_STRATEGY = {\r\n CENTER: 'CENTER',\r\n SMART: 'SMART',\r\n DETAIL: 'DETAIL',\r\n} as const;\r\n\r\nexport type CropFocusStrategy = ObjectValue<typeof CROP_FOCUS_STRATEGY>;\r\n\r\n/**\r\n * Crop type\r\n */\r\nexport const CROP_TYPE = {\r\n SIMPLE: 'SIMPLE',\r\n OBJECT: 'OBJECT',\r\n} as const;\r\n\r\nexport type CropType = ObjectValue<typeof CROP_TYPE>;\r\n\r\n/**\r\n * Object type for smart cropping\r\n */\r\nexport const CROP_OBJECT_TYPE = {\r\n FACE: 'FACE',\r\n UPPER_BODY: 'UPPER_BODY',\r\n} as const;\r\n\r\nexport type CropObjectType = ObjectValue<typeof CROP_OBJECT_TYPE>;\r\n\r\n/**\r\n * Rotation angle in degrees (clockwise)\r\n */\r\nexport type RotationAngle = 0 | 90 | 180 | 270;\r\n\r\n/**\r\n * Device pixel ratio for high-density displays\r\n */\r\nexport type DevicePixelRatio = 1 | 2 | 3 | 4;\r\n\r\n/**\r\n * Hex color string (with or without #)\r\n */\r\nexport type HexColor = string;\r\n\r\n/**\r\n * Resize transformation options\r\n */\r\nexport interface ResizeOptions {\r\n /** Target width in pixels (1-4096) */\r\n width?: number;\r\n /** Target height in pixels (1-4096) */\r\n height?: number;\r\n /** Device pixel ratio for retina displays */\r\n dpr?: DevicePixelRatio;\r\n /** Resize strategy */\r\n mode?: ResizeMode;\r\n /** Background color for PAD mode (hex) */\r\n background?: HexColor;\r\n}\r\n\r\n/**\r\n * Format and quality options\r\n */\r\nexport interface FormatOptions {\r\n /** Output format */\r\n format?: ImageFormat;\r\n /** Quality level (1-100) */\r\n quality?: number;\r\n /** Strip metadata from output */\r\n stripMetadata?: boolean;\r\n}\r\n\r\n/**\r\n * Effect transformation options\r\n */\r\nexport interface EffectOptions {\r\n /** Gaussian blur intensity (0-100) */\r\n blur?: number;\r\n /** Brightness adjustment (0-100) */\r\n brightness?: number;\r\n /** Contrast adjustment (0-100) */\r\n contrast?: number;\r\n /** Convert to grayscale */\r\n grayscale?: boolean;\r\n /** Saturation adjustment (0-100) */\r\n saturation?: number;\r\n /** Apply sepia effect */\r\n sepia?: boolean;\r\n /** Sharpen intensity (0-100) */\r\n sharpen?: number;\r\n /** Add noise intensity (0-100) */\r\n noise?: number;\r\n /** Rotation angle */\r\n rotate?: RotationAngle;\r\n}\r\n\r\n/**\r\n * Border options\r\n */\r\nexport interface BorderOptions {\r\n /** Border width in pixels */\r\n width?: number;\r\n /** Border color (hex) */\r\n color?: HexColor;\r\n /** Corner radius in pixels (1-2000) */\r\n radius?: number;\r\n}\r\n\r\n/**\r\n * Crop focus position for SPECIFIED focus type\r\n */\r\nexport interface CropFocusPosition {\r\n x?: number;\r\n y?: number;\r\n}\r\n\r\n/**\r\n * Crop focus options\r\n */\r\nexport interface CropFocusOptions {\r\n /** Focus type - SPECIFIED (manual position) or AUTO (strategy-based) */\r\n type?: CropFocus;\r\n /** Manual focus position when type is SPECIFIED */\r\n position?: CropFocusPosition;\r\n /** Auto focus strategy when type is AUTO */\r\n strategy?: CropFocusStrategy;\r\n}\r\n\r\n/**\r\n * Crop options\r\n */\r\nexport interface CropOptions {\r\n /** Crop type - SIMPLE or OBJECT */\r\n type?: CropType;\r\n /** Object type for OBJECT crop type */\r\n objectType?: CropObjectType;\r\n /** Focus options */\r\n focus?: CropFocusOptions;\r\n /** Crop width in pixels */\r\n width?: number;\r\n /** Crop height in pixels */\r\n height?: number;\r\n /** Apply crop after resize */\r\n afterResize?: boolean;\r\n}\r\n\r\n/**\r\n * Text overlay options\r\n */\r\nexport interface TextOptions {\r\n /** Text content to render */\r\n text?: string;\r\n /** Text color (hex) */\r\n color?: HexColor;\r\n /** Text opacity (0-100) */\r\n opacity?: number;\r\n /** Background color behind text (hex) */\r\n background?: HexColor;\r\n /** Background opacity (0-100) */\r\n backgroundOpacity?: number;\r\n /** Text size as percentage of image (1-100) */\r\n size?: number;\r\n /** Font family name */\r\n font?: string;\r\n /** Font size in pixels */\r\n fontSize?: number;\r\n /** Text position */\r\n position?: Position;\r\n}\r\n\r\n/**\r\n * Watermark options\r\n */\r\nexport interface WatermarkOptions {\r\n /** Watermark name (predefined in dashboard) */\r\n name?: string;\r\n /** Watermark opacity (0-100) */\r\n opacity?: number;\r\n /** Watermark size as percentage (1-100) */\r\n size?: number;\r\n /** Watermark width in pixels */\r\n width?: number;\r\n /** Watermark height in pixels */\r\n height?: number;\r\n /** Watermark position */\r\n position?: Position;\r\n}\r\n\r\n/**\r\n * All transformation options combined\r\n */\r\nexport interface TransformationOptions\r\n extends ResizeOptions,\r\n FormatOptions,\r\n EffectOptions {\r\n /** Border options */\r\n border?: BorderOptions;\r\n /** Crop options */\r\n crop?: CropOptions;\r\n /** Text overlay options */\r\n text?: TextOptions;\r\n /** Watermark options */\r\n watermark?: WatermarkOptions;\r\n /** Use predefined transformation alias */\r\n alias?: string;\r\n /** Return original image without transformations */\r\n original?: boolean;\r\n}\r\n\r\n/**\r\n * Configuration for PixelFiddler client\r\n */\r\nexport interface PixelFiddlerConfig {\r\n /** Base URL for the CDN (defaults to https://cdn.pixel-fiddler.com) */\r\n baseUrl?: string;\r\n /** Secret key for URL signing */\r\n signatureKey?: string;\r\n}\r\n\r\n/**\r\n * URL builder configuration (internal)\r\n */\r\nexport interface UrlBuilderConfig extends PixelFiddlerConfig {\r\n /** Resolved base URL */\r\n baseUrl: string;\r\n}\r\n\r\n/**\r\n * Mapping of transformation options to query parameter names\r\n */\r\nexport interface QueryParameterMapping {\r\n /** Full parameter name */\r\n name: string;\r\n /** Short alias */\r\n alias?: string;\r\n}\r\n\r\n\r\n","import { Path, PathValue } from './util-types';\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","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\ntype 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 buildQueryParams = (\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://cdn.example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://cdn.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://cdn.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://cdn.example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://cdn.example.com/images/photo.jpg?width=400'\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 if (options.original) {\r\n return `${config.baseUrl}?original`;\r\n }\r\n\r\n const query = buildQueryParams(options, mode);\r\n\r\n const baseUrl = removeTrailingSlash(config.baseUrl)\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
1
+ {"version":3,"sources":["../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import { Path, PathValue } from './util-types';\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","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\ntype 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\nexport const buildTransformationUrl = (\r\n config: UrlBuilderConfig,\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n) => {\r\n if (options.original) {\r\n return `${config.baseUrl}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(options, mode);\r\n\r\n const baseUrl = removeTrailingSlash(config.baseUrl)\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
package/dist/index.d.cts CHANGED
@@ -9,11 +9,11 @@ type ResizeMode = 'FILL' | 'FIT' | 'PAD' | 'FORCE' | 'COVER';
9
9
  /**
10
10
  * Output image format - null or empty means AUTO
11
11
  */
12
- type ImageFormat = 'jpeg' | 'png' | 'webp' | 'avif' | 'gif';
12
+ type ImageFormat = 'JPEG' | 'PNG' | 'WEBP' | 'AVIF' | 'GIF';
13
13
  /**
14
14
  * Position for text overlays and watermarks
15
15
  */
16
- type Position = 'TOP_LEFT' | 'TOP_CENTER' | 'TOP_RIGHT' | 'CENTER_LEFT' | 'CENTER' | 'CENTER_RIGHT' | 'BOTTOM_LEFT' | 'BOTTOM_CENTER' | 'BOTTOM_RIGHT';
16
+ type Position = 'TOP_LEFT' | 'TOP_RIGHT' | 'LEFT' | 'RIGHT' | 'BOTTOM' | 'TOP' | 'CENTER' | 'BOTTOM_LEFT' | 'BOTTOM_RIGHT' | 'AUTO';
17
17
  /**
18
18
  * Crop focus type
19
19
  */
@@ -127,33 +127,53 @@ interface CropFocusPosition {
127
127
  y?: number;
128
128
  }
129
129
  /**
130
- * Crop focus options
130
+ * Specified focus - manual position
131
131
  */
132
- interface CropFocusOptions {
133
- /** Focus type - SPECIFIED (manual position) or AUTO (strategy-based) */
134
- type?: CropFocus;
135
- /** Manual focus position when type is SPECIFIED */
136
- position?: CropFocusPosition;
137
- /** Auto focus strategy when type is AUTO */
132
+ interface SpecifiedCropFocus {
133
+ type: typeof CROP_FOCUS.SPECIFIED;
134
+ position: CropFocusPosition;
135
+ }
136
+ /**
137
+ * Auto focus - strategy-based
138
+ */
139
+ interface AutoCropFocus {
140
+ type: typeof CROP_FOCUS.AUTO;
138
141
  strategy?: CropFocusStrategy;
139
142
  }
140
143
  /**
141
- * Crop options
144
+ * Crop focus options - discriminated union
142
145
  */
143
- interface CropOptions {
144
- /** Crop type - SIMPLE or OBJECT */
145
- type?: CropType;
146
- /** Object type for OBJECT crop type */
147
- objectType?: CropObjectType;
148
- /** Focus options */
149
- focus?: CropFocusOptions;
146
+ type CropFocusOptions = SpecifiedCropFocus | AutoCropFocus;
147
+ /**
148
+ * Object crop options - smart object detection
149
+ */
150
+ interface ObjectCropOptions {
151
+ type?: typeof CROP_TYPE.OBJECT;
150
152
  /** Crop width in pixels */
151
153
  width?: number;
152
154
  /** Crop height in pixels */
153
155
  height?: number;
156
+ /** Object type for smart cropping */
157
+ objectType?: CropObjectType;
158
+ }
159
+ /**
160
+ * Simple crop options - manual or strategy-based
161
+ */
162
+ interface SimpleCropOptions {
163
+ type: typeof CROP_TYPE.SIMPLE;
154
164
  /** Apply crop after resize */
155
165
  afterResize?: boolean;
166
+ /** Crop width in pixels */
167
+ width?: number;
168
+ /** Crop height in pixels */
169
+ height?: number;
170
+ /** Focus options */
171
+ focus: CropFocusOptions;
156
172
  }
173
+ /**
174
+ * Crop options - discriminated union
175
+ */
176
+ type CropOptions = ObjectCropOptions | SimpleCropOptions;
157
177
  /**
158
178
  * Text overlay options
159
179
  */
@@ -260,7 +280,7 @@ type NameMode = 'short' | 'long';
260
280
  * // => 'bo.w=2&bo.c=ff0000'
261
281
  * ```
262
282
  */
263
- declare const buildQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
283
+ declare const buildTransformationQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
264
284
  /**
265
285
  * Builds a complete transformation URL from a base URL and transformation options.
266
286
  *
@@ -275,11 +295,11 @@ declare const buildQueryParams: (options: TransformationOptions, mode?: NameMode
275
295
  *
276
296
  * @example
277
297
  * ```ts
278
- * const config = { baseUrl: 'https://cdn.example.com/images/photo.jpg' };
298
+ * const config = { baseUrl: 'https://example.com/images/photo.jpg' };
279
299
  *
280
300
  * // Basic resize
281
301
  * buildTransformationUrl(config, { width: 400, height: 300 });
282
- * // => 'https://cdn.example.com/images/photo.jpg?w=400&h=300'
302
+ * // => 'https://example.com/images/photo.jpg?w=400&h=300'
283
303
  *
284
304
  * // Multiple transformations
285
305
  * buildTransformationUrl(config, {
@@ -288,17 +308,17 @@ declare const buildQueryParams: (options: TransformationOptions, mode?: NameMode
288
308
  * quality: 85,
289
309
  * blur: 5
290
310
  * });
291
- * // => 'https://cdn.example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'
311
+ * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'
292
312
  *
293
313
  * // Request original image (no transformations)
294
314
  * buildTransformationUrl(config, { original: true });
295
- * // => 'https://cdn.example.com/images/photo.jpg?original'
315
+ * // => 'https://example.com/images/photo.jpg?original'
296
316
  *
297
317
  * // Using long parameter names
298
318
  * buildTransformationUrl(config, { width: 400 }, 'long');
299
- * // => 'https://cdn.example.com/images/photo.jpg?width=400'
319
+ * // => 'https://example.com/images/photo.jpg?width=400'
300
320
  * ```
301
321
  */
302
322
  declare const buildTransformationUrl: (config: UrlBuilderConfig, options: TransformationOptions, mode?: NameMode) => string;
303
323
 
304
- export { type BorderOptions, CROP_FOCUS, CROP_FOCUS_STRATEGY, CROP_OBJECT_TYPE, CROP_TYPE, 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 PixelFiddlerConfig, type Position, type ResizeMode, type ResizeOptions, type RotationAngle, type TextOptions, type TransformationOptions, type UrlBuilderConfig, type WatermarkOptions, buildQueryParams, buildTransformationUrl };
324
+ 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 };
package/dist/index.d.ts CHANGED
@@ -9,11 +9,11 @@ type ResizeMode = 'FILL' | 'FIT' | 'PAD' | 'FORCE' | 'COVER';
9
9
  /**
10
10
  * Output image format - null or empty means AUTO
11
11
  */
12
- type ImageFormat = 'jpeg' | 'png' | 'webp' | 'avif' | 'gif';
12
+ type ImageFormat = 'JPEG' | 'PNG' | 'WEBP' | 'AVIF' | 'GIF';
13
13
  /**
14
14
  * Position for text overlays and watermarks
15
15
  */
16
- type Position = 'TOP_LEFT' | 'TOP_CENTER' | 'TOP_RIGHT' | 'CENTER_LEFT' | 'CENTER' | 'CENTER_RIGHT' | 'BOTTOM_LEFT' | 'BOTTOM_CENTER' | 'BOTTOM_RIGHT';
16
+ type Position = 'TOP_LEFT' | 'TOP_RIGHT' | 'LEFT' | 'RIGHT' | 'BOTTOM' | 'TOP' | 'CENTER' | 'BOTTOM_LEFT' | 'BOTTOM_RIGHT' | 'AUTO';
17
17
  /**
18
18
  * Crop focus type
19
19
  */
@@ -127,33 +127,53 @@ interface CropFocusPosition {
127
127
  y?: number;
128
128
  }
129
129
  /**
130
- * Crop focus options
130
+ * Specified focus - manual position
131
131
  */
132
- interface CropFocusOptions {
133
- /** Focus type - SPECIFIED (manual position) or AUTO (strategy-based) */
134
- type?: CropFocus;
135
- /** Manual focus position when type is SPECIFIED */
136
- position?: CropFocusPosition;
137
- /** Auto focus strategy when type is AUTO */
132
+ interface SpecifiedCropFocus {
133
+ type: typeof CROP_FOCUS.SPECIFIED;
134
+ position: CropFocusPosition;
135
+ }
136
+ /**
137
+ * Auto focus - strategy-based
138
+ */
139
+ interface AutoCropFocus {
140
+ type: typeof CROP_FOCUS.AUTO;
138
141
  strategy?: CropFocusStrategy;
139
142
  }
140
143
  /**
141
- * Crop options
144
+ * Crop focus options - discriminated union
142
145
  */
143
- interface CropOptions {
144
- /** Crop type - SIMPLE or OBJECT */
145
- type?: CropType;
146
- /** Object type for OBJECT crop type */
147
- objectType?: CropObjectType;
148
- /** Focus options */
149
- focus?: CropFocusOptions;
146
+ type CropFocusOptions = SpecifiedCropFocus | AutoCropFocus;
147
+ /**
148
+ * Object crop options - smart object detection
149
+ */
150
+ interface ObjectCropOptions {
151
+ type?: typeof CROP_TYPE.OBJECT;
150
152
  /** Crop width in pixels */
151
153
  width?: number;
152
154
  /** Crop height in pixels */
153
155
  height?: number;
156
+ /** Object type for smart cropping */
157
+ objectType?: CropObjectType;
158
+ }
159
+ /**
160
+ * Simple crop options - manual or strategy-based
161
+ */
162
+ interface SimpleCropOptions {
163
+ type: typeof CROP_TYPE.SIMPLE;
154
164
  /** Apply crop after resize */
155
165
  afterResize?: boolean;
166
+ /** Crop width in pixels */
167
+ width?: number;
168
+ /** Crop height in pixels */
169
+ height?: number;
170
+ /** Focus options */
171
+ focus: CropFocusOptions;
156
172
  }
173
+ /**
174
+ * Crop options - discriminated union
175
+ */
176
+ type CropOptions = ObjectCropOptions | SimpleCropOptions;
157
177
  /**
158
178
  * Text overlay options
159
179
  */
@@ -260,7 +280,7 @@ type NameMode = 'short' | 'long';
260
280
  * // => 'bo.w=2&bo.c=ff0000'
261
281
  * ```
262
282
  */
263
- declare const buildQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
283
+ declare const buildTransformationQueryParams: (options: TransformationOptions, mode?: NameMode) => string;
264
284
  /**
265
285
  * Builds a complete transformation URL from a base URL and transformation options.
266
286
  *
@@ -275,11 +295,11 @@ declare const buildQueryParams: (options: TransformationOptions, mode?: NameMode
275
295
  *
276
296
  * @example
277
297
  * ```ts
278
- * const config = { baseUrl: 'https://cdn.example.com/images/photo.jpg' };
298
+ * const config = { baseUrl: 'https://example.com/images/photo.jpg' };
279
299
  *
280
300
  * // Basic resize
281
301
  * buildTransformationUrl(config, { width: 400, height: 300 });
282
- * // => 'https://cdn.example.com/images/photo.jpg?w=400&h=300'
302
+ * // => 'https://example.com/images/photo.jpg?w=400&h=300'
283
303
  *
284
304
  * // Multiple transformations
285
305
  * buildTransformationUrl(config, {
@@ -288,17 +308,17 @@ declare const buildQueryParams: (options: TransformationOptions, mode?: NameMode
288
308
  * quality: 85,
289
309
  * blur: 5
290
310
  * });
291
- * // => 'https://cdn.example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'
311
+ * // => 'https://example.com/images/photo.jpg?w=800&f=webp&q=85&bl=5'
292
312
  *
293
313
  * // Request original image (no transformations)
294
314
  * buildTransformationUrl(config, { original: true });
295
- * // => 'https://cdn.example.com/images/photo.jpg?original'
315
+ * // => 'https://example.com/images/photo.jpg?original'
296
316
  *
297
317
  * // Using long parameter names
298
318
  * buildTransformationUrl(config, { width: 400 }, 'long');
299
- * // => 'https://cdn.example.com/images/photo.jpg?width=400'
319
+ * // => 'https://example.com/images/photo.jpg?width=400'
300
320
  * ```
301
321
  */
302
322
  declare const buildTransformationUrl: (config: UrlBuilderConfig, options: TransformationOptions, mode?: NameMode) => string;
303
323
 
304
- export { type BorderOptions, CROP_FOCUS, CROP_FOCUS_STRATEGY, CROP_OBJECT_TYPE, CROP_TYPE, 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 PixelFiddlerConfig, type Position, type ResizeMode, type ResizeOptions, type RotationAngle, type TextOptions, type TransformationOptions, type UrlBuilderConfig, type WatermarkOptions, buildQueryParams, buildTransformationUrl };
324
+ 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 };
package/dist/index.js CHANGED
@@ -1,22 +1,3 @@
1
- // src/types.ts
2
- var CROP_FOCUS = {
3
- SPECIFIED: "SPECIFIED",
4
- AUTO: "AUTO"
5
- };
6
- var CROP_FOCUS_STRATEGY = {
7
- CENTER: "CENTER",
8
- SMART: "SMART",
9
- DETAIL: "DETAIL"
10
- };
11
- var CROP_TYPE = {
12
- SIMPLE: "SIMPLE",
13
- OBJECT: "OBJECT"
14
- };
15
- var CROP_OBJECT_TYPE = {
16
- FACE: "FACE",
17
- UPPER_BODY: "UPPER_BODY"
18
- };
19
-
20
1
  // src/utils.ts
21
2
  var normalizeHex = (value) => value.replace("#", "");
22
3
  var removeTrailingSlash = (baseUrl) => {
@@ -95,7 +76,7 @@ var PARAMS = [
95
76
  ];
96
77
 
97
78
  // src/url-builder.ts
98
- var buildQueryParams = (options, mode = "short") => {
79
+ var buildTransformationQueryParams = (options, mode = "short") => {
99
80
  const params = [];
100
81
  for (const spec of PARAMS) {
101
82
  const value = getNestedValue(options, spec.path);
@@ -115,11 +96,11 @@ var buildTransformationUrl = (config, options, mode = "short") => {
115
96
  if (options.original) {
116
97
  return `${config.baseUrl}?original`;
117
98
  }
118
- const query = buildQueryParams(options, mode);
99
+ const query = buildTransformationQueryParams(options, mode);
119
100
  const baseUrl = removeTrailingSlash(config.baseUrl);
120
101
  return `${baseUrl}?${query}`;
121
102
  };
122
103
 
123
- export { CROP_FOCUS, CROP_FOCUS_STRATEGY, CROP_OBJECT_TYPE, CROP_TYPE, buildQueryParams, buildTransformationUrl };
104
+ export { buildTransformationQueryParams, buildTransformationUrl };
124
105
  //# sourceMappingURL=index.js.map
125
106
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * Helper type to extract values from const objects\r\n */\r\ntype ObjectValue<T> = T[keyof T];\r\n\r\n/**\r\n * Resize mode for image transformations\r\n */\r\nexport type ResizeMode = 'FILL' | 'FIT' | 'PAD' | 'FORCE' | 'COVER';\r\n\r\n/**\r\n * Output image format - null or empty means AUTO\r\n */\r\nexport type ImageFormat = 'jpeg' | 'png' | 'webp' | 'avif' | 'gif'\r\n\r\n/**\r\n * Position for text overlays and watermarks\r\n */\r\nexport type Position =\r\n | 'TOP_LEFT'\r\n | 'TOP_CENTER'\r\n | 'TOP_RIGHT'\r\n | 'CENTER_LEFT'\r\n | 'CENTER'\r\n | 'CENTER_RIGHT'\r\n | 'BOTTOM_LEFT'\r\n | 'BOTTOM_CENTER'\r\n | 'BOTTOM_RIGHT';\r\n\r\n/**\r\n * Crop focus type\r\n */\r\nexport const CROP_FOCUS = {\r\n SPECIFIED: 'SPECIFIED',\r\n AUTO: 'AUTO',\r\n} as const;\r\n\r\nexport type CropFocus = ObjectValue<typeof CROP_FOCUS>;\r\n\r\n/**\r\n * Crop focus strategy for AUTO focus\r\n */\r\nexport const CROP_FOCUS_STRATEGY = {\r\n CENTER: 'CENTER',\r\n SMART: 'SMART',\r\n DETAIL: 'DETAIL',\r\n} as const;\r\n\r\nexport type CropFocusStrategy = ObjectValue<typeof CROP_FOCUS_STRATEGY>;\r\n\r\n/**\r\n * Crop type\r\n */\r\nexport const CROP_TYPE = {\r\n SIMPLE: 'SIMPLE',\r\n OBJECT: 'OBJECT',\r\n} as const;\r\n\r\nexport type CropType = ObjectValue<typeof CROP_TYPE>;\r\n\r\n/**\r\n * Object type for smart cropping\r\n */\r\nexport const CROP_OBJECT_TYPE = {\r\n FACE: 'FACE',\r\n UPPER_BODY: 'UPPER_BODY',\r\n} as const;\r\n\r\nexport type CropObjectType = ObjectValue<typeof CROP_OBJECT_TYPE>;\r\n\r\n/**\r\n * Rotation angle in degrees (clockwise)\r\n */\r\nexport type RotationAngle = 0 | 90 | 180 | 270;\r\n\r\n/**\r\n * Device pixel ratio for high-density displays\r\n */\r\nexport type DevicePixelRatio = 1 | 2 | 3 | 4;\r\n\r\n/**\r\n * Hex color string (with or without #)\r\n */\r\nexport type HexColor = string;\r\n\r\n/**\r\n * Resize transformation options\r\n */\r\nexport interface ResizeOptions {\r\n /** Target width in pixels (1-4096) */\r\n width?: number;\r\n /** Target height in pixels (1-4096) */\r\n height?: number;\r\n /** Device pixel ratio for retina displays */\r\n dpr?: DevicePixelRatio;\r\n /** Resize strategy */\r\n mode?: ResizeMode;\r\n /** Background color for PAD mode (hex) */\r\n background?: HexColor;\r\n}\r\n\r\n/**\r\n * Format and quality options\r\n */\r\nexport interface FormatOptions {\r\n /** Output format */\r\n format?: ImageFormat;\r\n /** Quality level (1-100) */\r\n quality?: number;\r\n /** Strip metadata from output */\r\n stripMetadata?: boolean;\r\n}\r\n\r\n/**\r\n * Effect transformation options\r\n */\r\nexport interface EffectOptions {\r\n /** Gaussian blur intensity (0-100) */\r\n blur?: number;\r\n /** Brightness adjustment (0-100) */\r\n brightness?: number;\r\n /** Contrast adjustment (0-100) */\r\n contrast?: number;\r\n /** Convert to grayscale */\r\n grayscale?: boolean;\r\n /** Saturation adjustment (0-100) */\r\n saturation?: number;\r\n /** Apply sepia effect */\r\n sepia?: boolean;\r\n /** Sharpen intensity (0-100) */\r\n sharpen?: number;\r\n /** Add noise intensity (0-100) */\r\n noise?: number;\r\n /** Rotation angle */\r\n rotate?: RotationAngle;\r\n}\r\n\r\n/**\r\n * Border options\r\n */\r\nexport interface BorderOptions {\r\n /** Border width in pixels */\r\n width?: number;\r\n /** Border color (hex) */\r\n color?: HexColor;\r\n /** Corner radius in pixels (1-2000) */\r\n radius?: number;\r\n}\r\n\r\n/**\r\n * Crop focus position for SPECIFIED focus type\r\n */\r\nexport interface CropFocusPosition {\r\n x?: number;\r\n y?: number;\r\n}\r\n\r\n/**\r\n * Crop focus options\r\n */\r\nexport interface CropFocusOptions {\r\n /** Focus type - SPECIFIED (manual position) or AUTO (strategy-based) */\r\n type?: CropFocus;\r\n /** Manual focus position when type is SPECIFIED */\r\n position?: CropFocusPosition;\r\n /** Auto focus strategy when type is AUTO */\r\n strategy?: CropFocusStrategy;\r\n}\r\n\r\n/**\r\n * Crop options\r\n */\r\nexport interface CropOptions {\r\n /** Crop type - SIMPLE or OBJECT */\r\n type?: CropType;\r\n /** Object type for OBJECT crop type */\r\n objectType?: CropObjectType;\r\n /** Focus options */\r\n focus?: CropFocusOptions;\r\n /** Crop width in pixels */\r\n width?: number;\r\n /** Crop height in pixels */\r\n height?: number;\r\n /** Apply crop after resize */\r\n afterResize?: boolean;\r\n}\r\n\r\n/**\r\n * Text overlay options\r\n */\r\nexport interface TextOptions {\r\n /** Text content to render */\r\n text?: string;\r\n /** Text color (hex) */\r\n color?: HexColor;\r\n /** Text opacity (0-100) */\r\n opacity?: number;\r\n /** Background color behind text (hex) */\r\n background?: HexColor;\r\n /** Background opacity (0-100) */\r\n backgroundOpacity?: number;\r\n /** Text size as percentage of image (1-100) */\r\n size?: number;\r\n /** Font family name */\r\n font?: string;\r\n /** Font size in pixels */\r\n fontSize?: number;\r\n /** Text position */\r\n position?: Position;\r\n}\r\n\r\n/**\r\n * Watermark options\r\n */\r\nexport interface WatermarkOptions {\r\n /** Watermark name (predefined in dashboard) */\r\n name?: string;\r\n /** Watermark opacity (0-100) */\r\n opacity?: number;\r\n /** Watermark size as percentage (1-100) */\r\n size?: number;\r\n /** Watermark width in pixels */\r\n width?: number;\r\n /** Watermark height in pixels */\r\n height?: number;\r\n /** Watermark position */\r\n position?: Position;\r\n}\r\n\r\n/**\r\n * All transformation options combined\r\n */\r\nexport interface TransformationOptions\r\n extends ResizeOptions,\r\n FormatOptions,\r\n EffectOptions {\r\n /** Border options */\r\n border?: BorderOptions;\r\n /** Crop options */\r\n crop?: CropOptions;\r\n /** Text overlay options */\r\n text?: TextOptions;\r\n /** Watermark options */\r\n watermark?: WatermarkOptions;\r\n /** Use predefined transformation alias */\r\n alias?: string;\r\n /** Return original image without transformations */\r\n original?: boolean;\r\n}\r\n\r\n/**\r\n * Configuration for PixelFiddler client\r\n */\r\nexport interface PixelFiddlerConfig {\r\n /** Base URL for the CDN (defaults to https://cdn.pixel-fiddler.com) */\r\n baseUrl?: string;\r\n /** Secret key for URL signing */\r\n signatureKey?: string;\r\n}\r\n\r\n/**\r\n * URL builder configuration (internal)\r\n */\r\nexport interface UrlBuilderConfig extends PixelFiddlerConfig {\r\n /** Resolved base URL */\r\n baseUrl: string;\r\n}\r\n\r\n/**\r\n * Mapping of transformation options to query parameter names\r\n */\r\nexport interface QueryParameterMapping {\r\n /** Full parameter name */\r\n name: string;\r\n /** Short alias */\r\n alias?: string;\r\n}\r\n\r\n\r\n","import { Path, PathValue } from './util-types';\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","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\ntype 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 buildQueryParams = (\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://cdn.example.com/images/photo.jpg' };\r\n *\r\n * // Basic resize\r\n * buildTransformationUrl(config, { width: 400, height: 300 });\r\n * // => 'https://cdn.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://cdn.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://cdn.example.com/images/photo.jpg?original'\r\n *\r\n * // Using long parameter names\r\n * buildTransformationUrl(config, { width: 400 }, 'long');\r\n * // => 'https://cdn.example.com/images/photo.jpg?width=400'\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 if (options.original) {\r\n return `${config.baseUrl}?original`;\r\n }\r\n\r\n const query = buildQueryParams(options, mode);\r\n\r\n const baseUrl = removeTrailingSlash(config.baseUrl)\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
1
+ {"version":3,"sources":["../src/utils.ts","../src/config.ts","../src/url-builder.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { Path, PathValue } from './util-types';\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","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\ntype 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\nexport const buildTransformationUrl = (\r\n config: UrlBuilderConfig,\r\n options: TransformationOptions,\r\n mode: NameMode = 'short'\r\n) => {\r\n if (options.original) {\r\n return `${config.baseUrl}?original`;\r\n }\r\n\r\n const query = buildTransformationQueryParams(options, mode);\r\n\r\n const baseUrl = removeTrailingSlash(config.baseUrl)\r\n return `${baseUrl}?${query}`;\r\n};\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixelfiddler/core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Core utilities for PixelFiddler image transformation SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",