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