@fluxbase/sdk 0.0.1-rc.32 → 0.0.1-rc.34

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 CHANGED
@@ -293,6 +293,14 @@ var FluxbaseAuth = class {
293
293
  return { user: session.user, session };
294
294
  });
295
295
  }
296
+ /**
297
+ * Refresh the session (Supabase-compatible alias)
298
+ * Alias for refreshSession() to maintain compatibility with Supabase naming
299
+ * Returns a new session with refreshed tokens
300
+ */
301
+ async refreshToken() {
302
+ return this.refreshSession();
303
+ }
296
304
  /**
297
305
  * Get the current user from the server
298
306
  */
@@ -349,15 +357,17 @@ var FluxbaseAuth = class {
349
357
  /**
350
358
  * Setup 2FA for the current user (Supabase-compatible)
351
359
  * Enrolls a new MFA factor and returns TOTP details
360
+ * @param issuer - Optional custom issuer name for the QR code (e.g., "MyApp"). If not provided, uses server default.
352
361
  * @returns Promise with factor id, type, and TOTP setup details
353
362
  */
354
- async setup2FA() {
363
+ async setup2FA(issuer) {
355
364
  return wrapAsync(async () => {
356
365
  if (!this.session) {
357
366
  throw new Error("Not authenticated");
358
367
  }
359
368
  return await this.fetch.post(
360
- "/api/v1/auth/2fa/setup"
369
+ "/api/v1/auth/2fa/setup",
370
+ issuer ? { issuer } : void 0
361
371
  );
362
372
  });
363
373
  }
@@ -619,6 +629,136 @@ var FluxbaseAuth = class {
619
629
  return { provider, url };
620
630
  });
621
631
  }
632
+ /**
633
+ * Sign in with OTP (One-Time Password) - Supabase-compatible
634
+ * Sends a one-time password via email or SMS for passwordless authentication
635
+ * @param credentials - Email or phone number and optional configuration
636
+ * @returns Promise with OTP-style response
637
+ */
638
+ async signInWithOtp(credentials) {
639
+ return wrapAsync(async () => {
640
+ await this.fetch.post("/api/v1/auth/otp/signin", credentials);
641
+ return { user: null, session: null };
642
+ });
643
+ }
644
+ /**
645
+ * Verify OTP (One-Time Password) - Supabase-compatible
646
+ * Verify OTP tokens for various authentication flows
647
+ * @param params - OTP verification parameters including token and type
648
+ * @returns Promise with user and session if successful
649
+ */
650
+ async verifyOtp(params) {
651
+ return wrapAsync(async () => {
652
+ const response = await this.fetch.post(
653
+ "/api/v1/auth/otp/verify",
654
+ params
655
+ );
656
+ if (response.access_token && response.refresh_token) {
657
+ const session = {
658
+ ...response,
659
+ expires_at: Date.now() + response.expires_in * 1e3
660
+ };
661
+ this.setSessionInternal(session);
662
+ return { user: response.user, session };
663
+ }
664
+ return { user: response.user, session: null };
665
+ });
666
+ }
667
+ /**
668
+ * Resend OTP (One-Time Password) - Supabase-compatible
669
+ * Resend OTP code when user doesn't receive it
670
+ * @param params - Resend parameters including type and email/phone
671
+ * @returns Promise with OTP-style response
672
+ */
673
+ async resendOtp(params) {
674
+ return wrapAsync(async () => {
675
+ await this.fetch.post("/api/v1/auth/otp/resend", params);
676
+ return { user: null, session: null };
677
+ });
678
+ }
679
+ /**
680
+ * Get user identities (linked OAuth providers) - Supabase-compatible
681
+ * Lists all OAuth identities linked to the current user
682
+ * @returns Promise with list of user identities
683
+ */
684
+ async getUserIdentities() {
685
+ return wrapAsync(async () => {
686
+ if (!this.session) {
687
+ throw new Error("Not authenticated");
688
+ }
689
+ return await this.fetch.get(
690
+ "/api/v1/auth/user/identities"
691
+ );
692
+ });
693
+ }
694
+ /**
695
+ * Link an OAuth identity to current user - Supabase-compatible
696
+ * Links an additional OAuth provider to the existing account
697
+ * @param credentials - Provider to link
698
+ * @returns Promise with OAuth URL to complete linking
699
+ */
700
+ async linkIdentity(credentials) {
701
+ return wrapAsync(async () => {
702
+ if (!this.session) {
703
+ throw new Error("Not authenticated");
704
+ }
705
+ return await this.fetch.post(
706
+ "/api/v1/auth/user/identities",
707
+ credentials
708
+ );
709
+ });
710
+ }
711
+ /**
712
+ * Unlink an OAuth identity from current user - Supabase-compatible
713
+ * Removes a linked OAuth provider from the account
714
+ * @param params - Identity to unlink
715
+ * @returns Promise with void response
716
+ */
717
+ async unlinkIdentity(params) {
718
+ return wrapAsyncVoid(async () => {
719
+ if (!this.session) {
720
+ throw new Error("Not authenticated");
721
+ }
722
+ await this.fetch.delete(
723
+ `/api/v1/auth/user/identities/${params.identity.id}`
724
+ );
725
+ });
726
+ }
727
+ /**
728
+ * Reauthenticate to get security nonce - Supabase-compatible
729
+ * Get a security nonce for sensitive operations (password change, etc.)
730
+ * @returns Promise with nonce for reauthentication
731
+ */
732
+ async reauthenticate() {
733
+ return wrapAsync(async () => {
734
+ if (!this.session) {
735
+ throw new Error("Not authenticated");
736
+ }
737
+ return await this.fetch.post(
738
+ "/api/v1/auth/reauthenticate"
739
+ );
740
+ });
741
+ }
742
+ /**
743
+ * Sign in with ID token (for native mobile apps) - Supabase-compatible
744
+ * Authenticate using native mobile app ID tokens (Google, Apple)
745
+ * @param credentials - Provider, ID token, and optional nonce
746
+ * @returns Promise with user and session
747
+ */
748
+ async signInWithIdToken(credentials) {
749
+ return wrapAsync(async () => {
750
+ const response = await this.fetch.post(
751
+ "/api/v1/auth/signin/idtoken",
752
+ credentials
753
+ );
754
+ const session = {
755
+ ...response,
756
+ expires_at: Date.now() + response.expires_in * 1e3
757
+ };
758
+ this.setSessionInternal(session);
759
+ return { user: session.user, session };
760
+ });
761
+ }
622
762
  /**
623
763
  * Internal: Set the session and persist it
624
764
  */
@@ -702,6 +842,8 @@ var RealtimeChannel = class {
702
842
  this.maxReconnectAttempts = 10;
703
843
  this.reconnectDelay = 1e3;
704
844
  this.heartbeatInterval = null;
845
+ this.pendingAcks = /* @__PURE__ */ new Map();
846
+ this.messageIdCounter = 0;
705
847
  this.url = url;
706
848
  this.channelName = channelName;
707
849
  this.token = token;
@@ -824,16 +966,40 @@ var RealtimeChannel = class {
824
966
  return "error";
825
967
  }
826
968
  try {
969
+ const messageId = this.config.broadcast?.ack ? `msg_${Date.now()}_${++this.messageIdCounter}` : void 0;
827
970
  this.ws.send(
828
971
  JSON.stringify({
829
972
  type: "broadcast",
830
973
  channel: this.channelName,
831
974
  event: message.event,
832
- payload: message.payload
975
+ payload: message.payload,
976
+ ...messageId && { messageId }
833
977
  })
834
978
  );
835
- if (this.config.broadcast?.ack) {
836
- return "ok";
979
+ if (this.config.broadcast?.ack && messageId) {
980
+ const ackTimeout = this.config.broadcast.ackTimeout || 5e3;
981
+ return await new Promise((resolve, reject) => {
982
+ const timeout = setTimeout(() => {
983
+ this.pendingAcks.delete(messageId);
984
+ reject(new Error("Acknowledgment timeout"));
985
+ }, ackTimeout);
986
+ this.pendingAcks.set(messageId, {
987
+ resolve: (value) => {
988
+ clearTimeout(timeout);
989
+ this.pendingAcks.delete(messageId);
990
+ resolve(value);
991
+ },
992
+ reject: (reason) => {
993
+ clearTimeout(timeout);
994
+ this.pendingAcks.delete(messageId);
995
+ reject(reason);
996
+ },
997
+ timeout
998
+ });
999
+ }).catch((error) => {
1000
+ console.error("[Fluxbase Realtime] Acknowledgment error:", error);
1001
+ return "error";
1002
+ });
837
1003
  }
838
1004
  return "ok";
839
1005
  } catch (error) {
@@ -1012,7 +1178,14 @@ var RealtimeChannel = class {
1012
1178
  }
1013
1179
  break;
1014
1180
  case "ack":
1015
- console.log("[Fluxbase Realtime] Subscription acknowledged");
1181
+ if (message.messageId && this.pendingAcks.has(message.messageId)) {
1182
+ const ackHandler = this.pendingAcks.get(message.messageId);
1183
+ if (ackHandler) {
1184
+ ackHandler.resolve(message.status || "ok");
1185
+ }
1186
+ } else {
1187
+ console.log("[Fluxbase Realtime] Acknowledged:", message);
1188
+ }
1016
1189
  break;
1017
1190
  case "error":
1018
1191
  console.error("[Fluxbase Realtime] Error:", message.error);