@tspvivek/baasix-sdk 0.1.0-alpha.1

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