@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.
package/dist/index.cjs ADDED
@@ -0,0 +1,1193 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AuthOwlProvider: () => AuthOwlProvider,
24
+ EmailOtpForm: () => EmailOtpForm,
25
+ Field: () => Field,
26
+ FormError: () => FormError,
27
+ MemoryStorage: () => MemoryStorage,
28
+ OrganizationSwitcher: () => OrganizationSwitcher,
29
+ PasskeyEnrollment: () => PasskeyEnrollment,
30
+ PasskeySignInButton: () => PasskeySignInButton,
31
+ SignIn: () => SignIn,
32
+ SignUp: () => SignUp,
33
+ SocialButtons: () => SocialButtons,
34
+ SubmitButton: () => SubmitButton,
35
+ createAuthOwlNative: () => createAuthOwlNative,
36
+ createCookieJarFetch: () => createCookieJarFetch,
37
+ createNativePasskeys: () => createNativePasskeys,
38
+ createStyles: () => createStyles,
39
+ darkTheme: () => darkTheme,
40
+ defaultTheme: () => defaultTheme,
41
+ readSetCookie: () => readSetCookie,
42
+ sessionCookieName: () => import_native8.sessionCookieName,
43
+ sessionStorageKey: () => sessionStorageKey,
44
+ signInWithSocialIdToken: () => signInWithSocialIdToken,
45
+ useAuth: () => useAuth,
46
+ useAuthOwlClient: () => useAuthOwlClient,
47
+ useAuthOwlLocale: () => useAuthOwlLocale,
48
+ useLocale: () => useLocale,
49
+ usePublicConfig: () => usePublicConfig,
50
+ useServerError: () => useServerError,
51
+ useSession: () => useSession,
52
+ useSocialSignIn: () => useSocialSignIn,
53
+ useStyles: () => useStyles,
54
+ useT: () => useT,
55
+ useUser: () => useUser
56
+ });
57
+ module.exports = __toCommonJS(index_exports);
58
+
59
+ // src/client.ts
60
+ var import_native2 = require("@authowl/core/native");
61
+
62
+ // src/cookie-jar.ts
63
+ var import_native = require("@authowl/core/native");
64
+ function sessionStorageKey(projectId) {
65
+ return `authowl.session.${projectId}`;
66
+ }
67
+ function readSetCookie(header, name) {
68
+ if (!header) return null;
69
+ const entries = typeof header === "string" ? header.split("\n") : header;
70
+ for (const entry of entries) {
71
+ const trimmed = entry.trim();
72
+ const separator = trimmed.indexOf("=");
73
+ if (separator === -1) continue;
74
+ if (trimmed.slice(0, separator).trim() !== name) continue;
75
+ const value = trimmed.slice(separator + 1).split(";", 1)[0] ?? "";
76
+ return value;
77
+ }
78
+ return null;
79
+ }
80
+ function setCookieValues(headers) {
81
+ const withGetter = headers;
82
+ if (typeof withGetter.getSetCookie === "function") {
83
+ return withGetter.getSetCookie();
84
+ }
85
+ return headers.get("set-cookie");
86
+ }
87
+ function withSessionCookie(headers, name, value) {
88
+ const existing = headers.get("cookie");
89
+ const pair = `${name}=${value}`;
90
+ headers.set("cookie", existing ? `${existing}; ${pair}` : pair);
91
+ }
92
+ function createCookieJarFetch(options) {
93
+ const { storage, projectId, secure } = options;
94
+ const baseFetch = options.fetchImpl ?? globalThis.fetch;
95
+ if (typeof baseFetch !== "function") {
96
+ throw new Error(
97
+ "@authowl/react-native requires a global fetch. Pass `fetchImpl` if your runtime lacks one."
98
+ );
99
+ }
100
+ const cookieName = (0, import_native.sessionCookieName)(projectId, { secure });
101
+ const storageKey = sessionStorageKey(projectId);
102
+ return async function cookieJarFetch(input, init) {
103
+ const useSessionJar = init?.credentials !== "omit";
104
+ const stored = useSessionJar ? await storage.getItem(storageKey) : null;
105
+ const inherited = init?.headers ?? (typeof input === "object" && input !== null && "headers" in input ? input.headers : void 0);
106
+ const headers = new Headers(inherited);
107
+ if (stored) withSessionCookie(headers, cookieName, stored);
108
+ const response = await baseFetch(input, { ...init, headers });
109
+ const issued = useSessionJar ? readSetCookie(setCookieValues(response.headers), cookieName) : null;
110
+ if (issued !== null) {
111
+ if (issued === "") await storage.removeItem(storageKey);
112
+ else await storage.setItem(storageKey, issued);
113
+ }
114
+ return response;
115
+ };
116
+ }
117
+
118
+ // src/client.ts
119
+ function createAuthOwlNative(config) {
120
+ const { projectId } = (0, import_native2.decodePublishableKey)(config.publishableKey);
121
+ const secure = new URL(config.apiUrl).protocol === "https:";
122
+ const resolved = (0, import_native2.resolveConfig)({
123
+ publishableKey: config.publishableKey,
124
+ apiUrl: config.apiUrl,
125
+ fetch: createCookieJarFetch({
126
+ storage: config.storage,
127
+ projectId,
128
+ secure,
129
+ fetchImpl: config.fetchImpl
130
+ })
131
+ });
132
+ const client = config.passkeys ? (0, import_native2.createNativeAuthClient)(resolved, config.onSessionMutation, config.passkeys) : (0, import_native2.createNativeAuthClient)(resolved, config.onSessionMutation);
133
+ return { client, projectId, getPublicConfig: () => (0, import_native2.getPublicConfig)(resolved) };
134
+ }
135
+
136
+ // src/oauth.ts
137
+ function signInWithSocialIdToken(client, options) {
138
+ return client.signIn.social(options);
139
+ }
140
+
141
+ // src/provider.tsx
142
+ var import_react = require("react");
143
+ var import_native3 = require("@authowl/core/native");
144
+ var AuthOwlContext = (0, import_react.createContext)(null);
145
+ function AuthOwlProvider(props) {
146
+ const {
147
+ children,
148
+ publishableKey,
149
+ apiUrl,
150
+ storage,
151
+ fetchImpl,
152
+ onSessionMutation,
153
+ passkeys,
154
+ locale = "en"
155
+ } = props;
156
+ const native = (0, import_react.useMemo)(() => {
157
+ return createAuthOwlNative({
158
+ publishableKey,
159
+ apiUrl,
160
+ storage,
161
+ fetchImpl,
162
+ onSessionMutation,
163
+ passkeys
164
+ });
165
+ }, [publishableKey, apiUrl, storage, fetchImpl, onSessionMutation, passkeys]);
166
+ const [publicConfig, setPublicConfig] = (0, import_react.useState)(null);
167
+ const [publicConfigState, setPublicConfigState] = (0, import_react.useState)("loading");
168
+ (0, import_react.useEffect)(() => {
169
+ let active = true;
170
+ setPublicConfig(null);
171
+ setPublicConfigState("loading");
172
+ native.getPublicConfig().then((config) => {
173
+ if (!active) return;
174
+ setPublicConfig(config);
175
+ setPublicConfigState("ready");
176
+ }).catch(() => {
177
+ if (!active) return;
178
+ setPublicConfig(null);
179
+ setPublicConfigState("error");
180
+ });
181
+ return () => {
182
+ active = false;
183
+ };
184
+ }, [native]);
185
+ const value = (0, import_react.useMemo)(() => ({
186
+ client: native.client,
187
+ projectId: native.projectId,
188
+ locale,
189
+ publicConfig,
190
+ publicConfigState
191
+ }), [native, locale, publicConfig, publicConfigState]);
192
+ return (0, import_react.createElement)(AuthOwlContext.Provider, { value }, children);
193
+ }
194
+ function useAuthOwlContext() {
195
+ const value = (0, import_react.useContext)(AuthOwlContext);
196
+ if (value === null) {
197
+ throw new Error("AuthOwl hooks must be used inside an <AuthOwlProvider>.");
198
+ }
199
+ return value;
200
+ }
201
+ function useAuthOwlLocale() {
202
+ return useAuthOwlContext().locale;
203
+ }
204
+ function useAuthOwlClient() {
205
+ return useAuthOwlContext().client;
206
+ }
207
+ function usePublicConfig() {
208
+ const { publicConfig, publicConfigState } = useAuthOwlContext();
209
+ return {
210
+ data: publicConfig,
211
+ state: publicConfigState,
212
+ isLoading: publicConfigState === "loading"
213
+ };
214
+ }
215
+ function useSession() {
216
+ const { client } = useAuthOwlContext();
217
+ const store = client.sessionStore;
218
+ return (0, import_react.useSyncExternalStore)(
219
+ (listener) => store.subscribe(listener),
220
+ () => store.getSnapshot(),
221
+ () => store.getSnapshot()
222
+ );
223
+ }
224
+ function useAuth() {
225
+ const { client } = useAuthOwlContext();
226
+ const state = useSession();
227
+ const membership = state.data?.session.membership ?? null;
228
+ const { has, hasPermission } = (0, import_react.useMemo)(
229
+ () => (0, import_native3.createMembershipHas)(membership),
230
+ [membership]
231
+ );
232
+ return {
233
+ isLoaded: !state.isPending,
234
+ isSignedIn: state.data !== null,
235
+ user: state.data?.user ?? null,
236
+ session: state.data?.session ?? null,
237
+ signOut: async () => {
238
+ await client.signOut();
239
+ },
240
+ has,
241
+ hasPermission
242
+ };
243
+ }
244
+ function useUser() {
245
+ return useSession().data?.user ?? null;
246
+ }
247
+ function useSocialSignIn() {
248
+ const { client } = useAuthOwlContext();
249
+ return (0, import_react.useCallback)(
250
+ (options) => signInWithSocialIdToken(client, options),
251
+ [client]
252
+ );
253
+ }
254
+
255
+ // src/components/SignIn.tsx
256
+ var import_react4 = require("react");
257
+ var import_react_native3 = require("react-native");
258
+
259
+ // src/i18n.ts
260
+ var import_react2 = require("react");
261
+ var import_i18n = require("@authowl/core/i18n");
262
+ function useT() {
263
+ const locale = useAuthOwlLocale();
264
+ return (0, import_react2.useMemo)(
265
+ () => (key, params) => (0, import_i18n.formatMessage)(locale, key, params),
266
+ [locale]
267
+ );
268
+ }
269
+ function useLocale() {
270
+ const locale = useAuthOwlLocale();
271
+ return (0, import_react2.useMemo)(() => ({ locale, direction: (0, import_i18n.directionFor)(locale) }), [locale]);
272
+ }
273
+ function useServerError() {
274
+ const locale = useAuthOwlLocale();
275
+ const t = useT();
276
+ return (0, import_react2.useMemo)(
277
+ () => (error, fallback) => (0, import_i18n.resolveServerError)(locale, error, t(fallback)),
278
+ [locale, t]
279
+ );
280
+ }
281
+
282
+ // src/components/SignIn.tsx
283
+ var import_native4 = require("@authowl/core/native");
284
+
285
+ // src/components/primitives.tsx
286
+ var import_react3 = require("react");
287
+ var import_react_native2 = require("react-native");
288
+
289
+ // src/components/theme.ts
290
+ var import_react_native = require("react-native");
291
+ var defaultTheme = {
292
+ accent: "#F5B84C",
293
+ accentText: "#241703",
294
+ link: "#624A1E",
295
+ text: "#111827",
296
+ mutedText: "#6b7280",
297
+ background: "#ffffff",
298
+ surface: "#f9fafb",
299
+ border: "#d1d5db",
300
+ danger: "#b91c1c",
301
+ radius: 10,
302
+ spacing: 12
303
+ };
304
+ var darkTheme = {
305
+ ...defaultTheme,
306
+ link: "#F5B84C",
307
+ text: "#f9fafb",
308
+ mutedText: "#9ca3af",
309
+ background: "#111827",
310
+ surface: "#1f2937",
311
+ border: "#374151",
312
+ danger: "#fca5a5"
313
+ };
314
+ function createStyles(theme) {
315
+ return import_react_native.StyleSheet.create({
316
+ container: { gap: theme.spacing, backgroundColor: theme.background },
317
+ title: { fontSize: 22, fontWeight: "600", color: theme.text },
318
+ label: { fontSize: 13, fontWeight: "500", color: theme.mutedText },
319
+ field: { gap: 4 },
320
+ input: {
321
+ borderWidth: 1,
322
+ borderColor: theme.border,
323
+ borderRadius: theme.radius,
324
+ paddingHorizontal: theme.spacing,
325
+ paddingVertical: theme.spacing * 0.75,
326
+ fontSize: 16,
327
+ color: theme.text,
328
+ backgroundColor: theme.surface
329
+ },
330
+ inputInvalid: { borderColor: theme.danger },
331
+ button: {
332
+ borderRadius: theme.radius,
333
+ paddingVertical: theme.spacing,
334
+ alignItems: "center",
335
+ backgroundColor: theme.accent
336
+ },
337
+ buttonDisabled: { opacity: 0.5 },
338
+ buttonText: { color: theme.accentText, fontSize: 16, fontWeight: "600" },
339
+ link: { color: theme.link ?? theme.accent, fontSize: 14 },
340
+ consentRow: {
341
+ flexDirection: "row",
342
+ alignItems: "flex-start",
343
+ gap: 8
344
+ },
345
+ consentToggle: {
346
+ minWidth: 24,
347
+ height: 19,
348
+ alignItems: "center",
349
+ justifyContent: "center"
350
+ },
351
+ consentBox: {
352
+ width: 18,
353
+ height: 18,
354
+ alignItems: "center",
355
+ justifyContent: "center",
356
+ borderWidth: 1,
357
+ borderColor: theme.border,
358
+ borderRadius: 4,
359
+ backgroundColor: theme.surface
360
+ },
361
+ consentBoxChecked: {
362
+ borderColor: theme.accent,
363
+ backgroundColor: theme.accent
364
+ },
365
+ consentBoxDisabled: { opacity: 0.55 },
366
+ consentCheck: {
367
+ color: theme.accentText,
368
+ fontSize: 13,
369
+ fontWeight: "700",
370
+ lineHeight: 16
371
+ },
372
+ consentText: {
373
+ flex: 1,
374
+ color: theme.text,
375
+ fontSize: 13,
376
+ lineHeight: 19
377
+ },
378
+ consentLink: {
379
+ color: theme.link ?? theme.accent,
380
+ textDecorationLine: "underline"
381
+ },
382
+ error: { color: theme.danger, fontSize: 14 }
383
+ });
384
+ }
385
+
386
+ // src/components/primitives.tsx
387
+ var import_jsx_runtime = require("react/jsx-runtime");
388
+ function useStyles(theme = defaultTheme) {
389
+ return (0, import_react3.useMemo)(() => createStyles(theme), [theme]);
390
+ }
391
+ function Field({
392
+ label,
393
+ value,
394
+ onChangeText,
395
+ theme = defaultTheme,
396
+ placeholder,
397
+ secure = false,
398
+ invalid = false,
399
+ editable = true,
400
+ testID,
401
+ autoComplete,
402
+ keyboardType,
403
+ maxLength,
404
+ onSubmitEditing
405
+ }) {
406
+ const styles = useStyles(theme);
407
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.field, children: [
408
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.label, children: label }),
409
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
410
+ import_react_native2.TextInput,
411
+ {
412
+ style: invalid ? [styles.input, styles.inputInvalid] : styles.input,
413
+ value,
414
+ onChangeText,
415
+ placeholder,
416
+ placeholderTextColor: theme.mutedText,
417
+ secureTextEntry: secure,
418
+ editable,
419
+ testID,
420
+ autoCapitalize: "none",
421
+ autoCorrect: false,
422
+ autoComplete,
423
+ keyboardType,
424
+ maxLength,
425
+ accessibilityLabel: label,
426
+ onSubmitEditing
427
+ }
428
+ )
429
+ ] });
430
+ }
431
+ function SubmitButton({
432
+ label,
433
+ busyLabel,
434
+ onPress,
435
+ busy = false,
436
+ disabled = false,
437
+ theme = defaultTheme,
438
+ testID
439
+ }) {
440
+ const styles = useStyles(theme);
441
+ const blocked = busy || disabled;
442
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
443
+ import_react_native2.Pressable,
444
+ {
445
+ style: blocked ? [styles.button, styles.buttonDisabled] : styles.button,
446
+ onPress,
447
+ disabled: blocked,
448
+ testID,
449
+ accessibilityRole: "button",
450
+ accessibilityState: { disabled: blocked, busy },
451
+ children: [
452
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.ActivityIndicator, { color: theme.accentText }) : null,
453
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.buttonText, children: busy ? busyLabel : label })
454
+ ]
455
+ }
456
+ );
457
+ }
458
+ function FormError({
459
+ message,
460
+ theme = defaultTheme,
461
+ testID = "authowl-error"
462
+ }) {
463
+ const styles = useStyles(theme);
464
+ if (!message) return null;
465
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { accessibilityLiveRegion: "polite", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.error, testID, children: message }) });
466
+ }
467
+
468
+ // src/components/SignIn.tsx
469
+ var import_jsx_runtime2 = require("react/jsx-runtime");
470
+ function SignIn({
471
+ onSignedIn,
472
+ onSecondFactorRequired,
473
+ onForgotPassword,
474
+ theme = defaultTheme
475
+ }) {
476
+ const t = useT();
477
+ const toMessage = useServerError();
478
+ const client = useAuthOwlClient();
479
+ const config = usePublicConfig();
480
+ const capabilities = (0, import_native4.resolveProjectCapabilities)(config.data);
481
+ const styles = useStyles(theme);
482
+ const [email, setEmail] = (0, import_react4.useState)("");
483
+ const [password, setPassword] = (0, import_react4.useState)("");
484
+ const [busy, setBusy] = (0, import_react4.useState)(false);
485
+ const [error, setError] = (0, import_react4.useState)(null);
486
+ const canSubmit = email.trim().length > 0 && password.length > 0;
487
+ async function submit() {
488
+ if (busy || !canSubmit) return;
489
+ setBusy(true);
490
+ setError(null);
491
+ try {
492
+ const result = await client.signIn.email({ email: email.trim(), password });
493
+ if (result.error !== null) {
494
+ setError(toMessage(result.error, "signIn.error.failed"));
495
+ return;
496
+ }
497
+ if (result.data !== null && "twoFactorRedirect" in result.data) {
498
+ onSecondFactorRequired?.();
499
+ return;
500
+ }
501
+ onSignedIn?.();
502
+ } catch {
503
+ setError(t("signIn.error.failed"));
504
+ } finally {
505
+ setBusy(false);
506
+ }
507
+ }
508
+ if (config.isLoading || config.data !== null && !capabilities.passwordSignIn) return null;
509
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: styles.container, testID: "authowl-signin", children: [
510
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: styles.title, children: t("signIn.title") }),
511
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
512
+ Field,
513
+ {
514
+ label: t("common.emailLabel"),
515
+ value: email,
516
+ onChangeText: setEmail,
517
+ theme,
518
+ editable: !busy,
519
+ testID: "authowl-signin-email",
520
+ autoComplete: "email",
521
+ keyboardType: "email-address"
522
+ }
523
+ ),
524
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
525
+ Field,
526
+ {
527
+ label: t("common.passwordLabel"),
528
+ value: password,
529
+ onChangeText: setPassword,
530
+ theme,
531
+ secure: true,
532
+ editable: !busy,
533
+ testID: "authowl-signin-password",
534
+ autoComplete: "current-password",
535
+ onSubmitEditing: submit
536
+ }
537
+ ),
538
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FormError, { message: error, theme }),
539
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
540
+ SubmitButton,
541
+ {
542
+ label: t("signIn.submit"),
543
+ busyLabel: t("signIn.submitPending"),
544
+ onPress: submit,
545
+ busy,
546
+ disabled: !canSubmit,
547
+ theme,
548
+ testID: "authowl-signin-submit"
549
+ }
550
+ ),
551
+ onForgotPassword ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: styles.link, onPress: onForgotPassword, testID: "authowl-signin-forgot", children: t("signIn.forgotLink") }) : null
552
+ ] });
553
+ }
554
+
555
+ // src/components/SignUp.tsx
556
+ var import_react5 = require("react");
557
+ var import_react_native4 = require("react-native");
558
+ var import_native5 = require("@authowl/core/native");
559
+ var import_jsx_runtime3 = require("react/jsx-runtime");
560
+ function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
561
+ const t = useT();
562
+ const { direction } = useLocale();
563
+ const toMessage = useServerError();
564
+ const client = useAuthOwlClient();
565
+ const config = usePublicConfig();
566
+ const capabilities = (0, import_native5.resolveProjectCapabilities)(config.data);
567
+ const styles = useStyles(theme);
568
+ const [email, setEmail] = (0, import_react5.useState)("");
569
+ const [password, setPassword] = (0, import_react5.useState)("");
570
+ const [name, setName] = (0, import_react5.useState)("");
571
+ const [firstName, setFirstName] = (0, import_react5.useState)("");
572
+ const [lastName, setLastName] = (0, import_react5.useState)("");
573
+ const [busy, setBusy] = (0, import_react5.useState)(false);
574
+ const [error, setError] = (0, import_react5.useState)(null);
575
+ const [acceptedConsent, setAcceptedConsent] = (0, import_react5.useState)(false);
576
+ const legal = config.data?.legal;
577
+ (0, import_react5.useEffect)(() => {
578
+ setAcceptedConsent(false);
579
+ }, [legal?.version]);
580
+ const useStructuredName = structuredName || capabilities.firstLastName;
581
+ const displayName = useStructuredName ? [firstName.trim(), lastName.trim()].filter(Boolean).join(" ") : name.trim();
582
+ const canSubmit = email.trim().length > 0 && password.length >= capabilities.passwordMinLength && password.length <= capabilities.passwordMaxLength && displayName.length > 0 && (!legal?.required || acceptedConsent);
583
+ async function submit() {
584
+ if (busy || !canSubmit) return;
585
+ setBusy(true);
586
+ setError(null);
587
+ const result = await client.signUp.email({
588
+ email: email.trim(),
589
+ password,
590
+ name: displayName,
591
+ ...legal?.required ? { consentVersion: legal.version } : {},
592
+ ...useStructuredName ? { firstName: firstName.trim(), lastName: lastName.trim() } : {}
593
+ });
594
+ setBusy(false);
595
+ if (result.error !== null) {
596
+ setError(toMessage(result.error, "signUp.error.failed"));
597
+ return;
598
+ }
599
+ onSignedUp?.({ sessionCreated: result.data?.sessionCreated === true });
600
+ }
601
+ if (config.isLoading || config.data !== null && !capabilities.passwordSignUp) return null;
602
+ const termsUrl = legal?.termsUrl;
603
+ const privacyUrl = legal?.privacyUrl;
604
+ const consentDocuments = [
605
+ termsUrl ? t("consent.termsOfService") : null,
606
+ privacyUrl ? t("consent.privacyPolicy") : null
607
+ ].filter((value) => value !== null).join(t("consent.docJoiner"));
608
+ const consentTemplate = t("signUp.consentLabel");
609
+ const consentMarker = consentTemplate.indexOf("{links}");
610
+ const consentPrefix = consentMarker === -1 ? consentTemplate : consentTemplate.slice(0, consentMarker);
611
+ const consentSuffix = consentMarker === -1 ? "" : consentTemplate.slice(consentMarker + "{links}".length);
612
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles.container, testID: "authowl-signup", children: [
613
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: styles.title, children: t("signUp.title") }),
614
+ useStructuredName ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
615
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
616
+ Field,
617
+ {
618
+ label: t("signUp.firstNameLabel"),
619
+ value: firstName,
620
+ onChangeText: setFirstName,
621
+ theme,
622
+ editable: !busy,
623
+ testID: "authowl-signup-first-name",
624
+ autoComplete: "given-name"
625
+ }
626
+ ),
627
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
628
+ Field,
629
+ {
630
+ label: t("signUp.lastNameLabel"),
631
+ value: lastName,
632
+ onChangeText: setLastName,
633
+ theme,
634
+ editable: !busy,
635
+ testID: "authowl-signup-last-name",
636
+ autoComplete: "family-name"
637
+ }
638
+ )
639
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
640
+ Field,
641
+ {
642
+ label: t("signUp.nameLabel"),
643
+ value: name,
644
+ onChangeText: setName,
645
+ theme,
646
+ editable: !busy,
647
+ testID: "authowl-signup-name",
648
+ autoComplete: "name"
649
+ }
650
+ ),
651
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
652
+ Field,
653
+ {
654
+ label: t("common.emailLabel"),
655
+ value: email,
656
+ onChangeText: setEmail,
657
+ theme,
658
+ editable: !busy,
659
+ testID: "authowl-signup-email",
660
+ autoComplete: "email",
661
+ keyboardType: "email-address"
662
+ }
663
+ ),
664
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
665
+ Field,
666
+ {
667
+ label: t("common.passwordLabel"),
668
+ value: password,
669
+ onChangeText: setPassword,
670
+ theme,
671
+ secure: true,
672
+ editable: !busy,
673
+ testID: "authowl-signup-password",
674
+ autoComplete: "new-password",
675
+ maxLength: capabilities.passwordMaxLength,
676
+ onSubmitEditing: submit
677
+ }
678
+ ),
679
+ legal?.required ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: [styles.consentRow, { direction }], children: [
680
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
681
+ import_react_native4.Pressable,
682
+ {
683
+ onPress: () => setAcceptedConsent((accepted) => !accepted),
684
+ disabled: busy,
685
+ hitSlop: 8,
686
+ style: styles.consentToggle,
687
+ testID: "authowl-signup-consent",
688
+ accessibilityRole: "checkbox",
689
+ accessibilityState: { checked: acceptedConsent },
690
+ accessibilityLabel: t("signUp.consentLabel", { links: consentDocuments }),
691
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
692
+ import_react_native4.View,
693
+ {
694
+ style: [
695
+ styles.consentBox,
696
+ acceptedConsent && styles.consentBoxChecked,
697
+ busy && styles.consentBoxDisabled
698
+ ],
699
+ testID: "authowl-signup-consent-box",
700
+ children: acceptedConsent ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: styles.consentCheck, children: "\u2713" }) : null
701
+ }
702
+ )
703
+ }
704
+ ),
705
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.Text, { style: styles.consentText, children: [
706
+ consentPrefix,
707
+ termsUrl ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
708
+ import_react_native4.Text,
709
+ {
710
+ style: styles.consentLink,
711
+ onPress: () => void import_react_native4.Linking.openURL(termsUrl),
712
+ testID: "authowl-signup-terms",
713
+ children: t("consent.termsOfService")
714
+ }
715
+ ) : null,
716
+ termsUrl && privacyUrl ? t("consent.docJoiner") : null,
717
+ privacyUrl ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
718
+ import_react_native4.Text,
719
+ {
720
+ style: styles.consentLink,
721
+ onPress: () => void import_react_native4.Linking.openURL(privacyUrl),
722
+ testID: "authowl-signup-privacy",
723
+ children: t("consent.privacyPolicy")
724
+ }
725
+ ) : null,
726
+ consentSuffix
727
+ ] })
728
+ ] }) : null,
729
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FormError, { message: error, theme }),
730
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
731
+ SubmitButton,
732
+ {
733
+ label: t("signUp.submit"),
734
+ busyLabel: t("signUp.submitPending"),
735
+ onPress: submit,
736
+ busy,
737
+ disabled: !canSubmit,
738
+ theme,
739
+ testID: "authowl-signup-submit"
740
+ }
741
+ )
742
+ ] });
743
+ }
744
+
745
+ // src/components/EmailOtpForm.tsx
746
+ var import_react6 = require("react");
747
+ var import_react_native5 = require("react-native");
748
+ var import_jsx_runtime4 = require("react/jsx-runtime");
749
+ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
750
+ const t = useT();
751
+ const toMessage = useServerError();
752
+ const client = useAuthOwlClient();
753
+ const styles = useStyles(theme);
754
+ const [stage, setStage] = (0, import_react6.useState)("email");
755
+ const [email, setEmail] = (0, import_react6.useState)("");
756
+ const [code, setCode] = (0, import_react6.useState)("");
757
+ const [busy, setBusy] = (0, import_react6.useState)(false);
758
+ const [error, setError] = (0, import_react6.useState)(null);
759
+ async function requestCode() {
760
+ if (busy || email.trim().length === 0) return;
761
+ setBusy(true);
762
+ setError(null);
763
+ const result = await client.emailOtp.sendVerificationOtp({
764
+ email: email.trim(),
765
+ type: "sign-in"
766
+ });
767
+ setBusy(false);
768
+ if (result.error !== null) {
769
+ setError(toMessage(result.error, "emailOtp.error.sendFailed"));
770
+ return;
771
+ }
772
+ setStage("code");
773
+ }
774
+ async function verifyCode() {
775
+ if (busy || code.trim().length === 0) return;
776
+ setBusy(true);
777
+ setError(null);
778
+ const result = await client.signIn.emailOtp({ email: email.trim(), otp: code.trim() });
779
+ setBusy(false);
780
+ if (result.error !== null) {
781
+ setError(toMessage(result.error, "emailOtp.error.invalidCode"));
782
+ return;
783
+ }
784
+ onSignedIn?.();
785
+ }
786
+ function changeEmail() {
787
+ setStage("email");
788
+ setCode("");
789
+ setError(null);
790
+ }
791
+ if (stage === "email") {
792
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: styles.container, testID: "authowl-emailotp", children: [
793
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
794
+ Field,
795
+ {
796
+ label: t("common.emailLabel"),
797
+ value: email,
798
+ onChangeText: setEmail,
799
+ theme,
800
+ editable: !busy,
801
+ testID: "authowl-emailotp-email",
802
+ autoComplete: "email",
803
+ keyboardType: "email-address",
804
+ onSubmitEditing: requestCode
805
+ }
806
+ ),
807
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FormError, { message: error, theme }),
808
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
809
+ SubmitButton,
810
+ {
811
+ label: t("emailOtp.requestSubmit"),
812
+ busyLabel: t("common.sending"),
813
+ onPress: requestCode,
814
+ busy,
815
+ disabled: email.trim().length === 0,
816
+ theme,
817
+ testID: "authowl-emailotp-request"
818
+ }
819
+ )
820
+ ] });
821
+ }
822
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: styles.container, testID: "authowl-emailotp", children: [
823
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
824
+ Field,
825
+ {
826
+ label: t("emailOtp.codeLabel", { email: email.trim() }),
827
+ value: code,
828
+ onChangeText: setCode,
829
+ theme,
830
+ editable: !busy,
831
+ testID: "authowl-emailotp-code",
832
+ keyboardType: "number-pad",
833
+ autoComplete: "one-time-code",
834
+ onSubmitEditing: verifyCode
835
+ }
836
+ ),
837
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FormError, { message: error, theme }),
838
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
839
+ SubmitButton,
840
+ {
841
+ label: t("emailOtp.verifySubmit"),
842
+ busyLabel: t("common.verifying"),
843
+ onPress: verifyCode,
844
+ busy,
845
+ disabled: code.trim().length === 0,
846
+ theme,
847
+ testID: "authowl-emailotp-verify"
848
+ }
849
+ ),
850
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: styles.link, onPress: changeEmail, testID: "authowl-emailotp-change", children: t("emailOtp.changeEmail") })
851
+ ] });
852
+ }
853
+
854
+ // src/components/OrganizationSwitcher.tsx
855
+ var import_react7 = require("react");
856
+ var import_react_native6 = require("react-native");
857
+ var import_jsx_runtime5 = require("react/jsx-runtime");
858
+ function OrganizationSwitcher({
859
+ onSwitched,
860
+ allowPersonal = false,
861
+ theme = defaultTheme
862
+ }) {
863
+ const t = useT();
864
+ const toMessage = useServerError();
865
+ const client = useAuthOwlClient();
866
+ const config = usePublicConfig();
867
+ const session = useSession();
868
+ const styles = useStyles(theme);
869
+ const [organizations, setOrganizations] = (0, import_react7.useState)(null);
870
+ const [switching, setSwitching] = (0, import_react7.useState)(null);
871
+ const [error, setError] = (0, import_react7.useState)(null);
872
+ const activeId = session.data?.session.activeOrganizationId ?? null;
873
+ const userId = session.data?.user.id ?? null;
874
+ const signedIn = userId !== null;
875
+ const requestGeneration = (0, import_react7.useRef)(0);
876
+ const load = (0, import_react7.useCallback)(async () => {
877
+ const generation = ++requestGeneration.current;
878
+ setError(null);
879
+ const result = await client.organization.list();
880
+ if (generation !== requestGeneration.current) return;
881
+ if (result.error !== null) {
882
+ setError(toMessage(result.error, "organization.error.load"));
883
+ return;
884
+ }
885
+ setOrganizations(result.data ?? []);
886
+ }, [client, toMessage]);
887
+ (0, import_react7.useEffect)(() => {
888
+ requestGeneration.current += 1;
889
+ setOrganizations(null);
890
+ setError(null);
891
+ if (userId === null) return;
892
+ void load();
893
+ return () => {
894
+ requestGeneration.current += 1;
895
+ };
896
+ }, [userId, load]);
897
+ async function switchTo(organization) {
898
+ if (switching !== null) return;
899
+ setSwitching(organization?.id ?? "personal");
900
+ setError(null);
901
+ const result = await client.organization.setActive({
902
+ organizationId: organization?.id ?? null
903
+ });
904
+ setSwitching(null);
905
+ if (result.error !== null) {
906
+ setError(toMessage(result.error, "organization.switcher.error"));
907
+ return;
908
+ }
909
+ onSwitched?.(result.data ?? null);
910
+ }
911
+ if (config.isLoading || config.data !== null && !config.data.organizations) return null;
912
+ if (!signedIn) {
913
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.View, { style: styles.container, testID: "authowl-orgswitcher", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.Text, { style: styles.label, children: t("organization.signedOut") }) });
914
+ }
915
+ if (organizations === null && error === null) {
916
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.View, { style: styles.container, testID: "authowl-orgswitcher", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.Text, { style: styles.label, children: t("organization.loading") }) });
917
+ }
918
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native6.View, { style: styles.container, testID: "authowl-orgswitcher", children: [
919
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.Text, { style: styles.label, children: t("organization.switcher.label") }),
920
+ allowPersonal ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
921
+ OrganizationRow,
922
+ {
923
+ label: t("organization.personal"),
924
+ selected: activeId === null,
925
+ busy: switching === "personal",
926
+ disabled: switching !== null,
927
+ onPress: () => void switchTo(null),
928
+ testID: "authowl-orgswitcher-personal",
929
+ theme
930
+ }
931
+ ) : null,
932
+ (organizations ?? []).map((organization) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
933
+ OrganizationRow,
934
+ {
935
+ label: organization.name,
936
+ selected: organization.id === activeId,
937
+ busy: switching === organization.id,
938
+ disabled: switching !== null,
939
+ onPress: () => void switchTo(organization),
940
+ testID: `authowl-orgswitcher-${organization.id}`,
941
+ theme
942
+ },
943
+ organization.id
944
+ )),
945
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FormError, { message: error, theme, testID: "authowl-orgswitcher-error" }),
946
+ error !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
947
+ import_react_native6.Text,
948
+ {
949
+ style: styles.link,
950
+ onPress: () => void load(),
951
+ testID: "authowl-orgswitcher-retry",
952
+ children: t("organization.retry")
953
+ }
954
+ ) : null
955
+ ] });
956
+ }
957
+ function OrganizationRow({
958
+ label,
959
+ selected,
960
+ busy,
961
+ disabled,
962
+ onPress,
963
+ testID,
964
+ theme
965
+ }) {
966
+ const styles = useStyles(theme);
967
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
968
+ import_react_native6.Pressable,
969
+ {
970
+ onPress,
971
+ disabled: disabled || selected,
972
+ testID,
973
+ accessibilityRole: "button",
974
+ accessibilityState: { disabled: disabled || selected, busy },
975
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.Text, { style: selected ? [styles.label, { color: theme.accent }] : styles.label, children: label })
976
+ }
977
+ );
978
+ }
979
+
980
+ // src/components/PasskeyEnrollment.tsx
981
+ var import_react8 = require("react");
982
+ var import_react_native7 = require("react-native");
983
+ var import_native6 = require("@authowl/core/native");
984
+ var import_jsx_runtime6 = require("react/jsx-runtime");
985
+ function usePasskeyClient() {
986
+ const client = useAuthOwlClient();
987
+ return "addPasskey" in client.passkey ? client : null;
988
+ }
989
+ function PasskeyEnrollment({
990
+ name,
991
+ onEnrolled,
992
+ onSkip,
993
+ theme = defaultTheme
994
+ }) {
995
+ const t = useT();
996
+ const toMessage = useServerError();
997
+ const client = usePasskeyClient();
998
+ const config = usePublicConfig();
999
+ const capabilities = (0, import_native6.resolveProjectCapabilities)(config.data);
1000
+ const styles = useStyles(theme);
1001
+ const [busy, setBusy] = (0, import_react8.useState)(false);
1002
+ const [error, setError] = (0, import_react8.useState)(null);
1003
+ if (client === null || config.isLoading || config.data !== null && !capabilities.passkeyAdd) {
1004
+ return null;
1005
+ }
1006
+ async function enrol() {
1007
+ if (busy || client === null) return;
1008
+ setBusy(true);
1009
+ setError(null);
1010
+ const result = await client.passkey.addPasskey(name === void 0 ? {} : { name });
1011
+ setBusy(false);
1012
+ if (result.error !== null) {
1013
+ setError(toMessage(result.error, "signUp.error.passkeyFailed"));
1014
+ return;
1015
+ }
1016
+ onEnrolled?.();
1017
+ }
1018
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: styles.container, testID: "authowl-passkey-enrollment", children: [
1019
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: styles.title, children: t("signUp.passkeyTitle") }),
1020
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: styles.label, children: t("signUp.passkeyDescription") }),
1021
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormError, { message: error, theme, testID: "authowl-passkey-error" }),
1022
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1023
+ SubmitButton,
1024
+ {
1025
+ label: t("signUp.passkeySubmit"),
1026
+ busyLabel: t("passkey.waiting"),
1027
+ onPress: () => void enrol(),
1028
+ busy,
1029
+ theme,
1030
+ testID: "authowl-passkey-submit"
1031
+ }
1032
+ ),
1033
+ onSkip ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.Text, { style: styles.link, onPress: onSkip, testID: "authowl-passkey-skip", children: t("signUp.passkeySkip") }) : null
1034
+ ] });
1035
+ }
1036
+ function PasskeySignInButton({
1037
+ onSignedIn,
1038
+ theme = defaultTheme
1039
+ }) {
1040
+ const t = useT();
1041
+ const toMessage = useServerError();
1042
+ const client = usePasskeyClient();
1043
+ const config = usePublicConfig();
1044
+ const capabilities = (0, import_native6.resolveProjectCapabilities)(config.data);
1045
+ const styles = useStyles(theme);
1046
+ const [busy, setBusy] = (0, import_react8.useState)(false);
1047
+ const [error, setError] = (0, import_react8.useState)(null);
1048
+ if (client === null || config.isLoading || config.data !== null && !capabilities.passkeySignIn) return null;
1049
+ async function signIn() {
1050
+ if (busy || client === null) return;
1051
+ setBusy(true);
1052
+ setError(null);
1053
+ const result = await client.signIn.passkey();
1054
+ setBusy(false);
1055
+ if (result.error !== null) {
1056
+ setError(toMessage(result.error, "passkey.error.signInFailed"));
1057
+ return;
1058
+ }
1059
+ onSignedIn?.();
1060
+ }
1061
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: styles.container, testID: "authowl-passkey-signin", children: [
1062
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1063
+ SubmitButton,
1064
+ {
1065
+ label: t("passkey.signInButton"),
1066
+ busyLabel: t("passkey.waiting"),
1067
+ onPress: () => void signIn(),
1068
+ busy,
1069
+ theme,
1070
+ testID: "authowl-passkey-signin-submit"
1071
+ }
1072
+ ),
1073
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormError, { message: error, theme, testID: "authowl-passkey-signin-error" })
1074
+ ] });
1075
+ }
1076
+
1077
+ // src/passkeys.ts
1078
+ var import_native7 = require("@authowl/core/native");
1079
+ function createNativePasskeys(adapter) {
1080
+ return (http, sessionChanged) => (0, import_native7.createPasskeyClient)(http, sessionChanged, {
1081
+ register: ({ optionsJSON }) => adapter.register(optionsJSON),
1082
+ authenticate: ({ optionsJSON }) => adapter.authenticate(optionsJSON),
1083
+ errorCode: adapter.errorCode?.bind(adapter)
1084
+ });
1085
+ }
1086
+
1087
+ // src/components/SocialButtons.tsx
1088
+ var import_react9 = require("react");
1089
+ var import_react_native8 = require("react-native");
1090
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1091
+ function SocialButtons({
1092
+ providers,
1093
+ onSignedIn,
1094
+ theme = defaultTheme
1095
+ }) {
1096
+ const t = useT();
1097
+ const toMessage = useServerError();
1098
+ const client = useAuthOwlClient();
1099
+ const styles = useStyles(theme);
1100
+ const [pending, setPending] = (0, import_react9.useState)(null);
1101
+ const [error, setError] = (0, import_react9.useState)(null);
1102
+ async function signIn(provider) {
1103
+ if (pending !== null) return;
1104
+ setPending(provider.id);
1105
+ setError(null);
1106
+ try {
1107
+ const idToken = await provider.getIdToken();
1108
+ if (idToken === null) return;
1109
+ const result = await client.signIn.social({ provider: provider.id, idToken });
1110
+ if (result.error !== null) {
1111
+ setError(toMessage(result.error, "social.error.startFailed"));
1112
+ return;
1113
+ }
1114
+ onSignedIn?.();
1115
+ } catch {
1116
+ setError(t("social.error.startFailed"));
1117
+ } finally {
1118
+ setPending(null);
1119
+ }
1120
+ }
1121
+ if (providers.length === 0) return null;
1122
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles.container, testID: "authowl-social", children: [
1123
+ providers.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1124
+ SubmitButton,
1125
+ {
1126
+ label: t("social.continueWith", { provider: provider.label }),
1127
+ busyLabel: t("social.redirecting"),
1128
+ onPress: () => {
1129
+ void signIn(provider);
1130
+ },
1131
+ busy: pending === provider.id,
1132
+ disabled: pending !== null && pending !== provider.id,
1133
+ theme,
1134
+ testID: `authowl-social-${provider.id}`
1135
+ },
1136
+ provider.id
1137
+ )),
1138
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FormError, { message: error, theme, testID: "authowl-social-error" })
1139
+ ] });
1140
+ }
1141
+
1142
+ // src/storage.ts
1143
+ var MemoryStorage = class {
1144
+ entries = /* @__PURE__ */ new Map();
1145
+ async getItem(key) {
1146
+ return this.entries.get(key) ?? null;
1147
+ }
1148
+ async setItem(key, value) {
1149
+ this.entries.set(key, value);
1150
+ }
1151
+ async removeItem(key) {
1152
+ this.entries.delete(key);
1153
+ }
1154
+ };
1155
+
1156
+ // src/index.ts
1157
+ var import_native8 = require("@authowl/core/native");
1158
+ // Annotate the CommonJS export names for ESM import in node:
1159
+ 0 && (module.exports = {
1160
+ AuthOwlProvider,
1161
+ EmailOtpForm,
1162
+ Field,
1163
+ FormError,
1164
+ MemoryStorage,
1165
+ OrganizationSwitcher,
1166
+ PasskeyEnrollment,
1167
+ PasskeySignInButton,
1168
+ SignIn,
1169
+ SignUp,
1170
+ SocialButtons,
1171
+ SubmitButton,
1172
+ createAuthOwlNative,
1173
+ createCookieJarFetch,
1174
+ createNativePasskeys,
1175
+ createStyles,
1176
+ darkTheme,
1177
+ defaultTheme,
1178
+ readSetCookie,
1179
+ sessionCookieName,
1180
+ sessionStorageKey,
1181
+ signInWithSocialIdToken,
1182
+ useAuth,
1183
+ useAuthOwlClient,
1184
+ useAuthOwlLocale,
1185
+ useLocale,
1186
+ usePublicConfig,
1187
+ useServerError,
1188
+ useSession,
1189
+ useSocialSignIn,
1190
+ useStyles,
1191
+ useT,
1192
+ useUser
1193
+ });