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