Refactor wallet user API integration to use tw api (#7987)
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
],
|
],
|
||||||
"ignoreBinaries": ["only-allow"],
|
"ignoreBinaries": ["only-allow"],
|
||||||
"ignoreDependencies": [
|
"ignoreDependencies": [
|
||||||
|
"@thirdweb-dev/api",
|
||||||
"@thirdweb-dev/service-utils",
|
"@thirdweb-dev/service-utils",
|
||||||
"@thirdweb-dev/vault-sdk",
|
"@thirdweb-dev/vault-sdk",
|
||||||
"thirdweb",
|
"thirdweb",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"@shazow/whatsabi": "0.22.2",
|
"@shazow/whatsabi": "0.22.2",
|
||||||
"@tanstack/react-query": "5.81.5",
|
"@tanstack/react-query": "5.81.5",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
|
"@thirdweb-dev/api": "workspace:*",
|
||||||
"@thirdweb-dev/service-utils": "workspace:*",
|
"@thirdweb-dev/service-utils": "workspace:*",
|
||||||
"@thirdweb-dev/vault-sdk": "workspace:*",
|
"@thirdweb-dev/vault-sdk": "workspace:*",
|
||||||
"@vercel/functions": "2.2.2",
|
"@vercel/functions": "2.2.2",
|
||||||
|
|||||||
@@ -1,7 +1,79 @@
|
|||||||
|
import type {
|
||||||
|
ListUserWalletsData,
|
||||||
|
ListUserWalletsResponses,
|
||||||
|
} from "@thirdweb-dev/api";
|
||||||
|
import { configure, listUserWallets } from "@thirdweb-dev/api";
|
||||||
import type { WalletUser } from "thirdweb/wallets";
|
import type { WalletUser } from "thirdweb/wallets";
|
||||||
import { THIRDWEB_EWS_API_HOST } from "@/constants/urls";
|
import { THIRDWEB_API_HOST } from "@/constants/urls";
|
||||||
import type { SearchType } from "./types";
|
import type { SearchType } from "./types";
|
||||||
|
|
||||||
|
// Configure the API client to use the correct base URL
|
||||||
|
configure({
|
||||||
|
override: {
|
||||||
|
baseUrl: THIRDWEB_API_HOST,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extract types from the generated API
|
||||||
|
type APIWallet = ListUserWalletsResponses[200]["result"]["wallets"][0];
|
||||||
|
type APIProfile = APIWallet["profiles"][0];
|
||||||
|
|
||||||
|
// Transform API response to match existing WalletUser format
|
||||||
|
function transformToWalletUser(apiWallet: APIWallet): WalletUser {
|
||||||
|
return {
|
||||||
|
id: getProfileId(apiWallet.profiles[0]) || "",
|
||||||
|
linkedAccounts: apiWallet.profiles.map((profile) => {
|
||||||
|
// Create details object based on the profile data
|
||||||
|
let details:
|
||||||
|
| { email: string; [key: string]: string }
|
||||||
|
| { phone: string; [key: string]: string }
|
||||||
|
| { address: string; [key: string]: string }
|
||||||
|
| { id: string; [key: string]: string };
|
||||||
|
|
||||||
|
const profileId = getProfileId(profile);
|
||||||
|
|
||||||
|
if ("email" in profile && profile.email) {
|
||||||
|
details = { email: profile.email, id: profileId };
|
||||||
|
} else if ("phone" in profile && profile.phone) {
|
||||||
|
details = { phone: profile.phone, id: profileId };
|
||||||
|
} else if ("walletAddress" in profile && profile.walletAddress) {
|
||||||
|
details = { address: profile.walletAddress, id: profileId };
|
||||||
|
} else {
|
||||||
|
details = { id: profileId };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: profile.type,
|
||||||
|
details,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
wallets: apiWallet.address
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
address: apiWallet.address,
|
||||||
|
createdAt: apiWallet.createdAt || new Date().toISOString(),
|
||||||
|
type: "enclave" as const,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to safely get ID from any profile type
|
||||||
|
function getProfileId(profile: APIProfile | undefined): string {
|
||||||
|
if (!profile) return "";
|
||||||
|
|
||||||
|
if ("id" in profile) {
|
||||||
|
return profile.id;
|
||||||
|
} else if ("credentialId" in profile) {
|
||||||
|
return profile.credentialId;
|
||||||
|
} else if ("identifier" in profile) {
|
||||||
|
return profile.identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
export async function searchUsers(
|
export async function searchUsers(
|
||||||
authToken: string,
|
authToken: string,
|
||||||
clientId: string | undefined,
|
clientId: string | undefined,
|
||||||
@@ -10,50 +82,57 @@ export async function searchUsers(
|
|||||||
searchType: SearchType,
|
searchType: SearchType,
|
||||||
query: string,
|
query: string,
|
||||||
): Promise<WalletUser[]> {
|
): Promise<WalletUser[]> {
|
||||||
const url = new URL(`${THIRDWEB_EWS_API_HOST}/api/2024-05-05/account/list`);
|
try {
|
||||||
|
// Prepare query parameters
|
||||||
|
const queryParams: ListUserWalletsData["query"] = {
|
||||||
|
limit: 50,
|
||||||
|
};
|
||||||
|
|
||||||
// Add clientId or ecosystemSlug parameter
|
// Add search parameter based on search type
|
||||||
if (ecosystemSlug) {
|
switch (searchType) {
|
||||||
url.searchParams.append("ecosystemSlug", `ecosystem.${ecosystemSlug}`);
|
case "email":
|
||||||
} else if (clientId) {
|
queryParams.email = query;
|
||||||
url.searchParams.append("clientId", clientId);
|
break;
|
||||||
|
case "phone":
|
||||||
|
queryParams.phone = query;
|
||||||
|
break;
|
||||||
|
case "id":
|
||||||
|
queryParams.id = query;
|
||||||
|
break;
|
||||||
|
case "address":
|
||||||
|
queryParams.address = query;
|
||||||
|
break;
|
||||||
|
case "externalWallet":
|
||||||
|
queryParams.externalWalletAddress = query;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the generated API function with Bearer authentication
|
||||||
|
const response = await listUserWallets({
|
||||||
|
query: queryParams,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${authToken}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-thirdweb-team-id": teamId,
|
||||||
|
...(clientId && { "x-client-id": clientId }),
|
||||||
|
...(ecosystemSlug && {
|
||||||
|
"x-ecosystem-id": `ecosystem.${ecosystemSlug}`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle response
|
||||||
|
if (response.error || !response.data) {
|
||||||
|
console.error(
|
||||||
|
"Error searching users:",
|
||||||
|
response.error || "No data returned",
|
||||||
|
);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.data.result.wallets.map(transformToWalletUser);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error searching users:", error);
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add search parameter based on search type
|
|
||||||
switch (searchType) {
|
|
||||||
case "email":
|
|
||||||
url.searchParams.append("email", query);
|
|
||||||
break;
|
|
||||||
case "phone":
|
|
||||||
url.searchParams.append("phone", query);
|
|
||||||
break;
|
|
||||||
case "id":
|
|
||||||
url.searchParams.append("id", query);
|
|
||||||
break;
|
|
||||||
case "address":
|
|
||||||
url.searchParams.append("address", query);
|
|
||||||
break;
|
|
||||||
case "externalWallet":
|
|
||||||
url.searchParams.append("externalWalletAddress", query);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(url.toString(), {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${authToken}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"x-thirdweb-team-id": teamId,
|
|
||||||
...(clientId && { "x-client-id": clientId }),
|
|
||||||
},
|
|
||||||
method: "GET",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(
|
|
||||||
`Failed to search users: ${response.status} ${response.statusText}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
return data.users as WalletUser[];
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export const THIRDWEB_EWS_API_HOST =
|
export const THIRDWEB_API_HOST =
|
||||||
process.env.NEXT_PUBLIC_THIRDWEB_EWS_API_HOST ||
|
process.env.NEXT_PUBLIC_THIRDWEB_API_HOST || "https://api.thirdweb-dev.com";
|
||||||
"https://in-app-wallet.thirdweb.com";
|
|
||||||
|
|
||||||
export const THIRDWEB_PAY_DOMAIN =
|
export const THIRDWEB_PAY_DOMAIN =
|
||||||
process.env.NEXT_PUBLIC_PAY_URL || "pay.thirdweb-dev.com";
|
process.env.NEXT_PUBLIC_PAY_URL || "pay.thirdweb-dev.com";
|
||||||
|
|||||||
@@ -1,9 +1,25 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import type {
|
||||||
|
ListUserWalletsData,
|
||||||
|
ListUserWalletsResponses,
|
||||||
|
} from "@thirdweb-dev/api";
|
||||||
|
import { configure, listUserWallets } from "@thirdweb-dev/api";
|
||||||
import { useActiveAccount } from "thirdweb/react";
|
import { useActiveAccount } from "thirdweb/react";
|
||||||
import type { WalletUser } from "thirdweb/wallets";
|
import type { WalletUser } from "thirdweb/wallets";
|
||||||
import { THIRDWEB_EWS_API_HOST } from "@/constants/urls";
|
import { THIRDWEB_API_HOST } from "@/constants/urls";
|
||||||
import { embeddedWalletsKeys } from "../query-keys/cache-keys";
|
import { embeddedWalletsKeys } from "../query-keys/cache-keys";
|
||||||
|
|
||||||
|
// Configure the API client to use the correct base URL
|
||||||
|
configure({
|
||||||
|
override: {
|
||||||
|
baseUrl: THIRDWEB_API_HOST,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extract types from the generated API
|
||||||
|
type APIWallet = ListUserWalletsResponses[200]["result"]["wallets"][0];
|
||||||
|
type APIProfile = APIWallet["profiles"][0];
|
||||||
|
|
||||||
const fetchAccountList = ({
|
const fetchAccountList = ({
|
||||||
jwt,
|
jwt,
|
||||||
clientId,
|
clientId,
|
||||||
@@ -18,37 +34,104 @@ const fetchAccountList = ({
|
|||||||
pageNumber: number;
|
pageNumber: number;
|
||||||
}) => {
|
}) => {
|
||||||
return async () => {
|
return async () => {
|
||||||
const url = new URL(`${THIRDWEB_EWS_API_HOST}/api/2024-05-05/account/list`);
|
try {
|
||||||
|
// Prepare query parameters for the new API
|
||||||
|
const queryParams: ListUserWalletsData["query"] = {
|
||||||
|
page: pageNumber,
|
||||||
|
limit: 50, // Keep the same page size
|
||||||
|
};
|
||||||
|
|
||||||
// Add clientId or ecosystemSlug parameter
|
// Use the generated API function with Bearer authentication
|
||||||
if (ecosystemSlug) {
|
const response = await listUserWallets({
|
||||||
url.searchParams.append("ecosystemSlug", `ecosystem.${ecosystemSlug}`);
|
query: queryParams,
|
||||||
} else if (clientId) {
|
headers: {
|
||||||
url.searchParams.append("clientId", clientId);
|
Authorization: `Bearer ${jwt}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-thirdweb-team-id": teamId,
|
||||||
|
...(clientId && { "x-client-id": clientId }),
|
||||||
|
...(ecosystemSlug && {
|
||||||
|
"x-ecosystem-id": `ecosystem.${ecosystemSlug}`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle response
|
||||||
|
if (response.error || !response.data) {
|
||||||
|
const errorMessage =
|
||||||
|
typeof response.error === "string"
|
||||||
|
? response.error
|
||||||
|
: "No data returned";
|
||||||
|
throw new Error(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform the response to match the expected format
|
||||||
|
return {
|
||||||
|
users: response.data.result.wallets.map(transformToWalletUser),
|
||||||
|
hasMore: response.data.result.pagination.hasMore ?? false,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch wallets:", error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
url.searchParams.append("page", pageNumber.toString());
|
|
||||||
|
|
||||||
const res = await fetch(url.href, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${jwt}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"x-thirdweb-team-id": teamId,
|
|
||||||
...(clientId && { "x-client-id": clientId }),
|
|
||||||
},
|
|
||||||
method: "GET",
|
|
||||||
});
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`Failed to fetch wallets: ${await res.text()}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const json = await res.json();
|
|
||||||
return json as {
|
|
||||||
users: WalletUser[];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Transform API response to match existing WalletUser format
|
||||||
|
function transformToWalletUser(apiWallet: APIWallet): WalletUser {
|
||||||
|
return {
|
||||||
|
id: getProfileId(apiWallet.profiles[0]) || "",
|
||||||
|
linkedAccounts: apiWallet.profiles.map((profile) => {
|
||||||
|
// Create details object based on the profile data
|
||||||
|
let details:
|
||||||
|
| { email: string; [key: string]: string }
|
||||||
|
| { phone: string; [key: string]: string }
|
||||||
|
| { address: string; [key: string]: string }
|
||||||
|
| { id: string; [key: string]: string };
|
||||||
|
|
||||||
|
const profileId = getProfileId(profile);
|
||||||
|
|
||||||
|
if ("email" in profile && profile.email) {
|
||||||
|
details = { email: profile.email, id: profileId };
|
||||||
|
} else if ("phone" in profile && profile.phone) {
|
||||||
|
details = { phone: profile.phone, id: profileId };
|
||||||
|
} else if ("walletAddress" in profile && profile.walletAddress) {
|
||||||
|
details = { address: profile.walletAddress, id: profileId };
|
||||||
|
} else {
|
||||||
|
details = { id: profileId };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: profile.type,
|
||||||
|
details,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
wallets: apiWallet.address
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
address: apiWallet.address,
|
||||||
|
createdAt: apiWallet.createdAt || new Date().toISOString(),
|
||||||
|
type: "enclave" as const,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to safely get ID from any profile type
|
||||||
|
function getProfileId(profile: APIProfile | undefined): string {
|
||||||
|
if (!profile) return "";
|
||||||
|
|
||||||
|
if ("id" in profile) {
|
||||||
|
return profile.id;
|
||||||
|
} else if ("credentialId" in profile) {
|
||||||
|
return profile.credentialId;
|
||||||
|
} else if ("identifier" in profile) {
|
||||||
|
return profile.identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
export function useEmbeddedWallets(params: {
|
export function useEmbeddedWallets(params: {
|
||||||
clientId?: string;
|
clientId?: string;
|
||||||
ecosystemSlug?: string;
|
ecosystemSlug?: string;
|
||||||
@@ -98,6 +181,7 @@ export function useAllEmbeddedWallets(params: { authToken: string }) {
|
|||||||
while (true) {
|
while (true) {
|
||||||
const res = await queryClient.fetchQuery<{
|
const res = await queryClient.fetchQuery<{
|
||||||
users: WalletUser[];
|
users: WalletUser[];
|
||||||
|
hasMore: boolean;
|
||||||
}>({
|
}>({
|
||||||
queryFn: fetchAccountList({
|
queryFn: fetchAccountList({
|
||||||
clientId,
|
clientId,
|
||||||
@@ -113,12 +197,13 @@ export function useAllEmbeddedWallets(params: { authToken: string }) {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.users.length === 0) {
|
responses.push(...res.users);
|
||||||
|
|
||||||
|
if (!res.hasMore) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
page++;
|
page++;
|
||||||
responses.push(...res.users);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return responses;
|
return responses;
|
||||||
|
|||||||
+750
-558
File diff suppressed because it is too large
Load Diff
+3393
-2066
File diff suppressed because it is too large
Load Diff
Generated
+5
-2
@@ -130,6 +130,9 @@ importers:
|
|||||||
'@tanstack/react-table':
|
'@tanstack/react-table':
|
||||||
specifier: ^8.21.3
|
specifier: ^8.21.3
|
||||||
version: 8.21.3([email protected]([email protected]))([email protected])
|
version: 8.21.3([email protected]([email protected]))([email protected])
|
||||||
|
'@thirdweb-dev/api':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../packages/api
|
||||||
'@thirdweb-dev/service-utils':
|
'@thirdweb-dev/service-utils':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/service-utils
|
version: link:../../packages/service-utils
|
||||||
@@ -31301,7 +31304,7 @@ snapshots:
|
|||||||
[email protected]:
|
[email protected]:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.0
|
'@babel/core': 7.28.0
|
||||||
'@babel/parser': 7.28.0
|
'@babel/parser': 7.28.3
|
||||||
'@istanbuljs/schema': 0.1.3
|
'@istanbuljs/schema': 0.1.3
|
||||||
istanbul-lib-coverage: 3.2.2
|
istanbul-lib-coverage: 3.2.2
|
||||||
semver: 7.7.2
|
semver: 7.7.2
|
||||||
@@ -32343,7 +32346,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.0
|
'@babel/core': 7.28.0
|
||||||
'@babel/generator': 7.28.0
|
'@babel/generator': 7.28.0
|
||||||
'@babel/parser': 7.28.0
|
'@babel/parser': 7.28.3
|
||||||
'@babel/types': 7.28.2
|
'@babel/types': 7.28.2
|
||||||
flow-enums-runtime: 0.0.6
|
flow-enums-runtime: 0.0.6
|
||||||
metro: 0.81.4([email protected])([email protected])
|
metro: 0.81.4([email protected])([email protected])
|
||||||
|
|||||||
Reference in New Issue
Block a user