agent-hustle-demo 1.0.1

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.
Files changed (60) hide show
  1. package/README.md +429 -0
  2. package/dist/HustleChat-BC9wvWVA.d.ts +90 -0
  3. package/dist/HustleChat-BcrKkkyn.d.cts +90 -0
  4. package/dist/browser/hustle-react.js +14854 -0
  5. package/dist/browser/hustle-react.js.map +1 -0
  6. package/dist/components/index.cjs +3141 -0
  7. package/dist/components/index.cjs.map +1 -0
  8. package/dist/components/index.d.cts +20 -0
  9. package/dist/components/index.d.ts +20 -0
  10. package/dist/components/index.js +3112 -0
  11. package/dist/components/index.js.map +1 -0
  12. package/dist/hooks/index.cjs +845 -0
  13. package/dist/hooks/index.cjs.map +1 -0
  14. package/dist/hooks/index.d.cts +6 -0
  15. package/dist/hooks/index.d.ts +6 -0
  16. package/dist/hooks/index.js +838 -0
  17. package/dist/hooks/index.js.map +1 -0
  18. package/dist/hustle-Kj0X8qXC.d.cts +193 -0
  19. package/dist/hustle-Kj0X8qXC.d.ts +193 -0
  20. package/dist/index-ChUsRBwL.d.ts +152 -0
  21. package/dist/index-DE1N7C3W.d.cts +152 -0
  22. package/dist/index-DuPFrMZy.d.cts +214 -0
  23. package/dist/index-kFIdHjNw.d.ts +214 -0
  24. package/dist/index.cjs +3746 -0
  25. package/dist/index.cjs.map +1 -0
  26. package/dist/index.d.cts +271 -0
  27. package/dist/index.d.ts +271 -0
  28. package/dist/index.js +3697 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/providers/index.cjs +844 -0
  31. package/dist/providers/index.cjs.map +1 -0
  32. package/dist/providers/index.d.cts +5 -0
  33. package/dist/providers/index.d.ts +5 -0
  34. package/dist/providers/index.js +838 -0
  35. package/dist/providers/index.js.map +1 -0
  36. package/package.json +80 -0
  37. package/src/components/AuthStatus.tsx +352 -0
  38. package/src/components/ConnectButton.tsx +421 -0
  39. package/src/components/HustleChat.tsx +1273 -0
  40. package/src/components/MarkdownContent.tsx +431 -0
  41. package/src/components/index.ts +15 -0
  42. package/src/hooks/index.ts +40 -0
  43. package/src/hooks/useEmblemAuth.ts +27 -0
  44. package/src/hooks/useHustle.ts +36 -0
  45. package/src/hooks/usePlugins.ts +135 -0
  46. package/src/index.ts +142 -0
  47. package/src/plugins/index.ts +48 -0
  48. package/src/plugins/migrateFun.ts +211 -0
  49. package/src/plugins/predictionMarket.ts +411 -0
  50. package/src/providers/EmblemAuthProvider.tsx +319 -0
  51. package/src/providers/HustleProvider.tsx +540 -0
  52. package/src/providers/index.ts +6 -0
  53. package/src/styles/index.ts +2 -0
  54. package/src/styles/tokens.ts +447 -0
  55. package/src/types/auth.ts +85 -0
  56. package/src/types/hustle.ts +217 -0
  57. package/src/types/index.ts +49 -0
  58. package/src/types/plugin.ts +180 -0
  59. package/src/utils/index.ts +122 -0
  60. package/src/utils/pluginRegistry.ts +375 -0
@@ -0,0 +1,319 @@
1
+ 'use client';
2
+
3
+ import React, {
4
+ createContext,
5
+ useContext,
6
+ useState,
7
+ useEffect,
8
+ useCallback,
9
+ useRef,
10
+ } from 'react';
11
+ import { EmblemAuthSDK } from 'emblem-auth-sdk';
12
+ import type {
13
+ AuthSession,
14
+ VaultInfo,
15
+ EmblemAuthContextValue,
16
+ EmblemAuthProviderProps,
17
+ } from '../types';
18
+
19
+ /**
20
+ * Global SDK instance to prevent multiple initializations
21
+ * This is important for React strict mode and hot reloading
22
+ */
23
+ let globalSDKInstance: EmblemAuthSDK | null = null;
24
+ let isSDKInitializing = false;
25
+
26
+ /**
27
+ * Auth context - undefined when not within provider
28
+ */
29
+ const EmblemAuthContext = createContext<EmblemAuthContextValue | undefined>(undefined);
30
+
31
+ /**
32
+ * EmblemAuthProvider - Provides authentication state and actions to the app
33
+ *
34
+ * This is a first-class citizen - it has no dependency on Hustle SDK.
35
+ * The Hustle SDK depends on this provider for authentication.
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * <EmblemAuthProvider
40
+ * appId="your-app-id"
41
+ * apiUrl="https://dev-api.emblemvault.ai"
42
+ * modalUrl="https://dev-auth.emblemvault.ai/connect"
43
+ * >
44
+ * <App />
45
+ * </EmblemAuthProvider>
46
+ * ```
47
+ */
48
+ export function EmblemAuthProvider({
49
+ children,
50
+ appId,
51
+ apiUrl,
52
+ modalUrl,
53
+ debug = false,
54
+ }: EmblemAuthProviderProps) {
55
+ // State
56
+ const [session, setSession] = useState<AuthSession | null>(null);
57
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
58
+ const [isLoading, setIsLoading] = useState(false);
59
+ const [error, setError] = useState<Error | null>(null);
60
+ const [vaultInfo, setVaultInfo] = useState<VaultInfo | null>(null);
61
+ const [authSDK, setAuthSDK] = useState<EmblemAuthSDK | null>(globalSDKInstance);
62
+
63
+ // Track if we've initialized
64
+ const initialized = useRef(false);
65
+
66
+ // Debug logger
67
+ const log = useCallback(
68
+ (message: string, ...args: unknown[]) => {
69
+ if (debug) {
70
+ console.log(`[EmblemAuth] ${message}`, ...args);
71
+ }
72
+ },
73
+ [debug]
74
+ );
75
+
76
+ /**
77
+ * Fetch vault info after authentication
78
+ */
79
+ const fetchVaultInfo = useCallback(
80
+ async (sdk: EmblemAuthSDK) => {
81
+ try {
82
+ const info = await sdk.getVaultInfo();
83
+ if (info) {
84
+ setVaultInfo(info);
85
+ log('Vault info loaded:', info);
86
+ }
87
+ } catch (err) {
88
+ log('Failed to fetch vault info:', err);
89
+ }
90
+ },
91
+ [log]
92
+ );
93
+
94
+ /**
95
+ * Handle successful authentication
96
+ */
97
+ const handleAuthSuccess = useCallback(
98
+ (newSession: AuthSession, sdk: EmblemAuthSDK) => {
99
+ log('Auth success - session:', newSession);
100
+ setSession(newSession);
101
+ setIsAuthenticated(true);
102
+ setIsLoading(false);
103
+ setError(null);
104
+ fetchVaultInfo(sdk);
105
+ },
106
+ [log, fetchVaultInfo]
107
+ );
108
+
109
+ /**
110
+ * Handle authentication error
111
+ */
112
+ const handleAuthError = useCallback(
113
+ (err: Error) => {
114
+ log('Auth error:', err);
115
+ setError(err);
116
+ setIsLoading(false);
117
+ setIsAuthenticated(false);
118
+ setSession(null);
119
+ },
120
+ [log]
121
+ );
122
+
123
+ /**
124
+ * Handle session expiration
125
+ */
126
+ const handleSessionExpired = useCallback(() => {
127
+ log('Session expired');
128
+ setSession(null);
129
+ setIsAuthenticated(false);
130
+ setVaultInfo(null);
131
+ }, [log]);
132
+
133
+ /**
134
+ * Initialize the SDK
135
+ */
136
+ useEffect(() => {
137
+ // Prevent double initialization
138
+ if (initialized.current || globalSDKInstance || isSDKInitializing) {
139
+ if (globalSDKInstance && !authSDK) {
140
+ setAuthSDK(globalSDKInstance);
141
+ // Check for existing session
142
+ const existingSession = globalSDKInstance.getSession();
143
+ if (existingSession) {
144
+ handleAuthSuccess(existingSession, globalSDKInstance);
145
+ }
146
+ }
147
+ return;
148
+ }
149
+
150
+ initialized.current = true;
151
+ isSDKInitializing = true;
152
+ log('Initializing SDK with appId:', appId);
153
+
154
+ // Create SDK instance
155
+ const sdk = new EmblemAuthSDK({
156
+ appId,
157
+ apiUrl,
158
+ modalUrl,
159
+ onSuccess: (newSession) => {
160
+ handleAuthSuccess(newSession as AuthSession, sdk);
161
+ },
162
+ onError: (err) => {
163
+ handleAuthError(err);
164
+ },
165
+ });
166
+
167
+ // Store globally and locally
168
+ globalSDKInstance = sdk;
169
+ isSDKInitializing = false;
170
+ setAuthSDK(sdk);
171
+
172
+ // Check for existing session
173
+ const existingSession = sdk.getSession();
174
+ if (existingSession) {
175
+ log('Found existing session');
176
+ handleAuthSuccess(existingSession as AuthSession, sdk);
177
+ }
178
+
179
+ // Subscribe to session events
180
+ const handleSessionUpdate = (updatedSession: AuthSession | null) => {
181
+ if (updatedSession) {
182
+ setSession(updatedSession);
183
+ setIsAuthenticated(true);
184
+ } else {
185
+ handleSessionExpired();
186
+ }
187
+ };
188
+
189
+ sdk.on('session', handleSessionUpdate);
190
+ sdk.on('sessionExpired', handleSessionExpired);
191
+
192
+ // Cleanup
193
+ return () => {
194
+ sdk.off('session', handleSessionUpdate);
195
+ sdk.off('sessionExpired', handleSessionExpired);
196
+ };
197
+ }, [appId, apiUrl, modalUrl, log, handleAuthSuccess, handleAuthError, handleSessionExpired, authSDK]);
198
+
199
+ /**
200
+ * Open the auth modal
201
+ */
202
+ const openAuthModal = useCallback(async () => {
203
+ if (!authSDK) {
204
+ setError(new Error('Auth SDK not initialized'));
205
+ return;
206
+ }
207
+
208
+ log('Opening auth modal');
209
+ setIsLoading(true);
210
+ setError(null);
211
+
212
+ try {
213
+ await authSDK.openAuthModal();
214
+ // Success is handled by onSuccess callback
215
+ } catch (err) {
216
+ setIsLoading(false);
217
+ setError(err instanceof Error ? err : new Error('Failed to open auth modal'));
218
+ }
219
+ }, [authSDK, log]);
220
+
221
+ /**
222
+ * Logout and clear session
223
+ */
224
+ const logout = useCallback(() => {
225
+ if (!authSDK) return;
226
+
227
+ log('Logging out');
228
+ authSDK.logout();
229
+ setSession(null);
230
+ setIsAuthenticated(false);
231
+ setVaultInfo(null);
232
+ setError(null);
233
+ }, [authSDK, log]);
234
+
235
+ /**
236
+ * Refresh the current session
237
+ */
238
+ const refreshSession = useCallback(async (): Promise<AuthSession | null> => {
239
+ if (!authSDK) return null;
240
+
241
+ log('Refreshing session');
242
+ try {
243
+ const refreshedSession = await authSDK.refreshSession();
244
+ if (refreshedSession) {
245
+ setSession(refreshedSession as AuthSession);
246
+ setIsAuthenticated(true);
247
+ return refreshedSession as AuthSession;
248
+ }
249
+ return null;
250
+ } catch (err) {
251
+ log('Failed to refresh session:', err);
252
+ setError(err instanceof Error ? err : new Error('Failed to refresh session'));
253
+ return null;
254
+ }
255
+ }, [authSDK, log]);
256
+
257
+ // Derived values
258
+ const vaultId = session?.user?.vaultId ?? null;
259
+ const walletAddress = session?.user?.evmAddress ?? null;
260
+
261
+ // Context value
262
+ const value: EmblemAuthContextValue = {
263
+ // State
264
+ session,
265
+ isAuthenticated,
266
+ isLoading,
267
+ error,
268
+ vaultInfo,
269
+
270
+ // Derived
271
+ vaultId,
272
+ walletAddress,
273
+
274
+ // Actions
275
+ openAuthModal,
276
+ logout,
277
+ refreshSession,
278
+
279
+ // For Hustle integration
280
+ authSDK,
281
+ };
282
+
283
+ return (
284
+ <EmblemAuthContext.Provider value={value}>
285
+ {children}
286
+ </EmblemAuthContext.Provider>
287
+ );
288
+ }
289
+
290
+ /**
291
+ * Hook to access auth context
292
+ * Must be used within EmblemAuthProvider
293
+ *
294
+ * @example
295
+ * ```tsx
296
+ * function MyComponent() {
297
+ * const { isAuthenticated, openAuthModal, logout } = useEmblemAuth();
298
+ *
299
+ * return isAuthenticated
300
+ * ? <button onClick={logout}>Logout</button>
301
+ * : <button onClick={openAuthModal}>Connect</button>;
302
+ * }
303
+ * ```
304
+ */
305
+ export function useEmblemAuth(): EmblemAuthContextValue {
306
+ const context = useContext(EmblemAuthContext);
307
+ if (context === undefined) {
308
+ throw new Error('useEmblemAuth must be used within an EmblemAuthProvider');
309
+ }
310
+ return context;
311
+ }
312
+
313
+ /**
314
+ * Reset the global SDK instance (useful for testing)
315
+ */
316
+ export function resetAuthSDK(): void {
317
+ globalSDKInstance = null;
318
+ isSDKInitializing = false;
319
+ }