@techfinityedge/koolbase-react-native 5.2.0 → 5.3.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
@@ -73,6 +73,8 @@ const unsubscribe = Koolbase.auth.onAuthStateChange((user) => {
73
73
  });
74
74
  ```
75
75
 
76
+ ---
77
+
76
78
  ### OAuth — Apple
77
79
 
78
80
  Apple Sign-In uses the native authentication flow via `@invertase/react-native-apple-authentication` as a peer dependency:
@@ -100,6 +102,8 @@ const session = await Koolbase.auth.signInWithApple({
100
102
 
101
103
  Configure Apple Sign-In for your environment with your iOS app's Bundle ID. Full setup guide at [docs.koolbase.com/auth/oauth](https://docs.koolbase.com/auth/oauth).
102
104
 
105
+ ---
106
+
103
107
  ### OAuth — Google
104
108
 
105
109
  Google Sign-In uses the native authentication flow via `@react-native-google-signin/google-signin` as a peer dependency:
@@ -121,6 +125,8 @@ const session = await Koolbase.auth.signInWithGoogle({
121
125
 
122
126
  Configure Google Sign-In for your environment with the OAuth client IDs from Google Cloud Console (typically one each for iOS, Android, and web). Full setup guide at [docs.koolbase.com/auth/oauth](https://docs.koolbase.com/auth/oauth).
123
127
 
128
+ ---
129
+
124
130
  ### Phone + OTP
125
131
 
126
132
  ```typescript
@@ -173,6 +179,8 @@ await Koolbase.db.update('record-id', { title: 'Updated' });
173
179
  await Koolbase.db.delete('record-id');
174
180
  ```
175
181
 
182
+ ---
183
+
176
184
  ### Handling unique-constraint conflicts
177
185
 
178
186
  A write that would violate a unique constraint throws `KoolbaseConflictError`:
@@ -187,6 +195,46 @@ try {
187
195
  }
188
196
  ```
189
197
 
198
+ ---
199
+
200
+ ### Public bucket URLs
201
+
202
+ For files in public buckets, you can construct the stable CDN URL directly — no
203
+ network call, no expiry, embeddable anywhere a browser fetches a URL.
204
+
205
+ ```typescript
206
+ import { KoolbaseStorage } from '@techfinityedge/koolbase-react-native';
207
+
208
+ // From a KoolbaseObject you already have (e.g. from upload() or another read)
209
+ const { object } = await Koolbase.storage.upload({
210
+ bucket: 'avatars',
211
+ path: `user-${userId}.jpg`,
212
+ file: { uri: imageUri, name: 'avatar.jpg', type: 'image/jpeg' },
213
+ });
214
+
215
+ const url = KoolbaseStorage.publicUrlForObject(object, 'avatars');
216
+ // url is null for private-bucket objects; the CDN URL for public-bucket ones.
217
+
218
+ if (url) {
219
+ // Safe to use — file lives in the public R2 bucket
220
+ return <Image source={{ uri: url }} />;
221
+ }
222
+
223
+ // For build-time URL construction (no Object on hand)
224
+ const url = KoolbaseStorage.publicUrl({
225
+ projectId: 'proj_abc',
226
+ bucket: 'avatars',
227
+ path: 'user-123.jpg',
228
+ });
229
+ // Always returns the URL pattern; caller is responsible for knowing
230
+ // the file lives in a public bucket. For files in private buckets,
231
+ // the resulting URL will 404.
232
+ ```
233
+
234
+ URLs follow the pattern `https://cdn.koolbase.com/{project_id}/{bucket}/{path}` — long-lived, edge-cached, no authentication. For files in private buckets, use `getDownloadUrl` instead, which returns a 1-hour presigned URL.
235
+
236
+ ---
237
+
190
238
  ### Upsert
191
239
 
192
240
  Insert a record, or update the existing one matching a filter.
@@ -230,6 +278,8 @@ if (isFromCache) console.log('Served from local cache');
230
278
  await Koolbase.db.syncPendingWrites();
231
279
  ```
232
280
 
281
+ ---
282
+
233
283
  ### Atomic batch writes
234
284
 
235
285
  Run multiple writes in a single server-side transaction. All operations commit together or none are applied — any failure rolls back the entire batch.
@@ -309,6 +359,8 @@ const url = await Koolbase.storage.getDownloadUrl('avatars', `user-${userId}.jpg
309
359
  await Koolbase.storage.delete('avatars', `user-${userId}.jpg`);
310
360
  ```
311
361
 
362
+ ---
363
+
312
364
  ### Handling upload conflicts
313
365
 
314
366
  For user-supplied filenames, prompt the user before overwriting:
@@ -622,6 +674,8 @@ try {
622
674
  > the background, so their conflicts surface via the sync engine, not as a
623
675
  > thrown error.
624
676
 
677
+ ---
678
+
625
679
  ### Storage errors
626
680
 
627
681
  All storage failures extend `KoolbaseStorageError` (which extends `Error`):
package/dist/storage.d.ts CHANGED
@@ -73,6 +73,40 @@ export declare class KoolbaseStorage {
73
73
  * Get a signed download URL for a file.
74
74
  */
75
75
  getDownloadUrl(bucket: string, path: string): Promise<string>;
76
+ /**
77
+ * Build the stable public CDN URL for a file in a public bucket.
78
+ *
79
+ * Returns the URL unconditionally — no check on whether the file
80
+ * exists or whether the bucket is actually public. Use when you
81
+ * know the file is in a public bucket and want the URL without a
82
+ * network round-trip (build-time URL generation, server-side
83
+ * rendering, batch image processing, etc.).
84
+ *
85
+ * For safer construction from an Object you already have, use
86
+ * {@link KoolbaseStorage.publicUrlForObject} — it checks the stored
87
+ * `r2Bucket` value and returns `null` when the object isn't in the
88
+ * public R2 bucket.
89
+ */
90
+ static publicUrl(args: {
91
+ projectId: string;
92
+ bucket: string;
93
+ path: string;
94
+ }): string;
95
+ /**
96
+ * Returns the stable CDN URL for an object when its bytes physically
97
+ * live in the public R2 bucket, `null` otherwise.
98
+ *
99
+ * Returns `null` for:
100
+ * - Files in private buckets (no public URL ever)
101
+ * - Legacy files in public buckets whose bytes still live in the
102
+ * private R2 bucket from before Gap #2 (no permanent URL until
103
+ * they're re-uploaded)
104
+ *
105
+ * The bucket name must be supplied because {@link KoolbaseObject}
106
+ * carries only the bucket ID, not its name. Typically the caller
107
+ * already knows which bucket they queried.
108
+ */
109
+ static publicUrlForObject(obj: KoolbaseObject, bucket: string): string | null;
76
110
  /**
77
111
  * Delete a file from a bucket.
78
112
  */
package/dist/storage.js CHANGED
@@ -176,6 +176,45 @@ class KoolbaseStorage {
176
176
  const data = (await res.json());
177
177
  return data.url;
178
178
  }
179
+ /**
180
+ * Build the stable public CDN URL for a file in a public bucket.
181
+ *
182
+ * Returns the URL unconditionally — no check on whether the file
183
+ * exists or whether the bucket is actually public. Use when you
184
+ * know the file is in a public bucket and want the URL without a
185
+ * network round-trip (build-time URL generation, server-side
186
+ * rendering, batch image processing, etc.).
187
+ *
188
+ * For safer construction from an Object you already have, use
189
+ * {@link KoolbaseStorage.publicUrlForObject} — it checks the stored
190
+ * `r2Bucket` value and returns `null` when the object isn't in the
191
+ * public R2 bucket.
192
+ */
193
+ static publicUrl(args) {
194
+ // Encode each path segment individually so slashes are preserved
195
+ // while spaces, parens, hashes, and query characters are escaped.
196
+ const encoded = args.path.split('/').map(encodeURIComponent).join('/');
197
+ return `https://cdn.koolbase.com/${args.projectId}/${args.bucket}/${encoded}`;
198
+ }
199
+ /**
200
+ * Returns the stable CDN URL for an object when its bytes physically
201
+ * live in the public R2 bucket, `null` otherwise.
202
+ *
203
+ * Returns `null` for:
204
+ * - Files in private buckets (no public URL ever)
205
+ * - Legacy files in public buckets whose bytes still live in the
206
+ * private R2 bucket from before Gap #2 (no permanent URL until
207
+ * they're re-uploaded)
208
+ *
209
+ * The bucket name must be supplied because {@link KoolbaseObject}
210
+ * carries only the bucket ID, not its name. Typically the caller
211
+ * already knows which bucket they queried.
212
+ */
213
+ static publicUrlForObject(obj, bucket) {
214
+ if (obj.r2Bucket !== 'koolbase-storage-public')
215
+ return null;
216
+ return KoolbaseStorage.publicUrl({ projectId: obj.projectId, bucket, path: obj.path });
217
+ }
179
218
  /**
180
219
  * Delete a file from a bucket.
181
220
  */
@@ -212,6 +251,7 @@ function mapObjectFromServer(raw) {
212
251
  size: raw.size ?? 0,
213
252
  contentType: raw.content_type ?? null,
214
253
  metadata: raw.metadata ?? {},
254
+ r2Bucket: raw.r2_bucket ?? 'koolbase-storage',
215
255
  createdAt: raw.created_at,
216
256
  updatedAt: raw.updated_at,
217
257
  };
package/dist/types.d.ts CHANGED
@@ -185,6 +185,16 @@ export interface KoolbaseObject {
185
185
  id: string;
186
186
  projectId: string;
187
187
  bucketId: string;
188
+ /**
189
+ * Name of the physical R2 bucket holding this object's bytes
190
+ * (Gap #2). `'koolbase-storage-public'` means the object has a
191
+ * stable CDN URL — construct it with
192
+ * `KoolbaseStorage.publicUrlForObject(obj, bucket)`. Anything else
193
+ * (typically `'koolbase-storage'`) means the object is in private
194
+ * storage and reads go through {@link KoolbaseStorage.getDownloadUrl},
195
+ * which returns a 1-hour presigned URL.
196
+ */
197
+ r2Bucket: string;
188
198
  userId: string | null;
189
199
  path: string;
190
200
  size: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techfinityedge/koolbase-react-native",
3
- "version": "5.2.0",
3
+ "version": "5.3.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",
@@ -27,6 +27,8 @@
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/jszip": "^3.4.0",
30
+ "@types/node": "^25.9.1",
31
+ "react-native": "^0.85.3",
30
32
  "react-native-keychain": "^10.0.0",
31
33
  "typescript": "^5.0.0"
32
34
  },