@b3dotfun/sdk 0.0.88-alpha.2 → 0.0.88-alpha.3

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 (31) hide show
  1. package/dist/cjs/global-account/react/components/B3Provider/RelayKitProviderWrapper.js +3 -1
  2. package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +80 -20
  3. package/dist/cjs/global-account/react/components/TurnkeyAuthModal.js +3 -1
  4. package/dist/cjs/global-account/react/hooks/index.d.ts +1 -0
  5. package/dist/cjs/global-account/react/hooks/index.js +3 -1
  6. package/dist/cjs/global-account/react/hooks/useAuth.d.ts +76 -0
  7. package/dist/cjs/global-account/react/hooks/useAuth.js +338 -0
  8. package/dist/cjs/global-account/react/hooks/useTWAuth.d.ts +3 -0
  9. package/dist/cjs/global-account/react/hooks/useTWAuth.js +8 -0
  10. package/dist/cjs/global-account/react/hooks/useTurnkeyAuth.js +50 -22
  11. package/dist/esm/global-account/react/components/B3Provider/RelayKitProviderWrapper.js +3 -1
  12. package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +81 -21
  13. package/dist/esm/global-account/react/components/TurnkeyAuthModal.js +5 -3
  14. package/dist/esm/global-account/react/hooks/index.d.ts +1 -0
  15. package/dist/esm/global-account/react/hooks/index.js +1 -0
  16. package/dist/esm/global-account/react/hooks/useAuth.d.ts +76 -0
  17. package/dist/esm/global-account/react/hooks/useAuth.js +332 -0
  18. package/dist/esm/global-account/react/hooks/useTWAuth.d.ts +3 -0
  19. package/dist/esm/global-account/react/hooks/useTWAuth.js +8 -0
  20. package/dist/esm/global-account/react/hooks/useTurnkeyAuth.js +50 -22
  21. package/dist/types/global-account/react/hooks/index.d.ts +1 -0
  22. package/dist/types/global-account/react/hooks/useAuth.d.ts +76 -0
  23. package/dist/types/global-account/react/hooks/useTWAuth.d.ts +3 -0
  24. package/package.json +1 -1
  25. package/src/global-account/react/components/B3Provider/RelayKitProviderWrapper.tsx +4 -1
  26. package/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx +170 -99
  27. package/src/global-account/react/components/TurnkeyAuthModal.tsx +7 -4
  28. package/src/global-account/react/hooks/index.ts +1 -0
  29. package/src/global-account/react/hooks/useAuth.ts +380 -0
  30. package/src/global-account/react/hooks/useTWAuth.tsx +10 -0
  31. package/src/global-account/react/hooks/useTurnkeyAuth.ts +54 -23
@@ -14,6 +14,8 @@ function RelayKitProviderWrapper({ children, simDuneApiKey, }) {
14
14
  };
15
15
  fetchChains();
16
16
  }, []);
17
+ const isTurnkeyPrimary = process.env.NEXT_PUBLIC_TURNKEY_PRIMARY === "true";
18
+ const appName = isTurnkeyPrimary ? "Smart Wallet" : "AnySpend";
17
19
  return ((0, jsx_runtime_1.jsx)(relay_kit_ui_1.RelayKitProvider, { options: {
18
20
  baseApiUrl: relay_sdk_1.MAINNET_RELAY_API,
19
21
  source: "anyspend",
@@ -23,7 +25,7 @@ function RelayKitProviderWrapper({ children, simDuneApiKey, }) {
23
25
  },
24
26
  chains: relayChains,
25
27
  privateChainIds: undefined,
26
- appName: "AnySpend",
28
+ appName,
27
29
  useGasFeeEstimations: true,
28
30
  }, children: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children }) }));
29
31
  }
@@ -6,6 +6,7 @@ const react_1 = require("../../../../global-account/react");
6
6
  const debug_1 = require("../../../../shared/utils/debug");
7
7
  const react_2 = require("react");
8
8
  const react_3 = require("thirdweb/react");
9
+ const TurnkeyAuthModal_1 = require("../TurnkeyAuthModal");
9
10
  const SignInWithB3Privy_1 = require("./SignInWithB3Privy");
10
11
  const LoginStep_1 = require("./steps/LoginStep");
11
12
  const LoginStepCustom_1 = require("./steps/LoginStepCustom");
@@ -24,11 +25,14 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
24
25
  const account = (0, react_3.useActiveAccount)();
25
26
  const isAuthenticating = (0, react_1.useAuthStore)(state => state.isAuthenticating);
26
27
  const isAuthenticated = (0, react_1.useAuthStore)(state => state.isAuthenticated);
28
+ const setIsAuthenticated = (0, react_1.useAuthStore)(state => state.setIsAuthenticated);
27
29
  const isConnected = (0, react_1.useAuthStore)(state => state.isConnected);
30
+ const setIsConnected = (0, react_1.useAuthStore)(state => state.setIsConnected);
28
31
  const setJustCompletedLogin = (0, react_1.useAuthStore)(state => state.setJustCompletedLogin);
29
32
  const [refetchCount, setRefetchCount] = (0, react_2.useState)(0);
30
33
  const [refetchError, setRefetchError] = (0, react_2.useState)(null);
31
34
  const [turnkeyAuthCompleted, setTurnkeyAuthCompleted] = (0, react_2.useState)(false);
35
+ const justCompletedLoginRef = (0, react_2.useRef)(false);
32
36
  const { data: signers, refetch: refetchSigners, isFetching: isFetchingSigners, } = (0, react_1.useGetAllTWSigners)({
33
37
  chain,
34
38
  accountAddress: account?.address,
@@ -57,7 +61,9 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
57
61
  refetchSigners();
58
62
  setRefetchQueued(false);
59
63
  }, backoffDelay);
60
- }, [refetchCount, refetchSigners, onError, setRefetchQueued, refetchQueued]);
64
+ // State setters are stable and don't need to be in dependencies
65
+ // eslint-disable-next-line react-hooks/exhaustive-deps
66
+ }, [refetchCount, refetchSigners, onError, refetchQueued]);
61
67
  // Extract the completion flow logic to be reused
62
68
  const handlePostTurnkeyFlow = (0, react_2.useCallback)(() => {
63
69
  debug("Running post-Turnkey flow logic");
@@ -126,6 +132,10 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
126
132
  debug("Refetching user after Turnkey success...");
127
133
  await refetchUser();
128
134
  debug("User refetched successfully");
135
+ // Set authentication and connection state so UI updates properly
136
+ setIsAuthenticated(true);
137
+ setIsConnected(true);
138
+ setJustCompletedLogin(true);
129
139
  // After user data is refreshed, close Turnkey modal and go back to sign-in flow
130
140
  debug("Switching back to signInWithB3 modal");
131
141
  setB3ModalContentType({
@@ -142,7 +152,10 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
142
152
  signersEnabled,
143
153
  });
144
154
  // The useEffect will re-run with updated user data to complete the sign-in process
145
- }, [
155
+ },
156
+ // Zustand setters are stable and don't need to be in dependencies:
157
+ // eslint-disable-next-line react-hooks/exhaustive-deps
158
+ [
146
159
  refetchUser,
147
160
  setB3ModalContentType,
148
161
  strategies,
@@ -155,6 +168,8 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
155
168
  closeAfterLogin,
156
169
  source,
157
170
  signersEnabled,
171
+ // Zustand setters are stable and don't need to be in dependencies:
172
+ // setIsAuthenticated, setIsConnected, setJustCompletedLogin
158
173
  ]);
159
174
  // Handle post-login flow after signers are loaded
160
175
  (0, react_2.useEffect)(() => {
@@ -169,18 +184,25 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
169
184
  if (isConnected && isAuthenticated && user) {
170
185
  // Mark that login just completed BEFORE opening manage account or closing modal
171
186
  // This allows Turnkey modal to show (if enableTurnkey is true)
172
- if (closeAfterLogin) {
187
+ // Use ref to prevent setting this multiple times and causing infinite loops
188
+ if (closeAfterLogin && !justCompletedLoginRef.current) {
189
+ justCompletedLoginRef.current = true;
173
190
  setJustCompletedLogin(true);
174
191
  }
175
- // Check if we should show Turnkey login form
176
- // Show if enableTurnkey is true AND user just logged in AND hasn't completed Turnkey auth in this session
192
+ // Check if we should show Turnkey login form as SECONDARY option (after wallet connection)
193
+ // This only applies when:
194
+ // - enableTurnkey={true} is set on B3Provider
195
+ // - NEXT_PUBLIC_TURNKEY_PRIMARY is NOT set to true (otherwise Turnkey shows as primary)
196
+ // - User just logged in AND hasn't completed Turnkey auth in this session
177
197
  // For new users (!turnkeyId): Show email form
178
198
  // For returning users (turnkeyId && turnkeyEmail): Auto-skip to OTP
179
199
  // Also check that we're not already showing the Turnkey modal
180
200
  const hasTurnkeyId = user?.partnerIds?.turnkeyId;
181
201
  const hasTurnkeyEmail = !!user?.email;
182
202
  const isTurnkeyModalCurrentlyOpen = contentType?.type === "turnkeyAuth";
203
+ const isTurnkeyPrimary = process.env.NEXT_PUBLIC_TURNKEY_PRIMARY === "true";
183
204
  const shouldShowTurnkeyModal = enableTurnkey &&
205
+ !isTurnkeyPrimary &&
184
206
  user &&
185
207
  !turnkeyAuthCompleted &&
186
208
  !isTurnkeyModalCurrentlyOpen &&
@@ -207,7 +229,10 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
207
229
  // Normal flow continues after Turnkey auth is complete (or if not needed)
208
230
  handlePostTurnkeyFlow();
209
231
  }
210
- }, [
232
+ },
233
+ // handlePostTurnkeyFlow changes when its dependencies change, causing infinite loops
234
+ // eslint-disable-next-line react-hooks/exhaustive-deps
235
+ [
211
236
  signers,
212
237
  isFetchingSigners,
213
238
  partnerId,
@@ -223,13 +248,12 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
223
248
  isAuthenticating,
224
249
  isAuthenticated,
225
250
  isOpen,
226
- setJustCompletedLogin,
227
251
  user,
228
252
  enableTurnkey,
229
253
  turnkeyAuthCompleted,
230
254
  handleTurnkeySuccess,
231
255
  contentType,
232
- handlePostTurnkeyFlow,
256
+ // handlePostTurnkeyFlow - removed because it changes when signers/partnerId/etc change, triggering infinite loops
233
257
  ]);
234
258
  debug("render", {
235
259
  step,
@@ -290,21 +314,57 @@ function SignInWithB3Flow({ strategies, onLoginSuccess, onSessionKeySuccess, onE
290
314
  if (refetchError) {
291
315
  content = ((0, jsx_runtime_1.jsx)(LoginStep_1.LoginStepContainer, { partnerId: partnerId, children: (0, jsx_runtime_1.jsx)("div", { className: "p-4 text-center text-red-500", children: refetchError }) }));
292
316
  }
293
- else if (isAuthenticating || (isFetchingSigners && step === "login") || source === "requestPermissions") {
294
- content = ((0, jsx_runtime_1.jsx)(LoginStep_1.LoginStepContainer, { partnerId: partnerId, children: (0, jsx_runtime_1.jsx)("div", { className: "my-8 flex min-h-[350px] items-center justify-center", children: (0, jsx_runtime_1.jsx)(react_1.Loading, { variant: "white", size: "lg" }) }) }));
295
- }
296
317
  else if (step === "login") {
297
- // Custom strategy
298
- if (strategies?.[0] === "privy") {
299
- content = (0, jsx_runtime_1.jsx)(SignInWithB3Privy_1.SignInWithB3Privy, { onSuccess: handleLoginSuccess, chain: chain });
300
- }
301
- else if (strategies) {
302
- // Strategies are explicitly provided
303
- content = ((0, jsx_runtime_1.jsx)(LoginStepCustom_1.LoginStepCustom, { strategies: strategies, chain: chain, onSuccess: handleLoginSuccess, onError: onError, automaticallySetFirstEoa: !!automaticallySetFirstEoa }));
318
+ // PRIORITY: If NEXT_PUBLIC_TURNKEY_PRIMARY is true, show Turnkey modal FIRST as the primary authentication option
319
+ // Setting NEXT_PUBLIC_TURNKEY_PRIMARY="true" implicitly enables Turnkey
320
+ const isTurnkeyPrimary = process.env.NEXT_PUBLIC_TURNKEY_PRIMARY === "true";
321
+ const shouldShowTurnkeyFirst = isTurnkeyPrimary && !turnkeyAuthCompleted;
322
+ if (shouldShowTurnkeyFirst) {
323
+ // Don't show loading spinner for Turnkey - let the modal handle its own loading state
324
+ // This prevents the infinite loop where isAuthenticating causes the modal to be replaced
325
+ debug("Showing Turnkey as primary authentication option", {
326
+ isTurnkeyPrimary,
327
+ turnkeyAuthCompleted,
328
+ isAuthenticated,
329
+ });
330
+ // Show Turnkey authentication as primary option
331
+ content = ((0, jsx_runtime_1.jsx)(LoginStep_1.LoginStepContainer, { partnerId: partnerId, children: (0, jsx_runtime_1.jsx)(TurnkeyAuthModal_1.TurnkeyAuthModal, { onSuccess: async (authenticatedUser) => {
332
+ debug("Turnkey authentication successful in primary flow", { authenticatedUser });
333
+ setTurnkeyAuthCompleted(true);
334
+ // After Turnkey auth, refetch user to get the full user object
335
+ await refetchUser();
336
+ // User is now authenticated via Turnkey
337
+ // Set both isAuthenticated and isConnected to true so UI updates properly
338
+ // Wallet connection is optional and can happen later for signing transactions
339
+ setIsAuthenticated(true);
340
+ setIsConnected(true);
341
+ setJustCompletedLogin(true);
342
+ // Call the login success callback
343
+ onLoginSuccess?.({});
344
+ }, onClose: () => {
345
+ // If user closes Turnkey modal, they can still use wallet connection as fallback
346
+ setTurnkeyAuthCompleted(true);
347
+ }, initialEmail: "", skipToOtp: false }) }));
304
348
  }
305
349
  else {
306
- // Default to handle all strategies we support
307
- content = (0, jsx_runtime_1.jsx)(LoginStep_1.LoginStep, { chain: chain, onSuccess: handleLoginSuccess, onError: onError });
350
+ // Show loading spinner only if not in Turnkey flow
351
+ if (isAuthenticating || (isFetchingSigners && step === "login") || source === "requestPermissions") {
352
+ content = ((0, jsx_runtime_1.jsx)(LoginStep_1.LoginStepContainer, { partnerId: partnerId, children: (0, jsx_runtime_1.jsx)("div", { className: "my-8 flex min-h-[350px] items-center justify-center", children: (0, jsx_runtime_1.jsx)(react_1.Loading, { variant: "white", size: "lg" }) }) }));
353
+ }
354
+ else {
355
+ // Custom strategy
356
+ if (strategies?.[0] === "privy") {
357
+ content = (0, jsx_runtime_1.jsx)(SignInWithB3Privy_1.SignInWithB3Privy, { onSuccess: handleLoginSuccess, chain: chain });
358
+ }
359
+ else if (strategies) {
360
+ // Strategies are explicitly provided
361
+ content = ((0, jsx_runtime_1.jsx)(LoginStepCustom_1.LoginStepCustom, { strategies: strategies, chain: chain, onSuccess: handleLoginSuccess, onError: onError, automaticallySetFirstEoa: !!automaticallySetFirstEoa }));
362
+ }
363
+ else {
364
+ // Default to handle all strategies we support
365
+ content = (0, jsx_runtime_1.jsx)(LoginStep_1.LoginStep, { chain: chain, onSuccess: handleLoginSuccess, onError: onError });
366
+ }
367
+ }
308
368
  }
309
369
  }
310
370
  return content;
@@ -80,5 +80,7 @@ function TurnkeyAuthModal({ onClose, onSuccess, initialEmail = "", skipToOtp = f
80
80
  console.error("Failed to resend OTP:", err);
81
81
  }
82
82
  };
83
- return ((0, jsx_runtime_1.jsxs)("div", { className: "font-neue-montreal p-8", children: [step === "email" && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("h2", { className: "mb-6 text-center text-2xl font-bold text-gray-900 dark:text-white", children: "Setup your AnySpend Wallet" }), (0, jsx_runtime_1.jsxs)("div", { className: "mb-6 space-y-3 text-center text-sm text-gray-600 dark:text-gray-400", children: [(0, jsx_runtime_1.jsxs)("p", { children: ["AnySpend uses a secure,", (0, jsx_runtime_1.jsx)("br", {}), "embedded wallet to fund your workflows."] }), (0, jsx_runtime_1.jsxs)("p", { children: ["Please provide an email address to secure", (0, jsx_runtime_1.jsx)("br", {}), "your wallet."] })] }), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleEmailSubmit, className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("input", { type: "email", placeholder: "email", value: email, onChange: e => setEmail(e.target.value), required: true, disabled: isLoading, className: "w-full rounded-lg border border-gray-300 px-4 py-3 text-center text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 disabled:cursor-not-allowed disabled:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500" }) }), error && ((0, jsx_runtime_1.jsx)("div", { className: "rounded-md bg-red-50 p-3 text-sm text-red-800 dark:bg-red-900/20 dark:text-red-400", children: error })), (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: isLoading || !email, className: "w-full rounded-lg bg-blue-600 px-6 py-3 font-semibold text-white transition-all duration-200 hover:bg-blue-700 disabled:cursor-not-allowed disabled:bg-gray-300 dark:disabled:bg-gray-700", children: isLoading ? ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }), "Sending..."] })) : ("Continue") })] })] })), step === "otp" && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("h2", { className: "mb-4 text-center text-2xl font-bold text-gray-900 dark:text-white", children: "2FA Security" }), (0, jsx_runtime_1.jsx)("div", { className: "mb-6 space-y-3 text-center text-sm text-gray-600 dark:text-gray-400", children: (0, jsx_runtime_1.jsxs)("p", { children: ["AnySpend uses a secure,", (0, jsx_runtime_1.jsx)("br", {}), "embedded wallet to fund your workflows.", (0, jsx_runtime_1.jsx)("br", {}), "Please provide 2FA code sent to your email."] }) }), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleOtpSubmit, className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Enter code", value: otpCode, onChange: e => setOtpCode(e.target.value.toUpperCase()), required: true, disabled: isLoading, autoFocus: true, className: "w-full rounded-lg border border-gray-300 px-4 py-3 text-center font-mono text-lg uppercase tracking-wider text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 disabled:cursor-not-allowed disabled:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500", maxLength: 20 }) }), error && ((0, jsx_runtime_1.jsx)("div", { className: "rounded-md bg-red-50 p-3 text-sm text-red-800 dark:bg-red-900/20 dark:text-red-400", children: error })), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-2", children: [(0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: isLoading || !otpCode, className: "w-full rounded-lg bg-blue-600 px-6 py-3 font-semibold text-white transition-all duration-200 hover:bg-blue-700 disabled:cursor-not-allowed disabled:bg-gray-300 dark:disabled:bg-gray-700", children: isLoading ? ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }), "Verifying..."] })) : ("Confirm") }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleResendOtp, disabled: isLoading, className: "text-sm text-blue-600 hover:text-blue-700 hover:underline disabled:cursor-not-allowed disabled:text-gray-400 dark:text-blue-400 dark:hover:text-blue-300", children: "Resend code" })] })] })] })), step === "success" && ((0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "mb-6 flex items-center justify-center", children: (0, jsx_runtime_1.jsx)("div", { className: "flex h-16 w-16 items-center justify-center rounded-full bg-green-100 dark:bg-green-900/20", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-8 w-8 text-green-600 dark:text-green-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }) }) }), (0, jsx_runtime_1.jsx)("h2", { className: "mb-2 text-2xl font-bold text-gray-900 dark:text-white", children: "Successfully Authenticated!" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Redirecting..." })] }))] }));
83
+ const isTurnkeyPrimary = process.env.NEXT_PUBLIC_TURNKEY_PRIMARY === "true";
84
+ const walletBrand = isTurnkeyPrimary ? "Smart Wallet" : "AnySpend Wallet";
85
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "font-neue-montreal p-8", children: [step === "email" && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("h2", { className: "mb-6 text-center text-2xl font-bold text-gray-900 dark:text-white", children: ["Setup your ", walletBrand] }), (0, jsx_runtime_1.jsxs)("div", { className: "mb-6 space-y-3 text-center text-sm text-gray-600 dark:text-gray-400", children: [(0, jsx_runtime_1.jsxs)("p", { children: [isTurnkeyPrimary ? "We use a secure," : "AnySpend uses a secure,", (0, jsx_runtime_1.jsx)("br", {}), "embedded wallet to fund your workflows."] }), (0, jsx_runtime_1.jsxs)("p", { children: ["Please provide an email address to secure", (0, jsx_runtime_1.jsx)("br", {}), "your wallet."] })] }), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleEmailSubmit, className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("input", { type: "email", placeholder: "email", value: email, onChange: e => setEmail(e.target.value), required: true, disabled: isLoading, className: "w-full rounded-lg border border-gray-300 px-4 py-3 text-center text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 disabled:cursor-not-allowed disabled:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500" }) }), error && ((0, jsx_runtime_1.jsx)("div", { className: "rounded-md bg-red-50 p-3 text-sm text-red-800 dark:bg-red-900/20 dark:text-red-400", children: error })), (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: isLoading || !email, className: "w-full rounded-lg bg-blue-600 px-6 py-3 font-semibold text-white transition-all duration-200 hover:bg-blue-700 disabled:cursor-not-allowed disabled:bg-gray-300 dark:disabled:bg-gray-700", children: isLoading ? ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }), "Sending..."] })) : ("Continue") })] })] })), step === "otp" && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("h2", { className: "mb-4 text-center text-2xl font-bold text-gray-900 dark:text-white", children: "2FA Security" }), (0, jsx_runtime_1.jsx)("div", { className: "mb-6 space-y-3 text-center text-sm text-gray-600 dark:text-gray-400", children: (0, jsx_runtime_1.jsxs)("p", { children: [isTurnkeyPrimary ? "We use a secure," : "AnySpend uses a secure,", (0, jsx_runtime_1.jsx)("br", {}), "embedded wallet to fund your workflows.", (0, jsx_runtime_1.jsx)("br", {}), "Please provide 2FA code sent to your email."] }) }), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleOtpSubmit, className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Enter code", value: otpCode, onChange: e => setOtpCode(e.target.value.toUpperCase()), required: true, disabled: isLoading, autoFocus: true, className: "w-full rounded-lg border border-gray-300 px-4 py-3 text-center font-mono text-lg uppercase tracking-wider text-gray-900 placeholder-gray-400 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 disabled:cursor-not-allowed disabled:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500", maxLength: 20 }) }), error && ((0, jsx_runtime_1.jsx)("div", { className: "rounded-md bg-red-50 p-3 text-sm text-red-800 dark:bg-red-900/20 dark:text-red-400", children: error })), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-2", children: [(0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: isLoading || !otpCode, className: "w-full rounded-lg bg-blue-600 px-6 py-3 font-semibold text-white transition-all duration-200 hover:bg-blue-700 disabled:cursor-not-allowed disabled:bg-gray-300 dark:disabled:bg-gray-700", children: isLoading ? ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }), "Verifying..."] })) : ("Confirm") }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleResendOtp, disabled: isLoading, className: "text-sm text-blue-600 hover:text-blue-700 hover:underline disabled:cursor-not-allowed disabled:text-gray-400 dark:text-blue-400 dark:hover:text-blue-300", children: "Resend code" })] })] })] })), step === "success" && ((0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "mb-6 flex items-center justify-center", children: (0, jsx_runtime_1.jsx)("div", { className: "flex h-16 w-16 items-center justify-center rounded-full bg-green-100 dark:bg-green-900/20", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-8 w-8 text-green-600 dark:text-green-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }) }) }), (0, jsx_runtime_1.jsx)("h2", { className: "mb-2 text-2xl font-bold text-gray-900 dark:text-white", children: "Successfully Authenticated!" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Redirecting..." })] }))] }));
84
86
  }
@@ -3,6 +3,7 @@ export { useAccountAssets } from "./useAccountAssets";
3
3
  export { useAccountWallet } from "./useAccountWallet";
4
4
  export { useAddTWSessionKey } from "./useAddTWSessionKey";
5
5
  export { useAnalytics } from "./useAnalytics";
6
+ export { useAuth } from "./useAuth";
6
7
  export { useAuthentication } from "./useAuthentication";
7
8
  export { useB3BalanceFromAddresses } from "./useB3BalanceFromAddresses";
8
9
  export { useB3EnsName } from "./useB3EnsName";
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.useURLParams = exports.useUnifiedChainSwitchAndExecute = exports.useTurnkeyAuth = exports.useTokensFromAddress = exports.useTokenPriceWithFallback = exports.useTokenPrice = exports.useTokenFromUrl = exports.useTokenData = exports.useTokenBalancesByChain = exports.useTokenBalanceDirect = exports.useTokenBalance = exports.useSiwe = exports.useSimSvmBalance = exports.useSimBalance = exports.useSearchParamsSSR = exports.useRouter = exports.useRemoveSessionKey = exports.useQueryBSMNT = exports.useQueryB3 = exports.useProfileSettings = exports.useProfilePreference = exports.useProfile = exports.useDisplayName = exports.useOneBalance = exports.useNotifications = exports.useNativeBalanceFromRPC = exports.useNativeBalance = exports.useMediaQuery = exports.useIsomorphicLayoutEffect = exports.useIsMobile = exports.useHasMounted = exports.useHandleConnectWithPrivy = exports.useGlobalAccount = exports.useGetGeo = exports.useGetAllTWSigners = exports.useFirstEOA = exports.useExchangeRate = exports.useConnect = exports.useClient = exports.useChainSwitchWithAction = exports.useB3EnsName = exports.useB3BalanceFromAddresses = exports.useAuthentication = exports.useAnalytics = exports.useAddTWSessionKey = exports.useAccountWallet = exports.useAccountAssets = exports.createWagmiConfig = void 0;
17
+ exports.useURLParams = exports.useUnifiedChainSwitchAndExecute = exports.useTurnkeyAuth = exports.useTokensFromAddress = exports.useTokenPriceWithFallback = exports.useTokenPrice = exports.useTokenFromUrl = exports.useTokenData = exports.useTokenBalancesByChain = exports.useTokenBalanceDirect = exports.useTokenBalance = exports.useSiwe = exports.useSimSvmBalance = exports.useSimBalance = exports.useSearchParamsSSR = exports.useRouter = exports.useRemoveSessionKey = exports.useQueryBSMNT = exports.useQueryB3 = exports.useProfileSettings = exports.useProfilePreference = exports.useProfile = exports.useDisplayName = exports.useOneBalance = exports.useNotifications = exports.useNativeBalanceFromRPC = exports.useNativeBalance = exports.useMediaQuery = exports.useIsomorphicLayoutEffect = exports.useIsMobile = exports.useHasMounted = exports.useHandleConnectWithPrivy = exports.useGlobalAccount = exports.useGetGeo = exports.useGetAllTWSigners = exports.useFirstEOA = exports.useExchangeRate = exports.useConnect = exports.useClient = exports.useChainSwitchWithAction = exports.useB3EnsName = exports.useB3BalanceFromAddresses = exports.useAuthentication = exports.useAuth = exports.useAnalytics = exports.useAddTWSessionKey = exports.useAccountWallet = exports.useAccountAssets = exports.createWagmiConfig = void 0;
18
18
  var createWagmiConfig_1 = require("../utils/createWagmiConfig");
19
19
  Object.defineProperty(exports, "createWagmiConfig", { enumerable: true, get: function () { return createWagmiConfig_1.createWagmiConfig; } });
20
20
  var useAccountAssets_1 = require("./useAccountAssets");
@@ -25,6 +25,8 @@ var useAddTWSessionKey_1 = require("./useAddTWSessionKey");
25
25
  Object.defineProperty(exports, "useAddTWSessionKey", { enumerable: true, get: function () { return useAddTWSessionKey_1.useAddTWSessionKey; } });
26
26
  var useAnalytics_1 = require("./useAnalytics");
27
27
  Object.defineProperty(exports, "useAnalytics", { enumerable: true, get: function () { return useAnalytics_1.useAnalytics; } });
28
+ var useAuth_1 = require("./useAuth");
29
+ Object.defineProperty(exports, "useAuth", { enumerable: true, get: function () { return useAuth_1.useAuth; } });
28
30
  var useAuthentication_1 = require("./useAuthentication");
29
31
  Object.defineProperty(exports, "useAuthentication", { enumerable: true, get: function () { return useAuthentication_1.useAuthentication; } });
30
32
  var useB3BalanceFromAddresses_1 = require("./useB3BalanceFromAddresses");
@@ -0,0 +1,76 @@
1
+ import { Wallet } from "thirdweb/wallets";
2
+ import { preAuthenticate } from "thirdweb/wallets/in-app";
3
+ /**
4
+ * Unified authentication hook that uses Turnkey for authentication
5
+ * This replaces the previous Thirdweb-based authentication
6
+ *
7
+ * This hook provides 1:1 feature parity with useAuthentication.ts
8
+ */
9
+ export declare function useAuth(): {
10
+ authenticate: (turnkeySessionJwt: string, partnerId: string) => Promise<import("@feathersjs/authentication").AuthenticationResult>;
11
+ reAuthenticate: () => Promise<import("@feathersjs/authentication").AuthenticationResult>;
12
+ logout: (callback?: () => void) => Promise<void>;
13
+ isAuthenticated: boolean;
14
+ isReady: boolean;
15
+ isConnecting: boolean;
16
+ isConnected: boolean;
17
+ wallet: import("thirdweb/dist/types/wallets/in-app/core/wallet/types").EcosystemWallet;
18
+ preAuthenticate: typeof preAuthenticate;
19
+ connect: (_walleAutoConnectedWith: Wallet, allConnectedWallets: Wallet[]) => Promise<void>;
20
+ isAuthenticating: boolean;
21
+ onConnect: (_walleAutoConnectedWith: Wallet, allConnectedWallets: Wallet[]) => Promise<void>;
22
+ user: {
23
+ email?: string | undefined;
24
+ username?: string | undefined;
25
+ telNumber?: string | undefined;
26
+ ens?: string | undefined;
27
+ avatar?: string | undefined;
28
+ preferences?: {} | undefined;
29
+ referredBy?: string | {} | undefined;
30
+ sourceApp?: string | undefined;
31
+ referralCode?: string | undefined;
32
+ userGroups?: number[] | undefined;
33
+ isMigratedFromBSMNT?: boolean | undefined;
34
+ privyLinkedAccounts?: {
35
+ name?: string | undefined;
36
+ address?: string | undefined;
37
+ email?: string | undefined;
38
+ chain_type?: string | undefined;
39
+ lv?: number | undefined;
40
+ wallet_client_type?: string | undefined;
41
+ smart_wallet_type?: string | undefined;
42
+ subject?: string | undefined;
43
+ type: string;
44
+ }[] | undefined;
45
+ twProfiles?: {
46
+ type: string;
47
+ details: {
48
+ id?: string | undefined;
49
+ name?: string | undefined;
50
+ address?: string | undefined;
51
+ email?: string | undefined;
52
+ username?: string | undefined;
53
+ phone?: string | undefined;
54
+ fid?: string | undefined;
55
+ };
56
+ }[] | undefined;
57
+ turnkeySubOrgs?: {
58
+ hasDelegatedUser?: boolean | undefined;
59
+ subOrgId: string;
60
+ accounts: Record<string, any>[];
61
+ }[] | undefined;
62
+ _id: string | {};
63
+ userId: string;
64
+ smartAccountAddress: string;
65
+ createdAt: number;
66
+ updatedAt: number;
67
+ partnerIds: {
68
+ privyId?: string | undefined;
69
+ thirdwebId?: string | undefined;
70
+ turnkeyId?: string | undefined;
71
+ turnkeyOtpId?: string | undefined;
72
+ };
73
+ } | undefined;
74
+ refetchUser: () => Promise<import("@feathersjs/authentication").AuthenticationResult>;
75
+ setUser: (newUser?: import("@b3dotfun/b3-api").Users) => void;
76
+ };