@techfinityedge/koolbase-react-native 5.3.0 → 5.5.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 +109 -1
- package/dist/storage.d.ts +74 -4
- package/dist/storage.js +187 -7
- package/dist/types.d.ts +76 -0
- package/package.json +1 -1
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.
|
|
@@ -435,6 +485,64 @@ so nothing leaks.
|
|
|
435
485
|
|
|
436
486
|
---
|
|
437
487
|
|
|
488
|
+
### Object versioning
|
|
489
|
+
|
|
490
|
+
For buckets with versioning enabled, every overwrite preserves the prior
|
|
491
|
+
content as a history version, and deletes are soft (recoverable until
|
|
492
|
+
force-purged). Enable versioning on a bucket from the dashboard.
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
// List all versions of a path, newest first
|
|
496
|
+
const versions = await Koolbase.storage.listVersions('documents', 'contract.pdf');
|
|
497
|
+
|
|
498
|
+
for (const v of versions) {
|
|
499
|
+
console.log(`${v.versionId}: size=${v.size} isCurrent=${v.isCurrent}`);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Download a specific historical version
|
|
503
|
+
const url = await Koolbase.storage.getDownloadUrl(
|
|
504
|
+
'documents',
|
|
505
|
+
'contract.pdf',
|
|
506
|
+
'019e98ed-eed6-7e71-...',
|
|
507
|
+
);
|
|
508
|
+
|
|
509
|
+
// Bring a history version back as current
|
|
510
|
+
// (the existing current is snapshotted to history first)
|
|
511
|
+
const restored = await Koolbase.storage.restoreVersion(
|
|
512
|
+
'documents',
|
|
513
|
+
'contract.pdf',
|
|
514
|
+
'019e98ed-eed6-7e71-...',
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
// Hard-remove a single history version (row + R2 bytes)
|
|
518
|
+
await Koolbase.storage.purgeVersion(
|
|
519
|
+
'documents',
|
|
520
|
+
'contract.pdf',
|
|
521
|
+
'old-version-id',
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
// Wipe the entire timeline for a path - every version, every R2 key
|
|
525
|
+
await Koolbase.storage.delete('documents', 'contract.pdf', true);
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
A few behaviors worth knowing:
|
|
529
|
+
|
|
530
|
+
- **Overwrite snapshots automatically.** Upload to a path that already
|
|
531
|
+
exists in a versioned bucket and the prior bytes are preserved as
|
|
532
|
+
history; the upload becomes the new current.
|
|
533
|
+
- **Delete is soft by default.** On a versioned bucket, `delete`
|
|
534
|
+
snapshots the current content and records a delete marker. The
|
|
535
|
+
content is still recoverable via `restoreVersion` until force-purged.
|
|
536
|
+
- **Restore is itself a versioned event.** The previously-current row
|
|
537
|
+
gets snapshotted before the target's bytes overwrite canonical. The
|
|
538
|
+
restored row gets a fresh `versionId`; the target stays in history at
|
|
539
|
+
its original id - so you can always undo a restore.
|
|
540
|
+
- **Delete markers can be listed but not downloaded.** A marker has
|
|
541
|
+
`size === 0`, `isDeleteMarker === true`, and no bytes. Calling
|
|
542
|
+
`getDownloadUrl` with a marker's `versionId` throws.
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
438
546
|
## Realtime
|
|
439
547
|
|
|
440
548
|
Subscribe to live changes on a collection. Uses the signed-in user's session, so
|
|
@@ -721,7 +829,7 @@ try {
|
|
|
721
829
|
|
|
722
830
|
- Authentication: email + password, Apple Sign-In, Google Sign-In, phone + OTP
|
|
723
831
|
- Database with offline-first cache, realtime subscriptions, and populate
|
|
724
|
-
- Storage with presigned uploads and downloads, safe-by-default conflict handling
|
|
832
|
+
- Storage with presigned uploads and downloads, safe-by-default conflict handling, image transforms, object versioning (history + restore + soft-delete)
|
|
725
833
|
- Realtime subscriptions over WebSocket
|
|
726
834
|
- Authenticated functions (`ctx.auth` exposes the caller automatically)
|
|
727
835
|
- Feature flags and remote config
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { KoolbaseConfig, UploadOptions, UploadResult, KoolbaseObject } from './types';
|
|
1
|
+
import { KoolbaseConfig, UploadOptions, UploadResult, KoolbaseObject, KoolbaseObjectVersion, KoolbaseImageTransform } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Koolbase storage client — uploads, downloads, and deletes via presigned
|
|
4
4
|
* Cloudflare R2 URLs.
|
|
@@ -72,7 +72,7 @@ export declare class KoolbaseStorage {
|
|
|
72
72
|
/**
|
|
73
73
|
* Get a signed download URL for a file.
|
|
74
74
|
*/
|
|
75
|
-
getDownloadUrl(bucket: string, path: string): Promise<string>;
|
|
75
|
+
getDownloadUrl(bucket: string, path: string, versionId?: string): Promise<string>;
|
|
76
76
|
/**
|
|
77
77
|
* Build the stable public CDN URL for a file in a public bucket.
|
|
78
78
|
*
|
|
@@ -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,9 +113,72 @@ 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
|
|
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
|
*/
|
|
113
|
-
delete(bucket: string, path: string): Promise<void>;
|
|
148
|
+
delete(bucket: string, path: string, forcePurge?: boolean): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* List all versions of a file path, newest-first. Returns a flat list
|
|
151
|
+
* mixing the current row (with `isCurrent: true`) and all history
|
|
152
|
+
* rows. Delete markers are included so callers can render the full
|
|
153
|
+
* timeline; filter client-side to hide them if the UI only wants
|
|
154
|
+
* restorable versions.
|
|
155
|
+
*
|
|
156
|
+
* Returns an empty array (not an error) when the path has no history
|
|
157
|
+
* and no current row.
|
|
158
|
+
*/
|
|
159
|
+
listVersions(bucket: string, path: string): Promise<KoolbaseObjectVersion[]>;
|
|
160
|
+
/**
|
|
161
|
+
* Fetch metadata for a single version by id. Works against both the
|
|
162
|
+
* current row and any history row — the response's `isCurrent` tells
|
|
163
|
+
* you which.
|
|
164
|
+
*/
|
|
165
|
+
getVersion(bucket: string, path: string, versionId: string): Promise<KoolbaseObjectVersion>;
|
|
166
|
+
/**
|
|
167
|
+
* Bring a history version back as the current version. The
|
|
168
|
+
* previously-current row (if any) is snapshotted into history first,
|
|
169
|
+
* so this operation is itself a versioned event you can undo. The
|
|
170
|
+
* restored row gets a freshly-minted version_id; the target stays in
|
|
171
|
+
* history at its original version_id.
|
|
172
|
+
*
|
|
173
|
+
* Throws if the bucket has versioning off, if the target is the
|
|
174
|
+
* already-current version, or if the target is a delete marker.
|
|
175
|
+
*/
|
|
176
|
+
restoreVersion(bucket: string, path: string, versionId: string): Promise<KoolbaseObject>;
|
|
177
|
+
/**
|
|
178
|
+
* Hard-remove a single history version — both the metadata row and
|
|
179
|
+
* the .versions/ R2 bytes (or just the row, for delete markers).
|
|
180
|
+
* Refuses to operate on the current version; use {@link delete} with
|
|
181
|
+
* `forcePurge: true` to wipe everything for a path.
|
|
182
|
+
*/
|
|
183
|
+
purgeVersion(bucket: string, path: string, versionId: string): Promise<void>;
|
|
114
184
|
}
|
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.
|
|
@@ -166,9 +195,12 @@ class KoolbaseStorage {
|
|
|
166
195
|
/**
|
|
167
196
|
* Get a signed download URL for a file.
|
|
168
197
|
*/
|
|
169
|
-
async getDownloadUrl(bucket, path) {
|
|
170
|
-
|
|
198
|
+
async getDownloadUrl(bucket, path, versionId) {
|
|
199
|
+
let url = `${this.config.baseUrl}/v1/sdk/storage/download-url` +
|
|
171
200
|
`?bucket=${encodeURIComponent(bucket)}&path=${encodeURIComponent(path)}`;
|
|
201
|
+
if (versionId) {
|
|
202
|
+
url += `&version_id=${encodeURIComponent(versionId)}`;
|
|
203
|
+
}
|
|
172
204
|
const res = await fetch(url, { headers: await this.buildHeaders() });
|
|
173
205
|
if (!res.ok) {
|
|
174
206
|
throw await (0, storage_errors_1.koolbaseStorageErrorFromResponse)(res, 'Failed to get download URL');
|
|
@@ -194,7 +226,11 @@ class KoolbaseStorage {
|
|
|
194
226
|
// Encode each path segment individually so slashes are preserved
|
|
195
227
|
// while spaces, parens, hashes, and query characters are escaped.
|
|
196
228
|
const encoded = args.path.split('/').map(encodeURIComponent).join('/');
|
|
197
|
-
|
|
229
|
+
const opts = args.transform ? serializeTransform(args.transform) : '';
|
|
230
|
+
if (!opts) {
|
|
231
|
+
return `https://cdn.koolbase.com/${args.projectId}/${args.bucket}/${encoded}`;
|
|
232
|
+
}
|
|
233
|
+
return `https://cdn.koolbase.com/cdn-cgi/image/${opts}/${args.projectId}/${args.bucket}/${encoded}`;
|
|
198
234
|
}
|
|
199
235
|
/**
|
|
200
236
|
* Returns the stable CDN URL for an object when its bytes physically
|
|
@@ -210,16 +246,57 @@ class KoolbaseStorage {
|
|
|
210
246
|
* carries only the bucket ID, not its name. Typically the caller
|
|
211
247
|
* already knows which bucket they queried.
|
|
212
248
|
*/
|
|
213
|
-
static publicUrlForObject(obj, bucket) {
|
|
249
|
+
static publicUrlForObject(obj, bucket, options) {
|
|
250
|
+
if (obj.r2Bucket !== 'koolbase-storage-public')
|
|
251
|
+
return null;
|
|
252
|
+
return KoolbaseStorage.publicUrl({
|
|
253
|
+
projectId: obj.projectId,
|
|
254
|
+
bucket,
|
|
255
|
+
path: obj.path,
|
|
256
|
+
transform: options?.transform,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Builds a named-preset CDN URL. The preset is resolved at the Cloudflare
|
|
261
|
+
* edge by the koolbase-cdn-worker, which looks up
|
|
262
|
+
* `preset:{project_id}:{preset_name}` in Workers KV and applies the stored
|
|
263
|
+
* transformation options. Presets are managed in the dashboard under
|
|
264
|
+
* Storage → Presets.
|
|
265
|
+
*
|
|
266
|
+
* Unknown preset names yield a 404 at the edge — the URL itself always
|
|
267
|
+
* constructs successfully without a network round-trip.
|
|
268
|
+
*
|
|
269
|
+
* For safer construction from an Object you already have, use
|
|
270
|
+
* {@link KoolbaseStorage.publicUrlForObjectWithPreset} — it checks the
|
|
271
|
+
* stored `r2Bucket` value and returns `null` when the object isn't in the
|
|
272
|
+
* public R2 bucket.
|
|
273
|
+
*/
|
|
274
|
+
static publicUrlWithPreset(args) {
|
|
275
|
+
const encoded = args.path.split('/').map(encodeURIComponent).join('/');
|
|
276
|
+
return `https://cdn.koolbase.com/p/${args.projectId}/${args.presetName}/${args.bucket}/${encoded}`;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Returns the named-preset CDN URL for the given object, or `null` if the
|
|
280
|
+
* object isn't in the public R2 bucket.
|
|
281
|
+
*/
|
|
282
|
+
static publicUrlForObjectWithPreset(obj, bucket, presetName) {
|
|
214
283
|
if (obj.r2Bucket !== 'koolbase-storage-public')
|
|
215
284
|
return null;
|
|
216
|
-
return KoolbaseStorage.
|
|
285
|
+
return KoolbaseStorage.publicUrlWithPreset({
|
|
286
|
+
projectId: obj.projectId,
|
|
287
|
+
presetName,
|
|
288
|
+
bucket,
|
|
289
|
+
path: obj.path,
|
|
290
|
+
});
|
|
217
291
|
}
|
|
218
292
|
/**
|
|
219
293
|
* Delete a file from a bucket.
|
|
220
294
|
*/
|
|
221
|
-
async delete(bucket, path) {
|
|
222
|
-
const
|
|
295
|
+
async delete(bucket, path, forcePurge) {
|
|
296
|
+
const url = forcePurge
|
|
297
|
+
? `${this.config.baseUrl}/v1/sdk/storage/object?force_purge=true`
|
|
298
|
+
: `${this.config.baseUrl}/v1/sdk/storage/object`;
|
|
299
|
+
const res = await fetch(url, {
|
|
223
300
|
method: 'DELETE',
|
|
224
301
|
headers: {
|
|
225
302
|
...(await this.buildHeaders()),
|
|
@@ -233,6 +310,82 @@ class KoolbaseStorage {
|
|
|
233
310
|
throw await (0, storage_errors_1.koolbaseStorageErrorFromResponse)(res, 'Failed to delete file');
|
|
234
311
|
}
|
|
235
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* List all versions of a file path, newest-first. Returns a flat list
|
|
315
|
+
* mixing the current row (with `isCurrent: true`) and all history
|
|
316
|
+
* rows. Delete markers are included so callers can render the full
|
|
317
|
+
* timeline; filter client-side to hide them if the UI only wants
|
|
318
|
+
* restorable versions.
|
|
319
|
+
*
|
|
320
|
+
* Returns an empty array (not an error) when the path has no history
|
|
321
|
+
* and no current row.
|
|
322
|
+
*/
|
|
323
|
+
async listVersions(bucket, path) {
|
|
324
|
+
const url = `${this.config.baseUrl}/v1/sdk/storage/object-versions` +
|
|
325
|
+
`?bucket=${encodeURIComponent(bucket)}&path=${encodeURIComponent(path)}`;
|
|
326
|
+
const res = await fetch(url, { headers: await this.buildHeaders() });
|
|
327
|
+
if (!res.ok) {
|
|
328
|
+
throw await (0, storage_errors_1.koolbaseStorageErrorFromResponse)(res, 'Failed to list versions');
|
|
329
|
+
}
|
|
330
|
+
const data = (await res.json());
|
|
331
|
+
const list = Array.isArray(data.versions) ? data.versions : [];
|
|
332
|
+
return list.map((v) => fromVersionJson(v));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Fetch metadata for a single version by id. Works against both the
|
|
336
|
+
* current row and any history row — the response's `isCurrent` tells
|
|
337
|
+
* you which.
|
|
338
|
+
*/
|
|
339
|
+
async getVersion(bucket, path, versionId) {
|
|
340
|
+
const url = `${this.config.baseUrl}/v1/sdk/storage/object-versions/${encodeURIComponent(versionId)}` +
|
|
341
|
+
`?bucket=${encodeURIComponent(bucket)}&path=${encodeURIComponent(path)}`;
|
|
342
|
+
const res = await fetch(url, { headers: await this.buildHeaders() });
|
|
343
|
+
if (!res.ok) {
|
|
344
|
+
throw await (0, storage_errors_1.koolbaseStorageErrorFromResponse)(res, 'Failed to fetch version');
|
|
345
|
+
}
|
|
346
|
+
return fromVersionJson((await res.json()));
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Bring a history version back as the current version. The
|
|
350
|
+
* previously-current row (if any) is snapshotted into history first,
|
|
351
|
+
* so this operation is itself a versioned event you can undo. The
|
|
352
|
+
* restored row gets a freshly-minted version_id; the target stays in
|
|
353
|
+
* history at its original version_id.
|
|
354
|
+
*
|
|
355
|
+
* Throws if the bucket has versioning off, if the target is the
|
|
356
|
+
* already-current version, or if the target is a delete marker.
|
|
357
|
+
*/
|
|
358
|
+
async restoreVersion(bucket, path, versionId) {
|
|
359
|
+
const url = `${this.config.baseUrl}/v1/sdk/storage/object-versions/${encodeURIComponent(versionId)}/restore` +
|
|
360
|
+
`?bucket=${encodeURIComponent(bucket)}&path=${encodeURIComponent(path)}`;
|
|
361
|
+
const res = await fetch(url, {
|
|
362
|
+
method: 'POST',
|
|
363
|
+
headers: await this.buildHeaders(),
|
|
364
|
+
});
|
|
365
|
+
if (!res.ok) {
|
|
366
|
+
throw await (0, storage_errors_1.koolbaseStorageErrorFromResponse)(res, 'Failed to restore version');
|
|
367
|
+
}
|
|
368
|
+
return mapObjectFromServer(await res.json());
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Hard-remove a single history version — both the metadata row and
|
|
372
|
+
* the .versions/ R2 bytes (or just the row, for delete markers).
|
|
373
|
+
* Refuses to operate on the current version; use {@link delete} with
|
|
374
|
+
* `forcePurge: true` to wipe everything for a path.
|
|
375
|
+
*/
|
|
376
|
+
async purgeVersion(bucket, path, versionId) {
|
|
377
|
+
const url = `${this.config.baseUrl}/v1/sdk/storage/object-versions/${encodeURIComponent(versionId)}` +
|
|
378
|
+
`?bucket=${encodeURIComponent(bucket)}&path=${encodeURIComponent(path)}`;
|
|
379
|
+
const res = await fetch(url, {
|
|
380
|
+
method: 'DELETE',
|
|
381
|
+
headers: await this.buildHeaders(),
|
|
382
|
+
});
|
|
383
|
+
if (res.status === 204)
|
|
384
|
+
return;
|
|
385
|
+
if (!res.ok) {
|
|
386
|
+
throw await (0, storage_errors_1.koolbaseStorageErrorFromResponse)(res, 'Failed to purge version');
|
|
387
|
+
}
|
|
388
|
+
}
|
|
236
389
|
}
|
|
237
390
|
exports.KoolbaseStorage = KoolbaseStorage;
|
|
238
391
|
/**
|
|
@@ -256,3 +409,30 @@ function mapObjectFromServer(raw) {
|
|
|
256
409
|
updatedAt: raw.updated_at,
|
|
257
410
|
};
|
|
258
411
|
}
|
|
412
|
+
/**
|
|
413
|
+
* Maps the snake_case server JSON of a version row to the camelCase
|
|
414
|
+
* {@link KoolbaseObjectVersion}. Mirrors `fromObjectJson` shape.
|
|
415
|
+
*/
|
|
416
|
+
function fromVersionJson(j) {
|
|
417
|
+
const rawMeta = j.metadata;
|
|
418
|
+
const metadata = {};
|
|
419
|
+
if (rawMeta && typeof rawMeta === 'object') {
|
|
420
|
+
for (const [k, v] of Object.entries(rawMeta)) {
|
|
421
|
+
if (typeof v === 'string')
|
|
422
|
+
metadata[k] = v;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
versionId: j.version_id ?? null,
|
|
427
|
+
path: j.path,
|
|
428
|
+
size: Number(j.size ?? 0),
|
|
429
|
+
contentType: j.content_type ?? null,
|
|
430
|
+
etag: j.etag ?? null,
|
|
431
|
+
metadata,
|
|
432
|
+
r2Bucket: j.r2_bucket ?? '',
|
|
433
|
+
userId: j.user_id ?? null,
|
|
434
|
+
isDeleteMarker: Boolean(j.is_delete_marker),
|
|
435
|
+
isCurrent: Boolean(j.is_current),
|
|
436
|
+
createdAt: j.created_at,
|
|
437
|
+
};
|
|
438
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -212,6 +212,48 @@ export interface KoolbaseObject {
|
|
|
212
212
|
/** ISO 8601 timestamp from the server. */
|
|
213
213
|
updatedAt: string;
|
|
214
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* One entry in an object's version timeline. Covers both the current
|
|
217
|
+
* row (when {@link isCurrent} is true) and every history row, including
|
|
218
|
+
* soft-delete markers (when {@link isDeleteMarker} is true — size 0, no
|
|
219
|
+
* fetchable bytes). Returned from {@link KoolbaseStorage.listVersions}
|
|
220
|
+
* and {@link KoolbaseStorage.getVersion}; the underlying bytes are
|
|
221
|
+
* downloadable via {@link KoolbaseStorage.getDownloadUrl} with the
|
|
222
|
+
* `versionId` argument.
|
|
223
|
+
*
|
|
224
|
+
* `versionId` may be null only on legacy rows uploaded before versioning
|
|
225
|
+
* was enabled on the bucket — for those, {@link isCurrent} is true and
|
|
226
|
+
* the row carries no history identity yet (gets backfilled on the next
|
|
227
|
+
* overwrite).
|
|
228
|
+
*/
|
|
229
|
+
export interface KoolbaseObjectVersion {
|
|
230
|
+
versionId: string | null;
|
|
231
|
+
path: string;
|
|
232
|
+
size: number;
|
|
233
|
+
contentType: string | null;
|
|
234
|
+
etag: string | null;
|
|
235
|
+
metadata: Record<string, string>;
|
|
236
|
+
r2Bucket: string;
|
|
237
|
+
userId: string | null;
|
|
238
|
+
/**
|
|
239
|
+
* True for a tombstone row recording a soft-delete event. Size is 0
|
|
240
|
+
* and there are no R2 bytes — treat as "the path was deleted at this
|
|
241
|
+
* time" rather than fetchable content.
|
|
242
|
+
*/
|
|
243
|
+
isDeleteMarker: boolean;
|
|
244
|
+
/**
|
|
245
|
+
* True for the row that currently lives in `storage_objects` (i.e.
|
|
246
|
+
* what a no-versionId download returns). False for everything in
|
|
247
|
+
* `storage_object_versions`.
|
|
248
|
+
*/
|
|
249
|
+
isCurrent: boolean;
|
|
250
|
+
/**
|
|
251
|
+
* For the current row this is the time the current version became
|
|
252
|
+
* current (overwrite or upload time). For history rows it's the time
|
|
253
|
+
* the version was originally uploaded.
|
|
254
|
+
*/
|
|
255
|
+
createdAt: string;
|
|
256
|
+
}
|
|
215
257
|
/**
|
|
216
258
|
* Result of a successful `KoolbaseStorage.upload()` call.
|
|
217
259
|
*/
|
|
@@ -345,3 +387,37 @@ export interface BatchResult {
|
|
|
345
387
|
/** True for a successful delete. */
|
|
346
388
|
deleted?: boolean;
|
|
347
389
|
}
|
|
390
|
+
export type KoolbaseImageFormat = 'auto' | 'webp' | 'avif' | 'jpeg' | 'png';
|
|
391
|
+
export type KoolbaseImageFit = 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
|
|
392
|
+
export type KoolbaseImageGravity = 'auto' | 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
393
|
+
/**
|
|
394
|
+
* Image-transformation options for `KoolbaseStorage.publicUrl` and
|
|
395
|
+
* `KoolbaseStorage.publicUrlForObject`. Each field maps to one Cloudflare
|
|
396
|
+
* Image Transformations parameter; unset fields are omitted.
|
|
397
|
+
*
|
|
398
|
+
* All numeric inputs are clamped silently to Cloudflare-supported ranges
|
|
399
|
+
* (width/height 1-2000, quality 1-100, dpr 1-3) so a stray `width: 99999`
|
|
400
|
+
* can't trigger error 9422 at the edge.
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* const url = KoolbaseStorage.publicUrl({
|
|
404
|
+
* projectId: pid, bucket: 'avatars', path: 'user.jpg',
|
|
405
|
+
* transform: { width: 400, height: 400, format: 'webp', quality: 80, fit: 'cover' },
|
|
406
|
+
* });
|
|
407
|
+
*/
|
|
408
|
+
export interface KoolbaseImageTransform {
|
|
409
|
+
/** Output width in pixels. Clamped to 1-2000. */
|
|
410
|
+
width?: number;
|
|
411
|
+
/** Output height in pixels. Clamped to 1-2000. */
|
|
412
|
+
height?: number;
|
|
413
|
+
/** Output format. `auto` negotiates based on the request's `Accept` header. */
|
|
414
|
+
format?: KoolbaseImageFormat;
|
|
415
|
+
/** Quality 1-100. Clamped. Has no effect on lossless formats (`png`). */
|
|
416
|
+
quality?: number;
|
|
417
|
+
/** Resize mode when both width and height are specified. */
|
|
418
|
+
fit?: KoolbaseImageFit;
|
|
419
|
+
/** Device pixel ratio multiplier. Clamped to 1-3. */
|
|
420
|
+
dpr?: number;
|
|
421
|
+
/** Crop anchor. Use with `fit: 'cover'` or `fit: 'crop'`. */
|
|
422
|
+
gravity?: KoolbaseImageGravity;
|
|
423
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@techfinityedge/koolbase-react-native",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.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",
|