@fluxbase/sdk 0.0.1-rc.10

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