@basictech/react 0.6.0 → 0.7.0-beta.1

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/changelog.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # 1.3.4
2
2
 
3
+ ## 0.7.0-beta.1
4
+
5
+ ### Minor Changes
6
+
7
+ - storage adapater update
8
+
9
+ ## 0.7.0-beta.0
10
+
11
+ ### Minor Changes
12
+
13
+ - localstorage update
14
+
3
15
  ## 0.6.0
4
16
 
5
17
  ### Minor Changes
package/dist/index.d.mts CHANGED
@@ -2,6 +2,11 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
3
  export { useLiveQuery as useQuery } from 'dexie-react-hooks';
4
4
 
5
+ interface BasicStorage {
6
+ get(key: string): Promise<string | null>;
7
+ set(key: string, value: string): Promise<void>;
8
+ remove(key: string): Promise<void>;
9
+ }
5
10
  declare enum DBStatus {
6
11
  LOADING = "LOADING",
7
12
  OFFLINE = "OFFLINE",
@@ -19,21 +24,26 @@ type User = {
19
24
  };
20
25
  fullName?: string;
21
26
  };
22
- declare function BasicProvider({ children, project_id, schema, debug }: {
27
+ declare function BasicProvider({ children, project_id, schema, debug, storage }: {
23
28
  children: React.ReactNode;
24
29
  project_id?: string;
25
30
  schema?: any;
26
31
  debug?: boolean;
32
+ storage?: BasicStorage;
27
33
  }): react_jsx_runtime.JSX.Element;
28
34
  declare function useBasic(): {
29
35
  unicorn: string;
30
36
  isAuthReady: boolean;
31
37
  isSignedIn: boolean;
32
38
  user: User | null;
33
- signout: () => void;
34
- signin: () => void;
39
+ signout: () => Promise<void>;
40
+ signin: () => Promise<void>;
41
+ signinWithCode: (code: string, state?: string) => Promise<{
42
+ success: boolean;
43
+ error?: string;
44
+ }>;
35
45
  getToken: () => Promise<string>;
36
- getSignInLink: () => string;
46
+ getSignInLink: (redirectUri?: string) => Promise<string>;
37
47
  db: any;
38
48
  dbStatus: DBStatus;
39
49
  };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,11 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
3
  export { useLiveQuery as useQuery } from 'dexie-react-hooks';
4
4
 
5
+ interface BasicStorage {
6
+ get(key: string): Promise<string | null>;
7
+ set(key: string, value: string): Promise<void>;
8
+ remove(key: string): Promise<void>;
9
+ }
5
10
  declare enum DBStatus {
6
11
  LOADING = "LOADING",
7
12
  OFFLINE = "OFFLINE",
@@ -19,21 +24,26 @@ type User = {
19
24
  };
20
25
  fullName?: string;
21
26
  };
22
- declare function BasicProvider({ children, project_id, schema, debug }: {
27
+ declare function BasicProvider({ children, project_id, schema, debug, storage }: {
23
28
  children: React.ReactNode;
24
29
  project_id?: string;
25
30
  schema?: any;
26
31
  debug?: boolean;
32
+ storage?: BasicStorage;
27
33
  }): react_jsx_runtime.JSX.Element;
28
34
  declare function useBasic(): {
29
35
  unicorn: string;
30
36
  isAuthReady: boolean;
31
37
  isSignedIn: boolean;
32
38
  user: User | null;
33
- signout: () => void;
34
- signin: () => void;
39
+ signout: () => Promise<void>;
40
+ signin: () => Promise<void>;
41
+ signinWithCode: (code: string, state?: string) => Promise<{
42
+ success: boolean;
43
+ error?: string;
44
+ }>;
35
45
  getToken: () => Promise<string>;
36
- getSignInLink: () => string;
46
+ getSignInLink: (redirectUri?: string) => Promise<string>;
37
47
  db: any;
38
48
  dbStatus: DBStatus;
39
49
  };
package/dist/index.js CHANGED
@@ -446,22 +446,33 @@ async function deleteRecord({ projectId, accountId, tableName, id, token }) {
446
446
  var import_schema2 = require("@basictech/schema");
447
447
 
448
448
  // package.json
449
- var version = "0.6.0-beta.0";
449
+ var version = "0.6.0";
450
450
 
451
451
  // src/AuthContext.tsx
452
452
  var import_jsx_runtime = require("react/jsx-runtime");
453
+ var LocalStorageAdapter = class {
454
+ async get(key) {
455
+ return localStorage.getItem(key);
456
+ }
457
+ async set(key, value) {
458
+ localStorage.setItem(key, value);
459
+ }
460
+ async remove(key) {
461
+ localStorage.removeItem(key);
462
+ }
463
+ };
453
464
  var BasicContext = (0, import_react.createContext)({
454
465
  unicorn: "\u{1F984}",
455
466
  isAuthReady: false,
456
467
  isSignedIn: false,
457
468
  user: null,
458
- signout: () => {
459
- },
460
- signin: () => {
461
- },
469
+ signout: () => Promise.resolve(),
470
+ signin: () => Promise.resolve(),
471
+ signinWithCode: () => new Promise(() => {
472
+ }),
462
473
  getToken: () => new Promise(() => {
463
474
  }),
464
- getSignInLink: () => "",
475
+ getSignInLink: () => Promise.resolve(""),
465
476
  db: {},
466
477
  dbStatus: "LOADING" /* LOADING */
467
478
  });
@@ -578,7 +589,13 @@ run "npm install @basictech/react@${latestVersion}" to update`);
578
589
  };
579
590
  }
580
591
  }
581
- function BasicProvider({ children, project_id, schema, debug = false }) {
592
+ function BasicProvider({
593
+ children,
594
+ project_id,
595
+ schema,
596
+ debug = false,
597
+ storage
598
+ }) {
582
599
  const [isAuthReady, setIsAuthReady] = (0, import_react.useState)(false);
583
600
  const [isSignedIn, setIsSignedIn] = (0, import_react.useState)(false);
584
601
  const [token, setToken] = (0, import_react.useState)(null);
@@ -587,7 +604,56 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
587
604
  const [isReady, setIsReady] = (0, import_react.useState)(false);
588
605
  const [dbStatus, setDbStatus] = (0, import_react.useState)("OFFLINE" /* OFFLINE */);
589
606
  const [error, setError] = (0, import_react.useState)(null);
607
+ const [isOnline, setIsOnline] = (0, import_react.useState)(navigator.onLine);
608
+ const [pendingRefresh, setPendingRefresh] = (0, import_react.useState)(false);
590
609
  const syncRef = (0, import_react.useRef)(null);
610
+ const storageAdapter = storage || new LocalStorageAdapter();
611
+ const STORAGE_KEYS = {
612
+ REFRESH_TOKEN: "basic_refresh_token",
613
+ USER_INFO: "basic_user_info",
614
+ AUTH_STATE: "basic_auth_state",
615
+ DEBUG: "basic_debug"
616
+ };
617
+ const isDevelopment = () => {
618
+ return window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname.includes("localhost") || window.location.hostname.includes("127.0.0.1") || window.location.hostname.includes(".local") || process.env.NODE_ENV === "development" || debug === true;
619
+ };
620
+ const cleanOAuthParamsFromUrl = () => {
621
+ if (window.location.search.includes("code") || window.location.search.includes("state")) {
622
+ const url = new URL(window.location.href);
623
+ url.searchParams.delete("code");
624
+ url.searchParams.delete("state");
625
+ window.history.pushState({}, document.title, url.pathname + url.search);
626
+ log("Cleaned OAuth parameters from URL");
627
+ }
628
+ };
629
+ (0, import_react.useEffect)(() => {
630
+ const handleOnline = () => {
631
+ log("Network came back online");
632
+ setIsOnline(true);
633
+ if (pendingRefresh) {
634
+ log("Retrying pending token refresh");
635
+ setPendingRefresh(false);
636
+ if (token) {
637
+ const refreshToken = token.refresh_token || localStorage.getItem("basic_refresh_token");
638
+ if (refreshToken) {
639
+ fetchToken(refreshToken).catch((error2) => {
640
+ log("Retry refresh failed:", error2);
641
+ });
642
+ }
643
+ }
644
+ }
645
+ };
646
+ const handleOffline = () => {
647
+ log("Network went offline");
648
+ setIsOnline(false);
649
+ };
650
+ window.addEventListener("online", handleOnline);
651
+ window.addEventListener("offline", handleOffline);
652
+ return () => {
653
+ window.removeEventListener("online", handleOnline);
654
+ window.removeEventListener("offline", handleOffline);
655
+ };
656
+ }, [pendingRefresh, token]);
591
657
  (0, import_react.useEffect)(() => {
592
658
  function initDb(options) {
593
659
  if (!syncRef.current) {
@@ -653,32 +719,68 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
653
719
  connectToDb();
654
720
  }
655
721
  }, [isSignedIn, shouldConnect]);
722
+ const connectToDb = async () => {
723
+ const tok = await getToken();
724
+ if (!tok) {
725
+ log("no token found");
726
+ return;
727
+ }
728
+ log("connecting to db...");
729
+ syncRef.current.connect({ access_token: tok }).catch((e) => {
730
+ log("error connecting to db", e);
731
+ });
732
+ };
656
733
  (0, import_react.useEffect)(() => {
657
- localStorage.setItem("basic_debug", debug ? "true" : "false");
658
- try {
659
- if (window.location.search.includes("code")) {
660
- let code = window.location?.search?.split("code=")[1].split("&")[0];
661
- const state = localStorage.getItem("basic_auth_state");
662
- if (!state || state !== window.location.search.split("state=")[1].split("&")[0]) {
663
- log("error: auth state does not match");
664
- setIsAuthReady(true);
665
- localStorage.removeItem("basic_auth_state");
666
- window.history.pushState({}, document.title, "/");
667
- return;
668
- }
669
- localStorage.removeItem("basic_auth_state");
670
- fetchToken(code);
671
- } else {
672
- let cookie_token = getCookie("basic_token");
673
- if (cookie_token !== "") {
674
- setToken(JSON.parse(cookie_token));
734
+ const initializeAuth = async () => {
735
+ await storageAdapter.set(STORAGE_KEYS.DEBUG, debug ? "true" : "false");
736
+ try {
737
+ if (window.location.search.includes("code")) {
738
+ let code = window.location?.search?.split("code=")[1].split("&")[0];
739
+ const state = await storageAdapter.get(STORAGE_KEYS.AUTH_STATE);
740
+ if (!state || state !== window.location.search.split("state=")[1].split("&")[0]) {
741
+ log("error: auth state does not match");
742
+ setIsAuthReady(true);
743
+ await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
744
+ cleanOAuthParamsFromUrl();
745
+ return;
746
+ }
747
+ await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
748
+ cleanOAuthParamsFromUrl();
749
+ fetchToken(code);
675
750
  } else {
676
- setIsAuthReady(true);
751
+ const refreshToken = await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN);
752
+ if (refreshToken) {
753
+ log("Found refresh token in storage, attempting to refresh access token");
754
+ fetchToken(refreshToken);
755
+ } else {
756
+ let cookie_token = getCookie("basic_token");
757
+ if (cookie_token !== "") {
758
+ const tokenData = JSON.parse(cookie_token);
759
+ setToken(tokenData);
760
+ if (tokenData.refresh_token) {
761
+ await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, tokenData.refresh_token);
762
+ }
763
+ } else {
764
+ const cachedUserInfo = await storageAdapter.get(STORAGE_KEYS.USER_INFO);
765
+ if (cachedUserInfo) {
766
+ try {
767
+ const userData = JSON.parse(cachedUserInfo);
768
+ setUser(userData);
769
+ setIsSignedIn(true);
770
+ log("Loaded cached user info for offline mode");
771
+ } catch (error2) {
772
+ log("Error parsing cached user info:", error2);
773
+ }
774
+ }
775
+ setIsAuthReady(true);
776
+ }
777
+ }
677
778
  }
779
+ } catch (e) {
780
+ log("error getting token", e);
678
781
  }
679
- } catch (e) {
680
- log("error getting cookie", e);
681
- }
782
+ };
783
+ initializeAuth();
682
784
  }, []);
683
785
  (0, import_react.useEffect)(() => {
684
786
  async function fetchUser(acc_token) {
@@ -693,10 +795,13 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
693
795
  log("error fetching user", user2.error);
694
796
  return;
695
797
  } else {
696
- document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;
697
- if (window.location.search.includes("code")) {
698
- window.history.pushState({}, document.title, "/");
798
+ if (token?.refresh_token) {
799
+ await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, token.refresh_token);
699
800
  }
801
+ await storageAdapter.set(STORAGE_KEYS.USER_INFO, JSON.stringify(user2));
802
+ log("Cached user info in storage");
803
+ document.cookie = `basic_access_token=${token.access_token}; Secure; SameSite=Strict; HttpOnly=false`;
804
+ document.cookie = `basic_token=${JSON.stringify(token)}; Secure; SameSite=Strict`;
700
805
  setUser(user2);
701
806
  setIsSignedIn(true);
702
807
  setIsAuthReady(true);
@@ -712,8 +817,18 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
712
817
  const isExpired = decoded.exp && decoded.exp < Date.now() / 1e3;
713
818
  if (isExpired) {
714
819
  log("token is expired - refreshing ...");
715
- const newToken = await fetchToken(token?.refresh);
716
- fetchUser(newToken.access_token);
820
+ try {
821
+ const newToken = await fetchToken(token?.refresh_token);
822
+ fetchUser(newToken.access_token);
823
+ } catch (error2) {
824
+ log("Failed to refresh token in checkToken:", error2);
825
+ if (error2.message.includes("offline") || error2.message.includes("Network")) {
826
+ log("Network issue - continuing with expired token until online");
827
+ fetchUser(token.access_token);
828
+ } else {
829
+ setIsAuthReady(true);
830
+ }
831
+ }
717
832
  } else {
718
833
  fetchUser(token.access_token);
719
834
  }
@@ -722,41 +837,97 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
722
837
  checkToken();
723
838
  }
724
839
  }, [token]);
725
- const connectToDb = async () => {
726
- const tok = await getToken();
727
- if (!tok) {
728
- log("no token found");
729
- return;
840
+ const getSignInLink = async (redirectUri) => {
841
+ try {
842
+ log("getting sign in link...");
843
+ if (!project_id) {
844
+ throw new Error("Project ID is required to generate sign-in link");
845
+ }
846
+ const randomState = Math.random().toString(36).substring(6);
847
+ await storageAdapter.set(STORAGE_KEYS.AUTH_STATE, randomState);
848
+ const redirectUrl = redirectUri || window.location.href;
849
+ if (!redirectUrl || !redirectUrl.startsWith("http://") && !redirectUrl.startsWith("https://")) {
850
+ throw new Error("Invalid redirect URI provided");
851
+ }
852
+ let baseUrl2 = "https://api.basic.tech/auth/authorize";
853
+ baseUrl2 += `?client_id=${project_id}`;
854
+ baseUrl2 += `&redirect_uri=${encodeURIComponent(redirectUrl)}`;
855
+ baseUrl2 += `&response_type=code`;
856
+ baseUrl2 += `&scope=profile`;
857
+ baseUrl2 += `&state=${randomState}`;
858
+ log("Generated sign-in link successfully");
859
+ return baseUrl2;
860
+ } catch (error2) {
861
+ log("Error generating sign-in link:", error2);
862
+ throw error2;
730
863
  }
731
- log("connecting to db...");
732
- syncRef.current.connect({ access_token: tok }).catch((e) => {
733
- log("error connecting to db", e);
734
- });
735
864
  };
736
- const getSignInLink = () => {
737
- log("getting sign in link...");
738
- const randomState = Math.random().toString(36).substring(6);
739
- localStorage.setItem("basic_auth_state", randomState);
740
- let baseUrl2 = "https://api.basic.tech/auth/authorize";
741
- baseUrl2 += `?client_id=${project_id}`;
742
- baseUrl2 += `&redirect_uri=${encodeURIComponent(window.location.href)}`;
743
- baseUrl2 += `&response_type=code`;
744
- baseUrl2 += `&scope=profile`;
745
- baseUrl2 += `&state=${randomState}`;
746
- return baseUrl2;
865
+ const signin = async () => {
866
+ try {
867
+ log("signing in...");
868
+ if (!project_id) {
869
+ log("Error: project_id is required for sign-in");
870
+ throw new Error("Project ID is required for authentication");
871
+ }
872
+ const signInLink = await getSignInLink();
873
+ log("Generated sign-in link:", signInLink);
874
+ if (!signInLink || !signInLink.startsWith("https://")) {
875
+ log("Error: Invalid sign-in link generated");
876
+ throw new Error("Failed to generate valid sign-in URL");
877
+ }
878
+ window.location.href = signInLink;
879
+ } catch (error2) {
880
+ log("Error during sign-in:", error2);
881
+ if (isDevelopment()) {
882
+ setError({
883
+ code: "signin_error",
884
+ title: "Sign-in Failed",
885
+ message: error2.message || "An error occurred during sign-in. Please try again."
886
+ });
887
+ }
888
+ throw error2;
889
+ }
747
890
  };
748
- const signin = () => {
749
- log("signing in: ", getSignInLink());
750
- const signInLink = getSignInLink();
751
- window.location.href = signInLink;
891
+ const signinWithCode = async (code, state) => {
892
+ try {
893
+ log("signinWithCode called with code:", code);
894
+ if (!code || typeof code !== "string") {
895
+ return { success: false, error: "Invalid authorization code" };
896
+ }
897
+ if (state) {
898
+ const storedState = await storageAdapter.get(STORAGE_KEYS.AUTH_STATE);
899
+ if (storedState && storedState !== state) {
900
+ log("State parameter mismatch:", { provided: state, stored: storedState });
901
+ return { success: false, error: "State parameter mismatch" };
902
+ }
903
+ }
904
+ await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
905
+ cleanOAuthParamsFromUrl();
906
+ const token2 = await fetchToken(code);
907
+ if (token2) {
908
+ log("signinWithCode successful");
909
+ return { success: true };
910
+ } else {
911
+ return { success: false, error: "Failed to exchange code for token" };
912
+ }
913
+ } catch (error2) {
914
+ log("signinWithCode error:", error2);
915
+ return {
916
+ success: false,
917
+ error: error2.message || "Authentication failed"
918
+ };
919
+ }
752
920
  };
753
- const signout = () => {
921
+ const signout = async () => {
754
922
  log("signing out!");
755
923
  setUser({});
756
924
  setIsSignedIn(false);
757
925
  setToken(null);
758
926
  document.cookie = `basic_token=; Secure; SameSite=Strict`;
759
- localStorage.removeItem("basic_auth_state");
927
+ document.cookie = `basic_access_token=; Secure; SameSite=Strict`;
928
+ await storageAdapter.remove(STORAGE_KEYS.AUTH_STATE);
929
+ await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
930
+ await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
760
931
  if (syncRef.current) {
761
932
  (async () => {
762
933
  try {
@@ -773,6 +944,27 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
773
944
  const getToken = async () => {
774
945
  log("getting token...");
775
946
  if (!token) {
947
+ const refreshToken = await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN);
948
+ if (refreshToken) {
949
+ log("No token in memory, attempting to refresh from storage");
950
+ try {
951
+ const newToken = await fetchToken(refreshToken);
952
+ if (newToken?.access_token) {
953
+ return newToken.access_token;
954
+ }
955
+ } catch (error2) {
956
+ log("Failed to refresh token from storage:", error2);
957
+ if (error2.message.includes("offline") || error2.message.includes("Network")) {
958
+ log("Network issue - continuing with potentially expired token");
959
+ const lastToken = localStorage.getItem("basic_access_token");
960
+ if (lastToken) {
961
+ return lastToken;
962
+ }
963
+ throw new Error("Network offline - authentication will be retried when online");
964
+ }
965
+ throw new Error("Authentication expired. Please sign in again.");
966
+ }
967
+ }
776
968
  log("no token found");
777
969
  throw new Error("no token found");
778
970
  }
@@ -780,8 +972,22 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
780
972
  const isExpired = decoded.exp && decoded.exp < Date.now() / 1e3;
781
973
  if (isExpired) {
782
974
  log("token is expired - refreshing ...");
783
- const newToken = await fetchToken(token?.refresh);
784
- return newToken?.access_token || "";
975
+ const refreshToken = token?.refresh_token || await storageAdapter.get(STORAGE_KEYS.REFRESH_TOKEN);
976
+ if (refreshToken) {
977
+ try {
978
+ const newToken = await fetchToken(refreshToken);
979
+ return newToken?.access_token || "";
980
+ } catch (error2) {
981
+ log("Failed to refresh expired token:", error2);
982
+ if (error2.message.includes("offline") || error2.message.includes("Network")) {
983
+ log("Network issue - using expired token until network is restored");
984
+ return token.access_token;
985
+ }
986
+ throw new Error("Authentication expired. Please sign in again.");
987
+ }
988
+ } else {
989
+ throw new Error("no refresh token available");
990
+ }
785
991
  }
786
992
  return token?.access_token || "";
787
993
  };
@@ -800,20 +1006,66 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
800
1006
  return cookieValue;
801
1007
  }
802
1008
  const fetchToken = async (code) => {
803
- const token2 = await fetch("https://api.basic.tech/auth/token", {
804
- method: "POST",
805
- headers: {
806
- "Content-Type": "application/json"
807
- },
808
- body: JSON.stringify({ code })
809
- }).then((response) => response.json()).catch((error2) => log("Error:", error2));
810
- if (token2.error) {
811
- log("error fetching token", token2.error);
812
- return;
813
- } else {
814
- setToken(token2);
1009
+ try {
1010
+ if (!isOnline) {
1011
+ log("Network is offline, marking refresh as pending");
1012
+ setPendingRefresh(true);
1013
+ throw new Error("Network offline - refresh will be retried when online");
1014
+ }
1015
+ const token2 = await fetch("https://api.basic.tech/auth/token", {
1016
+ method: "POST",
1017
+ headers: {
1018
+ "Content-Type": "application/json"
1019
+ },
1020
+ body: JSON.stringify({ code })
1021
+ }).then((response) => response.json()).catch((error2) => {
1022
+ log("Network error fetching token:", error2);
1023
+ if (!isOnline) {
1024
+ setPendingRefresh(true);
1025
+ throw new Error("Network offline - refresh will be retried when online");
1026
+ }
1027
+ throw new Error("Network error during token refresh");
1028
+ });
1029
+ if (token2.error) {
1030
+ log("error fetching token", token2.error);
1031
+ if (token2.error.includes("network") || token2.error.includes("timeout")) {
1032
+ setPendingRefresh(true);
1033
+ throw new Error("Network issue - refresh will be retried when online");
1034
+ }
1035
+ await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
1036
+ await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
1037
+ document.cookie = `basic_token=; Secure; SameSite=Strict`;
1038
+ document.cookie = `basic_access_token=; Secure; SameSite=Strict`;
1039
+ setUser({});
1040
+ setIsSignedIn(false);
1041
+ setToken(null);
1042
+ setIsAuthReady(true);
1043
+ throw new Error(`Token refresh failed: ${token2.error}`);
1044
+ } else {
1045
+ setToken(token2);
1046
+ setPendingRefresh(false);
1047
+ if (token2.refresh_token) {
1048
+ await storageAdapter.set(STORAGE_KEYS.REFRESH_TOKEN, token2.refresh_token);
1049
+ log("Updated refresh token in storage");
1050
+ }
1051
+ document.cookie = `basic_access_token=${token2.access_token}; Secure; SameSite=Strict; HttpOnly=false`;
1052
+ log("Updated access token in cookie");
1053
+ }
1054
+ return token2;
1055
+ } catch (error2) {
1056
+ log("Token refresh error:", error2);
1057
+ if (!error2.message.includes("offline") && !error2.message.includes("Network")) {
1058
+ await storageAdapter.remove(STORAGE_KEYS.REFRESH_TOKEN);
1059
+ await storageAdapter.remove(STORAGE_KEYS.USER_INFO);
1060
+ document.cookie = `basic_token=; Secure; SameSite=Strict`;
1061
+ document.cookie = `basic_access_token=; Secure; SameSite=Strict`;
1062
+ setUser({});
1063
+ setIsSignedIn(false);
1064
+ setToken(null);
1065
+ setIsAuthReady(true);
1066
+ }
1067
+ throw error2;
815
1068
  }
816
- return token2;
817
1069
  };
818
1070
  const db_ = (tableName) => {
819
1071
  const checkSignIn = () => {
@@ -856,12 +1108,13 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
856
1108
  user,
857
1109
  signout,
858
1110
  signin,
1111
+ signinWithCode,
859
1112
  getToken,
860
1113
  getSignInLink,
861
1114
  db: syncRef.current ? syncRef.current : noDb,
862
1115
  dbStatus
863
1116
  }, children: [
864
- error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorDisplay, { error }),
1117
+ error && isDevelopment() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorDisplay, { error }),
865
1118
  isReady && children
866
1119
  ] });
867
1120
  }