cdp-wallet-onramp-kit
Version:
Complete toolkit for Coinbase Developer Platform (CDP) Embedded Wallets and Onramp integration with reusable components, utilities, and documentation
224 lines (193 loc) • 7.09 kB
text/typescript
/**
* Hook return type detection and normalization utilities
* Handles compatibility between different CDP SDK versions that return different types
*/
/**
* Normalized user data structure
*/
export interface NormalizedUser {
userId: string;
email?: string;
evmAccounts: string[];
}
/**
* Hook compatibility warnings
*/
let hasWarnedAboutObjectReturns = false;
/**
* Safe extraction of EVM address from CDP hooks
* Handles both primitive string returns and object returns
*
* @param evmAddressResult - Result from useEvmAddress() hook
* @returns string | null - The EVM address or null
*/
export function getEvmAddress(evmAddressResult: any): string | null {
// Handle null/undefined
if (!evmAddressResult) {
return null;
}
// Handle primitive string return (expected behavior)
if (typeof evmAddressResult === 'string') {
return evmAddressResult;
}
// Handle object return (compatibility issue in some environments)
if (typeof evmAddressResult === 'object' && evmAddressResult.evmAddress) {
// Warn developers about compatibility issue
if (!hasWarnedAboutObjectReturns && typeof window !== 'undefined' && console) {
console.warn(
'[CDP Kit] Detected object return from useEvmAddress(). This may indicate a version compatibility issue.\n' +
'Expected: string | null\n' +
'Received: object with evmAddress property\n' +
'Using defensive extraction. Consider updating CDP SDK versions.'
);
hasWarnedAboutObjectReturns = true;
}
return typeof evmAddressResult.evmAddress === 'string' ? evmAddressResult.evmAddress : null;
}
// Handle unexpected return types
if (typeof window !== 'undefined' && console) {
console.error('[CDP Kit] Unexpected return type from useEvmAddress():', typeof evmAddressResult, evmAddressResult);
}
return null;
}
/**
* Safe extraction of current user from CDP hooks
* Handles both primitive object returns and nested object returns
*
* @param currentUserResult - Result from useCurrentUser() hook
* @returns NormalizedUser | null - The normalized user data or null
*/
export function getCurrentUser(currentUserResult: any): NormalizedUser | null {
// Handle null/undefined
if (!currentUserResult) {
return null;
}
// Handle direct user object (expected behavior)
if (currentUserResult.userId && Array.isArray(currentUserResult.evmAccounts)) {
return {
userId: currentUserResult.userId,
email: currentUserResult.email,
evmAccounts: currentUserResult.evmAccounts
};
}
// Handle nested user object (compatibility fallback)
if (currentUserResult.user && currentUserResult.user.userId) {
return {
userId: currentUserResult.user.userId,
email: currentUserResult.user.email,
evmAccounts: currentUserResult.user.evmAccounts || []
};
}
// Handle unexpected structure
if (typeof window !== 'undefined' && console) {
console.error('[CDP Kit] Unexpected return type from useCurrentUser():', currentUserResult);
}
return null;
}
/**
* Safe extraction of initialization status
* Handles both boolean returns and object returns
*
* @param isInitializedResult - Result from useIsInitialized() hook
* @returns boolean - The initialization status
*/
export function getIsInitialized(isInitializedResult: any): boolean {
// Handle null/undefined
if (isInitializedResult === null || isInitializedResult === undefined) {
return false;
}
// Handle primitive boolean return (expected behavior)
if (typeof isInitializedResult === 'boolean') {
return isInitializedResult;
}
// Handle object return with isInitialized property
if (typeof isInitializedResult === 'object' && typeof isInitializedResult.isInitialized === 'boolean') {
return isInitializedResult.isInitialized;
}
// Default to false for safety
return false;
}
/**
* Safe extraction of action hooks (signOut, signInWithEmail, etc.)
* These hooks typically return objects with action functions
*
* @param hookResult - Result from action hook (useSignOut, useSignInWithEmail, etc.)
* @returns object - The action functions or empty object
*/
export function getHookActions(hookResult: any): Record<string, Function> {
// Handle null/undefined
if (!hookResult) {
return {};
}
// Handle object with functions (expected behavior)
if (typeof hookResult === 'object') {
return hookResult;
}
// Handle unexpected return types
if (typeof window !== 'undefined' && console) {
console.error('[CDP Kit] Unexpected return type from action hook:', typeof hookResult, hookResult);
}
return {};
}
/**
* Detect CDP SDK environment and version compatibility
* Provides diagnostic information for troubleshooting
*
* @returns object - Environment diagnostic information
*/
export function detectCDPEnvironment() {
const diagnostics = {
hasWindow: typeof window !== 'undefined',
hasProcess: typeof process !== 'undefined',
nodeEnv: typeof process !== 'undefined' ? process.env.NODE_ENV : 'unknown',
userAgent: typeof window !== 'undefined' ? window.navigator?.userAgent : 'unknown',
recommendations: [] as string[]
};
// Check for common setup issues
if (typeof window === 'undefined') {
diagnostics.recommendations.push('Ensure components using CDP hooks have "use client" directive in Next.js');
}
if (typeof process !== 'undefined' && !process.env.NEXT_PUBLIC_CDP_PROJECT_ID) {
diagnostics.recommendations.push('Set NEXT_PUBLIC_CDP_PROJECT_ID environment variable');
}
return diagnostics;
}
/**
* Validate that CDP hooks are returning expected types
* Run this in development to catch compatibility issues early
*
* @param hookResults - Object containing results from various hooks
*/
export function validateHookReturns(hookResults: {
evmAddress?: any;
currentUser?: any;
isInitialized?: any;
}) {
if (typeof window === 'undefined' || process.env.NODE_ENV !== 'development') {
return;
}
const issues = [];
// Check evmAddress return type
if (hookResults.evmAddress !== undefined && hookResults.evmAddress !== null) {
if (typeof hookResults.evmAddress !== 'string') {
issues.push(`useEvmAddress() returned ${typeof hookResults.evmAddress}, expected string | null`);
}
}
// Check currentUser return type
if (hookResults.currentUser !== undefined && hookResults.currentUser !== null) {
if (!hookResults.currentUser.userId) {
issues.push(`useCurrentUser() returned object without userId property`);
}
}
// Check isInitialized return type
if (hookResults.isInitialized !== undefined) {
if (typeof hookResults.isInitialized !== 'boolean') {
issues.push(`useIsInitialized() returned ${typeof hookResults.isInitialized}, expected boolean`);
}
}
if (issues.length > 0) {
console.warn('[CDP Kit] Hook return type validation issues detected:');
issues.forEach(issue => console.warn(` - ${issue}`));
console.warn('This may indicate CDP SDK version compatibility issues.');
}
}