@emblemvault/emblem-auth-react 1.0.0

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.
@@ -0,0 +1,135 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { EmblemAuthSDK } from 'emblem-auth-sdk';
3
+
4
+ /**
5
+ * Auth Types for Emblem Auth SDK integration
6
+ * These types mirror the EmblemAuthSDK types for use in React components
7
+ */
8
+
9
+ /**
10
+ * User information from the authenticated session
11
+ */
12
+ interface AuthUser {
13
+ identifier: string;
14
+ vaultId: string;
15
+ evmAddress?: string;
16
+ solanaAddress?: string;
17
+ }
18
+ /**
19
+ * Authenticated session returned by the Auth SDK
20
+ */
21
+ interface AuthSession {
22
+ user: AuthUser;
23
+ authToken: string;
24
+ refreshToken?: string;
25
+ expiresAt: number;
26
+ appId: string;
27
+ scope?: string;
28
+ }
29
+ /**
30
+ * Vault information retrieved after authentication
31
+ */
32
+ interface VaultInfo {
33
+ vaultId: string;
34
+ evmAddress?: string;
35
+ solanaAddress?: string;
36
+ hederaAccountId?: string;
37
+ createdAt?: string;
38
+ metadata?: Record<string, unknown>;
39
+ }
40
+ /**
41
+ * Configuration options for EmblemAuthProvider
42
+ */
43
+ interface EmblemAuthConfig {
44
+ /** Application ID registered with Emblem */
45
+ appId: string;
46
+ /** API endpoint URL (defaults to production) */
47
+ apiUrl?: string;
48
+ /** Auth modal URL (defaults to production) */
49
+ modalUrl?: string;
50
+ /** Enable debug logging */
51
+ debug?: boolean;
52
+ }
53
+ /**
54
+ * Context value exposed by EmblemAuthProvider
55
+ */
56
+ interface EmblemAuthContextValue {
57
+ session: AuthSession | null;
58
+ isAuthenticated: boolean;
59
+ isLoading: boolean;
60
+ error: Error | null;
61
+ vaultInfo: VaultInfo | null;
62
+ vaultId: string | null;
63
+ walletAddress: string | null;
64
+ openAuthModal: () => Promise<void>;
65
+ logout: () => void;
66
+ refreshSession: () => Promise<AuthSession | null>;
67
+ authSDK: EmblemAuthSDK | null;
68
+ }
69
+ /**
70
+ * Props for EmblemAuthProvider component
71
+ */
72
+ interface EmblemAuthProviderProps extends EmblemAuthConfig {
73
+ children: React.ReactNode;
74
+ }
75
+
76
+ /**
77
+ * EmblemAuthProvider - Provides authentication state and actions to the app
78
+ *
79
+ * This is a first-class citizen - it has no dependency on Hustle SDK.
80
+ * The Hustle SDK depends on this provider for authentication.
81
+ *
82
+ * @example
83
+ * ```tsx
84
+ * <EmblemAuthProvider
85
+ * appId="your-app-id"
86
+ * apiUrl="https://api.emblemvault.ai"
87
+ * modalUrl="https://auth.emblemvault.ai/connect"
88
+ * >
89
+ * <App />
90
+ * </EmblemAuthProvider>
91
+ * ```
92
+ */
93
+ declare function EmblemAuthProvider({ children, appId, apiUrl, modalUrl, debug, }: EmblemAuthProviderProps): react_jsx_runtime.JSX.Element;
94
+ /**
95
+ * Hook to access auth context
96
+ * Must be used within EmblemAuthProvider
97
+ *
98
+ * @example
99
+ * ```tsx
100
+ * function MyComponent() {
101
+ * const { isAuthenticated, openAuthModal, logout } = useEmblemAuth();
102
+ *
103
+ * return isAuthenticated
104
+ * ? <button onClick={logout}>Logout</button>
105
+ * : <button onClick={openAuthModal}>Connect</button>;
106
+ * }
107
+ * ```
108
+ */
109
+ declare function useEmblemAuth(): EmblemAuthContextValue;
110
+ /**
111
+ * Optional version of useEmblemAuth that returns null when used outside EmblemAuthProvider
112
+ *
113
+ * Use this when authentication is optional, such as when using HustleProvider
114
+ * with direct API key authentication.
115
+ *
116
+ * @example
117
+ * ```tsx
118
+ * function OptionalAuthComponent() {
119
+ * const auth = useEmblemAuthOptional();
120
+ *
121
+ * if (!auth) {
122
+ * return <p>Auth not available</p>;
123
+ * }
124
+ *
125
+ * return <p>Logged in as {auth.walletAddress}</p>;
126
+ * }
127
+ * ```
128
+ */
129
+ declare function useEmblemAuthOptional(): EmblemAuthContextValue | null;
130
+ /**
131
+ * Reset the global SDK instance (useful for testing)
132
+ */
133
+ declare function resetAuthSDK(): void;
134
+
135
+ export { type AuthSession, type AuthUser, type EmblemAuthConfig, type EmblemAuthContextValue, EmblemAuthProvider, type EmblemAuthProviderProps, type VaultInfo, resetAuthSDK, useEmblemAuth, useEmblemAuthOptional };
@@ -0,0 +1,199 @@
1
+ import { createContext, useState, useRef, useCallback, useEffect, useContext } from 'react';
2
+ import { EmblemAuthSDK } from 'emblem-auth-sdk';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ var globalSDKInstance = null;
6
+ var isSDKInitializing = false;
7
+ var EmblemAuthContext = createContext(void 0);
8
+ function EmblemAuthProvider({
9
+ children,
10
+ appId,
11
+ apiUrl,
12
+ modalUrl,
13
+ debug = false
14
+ }) {
15
+ const [session, setSession] = useState(null);
16
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
17
+ const [isLoading, setIsLoading] = useState(false);
18
+ const [error, setError] = useState(null);
19
+ const [vaultInfo, setVaultInfo] = useState(null);
20
+ const [authSDK, setAuthSDK] = useState(globalSDKInstance);
21
+ const initialized = useRef(false);
22
+ const log = useCallback(
23
+ (message, ...args) => {
24
+ if (debug) {
25
+ console.log(`[EmblemAuth] ${message}`, ...args);
26
+ }
27
+ },
28
+ [debug]
29
+ );
30
+ const fetchVaultInfo = useCallback(
31
+ async (sdk) => {
32
+ try {
33
+ const info = await sdk.getVaultInfo();
34
+ if (info) {
35
+ setVaultInfo(info);
36
+ log("Vault info loaded:", info);
37
+ }
38
+ } catch (err) {
39
+ log("Failed to fetch vault info:", err);
40
+ }
41
+ },
42
+ [log]
43
+ );
44
+ const handleAuthSuccess = useCallback(
45
+ (newSession, sdk) => {
46
+ log("Auth success - session:", newSession);
47
+ setSession(newSession);
48
+ setIsAuthenticated(true);
49
+ setIsLoading(false);
50
+ setError(null);
51
+ fetchVaultInfo(sdk);
52
+ },
53
+ [log, fetchVaultInfo]
54
+ );
55
+ const handleAuthError = useCallback(
56
+ (err) => {
57
+ log("Auth error:", err);
58
+ setError(err);
59
+ setIsLoading(false);
60
+ setIsAuthenticated(false);
61
+ setSession(null);
62
+ },
63
+ [log]
64
+ );
65
+ const handleSessionExpired = useCallback(() => {
66
+ log("Session expired");
67
+ setSession(null);
68
+ setIsAuthenticated(false);
69
+ setVaultInfo(null);
70
+ }, [log]);
71
+ useEffect(() => {
72
+ if (initialized.current || globalSDKInstance || isSDKInitializing) {
73
+ if (globalSDKInstance && !authSDK) {
74
+ setAuthSDK(globalSDKInstance);
75
+ const existingSession2 = globalSDKInstance.getSession();
76
+ if (existingSession2) {
77
+ handleAuthSuccess(existingSession2, globalSDKInstance);
78
+ }
79
+ }
80
+ return;
81
+ }
82
+ initialized.current = true;
83
+ isSDKInitializing = true;
84
+ log("Initializing SDK with appId:", appId);
85
+ const sdk = new EmblemAuthSDK({
86
+ appId,
87
+ apiUrl,
88
+ modalUrl,
89
+ onSuccess: (newSession) => {
90
+ handleAuthSuccess(newSession, sdk);
91
+ },
92
+ onError: (err) => {
93
+ handleAuthError(err);
94
+ }
95
+ });
96
+ globalSDKInstance = sdk;
97
+ isSDKInitializing = false;
98
+ setAuthSDK(sdk);
99
+ const existingSession = sdk.getSession();
100
+ if (existingSession) {
101
+ log("Found existing session");
102
+ handleAuthSuccess(existingSession, sdk);
103
+ }
104
+ const handleSessionUpdate = (updatedSession) => {
105
+ if (updatedSession) {
106
+ setSession(updatedSession);
107
+ setIsAuthenticated(true);
108
+ } else {
109
+ handleSessionExpired();
110
+ }
111
+ };
112
+ sdk.on("session", handleSessionUpdate);
113
+ sdk.on("sessionExpired", handleSessionExpired);
114
+ return () => {
115
+ sdk.off("session", handleSessionUpdate);
116
+ sdk.off("sessionExpired", handleSessionExpired);
117
+ };
118
+ }, [appId, apiUrl, modalUrl, log, handleAuthSuccess, handleAuthError, handleSessionExpired, authSDK]);
119
+ const openAuthModal = useCallback(async () => {
120
+ if (!authSDK) {
121
+ setError(new Error("Auth SDK not initialized"));
122
+ return;
123
+ }
124
+ log("Opening auth modal");
125
+ setIsLoading(true);
126
+ setError(null);
127
+ try {
128
+ await authSDK.openAuthModal();
129
+ } catch (err) {
130
+ setIsLoading(false);
131
+ setError(err instanceof Error ? err : new Error("Failed to open auth modal"));
132
+ }
133
+ }, [authSDK, log]);
134
+ const logout = useCallback(() => {
135
+ if (!authSDK) return;
136
+ log("Logging out");
137
+ authSDK.logout();
138
+ setSession(null);
139
+ setIsAuthenticated(false);
140
+ setVaultInfo(null);
141
+ setError(null);
142
+ }, [authSDK, log]);
143
+ const refreshSession = useCallback(async () => {
144
+ if (!authSDK) return null;
145
+ log("Refreshing session");
146
+ try {
147
+ const refreshedSession = await authSDK.refreshSession();
148
+ if (refreshedSession) {
149
+ setSession(refreshedSession);
150
+ setIsAuthenticated(true);
151
+ return refreshedSession;
152
+ }
153
+ return null;
154
+ } catch (err) {
155
+ log("Failed to refresh session:", err);
156
+ setError(err instanceof Error ? err : new Error("Failed to refresh session"));
157
+ return null;
158
+ }
159
+ }, [authSDK, log]);
160
+ const vaultId = session?.user?.vaultId ?? null;
161
+ const walletAddress = session?.user?.evmAddress ?? null;
162
+ const value = {
163
+ // State
164
+ session,
165
+ isAuthenticated,
166
+ isLoading,
167
+ error,
168
+ vaultInfo,
169
+ // Derived
170
+ vaultId,
171
+ walletAddress,
172
+ // Actions
173
+ openAuthModal,
174
+ logout,
175
+ refreshSession,
176
+ // For Hustle integration
177
+ authSDK
178
+ };
179
+ return /* @__PURE__ */ jsx(EmblemAuthContext.Provider, { value, children });
180
+ }
181
+ function useEmblemAuth() {
182
+ const context = useContext(EmblemAuthContext);
183
+ if (context === void 0) {
184
+ throw new Error("useEmblemAuth must be used within an EmblemAuthProvider");
185
+ }
186
+ return context;
187
+ }
188
+ function useEmblemAuthOptional() {
189
+ const context = useContext(EmblemAuthContext);
190
+ return context ?? null;
191
+ }
192
+ function resetAuthSDK() {
193
+ globalSDKInstance = null;
194
+ isSDKInitializing = false;
195
+ }
196
+
197
+ export { EmblemAuthProvider, resetAuthSDK, useEmblemAuth, useEmblemAuthOptional };
198
+ //# sourceMappingURL=index.js.map
199
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/EmblemAuthProvider.tsx"],"names":["existingSession"],"mappings":"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","file":"index.js","sourcesContent":["'use client';\n\nimport React, {\n createContext,\n useContext,\n useState,\n useEffect,\n useCallback,\n useRef,\n} from 'react';\nimport { EmblemAuthSDK } from 'emblem-auth-sdk';\nimport type {\n AuthSession,\n VaultInfo,\n EmblemAuthContextValue,\n EmblemAuthProviderProps,\n} from '../types';\n\n/**\n * Global SDK instance to prevent multiple initializations\n * This is important for React strict mode and hot reloading\n */\nlet globalSDKInstance: EmblemAuthSDK | null = null;\nlet isSDKInitializing = false;\n\n/**\n * Auth context - undefined when not within provider\n */\nconst EmblemAuthContext = createContext<EmblemAuthContextValue | undefined>(undefined);\n\n/**\n * EmblemAuthProvider - Provides authentication state and actions to the app\n *\n * This is a first-class citizen - it has no dependency on Hustle SDK.\n * The Hustle SDK depends on this provider for authentication.\n *\n * @example\n * ```tsx\n * <EmblemAuthProvider\n * appId=\"your-app-id\"\n * apiUrl=\"https://api.emblemvault.ai\"\n * modalUrl=\"https://auth.emblemvault.ai/connect\"\n * >\n * <App />\n * </EmblemAuthProvider>\n * ```\n */\nexport function EmblemAuthProvider({\n children,\n appId,\n apiUrl,\n modalUrl,\n debug = false,\n}: EmblemAuthProviderProps) {\n // State\n const [session, setSession] = useState<AuthSession | null>(null);\n const [isAuthenticated, setIsAuthenticated] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [vaultInfo, setVaultInfo] = useState<VaultInfo | null>(null);\n const [authSDK, setAuthSDK] = useState<EmblemAuthSDK | null>(globalSDKInstance);\n\n // Track if we've initialized\n const initialized = useRef(false);\n\n // Debug logger\n const log = useCallback(\n (message: string, ...args: unknown[]) => {\n if (debug) {\n console.log(`[EmblemAuth] ${message}`, ...args);\n }\n },\n [debug]\n );\n\n /**\n * Fetch vault info after authentication\n */\n const fetchVaultInfo = useCallback(\n async (sdk: EmblemAuthSDK) => {\n try {\n const info = await sdk.getVaultInfo();\n if (info) {\n setVaultInfo(info);\n log('Vault info loaded:', info);\n }\n } catch (err) {\n log('Failed to fetch vault info:', err);\n }\n },\n [log]\n );\n\n /**\n * Handle successful authentication\n */\n const handleAuthSuccess = useCallback(\n (newSession: AuthSession, sdk: EmblemAuthSDK) => {\n log('Auth success - session:', newSession);\n setSession(newSession);\n setIsAuthenticated(true);\n setIsLoading(false);\n setError(null);\n fetchVaultInfo(sdk);\n },\n [log, fetchVaultInfo]\n );\n\n /**\n * Handle authentication error\n */\n const handleAuthError = useCallback(\n (err: Error) => {\n log('Auth error:', err);\n setError(err);\n setIsLoading(false);\n setIsAuthenticated(false);\n setSession(null);\n },\n [log]\n );\n\n /**\n * Handle session expiration\n */\n const handleSessionExpired = useCallback(() => {\n log('Session expired');\n setSession(null);\n setIsAuthenticated(false);\n setVaultInfo(null);\n }, [log]);\n\n /**\n * Initialize the SDK\n */\n useEffect(() => {\n // Prevent double initialization\n if (initialized.current || globalSDKInstance || isSDKInitializing) {\n if (globalSDKInstance && !authSDK) {\n setAuthSDK(globalSDKInstance);\n // Check for existing session\n const existingSession = globalSDKInstance.getSession();\n if (existingSession) {\n handleAuthSuccess(existingSession, globalSDKInstance);\n }\n }\n return;\n }\n\n initialized.current = true;\n isSDKInitializing = true;\n log('Initializing SDK with appId:', appId);\n\n // Create SDK instance\n const sdk = new EmblemAuthSDK({\n appId,\n apiUrl,\n modalUrl,\n onSuccess: (newSession) => {\n handleAuthSuccess(newSession as AuthSession, sdk);\n },\n onError: (err) => {\n handleAuthError(err);\n },\n });\n\n // Store globally and locally\n globalSDKInstance = sdk;\n isSDKInitializing = false;\n setAuthSDK(sdk);\n\n // Check for existing session\n const existingSession = sdk.getSession();\n if (existingSession) {\n log('Found existing session');\n handleAuthSuccess(existingSession as AuthSession, sdk);\n }\n\n // Subscribe to session events\n const handleSessionUpdate = (updatedSession: AuthSession | null) => {\n if (updatedSession) {\n setSession(updatedSession);\n setIsAuthenticated(true);\n } else {\n handleSessionExpired();\n }\n };\n\n sdk.on('session', handleSessionUpdate);\n sdk.on('sessionExpired', handleSessionExpired);\n\n // Cleanup\n return () => {\n sdk.off('session', handleSessionUpdate);\n sdk.off('sessionExpired', handleSessionExpired);\n };\n }, [appId, apiUrl, modalUrl, log, handleAuthSuccess, handleAuthError, handleSessionExpired, authSDK]);\n\n /**\n * Open the auth modal\n */\n const openAuthModal = useCallback(async () => {\n if (!authSDK) {\n setError(new Error('Auth SDK not initialized'));\n return;\n }\n\n log('Opening auth modal');\n setIsLoading(true);\n setError(null);\n\n try {\n await authSDK.openAuthModal();\n // Success is handled by onSuccess callback\n } catch (err) {\n setIsLoading(false);\n setError(err instanceof Error ? err : new Error('Failed to open auth modal'));\n }\n }, [authSDK, log]);\n\n /**\n * Logout and clear session\n */\n const logout = useCallback(() => {\n if (!authSDK) return;\n\n log('Logging out');\n authSDK.logout();\n setSession(null);\n setIsAuthenticated(false);\n setVaultInfo(null);\n setError(null);\n }, [authSDK, log]);\n\n /**\n * Refresh the current session\n */\n const refreshSession = useCallback(async (): Promise<AuthSession | null> => {\n if (!authSDK) return null;\n\n log('Refreshing session');\n try {\n const refreshedSession = await authSDK.refreshSession();\n if (refreshedSession) {\n setSession(refreshedSession as AuthSession);\n setIsAuthenticated(true);\n return refreshedSession as AuthSession;\n }\n return null;\n } catch (err) {\n log('Failed to refresh session:', err);\n setError(err instanceof Error ? err : new Error('Failed to refresh session'));\n return null;\n }\n }, [authSDK, log]);\n\n // Derived values\n const vaultId = session?.user?.vaultId ?? null;\n const walletAddress = session?.user?.evmAddress ?? null;\n\n // Context value\n const value: EmblemAuthContextValue = {\n // State\n session,\n isAuthenticated,\n isLoading,\n error,\n vaultInfo,\n\n // Derived\n vaultId,\n walletAddress,\n\n // Actions\n openAuthModal,\n logout,\n refreshSession,\n\n // For Hustle integration\n authSDK,\n };\n\n return (\n <EmblemAuthContext.Provider value={value}>\n {children}\n </EmblemAuthContext.Provider>\n );\n}\n\n/**\n * Hook to access auth context\n * Must be used within EmblemAuthProvider\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { isAuthenticated, openAuthModal, logout } = useEmblemAuth();\n *\n * return isAuthenticated\n * ? <button onClick={logout}>Logout</button>\n * : <button onClick={openAuthModal}>Connect</button>;\n * }\n * ```\n */\nexport function useEmblemAuth(): EmblemAuthContextValue {\n const context = useContext(EmblemAuthContext);\n if (context === undefined) {\n throw new Error('useEmblemAuth must be used within an EmblemAuthProvider');\n }\n return context;\n}\n\n/**\n * Optional version of useEmblemAuth that returns null when used outside EmblemAuthProvider\n *\n * Use this when authentication is optional, such as when using HustleProvider\n * with direct API key authentication.\n *\n * @example\n * ```tsx\n * function OptionalAuthComponent() {\n * const auth = useEmblemAuthOptional();\n *\n * if (!auth) {\n * return <p>Auth not available</p>;\n * }\n *\n * return <p>Logged in as {auth.walletAddress}</p>;\n * }\n * ```\n */\nexport function useEmblemAuthOptional(): EmblemAuthContextValue | null {\n const context = useContext(EmblemAuthContext);\n return context ?? null;\n}\n\n/**\n * Reset the global SDK instance (useful for testing)\n */\nexport function resetAuthSDK(): void {\n globalSDKInstance = null;\n isSDKInitializing = false;\n}\n"]}