Skip to content

Commit c96a85d

Browse files
committed
feat(storage): edge image transforms (Gap #8) — v5.4.0
KoolbaseImageTransform type + format/fit/gravity unions for direct transforms via Cloudflare /cdn-cgi/image/. Named presets via publicUrlWithPreset resolving server-managed option sets at cdn.koolbase.com/p/{project_id}/{preset_name}/... - KoolbaseStorage.publicUrl({..., transform}) — optional opts - KoolbaseStorage.publicUrlWithPreset({...}) - KoolbaseStorage.publicUrlForObjectWithPreset(obj, bucket, name) - README: new Image transforms section - CHANGELOG: 5.4.0 entry Additive, backward-compatible. Existing publicUrl calls without transform unchanged.
1 parent 0ac27b3 commit c96a85d

4 files changed

Lines changed: 132 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,44 @@ adheres to [Semantic Versioning][semver].
77
[kac]: https://keepachangelog.com/en/1.1.0/
88
[semver]: https://semver.org/
99

10+
# 5.4.0
11+
12+
### Added — storage
13+
14+
- Edge image transforms (Gap #8). Two complementary forms:
15+
- `KoolbaseStorage.publicUrl({ ..., transform })` accepts an
16+
optional `KoolbaseImageTransform` object — width, height,
17+
format, quality, fit, dpr, gravity. The resulting URL hits
18+
Cloudflare's image pipeline at
19+
`cdn.koolbase.com/cdn-cgi/image/<opts>/...` and serves a
20+
resized, re-encoded copy of the source.
21+
- `KoolbaseStorage.publicUrlWithPreset({ projectId, presetName,
22+
bucket, path })` resolves a named preset stored server-side
23+
(managed via the dashboard or REST API) at
24+
`cdn.koolbase.com/p/{project_id}/{preset_name}/{bucket}/{path}`.
25+
Edit the preset once on the server and every URL using it
26+
updates as the edge cache rolls over.
27+
- `KoolbaseStorage.publicUrlForObjectWithPreset(obj, bucket,
28+
presetName)` — instance-style variant when you already have a
29+
`KoolbaseObject` in hand.
30+
- New typed exports: `KoolbaseImageTransform`, `KoolbaseImageFormat`
31+
(`'auto' | 'webp' | 'avif' | 'jpeg' | 'png'`), `KoolbaseImageFit`
32+
(`'scale-down' | 'contain' | 'cover' | 'crop' | 'pad'`),
33+
`KoolbaseImageGravity` (10 anchor positions). Out-of-range numeric
34+
values clamp silently to Cloudflare's valid ranges (width/height
35+
1–2000, quality 1–100, dpr 1–3).
36+
37+
### Notes
38+
39+
Cloudflare bills unique transformations per calendar month; every
40+
Koolbase account includes 5,000 free. Transformed responses are
41+
edge-cached for 4 hours.
42+
43+
### Compatibility
44+
45+
No breaking changes. All new APIs are additive; existing `publicUrl`
46+
calls without `transform` produce the exact same URL they did in 5.3.0.
47+
1048
# 5.3.0
1149

1250
### Added — storage

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,56 @@ URLs follow the pattern `https://cdn.koolbase.com/{project_id}/{bucket}/{path}`
235235

236236
---
237237

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+
238288
### Upsert
239289

240290
Insert a record, or update the existing one matching a filter.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@techfinityedge/koolbase-react-native",
3-
"version": "5.3.0",
3+
"version": "5.4.0",
44
"description": "React Native SDK for Koolbase — auth, database, storage, realtime, feature flags, and functions in one package.",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/storage.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,49 @@ export class KoolbaseStorage {
308308
});
309309
}
310310

311+
/**
312+
* Builds a named-preset CDN URL. The preset is resolved at the Cloudflare
313+
* edge by the koolbase-cdn-worker, which looks up
314+
* `preset:{project_id}:{preset_name}` in Workers KV and applies the stored
315+
* transformation options. Presets are managed in the dashboard under
316+
* Storage → Presets.
317+
*
318+
* Unknown preset names yield a 404 at the edge — the URL itself always
319+
* constructs successfully without a network round-trip.
320+
*
321+
* For safer construction from an Object you already have, use
322+
* {@link KoolbaseStorage.publicUrlForObjectWithPreset} — it checks the
323+
* stored `r2Bucket` value and returns `null` when the object isn't in the
324+
* public R2 bucket.
325+
*/
326+
static publicUrlWithPreset(args: {
327+
projectId: string;
328+
presetName: string;
329+
bucket: string;
330+
path: string;
331+
}): string {
332+
const encoded = args.path.split('/').map(encodeURIComponent).join('/');
333+
return `https://cdn.koolbase.com/p/${args.projectId}/${args.presetName}/${args.bucket}/${encoded}`;
334+
}
335+
336+
/**
337+
* Returns the named-preset CDN URL for the given object, or `null` if the
338+
* object isn't in the public R2 bucket.
339+
*/
340+
static publicUrlForObjectWithPreset(
341+
obj: KoolbaseObject,
342+
bucket: string,
343+
presetName: string,
344+
): string | null {
345+
if (obj.r2Bucket !== 'koolbase-storage-public') return null;
346+
return KoolbaseStorage.publicUrlWithPreset({
347+
projectId: obj.projectId,
348+
presetName,
349+
bucket,
350+
path: obj.path,
351+
});
352+
}
353+
311354
/**
312355
* Delete a file from a bucket.
313356
*/

0 commit comments

Comments
 (0)