@baasix/sdk 0.1.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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1197 -0
  3. package/dist/client-DeXa-R9w.d.ts +680 -0
  4. package/dist/client-VT7NckyI.d.cts +680 -0
  5. package/dist/index.cjs +4567 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +1788 -0
  8. package/dist/index.d.ts +1788 -0
  9. package/dist/index.js +4543 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/modules/auth.cjs +650 -0
  12. package/dist/modules/auth.cjs.map +1 -0
  13. package/dist/modules/auth.d.cts +384 -0
  14. package/dist/modules/auth.d.ts +384 -0
  15. package/dist/modules/auth.js +648 -0
  16. package/dist/modules/auth.js.map +1 -0
  17. package/dist/modules/files.cjs +269 -0
  18. package/dist/modules/files.cjs.map +1 -0
  19. package/dist/modules/files.d.cts +187 -0
  20. package/dist/modules/files.d.ts +187 -0
  21. package/dist/modules/files.js +267 -0
  22. package/dist/modules/files.js.map +1 -0
  23. package/dist/modules/items.cjs +640 -0
  24. package/dist/modules/items.cjs.map +1 -0
  25. package/dist/modules/items.d.cts +465 -0
  26. package/dist/modules/items.d.ts +465 -0
  27. package/dist/modules/items.js +637 -0
  28. package/dist/modules/items.js.map +1 -0
  29. package/dist/modules/schemas.cjs +322 -0
  30. package/dist/modules/schemas.cjs.map +1 -0
  31. package/dist/modules/schemas.d.cts +260 -0
  32. package/dist/modules/schemas.d.ts +260 -0
  33. package/dist/modules/schemas.js +320 -0
  34. package/dist/modules/schemas.js.map +1 -0
  35. package/dist/storage/index.cjs +162 -0
  36. package/dist/storage/index.cjs.map +1 -0
  37. package/dist/storage/index.d.cts +96 -0
  38. package/dist/storage/index.d.ts +96 -0
  39. package/dist/storage/index.js +157 -0
  40. package/dist/storage/index.js.map +1 -0
  41. package/dist/types-BdjsGANq.d.cts +40 -0
  42. package/dist/types-BdjsGANq.d.ts +40 -0
  43. package/package.json +108 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,4567 @@
1
+ 'use strict';
2
+
3
+ // src/storage/types.ts
4
+ var STORAGE_KEYS = {
5
+ ACCESS_TOKEN: "baasix_access_token",
6
+ REFRESH_TOKEN: "baasix_refresh_token",
7
+ TOKEN_EXPIRY: "baasix_token_expiry",
8
+ USER: "baasix_user",
9
+ TENANT: "baasix_tenant"
10
+ };
11
+
12
+ // src/types.ts
13
+ var BaasixError = class _BaasixError extends Error {
14
+ status;
15
+ code;
16
+ details;
17
+ isRetryable;
18
+ constructor(message, status = 500, code, details) {
19
+ super(message);
20
+ this.name = "BaasixError";
21
+ this.status = status;
22
+ this.code = code;
23
+ this.details = details;
24
+ this.isRetryable = status >= 500 || status === 429;
25
+ if (Error.captureStackTrace) {
26
+ Error.captureStackTrace(this, _BaasixError);
27
+ }
28
+ }
29
+ toJSON() {
30
+ return {
31
+ name: this.name,
32
+ message: this.message,
33
+ status: this.status,
34
+ code: this.code,
35
+ details: this.details
36
+ };
37
+ }
38
+ };
39
+
40
+ // src/client.ts
41
+ var HttpClient = class {
42
+ config;
43
+ refreshPromise = null;
44
+ constructor(config) {
45
+ this.config = config;
46
+ }
47
+ /**
48
+ * Update client configuration
49
+ */
50
+ updateConfig(config) {
51
+ this.config = { ...this.config, ...config };
52
+ }
53
+ /**
54
+ * Get the current base URL
55
+ */
56
+ getBaseUrl() {
57
+ return this.config.baseUrl;
58
+ }
59
+ /**
60
+ * Build the full URL with query parameters
61
+ */
62
+ buildUrl(path, params) {
63
+ const url = new URL(path, this.config.baseUrl);
64
+ if (params) {
65
+ Object.entries(params).forEach(([key, value]) => {
66
+ if (value !== void 0 && value !== null) {
67
+ if (typeof value === "object") {
68
+ url.searchParams.set(key, JSON.stringify(value));
69
+ } else {
70
+ url.searchParams.set(key, String(value));
71
+ }
72
+ }
73
+ });
74
+ }
75
+ return url.toString();
76
+ }
77
+ /**
78
+ * Get the current access token
79
+ */
80
+ async getAccessToken() {
81
+ if (this.config.token) {
82
+ return this.config.token;
83
+ }
84
+ if (this.config.authMode === "cookie") {
85
+ return null;
86
+ }
87
+ const token = await this.config.storage.get(STORAGE_KEYS.ACCESS_TOKEN);
88
+ return token;
89
+ }
90
+ /**
91
+ * Check if token is expired or about to expire (within 60 seconds)
92
+ */
93
+ async isTokenExpired() {
94
+ const expiry = await this.config.storage.get(STORAGE_KEYS.TOKEN_EXPIRY);
95
+ if (!expiry) return false;
96
+ const expiryTime = parseInt(expiry, 10);
97
+ const bufferTime = 60 * 1e3;
98
+ return Date.now() >= expiryTime - bufferTime;
99
+ }
100
+ /**
101
+ * Refresh the access token
102
+ */
103
+ async refreshToken() {
104
+ if (this.refreshPromise) {
105
+ return this.refreshPromise;
106
+ }
107
+ this.refreshPromise = (async () => {
108
+ try {
109
+ const refreshToken = await this.config.storage.get(
110
+ STORAGE_KEYS.REFRESH_TOKEN
111
+ );
112
+ if (!refreshToken && this.config.authMode === "jwt") {
113
+ throw new BaasixError("No refresh token available", 401, "NO_REFRESH_TOKEN");
114
+ }
115
+ const response = await fetch(
116
+ this.buildUrl("/auth/refresh"),
117
+ {
118
+ method: "POST",
119
+ headers: {
120
+ "Content-Type": "application/json",
121
+ ...this.config.headers
122
+ },
123
+ body: this.config.authMode === "jwt" ? JSON.stringify({ refreshToken }) : void 0,
124
+ credentials: this.config.credentials
125
+ }
126
+ );
127
+ if (!response.ok) {
128
+ throw new BaasixError("Token refresh failed", response.status, "REFRESH_FAILED");
129
+ }
130
+ const data = await response.json();
131
+ const tokens = {
132
+ accessToken: data.token,
133
+ refreshToken: data.refreshToken,
134
+ expiresIn: data.expiresIn,
135
+ expiresAt: data.expiresIn ? Date.now() + data.expiresIn * 1e3 : void 0
136
+ };
137
+ await this.config.storage.set(STORAGE_KEYS.ACCESS_TOKEN, tokens.accessToken);
138
+ if (tokens.refreshToken) {
139
+ await this.config.storage.set(STORAGE_KEYS.REFRESH_TOKEN, tokens.refreshToken);
140
+ }
141
+ if (tokens.expiresAt) {
142
+ await this.config.storage.set(
143
+ STORAGE_KEYS.TOKEN_EXPIRY,
144
+ tokens.expiresAt.toString()
145
+ );
146
+ }
147
+ this.config.onTokenRefresh?.(tokens);
148
+ return tokens;
149
+ } finally {
150
+ this.refreshPromise = null;
151
+ }
152
+ })();
153
+ return this.refreshPromise;
154
+ }
155
+ /**
156
+ * Build request headers
157
+ */
158
+ async buildHeaders(options = {}) {
159
+ const headers = {
160
+ "Content-Type": "application/json",
161
+ ...this.config.headers
162
+ };
163
+ if (this.config.tenantId) {
164
+ headers["X-Tenant-Id"] = this.config.tenantId;
165
+ }
166
+ if (options.skipAuth) {
167
+ return headers;
168
+ }
169
+ if (this.config.authMode === "jwt") {
170
+ if (this.config.autoRefresh && await this.isTokenExpired()) {
171
+ try {
172
+ await this.refreshToken();
173
+ } catch {
174
+ }
175
+ }
176
+ const token = await this.getAccessToken();
177
+ if (token) {
178
+ headers["Authorization"] = `Bearer ${token}`;
179
+ }
180
+ }
181
+ return headers;
182
+ }
183
+ /**
184
+ * Parse error response
185
+ */
186
+ async parseError(response) {
187
+ let errorData = {};
188
+ try {
189
+ errorData = await response.json();
190
+ } catch {
191
+ }
192
+ const message = errorData.error?.message || errorData.message || response.statusText || "Request failed";
193
+ const code = errorData.error?.code;
194
+ const details = errorData.details;
195
+ return new BaasixError(message, response.status, code, details);
196
+ }
197
+ /**
198
+ * Make an HTTP request
199
+ */
200
+ async request(method, path, options = {}) {
201
+ const { params, timeout, skipAuth, rawResponse, ...fetchOptions } = options;
202
+ const url = this.buildUrl(path, params);
203
+ const headers = await this.buildHeaders({ skipAuth });
204
+ const requestTimeout = timeout || this.config.timeout;
205
+ const controller = new AbortController();
206
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
207
+ try {
208
+ const response = await fetch(url, {
209
+ method,
210
+ headers: {
211
+ ...headers,
212
+ ...fetchOptions.headers
213
+ },
214
+ credentials: this.config.credentials,
215
+ signal: controller.signal,
216
+ ...fetchOptions
217
+ });
218
+ if (response.status === 401 && !skipAuth && this.config.autoRefresh) {
219
+ try {
220
+ await this.refreshToken();
221
+ const retryHeaders = await this.buildHeaders({ skipAuth: false });
222
+ const retryResponse = await fetch(url, {
223
+ method,
224
+ headers: {
225
+ ...retryHeaders,
226
+ ...fetchOptions.headers
227
+ },
228
+ credentials: this.config.credentials,
229
+ ...fetchOptions
230
+ });
231
+ if (!retryResponse.ok) {
232
+ throw await this.parseError(retryResponse);
233
+ }
234
+ if (rawResponse) {
235
+ return retryResponse;
236
+ }
237
+ if (retryResponse.status === 204) {
238
+ return {};
239
+ }
240
+ return await retryResponse.json();
241
+ } catch (refreshError) {
242
+ this.config.onAuthError?.();
243
+ throw refreshError;
244
+ }
245
+ }
246
+ if (!response.ok) {
247
+ throw await this.parseError(response);
248
+ }
249
+ if (rawResponse) {
250
+ return response;
251
+ }
252
+ if (response.status === 204) {
253
+ return {};
254
+ }
255
+ return await response.json();
256
+ } catch (error) {
257
+ if (error instanceof BaasixError) {
258
+ throw error;
259
+ }
260
+ if (error instanceof Error) {
261
+ if (error.name === "AbortError") {
262
+ throw new BaasixError("Request timeout", 408, "TIMEOUT");
263
+ }
264
+ throw new BaasixError(error.message, 0, "NETWORK_ERROR");
265
+ }
266
+ throw new BaasixError("Unknown error occurred", 500, "UNKNOWN");
267
+ } finally {
268
+ clearTimeout(timeoutId);
269
+ }
270
+ }
271
+ /**
272
+ * GET request
273
+ */
274
+ get(path, options) {
275
+ return this.request("GET", path, options);
276
+ }
277
+ /**
278
+ * POST request
279
+ */
280
+ post(path, data, options) {
281
+ return this.request("POST", path, {
282
+ ...options,
283
+ body: data ? JSON.stringify(data) : void 0
284
+ });
285
+ }
286
+ /**
287
+ * PATCH request
288
+ */
289
+ patch(path, data, options) {
290
+ return this.request("PATCH", path, {
291
+ ...options,
292
+ body: data ? JSON.stringify(data) : void 0
293
+ });
294
+ }
295
+ /**
296
+ * PUT request
297
+ */
298
+ put(path, data, options) {
299
+ return this.request("PUT", path, {
300
+ ...options,
301
+ body: data ? JSON.stringify(data) : void 0
302
+ });
303
+ }
304
+ /**
305
+ * DELETE request
306
+ */
307
+ delete(path, options) {
308
+ return this.request("DELETE", path, options);
309
+ }
310
+ /**
311
+ * Upload file with multipart/form-data
312
+ */
313
+ async upload(path, formData, options) {
314
+ const { params, timeout, skipAuth, onProgress } = options || {};
315
+ const url = this.buildUrl(path, params);
316
+ const headers = await this.buildHeaders({ skipAuth });
317
+ const requestTimeout = timeout || this.config.timeout;
318
+ delete headers["Content-Type"];
319
+ if (onProgress && typeof XMLHttpRequest !== "undefined") {
320
+ return new Promise((resolve, reject) => {
321
+ const xhr = new XMLHttpRequest();
322
+ xhr.open("POST", url);
323
+ Object.entries(headers).forEach(
324
+ ([key, value]) => {
325
+ xhr.setRequestHeader(key, value);
326
+ }
327
+ );
328
+ xhr.withCredentials = this.config.credentials === "include";
329
+ xhr.upload.onprogress = (event) => {
330
+ if (event.lengthComputable) {
331
+ const progress = Math.round(event.loaded / event.total * 100);
332
+ onProgress(progress);
333
+ }
334
+ };
335
+ xhr.onload = () => {
336
+ if (xhr.status >= 200 && xhr.status < 300) {
337
+ try {
338
+ resolve(JSON.parse(xhr.responseText));
339
+ } catch {
340
+ resolve({});
341
+ }
342
+ } else {
343
+ reject(
344
+ new BaasixError(
345
+ xhr.statusText || "Upload failed",
346
+ xhr.status,
347
+ "UPLOAD_ERROR"
348
+ )
349
+ );
350
+ }
351
+ };
352
+ xhr.onerror = () => {
353
+ reject(new BaasixError("Network error during upload", 0, "NETWORK_ERROR"));
354
+ };
355
+ xhr.ontimeout = () => {
356
+ reject(new BaasixError("Upload timeout", 408, "TIMEOUT"));
357
+ };
358
+ xhr.timeout = requestTimeout;
359
+ xhr.send(formData);
360
+ });
361
+ }
362
+ const controller = new AbortController();
363
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
364
+ try {
365
+ const response = await fetch(url, {
366
+ method: "POST",
367
+ headers,
368
+ body: formData,
369
+ credentials: this.config.credentials,
370
+ signal: controller.signal
371
+ });
372
+ if (!response.ok) {
373
+ throw await this.parseError(response);
374
+ }
375
+ return await response.json();
376
+ } finally {
377
+ clearTimeout(timeoutId);
378
+ }
379
+ }
380
+ };
381
+
382
+ // src/storage/localStorage.ts
383
+ var LocalStorageAdapter = class {
384
+ prefix;
385
+ constructor(prefix = "baasix_") {
386
+ this.prefix = prefix;
387
+ }
388
+ getKey(key) {
389
+ if (key.startsWith(this.prefix)) {
390
+ return key;
391
+ }
392
+ return `${this.prefix}${key}`;
393
+ }
394
+ get(key) {
395
+ if (typeof window === "undefined" || !window.localStorage) {
396
+ return null;
397
+ }
398
+ try {
399
+ return localStorage.getItem(this.getKey(key));
400
+ } catch {
401
+ console.warn(`[Baasix SDK] Failed to get item from localStorage: ${key}`);
402
+ return null;
403
+ }
404
+ }
405
+ set(key, value) {
406
+ if (typeof window === "undefined" || !window.localStorage) {
407
+ return;
408
+ }
409
+ try {
410
+ localStorage.setItem(this.getKey(key), value);
411
+ } catch {
412
+ console.warn(`[Baasix SDK] Failed to set item in localStorage: ${key}`);
413
+ }
414
+ }
415
+ remove(key) {
416
+ if (typeof window === "undefined" || !window.localStorage) {
417
+ return;
418
+ }
419
+ try {
420
+ localStorage.removeItem(this.getKey(key));
421
+ } catch {
422
+ console.warn(`[Baasix SDK] Failed to remove item from localStorage: ${key}`);
423
+ }
424
+ }
425
+ clear() {
426
+ if (typeof window === "undefined" || !window.localStorage) {
427
+ return;
428
+ }
429
+ try {
430
+ const keysToRemove = [];
431
+ for (let i = 0; i < localStorage.length; i++) {
432
+ const key = localStorage.key(i);
433
+ if (key?.startsWith(this.prefix)) {
434
+ keysToRemove.push(key);
435
+ }
436
+ }
437
+ keysToRemove.forEach((key) => localStorage.removeItem(key));
438
+ } catch {
439
+ console.warn("[Baasix SDK] Failed to clear localStorage");
440
+ }
441
+ }
442
+ };
443
+
444
+ // src/storage/memoryStorage.ts
445
+ var MemoryStorageAdapter = class {
446
+ store;
447
+ constructor() {
448
+ this.store = /* @__PURE__ */ new Map();
449
+ }
450
+ get(key) {
451
+ return this.store.get(key) ?? null;
452
+ }
453
+ set(key, value) {
454
+ this.store.set(key, value);
455
+ }
456
+ remove(key) {
457
+ this.store.delete(key);
458
+ }
459
+ clear() {
460
+ this.store.clear();
461
+ }
462
+ /**
463
+ * Get all stored keys (useful for debugging)
464
+ */
465
+ keys() {
466
+ return Array.from(this.store.keys());
467
+ }
468
+ /**
469
+ * Get the number of stored items
470
+ */
471
+ size() {
472
+ return this.store.size;
473
+ }
474
+ };
475
+
476
+ // src/modules/auth.ts
477
+ var AuthModule = class {
478
+ client;
479
+ storage;
480
+ authMode;
481
+ onAuthStateChange;
482
+ currentUser = null;
483
+ constructor(config) {
484
+ this.client = config.client;
485
+ this.storage = config.storage;
486
+ this.authMode = config.authMode;
487
+ this.onAuthStateChange = config.onAuthStateChange;
488
+ }
489
+ /**
490
+ * Emit an authentication state change event
491
+ */
492
+ emitAuthStateChange(event, user) {
493
+ this.currentUser = user;
494
+ this.onAuthStateChange?.(event, user);
495
+ }
496
+ /**
497
+ * Store authentication tokens
498
+ */
499
+ async storeTokens(response) {
500
+ if (this.authMode === "jwt") {
501
+ await this.storage.set(STORAGE_KEYS.ACCESS_TOKEN, response.token);
502
+ if (response.refreshToken) {
503
+ await this.storage.set(STORAGE_KEYS.REFRESH_TOKEN, response.refreshToken);
504
+ }
505
+ if (response.expiresIn) {
506
+ const expiresAt = Date.now() + response.expiresIn * 1e3;
507
+ await this.storage.set(STORAGE_KEYS.TOKEN_EXPIRY, expiresAt.toString());
508
+ }
509
+ }
510
+ if (response.user) {
511
+ await this.storage.set(STORAGE_KEYS.USER, JSON.stringify(response.user));
512
+ }
513
+ }
514
+ /**
515
+ * Clear stored authentication data
516
+ */
517
+ async clearAuth() {
518
+ await this.storage.remove(STORAGE_KEYS.ACCESS_TOKEN);
519
+ await this.storage.remove(STORAGE_KEYS.REFRESH_TOKEN);
520
+ await this.storage.remove(STORAGE_KEYS.TOKEN_EXPIRY);
521
+ await this.storage.remove(STORAGE_KEYS.USER);
522
+ await this.storage.remove(STORAGE_KEYS.TENANT);
523
+ this.currentUser = null;
524
+ }
525
+ /**
526
+ * Register a new user
527
+ *
528
+ * @example
529
+ * ```typescript
530
+ * const { user, token } = await baasix.auth.register({
531
+ * email: 'newuser@example.com',
532
+ * password: 'securepassword',
533
+ * firstName: 'John',
534
+ * lastName: 'Doe'
535
+ * });
536
+ * ```
537
+ */
538
+ async register(data) {
539
+ const response = await this.client.post("/auth/register", data, {
540
+ skipAuth: true
541
+ });
542
+ await this.storeTokens(response);
543
+ this.emitAuthStateChange("SIGNED_IN", response.user);
544
+ return response;
545
+ }
546
+ /**
547
+ * Login with email and password
548
+ *
549
+ * @example
550
+ * ```typescript
551
+ * const { user, token } = await baasix.auth.login({
552
+ * email: 'user@example.com',
553
+ * password: 'password123'
554
+ * });
555
+ *
556
+ * // Login with tenant (multi-tenant mode)
557
+ * const result = await baasix.auth.login({
558
+ * email: 'user@example.com',
559
+ * password: 'password123',
560
+ * tenantId: 'tenant-uuid'
561
+ * });
562
+ * ```
563
+ */
564
+ async login(credentials) {
565
+ const response = await this.client.post(
566
+ "/auth/login",
567
+ {
568
+ email: credentials.email,
569
+ password: credentials.password,
570
+ tenant_Id: credentials.tenantId
571
+ },
572
+ { skipAuth: true }
573
+ );
574
+ await this.storeTokens(response);
575
+ this.emitAuthStateChange("SIGNED_IN", response.user);
576
+ return response;
577
+ }
578
+ /**
579
+ * Logout the current user
580
+ *
581
+ * @example
582
+ * ```typescript
583
+ * await baasix.auth.logout();
584
+ * ```
585
+ */
586
+ async logout() {
587
+ try {
588
+ await this.client.get("/auth/logout");
589
+ } catch {
590
+ }
591
+ await this.clearAuth();
592
+ this.emitAuthStateChange("SIGNED_OUT", null);
593
+ }
594
+ /**
595
+ * Get the current authenticated user from the server
596
+ *
597
+ * @example
598
+ * ```typescript
599
+ * const user = await baasix.auth.getUser();
600
+ * console.log(user?.email);
601
+ * ```
602
+ */
603
+ async getUser() {
604
+ try {
605
+ const response = await this.client.get("/auth/me");
606
+ this.currentUser = response.data;
607
+ await this.storage.set(STORAGE_KEYS.USER, JSON.stringify(response.data));
608
+ return response.data;
609
+ } catch (error) {
610
+ if (error instanceof BaasixError && error.status === 401) {
611
+ await this.clearAuth();
612
+ return null;
613
+ }
614
+ throw error;
615
+ }
616
+ }
617
+ /**
618
+ * Get the cached current user (does not make an API call)
619
+ *
620
+ * @example
621
+ * ```typescript
622
+ * const user = await baasix.auth.getCachedUser();
623
+ * ```
624
+ */
625
+ async getCachedUser() {
626
+ if (this.currentUser) {
627
+ return this.currentUser;
628
+ }
629
+ const userJson = await this.storage.get(STORAGE_KEYS.USER);
630
+ if (userJson) {
631
+ try {
632
+ this.currentUser = JSON.parse(userJson);
633
+ return this.currentUser;
634
+ } catch {
635
+ return null;
636
+ }
637
+ }
638
+ return null;
639
+ }
640
+ /**
641
+ * Check if user is authenticated (has valid token)
642
+ *
643
+ * @example
644
+ * ```typescript
645
+ * if (await baasix.auth.isAuthenticated()) {
646
+ * // User is logged in
647
+ * }
648
+ * ```
649
+ */
650
+ async isAuthenticated() {
651
+ if (this.authMode === "cookie") {
652
+ const user = await this.getCachedUser();
653
+ return user !== null;
654
+ }
655
+ const token = await this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);
656
+ if (!token) return false;
657
+ const expiry = await this.storage.get(STORAGE_KEYS.TOKEN_EXPIRY);
658
+ if (expiry && Date.now() >= parseInt(expiry, 10)) {
659
+ const refreshToken = await this.storage.get(STORAGE_KEYS.REFRESH_TOKEN);
660
+ return !!refreshToken;
661
+ }
662
+ return true;
663
+ }
664
+ /**
665
+ * Get the current access token
666
+ *
667
+ * @example
668
+ * ```typescript
669
+ * const token = await baasix.auth.getToken();
670
+ * ```
671
+ */
672
+ async getToken() {
673
+ if (this.authMode === "cookie") {
674
+ return null;
675
+ }
676
+ return await this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);
677
+ }
678
+ /**
679
+ * Set a static token (useful for server-side or service accounts)
680
+ *
681
+ * @example
682
+ * ```typescript
683
+ * baasix.auth.setToken('your-api-token');
684
+ * ```
685
+ */
686
+ async setToken(token) {
687
+ await this.storage.set(STORAGE_KEYS.ACCESS_TOKEN, token);
688
+ }
689
+ /**
690
+ * Refresh the current token
691
+ *
692
+ * @example
693
+ * ```typescript
694
+ * const tokens = await baasix.auth.refreshToken();
695
+ * ```
696
+ */
697
+ async refreshToken() {
698
+ const refreshToken = await this.storage.get(STORAGE_KEYS.REFRESH_TOKEN);
699
+ const response = await this.client.post(
700
+ "/auth/refresh",
701
+ this.authMode === "jwt" ? { refreshToken } : void 0
702
+ );
703
+ await this.storeTokens(response);
704
+ const tokens = {
705
+ accessToken: response.token,
706
+ refreshToken: response.refreshToken,
707
+ expiresIn: response.expiresIn,
708
+ expiresAt: response.expiresIn ? Date.now() + response.expiresIn * 1e3 : void 0
709
+ };
710
+ this.emitAuthStateChange("TOKEN_REFRESHED", response.user);
711
+ return tokens;
712
+ }
713
+ /**
714
+ * Request a magic link for passwordless login
715
+ *
716
+ * @example
717
+ * ```typescript
718
+ * await baasix.auth.sendMagicLink({
719
+ * email: 'user@example.com',
720
+ * redirectUrl: 'https://myapp.com/auth/callback'
721
+ * });
722
+ * ```
723
+ */
724
+ async sendMagicLink(options) {
725
+ await this.client.post(
726
+ "/auth/magiclink",
727
+ {
728
+ email: options.email,
729
+ link: options.redirectUrl,
730
+ mode: options.mode || "link"
731
+ },
732
+ { skipAuth: true }
733
+ );
734
+ }
735
+ /**
736
+ * Verify magic link/code and complete login
737
+ *
738
+ * @example
739
+ * ```typescript
740
+ * const { user, token } = await baasix.auth.verifyMagicLink('verification-token');
741
+ * ```
742
+ */
743
+ async verifyMagicLink(token) {
744
+ const response = await this.client.get(
745
+ `/auth/magiclink/${encodeURIComponent(token)}`,
746
+ { skipAuth: true }
747
+ );
748
+ await this.storeTokens(response);
749
+ this.emitAuthStateChange("SIGNED_IN", response.user);
750
+ return response;
751
+ }
752
+ /**
753
+ * Request a password reset
754
+ *
755
+ * @example
756
+ * ```typescript
757
+ * await baasix.auth.forgotPassword({
758
+ * email: 'user@example.com',
759
+ * redirectUrl: 'https://myapp.com/reset-password'
760
+ * });
761
+ * ```
762
+ */
763
+ async forgotPassword(options) {
764
+ await this.client.post(
765
+ "/auth/forgot-password",
766
+ {
767
+ email: options.email,
768
+ link: options.redirectUrl
769
+ },
770
+ { skipAuth: true }
771
+ );
772
+ }
773
+ /**
774
+ * Reset password using a reset token
775
+ *
776
+ * @example
777
+ * ```typescript
778
+ * await baasix.auth.resetPassword('reset-token', 'newpassword123');
779
+ * ```
780
+ */
781
+ async resetPassword(token, newPassword) {
782
+ await this.client.post(
783
+ "/auth/reset-password",
784
+ { token, password: newPassword },
785
+ { skipAuth: true }
786
+ );
787
+ }
788
+ /**
789
+ * Change the current user's password
790
+ *
791
+ * @example
792
+ * ```typescript
793
+ * await baasix.auth.changePassword('currentPassword', 'newPassword');
794
+ * ```
795
+ */
796
+ async changePassword(currentPassword, newPassword) {
797
+ await this.client.post("/auth/change-password", {
798
+ currentPassword,
799
+ newPassword
800
+ });
801
+ }
802
+ /**
803
+ * Update the current user's profile
804
+ *
805
+ * @example
806
+ * ```typescript
807
+ * const updatedUser = await baasix.auth.updateProfile({
808
+ * firstName: 'Jane',
809
+ * lastName: 'Doe'
810
+ * });
811
+ * ```
812
+ */
813
+ async updateProfile(data) {
814
+ const response = await this.client.patch("/auth/me", data);
815
+ await this.storage.set(STORAGE_KEYS.USER, JSON.stringify(response.data));
816
+ this.emitAuthStateChange("USER_UPDATED", response.data);
817
+ return response.data;
818
+ }
819
+ /**
820
+ * Get available tenants for the current user (multi-tenant mode)
821
+ *
822
+ * @example
823
+ * ```typescript
824
+ * const tenants = await baasix.auth.getTenants();
825
+ * ```
826
+ */
827
+ async getTenants() {
828
+ const response = await this.client.get("/auth/tenants");
829
+ return response.data;
830
+ }
831
+ /**
832
+ * Switch to a different tenant (multi-tenant mode)
833
+ *
834
+ * @example
835
+ * ```typescript
836
+ * const { user, token } = await baasix.auth.switchTenant('tenant-uuid');
837
+ * ```
838
+ */
839
+ async switchTenant(tenantId) {
840
+ const response = await this.client.post("/auth/switch-tenant", {
841
+ tenant_Id: tenantId
842
+ });
843
+ await this.storeTokens(response);
844
+ await this.storage.set(STORAGE_KEYS.TENANT, tenantId);
845
+ this.emitAuthStateChange("TENANT_SWITCHED", response.user);
846
+ return response;
847
+ }
848
+ /**
849
+ * Get the current authentication state
850
+ *
851
+ * @example
852
+ * ```typescript
853
+ * const state = await baasix.auth.getState();
854
+ * console.log(state.isAuthenticated, state.user);
855
+ * ```
856
+ */
857
+ async getState() {
858
+ const isAuthenticated = await this.isAuthenticated();
859
+ const user = await this.getCachedUser();
860
+ return {
861
+ user,
862
+ isAuthenticated,
863
+ isLoading: false,
864
+ error: null
865
+ };
866
+ }
867
+ /**
868
+ * Initialize authentication state from storage
869
+ * Call this on app startup to restore previous session
870
+ *
871
+ * @example
872
+ * ```typescript
873
+ * await baasix.auth.initialize();
874
+ * ```
875
+ */
876
+ async initialize() {
877
+ const state = await this.getState();
878
+ if (state.isAuthenticated && state.user) {
879
+ this.emitAuthStateChange("SIGNED_IN", state.user);
880
+ }
881
+ return state;
882
+ }
883
+ // ===================
884
+ // OAuth / Social Login
885
+ // ===================
886
+ /**
887
+ * Get the OAuth authorization URL for a provider
888
+ * Redirect the user to this URL to start the OAuth flow
889
+ *
890
+ * @example
891
+ * ```typescript
892
+ * const url = baasix.auth.getOAuthUrl({
893
+ * provider: 'google',
894
+ * redirectUrl: 'https://myapp.com/auth/callback'
895
+ * });
896
+ * window.location.href = url;
897
+ * ```
898
+ */
899
+ getOAuthUrl(options) {
900
+ const baseUrl = this.client.getBaseUrl();
901
+ const params = new URLSearchParams({
902
+ redirect_url: options.redirectUrl
903
+ });
904
+ if (options.scopes?.length) {
905
+ params.set("scopes", options.scopes.join(","));
906
+ }
907
+ if (options.state) {
908
+ params.set("state", options.state);
909
+ }
910
+ return `${baseUrl}/auth/signin/${options.provider}?${params.toString()}`;
911
+ }
912
+ /**
913
+ * Handle OAuth callback and complete login
914
+ * Call this from your callback page with the token from URL
915
+ *
916
+ * @example
917
+ * ```typescript
918
+ * // In your callback page
919
+ * const params = new URLSearchParams(window.location.search);
920
+ * const token = params.get('token');
921
+ *
922
+ * if (token) {
923
+ * await baasix.auth.handleOAuthCallback(token);
924
+ * }
925
+ * ```
926
+ */
927
+ async handleOAuthCallback(token) {
928
+ await this.storage.set(STORAGE_KEYS.ACCESS_TOKEN, token);
929
+ const user = await this.getUser();
930
+ const response = {
931
+ token,
932
+ user
933
+ };
934
+ this.emitAuthStateChange("SIGNED_IN", user);
935
+ return response;
936
+ }
937
+ // ===================
938
+ // Email Verification
939
+ // ===================
940
+ /**
941
+ * Request email verification
942
+ * Sends a verification email to the current user
943
+ *
944
+ * @example
945
+ * ```typescript
946
+ * await baasix.auth.requestEmailVerification('https://myapp.com/verify-email');
947
+ * ```
948
+ */
949
+ async requestEmailVerification(redirectUrl) {
950
+ await this.client.post("/auth/request-verify-email", {
951
+ link: redirectUrl
952
+ });
953
+ }
954
+ /**
955
+ * Verify email with token
956
+ *
957
+ * @example
958
+ * ```typescript
959
+ * const params = new URLSearchParams(window.location.search);
960
+ * const token = params.get('token');
961
+ *
962
+ * await baasix.auth.verifyEmail(token);
963
+ * ```
964
+ */
965
+ async verifyEmail(token) {
966
+ await this.client.get("/auth/verify-email", {
967
+ params: { token },
968
+ skipAuth: true
969
+ });
970
+ }
971
+ /**
972
+ * Check if current session/token is valid
973
+ *
974
+ * @example
975
+ * ```typescript
976
+ * const isValid = await baasix.auth.checkSession();
977
+ * ```
978
+ */
979
+ async checkSession() {
980
+ try {
981
+ const response = await this.client.get("/auth/check");
982
+ return response.data.valid;
983
+ } catch {
984
+ return false;
985
+ }
986
+ }
987
+ // ===================
988
+ // Invitation System
989
+ // ===================
990
+ /**
991
+ * Send an invitation to a user (multi-tenant mode)
992
+ *
993
+ * @example
994
+ * ```typescript
995
+ * await baasix.auth.sendInvite({
996
+ * email: 'newuser@example.com',
997
+ * roleId: 'role-uuid',
998
+ * tenantId: 'tenant-uuid',
999
+ * redirectUrl: 'https://myapp.com/accept-invite'
1000
+ * });
1001
+ * ```
1002
+ */
1003
+ async sendInvite(options) {
1004
+ await this.client.post("/auth/invite", {
1005
+ email: options.email,
1006
+ role_Id: options.roleId,
1007
+ tenant_Id: options.tenantId,
1008
+ link: options.redirectUrl
1009
+ });
1010
+ }
1011
+ /**
1012
+ * Verify an invitation token
1013
+ *
1014
+ * @example
1015
+ * ```typescript
1016
+ * const params = new URLSearchParams(window.location.search);
1017
+ * const token = params.get('token');
1018
+ *
1019
+ * const result = await baasix.auth.verifyInvite(token);
1020
+ * if (result.valid) {
1021
+ * // Show registration form with pre-filled email
1022
+ * }
1023
+ * ```
1024
+ */
1025
+ async verifyInvite(token, redirectUrl) {
1026
+ const response = await this.client.get(
1027
+ "/auth/verify-invite",
1028
+ {
1029
+ params: {
1030
+ token,
1031
+ link: redirectUrl
1032
+ },
1033
+ skipAuth: true
1034
+ }
1035
+ );
1036
+ return response.data;
1037
+ }
1038
+ /**
1039
+ * Accept an invitation (for existing users)
1040
+ *
1041
+ * @example
1042
+ * ```typescript
1043
+ * await baasix.auth.acceptInvite(token);
1044
+ * ```
1045
+ */
1046
+ async acceptInvite(token) {
1047
+ const response = await this.client.post(
1048
+ "/auth/accept-invite",
1049
+ { token }
1050
+ );
1051
+ await this.storeTokens(response);
1052
+ this.emitAuthStateChange("SIGNED_IN", response.user);
1053
+ return response;
1054
+ }
1055
+ /**
1056
+ * Register with an invitation token
1057
+ *
1058
+ * @example
1059
+ * ```typescript
1060
+ * const { user, token } = await baasix.auth.registerWithInvite({
1061
+ * email: 'user@example.com',
1062
+ * password: 'password',
1063
+ * firstName: 'John',
1064
+ * lastName: 'Doe',
1065
+ * inviteToken: 'invite-token'
1066
+ * });
1067
+ * ```
1068
+ */
1069
+ async registerWithInvite(data) {
1070
+ const response = await this.client.post(
1071
+ "/auth/register",
1072
+ {
1073
+ ...data,
1074
+ inviteToken: data.inviteToken
1075
+ },
1076
+ { skipAuth: true }
1077
+ );
1078
+ await this.storeTokens(response);
1079
+ this.emitAuthStateChange("SIGNED_IN", response.user);
1080
+ return response;
1081
+ }
1082
+ };
1083
+
1084
+ // src/modules/items.ts
1085
+ var QueryBuilder = class {
1086
+ collection;
1087
+ client;
1088
+ queryParams = {};
1089
+ constructor(collection, client) {
1090
+ this.collection = collection;
1091
+ this.client = client;
1092
+ }
1093
+ /**
1094
+ * Select specific fields to return
1095
+ *
1096
+ * @example
1097
+ * ```typescript
1098
+ * items.select(['id', 'name', 'author.*'])
1099
+ * items.select('*', 'category.name')
1100
+ * ```
1101
+ */
1102
+ select(...fields) {
1103
+ const flatFields = fields.length === 1 && Array.isArray(fields[0]) ? fields[0] : fields;
1104
+ this.queryParams.fields = flatFields;
1105
+ return this;
1106
+ }
1107
+ /**
1108
+ * Alias for select()
1109
+ */
1110
+ fields(...fields) {
1111
+ return this.select(...fields);
1112
+ }
1113
+ /**
1114
+ * Add filter conditions
1115
+ *
1116
+ * @example
1117
+ * ```typescript
1118
+ * // Simple equality
1119
+ * items.filter({ status: { eq: 'active' } })
1120
+ *
1121
+ * // Multiple conditions
1122
+ * items.filter({
1123
+ * AND: [
1124
+ * { status: { eq: 'active' } },
1125
+ * { price: { gte: 100 } }
1126
+ * ]
1127
+ * })
1128
+ *
1129
+ * // Relation filtering
1130
+ * items.filter({ 'author.name': { like: 'John' } })
1131
+ * ```
1132
+ */
1133
+ filter(filter) {
1134
+ this.queryParams.filter = filter;
1135
+ return this;
1136
+ }
1137
+ /**
1138
+ * Alias for filter()
1139
+ */
1140
+ where(filter) {
1141
+ return this.filter(filter);
1142
+ }
1143
+ /**
1144
+ * Sort results
1145
+ *
1146
+ * @example
1147
+ * ```typescript
1148
+ * // Object notation
1149
+ * items.sort({ createdAt: 'desc', name: 'asc' })
1150
+ *
1151
+ * // Array notation with prefix
1152
+ * items.sort(['-createdAt', 'name'])
1153
+ *
1154
+ * // String shorthand
1155
+ * items.sort('createdAt:desc')
1156
+ * ```
1157
+ */
1158
+ sort(sort) {
1159
+ this.queryParams.sort = sort;
1160
+ return this;
1161
+ }
1162
+ /**
1163
+ * Alias for sort()
1164
+ */
1165
+ orderBy(sort) {
1166
+ return this.sort(sort);
1167
+ }
1168
+ /**
1169
+ * Limit number of results
1170
+ *
1171
+ * @example
1172
+ * ```typescript
1173
+ * items.limit(20)
1174
+ * items.limit(-1) // All results
1175
+ * ```
1176
+ */
1177
+ limit(limit) {
1178
+ this.queryParams.limit = limit;
1179
+ return this;
1180
+ }
1181
+ /**
1182
+ * Set page number (1-indexed)
1183
+ *
1184
+ * @example
1185
+ * ```typescript
1186
+ * items.page(2).limit(20)
1187
+ * ```
1188
+ */
1189
+ page(page) {
1190
+ this.queryParams.page = page;
1191
+ return this;
1192
+ }
1193
+ /**
1194
+ * Skip a number of results
1195
+ *
1196
+ * @example
1197
+ * ```typescript
1198
+ * items.offset(20)
1199
+ * ```
1200
+ */
1201
+ offset(offset) {
1202
+ this.queryParams.offset = offset;
1203
+ return this;
1204
+ }
1205
+ /**
1206
+ * Full-text search
1207
+ *
1208
+ * @example
1209
+ * ```typescript
1210
+ * items.search('keyword', ['title', 'description'])
1211
+ * ```
1212
+ */
1213
+ search(query, fields) {
1214
+ this.queryParams.search = query;
1215
+ if (fields) {
1216
+ this.queryParams.searchFields = fields;
1217
+ }
1218
+ return this;
1219
+ }
1220
+ /**
1221
+ * Include soft-deleted items
1222
+ *
1223
+ * @example
1224
+ * ```typescript
1225
+ * items.withDeleted()
1226
+ * ```
1227
+ */
1228
+ withDeleted() {
1229
+ this.queryParams.paranoid = false;
1230
+ return this;
1231
+ }
1232
+ /**
1233
+ * Filter related items in O2M/M2M relations
1234
+ *
1235
+ * @example
1236
+ * ```typescript
1237
+ * // Only show approved comments
1238
+ * items.relFilter({
1239
+ * comments: { approved: { eq: true } }
1240
+ * })
1241
+ * ```
1242
+ */
1243
+ relFilter(conditions) {
1244
+ this.queryParams.relConditions = conditions;
1245
+ return this;
1246
+ }
1247
+ /**
1248
+ * Get the built query parameters
1249
+ */
1250
+ getQuery() {
1251
+ return { ...this.queryParams };
1252
+ }
1253
+ /**
1254
+ * Execute the query and return results
1255
+ *
1256
+ * @example
1257
+ * ```typescript
1258
+ * const { data, totalCount } = await items
1259
+ * .filter({ status: { eq: 'active' } })
1260
+ * .sort({ createdAt: 'desc' })
1261
+ * .limit(10)
1262
+ * .get();
1263
+ * ```
1264
+ */
1265
+ async get() {
1266
+ return this.client.get(`/items/${this.collection}`, {
1267
+ params: this.buildParams()
1268
+ });
1269
+ }
1270
+ /**
1271
+ * Execute the query and return the first result
1272
+ *
1273
+ * @example
1274
+ * ```typescript
1275
+ * const item = await items
1276
+ * .filter({ slug: { eq: 'my-post' } })
1277
+ * .first();
1278
+ * ```
1279
+ */
1280
+ async first() {
1281
+ const result = await this.limit(1).get();
1282
+ return result.data[0] || null;
1283
+ }
1284
+ /**
1285
+ * Count matching items
1286
+ *
1287
+ * @example
1288
+ * ```typescript
1289
+ * const count = await items.filter({ status: { eq: 'active' } }).count();
1290
+ * ```
1291
+ */
1292
+ async count() {
1293
+ const result = await this.client.get(
1294
+ `/items/${this.collection}`,
1295
+ {
1296
+ params: {
1297
+ ...this.buildParams(),
1298
+ limit: 0
1299
+ }
1300
+ }
1301
+ );
1302
+ return result.totalCount || 0;
1303
+ }
1304
+ /**
1305
+ * Build query parameters for the request
1306
+ */
1307
+ buildParams() {
1308
+ const params = {};
1309
+ if (this.queryParams.fields) {
1310
+ params.fields = this.queryParams.fields;
1311
+ }
1312
+ if (this.queryParams.filter) {
1313
+ params.filter = this.queryParams.filter;
1314
+ }
1315
+ if (this.queryParams.sort) {
1316
+ params.sort = this.queryParams.sort;
1317
+ }
1318
+ if (this.queryParams.limit !== void 0) {
1319
+ params.limit = this.queryParams.limit;
1320
+ }
1321
+ if (this.queryParams.page !== void 0) {
1322
+ params.page = this.queryParams.page;
1323
+ }
1324
+ if (this.queryParams.offset !== void 0) {
1325
+ params.offset = this.queryParams.offset;
1326
+ }
1327
+ if (this.queryParams.search) {
1328
+ params.search = this.queryParams.search;
1329
+ }
1330
+ if (this.queryParams.searchFields) {
1331
+ params.searchFields = this.queryParams.searchFields;
1332
+ }
1333
+ if (this.queryParams.paranoid !== void 0) {
1334
+ params.paranoid = this.queryParams.paranoid;
1335
+ }
1336
+ if (this.queryParams.relConditions) {
1337
+ params.relConditions = this.queryParams.relConditions;
1338
+ }
1339
+ if (this.queryParams.aggregate) {
1340
+ params.aggregate = this.queryParams.aggregate;
1341
+ }
1342
+ if (this.queryParams.groupBy) {
1343
+ params.groupBy = this.queryParams.groupBy;
1344
+ }
1345
+ return params;
1346
+ }
1347
+ };
1348
+ var ItemsModule = class {
1349
+ collection;
1350
+ client;
1351
+ constructor(collection, config) {
1352
+ this.collection = collection;
1353
+ this.client = config.client;
1354
+ }
1355
+ /**
1356
+ * Create a query builder for fluent query construction
1357
+ *
1358
+ * @example
1359
+ * ```typescript
1360
+ * const results = await baasix.items('posts')
1361
+ * .query()
1362
+ * .select('*', 'author.*')
1363
+ * .filter({ status: { eq: 'published' } })
1364
+ * .sort({ createdAt: 'desc' })
1365
+ * .limit(10)
1366
+ * .get();
1367
+ * ```
1368
+ */
1369
+ query() {
1370
+ return new QueryBuilder(this.collection, this.client);
1371
+ }
1372
+ /**
1373
+ * Find items with optional query parameters
1374
+ *
1375
+ * @example
1376
+ * ```typescript
1377
+ * // Simple query
1378
+ * const { data } = await items.find();
1379
+ *
1380
+ * // With parameters
1381
+ * const { data, totalCount } = await items.find({
1382
+ * filter: { status: { eq: 'active' } },
1383
+ * sort: { createdAt: 'desc' },
1384
+ * limit: 20,
1385
+ * page: 1,
1386
+ * fields: ['id', 'name', 'price']
1387
+ * });
1388
+ * ```
1389
+ */
1390
+ async find(params) {
1391
+ return this.client.get(`/items/${this.collection}`, {
1392
+ params
1393
+ });
1394
+ }
1395
+ /**
1396
+ * Alias for find()
1397
+ */
1398
+ async findMany(params) {
1399
+ return this.find(params);
1400
+ }
1401
+ /**
1402
+ * Find a single item by ID
1403
+ *
1404
+ * @example
1405
+ * ```typescript
1406
+ * const product = await items.findOne('product-uuid');
1407
+ *
1408
+ * // With specific fields
1409
+ * const product = await items.findOne('product-uuid', {
1410
+ * fields: ['id', 'name', 'category.*']
1411
+ * });
1412
+ * ```
1413
+ */
1414
+ async findOne(id, params) {
1415
+ const response = await this.client.get(
1416
+ `/items/${this.collection}/${id}`,
1417
+ { params }
1418
+ );
1419
+ return response.data;
1420
+ }
1421
+ /**
1422
+ * Alias for findOne()
1423
+ */
1424
+ async get(id, params) {
1425
+ return this.findOne(id, params);
1426
+ }
1427
+ /**
1428
+ * Create a new item
1429
+ *
1430
+ * @example
1431
+ * ```typescript
1432
+ * const id = await items.create({
1433
+ * name: 'New Product',
1434
+ * price: 29.99,
1435
+ * status: 'draft'
1436
+ * });
1437
+ * ```
1438
+ */
1439
+ async create(data) {
1440
+ const response = await this.client.post(
1441
+ `/items/${this.collection}`,
1442
+ data
1443
+ );
1444
+ return response.data;
1445
+ }
1446
+ /**
1447
+ * Alias for create()
1448
+ */
1449
+ async insert(data) {
1450
+ return this.create(data);
1451
+ }
1452
+ /**
1453
+ * Create multiple items at once
1454
+ *
1455
+ * @example
1456
+ * ```typescript
1457
+ * const ids = await items.createMany([
1458
+ * { name: 'Product 1', price: 10 },
1459
+ * { name: 'Product 2', price: 20 }
1460
+ * ]);
1461
+ * ```
1462
+ */
1463
+ async createMany(data) {
1464
+ const response = await this.client.post(
1465
+ `/items/${this.collection}/bulk`,
1466
+ data
1467
+ );
1468
+ return response.data;
1469
+ }
1470
+ /**
1471
+ * Alias for createMany()
1472
+ */
1473
+ async insertMany(data) {
1474
+ return this.createMany(data);
1475
+ }
1476
+ /**
1477
+ * Update an existing item
1478
+ *
1479
+ * @example
1480
+ * ```typescript
1481
+ * await items.update('product-uuid', {
1482
+ * price: 24.99,
1483
+ * status: 'published'
1484
+ * });
1485
+ * ```
1486
+ */
1487
+ async update(id, data) {
1488
+ const response = await this.client.patch(
1489
+ `/items/${this.collection}/${id}`,
1490
+ data
1491
+ );
1492
+ return response.data;
1493
+ }
1494
+ /**
1495
+ * Update multiple items at once
1496
+ *
1497
+ * @example
1498
+ * ```typescript
1499
+ * // Update by IDs with same data
1500
+ * await items.updateMany(['id1', 'id2'], { status: 'archived' });
1501
+ * ```
1502
+ */
1503
+ async updateMany(ids, data) {
1504
+ const updates = ids.map((id) => ({ id, data }));
1505
+ const response = await this.client.patch(
1506
+ `/items/${this.collection}/bulk`,
1507
+ updates
1508
+ );
1509
+ return response.data;
1510
+ }
1511
+ /**
1512
+ * Upsert an item (create if not exists, update if exists)
1513
+ *
1514
+ * @example
1515
+ * ```typescript
1516
+ * const id = await items.upsert(
1517
+ * { sku: 'WIDGET-001' },
1518
+ * { name: 'Widget', price: 29.99, sku: 'WIDGET-001' }
1519
+ * );
1520
+ * ```
1521
+ */
1522
+ async upsert(filter, data) {
1523
+ const existing = await this.find({ filter, limit: 1 });
1524
+ if (existing.data.length > 0) {
1525
+ return this.update(existing.data[0].id, data);
1526
+ }
1527
+ return this.create(data);
1528
+ }
1529
+ /**
1530
+ * Delete an item by ID
1531
+ *
1532
+ * @example
1533
+ * ```typescript
1534
+ * await items.delete('product-uuid');
1535
+ * ```
1536
+ */
1537
+ async delete(id) {
1538
+ await this.client.delete(`/items/${this.collection}/${id}`);
1539
+ }
1540
+ /**
1541
+ * Delete multiple items
1542
+ *
1543
+ * @example
1544
+ * ```typescript
1545
+ * await items.deleteMany(['id1', 'id2', 'id3']);
1546
+ * ```
1547
+ */
1548
+ async deleteMany(ids) {
1549
+ await this.client.delete(`/items/${this.collection}/bulk`, {
1550
+ body: JSON.stringify(ids)
1551
+ });
1552
+ }
1553
+ /**
1554
+ * Soft delete an item (if paranoid mode is enabled)
1555
+ *
1556
+ * @example
1557
+ * ```typescript
1558
+ * await items.softDelete('product-uuid');
1559
+ * ```
1560
+ */
1561
+ async softDelete(id) {
1562
+ await this.update(id, { deletedAt: (/* @__PURE__ */ new Date()).toISOString() });
1563
+ }
1564
+ /**
1565
+ * Restore a soft-deleted item
1566
+ *
1567
+ * @example
1568
+ * ```typescript
1569
+ * await items.restore('product-uuid');
1570
+ * ```
1571
+ */
1572
+ async restore(id) {
1573
+ await this.update(id, { deletedAt: null });
1574
+ }
1575
+ /**
1576
+ * Aggregate data with grouping
1577
+ *
1578
+ * @example
1579
+ * ```typescript
1580
+ * const results = await items.aggregate({
1581
+ * aggregate: {
1582
+ * total: { function: 'sum', field: 'amount' },
1583
+ * count: { function: 'count', field: 'id' },
1584
+ * avgPrice: { function: 'avg', field: 'price' }
1585
+ * },
1586
+ * groupBy: ['category', 'status'],
1587
+ * filter: { createdAt: { gte: '$NOW-DAYS_30' } }
1588
+ * });
1589
+ * ```
1590
+ */
1591
+ async aggregate(params) {
1592
+ const response = await this.client.get(
1593
+ `/items/${this.collection}`,
1594
+ { params }
1595
+ );
1596
+ return response.data;
1597
+ }
1598
+ // ===================
1599
+ // Import Operations
1600
+ // ===================
1601
+ /**
1602
+ * Import items from a CSV file
1603
+ *
1604
+ * @example
1605
+ * ```typescript
1606
+ * // Browser
1607
+ * const fileInput = document.querySelector('input[type="file"]');
1608
+ * const file = fileInput.files[0];
1609
+ *
1610
+ * const result = await baasix.items('products').importCSV(file);
1611
+ *
1612
+ * console.log(`Imported ${result.imported} items`);
1613
+ * ```
1614
+ */
1615
+ async importCSV(file) {
1616
+ const formData = new FormData();
1617
+ if (file instanceof File) {
1618
+ formData.append("csvFile", file);
1619
+ } else {
1620
+ formData.append("csvFile", file);
1621
+ }
1622
+ const response = await this.client.post(
1623
+ `/items/${this.collection}/import-csv`,
1624
+ formData
1625
+ );
1626
+ return response.results;
1627
+ }
1628
+ /**
1629
+ * Import items from a JSON file
1630
+ *
1631
+ * @example
1632
+ * ```typescript
1633
+ * const file = fileInput.files[0]; // JSON file
1634
+ * const result = await baasix.items('products').importJSON(file);
1635
+ *
1636
+ * console.log(`Imported ${result.imported} items`);
1637
+ * ```
1638
+ */
1639
+ async importJSON(file) {
1640
+ const formData = new FormData();
1641
+ if (file instanceof File) {
1642
+ formData.append("jsonFile", file);
1643
+ } else {
1644
+ formData.append("jsonFile", file);
1645
+ }
1646
+ const response = await this.client.post(
1647
+ `/items/${this.collection}/import-json`,
1648
+ formData
1649
+ );
1650
+ return response.results;
1651
+ }
1652
+ /**
1653
+ * Import items from an array of objects
1654
+ *
1655
+ * @example
1656
+ * ```typescript
1657
+ * const data = [
1658
+ * { name: 'Product 1', price: 29.99 },
1659
+ * { name: 'Product 2', price: 39.99 }
1660
+ * ];
1661
+ *
1662
+ * const result = await baasix.items('products').importData(data);
1663
+ * ```
1664
+ */
1665
+ async importData(data) {
1666
+ const response = await this.client.post(
1667
+ `/items/${this.collection}/bulk`,
1668
+ data
1669
+ );
1670
+ return response;
1671
+ }
1672
+ // ===================
1673
+ // Sort Operations
1674
+ // ===================
1675
+ /**
1676
+ * Sort/reorder items (move item before or after another)
1677
+ *
1678
+ * @example
1679
+ * ```typescript
1680
+ * // Move item1 before item2
1681
+ * await baasix.items('products').sortItem('item1-uuid', 'item2-uuid');
1682
+ *
1683
+ * // Move item1 after item2
1684
+ * await baasix.items('products').sortItem('item1-uuid', 'item2-uuid', 'after');
1685
+ * ```
1686
+ */
1687
+ async sortItem(itemId, targetItemId, mode = "before") {
1688
+ await this.client.post(`/utils/sort/${this.collection}`, {
1689
+ item: itemId,
1690
+ to: targetItemId,
1691
+ mode
1692
+ });
1693
+ }
1694
+ /**
1695
+ * Reorder multiple items
1696
+ *
1697
+ * @example
1698
+ * ```typescript
1699
+ * // Set explicit order
1700
+ * await baasix.items('products').reorder([
1701
+ * 'item3-uuid',
1702
+ * 'item1-uuid',
1703
+ * 'item2-uuid'
1704
+ * ]);
1705
+ * ```
1706
+ */
1707
+ async reorder(orderedIds) {
1708
+ for (let i = 1; i < orderedIds.length; i++) {
1709
+ await this.client.post(`/utils/sort/${this.collection}`, {
1710
+ item: orderedIds[i],
1711
+ to: orderedIds[i - 1],
1712
+ mode: "after"
1713
+ });
1714
+ }
1715
+ }
1716
+ };
1717
+
1718
+ // src/modules/files.ts
1719
+ var FilesModule = class {
1720
+ client;
1721
+ constructor(config) {
1722
+ this.client = config.client;
1723
+ }
1724
+ /**
1725
+ * Upload a file
1726
+ *
1727
+ * @example
1728
+ * ```typescript
1729
+ * // Browser File API
1730
+ * const metadata = await baasix.files.upload(fileInput.files[0], {
1731
+ * title: 'Product Image',
1732
+ * folder: 'products',
1733
+ * isPublic: true,
1734
+ * onProgress: (progress) => console.log(`${progress}% uploaded`)
1735
+ * });
1736
+ *
1737
+ * // React Native with expo-image-picker
1738
+ * const metadata = await baasix.files.upload({
1739
+ * uri: result.uri,
1740
+ * name: 'photo.jpg',
1741
+ * type: 'image/jpeg'
1742
+ * });
1743
+ * ```
1744
+ */
1745
+ async upload(file, options) {
1746
+ const formData = new FormData();
1747
+ if (file instanceof File || file instanceof Blob) {
1748
+ formData.append("file", file);
1749
+ } else {
1750
+ formData.append("file", file);
1751
+ }
1752
+ if (options?.title) {
1753
+ formData.append("title", options.title);
1754
+ }
1755
+ if (options?.description) {
1756
+ formData.append("description", options.description);
1757
+ }
1758
+ if (options?.folder) {
1759
+ formData.append("folder", options.folder);
1760
+ }
1761
+ if (options?.storage) {
1762
+ formData.append("storage", options.storage);
1763
+ }
1764
+ if (options?.isPublic !== void 0) {
1765
+ formData.append("isPublic", String(options.isPublic));
1766
+ }
1767
+ if (options?.metadata) {
1768
+ formData.append("metadata", JSON.stringify(options.metadata));
1769
+ }
1770
+ const response = await this.client.upload(
1771
+ "/files",
1772
+ formData,
1773
+ {
1774
+ onProgress: options?.onProgress,
1775
+ timeout: options?.timeout
1776
+ }
1777
+ );
1778
+ return response.data;
1779
+ }
1780
+ /**
1781
+ * Upload multiple files
1782
+ *
1783
+ * @example
1784
+ * ```typescript
1785
+ * const files = await baasix.files.uploadMany(fileInput.files, {
1786
+ * folder: 'gallery',
1787
+ * isPublic: true
1788
+ * });
1789
+ * ```
1790
+ */
1791
+ async uploadMany(files, options) {
1792
+ const results = [];
1793
+ const fileArray = files instanceof FileList ? Array.from(files) : files;
1794
+ for (const file of fileArray) {
1795
+ const metadata = await this.upload(file, options);
1796
+ results.push(metadata);
1797
+ }
1798
+ return results;
1799
+ }
1800
+ /**
1801
+ * List files with optional filtering
1802
+ *
1803
+ * @example
1804
+ * ```typescript
1805
+ * const { data, totalCount } = await baasix.files.find({
1806
+ * filter: { mimeType: { startsWith: 'image/' } },
1807
+ * limit: 20
1808
+ * });
1809
+ * ```
1810
+ */
1811
+ async find(params) {
1812
+ return this.client.get("/files", {
1813
+ params
1814
+ });
1815
+ }
1816
+ /**
1817
+ * Get file metadata by ID
1818
+ *
1819
+ * @example
1820
+ * ```typescript
1821
+ * const file = await baasix.files.findOne('file-uuid');
1822
+ * console.log(file.filename, file.size);
1823
+ * ```
1824
+ */
1825
+ async findOne(id) {
1826
+ const response = await this.client.get(`/files/${id}`);
1827
+ return response.data;
1828
+ }
1829
+ /**
1830
+ * Update file metadata
1831
+ *
1832
+ * @example
1833
+ * ```typescript
1834
+ * await baasix.files.update('file-uuid', {
1835
+ * title: 'Updated Title',
1836
+ * description: 'New description'
1837
+ * });
1838
+ * ```
1839
+ */
1840
+ async update(id, data) {
1841
+ const response = await this.client.patch(
1842
+ `/files/${id}`,
1843
+ data
1844
+ );
1845
+ return response.data;
1846
+ }
1847
+ /**
1848
+ * Delete a file
1849
+ *
1850
+ * @example
1851
+ * ```typescript
1852
+ * await baasix.files.delete('file-uuid');
1853
+ * ```
1854
+ */
1855
+ async delete(id) {
1856
+ await this.client.delete(`/files/${id}`);
1857
+ }
1858
+ /**
1859
+ * Delete multiple files
1860
+ *
1861
+ * @example
1862
+ * ```typescript
1863
+ * await baasix.files.deleteMany(['id1', 'id2', 'id3']);
1864
+ * ```
1865
+ */
1866
+ async deleteMany(ids) {
1867
+ await Promise.all(ids.map((id) => this.delete(id)));
1868
+ }
1869
+ /**
1870
+ * Get the URL for an asset with optional transformations
1871
+ *
1872
+ * @example
1873
+ * ```typescript
1874
+ * // Original file
1875
+ * const url = baasix.files.getAssetUrl('file-uuid');
1876
+ *
1877
+ * // Resized thumbnail
1878
+ * const thumbUrl = baasix.files.getAssetUrl('file-uuid', {
1879
+ * width: 200,
1880
+ * height: 200,
1881
+ * fit: 'cover',
1882
+ * quality: 80
1883
+ * });
1884
+ *
1885
+ * // Convert to WebP
1886
+ * const webpUrl = baasix.files.getAssetUrl('file-uuid', {
1887
+ * format: 'webp',
1888
+ * quality: 85
1889
+ * });
1890
+ * ```
1891
+ */
1892
+ getAssetUrl(id, options) {
1893
+ const baseUrl = this.client.getBaseUrl();
1894
+ const url = new URL(`/assets/${id}`, baseUrl);
1895
+ if (options) {
1896
+ if (options.width) {
1897
+ url.searchParams.set("width", String(options.width));
1898
+ }
1899
+ if (options.height) {
1900
+ url.searchParams.set("height", String(options.height));
1901
+ }
1902
+ if (options.fit) {
1903
+ url.searchParams.set("fit", options.fit);
1904
+ }
1905
+ if (options.quality) {
1906
+ url.searchParams.set("quality", String(options.quality));
1907
+ }
1908
+ if (options.format) {
1909
+ url.searchParams.set("format", options.format);
1910
+ }
1911
+ }
1912
+ return url.toString();
1913
+ }
1914
+ /**
1915
+ * Download a file as a Blob
1916
+ *
1917
+ * @example
1918
+ * ```typescript
1919
+ * const blob = await baasix.files.download('file-uuid');
1920
+ *
1921
+ * // Create download link
1922
+ * const url = URL.createObjectURL(blob);
1923
+ * const a = document.createElement('a');
1924
+ * a.href = url;
1925
+ * a.download = 'filename.pdf';
1926
+ * a.click();
1927
+ * ```
1928
+ */
1929
+ async download(id, options) {
1930
+ const url = this.getAssetUrl(id, options);
1931
+ const response = await fetch(url);
1932
+ if (!response.ok) {
1933
+ throw new Error(`Failed to download file: ${response.statusText}`);
1934
+ }
1935
+ return response.blob();
1936
+ }
1937
+ /**
1938
+ * Get file as base64 string (useful for React Native)
1939
+ *
1940
+ * @example
1941
+ * ```typescript
1942
+ * const base64 = await baasix.files.toBase64('file-uuid');
1943
+ * // Use in Image component: <Image source={{ uri: `data:image/jpeg;base64,${base64}` }} />
1944
+ * ```
1945
+ */
1946
+ async toBase64(id, options) {
1947
+ const blob = await this.download(id, options);
1948
+ return new Promise((resolve, reject) => {
1949
+ const reader = new FileReader();
1950
+ reader.onloadend = () => {
1951
+ const result = reader.result;
1952
+ const base64 = result.split(",")[1];
1953
+ resolve(base64);
1954
+ };
1955
+ reader.onerror = reject;
1956
+ reader.readAsDataURL(blob);
1957
+ });
1958
+ }
1959
+ /**
1960
+ * Import file from URL
1961
+ *
1962
+ * @example
1963
+ * ```typescript
1964
+ * const file = await baasix.files.importFromUrl(
1965
+ * 'https://example.com/image.jpg',
1966
+ * { title: 'Imported Image' }
1967
+ * );
1968
+ * ```
1969
+ */
1970
+ async importFromUrl(url, options) {
1971
+ const response = await this.client.post(
1972
+ "/files/import",
1973
+ {
1974
+ url,
1975
+ ...options
1976
+ }
1977
+ );
1978
+ return response.data;
1979
+ }
1980
+ };
1981
+
1982
+ // src/utils/sort.ts
1983
+ function normalizeSort(sort) {
1984
+ if (!sort) return void 0;
1985
+ if (typeof sort === "string") {
1986
+ return sort;
1987
+ }
1988
+ if (Array.isArray(sort)) {
1989
+ if (sort.length === 0) return void 0;
1990
+ if (typeof sort[0] === "object" && "column" in sort[0]) {
1991
+ return sort.map((s) => `${s.column}:${s.order.toLowerCase()}`).join(",");
1992
+ }
1993
+ return sort.map((s) => {
1994
+ if (s.startsWith("-")) {
1995
+ return `${s.substring(1)}:desc`;
1996
+ }
1997
+ if (s.includes(":")) {
1998
+ return s;
1999
+ }
2000
+ return `${s}:asc`;
2001
+ }).join(",");
2002
+ }
2003
+ if (typeof sort === "object") {
2004
+ const entries = Object.entries(sort);
2005
+ if (entries.length === 0) return void 0;
2006
+ return entries.map(([field, direction]) => `${field}:${direction.toLowerCase()}`).join(",");
2007
+ }
2008
+ return void 0;
2009
+ }
2010
+
2011
+ // src/modules/schemas.ts
2012
+ var SchemasModule = class {
2013
+ client;
2014
+ constructor(config) {
2015
+ this.client = config.client;
2016
+ }
2017
+ /**
2018
+ * List all schemas
2019
+ *
2020
+ * @example
2021
+ * ```typescript
2022
+ * const { data } = await baasix.schemas.find();
2023
+ * console.log(data.map(s => s.collectionName));
2024
+ *
2025
+ * // With pagination
2026
+ * const { data } = await baasix.schemas.find({ page: 1, limit: 50 });
2027
+ * ```
2028
+ */
2029
+ async find(params) {
2030
+ const normalizedParams = params ? {
2031
+ ...params,
2032
+ sort: normalizeSort(params.sort)
2033
+ } : void 0;
2034
+ return this.client.get("/schemas", { params: normalizedParams });
2035
+ }
2036
+ /**
2037
+ * Get schema for a specific collection
2038
+ *
2039
+ * @example
2040
+ * ```typescript
2041
+ * const schema = await baasix.schemas.findOne('products');
2042
+ * console.log(schema.fields);
2043
+ * ```
2044
+ */
2045
+ async findOne(collection) {
2046
+ const response = await this.client.get(
2047
+ `/schemas/${collection}`
2048
+ );
2049
+ return response.data;
2050
+ }
2051
+ /**
2052
+ * Create a new collection/schema
2053
+ *
2054
+ * @example
2055
+ * ```typescript
2056
+ * await baasix.schemas.create({
2057
+ * collectionName: 'orders',
2058
+ * schema: {
2059
+ * name: 'Order',
2060
+ * timestamps: true,
2061
+ * paranoid: true,
2062
+ * fields: {
2063
+ * id: {
2064
+ * type: 'UUID',
2065
+ * primaryKey: true,
2066
+ * defaultValue: { type: 'UUIDV4' }
2067
+ * },
2068
+ * orderNumber: {
2069
+ * type: 'String',
2070
+ * allowNull: false,
2071
+ * unique: true
2072
+ * },
2073
+ * total: {
2074
+ * type: 'Decimal',
2075
+ * values: { precision: 10, scale: 2 },
2076
+ * allowNull: false,
2077
+ * defaultValue: 0
2078
+ * },
2079
+ * status: {
2080
+ * type: 'String',
2081
+ * allowNull: false,
2082
+ * defaultValue: 'pending'
2083
+ * },
2084
+ * items: {
2085
+ * type: 'JSONB',
2086
+ * allowNull: true,
2087
+ * defaultValue: []
2088
+ * }
2089
+ * }
2090
+ * }
2091
+ * });
2092
+ * ```
2093
+ */
2094
+ async create(data) {
2095
+ const response = await this.client.post(
2096
+ "/schemas",
2097
+ data
2098
+ );
2099
+ return response.data;
2100
+ }
2101
+ /**
2102
+ * Update an existing schema
2103
+ *
2104
+ * @example
2105
+ * ```typescript
2106
+ * await baasix.schemas.update('products', {
2107
+ * schema: {
2108
+ * name: 'Product',
2109
+ * timestamps: true,
2110
+ * fields: {
2111
+ * // Updated fields
2112
+ * description: { type: 'Text', allowNull: true }
2113
+ * }
2114
+ * }
2115
+ * });
2116
+ * ```
2117
+ */
2118
+ async update(collection, data) {
2119
+ const response = await this.client.patch(
2120
+ `/schemas/${collection}`,
2121
+ data
2122
+ );
2123
+ return response.data;
2124
+ }
2125
+ /**
2126
+ * Delete a schema (drops the table)
2127
+ *
2128
+ * @example
2129
+ * ```typescript
2130
+ * await baasix.schemas.delete('old_collection');
2131
+ * ```
2132
+ */
2133
+ async delete(collection) {
2134
+ await this.client.delete(`/schemas/${collection}`);
2135
+ }
2136
+ /**
2137
+ * Create a relationship between collections
2138
+ *
2139
+ * @example
2140
+ * ```typescript
2141
+ * // Many-to-One (BelongsTo)
2142
+ * await baasix.schemas.createRelationship('posts', {
2143
+ * type: 'M2O',
2144
+ * target: 'baasix_User',
2145
+ * name: 'author',
2146
+ * alias: 'posts'
2147
+ * });
2148
+ *
2149
+ * // Many-to-Many
2150
+ * await baasix.schemas.createRelationship('posts', {
2151
+ * type: 'M2M',
2152
+ * target: 'tags',
2153
+ * name: 'tags',
2154
+ * alias: 'posts'
2155
+ * });
2156
+ * ```
2157
+ */
2158
+ async createRelationship(collection, relationship) {
2159
+ await this.client.post(
2160
+ `/schemas/${collection}/relationships`,
2161
+ relationship
2162
+ );
2163
+ }
2164
+ /**
2165
+ * Delete a relationship
2166
+ *
2167
+ * @example
2168
+ * ```typescript
2169
+ * await baasix.schemas.deleteRelationship('posts', 'author');
2170
+ * ```
2171
+ */
2172
+ async deleteRelationship(collection, relationshipName) {
2173
+ await this.client.delete(
2174
+ `/schemas/${collection}/relationships/${relationshipName}`
2175
+ );
2176
+ }
2177
+ /**
2178
+ * Update a relationship
2179
+ *
2180
+ * @example
2181
+ * ```typescript
2182
+ * await baasix.schemas.updateRelationship('posts', 'author', {
2183
+ * alias: 'authoredPosts',
2184
+ * onDelete: 'CASCADE'
2185
+ * });
2186
+ * ```
2187
+ */
2188
+ async updateRelationship(collection, relationshipName, data) {
2189
+ await this.client.patch(
2190
+ `/schemas/${collection}/relationships/${relationshipName}`,
2191
+ data
2192
+ );
2193
+ }
2194
+ /**
2195
+ * Create an index on a collection
2196
+ *
2197
+ * @example
2198
+ * ```typescript
2199
+ * // Unique index
2200
+ * await baasix.schemas.createIndex('users', {
2201
+ * name: 'idx_users_email',
2202
+ * fields: ['email'],
2203
+ * unique: true
2204
+ * });
2205
+ *
2206
+ * // Composite index
2207
+ * await baasix.schemas.createIndex('orders', {
2208
+ * name: 'idx_orders_status_created',
2209
+ * fields: ['status', 'createdAt']
2210
+ * });
2211
+ * ```
2212
+ */
2213
+ async createIndex(collection, index) {
2214
+ await this.client.post(`/schemas/${collection}/indexes`, index);
2215
+ }
2216
+ /**
2217
+ * Delete an index
2218
+ *
2219
+ * @example
2220
+ * ```typescript
2221
+ * await baasix.schemas.deleteIndex('users', 'idx_users_email');
2222
+ * ```
2223
+ */
2224
+ async deleteIndex(collection, indexName) {
2225
+ await this.client.delete(`/schemas/${collection}/indexes/${indexName}`);
2226
+ }
2227
+ /**
2228
+ * Add a field to an existing schema
2229
+ *
2230
+ * @example
2231
+ * ```typescript
2232
+ * await baasix.schemas.addField('products', 'rating', {
2233
+ * type: 'Decimal',
2234
+ * values: { precision: 3, scale: 2 },
2235
+ * allowNull: true,
2236
+ * defaultValue: 0
2237
+ * });
2238
+ * ```
2239
+ */
2240
+ async addField(collection, fieldName, fieldDefinition) {
2241
+ const currentSchema = await this.findOne(collection);
2242
+ const updatedFields = {
2243
+ ...currentSchema.schema.fields,
2244
+ [fieldName]: fieldDefinition
2245
+ };
2246
+ return this.update(collection, {
2247
+ schema: {
2248
+ ...currentSchema.schema,
2249
+ fields: updatedFields
2250
+ }
2251
+ });
2252
+ }
2253
+ /**
2254
+ * Remove a field from a schema
2255
+ *
2256
+ * @example
2257
+ * ```typescript
2258
+ * await baasix.schemas.removeField('products', 'deprecated_field');
2259
+ * ```
2260
+ */
2261
+ async removeField(collection, fieldName) {
2262
+ const currentSchema = await this.findOne(collection);
2263
+ const { [fieldName]: _, ...remainingFields } = currentSchema.schema.fields;
2264
+ return this.update(collection, {
2265
+ schema: {
2266
+ ...currentSchema.schema,
2267
+ fields: remainingFields
2268
+ }
2269
+ });
2270
+ }
2271
+ /**
2272
+ * Export all schemas as JSON
2273
+ *
2274
+ * @example
2275
+ * ```typescript
2276
+ * const schemas = await baasix.schemas.export();
2277
+ * // Save to file for backup
2278
+ * ```
2279
+ */
2280
+ async export() {
2281
+ const response = await this.client.get(
2282
+ "/schemas/export"
2283
+ );
2284
+ return response.data;
2285
+ }
2286
+ /**
2287
+ * Import schemas from JSON
2288
+ *
2289
+ * @example
2290
+ * ```typescript
2291
+ * await baasix.schemas.import(savedSchemas);
2292
+ * ```
2293
+ */
2294
+ async import(schemas) {
2295
+ await this.client.post("/schemas/import", { schemas });
2296
+ }
2297
+ };
2298
+
2299
+ // src/modules/notifications.ts
2300
+ var NotificationsModule = class {
2301
+ client;
2302
+ constructor(config) {
2303
+ this.client = config.client;
2304
+ }
2305
+ /**
2306
+ * List notifications for the current user
2307
+ *
2308
+ * @example
2309
+ * ```typescript
2310
+ * const { data } = await baasix.notifications.find({
2311
+ * limit: 20,
2312
+ * filter: { seen: { eq: false } }
2313
+ * });
2314
+ * ```
2315
+ */
2316
+ async find(params) {
2317
+ return this.client.get("/notifications", {
2318
+ params
2319
+ });
2320
+ }
2321
+ /**
2322
+ * Get unread notification count
2323
+ *
2324
+ * @example
2325
+ * ```typescript
2326
+ * const count = await baasix.notifications.getUnreadCount();
2327
+ * ```
2328
+ */
2329
+ async getUnreadCount() {
2330
+ const response = await this.client.get(
2331
+ "/notifications/unread/count"
2332
+ );
2333
+ return response.count;
2334
+ }
2335
+ /**
2336
+ * Mark notifications as seen
2337
+ *
2338
+ * @example
2339
+ * ```typescript
2340
+ * // Mark specific notifications as seen
2341
+ * await baasix.notifications.markAsSeen(['id1', 'id2']);
2342
+ *
2343
+ * // Mark all notifications as seen
2344
+ * await baasix.notifications.markAsSeen();
2345
+ * ```
2346
+ */
2347
+ async markAsSeen(notificationIds) {
2348
+ const response = await this.client.post(
2349
+ "/notifications/mark-seen",
2350
+ { notificationIds }
2351
+ );
2352
+ return { count: response.count };
2353
+ }
2354
+ /**
2355
+ * Delete notifications for the current user
2356
+ *
2357
+ * @example
2358
+ * ```typescript
2359
+ * // Delete specific notifications
2360
+ * await baasix.notifications.delete(['id1', 'id2']);
2361
+ *
2362
+ * // Delete all notifications
2363
+ * await baasix.notifications.delete();
2364
+ * ```
2365
+ */
2366
+ async delete(notificationIds) {
2367
+ const response = await this.client.delete(
2368
+ "/notifications",
2369
+ { params: notificationIds ? { notificationIds } : void 0 }
2370
+ );
2371
+ return { count: response.count };
2372
+ }
2373
+ /**
2374
+ * Send a notification to users (requires admin permissions)
2375
+ *
2376
+ * @example
2377
+ * ```typescript
2378
+ * await baasix.notifications.send({
2379
+ * type: 'alert',
2380
+ * title: 'System Update',
2381
+ * message: 'The system will be down for maintenance',
2382
+ * data: { link: '/updates' },
2383
+ * userIds: ['user1-uuid', 'user2-uuid']
2384
+ * });
2385
+ * ```
2386
+ */
2387
+ async send(data) {
2388
+ const response = await this.client.post(
2389
+ "/notifications/send",
2390
+ data
2391
+ );
2392
+ return { notificationIds: response.notificationIds };
2393
+ }
2394
+ /**
2395
+ * Cleanup old notifications (requires admin permissions)
2396
+ *
2397
+ * @example
2398
+ * ```typescript
2399
+ * // Clean up notifications older than 30 days (default)
2400
+ * await baasix.notifications.cleanup();
2401
+ *
2402
+ * // Clean up notifications older than 7 days
2403
+ * await baasix.notifications.cleanup(7);
2404
+ * ```
2405
+ */
2406
+ async cleanup(days = 30) {
2407
+ const response = await this.client.post(
2408
+ "/notifications/cleanup",
2409
+ { days }
2410
+ );
2411
+ return { count: response.count };
2412
+ }
2413
+ };
2414
+
2415
+ // src/modules/permissions.ts
2416
+ var PermissionsModule = class {
2417
+ client;
2418
+ constructor(config) {
2419
+ this.client = config.client;
2420
+ }
2421
+ /**
2422
+ * List all permissions
2423
+ *
2424
+ * @example
2425
+ * ```typescript
2426
+ * const { data } = await baasix.permissions.find();
2427
+ * ```
2428
+ */
2429
+ async find(params) {
2430
+ return this.client.get("/permissions", {
2431
+ params
2432
+ });
2433
+ }
2434
+ /**
2435
+ * Get a permission by ID
2436
+ */
2437
+ async findOne(id) {
2438
+ const response = await this.client.get(
2439
+ `/permissions/${id}`
2440
+ );
2441
+ return response.data;
2442
+ }
2443
+ /**
2444
+ * Get permissions for a specific role
2445
+ *
2446
+ * @example
2447
+ * ```typescript
2448
+ * const { data } = await baasix.permissions.findByRole('role-uuid');
2449
+ * ```
2450
+ */
2451
+ async findByRole(roleId) {
2452
+ return this.client.get("/permissions", {
2453
+ params: {
2454
+ filter: { role_Id: { eq: roleId } },
2455
+ limit: -1
2456
+ }
2457
+ });
2458
+ }
2459
+ /**
2460
+ * Get permissions for a specific collection
2461
+ *
2462
+ * @example
2463
+ * ```typescript
2464
+ * const { data } = await baasix.permissions.findByCollection('products');
2465
+ * ```
2466
+ */
2467
+ async findByCollection(collection) {
2468
+ return this.client.get("/permissions", {
2469
+ params: {
2470
+ filter: { collection: { eq: collection } },
2471
+ limit: -1
2472
+ }
2473
+ });
2474
+ }
2475
+ /**
2476
+ * Create a new permission
2477
+ *
2478
+ * @example
2479
+ * ```typescript
2480
+ * await baasix.permissions.create({
2481
+ * role_Id: 'editor-role-uuid',
2482
+ * collection: 'posts',
2483
+ * action: 'update',
2484
+ * fields: ['title', 'content', 'status'],
2485
+ * conditions: {
2486
+ * author_Id: { eq: '$CURRENT_USER' }
2487
+ * }
2488
+ * });
2489
+ * ```
2490
+ */
2491
+ async create(data) {
2492
+ const response = await this.client.post(
2493
+ "/permissions",
2494
+ data
2495
+ );
2496
+ return response.data;
2497
+ }
2498
+ /**
2499
+ * Update a permission
2500
+ *
2501
+ * @example
2502
+ * ```typescript
2503
+ * await baasix.permissions.update('permission-uuid', {
2504
+ * fields: ['*'],
2505
+ * conditions: null
2506
+ * });
2507
+ * ```
2508
+ */
2509
+ async update(id, data) {
2510
+ const response = await this.client.patch(
2511
+ `/permissions/${id}`,
2512
+ data
2513
+ );
2514
+ return response.data;
2515
+ }
2516
+ /**
2517
+ * Delete a permission
2518
+ *
2519
+ * @example
2520
+ * ```typescript
2521
+ * await baasix.permissions.delete('permission-uuid');
2522
+ * ```
2523
+ */
2524
+ async delete(id) {
2525
+ await this.client.delete(`/permissions/${id}`);
2526
+ }
2527
+ /**
2528
+ * List all roles
2529
+ *
2530
+ * @example
2531
+ * ```typescript
2532
+ * const { data } = await baasix.permissions.getRoles();
2533
+ * ```
2534
+ */
2535
+ async getRoles() {
2536
+ return this.client.get("/items/baasix_Role", {
2537
+ params: { limit: -1 }
2538
+ });
2539
+ }
2540
+ /**
2541
+ * Create CRUD permissions for a collection
2542
+ *
2543
+ * @example
2544
+ * ```typescript
2545
+ * await baasix.permissions.createCrudPermissions('role-uuid', 'products', {
2546
+ * create: { fields: ['name', 'price', 'description'] },
2547
+ * read: { fields: ['*'] },
2548
+ * update: { fields: ['name', 'price', 'description'] },
2549
+ * delete: false
2550
+ * });
2551
+ * ```
2552
+ */
2553
+ async createCrudPermissions(roleId, collection, config) {
2554
+ const permissions = [];
2555
+ const actions = ["create", "read", "update", "delete"];
2556
+ for (const action of actions) {
2557
+ const actionConfig = config[action];
2558
+ if (actionConfig === false) continue;
2559
+ const permission = await this.create({
2560
+ role_Id: roleId,
2561
+ collection,
2562
+ action,
2563
+ fields: actionConfig?.fields || ["*"],
2564
+ conditions: actionConfig?.conditions
2565
+ });
2566
+ permissions.push(permission);
2567
+ }
2568
+ return permissions;
2569
+ }
2570
+ /**
2571
+ * Reload permissions cache (admin only)
2572
+ *
2573
+ * @example
2574
+ * ```typescript
2575
+ * await baasix.permissions.reloadCache();
2576
+ * ```
2577
+ */
2578
+ async reloadCache() {
2579
+ await this.client.post("/permissions/reload");
2580
+ }
2581
+ };
2582
+
2583
+ // src/modules/settings.ts
2584
+ var SettingsModule = class {
2585
+ client;
2586
+ constructor(config) {
2587
+ this.client = config.client;
2588
+ }
2589
+ /**
2590
+ * Get all settings
2591
+ *
2592
+ * @example
2593
+ * ```typescript
2594
+ * const settings = await baasix.settings.get();
2595
+ * console.log(settings.appName);
2596
+ * ```
2597
+ */
2598
+ async get() {
2599
+ const response = await this.client.get("/settings");
2600
+ return response.data;
2601
+ }
2602
+ /**
2603
+ * Get a specific setting by key
2604
+ *
2605
+ * @example
2606
+ * ```typescript
2607
+ * const appName = await baasix.settings.getKey('appName');
2608
+ * ```
2609
+ */
2610
+ async getKey(key) {
2611
+ const settings = await this.get();
2612
+ return settings[key] ?? null;
2613
+ }
2614
+ /**
2615
+ * Update settings
2616
+ *
2617
+ * @example
2618
+ * ```typescript
2619
+ * await baasix.settings.update({
2620
+ * appName: 'Updated App Name',
2621
+ * logo: 'file-uuid',
2622
+ * customConfig: {
2623
+ * feature1: true,
2624
+ * feature2: false
2625
+ * }
2626
+ * });
2627
+ * ```
2628
+ */
2629
+ async update(settings) {
2630
+ const response = await this.client.patch(
2631
+ "/settings",
2632
+ settings
2633
+ );
2634
+ return response.data;
2635
+ }
2636
+ /**
2637
+ * Set a specific setting
2638
+ *
2639
+ * @example
2640
+ * ```typescript
2641
+ * await baasix.settings.set('appName', 'My New App Name');
2642
+ * ```
2643
+ */
2644
+ async set(key, value) {
2645
+ return this.update({ [key]: value });
2646
+ }
2647
+ };
2648
+
2649
+ // src/modules/reports.ts
2650
+ var ReportsModule = class {
2651
+ client;
2652
+ constructor(config) {
2653
+ this.client = config.client;
2654
+ }
2655
+ /**
2656
+ * Generate a report for a collection using POST method
2657
+ *
2658
+ * @example
2659
+ * ```typescript
2660
+ * // Sales by month
2661
+ * const report = await baasix.reports.generate('orders', {
2662
+ * aggregate: {
2663
+ * revenue: { function: 'sum', field: 'total' },
2664
+ * orders: { function: 'count', field: 'id' }
2665
+ * },
2666
+ * groupBy: ['month'],
2667
+ * dateRange: {
2668
+ * start: '2025-01-01',
2669
+ * end: '2025-12-31'
2670
+ * }
2671
+ * });
2672
+ * ```
2673
+ */
2674
+ async generate(collection, config) {
2675
+ const response = await this.client.post(
2676
+ `/reports/${collection}`,
2677
+ config
2678
+ );
2679
+ return response;
2680
+ }
2681
+ /**
2682
+ * Query a report for a collection using GET method with query params
2683
+ *
2684
+ * @example
2685
+ * ```typescript
2686
+ * const report = await baasix.reports.query('orders', {
2687
+ * aggregate: {
2688
+ * total: { function: 'sum', field: 'amount' }
2689
+ * },
2690
+ * groupBy: ['status']
2691
+ * });
2692
+ * ```
2693
+ */
2694
+ async query(collection, params) {
2695
+ const response = await this.client.get(
2696
+ `/reports/${collection}`,
2697
+ { params }
2698
+ );
2699
+ return response;
2700
+ }
2701
+ /**
2702
+ * Get statistics for multiple collections in a single request
2703
+ *
2704
+ * @example
2705
+ * ```typescript
2706
+ * const stats = await baasix.reports.getStats([
2707
+ * {
2708
+ * name: 'total_products',
2709
+ * collection: 'products',
2710
+ * query: {
2711
+ * aggregate: { count: { function: 'count', field: '*' } }
2712
+ * }
2713
+ * },
2714
+ * {
2715
+ * name: 'total_orders',
2716
+ * collection: 'orders',
2717
+ * query: {
2718
+ * aggregate: {
2719
+ * count: { function: 'count', field: '*' },
2720
+ * total_amount: { function: 'sum', field: 'amount' }
2721
+ * }
2722
+ * }
2723
+ * }
2724
+ * ]);
2725
+ * ```
2726
+ */
2727
+ async getStats(stats) {
2728
+ const response = await this.client.post(`/reports/stats`, {
2729
+ stats
2730
+ });
2731
+ return response;
2732
+ }
2733
+ /**
2734
+ * Generate an aggregation query
2735
+ *
2736
+ * @example
2737
+ * ```typescript
2738
+ * const results = await baasix.reports.aggregate('orders', {
2739
+ * aggregate: {
2740
+ * total: { function: 'sum', field: 'amount' },
2741
+ * count: { function: 'count', field: 'id' },
2742
+ * min: { function: 'min', field: 'amount' },
2743
+ * max: { function: 'max', field: 'amount' },
2744
+ * avg: { function: 'avg', field: 'amount' }
2745
+ * },
2746
+ * groupBy: ['status', 'paymentMethod'],
2747
+ * filter: { createdAt: { gte: '$NOW-DAYS_30' } }
2748
+ * });
2749
+ * ```
2750
+ */
2751
+ async aggregate(collection, options) {
2752
+ const response = await this.client.get(
2753
+ `/items/${collection}`,
2754
+ {
2755
+ params: {
2756
+ aggregate: options.aggregate,
2757
+ groupBy: options.groupBy,
2758
+ filter: options.filter,
2759
+ limit: -1
2760
+ }
2761
+ }
2762
+ );
2763
+ return response.data;
2764
+ }
2765
+ /**
2766
+ * Count items matching a filter
2767
+ *
2768
+ * @example
2769
+ * ```typescript
2770
+ * const activeUsers = await baasix.reports.count('users', {
2771
+ * status: { eq: 'active' }
2772
+ * });
2773
+ * ```
2774
+ */
2775
+ async count(collection, filter) {
2776
+ const response = await this.client.get(
2777
+ `/items/${collection}`,
2778
+ {
2779
+ params: {
2780
+ filter,
2781
+ limit: 0
2782
+ }
2783
+ }
2784
+ );
2785
+ return response.totalCount || 0;
2786
+ }
2787
+ /**
2788
+ * Get distinct values for a field
2789
+ *
2790
+ * @example
2791
+ * ```typescript
2792
+ * const categories = await baasix.reports.distinct('products', 'category');
2793
+ * ```
2794
+ */
2795
+ async distinct(collection, field, filter) {
2796
+ const response = await this.client.get(
2797
+ `/items/${collection}`,
2798
+ {
2799
+ params: {
2800
+ filter,
2801
+ fields: [field],
2802
+ groupBy: [field],
2803
+ limit: -1
2804
+ }
2805
+ }
2806
+ );
2807
+ return response.data.map((item) => item[field]);
2808
+ }
2809
+ };
2810
+
2811
+ // src/modules/workflows.ts
2812
+ var WorkflowsModule = class {
2813
+ client;
2814
+ constructor(config) {
2815
+ this.client = config.client;
2816
+ }
2817
+ /**
2818
+ * List all workflows
2819
+ *
2820
+ * @example
2821
+ * ```typescript
2822
+ * const { data } = await baasix.workflows.find();
2823
+ * ```
2824
+ */
2825
+ async find(params) {
2826
+ return this.client.get("/workflows", {
2827
+ params
2828
+ });
2829
+ }
2830
+ /**
2831
+ * Get a workflow by ID
2832
+ *
2833
+ * @example
2834
+ * ```typescript
2835
+ * const workflow = await baasix.workflows.findOne('workflow-uuid');
2836
+ * ```
2837
+ */
2838
+ async findOne(id) {
2839
+ const response = await this.client.get(
2840
+ `/workflows/${id}`
2841
+ );
2842
+ return response.data;
2843
+ }
2844
+ /**
2845
+ * Create a new workflow
2846
+ *
2847
+ * @example
2848
+ * ```typescript
2849
+ * const workflow = await baasix.workflows.create({
2850
+ * name: 'Order Processing',
2851
+ * description: 'Process new orders',
2852
+ * trigger: {
2853
+ * type: 'hook',
2854
+ * config: {
2855
+ * collection: 'orders',
2856
+ * event: 'items.create.after'
2857
+ * }
2858
+ * },
2859
+ * nodes: [...],
2860
+ * edges: [...],
2861
+ * isActive: true
2862
+ * });
2863
+ * ```
2864
+ */
2865
+ async create(data) {
2866
+ const response = await this.client.post(
2867
+ "/workflows",
2868
+ data
2869
+ );
2870
+ return response.data;
2871
+ }
2872
+ /**
2873
+ * Update a workflow
2874
+ *
2875
+ * @example
2876
+ * ```typescript
2877
+ * await baasix.workflows.update('workflow-uuid', {
2878
+ * name: 'Updated Workflow Name',
2879
+ * isActive: false
2880
+ * });
2881
+ * ```
2882
+ */
2883
+ async update(id, data) {
2884
+ const response = await this.client.patch(
2885
+ `/workflows/${id}`,
2886
+ data
2887
+ );
2888
+ return response.data;
2889
+ }
2890
+ /**
2891
+ * Delete a workflow
2892
+ *
2893
+ * @example
2894
+ * ```typescript
2895
+ * await baasix.workflows.delete('workflow-uuid');
2896
+ * ```
2897
+ */
2898
+ async delete(id) {
2899
+ await this.client.delete(`/workflows/${id}`);
2900
+ }
2901
+ /**
2902
+ * Execute a workflow manually
2903
+ *
2904
+ * @example
2905
+ * ```typescript
2906
+ * const result = await baasix.workflows.execute('workflow-uuid', {
2907
+ * // Trigger data
2908
+ * customerId: 'customer-123',
2909
+ * action: 'sendEmail'
2910
+ * });
2911
+ * ```
2912
+ */
2913
+ async execute(id, triggerData) {
2914
+ const response = await this.client.post(
2915
+ `/workflows/${id}/execute`,
2916
+ { triggerData }
2917
+ );
2918
+ return response.data;
2919
+ }
2920
+ /**
2921
+ * Test a workflow without persisting execution
2922
+ *
2923
+ * @example
2924
+ * ```typescript
2925
+ * const result = await baasix.workflows.test('workflow-uuid', {
2926
+ * testData: { value: 123 }
2927
+ * });
2928
+ * ```
2929
+ */
2930
+ async test(id, triggerData) {
2931
+ const response = await this.client.post(
2932
+ `/workflows/${id}/test`,
2933
+ { triggerData }
2934
+ );
2935
+ return response.data;
2936
+ }
2937
+ /**
2938
+ * Get workflow execution history
2939
+ *
2940
+ * @example
2941
+ * ```typescript
2942
+ * const { data } = await baasix.workflows.getExecutions('workflow-uuid', {
2943
+ * limit: 50
2944
+ * });
2945
+ * ```
2946
+ */
2947
+ async getExecutions(id, params) {
2948
+ return this.client.get(
2949
+ `/workflows/${id}/executions`,
2950
+ { params }
2951
+ );
2952
+ }
2953
+ /**
2954
+ * Get a specific execution
2955
+ *
2956
+ * @example
2957
+ * ```typescript
2958
+ * const execution = await baasix.workflows.getExecution(
2959
+ * 'workflow-uuid',
2960
+ * 'execution-uuid'
2961
+ * );
2962
+ * ```
2963
+ */
2964
+ async getExecution(workflowId, executionId) {
2965
+ const response = await this.client.get(
2966
+ `/workflows/${workflowId}/executions/${executionId}`
2967
+ );
2968
+ return response.data;
2969
+ }
2970
+ /**
2971
+ * Cancel a running execution
2972
+ *
2973
+ * @example
2974
+ * ```typescript
2975
+ * await baasix.workflows.cancelExecution('workflow-uuid', 'execution-uuid');
2976
+ * ```
2977
+ */
2978
+ async cancelExecution(workflowId, executionId) {
2979
+ await this.client.post(
2980
+ `/workflows/${workflowId}/executions/${executionId}/cancel`
2981
+ );
2982
+ }
2983
+ /**
2984
+ * Enable a workflow
2985
+ *
2986
+ * @example
2987
+ * ```typescript
2988
+ * await baasix.workflows.enable('workflow-uuid');
2989
+ * ```
2990
+ */
2991
+ async enable(id) {
2992
+ return this.update(id, { isActive: true });
2993
+ }
2994
+ /**
2995
+ * Disable a workflow
2996
+ *
2997
+ * @example
2998
+ * ```typescript
2999
+ * await baasix.workflows.disable('workflow-uuid');
3000
+ * ```
3001
+ */
3002
+ async disable(id) {
3003
+ return this.update(id, { isActive: false });
3004
+ }
3005
+ /**
3006
+ * Duplicate a workflow
3007
+ *
3008
+ * @example
3009
+ * ```typescript
3010
+ * const newWorkflow = await baasix.workflows.duplicate('workflow-uuid', {
3011
+ * name: 'Copy of My Workflow'
3012
+ * });
3013
+ * ```
3014
+ */
3015
+ async duplicate(id, overrides) {
3016
+ const original = await this.findOne(id);
3017
+ const { id: _, createdAt, updatedAt, ...workflowData } = original;
3018
+ return this.create({
3019
+ ...workflowData,
3020
+ name: `Copy of ${workflowData.name}`,
3021
+ ...overrides
3022
+ });
3023
+ }
3024
+ };
3025
+
3026
+ // src/modules/realtime.ts
3027
+ var RealtimeModule = class {
3028
+ client;
3029
+ storage;
3030
+ socket = null;
3031
+ socketClient = null;
3032
+ socketUrl;
3033
+ socketPath;
3034
+ subscriptions = /* @__PURE__ */ new Map();
3035
+ workflowCallbacks = /* @__PURE__ */ new Map();
3036
+ roomCallbacks = /* @__PURE__ */ new Map();
3037
+ // room -> event -> callbacks
3038
+ roomUserCallbacks = /* @__PURE__ */ new Map();
3039
+ connectionCallbacks = /* @__PURE__ */ new Set();
3040
+ reconnecting = false;
3041
+ connectionPromise = null;
3042
+ constructor(config) {
3043
+ this.client = config.client;
3044
+ this.storage = config.storage;
3045
+ this.socketUrl = config.socketUrl || "";
3046
+ this.socketPath = config.socketPath || "/realtime";
3047
+ }
3048
+ /**
3049
+ * Set the socket.io client instance
3050
+ * This allows the SDK to work without bundling socket.io-client
3051
+ *
3052
+ * @example
3053
+ * ```typescript
3054
+ * import { io } from 'socket.io-client';
3055
+ * baasix.realtime.setSocketClient(io);
3056
+ * ```
3057
+ */
3058
+ setSocketClient(socketIO) {
3059
+ this.socketClient = socketIO;
3060
+ }
3061
+ /**
3062
+ * Set the WebSocket server URL
3063
+ * By default, uses the same URL as the API
3064
+ */
3065
+ setSocketUrl(url) {
3066
+ this.socketUrl = url;
3067
+ }
3068
+ /**
3069
+ * Check if socket.io client is available
3070
+ */
3071
+ ensureSocketClient() {
3072
+ if (!this.socketClient) {
3073
+ throw new Error(
3074
+ "Socket.io client not set. Please call baasix.realtime.setSocketClient(io) with socket.io-client."
3075
+ );
3076
+ }
3077
+ }
3078
+ /**
3079
+ * Get the authentication token for socket connection
3080
+ */
3081
+ async getAuthToken() {
3082
+ return await this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);
3083
+ }
3084
+ /**
3085
+ * Connect to the realtime server
3086
+ *
3087
+ * @example
3088
+ * ```typescript
3089
+ * await baasix.realtime.connect();
3090
+ * console.log('Connected to realtime server');
3091
+ * ```
3092
+ */
3093
+ async connect() {
3094
+ if (this.connectionPromise) {
3095
+ return this.connectionPromise;
3096
+ }
3097
+ if (this.socket?.connected) {
3098
+ return Promise.resolve();
3099
+ }
3100
+ this.ensureSocketClient();
3101
+ this.connectionPromise = new Promise(async (resolve, reject) => {
3102
+ try {
3103
+ const token = await this.getAuthToken();
3104
+ const baseUrl = this.socketUrl || this.client.getBaseUrl();
3105
+ this.socket = this.socketClient(baseUrl, {
3106
+ auth: { token: token || void 0 },
3107
+ path: this.socketPath,
3108
+ transports: ["websocket", "polling"],
3109
+ reconnection: true,
3110
+ reconnectionAttempts: 10,
3111
+ reconnectionDelay: 1e3,
3112
+ timeout: 2e4
3113
+ });
3114
+ this.socket.on("connect", () => {
3115
+ console.log("[Baasix Realtime] Connected");
3116
+ this.reconnecting = false;
3117
+ this.notifyConnectionChange(true);
3118
+ resolve();
3119
+ });
3120
+ this.socket.on("disconnect", (reason) => {
3121
+ console.log("[Baasix Realtime] Disconnected:", reason);
3122
+ this.notifyConnectionChange(false);
3123
+ });
3124
+ this.socket.on("connect_error", (error) => {
3125
+ console.error("[Baasix Realtime] Connection error:", error.message);
3126
+ if (!this.reconnecting) {
3127
+ reject(error);
3128
+ }
3129
+ });
3130
+ this.socket.on("reconnect", () => {
3131
+ console.log("[Baasix Realtime] Reconnected");
3132
+ this.reconnecting = false;
3133
+ this.resubscribeAll();
3134
+ this.notifyConnectionChange(true);
3135
+ });
3136
+ this.socket.on("reconnect_attempt", () => {
3137
+ this.reconnecting = true;
3138
+ });
3139
+ this.socket.on("connected", (data) => {
3140
+ console.log("[Baasix Realtime] Authenticated as user:", data.userId);
3141
+ });
3142
+ this.socket.on("workflow:execution:update", (data) => {
3143
+ this.handleWorkflowUpdate(data);
3144
+ });
3145
+ this.socket.on("workflow:execution:complete", (data) => {
3146
+ this.handleWorkflowUpdate({ ...data, status: "complete" });
3147
+ });
3148
+ this.socket.on("room:user:joined", (data) => {
3149
+ const callbacks = this.roomUserCallbacks.get(data.room);
3150
+ callbacks?.joined.forEach((cb) => {
3151
+ try {
3152
+ cb(data);
3153
+ } catch (e) {
3154
+ console.error("[Baasix Realtime] Error in room user joined callback:", e);
3155
+ }
3156
+ });
3157
+ });
3158
+ this.socket.on("room:user:left", (data) => {
3159
+ const callbacks = this.roomUserCallbacks.get(data.room);
3160
+ callbacks?.left.forEach((cb) => {
3161
+ try {
3162
+ cb(data);
3163
+ } catch (e) {
3164
+ console.error("[Baasix Realtime] Error in room user left callback:", e);
3165
+ }
3166
+ });
3167
+ });
3168
+ this.socket.connect();
3169
+ } catch (error) {
3170
+ this.connectionPromise = null;
3171
+ reject(error);
3172
+ }
3173
+ });
3174
+ try {
3175
+ await this.connectionPromise;
3176
+ } finally {
3177
+ this.connectionPromise = null;
3178
+ }
3179
+ }
3180
+ /**
3181
+ * Disconnect from the realtime server
3182
+ *
3183
+ * @example
3184
+ * ```typescript
3185
+ * baasix.realtime.disconnect();
3186
+ * ```
3187
+ */
3188
+ disconnect() {
3189
+ if (this.socket) {
3190
+ this.socket.disconnect();
3191
+ this.socket = null;
3192
+ }
3193
+ this.subscriptions.clear();
3194
+ this.workflowCallbacks.clear();
3195
+ this.roomCallbacks.clear();
3196
+ this.roomUserCallbacks.clear();
3197
+ }
3198
+ /**
3199
+ * Check if connected to the realtime server
3200
+ */
3201
+ get isConnected() {
3202
+ return this.socket?.connected ?? false;
3203
+ }
3204
+ /**
3205
+ * Subscribe to connection state changes
3206
+ *
3207
+ * @example
3208
+ * ```typescript
3209
+ * const unsubscribe = baasix.realtime.onConnectionChange((connected) => {
3210
+ * console.log('Connection state:', connected ? 'online' : 'offline');
3211
+ * });
3212
+ * ```
3213
+ */
3214
+ onConnectionChange(callback) {
3215
+ this.connectionCallbacks.add(callback);
3216
+ return () => {
3217
+ this.connectionCallbacks.delete(callback);
3218
+ };
3219
+ }
3220
+ notifyConnectionChange(connected) {
3221
+ this.connectionCallbacks.forEach((callback) => callback(connected));
3222
+ }
3223
+ /**
3224
+ * Subscribe to a collection for real-time updates
3225
+ *
3226
+ * @example
3227
+ * ```typescript
3228
+ * // Subscribe to all changes
3229
+ * const unsubscribe = baasix.realtime.subscribe('products', (payload) => {
3230
+ * console.log(`${payload.action}:`, payload.data);
3231
+ * });
3232
+ *
3233
+ * // Subscribe to specific events
3234
+ * const unsubscribe = baasix.realtime.subscribe('orders', (payload) => {
3235
+ * if (payload.action === 'create') {
3236
+ * console.log('New order:', payload.data);
3237
+ * }
3238
+ * });
3239
+ *
3240
+ * // Unsubscribe when done
3241
+ * unsubscribe();
3242
+ * ```
3243
+ */
3244
+ subscribe(collection, callback) {
3245
+ if (!this.socket?.connected) {
3246
+ console.warn("[Baasix Realtime] Not connected. Call connect() first.");
3247
+ }
3248
+ const callbackId = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
3249
+ let subscription = this.subscriptions.get(collection);
3250
+ if (!subscription) {
3251
+ subscription = {
3252
+ collection,
3253
+ callbacks: /* @__PURE__ */ new Map()
3254
+ };
3255
+ this.subscriptions.set(collection, subscription);
3256
+ this.subscribeOnServer(collection);
3257
+ this.setupCollectionListeners(collection);
3258
+ }
3259
+ subscription.callbacks.set(callbackId, callback);
3260
+ return () => {
3261
+ const sub = this.subscriptions.get(collection);
3262
+ if (sub) {
3263
+ sub.callbacks.delete(callbackId);
3264
+ if (sub.callbacks.size === 0) {
3265
+ this.unsubscribeOnServer(collection);
3266
+ this.removeCollectionListeners(collection);
3267
+ this.subscriptions.delete(collection);
3268
+ }
3269
+ }
3270
+ };
3271
+ }
3272
+ /**
3273
+ * Subscribe to specific events on a collection
3274
+ *
3275
+ * @example
3276
+ * ```typescript
3277
+ * // Only listen for creates
3278
+ * const unsubscribe = baasix.realtime.on('products', 'create', (data) => {
3279
+ * console.log('New product:', data);
3280
+ * });
3281
+ * ```
3282
+ */
3283
+ on(collection, event, callback) {
3284
+ return this.subscribe(collection, (payload) => {
3285
+ if (payload.action === event) {
3286
+ callback(payload.data);
3287
+ }
3288
+ });
3289
+ }
3290
+ /**
3291
+ * Listen to all changes across all subscribed collections
3292
+ *
3293
+ * @example
3294
+ * ```typescript
3295
+ * const unsubscribe = baasix.realtime.onAny((collection, payload) => {
3296
+ * console.log(`${collection}:${payload.action}`, payload.data);
3297
+ * });
3298
+ * ```
3299
+ */
3300
+ onAny(callback) {
3301
+ const unsubscribers = [];
3302
+ this.subscriptions.forEach((_, collection) => {
3303
+ const unsub = this.subscribe(collection, (payload) => {
3304
+ callback(collection, payload);
3305
+ });
3306
+ unsubscribers.push(unsub);
3307
+ });
3308
+ return () => {
3309
+ unsubscribers.forEach((unsub) => unsub());
3310
+ };
3311
+ }
3312
+ subscribeOnServer(collection) {
3313
+ if (this.socket?.connected) {
3314
+ this.socket.emit("subscribe", { collection }, (response) => {
3315
+ if (response.status === "error") {
3316
+ console.error(`[Baasix Realtime] Failed to subscribe to ${collection}:`, response.message);
3317
+ }
3318
+ });
3319
+ }
3320
+ }
3321
+ unsubscribeOnServer(collection) {
3322
+ if (this.socket?.connected) {
3323
+ this.socket.emit("unsubscribe", { collection });
3324
+ }
3325
+ }
3326
+ setupCollectionListeners(collection) {
3327
+ if (!this.socket) return;
3328
+ const events = ["create", "update", "delete"];
3329
+ events.forEach((event) => {
3330
+ const eventName = `${collection}:${event}`;
3331
+ this.socket.on(eventName, (payload) => {
3332
+ this.handleCollectionEvent(collection, payload);
3333
+ });
3334
+ });
3335
+ }
3336
+ removeCollectionListeners(collection) {
3337
+ if (!this.socket) return;
3338
+ const events = ["create", "update", "delete"];
3339
+ events.forEach((event) => {
3340
+ const eventName = `${collection}:${event}`;
3341
+ this.socket.off(eventName);
3342
+ });
3343
+ }
3344
+ handleCollectionEvent(collection, payload) {
3345
+ const subscription = this.subscriptions.get(collection);
3346
+ if (subscription) {
3347
+ subscription.callbacks.forEach((callback) => {
3348
+ try {
3349
+ callback(payload);
3350
+ } catch (error) {
3351
+ console.error(`[Baasix Realtime] Error in subscription callback:`, error);
3352
+ }
3353
+ });
3354
+ }
3355
+ }
3356
+ resubscribeAll() {
3357
+ this.subscriptions.forEach((_, collection) => {
3358
+ this.subscribeOnServer(collection);
3359
+ this.setupCollectionListeners(collection);
3360
+ });
3361
+ }
3362
+ // ===================
3363
+ // Workflow Realtime
3364
+ // ===================
3365
+ /**
3366
+ * Join a workflow execution room to receive real-time updates
3367
+ *
3368
+ * @example
3369
+ * ```typescript
3370
+ * const unsubscribe = baasix.realtime.subscribeToExecution(executionId, (update) => {
3371
+ * console.log('Execution update:', update);
3372
+ * if (update.status === 'complete') {
3373
+ * console.log('Workflow finished!');
3374
+ * }
3375
+ * });
3376
+ * ```
3377
+ */
3378
+ subscribeToExecution(executionId, callback) {
3379
+ const id = String(executionId);
3380
+ if (this.socket?.connected) {
3381
+ this.socket.emit("workflow:execution:join", { executionId: id });
3382
+ }
3383
+ let callbacks = this.workflowCallbacks.get(id);
3384
+ if (!callbacks) {
3385
+ callbacks = /* @__PURE__ */ new Set();
3386
+ this.workflowCallbacks.set(id, callbacks);
3387
+ }
3388
+ callbacks.add(callback);
3389
+ return () => {
3390
+ const cbs = this.workflowCallbacks.get(id);
3391
+ if (cbs) {
3392
+ cbs.delete(callback);
3393
+ if (cbs.size === 0) {
3394
+ this.workflowCallbacks.delete(id);
3395
+ }
3396
+ }
3397
+ };
3398
+ }
3399
+ handleWorkflowUpdate(data) {
3400
+ const id = String(data.executionId);
3401
+ const callbacks = this.workflowCallbacks.get(id);
3402
+ if (callbacks) {
3403
+ callbacks.forEach((callback) => {
3404
+ try {
3405
+ callback(data);
3406
+ } catch (error) {
3407
+ console.error(`[Baasix Realtime] Error in workflow callback:`, error);
3408
+ }
3409
+ });
3410
+ }
3411
+ }
3412
+ // ===================
3413
+ // Custom Rooms API
3414
+ // ===================
3415
+ /**
3416
+ * Join a custom room for real-time communication
3417
+ *
3418
+ * @example
3419
+ * ```typescript
3420
+ * // Join a room
3421
+ * await baasix.realtime.joinRoom('game:lobby');
3422
+ *
3423
+ * // Listen for messages
3424
+ * baasix.realtime.onRoomMessage('game:lobby', 'chat', (data) => {
3425
+ * console.log(`${data.sender.userId}: ${data.payload.text}`);
3426
+ * });
3427
+ * ```
3428
+ */
3429
+ async joinRoom(roomName) {
3430
+ if (!this.socket?.connected) {
3431
+ throw new Error("Not connected. Call connect() first.");
3432
+ }
3433
+ return new Promise((resolve, reject) => {
3434
+ this.socket.emit("room:join", { room: roomName }, (response) => {
3435
+ if (response.status === "success") {
3436
+ this.setupRoomListeners(roomName);
3437
+ resolve();
3438
+ } else {
3439
+ reject(new Error(response.message || "Failed to join room"));
3440
+ }
3441
+ });
3442
+ });
3443
+ }
3444
+ /**
3445
+ * Leave a custom room
3446
+ *
3447
+ * @example
3448
+ * ```typescript
3449
+ * await baasix.realtime.leaveRoom('game:lobby');
3450
+ * ```
3451
+ */
3452
+ async leaveRoom(roomName) {
3453
+ if (!this.socket?.connected) {
3454
+ return;
3455
+ }
3456
+ return new Promise((resolve, reject) => {
3457
+ this.socket.emit("room:leave", { room: roomName }, (response) => {
3458
+ if (response.status === "success") {
3459
+ this.cleanupRoomListeners(roomName);
3460
+ resolve();
3461
+ } else {
3462
+ reject(new Error(response.message || "Failed to leave room"));
3463
+ }
3464
+ });
3465
+ });
3466
+ }
3467
+ /**
3468
+ * Send a message to a room
3469
+ *
3470
+ * @example
3471
+ * ```typescript
3472
+ * // Send a chat message
3473
+ * await baasix.realtime.sendToRoom('game:lobby', 'chat', { text: 'Hello!' });
3474
+ *
3475
+ * // Send a game event
3476
+ * await baasix.realtime.sendToRoom('game:123', 'move', { x: 10, y: 20 });
3477
+ * ```
3478
+ */
3479
+ async sendToRoom(roomName, event, payload) {
3480
+ if (!this.socket?.connected) {
3481
+ throw new Error("Not connected. Call connect() first.");
3482
+ }
3483
+ return new Promise((resolve, reject) => {
3484
+ this.socket.emit(
3485
+ "room:message",
3486
+ { room: roomName, event, payload },
3487
+ (response) => {
3488
+ if (response.status === "success") {
3489
+ resolve();
3490
+ } else {
3491
+ reject(new Error(response.message || "Failed to send message"));
3492
+ }
3493
+ }
3494
+ );
3495
+ });
3496
+ }
3497
+ /**
3498
+ * Listen for messages in a room with a specific event type
3499
+ *
3500
+ * @example
3501
+ * ```typescript
3502
+ * const unsubscribe = baasix.realtime.onRoomMessage('game:lobby', 'chat', (data) => {
3503
+ * console.log(`${data.sender.userId}: ${data.payload.text}`);
3504
+ * });
3505
+ *
3506
+ * // Later
3507
+ * unsubscribe();
3508
+ * ```
3509
+ */
3510
+ onRoomMessage(roomName, event, callback) {
3511
+ if (!this.roomCallbacks.has(roomName)) {
3512
+ this.roomCallbacks.set(roomName, /* @__PURE__ */ new Map());
3513
+ }
3514
+ const roomEvents = this.roomCallbacks.get(roomName);
3515
+ if (!roomEvents.has(event)) {
3516
+ roomEvents.set(event, /* @__PURE__ */ new Set());
3517
+ }
3518
+ roomEvents.get(event).add(callback);
3519
+ return () => {
3520
+ const events = this.roomCallbacks.get(roomName);
3521
+ if (events) {
3522
+ const callbacks = events.get(event);
3523
+ if (callbacks) {
3524
+ callbacks.delete(callback);
3525
+ if (callbacks.size === 0) {
3526
+ events.delete(event);
3527
+ }
3528
+ }
3529
+ if (events.size === 0) {
3530
+ this.roomCallbacks.delete(roomName);
3531
+ }
3532
+ }
3533
+ };
3534
+ }
3535
+ /**
3536
+ * Listen for users joining a room
3537
+ *
3538
+ * @example
3539
+ * ```typescript
3540
+ * const unsubscribe = baasix.realtime.onRoomUserJoined('game:lobby', (data) => {
3541
+ * console.log(`User ${data.userId} joined the room`);
3542
+ * });
3543
+ * ```
3544
+ */
3545
+ onRoomUserJoined(roomName, callback) {
3546
+ if (!this.roomUserCallbacks.has(roomName)) {
3547
+ this.roomUserCallbacks.set(roomName, { joined: /* @__PURE__ */ new Set(), left: /* @__PURE__ */ new Set() });
3548
+ }
3549
+ this.roomUserCallbacks.get(roomName).joined.add(callback);
3550
+ return () => {
3551
+ const callbacks = this.roomUserCallbacks.get(roomName);
3552
+ if (callbacks) {
3553
+ callbacks.joined.delete(callback);
3554
+ if (callbacks.joined.size === 0 && callbacks.left.size === 0) {
3555
+ this.roomUserCallbacks.delete(roomName);
3556
+ }
3557
+ }
3558
+ };
3559
+ }
3560
+ /**
3561
+ * Listen for users leaving a room
3562
+ *
3563
+ * @example
3564
+ * ```typescript
3565
+ * const unsubscribe = baasix.realtime.onRoomUserLeft('game:lobby', (data) => {
3566
+ * console.log(`User ${data.userId} left the room`);
3567
+ * });
3568
+ * ```
3569
+ */
3570
+ onRoomUserLeft(roomName, callback) {
3571
+ if (!this.roomUserCallbacks.has(roomName)) {
3572
+ this.roomUserCallbacks.set(roomName, { joined: /* @__PURE__ */ new Set(), left: /* @__PURE__ */ new Set() });
3573
+ }
3574
+ this.roomUserCallbacks.get(roomName).left.add(callback);
3575
+ return () => {
3576
+ const callbacks = this.roomUserCallbacks.get(roomName);
3577
+ if (callbacks) {
3578
+ callbacks.left.delete(callback);
3579
+ if (callbacks.joined.size === 0 && callbacks.left.size === 0) {
3580
+ this.roomUserCallbacks.delete(roomName);
3581
+ }
3582
+ }
3583
+ };
3584
+ }
3585
+ /**
3586
+ * Invoke a custom server-side handler
3587
+ *
3588
+ * @example
3589
+ * ```typescript
3590
+ * const result = await baasix.realtime.invoke('game:roll-dice', { sides: 6 });
3591
+ * console.log('Dice result:', result);
3592
+ * ```
3593
+ */
3594
+ async invoke(event, payload) {
3595
+ if (!this.socket?.connected) {
3596
+ throw new Error("Not connected. Call connect() first.");
3597
+ }
3598
+ return new Promise((resolve, reject) => {
3599
+ this.socket.emit("custom", { event, payload }, (response) => {
3600
+ if (response.status === "success") {
3601
+ resolve(response);
3602
+ } else {
3603
+ reject(new Error(response.message || "Custom event failed"));
3604
+ }
3605
+ });
3606
+ });
3607
+ }
3608
+ setupRoomListeners(roomName) {
3609
+ if (!this.roomCallbacks.has(roomName)) {
3610
+ this.roomCallbacks.set(roomName, /* @__PURE__ */ new Map());
3611
+ }
3612
+ if (!this.roomUserCallbacks.has(roomName)) {
3613
+ this.roomUserCallbacks.set(roomName, { joined: /* @__PURE__ */ new Set(), left: /* @__PURE__ */ new Set() });
3614
+ }
3615
+ }
3616
+ cleanupRoomListeners(roomName) {
3617
+ this.roomCallbacks.delete(roomName);
3618
+ this.roomUserCallbacks.delete(roomName);
3619
+ }
3620
+ // ===================
3621
+ // Channel (Room) API - Supabase-style
3622
+ // ===================
3623
+ /**
3624
+ * Create a channel for a collection (Supabase-style API)
3625
+ *
3626
+ * @example
3627
+ * ```typescript
3628
+ * const channel = baasix.realtime
3629
+ * .channel('products')
3630
+ * .on('INSERT', (payload) => console.log('New:', payload))
3631
+ * .on('UPDATE', (payload) => console.log('Updated:', payload))
3632
+ * .on('DELETE', (payload) => console.log('Deleted:', payload))
3633
+ * .subscribe();
3634
+ *
3635
+ * // Later
3636
+ * channel.unsubscribe();
3637
+ * ```
3638
+ */
3639
+ channel(collection) {
3640
+ return new RealtimeChannel(this, collection);
3641
+ }
3642
+ };
3643
+ var RealtimeChannel = class {
3644
+ realtime;
3645
+ collection;
3646
+ handlers = /* @__PURE__ */ new Map();
3647
+ unsubscribeFn = null;
3648
+ constructor(realtime, collection) {
3649
+ this.realtime = realtime;
3650
+ this.collection = collection;
3651
+ }
3652
+ /**
3653
+ * Add an event handler (chainable)
3654
+ *
3655
+ * @param event - 'INSERT', 'UPDATE', 'DELETE', or '*' for all
3656
+ * @param callback - Handler function
3657
+ */
3658
+ on(event, callback) {
3659
+ const mappedEvent = this.mapEvent(event);
3660
+ if (mappedEvent === "*") {
3661
+ ["create", "update", "delete"].forEach((e) => {
3662
+ this.addHandler(e, callback);
3663
+ });
3664
+ } else {
3665
+ this.addHandler(mappedEvent, callback);
3666
+ }
3667
+ return this;
3668
+ }
3669
+ mapEvent(event) {
3670
+ switch (event.toUpperCase()) {
3671
+ case "INSERT":
3672
+ return "create";
3673
+ case "UPDATE":
3674
+ return "update";
3675
+ case "DELETE":
3676
+ return "delete";
3677
+ default:
3678
+ return "*";
3679
+ }
3680
+ }
3681
+ addHandler(event, callback) {
3682
+ if (!this.handlers.has(event)) {
3683
+ this.handlers.set(event, []);
3684
+ }
3685
+ this.handlers.get(event).push(callback);
3686
+ }
3687
+ /**
3688
+ * Start the subscription
3689
+ */
3690
+ subscribe() {
3691
+ this.unsubscribeFn = this.realtime.subscribe(this.collection, (payload) => {
3692
+ const handlers = this.handlers.get(payload.action);
3693
+ if (handlers) {
3694
+ handlers.forEach((handler) => {
3695
+ try {
3696
+ handler(payload);
3697
+ } catch (error) {
3698
+ console.error("[Baasix Channel] Handler error:", error);
3699
+ }
3700
+ });
3701
+ }
3702
+ });
3703
+ return this;
3704
+ }
3705
+ /**
3706
+ * Stop the subscription
3707
+ */
3708
+ unsubscribe() {
3709
+ if (this.unsubscribeFn) {
3710
+ this.unsubscribeFn();
3711
+ this.unsubscribeFn = null;
3712
+ }
3713
+ this.handlers.clear();
3714
+ }
3715
+ };
3716
+
3717
+ // src/modules/roles.ts
3718
+ var RolesModule = class {
3719
+ client;
3720
+ collection = "baasix_Role";
3721
+ constructor(config) {
3722
+ this.client = config.client;
3723
+ }
3724
+ /**
3725
+ * Get all roles
3726
+ *
3727
+ * @example
3728
+ * ```typescript
3729
+ * const { data: roles } = await baasix.roles.find();
3730
+ * ```
3731
+ */
3732
+ async find() {
3733
+ return this.client.get(
3734
+ `/items/${this.collection}`,
3735
+ {
3736
+ params: { limit: -1 }
3737
+ }
3738
+ );
3739
+ }
3740
+ /**
3741
+ * Get a role by ID
3742
+ *
3743
+ * @example
3744
+ * ```typescript
3745
+ * const role = await baasix.roles.findOne('role-uuid');
3746
+ * ```
3747
+ */
3748
+ async findOne(id) {
3749
+ const response = await this.client.get(
3750
+ `/items/${this.collection}/${id}`
3751
+ );
3752
+ return response.data;
3753
+ }
3754
+ /**
3755
+ * Get a role by name
3756
+ *
3757
+ * @example
3758
+ * ```typescript
3759
+ * const role = await baasix.roles.findByName('Administrator');
3760
+ * ```
3761
+ */
3762
+ async findByName(name) {
3763
+ const response = await this.client.get(
3764
+ `/items/${this.collection}`,
3765
+ {
3766
+ params: {
3767
+ filter: JSON.stringify({ name: { eq: name } }),
3768
+ limit: 1
3769
+ }
3770
+ }
3771
+ );
3772
+ return response.data[0] || null;
3773
+ }
3774
+ /**
3775
+ * Create a new role
3776
+ *
3777
+ * @example
3778
+ * ```typescript
3779
+ * const id = await baasix.roles.create({
3780
+ * name: 'Editor',
3781
+ * description: 'Content editor role',
3782
+ * appAccess: true
3783
+ * });
3784
+ * ```
3785
+ */
3786
+ async create(data) {
3787
+ const response = await this.client.post(
3788
+ `/items/${this.collection}`,
3789
+ data
3790
+ );
3791
+ return response.data.id;
3792
+ }
3793
+ /**
3794
+ * Update a role
3795
+ *
3796
+ * @example
3797
+ * ```typescript
3798
+ * await baasix.roles.update('role-uuid', {
3799
+ * description: 'Updated description'
3800
+ * });
3801
+ * ```
3802
+ */
3803
+ async update(id, data) {
3804
+ await this.client.patch(`/items/${this.collection}/${id}`, data);
3805
+ }
3806
+ /**
3807
+ * Delete a role
3808
+ *
3809
+ * @example
3810
+ * ```typescript
3811
+ * await baasix.roles.delete('role-uuid');
3812
+ * ```
3813
+ */
3814
+ async delete(id) {
3815
+ await this.client.delete(`/items/${this.collection}/${id}`);
3816
+ }
3817
+ };
3818
+
3819
+ // src/modules/users.ts
3820
+ var UsersModule = class {
3821
+ client;
3822
+ collection = "baasix_User";
3823
+ constructor(config) {
3824
+ this.client = config.client;
3825
+ }
3826
+ /**
3827
+ * Get all users with optional filtering
3828
+ *
3829
+ * @example
3830
+ * ```typescript
3831
+ * const { data: users } = await baasix.users.find({
3832
+ * filter: { status: { eq: 'active' } },
3833
+ * limit: 20
3834
+ * });
3835
+ * ```
3836
+ */
3837
+ async find(options = {}) {
3838
+ const params = {};
3839
+ if (options.filter) {
3840
+ params.filter = JSON.stringify(options.filter);
3841
+ }
3842
+ if (options.sort) {
3843
+ params.sort = options.sort;
3844
+ }
3845
+ if (options.limit !== void 0) {
3846
+ params.limit = options.limit;
3847
+ }
3848
+ if (options.page !== void 0) {
3849
+ params.page = options.page;
3850
+ }
3851
+ if (options.fields?.length) {
3852
+ params.fields = options.fields.join(",");
3853
+ }
3854
+ return this.client.get(
3855
+ `/items/${this.collection}`,
3856
+ { params }
3857
+ );
3858
+ }
3859
+ /**
3860
+ * Get a user by ID
3861
+ *
3862
+ * @example
3863
+ * ```typescript
3864
+ * const user = await baasix.users.findOne('user-uuid');
3865
+ * ```
3866
+ */
3867
+ async findOne(id, fields) {
3868
+ const params = {};
3869
+ if (fields?.length) {
3870
+ params.fields = fields.join(",");
3871
+ }
3872
+ const response = await this.client.get(
3873
+ `/items/${this.collection}/${id}`,
3874
+ { params }
3875
+ );
3876
+ return response.data;
3877
+ }
3878
+ /**
3879
+ * Get a user by email
3880
+ *
3881
+ * @example
3882
+ * ```typescript
3883
+ * const user = await baasix.users.findByEmail('user@example.com');
3884
+ * ```
3885
+ */
3886
+ async findByEmail(email) {
3887
+ const response = await this.client.get(
3888
+ `/items/${this.collection}`,
3889
+ {
3890
+ params: {
3891
+ filter: JSON.stringify({ email: { eq: email } }),
3892
+ limit: 1
3893
+ }
3894
+ }
3895
+ );
3896
+ return response.data[0] || null;
3897
+ }
3898
+ /**
3899
+ * Create a new user
3900
+ *
3901
+ * @example
3902
+ * ```typescript
3903
+ * const id = await baasix.users.create({
3904
+ * email: 'user@example.com',
3905
+ * password: 'securepassword',
3906
+ * firstName: 'John',
3907
+ * lastName: 'Doe',
3908
+ * role_Id: 'role-uuid'
3909
+ * });
3910
+ * ```
3911
+ */
3912
+ async create(data) {
3913
+ const response = await this.client.post(
3914
+ `/items/${this.collection}`,
3915
+ data
3916
+ );
3917
+ return response.data.id;
3918
+ }
3919
+ /**
3920
+ * Update a user
3921
+ *
3922
+ * @example
3923
+ * ```typescript
3924
+ * await baasix.users.update('user-uuid', {
3925
+ * firstName: 'Jane'
3926
+ * });
3927
+ * ```
3928
+ */
3929
+ async update(id, data) {
3930
+ await this.client.patch(`/items/${this.collection}/${id}`, data);
3931
+ }
3932
+ /**
3933
+ * Delete a user
3934
+ *
3935
+ * @example
3936
+ * ```typescript
3937
+ * await baasix.users.delete('user-uuid');
3938
+ * ```
3939
+ */
3940
+ async delete(id) {
3941
+ await this.client.delete(`/items/${this.collection}/${id}`);
3942
+ }
3943
+ /**
3944
+ * Change a user's password (admin operation)
3945
+ *
3946
+ * @example
3947
+ * ```typescript
3948
+ * await baasix.users.changePassword('user-uuid', 'newpassword');
3949
+ * ```
3950
+ */
3951
+ async changePassword(userId, newPassword) {
3952
+ await this.client.post("/auth/admin/change-password", {
3953
+ userId,
3954
+ password: newPassword
3955
+ });
3956
+ }
3957
+ /**
3958
+ * Suspend a user
3959
+ *
3960
+ * @example
3961
+ * ```typescript
3962
+ * await baasix.users.suspend('user-uuid');
3963
+ * ```
3964
+ */
3965
+ async suspend(id) {
3966
+ await this.client.patch(`/items/${this.collection}/${id}`, {
3967
+ status: "suspended"
3968
+ });
3969
+ }
3970
+ /**
3971
+ * Activate a user
3972
+ *
3973
+ * @example
3974
+ * ```typescript
3975
+ * await baasix.users.activate('user-uuid');
3976
+ * ```
3977
+ */
3978
+ async activate(id) {
3979
+ await this.client.patch(`/items/${this.collection}/${id}`, {
3980
+ status: "active"
3981
+ });
3982
+ }
3983
+ /**
3984
+ * Bulk create users
3985
+ *
3986
+ * @example
3987
+ * ```typescript
3988
+ * const ids = await baasix.users.createMany([
3989
+ * { email: 'user1@example.com', firstName: 'User 1' },
3990
+ * { email: 'user2@example.com', firstName: 'User 2' }
3991
+ * ]);
3992
+ * ```
3993
+ */
3994
+ async createMany(users) {
3995
+ const response = await this.client.post(
3996
+ `/items/${this.collection}/bulk`,
3997
+ users
3998
+ );
3999
+ return response.data;
4000
+ }
4001
+ /**
4002
+ * Bulk delete users
4003
+ *
4004
+ * @example
4005
+ * ```typescript
4006
+ * await baasix.users.deleteMany(['user-uuid-1', 'user-uuid-2']);
4007
+ * ```
4008
+ */
4009
+ async deleteMany(ids) {
4010
+ await this.client.delete(`/items/${this.collection}/bulk`, {
4011
+ body: JSON.stringify(ids)
4012
+ });
4013
+ }
4014
+ };
4015
+
4016
+ // src/modules/migrations.ts
4017
+ var MigrationsModule = class {
4018
+ client;
4019
+ constructor(config) {
4020
+ this.client = config.client;
4021
+ }
4022
+ /**
4023
+ * Get migration status
4024
+ *
4025
+ * @example
4026
+ * ```typescript
4027
+ * const status = await baasix.migrations.status();
4028
+ * console.log(`Pending migrations: ${status.pendingCount}`);
4029
+ * ```
4030
+ */
4031
+ async status() {
4032
+ const response = await this.client.get(
4033
+ "/migrations/status"
4034
+ );
4035
+ return response.data;
4036
+ }
4037
+ /**
4038
+ * Get all migrations with optional filtering
4039
+ *
4040
+ * @example
4041
+ * ```typescript
4042
+ * // Get all migrations
4043
+ * const migrations = await baasix.migrations.list();
4044
+ *
4045
+ * // Get completed migrations
4046
+ * const completed = await baasix.migrations.list({ status: 'completed' });
4047
+ * ```
4048
+ */
4049
+ async list(options) {
4050
+ const response = await this.client.get("/migrations", {
4051
+ params: options
4052
+ });
4053
+ return response.data;
4054
+ }
4055
+ /**
4056
+ * Get pending migrations
4057
+ *
4058
+ * @example
4059
+ * ```typescript
4060
+ * const pending = await baasix.migrations.pending();
4061
+ * ```
4062
+ */
4063
+ async pending() {
4064
+ const response = await this.client.get(
4065
+ "/migrations/pending"
4066
+ );
4067
+ return response.data;
4068
+ }
4069
+ /**
4070
+ * Check if migrations are needed
4071
+ *
4072
+ * @example
4073
+ * ```typescript
4074
+ * const check = await baasix.migrations.check();
4075
+ * if (check.hasPending) {
4076
+ * console.log('Migrations needed');
4077
+ * }
4078
+ * ```
4079
+ */
4080
+ async check() {
4081
+ const response = await this.client.get(
4082
+ "/migrations/check"
4083
+ );
4084
+ return response.data;
4085
+ }
4086
+ /**
4087
+ * Get a specific migration by version
4088
+ *
4089
+ * @example
4090
+ * ```typescript
4091
+ * const migration = await baasix.migrations.get('20231201000000');
4092
+ * ```
4093
+ */
4094
+ async get(version) {
4095
+ try {
4096
+ const response = await this.client.get(
4097
+ `/migrations/${encodeURIComponent(version)}`
4098
+ );
4099
+ return response.data;
4100
+ } catch {
4101
+ return null;
4102
+ }
4103
+ }
4104
+ /**
4105
+ * Run pending migrations
4106
+ *
4107
+ * @example
4108
+ * ```typescript
4109
+ * // Run all pending migrations
4110
+ * const result = await baasix.migrations.run();
4111
+ *
4112
+ * // Run with options
4113
+ * const result = await baasix.migrations.run({
4114
+ * step: 1, // Run only 1 migration
4115
+ * dryRun: true // Preview without executing
4116
+ * });
4117
+ * ```
4118
+ */
4119
+ async run(options) {
4120
+ const response = await this.client.post(
4121
+ "/migrations/run",
4122
+ options || {}
4123
+ );
4124
+ return response.data;
4125
+ }
4126
+ /**
4127
+ * Rollback a specific migration
4128
+ *
4129
+ * @example
4130
+ * ```typescript
4131
+ * const result = await baasix.migrations.rollback('20231201000000');
4132
+ * ```
4133
+ */
4134
+ async rollback(version) {
4135
+ const response = await this.client.post(
4136
+ `/migrations/rollback/${encodeURIComponent(version)}`,
4137
+ {}
4138
+ );
4139
+ return response.data;
4140
+ }
4141
+ /**
4142
+ * Rollback the last batch of migrations
4143
+ *
4144
+ * @example
4145
+ * ```typescript
4146
+ * const result = await baasix.migrations.rollbackBatch();
4147
+ * ```
4148
+ */
4149
+ async rollbackBatch() {
4150
+ const response = await this.client.post(
4151
+ "/migrations/rollback-batch",
4152
+ {}
4153
+ );
4154
+ return response.data;
4155
+ }
4156
+ /**
4157
+ * Create a new migration file
4158
+ *
4159
+ * @example
4160
+ * ```typescript
4161
+ * const { filepath } = await baasix.migrations.create('add_status_column', {
4162
+ * type: 'schema',
4163
+ * description: 'Add status column to orders'
4164
+ * });
4165
+ * ```
4166
+ */
4167
+ async create(name, options) {
4168
+ const response = await this.client.post(
4169
+ "/migrations/create",
4170
+ { name, ...options }
4171
+ );
4172
+ return response.data;
4173
+ }
4174
+ /**
4175
+ * Mark a specific migration as completed without running it
4176
+ * Useful for existing installations that already have the changes
4177
+ *
4178
+ * @example
4179
+ * ```typescript
4180
+ * await baasix.migrations.markCompleted('20231201000000');
4181
+ * ```
4182
+ */
4183
+ async markCompleted(version, metadata) {
4184
+ const response = await this.client.post(
4185
+ `/migrations/mark-completed/${encodeURIComponent(version)}`,
4186
+ { metadata }
4187
+ );
4188
+ return response.data;
4189
+ }
4190
+ /**
4191
+ * Mark all pending migrations as completed
4192
+ * Useful for bringing an existing database up to date without running migrations
4193
+ *
4194
+ * @example
4195
+ * ```typescript
4196
+ * // Mark all pending
4197
+ * await baasix.migrations.markAllCompleted();
4198
+ *
4199
+ * // Mark up to a specific version
4200
+ * await baasix.migrations.markAllCompleted('20231201000000');
4201
+ * ```
4202
+ */
4203
+ async markAllCompleted(toVersion) {
4204
+ const response = await this.client.post(
4205
+ "/migrations/mark-all-completed",
4206
+ { toVersion }
4207
+ );
4208
+ return response.data;
4209
+ }
4210
+ };
4211
+
4212
+ // src/modules/server.ts
4213
+ var ServerModule = class {
4214
+ client;
4215
+ constructor(config) {
4216
+ this.client = config.client;
4217
+ }
4218
+ /**
4219
+ * Get server information including project settings
4220
+ *
4221
+ * @example
4222
+ * ```typescript
4223
+ * const info = await baasix.server.info();
4224
+ * console.log('Project:', info.project?.name);
4225
+ * console.log('Version:', info.version);
4226
+ * ```
4227
+ */
4228
+ async info() {
4229
+ return this.client.get("/");
4230
+ }
4231
+ /**
4232
+ * Check server health
4233
+ *
4234
+ * @example
4235
+ * ```typescript
4236
+ * const isHealthy = await baasix.server.health();
4237
+ * ```
4238
+ */
4239
+ async health() {
4240
+ try {
4241
+ await this.client.get("/health");
4242
+ return true;
4243
+ } catch {
4244
+ return false;
4245
+ }
4246
+ }
4247
+ };
4248
+
4249
+ // src/storage/asyncStorage.ts
4250
+ var AsyncStorageAdapter = class {
4251
+ asyncStorage;
4252
+ prefix;
4253
+ constructor(asyncStorage, prefix = "baasix_") {
4254
+ this.asyncStorage = asyncStorage;
4255
+ this.prefix = prefix;
4256
+ }
4257
+ getKey(key) {
4258
+ if (key.startsWith(this.prefix)) {
4259
+ return key;
4260
+ }
4261
+ return `${this.prefix}${key}`;
4262
+ }
4263
+ async get(key) {
4264
+ try {
4265
+ return await this.asyncStorage.getItem(this.getKey(key));
4266
+ } catch {
4267
+ console.warn(`[Baasix SDK] Failed to get item from AsyncStorage: ${key}`);
4268
+ return null;
4269
+ }
4270
+ }
4271
+ async set(key, value) {
4272
+ try {
4273
+ await this.asyncStorage.setItem(this.getKey(key), value);
4274
+ } catch {
4275
+ console.warn(`[Baasix SDK] Failed to set item in AsyncStorage: ${key}`);
4276
+ }
4277
+ }
4278
+ async remove(key) {
4279
+ try {
4280
+ await this.asyncStorage.removeItem(this.getKey(key));
4281
+ } catch {
4282
+ console.warn(`[Baasix SDK] Failed to remove item from AsyncStorage: ${key}`);
4283
+ }
4284
+ }
4285
+ async clear() {
4286
+ try {
4287
+ if (this.asyncStorage.getAllKeys && this.asyncStorage.multiRemove) {
4288
+ const allKeys = await this.asyncStorage.getAllKeys();
4289
+ const sdkKeys = allKeys.filter((key) => key.startsWith(this.prefix));
4290
+ if (sdkKeys.length > 0) {
4291
+ await this.asyncStorage.multiRemove(sdkKeys);
4292
+ }
4293
+ }
4294
+ } catch {
4295
+ console.warn("[Baasix SDK] Failed to clear AsyncStorage");
4296
+ }
4297
+ }
4298
+ };
4299
+
4300
+ // src/index.ts
4301
+ function getDefaultStorage() {
4302
+ if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
4303
+ return new LocalStorageAdapter();
4304
+ }
4305
+ return new MemoryStorageAdapter();
4306
+ }
4307
+ var Baasix = class {
4308
+ config;
4309
+ httpClient;
4310
+ storage;
4311
+ // Modules
4312
+ auth;
4313
+ files;
4314
+ schemas;
4315
+ notifications;
4316
+ permissions;
4317
+ settings;
4318
+ reports;
4319
+ workflows;
4320
+ realtime;
4321
+ roles;
4322
+ users;
4323
+ migrations;
4324
+ server;
4325
+ // Items module factory cache
4326
+ itemsModules = /* @__PURE__ */ new Map();
4327
+ constructor(config) {
4328
+ if (!config.url) {
4329
+ throw new Error("Baasix SDK: url is required");
4330
+ }
4331
+ const normalizedUrl = config.url.replace(/\/$/, "");
4332
+ this.config = {
4333
+ ...config,
4334
+ url: normalizedUrl,
4335
+ authMode: config.authMode || "jwt",
4336
+ timeout: config.timeout || 6e5,
4337
+ // 10 minutes default
4338
+ autoRefresh: config.autoRefresh !== false
4339
+ };
4340
+ this.storage = config.storage || getDefaultStorage();
4341
+ const credentials = config.credentials || (this.config.authMode === "cookie" ? "include" : "same-origin");
4342
+ this.httpClient = new HttpClient({
4343
+ baseUrl: normalizedUrl,
4344
+ authMode: this.config.authMode,
4345
+ storage: this.storage,
4346
+ timeout: this.config.timeout,
4347
+ autoRefresh: this.config.autoRefresh,
4348
+ credentials,
4349
+ headers: config.headers || {},
4350
+ token: config.token,
4351
+ tenantId: config.tenantId,
4352
+ onAuthError: () => {
4353
+ this.config.onAuthStateChange?.("SIGNED_OUT", null);
4354
+ },
4355
+ onTokenRefresh: () => {
4356
+ }
4357
+ });
4358
+ this.auth = new AuthModule({
4359
+ client: this.httpClient,
4360
+ storage: this.storage,
4361
+ authMode: this.config.authMode,
4362
+ onAuthStateChange: config.onAuthStateChange
4363
+ });
4364
+ this.files = new FilesModule({ client: this.httpClient });
4365
+ this.schemas = new SchemasModule({ client: this.httpClient });
4366
+ this.notifications = new NotificationsModule({ client: this.httpClient });
4367
+ this.permissions = new PermissionsModule({ client: this.httpClient });
4368
+ this.settings = new SettingsModule({ client: this.httpClient });
4369
+ this.reports = new ReportsModule({ client: this.httpClient });
4370
+ this.workflows = new WorkflowsModule({ client: this.httpClient });
4371
+ this.roles = new RolesModule({ client: this.httpClient });
4372
+ this.users = new UsersModule({ client: this.httpClient });
4373
+ this.migrations = new MigrationsModule({ client: this.httpClient });
4374
+ this.server = new ServerModule({ client: this.httpClient });
4375
+ this.realtime = new RealtimeModule({
4376
+ client: this.httpClient,
4377
+ storage: this.storage,
4378
+ socketUrl: config.socketUrl,
4379
+ socketPath: config.socketPath
4380
+ });
4381
+ }
4382
+ /**
4383
+ * Get an Items module for a specific collection.
4384
+ * Returns a cached instance for repeated calls with the same collection.
4385
+ *
4386
+ * @example
4387
+ * ```typescript
4388
+ * // Get items module
4389
+ * const products = baasix.items('products');
4390
+ *
4391
+ * // CRUD operations
4392
+ * const { data } = await products.find({ filter: { status: { eq: 'active' } } });
4393
+ * const product = await products.findOne('product-uuid');
4394
+ * const id = await products.create({ name: 'New Product', price: 29.99 });
4395
+ * await products.update('product-uuid', { price: 24.99 });
4396
+ * await products.delete('product-uuid');
4397
+ *
4398
+ * // Query builder
4399
+ * const results = await baasix.items('posts')
4400
+ * .query()
4401
+ * .select('*', 'author.*')
4402
+ * .filter({ status: { eq: 'published' } })
4403
+ * .sort({ createdAt: 'desc' })
4404
+ * .limit(10)
4405
+ * .get();
4406
+ * ```
4407
+ */
4408
+ items(collection) {
4409
+ if (!this.itemsModules.has(collection)) {
4410
+ this.itemsModules.set(
4411
+ collection,
4412
+ new ItemsModule(collection, { client: this.httpClient })
4413
+ );
4414
+ }
4415
+ return this.itemsModules.get(collection);
4416
+ }
4417
+ /**
4418
+ * Alias for items() - get a collection
4419
+ *
4420
+ * @example
4421
+ * ```typescript
4422
+ * const products = baasix.collection('products');
4423
+ * ```
4424
+ */
4425
+ collection(collection) {
4426
+ return this.items(collection);
4427
+ }
4428
+ /**
4429
+ * Alias for items() - from a collection (Supabase-style)
4430
+ *
4431
+ * @example
4432
+ * ```typescript
4433
+ * const products = baasix.from('products');
4434
+ * ```
4435
+ */
4436
+ from(collection) {
4437
+ return this.items(collection);
4438
+ }
4439
+ /**
4440
+ * Get the underlying HTTP client for custom requests
4441
+ *
4442
+ * @example
4443
+ * ```typescript
4444
+ * // Custom GET request
4445
+ * const data = await baasix.request.get('/custom-endpoint');
4446
+ *
4447
+ * // Custom POST request
4448
+ * const result = await baasix.request.post('/custom-endpoint', { data: 'value' });
4449
+ * ```
4450
+ */
4451
+ get request() {
4452
+ return this.httpClient;
4453
+ }
4454
+ /**
4455
+ * Update SDK configuration
4456
+ *
4457
+ * @example
4458
+ * ```typescript
4459
+ * baasix.configure({
4460
+ * headers: { 'X-Custom-Header': 'value' }
4461
+ * });
4462
+ * ```
4463
+ */
4464
+ configure(config) {
4465
+ if (config.headers) {
4466
+ this.httpClient.updateConfig({ headers: config.headers });
4467
+ }
4468
+ if (config.tenantId !== void 0) {
4469
+ this.httpClient.updateConfig({ tenantId: config.tenantId });
4470
+ }
4471
+ if (config.token) {
4472
+ this.httpClient.updateConfig({ token: config.token });
4473
+ }
4474
+ if (config.timeout) {
4475
+ this.httpClient.updateConfig({ timeout: config.timeout });
4476
+ }
4477
+ }
4478
+ /**
4479
+ * Set the tenant for multi-tenant mode
4480
+ *
4481
+ * @example
4482
+ * ```typescript
4483
+ * baasix.setTenant('tenant-uuid');
4484
+ * ```
4485
+ */
4486
+ async setTenant(tenantId) {
4487
+ this.httpClient.updateConfig({ tenantId });
4488
+ await this.storage.set(STORAGE_KEYS.TENANT, tenantId);
4489
+ }
4490
+ /**
4491
+ * Get the current tenant ID
4492
+ */
4493
+ async getTenant() {
4494
+ return await this.storage.get(STORAGE_KEYS.TENANT);
4495
+ }
4496
+ /**
4497
+ * Clear the tenant
4498
+ */
4499
+ async clearTenant() {
4500
+ this.httpClient.updateConfig({ tenantId: void 0 });
4501
+ await this.storage.remove(STORAGE_KEYS.TENANT);
4502
+ }
4503
+ /**
4504
+ * Set a static token (convenience method that delegates to auth.setToken)
4505
+ *
4506
+ * @example
4507
+ * ```typescript
4508
+ * baasix.setToken('your-api-token');
4509
+ * ```
4510
+ */
4511
+ async setToken(token) {
4512
+ return this.auth.setToken(token);
4513
+ }
4514
+ /**
4515
+ * Get the current auth token
4516
+ */
4517
+ async getToken() {
4518
+ return this.storage.get(STORAGE_KEYS.ACCESS_TOKEN);
4519
+ }
4520
+ /**
4521
+ * Get the base URL
4522
+ */
4523
+ getUrl() {
4524
+ return this.config.url;
4525
+ }
4526
+ /**
4527
+ * Get the current auth mode
4528
+ */
4529
+ getAuthMode() {
4530
+ return this.config.authMode;
4531
+ }
4532
+ /**
4533
+ * Get the storage adapter
4534
+ */
4535
+ getStorage() {
4536
+ return this.storage;
4537
+ }
4538
+ };
4539
+ function createBaasix(config) {
4540
+ return new Baasix(config);
4541
+ }
4542
+
4543
+ exports.AsyncStorageAdapter = AsyncStorageAdapter;
4544
+ exports.AuthModule = AuthModule;
4545
+ exports.Baasix = Baasix;
4546
+ exports.BaasixError = BaasixError;
4547
+ exports.FilesModule = FilesModule;
4548
+ exports.HttpClient = HttpClient;
4549
+ exports.ItemsModule = ItemsModule;
4550
+ exports.LocalStorageAdapter = LocalStorageAdapter;
4551
+ exports.MemoryStorageAdapter = MemoryStorageAdapter;
4552
+ exports.MigrationsModule = MigrationsModule;
4553
+ exports.NotificationsModule = NotificationsModule;
4554
+ exports.PermissionsModule = PermissionsModule;
4555
+ exports.QueryBuilder = QueryBuilder;
4556
+ exports.RealtimeChannel = RealtimeChannel;
4557
+ exports.RealtimeModule = RealtimeModule;
4558
+ exports.ReportsModule = ReportsModule;
4559
+ exports.RolesModule = RolesModule;
4560
+ exports.STORAGE_KEYS = STORAGE_KEYS;
4561
+ exports.SchemasModule = SchemasModule;
4562
+ exports.SettingsModule = SettingsModule;
4563
+ exports.UsersModule = UsersModule;
4564
+ exports.WorkflowsModule = WorkflowsModule;
4565
+ exports.createBaasix = createBaasix;
4566
+ //# sourceMappingURL=index.cjs.map
4567
+ //# sourceMappingURL=index.cjs.map