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.
- package/README.md +429 -0
- package/dist/HustleChat-BC9wvWVA.d.ts +90 -0
- package/dist/HustleChat-BcrKkkyn.d.cts +90 -0
- package/dist/browser/hustle-react.js +14854 -0
- package/dist/browser/hustle-react.js.map +1 -0
- package/dist/components/index.cjs +3141 -0
- package/dist/components/index.cjs.map +1 -0
- package/dist/components/index.d.cts +20 -0
- package/dist/components/index.d.ts +20 -0
- package/dist/components/index.js +3112 -0
- package/dist/components/index.js.map +1 -0
- package/dist/hooks/index.cjs +845 -0
- package/dist/hooks/index.cjs.map +1 -0
- package/dist/hooks/index.d.cts +6 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.js +838 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hustle-Kj0X8qXC.d.cts +193 -0
- package/dist/hustle-Kj0X8qXC.d.ts +193 -0
- package/dist/index-ChUsRBwL.d.ts +152 -0
- package/dist/index-DE1N7C3W.d.cts +152 -0
- package/dist/index-DuPFrMZy.d.cts +214 -0
- package/dist/index-kFIdHjNw.d.ts +214 -0
- package/dist/index.cjs +3746 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +271 -0
- package/dist/index.d.ts +271 -0
- package/dist/index.js +3697 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/index.cjs +844 -0
- package/dist/providers/index.cjs.map +1 -0
- package/dist/providers/index.d.cts +5 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.js +838 -0
- package/dist/providers/index.js.map +1 -0
- package/package.json +80 -0
- package/src/components/AuthStatus.tsx +352 -0
- package/src/components/ConnectButton.tsx +421 -0
- package/src/components/HustleChat.tsx +1273 -0
- package/src/components/MarkdownContent.tsx +431 -0
- package/src/components/index.ts +15 -0
- package/src/hooks/index.ts +40 -0
- package/src/hooks/useEmblemAuth.ts +27 -0
- package/src/hooks/useHustle.ts +36 -0
- package/src/hooks/usePlugins.ts +135 -0
- package/src/index.ts +142 -0
- package/src/plugins/index.ts +48 -0
- package/src/plugins/migrateFun.ts +211 -0
- package/src/plugins/predictionMarket.ts +411 -0
- package/src/providers/EmblemAuthProvider.tsx +319 -0
- package/src/providers/HustleProvider.tsx +540 -0
- package/src/providers/index.ts +6 -0
- package/src/styles/index.ts +2 -0
- package/src/styles/tokens.ts +447 -0
- package/src/types/auth.ts +85 -0
- package/src/types/hustle.ts +217 -0
- package/src/types/index.ts +49 -0
- package/src/types/plugin.ts +180 -0
- package/src/utils/index.ts +122 -0
- 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
|
+
}
|