@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.
- package/dist/expo/index.cjs +1 -1
- package/dist/expo/index.mjs +1 -1
- package/dist/react/index.cjs +856 -115
- package/dist/react/index.d.mts +697 -31
- package/dist/react/index.d.ts +697 -31
- package/dist/react/index.mjs +857 -112
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -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/
|
|
4549
|
-
var
|
|
4550
|
-
|
|
4551
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
4595
|
+
function storeTokenData(provider, data) {
|
|
4570
4596
|
if (typeof window === "undefined") return;
|
|
4571
|
-
|
|
4597
|
+
localStorage.setItem(getStorageKey2(provider), JSON.stringify(data));
|
|
4572
4598
|
}
|
|
4573
|
-
function
|
|
4599
|
+
function clearTokenData(provider) {
|
|
4574
4600
|
if (typeof window === "undefined") return;
|
|
4575
|
-
|
|
4601
|
+
localStorage.removeItem(getStorageKey2(provider));
|
|
4576
4602
|
}
|
|
4577
|
-
function
|
|
4578
|
-
if (
|
|
4579
|
-
|
|
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
|
|
4582
|
-
|
|
4583
|
-
|
|
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
|
|
4586
|
-
|
|
4587
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4672
|
+
const storedState = getAndClearOAuthState();
|
|
4673
|
+
if (!code || !state || state !== storedState) {
|
|
4674
|
+
return null;
|
|
4675
|
+
}
|
|
4601
4676
|
try {
|
|
4602
|
-
const response = await
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
},
|
|
4607
|
-
body: new URLSearchParams({
|
|
4677
|
+
const response = await postAuthOauthByProviderExchange({
|
|
4678
|
+
client: apiClient,
|
|
4679
|
+
path: { provider: PROVIDER },
|
|
4680
|
+
body: {
|
|
4608
4681
|
code,
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
redirect_uri: getRedirectUri(callbackPath),
|
|
4612
|
-
code_verifier: verifier
|
|
4613
|
-
})
|
|
4682
|
+
redirect_uri: getRedirectUri(callbackPath)
|
|
4683
|
+
}
|
|
4614
4684
|
});
|
|
4615
|
-
if (!response.
|
|
4616
|
-
throw new Error("
|
|
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
|
-
|
|
4624
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
4634
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
const
|
|
4654
|
-
|
|
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
|
|
4671
|
-
|
|
4672
|
-
|
|
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
|
|
4792
|
+
if (!isConfigured) return;
|
|
4677
4793
|
const handleCallback = async () => {
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
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
|
-
}, [
|
|
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 =
|
|
4817
|
+
const storedToken = await getDropboxAccessToken(apiClient);
|
|
4693
4818
|
if (storedToken) {
|
|
4694
4819
|
setAccessToken(storedToken);
|
|
4695
4820
|
return storedToken;
|
|
4696
4821
|
}
|
|
4697
|
-
return
|
|
4698
|
-
}, [accessToken, appKey, callbackPath, isConfigured]);
|
|
4699
|
-
const logout = useCallback10(() => {
|
|
4700
|
-
|
|
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:
|
|
4864
|
+
requestAccess: requestDropboxAccess
|
|
4739
4865
|
} = useDropboxAuth();
|
|
4740
4866
|
const deps = useMemo4(
|
|
4741
4867
|
() => ({
|
|
4742
|
-
requestDropboxAccess
|
|
4868
|
+
requestDropboxAccess,
|
|
4743
4869
|
requestEncryptionKey: requestEncryptionKey2,
|
|
4744
4870
|
exportConversation,
|
|
4745
4871
|
importConversation
|
|
4746
4872
|
}),
|
|
4747
|
-
[
|
|
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
|
|
4878
|
+
return await requestDropboxAccess();
|
|
4753
4879
|
} catch {
|
|
4754
4880
|
return null;
|
|
4755
4881
|
}
|
|
4756
|
-
}, [dropboxToken,
|
|
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
|
|
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 =
|
|
5147
|
-
if (
|
|
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
|
-
}, [
|
|
5154
|
-
const backup =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|