@fluxbase/sdk 0.0.1-rc.2

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