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