@koolbase/core 10.0.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.
Files changed (104) hide show
  1. package/README.md +19 -0
  2. package/dist/cjs/analytics.d.ts +24 -0
  3. package/dist/cjs/analytics.js +110 -0
  4. package/dist/cjs/auth-errors.d.ts +117 -0
  5. package/dist/cjs/auth-errors.js +250 -0
  6. package/dist/cjs/auth.d.ts +213 -0
  7. package/dist/cjs/auth.js +813 -0
  8. package/dist/cjs/cache-store.d.ts +50 -0
  9. package/dist/cjs/cache-store.js +194 -0
  10. package/dist/cjs/conflict.d.ts +80 -0
  11. package/dist/cjs/conflict.js +84 -0
  12. package/dist/cjs/database-errors.d.ts +101 -0
  13. package/dist/cjs/database-errors.js +200 -0
  14. package/dist/cjs/database.d.ts +298 -0
  15. package/dist/cjs/database.js +852 -0
  16. package/dist/cjs/device-id.d.ts +1 -0
  17. package/dist/cjs/device-id.js +57 -0
  18. package/dist/cjs/device-metadata.d.ts +36 -0
  19. package/dist/cjs/device-metadata.js +94 -0
  20. package/dist/cjs/errors.d.ts +64 -0
  21. package/dist/cjs/errors.js +85 -0
  22. package/dist/cjs/flags.d.ts +15 -0
  23. package/dist/cjs/flags.js +76 -0
  24. package/dist/cjs/function-errors.d.ts +51 -0
  25. package/dist/cjs/function-errors.js +103 -0
  26. package/dist/cjs/functions.d.ts +15 -0
  27. package/dist/cjs/functions.js +83 -0
  28. package/dist/cjs/index.d.ts +22 -0
  29. package/dist/cjs/index.js +56 -0
  30. package/dist/cjs/messaging.d.ts +13 -0
  31. package/dist/cjs/messaging.js +36 -0
  32. package/dist/cjs/offline-state.d.ts +97 -0
  33. package/dist/cjs/offline-state.js +198 -0
  34. package/dist/cjs/package.json +3 -0
  35. package/dist/cjs/pending-write.d.ts +47 -0
  36. package/dist/cjs/pending-write.js +22 -0
  37. package/dist/cjs/platform.d.ts +51 -0
  38. package/dist/cjs/platform.js +41 -0
  39. package/dist/cjs/realtime.d.ts +44 -0
  40. package/dist/cjs/realtime.js +195 -0
  41. package/dist/cjs/record.d.ts +2 -0
  42. package/dist/cjs/record.js +23 -0
  43. package/dist/cjs/shared.d.ts +9 -0
  44. package/dist/cjs/shared.js +43 -0
  45. package/dist/cjs/storage-errors.d.ts +163 -0
  46. package/dist/cjs/storage-errors.js +253 -0
  47. package/dist/cjs/storage.d.ts +198 -0
  48. package/dist/cjs/storage.js +451 -0
  49. package/dist/cjs/sync-engine.d.ts +30 -0
  50. package/dist/cjs/sync-engine.js +286 -0
  51. package/dist/cjs/types.d.ts +487 -0
  52. package/dist/cjs/types.js +40 -0
  53. package/dist/esm/analytics.d.ts +24 -0
  54. package/dist/esm/analytics.js +106 -0
  55. package/dist/esm/auth-errors.d.ts +117 -0
  56. package/dist/esm/auth-errors.js +222 -0
  57. package/dist/esm/auth.d.ts +213 -0
  58. package/dist/esm/auth.js +809 -0
  59. package/dist/esm/cache-store.d.ts +50 -0
  60. package/dist/esm/cache-store.js +179 -0
  61. package/dist/esm/conflict.d.ts +80 -0
  62. package/dist/esm/conflict.js +80 -0
  63. package/dist/esm/database-errors.d.ts +101 -0
  64. package/dist/esm/database-errors.js +189 -0
  65. package/dist/esm/database.d.ts +298 -0
  66. package/dist/esm/database.js +848 -0
  67. package/dist/esm/device-id.d.ts +1 -0
  68. package/dist/esm/device-id.js +54 -0
  69. package/dist/esm/device-metadata.d.ts +36 -0
  70. package/dist/esm/device-metadata.js +90 -0
  71. package/dist/esm/errors.d.ts +64 -0
  72. package/dist/esm/errors.js +79 -0
  73. package/dist/esm/flags.d.ts +15 -0
  74. package/dist/esm/flags.js +72 -0
  75. package/dist/esm/function-errors.d.ts +51 -0
  76. package/dist/esm/function-errors.js +93 -0
  77. package/dist/esm/functions.d.ts +15 -0
  78. package/dist/esm/functions.js +79 -0
  79. package/dist/esm/index.d.ts +22 -0
  80. package/dist/esm/index.js +25 -0
  81. package/dist/esm/messaging.d.ts +13 -0
  82. package/dist/esm/messaging.js +32 -0
  83. package/dist/esm/offline-state.d.ts +97 -0
  84. package/dist/esm/offline-state.js +189 -0
  85. package/dist/esm/package.json +3 -0
  86. package/dist/esm/pending-write.d.ts +47 -0
  87. package/dist/esm/pending-write.js +19 -0
  88. package/dist/esm/platform.d.ts +51 -0
  89. package/dist/esm/platform.js +36 -0
  90. package/dist/esm/realtime.d.ts +44 -0
  91. package/dist/esm/realtime.js +191 -0
  92. package/dist/esm/record.d.ts +2 -0
  93. package/dist/esm/record.js +20 -0
  94. package/dist/esm/shared.d.ts +9 -0
  95. package/dist/esm/shared.js +39 -0
  96. package/dist/esm/storage-errors.d.ts +163 -0
  97. package/dist/esm/storage-errors.js +239 -0
  98. package/dist/esm/storage.d.ts +198 -0
  99. package/dist/esm/storage.js +447 -0
  100. package/dist/esm/sync-engine.d.ts +30 -0
  101. package/dist/esm/sync-engine.js +282 -0
  102. package/dist/esm/types.d.ts +487 -0
  103. package/dist/esm/types.js +37 -0
  104. package/package.json +45 -0
@@ -0,0 +1,487 @@
1
+ export interface KoolbaseConfig {
2
+ /**
3
+ * Host platform adapter. Defaults to React Native. A web package or a test
4
+ * harness supplies its own; app code normally leaves this unset.
5
+ */
6
+ platform?: import('./platform.js').PlatformAdapter;
7
+ publicKey: string;
8
+ baseUrl: string;
9
+ analyticsEnabled?: boolean;
10
+ appVersion?: string;
11
+ messagingEnabled?: boolean;
12
+ /**
13
+ * Optional custom storage adapter for persisting auth state. If omitted,
14
+ * the SDK uses SecureAuthStorage backed by react-native-keychain (must
15
+ * be installed). For Expo Go or custom secure backends, provide your
16
+ * own KoolbaseAuthStorage implementation.
17
+ */
18
+ authStorage?: KoolbaseAuthStorage;
19
+ /**
20
+ * Per-request timeout in milliseconds for auth endpoints. Default 10000.
21
+ * On timeout, fetch rejects with an AbortError. restoreSession() treats
22
+ * this as Offline (preserves optimistic state).
23
+ */
24
+ authTimeout?: number;
25
+ /**
26
+ * Injectable fetch implementation. Defaults to the global fetch. Useful
27
+ * for testing (mock fetch), corporate proxies, or instrumented HTTP.
28
+ */
29
+ fetch?: FetchLike;
30
+ }
31
+ export interface KoolbaseUser {
32
+ id: string;
33
+ email: string;
34
+ phoneNumber?: string;
35
+ phoneVerified?: boolean;
36
+ fullName?: string;
37
+ avatarUrl?: string;
38
+ verified: boolean;
39
+ createdAt: string;
40
+ }
41
+ export interface KoolbaseSession {
42
+ accessToken: string;
43
+ refreshToken: string;
44
+ /** ISO 8601 timestamp when accessToken expires; from server response. */
45
+ expiresAt: string;
46
+ user: KoolbaseUser;
47
+ }
48
+ /**
49
+ * Abstract storage interface for persisting authentication state.
50
+ *
51
+ * The SDK ships with SecureAuthStorage (react-native-keychain) as the
52
+ * default. Apps with custom requirements — Expo Go (where keychain is
53
+ * unavailable), compliant encryption layers, or in-memory test mocks —
54
+ * can implement this interface and inject it via KoolbaseConfig.authStorage.
55
+ */
56
+ export interface KoolbaseAuthStorage {
57
+ saveSession(session: KoolbaseSession): Promise<void>;
58
+ readSession(): Promise<KoolbaseSession | null>;
59
+ clear(): Promise<void>;
60
+ }
61
+ /**
62
+ * Result of KoolbaseAuth.restoreSession(). Apps should branch on this:
63
+ * - NoSession → show login screen
64
+ * - Restored → show authenticated UI
65
+ * - Expired → show login screen with "session expired" message
66
+ * - Offline → show authenticated UI optimistically; API calls will
67
+ * fail until network is reachable
68
+ */
69
+ export declare enum RestoreResult {
70
+ NoSession = "no_session",
71
+ Restored = "restored",
72
+ Expired = "expired",
73
+ Offline = "offline"
74
+ }
75
+ /**
76
+ * Callback invoked when authentication state changes. Receives the
77
+ * current user, or null when signed out. Listeners fire on login,
78
+ * register, refresh, session restoration, logout, setSession, and
79
+ * linkPhone. Errors thrown from a listener are swallowed so one
80
+ * broken listener cannot break propagation to others.
81
+ */
82
+ export type AuthStateListener = (user: KoolbaseUser | null) => void;
83
+ /**
84
+ * Drop-in replacement for the global `fetch` function. Inject via
85
+ * KoolbaseConfig.fetch for testing (mock fetch), proxying, or
86
+ * monitoring. Matches the standard fetch signature.
87
+ */
88
+ export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
89
+ export interface RegisterParams {
90
+ email: string;
91
+ password: string;
92
+ fullName?: string;
93
+ }
94
+ export interface LoginParams {
95
+ email: string;
96
+ password: string;
97
+ }
98
+ export interface SendOtpParams {
99
+ phoneNumber: string;
100
+ }
101
+ export interface VerifyOtpParams {
102
+ phoneNumber: string;
103
+ code: string;
104
+ }
105
+ export interface LinkPhoneParams {
106
+ phoneNumber: string;
107
+ code: string;
108
+ }
109
+ export interface OtpSendResult {
110
+ expiresAt: string;
111
+ }
112
+ export interface PhoneVerifyResult {
113
+ session: KoolbaseSession;
114
+ isNewUser: boolean;
115
+ }
116
+ export interface KoolbaseRecord {
117
+ id: string;
118
+ collection?: string;
119
+ createdBy?: string;
120
+ data: Record<string, unknown>;
121
+ createdAt: string;
122
+ updatedAt: string;
123
+ /**
124
+ * Advanced by the server on every write.
125
+ *
126
+ * Pass it back on an update or delete to apply the change only if nothing
127
+ * else has touched the record since — the difference between overwriting
128
+ * someone else's change and being told about it.
129
+ *
130
+ * Undefined for records from a server that predates revisions, and for
131
+ * records cached by an earlier version of this SDK.
132
+ */
133
+ revision?: number;
134
+ }
135
+ export interface QueryOptions {
136
+ filters?: Record<string, unknown>;
137
+ limit?: number;
138
+ offset?: number;
139
+ orderBy?: string;
140
+ orderDesc?: boolean;
141
+ populate?: string[];
142
+ }
143
+ export interface QueryResult {
144
+ records: KoolbaseRecord[];
145
+ total: number;
146
+ isFromCache?: boolean;
147
+ }
148
+ export interface UpsertResult {
149
+ record: KoolbaseRecord;
150
+ created: boolean;
151
+ }
152
+ /**
153
+ * The 9.1.x queue entry shape. Superseded: the observable queue API returns
154
+ * the PendingWrite from './pending-write.js'; this shape survives only for
155
+ * migrateLegacyQueue, which drains the old storage key on first sync.
156
+ * No longer part of the public surface as of 9.2.0.
157
+ */
158
+ export interface LegacyPendingWrite {
159
+ id: string;
160
+ type: 'insert' | 'update' | 'delete';
161
+ collection?: string;
162
+ recordId?: string;
163
+ data?: Record<string, unknown>;
164
+ retries: number;
165
+ createdAt: string;
166
+ }
167
+ /**
168
+ * A stored vector retrieved by `KoolbaseDatabase.getVector()`. The `vector`
169
+ * field carries the float values exactly as stored on the server; the
170
+ * `recordId` + `fieldName` pair identifies which slot they came from.
171
+ */
172
+ export interface KoolbaseVector {
173
+ recordId: string;
174
+ fieldName: string;
175
+ vector: number[];
176
+ /** ISO 8601 timestamp from the server. */
177
+ createdAt: string;
178
+ /** ISO 8601 timestamp from the server. */
179
+ updatedAt: string;
180
+ }
181
+ /**
182
+ * Retrieval strategy for `KoolbaseDatabase.searchSemantic()`.
183
+ *
184
+ * - `'semantic'` (default) — pure vector search via HNSW on cosine
185
+ * distance. Best for fuzzy / conceptual queries where exact term
186
+ * match isn't required.
187
+ * - `'lexical'` — pure BM25 over the field's source text (Postgres
188
+ * `ts_rank_cd`). Best for exact terms, codes, names, acronyms.
189
+ * - `'hybrid'` — vector + lexical fused with reciprocal rank fusion
190
+ * (k=60). Generally the strongest default for production search.
191
+ */
192
+ export type SearchMode = 'semantic' | 'lexical' | 'hybrid';
193
+ /**
194
+ * One ranked hit from `KoolbaseDatabase.searchSemantic()`. `record` is
195
+ * the full record (same wire shape as a record returned by query/get).
196
+ * `distance` is the cosine distance between the query vector and the
197
+ * stored vector — lower means more similar. Range: 0 (identical
198
+ * direction) to 2 (opposite direction).
199
+ */
200
+ export interface KoolbaseSemanticHit {
201
+ record: KoolbaseRecord;
202
+ distance: number;
203
+ }
204
+ /**
205
+ * Result of `KoolbaseDatabase.searchSemantic()`. `hits` is the ranked
206
+ * list of nearest neighbors (best match first); `total` is the count of
207
+ * hits returned (matches `hits.length` in v1 — preserved as a separate
208
+ * field for future pagination).
209
+ */
210
+ export interface SemanticSearchResult {
211
+ hits: KoolbaseSemanticHit[];
212
+ total: number;
213
+ }
214
+ export interface UploadOptions {
215
+ bucket: string;
216
+ path: string;
217
+ file: {
218
+ uri: string;
219
+ name: string;
220
+ type: string;
221
+ };
222
+ /**
223
+ * If `false` (default in v5+), an upload to a path where an object
224
+ * already exists is rejected with `KoolbaseStorageConflictError`. Pass
225
+ * `true` to silently replace the existing object.
226
+ */
227
+ overwrite?: boolean;
228
+ /**
229
+ * User-defined key/value metadata to attach to the object at confirm
230
+ * time. Optional — when omitted, the object stores empty metadata `{}`.
231
+ *
232
+ * Subject to server-side validation (≤50 keys, ≤8KB total, keys 1–64
233
+ * chars matching `[a-z0-9_]+`, values ≤1024 chars, leading underscore
234
+ * reserved); violations throw `KoolbaseStorageMetadataInvalidError`.
235
+ *
236
+ * On the `overwrite: true` path, metadata REPLACES any prior metadata
237
+ * at this path (matches GCS semantics — a new upload at a path
238
+ * produces a new object, not a patch of the old). Use `updateMetadata`
239
+ * for post-upload merge changes.
240
+ */
241
+ metadata?: Record<string, string>;
242
+ onProgress?: (percent: number) => void;
243
+ }
244
+ /**
245
+ * A stored object's server-side metadata. Field names are camelCase here
246
+ * even though the wire format is snake_case — the SDK maps for you.
247
+ */
248
+ export interface KoolbaseObject {
249
+ id: string;
250
+ projectId: string;
251
+ bucketId: string;
252
+ /**
253
+ * Name of the physical R2 bucket holding this object's bytes
254
+ * (Gap #2). `'koolbase-storage-public'` means the object has a
255
+ * stable CDN URL — construct it with
256
+ * `KoolbaseStorage.publicUrlForObject(obj, bucket)`. Anything else
257
+ * (typically `'koolbase-storage'`) means the object is in private
258
+ * storage and reads go through {@link KoolbaseStorage.getDownloadUrl},
259
+ * which returns a 1-hour presigned URL.
260
+ */
261
+ r2Bucket: string;
262
+ userId: string | null;
263
+ path: string;
264
+ size: number;
265
+ contentType: string | null;
266
+ /**
267
+ * User-defined key/value metadata attached to this object. Always
268
+ * non-null — empty object when no metadata has been set (the server
269
+ * returns `{}` rather than `null` so callers can treat it as a
270
+ * guaranteed object without null checks). Set on upload via
271
+ * `upload({ metadata })` or mutated post-upload via `updateMetadata`.
272
+ */
273
+ metadata: Record<string, string>;
274
+ /** ISO 8601 timestamp from the server. */
275
+ createdAt: string;
276
+ /** ISO 8601 timestamp from the server. */
277
+ updatedAt: string;
278
+ }
279
+ /**
280
+ * One entry in an object's version timeline. Covers both the current
281
+ * row (when {@link isCurrent} is true) and every history row, including
282
+ * soft-delete markers (when {@link isDeleteMarker} is true — size 0, no
283
+ * fetchable bytes). Returned from {@link KoolbaseStorage.listVersions}
284
+ * and {@link KoolbaseStorage.getVersion}; the underlying bytes are
285
+ * downloadable via {@link KoolbaseStorage.getDownloadUrl} with the
286
+ * `versionId` argument.
287
+ *
288
+ * `versionId` may be null only on legacy rows uploaded before versioning
289
+ * was enabled on the bucket — for those, {@link isCurrent} is true and
290
+ * the row carries no history identity yet (gets backfilled on the next
291
+ * overwrite).
292
+ */
293
+ export interface KoolbaseObjectVersion {
294
+ versionId: string | null;
295
+ path: string;
296
+ size: number;
297
+ contentType: string | null;
298
+ etag: string | null;
299
+ metadata: Record<string, string>;
300
+ r2Bucket: string;
301
+ userId: string | null;
302
+ /**
303
+ * True for a tombstone row recording a soft-delete event. Size is 0
304
+ * and there are no R2 bytes — treat as "the path was deleted at this
305
+ * time" rather than fetchable content.
306
+ */
307
+ isDeleteMarker: boolean;
308
+ /**
309
+ * True for the row that currently lives in `storage_objects` (i.e.
310
+ * what a no-versionId download returns). False for everything in
311
+ * `storage_object_versions`.
312
+ */
313
+ isCurrent: boolean;
314
+ /**
315
+ * For the current row this is the time the current version became
316
+ * current (overwrite or upload time). For history rows it's the time
317
+ * the version was originally uploaded.
318
+ */
319
+ createdAt: string;
320
+ }
321
+ /**
322
+ * Result of a successful `KoolbaseStorage.upload()` call.
323
+ */
324
+ export interface UploadResult {
325
+ object: KoolbaseObject;
326
+ downloadUrl: string;
327
+ }
328
+ export interface RealtimeEvent {
329
+ type: 'created' | 'updated' | 'deleted';
330
+ collection: string;
331
+ record?: KoolbaseRecord;
332
+ recordId?: string;
333
+ }
334
+ export type RealtimeCallback = (event: RealtimeEvent) => void;
335
+ export interface BootstrapPayload {
336
+ payload_version: string;
337
+ flags: Record<string, {
338
+ enabled: boolean;
339
+ rollout_percentage: number;
340
+ kill_switch: boolean;
341
+ }>;
342
+ config: Record<string, unknown>;
343
+ version: {
344
+ min_version: string;
345
+ latest_version: string;
346
+ force_update: boolean;
347
+ update_message: string;
348
+ };
349
+ }
350
+ export type VersionStatus = 'up_to_date' | 'soft_update' | 'force_update';
351
+ export interface VersionCheckResult {
352
+ status: VersionStatus;
353
+ message: string;
354
+ latestVersion: string;
355
+ }
356
+ export declare enum FunctionRuntime {
357
+ Deno = "deno",
358
+ Dart = "dart"
359
+ }
360
+ export interface DeployOptions {
361
+ name: string;
362
+ code: string;
363
+ runtime?: FunctionRuntime;
364
+ timeoutMs?: number;
365
+ }
366
+ export interface DeployResult {
367
+ id: string;
368
+ name: string;
369
+ runtime: string;
370
+ version: number;
371
+ isActive: boolean;
372
+ timeoutMs: number;
373
+ lastDeployedAt: string | null;
374
+ }
375
+ export interface FunctionInvokeResult {
376
+ statusCode: number;
377
+ data: Record<string, unknown> | null;
378
+ success: boolean;
379
+ }
380
+ /**
381
+ * Apple's optional full-name structure returned only on a user's FIRST
382
+ * Sign in with Apple. Both fields nullable; subsequent sign-ins omit
383
+ * this entirely.
384
+ *
385
+ * Pass to `KoolbaseAuth.signInWithApple` only on first sign-in. The
386
+ * server persists at link time and ignores on subsequent sign-ins
387
+ * (matches Apple's documented contract).
388
+ */
389
+ export interface AppleFullName {
390
+ givenName?: string;
391
+ familyName?: string;
392
+ }
393
+ /**
394
+ * Parameters for `KoolbaseAuth.signInWithApple`. The SDK is
395
+ * library-agnostic — `identityToken` should come from any native
396
+ * Apple Sign-In package (e.g. `@invertase/react-native-apple-authentication`).
397
+ */
398
+ export interface SignInWithAppleParams {
399
+ identityToken: string;
400
+ nonce?: string;
401
+ fullName?: AppleFullName;
402
+ }
403
+ /**
404
+ * Parameters for `KoolbaseAuth.signInWithGoogle`. The SDK is
405
+ * library-agnostic — `idToken` should come from any native Google
406
+ * Sign-In package (e.g. `@react-native-google-signin/google-signin`).
407
+ *
408
+ * Unlike Apple, Google embeds the user's name and email in the idToken
409
+ * itself, so no separate `fullName` parameter is needed.
410
+ */
411
+ export interface SignInWithGoogleParams {
412
+ idToken: string;
413
+ nonce?: string;
414
+ }
415
+ export type BatchOp = {
416
+ type: 'insert';
417
+ collection: string;
418
+ data: Record<string, unknown>;
419
+ } | {
420
+ type: 'update';
421
+ recordId: string;
422
+ data: Record<string, unknown>;
423
+ } | {
424
+ type: 'delete';
425
+ recordId: string;
426
+ } | {
427
+ type: 'upsert';
428
+ collection: string;
429
+ match: Record<string, unknown>;
430
+ data: Record<string, unknown>;
431
+ };
432
+ /**
433
+ * Factory helpers for constructing batch operations. Same shape as
434
+ * Flutter's `KoolbaseBatchOp.insert(...)` etc., so the mental model
435
+ * transfers between platforms.
436
+ */
437
+ export declare const BatchOp: {
438
+ insert: (collection: string, data: Record<string, unknown>) => BatchOp;
439
+ update: (recordId: string, data: Record<string, unknown>) => BatchOp;
440
+ delete: (recordId: string) => BatchOp;
441
+ upsert: (collection: string, opts: {
442
+ match: Record<string, unknown>;
443
+ data: Record<string, unknown>;
444
+ }) => BatchOp;
445
+ };
446
+ export interface BatchResult {
447
+ type: string;
448
+ record?: KoolbaseRecord;
449
+ /** For upsert: true if a new record was inserted, false if one was updated. */
450
+ created?: boolean;
451
+ /** True for a successful delete. */
452
+ deleted?: boolean;
453
+ }
454
+ export type KoolbaseImageFormat = 'auto' | 'webp' | 'avif' | 'jpeg' | 'png';
455
+ export type KoolbaseImageFit = 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
456
+ export type KoolbaseImageGravity = 'auto' | 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
457
+ /**
458
+ * Image-transformation options for `KoolbaseStorage.publicUrl` and
459
+ * `KoolbaseStorage.publicUrlForObject`. Each field maps to one Cloudflare
460
+ * Image Transformations parameter; unset fields are omitted.
461
+ *
462
+ * All numeric inputs are clamped silently to Cloudflare-supported ranges
463
+ * (width/height 1-2000, quality 1-100, dpr 1-3) so a stray `width: 99999`
464
+ * can't trigger error 9422 at the edge.
465
+ *
466
+ * @example
467
+ * const url = KoolbaseStorage.publicUrl({
468
+ * projectId: pid, bucket: 'avatars', path: 'user.jpg',
469
+ * transform: { width: 400, height: 400, format: 'webp', quality: 80, fit: 'cover' },
470
+ * });
471
+ */
472
+ export interface KoolbaseImageTransform {
473
+ /** Output width in pixels. Clamped to 1-2000. */
474
+ width?: number;
475
+ /** Output height in pixels. Clamped to 1-2000. */
476
+ height?: number;
477
+ /** Output format. `auto` negotiates based on the request's `Accept` header. */
478
+ format?: KoolbaseImageFormat;
479
+ /** Quality 1-100. Clamped. Has no effect on lossless formats (`png`). */
480
+ quality?: number;
481
+ /** Resize mode when both width and height are specified. */
482
+ fit?: KoolbaseImageFit;
483
+ /** Device pixel ratio multiplier. Clamped to 1-3. */
484
+ dpr?: number;
485
+ /** Crop anchor. Use with `fit: 'cover'` or `fit: 'crop'`. */
486
+ gravity?: KoolbaseImageGravity;
487
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BatchOp = exports.FunctionRuntime = exports.RestoreResult = void 0;
4
+ /**
5
+ * Result of KoolbaseAuth.restoreSession(). Apps should branch on this:
6
+ * - NoSession → show login screen
7
+ * - Restored → show authenticated UI
8
+ * - Expired → show login screen with "session expired" message
9
+ * - Offline → show authenticated UI optimistically; API calls will
10
+ * fail until network is reachable
11
+ */
12
+ var RestoreResult;
13
+ (function (RestoreResult) {
14
+ RestoreResult["NoSession"] = "no_session";
15
+ RestoreResult["Restored"] = "restored";
16
+ RestoreResult["Expired"] = "expired";
17
+ RestoreResult["Offline"] = "offline";
18
+ })(RestoreResult || (exports.RestoreResult = RestoreResult = {}));
19
+ // ─── Functions ─────────────────────────────────────────────────────────────
20
+ var FunctionRuntime;
21
+ (function (FunctionRuntime) {
22
+ FunctionRuntime["Deno"] = "deno";
23
+ FunctionRuntime["Dart"] = "dart";
24
+ })(FunctionRuntime || (exports.FunctionRuntime = FunctionRuntime = {}));
25
+ /**
26
+ * Factory helpers for constructing batch operations. Same shape as
27
+ * Flutter's `KoolbaseBatchOp.insert(...)` etc., so the mental model
28
+ * transfers between platforms.
29
+ */
30
+ exports.BatchOp = {
31
+ insert: (collection, data) => ({ type: 'insert', collection, data }),
32
+ update: (recordId, data) => ({ type: 'update', recordId, data }),
33
+ delete: (recordId) => ({ type: 'delete', recordId }),
34
+ upsert: (collection, opts) => ({
35
+ type: 'upsert',
36
+ collection,
37
+ match: opts.match,
38
+ data: opts.data,
39
+ }),
40
+ };
@@ -0,0 +1,24 @@
1
+ import { KoolbaseConfig } from './types.js';
2
+ export declare class KoolbaseAnalytics {
3
+ private config;
4
+ private queue;
5
+ private deviceId;
6
+ private userId?;
7
+ private environmentId?;
8
+ private userProperties;
9
+ private sessionId;
10
+ private appVersion;
11
+ private flushTimer?;
12
+ private initialized;
13
+ constructor(config: KoolbaseConfig);
14
+ init(appVersion?: string): Promise<void>;
15
+ track(eventName: string, properties?: Record<string, unknown>): void;
16
+ screenView(screenName: string, properties?: Record<string, unknown>): void;
17
+ identify(userId: string): void;
18
+ setUserProperty(key: string, value: unknown): void;
19
+ setUserProperties(properties: Record<string, unknown>): void;
20
+ setEnvironment(environmentId: string): void;
21
+ reset(): void;
22
+ flush(): Promise<void>;
23
+ dispose(): Promise<void>;
24
+ }
@@ -0,0 +1,106 @@
1
+ import { getPlatform } from './platform.js';
2
+ import { getOrCreateDeviceId } from './device-id.js';
3
+ // ─── KoolbaseAnalytics ───────────────────────────────────────────────────────
4
+ const SDK_VERSION = '1.3.0';
5
+ const DEVICE_ID_KEY = 'koolbase:device_id';
6
+ const FLUSH_INTERVAL_MS = 30000;
7
+ const MAX_BATCH_SIZE = 20;
8
+ export class KoolbaseAnalytics {
9
+ constructor(config) {
10
+ this.queue = [];
11
+ this.deviceId = '';
12
+ this.userProperties = {};
13
+ this.sessionId = '';
14
+ this.appVersion = '1.0.0';
15
+ this.initialized = false;
16
+ this.config = config;
17
+ }
18
+ // ─── Init ─────────────────────────────────────────────────────────────────
19
+ async init(appVersion) {
20
+ if (this.initialized)
21
+ return;
22
+ this.deviceId = await getOrCreateDeviceId();
23
+ this.sessionId = `${this.deviceId}-${Date.now()}`;
24
+ this.appVersion = appVersion ?? '1.0.0';
25
+ // Auto flush on app background
26
+ getPlatform().lifecycle.onBackground(() => { this.flush(); });
27
+ // Periodic flush
28
+ this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
29
+ // Auto track app_open
30
+ this.track('app_open');
31
+ this.initialized = true;
32
+ }
33
+ // ─── Public API ───────────────────────────────────────────────────────────
34
+ track(eventName, properties) {
35
+ const event = {
36
+ device_id: this.deviceId,
37
+ user_id: this.userId,
38
+ environment_id: this.environmentId,
39
+ event_name: eventName,
40
+ properties: properties ?? {},
41
+ user_properties: { ...this.userProperties },
42
+ platform: getPlatform().info.os,
43
+ app_version: this.appVersion,
44
+ sdk_version: SDK_VERSION,
45
+ session_id: this.sessionId,
46
+ occurred_at: new Date().toISOString(),
47
+ };
48
+ this.queue.push(event);
49
+ if (this.queue.length >= MAX_BATCH_SIZE) {
50
+ this.flush();
51
+ }
52
+ }
53
+ screenView(screenName, properties) {
54
+ this.track('screen_view', {
55
+ screen_name: screenName,
56
+ ...properties,
57
+ });
58
+ }
59
+ identify(userId) {
60
+ this.userId = userId;
61
+ }
62
+ setUserProperty(key, value) {
63
+ this.userProperties[key] = value;
64
+ }
65
+ setUserProperties(properties) {
66
+ Object.assign(this.userProperties, properties);
67
+ }
68
+ setEnvironment(environmentId) {
69
+ this.environmentId = environmentId;
70
+ }
71
+ reset() {
72
+ this.userId = undefined;
73
+ this.userProperties = {};
74
+ }
75
+ // ─── Flush ────────────────────────────────────────────────────────────────
76
+ async flush() {
77
+ if (this.queue.length === 0)
78
+ return;
79
+ const batch = [...this.queue];
80
+ this.queue = [];
81
+ try {
82
+ const response = await fetch(`${this.config.baseUrl}/v1/analytics/events`, {
83
+ method: 'POST',
84
+ headers: {
85
+ 'Content-Type': 'application/json',
86
+ 'x-api-key': this.config.publicKey,
87
+ },
88
+ body: JSON.stringify({ events: batch }),
89
+ });
90
+ if (!response.ok) {
91
+ // Re-queue on failure
92
+ this.queue.unshift(...batch.slice(0, MAX_BATCH_SIZE - this.queue.length));
93
+ }
94
+ }
95
+ catch {
96
+ // Re-queue on network error
97
+ this.queue.unshift(...batch.slice(0, MAX_BATCH_SIZE - this.queue.length));
98
+ }
99
+ }
100
+ async dispose() {
101
+ if (this.flushTimer)
102
+ clearInterval(this.flushTimer);
103
+ this.track('session_end');
104
+ await this.flush();
105
+ }
106
+ }