[Refactor] Replace useApiAuthToken with useAccessToken (#3592)
<!-- start pr-codex -->
## PR-Codex overview
This PR enhances the `siwe_auth` functionality for better user authentication and access control.
### Detailed summary
- Renamed `ConnectWallet` component to `ConnectButton`
- Updated `useExtensionContractInfo` to use `useActiveAccount`
- Replaced `useApiAuthToken` with `useAccessToken` in multiple files
- Improved `useSiweAuth` with additional features and mutations
- Updated components to use `useAccessToken` for authentication
- Refactored `useLoggedInUser` to fetch user data efficiently
> The following files were skipped due to too many changes: `apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts`, `apps/dashboard/src/@3rdweb-sdk/react/components/connect-wallet/index.tsx`, `apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts`
> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`
<!-- end pr-codex -->
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"thirdweb": patch
|
||||
---
|
||||
|
||||
make siwe_auth more robust
|
||||
@@ -15,10 +15,75 @@ import Link from "next/link";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { defineChain } from "thirdweb";
|
||||
import { ConnectButton, type SiweAuthOptions } from "thirdweb/react";
|
||||
import { GLOBAL_AUTH_TOKEN_KEY } from "../../../../constants/app";
|
||||
import { fetchAuthToken } from "../../hooks/useApi";
|
||||
import { useFavoriteChains } from "../../hooks/useFavoriteChains";
|
||||
import { fetchUserQuery } from "../../hooks/useLoggedInUser";
|
||||
import { popularChains } from "../popularChains";
|
||||
import { clearAccessToken, setAccessToken } from "./useAccessToken";
|
||||
|
||||
// TODO remove all of this
|
||||
|
||||
type FetchAuthTokenResponse = {
|
||||
jwt: string;
|
||||
};
|
||||
|
||||
const TOKEN_PROMISE_MAP = new Map<string, Promise<FetchAuthTokenResponse>>();
|
||||
|
||||
async function fetchAuthToken(
|
||||
address: string,
|
||||
abortController?: AbortController,
|
||||
): Promise<FetchAuthTokenResponse> {
|
||||
if (!address) {
|
||||
throw new Error("address is required");
|
||||
}
|
||||
if (TOKEN_PROMISE_MAP.has(address)) {
|
||||
return TOKEN_PROMISE_MAP.get(address) as Promise<FetchAuthTokenResponse>;
|
||||
}
|
||||
const promise = new Promise<FetchAuthTokenResponse>((resolve, reject) => {
|
||||
return fetch(`${THIRDWEB_API_HOST}/v1/auth/token`, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
signal: abortController?.signal,
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((json) => {
|
||||
if (json.error) {
|
||||
throw new Error(json.error.message);
|
||||
}
|
||||
return {
|
||||
jwt: json.data.jwt as string,
|
||||
};
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.finally(() => {
|
||||
// remove the promise from the map when it's done
|
||||
TOKEN_PROMISE_MAP.delete(address);
|
||||
});
|
||||
});
|
||||
TOKEN_PROMISE_MAP.set(address, promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// END TODO
|
||||
|
||||
export async function logout() {
|
||||
// reset the token ASAP
|
||||
clearAccessToken();
|
||||
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/logout`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error("Failed to logout");
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export interface ConnectWalletProps {
|
||||
shrinkMobile?: boolean;
|
||||
@@ -99,49 +164,29 @@ export const CustomConnectWallet: React.FC<ConnectWalletProps> = ({
|
||||
const json = await res.json();
|
||||
|
||||
if (json.token) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: FIXME
|
||||
(window as any)[GLOBAL_AUTH_TOKEN_KEY] = json.token;
|
||||
queryClient.invalidateQueries({
|
||||
setAccessToken(json.token);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["logged_in_user"],
|
||||
});
|
||||
}
|
||||
return json;
|
||||
},
|
||||
doLogout: async () => {
|
||||
// reset the token ASAP
|
||||
// biome-ignore lint/suspicious/noExplicitAny: FIXME
|
||||
(window as any)[GLOBAL_AUTH_TOKEN_KEY] = undefined;
|
||||
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/logout`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
const l = await logout();
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["logged_in_user"],
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error("Failed to logout");
|
||||
}
|
||||
return res.json();
|
||||
return l;
|
||||
},
|
||||
isLoggedIn: async (address) => {
|
||||
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/user`, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!res.ok) {
|
||||
const user = await queryClient.fetchQuery(fetchUserQuery(address));
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { jwt } = await fetchAuthToken(address);
|
||||
if (jwt) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: FIXME
|
||||
(window as any)[GLOBAL_AUTH_TOKEN_KEY] = jwt;
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["logged_in_user"],
|
||||
});
|
||||
setAccessToken(jwt);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useSyncExternalStore } from "react";
|
||||
|
||||
// historical reasons
|
||||
const GLOBAL_AUTH_TOKEN_KEY = "TW_AUTH_TOKEN";
|
||||
|
||||
let currentAccessToken: string | null = null;
|
||||
let listeners: Array<() => void> = [];
|
||||
|
||||
const accessTokenStore = {
|
||||
set: (value: string | null) => {
|
||||
// also set it on window (because of legacy things reading from there)
|
||||
// biome-ignore lint/suspicious/noExplicitAny: needed
|
||||
(window as any)[GLOBAL_AUTH_TOKEN_KEY] = value;
|
||||
currentAccessToken = value;
|
||||
for (const listener of listeners) {
|
||||
listener();
|
||||
}
|
||||
},
|
||||
getSnapshot: () => currentAccessToken,
|
||||
subscribe: (listener: () => void) => {
|
||||
listeners = [...listeners, listener];
|
||||
return () => {
|
||||
listeners = listeners.filter((l) => l !== listener);
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export function setAccessToken(value: string) {
|
||||
accessTokenStore.set(value);
|
||||
}
|
||||
export function clearAccessToken() {
|
||||
accessTokenStore.set(null);
|
||||
}
|
||||
|
||||
export function useAccessToken() {
|
||||
return useSyncExternalStore(
|
||||
accessTokenStore.subscribe,
|
||||
accessTokenStore.getSnapshot,
|
||||
// TODO: we should actually be able to grab this server side once we move auth to the next server
|
||||
() => null,
|
||||
);
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
import type { Chain } from "@thirdweb-dev/chains";
|
||||
import { useEffect, useState } from "react";
|
||||
import invariant from "tiny-invariant";
|
||||
import { THIRDWEB_API_HOST } from "../../../constants/urls";
|
||||
import { accountKeys, apiKeys, authorizedWallets } from "../cache-keys";
|
||||
@@ -953,114 +952,6 @@ export function useAuthorizedWallets() {
|
||||
);
|
||||
}
|
||||
|
||||
type FetchAuthTokenResponse = {
|
||||
jwt: string;
|
||||
paymentsSellerId?: string;
|
||||
};
|
||||
|
||||
const TOKEN_PROMISE_MAP = new Map<string, Promise<FetchAuthTokenResponse>>();
|
||||
|
||||
export async function fetchAuthToken(
|
||||
address: string,
|
||||
abortController?: AbortController,
|
||||
): Promise<FetchAuthTokenResponse> {
|
||||
if (!address) {
|
||||
throw new Error("address is required");
|
||||
}
|
||||
if (TOKEN_PROMISE_MAP.has(address)) {
|
||||
return TOKEN_PROMISE_MAP.get(address) as Promise<FetchAuthTokenResponse>;
|
||||
}
|
||||
const promise = new Promise<FetchAuthTokenResponse>((resolve, reject) => {
|
||||
return fetch(`${THIRDWEB_API_HOST}/v1/auth/token`, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
signal: abortController?.signal,
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((json) => {
|
||||
if (json.error) {
|
||||
throw new Error(json.error.message);
|
||||
}
|
||||
return {
|
||||
jwt: json.data.jwt as string,
|
||||
paymentsSellerId: json.data.paymentsSellerId,
|
||||
};
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.finally(() => {
|
||||
// remove the promise from the map when it's done
|
||||
TOKEN_PROMISE_MAP.delete(address);
|
||||
});
|
||||
});
|
||||
TOKEN_PROMISE_MAP.set(address, promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// keep the promise around so we don't fetch it multiple times even if the hook gets called from different places
|
||||
let inflightPromise: Promise<FetchAuthTokenResponse> | null = null;
|
||||
export function useApiAuthToken() {
|
||||
const { user } = useLoggedInUser();
|
||||
const [token, setToken] = useState<string | null>(null);
|
||||
const [paymentsSellerId, setPaymentsSellerId] = useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
||||
// not using a query because we don't want to store this in any cache
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
setError(null);
|
||||
setIsLoading(false);
|
||||
if (!user?.address) {
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
|
||||
const abortController = new AbortController();
|
||||
|
||||
if (!inflightPromise) {
|
||||
inflightPromise = fetchAuthToken(user.address, abortController);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line promise/catch-or-return
|
||||
inflightPromise
|
||||
.then((t) => {
|
||||
// eslint-disable-next-line promise/always-return
|
||||
if (mounted) {
|
||||
setToken(t.jwt);
|
||||
if (t.paymentsSellerId) {
|
||||
setPaymentsSellerId(t.paymentsSellerId);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (mounted) {
|
||||
setError(err);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
if (mounted) {
|
||||
inflightPromise = null;
|
||||
setIsLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
// cancel the fetch if it's still in flight
|
||||
abortController.abort();
|
||||
inflightPromise = null;
|
||||
setToken(null);
|
||||
};
|
||||
}, [user?.address]);
|
||||
|
||||
return { error, isLoading, token, paymentsSellerId };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -4,8 +4,8 @@ import { useState } from "react";
|
||||
import { useActiveAccount, useActiveWalletChain } from "thirdweb/react";
|
||||
import invariant from "tiny-invariant";
|
||||
import { engineKeys } from "../cache-keys";
|
||||
import { useAccessToken } from "../components/connect-wallet/useAccessToken";
|
||||
import { useMutationWithInvalidate } from "./query/useQueryWithNetwork";
|
||||
import { useApiAuthToken } from "./useApi";
|
||||
import { useLoggedInUser } from "./useLoggedInUser";
|
||||
|
||||
export function useEngineConnectedInstance() {
|
||||
@@ -99,7 +99,7 @@ export type BackendWallet = {
|
||||
};
|
||||
|
||||
export function useEngineBackendWallets(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useQuery(
|
||||
[engineKeys.backendWallets(instance)],
|
||||
@@ -342,7 +342,7 @@ type TransactionResponse = {
|
||||
* @returns
|
||||
*/
|
||||
export function useEngineTransactions(instance: string, autoUpdate: boolean) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useQuery(
|
||||
engineKeys.transactions(instance),
|
||||
@@ -383,7 +383,7 @@ type WalletConfig =
|
||||
};
|
||||
|
||||
export function useEngineWalletConfig(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useQuery(
|
||||
engineKeys.walletConfig(instance),
|
||||
@@ -413,7 +413,7 @@ export function useEngineBackendWalletBalance(
|
||||
instance: string,
|
||||
address: string,
|
||||
) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const chainId = useActiveWalletChain()?.id;
|
||||
|
||||
invariant(chainId, "chainId is required");
|
||||
@@ -444,7 +444,7 @@ export type EngineAdmin = {
|
||||
};
|
||||
|
||||
export function useEnginePermissions(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const address = useActiveAccount()?.address;
|
||||
|
||||
return useQuery(
|
||||
@@ -479,7 +479,7 @@ export type AccessToken = {
|
||||
};
|
||||
|
||||
export function useEngineAccessTokens(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useQuery(
|
||||
engineKeys.accessTokens(instance),
|
||||
@@ -509,7 +509,7 @@ export type Keypair = {
|
||||
};
|
||||
|
||||
export function useEngineKeypairs(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useQuery(
|
||||
engineKeys.keypairs(instance),
|
||||
@@ -534,7 +534,7 @@ type AddKeypairInput = {
|
||||
};
|
||||
|
||||
export function useEngineAddKeypair(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -567,7 +567,7 @@ type RemoveKeypairInput = {
|
||||
};
|
||||
|
||||
export function useEngineRemoveKeypair(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -605,7 +605,7 @@ export type EngineRelayer = {
|
||||
};
|
||||
|
||||
export function useEngineRelayer(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useQuery(
|
||||
engineKeys.relayers(instance),
|
||||
@@ -632,7 +632,7 @@ export type CreateRelayerInput = {
|
||||
};
|
||||
|
||||
export function useEngineCreateRelayer(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -665,7 +665,7 @@ type RevokeRelayerInput = {
|
||||
};
|
||||
|
||||
export function useEngineRevokeRelayer(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -703,7 +703,7 @@ export type UpdateRelayerInput = {
|
||||
};
|
||||
|
||||
export function useEngineUpdateRelayer(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -742,7 +742,7 @@ export interface EngineWebhook {
|
||||
}
|
||||
|
||||
export function useEngineWebhooks(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useQuery(
|
||||
engineKeys.webhooks(instance),
|
||||
@@ -781,7 +781,7 @@ export type SetWalletConfigInput =
|
||||
};
|
||||
|
||||
export function useEngineSetWalletConfig(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -814,7 +814,7 @@ export type CreateBackendWalletInput = {
|
||||
};
|
||||
|
||||
export function useEngineCreateBackendWallet(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -850,7 +850,7 @@ interface UpdateBackendWalletInput {
|
||||
}
|
||||
|
||||
export function useEngineUpdateBackendWallet(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -901,7 +901,7 @@ export type ImportBackendWalletInput =
|
||||
};
|
||||
|
||||
export function useEngineImportBackendWallet(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -932,7 +932,7 @@ export function useEngineImportBackendWallet(instance: string) {
|
||||
}
|
||||
|
||||
export function useEngineGrantPermissions(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -965,7 +965,7 @@ type RevokePermissionsInput = {
|
||||
};
|
||||
|
||||
export function useEngineRevokePermissions(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -998,7 +998,7 @@ type CreateAccessTokenResponse = AccessToken & {
|
||||
};
|
||||
|
||||
export function useEngineCreateAccessToken(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -1031,7 +1031,7 @@ type RevokeAccessTokenInput = {
|
||||
};
|
||||
|
||||
export function useEngineRevokeAccessToken(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -1065,7 +1065,7 @@ type UpdateAccessTokenInput = {
|
||||
};
|
||||
|
||||
export function useEngineUpdateAccessToken(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -1100,7 +1100,7 @@ export type CreateWebhookInput = {
|
||||
};
|
||||
|
||||
export function useEngineCreateWebhook(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -1133,7 +1133,7 @@ type RevokeWebhookInput = {
|
||||
};
|
||||
|
||||
export function useEngineRevokeWebhook(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutationWithInvalidate(
|
||||
@@ -1170,7 +1170,7 @@ type SendTokensInput = {
|
||||
};
|
||||
|
||||
export function useEngineSendTokens(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useMutation(async (input: SendTokensInput) => {
|
||||
invariant(instance, "instance is required");
|
||||
@@ -1201,7 +1201,7 @@ export function useEngineSendTokens(instance: string) {
|
||||
}
|
||||
|
||||
export function useEngineCorsConfiguration(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useQuery(
|
||||
engineKeys.corsUrls(instance),
|
||||
@@ -1225,7 +1225,7 @@ interface SetCorsUrlInput {
|
||||
|
||||
export function useEngineSetCorsConfiguration(instance: string) {
|
||||
const queryClient = useQueryClient();
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useMutation(
|
||||
async (input: SetCorsUrlInput) => {
|
||||
@@ -1268,7 +1268,7 @@ export interface EngineContractSubscription {
|
||||
}
|
||||
|
||||
export function useEngineContractSubscription(instance: string) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
return useQuery(
|
||||
engineKeys.contractSubscriptions(instance),
|
||||
async () => {
|
||||
@@ -1298,7 +1298,7 @@ export interface AddContractSubscriptionInput {
|
||||
|
||||
export function useEngineAddContractSubscription(instance: string) {
|
||||
const queryClient = useQueryClient();
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useMutation(
|
||||
async (input: AddContractSubscriptionInput) => {
|
||||
@@ -1333,7 +1333,7 @@ export interface RemoveContractSubscriptionInput {
|
||||
|
||||
export function useEngineRemoveContractSubscription(instance: string) {
|
||||
const queryClient = useQueryClient();
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useMutation(
|
||||
async (input: RemoveContractSubscriptionInput) => {
|
||||
@@ -1367,7 +1367,7 @@ export function useEngineSubscriptionsLastBlock(
|
||||
chainId: number,
|
||||
autoUpdate: boolean,
|
||||
) {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
return useQuery(
|
||||
engineKeys.contractSubscriptionsLastBlock(instanceUrl, chainId),
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { UserWithData } from "@thirdweb-dev/react";
|
||||
import { THIRDWEB_API_HOST } from "constants/urls";
|
||||
import { useMemo } from "react";
|
||||
import { getAddress } from "thirdweb";
|
||||
import {
|
||||
useActiveAccount,
|
||||
useActiveWalletConnectionStatus,
|
||||
} from "thirdweb/react";
|
||||
import { useActiveAccount } from "thirdweb/react";
|
||||
|
||||
export function useLoggedInUser(): {
|
||||
isLoading: boolean;
|
||||
isLoggedIn: boolean;
|
||||
user: UserWithData | null;
|
||||
} {
|
||||
const connectedAddress = useActiveAccount()?.address;
|
||||
const connectionStatus = useActiveWalletConnectionStatus();
|
||||
const userQuery = useQuery({
|
||||
queryKey: ["logged_in_user"],
|
||||
export function fetchUserQuery(address: string) {
|
||||
return {
|
||||
enabled: !!address,
|
||||
queryKey: ["logged_in_user", address],
|
||||
queryFn: async () => {
|
||||
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/user`, {
|
||||
method: "GET",
|
||||
@@ -25,45 +16,48 @@ export function useLoggedInUser(): {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
return (await res.json()) as UserWithData | null;
|
||||
},
|
||||
enabled: !!connectedAddress,
|
||||
});
|
||||
|
||||
return useMemo(() => {
|
||||
switch (connectionStatus) {
|
||||
case "disconnected": {
|
||||
return {
|
||||
user: null,
|
||||
isLoading: false,
|
||||
isLoggedIn: false,
|
||||
};
|
||||
if (!res.ok) {
|
||||
throw new Error("Failed to fetch user data");
|
||||
}
|
||||
case "connected": {
|
||||
if (
|
||||
connectedAddress &&
|
||||
userQuery.data?.address &&
|
||||
getAddress(connectedAddress) !== getAddress(userQuery.data?.address)
|
||||
) {
|
||||
return {
|
||||
user: null,
|
||||
isLoading: userQuery.isLoading,
|
||||
isLoggedIn: false,
|
||||
};
|
||||
try {
|
||||
const json = await res.json();
|
||||
if (json === null) {
|
||||
throw new Error("Failed to fetch user data");
|
||||
}
|
||||
return {
|
||||
user: userQuery.data ?? null,
|
||||
isLoading: userQuery.isLoading,
|
||||
isLoggedIn: !!userQuery.data,
|
||||
};
|
||||
|
||||
const user = json as UserWithData;
|
||||
if (user && getAddress(user.address) === getAddress(address)) {
|
||||
return user;
|
||||
}
|
||||
throw new Error("Failed to fetch user data");
|
||||
} catch {
|
||||
throw new Error("Failed to fetch user data");
|
||||
}
|
||||
case "connecting": {
|
||||
return {
|
||||
user: null,
|
||||
isLoading: true,
|
||||
isLoggedIn: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}, [connectionStatus, userQuery.data, userQuery.isLoading, connectedAddress]);
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnMount: false,
|
||||
} as const;
|
||||
}
|
||||
|
||||
export function useLoggedInUser(): {
|
||||
isLoading: boolean;
|
||||
isLoggedIn: boolean;
|
||||
user: UserWithData | null;
|
||||
} {
|
||||
const connectedAddress = useActiveAccount()?.address;
|
||||
const query = useQuery(fetchUserQuery(connectedAddress || ""));
|
||||
|
||||
if (query.fetchStatus === "fetching") {
|
||||
return {
|
||||
isLoading: true,
|
||||
isLoggedIn: false,
|
||||
user: null,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isLoading: query.isLoading,
|
||||
isLoggedIn: query.isSuccess ? !!query.data : false,
|
||||
user: query.isSuccess ? query.data : null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useApiAuthToken } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import {
|
||||
type EditEngineInstanceInput,
|
||||
type EngineInstance,
|
||||
@@ -46,6 +45,7 @@ import { BiPencil } from "react-icons/bi";
|
||||
import { FiArrowRight, FiTrash } from "react-icons/fi";
|
||||
import { useActiveAccount } from "thirdweb/react";
|
||||
import { Badge, Button, FormLabel, Heading, Text } from "tw-components";
|
||||
import { useAccessToken } from "../../@3rdweb-sdk/react/components/connect-wallet/useAccessToken";
|
||||
|
||||
interface EngineInstancesTableProps {
|
||||
instances: EngineInstance[];
|
||||
@@ -65,7 +65,7 @@ export const EngineInstancesTable: React.FC<EngineInstancesTableProps> = ({
|
||||
const editDisclosure = useDisclosure();
|
||||
const removeDisclosure = useDisclosure();
|
||||
const trackEvent = useTrack();
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const address = useActiveAccount()?.address;
|
||||
const toast = useToast();
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Box, DarkMode } from "@chakra-ui/react";
|
||||
import { ClientOnly } from "components/ClientOnly/ClientOnly";
|
||||
import "../../../css/swagger-ui.css";
|
||||
import "swagger-ui-react/swagger-ui.css";
|
||||
import { useApiAuthToken } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import dynamic from "next/dynamic";
|
||||
import { useAccessToken } from "../../../@3rdweb-sdk/react/components/connect-wallet/useAccessToken";
|
||||
|
||||
const SwaggerUI = dynamic(() => import("swagger-ui-react"), { ssr: false });
|
||||
|
||||
@@ -14,7 +14,7 @@ interface EngineExplorerProps {
|
||||
export const EngineExplorer: React.FC<EngineExplorerProps> = ({
|
||||
instanceUrl,
|
||||
}) => {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
return (
|
||||
<ClientOnly ssr={null}>
|
||||
<DarkMode>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useApiAuthToken } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import type { Transaction } from "@3rdweb-sdk/react/hooks/useEngine";
|
||||
import {
|
||||
Flex,
|
||||
@@ -23,6 +22,7 @@ import { useRef } from "react";
|
||||
import { FiCheck } from "react-icons/fi";
|
||||
import { Button, FormLabel, Text } from "tw-components";
|
||||
import { AddressCopyButton } from "tw-components/AddressCopyButton";
|
||||
import { useAccessToken } from "../../../@3rdweb-sdk/react/components/connect-wallet/useAccessToken";
|
||||
|
||||
interface TimelineStep {
|
||||
step: string;
|
||||
@@ -182,7 +182,7 @@ const CancelTransactionButton = ({
|
||||
instanceUrl: string;
|
||||
}) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const auth = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const { onSuccess, onError } = useTxNotifications(
|
||||
"Successfully sent a request to cancel the transaction",
|
||||
"Failed to cancel transaction",
|
||||
@@ -195,7 +195,7 @@ const CancelTransactionButton = ({
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${auth.token}`,
|
||||
Authorization: `Bearer ${token}`,
|
||||
"x-backend-wallet-address": transaction.fromAddress ?? "",
|
||||
},
|
||||
body: JSON.stringify({ queueId: transaction.queueId }),
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { Flex, FocusLock, VStack } from "@chakra-ui/react";
|
||||
import { useDisconnect, useLogout } from "@thirdweb-dev/react";
|
||||
import { AccountForm } from "components/settings/Account/AccountForm";
|
||||
import { useState } from "react";
|
||||
import { useActiveWallet, useDisconnect } from "thirdweb/react";
|
||||
import { Button } from "tw-components";
|
||||
import { logout } from "../../@3rdweb-sdk/react/components/connect-wallet";
|
||||
import { OnboardingTitle } from "./Title";
|
||||
|
||||
type OnboardingGeneralProps = {
|
||||
@@ -17,14 +18,16 @@ export const OnboardingGeneral: React.FC<OnboardingGeneralProps> = ({
|
||||
onSave,
|
||||
onDuplicate,
|
||||
}) => {
|
||||
const { logout } = useLogout();
|
||||
const [existing, setExisting] = useState(false);
|
||||
const disconnect = useDisconnect();
|
||||
const activeWallet = useActiveWallet();
|
||||
const { disconnect } = useDisconnect();
|
||||
|
||||
const handleLogout = async () => {
|
||||
await logout();
|
||||
disconnect();
|
||||
};
|
||||
async function handleDisconnect() {
|
||||
if (activeWallet) {
|
||||
await logout();
|
||||
disconnect(activeWallet);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<FocusLock>
|
||||
@@ -68,7 +71,7 @@ export const OnboardingGeneral: React.FC<OnboardingGeneralProps> = ({
|
||||
</Button>
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={handleLogout}
|
||||
onClick={handleDisconnect}
|
||||
w="full"
|
||||
size="sm"
|
||||
pt={4}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useApiAuthToken } from "@3rdweb-sdk/react/hooks/useApi";
|
||||
import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
|
||||
import { Center, Flex, Tooltip } from "@chakra-ui/react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
@@ -9,6 +8,7 @@ import { DASHBOARD_STORAGE_URL } from "lib/sdk";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Button, Card, Heading, Text, TrackedCopyButton } from "tw-components";
|
||||
import { toSize } from "utils/number";
|
||||
import { useAccessToken } from "../../@3rdweb-sdk/react/components/connect-wallet/useAccessToken";
|
||||
|
||||
interface PinnedFilesResponse {
|
||||
result: PinnedFilesResult;
|
||||
@@ -37,7 +37,7 @@ function usePinnedFilesQuery({
|
||||
pageSize: number;
|
||||
}) {
|
||||
const user = useLoggedInUser();
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
|
||||
const offset = page * pageSize;
|
||||
|
||||
@@ -76,7 +76,7 @@ function usePinnedFilesQuery({
|
||||
}
|
||||
|
||||
function useUnpinFileMutation() {
|
||||
const { token } = useApiAuthToken();
|
||||
const token = useAccessToken();
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ cid }: { cid: string }) => {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { isBrowser } from "../utils/isBrowser";
|
||||
|
||||
export const GLOBAL_AUTH_TOKEN_KEY = "TW_AUTH_TOKEN";
|
||||
|
||||
// EWS token shenaningans
|
||||
|
||||
const GLOBAL_EWS_AUTH_TOKEN_KEY = "TW_EWS_AUTH_TOKEN";
|
||||
|
||||
export function storeEWSToken(token: string): void {
|
||||
|
||||
@@ -268,7 +268,7 @@ import { ThirdwebProvider, ConnectButton } from "thirdweb/react";
|
||||
export default function App() {
|
||||
return (
|
||||
<ThirdwebProvider>
|
||||
<ConnectWallet
|
||||
<ConnectButton
|
||||
client={client}
|
||||
accountAbstraction={{
|
||||
chain: defineChain({{chainId}}),
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import { useEVMContractInfo } from "@3rdweb-sdk/react";
|
||||
import { useAddress } from "@thirdweb-dev/react";
|
||||
import { usePublishedContractsFromDeploy } from "components/contract-components/hooks";
|
||||
import { THIRDWEB_DEPLOYER_ADDRESS } from "constants/addresses";
|
||||
import { useMemo } from "react";
|
||||
import { useActiveAccount } from "thirdweb/react";
|
||||
|
||||
export function useExtensionContractInfo(contractAddress: string) {
|
||||
const address = useAddress();
|
||||
const address = useActiveAccount()?.address;
|
||||
const activeNetworkInfo = useEVMContractInfo();
|
||||
|
||||
const publishedContractsFromDeploy = usePublishedContractsFromDeploy(
|
||||
|
||||
@@ -66,10 +66,12 @@ export function useSiweAuth(
|
||||
}
|
||||
return authOptions.isLoggedIn(activeAccount.address);
|
||||
},
|
||||
placeholderData: false,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
const loginMutation = useMutation({
|
||||
mutationKey: ["siwe_auth", "login"],
|
||||
mutationFn: async () => {
|
||||
if (!authOptions) {
|
||||
throw new Error("No auth options provided");
|
||||
@@ -109,6 +111,7 @@ export function useSiweAuth(
|
||||
});
|
||||
|
||||
const logoutMutation = useMutation({
|
||||
mutationKey: ["siwe_auth", "logout"],
|
||||
mutationFn: async () => {
|
||||
if (!authOptions) {
|
||||
throw new Error("No auth options provided");
|
||||
@@ -137,6 +140,6 @@ export function useSiweAuth(
|
||||
|
||||
// checking if logged in
|
||||
isLoggedIn: isLoggedInQuery.data,
|
||||
isLoading: isLoggedInQuery.isLoading,
|
||||
isLoading: isLoggedInQuery.isFetching,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ function ConnectButtonInner(
|
||||
if (siweAuth.requiresAuth) {
|
||||
// loading state if loading
|
||||
// TODO: figure out a way to consolidate the loading states with the ones from locale loading
|
||||
if (siweAuth.isLoading) {
|
||||
if (siweAuth.isLoading || siweAuth.isLoggingIn || siweAuth.isLoggingOut) {
|
||||
return (
|
||||
<AnimatedButton
|
||||
disabled={true}
|
||||
|
||||
Reference in New Issue
Block a user