@techfinityedge/koolbase-react-native 5.3.0 → 5.4.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/README.md CHANGED
@@ -235,6 +235,56 @@ URLs follow the pattern `https://cdn.koolbase.com/{project_id}/{bucket}/{path}`
235
235
 
236
236
  ---
237
237
 
238
+ ### Image transforms
239
+
240
+ Public bucket URLs can be transformed at the edge — resize, reformat,
241
+ optimize — without any preprocessing. Two ways:
242
+
243
+ **Direct transforms** — pass a `transform` option to `publicUrl`:
244
+
245
+ ```ts
246
+ const url = KoolbaseStorage.publicUrl({
247
+ projectId: 'proj_abc',
248
+ bucket: 'avatars',
249
+ path: 'user-123.jpg',
250
+ transform: {
251
+ width: 200,
252
+ height: 200,
253
+ fit: 'cover',
254
+ format: 'auto',
255
+ quality: 85,
256
+ },
257
+ });
258
+ ```
259
+
260
+ **Named presets** — store an option set server-side (via the dashboard or
261
+ REST API), reference it by name:
262
+
263
+ ```ts
264
+ const url = KoolbaseStorage.publicUrlWithPreset({
265
+ projectId: 'proj_abc',
266
+ presetName: 'thumbnail',
267
+ bucket: 'avatars',
268
+ path: 'user-123.jpg',
269
+ });
270
+
271
+ // Or from a KoolbaseObject instance:
272
+ const url = KoolbaseStorage.publicUrlForObjectWithPreset(object, 'avatars', 'thumbnail');
273
+ ```
274
+
275
+ Available options: `width` and `height` (1–2000), `format`
276
+ (`auto`/`webp`/`avif`/`jpeg`/`png`), `quality` (1–100), `fit`
277
+ (`scale-down`/`contain`/`cover`/`crop`/`pad`), `dpr` (1–3), `gravity`
278
+ (`auto`/`center`/`top`/`bottom`/`left`/`right`/`top-left`/`top-right`/
279
+ `bottom-left`/`bottom-right`). Transformed responses are edge-cached for 4
280
+ hours; Cloudflare includes 5,000 unique transformations/month free per
281
+ account.
282
+
283
+ See the [Image Transforms docs](https://docs.koolbase.com/storage/image-transforms)
284
+ for the full reference.
285
+
286
+ ---
287
+
238
288
  ### Upsert
239
289
 
240
290
  Insert a record, or update the existing one matching a filter.
package/dist/storage.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { KoolbaseConfig, UploadOptions, UploadResult, KoolbaseObject } from './types';
1
+ import { KoolbaseConfig, UploadOptions, UploadResult, KoolbaseObject, KoolbaseImageTransform } from './types';
2
2
  /**
3
3
  * Koolbase storage client — uploads, downloads, and deletes via presigned
4
4
  * Cloudflare R2 URLs.
@@ -91,6 +91,13 @@ export declare class KoolbaseStorage {
91
91
  projectId: string;
92
92
  bucket: string;
93
93
  path: string;
94
+ /**
95
+ * Optional Cloudflare Image Transformations. Adds a `/cdn-cgi/image/`
96
+ * URL prefix; billed against the koolbase.com zone's free monthly
97
+ * allocation (5,000 unique transforms/month). Each unique combination
98
+ * of `path` + options is cached and billed only once per calendar month.
99
+ */
100
+ transform?: KoolbaseImageTransform;
94
101
  }): string;
95
102
  /**
96
103
  * Returns the stable CDN URL for an object when its bytes physically
@@ -106,7 +113,35 @@ export declare class KoolbaseStorage {
106
113
  * carries only the bucket ID, not its name. Typically the caller
107
114
  * already knows which bucket they queried.
108
115
  */
109
- static publicUrlForObject(obj: KoolbaseObject, bucket: string): string | null;
116
+ static publicUrlForObject(obj: KoolbaseObject, bucket: string, options?: {
117
+ transform?: KoolbaseImageTransform;
118
+ }): string | null;
119
+ /**
120
+ * Builds a named-preset CDN URL. The preset is resolved at the Cloudflare
121
+ * edge by the koolbase-cdn-worker, which looks up
122
+ * `preset:{project_id}:{preset_name}` in Workers KV and applies the stored
123
+ * transformation options. Presets are managed in the dashboard under
124
+ * Storage → Presets.
125
+ *
126
+ * Unknown preset names yield a 404 at the edge — the URL itself always
127
+ * constructs successfully without a network round-trip.
128
+ *
129
+ * For safer construction from an Object you already have, use
130
+ * {@link KoolbaseStorage.publicUrlForObjectWithPreset} — it checks the
131
+ * stored `r2Bucket` value and returns `null` when the object isn't in the
132
+ * public R2 bucket.
133
+ */
134
+ static publicUrlWithPreset(args: {
135
+ projectId: string;
136
+ presetName: string;
137
+ bucket: string;
138
+ path: string;
139
+ }): string;
140
+ /**
141
+ * Returns the named-preset CDN URL for the given object, or `null` if the
142
+ * object isn't in the public R2 bucket.
143
+ */
144
+ static publicUrlForObjectWithPreset(obj: KoolbaseObject, bucket: string, presetName: string): string | null;
110
145
  /**
111
146
  * Delete a file from a bucket.
112
147
  */
package/dist/storage.js CHANGED
@@ -2,6 +2,35 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KoolbaseStorage = void 0;
4
4
  const storage_errors_1 = require("./storage-errors");
5
+ // --- Cloudflare image-transform URL helpers -------------------------------
6
+ // Module-private — callers use KoolbaseStorage.publicUrl / publicUrlForObject.
7
+ function clampInt(v, min, max) {
8
+ return Math.max(min, Math.min(max, Math.floor(v)));
9
+ }
10
+ /**
11
+ * Serializes a transform spec to Cloudflare's comma-separated key=value
12
+ * options segment (e.g. `width=400,format=webp,quality=80`). Returns the
13
+ * empty string when no fields are set — callers can use that to skip the
14
+ * `/cdn-cgi/image/` URL prefix entirely.
15
+ */
16
+ function serializeTransform(t) {
17
+ const parts = [];
18
+ if (t.width != null)
19
+ parts.push(`width=${clampInt(t.width, 1, 2000)}`);
20
+ if (t.height != null)
21
+ parts.push(`height=${clampInt(t.height, 1, 2000)}`);
22
+ if (t.format)
23
+ parts.push(`format=${t.format}`);
24
+ if (t.quality != null)
25
+ parts.push(`quality=${clampInt(t.quality, 1, 100)}`);
26
+ if (t.fit)
27
+ parts.push(`fit=${t.fit}`);
28
+ if (t.dpr != null)
29
+ parts.push(`dpr=${clampInt(t.dpr, 1, 3)}`);
30
+ if (t.gravity)
31
+ parts.push(`gravity=${t.gravity}`);
32
+ return parts.join(',');
33
+ }
5
34
  /**
6
35
  * Koolbase storage client — uploads, downloads, and deletes via presigned
7
36
  * Cloudflare R2 URLs.
@@ -194,7 +223,11 @@ class KoolbaseStorage {
194
223
  // Encode each path segment individually so slashes are preserved
195
224
  // while spaces, parens, hashes, and query characters are escaped.
196
225
  const encoded = args.path.split('/').map(encodeURIComponent).join('/');
197
- return `https://cdn.koolbase.com/${args.projectId}/${args.bucket}/${encoded}`;
226
+ const opts = args.transform ? serializeTransform(args.transform) : '';
227
+ if (!opts) {
228
+ return `https://cdn.koolbase.com/${args.projectId}/${args.bucket}/${encoded}`;
229
+ }
230
+ return `https://cdn.koolbase.com/cdn-cgi/image/${opts}/${args.projectId}/${args.bucket}/${encoded}`;
198
231
  }
199
232
  /**
200
233
  * Returns the stable CDN URL for an object when its bytes physically
@@ -210,10 +243,48 @@ class KoolbaseStorage {
210
243
  * carries only the bucket ID, not its name. Typically the caller
211
244
  * already knows which bucket they queried.
212
245
  */
213
- static publicUrlForObject(obj, bucket) {
246
+ static publicUrlForObject(obj, bucket, options) {
247
+ if (obj.r2Bucket !== 'koolbase-storage-public')
248
+ return null;
249
+ return KoolbaseStorage.publicUrl({
250
+ projectId: obj.projectId,
251
+ bucket,
252
+ path: obj.path,
253
+ transform: options?.transform,
254
+ });
255
+ }
256
+ /**
257
+ * Builds a named-preset CDN URL. The preset is resolved at the Cloudflare
258
+ * edge by the koolbase-cdn-worker, which looks up
259
+ * `preset:{project_id}:{preset_name}` in Workers KV and applies the stored
260
+ * transformation options. Presets are managed in the dashboard under
261
+ * Storage → Presets.
262
+ *
263
+ * Unknown preset names yield a 404 at the edge — the URL itself always
264
+ * constructs successfully without a network round-trip.
265
+ *
266
+ * For safer construction from an Object you already have, use
267
+ * {@link KoolbaseStorage.publicUrlForObjectWithPreset} — it checks the
268
+ * stored `r2Bucket` value and returns `null` when the object isn't in the
269
+ * public R2 bucket.
270
+ */
271
+ static publicUrlWithPreset(args) {
272
+ const encoded = args.path.split('/').map(encodeURIComponent).join('/');
273
+ return `https://cdn.koolbase.com/p/${args.projectId}/${args.presetName}/${args.bucket}/${encoded}`;
274
+ }
275
+ /**
276
+ * Returns the named-preset CDN URL for the given object, or `null` if the
277
+ * object isn't in the public R2 bucket.
278
+ */
279
+ static publicUrlForObjectWithPreset(obj, bucket, presetName) {
214
280
  if (obj.r2Bucket !== 'koolbase-storage-public')
215
281
  return null;
216
- return KoolbaseStorage.publicUrl({ projectId: obj.projectId, bucket, path: obj.path });
282
+ return KoolbaseStorage.publicUrlWithPreset({
283
+ projectId: obj.projectId,
284
+ presetName,
285
+ bucket,
286
+ path: obj.path,
287
+ });
217
288
  }
218
289
  /**
219
290
  * Delete a file from a bucket.
package/dist/types.d.ts CHANGED
@@ -345,3 +345,37 @@ export interface BatchResult {
345
345
  /** True for a successful delete. */
346
346
  deleted?: boolean;
347
347
  }
348
+ export type KoolbaseImageFormat = 'auto' | 'webp' | 'avif' | 'jpeg' | 'png';
349
+ export type KoolbaseImageFit = 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
350
+ export type KoolbaseImageGravity = 'auto' | 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
351
+ /**
352
+ * Image-transformation options for `KoolbaseStorage.publicUrl` and
353
+ * `KoolbaseStorage.publicUrlForObject`. Each field maps to one Cloudflare
354
+ * Image Transformations parameter; unset fields are omitted.
355
+ *
356
+ * All numeric inputs are clamped silently to Cloudflare-supported ranges
357
+ * (width/height 1-2000, quality 1-100, dpr 1-3) so a stray `width: 99999`
358
+ * can't trigger error 9422 at the edge.
359
+ *
360
+ * @example
361
+ * const url = KoolbaseStorage.publicUrl({
362
+ * projectId: pid, bucket: 'avatars', path: 'user.jpg',
363
+ * transform: { width: 400, height: 400, format: 'webp', quality: 80, fit: 'cover' },
364
+ * });
365
+ */
366
+ export interface KoolbaseImageTransform {
367
+ /** Output width in pixels. Clamped to 1-2000. */
368
+ width?: number;
369
+ /** Output height in pixels. Clamped to 1-2000. */
370
+ height?: number;
371
+ /** Output format. `auto` negotiates based on the request's `Accept` header. */
372
+ format?: KoolbaseImageFormat;
373
+ /** Quality 1-100. Clamped. Has no effect on lossless formats (`png`). */
374
+ quality?: number;
375
+ /** Resize mode when both width and height are specified. */
376
+ fit?: KoolbaseImageFit;
377
+ /** Device pixel ratio multiplier. Clamped to 1-3. */
378
+ dpr?: number;
379
+ /** Crop anchor. Use with `fit: 'cover'` or `fit: 'crop'`. */
380
+ gravity?: KoolbaseImageGravity;
381
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techfinityedge/koolbase-react-native",
3
- "version": "5.3.0",
3
+ "version": "5.4.0",
4
4
  "description": "React Native SDK for Koolbase — auth, database, storage, realtime, feature flags, and functions in one package.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",