ab-ecosystem-sso 0.1.18 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,214 @@
1
1
  import { JSX as JSX_2 } from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
3
 
4
- export declare function AccountSettings({ open, onOpenChange, initialSection, syncUrlHash, data, title, projectId, token, apiBaseUrl, onSaveProfile, onUpdateWhatsApp, onChangePassword, onToggleTwoFactor, onRevokeSession, onAddFunds, onChangePlan, onLogout, }: AccountSettingsProps): JSX_2.Element | null;
4
+ /**
5
+ * POST /invitations/:token/accept — joins the inviting account using an
6
+ * existing login. The caller's login email must match the invite. Follow it
7
+ * with `switchAccountApi` on the returned `account_id` to drop the user
8
+ * straight into the new account.
9
+ */
10
+ export declare function acceptInvitationApi(projectId: string, inviteToken: string, token: string, apiBaseUrl?: string): Promise<string>;
11
+
12
+ /**
13
+ * The invitee side of an invitation link — drop it on your
14
+ * `/accept-invite?token=…` route.
15
+ *
16
+ * It resolves the token first (`GET /invitations/:token`) and then renders the
17
+ * branch the backend asked for:
18
+ *
19
+ * - `mode: "signup"` — no login here yet, so it renders `Signup` with the
20
+ * invite token and the invited address prefilled and read-only.
21
+ * - `mode: "accept"` — they already have a login. Given a `token` it shows the
22
+ * invite details and an accept button (then switches the session onto the new
23
+ * account); without one it calls `onNeedLogin` so you can route them through
24
+ * your own login first.
25
+ *
26
+ * ```tsx
27
+ * <AcceptInvite
28
+ * projectId="…"
29
+ * inviteToken={new URLSearchParams(location.search).get('token') ?? ''}
30
+ * token={session}
31
+ * onAccepted={({ accessToken }) => accessToken && save(accessToken)}
32
+ * onNeedLogin={() => navigate('/login?next=' + encodeURIComponent(location.href))}
33
+ * />
34
+ * ```
35
+ */
36
+ export declare function AcceptInvite(props: AcceptInviteProps): JSX_2.Element;
37
+
38
+ export declare interface AcceptInviteProps {
39
+ projectId: string;
40
+ /** The `token` query param from the invite link. */
41
+ inviteToken: string;
42
+ /**
43
+ * A live session token, when the invitee is already signed in here. Required
44
+ * for the `"accept"` branch — without it the screen asks them to sign in
45
+ * first (see {@link onNeedLogin}).
46
+ */
47
+ token?: string;
48
+ /**
49
+ * After accepting with an existing login, switch the session onto the joined
50
+ * account straight away (that's `/auth/switch-account`, which returns a fresh
51
+ * token). Defaults to `true`.
52
+ */
53
+ switchOnAccept?: boolean;
54
+ /**
55
+ * Called once the invitation has been accepted. `accessToken` is present when
56
+ * the session was switched onto the new account — store it in place of the
57
+ * old token.
58
+ */
59
+ onAccepted?: (result: {
60
+ accountId: string;
61
+ accessToken?: string;
62
+ }) => void;
63
+ /**
64
+ * Called when the invite needs an existing login and none was given — send
65
+ * the user to your login route, then come back here with `token` set.
66
+ */
67
+ onNeedLogin?: (invitation: InvitationLookup) => void;
68
+ /** Forwarded to the embedded `Signup` on the "signup" branch. */
69
+ onSuccess?: (data: unknown) => void;
70
+ onError?: (error: Error) => void;
71
+ /** Forwarded to the embedded `Signup` on the "signup" branch. */
72
+ countries?: CountryOption[];
73
+ classNames?: AuthClassNames;
74
+ mode?: AuthMode;
75
+ config?: AuthConfig;
76
+ apiBaseUrl?: string;
77
+ /** Persist the token issued when the session switches onto the joined account. Default `true`. */
78
+ persistToken?: boolean;
79
+ tokenStorageKey?: string;
80
+ }
81
+
82
+ /** `{ data: { accessToken } }` from select-account / switch-account. */
83
+ export declare interface AccessTokenResponse {
84
+ success?: boolean;
85
+ message?: string;
86
+ data?: {
87
+ accessToken?: string;
88
+ [key: string]: unknown;
89
+ };
90
+ }
91
+
92
+ /**
93
+ * One account the user can sign in to, as returned by the login picker and by
94
+ * `GET /accounts` (both are built by the same backend helper, so the two lists
95
+ * can't disagree).
96
+ */
97
+ export declare interface AccountOption {
98
+ account_id: string;
99
+ name: string;
100
+ /** True for the user's own account; owners also get the roles/members admin. */
101
+ is_owner: boolean;
102
+ /** Role title, or null for an owner / a member with no role. */
103
+ role: string | null;
104
+ /** ISO date the member's access lapses, or null for no expiry. */
105
+ access_expiry: string | null;
106
+ }
107
+
108
+ /**
109
+ * Lets a user pick which account to open. It serves both halves of the
110
+ * multi-account flow:
111
+ *
112
+ * **After login** — pass the `selectionTicket` + `accounts` from a response
113
+ * that came back with `accountSelectionRequired`. Picking exchanges the ticket
114
+ * for a session token. (`Login` renders this step itself, so you only need
115
+ * this when you handle the branch in your own `onSuccess`.)
116
+ *
117
+ * ```tsx
118
+ * <AccountPicker
119
+ * projectId="…"
120
+ * selectionTicket={res.selectionTicket}
121
+ * accounts={res.accounts}
122
+ * onSelect={({ accessToken }) => save(accessToken)}
123
+ * />
124
+ * ```
125
+ *
126
+ * **On a live session** — pass `token` instead. The list comes from
127
+ * `GET /accounts` and picking switches the session, handing you a fresh token
128
+ * to store in place of the old one.
129
+ *
130
+ * ```tsx
131
+ * <AccountPicker projectId="…" token={token} variant="list"
132
+ * currentAccountId={accountId}
133
+ * onSelect={({ accessToken }) => save(accessToken)} />
134
+ * ```
135
+ */
136
+ export declare function AccountPicker(props: AccountPickerProps): JSX_2.Element;
137
+
138
+ export declare interface AccountPickerProps {
139
+ projectId: string;
140
+ /**
141
+ * Ticket mode (straight after login). The `selectionTicket` from a login or
142
+ * verify-2fa response that came back with `accountSelectionRequired`, plus
143
+ * the `accounts` it listed. Picking one exchanges the ticket for a session
144
+ * token via `/auth/select-account`.
145
+ *
146
+ * The ticket lives **five minutes**; after that the user has to log in again.
147
+ */
148
+ selectionTicket?: string;
149
+ /** The accounts to choose from. In session mode they're fetched instead. */
150
+ accounts?: AccountOption[];
151
+ /**
152
+ * Session mode (account switcher). A live session token: the list is loaded
153
+ * from `GET /accounts` and picking calls `/auth/switch-account`, which issues
154
+ * a **fresh token** — store it in place of the old one. The previous token
155
+ * stays valid until it expires or is logged out.
156
+ */
157
+ token?: string;
158
+ /** Recorded on the session by select-account, e.g. "webapp". */
159
+ client?: string;
160
+ /** "card" (default) renders the full auth card; "list" renders just the list. */
161
+ variant?: 'card' | 'list';
162
+ /** Card heading. Defaults to "Choose an account". */
163
+ title?: string;
164
+ /** Card subheading. */
165
+ description?: string;
166
+ /** Highlights the account the session is already on (session mode). */
167
+ currentAccountId?: string;
168
+ /** Called with the new token once an account has been chosen. */
169
+ onSelect?: (result: {
170
+ accessToken: string;
171
+ account: AccountOption;
172
+ }) => void;
173
+ onError?: (error: Error) => void;
174
+ /** Renders a secondary action under the list (e.g. "Back to sign in"). */
175
+ onCancel?: () => void;
176
+ cancelLabel?: string;
177
+ classNames?: AuthClassNames;
178
+ mode?: AuthMode;
179
+ config?: AuthConfig;
180
+ apiBaseUrl?: string;
181
+ /**
182
+ * Persist the issued token. Default `true` — important here, since
183
+ * switch-account returns a *fresh* token that has to replace the old one.
184
+ */
185
+ persistToken?: boolean;
186
+ tokenStorageKey?: string;
187
+ }
188
+
189
+ export declare function AccountSettings({ open, onOpenChange, initialSection, customComponents, syncUrlHash, data, title, mode, isOwner, inviteLinkBase, onAccountSwitch, currentAccountId, projectId, token: tokenProp, apiBaseUrl, onSaveProfile, onUpdateWhatsApp, onChangePassword, onToggleTwoFactor, onRevokeSession, onAddFunds, onChangePlan, onLogout, }: AccountSettingsProps): JSX_2.Element | null;
190
+
191
+ /** Where a custom panel's trigger appears in the modal chrome. */
192
+ export declare type AccountSettingsCustomLocation = 'sidebar' | 'sidebar-bottom' | 'header';
193
+
194
+ /**
195
+ * A host-supplied panel added to the Account Settings modal. Its trigger appears
196
+ * in the sidebar (as a nav item), pinned to the bottom of the sidebar, or in the
197
+ * header next to the close button; activating it renders `component` in the modal
198
+ * body in place of the built-in sections.
199
+ */
200
+ export declare interface AccountSettingsCustomPanel {
201
+ /** Stable id — used to track which panel is active. Must be unique. */
202
+ id: string;
203
+ /** Trigger placement. Defaults to "sidebar". */
204
+ location?: AccountSettingsCustomLocation;
205
+ /** Trigger text (sidebar label / header button tooltip + aria-label). */
206
+ label: string;
207
+ /** Optional trigger icon (an inline SVG or any node). */
208
+ icon?: ReactNode;
209
+ /** Rendered in the modal body when this panel is active. */
210
+ component: ReactNode;
211
+ }
5
212
 
6
213
  export declare interface AccountSettingsData {
7
214
  user: {
@@ -85,6 +292,12 @@ export declare interface AccountSettingsProps {
85
292
  onOpenChange: (open: boolean) => void;
86
293
  /** Section to show first. Defaults to "general". */
87
294
  initialSection?: AccountSettingsSection;
295
+ /**
296
+ * Host-supplied panels added to the modal. Each renders a trigger in the
297
+ * sidebar, sidebar bottom, or header, and shows its `component` in the body
298
+ * when activated. See {@link AccountSettingsCustomPanel}.
299
+ */
300
+ customComponents?: AccountSettingsCustomPanel[];
88
301
  /**
89
302
  * Sync the open state + active section to the URL hash as `#settings-<section>`,
90
303
  * so a page refresh re-opens the modal on the same section. The hash is cleared
@@ -95,9 +308,35 @@ export declare interface AccountSettingsProps {
95
308
  data?: Partial<AccountSettingsData>;
96
309
  /** Modal heading shown above the nav. Defaults to "Settings". */
97
310
  title?: string;
311
+ /** Colour scheme — `"light"` (default) or `"dark"`. */
312
+ mode?: AuthMode;
313
+ /**
314
+ * Show the owner-only Members / Roles / Invitations sections. Those endpoints
315
+ * are owner-only and answer a non-owner with "Only the account owner can do
316
+ * this", which the sections display — so the default is to show the tabs and
317
+ * let the API be the authority. Pass `false` to hide them outright.
318
+ */
319
+ isOwner?: boolean;
320
+ /**
321
+ * Where invite links point; the token is appended as `?token=…`. Defaults to
322
+ * `<your origin>/accept-invite`. Build that route with `AcceptInvite`.
323
+ */
324
+ inviteLinkBase?: string;
325
+ /**
326
+ * Enables the **Accounts** section (the account switcher). Called with a
327
+ * fresh token after `/auth/switch-account` — store it in place of the old
328
+ * one. Without this prop the switcher is hidden, since there'd be nowhere to
329
+ * put the new token.
330
+ */
331
+ onAccountSwitch?: (result: {
332
+ accessToken: string;
333
+ accountId: string;
334
+ }) => void;
335
+ /** The account the session is currently on — marked "Current" in the switcher. */
336
+ currentAccountId?: string;
98
337
  /** When provided (with token), the component loads/saves via the live API instead of sample data. */
99
338
  projectId?: string;
100
- /** Bearer token for API calls. */
339
+ /** Bearer token for API calls. Omit to use the one stored at login. */
101
340
  token?: string;
102
341
  /** API base URL override (defaults to VITE_AUTH_API_BASE_URL). */
103
342
  apiBaseUrl?: string;
@@ -121,11 +360,17 @@ export declare interface AccountSettingsProps {
121
360
  onLogout?: () => void;
122
361
  }
123
362
 
124
- export declare type AccountSettingsSection = 'general' | 'account' | 'billing' | 'wallet' | 'plans' | 'credits';
363
+ export declare type AccountSettingsSection = 'general' | 'account' | 'billing' | 'wallet' | 'plans' | 'credits'
364
+ /** Account switcher — only shown when `onAccountSwitch` is given. */
365
+ | 'accounts'
366
+ /** Owner-only team administration. */
367
+ | 'members' | 'roles' | 'invitations';
125
368
 
126
369
  export declare class AuthApiError extends Error {
127
370
  code: string | undefined;
128
- constructor(code: string | undefined, fallbackMessage: string);
371
+ /** HTTP status, when the caller had one to hand (select/switch answer 401). */
372
+ status: number | undefined;
373
+ constructor(code: string | undefined, fallbackMessage: string, status?: number);
129
374
  }
130
375
 
131
376
  /** CSS class overrides for all auth component sub-elements */
@@ -157,6 +402,18 @@ export declare interface AuthComponentBaseProps {
157
402
  onError?: (error: Error) => void;
158
403
  /** API base URL override */
159
404
  apiBaseUrl?: string;
405
+ /** Colour scheme — `"light"` (default) or `"dark"`. */
406
+ mode?: AuthMode;
407
+ /**
408
+ * Persist the issued session token so the rest of the package (and your own
409
+ * calls, via `getAuthHeader`) can use it without being handed one. Default
410
+ * `true`. Set `false` to keep handling the token entirely yourself.
411
+ *
412
+ * Configure the key/storage globally with `configureTokenStorage()`.
413
+ */
414
+ persistToken?: boolean;
415
+ /** Storage key override for this component. Default `"ab-sso:accessToken"`. */
416
+ tokenStorageKey?: string;
160
417
  }
161
418
 
162
419
  export declare interface AuthConfig {
@@ -178,6 +435,54 @@ export declare interface AuthErrorResponse {
178
435
  errors?: Record<string, string[]>;
179
436
  }
180
437
 
438
+ /**
439
+ * `fetch` with the session token attached and 401 handling wired in.
440
+ *
441
+ * ```ts
442
+ * const res = await authFetch("/api/orders");
443
+ * ```
444
+ *
445
+ * An `Authorization` header you set yourself is never overwritten. Everything
446
+ * else behaves exactly like `fetch`, including the returned unread body.
447
+ */
448
+ export declare function authFetch(input: RequestInfo | URL, init?: AuthFetchInit): Promise<Response>;
449
+
450
+ export declare interface AuthFetchInit extends RequestInit {
451
+ /** Token override; defaults to the stored session token. */
452
+ token?: string;
453
+ }
454
+
455
+ export declare interface AuthHandlers {
456
+ /**
457
+ * The session is no longer valid (401, and not the account-access case) —
458
+ * send the user to login.
459
+ */
460
+ onUnauthorized?: (info: UnauthorizedInfo) => void;
461
+ /**
462
+ * Access to *this account* was revoked or expired (`A403`). The login is
463
+ * still good: show the account picker rather than logging out.
464
+ */
465
+ onAccountAccessLost?: (info: UnauthorizedInfo) => void;
466
+ }
467
+
468
+ export declare interface AuthInterceptorOptions extends AuthHandlers {
469
+ /**
470
+ * **Required.** Origins allowed to receive the token — your own API hosts.
471
+ * `"self"` means the page's own origin (covers relative URLs like
472
+ * `/api/...`). There is no wildcard: anything not listed is left untouched,
473
+ * which is what keeps the token away from third-party scripts.
474
+ */
475
+ origins: string[];
476
+ }
477
+
478
+ /**
479
+ * Colour scheme for a rendered component. Defaults to `"light"`.
480
+ *
481
+ * Each component root carries `data-aas-theme`, so modes are per-component —
482
+ * a dark login card and a light settings modal can coexist on one page.
483
+ */
484
+ export declare type AuthMode = 'light' | 'dark';
485
+
181
486
  export declare function AuthProvider({ projectId, config: externalConfig, apiBaseUrl, children, }: AuthProviderProps): JSX_2.Element;
182
487
 
183
488
  declare interface AuthProviderProps {
@@ -188,11 +493,34 @@ declare interface AuthProviderProps {
188
493
  children: ReactNode;
189
494
  }
190
495
 
496
+ /**
497
+ * Response of `/auth/login` and `/auth/verify-2fa`.
498
+ *
499
+ * It has **three** branches, which must be checked in this order:
500
+ * 1. `twoFactorRequired` — collect an OTP and call `/auth/verify-2fa`.
501
+ * 2. `accountSelectionRequired` — the user belongs to more than one account;
502
+ * there is no token yet. Let them pick from `accounts`, then exchange
503
+ * `selectionTicket` via `/auth/select-account` (the ticket lives 5 minutes).
504
+ * 3. otherwise — signed in, token at `data.accessToken`.
505
+ */
191
506
  export declare interface AuthResponse {
507
+ success?: boolean;
508
+ message?: string;
509
+ /** Present on a completed login; the session token is `data.accessToken`. */
510
+ data?: {
511
+ accessToken?: string;
512
+ [key: string]: unknown;
513
+ };
192
514
  token: string;
193
515
  user: unknown;
194
516
  /** If true, the user must complete 2FA (re-sending email + password + OTP + captcha) */
195
517
  twoFactorRequired?: boolean;
518
+ /** If true, no token was issued — the user must choose an account first. */
519
+ accountSelectionRequired?: boolean;
520
+ /** The accounts to choose from. Only present with `accountSelectionRequired`. */
521
+ accounts?: AccountOption[];
522
+ /** Short-lived (5 min) credential for `/auth/select-account`. */
523
+ selectionTicket?: string;
196
524
  }
197
525
 
198
526
  export declare interface CaptchaConfig {
@@ -212,6 +540,34 @@ export declare interface CardLayoutConfig {
212
540
  signupEnabled: boolean;
213
541
  }
214
542
 
543
+ /** Removes the stored token. Called by logout and on an invalid session. */
544
+ export declare function clearStoredToken(options?: TokenAccessOptions): void;
545
+
546
+ /**
547
+ * Registers what should happen when a call made through `authFetch` (or an
548
+ * installed interceptor) comes back unauthorized. Call it once at bootstrap.
549
+ */
550
+ export declare function configureAuthHandlers(next: AuthHandlers): void;
551
+
552
+ /**
553
+ * Remaps any of the paths, for apps whose routes differ (`/sign-in` instead of
554
+ * `/login`, say). Call it once at bootstrap — `SessionProvider` and
555
+ * `SsoAuthRoutes` both read the result.
556
+ */
557
+ export declare function configureSsoRoutes(overrides: Partial<SsoRoutePaths>): void;
558
+
559
+ /**
560
+ * Overrides how the token is stored, for the whole package. Call it once
561
+ * before rendering (e.g. next to your app's bootstrap).
562
+ *
563
+ * ```ts
564
+ * configureTokenStorage({ key: 'authToken' }); // match an existing app
565
+ * configureTokenStorage({ storage: 'sessionStorage' }); // per-tab only
566
+ * configureTokenStorage({ enabled: false }); // opt out entirely
567
+ * ```
568
+ */
569
+ export declare function configureTokenStorage(options: Partial<TokenStorageConfig>): void;
570
+
215
571
  /** A country option for the signup country dropdown. */
216
572
  export declare interface CountryOption {
217
573
  /** ISO 3166-1 alpha-2 country code, e.g. "US". */
@@ -219,6 +575,47 @@ export declare interface CountryOption {
219
575
  name: string;
220
576
  }
221
577
 
578
+ /**
579
+ * The one and only time the invite `token` is returned — it never appears in
580
+ * the list. Build the link yourself as
581
+ * `{your-frontend}/accept-invite?token={token}`; **no email is sent.**
582
+ */
583
+ export declare interface CreatedInvite {
584
+ id: string;
585
+ email: string;
586
+ token: string;
587
+ /** Link expiry — 72 hours out. */
588
+ expires_at?: string;
589
+ }
590
+
591
+ export declare function createInvitationApi(projectId: string, payload: CreateInvitePayload, token?: string, apiBaseUrl?: string): Promise<CreatedInvite>;
592
+
593
+ export declare interface CreateInvitePayload {
594
+ email: string;
595
+ /** "member" (default) or "user". */
596
+ type?: 'member' | 'user';
597
+ /** Role id, or null/omitted for no permissions. */
598
+ role?: string | null;
599
+ /** Future ISO date, or null/omitted for no expiry. */
600
+ access_expiry?: string | null;
601
+ }
602
+
603
+ export declare function createRoleApi(projectId: string, payload: CreateRolePayload, token?: string, apiBaseUrl?: string): Promise<{
604
+ id: string;
605
+ }>;
606
+
607
+ export declare interface CreateRolePayload {
608
+ title: string;
609
+ description?: string;
610
+ /**
611
+ * Permission strings. The server trims, uppercases, dedupes and sorts them,
612
+ * so "billing.view", "BILLING.VIEW" and " user.list " are stored as
613
+ * BILLING.VIEW + USER.LIST. Max 200 after dedupe. They are not validated
614
+ * against a catalogue yet — an unknown string simply grants nothing.
615
+ */
616
+ permission?: string[];
617
+ }
618
+
222
619
  export declare interface CreditWallet {
223
620
  id: string;
224
621
  label: string;
@@ -234,6 +631,15 @@ export declare interface CreditWallet {
234
631
  rechargeable: boolean;
235
632
  }
236
633
 
634
+ /** The defaults. `inviteLinkBase` and the backend's email links assume these. */
635
+ export declare const DEFAULT_SSO_ROUTES: SsoRoutePaths;
636
+
637
+ /**
638
+ * Refused while the role is still assigned, with
639
+ * "This role is assigned to N members. Reassign them first."
640
+ */
641
+ export declare function deleteRoleApi(projectId: string, roleId: string, token?: string, apiBaseUrl?: string): Promise<unknown>;
642
+
237
643
  declare function fetchAuthConfig(projectId: string, apiBaseUrl?: string): Promise<AuthConfig>;
238
644
  export { fetchAuthConfig }
239
645
  export { fetchAuthConfig as getAuthConfig }
@@ -257,6 +663,16 @@ export declare interface ForgotPasswordRequest {
257
663
  captchaToken?: string;
258
664
  }
259
665
 
666
+ /**
667
+ * `Authorization` header for the given token, falling back to the stored one.
668
+ * Returns an empty object when there is no token, so it's safe to spread.
669
+ *
670
+ * ```ts
671
+ * fetch(url, { headers: { ...getAuthHeader(), 'Content-Type': 'application/json' } });
672
+ * ```
673
+ */
674
+ export declare function getAuthHeader(token?: string): Record<string, string>;
675
+
260
676
  /**
261
677
  * GET /currency — the currencies enabled for the project (shown in signup).
262
678
  * Response envelope: `{ success, data: [{ name, code }] }`. No token required.
@@ -264,44 +680,161 @@ export declare interface ForgotPasswordRequest {
264
680
  */
265
681
  export declare function getCurrenciesApi(projectId: string, apiBaseUrl?: string): Promise<ProjectCurrency[]>;
266
682
 
683
+ /**
684
+ * GET /invitations/:token — resolves an invite link. No auth. Call it before
685
+ * rendering anything so you know whether to collect a password (`mode:
686
+ * "signup"`) or just have them accept (`mode: "accept"`).
687
+ */
688
+ export declare function getInvitationApi(projectId: string, inviteToken: string, apiBaseUrl?: string): Promise<InvitationLookup>;
689
+
690
+ /** The paths currently in effect. */
691
+ export declare function getSsoRoutes(): SsoRoutePaths;
692
+
693
+ /**
694
+ * The stored session token, or `""` when there is none (not signed in, storage
695
+ * disabled, or persistence turned off).
696
+ */
697
+ export declare function getStoredToken(options?: TokenAccessOptions): string;
698
+
699
+ /** The storage settings currently in effect. */
700
+ export declare function getTokenStorageConfig(): TokenStorageConfig;
701
+
267
702
  /**
268
703
  * Fetches the current user from GET /api/v1/projects/:projectId/me.
269
704
  * Returns the raw response envelope, e.g.
270
705
  * { success, data: { id, username, profile: { name, email, address, ... }, mainWallet, coinWallet } }
271
706
  * Throws AuthApiError on a non-2xx response.
272
707
  */
273
- export declare function getUser(projectId: string, token: string, apiBaseUrl?: string): Promise<Record<string, unknown>>;
708
+ export declare function getUser(projectId: string, token?: string, apiBaseUrl?: string): Promise<Record<string, unknown>>;
274
709
 
275
710
  /**
276
711
  * GET /credit-wallets → the user's credit wallets (mapped CreditWallet[]).
277
712
  * Alias of `getCreditWalletsApi` with a consumer-friendly name.
278
713
  */
279
- export declare function getUserCreditWallet(projectId: string, token: string, apiBaseUrl?: string): Promise<CreditWallet[]>;
714
+ export declare function getUserCreditWallet(projectId: string, token?: string, apiBaseUrl?: string): Promise<CreditWallet[]>;
280
715
 
281
716
  /**
282
717
  * GET /me → the user's profile as flat, display-ready fields (MappedProfile).
283
718
  * Includes name, email/username, address, phone, language and wallet summaries.
284
719
  */
285
- export declare function getUserProfile(projectId: string, token: string, apiBaseUrl?: string): Promise<MappedProfile>;
720
+ export declare function getUserProfile(projectId: string, token?: string, apiBaseUrl?: string): Promise<MappedProfile>;
286
721
 
287
722
  /**
288
723
  * GET /subscription → the user's active subscription, as returned by the API
289
724
  * (unmodified). `request()` unwraps the `{ success, data }` envelope, so this
290
725
  * resolves to the raw subscription `data` object.
291
726
  */
292
- export declare function getUserSubscription(projectId: string, token: string, apiBaseUrl?: string): Promise<unknown>;
727
+ export declare function getUserSubscription(projectId: string, token?: string, apiBaseUrl?: string): Promise<unknown>;
293
728
 
294
729
  /**
295
730
  * GET /me → just the wallet balances ({ mainWallet, coinWallet }).
296
731
  * A convenience over `getUserProfile` when you only need the balances.
297
732
  */
298
- export declare function getUserWallet(projectId: string, token: string, apiBaseUrl?: string): Promise<UserWallets>;
733
+ export declare function getUserWallet(projectId: string, token?: string, apiBaseUrl?: string): Promise<UserWallets>;
734
+
735
+ /**
736
+ * Attaches the session token to requests your app makes to the listed origins,
737
+ * by patching `fetch` and `XMLHttpRequest`.
738
+ *
739
+ * Prefer `getAuthHeader()` or `authFetch()` — this exists for apps with too
740
+ * many call sites to touch. The allowlist is mandatory precisely because a
741
+ * blanket patch would hand your bearer token to every third-party endpoint the
742
+ * page talks to.
743
+ *
744
+ * ```ts
745
+ * const stop = installAuthInterceptor({
746
+ * origins: ["self", "https://api.example.com"],
747
+ * onUnauthorized: () => navigate("/login"),
748
+ * onAccountAccessLost: () => showAccountPicker(),
749
+ * });
750
+ * ```
751
+ *
752
+ * Returns a function that restores the originals. Calling it twice is a no-op:
753
+ * the second install replaces the first.
754
+ */
755
+ export declare function installAuthInterceptor(options: AuthInterceptorOptions): () => void;
756
+
757
+ export declare interface Invitation {
758
+ id: string;
759
+ email: string;
760
+ type?: 'member' | 'user' | string;
761
+ role?: {
762
+ id: string;
763
+ title: string;
764
+ } | null;
765
+ access_expiry?: string | null;
766
+ status?: InvitationStatus | string;
767
+ /** When the invite link stops working (72 hours after creation). */
768
+ invite_expires_at?: string;
769
+ created_at?: string;
770
+ }
771
+
772
+ /**
773
+ * `GET /invitations/:token` — what an invite link resolves to. Call this before
774
+ * rendering anything, and branch on `mode`:
775
+ * "signup" → collect a password and POST `/auth/signup` with `inviteToken`.
776
+ * "accept" → the person already has a login here; sign them in, then POST
777
+ * `/invitations/:token/accept`.
778
+ */
779
+ export declare interface InvitationLookup {
780
+ /** The invited address. Render it read-only — a different one is ignored/rejected. */
781
+ email: string;
782
+ /** Display name of the account owner who sent the invite. */
783
+ invited_by: string;
784
+ /** Role title they'll be given, or null for no permissions. */
785
+ role: string | null;
786
+ access_expiry: string | null;
787
+ mode: 'signup' | 'accept';
788
+ }
789
+
790
+ export declare function InvitationsSection({ projectId, token, apiBaseUrl, inviteLinkBase }: InvitationsSectionProps): JSX_2.Element;
791
+
792
+ export declare interface InvitationsSectionProps extends TeamSectionProps {
793
+ /**
794
+ * Where invite links point. The token is appended as `?token=…`.
795
+ * Defaults to `<your origin>/accept-invite`.
796
+ */
797
+ inviteLinkBase?: string;
798
+ }
799
+
800
+ /** Invite status as reported by the API. A lapsed pending invite reports "expired" immediately. */
801
+ export declare type InvitationStatus = 'pending' | 'accepted' | 'expired' | 'revoked';
802
+
803
+ /**
804
+ * True when an error means "this account is no longer reachable" — revoked or
805
+ * expired member access, a disabled account, or an account that doesn't belong
806
+ * to this product. The backend answers 401 with code `A403`.
807
+ *
808
+ * Treat it as "send the user back to the account picker", **not** as a logout:
809
+ * their login is intact and their other accounts still work.
810
+ */
811
+ export declare function isAccountAccessError(error: unknown): boolean;
812
+
813
+ /**
814
+ * GET /accounts — every account the caller can reach, for an account switcher.
815
+ * Built by the same backend helper as the login picker, so the two agree.
816
+ */
817
+ export declare function listAccountsApi(projectId: string, token: string, apiBaseUrl?: string): Promise<AccountOption[]>;
818
+
819
+ declare type Listener = (token: string) => void;
820
+
821
+ export declare function listInvitationsApi(projectId: string, token?: string, status?: InvitationStatus, apiBaseUrl?: string): Promise<Invitation[]>;
822
+
823
+ /** Defaults to active members; pass "revoked" to list revoked ones. */
824
+ export declare function listMembersApi(projectId: string, token?: string, status?: MemberStatus, apiBaseUrl?: string): Promise<Member[]>;
825
+
826
+ export declare function listRolesApi(projectId: string, token?: string, apiBaseUrl?: string): Promise<Role[]>;
299
827
 
300
828
  export declare function Login(props: LoginProps): JSX_2.Element;
301
829
 
302
830
  export declare interface LoginProps extends AuthComponentBaseProps {
303
831
  onForgotPassword?: () => void;
304
832
  onSignupClick?: () => void;
833
+ /**
834
+ * Client identifier recorded on the session when the user picks an account
835
+ * (sent as `client` to `/auth/select-account`), e.g. `"webapp"`.
836
+ */
837
+ client?: string;
305
838
  }
306
839
 
307
840
  export declare interface LoginRequest {
@@ -325,11 +858,13 @@ export declare function logout(options: LogoutOptions): Promise<void>;
325
858
 
326
859
  export declare function logoutApi(projectId: string, token: string, apiBaseUrl?: string): Promise<void>;
327
860
 
328
- export declare function LogoutButton({ className, children, projectId, token, apiBaseUrl, onSuccess, onError, }: LogoutButtonProps): JSX_2.Element;
861
+ export declare function LogoutButton({ className, children, mode, projectId, token, apiBaseUrl, onSuccess, onError, }: LogoutButtonProps): JSX_2.Element;
329
862
 
330
863
  declare interface LogoutButtonProps {
331
864
  className?: string;
332
865
  children?: React.ReactNode;
866
+ /** Colour scheme — "light" (default) or "dark". */
867
+ mode?: AuthMode;
333
868
  /**
334
869
  * Standalone mode: when `projectId` + `token` are supplied the button calls
335
870
  * POST /api/v1/projects/:projectId/auth/logout directly (no SessionProvider
@@ -346,7 +881,8 @@ declare interface LogoutButtonProps {
346
881
 
347
882
  export declare interface LogoutOptions {
348
883
  projectId: string;
349
- token: string;
884
+ /** Omit to use the stored session token. */
885
+ token?: string;
350
886
  apiBaseUrl?: string;
351
887
  /** Called after the logout request completes — clear local state / redirect here. */
352
888
  onSuccess?: () => void;
@@ -393,6 +929,51 @@ export declare interface MappedSubscription {
393
929
  packageCounts: Record<string, number>;
394
930
  }
395
931
 
932
+ /**
933
+ * Resolves a pathname to one of the auth screens, or null when it's not ours.
934
+ *
935
+ * Matching is prefix-based for the token-bearing routes, so both
936
+ * `/verify/<token>` and `/reset-password?token=<token>` work, and exact for the
937
+ * rest — `/login` must not swallow the host's `/login-help`.
938
+ */
939
+ export declare function matchSsoRoute(pathname: string, search?: string, options?: {
940
+ basePath?: string;
941
+ routes?: Partial<SsoRoutePaths>;
942
+ }): SsoRouteMatch | null;
943
+
944
+ export declare interface Member {
945
+ /** Membership id — this is what update/revoke take. */
946
+ id: string;
947
+ /** The person's login profile id (not the membership). */
948
+ user_id?: string;
949
+ name?: string;
950
+ email?: string;
951
+ type?: 'member' | 'user' | string;
952
+ role?: {
953
+ id: string;
954
+ title: string;
955
+ } | null;
956
+ access_expiry?: string | null;
957
+ expired?: boolean;
958
+ status?: MemberStatus | string;
959
+ joined_at?: string;
960
+ revoked_at?: string | null;
961
+ }
962
+
963
+ export declare function MembersSection({ projectId, token, apiBaseUrl }: TeamSectionProps): JSX_2.Element;
964
+
965
+ export declare type MemberStatus = 'active' | 'revoked';
966
+
967
+ /**
968
+ * Subscribes to token changes made through this module (login, switch-account,
969
+ * logout, …). Returns an unsubscribe function.
970
+ *
971
+ * This fires for changes made *in this tab*. It deliberately does not listen to
972
+ * the cross-tab `storage` event — syncing sessions between tabs is a host
973
+ * decision, not something a component library should impose.
974
+ */
975
+ export declare function onStoredTokenChange(listener: Listener): () => void;
976
+
396
977
  /**
397
978
  * Imperatively open the Account Settings modal from anywhere — e.g. a button
398
979
  * or menu item's onClick. Mounts the modal into a detached container appended
@@ -441,6 +1022,9 @@ export declare interface ProjectCurrency {
441
1022
  code: string;
442
1023
  }
443
1024
 
1025
+ /** Reads `accessToken` out of any of the envelope shapes the auth endpoints return. */
1026
+ export declare function readAccessTokenFrom(response: unknown): string;
1027
+
444
1028
  /**
445
1029
  * POST /auth/reset-password — sets a new password using the reset token from the
446
1030
  * emailed link. Body: { token, password, captchaToken }.
@@ -470,20 +1054,80 @@ export declare interface ResetPasswordRequest {
470
1054
  */
471
1055
  export declare function restoreAccountSettings(options?: OpenAccountSettingsOptions): AccountSettingsHandle | null;
472
1056
 
1057
+ /** Only works on a *pending* invite — revoking an accepted one is a member operation. */
1058
+ export declare function revokeInvitationApi(projectId: string, inviteId: string, token?: string, apiBaseUrl?: string): Promise<unknown>;
1059
+
1060
+ /**
1061
+ * Revokes this account's access for the member. Their login is untouched — only
1062
+ * this account becomes unreachable and it disappears from their picker, on
1063
+ * their next request rather than when their token expires. Re-inviting the same
1064
+ * person reactivates the existing row.
1065
+ */
1066
+ export declare function revokeMemberApi(projectId: string, memberId: string, token?: string, apiBaseUrl?: string): Promise<unknown>;
1067
+
1068
+ /** A role as returned by `GET /account/roles`. */
1069
+ export declare interface Role {
1070
+ id: string;
1071
+ title: string;
1072
+ description?: string;
1073
+ /** Permission strings, stored uppercased + deduped + sorted by the server. */
1074
+ permission: string[];
1075
+ /** Platform-provided role: assignable, but not editable or deletable. */
1076
+ is_system?: boolean;
1077
+ /** Live count of members holding this role — use it to warn before deleting. */
1078
+ members?: number;
1079
+ }
1080
+
1081
+ export declare function RolesSection({ projectId, token, apiBaseUrl }: TeamSectionProps): JSX_2.Element;
1082
+
1083
+ /**
1084
+ * POST /auth/select-account — exchanges a login `selectionTicket` for a session
1085
+ * token on the chosen account.
1086
+ *
1087
+ * Unauthenticated: the ticket *is* the credential, and it expires after five
1088
+ * minutes (then the user has to log in again). Pass the caller's own
1089
+ * `account_id` to enter their own account.
1090
+ */
1091
+ export declare function selectAccountApi(projectId: string, data: SelectAccountRequest, apiBaseUrl?: string): Promise<string>;
1092
+
1093
+ /** Body of `POST /auth/select-account` — unauthenticated; the ticket is the credential. */
1094
+ export declare interface SelectAccountRequest {
1095
+ selection_ticket: string;
1096
+ account_id: string;
1097
+ /** Free-form client identifier recorded on the session, e.g. "webapp". */
1098
+ client?: string;
1099
+ }
1100
+
473
1101
  declare interface SessionContextValue {
474
1102
  isAuthenticated: boolean;
475
1103
  isValidating: boolean;
476
1104
  logout: () => Promise<void>;
1105
+ /**
1106
+ * Set when the session was rejected because *this account* is no longer
1107
+ * reachable (member access revoked or expired, account disabled) — the login
1108
+ * itself is still valid. Null in every other state.
1109
+ */
1110
+ accountAccessLost: {
1111
+ message?: string;
1112
+ code?: string;
1113
+ } | null;
477
1114
  }
478
1115
 
479
- export declare function SessionProvider({ projectId, token, onSessionInvalid, apiBaseUrl, enforceActiveSubscription, children, }: SessionProviderProps): JSX_2.Element;
1116
+ export declare function SessionProvider({ projectId, token: tokenProp, onSessionInvalid: onSessionInvalidProp, apiBaseUrl, enforceActiveSubscription, onAccountAccessLost, onTokenChange, mode, children, }: SessionProviderProps): JSX_2.Element;
480
1117
 
481
1118
  declare interface SessionProviderProps {
482
1119
  projectId: string;
483
- /** The auth token (from login response) — typically stored in localStorage by the consumer */
484
- token: string | null;
485
- /** Called when session is invalid or user logs out — navigate to login page here */
486
- onSessionInvalid: () => void;
1120
+ /**
1121
+ * The session token. **Omit it** to use the token the package stored at
1122
+ * login; pass `null` to state explicitly that there is no session.
1123
+ */
1124
+ token?: string | null;
1125
+ /**
1126
+ * Called when the session is invalid or the user logged out — navigate to
1127
+ * your login route here. Optional: with no handler the provider sends the
1128
+ * browser to the package's login route (see `SSO_ROUTES`).
1129
+ */
1130
+ onSessionInvalid?: () => void;
487
1131
  apiBaseUrl?: string;
488
1132
  /**
489
1133
  * When true, after the session validates we fetch the user's subscription; if
@@ -491,9 +1135,50 @@ declare interface SessionProviderProps {
491
1135
  * so they can subscribe. The modal stays open but the user can still close it.
492
1136
  */
493
1137
  enforceActiveSubscription?: boolean;
1138
+ /**
1139
+ * Called when the session is rejected with `A403` — the member's access to
1140
+ * **this** account was revoked or expired, or the account was disabled. Their
1141
+ * login is intact and their other accounts still work, so this is not a
1142
+ * logout: send them back to the account picker.
1143
+ *
1144
+ * Leave it unset to let the provider render the picker itself (see
1145
+ * {@link onTokenChange}).
1146
+ */
1147
+ onAccountAccessLost?: (info: {
1148
+ message?: string;
1149
+ code?: string;
1150
+ }) => void;
1151
+ /**
1152
+ * Called with a fresh token when the user switches account from the
1153
+ * built-in picker. Store it in place of the old one — without this the
1154
+ * provider has nowhere to hand the new session, so it falls back to
1155
+ * `onSessionInvalid`.
1156
+ */
1157
+ onTokenChange?: (token: string) => void;
1158
+ /** Colour scheme for the built-in picker — "light" (default) or "dark". */
1159
+ mode?: AuthMode;
494
1160
  children: ReactNode;
495
1161
  }
496
1162
 
1163
+ /** Outcome of {@link validateSession}. */
1164
+ export declare interface SessionValidation {
1165
+ valid: boolean;
1166
+ /**
1167
+ * The session failed *because this account is no longer reachable* (member
1168
+ * access revoked or expired, account disabled). The login itself is still
1169
+ * good, so the user should be sent back to the account picker rather than
1170
+ * logged out. See `isAccountAccessError`.
1171
+ */
1172
+ accountAccessLost: boolean;
1173
+ /** Backend message, when it sent one. */
1174
+ message?: string;
1175
+ /** Backend error code — `A403` for the revoked/expired case. */
1176
+ code?: string;
1177
+ }
1178
+
1179
+ /** Writes the token. A falsy token clears it, so this is safe to call blindly. */
1180
+ export declare function setStoredToken(token: string, options?: TokenAccessOptions): void;
1181
+
497
1182
  /** Every section that can appear in the hash. Order is not significant. */
498
1183
  export declare const SETTINGS_SECTIONS: AccountSettingsSection[];
499
1184
 
@@ -501,6 +1186,21 @@ export declare function Signup(props: SignupProps): JSX_2.Element;
501
1186
 
502
1187
  export declare interface SignupProps extends AuthComponentBaseProps {
503
1188
  onLoginClick?: () => void;
1189
+ /**
1190
+ * Invitation token from an invite link. Sent as `inviteToken`, which lets the
1191
+ * signup through even when the project has signups disabled and creates the
1192
+ * account already verified and active (no verification email).
1193
+ *
1194
+ * `AcceptInvite` sets this for you; pass it yourself only if you're building
1195
+ * the invite screen by hand.
1196
+ */
1197
+ inviteToken?: string;
1198
+ /**
1199
+ * The invited address, from `GET /invitations/:token`. Prefills the email
1200
+ * field and makes it read-only — the server takes the address from the
1201
+ * invite record regardless of what's posted.
1202
+ */
1203
+ inviteEmail?: string;
504
1204
  /**
505
1205
  * Custom country list for the country dropdown. When provided it replaces the
506
1206
  * built-in list; each entry must be `{ code, name }`. Falls back to the
@@ -515,18 +1215,238 @@ export declare interface SignupRequest {
515
1215
  email: string;
516
1216
  password: string;
517
1217
  phoneNumber?: string;
1218
+ /** Country calling code without the `+`, e.g. "91". */
1219
+ dialCode?: string;
518
1220
  country?: string;
519
1221
  currency?: string;
520
1222
  captchaToken?: string;
1223
+ /**
1224
+ * Invitation token, when the user is signing up from an invite link. The
1225
+ * server then takes the email from the invite record and **ignores** the
1226
+ * `email` field here; signup is also allowed even when the project has
1227
+ * signups disabled, and the account is created already verified.
1228
+ */
1229
+ inviteToken?: string;
1230
+ }
1231
+
1232
+ /**
1233
+ * Renders a single auth screen, wired up for routing: sibling links navigate,
1234
+ * and a successful sign-in stores the token and leaves for `redirectTo`.
1235
+ *
1236
+ * Built for file-based routing — one tiny file per route:
1237
+ *
1238
+ * ```tsx
1239
+ * // app/login/page.tsx
1240
+ * export default () => <SsoAuthPage screen="login" projectId="…" />;
1241
+ * ```
1242
+ */
1243
+ export declare function SsoAuthPage({ screen, routeToken, ...props }: SsoAuthPageProps): JSX_2.Element;
1244
+
1245
+ export declare interface SsoAuthPageProps extends SsoScreenProps {
1246
+ /** Which screen to render. */
1247
+ screen: SsoScreen;
1248
+ /**
1249
+ * Token from the URL for the reset / verify / invite screens. Pass it when
1250
+ * your router already parsed it (Next's `params`/`searchParams`); omitted,
1251
+ * it's read from `window.location`.
1252
+ */
1253
+ routeToken?: string;
1254
+ }
1255
+
1256
+ /**
1257
+ * Mounts every auth route without needing a router: it matches
1258
+ * `window.location.pathname` itself and renders the right screen, or
1259
+ * `fallback` when the path isn't one of ours.
1260
+ *
1261
+ * ```tsx
1262
+ * <SsoAuthRoutes projectId="…" redirectTo="/dashboard" fallback={<App />} />
1263
+ * ```
1264
+ *
1265
+ * If you *do* have a router, prefer `ssoRoutes()` so the screens live inside
1266
+ * your layouts and guards.
1267
+ */
1268
+ export declare function SsoAuthRoutes({ fallback, ...props }: SsoAuthRoutesProps): JSX_2.Element;
1269
+
1270
+ export declare interface SsoAuthRoutesProps extends SsoScreenProps {
1271
+ /** Rendered when the current path isn't one of the auth routes. Default `null`. */
1272
+ fallback?: ReactNode;
1273
+ }
1274
+
1275
+ /**
1276
+ * Default navigation: a `history.pushState` plus an event so `SsoAuthRoutes`
1277
+ * re-renders.
1278
+ *
1279
+ * This is right for apps with **no** router. If you have one, pass its
1280
+ * navigate through `onNavigate` instead — react-router and friends own their
1281
+ * own history and won't notice a pushState from outside.
1282
+ */
1283
+ export declare function ssoNavigate(to: string): void;
1284
+
1285
+ export declare interface SsoRouteMatch {
1286
+ /** Which screen the path resolves to. */
1287
+ screen: SsoScreen;
1288
+ /** Token carried by the URL (reset / verify / invite links). */
1289
+ token: string;
1290
+ }
1291
+
1292
+ export declare interface SsoRouteObject {
1293
+ /** Path, prefixed with `basePath` when one is given. */
1294
+ path: string;
1295
+ /** The screen, ready to mount. */
1296
+ element: ReactNode;
1297
+ /** Which screen this is, in case you need to wrap or reorder them. */
1298
+ screen: SsoScreen;
1299
+ }
1300
+
1301
+ /**
1302
+ * The routes every app embedding this package needs.
1303
+ *
1304
+ * A library can't discover a host app's routes — react-router keeps no readable
1305
+ * registry at runtime and Next's routes are filesystem/build-time — so instead
1306
+ * of guessing, the package publishes the paths it expects and gives you two
1307
+ * ways to satisfy them: spread `ssoRoutes()` into your own router, or mount
1308
+ * `<SsoAuthRoutes />` and let the package match the path itself.
1309
+ *
1310
+ * ⚠️ Whichever you pick, **your server has to serve the app shell for these
1311
+ * paths**. If `/accept-invite` isn't rewritten to `index.html`, the user gets a
1312
+ * 404 before any JavaScript runs, and no client-side package can fix that.
1313
+ */
1314
+ export declare interface SsoRoutePaths {
1315
+ login: string;
1316
+ signup: string;
1317
+ forgotPassword: string;
1318
+ /** Target of the emailed reset link. Token read from `?token=` or a trailing segment. */
1319
+ resetPassword: string;
1320
+ /** Target of the emailed verification link, e.g. `/verify/<token>`. */
1321
+ verifyEmail: string;
1322
+ /** Target of invite links — see `inviteLinkBase` on the settings modal. */
1323
+ acceptInvite: string;
1324
+ }
1325
+
1326
+ /**
1327
+ * The auth screens as plain route objects, to spread into your own router.
1328
+ * Shaped to drop straight into react-router:
1329
+ *
1330
+ * ```tsx
1331
+ * const navigate = useNavigate();
1332
+ * createBrowserRouter([
1333
+ * ...ssoRoutes({ projectId: '…', onNavigate: navigate }),
1334
+ * ...appRoutes,
1335
+ * ]);
1336
+ * ```
1337
+ *
1338
+ * Pass `onNavigate` so the screens move through *your* router — the default
1339
+ * `pushState` won't re-render it. Token-bearing routes are registered with a
1340
+ * `:token` segment as well as the bare path, since the links arrive both ways.
1341
+ */
1342
+ export declare function ssoRoutes(options: SsoScreenProps): SsoRouteObject[];
1343
+
1344
+ export declare type SsoScreen = 'login' | 'signup' | 'forgot-password' | 'reset-password' | 'verify-email' | 'accept-invite';
1345
+
1346
+ export declare interface SsoScreenProps {
1347
+ projectId: string;
1348
+ apiBaseUrl?: string;
1349
+ /** Pre-fetched config, to skip the internal auth-config request. */
1350
+ config?: AuthConfig;
1351
+ mode?: AuthMode;
1352
+ classNames?: AuthClassNames;
1353
+ /** Custom country list for the signup screen. */
1354
+ countries?: CountryOption[];
1355
+ /** Client identifier recorded on the session when an account is chosen. */
1356
+ client?: string;
1357
+ /** Persist the issued token. Default `true`. */
1358
+ persistToken?: boolean;
1359
+ tokenStorageKey?: string;
1360
+ /**
1361
+ * Live session token, used by the accept-invite "accept" branch. Defaults to
1362
+ * the stored token, so an already-signed-in user can accept straight away.
1363
+ */
1364
+ token?: string;
1365
+ /** Where to go after a successful sign-in. Default `"/"`; a safe `?next=` wins. */
1366
+ redirectTo?: string;
1367
+ /**
1368
+ * Replaces the default post-auth behaviour (a full navigation to
1369
+ * `redirectTo`, so the host app boots with the stored token). Use it to hook
1370
+ * into your own router instead.
1371
+ */
1372
+ onAuthenticated?: (result: unknown) => void;
1373
+ onError?: (error: Error) => void;
1374
+ /** How to move between auth screens. Defaults to {@link ssoNavigate}. */
1375
+ onNavigate?: (to: string) => void;
1376
+ /** Prefix the routes are mounted under, e.g. `"/auth"`. */
1377
+ basePath?: string;
1378
+ /** Path overrides for this mount, on top of `configureSsoRoutes()`. */
1379
+ routes?: Partial<SsoRoutePaths>;
521
1380
  }
522
1381
 
523
- export declare function TwoFactorSetup({ projectId, token, apiBaseUrl, className, onEnabled, onDisabled, onError, }: TwoFactorSetupProps): JSX_2.Element;
1382
+ /**
1383
+ * POST /auth/switch-account — swaps a *live* session onto another account the
1384
+ * user belongs to, returning a fresh token. The old token stays valid until it
1385
+ * expires or is logged out, so replace whatever you stored with the new one.
1386
+ */
1387
+ export declare function switchAccountApi(projectId: string, accountId: string, token: string, apiBaseUrl?: string): Promise<string>;
1388
+
1389
+ export declare interface TeamSectionProps {
1390
+ projectId: string;
1391
+ /** Omit to use the stored session token. */
1392
+ token?: string;
1393
+ apiBaseUrl?: string;
1394
+ }
1395
+
1396
+ declare interface TokenAccessOptions {
1397
+ /** Key override for this call. */
1398
+ key?: string;
1399
+ /** Storage override for this call. */
1400
+ storage?: TokenStorageKind;
1401
+ }
1402
+
1403
+ export declare interface TokenStorageConfig {
1404
+ /** Storage key. Default `"ab-sso:accessToken"`. */
1405
+ key: string;
1406
+ /** Where the token is kept. Default `"localStorage"`. */
1407
+ storage: TokenStorageKind;
1408
+ /** Master switch for reading *and* writing. Default `true`. */
1409
+ enabled: boolean;
1410
+ }
1411
+
1412
+ /**
1413
+ * Session-token storage.
1414
+ *
1415
+ * The package persists the token itself so hosts don't have to re-implement it
1416
+ * in every app. Everything funnels through here so there is exactly one key,
1417
+ * one place that writes it, and one place that clears it.
1418
+ *
1419
+ * Design notes:
1420
+ *
1421
+ * - **One key, namespaced by default** (`ab-sso:accessToken`). A bare
1422
+ * `accessToken` collides with whatever the host app already keeps under that
1423
+ * very common name; set `key` if you need to match an existing app.
1424
+ * - **Every token source writes here** — login, verify-2fa, select-account,
1425
+ * switch-account, signup, accept-invite and the magic-link path. Missing one
1426
+ * is worse than persisting nothing: `switch-account` in particular issues a
1427
+ * *fresh* token, and a stale stored copy means the user silently keeps acting
1428
+ * as the previous account.
1429
+ * - **Storage can fail.** Private windows, disabled site data and quota errors
1430
+ * all throw on access, so every read/write is guarded and falls back to an
1431
+ * in-memory value that lasts for the page's lifetime.
1432
+ *
1433
+ * A bearer token in `localStorage` is readable by any script on the origin.
1434
+ * That is the same thing hosts were doing by hand, but it is now the default —
1435
+ * use `configureTokenStorage({ storage: 'sessionStorage' })`, or
1436
+ * `{ enabled: false }` to opt out entirely and keep handling it yourself.
1437
+ */
1438
+ export declare type TokenStorageKind = 'localStorage' | 'sessionStorage' | 'memory' | 'none';
1439
+
1440
+ export declare function TwoFactorSetup({ projectId, token: tokenProp, apiBaseUrl, className, mode, onEnabled, onDisabled, onError, }: TwoFactorSetupProps): JSX_2.Element;
524
1441
 
525
1442
  declare interface TwoFactorSetupProps {
526
1443
  projectId: string;
527
- token: string;
1444
+ /** Session token. Omit to use the one the package stored at login. */
1445
+ token?: string;
528
1446
  apiBaseUrl?: string;
529
1447
  className?: string;
1448
+ /** Colour scheme — "light" (default) or "dark". */
1449
+ mode?: AuthMode;
530
1450
  onEnabled?: () => void;
531
1451
  onDisabled?: () => void;
532
1452
  onError?: (error: Error) => void;
@@ -546,6 +1466,35 @@ export declare interface TwoFactorVerifySetupRequest {
546
1466
  secret: string;
547
1467
  }
548
1468
 
1469
+ export declare interface UnauthorizedInfo {
1470
+ /** The request that came back unauthorized. */
1471
+ url: string;
1472
+ status: number;
1473
+ message?: string;
1474
+ code?: string;
1475
+ }
1476
+
1477
+ export declare function updateMemberApi(projectId: string, memberId: string, payload: UpdateMemberPayload, token?: string, apiBaseUrl?: string): Promise<unknown>;
1478
+
1479
+ /**
1480
+ * Partial. Pass `role: null` to strip permissions and `access_expiry: null` to
1481
+ * remove an expiry — omitting a field leaves it alone, so the two cases are
1482
+ * genuinely different and the body is built from the keys actually present.
1483
+ */
1484
+ export declare interface UpdateMemberPayload {
1485
+ role?: string | null;
1486
+ access_expiry?: string | null;
1487
+ }
1488
+
1489
+ export declare function updateRoleApi(projectId: string, roleId: string, payload: UpdateRolePayload, token?: string, apiBaseUrl?: string): Promise<unknown>;
1490
+
1491
+ /** Partial — omitted fields are left alone; `permission` replaces the array wholesale. */
1492
+ export declare interface UpdateRolePayload {
1493
+ title?: string;
1494
+ description?: string;
1495
+ permission?: string[];
1496
+ }
1497
+
549
1498
  export declare function useAuthConfig(): AuthConfigContextValue;
550
1499
 
551
1500
  /** Like {@link useSession} but returns null instead of throwing when there is no provider. */
@@ -561,6 +1510,13 @@ export declare interface UserWallets {
561
1510
 
562
1511
  export declare function useSession(): SessionContextValue;
563
1512
 
1513
+ /**
1514
+ * GET /me, but reporting *why* a session was rejected instead of just a
1515
+ * boolean — `SessionProvider` needs to tell "logged out" apart from "this one
1516
+ * account went away".
1517
+ */
1518
+ export declare function validateSession(projectId: string, token: string, apiBaseUrl?: string): Promise<SessionValidation>;
1519
+
564
1520
  /**
565
1521
  * Email-verification screen for a `/verify/:token` route.
566
1522
  *