@reverbia/sdk 1.0.0-next.20251218224340 → 1.0.0-next.20251219092050

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.
@@ -2299,7 +2299,7 @@ function useChatStorage(options) {
2299
2299
  conversationId: convId,
2300
2300
  role: "assistant",
2301
2301
  content: assistantContent,
2302
- model: responseData.model,
2302
+ model: responseData.model || model,
2303
2303
  usage: convertUsageToStored(responseData.usage),
2304
2304
  responseDuration,
2305
2305
  sources
@@ -2995,6 +2995,36 @@ var postApiV1Search = (options) => {
2995
2995
  }
2996
2996
  });
2997
2997
  };
2998
+ var postAuthOauthByProviderExchange = (options) => {
2999
+ return (options.client ?? client).post({
3000
+ url: "/auth/oauth/{provider}/exchange",
3001
+ ...options,
3002
+ headers: {
3003
+ "Content-Type": "application/json",
3004
+ ...options.headers
3005
+ }
3006
+ });
3007
+ };
3008
+ var postAuthOauthByProviderRefresh = (options) => {
3009
+ return (options.client ?? client).post({
3010
+ url: "/auth/oauth/{provider}/refresh",
3011
+ ...options,
3012
+ headers: {
3013
+ "Content-Type": "application/json",
3014
+ ...options.headers
3015
+ }
3016
+ });
3017
+ };
3018
+ var postAuthOauthByProviderRevoke = (options) => {
3019
+ return (options.client ?? client).post({
3020
+ url: "/auth/oauth/{provider}/revoke",
3021
+ ...options,
3022
+ headers: {
3023
+ "Content-Type": "application/json",
3024
+ ...options.headers
3025
+ }
3026
+ });
3027
+ };
2998
3028
 
2999
3029
  // src/lib/memory/constants.ts
3000
3030
  var DEFAULT_LOCAL_EMBEDDING_MODEL = "Snowflake/snowflake-arctic-embed-xs";
@@ -4545,116 +4575,196 @@ import {
4545
4575
  useState as useState10
4546
4576
  } from "react";
4547
4577
 
4548
- // src/lib/backup/dropbox/auth.ts
4549
- var DROPBOX_AUTH_URL = "https://www.dropbox.com/oauth2/authorize";
4550
- var DROPBOX_TOKEN_URL = "https://api.dropboxapi.com/oauth2/token";
4551
- var TOKEN_STORAGE_KEY = "dropbox_access_token";
4552
- var VERIFIER_STORAGE_KEY = "dropbox_code_verifier";
4553
- function generateCodeVerifier() {
4554
- const array = new Uint8Array(32);
4555
- crypto.getRandomValues(array);
4556
- return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
4578
+ // src/lib/backup/oauth/storage.ts
4579
+ var STORAGE_KEY_PREFIX = "oauth_token_";
4580
+ function getStorageKey2(provider) {
4581
+ return `${STORAGE_KEY_PREFIX}${provider}`;
4557
4582
  }
4558
- async function generateCodeChallenge(verifier) {
4559
- const encoder = new TextEncoder();
4560
- const data = encoder.encode(verifier);
4561
- const hash = await crypto.subtle.digest("SHA-256", data);
4562
- const base64 = btoa(String.fromCharCode(...new Uint8Array(hash)));
4563
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
4564
- }
4565
- function getStoredToken() {
4583
+ function getStoredTokenData(provider) {
4566
4584
  if (typeof window === "undefined") return null;
4567
- return sessionStorage.getItem(TOKEN_STORAGE_KEY);
4585
+ try {
4586
+ const stored = localStorage.getItem(getStorageKey2(provider));
4587
+ if (!stored) return null;
4588
+ const data = JSON.parse(stored);
4589
+ if (!data.accessToken) return null;
4590
+ return data;
4591
+ } catch {
4592
+ return null;
4593
+ }
4568
4594
  }
4569
- function storeToken(token) {
4595
+ function storeTokenData(provider, data) {
4570
4596
  if (typeof window === "undefined") return;
4571
- sessionStorage.setItem(TOKEN_STORAGE_KEY, token);
4597
+ localStorage.setItem(getStorageKey2(provider), JSON.stringify(data));
4572
4598
  }
4573
- function clearToken() {
4599
+ function clearTokenData(provider) {
4574
4600
  if (typeof window === "undefined") return;
4575
- sessionStorage.removeItem(TOKEN_STORAGE_KEY);
4601
+ localStorage.removeItem(getStorageKey2(provider));
4576
4602
  }
4577
- function getStoredVerifier() {
4578
- if (typeof window === "undefined") return null;
4579
- return sessionStorage.getItem(VERIFIER_STORAGE_KEY);
4603
+ function isTokenExpired(data, bufferSeconds = 60) {
4604
+ if (!data) return true;
4605
+ if (!data.expiresAt) return false;
4606
+ const now = Date.now();
4607
+ const bufferMs = bufferSeconds * 1e3;
4608
+ return data.expiresAt - bufferMs <= now;
4580
4609
  }
4581
- function storeVerifier(verifier) {
4582
- if (typeof window === "undefined") return;
4583
- sessionStorage.setItem(VERIFIER_STORAGE_KEY, verifier);
4610
+ function getValidAccessToken(provider) {
4611
+ const data = getStoredTokenData(provider);
4612
+ if (!data) return null;
4613
+ if (data.expiresAt && isTokenExpired(data)) {
4614
+ return null;
4615
+ }
4616
+ return data.accessToken;
4584
4617
  }
4585
- function clearVerifier() {
4586
- if (typeof window === "undefined") return;
4587
- sessionStorage.removeItem(VERIFIER_STORAGE_KEY);
4618
+ function getRefreshToken(provider) {
4619
+ const data = getStoredTokenData(provider);
4620
+ return data?.refreshToken ?? null;
4621
+ }
4622
+ function tokenResponseToStoredData(accessToken, expiresIn, refreshToken, scope) {
4623
+ const data = {
4624
+ accessToken,
4625
+ refreshToken,
4626
+ scope
4627
+ };
4628
+ if (expiresIn) {
4629
+ data.expiresAt = Date.now() + expiresIn * 1e3;
4630
+ }
4631
+ return data;
4588
4632
  }
4633
+
4634
+ // src/lib/backup/dropbox/auth.ts
4635
+ var PROVIDER = "dropbox";
4636
+ var STATE_STORAGE_KEY = "dropbox_oauth_state";
4637
+ var DROPBOX_AUTH_URL = "https://www.dropbox.com/oauth2/authorize";
4589
4638
  function getRedirectUri(callbackPath) {
4590
4639
  if (typeof window === "undefined") return "";
4591
4640
  return `${window.location.origin}${callbackPath}`;
4592
4641
  }
4593
- async function handleDropboxCallback(appKey, callbackPath) {
4642
+ function generateState() {
4643
+ const array = new Uint8Array(16);
4644
+ crypto.getRandomValues(array);
4645
+ return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join(
4646
+ ""
4647
+ );
4648
+ }
4649
+ function storeOAuthState(state) {
4650
+ if (typeof window === "undefined") return;
4651
+ sessionStorage.setItem(STATE_STORAGE_KEY, state);
4652
+ }
4653
+ function getAndClearOAuthState() {
4654
+ if (typeof window === "undefined") return null;
4655
+ const state = sessionStorage.getItem(STATE_STORAGE_KEY);
4656
+ sessionStorage.removeItem(STATE_STORAGE_KEY);
4657
+ return state;
4658
+ }
4659
+ function isDropboxCallback() {
4660
+ if (typeof window === "undefined") return false;
4661
+ const url = new URL(window.location.href);
4662
+ const code = url.searchParams.get("code");
4663
+ const state = url.searchParams.get("state");
4664
+ const storedState = sessionStorage.getItem(STATE_STORAGE_KEY);
4665
+ return !!code && !!state && state === storedState;
4666
+ }
4667
+ async function handleDropboxCallback(callbackPath, apiClient) {
4594
4668
  if (typeof window === "undefined") return null;
4595
4669
  const url = new URL(window.location.href);
4596
4670
  const code = url.searchParams.get("code");
4597
4671
  const state = url.searchParams.get("state");
4598
- if (!code || state !== "dropbox_auth") return null;
4599
- const verifier = getStoredVerifier();
4600
- if (!verifier) return null;
4672
+ const storedState = getAndClearOAuthState();
4673
+ if (!code || !state || state !== storedState) {
4674
+ return null;
4675
+ }
4601
4676
  try {
4602
- const response = await fetch(DROPBOX_TOKEN_URL, {
4603
- method: "POST",
4604
- headers: {
4605
- "Content-Type": "application/x-www-form-urlencoded"
4606
- },
4607
- body: new URLSearchParams({
4677
+ const response = await postAuthOauthByProviderExchange({
4678
+ client: apiClient,
4679
+ path: { provider: PROVIDER },
4680
+ body: {
4608
4681
  code,
4609
- grant_type: "authorization_code",
4610
- client_id: appKey,
4611
- redirect_uri: getRedirectUri(callbackPath),
4612
- code_verifier: verifier
4613
- })
4682
+ redirect_uri: getRedirectUri(callbackPath)
4683
+ }
4614
4684
  });
4615
- if (!response.ok) {
4616
- throw new Error("Token exchange failed");
4617
- }
4618
- const data = await response.json();
4619
- const token = data.access_token;
4620
- if (typeof token !== "string" || token.trim() === "") {
4621
- throw new Error("Invalid token response: access_token is missing or empty");
4685
+ if (!response.data?.access_token) {
4686
+ throw new Error("No access token in response");
4622
4687
  }
4623
- storeToken(token);
4624
- clearVerifier();
4688
+ const tokenData = tokenResponseToStoredData(
4689
+ response.data.access_token,
4690
+ response.data.expires_in,
4691
+ response.data.refresh_token,
4692
+ response.data.scope
4693
+ );
4694
+ storeTokenData(PROVIDER, tokenData);
4625
4695
  window.history.replaceState({}, "", window.location.pathname);
4626
- return token;
4696
+ return response.data.access_token;
4697
+ } catch {
4698
+ return null;
4699
+ }
4700
+ }
4701
+ async function refreshDropboxToken(apiClient) {
4702
+ const refreshToken = getRefreshToken(PROVIDER);
4703
+ if (!refreshToken) return null;
4704
+ try {
4705
+ const response = await postAuthOauthByProviderRefresh({
4706
+ client: apiClient,
4707
+ path: { provider: PROVIDER },
4708
+ body: { refresh_token: refreshToken }
4709
+ });
4710
+ if (!response.data?.access_token) {
4711
+ throw new Error("No access token in refresh response");
4712
+ }
4713
+ const currentData = getStoredTokenData(PROVIDER);
4714
+ const tokenData = tokenResponseToStoredData(
4715
+ response.data.access_token,
4716
+ response.data.expires_in,
4717
+ response.data.refresh_token ?? currentData?.refreshToken,
4718
+ response.data.scope ?? currentData?.scope
4719
+ );
4720
+ storeTokenData(PROVIDER, tokenData);
4721
+ return response.data.access_token;
4627
4722
  } catch {
4628
- clearVerifier();
4723
+ clearTokenData(PROVIDER);
4629
4724
  return null;
4630
4725
  }
4631
4726
  }
4727
+ async function revokeDropboxToken(apiClient) {
4728
+ const tokenData = getStoredTokenData(PROVIDER);
4729
+ if (!tokenData) return;
4730
+ try {
4731
+ const tokenToRevoke = tokenData.refreshToken ?? tokenData.accessToken;
4732
+ await postAuthOauthByProviderRevoke({
4733
+ client: apiClient,
4734
+ path: { provider: PROVIDER },
4735
+ body: { token: tokenToRevoke }
4736
+ });
4737
+ } catch {
4738
+ } finally {
4739
+ clearTokenData(PROVIDER);
4740
+ }
4741
+ }
4742
+ async function getDropboxAccessToken(apiClient) {
4743
+ const validToken = getValidAccessToken(PROVIDER);
4744
+ if (validToken) return validToken;
4745
+ return refreshDropboxToken(apiClient);
4746
+ }
4632
4747
  async function startDropboxAuth(appKey, callbackPath) {
4633
- const verifier = generateCodeVerifier();
4634
- const challenge = await generateCodeChallenge(verifier);
4635
- storeVerifier(verifier);
4748
+ const state = generateState();
4749
+ storeOAuthState(state);
4636
4750
  const params = new URLSearchParams({
4637
4751
  client_id: appKey,
4638
4752
  redirect_uri: getRedirectUri(callbackPath),
4639
4753
  response_type: "code",
4640
- code_challenge: challenge,
4641
- code_challenge_method: "S256",
4642
- state: "dropbox_auth",
4754
+ state,
4643
4755
  token_access_type: "offline"
4756
+ // Request refresh token
4644
4757
  });
4645
4758
  window.location.href = `${DROPBOX_AUTH_URL}?${params.toString()}`;
4646
4759
  return new Promise(() => {
4647
4760
  });
4648
4761
  }
4649
- async function requestDropboxAccess(appKey, callbackPath) {
4650
- if (!appKey) {
4651
- throw new Error("Dropbox is not configured");
4652
- }
4653
- const storedToken = getStoredToken();
4654
- if (storedToken) {
4655
- return storedToken;
4656
- }
4657
- return startDropboxAuth(appKey, callbackPath);
4762
+ function clearToken() {
4763
+ clearTokenData(PROVIDER);
4764
+ }
4765
+ function hasDropboxCredentials() {
4766
+ const data = getStoredTokenData(PROVIDER);
4767
+ return !!(data?.accessToken || data?.refreshToken);
4658
4768
  }
4659
4769
 
4660
4770
  // src/react/useDropboxAuth.ts
@@ -4662,26 +4772,41 @@ var DropboxAuthContext = createContext(null);
4662
4772
  function DropboxAuthProvider({
4663
4773
  appKey,
4664
4774
  callbackPath = "/auth/dropbox/callback",
4775
+ apiClient,
4665
4776
  children
4666
4777
  }) {
4667
4778
  const [accessToken, setAccessToken] = useState10(null);
4668
4779
  const isConfigured = !!appKey;
4669
4780
  useEffect6(() => {
4670
- const storedToken = getStoredToken();
4671
- if (storedToken) {
4672
- setAccessToken(storedToken);
4673
- }
4674
- }, []);
4781
+ const checkStoredToken = async () => {
4782
+ if (hasDropboxCredentials()) {
4783
+ const token = await getDropboxAccessToken(apiClient);
4784
+ if (token) {
4785
+ setAccessToken(token);
4786
+ }
4787
+ }
4788
+ };
4789
+ checkStoredToken();
4790
+ }, [apiClient]);
4675
4791
  useEffect6(() => {
4676
- if (!isConfigured || !appKey) return;
4792
+ if (!isConfigured) return;
4677
4793
  const handleCallback = async () => {
4678
- const token = await handleDropboxCallback(appKey, callbackPath);
4679
- if (token) {
4680
- setAccessToken(token);
4794
+ if (isDropboxCallback()) {
4795
+ const token = await handleDropboxCallback(callbackPath, apiClient);
4796
+ if (token) {
4797
+ setAccessToken(token);
4798
+ }
4681
4799
  }
4682
4800
  };
4683
4801
  handleCallback();
4684
- }, [appKey, callbackPath, isConfigured]);
4802
+ }, [callbackPath, isConfigured, apiClient]);
4803
+ const refreshTokenFn = useCallback10(async () => {
4804
+ const token = await getDropboxAccessToken(apiClient);
4805
+ if (token) {
4806
+ setAccessToken(token);
4807
+ }
4808
+ return token;
4809
+ }, [apiClient]);
4685
4810
  const requestAccess = useCallback10(async () => {
4686
4811
  if (!isConfigured || !appKey) {
4687
4812
  throw new Error("Dropbox is not configured");
@@ -4689,17 +4814,17 @@ function DropboxAuthProvider({
4689
4814
  if (accessToken) {
4690
4815
  return accessToken;
4691
4816
  }
4692
- const storedToken = getStoredToken();
4817
+ const storedToken = await getDropboxAccessToken(apiClient);
4693
4818
  if (storedToken) {
4694
4819
  setAccessToken(storedToken);
4695
4820
  return storedToken;
4696
4821
  }
4697
- return requestDropboxAccess(appKey, callbackPath);
4698
- }, [accessToken, appKey, callbackPath, isConfigured]);
4699
- const logout = useCallback10(() => {
4700
- clearToken();
4822
+ return startDropboxAuth(appKey, callbackPath);
4823
+ }, [accessToken, appKey, callbackPath, isConfigured, apiClient]);
4824
+ const logout = useCallback10(async () => {
4825
+ await revokeDropboxToken(apiClient);
4701
4826
  setAccessToken(null);
4702
- }, []);
4827
+ }, [apiClient]);
4703
4828
  return createElement(
4704
4829
  DropboxAuthContext.Provider,
4705
4830
  {
@@ -4708,7 +4833,8 @@ function DropboxAuthProvider({
4708
4833
  isAuthenticated: !!accessToken,
4709
4834
  isConfigured,
4710
4835
  requestAccess,
4711
- logout
4836
+ logout,
4837
+ refreshToken: refreshTokenFn
4712
4838
  }
4713
4839
  },
4714
4840
  children
@@ -4735,25 +4861,25 @@ function useDropboxBackup(options) {
4735
4861
  const {
4736
4862
  accessToken: dropboxToken,
4737
4863
  isConfigured: isDropboxConfigured,
4738
- requestAccess: requestDropboxAccess2
4864
+ requestAccess: requestDropboxAccess
4739
4865
  } = useDropboxAuth();
4740
4866
  const deps = useMemo4(
4741
4867
  () => ({
4742
- requestDropboxAccess: requestDropboxAccess2,
4868
+ requestDropboxAccess,
4743
4869
  requestEncryptionKey: requestEncryptionKey2,
4744
4870
  exportConversation,
4745
4871
  importConversation
4746
4872
  }),
4747
- [requestDropboxAccess2, requestEncryptionKey2, exportConversation, importConversation]
4873
+ [requestDropboxAccess, requestEncryptionKey2, exportConversation, importConversation]
4748
4874
  );
4749
4875
  const ensureToken = useCallback11(async () => {
4750
4876
  if (dropboxToken) return dropboxToken;
4751
4877
  try {
4752
- return await requestDropboxAccess2();
4878
+ return await requestDropboxAccess();
4753
4879
  } catch {
4754
4880
  return null;
4755
4881
  }
4756
- }, [dropboxToken, requestDropboxAccess2]);
4882
+ }, [dropboxToken, requestDropboxAccess]);
4757
4883
  const backup = useCallback11(
4758
4884
  async (backupOptions) => {
4759
4885
  if (!userAddress) {
@@ -4813,8 +4939,247 @@ function useDropboxBackup(options) {
4813
4939
  };
4814
4940
  }
4815
4941
 
4942
+ // src/react/useGoogleDriveAuth.ts
4943
+ import {
4944
+ createContext as createContext2,
4945
+ createElement as createElement2,
4946
+ useCallback as useCallback12,
4947
+ useContext as useContext2,
4948
+ useEffect as useEffect7,
4949
+ useState as useState11
4950
+ } from "react";
4951
+
4952
+ // src/lib/backup/google/auth.ts
4953
+ var PROVIDER2 = "google-drive";
4954
+ var CODE_STORAGE_KEY = "google_oauth_state";
4955
+ var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
4956
+ var DRIVE_SCOPES = [
4957
+ "https://www.googleapis.com/auth/drive.file"
4958
+ // Access to files created by the app
4959
+ ].join(" ");
4960
+ function getRedirectUri2(callbackPath) {
4961
+ if (typeof window === "undefined") return "";
4962
+ return `${window.location.origin}${callbackPath}`;
4963
+ }
4964
+ function generateState2() {
4965
+ const array = new Uint8Array(16);
4966
+ crypto.getRandomValues(array);
4967
+ return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join(
4968
+ ""
4969
+ );
4970
+ }
4971
+ function storeOAuthState2(state) {
4972
+ if (typeof window === "undefined") return;
4973
+ sessionStorage.setItem(CODE_STORAGE_KEY, state);
4974
+ }
4975
+ function getAndClearOAuthState2() {
4976
+ if (typeof window === "undefined") return null;
4977
+ const state = sessionStorage.getItem(CODE_STORAGE_KEY);
4978
+ sessionStorage.removeItem(CODE_STORAGE_KEY);
4979
+ return state;
4980
+ }
4981
+ function isGoogleDriveCallback() {
4982
+ if (typeof window === "undefined") return false;
4983
+ const url = new URL(window.location.href);
4984
+ const code = url.searchParams.get("code");
4985
+ const state = url.searchParams.get("state");
4986
+ const storedState = sessionStorage.getItem(CODE_STORAGE_KEY);
4987
+ return !!code && !!state && state === storedState;
4988
+ }
4989
+ async function handleGoogleDriveCallback(callbackPath, apiClient) {
4990
+ if (typeof window === "undefined") return null;
4991
+ const url = new URL(window.location.href);
4992
+ const code = url.searchParams.get("code");
4993
+ const state = url.searchParams.get("state");
4994
+ const storedState = getAndClearOAuthState2();
4995
+ if (!code || !state || state !== storedState) {
4996
+ return null;
4997
+ }
4998
+ try {
4999
+ const response = await postAuthOauthByProviderExchange({
5000
+ client: apiClient,
5001
+ path: { provider: PROVIDER2 },
5002
+ body: {
5003
+ code,
5004
+ redirect_uri: getRedirectUri2(callbackPath)
5005
+ }
5006
+ });
5007
+ if (!response.data?.access_token) {
5008
+ throw new Error("No access token in response");
5009
+ }
5010
+ const tokenData = tokenResponseToStoredData(
5011
+ response.data.access_token,
5012
+ response.data.expires_in,
5013
+ response.data.refresh_token,
5014
+ response.data.scope
5015
+ );
5016
+ storeTokenData(PROVIDER2, tokenData);
5017
+ window.history.replaceState({}, "", window.location.pathname);
5018
+ return response.data.access_token;
5019
+ } catch {
5020
+ return null;
5021
+ }
5022
+ }
5023
+ async function refreshGoogleDriveToken(apiClient) {
5024
+ const refreshToken = getRefreshToken(PROVIDER2);
5025
+ if (!refreshToken) return null;
5026
+ try {
5027
+ const response = await postAuthOauthByProviderRefresh({
5028
+ client: apiClient,
5029
+ path: { provider: PROVIDER2 },
5030
+ body: { refresh_token: refreshToken }
5031
+ });
5032
+ if (!response.data?.access_token) {
5033
+ throw new Error("No access token in refresh response");
5034
+ }
5035
+ const currentData = getStoredTokenData(PROVIDER2);
5036
+ const tokenData = tokenResponseToStoredData(
5037
+ response.data.access_token,
5038
+ response.data.expires_in,
5039
+ response.data.refresh_token ?? currentData?.refreshToken,
5040
+ response.data.scope ?? currentData?.scope
5041
+ );
5042
+ storeTokenData(PROVIDER2, tokenData);
5043
+ return response.data.access_token;
5044
+ } catch {
5045
+ clearTokenData(PROVIDER2);
5046
+ return null;
5047
+ }
5048
+ }
5049
+ async function revokeGoogleDriveToken(apiClient) {
5050
+ const tokenData = getStoredTokenData(PROVIDER2);
5051
+ if (!tokenData) return;
5052
+ try {
5053
+ const tokenToRevoke = tokenData.refreshToken ?? tokenData.accessToken;
5054
+ await postAuthOauthByProviderRevoke({
5055
+ client: apiClient,
5056
+ path: { provider: PROVIDER2 },
5057
+ body: { token: tokenToRevoke }
5058
+ });
5059
+ } catch {
5060
+ } finally {
5061
+ clearTokenData(PROVIDER2);
5062
+ }
5063
+ }
5064
+ async function getGoogleDriveAccessToken(apiClient) {
5065
+ const validToken = getValidAccessToken(PROVIDER2);
5066
+ if (validToken) return validToken;
5067
+ return refreshGoogleDriveToken(apiClient);
5068
+ }
5069
+ async function startGoogleDriveAuth(clientId, callbackPath) {
5070
+ const state = generateState2();
5071
+ storeOAuthState2(state);
5072
+ const params = new URLSearchParams({
5073
+ client_id: clientId,
5074
+ redirect_uri: getRedirectUri2(callbackPath),
5075
+ response_type: "code",
5076
+ scope: DRIVE_SCOPES,
5077
+ state,
5078
+ access_type: "offline",
5079
+ // Request refresh token
5080
+ prompt: "consent"
5081
+ // Force consent to always get refresh token
5082
+ });
5083
+ window.location.href = `${GOOGLE_AUTH_URL}?${params.toString()}`;
5084
+ return new Promise(() => {
5085
+ });
5086
+ }
5087
+ function getGoogleDriveStoredToken() {
5088
+ return getValidAccessToken(PROVIDER2);
5089
+ }
5090
+ function clearGoogleDriveToken() {
5091
+ clearTokenData(PROVIDER2);
5092
+ }
5093
+ function hasGoogleDriveCredentials() {
5094
+ const data = getStoredTokenData(PROVIDER2);
5095
+ return !!(data?.accessToken || data?.refreshToken);
5096
+ }
5097
+
5098
+ // src/react/useGoogleDriveAuth.ts
5099
+ var GoogleDriveAuthContext = createContext2(null);
5100
+ function GoogleDriveAuthProvider({
5101
+ clientId,
5102
+ callbackPath = "/auth/google/callback",
5103
+ apiClient,
5104
+ children
5105
+ }) {
5106
+ const [accessToken, setAccessToken] = useState11(null);
5107
+ const isConfigured = !!clientId;
5108
+ useEffect7(() => {
5109
+ const checkStoredToken = async () => {
5110
+ if (hasGoogleDriveCredentials()) {
5111
+ const token = await getGoogleDriveAccessToken(apiClient);
5112
+ if (token) {
5113
+ setAccessToken(token);
5114
+ }
5115
+ }
5116
+ };
5117
+ checkStoredToken();
5118
+ }, [apiClient]);
5119
+ useEffect7(() => {
5120
+ if (!isConfigured) return;
5121
+ const handleCallback = async () => {
5122
+ if (isGoogleDriveCallback()) {
5123
+ const token = await handleGoogleDriveCallback(callbackPath, apiClient);
5124
+ if (token) {
5125
+ setAccessToken(token);
5126
+ }
5127
+ }
5128
+ };
5129
+ handleCallback();
5130
+ }, [callbackPath, isConfigured, apiClient]);
5131
+ const refreshTokenFn = useCallback12(async () => {
5132
+ const token = await getGoogleDriveAccessToken(apiClient);
5133
+ if (token) {
5134
+ setAccessToken(token);
5135
+ }
5136
+ return token;
5137
+ }, [apiClient]);
5138
+ const requestAccess = useCallback12(async () => {
5139
+ if (!isConfigured || !clientId) {
5140
+ throw new Error("Google Drive is not configured");
5141
+ }
5142
+ if (accessToken) {
5143
+ return accessToken;
5144
+ }
5145
+ const storedToken = await getGoogleDriveAccessToken(apiClient);
5146
+ if (storedToken) {
5147
+ setAccessToken(storedToken);
5148
+ return storedToken;
5149
+ }
5150
+ return startGoogleDriveAuth(clientId, callbackPath);
5151
+ }, [accessToken, clientId, callbackPath, isConfigured, apiClient]);
5152
+ const logout = useCallback12(async () => {
5153
+ await revokeGoogleDriveToken(apiClient);
5154
+ setAccessToken(null);
5155
+ }, [apiClient]);
5156
+ return createElement2(
5157
+ GoogleDriveAuthContext.Provider,
5158
+ {
5159
+ value: {
5160
+ accessToken,
5161
+ isAuthenticated: !!accessToken,
5162
+ isConfigured,
5163
+ requestAccess,
5164
+ logout,
5165
+ refreshToken: refreshTokenFn
5166
+ }
5167
+ },
5168
+ children
5169
+ );
5170
+ }
5171
+ function useGoogleDriveAuth() {
5172
+ const context = useContext2(GoogleDriveAuthContext);
5173
+ if (!context) {
5174
+ throw new Error(
5175
+ "useGoogleDriveAuth must be used within GoogleDriveAuthProvider"
5176
+ );
5177
+ }
5178
+ return context;
5179
+ }
5180
+
4816
5181
  // src/react/useGoogleDriveBackup.ts
4817
- import { useCallback as useCallback12, useMemo as useMemo5 } from "react";
5182
+ import { useCallback as useCallback13, useMemo as useMemo5 } from "react";
4818
5183
 
4819
5184
  // src/lib/backup/google/api.ts
4820
5185
  var DRIVE_API_URL = "https://www.googleapis.com/drive/v3";
@@ -5121,14 +5486,17 @@ function useGoogleDriveBackup(options) {
5121
5486
  const {
5122
5487
  database,
5123
5488
  userAddress,
5124
- accessToken,
5125
- requestDriveAccess,
5126
5489
  requestEncryptionKey: requestEncryptionKey2,
5127
5490
  exportConversation,
5128
5491
  importConversation,
5129
5492
  rootFolder = DEFAULT_ROOT_FOLDER,
5130
5493
  conversationsFolder = DEFAULT_CONVERSATIONS_FOLDER
5131
5494
  } = options;
5495
+ const {
5496
+ accessToken: driveToken,
5497
+ isConfigured: isDriveConfigured,
5498
+ requestAccess: requestDriveAccess
5499
+ } = useGoogleDriveAuth();
5132
5500
  const deps = useMemo5(
5133
5501
  () => ({
5134
5502
  requestDriveAccess,
@@ -5136,22 +5504,17 @@ function useGoogleDriveBackup(options) {
5136
5504
  exportConversation,
5137
5505
  importConversation
5138
5506
  }),
5139
- [
5140
- requestDriveAccess,
5141
- requestEncryptionKey2,
5142
- exportConversation,
5143
- importConversation
5144
- ]
5507
+ [requestDriveAccess, requestEncryptionKey2, exportConversation, importConversation]
5145
5508
  );
5146
- const ensureToken = useCallback12(async () => {
5147
- if (accessToken) return accessToken;
5509
+ const ensureToken = useCallback13(async () => {
5510
+ if (driveToken) return driveToken;
5148
5511
  try {
5149
5512
  return await requestDriveAccess();
5150
5513
  } catch {
5151
5514
  return null;
5152
5515
  }
5153
- }, [accessToken, requestDriveAccess]);
5154
- const backup = useCallback12(
5516
+ }, [driveToken, requestDriveAccess]);
5517
+ const backup = useCallback13(
5155
5518
  async (backupOptions) => {
5156
5519
  if (!userAddress) {
5157
5520
  return { error: "Please sign in to backup to Google Drive" };
@@ -5178,7 +5541,7 @@ function useGoogleDriveBackup(options) {
5178
5541
  },
5179
5542
  [database, userAddress, ensureToken, deps, rootFolder, conversationsFolder]
5180
5543
  );
5181
- const restore = useCallback12(
5544
+ const restore = useCallback13(
5182
5545
  async (restoreOptions) => {
5183
5546
  if (!userAddress) {
5184
5547
  return { error: "Please sign in to restore from Google Drive" };
@@ -5207,22 +5570,400 @@ function useGoogleDriveBackup(options) {
5207
5570
  return {
5208
5571
  backup,
5209
5572
  restore,
5210
- isAuthenticated: !!accessToken
5573
+ isConfigured: isDriveConfigured,
5574
+ isAuthenticated: !!driveToken
5575
+ };
5576
+ }
5577
+
5578
+ // src/react/useBackupAuth.ts
5579
+ import {
5580
+ createContext as createContext3,
5581
+ createElement as createElement3,
5582
+ useCallback as useCallback14,
5583
+ useContext as useContext3,
5584
+ useEffect as useEffect8,
5585
+ useState as useState12
5586
+ } from "react";
5587
+ var BackupAuthContext = createContext3(null);
5588
+ function BackupAuthProvider({
5589
+ dropboxAppKey,
5590
+ dropboxCallbackPath = "/auth/dropbox/callback",
5591
+ googleClientId,
5592
+ googleCallbackPath = "/auth/google/callback",
5593
+ apiClient,
5594
+ children
5595
+ }) {
5596
+ const [dropboxToken, setDropboxToken] = useState12(null);
5597
+ const isDropboxConfigured = !!dropboxAppKey;
5598
+ const [googleToken, setGoogleToken] = useState12(null);
5599
+ const isGoogleConfigured = !!googleClientId;
5600
+ useEffect8(() => {
5601
+ const checkStoredTokens = async () => {
5602
+ if (hasDropboxCredentials()) {
5603
+ const token = await getDropboxAccessToken(apiClient);
5604
+ if (token) {
5605
+ setDropboxToken(token);
5606
+ }
5607
+ }
5608
+ if (hasGoogleDriveCredentials()) {
5609
+ const token = await getGoogleDriveAccessToken(apiClient);
5610
+ if (token) {
5611
+ setGoogleToken(token);
5612
+ }
5613
+ }
5614
+ };
5615
+ checkStoredTokens();
5616
+ }, [apiClient]);
5617
+ useEffect8(() => {
5618
+ if (!isDropboxConfigured) return;
5619
+ const handleCallback = async () => {
5620
+ if (isDropboxCallback()) {
5621
+ const token = await handleDropboxCallback(
5622
+ dropboxCallbackPath,
5623
+ apiClient
5624
+ );
5625
+ if (token) {
5626
+ setDropboxToken(token);
5627
+ }
5628
+ }
5629
+ };
5630
+ handleCallback();
5631
+ }, [dropboxCallbackPath, isDropboxConfigured, apiClient]);
5632
+ useEffect8(() => {
5633
+ if (!isGoogleConfigured) return;
5634
+ const handleCallback = async () => {
5635
+ if (isGoogleDriveCallback()) {
5636
+ const token = await handleGoogleDriveCallback(
5637
+ googleCallbackPath,
5638
+ apiClient
5639
+ );
5640
+ if (token) {
5641
+ setGoogleToken(token);
5642
+ }
5643
+ }
5644
+ };
5645
+ handleCallback();
5646
+ }, [googleCallbackPath, isGoogleConfigured, apiClient]);
5647
+ const refreshDropboxTokenFn = useCallback14(async () => {
5648
+ const token = await getDropboxAccessToken(apiClient);
5649
+ if (token) {
5650
+ setDropboxToken(token);
5651
+ }
5652
+ return token;
5653
+ }, [apiClient]);
5654
+ const requestDropboxAccess = useCallback14(async () => {
5655
+ if (!isDropboxConfigured || !dropboxAppKey) {
5656
+ throw new Error("Dropbox is not configured");
5657
+ }
5658
+ if (dropboxToken) {
5659
+ return dropboxToken;
5660
+ }
5661
+ const storedToken = await getDropboxAccessToken(apiClient);
5662
+ if (storedToken) {
5663
+ setDropboxToken(storedToken);
5664
+ return storedToken;
5665
+ }
5666
+ return startDropboxAuth(dropboxAppKey, dropboxCallbackPath);
5667
+ }, [
5668
+ dropboxToken,
5669
+ dropboxAppKey,
5670
+ dropboxCallbackPath,
5671
+ isDropboxConfigured,
5672
+ apiClient
5673
+ ]);
5674
+ const logoutDropbox = useCallback14(async () => {
5675
+ await revokeDropboxToken(apiClient);
5676
+ setDropboxToken(null);
5677
+ }, [apiClient]);
5678
+ const refreshGoogleTokenFn = useCallback14(async () => {
5679
+ const token = await getGoogleDriveAccessToken(apiClient);
5680
+ if (token) {
5681
+ setGoogleToken(token);
5682
+ }
5683
+ return token;
5684
+ }, [apiClient]);
5685
+ const requestGoogleAccess = useCallback14(async () => {
5686
+ if (!isGoogleConfigured || !googleClientId) {
5687
+ throw new Error("Google Drive is not configured");
5688
+ }
5689
+ if (googleToken) {
5690
+ return googleToken;
5691
+ }
5692
+ const storedToken = await getGoogleDriveAccessToken(apiClient);
5693
+ if (storedToken) {
5694
+ setGoogleToken(storedToken);
5695
+ return storedToken;
5696
+ }
5697
+ return startGoogleDriveAuth(googleClientId, googleCallbackPath);
5698
+ }, [
5699
+ googleToken,
5700
+ googleClientId,
5701
+ googleCallbackPath,
5702
+ isGoogleConfigured,
5703
+ apiClient
5704
+ ]);
5705
+ const logoutGoogle = useCallback14(async () => {
5706
+ await revokeGoogleDriveToken(apiClient);
5707
+ setGoogleToken(null);
5708
+ }, [apiClient]);
5709
+ const logoutAll = useCallback14(async () => {
5710
+ await Promise.all([
5711
+ isDropboxConfigured ? logoutDropbox() : Promise.resolve(),
5712
+ isGoogleConfigured ? logoutGoogle() : Promise.resolve()
5713
+ ]);
5714
+ }, [isDropboxConfigured, isGoogleConfigured, logoutDropbox, logoutGoogle]);
5715
+ const dropboxState = {
5716
+ accessToken: dropboxToken,
5717
+ isAuthenticated: !!dropboxToken,
5718
+ isConfigured: isDropboxConfigured,
5719
+ requestAccess: requestDropboxAccess,
5720
+ logout: logoutDropbox,
5721
+ refreshToken: refreshDropboxTokenFn
5722
+ };
5723
+ const googleDriveState = {
5724
+ accessToken: googleToken,
5725
+ isAuthenticated: !!googleToken,
5726
+ isConfigured: isGoogleConfigured,
5727
+ requestAccess: requestGoogleAccess,
5728
+ logout: logoutGoogle,
5729
+ refreshToken: refreshGoogleTokenFn
5730
+ };
5731
+ return createElement3(
5732
+ BackupAuthContext.Provider,
5733
+ {
5734
+ value: {
5735
+ dropbox: dropboxState,
5736
+ googleDrive: googleDriveState,
5737
+ hasAnyProvider: isDropboxConfigured || isGoogleConfigured,
5738
+ hasAnyAuthentication: !!dropboxToken || !!googleToken,
5739
+ logoutAll
5740
+ }
5741
+ },
5742
+ children
5743
+ );
5744
+ }
5745
+ function useBackupAuth() {
5746
+ const context = useContext3(BackupAuthContext);
5747
+ if (!context) {
5748
+ throw new Error("useBackupAuth must be used within BackupAuthProvider");
5749
+ }
5750
+ return context;
5751
+ }
5752
+
5753
+ // src/react/useBackup.ts
5754
+ import { useCallback as useCallback15, useMemo as useMemo6 } from "react";
5755
+ function useBackup(options) {
5756
+ const {
5757
+ database,
5758
+ userAddress,
5759
+ requestEncryptionKey: requestEncryptionKey2,
5760
+ exportConversation,
5761
+ importConversation,
5762
+ dropboxFolder = DEFAULT_BACKUP_FOLDER,
5763
+ googleRootFolder = DEFAULT_ROOT_FOLDER,
5764
+ googleConversationsFolder = DEFAULT_CONVERSATIONS_FOLDER
5765
+ } = options;
5766
+ const {
5767
+ dropbox: dropboxAuth,
5768
+ googleDrive: googleDriveAuth,
5769
+ hasAnyProvider,
5770
+ hasAnyAuthentication,
5771
+ logoutAll
5772
+ } = useBackupAuth();
5773
+ const dropboxDeps = useMemo6(
5774
+ () => ({
5775
+ requestDropboxAccess: dropboxAuth.requestAccess,
5776
+ requestEncryptionKey: requestEncryptionKey2,
5777
+ exportConversation,
5778
+ importConversation
5779
+ }),
5780
+ [dropboxAuth.requestAccess, requestEncryptionKey2, exportConversation, importConversation]
5781
+ );
5782
+ const googleDriveDeps = useMemo6(
5783
+ () => ({
5784
+ requestDriveAccess: googleDriveAuth.requestAccess,
5785
+ requestEncryptionKey: requestEncryptionKey2,
5786
+ exportConversation,
5787
+ importConversation
5788
+ }),
5789
+ [googleDriveAuth.requestAccess, requestEncryptionKey2, exportConversation, importConversation]
5790
+ );
5791
+ const dropboxBackup = useCallback15(
5792
+ async (backupOptions) => {
5793
+ if (!userAddress) {
5794
+ return { error: "Please sign in to backup to Dropbox" };
5795
+ }
5796
+ let token = dropboxAuth.accessToken;
5797
+ if (!token) {
5798
+ try {
5799
+ token = await dropboxAuth.requestAccess();
5800
+ } catch {
5801
+ return { error: "Dropbox access denied" };
5802
+ }
5803
+ }
5804
+ try {
5805
+ return await performDropboxExport(
5806
+ database,
5807
+ userAddress,
5808
+ token,
5809
+ dropboxDeps,
5810
+ backupOptions?.onProgress,
5811
+ dropboxFolder
5812
+ );
5813
+ } catch (err) {
5814
+ return {
5815
+ error: err instanceof Error ? err.message : "Failed to backup to Dropbox"
5816
+ };
5817
+ }
5818
+ },
5819
+ [database, userAddress, dropboxAuth, dropboxDeps, dropboxFolder]
5820
+ );
5821
+ const dropboxRestore = useCallback15(
5822
+ async (restoreOptions) => {
5823
+ if (!userAddress) {
5824
+ return { error: "Please sign in to restore from Dropbox" };
5825
+ }
5826
+ let token = dropboxAuth.accessToken;
5827
+ if (!token) {
5828
+ try {
5829
+ token = await dropboxAuth.requestAccess();
5830
+ } catch {
5831
+ return { error: "Dropbox access denied" };
5832
+ }
5833
+ }
5834
+ try {
5835
+ return await performDropboxImport(
5836
+ userAddress,
5837
+ token,
5838
+ dropboxDeps,
5839
+ restoreOptions?.onProgress,
5840
+ dropboxFolder
5841
+ );
5842
+ } catch (err) {
5843
+ return {
5844
+ error: err instanceof Error ? err.message : "Failed to restore from Dropbox"
5845
+ };
5846
+ }
5847
+ },
5848
+ [userAddress, dropboxAuth, dropboxDeps, dropboxFolder]
5849
+ );
5850
+ const googleDriveBackup = useCallback15(
5851
+ async (backupOptions) => {
5852
+ if (!userAddress) {
5853
+ return { error: "Please sign in to backup to Google Drive" };
5854
+ }
5855
+ let token = googleDriveAuth.accessToken;
5856
+ if (!token) {
5857
+ try {
5858
+ token = await googleDriveAuth.requestAccess();
5859
+ } catch {
5860
+ return { error: "Google Drive access denied" };
5861
+ }
5862
+ }
5863
+ try {
5864
+ return await performGoogleDriveExport(
5865
+ database,
5866
+ userAddress,
5867
+ token,
5868
+ googleDriveDeps,
5869
+ backupOptions?.onProgress,
5870
+ googleRootFolder,
5871
+ googleConversationsFolder
5872
+ );
5873
+ } catch (err) {
5874
+ return {
5875
+ error: err instanceof Error ? err.message : "Failed to backup to Google Drive"
5876
+ };
5877
+ }
5878
+ },
5879
+ [
5880
+ database,
5881
+ userAddress,
5882
+ googleDriveAuth,
5883
+ googleDriveDeps,
5884
+ googleRootFolder,
5885
+ googleConversationsFolder
5886
+ ]
5887
+ );
5888
+ const googleDriveRestore = useCallback15(
5889
+ async (restoreOptions) => {
5890
+ if (!userAddress) {
5891
+ return { error: "Please sign in to restore from Google Drive" };
5892
+ }
5893
+ let token = googleDriveAuth.accessToken;
5894
+ if (!token) {
5895
+ try {
5896
+ token = await googleDriveAuth.requestAccess();
5897
+ } catch {
5898
+ return { error: "Google Drive access denied" };
5899
+ }
5900
+ }
5901
+ try {
5902
+ return await performGoogleDriveImport(
5903
+ userAddress,
5904
+ token,
5905
+ googleDriveDeps,
5906
+ restoreOptions?.onProgress,
5907
+ googleRootFolder,
5908
+ googleConversationsFolder
5909
+ );
5910
+ } catch (err) {
5911
+ return {
5912
+ error: err instanceof Error ? err.message : "Failed to restore from Google Drive"
5913
+ };
5914
+ }
5915
+ },
5916
+ [
5917
+ userAddress,
5918
+ googleDriveAuth,
5919
+ googleDriveDeps,
5920
+ googleRootFolder,
5921
+ googleConversationsFolder
5922
+ ]
5923
+ );
5924
+ const dropboxState = {
5925
+ isConfigured: dropboxAuth.isConfigured,
5926
+ isAuthenticated: dropboxAuth.isAuthenticated,
5927
+ backup: dropboxBackup,
5928
+ restore: dropboxRestore,
5929
+ connect: dropboxAuth.requestAccess,
5930
+ disconnect: dropboxAuth.logout
5931
+ };
5932
+ const googleDriveState = {
5933
+ isConfigured: googleDriveAuth.isConfigured,
5934
+ isAuthenticated: googleDriveAuth.isAuthenticated,
5935
+ backup: googleDriveBackup,
5936
+ restore: googleDriveRestore,
5937
+ connect: googleDriveAuth.requestAccess,
5938
+ disconnect: googleDriveAuth.logout
5939
+ };
5940
+ return {
5941
+ dropbox: dropboxState,
5942
+ googleDrive: googleDriveState,
5943
+ hasAnyProvider,
5944
+ hasAnyAuthentication,
5945
+ disconnectAll: logoutAll
5211
5946
  };
5212
5947
  }
5213
5948
  export {
5949
+ DEFAULT_CONVERSATIONS_FOLDER as BACKUP_DRIVE_CONVERSATIONS_FOLDER,
5950
+ DEFAULT_ROOT_FOLDER as BACKUP_DRIVE_ROOT_FOLDER,
5951
+ BackupAuthProvider,
5214
5952
  Conversation as ChatConversation,
5215
5953
  Message as ChatMessage,
5216
5954
  DEFAULT_BACKUP_FOLDER,
5217
5955
  DEFAULT_CONVERSATIONS_FOLDER as DEFAULT_DRIVE_CONVERSATIONS_FOLDER,
5218
5956
  DEFAULT_ROOT_FOLDER as DEFAULT_DRIVE_ROOT_FOLDER,
5957
+ DEFAULT_BACKUP_FOLDER as DEFAULT_DROPBOX_FOLDER,
5219
5958
  DEFAULT_TOOL_SELECTOR_MODEL,
5220
5959
  DropboxAuthProvider,
5960
+ GoogleDriveAuthProvider,
5221
5961
  Memory as StoredMemoryModel,
5222
5962
  ModelPreference as StoredModelPreferenceModel,
5223
5963
  chatStorageMigrations,
5224
5964
  chatStorageSchema,
5225
5965
  clearToken as clearDropboxToken,
5966
+ clearGoogleDriveToken,
5226
5967
  createMemoryContextSystemMessage,
5227
5968
  decryptData,
5228
5969
  decryptDataBytes,
@@ -5233,8 +5974,10 @@ export {
5233
5974
  generateCompositeKey,
5234
5975
  generateConversationId,
5235
5976
  generateUniqueKey,
5236
- getStoredToken as getDropboxToken,
5977
+ getGoogleDriveStoredToken,
5978
+ hasDropboxCredentials,
5237
5979
  hasEncryptionKey,
5980
+ hasGoogleDriveCredentials,
5238
5981
  memoryStorageSchema,
5239
5982
  requestEncryptionKey,
5240
5983
  sdkMigrations,
@@ -5242,12 +5985,14 @@ export {
5242
5985
  sdkSchema,
5243
5986
  selectTool,
5244
5987
  settingsStorageSchema,
5245
- storeToken as storeDropboxToken,
5988
+ useBackup,
5989
+ useBackupAuth,
5246
5990
  useChat,
5247
5991
  useChatStorage,
5248
5992
  useDropboxAuth,
5249
5993
  useDropboxBackup,
5250
5994
  useEncryption,
5995
+ useGoogleDriveAuth,
5251
5996
  useGoogleDriveBackup,
5252
5997
  useImageGeneration,
5253
5998
  useMemoryStorage,