cilantro-react 0.1.6 → 0.1.7

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 CHANGED
@@ -14,6 +14,7 @@ React SDK/UI for [Cilantro Smart Wallet](https://www.npmjs.com/package/cilantro-
14
14
  - [Storage Adapters](#storage-adapters)
15
15
  - [Hooks](#hooks)
16
16
  - [useAuth](#useauth)
17
+ - [useReturnUrl](#usereturnurl)
17
18
  - [useWallet](#usewallet)
18
19
  - [useSigners](#usesigners)
19
20
  - [usePasskey](#usepasskey)
@@ -23,8 +24,11 @@ React SDK/UI for [Cilantro Smart Wallet](https://www.npmjs.com/package/cilantro-
23
24
  - [Components](#components)
24
25
  - [Auth Components](#auth-components)
25
26
  - [LoginForm](#loginform)
27
+ - [RegisterForm](#registerform)
26
28
  - [LogoutButton](#logoutbutton)
27
29
  - [AuthGuard](#authguard)
30
+ - [AuthShell](#authshell)
31
+ - [NextAuthGuard (Next.js)](#nextauthguard-nextjs)
28
32
  - [Wallet Components](#wallet-components)
29
33
  - [WalletSelector](#walletselector)
30
34
  - [CreateWalletForm](#createwalletform)
@@ -144,10 +148,16 @@ const storage = createIndexedDBAdapter();
144
148
  | `apiKey` | `string` | No* | — | Platform API key for server-side operations |
145
149
  | `baseURL` | `string` | No | `https://api.cilantro.gg` | API base URL |
146
150
  | `storageAdapter` | `DeviceKeyStorage` | No | IndexedDB | Storage adapter for device keys |
151
+ | `syncJwtToCookie` | `boolean` | No | `false` | When true, sync JWT to a cookie for Next.js/middleware |
152
+ | `jwtCookieName` | `string` | No | `cilantro_jwt` | Cookie name when `syncJwtToCookie` is true |
147
153
  | `children` | `ReactNode` | Yes | — | App content |
148
154
 
149
155
  *Either `apiKey` or JWT (obtained via login) is required for authenticated requests.
150
156
 
157
+ ### SDK Auth (automatic)
158
+
159
+ **CilantroProvider configures the underlying cilantro-sdk authentication when the user is logged in.** Once you have a JWT in context (from login or session restore), all cilantro-sdk calls in the same app use that auth automatically. You do **not** need to call `setSdkAuth` or similar before each request; the provider handles it.
160
+
151
161
  ### Storage Adapters
152
162
 
153
163
  For email and phone signers, device keys must be stored. Choose an adapter:
@@ -171,6 +181,28 @@ const storage = createLocalStorageAdapter();
171
181
  const storage = createMemoryAdapter();
172
182
  ```
173
183
 
184
+ ### Next.js / Middleware
185
+
186
+ For Next.js apps, middleware runs on the server and cannot access `localStorage`. To protect routes or read the JWT in middleware:
187
+
188
+ 1. Enable JWT cookie sync: `<CilantroProvider syncJwtToCookie>`
189
+ 2. In middleware, read the cookie (default name: `cilantro_jwt`) to check auth.
190
+ 3. Optionally redirect unauthenticated users. Example:
191
+
192
+ ```ts
193
+ // middleware.ts
194
+ import { NextResponse } from 'next/server';
195
+ import type { NextRequest } from 'next/server';
196
+
197
+ export function middleware(request: NextRequest) {
198
+ const token = request.cookies.get('cilantro_jwt')?.value;
199
+ if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
200
+ return NextResponse.redirect(new URL('/login', request.url));
201
+ }
202
+ return NextResponse.next();
203
+ }
204
+ ```
205
+
174
206
  ---
175
207
 
176
208
  ## Hooks
@@ -183,12 +215,16 @@ Authentication state and actions.
183
215
  import { useAuth } from 'cilantro-react';
184
216
 
185
217
  function MyComponent() {
186
- const { user, jwt, isLoading, isAuthenticated, login, logout } = useAuth();
218
+ const { user, jwt, isLoading, isAuthenticated, login, register, logout, clearSessionDueToAuthError } = useAuth();
187
219
 
188
220
  const handleLogin = async () => {
189
221
  await login({ usernameOrEmail: 'user@example.com', password: 'password123' });
190
222
  };
191
223
 
224
+ const handleRegister = async () => {
225
+ await register('johndoe', 'john@example.com', 'password123');
226
+ };
227
+
192
228
  return (
193
229
  <div>
194
230
  {isLoading && <p>Loading...</p>}
@@ -210,11 +246,35 @@ function MyComponent() {
210
246
  | Property | Type | Description |
211
247
  |----------|------|-------------|
212
248
  | `user` | `User \| null` | Current user object (`{ username?, email?, userType? }`) |
213
- | `jwt` | `string \| null` | JWT token (null when not authenticated) |
249
+ | `jwt` | `string \| null` | JWT token (null when not authenticated). Prefer this name. |
250
+ | `token` | `string \| null` | Alias for `jwt`. Same value. |
214
251
  | `isLoading` | `boolean` | True while restoring session from storage |
215
252
  | `isAuthenticated` | `boolean` | True when user has valid JWT |
216
253
  | `login` | `(params: { usernameOrEmail: string; password: string }) => Promise<void>` | Log in; throws on error |
254
+ | `register` | `(username: string, email: string, password: string, isActive?: boolean) => Promise<void>` | Register and auto-login |
217
255
  | `logout` | `() => void` | Clear session and token |
256
+ | `clearSessionDueToAuthError` | `() => void` | Clear session when API returns 401/403; calls `onSessionExpired` |
257
+
258
+ ---
259
+
260
+ ### useReturnUrl
261
+
262
+ Read `returnUrl` from URL search params for redirect-after-auth flows.
263
+
264
+ ```tsx
265
+ import { useReturnUrl } from 'cilantro-react';
266
+
267
+ function LoginPage() {
268
+ const { returnPath, redirect, rawReturnUrl } = useReturnUrl({ param: 'returnUrl', defaultPath: '/' });
269
+
270
+ return (
271
+ <LoginForm
272
+ redirectAfterSuccess={returnPath}
273
+ onRedirect={(path) => router.replace(path)}
274
+ />
275
+ );
276
+ }
277
+ ```
218
278
 
219
279
  ---
220
280
 
@@ -226,7 +286,7 @@ Wallet state and actions.
226
286
  import { useWallet } from 'cilantro-react';
227
287
 
228
288
  function WalletManager() {
229
- const { wallet, wallets, createWallet, selectWallet, isLoading } = useWallet();
289
+ const { wallet, wallets, createWallet, selectWallet, refreshWallets, isLoading, error } = useWallet();
230
290
 
231
291
  const handleCreate = async () => {
232
292
  const result = await createWallet({ name: 'My New Wallet' });
@@ -236,6 +296,7 @@ function WalletManager() {
236
296
  return (
237
297
  <div>
238
298
  {isLoading && <p>Loading wallets...</p>}
299
+ {error && <p className="text-red-500">{error}</p>}
239
300
  <p>Current wallet: {wallet?.walletName ?? 'None selected'}</p>
240
301
  <ul>
241
302
  {wallets.map((w) => (
@@ -245,6 +306,7 @@ function WalletManager() {
245
306
  ))}
246
307
  </ul>
247
308
  <button onClick={handleCreate}>Create Wallet</button>
309
+ <button onClick={refreshWallets}>Refresh</button>
248
310
  </div>
249
311
  );
250
312
  }
@@ -258,7 +320,9 @@ function WalletManager() {
258
320
  | `wallets` | `WalletData[]` | All wallets for the authenticated user |
259
321
  | `createWallet` | `(params: { name: string; userId?: string }) => Promise<WalletControllerCreateResult>` | Create a new wallet |
260
322
  | `selectWallet` | `(walletId: string) => void` | Select a wallet by ID |
323
+ | `refreshWallets` | `() => Promise<void>` | Refresh wallet list from API |
261
324
  | `isLoading` | `boolean` | True while loading wallets |
325
+ | `error` | `string \| null` | Error from wallet operations (e.g. fetch failed) |
262
326
 
263
327
  ---
264
328
 
@@ -524,6 +588,8 @@ import { LoginForm } from 'cilantro-react';
524
588
  <LoginForm
525
589
  onSuccess={() => console.log('Logged in!')}
526
590
  onError={(err) => console.error(err.message)}
591
+ redirectAfterSuccess="/dashboard"
592
+ onRedirect={(path) => router.replace(path)}
527
593
  title="Welcome back"
528
594
  description="Sign in to your account"
529
595
  submitLabel="Sign in"
@@ -538,6 +604,9 @@ import { LoginForm } from 'cilantro-react';
538
604
  |------|------|---------|-------------|
539
605
  | `onSuccess` | `() => void` | — | Called after successful login |
540
606
  | `onError` | `(error: Error) => void` | — | Called on login error |
607
+ | `redirectAfterSuccess` | `string` | — | Redirect to this path after login. If unset, reads from URL `?returnUrl=` |
608
+ | `onRedirect` | `(path: string) => void` | — | Custom redirect for SPA routers |
609
+ | `returnUrlParam` | `string` | `"returnUrl"` | Query param to read return URL from |
541
610
  | `title` | `string` | `"Sign in"` | Form title |
542
611
  | `description` | `string` | — | Form description |
543
612
  | `submitLabel` | `string` | `"Sign in"` | Submit button label |
@@ -557,6 +626,8 @@ import { LogoutButton } from 'cilantro-react';
557
626
 
558
627
  <LogoutButton
559
628
  onLogout={() => console.log('Logged out')}
629
+ redirectAfterLogout="/login"
630
+ onRedirect={(path) => router.replace(path)}
560
631
  confirmBeforeLogout={true}
561
632
  >
562
633
  Sign out
@@ -568,6 +639,8 @@ import { LogoutButton } from 'cilantro-react';
568
639
  | Prop | Type | Default | Description |
569
640
  |------|------|---------|-------------|
570
641
  | `onLogout` | `() => void` | — | Called after logout |
642
+ | `redirectAfterLogout` | `string` | — | Redirect to this path after logout |
643
+ | `onRedirect` | `(path: string) => void` | — | Custom redirect for SPA routers |
571
644
  | `confirmBeforeLogout` | `boolean` | `false` | Show confirmation dialog |
572
645
  | `className` | `string` | — | Button class |
573
646
  | `children` | `ReactNode` | `"Log out"` | Button content |
@@ -591,11 +664,23 @@ import { AuthGuard, LoginForm } from 'cilantro-react';
591
664
  <ProtectedContent />
592
665
  </AuthGuard>
593
666
 
594
- // Redirect instead of showing fallback
667
+ // Redirect to login page (appends ?returnUrl=currentPath for redirect-after-login)
595
668
  <AuthGuard redirectTo="/login">
596
669
  <ProtectedContent />
597
670
  </AuthGuard>
598
671
 
672
+ // Next.js / React Router: use onRedirect for client-side navigation (no full page reload)
673
+ import { useRouter } from 'next/navigation';
674
+ const router = useRouter();
675
+ <AuthGuard redirectTo="/login" onRedirect={(path) => router.replace(path)}>
676
+ <ProtectedContent />
677
+ </AuthGuard>
678
+
679
+ // Polished UX: centered or fullscreen layout for auth fallback
680
+ <AuthGuard layout="centered"> {/* or "fullscreen" */}
681
+ <ProtectedContent />
682
+ </AuthGuard>
683
+
599
684
  // Hide content when not authenticated (no fallback)
600
685
  <AuthGuard showFallback={false}>
601
686
  <ProtectedContent />
@@ -613,7 +698,10 @@ import { AuthGuard, LoginForm } from 'cilantro-react';
613
698
  |------|------|---------|-------------|
614
699
  | `children` | `ReactNode` | — | Content to show when authenticated |
615
700
  | `fallback` | `ReactNode` | `<LoginForm />` | Content when not authenticated |
616
- | `redirectTo` | `string` | — | Redirect URL when not authenticated |
701
+ | `redirectTo` | `string` | — | Redirect unauthenticated users to this path (appends `?returnUrl=`) |
702
+ | `onRedirect` | `(path: string) => void` | — | Custom redirect for SPA routers (e.g. `router.replace`) |
703
+ | `returnUrlParam` | `string` | `"returnUrl"` | Query param name for return URL |
704
+ | `layout` | `"inline" \| "centered" \| "fullscreen"` | `"inline"` | Layout for fallback content |
617
705
  | `showFallback` | `boolean` | `true` | Whether to show fallback or null |
618
706
  | `useSkeleton` | `boolean` | `false` | Show skeleton while loading auth state |
619
707
  | `className` | `string` | — | Root element class |
@@ -621,6 +709,52 @@ import { AuthGuard, LoginForm } from 'cilantro-react';
621
709
 
622
710
  ---
623
711
 
712
+ #### RegisterForm
713
+
714
+ Registration form with username, email, and password. Auto-login after success.
715
+
716
+ ```tsx
717
+ import { RegisterForm } from 'cilantro-react';
718
+
719
+ <RegisterForm
720
+ onSuccess={() => console.log('Registered!')}
721
+ redirectAfterSuccess="/dashboard"
722
+ onRedirect={(path) => router.replace(path)} // For Next.js/React Router
723
+ renderSwitchToLogin={() => <a href="/login">Already have an account? Sign in</a>}
724
+ />
725
+ ```
726
+
727
+ ---
728
+
729
+ #### AuthShell
730
+
731
+ Full-page centered layout for auth screens. Use for standalone login/register pages.
732
+
733
+ ```tsx
734
+ import { AuthShell, LoginForm } from 'cilantro-react';
735
+
736
+ <AuthShell logo={<img src="/logo.svg" alt="App" />} maxWidth="sm">
737
+ <LoginForm redirectAfterSuccess="/dashboard" />
738
+ </AuthShell>
739
+ ```
740
+
741
+ ---
742
+
743
+ #### NextAuthGuard (Next.js)
744
+
745
+ Drop-in AuthGuard for Next.js App Router. Uses `router.replace()` for client-side redirects.
746
+ Requires `next` to be installed.
747
+
748
+ ```tsx
749
+ import { NextAuthGuard } from 'cilantro-react/next';
750
+
751
+ <NextAuthGuard redirectTo="/login" layout="fullscreen">
752
+ <ProtectedContent />
753
+ </NextAuthGuard>
754
+ ```
755
+
756
+ ---
757
+
624
758
  ### Wallet Components
625
759
 
626
760
  #### WalletSelector
@@ -1191,11 +1325,17 @@ const adapted = adaptSolanaConnection(connection);
1191
1325
  |----------|-------------|
1192
1326
  | `extractErrorMessage(error)` | Normalize unknown errors to string |
1193
1327
  | `extractResponseData(response)` | Unwrap SDK response shapes |
1194
- | `normalizeWallet(dto)` | Normalize wallet data from SDK |
1328
+ | `normalizeWallet(dto)` | Normalize wallet data from SDK (ensures `id` and `address`) |
1195
1329
  | `normalizeSigner(dto)` | Normalize signer data from SDK |
1196
- | `isJwtExpired(jwt)` | Check if JWT is expired |
1330
+ | `getWalletId(wallet)` | Get wallet ID from wallet-like object (`id ?? walletId`) |
1331
+ | `getWalletAddress(wallet)` | Get wallet address from wallet-like object (`address ?? walletAddress`) |
1332
+ | `isJwtExpired(token, bufferSeconds?)` | Check if JWT is expired. Uses `exp` claim; optional buffer (default 60s) treats tokens near expiry as expired. Exported for apps that sync JWT to cookies or need expiry checks. |
1197
1333
  | `isAuthError(error)` | Check if error is an auth error |
1198
1334
 
1335
+ ### Wallet shape
1336
+
1337
+ Wallet data from the SDK may use `walletId`/`walletAddress` or `id`/`address`. The library normalizes at boundaries so **`id`** and **`address`** are preferred. Use `getWalletId(wallet)` and `getWalletAddress(wallet)` when you need to handle both shapes consistently.
1338
+
1199
1339
  ---
1200
1340
 
1201
1341
  ## Types
@@ -0,0 +1,42 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface AuthGuardClassNames {
5
+ root?: string;
6
+ fallback?: string;
7
+ skeleton?: string;
8
+ loading?: string;
9
+ /** Centered/fullscreen layout wrapper */
10
+ layout?: string;
11
+ }
12
+ type AuthGuardLayout = "inline" | "centered" | "fullscreen";
13
+ interface AuthGuardProps {
14
+ children: ReactNode;
15
+ /** Shown when not authenticated. Default: <LoginForm /> */
16
+ fallback?: ReactNode;
17
+ /** Redirect unauthenticated users to this path (e.g. "/login"). Uses onRedirect if provided, else window.location. */
18
+ redirectTo?: string;
19
+ /** Custom redirect function for SPA routers (Next.js, React Router). e.g. (path) => router.replace(path) */
20
+ onRedirect?: (path: string) => void;
21
+ /** Query param for return URL when redirecting. Default: "returnUrl" */
22
+ returnUrlParam?: string;
23
+ /** Layout for fallback content. "centered" and "fullscreen" give polished auth UX. */
24
+ layout?: AuthGuardLayout;
25
+ /** Root class when showing fallback */
26
+ className?: string;
27
+ classNames?: AuthGuardClassNames;
28
+ /** When true, show fallback (login) instead of redirecting. When false, redirect when redirectTo is set, else render null. */
29
+ showFallback?: boolean;
30
+ /** When true, show skeleton while loading. When false, show "Loading..." text. */
31
+ useSkeleton?: boolean;
32
+ }
33
+ /**
34
+ * Wraps content and shows fallback (e.g. LoginForm) when the user is not authenticated.
35
+ * Use inside CilantroProvider.
36
+ *
37
+ * For Next.js: pass onRedirect={(path) => router.replace(path)} and redirectTo="/login".
38
+ * For return-after-login flow: set redirectTo="/login"; AuthGuard will redirect with ?returnUrl=currentPath.
39
+ */
40
+ declare function AuthGuard({ children, fallback, redirectTo, onRedirect, returnUrlParam, layout, className, classNames, showFallback, useSkeleton, }: AuthGuardProps): react_jsx_runtime.JSX.Element | null;
41
+
42
+ export { AuthGuard as A, type AuthGuardClassNames as a, type AuthGuardLayout as b, type AuthGuardProps as c };
@@ -0,0 +1,42 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface AuthGuardClassNames {
5
+ root?: string;
6
+ fallback?: string;
7
+ skeleton?: string;
8
+ loading?: string;
9
+ /** Centered/fullscreen layout wrapper */
10
+ layout?: string;
11
+ }
12
+ type AuthGuardLayout = "inline" | "centered" | "fullscreen";
13
+ interface AuthGuardProps {
14
+ children: ReactNode;
15
+ /** Shown when not authenticated. Default: <LoginForm /> */
16
+ fallback?: ReactNode;
17
+ /** Redirect unauthenticated users to this path (e.g. "/login"). Uses onRedirect if provided, else window.location. */
18
+ redirectTo?: string;
19
+ /** Custom redirect function for SPA routers (Next.js, React Router). e.g. (path) => router.replace(path) */
20
+ onRedirect?: (path: string) => void;
21
+ /** Query param for return URL when redirecting. Default: "returnUrl" */
22
+ returnUrlParam?: string;
23
+ /** Layout for fallback content. "centered" and "fullscreen" give polished auth UX. */
24
+ layout?: AuthGuardLayout;
25
+ /** Root class when showing fallback */
26
+ className?: string;
27
+ classNames?: AuthGuardClassNames;
28
+ /** When true, show fallback (login) instead of redirecting. When false, redirect when redirectTo is set, else render null. */
29
+ showFallback?: boolean;
30
+ /** When true, show skeleton while loading. When false, show "Loading..." text. */
31
+ useSkeleton?: boolean;
32
+ }
33
+ /**
34
+ * Wraps content and shows fallback (e.g. LoginForm) when the user is not authenticated.
35
+ * Use inside CilantroProvider.
36
+ *
37
+ * For Next.js: pass onRedirect={(path) => router.replace(path)} and redirectTo="/login".
38
+ * For return-after-login flow: set redirectTo="/login"; AuthGuard will redirect with ?returnUrl=currentPath.
39
+ */
40
+ declare function AuthGuard({ children, fallback, redirectTo, onRedirect, returnUrlParam, layout, className, classNames, showFallback, useSkeleton, }: AuthGuardProps): react_jsx_runtime.JSX.Element | null;
41
+
42
+ export { AuthGuard as A, type AuthGuardClassNames as a, type AuthGuardLayout as b, type AuthGuardProps as c };
package/dist/index.d.mts CHANGED
@@ -5,6 +5,7 @@ import { WalletControllerFindAllResult, WalletControllerCreateResult, WalletCont
5
5
  export { WalletControllerFindAllResult, WalletControllerFindOneResult, WalletControllerListSignersResult, WalletControllerSubmitTransactionResult } from 'cilantro-sdk/wallet';
6
6
  import { createIndexedDBAdapter, SignerInfo } from 'cilantro-sdk/helpers';
7
7
  export { createIndexedDBAdapter, createLocalStorageAdapter, createMemoryAdapter } from 'cilantro-sdk/helpers';
8
+ export { A as AuthGuard, a as AuthGuardClassNames, b as AuthGuardLayout, c as AuthGuardProps } from './AuthGuard-siMJeYPD.mjs';
8
9
  import { PublicKey, Transaction, Connection } from '@solana/web3.js';
9
10
  export { AuthControllerLogin200Data } from 'cilantro-sdk/auth';
10
11
  export { TransactionControllerSendRawPasskeyTransactionResult } from 'cilantro-sdk/transactions';
@@ -62,12 +63,16 @@ interface CilantroContextProviderProps {
62
63
  storageAdapter?: DeviceKeyStorage | null;
63
64
  jwtStorageKey?: string;
64
65
  walletStorageKey?: string;
66
+ /** When true, sync JWT to a cookie (same name as jwtStorageKey) for Next.js/middleware. Default: false. */
67
+ syncJwtToCookie?: boolean;
68
+ /** Cookie name for JWT when syncJwtToCookie is true. Default: cilantro_jwt. */
69
+ jwtCookieName?: string;
65
70
  onLoginSuccess?: () => void;
66
71
  onLogout?: () => void;
67
72
  onRegisterSuccess?: () => void;
68
73
  onSessionExpired?: () => void;
69
74
  }
70
- declare function CilantroContextProvider({ children, apiKey, baseURL, storageAdapter, jwtStorageKey, walletStorageKey, onLoginSuccess, onLogout, onRegisterSuccess, onSessionExpired, }: CilantroContextProviderProps): react_jsx_runtime.JSX.Element;
75
+ declare function CilantroContextProvider({ children, apiKey, baseURL, storageAdapter, jwtStorageKey, walletStorageKey, syncJwtToCookie, jwtCookieName, onLoginSuccess, onLogout, onRegisterSuccess, onSessionExpired, }: CilantroContextProviderProps): react_jsx_runtime.JSX.Element;
71
76
  declare function useCilantroContext(): CilantroContextValue;
72
77
 
73
78
  interface CilantroProviderProps {
@@ -86,15 +91,21 @@ interface CilantroProviderProps {
86
91
  jwtStorageKey?: string;
87
92
  /** localStorage key for selected wallet id (default: cilantro_selected_wallet_id) */
88
93
  walletStorageKey?: string;
94
+ /** When true, sync JWT to a cookie for Next.js/middleware. Default: false. */
95
+ syncJwtToCookie?: boolean;
96
+ /** Cookie name for JWT when syncJwtToCookie is true. Default: cilantro_jwt. */
97
+ jwtCookieName?: string;
89
98
  onLoginSuccess?: () => void;
90
99
  onLogout?: () => void;
91
100
  onRegisterSuccess?: () => void;
92
101
  onSessionExpired?: () => void;
93
102
  }
94
- declare function CilantroProvider({ children, apiKey: apiKeyProp, baseURL, storageAdapter, platformApiKey, apiUrl, jwtStorageKey, walletStorageKey, onLoginSuccess, onLogout, onRegisterSuccess, onSessionExpired, }: CilantroProviderProps): react_jsx_runtime.JSX.Element;
103
+ declare function CilantroProvider({ children, apiKey: apiKeyProp, baseURL, storageAdapter, platformApiKey, apiUrl, jwtStorageKey, walletStorageKey, syncJwtToCookie, jwtCookieName, onLoginSuccess, onLogout, onRegisterSuccess, onSessionExpired, }: CilantroProviderProps): react_jsx_runtime.JSX.Element;
95
104
 
96
105
  interface CilantroAuthContextType {
97
106
  user: User | null;
107
+ /** JWT token. Alias for token. */
108
+ jwt: string | null;
98
109
  token: string | null;
99
110
  isAuthenticated: boolean;
100
111
  login: (usernameOrEmail: string, password: string) => Promise<void>;
@@ -106,6 +117,9 @@ interface CilantroAuthContextType {
106
117
  declare function useCilantroAuth(): CilantroAuthContextType;
107
118
 
108
119
  interface WalletContextType {
120
+ /** Selected wallet. Primary name. */
121
+ wallet: WalletData | null;
122
+ /** @deprecated Use wallet instead. Alias for backward compat. */
109
123
  selectedWallet: WalletData | null;
110
124
  wallets: WalletData[];
111
125
  selectWallet: (walletId: string) => void;
@@ -124,19 +138,54 @@ interface UseCilantroConfigResult {
124
138
  declare function useCilantroConfig(): UseCilantroConfigResult;
125
139
 
126
140
  interface UseAuthResult {
141
+ /** Current user (from JWT payload or login response). */
127
142
  user: User | null;
143
+ /** JWT token. Prefer this name. */
128
144
  jwt: string | null;
145
+ /** Alias for jwt. Same value. */
146
+ token: string | null;
129
147
  isLoading: boolean;
130
148
  isAuthenticated: boolean;
131
149
  login: (params: {
132
150
  usernameOrEmail: string;
133
151
  password: string;
134
152
  }) => Promise<void>;
153
+ /** Register a new user and auto-login. */
154
+ register: (username: string, email: string, password: string, isActive?: boolean) => Promise<void>;
135
155
  logout: () => void;
156
+ /** Clear session when API returns 401/403. Call onSessionExpired. */
157
+ clearSessionDueToAuthError: () => void;
136
158
  }
137
159
  declare function useAuth(): UseAuthResult;
138
160
 
161
+ interface UseReturnUrlOptions {
162
+ /** Query param name for return URL. Default: "returnUrl" */
163
+ param?: string;
164
+ /** Default path when no returnUrl in URL. Default: "/" */
165
+ defaultPath?: string;
166
+ /** Only allow relative paths (no protocol). Default: true */
167
+ allowRelativeOnly?: boolean;
168
+ }
169
+ /**
170
+ * Read returnUrl from URL search params and provide a safe redirect path.
171
+ * Use with LoginForm/RegisterForm to redirect users back after auth.
172
+ *
173
+ * @example
174
+ * // In LoginForm wrapper - redirect to returnUrl after login
175
+ * const { returnPath, redirect } = useReturnUrl();
176
+ * <LoginForm onSuccess={() => redirect()} redirectAfterSuccess={returnPath} onRedirect={router.replace} />
177
+ */
178
+ declare function useReturnUrl(options?: UseReturnUrlOptions): {
179
+ /** Safe path to redirect to (from URL or defaultPath) */
180
+ returnPath: string;
181
+ /** Redirect to returnPath using window.location (or pass custom fn) */
182
+ redirect: (customRedirect?: (path: string) => void) => void;
183
+ /** Raw value from URL (may be empty) */
184
+ rawReturnUrl: string | null;
185
+ };
186
+
139
187
  interface UseWalletResult {
188
+ /** Selected wallet. Use this as primary. */
140
189
  wallet: WalletData | null;
141
190
  wallets: WalletData[];
142
191
  createWallet: (params: {
@@ -144,7 +193,11 @@ interface UseWalletResult {
144
193
  userId?: string;
145
194
  }) => Promise<WalletControllerCreateResult>;
146
195
  selectWallet: (walletId: string) => void;
196
+ /** Refresh wallet list from API. */
197
+ refreshWallets: () => Promise<void>;
147
198
  isLoading: boolean;
199
+ /** Error from wallet operations (e.g. fetch failed). */
200
+ error: string | null;
148
201
  }
149
202
  declare function useWallet(_walletId?: string): UseWalletResult;
150
203
 
@@ -277,6 +330,12 @@ interface LoginFormProps {
277
330
  style?: React.CSSProperties;
278
331
  onSuccess?: () => void;
279
332
  onError?: (error: Error) => void;
333
+ /** Redirect to this path after successful login. If not set, reads from URL ?returnUrl= (when returnUrlParam provided). */
334
+ redirectAfterSuccess?: string;
335
+ /** Custom redirect function for SPA routers. e.g. (path) => router.replace(path) */
336
+ onRedirect?: (path: string) => void;
337
+ /** Query param to read returnUrl from URL. Default: "returnUrl". Used when redirectAfterSuccess not set. */
338
+ returnUrlParam?: string;
280
339
  rememberMe?: boolean;
281
340
  /** Override submit button label */
282
341
  submitLabel?: string;
@@ -287,41 +346,78 @@ interface LoginFormProps {
287
346
  /** Render "Create account" link (e.g. to switch to register). Shown below submit. */
288
347
  renderSwitchToRegister?: () => React.ReactNode;
289
348
  }
290
- declare function LoginForm({ className, classNames, style, onSuccess, onError, submitLabel, title, description, renderSwitchToRegister, }: LoginFormProps): react_jsx_runtime.JSX.Element;
349
+ declare function LoginForm({ className, classNames, style, onSuccess, onError, redirectAfterSuccess, onRedirect, returnUrlParam, submitLabel, title, description, renderSwitchToRegister, }: LoginFormProps): react_jsx_runtime.JSX.Element;
350
+
351
+ interface RegisterFormClassNames {
352
+ root?: string;
353
+ header?: string;
354
+ title?: string;
355
+ description?: string;
356
+ form?: string;
357
+ label?: string;
358
+ input?: string;
359
+ submitButton?: string;
360
+ error?: string;
361
+ }
362
+ interface RegisterFormProps {
363
+ className?: string;
364
+ classNames?: RegisterFormClassNames;
365
+ style?: React.CSSProperties;
366
+ onSuccess?: () => void;
367
+ onError?: (error: Error) => void;
368
+ /** Redirect to this path after successful registration. If not set, reads from URL ?returnUrl= */
369
+ redirectAfterSuccess?: string;
370
+ /** Custom redirect function for SPA routers */
371
+ onRedirect?: (path: string) => void;
372
+ /** Query param to read returnUrl from URL. Default: "returnUrl" */
373
+ returnUrlParam?: string;
374
+ /** Override submit button label */
375
+ submitLabel?: string;
376
+ /** Override title */
377
+ title?: string;
378
+ /** Override description */
379
+ description?: string;
380
+ /** Render "Already have an account?" link to switch to login */
381
+ renderSwitchToLogin?: () => React.ReactNode;
382
+ }
383
+ declare function RegisterForm({ className, classNames, style, onSuccess, onError, redirectAfterSuccess, onRedirect, returnUrlParam, submitLabel, title, description, renderSwitchToLogin, }: RegisterFormProps): react_jsx_runtime.JSX.Element;
291
384
 
292
385
  interface LogoutButtonProps {
293
386
  onLogout?: () => void;
387
+ /** Redirect to this path after logout (e.g. "/login") */
388
+ redirectAfterLogout?: string;
389
+ /** Custom redirect for SPA routers. e.g. (path) => router.replace(path) */
390
+ onRedirect?: (path: string) => void;
294
391
  confirmBeforeLogout?: boolean;
295
392
  className?: string;
296
393
  children?: ReactNode;
297
394
  }
298
- declare function LogoutButton({ onLogout, confirmBeforeLogout, className, children, }: LogoutButtonProps): react_jsx_runtime.JSX.Element;
395
+ declare function LogoutButton({ onLogout, redirectAfterLogout, onRedirect, confirmBeforeLogout, className, children, }: LogoutButtonProps): react_jsx_runtime.JSX.Element;
299
396
 
300
- interface AuthGuardClassNames {
397
+ interface AuthShellClassNames {
301
398
  root?: string;
302
- fallback?: string;
303
- skeleton?: string;
304
- loading?: string;
399
+ inner?: string;
400
+ logo?: string;
305
401
  }
306
- interface AuthGuardProps {
402
+ interface AuthShellProps {
307
403
  children: ReactNode;
308
- /** Shown when not authenticated. Default: <LoginForm /> */
309
- fallback?: ReactNode;
310
- /** If using a router, redirect to this path when not authenticated (consumer can pass fallback={<Navigate to={redirectTo} />}) */
311
- redirectTo?: string;
312
- /** Root class when showing fallback */
404
+ /** Optional logo/brand (e.g. <img> or <Logo />) */
405
+ logo?: ReactNode;
406
+ /** Max width of the auth card area. Default: "sm" (24rem) */
407
+ maxWidth?: "sm" | "md" | "lg";
313
408
  className?: string;
314
- classNames?: AuthGuardClassNames;
315
- /** When true, show fallback (login) instead of children when unauthenticated. When false, render null when unauthenticated. */
316
- showFallback?: boolean;
317
- /** When true, show a small skeleton card while loading; when false (default), show "Loading..." text. */
318
- useSkeleton?: boolean;
409
+ classNames?: AuthShellClassNames;
319
410
  }
320
411
  /**
321
- * Wraps content and shows fallback (e.g. LoginForm) when the user is not authenticated.
322
- * Use inside CilantroProvider.
412
+ * Full-page centered layout for auth screens (login, register).
413
+ * Provides a polished, accessible UX with consistent spacing and optional logo.
414
+ *
415
+ * @example
416
+ * <AuthShell logo={<img src="/logo.svg" alt="App" />}>
417
+ * <LoginForm />
418
+ * </AuthShell>
323
419
  */
324
- declare function AuthGuard({ children, fallback, redirectTo, className, classNames, showFallback, useSkeleton, }: AuthGuardProps): react_jsx_runtime.JSX.Element | null;
420
+ declare function AuthShell({ children, logo, maxWidth, className, classNames, }: AuthShellProps): react_jsx_runtime.JSX.Element;
325
421
 
326
422
  interface CreateEmailSignerFormProps {
327
423
  walletId: string;
@@ -673,6 +769,21 @@ interface NormalizedWallet {
673
769
  * Accepts any object with optional walletId/id, walletAddress/address, isActive.
674
770
  */
675
771
  declare function normalizeWallet(dto: Record<string, unknown>): NormalizedWallet;
772
+ /** Wallet-like object with optional id/walletId and address/walletAddress. */
773
+ type WalletLike = {
774
+ id?: string;
775
+ walletId?: string;
776
+ address?: string;
777
+ walletAddress?: string;
778
+ } & Record<string, unknown>;
779
+ /**
780
+ * Get wallet ID from a wallet-like object. Prefer id; fallback to walletId.
781
+ */
782
+ declare function getWalletId(wallet: WalletLike | null | undefined): string;
783
+ /**
784
+ * Get wallet address from a wallet-like object. Prefer address; fallback to walletAddress.
785
+ */
786
+ declare function getWalletAddress(wallet: WalletLike | null | undefined): string;
676
787
 
677
788
  declare function extractErrorMessage(error: unknown): string;
678
789
  declare function isAuthError(error: unknown): boolean;
@@ -716,4 +827,4 @@ interface SignAndSendConnectionAdapter {
716
827
  */
717
828
  declare function adaptSolanaConnection(connection: Connection): SignAndSendConnectionAdapter;
718
829
 
719
- export { type ActionState, AddPasskeyButton, type AddPasskeyButtonProps, type ApiResponse, AuthGuard, type AuthGuardClassNames, type AuthGuardProps, type CilantroAuthContextType, type CilantroConfig, CilantroConnect, type CilantroConnectProps, CilantroContextProvider, type CilantroContextValue, CilantroProvider, type CilantroProviderProps, ConnectWalletButton, type ConnectWalletButtonProps, CreateEmailSignerForm, type CreateEmailSignerFormProps, CreatePhoneSignerForm, type CreatePhoneSignerFormProps, CreateWalletForm, type CreateWalletFormProps, type DeviceKeyStorage, ErrorBoundary, type ErrorBoundaryProps, type ErrorResponse, LoadingOverlay, type LoadingOverlayProps, LoginForm, type LoginFormClassNames, type LoginFormProps, LogoutButton, type LogoutButtonProps, type NormalizedWallet, type ResolvedTheme, SIGNER_TYPES, SendSOLForm, type SendSOLFormProps, type SignerType as SendSOLSignerType, SendSPLForm, type SendSPLFormProps, type SignerType$2 as SendTransactionSignerType, type SignAndSendConnection, type SignAndSendConnectionAdapter, type SignAndSendResult, type SignMessageResult, type SignerData, SignerList, type SignerListClassNames, type SignerListProps, SignerSelector, type SignerSelectorClassNames, type SignerSelectorProps, type SignerType$1 as SignerType, Skeleton, type SolanaWallet, type SubmitTransactionDataDto, type SubmitTransactionResult, type Theme, ThemeProvider, type ThemeProviderProps, TransactionHistory, type TransactionHistoryProps, TransactionStatus, type TransactionStatusProps, type UseAuthResult, type UseCilantroConfigResult, type UseExternalWalletResult, type UsePasskeyResult, type UseSendTransactionResult, type UseSignersOptions, type UseSignersResult, type UseWalletResult, type User, WalletAddress, type WalletAddressProps, WalletBalance, type WalletBalanceProps, type WalletContextType, type WalletData, type WalletDataDto$1 as WalletDataDto, type WalletDataDto as WalletDataDtoFromHook, type WalletData as WalletDataFromHook, type WalletInfo, WalletSelector, type WalletSelectorClassNames, type WalletSelectorProps, adaptSolanaConnection, extractErrorMessage, extractResponseData, getSignerPublicKey, getWalletData, isAuthError, isJwtExpired, normalizeSigner, normalizeWallet, signAndSendTransactionWithSigner, signMessageWithSigner, signTransactionWithSigner, useAuth, useCilantroAuth, useCilantroConfig, useCilantroContext, useExternalWallet, usePasskey, useSendTransaction, useSigners, useWallet, useWallets };
830
+ export { type ActionState, AddPasskeyButton, type AddPasskeyButtonProps, type ApiResponse, AuthShell, type AuthShellClassNames, type AuthShellProps, type CilantroAuthContextType, type CilantroConfig, CilantroConnect, type CilantroConnectProps, CilantroContextProvider, type CilantroContextValue, CilantroProvider, type CilantroProviderProps, ConnectWalletButton, type ConnectWalletButtonProps, CreateEmailSignerForm, type CreateEmailSignerFormProps, CreatePhoneSignerForm, type CreatePhoneSignerFormProps, CreateWalletForm, type CreateWalletFormProps, type DeviceKeyStorage, ErrorBoundary, type ErrorBoundaryProps, type ErrorResponse, LoadingOverlay, type LoadingOverlayProps, LoginForm, type LoginFormClassNames, type LoginFormProps, LogoutButton, type LogoutButtonProps, type NormalizedWallet, RegisterForm, type RegisterFormClassNames, type RegisterFormProps, type ResolvedTheme, SIGNER_TYPES, SendSOLForm, type SendSOLFormProps, type SignerType as SendSOLSignerType, SendSPLForm, type SendSPLFormProps, type SignerType$2 as SendTransactionSignerType, type SignAndSendConnection, type SignAndSendConnectionAdapter, type SignAndSendResult, type SignMessageResult, type SignerData, SignerList, type SignerListClassNames, type SignerListProps, SignerSelector, type SignerSelectorClassNames, type SignerSelectorProps, type SignerType$1 as SignerType, Skeleton, type SolanaWallet, type SubmitTransactionDataDto, type SubmitTransactionResult, type Theme, ThemeProvider, type ThemeProviderProps, TransactionHistory, type TransactionHistoryProps, TransactionStatus, type TransactionStatusProps, type UseAuthResult, type UseCilantroConfigResult, type UseExternalWalletResult, type UsePasskeyResult, type UseReturnUrlOptions, type UseSendTransactionResult, type UseSignersOptions, type UseSignersResult, type UseWalletResult, type User, WalletAddress, type WalletAddressProps, WalletBalance, type WalletBalanceProps, type WalletContextType, type WalletData, type WalletDataDto$1 as WalletDataDto, type WalletDataDto as WalletDataDtoFromHook, type WalletData as WalletDataFromHook, type WalletInfo, type WalletLike, WalletSelector, type WalletSelectorClassNames, type WalletSelectorProps, adaptSolanaConnection, extractErrorMessage, extractResponseData, getSignerPublicKey, getWalletAddress, getWalletData, getWalletId, isAuthError, isJwtExpired, normalizeSigner, normalizeWallet, signAndSendTransactionWithSigner, signMessageWithSigner, signTransactionWithSigner, useAuth, useCilantroAuth, useCilantroConfig, useCilantroContext, useExternalWallet, usePasskey, useReturnUrl, useSendTransaction, useSigners, useWallet, useWallets };