@fluxbase/sdk 0.0.1-rc.10

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.
package/dist/index.js ADDED
@@ -0,0 +1,3764 @@
1
+ // src/fetch.ts
2
+ var FluxbaseFetch = class {
3
+ constructor(baseUrl, options = {}) {
4
+ this.baseUrl = baseUrl.replace(/\/$/, "");
5
+ this.defaultHeaders = {
6
+ "Content-Type": "application/json",
7
+ ...options.headers
8
+ };
9
+ this.timeout = options.timeout ?? 3e4;
10
+ this.debug = options.debug ?? false;
11
+ }
12
+ /**
13
+ * Update the authorization header
14
+ */
15
+ setAuthToken(token) {
16
+ if (token) {
17
+ this.defaultHeaders["Authorization"] = `Bearer ${token}`;
18
+ } else {
19
+ delete this.defaultHeaders["Authorization"];
20
+ }
21
+ }
22
+ /**
23
+ * Make an HTTP request
24
+ */
25
+ async request(path, options) {
26
+ const url = `${this.baseUrl}${path}`;
27
+ const headers = { ...this.defaultHeaders, ...options.headers };
28
+ const controller = new AbortController();
29
+ const timeoutId = setTimeout(() => controller.abort(), options.timeout ?? this.timeout);
30
+ if (this.debug) {
31
+ console.log(`[Fluxbase SDK] ${options.method} ${url}`, options.body);
32
+ }
33
+ try {
34
+ const response = await fetch(url, {
35
+ method: options.method,
36
+ headers,
37
+ body: options.body ? JSON.stringify(options.body) : void 0,
38
+ signal: controller.signal
39
+ });
40
+ clearTimeout(timeoutId);
41
+ const contentType = response.headers.get("content-type");
42
+ let data;
43
+ if (contentType?.includes("application/json")) {
44
+ data = await response.json();
45
+ } else {
46
+ data = await response.text();
47
+ }
48
+ if (this.debug) {
49
+ console.log(`[Fluxbase SDK] Response:`, response.status, data);
50
+ }
51
+ if (!response.ok) {
52
+ const error = new Error(
53
+ typeof data === "object" && data && "error" in data ? String(data.error) : response.statusText
54
+ );
55
+ error.status = response.status;
56
+ error.details = data;
57
+ throw error;
58
+ }
59
+ return data;
60
+ } catch (err) {
61
+ clearTimeout(timeoutId);
62
+ if (err instanceof Error) {
63
+ if (err.name === "AbortError") {
64
+ const timeoutError = new Error("Request timeout");
65
+ timeoutError.status = 408;
66
+ throw timeoutError;
67
+ }
68
+ throw err;
69
+ }
70
+ throw new Error("Unknown error occurred");
71
+ }
72
+ }
73
+ /**
74
+ * GET request
75
+ */
76
+ async get(path, options = {}) {
77
+ return this.request(path, { ...options, method: "GET" });
78
+ }
79
+ /**
80
+ * POST request
81
+ */
82
+ async post(path, body, options = {}) {
83
+ return this.request(path, { ...options, method: "POST", body });
84
+ }
85
+ /**
86
+ * PUT request
87
+ */
88
+ async put(path, body, options = {}) {
89
+ return this.request(path, { ...options, method: "PUT", body });
90
+ }
91
+ /**
92
+ * PATCH request
93
+ */
94
+ async patch(path, body, options = {}) {
95
+ return this.request(path, { ...options, method: "PATCH", body });
96
+ }
97
+ /**
98
+ * DELETE request
99
+ */
100
+ async delete(path, options = {}) {
101
+ return this.request(path, { ...options, method: "DELETE" });
102
+ }
103
+ /**
104
+ * HEAD request
105
+ */
106
+ async head(path, options = {}) {
107
+ const url = `${this.baseUrl}${path}`;
108
+ const headers = { ...this.defaultHeaders, ...options.headers };
109
+ const response = await fetch(url, {
110
+ method: "HEAD",
111
+ headers
112
+ });
113
+ return response.headers;
114
+ }
115
+ };
116
+
117
+ // src/auth.ts
118
+ var AUTH_STORAGE_KEY = "fluxbase.auth.session";
119
+ var FluxbaseAuth = class {
120
+ constructor(fetch2, autoRefresh = true, persist = true) {
121
+ this.session = null;
122
+ this.refreshTimer = null;
123
+ this.stateChangeListeners = /* @__PURE__ */ new Set();
124
+ this.fetch = fetch2;
125
+ this.persist = persist;
126
+ this.autoRefresh = autoRefresh;
127
+ if (this.persist && typeof localStorage !== "undefined") {
128
+ const stored = localStorage.getItem(AUTH_STORAGE_KEY);
129
+ if (stored) {
130
+ try {
131
+ this.session = JSON.parse(stored);
132
+ if (this.session) {
133
+ this.fetch.setAuthToken(this.session.access_token);
134
+ this.scheduleTokenRefresh();
135
+ }
136
+ } catch {
137
+ localStorage.removeItem(AUTH_STORAGE_KEY);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ /**
143
+ * Get the current session
144
+ */
145
+ getSession() {
146
+ return this.session;
147
+ }
148
+ /**
149
+ * Get the current user
150
+ */
151
+ getUser() {
152
+ return this.session?.user ?? null;
153
+ }
154
+ /**
155
+ * Get the current access token
156
+ */
157
+ getAccessToken() {
158
+ return this.session?.access_token ?? null;
159
+ }
160
+ /**
161
+ * Listen to auth state changes
162
+ * @param callback - Function called when auth state changes
163
+ * @returns Subscription object with unsubscribe method
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * const { data: { subscription } } = client.auth.onAuthStateChange((event, session) => {
168
+ * console.log('Auth event:', event, session)
169
+ * })
170
+ *
171
+ * // Later, to unsubscribe:
172
+ * subscription.unsubscribe()
173
+ * ```
174
+ */
175
+ onAuthStateChange(callback) {
176
+ this.stateChangeListeners.add(callback);
177
+ return {
178
+ unsubscribe: () => {
179
+ this.stateChangeListeners.delete(callback);
180
+ }
181
+ };
182
+ }
183
+ /**
184
+ * Sign in with email and password
185
+ * Returns AuthSession if successful, or SignInWith2FAResponse if 2FA is required
186
+ */
187
+ async signIn(credentials) {
188
+ const response = await this.fetch.post(
189
+ "/api/v1/auth/signin",
190
+ credentials
191
+ );
192
+ if ("requires_2fa" in response && response.requires_2fa) {
193
+ return response;
194
+ }
195
+ const authResponse = response;
196
+ const session = {
197
+ ...authResponse,
198
+ expires_at: Date.now() + authResponse.expires_in * 1e3
199
+ };
200
+ this.setSession(session);
201
+ return session;
202
+ }
203
+ /**
204
+ * Sign up with email and password
205
+ */
206
+ async signUp(credentials) {
207
+ const response = await this.fetch.post("/api/v1/auth/signup", credentials);
208
+ const session = {
209
+ ...response,
210
+ expires_at: Date.now() + response.expires_in * 1e3
211
+ };
212
+ this.setSession(session);
213
+ return session;
214
+ }
215
+ /**
216
+ * Sign out the current user
217
+ */
218
+ async signOut() {
219
+ try {
220
+ await this.fetch.post("/api/v1/auth/signout");
221
+ } finally {
222
+ this.clearSession();
223
+ }
224
+ }
225
+ /**
226
+ * Refresh the access token
227
+ */
228
+ async refreshToken() {
229
+ if (!this.session?.refresh_token) {
230
+ throw new Error("No refresh token available");
231
+ }
232
+ const response = await this.fetch.post("/api/v1/auth/refresh", {
233
+ refresh_token: this.session.refresh_token
234
+ });
235
+ const session = {
236
+ ...response,
237
+ expires_at: Date.now() + response.expires_in * 1e3
238
+ };
239
+ this.setSession(session, "TOKEN_REFRESHED");
240
+ return session;
241
+ }
242
+ /**
243
+ * Get the current user from the server
244
+ */
245
+ async getCurrentUser() {
246
+ if (!this.session) {
247
+ throw new Error("Not authenticated");
248
+ }
249
+ return await this.fetch.get("/api/v1/auth/user");
250
+ }
251
+ /**
252
+ * Update the current user
253
+ */
254
+ async updateUser(data) {
255
+ if (!this.session) {
256
+ throw new Error("Not authenticated");
257
+ }
258
+ const user = await this.fetch.patch("/api/v1/auth/user", data);
259
+ if (this.session) {
260
+ this.session.user = user;
261
+ this.saveSession();
262
+ this.emitAuthChange("USER_UPDATED", this.session);
263
+ }
264
+ return user;
265
+ }
266
+ /**
267
+ * Set the auth token manually
268
+ */
269
+ setToken(token) {
270
+ this.fetch.setAuthToken(token);
271
+ }
272
+ /**
273
+ * Setup 2FA for the current user
274
+ * Returns TOTP secret and QR code URL
275
+ */
276
+ async setup2FA() {
277
+ if (!this.session) {
278
+ throw new Error("Not authenticated");
279
+ }
280
+ return await this.fetch.post("/api/v1/auth/2fa/setup");
281
+ }
282
+ /**
283
+ * Enable 2FA after verifying the TOTP code
284
+ * Returns backup codes that should be saved by the user
285
+ */
286
+ async enable2FA(code) {
287
+ if (!this.session) {
288
+ throw new Error("Not authenticated");
289
+ }
290
+ return await this.fetch.post("/api/v1/auth/2fa/enable", { code });
291
+ }
292
+ /**
293
+ * Disable 2FA for the current user
294
+ * Requires password confirmation
295
+ */
296
+ async disable2FA(password) {
297
+ if (!this.session) {
298
+ throw new Error("Not authenticated");
299
+ }
300
+ return await this.fetch.post(
301
+ "/api/v1/auth/2fa/disable",
302
+ { password }
303
+ );
304
+ }
305
+ /**
306
+ * Check 2FA status for the current user
307
+ */
308
+ async get2FAStatus() {
309
+ if (!this.session) {
310
+ throw new Error("Not authenticated");
311
+ }
312
+ return await this.fetch.get("/api/v1/auth/2fa/status");
313
+ }
314
+ /**
315
+ * Verify 2FA code during login
316
+ * Call this after signIn returns requires_2fa: true
317
+ */
318
+ async verify2FA(request) {
319
+ const response = await this.fetch.post("/api/v1/auth/2fa/verify", request);
320
+ const session = {
321
+ ...response,
322
+ expires_at: Date.now() + response.expires_in * 1e3
323
+ };
324
+ this.setSession(session, "MFA_CHALLENGE_VERIFIED");
325
+ return session;
326
+ }
327
+ /**
328
+ * Send password reset email
329
+ * Sends a password reset link to the provided email address
330
+ * @param email - Email address to send reset link to
331
+ */
332
+ async sendPasswordReset(email) {
333
+ return await this.fetch.post("/api/v1/auth/password/reset", { email });
334
+ }
335
+ /**
336
+ * Verify password reset token
337
+ * Check if a password reset token is valid before allowing password reset
338
+ * @param token - Password reset token to verify
339
+ */
340
+ async verifyResetToken(token) {
341
+ return await this.fetch.post("/api/v1/auth/password/reset/verify", {
342
+ token
343
+ });
344
+ }
345
+ /**
346
+ * Reset password with token
347
+ * Complete the password reset process with a valid token
348
+ * @param token - Password reset token
349
+ * @param newPassword - New password to set
350
+ */
351
+ async resetPassword(token, newPassword) {
352
+ return await this.fetch.post("/api/v1/auth/password/reset/confirm", {
353
+ token,
354
+ new_password: newPassword
355
+ });
356
+ }
357
+ /**
358
+ * Send magic link for passwordless authentication
359
+ * @param email - Email address to send magic link to
360
+ * @param options - Optional configuration for magic link
361
+ */
362
+ async sendMagicLink(email, options) {
363
+ return await this.fetch.post("/api/v1/auth/magiclink", {
364
+ email,
365
+ redirect_to: options?.redirect_to
366
+ });
367
+ }
368
+ /**
369
+ * Verify magic link token and sign in
370
+ * @param token - Magic link token from email
371
+ */
372
+ async verifyMagicLink(token) {
373
+ const response = await this.fetch.post("/api/v1/auth/magiclink/verify", {
374
+ token
375
+ });
376
+ const session = {
377
+ ...response,
378
+ expires_at: Date.now() + response.expires_in * 1e3
379
+ };
380
+ this.setSession(session);
381
+ return session;
382
+ }
383
+ /**
384
+ * Sign in anonymously
385
+ * Creates a temporary anonymous user session
386
+ */
387
+ async signInAnonymously() {
388
+ const response = await this.fetch.post("/api/v1/auth/signin/anonymous");
389
+ const session = {
390
+ ...response,
391
+ expires_at: Date.now() + response.expires_in * 1e3
392
+ };
393
+ this.setSession(session);
394
+ return session;
395
+ }
396
+ /**
397
+ * Get list of enabled OAuth providers
398
+ */
399
+ async getOAuthProviders() {
400
+ return await this.fetch.get("/api/v1/auth/oauth/providers");
401
+ }
402
+ /**
403
+ * Get OAuth authorization URL for a provider
404
+ * @param provider - OAuth provider name (e.g., 'google', 'github')
405
+ * @param options - Optional OAuth configuration
406
+ */
407
+ async getOAuthUrl(provider, options) {
408
+ const params = new URLSearchParams();
409
+ if (options?.redirect_to) {
410
+ params.append("redirect_to", options.redirect_to);
411
+ }
412
+ if (options?.scopes && options.scopes.length > 0) {
413
+ params.append("scopes", options.scopes.join(","));
414
+ }
415
+ const queryString = params.toString();
416
+ const url = queryString ? `/api/v1/auth/oauth/${provider}/authorize?${queryString}` : `/api/v1/auth/oauth/${provider}/authorize`;
417
+ const response = await this.fetch.get(url);
418
+ return response;
419
+ }
420
+ /**
421
+ * Exchange OAuth authorization code for session
422
+ * This is typically called in your OAuth callback handler
423
+ * @param code - Authorization code from OAuth callback
424
+ */
425
+ async exchangeCodeForSession(code) {
426
+ const response = await this.fetch.post("/api/v1/auth/oauth/callback", { code });
427
+ const session = {
428
+ ...response,
429
+ expires_at: Date.now() + response.expires_in * 1e3
430
+ };
431
+ this.setSession(session);
432
+ return session;
433
+ }
434
+ /**
435
+ * Convenience method to initiate OAuth sign-in
436
+ * Redirects the user to the OAuth provider's authorization page
437
+ * @param provider - OAuth provider name (e.g., 'google', 'github')
438
+ * @param options - Optional OAuth configuration
439
+ */
440
+ async signInWithOAuth(provider, options) {
441
+ const { url } = await this.getOAuthUrl(provider, options);
442
+ if (typeof window !== "undefined") {
443
+ window.location.href = url;
444
+ } else {
445
+ throw new Error("signInWithOAuth can only be called in a browser environment");
446
+ }
447
+ }
448
+ /**
449
+ * Internal: Set the session and persist it
450
+ */
451
+ setSession(session, event = "SIGNED_IN") {
452
+ this.session = session;
453
+ this.fetch.setAuthToken(session.access_token);
454
+ this.saveSession();
455
+ this.scheduleTokenRefresh();
456
+ this.emitAuthChange(event, session);
457
+ }
458
+ /**
459
+ * Internal: Clear the session
460
+ */
461
+ clearSession() {
462
+ this.session = null;
463
+ this.fetch.setAuthToken(null);
464
+ if (this.persist && typeof localStorage !== "undefined") {
465
+ localStorage.removeItem(AUTH_STORAGE_KEY);
466
+ }
467
+ if (this.refreshTimer) {
468
+ clearTimeout(this.refreshTimer);
469
+ this.refreshTimer = null;
470
+ }
471
+ this.emitAuthChange("SIGNED_OUT", null);
472
+ }
473
+ /**
474
+ * Internal: Save session to storage
475
+ */
476
+ saveSession() {
477
+ if (this.persist && typeof localStorage !== "undefined" && this.session) {
478
+ localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(this.session));
479
+ }
480
+ }
481
+ /**
482
+ * Internal: Schedule automatic token refresh
483
+ */
484
+ scheduleTokenRefresh() {
485
+ if (!this.autoRefresh || !this.session?.expires_at) {
486
+ return;
487
+ }
488
+ if (this.refreshTimer) {
489
+ clearTimeout(this.refreshTimer);
490
+ }
491
+ const refreshAt = this.session.expires_at - 60 * 1e3;
492
+ const delay = refreshAt - Date.now();
493
+ if (delay > 0) {
494
+ this.refreshTimer = setTimeout(() => {
495
+ this.refreshToken().catch((err) => {
496
+ console.error("Failed to refresh token:", err);
497
+ this.clearSession();
498
+ });
499
+ }, delay);
500
+ }
501
+ }
502
+ /**
503
+ * Internal: Emit auth state change event to all listeners
504
+ */
505
+ emitAuthChange(event, session) {
506
+ this.stateChangeListeners.forEach((callback) => {
507
+ try {
508
+ callback(event, session);
509
+ } catch (error) {
510
+ console.error("Error in auth state change listener:", error);
511
+ }
512
+ });
513
+ }
514
+ };
515
+
516
+ // src/realtime.ts
517
+ var RealtimeChannel = class {
518
+ constructor(url, channelName, token = null) {
519
+ this.ws = null;
520
+ this.callbacks = /* @__PURE__ */ new Map();
521
+ this.subscriptionConfig = null;
522
+ this.reconnectAttempts = 0;
523
+ this.maxReconnectAttempts = 10;
524
+ this.reconnectDelay = 1e3;
525
+ this.heartbeatInterval = null;
526
+ this.url = url;
527
+ this.channelName = channelName;
528
+ this.token = token;
529
+ }
530
+ // Implementation
531
+ on(event, configOrCallback, callback) {
532
+ if (event === "postgres_changes" && typeof configOrCallback !== "function") {
533
+ const config = configOrCallback;
534
+ this.subscriptionConfig = config;
535
+ const actualCallback = callback;
536
+ const eventType = config.event;
537
+ if (!this.callbacks.has(eventType)) {
538
+ this.callbacks.set(eventType, /* @__PURE__ */ new Set());
539
+ }
540
+ this.callbacks.get(eventType).add(actualCallback);
541
+ } else {
542
+ const actualEvent = event;
543
+ const actualCallback = configOrCallback;
544
+ if (!this.callbacks.has(actualEvent)) {
545
+ this.callbacks.set(actualEvent, /* @__PURE__ */ new Set());
546
+ }
547
+ this.callbacks.get(actualEvent).add(actualCallback);
548
+ }
549
+ return this;
550
+ }
551
+ /**
552
+ * Remove a callback
553
+ */
554
+ off(event, callback) {
555
+ const callbacks = this.callbacks.get(event);
556
+ if (callbacks) {
557
+ callbacks.delete(callback);
558
+ }
559
+ return this;
560
+ }
561
+ /**
562
+ * Subscribe to the channel
563
+ */
564
+ subscribe() {
565
+ this.connect();
566
+ return this;
567
+ }
568
+ /**
569
+ * Unsubscribe from the channel
570
+ */
571
+ unsubscribe() {
572
+ if (this.ws) {
573
+ this.send({
574
+ type: "unsubscribe",
575
+ channel: this.channelName
576
+ });
577
+ this.disconnect();
578
+ }
579
+ }
580
+ /**
581
+ * Internal: Connect to WebSocket
582
+ */
583
+ connect() {
584
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
585
+ return;
586
+ }
587
+ const wsUrl = new URL(this.url);
588
+ wsUrl.protocol = wsUrl.protocol === "https:" ? "wss:" : "ws:";
589
+ wsUrl.pathname = "/realtime";
590
+ if (this.token) {
591
+ wsUrl.searchParams.set("token", this.token);
592
+ }
593
+ this.ws = new WebSocket(wsUrl.toString());
594
+ this.ws.onopen = () => {
595
+ console.log("[Fluxbase Realtime] Connected");
596
+ this.reconnectAttempts = 0;
597
+ const subscribeMessage = {
598
+ type: "subscribe",
599
+ channel: this.channelName
600
+ };
601
+ if (this.subscriptionConfig) {
602
+ subscribeMessage.config = this.subscriptionConfig;
603
+ }
604
+ this.send(subscribeMessage);
605
+ this.startHeartbeat();
606
+ };
607
+ this.ws.onmessage = (event) => {
608
+ try {
609
+ const message = JSON.parse(event.data);
610
+ this.handleMessage(message);
611
+ } catch (err) {
612
+ console.error("[Fluxbase Realtime] Failed to parse message:", err);
613
+ }
614
+ };
615
+ this.ws.onerror = (error) => {
616
+ console.error("[Fluxbase Realtime] WebSocket error:", error);
617
+ };
618
+ this.ws.onclose = () => {
619
+ console.log("[Fluxbase Realtime] Disconnected");
620
+ this.stopHeartbeat();
621
+ this.attemptReconnect();
622
+ };
623
+ }
624
+ /**
625
+ * Internal: Disconnect WebSocket
626
+ */
627
+ disconnect() {
628
+ this.stopHeartbeat();
629
+ if (this.ws) {
630
+ this.ws.close();
631
+ this.ws = null;
632
+ }
633
+ }
634
+ /**
635
+ * Internal: Send a message
636
+ */
637
+ send(message) {
638
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
639
+ this.ws.send(JSON.stringify(message));
640
+ }
641
+ }
642
+ /**
643
+ * Internal: Handle incoming message
644
+ */
645
+ handleMessage(message) {
646
+ switch (message.type) {
647
+ case "heartbeat":
648
+ this.send({ type: "heartbeat" });
649
+ break;
650
+ case "broadcast":
651
+ if (message.payload) {
652
+ this.handleBroadcast(message.payload);
653
+ }
654
+ break;
655
+ case "ack":
656
+ console.log("[Fluxbase Realtime] Subscription acknowledged");
657
+ break;
658
+ case "error":
659
+ console.error("[Fluxbase Realtime] Error:", message.error);
660
+ break;
661
+ }
662
+ }
663
+ /**
664
+ * Internal: Handle broadcast message
665
+ */
666
+ handleBroadcast(payload) {
667
+ const callbacks = this.callbacks.get(payload.type);
668
+ if (callbacks) {
669
+ callbacks.forEach((callback) => callback(payload));
670
+ }
671
+ const wildcardCallbacks = this.callbacks.get("*");
672
+ if (wildcardCallbacks) {
673
+ wildcardCallbacks.forEach((callback) => callback(payload));
674
+ }
675
+ }
676
+ /**
677
+ * Internal: Start heartbeat interval
678
+ */
679
+ startHeartbeat() {
680
+ this.heartbeatInterval = setInterval(() => {
681
+ this.send({ type: "heartbeat" });
682
+ }, 3e4);
683
+ }
684
+ /**
685
+ * Internal: Stop heartbeat interval
686
+ */
687
+ stopHeartbeat() {
688
+ if (this.heartbeatInterval) {
689
+ clearInterval(this.heartbeatInterval);
690
+ this.heartbeatInterval = null;
691
+ }
692
+ }
693
+ /**
694
+ * Internal: Attempt to reconnect
695
+ */
696
+ attemptReconnect() {
697
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
698
+ console.error("[Fluxbase Realtime] Max reconnect attempts reached");
699
+ return;
700
+ }
701
+ this.reconnectAttempts++;
702
+ const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
703
+ console.log(`[Fluxbase Realtime] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
704
+ setTimeout(() => {
705
+ this.connect();
706
+ }, delay);
707
+ }
708
+ };
709
+ var FluxbaseRealtime = class {
710
+ constructor(url, token = null) {
711
+ this.channels = /* @__PURE__ */ new Map();
712
+ this.url = url;
713
+ this.token = token;
714
+ }
715
+ /**
716
+ * Create or get a channel
717
+ * @param channelName - Channel name (e.g., 'table:public.products')
718
+ */
719
+ channel(channelName) {
720
+ if (this.channels.has(channelName)) {
721
+ return this.channels.get(channelName);
722
+ }
723
+ const channel = new RealtimeChannel(this.url, channelName, this.token);
724
+ this.channels.set(channelName, channel);
725
+ return channel;
726
+ }
727
+ /**
728
+ * Remove all channels
729
+ */
730
+ removeAllChannels() {
731
+ this.channels.forEach((channel) => channel.unsubscribe());
732
+ this.channels.clear();
733
+ }
734
+ /**
735
+ * Update auth token for all channels
736
+ */
737
+ setToken(token) {
738
+ this.token = token;
739
+ }
740
+ };
741
+
742
+ // src/storage.ts
743
+ var StorageBucket = class {
744
+ constructor(fetch2, bucketName) {
745
+ this.fetch = fetch2;
746
+ this.bucketName = bucketName;
747
+ }
748
+ /**
749
+ * Upload a file to the bucket
750
+ * @param path - The path/key for the file
751
+ * @param file - The file to upload (File, Blob, or ArrayBuffer)
752
+ * @param options - Upload options
753
+ */
754
+ async upload(path, file, options) {
755
+ try {
756
+ const formData = new FormData();
757
+ const blob = file instanceof ArrayBuffer ? new Blob([file]) : file;
758
+ formData.append("file", blob);
759
+ if (options?.contentType) {
760
+ formData.append("content_type", options.contentType);
761
+ }
762
+ if (options?.metadata) {
763
+ formData.append("metadata", JSON.stringify(options.metadata));
764
+ }
765
+ if (options?.cacheControl) {
766
+ formData.append("cache_control", options.cacheControl);
767
+ }
768
+ if (options?.upsert !== void 0) {
769
+ formData.append("upsert", String(options.upsert));
770
+ }
771
+ const data = await this.fetch.request(
772
+ `/api/v1/storage/${this.bucketName}/${path}`,
773
+ {
774
+ method: "POST",
775
+ body: formData,
776
+ headers: {}
777
+ // Let browser set Content-Type for FormData
778
+ }
779
+ );
780
+ return { data, error: null };
781
+ } catch (error) {
782
+ return { data: null, error };
783
+ }
784
+ }
785
+ /**
786
+ * Download a file from the bucket
787
+ * @param path - The path/key of the file
788
+ */
789
+ async download(path) {
790
+ try {
791
+ const response = await fetch(
792
+ `${this.fetch["baseUrl"]}/api/v1/storage/${this.bucketName}/${path}`,
793
+ {
794
+ headers: this.fetch["defaultHeaders"]
795
+ }
796
+ );
797
+ if (!response.ok) {
798
+ throw new Error(`Failed to download file: ${response.statusText}`);
799
+ }
800
+ const blob = await response.blob();
801
+ return { data: blob, error: null };
802
+ } catch (error) {
803
+ return { data: null, error };
804
+ }
805
+ }
806
+ /**
807
+ * List files in the bucket
808
+ * @param options - List options (prefix, limit, offset)
809
+ */
810
+ async list(options) {
811
+ try {
812
+ const params = new URLSearchParams();
813
+ if (options?.prefix) {
814
+ params.set("prefix", options.prefix);
815
+ }
816
+ if (options?.limit) {
817
+ params.set("limit", String(options.limit));
818
+ }
819
+ if (options?.offset) {
820
+ params.set("offset", String(options.offset));
821
+ }
822
+ const queryString = params.toString();
823
+ const path = `/api/v1/storage/${this.bucketName}${queryString ? `?${queryString}` : ""}`;
824
+ const data = await this.fetch.get(path);
825
+ return { data: data.files || [], error: null };
826
+ } catch (error) {
827
+ return { data: null, error };
828
+ }
829
+ }
830
+ /**
831
+ * Remove files from the bucket
832
+ * @param paths - Array of file paths to remove
833
+ */
834
+ async remove(paths) {
835
+ try {
836
+ for (const path of paths) {
837
+ await this.fetch.delete(`/api/v1/storage/${this.bucketName}/${path}`);
838
+ }
839
+ return { data: null, error: null };
840
+ } catch (error) {
841
+ return { data: null, error };
842
+ }
843
+ }
844
+ /**
845
+ * Get a public URL for a file
846
+ * @param path - The file path
847
+ */
848
+ getPublicUrl(path) {
849
+ const publicUrl = `${this.fetch["baseUrl"]}/api/v1/storage/${this.bucketName}/${path}`;
850
+ return { data: { publicUrl } };
851
+ }
852
+ /**
853
+ * Create a signed URL for temporary access to a file
854
+ * @param path - The file path
855
+ * @param options - Signed URL options
856
+ */
857
+ async createSignedUrl(path, options) {
858
+ try {
859
+ const expiresIn = options?.expiresIn || 3600;
860
+ const data = await this.fetch.post(
861
+ `/api/v1/storage/${this.bucketName}/sign/${path}`,
862
+ { expires_in: expiresIn }
863
+ );
864
+ return { data: { signedUrl: data.signed_url }, error: null };
865
+ } catch (error) {
866
+ return { data: null, error };
867
+ }
868
+ }
869
+ /**
870
+ * Move a file to a new location
871
+ * @param fromPath - Current file path
872
+ * @param toPath - New file path
873
+ */
874
+ async move(fromPath, toPath) {
875
+ try {
876
+ const data = await this.fetch.post(
877
+ `/api/v1/storage/${this.bucketName}/move`,
878
+ {
879
+ from_path: fromPath,
880
+ to_path: toPath
881
+ }
882
+ );
883
+ return { data, error: null };
884
+ } catch (error) {
885
+ return { data: null, error };
886
+ }
887
+ }
888
+ /**
889
+ * Copy a file to a new location
890
+ * @param fromPath - Source file path
891
+ * @param toPath - Destination file path
892
+ */
893
+ async copy(fromPath, toPath) {
894
+ try {
895
+ const data = await this.fetch.post(
896
+ `/api/v1/storage/${this.bucketName}/copy`,
897
+ {
898
+ from_path: fromPath,
899
+ to_path: toPath
900
+ }
901
+ );
902
+ return { data, error: null };
903
+ } catch (error) {
904
+ return { data: null, error };
905
+ }
906
+ }
907
+ /**
908
+ * Share a file with another user (RLS)
909
+ * @param path - The file path
910
+ * @param options - Share options (userId and permission)
911
+ */
912
+ async share(path, options) {
913
+ try {
914
+ await this.fetch.post(
915
+ `/api/v1/storage/${this.bucketName}/${path}/share`,
916
+ {
917
+ user_id: options.userId,
918
+ permission: options.permission
919
+ }
920
+ );
921
+ return { data: null, error: null };
922
+ } catch (error) {
923
+ return { data: null, error };
924
+ }
925
+ }
926
+ /**
927
+ * Revoke file access from a user (RLS)
928
+ * @param path - The file path
929
+ * @param userId - The user ID to revoke access from
930
+ */
931
+ async revokeShare(path, userId) {
932
+ try {
933
+ await this.fetch.delete(
934
+ `/api/v1/storage/${this.bucketName}/${path}/share/${userId}`
935
+ );
936
+ return { data: null, error: null };
937
+ } catch (error) {
938
+ return { data: null, error };
939
+ }
940
+ }
941
+ /**
942
+ * List users a file is shared with (RLS)
943
+ * @param path - The file path
944
+ */
945
+ async listShares(path) {
946
+ try {
947
+ const data = await this.fetch.get(
948
+ `/api/v1/storage/${this.bucketName}/${path}/shares`
949
+ );
950
+ return { data: data.shares || [], error: null };
951
+ } catch (error) {
952
+ return { data: null, error };
953
+ }
954
+ }
955
+ };
956
+ var FluxbaseStorage = class {
957
+ constructor(fetch2) {
958
+ this.fetch = fetch2;
959
+ }
960
+ /**
961
+ * Get a reference to a storage bucket
962
+ * @param bucketName - The name of the bucket
963
+ */
964
+ from(bucketName) {
965
+ return new StorageBucket(this.fetch, bucketName);
966
+ }
967
+ /**
968
+ * List all buckets
969
+ */
970
+ async listBuckets() {
971
+ try {
972
+ const data = await this.fetch.get("/api/v1/storage/buckets");
973
+ return { data: data.buckets || [], error: null };
974
+ } catch (error) {
975
+ return { data: null, error };
976
+ }
977
+ }
978
+ /**
979
+ * Create a new bucket
980
+ * @param bucketName - The name of the bucket to create
981
+ */
982
+ async createBucket(bucketName) {
983
+ try {
984
+ await this.fetch.post(`/api/v1/storage/buckets/${bucketName}`);
985
+ return { data: null, error: null };
986
+ } catch (error) {
987
+ return { data: null, error };
988
+ }
989
+ }
990
+ /**
991
+ * Delete a bucket
992
+ * @param bucketName - The name of the bucket to delete
993
+ */
994
+ async deleteBucket(bucketName) {
995
+ try {
996
+ await this.fetch.delete(`/api/v1/storage/buckets/${bucketName}`);
997
+ return { data: null, error: null };
998
+ } catch (error) {
999
+ return { data: null, error };
1000
+ }
1001
+ }
1002
+ /**
1003
+ * Empty a bucket (delete all files)
1004
+ * @param bucketName - The name of the bucket to empty
1005
+ */
1006
+ async emptyBucket(bucketName) {
1007
+ try {
1008
+ const bucket = this.from(bucketName);
1009
+ const { data: objects, error: listError } = await bucket.list();
1010
+ if (listError) {
1011
+ return { data: null, error: listError };
1012
+ }
1013
+ if (objects && objects.length > 0) {
1014
+ const paths = objects.map((obj) => obj.key);
1015
+ const { error: removeError } = await bucket.remove(paths);
1016
+ if (removeError) {
1017
+ return { data: null, error: removeError };
1018
+ }
1019
+ }
1020
+ return { data: null, error: null };
1021
+ } catch (error) {
1022
+ return { data: null, error };
1023
+ }
1024
+ }
1025
+ /**
1026
+ * Update bucket settings (RLS - requires admin or service key)
1027
+ * @param bucketName - The name of the bucket
1028
+ * @param settings - Bucket settings to update
1029
+ */
1030
+ async updateBucketSettings(bucketName, settings) {
1031
+ try {
1032
+ await this.fetch.put(`/api/v1/storage/buckets/${bucketName}`, settings);
1033
+ return { data: null, error: null };
1034
+ } catch (error) {
1035
+ return { data: null, error };
1036
+ }
1037
+ }
1038
+ /**
1039
+ * Get bucket details
1040
+ * @param bucketName - The name of the bucket
1041
+ */
1042
+ async getBucket(bucketName) {
1043
+ try {
1044
+ const data = await this.fetch.get(
1045
+ `/api/v1/storage/buckets/${bucketName}`
1046
+ );
1047
+ return { data, error: null };
1048
+ } catch (error) {
1049
+ return { data: null, error };
1050
+ }
1051
+ }
1052
+ };
1053
+
1054
+ // src/settings.ts
1055
+ var SystemSettingsManager = class {
1056
+ constructor(fetch2) {
1057
+ this.fetch = fetch2;
1058
+ }
1059
+ /**
1060
+ * List all system settings
1061
+ *
1062
+ * @returns Promise resolving to ListSystemSettingsResponse
1063
+ *
1064
+ * @example
1065
+ * ```typescript
1066
+ * const response = await client.admin.settings.system.list()
1067
+ * console.log(response.settings)
1068
+ * ```
1069
+ */
1070
+ async list() {
1071
+ const settings = await this.fetch.get(
1072
+ "/api/v1/admin/system/settings"
1073
+ );
1074
+ return { settings: Array.isArray(settings) ? settings : [] };
1075
+ }
1076
+ /**
1077
+ * Get a specific system setting by key
1078
+ *
1079
+ * @param key - Setting key (e.g., 'app.auth.enable_signup')
1080
+ * @returns Promise resolving to SystemSetting
1081
+ *
1082
+ * @example
1083
+ * ```typescript
1084
+ * const setting = await client.admin.settings.system.get('app.auth.enable_signup')
1085
+ * console.log(setting.value)
1086
+ * ```
1087
+ */
1088
+ async get(key) {
1089
+ return await this.fetch.get(
1090
+ `/api/v1/admin/system/settings/${key}`
1091
+ );
1092
+ }
1093
+ /**
1094
+ * Update or create a system setting
1095
+ *
1096
+ * @param key - Setting key
1097
+ * @param request - Update request with value and optional description
1098
+ * @returns Promise resolving to SystemSetting
1099
+ *
1100
+ * @example
1101
+ * ```typescript
1102
+ * const updated = await client.admin.settings.system.update('app.auth.enable_signup', {
1103
+ * value: { value: true },
1104
+ * description: 'Enable user signup'
1105
+ * })
1106
+ * ```
1107
+ */
1108
+ async update(key, request) {
1109
+ return await this.fetch.put(
1110
+ `/api/v1/admin/system/settings/${key}`,
1111
+ request
1112
+ );
1113
+ }
1114
+ /**
1115
+ * Delete a system setting
1116
+ *
1117
+ * @param key - Setting key to delete
1118
+ * @returns Promise<void>
1119
+ *
1120
+ * @example
1121
+ * ```typescript
1122
+ * await client.admin.settings.system.delete('app.auth.enable_signup')
1123
+ * ```
1124
+ */
1125
+ async delete(key) {
1126
+ await this.fetch.delete(`/api/v1/admin/system/settings/${key}`);
1127
+ }
1128
+ };
1129
+ var AppSettingsManager = class {
1130
+ constructor(fetch2) {
1131
+ this.fetch = fetch2;
1132
+ }
1133
+ /**
1134
+ * Get all application settings
1135
+ *
1136
+ * Returns structured settings for authentication, features, email, and security.
1137
+ *
1138
+ * @returns Promise resolving to AppSettings
1139
+ *
1140
+ * @example
1141
+ * ```typescript
1142
+ * const settings = await client.admin.settings.app.get()
1143
+ *
1144
+ * console.log('Signup enabled:', settings.authentication.enable_signup)
1145
+ * console.log('Realtime enabled:', settings.features.enable_realtime)
1146
+ * console.log('Email provider:', settings.email.provider)
1147
+ * ```
1148
+ */
1149
+ async get() {
1150
+ return await this.fetch.get("/api/v1/admin/app/settings");
1151
+ }
1152
+ /**
1153
+ * Update application settings
1154
+ *
1155
+ * Supports partial updates - only provide the fields you want to change.
1156
+ *
1157
+ * @param request - Settings to update (partial update supported)
1158
+ * @returns Promise resolving to AppSettings - Updated settings
1159
+ *
1160
+ * @example
1161
+ * ```typescript
1162
+ * // Update authentication settings
1163
+ * const updated = await client.admin.settings.app.update({
1164
+ * authentication: {
1165
+ * enable_signup: true,
1166
+ * password_min_length: 12
1167
+ * }
1168
+ * })
1169
+ *
1170
+ * // Update multiple categories
1171
+ * await client.admin.settings.app.update({
1172
+ * authentication: { enable_signup: false },
1173
+ * features: { enable_realtime: true },
1174
+ * security: { enable_global_rate_limit: true }
1175
+ * })
1176
+ * ```
1177
+ */
1178
+ async update(request) {
1179
+ return await this.fetch.put(
1180
+ "/api/v1/admin/app/settings",
1181
+ request
1182
+ );
1183
+ }
1184
+ /**
1185
+ * Reset all application settings to defaults
1186
+ *
1187
+ * This will delete all custom settings and return to default values.
1188
+ *
1189
+ * @returns Promise resolving to AppSettings - Default settings
1190
+ *
1191
+ * @example
1192
+ * ```typescript
1193
+ * const defaults = await client.admin.settings.app.reset()
1194
+ * console.log('Settings reset to defaults:', defaults)
1195
+ * ```
1196
+ */
1197
+ async reset() {
1198
+ return await this.fetch.post(
1199
+ "/api/v1/admin/app/settings/reset",
1200
+ {}
1201
+ );
1202
+ }
1203
+ /**
1204
+ * Enable user signup
1205
+ *
1206
+ * Convenience method to enable user registration.
1207
+ *
1208
+ * @returns Promise resolving to AppSettings
1209
+ *
1210
+ * @example
1211
+ * ```typescript
1212
+ * await client.admin.settings.app.enableSignup()
1213
+ * ```
1214
+ */
1215
+ async enableSignup() {
1216
+ return await this.update({
1217
+ authentication: { enable_signup: true }
1218
+ });
1219
+ }
1220
+ /**
1221
+ * Disable user signup
1222
+ *
1223
+ * Convenience method to disable user registration.
1224
+ *
1225
+ * @returns Promise resolving to AppSettings
1226
+ *
1227
+ * @example
1228
+ * ```typescript
1229
+ * await client.admin.settings.app.disableSignup()
1230
+ * ```
1231
+ */
1232
+ async disableSignup() {
1233
+ return await this.update({
1234
+ authentication: { enable_signup: false }
1235
+ });
1236
+ }
1237
+ /**
1238
+ * Update password minimum length
1239
+ *
1240
+ * Convenience method to set password requirements.
1241
+ *
1242
+ * @param length - Minimum password length (8-128 characters)
1243
+ * @returns Promise resolving to AppSettings
1244
+ *
1245
+ * @example
1246
+ * ```typescript
1247
+ * await client.admin.settings.app.setPasswordMinLength(12)
1248
+ * ```
1249
+ */
1250
+ async setPasswordMinLength(length) {
1251
+ if (length < 8 || length > 128) {
1252
+ throw new Error(
1253
+ "Password minimum length must be between 8 and 128 characters"
1254
+ );
1255
+ }
1256
+ return await this.update({
1257
+ authentication: { password_min_length: length }
1258
+ });
1259
+ }
1260
+ /**
1261
+ * Enable or disable a feature
1262
+ *
1263
+ * Convenience method to toggle feature flags.
1264
+ *
1265
+ * @param feature - Feature name ('realtime' | 'storage' | 'functions')
1266
+ * @param enabled - Whether to enable or disable the feature
1267
+ * @returns Promise resolving to AppSettings
1268
+ *
1269
+ * @example
1270
+ * ```typescript
1271
+ * // Enable realtime
1272
+ * await client.admin.settings.app.setFeature('realtime', true)
1273
+ *
1274
+ * // Disable storage
1275
+ * await client.admin.settings.app.setFeature('storage', false)
1276
+ * ```
1277
+ */
1278
+ async setFeature(feature, enabled) {
1279
+ const featureKey = feature === "realtime" ? "enable_realtime" : feature === "storage" ? "enable_storage" : "enable_functions";
1280
+ return await this.update({
1281
+ features: { [featureKey]: enabled }
1282
+ });
1283
+ }
1284
+ /**
1285
+ * Enable or disable global rate limiting
1286
+ *
1287
+ * Convenience method to toggle global rate limiting.
1288
+ *
1289
+ * @param enabled - Whether to enable rate limiting
1290
+ * @returns Promise resolving to AppSettings
1291
+ *
1292
+ * @example
1293
+ * ```typescript
1294
+ * await client.admin.settings.app.setRateLimiting(true)
1295
+ * ```
1296
+ */
1297
+ async setRateLimiting(enabled) {
1298
+ return await this.update({
1299
+ security: { enable_global_rate_limit: enabled }
1300
+ });
1301
+ }
1302
+ /**
1303
+ * Configure SMTP email provider
1304
+ *
1305
+ * Convenience method to set up SMTP email delivery.
1306
+ *
1307
+ * @param config - SMTP configuration
1308
+ * @returns Promise resolving to AppSettings
1309
+ *
1310
+ * @example
1311
+ * ```typescript
1312
+ * await client.admin.settings.app.configureSMTP({
1313
+ * host: 'smtp.gmail.com',
1314
+ * port: 587,
1315
+ * username: 'your-email@gmail.com',
1316
+ * password: 'your-app-password',
1317
+ * use_tls: true,
1318
+ * from_address: 'noreply@yourapp.com',
1319
+ * from_name: 'Your App'
1320
+ * })
1321
+ * ```
1322
+ */
1323
+ async configureSMTP(config) {
1324
+ return await this.update({
1325
+ email: {
1326
+ enabled: true,
1327
+ provider: "smtp",
1328
+ from_address: config.from_address,
1329
+ from_name: config.from_name,
1330
+ reply_to_address: config.reply_to_address,
1331
+ smtp: {
1332
+ host: config.host,
1333
+ port: config.port,
1334
+ username: config.username,
1335
+ password: config.password,
1336
+ use_tls: config.use_tls
1337
+ }
1338
+ }
1339
+ });
1340
+ }
1341
+ /**
1342
+ * Configure SendGrid email provider
1343
+ *
1344
+ * Convenience method to set up SendGrid email delivery.
1345
+ *
1346
+ * @param apiKey - SendGrid API key
1347
+ * @param options - Optional from address, name, and reply-to
1348
+ * @returns Promise resolving to AppSettings
1349
+ *
1350
+ * @example
1351
+ * ```typescript
1352
+ * await client.admin.settings.app.configureSendGrid('SG.xxx', {
1353
+ * from_address: 'noreply@yourapp.com',
1354
+ * from_name: 'Your App'
1355
+ * })
1356
+ * ```
1357
+ */
1358
+ async configureSendGrid(apiKey, options) {
1359
+ return await this.update({
1360
+ email: {
1361
+ enabled: true,
1362
+ provider: "sendgrid",
1363
+ from_address: options?.from_address,
1364
+ from_name: options?.from_name,
1365
+ reply_to_address: options?.reply_to_address,
1366
+ sendgrid: {
1367
+ api_key: apiKey
1368
+ }
1369
+ }
1370
+ });
1371
+ }
1372
+ /**
1373
+ * Configure Mailgun email provider
1374
+ *
1375
+ * Convenience method to set up Mailgun email delivery.
1376
+ *
1377
+ * @param apiKey - Mailgun API key
1378
+ * @param domain - Mailgun domain
1379
+ * @param options - Optional EU region flag and email addresses
1380
+ * @returns Promise resolving to AppSettings
1381
+ *
1382
+ * @example
1383
+ * ```typescript
1384
+ * await client.admin.settings.app.configureMailgun('key-xxx', 'mg.yourapp.com', {
1385
+ * eu_region: false,
1386
+ * from_address: 'noreply@yourapp.com',
1387
+ * from_name: 'Your App'
1388
+ * })
1389
+ * ```
1390
+ */
1391
+ async configureMailgun(apiKey, domain, options) {
1392
+ return await this.update({
1393
+ email: {
1394
+ enabled: true,
1395
+ provider: "mailgun",
1396
+ from_address: options?.from_address,
1397
+ from_name: options?.from_name,
1398
+ reply_to_address: options?.reply_to_address,
1399
+ mailgun: {
1400
+ api_key: apiKey,
1401
+ domain,
1402
+ eu_region: options?.eu_region ?? false
1403
+ }
1404
+ }
1405
+ });
1406
+ }
1407
+ /**
1408
+ * Configure AWS SES email provider
1409
+ *
1410
+ * Convenience method to set up AWS SES email delivery.
1411
+ *
1412
+ * @param accessKeyId - AWS access key ID
1413
+ * @param secretAccessKey - AWS secret access key
1414
+ * @param region - AWS region (e.g., 'us-east-1')
1415
+ * @param options - Optional email addresses
1416
+ * @returns Promise resolving to AppSettings
1417
+ *
1418
+ * @example
1419
+ * ```typescript
1420
+ * await client.admin.settings.app.configureSES(
1421
+ * 'AKIAIOSFODNN7EXAMPLE',
1422
+ * 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
1423
+ * 'us-east-1',
1424
+ * {
1425
+ * from_address: 'noreply@yourapp.com',
1426
+ * from_name: 'Your App'
1427
+ * }
1428
+ * )
1429
+ * ```
1430
+ */
1431
+ async configureSES(accessKeyId, secretAccessKey, region, options) {
1432
+ return await this.update({
1433
+ email: {
1434
+ enabled: true,
1435
+ provider: "ses",
1436
+ from_address: options?.from_address,
1437
+ from_name: options?.from_name,
1438
+ reply_to_address: options?.reply_to_address,
1439
+ ses: {
1440
+ access_key_id: accessKeyId,
1441
+ secret_access_key: secretAccessKey,
1442
+ region
1443
+ }
1444
+ }
1445
+ });
1446
+ }
1447
+ /**
1448
+ * Enable or disable email functionality
1449
+ *
1450
+ * Convenience method to toggle email system on/off.
1451
+ *
1452
+ * @param enabled - Whether to enable email
1453
+ * @returns Promise resolving to AppSettings
1454
+ *
1455
+ * @example
1456
+ * ```typescript
1457
+ * await client.admin.settings.app.setEmailEnabled(true)
1458
+ * ```
1459
+ */
1460
+ async setEmailEnabled(enabled) {
1461
+ return await this.update({
1462
+ email: { enabled }
1463
+ });
1464
+ }
1465
+ /**
1466
+ * Configure password complexity requirements
1467
+ *
1468
+ * Convenience method to set password validation rules.
1469
+ *
1470
+ * @param requirements - Password complexity requirements
1471
+ * @returns Promise resolving to AppSettings
1472
+ *
1473
+ * @example
1474
+ * ```typescript
1475
+ * await client.admin.settings.app.setPasswordComplexity({
1476
+ * min_length: 12,
1477
+ * require_uppercase: true,
1478
+ * require_lowercase: true,
1479
+ * require_number: true,
1480
+ * require_special: true
1481
+ * })
1482
+ * ```
1483
+ */
1484
+ async setPasswordComplexity(requirements) {
1485
+ return await this.update({
1486
+ authentication: {
1487
+ password_min_length: requirements.min_length,
1488
+ password_require_uppercase: requirements.require_uppercase,
1489
+ password_require_lowercase: requirements.require_lowercase,
1490
+ password_require_number: requirements.require_number,
1491
+ password_require_special: requirements.require_special
1492
+ }
1493
+ });
1494
+ }
1495
+ /**
1496
+ * Configure session settings
1497
+ *
1498
+ * Convenience method to set session timeout and limits.
1499
+ *
1500
+ * @param timeoutMinutes - Session timeout in minutes (0 for no timeout)
1501
+ * @param maxSessionsPerUser - Maximum concurrent sessions per user (0 for unlimited)
1502
+ * @returns Promise resolving to AppSettings
1503
+ *
1504
+ * @example
1505
+ * ```typescript
1506
+ * // 30 minute sessions, max 3 devices per user
1507
+ * await client.admin.settings.app.setSessionSettings(30, 3)
1508
+ * ```
1509
+ */
1510
+ async setSessionSettings(timeoutMinutes, maxSessionsPerUser) {
1511
+ return await this.update({
1512
+ authentication: {
1513
+ session_timeout_minutes: timeoutMinutes,
1514
+ max_sessions_per_user: maxSessionsPerUser
1515
+ }
1516
+ });
1517
+ }
1518
+ /**
1519
+ * Enable or disable email verification requirement
1520
+ *
1521
+ * Convenience method to require email verification for new signups.
1522
+ *
1523
+ * @param required - Whether to require email verification
1524
+ * @returns Promise resolving to AppSettings
1525
+ *
1526
+ * @example
1527
+ * ```typescript
1528
+ * await client.admin.settings.app.setEmailVerificationRequired(true)
1529
+ * ```
1530
+ */
1531
+ async setEmailVerificationRequired(required) {
1532
+ return await this.update({
1533
+ authentication: { require_email_verification: required }
1534
+ });
1535
+ }
1536
+ };
1537
+ var CustomSettingsManager = class {
1538
+ constructor(fetch2) {
1539
+ this.fetch = fetch2;
1540
+ }
1541
+ /**
1542
+ * Create a new custom setting
1543
+ *
1544
+ * @param request - Custom setting creation request
1545
+ * @returns Promise resolving to CustomSetting
1546
+ *
1547
+ * @example
1548
+ * ```typescript
1549
+ * const setting = await client.admin.settings.custom.create({
1550
+ * key: 'api.quotas',
1551
+ * value: { free: 1000, pro: 10000, enterprise: 100000 },
1552
+ * value_type: 'json',
1553
+ * description: 'API request quotas by tier',
1554
+ * metadata: { category: 'billing' }
1555
+ * })
1556
+ * ```
1557
+ */
1558
+ async create(request) {
1559
+ return await this.fetch.post(
1560
+ "/api/v1/admin/settings/custom",
1561
+ request
1562
+ );
1563
+ }
1564
+ /**
1565
+ * List all custom settings
1566
+ *
1567
+ * @returns Promise resolving to ListCustomSettingsResponse
1568
+ *
1569
+ * @example
1570
+ * ```typescript
1571
+ * const response = await client.admin.settings.custom.list()
1572
+ * console.log(response.settings)
1573
+ * ```
1574
+ */
1575
+ async list() {
1576
+ const settings = await this.fetch.get(
1577
+ "/api/v1/admin/settings/custom"
1578
+ );
1579
+ return { settings: Array.isArray(settings) ? settings : [] };
1580
+ }
1581
+ /**
1582
+ * Get a specific custom setting by key
1583
+ *
1584
+ * @param key - Setting key (e.g., 'feature.dark_mode')
1585
+ * @returns Promise resolving to CustomSetting
1586
+ *
1587
+ * @example
1588
+ * ```typescript
1589
+ * const setting = await client.admin.settings.custom.get('feature.dark_mode')
1590
+ * console.log(setting.value)
1591
+ * ```
1592
+ */
1593
+ async get(key) {
1594
+ return await this.fetch.get(
1595
+ `/api/v1/admin/settings/custom/${key}`
1596
+ );
1597
+ }
1598
+ /**
1599
+ * Update an existing custom setting
1600
+ *
1601
+ * @param key - Setting key
1602
+ * @param request - Update request with new values
1603
+ * @returns Promise resolving to CustomSetting
1604
+ *
1605
+ * @example
1606
+ * ```typescript
1607
+ * const updated = await client.admin.settings.custom.update('feature.dark_mode', {
1608
+ * value: { enabled: false },
1609
+ * description: 'Updated description'
1610
+ * })
1611
+ * ```
1612
+ */
1613
+ async update(key, request) {
1614
+ return await this.fetch.put(
1615
+ `/api/v1/admin/settings/custom/${key}`,
1616
+ request
1617
+ );
1618
+ }
1619
+ /**
1620
+ * Delete a custom setting
1621
+ *
1622
+ * @param key - Setting key to delete
1623
+ * @returns Promise<void>
1624
+ *
1625
+ * @example
1626
+ * ```typescript
1627
+ * await client.admin.settings.custom.delete('feature.dark_mode')
1628
+ * ```
1629
+ */
1630
+ async delete(key) {
1631
+ await this.fetch.delete(`/api/v1/admin/settings/custom/${key}`);
1632
+ }
1633
+ };
1634
+ var EmailTemplateManager = class {
1635
+ constructor(fetch2) {
1636
+ this.fetch = fetch2;
1637
+ }
1638
+ /**
1639
+ * List all email templates
1640
+ *
1641
+ * @returns Promise resolving to ListEmailTemplatesResponse
1642
+ *
1643
+ * @example
1644
+ * ```typescript
1645
+ * const response = await client.admin.emailTemplates.list()
1646
+ * console.log(response.templates)
1647
+ * ```
1648
+ */
1649
+ async list() {
1650
+ const templates = await this.fetch.get(
1651
+ "/api/v1/admin/email/templates"
1652
+ );
1653
+ return { templates: Array.isArray(templates) ? templates : [] };
1654
+ }
1655
+ /**
1656
+ * Get a specific email template by type
1657
+ *
1658
+ * @param type - Template type (magic_link | verify_email | reset_password | invite_user)
1659
+ * @returns Promise resolving to EmailTemplate
1660
+ *
1661
+ * @example
1662
+ * ```typescript
1663
+ * const template = await client.admin.emailTemplates.get('magic_link')
1664
+ * console.log(template.subject)
1665
+ * console.log(template.html_body)
1666
+ * ```
1667
+ */
1668
+ async get(type) {
1669
+ return await this.fetch.get(
1670
+ `/api/v1/admin/email/templates/${type}`
1671
+ );
1672
+ }
1673
+ /**
1674
+ * Update an email template
1675
+ *
1676
+ * Available template variables:
1677
+ * - magic_link: `{{.MagicLink}}`, `{{.AppName}}`, `{{.ExpiryMinutes}}`
1678
+ * - verify_email: `{{.VerificationLink}}`, `{{.AppName}}`
1679
+ * - reset_password: `{{.ResetLink}}`, `{{.AppName}}`, `{{.ExpiryMinutes}}`
1680
+ * - invite_user: `{{.InviteLink}}`, `{{.AppName}}`, `{{.InviterName}}`
1681
+ *
1682
+ * @param type - Template type to update
1683
+ * @param request - Update request with subject, html_body, and optional text_body
1684
+ * @returns Promise resolving to EmailTemplate
1685
+ *
1686
+ * @example
1687
+ * ```typescript
1688
+ * const updated = await client.admin.emailTemplates.update('magic_link', {
1689
+ * subject: 'Your Magic Link - Sign in to ' + '{{.AppName}}',
1690
+ * html_body: '<html><body><h1>Welcome!</h1><a href="' + '{{.MagicLink}}' + '">Sign In</a></body></html>',
1691
+ * text_body: 'Click here to sign in: ' + '{{.MagicLink}}'
1692
+ * })
1693
+ * ```
1694
+ */
1695
+ async update(type, request) {
1696
+ return await this.fetch.put(
1697
+ `/api/v1/admin/email/templates/${type}`,
1698
+ request
1699
+ );
1700
+ }
1701
+ /**
1702
+ * Reset an email template to default
1703
+ *
1704
+ * Removes any customizations and restores the template to its original state.
1705
+ *
1706
+ * @param type - Template type to reset
1707
+ * @returns Promise resolving to EmailTemplate - The default template
1708
+ *
1709
+ * @example
1710
+ * ```typescript
1711
+ * const defaultTemplate = await client.admin.emailTemplates.reset('magic_link')
1712
+ * ```
1713
+ */
1714
+ async reset(type) {
1715
+ return await this.fetch.post(
1716
+ `/api/v1/admin/email/templates/${type}/reset`,
1717
+ {}
1718
+ );
1719
+ }
1720
+ /**
1721
+ * Send a test email using the template
1722
+ *
1723
+ * Useful for previewing template changes before deploying to production.
1724
+ *
1725
+ * @param type - Template type to test
1726
+ * @param recipientEmail - Email address to send test to
1727
+ * @returns Promise<void>
1728
+ *
1729
+ * @example
1730
+ * ```typescript
1731
+ * await client.admin.emailTemplates.test('magic_link', 'test@example.com')
1732
+ * ```
1733
+ */
1734
+ async test(type, recipientEmail) {
1735
+ await this.fetch.post(`/api/v1/admin/email/templates/${type}/test`, {
1736
+ recipient_email: recipientEmail
1737
+ });
1738
+ }
1739
+ };
1740
+ var FluxbaseSettings = class {
1741
+ constructor(fetch2) {
1742
+ this.system = new SystemSettingsManager(fetch2);
1743
+ this.app = new AppSettingsManager(fetch2);
1744
+ this.custom = new CustomSettingsManager(fetch2);
1745
+ }
1746
+ };
1747
+
1748
+ // src/ddl.ts
1749
+ var DDLManager = class {
1750
+ constructor(fetch2) {
1751
+ this.fetch = fetch2;
1752
+ }
1753
+ /**
1754
+ * Create a new database schema
1755
+ *
1756
+ * Creates a new schema in the database. Schemas are used to organize tables
1757
+ * into logical groups and provide namespace isolation.
1758
+ *
1759
+ * @param name - Schema name (must be valid PostgreSQL identifier)
1760
+ * @returns Promise resolving to CreateSchemaResponse
1761
+ *
1762
+ * @example
1763
+ * ```typescript
1764
+ * // Create a schema for analytics data
1765
+ * const result = await client.admin.ddl.createSchema('analytics')
1766
+ * console.log(result.message) // "Schema created successfully"
1767
+ * console.log(result.schema) // "analytics"
1768
+ * ```
1769
+ */
1770
+ async createSchema(name) {
1771
+ const request = { name };
1772
+ return await this.fetch.post("/api/v1/admin/ddl/schemas", request);
1773
+ }
1774
+ /**
1775
+ * List all database schemas
1776
+ *
1777
+ * Retrieves a list of all schemas in the database. This includes both
1778
+ * system schemas (like 'public', 'pg_catalog') and user-created schemas.
1779
+ *
1780
+ * @returns Promise resolving to ListSchemasResponse
1781
+ *
1782
+ * @example
1783
+ * ```typescript
1784
+ * const { schemas } = await client.admin.ddl.listSchemas()
1785
+ *
1786
+ * schemas.forEach(schema => {
1787
+ * console.log(`Schema: ${schema.name}, Owner: ${schema.owner}`)
1788
+ * })
1789
+ * ```
1790
+ */
1791
+ async listSchemas() {
1792
+ return await this.fetch.get("/api/v1/admin/ddl/schemas");
1793
+ }
1794
+ /**
1795
+ * Create a new table in a schema
1796
+ *
1797
+ * Creates a new table with the specified columns. Supports various column
1798
+ * options including primary keys, nullability, data types, and default values.
1799
+ *
1800
+ * @param schema - Schema name where the table will be created
1801
+ * @param name - Table name (must be valid PostgreSQL identifier)
1802
+ * @param columns - Array of column definitions
1803
+ * @returns Promise resolving to CreateTableResponse
1804
+ *
1805
+ * @example
1806
+ * ```typescript
1807
+ * // Create a users table
1808
+ * await client.admin.ddl.createTable('public', 'users', [
1809
+ * {
1810
+ * name: 'id',
1811
+ * type: 'UUID',
1812
+ * primaryKey: true,
1813
+ * defaultValue: 'gen_random_uuid()'
1814
+ * },
1815
+ * {
1816
+ * name: 'email',
1817
+ * type: 'TEXT',
1818
+ * nullable: false
1819
+ * },
1820
+ * {
1821
+ * name: 'name',
1822
+ * type: 'TEXT'
1823
+ * },
1824
+ * {
1825
+ * name: 'created_at',
1826
+ * type: 'TIMESTAMPTZ',
1827
+ * nullable: false,
1828
+ * defaultValue: 'NOW()'
1829
+ * }
1830
+ * ])
1831
+ * ```
1832
+ *
1833
+ * @example
1834
+ * ```typescript
1835
+ * // Create a products table with JSONB metadata
1836
+ * await client.admin.ddl.createTable('public', 'products', [
1837
+ * { name: 'id', type: 'SERIAL', primaryKey: true },
1838
+ * { name: 'name', type: 'TEXT', nullable: false },
1839
+ * { name: 'price', type: 'DECIMAL(10,2)', nullable: false },
1840
+ * { name: 'metadata', type: 'JSONB' },
1841
+ * { name: 'in_stock', type: 'BOOLEAN', defaultValue: 'true' }
1842
+ * ])
1843
+ * ```
1844
+ */
1845
+ async createTable(schema, name, columns) {
1846
+ const request = { schema, name, columns };
1847
+ return await this.fetch.post("/api/v1/admin/ddl/tables", request);
1848
+ }
1849
+ /**
1850
+ * List all tables in the database or a specific schema
1851
+ *
1852
+ * Retrieves a list of all tables. If a schema is specified, only tables
1853
+ * from that schema are returned. Otherwise, all tables from all schemas
1854
+ * are returned.
1855
+ *
1856
+ * @param schema - Optional schema name to filter tables
1857
+ * @returns Promise resolving to ListTablesResponse
1858
+ *
1859
+ * @example
1860
+ * ```typescript
1861
+ * // List all tables in the public schema
1862
+ * const { tables } = await client.admin.ddl.listTables('public')
1863
+ *
1864
+ * tables.forEach(table => {
1865
+ * console.log(`Table: ${table.schema}.${table.name}`)
1866
+ * table.columns?.forEach(col => {
1867
+ * console.log(` - ${col.name}: ${col.type}`)
1868
+ * })
1869
+ * })
1870
+ * ```
1871
+ *
1872
+ * @example
1873
+ * ```typescript
1874
+ * // List all tables across all schemas
1875
+ * const { tables } = await client.admin.ddl.listTables()
1876
+ *
1877
+ * const tablesBySchema = tables.reduce((acc, table) => {
1878
+ * if (!acc[table.schema]) acc[table.schema] = []
1879
+ * acc[table.schema].push(table.name)
1880
+ * return acc
1881
+ * }, {} as Record<string, string[]>)
1882
+ *
1883
+ * console.log(tablesBySchema)
1884
+ * ```
1885
+ */
1886
+ async listTables(schema) {
1887
+ const params = schema ? `?schema=${encodeURIComponent(schema)}` : "";
1888
+ return await this.fetch.get(`/api/v1/admin/ddl/tables${params}`);
1889
+ }
1890
+ /**
1891
+ * Delete a table from a schema
1892
+ *
1893
+ * Permanently deletes a table and all its data. This operation cannot be undone.
1894
+ *
1895
+ * @param schema - Schema name containing the table
1896
+ * @param name - Table name to delete
1897
+ * @returns Promise resolving to DeleteTableResponse
1898
+ *
1899
+ * @example
1900
+ * ```typescript
1901
+ * // Delete a table
1902
+ * const result = await client.admin.ddl.deleteTable('public', 'old_data')
1903
+ * console.log(result.message) // "Table deleted successfully"
1904
+ * ```
1905
+ *
1906
+ * @example
1907
+ * ```typescript
1908
+ * // Safe deletion with confirmation
1909
+ * const confirm = await askUser('Are you sure you want to delete this table?')
1910
+ * if (confirm) {
1911
+ * await client.admin.ddl.deleteTable('analytics', 'events')
1912
+ * console.log('Table deleted')
1913
+ * }
1914
+ * ```
1915
+ */
1916
+ async deleteTable(schema, name) {
1917
+ return await this.fetch.delete(
1918
+ `/api/v1/admin/ddl/tables/${encodeURIComponent(schema)}/${encodeURIComponent(name)}`
1919
+ );
1920
+ }
1921
+ };
1922
+
1923
+ // src/oauth.ts
1924
+ var OAuthProviderManager = class {
1925
+ constructor(fetch2) {
1926
+ this.fetch = fetch2;
1927
+ }
1928
+ /**
1929
+ * List all OAuth providers
1930
+ *
1931
+ * Retrieves all configured OAuth providers including both enabled and disabled providers.
1932
+ * Note: Client secrets are not included in the response for security reasons.
1933
+ *
1934
+ * @returns Promise resolving to ListOAuthProvidersResponse
1935
+ *
1936
+ * @example
1937
+ * ```typescript
1938
+ * const { providers } = await client.admin.oauth.listProviders()
1939
+ *
1940
+ * providers.forEach(provider => {
1941
+ * console.log(`${provider.display_name}: ${provider.enabled ? 'enabled' : 'disabled'}`)
1942
+ * })
1943
+ * ```
1944
+ */
1945
+ async listProviders() {
1946
+ const providers = await this.fetch.get("/api/v1/admin/oauth/providers");
1947
+ return Array.isArray(providers) ? providers : [];
1948
+ }
1949
+ /**
1950
+ * Get a specific OAuth provider by ID
1951
+ *
1952
+ * Retrieves detailed configuration for a single OAuth provider.
1953
+ * Note: Client secret is not included in the response.
1954
+ *
1955
+ * @param providerId - Provider ID (UUID)
1956
+ * @returns Promise resolving to OAuthProvider
1957
+ *
1958
+ * @example
1959
+ * ```typescript
1960
+ * const provider = await client.admin.oauth.getProvider('provider-uuid')
1961
+ *
1962
+ * console.log('Provider:', provider.display_name)
1963
+ * console.log('Scopes:', provider.scopes.join(', '))
1964
+ * console.log('Redirect URL:', provider.redirect_url)
1965
+ * ```
1966
+ */
1967
+ async getProvider(providerId) {
1968
+ return await this.fetch.get(`/api/v1/admin/oauth/providers/${providerId}`);
1969
+ }
1970
+ /**
1971
+ * Create a new OAuth provider
1972
+ *
1973
+ * Creates a new OAuth provider configuration. For built-in providers (Google, GitHub, etc.),
1974
+ * set `is_custom` to false. For custom OAuth2 providers, set `is_custom` to true and provide
1975
+ * the authorization, token, and user info URLs.
1976
+ *
1977
+ * @param request - OAuth provider configuration
1978
+ * @returns Promise resolving to CreateOAuthProviderResponse
1979
+ *
1980
+ * @example
1981
+ * ```typescript
1982
+ * // Create GitHub provider
1983
+ * const result = await client.admin.oauth.createProvider({
1984
+ * provider_name: 'github',
1985
+ * display_name: 'GitHub',
1986
+ * enabled: true,
1987
+ * client_id: process.env.GITHUB_CLIENT_ID,
1988
+ * client_secret: process.env.GITHUB_CLIENT_SECRET,
1989
+ * redirect_url: 'https://yourapp.com/auth/callback',
1990
+ * scopes: ['user:email', 'read:user'],
1991
+ * is_custom: false
1992
+ * })
1993
+ *
1994
+ * console.log('Provider created:', result.id)
1995
+ * ```
1996
+ *
1997
+ * @example
1998
+ * ```typescript
1999
+ * // Create custom OAuth2 provider
2000
+ * await client.admin.oauth.createProvider({
2001
+ * provider_name: 'custom_sso',
2002
+ * display_name: 'Custom SSO',
2003
+ * enabled: true,
2004
+ * client_id: 'client-id',
2005
+ * client_secret: 'client-secret',
2006
+ * redirect_url: 'https://yourapp.com/auth/callback',
2007
+ * scopes: ['openid', 'profile', 'email'],
2008
+ * is_custom: true,
2009
+ * authorization_url: 'https://sso.example.com/oauth/authorize',
2010
+ * token_url: 'https://sso.example.com/oauth/token',
2011
+ * user_info_url: 'https://sso.example.com/oauth/userinfo'
2012
+ * })
2013
+ * ```
2014
+ */
2015
+ async createProvider(request) {
2016
+ return await this.fetch.post("/api/v1/admin/oauth/providers", request);
2017
+ }
2018
+ /**
2019
+ * Update an existing OAuth provider
2020
+ *
2021
+ * Updates an OAuth provider configuration. All fields are optional - only provided fields
2022
+ * will be updated. To update the client secret, provide a non-empty value.
2023
+ *
2024
+ * @param providerId - Provider ID (UUID)
2025
+ * @param request - Fields to update
2026
+ * @returns Promise resolving to UpdateOAuthProviderResponse
2027
+ *
2028
+ * @example
2029
+ * ```typescript
2030
+ * // Disable a provider
2031
+ * await client.admin.oauth.updateProvider('provider-id', {
2032
+ * enabled: false
2033
+ * })
2034
+ * ```
2035
+ *
2036
+ * @example
2037
+ * ```typescript
2038
+ * // Update scopes and redirect URL
2039
+ * await client.admin.oauth.updateProvider('provider-id', {
2040
+ * scopes: ['user:email', 'read:user', 'read:org'],
2041
+ * redirect_url: 'https://newdomain.com/auth/callback'
2042
+ * })
2043
+ * ```
2044
+ *
2045
+ * @example
2046
+ * ```typescript
2047
+ * // Rotate client secret
2048
+ * await client.admin.oauth.updateProvider('provider-id', {
2049
+ * client_id: 'new-client-id',
2050
+ * client_secret: 'new-client-secret'
2051
+ * })
2052
+ * ```
2053
+ */
2054
+ async updateProvider(providerId, request) {
2055
+ return await this.fetch.put(
2056
+ `/api/v1/admin/oauth/providers/${providerId}`,
2057
+ request
2058
+ );
2059
+ }
2060
+ /**
2061
+ * Delete an OAuth provider
2062
+ *
2063
+ * Permanently deletes an OAuth provider configuration. This will prevent users from
2064
+ * authenticating with this provider.
2065
+ *
2066
+ * @param providerId - Provider ID (UUID) to delete
2067
+ * @returns Promise resolving to DeleteOAuthProviderResponse
2068
+ *
2069
+ * @example
2070
+ * ```typescript
2071
+ * await client.admin.oauth.deleteProvider('provider-id')
2072
+ * console.log('Provider deleted')
2073
+ * ```
2074
+ *
2075
+ * @example
2076
+ * ```typescript
2077
+ * // Safe deletion with confirmation
2078
+ * const provider = await client.admin.oauth.getProvider('provider-id')
2079
+ * const confirmed = await confirm(`Delete ${provider.display_name}?`)
2080
+ *
2081
+ * if (confirmed) {
2082
+ * await client.admin.oauth.deleteProvider('provider-id')
2083
+ * }
2084
+ * ```
2085
+ */
2086
+ async deleteProvider(providerId) {
2087
+ return await this.fetch.delete(
2088
+ `/api/v1/admin/oauth/providers/${providerId}`
2089
+ );
2090
+ }
2091
+ /**
2092
+ * Enable an OAuth provider
2093
+ *
2094
+ * Convenience method to enable a provider.
2095
+ *
2096
+ * @param providerId - Provider ID (UUID)
2097
+ * @returns Promise resolving to UpdateOAuthProviderResponse
2098
+ *
2099
+ * @example
2100
+ * ```typescript
2101
+ * await client.admin.oauth.enableProvider('provider-id')
2102
+ * ```
2103
+ */
2104
+ async enableProvider(providerId) {
2105
+ return await this.updateProvider(providerId, { enabled: true });
2106
+ }
2107
+ /**
2108
+ * Disable an OAuth provider
2109
+ *
2110
+ * Convenience method to disable a provider.
2111
+ *
2112
+ * @param providerId - Provider ID (UUID)
2113
+ * @returns Promise resolving to UpdateOAuthProviderResponse
2114
+ *
2115
+ * @example
2116
+ * ```typescript
2117
+ * await client.admin.oauth.disableProvider('provider-id')
2118
+ * ```
2119
+ */
2120
+ async disableProvider(providerId) {
2121
+ return await this.updateProvider(providerId, { enabled: false });
2122
+ }
2123
+ };
2124
+ var AuthSettingsManager = class {
2125
+ constructor(fetch2) {
2126
+ this.fetch = fetch2;
2127
+ }
2128
+ /**
2129
+ * Get current authentication settings
2130
+ *
2131
+ * Retrieves all authentication configuration settings.
2132
+ *
2133
+ * @returns Promise resolving to AuthSettings
2134
+ *
2135
+ * @example
2136
+ * ```typescript
2137
+ * const settings = await client.admin.authSettings.get()
2138
+ *
2139
+ * console.log('Password min length:', settings.password_min_length)
2140
+ * console.log('Signup enabled:', settings.enable_signup)
2141
+ * console.log('Session timeout:', settings.session_timeout_minutes, 'minutes')
2142
+ * ```
2143
+ */
2144
+ async get() {
2145
+ return await this.fetch.get("/api/v1/admin/auth/settings");
2146
+ }
2147
+ /**
2148
+ * Update authentication settings
2149
+ *
2150
+ * Updates one or more authentication settings. All fields are optional - only provided
2151
+ * fields will be updated.
2152
+ *
2153
+ * @param request - Settings to update
2154
+ * @returns Promise resolving to UpdateAuthSettingsResponse
2155
+ *
2156
+ * @example
2157
+ * ```typescript
2158
+ * // Strengthen password requirements
2159
+ * await client.admin.authSettings.update({
2160
+ * password_min_length: 16,
2161
+ * password_require_uppercase: true,
2162
+ * password_require_lowercase: true,
2163
+ * password_require_number: true,
2164
+ * password_require_special: true
2165
+ * })
2166
+ * ```
2167
+ *
2168
+ * @example
2169
+ * ```typescript
2170
+ * // Extend session timeout
2171
+ * await client.admin.authSettings.update({
2172
+ * session_timeout_minutes: 240,
2173
+ * max_sessions_per_user: 10
2174
+ * })
2175
+ * ```
2176
+ *
2177
+ * @example
2178
+ * ```typescript
2179
+ * // Disable email verification during development
2180
+ * await client.admin.authSettings.update({
2181
+ * require_email_verification: false
2182
+ * })
2183
+ * ```
2184
+ */
2185
+ async update(request) {
2186
+ return await this.fetch.put("/api/v1/admin/auth/settings", request);
2187
+ }
2188
+ };
2189
+ var FluxbaseOAuth = class {
2190
+ constructor(fetch2) {
2191
+ this.providers = new OAuthProviderManager(fetch2);
2192
+ this.authSettings = new AuthSettingsManager(fetch2);
2193
+ }
2194
+ };
2195
+
2196
+ // src/impersonation.ts
2197
+ var ImpersonationManager = class {
2198
+ constructor(fetch2) {
2199
+ this.fetch = fetch2;
2200
+ }
2201
+ /**
2202
+ * Impersonate a specific user
2203
+ *
2204
+ * Start an impersonation session as a specific user. This allows you to see data
2205
+ * exactly as that user would see it, respecting all RLS policies and permissions.
2206
+ *
2207
+ * @param request - Impersonation request with target user ID and reason
2208
+ * @returns Promise resolving to impersonation session with access token
2209
+ *
2210
+ * @example
2211
+ * ```typescript
2212
+ * const result = await client.admin.impersonation.impersonateUser({
2213
+ * target_user_id: 'user-123',
2214
+ * reason: 'Support ticket #5678 - user reports missing data'
2215
+ * })
2216
+ *
2217
+ * console.log('Impersonating:', result.target_user.email)
2218
+ * console.log('Session ID:', result.session.id)
2219
+ *
2220
+ * // Use the access token for subsequent requests
2221
+ * // (typically handled automatically by the SDK)
2222
+ * ```
2223
+ */
2224
+ async impersonateUser(request) {
2225
+ return await this.fetch.post("/api/v1/auth/impersonate", request);
2226
+ }
2227
+ /**
2228
+ * Impersonate anonymous user
2229
+ *
2230
+ * Start an impersonation session as an unauthenticated user. This allows you to see
2231
+ * what data is publicly accessible and test RLS policies for anonymous access.
2232
+ *
2233
+ * @param request - Impersonation request with reason
2234
+ * @returns Promise resolving to impersonation session with access token
2235
+ *
2236
+ * @example
2237
+ * ```typescript
2238
+ * await client.admin.impersonation.impersonateAnon({
2239
+ * reason: 'Testing public data access for blog posts'
2240
+ * })
2241
+ *
2242
+ * // Now all queries will use anonymous permissions
2243
+ * const publicPosts = await client.from('posts').select('*')
2244
+ * console.log('Public posts:', publicPosts.length)
2245
+ * ```
2246
+ */
2247
+ async impersonateAnon(request) {
2248
+ return await this.fetch.post("/api/v1/auth/impersonate/anon", request);
2249
+ }
2250
+ /**
2251
+ * Impersonate with service role
2252
+ *
2253
+ * Start an impersonation session with service-level permissions. This provides elevated
2254
+ * access that may bypass RLS policies, useful for administrative operations.
2255
+ *
2256
+ * @param request - Impersonation request with reason
2257
+ * @returns Promise resolving to impersonation session with access token
2258
+ *
2259
+ * @example
2260
+ * ```typescript
2261
+ * await client.admin.impersonation.impersonateService({
2262
+ * reason: 'Administrative data cleanup'
2263
+ * })
2264
+ *
2265
+ * // Now all queries will use service role permissions
2266
+ * const allRecords = await client.from('sensitive_data').select('*')
2267
+ * console.log('All records:', allRecords.length)
2268
+ * ```
2269
+ */
2270
+ async impersonateService(request) {
2271
+ return await this.fetch.post("/api/v1/auth/impersonate/service", request);
2272
+ }
2273
+ /**
2274
+ * Stop impersonation
2275
+ *
2276
+ * Ends the current impersonation session and returns to admin context.
2277
+ * The session is marked as ended in the audit trail.
2278
+ *
2279
+ * @returns Promise resolving to stop confirmation
2280
+ *
2281
+ * @example
2282
+ * ```typescript
2283
+ * await client.admin.impersonation.stop()
2284
+ * console.log('Impersonation ended')
2285
+ *
2286
+ * // Subsequent queries will use admin permissions
2287
+ * ```
2288
+ */
2289
+ async stop() {
2290
+ return await this.fetch.delete("/api/v1/auth/impersonate");
2291
+ }
2292
+ /**
2293
+ * Get current impersonation session
2294
+ *
2295
+ * Retrieves information about the active impersonation session, if any.
2296
+ *
2297
+ * @returns Promise resolving to current impersonation session or null
2298
+ *
2299
+ * @example
2300
+ * ```typescript
2301
+ * const current = await client.admin.impersonation.getCurrent()
2302
+ *
2303
+ * if (current.session) {
2304
+ * console.log('Currently impersonating:', current.target_user?.email)
2305
+ * console.log('Reason:', current.session.reason)
2306
+ * console.log('Started:', current.session.started_at)
2307
+ * } else {
2308
+ * console.log('No active impersonation')
2309
+ * }
2310
+ * ```
2311
+ */
2312
+ async getCurrent() {
2313
+ return await this.fetch.get("/api/v1/auth/impersonate");
2314
+ }
2315
+ /**
2316
+ * List impersonation sessions (audit trail)
2317
+ *
2318
+ * Retrieves a list of impersonation sessions for audit and compliance purposes.
2319
+ * Can be filtered by admin user, target user, type, and active status.
2320
+ *
2321
+ * @param options - Filter and pagination options
2322
+ * @returns Promise resolving to list of impersonation sessions
2323
+ *
2324
+ * @example
2325
+ * ```typescript
2326
+ * // List all sessions
2327
+ * const { sessions, total } = await client.admin.impersonation.listSessions()
2328
+ * console.log(`Total sessions: ${total}`)
2329
+ *
2330
+ * // List active sessions only
2331
+ * const active = await client.admin.impersonation.listSessions({
2332
+ * is_active: true
2333
+ * })
2334
+ * console.log('Active sessions:', active.sessions.length)
2335
+ *
2336
+ * // List sessions for a specific admin
2337
+ * const adminSessions = await client.admin.impersonation.listSessions({
2338
+ * admin_user_id: 'admin-uuid',
2339
+ * limit: 50
2340
+ * })
2341
+ *
2342
+ * // List user impersonation sessions only
2343
+ * const userSessions = await client.admin.impersonation.listSessions({
2344
+ * impersonation_type: 'user',
2345
+ * offset: 0,
2346
+ * limit: 100
2347
+ * })
2348
+ * ```
2349
+ *
2350
+ * @example
2351
+ * ```typescript
2352
+ * // Audit trail: Find who impersonated a specific user
2353
+ * const userHistory = await client.admin.impersonation.listSessions({
2354
+ * target_user_id: 'user-uuid'
2355
+ * })
2356
+ *
2357
+ * userHistory.sessions.forEach(session => {
2358
+ * console.log(`Admin ${session.admin_user_id} impersonated user`)
2359
+ * console.log(`Reason: ${session.reason}`)
2360
+ * console.log(`Duration: ${session.started_at} - ${session.ended_at}`)
2361
+ * })
2362
+ * ```
2363
+ */
2364
+ async listSessions(options = {}) {
2365
+ const params = new URLSearchParams();
2366
+ if (options.limit !== void 0) {
2367
+ params.append("limit", String(options.limit));
2368
+ }
2369
+ if (options.offset !== void 0) {
2370
+ params.append("offset", String(options.offset));
2371
+ }
2372
+ if (options.admin_user_id) {
2373
+ params.append("admin_user_id", options.admin_user_id);
2374
+ }
2375
+ if (options.target_user_id) {
2376
+ params.append("target_user_id", options.target_user_id);
2377
+ }
2378
+ if (options.impersonation_type) {
2379
+ params.append("impersonation_type", options.impersonation_type);
2380
+ }
2381
+ if (options.is_active !== void 0) {
2382
+ params.append("is_active", String(options.is_active));
2383
+ }
2384
+ const queryString = params.toString();
2385
+ const url = queryString ? `/api/v1/auth/impersonate/sessions?${queryString}` : "/api/v1/auth/impersonate/sessions";
2386
+ return await this.fetch.get(url);
2387
+ }
2388
+ };
2389
+
2390
+ // src/management.ts
2391
+ var APIKeysManager = class {
2392
+ constructor(fetch2) {
2393
+ this.fetch = fetch2;
2394
+ }
2395
+ /**
2396
+ * Create a new API key
2397
+ *
2398
+ * @param request - API key configuration
2399
+ * @returns Created API key with the full key value (only shown once)
2400
+ *
2401
+ * @example
2402
+ * ```typescript
2403
+ * const { api_key, key } = await client.management.apiKeys.create({
2404
+ * name: 'Production Service',
2405
+ * description: 'API key for production service',
2406
+ * scopes: ['read:users', 'write:users'],
2407
+ * rate_limit_per_minute: 100,
2408
+ * expires_at: '2025-12-31T23:59:59Z'
2409
+ * })
2410
+ *
2411
+ * // Store the key securely - it won't be shown again
2412
+ * console.log('API Key:', key)
2413
+ * ```
2414
+ */
2415
+ async create(request) {
2416
+ return await this.fetch.post("/api/v1/api-keys", request);
2417
+ }
2418
+ /**
2419
+ * List all API keys for the authenticated user
2420
+ *
2421
+ * @returns List of API keys (without full key values)
2422
+ *
2423
+ * @example
2424
+ * ```typescript
2425
+ * const { api_keys, total } = await client.management.apiKeys.list()
2426
+ *
2427
+ * api_keys.forEach(key => {
2428
+ * console.log(`${key.name}: ${key.key_prefix}... (expires: ${key.expires_at})`)
2429
+ * })
2430
+ * ```
2431
+ */
2432
+ async list() {
2433
+ return await this.fetch.get("/api/v1/api-keys");
2434
+ }
2435
+ /**
2436
+ * Get a specific API key by ID
2437
+ *
2438
+ * @param keyId - API key ID
2439
+ * @returns API key details
2440
+ *
2441
+ * @example
2442
+ * ```typescript
2443
+ * const apiKey = await client.management.apiKeys.get('key-uuid')
2444
+ * console.log('Last used:', apiKey.last_used_at)
2445
+ * ```
2446
+ */
2447
+ async get(keyId) {
2448
+ return await this.fetch.get(`/api/v1/api-keys/${keyId}`);
2449
+ }
2450
+ /**
2451
+ * Update an API key
2452
+ *
2453
+ * @param keyId - API key ID
2454
+ * @param updates - Fields to update
2455
+ * @returns Updated API key
2456
+ *
2457
+ * @example
2458
+ * ```typescript
2459
+ * const updated = await client.management.apiKeys.update('key-uuid', {
2460
+ * name: 'Updated Name',
2461
+ * rate_limit_per_minute: 200
2462
+ * })
2463
+ * ```
2464
+ */
2465
+ async update(keyId, updates) {
2466
+ return await this.fetch.patch(`/api/v1/api-keys/${keyId}`, updates);
2467
+ }
2468
+ /**
2469
+ * Revoke an API key
2470
+ *
2471
+ * Revoked keys can no longer be used but remain in the system for audit purposes.
2472
+ *
2473
+ * @param keyId - API key ID
2474
+ * @returns Revocation confirmation
2475
+ *
2476
+ * @example
2477
+ * ```typescript
2478
+ * await client.management.apiKeys.revoke('key-uuid')
2479
+ * console.log('API key revoked')
2480
+ * ```
2481
+ */
2482
+ async revoke(keyId) {
2483
+ return await this.fetch.post(`/api/v1/api-keys/${keyId}/revoke`, {});
2484
+ }
2485
+ /**
2486
+ * Delete an API key
2487
+ *
2488
+ * Permanently removes the API key from the system.
2489
+ *
2490
+ * @param keyId - API key ID
2491
+ * @returns Deletion confirmation
2492
+ *
2493
+ * @example
2494
+ * ```typescript
2495
+ * await client.management.apiKeys.delete('key-uuid')
2496
+ * console.log('API key deleted')
2497
+ * ```
2498
+ */
2499
+ async delete(keyId) {
2500
+ return await this.fetch.delete(`/api/v1/api-keys/${keyId}`);
2501
+ }
2502
+ };
2503
+ var WebhooksManager = class {
2504
+ constructor(fetch2) {
2505
+ this.fetch = fetch2;
2506
+ }
2507
+ /**
2508
+ * Create a new webhook
2509
+ *
2510
+ * @param request - Webhook configuration
2511
+ * @returns Created webhook
2512
+ *
2513
+ * @example
2514
+ * ```typescript
2515
+ * const webhook = await client.management.webhooks.create({
2516
+ * url: 'https://myapp.com/webhook',
2517
+ * events: ['user.created', 'user.updated', 'user.deleted'],
2518
+ * description: 'User events webhook',
2519
+ * secret: 'my-webhook-secret'
2520
+ * })
2521
+ * ```
2522
+ */
2523
+ async create(request) {
2524
+ return await this.fetch.post("/api/v1/webhooks", request);
2525
+ }
2526
+ /**
2527
+ * List all webhooks for the authenticated user
2528
+ *
2529
+ * @returns List of webhooks
2530
+ *
2531
+ * @example
2532
+ * ```typescript
2533
+ * const { webhooks, total } = await client.management.webhooks.list()
2534
+ *
2535
+ * webhooks.forEach(webhook => {
2536
+ * console.log(`${webhook.url}: ${webhook.is_active ? 'active' : 'inactive'}`)
2537
+ * })
2538
+ * ```
2539
+ */
2540
+ async list() {
2541
+ return await this.fetch.get("/api/v1/webhooks");
2542
+ }
2543
+ /**
2544
+ * Get a specific webhook by ID
2545
+ *
2546
+ * @param webhookId - Webhook ID
2547
+ * @returns Webhook details
2548
+ *
2549
+ * @example
2550
+ * ```typescript
2551
+ * const webhook = await client.management.webhooks.get('webhook-uuid')
2552
+ * console.log('Events:', webhook.events)
2553
+ * ```
2554
+ */
2555
+ async get(webhookId) {
2556
+ return await this.fetch.get(`/api/v1/webhooks/${webhookId}`);
2557
+ }
2558
+ /**
2559
+ * Update a webhook
2560
+ *
2561
+ * @param webhookId - Webhook ID
2562
+ * @param updates - Fields to update
2563
+ * @returns Updated webhook
2564
+ *
2565
+ * @example
2566
+ * ```typescript
2567
+ * const updated = await client.management.webhooks.update('webhook-uuid', {
2568
+ * events: ['user.created', 'user.deleted'],
2569
+ * is_active: false
2570
+ * })
2571
+ * ```
2572
+ */
2573
+ async update(webhookId, updates) {
2574
+ return await this.fetch.patch(`/api/v1/webhooks/${webhookId}`, updates);
2575
+ }
2576
+ /**
2577
+ * Delete a webhook
2578
+ *
2579
+ * @param webhookId - Webhook ID
2580
+ * @returns Deletion confirmation
2581
+ *
2582
+ * @example
2583
+ * ```typescript
2584
+ * await client.management.webhooks.delete('webhook-uuid')
2585
+ * console.log('Webhook deleted')
2586
+ * ```
2587
+ */
2588
+ async delete(webhookId) {
2589
+ return await this.fetch.delete(`/api/v1/webhooks/${webhookId}`);
2590
+ }
2591
+ /**
2592
+ * Test a webhook by sending a test payload
2593
+ *
2594
+ * @param webhookId - Webhook ID
2595
+ * @returns Test result with status and response
2596
+ *
2597
+ * @example
2598
+ * ```typescript
2599
+ * const result = await client.management.webhooks.test('webhook-uuid')
2600
+ *
2601
+ * if (result.success) {
2602
+ * console.log('Webhook test successful')
2603
+ * } else {
2604
+ * console.error('Webhook test failed:', result.error)
2605
+ * }
2606
+ * ```
2607
+ */
2608
+ async test(webhookId) {
2609
+ return await this.fetch.post(`/api/v1/webhooks/${webhookId}/test`, {});
2610
+ }
2611
+ /**
2612
+ * List webhook delivery history
2613
+ *
2614
+ * @param webhookId - Webhook ID
2615
+ * @param limit - Maximum number of deliveries to return (default: 50)
2616
+ * @returns List of webhook deliveries
2617
+ *
2618
+ * @example
2619
+ * ```typescript
2620
+ * const { deliveries } = await client.management.webhooks.listDeliveries('webhook-uuid', 100)
2621
+ *
2622
+ * deliveries.forEach(delivery => {
2623
+ * console.log(`Event: ${delivery.event}, Status: ${delivery.status_code}`)
2624
+ * })
2625
+ * ```
2626
+ */
2627
+ async listDeliveries(webhookId, limit = 50) {
2628
+ return await this.fetch.get(
2629
+ `/api/v1/webhooks/${webhookId}/deliveries?limit=${limit}`
2630
+ );
2631
+ }
2632
+ };
2633
+ var InvitationsManager = class {
2634
+ constructor(fetch2) {
2635
+ this.fetch = fetch2;
2636
+ }
2637
+ /**
2638
+ * Create a new invitation (admin only)
2639
+ *
2640
+ * @param request - Invitation details
2641
+ * @returns Created invitation with invite link
2642
+ *
2643
+ * @example
2644
+ * ```typescript
2645
+ * const invitation = await client.management.invitations.create({
2646
+ * email: 'newuser@example.com',
2647
+ * role: 'dashboard_user',
2648
+ * expiry_duration: 604800 // 7 days in seconds
2649
+ * })
2650
+ *
2651
+ * // Share the invite link
2652
+ * console.log('Send this link to the user:', invitation.invite_link)
2653
+ * ```
2654
+ */
2655
+ async create(request) {
2656
+ return await this.fetch.post("/api/v1/admin/invitations", request);
2657
+ }
2658
+ /**
2659
+ * List all invitations (admin only)
2660
+ *
2661
+ * @param options - Filter options
2662
+ * @returns List of invitations
2663
+ *
2664
+ * @example
2665
+ * ```typescript
2666
+ * // List pending invitations only
2667
+ * const { invitations } = await client.management.invitations.list({
2668
+ * include_accepted: false,
2669
+ * include_expired: false
2670
+ * })
2671
+ *
2672
+ * // List all invitations including accepted and expired
2673
+ * const all = await client.management.invitations.list({
2674
+ * include_accepted: true,
2675
+ * include_expired: true
2676
+ * })
2677
+ * ```
2678
+ */
2679
+ async list(options = {}) {
2680
+ const params = new URLSearchParams();
2681
+ if (options.include_accepted !== void 0) {
2682
+ params.append("include_accepted", String(options.include_accepted));
2683
+ }
2684
+ if (options.include_expired !== void 0) {
2685
+ params.append("include_expired", String(options.include_expired));
2686
+ }
2687
+ const queryString = params.toString();
2688
+ const url = queryString ? `/api/v1/admin/invitations?${queryString}` : "/api/v1/admin/invitations";
2689
+ return await this.fetch.get(url);
2690
+ }
2691
+ /**
2692
+ * Validate an invitation token (public endpoint)
2693
+ *
2694
+ * @param token - Invitation token
2695
+ * @returns Validation result with invitation details
2696
+ *
2697
+ * @example
2698
+ * ```typescript
2699
+ * const result = await client.management.invitations.validate('invitation-token')
2700
+ *
2701
+ * if (result.valid) {
2702
+ * console.log('Valid invitation for:', result.invitation?.email)
2703
+ * } else {
2704
+ * console.error('Invalid:', result.error)
2705
+ * }
2706
+ * ```
2707
+ */
2708
+ async validate(token) {
2709
+ return await this.fetch.get(`/api/v1/invitations/${token}/validate`);
2710
+ }
2711
+ /**
2712
+ * Accept an invitation and create a new user (public endpoint)
2713
+ *
2714
+ * @param token - Invitation token
2715
+ * @param request - User details (password and name)
2716
+ * @returns Created user with authentication tokens
2717
+ *
2718
+ * @example
2719
+ * ```typescript
2720
+ * const response = await client.management.invitations.accept('invitation-token', {
2721
+ * password: 'SecurePassword123!',
2722
+ * name: 'John Doe'
2723
+ * })
2724
+ *
2725
+ * // Store tokens
2726
+ * localStorage.setItem('access_token', response.access_token)
2727
+ * console.log('Welcome:', response.user.name)
2728
+ * ```
2729
+ */
2730
+ async accept(token, request) {
2731
+ return await this.fetch.post(`/api/v1/invitations/${token}/accept`, request);
2732
+ }
2733
+ /**
2734
+ * Revoke an invitation (admin only)
2735
+ *
2736
+ * @param token - Invitation token
2737
+ * @returns Revocation confirmation
2738
+ *
2739
+ * @example
2740
+ * ```typescript
2741
+ * await client.management.invitations.revoke('invitation-token')
2742
+ * console.log('Invitation revoked')
2743
+ * ```
2744
+ */
2745
+ async revoke(token) {
2746
+ return await this.fetch.delete(`/api/v1/admin/invitations/${token}`);
2747
+ }
2748
+ };
2749
+ var FluxbaseManagement = class {
2750
+ constructor(fetch2) {
2751
+ this.apiKeys = new APIKeysManager(fetch2);
2752
+ this.webhooks = new WebhooksManager(fetch2);
2753
+ this.invitations = new InvitationsManager(fetch2);
2754
+ }
2755
+ };
2756
+
2757
+ // src/admin.ts
2758
+ var FluxbaseAdmin = class {
2759
+ constructor(fetch2) {
2760
+ this.adminToken = null;
2761
+ this.fetch = fetch2;
2762
+ this.settings = new FluxbaseSettings(fetch2);
2763
+ this.ddl = new DDLManager(fetch2);
2764
+ this.oauth = new FluxbaseOAuth(fetch2);
2765
+ this.impersonation = new ImpersonationManager(fetch2);
2766
+ this.management = new FluxbaseManagement(fetch2);
2767
+ this.emailTemplates = new EmailTemplateManager(fetch2);
2768
+ }
2769
+ /**
2770
+ * Set admin authentication token
2771
+ */
2772
+ setToken(token) {
2773
+ this.adminToken = token;
2774
+ this.fetch.setAuthToken(token);
2775
+ }
2776
+ /**
2777
+ * Get current admin token
2778
+ */
2779
+ getToken() {
2780
+ return this.adminToken;
2781
+ }
2782
+ /**
2783
+ * Clear admin token
2784
+ */
2785
+ clearToken() {
2786
+ this.adminToken = null;
2787
+ this.fetch.setAuthToken(null);
2788
+ }
2789
+ // ============================================================================
2790
+ // Admin Authentication
2791
+ // ============================================================================
2792
+ /**
2793
+ * Check if initial admin setup is needed
2794
+ *
2795
+ * @returns Setup status indicating if initial setup is required
2796
+ *
2797
+ * @example
2798
+ * ```typescript
2799
+ * const status = await admin.getSetupStatus();
2800
+ * if (status.needs_setup) {
2801
+ * console.log('Initial setup required');
2802
+ * }
2803
+ * ```
2804
+ */
2805
+ async getSetupStatus() {
2806
+ return await this.fetch.get(
2807
+ "/api/v1/admin/setup/status"
2808
+ );
2809
+ }
2810
+ /**
2811
+ * Perform initial admin setup
2812
+ *
2813
+ * Creates the first admin user and completes initial setup.
2814
+ * This endpoint can only be called once.
2815
+ *
2816
+ * @param email - Admin email address
2817
+ * @param password - Admin password (minimum 12 characters)
2818
+ * @param name - Admin display name
2819
+ * @returns Authentication response with tokens
2820
+ *
2821
+ * @example
2822
+ * ```typescript
2823
+ * const response = await admin.setup({
2824
+ * email: 'admin@example.com',
2825
+ * password: 'SecurePassword123!',
2826
+ * name: 'Admin User'
2827
+ * });
2828
+ *
2829
+ * // Store tokens
2830
+ * localStorage.setItem('admin_token', response.access_token);
2831
+ * ```
2832
+ */
2833
+ async setup(request) {
2834
+ const response = await this.fetch.post(
2835
+ "/api/v1/admin/setup",
2836
+ request
2837
+ );
2838
+ this.setToken(response.access_token);
2839
+ return response;
2840
+ }
2841
+ /**
2842
+ * Admin login
2843
+ *
2844
+ * Authenticate as an admin user
2845
+ *
2846
+ * @param email - Admin email
2847
+ * @param password - Admin password
2848
+ * @returns Authentication response with tokens
2849
+ *
2850
+ * @example
2851
+ * ```typescript
2852
+ * const response = await admin.login({
2853
+ * email: 'admin@example.com',
2854
+ * password: 'password123'
2855
+ * });
2856
+ *
2857
+ * // Token is automatically set in the client
2858
+ * console.log('Logged in as:', response.user.email);
2859
+ * ```
2860
+ */
2861
+ async login(request) {
2862
+ const response = await this.fetch.post(
2863
+ "/api/v1/admin/login",
2864
+ request
2865
+ );
2866
+ this.setToken(response.access_token);
2867
+ return response;
2868
+ }
2869
+ /**
2870
+ * Refresh admin access token
2871
+ *
2872
+ * @param refreshToken - Refresh token
2873
+ * @returns New access and refresh tokens
2874
+ *
2875
+ * @example
2876
+ * ```typescript
2877
+ * const refreshToken = localStorage.getItem('admin_refresh_token');
2878
+ * const response = await admin.refreshToken({ refresh_token: refreshToken });
2879
+ *
2880
+ * // Update stored tokens
2881
+ * localStorage.setItem('admin_token', response.access_token);
2882
+ * localStorage.setItem('admin_refresh_token', response.refresh_token);
2883
+ * ```
2884
+ */
2885
+ async refreshToken(request) {
2886
+ const response = await this.fetch.post(
2887
+ "/api/v1/admin/refresh",
2888
+ request
2889
+ );
2890
+ this.setToken(response.access_token);
2891
+ return response;
2892
+ }
2893
+ /**
2894
+ * Admin logout
2895
+ *
2896
+ * Invalidates the current admin session
2897
+ *
2898
+ * @example
2899
+ * ```typescript
2900
+ * await admin.logout();
2901
+ * localStorage.removeItem('admin_token');
2902
+ * ```
2903
+ */
2904
+ async logout() {
2905
+ await this.fetch.post("/api/v1/admin/logout", {});
2906
+ this.clearToken();
2907
+ }
2908
+ /**
2909
+ * Get current admin user information
2910
+ *
2911
+ * @returns Current admin user details
2912
+ *
2913
+ * @example
2914
+ * ```typescript
2915
+ * const { user } = await admin.me();
2916
+ * console.log('Logged in as:', user.email);
2917
+ * console.log('Role:', user.role);
2918
+ * ```
2919
+ */
2920
+ async me() {
2921
+ return await this.fetch.get("/api/v1/admin/me");
2922
+ }
2923
+ // ============================================================================
2924
+ // User Management
2925
+ // ============================================================================
2926
+ /**
2927
+ * List all users
2928
+ *
2929
+ * @param options - Filter and pagination options
2930
+ * @returns List of users with metadata
2931
+ *
2932
+ * @example
2933
+ * ```typescript
2934
+ * // List all users
2935
+ * const { users, total } = await admin.listUsers();
2936
+ *
2937
+ * // List with filters
2938
+ * const result = await admin.listUsers({
2939
+ * exclude_admins: true,
2940
+ * search: 'john',
2941
+ * limit: 50,
2942
+ * type: 'app'
2943
+ * });
2944
+ * ```
2945
+ */
2946
+ async listUsers(options = {}) {
2947
+ const params = new URLSearchParams();
2948
+ if (options.exclude_admins !== void 0) {
2949
+ params.append("exclude_admins", String(options.exclude_admins));
2950
+ }
2951
+ if (options.search) {
2952
+ params.append("search", options.search);
2953
+ }
2954
+ if (options.limit !== void 0) {
2955
+ params.append("limit", String(options.limit));
2956
+ }
2957
+ if (options.type) {
2958
+ params.append("type", options.type);
2959
+ }
2960
+ const queryString = params.toString();
2961
+ const url = queryString ? `/api/v1/admin/users?${queryString}` : "/api/v1/admin/users";
2962
+ return await this.fetch.get(url);
2963
+ }
2964
+ /**
2965
+ * Get a user by ID
2966
+ *
2967
+ * Fetch a single user's details by their user ID
2968
+ *
2969
+ * @param userId - User ID to fetch
2970
+ * @param type - User type ('app' or 'dashboard')
2971
+ * @returns User details with metadata
2972
+ *
2973
+ * @example
2974
+ * ```typescript
2975
+ * // Get an app user
2976
+ * const user = await admin.getUserById('user-123');
2977
+ *
2978
+ * // Get a dashboard user
2979
+ * const dashboardUser = await admin.getUserById('admin-456', 'dashboard');
2980
+ * console.log('User email:', dashboardUser.email);
2981
+ * console.log('Last login:', dashboardUser.last_login_at);
2982
+ * ```
2983
+ */
2984
+ async getUserById(userId, type = "app") {
2985
+ const url = `/api/v1/admin/users/${userId}?type=${type}`;
2986
+ return await this.fetch.get(url);
2987
+ }
2988
+ /**
2989
+ * Invite a new user
2990
+ *
2991
+ * Creates a new user and optionally sends an invitation email
2992
+ *
2993
+ * @param request - User invitation details
2994
+ * @param type - User type ('app' or 'dashboard')
2995
+ * @returns Created user and invitation details
2996
+ *
2997
+ * @example
2998
+ * ```typescript
2999
+ * const response = await admin.inviteUser({
3000
+ * email: 'newuser@example.com',
3001
+ * role: 'user',
3002
+ * send_email: true
3003
+ * });
3004
+ *
3005
+ * console.log('User invited:', response.user.email);
3006
+ * console.log('Invitation link:', response.invitation_link);
3007
+ * ```
3008
+ */
3009
+ async inviteUser(request, type = "app") {
3010
+ const url = `/api/v1/admin/users/invite?type=${type}`;
3011
+ return await this.fetch.post(url, request);
3012
+ }
3013
+ /**
3014
+ * Delete a user
3015
+ *
3016
+ * Permanently deletes a user and all associated data
3017
+ *
3018
+ * @param userId - User ID to delete
3019
+ * @param type - User type ('app' or 'dashboard')
3020
+ * @returns Deletion confirmation
3021
+ *
3022
+ * @example
3023
+ * ```typescript
3024
+ * await admin.deleteUser('user-uuid');
3025
+ * console.log('User deleted');
3026
+ * ```
3027
+ */
3028
+ async deleteUser(userId, type = "app") {
3029
+ const url = `/api/v1/admin/users/${userId}?type=${type}`;
3030
+ return await this.fetch.delete(url);
3031
+ }
3032
+ /**
3033
+ * Update user role
3034
+ *
3035
+ * Changes a user's role
3036
+ *
3037
+ * @param userId - User ID
3038
+ * @param role - New role
3039
+ * @param type - User type ('app' or 'dashboard')
3040
+ * @returns Updated user
3041
+ *
3042
+ * @example
3043
+ * ```typescript
3044
+ * const user = await admin.updateUserRole('user-uuid', 'admin');
3045
+ * console.log('User role updated:', user.role);
3046
+ * ```
3047
+ */
3048
+ async updateUserRole(userId, role, type = "app") {
3049
+ const url = `/api/v1/admin/users/${userId}/role?type=${type}`;
3050
+ return await this.fetch.patch(url, { role });
3051
+ }
3052
+ /**
3053
+ * Reset user password
3054
+ *
3055
+ * Generates a new password for the user and optionally sends it via email
3056
+ *
3057
+ * @param userId - User ID
3058
+ * @param type - User type ('app' or 'dashboard')
3059
+ * @returns Reset confirmation message
3060
+ *
3061
+ * @example
3062
+ * ```typescript
3063
+ * const response = await admin.resetUserPassword('user-uuid');
3064
+ * console.log(response.message);
3065
+ * ```
3066
+ */
3067
+ async resetUserPassword(userId, type = "app") {
3068
+ const url = `/api/v1/admin/users/${userId}/reset-password?type=${type}`;
3069
+ return await this.fetch.post(url, {});
3070
+ }
3071
+ };
3072
+
3073
+ // src/query-builder.ts
3074
+ var QueryBuilder = class {
3075
+ constructor(fetch2, table) {
3076
+ this.selectQuery = "*";
3077
+ this.filters = [];
3078
+ this.orderBys = [];
3079
+ this.singleRow = false;
3080
+ this.fetch = fetch2;
3081
+ this.table = table;
3082
+ }
3083
+ /**
3084
+ * Select columns to return
3085
+ * @example select('*')
3086
+ * @example select('id, name, email')
3087
+ * @example select('id, name, posts(title, content)')
3088
+ */
3089
+ select(columns = "*") {
3090
+ this.selectQuery = columns;
3091
+ return this;
3092
+ }
3093
+ /**
3094
+ * Insert a single row or multiple rows
3095
+ */
3096
+ async insert(data) {
3097
+ const body = Array.isArray(data) ? data : data;
3098
+ const response = await this.fetch.post(`/api/v1/tables/${this.table}`, body);
3099
+ return {
3100
+ data: response,
3101
+ error: null,
3102
+ count: Array.isArray(data) ? data.length : 1,
3103
+ status: 201,
3104
+ statusText: "Created"
3105
+ };
3106
+ }
3107
+ /**
3108
+ * Upsert (insert or update) rows
3109
+ */
3110
+ async upsert(data) {
3111
+ const body = Array.isArray(data) ? data : data;
3112
+ const response = await this.fetch.post(`/api/v1/tables/${this.table}`, body, {
3113
+ headers: {
3114
+ Prefer: "resolution=merge-duplicates"
3115
+ }
3116
+ });
3117
+ return {
3118
+ data: response,
3119
+ error: null,
3120
+ count: Array.isArray(data) ? data.length : 1,
3121
+ status: 201,
3122
+ statusText: "Created"
3123
+ };
3124
+ }
3125
+ /**
3126
+ * Update rows matching the filters
3127
+ */
3128
+ async update(data) {
3129
+ const queryString = this.buildQueryString();
3130
+ const path = `/api/v1/tables/${this.table}${queryString}`;
3131
+ const response = await this.fetch.patch(path, data);
3132
+ return {
3133
+ data: response,
3134
+ error: null,
3135
+ count: null,
3136
+ status: 200,
3137
+ statusText: "OK"
3138
+ };
3139
+ }
3140
+ /**
3141
+ * Delete rows matching the filters
3142
+ */
3143
+ async delete() {
3144
+ const queryString = this.buildQueryString();
3145
+ const path = `/api/v1/tables/${this.table}${queryString}`;
3146
+ await this.fetch.delete(path);
3147
+ return {
3148
+ data: null,
3149
+ error: null,
3150
+ count: null,
3151
+ status: 204,
3152
+ statusText: "No Content"
3153
+ };
3154
+ }
3155
+ /**
3156
+ * Equal to
3157
+ */
3158
+ eq(column, value) {
3159
+ this.filters.push({ column, operator: "eq", value });
3160
+ return this;
3161
+ }
3162
+ /**
3163
+ * Not equal to
3164
+ */
3165
+ neq(column, value) {
3166
+ this.filters.push({ column, operator: "neq", value });
3167
+ return this;
3168
+ }
3169
+ /**
3170
+ * Greater than
3171
+ */
3172
+ gt(column, value) {
3173
+ this.filters.push({ column, operator: "gt", value });
3174
+ return this;
3175
+ }
3176
+ /**
3177
+ * Greater than or equal to
3178
+ */
3179
+ gte(column, value) {
3180
+ this.filters.push({ column, operator: "gte", value });
3181
+ return this;
3182
+ }
3183
+ /**
3184
+ * Less than
3185
+ */
3186
+ lt(column, value) {
3187
+ this.filters.push({ column, operator: "lt", value });
3188
+ return this;
3189
+ }
3190
+ /**
3191
+ * Less than or equal to
3192
+ */
3193
+ lte(column, value) {
3194
+ this.filters.push({ column, operator: "lte", value });
3195
+ return this;
3196
+ }
3197
+ /**
3198
+ * Pattern matching (case-sensitive)
3199
+ */
3200
+ like(column, pattern) {
3201
+ this.filters.push({ column, operator: "like", value: pattern });
3202
+ return this;
3203
+ }
3204
+ /**
3205
+ * Pattern matching (case-insensitive)
3206
+ */
3207
+ ilike(column, pattern) {
3208
+ this.filters.push({ column, operator: "ilike", value: pattern });
3209
+ return this;
3210
+ }
3211
+ /**
3212
+ * Check if value is null or not null
3213
+ */
3214
+ is(column, value) {
3215
+ this.filters.push({ column, operator: "is", value });
3216
+ return this;
3217
+ }
3218
+ /**
3219
+ * Check if value is in array
3220
+ */
3221
+ in(column, values) {
3222
+ this.filters.push({ column, operator: "in", value: values });
3223
+ return this;
3224
+ }
3225
+ /**
3226
+ * Contains (for arrays and JSONB)
3227
+ */
3228
+ contains(column, value) {
3229
+ this.filters.push({ column, operator: "cs", value });
3230
+ return this;
3231
+ }
3232
+ /**
3233
+ * Full-text search
3234
+ */
3235
+ textSearch(column, query) {
3236
+ this.filters.push({ column, operator: "fts", value: query });
3237
+ return this;
3238
+ }
3239
+ /**
3240
+ * Order results
3241
+ */
3242
+ order(column, options) {
3243
+ this.orderBys.push({
3244
+ column,
3245
+ direction: options?.ascending === false ? "desc" : "asc",
3246
+ nulls: options?.nullsFirst ? "first" : "last"
3247
+ });
3248
+ return this;
3249
+ }
3250
+ /**
3251
+ * Limit number of rows returned
3252
+ */
3253
+ limit(count) {
3254
+ this.limitValue = count;
3255
+ return this;
3256
+ }
3257
+ /**
3258
+ * Skip rows
3259
+ */
3260
+ offset(count) {
3261
+ this.offsetValue = count;
3262
+ return this;
3263
+ }
3264
+ /**
3265
+ * Return a single row (adds limit(1))
3266
+ */
3267
+ single() {
3268
+ this.singleRow = true;
3269
+ this.limitValue = 1;
3270
+ return this;
3271
+ }
3272
+ /**
3273
+ * Range selection (pagination)
3274
+ */
3275
+ range(from, to) {
3276
+ this.offsetValue = from;
3277
+ this.limitValue = to - from + 1;
3278
+ return this;
3279
+ }
3280
+ /**
3281
+ * Group results by one or more columns (for use with aggregations)
3282
+ *
3283
+ * @param columns - Column name(s) to group by
3284
+ * @returns Query builder for chaining
3285
+ *
3286
+ * @example
3287
+ * ```typescript
3288
+ * // Group by single column
3289
+ * const { data } = await client.from('orders')
3290
+ * .count('*')
3291
+ * .groupBy('status')
3292
+ * .execute()
3293
+ *
3294
+ * // Group by multiple columns
3295
+ * const { data } = await client.from('sales')
3296
+ * .sum('amount')
3297
+ * .groupBy(['region', 'product_category'])
3298
+ * .execute()
3299
+ * ```
3300
+ *
3301
+ * @category Aggregation
3302
+ */
3303
+ groupBy(columns) {
3304
+ this.groupByColumns = Array.isArray(columns) ? columns : [columns];
3305
+ return this;
3306
+ }
3307
+ /**
3308
+ * Count rows or a specific column
3309
+ *
3310
+ * @param column - Column to count (default: '*' for row count)
3311
+ * @returns Query builder for chaining
3312
+ *
3313
+ * @example
3314
+ * ```typescript
3315
+ * // Count all rows
3316
+ * const { data } = await client.from('users').count().execute()
3317
+ * // Returns: { count: 150 }
3318
+ *
3319
+ * // Count non-null values in a column
3320
+ * const { data } = await client.from('orders').count('completed_at').execute()
3321
+ *
3322
+ * // Count with grouping
3323
+ * const { data } = await client.from('products')
3324
+ * .count('*')
3325
+ * .groupBy('category')
3326
+ * .execute()
3327
+ * // Returns: [{ category: 'electronics', count: 45 }, { category: 'books', count: 23 }]
3328
+ * ```
3329
+ *
3330
+ * @category Aggregation
3331
+ */
3332
+ count(column = "*") {
3333
+ this.selectQuery = `count(${column})`;
3334
+ return this;
3335
+ }
3336
+ /**
3337
+ * Calculate the sum of a numeric column
3338
+ *
3339
+ * @param column - Column to sum
3340
+ * @returns Query builder for chaining
3341
+ *
3342
+ * @example
3343
+ * ```typescript
3344
+ * // Sum all prices
3345
+ * const { data } = await client.from('products').sum('price').execute()
3346
+ * // Returns: { sum_price: 15420.50 }
3347
+ *
3348
+ * // Sum by category
3349
+ * const { data } = await client.from('orders')
3350
+ * .sum('total')
3351
+ * .groupBy('status')
3352
+ * .execute()
3353
+ * // Returns: [{ status: 'completed', sum_total: 12500 }, { status: 'pending', sum_total: 3200 }]
3354
+ * ```
3355
+ *
3356
+ * @category Aggregation
3357
+ */
3358
+ sum(column) {
3359
+ this.selectQuery = `sum(${column})`;
3360
+ return this;
3361
+ }
3362
+ /**
3363
+ * Calculate the average of a numeric column
3364
+ *
3365
+ * @param column - Column to average
3366
+ * @returns Query builder for chaining
3367
+ *
3368
+ * @example
3369
+ * ```typescript
3370
+ * // Average price
3371
+ * const { data } = await client.from('products').avg('price').execute()
3372
+ * // Returns: { avg_price: 129.99 }
3373
+ *
3374
+ * // Average by category
3375
+ * const { data } = await client.from('products')
3376
+ * .avg('price')
3377
+ * .groupBy('category')
3378
+ * .execute()
3379
+ * ```
3380
+ *
3381
+ * @category Aggregation
3382
+ */
3383
+ avg(column) {
3384
+ this.selectQuery = `avg(${column})`;
3385
+ return this;
3386
+ }
3387
+ /**
3388
+ * Find the minimum value in a column
3389
+ *
3390
+ * @param column - Column to find minimum value
3391
+ * @returns Query builder for chaining
3392
+ *
3393
+ * @example
3394
+ * ```typescript
3395
+ * // Find lowest price
3396
+ * const { data } = await client.from('products').min('price').execute()
3397
+ * // Returns: { min_price: 9.99 }
3398
+ *
3399
+ * // Find earliest date
3400
+ * const { data } = await client.from('orders').min('created_at').execute()
3401
+ * ```
3402
+ *
3403
+ * @category Aggregation
3404
+ */
3405
+ min(column) {
3406
+ this.selectQuery = `min(${column})`;
3407
+ return this;
3408
+ }
3409
+ /**
3410
+ * Find the maximum value in a column
3411
+ *
3412
+ * @param column - Column to find maximum value
3413
+ * @returns Query builder for chaining
3414
+ *
3415
+ * @example
3416
+ * ```typescript
3417
+ * // Find highest price
3418
+ * const { data } = await client.from('products').max('price').execute()
3419
+ * // Returns: { max_price: 1999.99 }
3420
+ *
3421
+ * // Find most recent order
3422
+ * const { data } = await client.from('orders').max('created_at').execute()
3423
+ * ```
3424
+ *
3425
+ * @category Aggregation
3426
+ */
3427
+ max(column) {
3428
+ this.selectQuery = `max(${column})`;
3429
+ return this;
3430
+ }
3431
+ /**
3432
+ * Insert multiple rows in a single request (batch insert)
3433
+ *
3434
+ * This is a convenience method that explicitly shows intent for batch operations.
3435
+ * Internally calls `insert()` with an array.
3436
+ *
3437
+ * @param rows - Array of row objects to insert
3438
+ * @returns Promise with the inserted rows
3439
+ *
3440
+ * @example
3441
+ * ```typescript
3442
+ * // Insert multiple users at once
3443
+ * const { data } = await client.from('users').insertMany([
3444
+ * { name: 'Alice', email: 'alice@example.com' },
3445
+ * { name: 'Bob', email: 'bob@example.com' },
3446
+ * { name: 'Charlie', email: 'charlie@example.com' }
3447
+ * ]).execute()
3448
+ * ```
3449
+ *
3450
+ * @category Batch Operations
3451
+ */
3452
+ async insertMany(rows) {
3453
+ return this.insert(rows);
3454
+ }
3455
+ /**
3456
+ * Update multiple rows matching the filters (batch update)
3457
+ *
3458
+ * Updates all rows that match the current query filters.
3459
+ * This is a convenience method that explicitly shows intent for batch operations.
3460
+ *
3461
+ * @param data - Data to update matching rows with
3462
+ * @returns Promise with the updated rows
3463
+ *
3464
+ * @example
3465
+ * ```typescript
3466
+ * // Apply discount to all electronics
3467
+ * const { data } = await client.from('products')
3468
+ * .eq('category', 'electronics')
3469
+ * .updateMany({ discount: 10, updated_at: new Date() })
3470
+ * .execute()
3471
+ *
3472
+ * // Mark all pending orders as processing
3473
+ * const { data } = await client.from('orders')
3474
+ * .eq('status', 'pending')
3475
+ * .updateMany({ status: 'processing' })
3476
+ * .execute()
3477
+ * ```
3478
+ *
3479
+ * @category Batch Operations
3480
+ */
3481
+ async updateMany(data) {
3482
+ return this.update(data);
3483
+ }
3484
+ /**
3485
+ * Delete multiple rows matching the filters (batch delete)
3486
+ *
3487
+ * Deletes all rows that match the current query filters.
3488
+ * This is a convenience method that explicitly shows intent for batch operations.
3489
+ *
3490
+ * @returns Promise confirming deletion
3491
+ *
3492
+ * @example
3493
+ * ```typescript
3494
+ * // Delete all inactive users
3495
+ * await client.from('users')
3496
+ * .eq('active', false)
3497
+ * .deleteMany()
3498
+ * .execute()
3499
+ *
3500
+ * // Delete old logs
3501
+ * await client.from('logs')
3502
+ * .lt('created_at', '2024-01-01')
3503
+ * .deleteMany()
3504
+ * .execute()
3505
+ * ```
3506
+ *
3507
+ * @category Batch Operations
3508
+ */
3509
+ async deleteMany() {
3510
+ return this.delete();
3511
+ }
3512
+ /**
3513
+ * Execute the query and return results
3514
+ */
3515
+ async execute() {
3516
+ const queryString = this.buildQueryString();
3517
+ const path = `/api/v1/tables/${this.table}${queryString}`;
3518
+ try {
3519
+ const data = await this.fetch.get(path);
3520
+ if (this.singleRow) {
3521
+ if (Array.isArray(data) && data.length === 0) {
3522
+ return {
3523
+ data: null,
3524
+ error: { message: "No rows found", code: "PGRST116" },
3525
+ count: 0,
3526
+ status: 404,
3527
+ statusText: "Not Found"
3528
+ };
3529
+ }
3530
+ const singleData = Array.isArray(data) ? data[0] : data;
3531
+ return {
3532
+ data: singleData,
3533
+ error: null,
3534
+ count: 1,
3535
+ status: 200,
3536
+ statusText: "OK"
3537
+ };
3538
+ }
3539
+ return {
3540
+ data,
3541
+ error: null,
3542
+ count: Array.isArray(data) ? data.length : null,
3543
+ status: 200,
3544
+ statusText: "OK"
3545
+ };
3546
+ } catch (err) {
3547
+ const error = err;
3548
+ return {
3549
+ data: null,
3550
+ error: {
3551
+ message: error.message,
3552
+ code: "PGRST000"
3553
+ },
3554
+ count: null,
3555
+ status: 500,
3556
+ statusText: "Internal Server Error"
3557
+ };
3558
+ }
3559
+ }
3560
+ /**
3561
+ * Make QueryBuilder awaitable (implements PromiseLike)
3562
+ * This allows using `await client.from('table').select()` without calling `.execute()`
3563
+ *
3564
+ * @example
3565
+ * ```typescript
3566
+ * // Without .execute() (new way)
3567
+ * const { data } = await client.from('users').select('*')
3568
+ *
3569
+ * // With .execute() (old way, still supported)
3570
+ * const { data } = await client.from('users').select('*').execute()
3571
+ * ```
3572
+ */
3573
+ then(onfulfilled, onrejected) {
3574
+ return this.execute().then(onfulfilled, onrejected);
3575
+ }
3576
+ /**
3577
+ * Build the query string from filters, ordering, etc.
3578
+ */
3579
+ buildQueryString() {
3580
+ const params = new URLSearchParams();
3581
+ if (this.selectQuery && this.selectQuery !== "*") {
3582
+ params.append("select", this.selectQuery);
3583
+ }
3584
+ for (const filter of this.filters) {
3585
+ params.append(filter.column, `${filter.operator}.${this.formatValue(filter.value)}`);
3586
+ }
3587
+ if (this.groupByColumns && this.groupByColumns.length > 0) {
3588
+ params.append("group_by", this.groupByColumns.join(","));
3589
+ }
3590
+ if (this.orderBys.length > 0) {
3591
+ const orderStr = this.orderBys.map((o) => `${o.column}.${o.direction}${o.nulls ? `.nulls${o.nulls}` : ""}`).join(",");
3592
+ params.append("order", orderStr);
3593
+ }
3594
+ if (this.limitValue !== void 0) {
3595
+ params.append("limit", String(this.limitValue));
3596
+ }
3597
+ if (this.offsetValue !== void 0) {
3598
+ params.append("offset", String(this.offsetValue));
3599
+ }
3600
+ const queryString = params.toString();
3601
+ return queryString ? `?${queryString}` : "";
3602
+ }
3603
+ /**
3604
+ * Format a value for the query string
3605
+ */
3606
+ formatValue(value) {
3607
+ if (value === null) {
3608
+ return "null";
3609
+ }
3610
+ if (typeof value === "boolean") {
3611
+ return value ? "true" : "false";
3612
+ }
3613
+ if (Array.isArray(value)) {
3614
+ return `(${value.map((v) => this.formatValue(v)).join(",")})`;
3615
+ }
3616
+ if (typeof value === "object") {
3617
+ return JSON.stringify(value);
3618
+ }
3619
+ return String(value);
3620
+ }
3621
+ };
3622
+
3623
+ // src/client.ts
3624
+ var FluxbaseClient = class {
3625
+ /**
3626
+ * Create a new Fluxbase client instance
3627
+ * @param options - Client configuration options
3628
+ */
3629
+ constructor(options) {
3630
+ this.fetch = new FluxbaseFetch(options.url, {
3631
+ headers: options.headers,
3632
+ timeout: options.timeout,
3633
+ debug: options.debug
3634
+ });
3635
+ this.auth = new FluxbaseAuth(
3636
+ this.fetch,
3637
+ options.auth?.autoRefresh ?? true,
3638
+ options.auth?.persist ?? true
3639
+ );
3640
+ if (options.auth?.token) {
3641
+ this.fetch.setAuthToken(options.auth.token);
3642
+ }
3643
+ this.realtime = new FluxbaseRealtime(options.url, options.auth?.token || null);
3644
+ this.storage = new FluxbaseStorage(this.fetch);
3645
+ this.admin = new FluxbaseAdmin(this.fetch);
3646
+ this.management = new FluxbaseManagement(this.fetch);
3647
+ this.setupAuthSync();
3648
+ }
3649
+ /**
3650
+ * Create a query builder for a database table
3651
+ *
3652
+ * @param table - The table name (can include schema, e.g., 'public.users')
3653
+ * @returns A query builder instance for constructing and executing queries
3654
+ *
3655
+ * @example
3656
+ * ```typescript
3657
+ * // Simple select
3658
+ * const { data } = await client.from('users').select('*').execute()
3659
+ *
3660
+ * // With filters
3661
+ * const { data } = await client.from('products')
3662
+ * .select('id, name, price')
3663
+ * .gt('price', 100)
3664
+ * .eq('category', 'electronics')
3665
+ * .execute()
3666
+ *
3667
+ * // Insert
3668
+ * await client.from('users').insert({ name: 'John', email: 'john@example.com' }).execute()
3669
+ * ```
3670
+ *
3671
+ * @category Database
3672
+ */
3673
+ from(table) {
3674
+ return new QueryBuilder(this.fetch, table);
3675
+ }
3676
+ /**
3677
+ * Call a PostgreSQL function (Remote Procedure Call)
3678
+ *
3679
+ * @param functionName - The name of the PostgreSQL function to call
3680
+ * @param params - Optional parameters to pass to the function
3681
+ * @returns Promise containing the function result or error
3682
+ *
3683
+ * @example
3684
+ * ```typescript
3685
+ * // Call a function without parameters
3686
+ * const { data, error } = await client.rpc('get_total_users')
3687
+ *
3688
+ * // Call a function with parameters
3689
+ * const { data, error } = await client.rpc('calculate_discount', {
3690
+ * product_id: 123,
3691
+ * coupon_code: 'SAVE20'
3692
+ * })
3693
+ * ```
3694
+ *
3695
+ * @category Database
3696
+ */
3697
+ async rpc(functionName, params) {
3698
+ try {
3699
+ const data = await this.fetch.post(`/api/v1/rpc/${functionName}`, params || {});
3700
+ return { data, error: null };
3701
+ } catch (error) {
3702
+ return { data: null, error };
3703
+ }
3704
+ }
3705
+ /**
3706
+ * Sync auth state with realtime connections
3707
+ * @internal
3708
+ */
3709
+ setupAuthSync() {
3710
+ const originalSetAuthToken = this.fetch.setAuthToken.bind(this.fetch);
3711
+ this.fetch.setAuthToken = (token) => {
3712
+ originalSetAuthToken(token);
3713
+ this.realtime.setToken(token);
3714
+ };
3715
+ }
3716
+ /**
3717
+ * Get the current authentication token
3718
+ *
3719
+ * @returns The current JWT access token, or null if not authenticated
3720
+ *
3721
+ * @category Authentication
3722
+ */
3723
+ getAuthToken() {
3724
+ return this.auth.getAccessToken();
3725
+ }
3726
+ /**
3727
+ * Set a new authentication token
3728
+ *
3729
+ * This updates both the HTTP client and realtime connection with the new token.
3730
+ *
3731
+ * @param token - The JWT access token to set, or null to clear authentication
3732
+ *
3733
+ * @category Authentication
3734
+ */
3735
+ setAuthToken(token) {
3736
+ this.fetch.setAuthToken(token);
3737
+ this.realtime.setToken(token);
3738
+ }
3739
+ /**
3740
+ * Get the internal HTTP client
3741
+ *
3742
+ * Use this for advanced scenarios like making custom API calls or admin operations.
3743
+ *
3744
+ * @returns The internal FluxbaseFetch instance
3745
+ *
3746
+ * @example
3747
+ * ```typescript
3748
+ * // Make a custom API call
3749
+ * const data = await client.http.get('/api/custom-endpoint')
3750
+ * ```
3751
+ *
3752
+ * @category Advanced
3753
+ */
3754
+ get http() {
3755
+ return this.fetch;
3756
+ }
3757
+ };
3758
+ function createClient(options) {
3759
+ return new FluxbaseClient(options);
3760
+ }
3761
+
3762
+ export { APIKeysManager, AppSettingsManager, AuthSettingsManager, DDLManager, EmailTemplateManager, FluxbaseAdmin, FluxbaseAuth, FluxbaseClient, FluxbaseFetch, FluxbaseManagement, FluxbaseOAuth, FluxbaseRealtime, FluxbaseSettings, FluxbaseStorage, ImpersonationManager, InvitationsManager, OAuthProviderManager, QueryBuilder, RealtimeChannel, StorageBucket, SystemSettingsManager, WebhooksManager, createClient };
3763
+ //# sourceMappingURL=index.js.map
3764
+ //# sourceMappingURL=index.js.map