@authowl/react-native 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,654 @@
1
+ import { PublicConfig, NativeAuthClient, NativePasskeyCapableClient, PasskeyCeremonyClientFactory, NativeSocialSignInOptions, AuthActionResult, SocialAuthData, AuthUser, AuthSession, HasParams, SessionState, Organization, PasskeyRegistrationResponse, PasskeyAuthenticationResponse } from '@authowl/core/native';
2
+ export { AuthSession, AuthUser, HasParams, NativeAuthClient, NativeSocialSignInOptions, OrganizationMembership, SessionState, NativeSocialSignInOptions as SocialIdTokenSignInOptions, sessionCookieName } from '@authowl/core/native';
3
+ import * as react from 'react';
4
+ import { ReactNode } from 'react';
5
+ import { Locale, ServerErrorInput, MessageKey, MessageParams } from '@authowl/core/i18n';
6
+ export { Locale, MessageKey, MessageParams } from '@authowl/core/i18n';
7
+
8
+ /**
9
+ * Where a native app keeps its session.
10
+ *
11
+ * The session cookie is a bearer credential: anything holding it IS the signed-in
12
+ * user until it expires. On a phone that means the OS keychain / keystore, not
13
+ * AsyncStorage, which is plain unencrypted files any process with the sandbox
14
+ * can read. `@authowl/expo` supplies an `expo-secure-store` adapter; bare React
15
+ * Native apps typically use `react-native-keychain`.
16
+ */
17
+ interface SecureStorage {
18
+ getItem(key: string): Promise<string | null>;
19
+ setItem(key: string, value: string): Promise<void>;
20
+ removeItem(key: string): Promise<void>;
21
+ }
22
+ /**
23
+ * An in-memory store, for tests and for previews where persistence is unwanted.
24
+ *
25
+ * Explicitly NOT a default: silently falling back to memory would make sign-in
26
+ * appear to work and then drop the session on the next app launch, which is a
27
+ * confusing bug to chase. Callers must choose their storage.
28
+ */
29
+ declare class MemoryStorage implements SecureStorage {
30
+ private readonly entries;
31
+ getItem(key: string): Promise<string | null>;
32
+ setItem(key: string, value: string): Promise<void>;
33
+ removeItem(key: string): Promise<void>;
34
+ }
35
+
36
+ /** Building the AuthOwl client for a native app. */
37
+
38
+ interface AuthOwlNativeConfig {
39
+ /** The project's `pk_live_…` / `pk_test_…` key. Secret keys are refused. */
40
+ publishableKey: string;
41
+ /** The AuthOwl API origin, e.g. `https://api.authowl.dev`. */
42
+ apiUrl: string;
43
+ /** Where the session cookie is persisted. Use the OS keychain in production. */
44
+ storage: SecureStorage;
45
+ /** Defaults to the global fetch. Injectable for tests. */
46
+ fetchImpl?: typeof fetch;
47
+ /** Called after any action that mutates the session. */
48
+ onSessionMutation?: () => void;
49
+ /**
50
+ * Platform passkey ceremony, from `createNativePasskeys()`.
51
+ *
52
+ * Omit it and the passkey methods are absent from the client's TYPE, so an
53
+ * app cannot call a prompt the runtime could never show.
54
+ */
55
+ passkeys?: PasskeyCeremonyClientFactory;
56
+ }
57
+ interface AuthOwlNativeConfigWithPasskeys extends AuthOwlNativeConfig {
58
+ passkeys: PasskeyCeremonyClientFactory;
59
+ }
60
+ interface AuthOwlNativeBase {
61
+ projectId: string;
62
+ getPublicConfig: () => Promise<PublicConfig>;
63
+ }
64
+ interface AuthOwlNative extends AuthOwlNativeBase {
65
+ client: NativeAuthClient | NativePasskeyCapableClient;
66
+ }
67
+ interface AuthOwlPasskeyNative extends AuthOwlNativeBase {
68
+ client: NativePasskeyCapableClient;
69
+ }
70
+ interface AuthOwlHeadlessNative extends AuthOwlNativeBase {
71
+ client: NativeAuthClient;
72
+ }
73
+ /**
74
+ * Build a native AuthOwl client with session persistence wired up.
75
+ *
76
+ * The publishable key is decoded up front so a `sk_` key fails HERE, loudly, at
77
+ * startup - rather than being shipped inside an app binary where it cannot be
78
+ * rotated out of users' hands.
79
+ */
80
+ declare function createAuthOwlNative(config: AuthOwlNativeConfigWithPasskeys): AuthOwlPasskeyNative;
81
+ declare function createAuthOwlNative(config: AuthOwlNativeConfig & {
82
+ passkeys?: undefined;
83
+ }): AuthOwlHeadlessNative;
84
+ declare function createAuthOwlNative(config: AuthOwlNativeConfig): AuthOwlNative;
85
+
86
+ /**
87
+ * A one-cookie jar backed by secure storage.
88
+ *
89
+ * Why this exists: the AuthOwl server authenticates with a session COOKIE, and
90
+ * the browser SDK simply lets the browser's cookie jar do the work. React Native
91
+ * has no dependable equivalent - its `fetch` cookie behaviour differs between
92
+ * iOS and Android, is invisible to JS, and does not reliably survive an app
93
+ * restart or update. So the native SDK keeps the one cookie it cares about
94
+ * itself: replay it on every request, and re-capture it whenever the server
95
+ * rotates it.
96
+ *
97
+ * This talks to the server exactly as the browser does, so no server-side
98
+ * "native mode" is required.
99
+ */
100
+
101
+ interface CookieJarOptions {
102
+ /** Where the session cookie is persisted. */
103
+ storage: SecureStorage;
104
+ /** The project id, used to derive the exact cookie name the server sets. */
105
+ projectId: string;
106
+ /**
107
+ * Whether the server issues `__Secure-` cookies. Derive it from the API URL's
108
+ * scheme (`https:` => true) - it must match the SERVER, not the client.
109
+ */
110
+ secure: boolean;
111
+ /** Defaults to the global fetch. Injectable for tests. */
112
+ fetchImpl?: typeof fetch;
113
+ }
114
+ /** The storage key under which the raw cookie value is kept. */
115
+ declare function sessionStorageKey(projectId: string): string;
116
+ /**
117
+ * Parse the cookie value the server set for `name`, if this response sets it.
118
+ *
119
+ * Deliberately hand-rolled and narrow: it looks for ONE cookie by exact name and
120
+ * ignores every attribute (`Path`, `HttpOnly`, `SameSite`, …). A general cookie
121
+ * jar would have to model domains and paths, which is a large amount of surface
122
+ * for a client that only ever talks to one origin.
123
+ *
124
+ * Returns `null` when the response does not set the cookie, and the empty string
125
+ * when the server clears it (sign-out), which the caller treats as a deletion.
126
+ */
127
+ declare function readSetCookie(header: readonly string[] | string | null, name: string): string | null;
128
+ /**
129
+ * Wrap `fetch` so the session cookie is replayed from, and captured into,
130
+ * secure storage.
131
+ */
132
+ declare function createCookieJarFetch(options: CookieJarOptions): typeof fetch;
133
+
134
+ /** Native social sign-in through a provider-issued ID token. */
135
+
136
+ /**
137
+ * Exchange an ID token obtained from a provider's native SDK for an AuthOwl
138
+ * session. The cookie jar captures the session cookie from this same response,
139
+ * so no browser-cookie bridge or deep-link credential is required.
140
+ */
141
+ declare function signInWithSocialIdToken(client: NativeAuthClient, options: NativeSocialSignInOptions): Promise<AuthActionResult<SocialAuthData>>;
142
+
143
+ /** React context and hooks for a native AuthOwl app. */
144
+
145
+ type PublicConfigState = 'loading' | 'ready' | 'error';
146
+ interface AuthOwlProviderProps extends AuthOwlNativeConfig {
147
+ children?: ReactNode;
148
+ /**
149
+ * Locale for the built-in components. Defaults to English.
150
+ *
151
+ * Not auto-detected from the device: a phone set to Arabic does not imply the
152
+ * app is localized to Arabic, and silently switching the auth screens away
153
+ * from the rest of the app is worse than defaulting. Pass the locale the app
154
+ * has already resolved.
155
+ */
156
+ locale?: Locale;
157
+ }
158
+ /** Provides the AuthOwl client to a native React tree. */
159
+ declare function AuthOwlProvider(props: AuthOwlProviderProps): ReactNode;
160
+ /** The locale the provider resolved, for the built-in components. */
161
+ declare function useAuthOwlLocale(): Locale;
162
+ /** Native-safe sign-in, account, organization, and passkey-management actions. */
163
+ declare function useAuthOwlClient(): NativeAuthClient | NativePasskeyCapableClient;
164
+ /** Project capabilities and legal policy used by the built-in components. */
165
+ declare function usePublicConfig(): {
166
+ data: PublicConfig | null;
167
+ state: PublicConfigState;
168
+ isLoading: boolean;
169
+ };
170
+ /** The live session state, re-rendering whenever the session changes. */
171
+ declare function useSession(): SessionState;
172
+ interface UseAuthResult {
173
+ isLoaded: boolean;
174
+ isSignedIn: boolean;
175
+ user: AuthUser | null;
176
+ session: AuthSession | null;
177
+ signOut: () => Promise<void>;
178
+ /**
179
+ * Advisory permission check over the CURRENT session claim.
180
+ *
181
+ * Advisory only: this is for hiding UI the user cannot use. The real boundary
182
+ * is server-side, over a verified token - never gate anything that matters on
183
+ * a client-side answer.
184
+ */
185
+ has: (params: HasParams) => boolean;
186
+ hasPermission: (params: {
187
+ permission: string;
188
+ }) => boolean;
189
+ }
190
+ /** The primary hook: who is signed in, and what may they do. */
191
+ declare function useAuth(): UseAuthResult;
192
+ /** The signed-in user, or null. */
193
+ declare function useUser(): AuthUser | null;
194
+ /** Exchange an ID token from a provider's native SDK for an AuthOwl session. */
195
+ declare function useSocialSignIn(): (options: NativeSocialSignInOptions) => Promise<AuthActionResult<SocialAuthData>>;
196
+
197
+ /**
198
+ * Visual tokens for the built-in components.
199
+ *
200
+ * Deliberately small and overridable rather than a full theming engine: an app
201
+ * that wants its own look should compose the headless hooks, not fight a
202
+ * cascade. These exist so the drop-in screens look deliberate out of the box.
203
+ */
204
+ interface AuthOwlTheme {
205
+ accent: string;
206
+ accentText: string;
207
+ /** Readable inline-link color; defaults to `accent` for custom themes. */
208
+ link?: string;
209
+ text: string;
210
+ mutedText: string;
211
+ background: string;
212
+ surface: string;
213
+ border: string;
214
+ danger: string;
215
+ radius: number;
216
+ spacing: number;
217
+ }
218
+ declare const defaultTheme: AuthOwlTheme;
219
+ declare const darkTheme: AuthOwlTheme;
220
+ /** Build the stylesheet for a theme. Memoize per theme at the call site. */
221
+ declare function createStyles(theme: AuthOwlTheme): {
222
+ container: {
223
+ gap: number;
224
+ backgroundColor: string;
225
+ };
226
+ title: {
227
+ fontSize: number;
228
+ fontWeight: string;
229
+ color: string;
230
+ };
231
+ label: {
232
+ fontSize: number;
233
+ fontWeight: string;
234
+ color: string;
235
+ };
236
+ field: {
237
+ gap: number;
238
+ };
239
+ input: {
240
+ borderWidth: number;
241
+ borderColor: string;
242
+ borderRadius: number;
243
+ paddingHorizontal: number;
244
+ paddingVertical: number;
245
+ fontSize: number;
246
+ color: string;
247
+ backgroundColor: string;
248
+ };
249
+ inputInvalid: {
250
+ borderColor: string;
251
+ };
252
+ button: {
253
+ borderRadius: number;
254
+ paddingVertical: number;
255
+ alignItems: string;
256
+ backgroundColor: string;
257
+ };
258
+ buttonDisabled: {
259
+ opacity: number;
260
+ };
261
+ buttonText: {
262
+ color: string;
263
+ fontSize: number;
264
+ fontWeight: string;
265
+ };
266
+ link: {
267
+ color: string;
268
+ fontSize: number;
269
+ };
270
+ consentRow: {
271
+ flexDirection: string;
272
+ alignItems: string;
273
+ gap: number;
274
+ };
275
+ consentToggle: {
276
+ minWidth: number;
277
+ height: number;
278
+ alignItems: string;
279
+ justifyContent: string;
280
+ };
281
+ consentBox: {
282
+ width: number;
283
+ height: number;
284
+ alignItems: string;
285
+ justifyContent: string;
286
+ borderWidth: number;
287
+ borderColor: string;
288
+ borderRadius: number;
289
+ backgroundColor: string;
290
+ };
291
+ consentBoxChecked: {
292
+ borderColor: string;
293
+ backgroundColor: string;
294
+ };
295
+ consentBoxDisabled: {
296
+ opacity: number;
297
+ };
298
+ consentCheck: {
299
+ color: string;
300
+ fontSize: number;
301
+ fontWeight: string;
302
+ lineHeight: number;
303
+ };
304
+ consentText: {
305
+ flex: number;
306
+ color: string;
307
+ fontSize: number;
308
+ lineHeight: number;
309
+ };
310
+ consentLink: {
311
+ color: string;
312
+ textDecorationLine: string;
313
+ };
314
+ error: {
315
+ color: string;
316
+ fontSize: number;
317
+ };
318
+ };
319
+
320
+ interface SignInProps {
321
+ /** Called once a session exists. */
322
+ onSignedIn?: () => void;
323
+ /** Called when valid credentials require an MFA challenge before a session exists. */
324
+ onSecondFactorRequired?: () => void;
325
+ /** Rendered as a link under the form, when provided. */
326
+ onForgotPassword?: () => void;
327
+ theme?: AuthOwlTheme;
328
+ }
329
+ /**
330
+ * Email and password sign-in.
331
+ *
332
+ * Social sign-in is intentionally NOT rendered here. It needs a provider ID
333
+ * token from a native SDK the app has to configure itself, so a button that
334
+ * cannot work without that wiring would be a broken affordance. Use
335
+ * `useSocialSignIn()` alongside this screen.
336
+ */
337
+ declare function SignIn({ onSignedIn, onSecondFactorRequired, onForgotPassword, theme, }: SignInProps): react.JSX.Element | null;
338
+
339
+ interface SignUpProps {
340
+ /**
341
+ * Called when sign-up succeeds.
342
+ *
343
+ * `sessionCreated` is false when the project requires email verification
344
+ * first. The caller decides what happens next, because "check your email" and
345
+ * "you are signed in" are different screens.
346
+ */
347
+ onSignedUp?: (result: {
348
+ sessionCreated: boolean;
349
+ }) => void;
350
+ /** Collect first and last name instead of a single display name. */
351
+ structuredName?: boolean;
352
+ theme?: AuthOwlTheme;
353
+ }
354
+ /** Create an account with an email address and password. */
355
+ declare function SignUp({ onSignedUp, structuredName, theme }: SignUpProps): react.JSX.Element | null;
356
+
357
+ interface EmailOtpFormProps {
358
+ onSignedIn?: () => void;
359
+ theme?: AuthOwlTheme;
360
+ }
361
+ /**
362
+ * Two stages in one screen: request a code, then verify it.
363
+ *
364
+ * Kept together because the second stage is meaningless without the address
365
+ * entered in the first, and splitting them across screens loses that context on
366
+ * a back navigation.
367
+ */
368
+ declare function EmailOtpForm({ onSignedIn, theme }: EmailOtpFormProps): react.JSX.Element;
369
+
370
+ interface OrganizationSwitcherProps {
371
+ /** Called after the active organization changes, including to personal. */
372
+ onSwitched?: (organization: Organization | null) => void;
373
+ /**
374
+ * Offer a "personal account" row that clears the active organization.
375
+ * Off by default: many apps require an organization context to function.
376
+ */
377
+ allowPersonal?: boolean;
378
+ theme?: AuthOwlTheme;
379
+ }
380
+ /**
381
+ * Lists the caller's organizations and switches between them.
382
+ *
383
+ * Reads the ACTIVE organization from the session rather than tracking it
384
+ * locally. Switching re-mints the session claim server-side, so local state
385
+ * would be a second source of truth that drifts the moment anything else
386
+ * changes the active org.
387
+ */
388
+ declare function OrganizationSwitcher({ onSwitched, allowPersonal, theme, }: OrganizationSwitcherProps): react.JSX.Element | null;
389
+
390
+ interface PasskeyEnrollmentProps {
391
+ /** Suggested credential name, shown in the platform's list. */
392
+ name?: string;
393
+ onEnrolled?: () => void;
394
+ /** Rendered as a skip link when provided. */
395
+ onSkip?: () => void;
396
+ theme?: AuthOwlTheme;
397
+ }
398
+ /**
399
+ * Offer to create a passkey.
400
+ *
401
+ * Renders nothing without a passkey adapter, so it is safe to drop into a
402
+ * post-sign-up flow that also runs on projects with passkeys disabled.
403
+ */
404
+ declare function PasskeyEnrollment({ name, onEnrolled, onSkip, theme, }: PasskeyEnrollmentProps): react.JSX.Element | null;
405
+ interface PasskeySignInButtonProps {
406
+ onSignedIn?: () => void;
407
+ theme?: AuthOwlTheme;
408
+ }
409
+ /** Sign in with an already-enrolled passkey. */
410
+ declare function PasskeySignInButton({ onSignedIn, theme, }: PasskeySignInButtonProps): react.JSX.Element | null;
411
+
412
+ /**
413
+ * Platform passkeys on a phone.
414
+ *
415
+ * React Native has no `navigator.credentials`, but both platforms do have
416
+ * passkey APIs - `ASAuthorization` on iOS, Credential Manager on Android - and
417
+ * the community libraries (`react-native-passkey`, `expo-passkeys`) speak the
418
+ * same WebAuthn JSON the server already emits. So the app supplies the ceremony
419
+ * and the SDK keeps the protocol: option decoding, response projection, and the
420
+ * in-flight de-duplication all come from `@authowl/core`.
421
+ *
422
+ * The adapter is the app's because the native libraries differ, need native
423
+ * builds, and require associated-domain configuration the SDK cannot do on the
424
+ * app's behalf.
425
+ */
426
+
427
+ /** The platform passkey calls an app must provide. */
428
+ interface NativePasskeyAdapter {
429
+ /**
430
+ * Run the platform's registration ceremony.
431
+ *
432
+ * `optionsJSON` is the server's WebAuthn creation options; return the
433
+ * credential the platform produced. Throw to signal cancellation or failure.
434
+ */
435
+ register(optionsJSON: unknown): Promise<PasskeyRegistrationResponse>;
436
+ /** Run the platform's authentication ceremony. */
437
+ authenticate(optionsJSON: unknown): Promise<PasskeyAuthenticationResponse>;
438
+ /**
439
+ * Optional: map a platform failure to a stable code.
440
+ *
441
+ * Without it a cancelled prompt is reported as a generic ceremony error. iOS
442
+ * and Android both surface cancellation distinctly, and users cancel far more
443
+ * often than anything actually breaks, so implementing this is worth it.
444
+ */
445
+ errorCode?(error: unknown): string | undefined;
446
+ }
447
+ /**
448
+ * Adapt a platform passkey library into the factory `@authowl/core` expects.
449
+ *
450
+ * Pass the result as `passkeys` to `<AuthOwlProvider>`; without it the passkey
451
+ * ceremony is absent from the client's type entirely, so an app cannot call a
452
+ * prompt that would fail.
453
+ */
454
+ declare function createNativePasskeys(adapter: NativePasskeyAdapter): PasskeyCeremonyClientFactory;
455
+
456
+ /** An ID token obtained from a provider's native SDK. */
457
+ interface ProviderIdToken {
458
+ token: string;
459
+ accessToken?: string;
460
+ nonce?: string;
461
+ }
462
+ interface SocialProvider {
463
+ /** The provider id AuthOwl knows, e.g. `google` or `apple`. */
464
+ id: string;
465
+ /** Display name, interpolated into the localized button label. */
466
+ label: string;
467
+ /**
468
+ * Run the provider's native sign-in and return its ID token.
469
+ *
470
+ * Return `null` when the user cancels. The app owns this because the native
471
+ * SDKs differ per provider and per platform, and bundling one would force
472
+ * every consumer to carry it - `google_sign_in`, `expo-apple-authentication`,
473
+ * and friends stay the app's dependency, not the SDK's.
474
+ */
475
+ getIdToken: () => Promise<ProviderIdToken | null>;
476
+ }
477
+ interface SocialButtonsProps {
478
+ providers: readonly SocialProvider[];
479
+ onSignedIn?: () => void;
480
+ theme?: AuthOwlTheme;
481
+ }
482
+ /**
483
+ * One button per provider.
484
+ *
485
+ * Redirect OAuth is not an option here: it completes inside a system browser
486
+ * whose cookie jar this client cannot read, so the session would land somewhere
487
+ * the app can never see it. ID-token exchange is the only native flow that
488
+ * actually establishes a session.
489
+ */
490
+ declare function SocialButtons({ providers, onSignedIn, theme, }: SocialButtonsProps): react.JSX.Element | null;
491
+
492
+ declare function useStyles(theme?: AuthOwlTheme): {
493
+ container: {
494
+ gap: number;
495
+ backgroundColor: string;
496
+ };
497
+ title: {
498
+ fontSize: number;
499
+ fontWeight: string;
500
+ color: string;
501
+ };
502
+ label: {
503
+ fontSize: number;
504
+ fontWeight: string;
505
+ color: string;
506
+ };
507
+ field: {
508
+ gap: number;
509
+ };
510
+ input: {
511
+ borderWidth: number;
512
+ borderColor: string;
513
+ borderRadius: number;
514
+ paddingHorizontal: number;
515
+ paddingVertical: number;
516
+ fontSize: number;
517
+ color: string;
518
+ backgroundColor: string;
519
+ };
520
+ inputInvalid: {
521
+ borderColor: string;
522
+ };
523
+ button: {
524
+ borderRadius: number;
525
+ paddingVertical: number;
526
+ alignItems: string;
527
+ backgroundColor: string;
528
+ };
529
+ buttonDisabled: {
530
+ opacity: number;
531
+ };
532
+ buttonText: {
533
+ color: string;
534
+ fontSize: number;
535
+ fontWeight: string;
536
+ };
537
+ link: {
538
+ color: string;
539
+ fontSize: number;
540
+ };
541
+ consentRow: {
542
+ flexDirection: string;
543
+ alignItems: string;
544
+ gap: number;
545
+ };
546
+ consentToggle: {
547
+ minWidth: number;
548
+ height: number;
549
+ alignItems: string;
550
+ justifyContent: string;
551
+ };
552
+ consentBox: {
553
+ width: number;
554
+ height: number;
555
+ alignItems: string;
556
+ justifyContent: string;
557
+ borderWidth: number;
558
+ borderColor: string;
559
+ borderRadius: number;
560
+ backgroundColor: string;
561
+ };
562
+ consentBoxChecked: {
563
+ borderColor: string;
564
+ backgroundColor: string;
565
+ };
566
+ consentBoxDisabled: {
567
+ opacity: number;
568
+ };
569
+ consentCheck: {
570
+ color: string;
571
+ fontSize: number;
572
+ fontWeight: string;
573
+ lineHeight: number;
574
+ };
575
+ consentText: {
576
+ flex: number;
577
+ color: string;
578
+ fontSize: number;
579
+ lineHeight: number;
580
+ };
581
+ consentLink: {
582
+ color: string;
583
+ textDecorationLine: string;
584
+ };
585
+ error: {
586
+ color: string;
587
+ fontSize: number;
588
+ };
589
+ };
590
+ interface FieldProps {
591
+ label: string;
592
+ value: string;
593
+ onChangeText: (value: string) => void;
594
+ theme?: AuthOwlTheme;
595
+ placeholder?: string;
596
+ secure?: boolean;
597
+ invalid?: boolean;
598
+ editable?: boolean;
599
+ testID?: string;
600
+ autoComplete?: string;
601
+ keyboardType?: string;
602
+ maxLength?: number;
603
+ onSubmitEditing?: () => void;
604
+ }
605
+ /** A labelled text input. */
606
+ declare function Field({ label, value, onChangeText, theme, placeholder, secure, invalid, editable, testID, autoComplete, keyboardType, maxLength, onSubmitEditing, }: FieldProps): react.JSX.Element;
607
+ interface SubmitButtonProps {
608
+ label: string;
609
+ busyLabel: string;
610
+ onPress: () => void;
611
+ busy?: boolean;
612
+ disabled?: boolean;
613
+ theme?: AuthOwlTheme;
614
+ testID?: string;
615
+ }
616
+ /** The primary action, with its own busy state. */
617
+ declare function SubmitButton({ label, busyLabel, onPress, busy, disabled, theme, testID, }: SubmitButtonProps): react.JSX.Element;
618
+ /**
619
+ * An error message.
620
+ *
621
+ * Announced politely so a screen reader reports a failed sign-in without
622
+ * interrupting whatever the user is doing.
623
+ */
624
+ declare function FormError({ message, theme, testID, }: {
625
+ message: string | null;
626
+ theme?: AuthOwlTheme;
627
+ testID?: string;
628
+ }): react.JSX.Element | null;
629
+
630
+ /**
631
+ * Localization for the React Native components.
632
+ *
633
+ * Reads the SAME catalogs the web components use (`@authowl/core/i18n`). That
634
+ * is a hard rule, not a convenience: a second catalog is how an Arabic string
635
+ * silently stops matching between the web app and the phone app.
636
+ */
637
+
638
+ /** Translate a catalog key in the active locale. */
639
+ declare function useT(): (key: MessageKey, params?: MessageParams) => string;
640
+ /** The active locale and its writing direction. */
641
+ declare function useLocale(): {
642
+ locale: Locale;
643
+ direction: 'ltr' | 'rtl';
644
+ };
645
+ /**
646
+ * Turn a server failure into a localized sentence.
647
+ *
648
+ * Falls back to the generic message rather than surfacing a raw server string:
649
+ * an untranslated backend error in the middle of an Arabic sign-in screen is
650
+ * both a leak and a UX failure.
651
+ */
652
+ declare function useServerError(): (error: ServerErrorInput | null | undefined, fallback: MessageKey) => string;
653
+
654
+ export { type AuthOwlHeadlessNative, type AuthOwlNative, type AuthOwlNativeConfig, type AuthOwlNativeConfigWithPasskeys, type AuthOwlPasskeyNative, AuthOwlProvider, type AuthOwlProviderProps, type AuthOwlTheme, type CookieJarOptions, EmailOtpForm, type EmailOtpFormProps, Field, type FieldProps, FormError, MemoryStorage, type NativePasskeyAdapter, OrganizationSwitcher, type OrganizationSwitcherProps, PasskeyEnrollment, type PasskeyEnrollmentProps, PasskeySignInButton, type PasskeySignInButtonProps, type ProviderIdToken, type PublicConfigState, type SecureStorage, SignIn, type SignInProps, SignUp, type SignUpProps, SocialButtons, type SocialButtonsProps, type SocialProvider, SubmitButton, type SubmitButtonProps, type UseAuthResult, createAuthOwlNative, createCookieJarFetch, createNativePasskeys, createStyles, darkTheme, defaultTheme, readSetCookie, sessionStorageKey, signInWithSocialIdToken, useAuth, useAuthOwlClient, useAuthOwlLocale, useLocale, usePublicConfig, useServerError, useSession, useSocialSignIn, useStyles, useT, useUser };