UNPKG

@nuwa-ai/identity-kit-web

Version:

Web extensions for Nuwa Identity Kit

163 lines (146 loc) 4.62 kB
import { useState, useEffect, useCallback } from 'react'; import { IdentityKitWeb } from '..'; import { NIP1SignedObject } from '@nuwa-ai/identity-kit'; export interface IdentityKitState { isConnected: boolean; isConnecting: boolean; agentDid: string | null; keyId: string | null; error: string | null; } export interface IdentityKitHook { state: IdentityKitState; connect: () => Promise<void>; sign: (payload: any) => Promise<NIP1SignedObject>; verify: (sig: NIP1SignedObject) => Promise<boolean>; logout: () => Promise<void>; sdk: IdentityKitWeb | null; } export interface UseIdentityKitOptions { appName?: string; cadopDomain?: string; storage?: 'local' | 'indexeddb'; autoConnect?: boolean; roochRpcUrl?: string; } /** * React hook for Nuwa Identity Kit (Web) */ export function useIdentityKit(options: UseIdentityKitOptions = {}): IdentityKitHook { const [sdk, setSdk] = useState<IdentityKitWeb | null>(null); const [state, setState] = useState<IdentityKitState>({ isConnected: false, isConnecting: false, agentDid: null, keyId: null, error: null, }); /** * Helper – refresh connection state from SDK instance */ async function refreshConnection(kit: IdentityKitWeb | null = sdk) { if (!kit) return; const isConnected = await kit.isConnected(); if (isConnected) { const did = await kit.getDid(); const keyIds = await kit.listKeyIds(); setState({ isConnected: true, isConnecting: false, agentDid: did, keyId: keyIds.length > 0 ? keyIds[0] : null, error: null, }); } else { setState(prev => ({ ...prev, isConnected: false, isConnecting: false, })); } } // Initialize SDK useEffect(() => { async function initSdk() { try { const newSdk = await IdentityKitWeb.init({ appName: options.appName, cadopDomain: options.cadopDomain, storage: options.storage, roochRpcUrl: options.roochRpcUrl, }); setSdk(newSdk); // Check connection status await refreshConnection(newSdk); } catch (error) { setState(prev => ({ ...prev, error: `Failed to initialize SDK: ${error instanceof Error ? error.message : String(error)}`, })); } } initSdk(); }, [options.appName, options.cadopDomain, options.storage]); // Listen for postMessage from callback window useEffect(() => { function handleMessage(event: MessageEvent) { if (event.data && event.data.type === 'nuwa-auth-success') { // Re-check connection status when callback signals success refreshConnection(); } } window.addEventListener('message', handleMessage); return () => window.removeEventListener('message', handleMessage); }, [sdk]); // Auto connect useEffect(() => { if (options.autoConnect && sdk && !state.isConnected && !state.isConnecting) { connect(); } }, [sdk, options.autoConnect, state.isConnected, state.isConnecting]); // Connect action const connect = useCallback(async () => { if (!sdk) { setState(prev => ({ ...prev, error: 'SDK not initialized' })); return; } setState(prev => ({ ...prev, isConnecting: true, error: null })); try { await sdk.connect(); // Actual connection result will be handled via postMessage in callback setState(prev => ({ ...prev, isConnecting: false })); } catch (error) { setState({ isConnected: false, isConnecting: false, agentDid: null, keyId: null, error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`, }); } }, [sdk]); // Sign operation const sign = useCallback(async (payload: any): Promise<NIP1SignedObject> => { if (!sdk) throw new Error('SDK not initialized'); if (!state.isConnected) throw new Error('Not connected'); return sdk.sign(payload); }, [sdk, state.isConnected]); // Verify signature const verify = useCallback(async (sig: NIP1SignedObject): Promise<boolean> => { if (!sdk) throw new Error('SDK not initialized'); return sdk.verify(sig); }, [sdk]); // Logout const logout = useCallback(async (): Promise<void> => { if (!sdk) throw new Error('SDK not initialized'); await sdk.logout(); setState({ isConnected: false, isConnecting: false, agentDid: null, keyId: null, error: null, }); }, [sdk]); return { state, connect, sign, verify, logout, sdk }; }