cloudinary-lite 1.0.0 → 1.1.0

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/.gitattributes ADDED
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
@@ -0,0 +1,27 @@
1
+ name: Publish to NPM
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout Repository
13
+ uses: actions/checkout@v4
14
+
15
+ - name: Set up Node.js
16
+ uses: actions/setup-node@v4
17
+ with:
18
+ node-version: '20'
19
+ registry-url: 'https://registry.npmjs.org/'
20
+
21
+ - name: Install Dependencies
22
+ run: npm ci
23
+
24
+ - name: Publish Package
25
+ run: npm publish --access public
26
+ env:
27
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/index.js CHANGED
@@ -158,3 +158,101 @@ export function parseCloudinaryUrl(url) {
158
158
  return null;
159
159
  }
160
160
  }
161
+
162
+ /**
163
+ * Generates a transformed/scaled Cloudinary URL on the fly.
164
+ *
165
+ * @param {string} url - The original Cloudinary secure URL.
166
+ * @param {Object|string} options - An object of transformations (e.g. { width: 300, height: 300, crop: 'fill', quality: 'auto', format: 'auto' }) or a raw transformation string (e.g. 'w_300,h_300,c_fill').
167
+ * @returns {string} - The transformed Cloudinary URL.
168
+ */
169
+ export function getTransformedUrl(url, options) {
170
+ if (!url || typeof url !== 'string' || !url.includes('cloudinary.com')) {
171
+ return url;
172
+ }
173
+
174
+ let transformStr = '';
175
+ if (typeof options === 'string') {
176
+ transformStr = options;
177
+ } else if (options && typeof options === 'object') {
178
+ const parts = [];
179
+ if (options.width) parts.push(`w_${options.width}`);
180
+ if (options.height) parts.push(`h_${options.height}`);
181
+ if (options.crop) parts.push(`c_${options.crop}`);
182
+ if (options.quality) parts.push(`q_${options.quality}`);
183
+ if (options.fetch_format || options.format) parts.push(`f_${options.fetch_format || options.format}`);
184
+ if (options.gravity) parts.push(`g_${options.gravity}`);
185
+
186
+ if (options.raw) parts.push(options.raw);
187
+
188
+ transformStr = parts.join(',');
189
+ }
190
+
191
+ if (!transformStr) {
192
+ return url;
193
+ }
194
+
195
+ try {
196
+ const parsed = new URL(url);
197
+ const path = parsed.pathname;
198
+ const pathParts = path.split('/').filter(Boolean);
199
+
200
+ const uploadIndex = pathParts.indexOf('upload');
201
+ if (uploadIndex === -1) {
202
+ return url;
203
+ }
204
+
205
+ pathParts.splice(uploadIndex + 1, 0, transformStr);
206
+
207
+ parsed.pathname = '/' + pathParts.join('/');
208
+ return parsed.toString();
209
+ } catch (_) {
210
+ return url;
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Cloudinary Crop modes (`c_` transformations).
216
+ * @enum {string}
217
+ */
218
+ export const Crop = Object.freeze({
219
+ FILL: 'fill',
220
+ LFILL: 'lfill',
221
+ FILL_PAD: 'fill_pad',
222
+ FIT: 'fit',
223
+ LIMIT: 'limit',
224
+ MFIT: 'mfit',
225
+ PAD: 'pad',
226
+ LPAD: 'lpad',
227
+ MPAD: 'mpad',
228
+ SCALE: 'scale',
229
+ THUMB: 'thumb',
230
+ CROP: 'crop'
231
+ });
232
+
233
+ /**
234
+ * Cloudinary Quality modes (`q_` transformations).
235
+ * @enum {string}
236
+ */
237
+ export const Quality = Object.freeze({
238
+ AUTO: 'auto',
239
+ AUTO_BEST: 'auto:best',
240
+ AUTO_GOOD: 'auto:good',
241
+ AUTO_ECO: 'auto:eco',
242
+ AUTO_LOW: 'auto:low'
243
+ });
244
+
245
+ /**
246
+ * Cloudinary Format modes (`f_` transformations).
247
+ * @enum {string}
248
+ */
249
+ export const Format = Object.freeze({
250
+ AUTO: 'auto',
251
+ JPG: 'jpg',
252
+ PNG: 'png',
253
+ WEBP: 'webp',
254
+ GIF: 'gif',
255
+ AVIF: 'avif',
256
+ PDF: 'pdf'
257
+ });
258
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudinary-lite",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Zero-dependency, lightweight helper for Cloudinary uploads (unsigned client-side) and secure deletes (signed server-side).",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/readme.md CHANGED
@@ -117,6 +117,76 @@ console.log(parsed);
117
117
 
118
118
  ---
119
119
 
120
+ ### 4. Dynamic URL Scaling & Transformations (Universal Helper)
121
+
122
+ Generate resized, cropped, or transformed Cloudinary asset URLs on-the-fly.
123
+
124
+ ```javascript
125
+ import { getTransformedUrl, Crop, Quality, Format } from 'cloudinary-lite';
126
+
127
+ const originalUrl = 'https://res.cloudinary.com/de3t60fd7/image/upload/v1722513904/alumni/profile-photos/abc123xyz.jpg';
128
+
129
+ // Option A: Pass options object using built-in enums (or plain strings)
130
+ const resizedUrl = getTransformedUrl(originalUrl, {
131
+ width: 300,
132
+ height: 300,
133
+ crop: Crop.FILL,
134
+ quality: Quality.AUTO,
135
+ format: Format.AUTO
136
+ });
137
+ console.log(resizedUrl);
138
+ // Output:
139
+ // https://res.cloudinary.com/de3t60fd7/image/upload/w_300,h_300,c_fill,q_auto,f_auto/v1722513904/alumni/profile-photos/abc123xyz.jpg
140
+
141
+ // Option B: Pass raw transformation string
142
+ const rawTransformedUrl = getTransformedUrl(originalUrl, 'w_150,h_150,c_thumb,g_face');
143
+ console.log(rawTransformedUrl);
144
+ // Output:
145
+ // https://res.cloudinary.com/de3t60fd7/image/upload/w_150,h_150,c_thumb,g_face/v1722513904/alumni/profile-photos/abc123xyz.jpg
146
+ ```
147
+
148
+ ---
149
+
150
+ ### 5. Configuration Enums (Helper Constants)
151
+
152
+ The library exports frozen objects (`Crop`, `Quality`, `Format`) to provide autocomplete, prevent typos, and document standard Cloudinary transformation values.
153
+
154
+ ```javascript
155
+ import { Crop, Quality, Format } from 'cloudinary-lite';
156
+ ```
157
+
158
+ #### `Crop`
159
+ * `Crop.FILL`: `'fill'`
160
+ * `Crop.LFILL`: `'lfill'`
161
+ * `Crop.FILL_PAD`: `'fill_pad'`
162
+ * `Crop.FIT`: `'fit'`
163
+ * `Crop.LIMIT`: `'limit'`
164
+ * `Crop.MFIT`: `'mfit'`
165
+ * `Crop.PAD`: `'pad'`
166
+ * `Crop.LPAD`: `'lpad'`
167
+ * `Crop.MPAD`: `'mpad'`
168
+ * `Crop.SCALE`: `'scale'`
169
+ * `Crop.THUMB`: `'thumb'`
170
+ * `Crop.CROP`: `'crop'`
171
+
172
+ #### `Quality`
173
+ * `Quality.AUTO`: `'auto'`
174
+ * `Quality.AUTO_BEST`: `'auto:best'`
175
+ * `Quality.AUTO_GOOD`: `'auto:good'`
176
+ * `Quality.AUTO_ECO`: `'auto:eco'`
177
+ * `Quality.AUTO_LOW`: `'auto:low'`
178
+
179
+ #### `Format`
180
+ * `Format.AUTO`: `'auto'`
181
+ * `Format.JPG`: `'jpg'`
182
+ * `Format.PNG`: `'png'`
183
+ * `Format.WEBP`: `'webp'`
184
+ * `Format.GIF`: `'gif'`
185
+ * `Format.AVIF`: `'avif'`
186
+ * `Format.PDF`: `'pdf'`
187
+
188
+ ---
189
+
120
190
  ## License
121
191
 
122
192
  MIT