@elvix.is/sdk 0.5.6 → 0.5.8

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/react.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, CSSProperties } from 'react';
3
- import { ElvixActionResult } from './index.js';
4
- export { ElvixUser, ElvixVerifyResult } from './index.js';
3
+ import { z } from 'zod';
4
+ export { ElvixActionResult, ElvixUser, ElvixVerifyResult } from './index.js';
5
5
 
6
6
  /** Size overrides every <Elvix*> component accepts so hosts can fit it to any slot. */
7
7
  type ElvixSizeProps = {
@@ -136,6 +136,23 @@ type ElvixBootstrapEnvelope = {
136
136
  showHeader: boolean;
137
137
  transparentBg: boolean;
138
138
  signInVerb: "signin" | "login";
139
+ /**
140
+ * Per-app Google Identity Services config (One Tap / Auto-select / Popup
141
+ * / FedCM). Present on the wire; the SDK's `<ElvixSignInForm>` reads it
142
+ * into its resolved props. When any GIS flag is on AND `googleClientId`
143
+ * is present, the form swaps the static redirect anchor for Google's
144
+ * GIS-rendered personalized button.
145
+ */
146
+ googleConfig: unknown;
147
+ /**
148
+ * Public Google OAuth client id for GIS (the personalized "Continue as
149
+ * <name>" One Tap / renderButton path). In the elvix monorepo this is the
150
+ * build-time `NEXT_PUBLIC_GOOGLE_CLIENT_ID`; for the published SDK it
151
+ * arrives per-app on the bootstrap envelope. When absent, the Google
152
+ * factor degrades to the static redirect anchor (which uses elvix's
153
+ * server-side client id via `/api/auth/google/start`).
154
+ */
155
+ googleClientId?: string;
139
156
  signinGate: "public" | "private_beta" | "closed";
140
157
  archivedAt: string | null;
141
158
  /**
@@ -163,18 +180,53 @@ type ElvixSignInResultErr = {
163
180
  error: string;
164
181
  message?: string;
165
182
  };
166
- type ElvixSignInResult = ElvixSignInResultOk | ElvixSignInResultErr;
183
+ type ElvixSignInResult$1 = ElvixSignInResultOk | ElvixSignInResultErr;
167
184
  /** Theme override. Omit to inherit the Console-configured pair. */
168
185
  type ElvixTheme = "light" | "dark" | "system";
169
186
 
187
+ /**
188
+ * Per-app user envelope returned by
189
+ * `GET /api/account/apps/<clientId>/sdk-context`. The provider fetches it on
190
+ * mount alongside the public bootstrap whenever a session is present (cookie
191
+ * same-origin, bearer cross-origin). Mirrors the monorepo `ElvixAppContext`
192
+ * shape exactly so the ported `<Elvix*>` identity / account components read
193
+ * `useElvixAppContext()` and skip the `appId` / `appName` / `current` /
194
+ * `membership` props a host would otherwise thread down. `null` while loading,
195
+ * with no `clientId`, or when there's no user session (the SDK falls back to
196
+ * its empty / "sign in to see this" state).
197
+ */
198
+ type ElvixAppContext = {
199
+ user: {
200
+ id: string;
201
+ name: string | null;
202
+ email: string | null;
203
+ avatarUrl: string | null;
204
+ };
205
+ membership: {
206
+ username: string | null;
207
+ status: string;
208
+ inactiveAt: string | null;
209
+ inactivatedBy: string | null;
210
+ deletedAt: string | null;
211
+ deletedBy: string | null;
212
+ avatarSizes: number[];
213
+ avatarUpdatedAt: string;
214
+ bannerSizes: number[];
215
+ bannerUpdatedAt: string;
216
+ } | null;
217
+ };
170
218
  type ElvixContextValue = {
171
219
  clientId: string | undefined;
172
220
  baseUrl: string;
173
221
  app: ElvixBootstrapEnvelope | null;
174
222
  appError: string | null;
223
+ appContext: ElvixAppContext | null;
175
224
  resolvedTheme: "light" | "dark";
176
225
  };
177
226
  declare function useElvixApp(): ElvixBootstrapEnvelope | null;
227
+ /** Per-app signed-in user envelope (session-bound). `null` while loading,
228
+ * with no clientId, or when there's no user session. */
229
+ declare function useElvixAppContext(): ElvixAppContext | null;
178
230
  declare function useElvixContext(): ElvixContextValue;
179
231
  declare function ElvixProvider({ clientId, theme, brand, baseUrl, children, className, }: {
180
232
  clientId?: string;
@@ -204,7 +256,7 @@ declare function ElvixProvider({ clientId, theme, brand, baseUrl, children, clas
204
256
  * calls `router.push` itself.
205
257
  */
206
258
  declare function ElvixSignIn({ onResult, redirectAfterSignIn, copy: copyProp, className, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
207
- onResult?: (r: ElvixSignInResult) => void;
259
+ onResult?: (r: ElvixSignInResult$1) => void;
208
260
  /** Default redirect target on success when the server doesn't echo one. */
209
261
  redirectAfterSignIn?: string;
210
262
  /**
@@ -217,42 +269,182 @@ declare function ElvixSignIn({ onResult, redirectAfterSignIn, copy: copyProp, cl
217
269
  } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
218
270
 
219
271
  /**
220
- * `<ElvixSignInForm>` the polished, fully-styled sign-in surface a
221
- * customer drops onto their own app.
272
+ * Public ResponseDto shape the SDK surfaces to `onResult` listeners.
273
+ * Mirrors the `{ ok: true | false, ... }` envelope every elvix API
274
+ * route returns via `withErrorHandling`. Customers branch on `ok`.
275
+ */
276
+ type ElvixSignInResult = {
277
+ ok: true;
278
+ redirect?: string;
279
+ } | {
280
+ ok: false;
281
+ error: string;
282
+ message?: string;
283
+ status?: number;
284
+ };
285
+ declare const Mode: {
286
+ readonly PREVIEW: "preview";
287
+ readonly INTERACTIVE: "interactive";
288
+ };
289
+ type Mode = (typeof Mode)[keyof typeof Mode];
290
+ declare const Intent: {
291
+ readonly CONSOLE: "console";
292
+ readonly ACCOUNT: "account";
293
+ readonly APP: "app";
294
+ };
295
+ type Intent = (typeof Intent)[keyof typeof Intent];
296
+ declare const Layout: {
297
+ readonly CENTERED: "centered";
298
+ readonly LEFT: "left";
299
+ readonly BANNER: "banner";
300
+ };
301
+ type Layout = (typeof Layout)[keyof typeof Layout];
302
+ declare const SocialLayout: {
303
+ readonly STACKED: "stacked";
304
+ readonly GRID: "grid";
305
+ };
306
+ type SocialLayout = (typeof SocialLayout)[keyof typeof SocialLayout];
307
+ declare const Presentation: {
308
+ readonly CARD: "card";
309
+ readonly DRAWER: "drawer";
310
+ readonly MODAL: "modal";
311
+ };
312
+ type Presentation = (typeof Presentation)[keyof typeof Presentation];
313
+ declare const Theme: {
314
+ readonly LIGHT: "light";
315
+ readonly DARK: "dark";
316
+ readonly AUTO: "auto";
317
+ };
318
+ type Theme = (typeof Theme)[keyof typeof Theme];
319
+ declare const SignInVerb: {
320
+ readonly SIGNIN: "signin";
321
+ readonly LOGIN: "login";
322
+ };
323
+ type SignInVerb = (typeof SignInVerb)[keyof typeof SignInVerb];
324
+ /**
325
+ * One auth surface to rule them all. Same component renders:
222
326
  *
223
- * Where `<ElvixSignIn>` is the bare-bones flow (class-hooked, host paints
224
- * it), this is the finished card: rounded logo tile, "Sign in to {app}"
225
- * heading, "Continue with Google", an OR divider, the email→code OTP
226
- * flow, a legal footer, and a "Secured by elvix" badge. It ships with
227
- * **inline styles only** — no host CSS required, so it looks right the
228
- * moment it mounts on any origin.
327
+ * - The live preview inside the Console (Create app + Sign-in configure).
328
+ * mode="preview" all controls disabled, just visual.
229
329
  *
230
- * Cross-origin correct: OTP start/verify pick credentials from
231
- * `isSameOrigin(baseUrl)` exactly like `<ElvixSignIn>`; on a third-party
232
- * origin the session token comes back in the response body and is stored
233
- * via `setElvixToken`. Google is a top-level redirect.
330
+ * - The actual hosted sign-in at /sign-in/<clientId> for any customer app.
331
+ * mode="interactive" + intent="app:<clientId>" real flows.
234
332
  *
235
- * Reads enabled methods + branding from the Console-configured bootstrap
236
- * envelope (`<ElvixProvider clientId>` must be an ancestor). Renders only
237
- * the factors the Console turned on; never invents UI it denied.
333
+ * - The elvix Console's own sign-in at /sign-in/console.
334
+ * mode="interactive" + intent="console" dogfoods our own auth.
238
335
  *
239
- * `onResult({ ok, ... })` fires on success AND every failure, mirroring
240
- * `<ElvixSignIn>`. The component never navigates the host itself.
336
+ * - The account surface at /sign-in/account.
337
+ * mode="interactive" + intent="account".
338
+ *
339
+ * Sign-in = Sign-up. There's no separate signup route. If you don't exist
340
+ * yet, the first successful auth creates you.
241
341
  */
242
- type ElvixSignInFormProps = {
243
- /** Fires on every terminal outcome — success and failure — like `<ElvixSignIn>`. */
244
- onResult?: (r: ElvixSignInResult) => void;
245
- /** Default redirect target on success when the server doesn't echo one. */
246
- redirectAfterSignIn?: string;
342
+ type AuthFormProps = {
247
343
  /**
248
- * Thin per-embed copy override. The primary way to edit copy is the elvix
249
- * Console (served live in the bootstrap `strings`); this prop just lets a
250
- * single embed tweak a string or two without a Console change.
344
+ * "interactive" (default) hits real auth endpoints.
345
+ * "preview" renders the surface read-only every CTA paints but
346
+ * never makes a request. Console live-preview uses this.
251
347
  */
252
- copy?: Partial<ElvixCopy>;
253
- className?: string;
254
- } & /** Sizing applied to the card root inline style (SDK components are sizable). */ ElvixSizeProps;
255
- declare function ElvixSignInForm({ onResult, redirectAfterSignIn, copy: copyProp, className, minWidth, maxWidth, minHeight, maxHeight, width, height, }: ElvixSignInFormProps): react_jsx_runtime.JSX.Element;
348
+ mode?: Mode;
349
+ /**
350
+ * App display name. Optional when `<ElvixProvider clientId>` is
351
+ * mounted the provider fetches it from the Console-configured
352
+ * Application row. Explicit prop wins (Console passes its unsaved
353
+ * live state here).
354
+ */
355
+ appName?: string;
356
+ logoUrl?: string | null;
357
+ /** Optional dark-mode variant. Used when `theme="dark"`, otherwise we
358
+ * show the same logoUrl in both themes. */
359
+ logoUrlDark?: string | null;
360
+ /** Optional pre-rendered logo node. Wins over logoUrl + letter fallback. */
361
+ logoNode?: React.ReactNode;
362
+ brandColor?: string;
363
+ /** Foreground colour painted on top of brandColor (CTA text/icons). */
364
+ onBrandColor?: string;
365
+ methodGoogle?: boolean;
366
+ methodEmailOtp?: boolean;
367
+ methodPasskey?: boolean;
368
+ methodUsername?: boolean;
369
+ privacyPolicyUrl?: string | null;
370
+ termsOfServiceUrl?: string | null;
371
+ framed?: boolean;
372
+ /** Used in interactive mode to route auth requests. */
373
+ intent?: Intent;
374
+ /** For intent="app": the Application client_id. */
375
+ clientId?: string;
376
+ /** If set, the logo becomes a clickable link to this URL (the app's website). */
377
+ websiteUrl?: string | null;
378
+ /** Visual layout. Three variants today. */
379
+ layout?: Layout;
380
+ /** Social button arrangement: stacked rows (default) or 2-up grid. */
381
+ socialLayout?: SocialLayout;
382
+ /** Surrounding chrome — card / drawer (bottom sheet) / modal overlay. */
383
+ presentation?: Presentation;
384
+ /** Theme override for the form's surface tokens. */
385
+ theme?: Theme;
386
+ /** Hide the built-in header (logo + "Sign in to X" title + subtitle). */
387
+ showHeader?: boolean;
388
+ /** Which verb the customer wants on the CTA + heading. Some brands
389
+ * prefer "Log in" (banks, B2B legacy); SaaS defaults to "Sign in". */
390
+ signInVerb?: SignInVerb;
391
+ /** Strip card bg + border + shadow so the form blends into its host. */
392
+ transparentBg?: boolean;
393
+ /** Optional node rendered directly below the "Pick how you want to
394
+ * continue" subtitle. Used for gate-state badges ("Private beta",
395
+ * "Closed signups") so they sit inline with the form instead of
396
+ * competing as a separate surface above the card. */
397
+ belowHeading?: React.ReactNode;
398
+ /** Optional pre-rendered node injected just under the methods, on
399
+ * the way to the "Secured by elvix" chip. Used for the
400
+ * "Inform me when it goes public" + "Request access" text-links
401
+ * shown on gated hosted surfaces. */
402
+ belowMethods?: React.ReactNode;
403
+ /** Per-app Google Identity Services config. When set + `methodGoogle`
404
+ * is on + we're in interactive mode + a `googleClientId` is available,
405
+ * the ElvixSignInForm loads the GIS client lib and applies One Tap /
406
+ * Auto-select / FedCM / popup ux_mode based on each flag. Falls back to
407
+ * the plain redirect-OAuth anchor otherwise. */
408
+ googleConfig?: {
409
+ oneTap?: boolean;
410
+ autoSelect?: boolean;
411
+ popup?: boolean;
412
+ fedcm?: boolean;
413
+ hostedDomain?: string;
414
+ };
415
+ /** Public Google OAuth client id for the GIS personalized button. In the
416
+ * elvix monorepo this is the build-time `NEXT_PUBLIC_GOOGLE_CLIENT_ID`;
417
+ * the SDK reads it off the bootstrap envelope (`googleClientId`). When
418
+ * absent, the Google factor degrades to the static redirect anchor. */
419
+ googleClientId?: string;
420
+ /**
421
+ * Fires after a successful sign-in (OTP, Google, Passkey) — BEFORE
422
+ * the default redirect runs. When provided, the form will NOT
423
+ * navigate; the host owns post-auth routing. Use this to keep an
424
+ * embedded surface (Drawer/Modal/Card) in place after auth and let
425
+ * the host call `router.push()` itself.
426
+ *
427
+ * Call `GET /api/me` from the host to fetch the authenticated user.
428
+ * The v2 SDK will surface user details directly in the payload.
429
+ */
430
+ onAuthenticated?: (result: {
431
+ ok: true;
432
+ redirect?: string;
433
+ token?: string;
434
+ }) => void;
435
+ /**
436
+ * Fires on every terminal outcome: success AND every error path
437
+ * (invalid OTP, expired challenge, rate-limited, network blip,
438
+ * passkey failure). Mirrors the ResponseDto shape the rest of the
439
+ * elvix API surfaces, so the customer branches on `ok` the same
440
+ * way they would for a `/api/v1/verify` call.
441
+ *
442
+ * Both `onResult` and `onAuthenticated` may be set. `onResult` fires
443
+ * regardless; `onAuthenticated` only on success (legacy contract).
444
+ */
445
+ onResult?: (result: ElvixSignInResult) => void;
446
+ };
447
+ declare function ElvixSignInForm(props: AuthFormProps): react_jsx_runtime.JSX.Element;
256
448
 
257
449
  type ElvixSignInButtonSize = "sm" | "md" | "lg";
258
450
  type ElvixSignInButtonTheme = "light" | "dark" | "auto";
@@ -278,7 +470,7 @@ type ElvixSignInButtonProps = {
278
470
  mode?: ElvixSignInButtonMode;
279
471
  onClick?: () => void;
280
472
  /** Terminal outcome of mode="embed": success (with token) or error. */
281
- onResult?: (result: ElvixSignInResult) => void;
473
+ onResult?: (result: ElvixSignInResult$1) => void;
282
474
  } & /**
283
475
  * Dimensional sizing (width/height/min/max), additive to the `size` preset.
284
476
  * Merged last into the root element so an explicit width/height wins.
@@ -315,6 +507,18 @@ declare function ElvixSecuredBadge({ variant, size, theme, accentColor, href, cl
315
507
  declare function getElvixToken(): string | null;
316
508
  /** Store (or clear with null) the session token. Persists to localStorage. */
317
509
  declare function setElvixToken(token: string | null): void;
510
+ /**
511
+ * On the host page, pick up a session token handed back by elvix's Google
512
+ * redirect-callback in the URL fragment, store it, and strip it from the URL
513
+ * so a refresh/back-nav doesn't replay it (and it never leaks into history,
514
+ * referrers, or analytics). Returns the token it consumed, or null.
515
+ *
516
+ * Idempotent and SSR-safe: a no-op (returns null) when there's no `window` or
517
+ * no `#elvix_token=` present. `<ElvixProvider>` calls this automatically on
518
+ * mount; hosts that don't mount the provider at the redirect target can call
519
+ * it directly (it's exported from `@elvix.is/sdk/react`).
520
+ */
521
+ declare function consumeElvixReturnToken(): string | null;
318
522
 
319
523
  type UseUserListResult = {
320
524
  slugs: string[];
@@ -343,116 +547,497 @@ declare function ElvixLifecycleWatcher({ baseUrl, pollMs, onSignedOut, }: {
343
547
  onSignedOut?: (reason: string) => void;
344
548
  }): null;
345
549
 
346
- /**
347
- * `<ElvixUsername>` — claim or change the end-user's username for the
348
- * current Application. PATCH /api/account/apps/<appId>/username.
349
- * Render a single in-frame card with two panes: edit + done.
350
- */
351
- declare function ElvixUsername({ onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
352
- onResult?: (r: ElvixActionResult<{
353
- username: string;
354
- }>) => void;
355
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
550
+ type ElvixUsernameResult = {
551
+ ok: true;
552
+ username: string;
553
+ } | {
554
+ ok: false;
555
+ error: string;
556
+ message?: string;
557
+ };
558
+ declare function ElvixUsername(props: ElvixUsernameProps): react_jsx_runtime.JSX.Element;
559
+ type ElvixUsernameProps = {
560
+ appId?: string;
561
+ appName?: string;
562
+ current?: string | null;
563
+ methodUsername?: boolean;
564
+ supportUrl?: string | null;
565
+ supportEmail?: string | null;
566
+ onSuccess?: (value: string) => void;
567
+ onFail?: (error: string) => void;
568
+ onResult?: (result: ElvixUsernameResult) => void;
569
+ };
356
570
 
357
- /**
358
- * `<ElvixAvatar>` — upload / replace the end-user's avatar for this
359
- * Application. Reads file → base64 → PATCH /api/account/apps/<appId>/avatar.
360
- */
361
- declare function ElvixAvatar({ onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
362
- onResult?: (r: ElvixActionResult<{
363
- avatarUrl: string;
364
- }>) => void;
365
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
571
+ declare const Shape: {
572
+ readonly CIRCLE: "circle";
573
+ readonly SQUARE: "square";
574
+ };
575
+ type Shape = (typeof Shape)[keyof typeof Shape];
576
+ type UserAvatarProps = {
577
+ /** App slug — Application.urlSlug. */
578
+ appSlug: string;
579
+ userId: string;
580
+ membership: {
581
+ avatarUpdatedAt: Date | number;
582
+ avatarSizes: number[];
583
+ };
584
+ user: {
585
+ name?: string | null;
586
+ email?: string | null;
587
+ avatarUrl?: string | null;
588
+ };
589
+ /** Pixel display size (1× CSS px). srcset handles retina automatically. */
590
+ size?: number;
591
+ className?: string;
592
+ /** Round vs square. Default rounded-full. */
593
+ shape?: Shape;
594
+ };
366
595
 
367
- /**
368
- * `<ElvixBanner>` — upload / replace the end-user's profile banner
369
- * (16:9 cover image) for this Application.
370
- */
371
- declare function ElvixBanner({ onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
372
- onResult?: (r: ElvixActionResult<{
373
- bannerUrl: string;
374
- }>) => void;
375
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
596
+ type ElvixAvatarResult = {
597
+ ok: true;
598
+ sizes: number[];
599
+ updatedAt: string;
600
+ } | {
601
+ ok: false;
602
+ error: string;
603
+ message?: string;
604
+ };
605
+ type ElvixAvatarProps = Omit<UserAvatarProps, "size"> & {
606
+ applicationId: string;
607
+ /** Diameter (px). Default 128. The widget stays at this size in
608
+ * every state — no expand-on-edit. */
609
+ size?: number;
610
+ /** Fired after a successful upload / remove. */
611
+ onChange?: (next: {
612
+ sizes: number[];
613
+ updatedAt: Date | number;
614
+ }) => void;
615
+ /** Fires on every terminal upload / remove outcome. Safe payload:
616
+ * rendered avatar sizes + updatedAt only (no image bytes). */
617
+ onResult?: (result: ElvixAvatarResult) => void;
618
+ };
619
+ declare function ElvixAvatar(props: Partial<ElvixAvatarProps>): react_jsx_runtime.JSX.Element;
376
620
 
377
- /**
378
- * `<ElvixIdentityForm>` — edit the end-user's display name + bio for
379
- * the current Application. Lightweight per-app profile fields.
380
- */
381
- declare function ElvixIdentityForm({ initialName, initialBio, onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
382
- initialName?: string;
383
- initialBio?: string;
384
- onResult?: (r: ElvixActionResult<{
385
- name: string;
386
- bio: string;
387
- }>) => void;
388
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
621
+ type UserBannerProps = {
622
+ appSlug: string;
623
+ userId: string;
624
+ membership: {
625
+ bannerUpdatedAt: Date | number;
626
+ bannerSizes: number[];
627
+ };
628
+ /** Container max-width in CSS px. Drives `sizes` for srcset. */
629
+ containerPx?: number;
630
+ className?: string;
631
+ /** Class for the empty placeholder background (gradient by default). */
632
+ emptyClassName?: string;
633
+ };
389
634
 
390
- /**
391
- * `<ElvixRegion>` — set the end-user's region (ISO 3166-1 alpha-2
392
- * country code + timezone). Used by elvix for data-residency hints
393
- * and locale defaults.
394
- */
395
- declare function ElvixRegion({ initialCountry, initialTimezone, onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
396
- initialCountry?: string;
397
- initialTimezone?: string;
398
- onResult?: (r: ElvixActionResult<{
399
- country: string;
400
- timezone: string;
401
- }>) => void;
402
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
635
+ type ElvixBannerResult = {
636
+ ok: true;
637
+ sizes: number[];
638
+ updatedAt: string;
639
+ } | {
640
+ ok: false;
641
+ error: string;
642
+ message?: string;
643
+ };
644
+ type ElvixBannerProps = UserBannerProps & {
645
+ applicationId: string;
646
+ /** Corner radius for the frame. Default 14 (matches the SDK card chrome). */
647
+ cornerRadius?: number;
648
+ /** Fired after a successful upload / remove. */
649
+ onChange?: (next: {
650
+ sizes: number[];
651
+ updatedAt: Date | number;
652
+ }) => void;
653
+ /** Fires on every terminal upload / remove outcome. Safe payload:
654
+ * rendered banner sizes + updatedAt only (no image bytes). */
655
+ onResult?: (result: ElvixBannerResult) => void;
656
+ };
657
+ declare function ElvixBanner(props: Partial<ElvixBannerProps>): react_jsx_runtime.JSX.Element;
403
658
 
404
- /**
405
- * `<ElvixLanguages>` — set the end-user's preferred languages (BCP-47
406
- * tag list, ordered by preference). The first entry drives UI locale.
407
- */
408
- declare function ElvixLanguages({ initial, onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
409
- initial?: string[];
410
- onResult?: (r: ElvixActionResult<{
411
- languages: string[];
412
- }>) => void;
413
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
659
+ declare const identitySchema: z.ZodObject<{
660
+ givenName: z.ZodString;
661
+ familyName: z.ZodString;
662
+ birthdate: z.ZodString;
663
+ gender: z.ZodEnum<{
664
+ male: "male";
665
+ female: "female";
666
+ non_binary: "non_binary";
667
+ prefer_not_to_say: "prefer_not_to_say";
668
+ }>;
669
+ pronouns: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
670
+ other: "other";
671
+ prefer_not_to_say: "prefer_not_to_say";
672
+ she_her: "she_her";
673
+ he_him: "he_him";
674
+ they_them: "they_them";
675
+ }>>>;
676
+ }, z.core.$strip>;
677
+ type IdentityInput = z.infer<typeof identitySchema>;
414
678
 
415
- declare function ElvixSessions({ onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
416
- onResult?: (r: ElvixActionResult<{
417
- revoked: number;
418
- }>) => void;
419
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
679
+ type ElvixIdentityFormResult = {
680
+ ok: true;
681
+ } | {
682
+ ok: false;
683
+ error: string;
684
+ message?: string;
685
+ };
686
+ declare function ElvixIdentityForm({ initial, onResult, }: {
687
+ /**
688
+ * Pre-loaded identity fields. Optional — when omitted, the SDK
689
+ * fetches `/api/account/profile/identity` on mount so the
690
+ * customer doesn't have to thread server-side state in.
691
+ */
692
+ initial?: Partial<IdentityInput>;
693
+ /** Fires on every terminal save outcome. Safe payload: no PII —
694
+ * identity edits are saved, not echoed back to the host. */
695
+ onResult?: (result: ElvixIdentityFormResult) => void;
696
+ }): react_jsx_runtime.JSX.Element;
420
697
 
421
- /**
422
- * `<ElvixExport>` — GDPR Art. 15 data-export request. Triggers an
423
- * async server-side zip + emails a single-use download link to the
424
- * end-user's bound email address.
425
- */
426
- declare function ElvixExport({ onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
427
- onResult?: (r: ElvixActionResult<{
428
- requestId: string;
429
- }>) => void;
430
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
698
+ type RegionRecord = {
699
+ id: string;
700
+ country: string;
701
+ uiLocale: string | null;
702
+ timeZone: string | null;
703
+ firstDayOfWeek: number;
704
+ timeFormat: string;
705
+ dateFormat: string;
706
+ numberFormat: string;
707
+ currency: string | null;
708
+ measurementSystem: string;
709
+ createdAt: string;
710
+ updatedAt: string;
711
+ };
431
712
 
432
- declare function ElvixDeactivate({ onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
433
- onResult?: (r: ElvixActionResult) => void;
434
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
713
+ type ElvixRegionResult = {
714
+ ok: true;
715
+ country: string;
716
+ locale: string;
717
+ } | {
718
+ ok: false;
719
+ error: string;
720
+ message?: string;
721
+ };
722
+ type ElvixRegionProps = {
723
+ height?: number;
724
+ minHeight?: number;
725
+ maxHeight?: number;
726
+ width?: number | string;
727
+ onChange?: (region: RegionRecord | null) => void;
728
+ /** Fires on every terminal save outcome. Safe payload: country +
729
+ * locale code only. `onChange` keeps firing too on every refresh. */
730
+ onResult?: (result: ElvixRegionResult) => void;
731
+ };
732
+ declare function ElvixRegion({ height, minHeight, maxHeight, width, onChange, onResult, }: ElvixRegionProps): react_jsx_runtime.JSX.Element;
435
733
 
436
- declare function ElvixLeave({ onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
437
- onResult?: (r: ElvixActionResult) => void;
438
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
734
+ declare const languageSchema: z.ZodObject<{
735
+ code: z.ZodString;
736
+ level: z.ZodEnum<{
737
+ ELEMENTARY: "ELEMENTARY";
738
+ INTERMEDIATE: "INTERMEDIATE";
739
+ PROFICIENT: "PROFICIENT";
740
+ NATIVE: "NATIVE";
741
+ }>;
742
+ }, z.core.$strip>;
743
+ type LanguageInput = z.infer<typeof languageSchema>;
744
+ type LanguageRecord = LanguageInput & {
745
+ id: string;
746
+ createdAt: string;
747
+ updatedAt: string;
748
+ };
749
+
750
+ type ElvixLanguagesResult = {
751
+ ok: true;
752
+ count: number;
753
+ } | {
754
+ ok: false;
755
+ error: string;
756
+ message?: string;
757
+ };
758
+ type ElvixLanguagesProps = {
759
+ height?: number;
760
+ minHeight?: number;
761
+ maxHeight?: number;
762
+ width?: number | string;
763
+ onChange?: (languages: LanguageRecord[]) => void;
764
+ /** Fires on every terminal save outcome. Safe payload: count only. */
765
+ onResult?: (result: ElvixLanguagesResult) => void;
766
+ };
767
+ declare function ElvixLanguages({ height, minHeight, maxHeight, width, onChange, onResult, }: ElvixLanguagesProps): react_jsx_runtime.JSX.Element;
768
+
769
+ declare const ElvixSessionsAction: {
770
+ readonly REVOKE_ONE: "revoke_one";
771
+ readonly SIGN_OUT_OTHERS: "sign_out_others";
772
+ readonly SIGN_OUT_ALL: "sign_out_all";
773
+ };
774
+ type ElvixSessionsAction = (typeof ElvixSessionsAction)[keyof typeof ElvixSessionsAction];
775
+ type ElvixSessionsResult = {
776
+ ok: true;
777
+ action: ElvixSessionsAction;
778
+ ended?: number;
779
+ } | {
780
+ ok: false;
781
+ error: string;
782
+ message?: string;
783
+ };
784
+ declare function ElvixSessions({ appId, signInUrl, onChanged, onResult, }: {
785
+ /** When set, scopes the list to one customer app. When undefined,
786
+ * lists `surface="account"` sessions. */
787
+ appId?: string;
788
+ /** Where to send the user after a "sign out everywhere too"
789
+ * action. Defaults to elvix's account sign-in. */
790
+ signInUrl?: string;
791
+ onChanged?: () => void;
792
+ /** Fires on every terminal revoke outcome. Safe payload: action
793
+ * kind + count of ended sessions. No session IDs leak to the host. */
794
+ onResult?: (result: ElvixSessionsResult) => void;
795
+ }): react_jsx_runtime.JSX.Element;
796
+
797
+ type ExportTarget = {
798
+ kind: "identity";
799
+ } | {
800
+ kind: "app";
801
+ appId: string;
802
+ appName: string;
803
+ };
804
+ type ElvixExportResult = {
805
+ ok: true;
806
+ downloadId: string;
807
+ deliveredTo: string;
808
+ } | {
809
+ ok: false;
810
+ error: string;
811
+ message?: string;
812
+ };
813
+ declare function ElvixExport({ target, primaryEmail, onSuccess, onFail, onResult, }: {
814
+ /** Scope: identity-level export, or per-app export. Defaults to
815
+ * identity — the most common surface. */
816
+ target?: ExportTarget;
817
+ /** Address the export zip is delivered to. Optional — when
818
+ * omitted, the SDK reads it from the signed-in user's session
819
+ * via `useElvixAppContext().user.email`. */
820
+ primaryEmail?: string;
821
+ onSuccess?: (downloadId: string) => void;
822
+ onFail?: (error: string) => void;
823
+ /** Fires on every terminal export outcome. Safe payload: the
824
+ * single-use downloadId (only redeemable with the OTP-verified
825
+ * session) + the email address the zip was sent to. */
826
+ onResult?: (result: ElvixExportResult) => void;
827
+ }): react_jsx_runtime.JSX.Element;
828
+
829
+ declare const State$1: {
830
+ readonly INACTIVE: "inactive";
831
+ readonly ACTIVE: "active";
832
+ };
833
+ type State$1 = (typeof State$1)[keyof typeof State$1];
834
+ type ElvixDeactivateResult = {
835
+ ok: true;
836
+ state: State$1;
837
+ } | {
838
+ ok: false;
839
+ error: string;
840
+ message?: string;
841
+ };
842
+ declare function ElvixDeactivate(props: {
843
+ appId?: string;
844
+ appName?: string;
845
+ inactive?: boolean;
846
+ inactivatedBy?: string | null;
847
+ onSuccess?: (state: State$1) => void;
848
+ onFail?: (error: string) => void;
849
+ onResult?: (result: ElvixDeactivateResult) => void;
850
+ }): react_jsx_runtime.JSX.Element;
851
+
852
+ declare const State: {
853
+ readonly LEFT: "left";
854
+ readonly RESTORED: "restored";
855
+ };
856
+ type State = (typeof State)[keyof typeof State];
857
+ type ElvixLeaveResult = {
858
+ ok: true;
859
+ state: State;
860
+ } | {
861
+ ok: false;
862
+ error: string;
863
+ message?: string;
864
+ };
865
+ declare function ElvixLeave(props: {
866
+ appId?: string;
867
+ appName?: string;
868
+ deletedAt?: string | null;
869
+ deletedBy?: string | null;
870
+ privacyPolicyUrl?: string | null;
871
+ termsOfServiceUrl?: string | null;
872
+ onSuccess?: (state: State) => void;
873
+ onFail?: (error: string) => void;
874
+ onResult?: (result: ElvixLeaveResult) => void;
875
+ }): react_jsx_runtime.JSX.Element;
439
876
 
440
877
  /**
441
- * `<ElvixAddressBook>` list / add / remove the end-user's addresses
442
- * on this Application. Read uses GET /api/account/apps/<appId>/addresses;
443
- * mutations POST + DELETE on the same path.
878
+ * Address schema for the elvix Profile SDK.
879
+ *
880
+ * Two flavours mirror the basic-info pattern:
881
+ *
882
+ * `addressSchema` — STRICT. SDK form enforces it client-side
883
+ * before submit.
884
+ * `addressPatchSchema` — LOOSE. Server-side accepts partial
885
+ * updates (single field PATCHs from admin
886
+ * tools, Google Places merges, etc.).
887
+ *
888
+ * Field shape mirrors DC EventAddress: country has both ISO code and
889
+ * human name; region has both code (ISO-3166-2) and name; coords are
890
+ * stored alongside Google Places provenance for shipping-zone /
891
+ * delivery-map use without re-geocoding.
444
892
  */
445
- declare function ElvixAddressBook({ onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
446
- onResult?: (r: ElvixActionResult) => void;
447
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
893
+ declare const ADDRESS_KINDS: readonly ["billing", "shipping"];
894
+ type AddressKind = (typeof ADDRESS_KINDS)[number];
895
+ declare const addressSchema: z.ZodObject<{
896
+ kind: z.ZodEnum<{
897
+ billing: "billing";
898
+ shipping: "shipping";
899
+ }>;
900
+ label: z.ZodNullable<z.ZodOptional<z.ZodString>>;
901
+ isDefault: z.ZodOptional<z.ZodBoolean>;
902
+ recipientName: z.ZodString;
903
+ companyName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
904
+ line1: z.ZodString;
905
+ line2: z.ZodNullable<z.ZodOptional<z.ZodString>>;
906
+ city: z.ZodString;
907
+ regionName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
908
+ regionCode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
909
+ postalCode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
910
+ country: z.ZodString;
911
+ countryName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
912
+ deliveryNotes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
913
+ timezone: z.ZodNullable<z.ZodOptional<z.ZodString>>;
914
+ venueName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
915
+ placeId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
916
+ formattedAddress: z.ZodNullable<z.ZodOptional<z.ZodString>>;
917
+ latitude: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
918
+ longitude: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
919
+ }, z.core.$strip>;
920
+ type AddressInput = z.infer<typeof addressSchema>;
921
+ /** Server response shape — adds id + audit fields. */
922
+ type AddressRecord = AddressInput & {
923
+ id: string;
924
+ createdAt: string;
925
+ updatedAt: string;
926
+ };
927
+
928
+ type ElvixAddressBookResult = {
929
+ ok: true;
930
+ count: number;
931
+ } | {
932
+ ok: false;
933
+ error: string;
934
+ message?: string;
935
+ };
936
+ type ElvixAddressBookProps = {
937
+ kind: AddressKind;
938
+ /** Fixed frame height. Defaults to 520. Takes precedence over min/max. */
939
+ height?: number;
940
+ /** Bottom bound when `height` is unset. */
941
+ minHeight?: number;
942
+ /** Top bound when `height` is unset. */
943
+ maxHeight?: number;
944
+ /** Frame width. Defaults to "100%" so it fills whatever container
945
+ * the host puts it in. Pass a number for a fixed pixel width. */
946
+ width?: number | string;
947
+ /**
948
+ * Signed-in user's display name. Powers the "Me" card on the
949
+ * recipient step so the user can pick their own name with one
950
+ * click. Falls back to email or "You" if the host doesn't provide.
951
+ */
952
+ userDisplayName?: string | null;
953
+ /** Optional callback fired after a successful save / delete. */
954
+ onChange?: (addresses: AddressRecord[]) => void;
955
+ /** Fires on every terminal save / delete outcome. Safe payload:
956
+ * count only — never the address rows themselves. */
957
+ onResult?: (result: ElvixAddressBookResult) => void;
958
+ };
959
+ declare function ElvixAddressBook({ kind, height, minHeight, maxHeight, width, userDisplayName, onChange, onResult, }: ElvixAddressBookProps): react_jsx_runtime.JSX.Element;
448
960
 
449
961
  /**
450
- * `<ElvixLegalEntities>` list / add / remove the end-user's legal
451
- * entities (company names + tax IDs) on this Application. Useful for
452
- * B2B apps that bill at the entity level.
962
+ * Strict schema layered atop the loose shape. The `superRefine` adds
963
+ * the per-type required-field gates the wizard enforces at commit
964
+ * time but server-PATCH endpoints don't want.
453
965
  */
454
- declare function ElvixLegalEntities({ onResult, width, height, minWidth, maxWidth, minHeight, maxHeight, }: {
455
- onResult?: (r: ElvixActionResult) => void;
456
- } & ElvixSizeProps): react_jsx_runtime.JSX.Element;
966
+ declare const legalEntitySchema: z.ZodObject<{
967
+ type: z.ZodEnum<{
968
+ company: "company";
969
+ individual: "individual";
970
+ sole_prop: "sole_prop";
971
+ }>;
972
+ label: z.ZodNullable<z.ZodOptional<z.ZodString>>;
973
+ isDefault: z.ZodOptional<z.ZodBoolean>;
974
+ legalName: z.ZodString;
975
+ tradingName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
976
+ dateOfBirth: z.ZodNullable<z.ZodOptional<z.ZodString>>;
977
+ placeOfBirth: z.ZodNullable<z.ZodOptional<z.ZodString>>;
978
+ placeOfBirthPlaceId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
979
+ nationality: z.ZodNullable<z.ZodOptional<z.ZodString>>;
980
+ taxCountry: z.ZodString;
981
+ taxId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
982
+ vatId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
983
+ vatIdValidation: z.ZodOptional<z.ZodEnum<{
984
+ none: "none";
985
+ format: "format";
986
+ invalid: "invalid";
987
+ live: "live";
988
+ }>>;
989
+ vatIdValidatedAt: z.ZodNullable<z.ZodOptional<z.ZodString>>;
990
+ vatIdValidatedName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
991
+ registrationNumber: z.ZodNullable<z.ZodOptional<z.ZodString>>;
992
+ registrationBody: z.ZodNullable<z.ZodOptional<z.ZodString>>;
993
+ registeredSince: z.ZodNullable<z.ZodOptional<z.ZodString>>;
994
+ contactEmail: z.ZodNullable<z.ZodOptional<z.ZodString>>;
995
+ contactPhone: z.ZodNullable<z.ZodOptional<z.ZodString>>;
996
+ addressLine1: z.ZodNullable<z.ZodOptional<z.ZodString>>;
997
+ addressLine2: z.ZodNullable<z.ZodOptional<z.ZodString>>;
998
+ addressCity: z.ZodNullable<z.ZodOptional<z.ZodString>>;
999
+ addressRegionName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
1000
+ addressRegionCode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
1001
+ addressPostalCode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
1002
+ addressCountry: z.ZodNullable<z.ZodOptional<z.ZodString>>;
1003
+ addressCountryName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
1004
+ addressFormatted: z.ZodNullable<z.ZodOptional<z.ZodString>>;
1005
+ addressPlaceId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
1006
+ addressTimezone: z.ZodNullable<z.ZodOptional<z.ZodString>>;
1007
+ addressLatitude: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
1008
+ addressLongitude: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
1009
+ }, z.core.$strip>;
1010
+ type LegalEntityInput = z.infer<typeof legalEntitySchema>;
1011
+ /** Server-emitted record. Adds audit fields, normalises dates to ISO. */
1012
+ type LegalEntityRecord = Omit<LegalEntityInput, "dateOfBirth" | "registeredSince"> & {
1013
+ id: string;
1014
+ dateOfBirth: string | null;
1015
+ registeredSince: string | null;
1016
+ createdAt: string;
1017
+ updatedAt: string;
1018
+ };
1019
+
1020
+ type ElvixLegalEntitiesResult = {
1021
+ ok: true;
1022
+ count: number;
1023
+ } | {
1024
+ ok: false;
1025
+ error: string;
1026
+ message?: string;
1027
+ };
1028
+ type ElvixLegalEntitiesProps = {
1029
+ /** Fixed frame height. Defaults to 580. */
1030
+ height?: number;
1031
+ minHeight?: number;
1032
+ maxHeight?: number;
1033
+ /** Frame width. Defaults to "100%". */
1034
+ width?: number | string;
1035
+ /** Optional callback fired after a successful save / delete. */
1036
+ onChange?: (entities: LegalEntityRecord[]) => void;
1037
+ /** Fires on every terminal save / delete outcome. Safe payload:
1038
+ * count only — never the entity rows themselves. */
1039
+ onResult?: (result: ElvixLegalEntitiesResult) => void;
1040
+ };
1041
+ declare function ElvixLegalEntities({ height, minHeight, maxHeight, width, onChange, onResult, }: ElvixLegalEntitiesProps): react_jsx_runtime.JSX.Element;
457
1042
 
458
- export { DEFAULT_COPY, ElvixActionResult, ElvixAddressBook, ElvixAvatar, ElvixBanner, type ElvixBootstrapEnvelope, type ElvixBrand, ElvixCard, type ElvixCopy, ElvixDeactivate, ElvixExport, ElvixIdentityForm, ElvixLanguages, ElvixLeave, ElvixLegalEntities, ElvixLifecycleWatcher, ElvixProvider, ElvixRegion, ElvixSecuredBadge, ElvixSessions, ElvixSignIn, ElvixSignInButton, ElvixSignInForm, type ElvixSignInMethod, type ElvixSignInResult, type ElvixSignInResultErr, type ElvixSignInResultOk, type ElvixSizeProps, type ElvixTheme, ElvixUsername, type UseUserListResult, getElvixToken, setElvixToken, useElvixApp, useElvixContext, useUserMemberships, useUserRoles, useUserScopes };
1043
+ export { DEFAULT_COPY, ElvixAddressBook, type ElvixAppContext, ElvixAvatar, ElvixBanner, type ElvixBootstrapEnvelope, type ElvixBrand, ElvixCard, type ElvixCopy, ElvixDeactivate, ElvixExport, ElvixIdentityForm, ElvixLanguages, ElvixLeave, ElvixLegalEntities, ElvixLifecycleWatcher, ElvixProvider, ElvixRegion, ElvixSecuredBadge, ElvixSessions, ElvixSignIn, ElvixSignInButton, ElvixSignInForm, type ElvixSignInMethod, type ElvixSignInResult$1 as ElvixSignInResult, type ElvixSignInResultErr, type ElvixSignInResultOk, type ElvixSizeProps, type ElvixTheme, ElvixUsername, type UseUserListResult, consumeElvixReturnToken, getElvixToken, setElvixToken, useElvixApp, useElvixAppContext, useElvixContext, useUserMemberships, useUserRoles, useUserScopes };