@koolbase/core 12.1.0 → 12.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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Network failures, made actionable.
3
+ *
4
+ * A browser rejects a request it may not make cross-origin with the same bare
5
+ * TypeError ("Failed to fetch") as a dead network, and deliberately hides which
6
+ * it was. The SDK cannot tell them apart either, so it names the likely causes,
7
+ * starting with the one only the app's developer can fix: Trusted Origins.
8
+ *
9
+ * It stays a TypeError, so code that tells a network failure from a server
10
+ * rejection that way (the offline queue) behaves exactly as before.
11
+ */
12
+ export declare class KoolbaseNetworkError extends TypeError {
13
+ code: string;
14
+ readonly url: string;
15
+ readonly origin?: string;
16
+ constructor(url: string, cause: unknown);
17
+ }
18
+ /** fetch, with network failures turned into a KoolbaseNetworkError. */
19
+ export declare function koolbaseFetch(input: string, init?: RequestInit): Promise<Response>;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Network failures, made actionable.
3
+ *
4
+ * A browser rejects a request it may not make cross-origin with the same bare
5
+ * TypeError ("Failed to fetch") as a dead network, and deliberately hides which
6
+ * it was. The SDK cannot tell them apart either, so it names the likely causes,
7
+ * starting with the one only the app's developer can fix: Trusted Origins.
8
+ *
9
+ * It stays a TypeError, so code that tells a network failure from a server
10
+ * rejection that way (the offline queue) behaves exactly as before.
11
+ */
12
+ export class KoolbaseNetworkError extends TypeError {
13
+ constructor(url, cause) {
14
+ const loc = globalThis.location;
15
+ const origin = loc?.origin && loc.origin !== 'null' ? loc.origin : undefined;
16
+ const reason = cause instanceof Error ? cause.message : String(cause);
17
+ let host = url;
18
+ try {
19
+ host = new URL(url).origin;
20
+ }
21
+ catch {
22
+ // keep the raw url
23
+ }
24
+ let message = `Could not reach Koolbase at ${host} (${reason}).`;
25
+ message += origin
26
+ ? ` If you are online, check that this site's address (${origin}) is in the project's Trusted Origins in the Koolbase dashboard.`
27
+ : ' Check the network connection and the configured base URL.';
28
+ super(message);
29
+ this.code = 'network_error';
30
+ this.name = 'KoolbaseNetworkError';
31
+ this.url = url;
32
+ this.origin = origin;
33
+ Object.setPrototypeOf(this, new.target.prototype);
34
+ }
35
+ }
36
+ /** fetch, with network failures turned into a KoolbaseNetworkError. */
37
+ export async function koolbaseFetch(input, init) {
38
+ try {
39
+ return await fetch(input, init);
40
+ }
41
+ catch (e) {
42
+ // A request the caller cancelled keeps its meaning.
43
+ if (e?.name === 'AbortError')
44
+ throw e;
45
+ throw new KoolbaseNetworkError(input, e);
46
+ }
47
+ }
@@ -1,3 +1,4 @@
1
+ import { koolbaseFetch } from './network.js';
1
2
  import { KoolbaseUnauthenticatedError } from './errors.js';
2
3
  import { KoolbaseStorageError, koolbaseStorageErrorFromResponse, } from './storage-errors.js';
3
4
  // --- Cloudflare image-transform URL helpers -------------------------------
@@ -94,7 +95,7 @@ export class KoolbaseStorage {
94
95
  ? options.file.type || 'application/octet-stream'
95
96
  : options.file.type;
96
97
  // ─── Step 1: Get presigned upload URL ───
97
- const urlRes = await fetch(`${this.config.baseUrl}/v1/sdk/storage/upload-url`, {
98
+ const urlRes = await koolbaseFetch(`${this.config.baseUrl}/v1/sdk/storage/upload-url`, {
98
99
  method: 'POST',
99
100
  headers: {
100
101
  ...(await this.buildHeaders()),
@@ -120,9 +121,9 @@ export class KoolbaseStorage {
120
121
  // the two hosts differ here and nowhere else in this method.
121
122
  const fileBlob = isBlob
122
123
  ? options.file
123
- : await (await fetch(options.file.uri)).blob();
124
+ : await (await koolbaseFetch(options.file.uri)).blob();
124
125
  const fileSize = fileBlob.size;
125
- const uploadRes = await fetch(upload_url, {
126
+ const uploadRes = await koolbaseFetch(upload_url, {
126
127
  method: 'PUT',
127
128
  headers: { 'Content-Type': contentType },
128
129
  body: fileBlob,
@@ -149,7 +150,7 @@ export class KoolbaseStorage {
149
150
  if (options.metadata !== undefined) {
150
151
  confirmBody.metadata = options.metadata;
151
152
  }
152
- const confirmRes = await fetch(`${this.config.baseUrl}/v1/sdk/storage/confirm`, {
153
+ const confirmRes = await koolbaseFetch(`${this.config.baseUrl}/v1/sdk/storage/confirm`, {
153
154
  method: 'POST',
154
155
  headers: {
155
156
  ...(await this.buildHeaders()),
@@ -200,7 +201,7 @@ export class KoolbaseStorage {
200
201
  * // -> { category: 'landscape', tag: 'sunset' }
201
202
  */
202
203
  async updateMetadata(bucket, path, metadata) {
203
- const res = await fetch(`${this.config.baseUrl}/v1/sdk/storage/objects/metadata`, {
204
+ const res = await koolbaseFetch(`${this.config.baseUrl}/v1/sdk/storage/objects/metadata`, {
204
205
  method: 'PATCH',
205
206
  headers: {
206
207
  ...(await this.buildHeaders()),
@@ -223,7 +224,7 @@ export class KoolbaseStorage {
223
224
  if (versionId) {
224
225
  url += `&version_id=${encodeURIComponent(versionId)}`;
225
226
  }
226
- const res = await fetch(url, { headers: await this.buildHeaders() });
227
+ const res = await koolbaseFetch(url, { headers: await this.buildHeaders() });
227
228
  if (!res.ok) {
228
229
  throw await this.error(res, 'Failed to get download URL');
229
230
  }
@@ -318,7 +319,7 @@ export class KoolbaseStorage {
318
319
  const url = forcePurge
319
320
  ? `${this.config.baseUrl}/v1/sdk/storage/object?force_purge=true`
320
321
  : `${this.config.baseUrl}/v1/sdk/storage/object`;
321
- const res = await fetch(url, {
322
+ const res = await koolbaseFetch(url, {
322
323
  method: 'DELETE',
323
324
  headers: {
324
325
  ...(await this.buildHeaders()),
@@ -345,7 +346,7 @@ export class KoolbaseStorage {
345
346
  async listVersions(bucket, path) {
346
347
  const url = `${this.config.baseUrl}/v1/sdk/storage/object-versions` +
347
348
  `?bucket=${encodeURIComponent(bucket)}&path=${encodeURIComponent(path)}`;
348
- const res = await fetch(url, { headers: await this.buildHeaders() });
349
+ const res = await koolbaseFetch(url, { headers: await this.buildHeaders() });
349
350
  if (!res.ok) {
350
351
  throw await this.error(res, 'Failed to list versions');
351
352
  }
@@ -361,7 +362,7 @@ export class KoolbaseStorage {
361
362
  async getVersion(bucket, path, versionId) {
362
363
  const url = `${this.config.baseUrl}/v1/sdk/storage/object-versions/${encodeURIComponent(versionId)}` +
363
364
  `?bucket=${encodeURIComponent(bucket)}&path=${encodeURIComponent(path)}`;
364
- const res = await fetch(url, { headers: await this.buildHeaders() });
365
+ const res = await koolbaseFetch(url, { headers: await this.buildHeaders() });
365
366
  if (!res.ok) {
366
367
  throw await this.error(res, 'Failed to fetch version');
367
368
  }
@@ -380,7 +381,7 @@ export class KoolbaseStorage {
380
381
  async restoreVersion(bucket, path, versionId) {
381
382
  const url = `${this.config.baseUrl}/v1/sdk/storage/object-versions/${encodeURIComponent(versionId)}/restore` +
382
383
  `?bucket=${encodeURIComponent(bucket)}&path=${encodeURIComponent(path)}`;
383
- const res = await fetch(url, {
384
+ const res = await koolbaseFetch(url, {
384
385
  method: 'POST',
385
386
  headers: await this.buildHeaders(),
386
387
  });
@@ -398,7 +399,7 @@ export class KoolbaseStorage {
398
399
  async purgeVersion(bucket, path, versionId) {
399
400
  const url = `${this.config.baseUrl}/v1/sdk/storage/object-versions/${encodeURIComponent(versionId)}` +
400
401
  `?bucket=${encodeURIComponent(bucket)}&path=${encodeURIComponent(path)}`;
401
- const res = await fetch(url, {
402
+ const res = await koolbaseFetch(url, {
402
403
  method: 'DELETE',
403
404
  headers: await this.buildHeaders(),
404
405
  });
@@ -1,3 +1,4 @@
1
+ import { koolbaseFetch } from './network.js';
1
2
  import { readOfflineState, mutateOfflineState, migrateLegacyQueue, flushLockName, } from './offline-state.js';
2
3
  import { KoolbaseUnauthenticatedError } from './errors.js';
3
4
  import { getPlatform } from './platform.js';
@@ -242,7 +243,7 @@ export class SyncEngine {
242
243
  : `${this.config.baseUrl}/v1/sdk/db/records/${write.recordId}`;
243
244
  let res;
244
245
  if (write.operation === 'insert') {
245
- res = await fetch(url, {
246
+ res = await koolbaseFetch(url, {
246
247
  method: 'POST',
247
248
  headers,
248
249
  // The write's own id: generated at enqueue, identical on every retry.
@@ -256,7 +257,7 @@ export class SyncEngine {
256
257
  });
257
258
  }
258
259
  else if (write.operation === 'update') {
259
- res = await fetch(url, {
260
+ res = await koolbaseFetch(url, {
260
261
  method: 'PATCH',
261
262
  headers,
262
263
  // The revision the change was composed against. The server applies it
@@ -275,7 +276,7 @@ export class SyncEngine {
275
276
  const q = write.baseRevision !== undefined
276
277
  ? `?expected_revision=${write.baseRevision}`
277
278
  : '';
278
- res = await fetch(`${url}${q}`, { method: 'DELETE', headers });
279
+ res = await koolbaseFetch(`${url}${q}`, { method: 'DELETE', headers });
279
280
  }
280
281
  if (res.status === 401)
281
282
  throw new KoolbaseUnauthenticatedError('unauthorized');
@@ -239,6 +239,13 @@ export interface QueryOptions {
239
239
  orderBy?: string;
240
240
  orderDesc?: boolean;
241
241
  populate?: string[];
242
+ /**
243
+ * How to read: 'default' is cache-first, refreshed in the background;
244
+ * 'network-only' skips the cache and waits for the server (the result still
245
+ * refreshes the cache). Use 'network-only' after a write this client did not
246
+ * make, by a Function or another user, when you need the server's state now.
247
+ */
248
+ cache?: 'default' | 'network-only';
242
249
  }
243
250
  export interface QueryResult {
244
251
  records: KoolbaseRecord[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@koolbase/core",
3
- "version": "12.1.0",
4
- "description": "Koolbase SDK core \u2014 shared behaviour behind @koolbase/react-native and @koolbase/js. Install one of those, not this.",
3
+ "version": "12.3.0",
4
+ "description": "Koolbase SDK core — shared behaviour behind @koolbase/react-native and @koolbase/js. Install one of those, not this.",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "types": "./dist/esm/index.d.ts",
7
7
  "files": [