@erikey/react 0.4.26 → 0.4.28

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.
Files changed (145) hide show
  1. package/dist/index.mjs +1 -1
  2. package/dist/index.mjs.map +1 -1
  3. package/package.json +2 -1
  4. package/src/__tests__/auth-client.test.ts +105 -0
  5. package/src/__tests__/security/localStorage-encryption.test.ts +171 -0
  6. package/src/auth-client.ts +158 -0
  7. package/src/dashboard-client.ts +60 -0
  8. package/src/index.ts +88 -0
  9. package/src/kv-client.ts +316 -0
  10. package/src/lib/cross-origin-auth.ts +99 -0
  11. package/src/stubs/captcha.ts +24 -0
  12. package/src/stubs/hashes.ts +16 -0
  13. package/src/stubs/index.ts +17 -0
  14. package/src/stubs/passkey.ts +12 -0
  15. package/src/stubs/qr-code.ts +10 -0
  16. package/src/stubs/query.ts +16 -0
  17. package/src/stubs/realtime.ts +17 -0
  18. package/src/stubs/use-sync-external-store.ts +12 -0
  19. package/src/styles.css +141 -0
  20. package/src/types.ts +14 -0
  21. package/src/ui/components/auth/auth-callback.tsx +36 -0
  22. package/src/ui/components/auth/auth-form.tsx +310 -0
  23. package/src/ui/components/auth/auth-view.tsx +435 -0
  24. package/src/ui/components/auth/email-otp-button.tsx +53 -0
  25. package/src/ui/components/auth/forms/email-otp-form.tsx +312 -0
  26. package/src/ui/components/auth/forms/email-verification-form.tsx +271 -0
  27. package/src/ui/components/auth/forms/forgot-password-form.tsx +173 -0
  28. package/src/ui/components/auth/forms/magic-link-form.tsx +196 -0
  29. package/src/ui/components/auth/forms/recover-account-form.tsx +143 -0
  30. package/src/ui/components/auth/forms/reset-password-form.tsx +220 -0
  31. package/src/ui/components/auth/forms/sign-in-form.tsx +323 -0
  32. package/src/ui/components/auth/forms/sign-up-form.tsx +820 -0
  33. package/src/ui/components/auth/forms/two-factor-form.tsx +381 -0
  34. package/src/ui/components/auth/magic-link-button.tsx +54 -0
  35. package/src/ui/components/auth/one-tap.tsx +53 -0
  36. package/src/ui/components/auth/otp-input-group.tsx +65 -0
  37. package/src/ui/components/auth/passkey-button.tsx +91 -0
  38. package/src/ui/components/auth/provider-button.tsx +155 -0
  39. package/src/ui/components/auth/sign-out.tsx +25 -0
  40. package/src/ui/components/auth/wallet-button.tsx +192 -0
  41. package/src/ui/components/auth-loading.tsx +21 -0
  42. package/src/ui/components/captcha/captcha.tsx +91 -0
  43. package/src/ui/components/captcha/recaptcha-badge.tsx +61 -0
  44. package/src/ui/components/captcha/recaptcha-v2.tsx +58 -0
  45. package/src/ui/components/captcha/recaptcha-v3.tsx +73 -0
  46. package/src/ui/components/email/email-template.tsx +216 -0
  47. package/src/ui/components/form-error.tsx +27 -0
  48. package/src/ui/components/password-input.tsx +56 -0
  49. package/src/ui/components/provider-icons.tsx +404 -0
  50. package/src/ui/components/redirect-to-sign-in.tsx +16 -0
  51. package/src/ui/components/redirect-to-sign-up.tsx +16 -0
  52. package/src/ui/components/signed-in.tsx +20 -0
  53. package/src/ui/components/signed-out.tsx +20 -0
  54. package/src/ui/components/ui/alert.tsx +66 -0
  55. package/src/ui/components/ui/button.tsx +70 -0
  56. package/src/ui/components/ui/card.tsx +92 -0
  57. package/src/ui/components/ui/checkbox.tsx +66 -0
  58. package/src/ui/components/ui/field.tsx +248 -0
  59. package/src/ui/components/ui/form.tsx +165 -0
  60. package/src/ui/components/ui/input-otp.tsx +77 -0
  61. package/src/ui/components/ui/input.tsx +21 -0
  62. package/src/ui/components/ui/label.tsx +23 -0
  63. package/src/ui/components/ui/separator.tsx +34 -0
  64. package/src/ui/components/ui/skeleton.tsx +13 -0
  65. package/src/ui/components/ui/textarea.tsx +18 -0
  66. package/src/ui/components/user-avatar.tsx +151 -0
  67. package/src/ui/hooks/use-auth-data.ts +193 -0
  68. package/src/ui/hooks/use-authenticate.ts +64 -0
  69. package/src/ui/hooks/use-captcha.tsx +151 -0
  70. package/src/ui/hooks/use-hydrated.ts +13 -0
  71. package/src/ui/hooks/use-lang.ts +32 -0
  72. package/src/ui/hooks/use-success-transition.ts +41 -0
  73. package/src/ui/hooks/use-theme.ts +39 -0
  74. package/src/ui/index.ts +46 -0
  75. package/src/ui/instantdb.ts +1 -0
  76. package/src/ui/lib/auth-data-cache.ts +90 -0
  77. package/src/ui/lib/auth-ui-provider.tsx +769 -0
  78. package/src/ui/lib/gravatar-utils.ts +58 -0
  79. package/src/ui/lib/image-utils.ts +55 -0
  80. package/src/ui/lib/instantdb/model-names.ts +24 -0
  81. package/src/ui/lib/instantdb/use-instant-options.ts +98 -0
  82. package/src/ui/lib/instantdb/use-list-accounts.ts +38 -0
  83. package/src/ui/lib/instantdb/use-list-sessions.ts +53 -0
  84. package/src/ui/lib/instantdb/use-session.ts +55 -0
  85. package/src/ui/lib/social-providers.ts +150 -0
  86. package/src/ui/lib/tanstack/auth-ui-provider-tanstack.tsx +49 -0
  87. package/src/ui/lib/tanstack/use-tanstack-options.ts +112 -0
  88. package/src/ui/lib/triplit/model-names.ts +24 -0
  89. package/src/ui/lib/triplit/use-conditional-query.ts +82 -0
  90. package/src/ui/lib/triplit/use-list-accounts.ts +31 -0
  91. package/src/ui/lib/triplit/use-list-sessions.ts +33 -0
  92. package/src/ui/lib/triplit/use-session.ts +42 -0
  93. package/src/ui/lib/triplit/use-triplit-hooks.ts +68 -0
  94. package/src/ui/lib/triplit/use-triplit-token.ts +44 -0
  95. package/src/ui/lib/utils.ts +119 -0
  96. package/src/ui/lib/view-paths.ts +61 -0
  97. package/src/ui/lib/wallet.ts +129 -0
  98. package/src/ui/localization/admin-error-codes.ts +20 -0
  99. package/src/ui/localization/anonymous-error-codes.ts +6 -0
  100. package/src/ui/localization/api-key-error-codes.ts +32 -0
  101. package/src/ui/localization/auth-localization.ts +865 -0
  102. package/src/ui/localization/base-error-codes.ts +27 -0
  103. package/src/ui/localization/captcha-error-codes.ts +17 -0
  104. package/src/ui/localization/email-otp-error-codes.ts +7 -0
  105. package/src/ui/localization/generic-oauth-error-codes.ts +3 -0
  106. package/src/ui/localization/haveibeenpwned-error-codes.ts +4 -0
  107. package/src/ui/localization/multi-session-error-codes.ts +3 -0
  108. package/src/ui/localization/organization-error-codes.ts +57 -0
  109. package/src/ui/localization/passkey-error-codes.ts +10 -0
  110. package/src/ui/localization/phone-number-error-codes.ts +10 -0
  111. package/src/ui/localization/stripe-localization.ts +12 -0
  112. package/src/ui/localization/team-error-codes.ts +12 -0
  113. package/src/ui/localization/two-factor-error-codes.ts +12 -0
  114. package/src/ui/localization/username-error-codes.ts +9 -0
  115. package/src/ui/server.ts +4 -0
  116. package/src/ui/style.css +146 -0
  117. package/src/ui/tanstack.ts +1 -0
  118. package/src/ui/triplit.ts +1 -0
  119. package/src/ui/types/account-options.ts +35 -0
  120. package/src/ui/types/additional-fields.ts +21 -0
  121. package/src/ui/types/any-auth-client.ts +6 -0
  122. package/src/ui/types/api-key.ts +9 -0
  123. package/src/ui/types/auth-client.ts +41 -0
  124. package/src/ui/types/auth-hooks.ts +81 -0
  125. package/src/ui/types/auth-mutators.ts +21 -0
  126. package/src/ui/types/avatar-options.ts +29 -0
  127. package/src/ui/types/captcha-options.ts +32 -0
  128. package/src/ui/types/captcha-provider.ts +7 -0
  129. package/src/ui/types/credentials-options.ts +38 -0
  130. package/src/ui/types/delete-user-options.ts +7 -0
  131. package/src/ui/types/email-verification-options.ts +7 -0
  132. package/src/ui/types/fetch-error.ts +6 -0
  133. package/src/ui/types/generic-oauth-options.ts +16 -0
  134. package/src/ui/types/gravatar-options.ts +21 -0
  135. package/src/ui/types/image.ts +7 -0
  136. package/src/ui/types/invitation.ts +10 -0
  137. package/src/ui/types/link.ts +7 -0
  138. package/src/ui/types/organization-options.ts +106 -0
  139. package/src/ui/types/password-validation.ts +16 -0
  140. package/src/ui/types/profile.ts +15 -0
  141. package/src/ui/types/refetch.ts +1 -0
  142. package/src/ui/types/render-toast.ts +9 -0
  143. package/src/ui/types/sign-up-options.ts +7 -0
  144. package/src/ui/types/social-options.ts +16 -0
  145. package/src/ui/types/team-options.ts +47 -0
@@ -0,0 +1,769 @@
1
+ "use client"
2
+
3
+ import { createContext, type ReactNode, useMemo } from "react"
4
+
5
+ import { RecaptchaV3 } from "../components/captcha/recaptcha-v3"
6
+ import { useAuthData } from "../hooks/use-auth-data"
7
+ import {
8
+ type AuthLocalization,
9
+ authLocalization
10
+ } from "../localization/auth-localization"
11
+ import type {
12
+ AccountOptions,
13
+ AccountOptionsContext
14
+ } from "../types/account-options"
15
+ import type { AdditionalFields } from "../types/additional-fields"
16
+ import type { AnyAuthClient } from "../types/any-auth-client"
17
+ import type { AuthClient } from "../types/auth-client"
18
+ import type { AuthHooks } from "../types/auth-hooks"
19
+ import type { AuthMutators } from "../types/auth-mutators"
20
+ import type { AvatarOptions } from "../types/avatar-options"
21
+ import type { CaptchaOptions } from "../types/captcha-options"
22
+ import type { CredentialsOptions } from "../types/credentials-options"
23
+ import type { DeleteUserOptions } from "../types/delete-user-options"
24
+ import type { EmailVerificationOptions } from "../types/email-verification-options"
25
+ import type { GenericOAuthOptions } from "../types/generic-oauth-options"
26
+ import type { GravatarOptions } from "../types/gravatar-options"
27
+ import type { Link } from "../types/link"
28
+ import type {
29
+ OrganizationOptions,
30
+ OrganizationOptionsContext
31
+ } from "../types/organization-options"
32
+ import type { RenderToast } from "../types/render-toast"
33
+ import type { SignUpOptions } from "../types/sign-up-options"
34
+ import type { SocialOptions } from "../types/social-options"
35
+ import type { TeamOptions, TeamOptionsContext } from "../types/team-options"
36
+ import type { AuthViewPaths } from "./view-paths"
37
+ import {
38
+ accountViewPaths,
39
+ authViewPaths,
40
+ organizationViewPaths
41
+ } from "./view-paths"
42
+
43
+ const DefaultLink: Link = ({ href, className, children }) => (
44
+ <a className={className} href={href}>
45
+ {children}
46
+ </a>
47
+ )
48
+
49
+ const defaultNavigate = (href: string) => {
50
+ window.location.href = href
51
+ }
52
+
53
+ const defaultReplace = (href: string) => {
54
+ window.location.replace(href)
55
+ }
56
+
57
+ // Default toast is a no-op - users should provide their own via onError/onSuccess
58
+ const defaultToast: RenderToast = () => {}
59
+
60
+ export type AuthUIContextType = {
61
+ authClient: AuthClient
62
+ /**
63
+ * Additional fields for users
64
+ */
65
+ additionalFields?: AdditionalFields
66
+ /**
67
+ * API Key plugin configuration
68
+ */
69
+ apiKey?:
70
+ | {
71
+ /**
72
+ * Prefix for API Keys
73
+ */
74
+ prefix?: string
75
+ /**
76
+ * Metadata for API Keys
77
+ */
78
+ metadata?: Record<string, unknown>
79
+ }
80
+ | boolean
81
+ /**
82
+ * Avatar configuration
83
+ * @default undefined
84
+ */
85
+ avatar?: AvatarOptions
86
+ /**
87
+ * Base path for the auth views
88
+ * @default "/auth"
89
+ */
90
+ basePath: string
91
+ /**
92
+ * Front end base URL for auth API callbacks
93
+ */
94
+ baseURL?: string
95
+ /**
96
+ * Captcha configuration
97
+ */
98
+ captcha?: CaptchaOptions
99
+ credentials?: CredentialsOptions
100
+ /**
101
+ * Default redirect URL after authenticating
102
+ * @default "/"
103
+ */
104
+ redirectTo: string
105
+ /**
106
+ * Enable or disable user change email support
107
+ * @default true
108
+ */
109
+ changeEmail?: boolean
110
+ /**
111
+ * User Account deletion configuration
112
+ * @default undefined
113
+ */
114
+ deleteUser?: DeleteUserOptions
115
+ /**
116
+ * Email verification configuration
117
+ */
118
+ emailVerification?: EmailVerificationOptions
119
+ /**
120
+ * Freshness age for Session data
121
+ * @default 60 * 60 * 24
122
+ */
123
+ freshAge: number
124
+ /**
125
+ * Generic OAuth provider configuration
126
+ */
127
+ genericOAuth?: GenericOAuthOptions
128
+ /**
129
+ * Gravatar configuration
130
+ */
131
+ gravatar?: boolean | GravatarOptions
132
+ hooks: AuthHooks
133
+ localization: typeof authLocalization
134
+ /**
135
+ * Enable or disable error localization.
136
+ * When false, errors messages from backend will be used directly.
137
+ * @default true
138
+ */
139
+ localizeErrors: boolean
140
+ /**
141
+ * Enable or disable Magic Link support
142
+ * @default false
143
+ */
144
+ magicLink?: boolean
145
+ /**
146
+ * Enable or disable Email OTP support
147
+ * @default false
148
+ */
149
+ emailOTP?: boolean
150
+ /**
151
+ * Enable or disable Multi Session support
152
+ * @default false
153
+ */
154
+ multiSession?: boolean
155
+ mutators: AuthMutators
156
+ /**
157
+ * Whether the name field should be required
158
+ * @default true
159
+ */
160
+ nameRequired?: boolean
161
+ /**
162
+ * Enable or disable One Tap support
163
+ * @default false
164
+ */
165
+ oneTap?: boolean
166
+ /**
167
+ * Perform some User updates optimistically
168
+ * @default false
169
+ */
170
+ optimistic?: boolean
171
+ /**
172
+ * Organization configuration
173
+ */
174
+ organization?: OrganizationOptionsContext
175
+ /**
176
+ * Teams configuration (requires organizations to be enabled)
177
+ */
178
+ teams?: TeamOptionsContext
179
+ /**
180
+ * Enable or disable Passkey support
181
+ * @default false
182
+ */
183
+ passkey?: boolean
184
+ /**
185
+ * Enable or disable Wallet (SIWE) support
186
+ * @default false
187
+ */
188
+ wallet?: boolean
189
+ /**
190
+ * Forces better-auth-tanstack to refresh the Session on the auth callback page
191
+ * @default false
192
+ */
193
+ persistClient?: boolean
194
+ /**
195
+ * Account configuration
196
+ */
197
+ account?: AccountOptionsContext
198
+ /**
199
+ * Sign Up configuration
200
+ */
201
+ signUp?: SignUpOptions
202
+ /**
203
+ * Social provider configuration
204
+ */
205
+ social?: SocialOptions
206
+ toast: RenderToast
207
+ /**
208
+ * Enable or disable two-factor authentication support
209
+ * @default undefined
210
+ */
211
+ twoFactor?: ("otp" | "totp")[]
212
+ viewPaths: AuthViewPaths
213
+ /**
214
+ * Navigate to a new URL
215
+ * @default window.location.href
216
+ */
217
+ navigate: (href: string) => void
218
+ /**
219
+ * Called whenever the Session changes
220
+ */
221
+ onSessionChange?: () => void | Promise<void>
222
+ /**
223
+ * Replace the current URL
224
+ * @default navigate
225
+ */
226
+ replace: (href: string) => void
227
+ /**
228
+ * Custom Link component for navigation
229
+ * @default <a>
230
+ */
231
+ Link: Link
232
+ }
233
+
234
+ export type AuthUIProviderProps = {
235
+ children: ReactNode
236
+ /**
237
+ * Better Auth client returned from createAuthClient
238
+ * @default Required
239
+ * @remarks `AuthClient`
240
+ */
241
+ authClient: AnyAuthClient
242
+ /**
243
+ * Enable account view & account configuration
244
+ * @default { fields: ["image", "name"] }
245
+ */
246
+ account?: boolean | Partial<AccountOptions>
247
+ /**
248
+ * Avatar configuration
249
+ * @default undefined
250
+ */
251
+ avatar?: boolean | Partial<AvatarOptions>
252
+ /**
253
+ * User Account deletion configuration
254
+ * @default undefined
255
+ */
256
+ deleteUser?: DeleteUserOptions | boolean
257
+ /**
258
+ * ADVANCED: Custom hooks for fetching auth data
259
+ */
260
+ hooks?: Partial<AuthHooks>
261
+ /**
262
+ * Customize the paths for the auth views
263
+ * @default authViewPaths
264
+ * @remarks `AuthViewPaths`
265
+ */
266
+ viewPaths?: Partial<AuthViewPaths>
267
+ /**
268
+ * Email verification configuration
269
+ * @default undefined
270
+ */
271
+ emailVerification?: boolean | Partial<EmailVerificationOptions>
272
+ /**
273
+ * Render custom Toasts
274
+ * @default Sonner
275
+ */
276
+ toast?: RenderToast
277
+ /**
278
+ * Customize the Localization strings
279
+ * @default authLocalization
280
+ * @remarks `AuthLocalization`
281
+ */
282
+ localization?: AuthLocalization
283
+ /**
284
+ * Enable or disable error localization.
285
+ * When false, errors messages from backend will be used directly.
286
+ * @default true
287
+ */
288
+ localizeErrors?: boolean
289
+ /**
290
+ * ADVANCED: Custom mutators for updating auth data
291
+ */
292
+ mutators?: Partial<AuthMutators>
293
+ /**
294
+ * Organization plugin configuration
295
+ */
296
+ organization?: OrganizationOptions | boolean
297
+ /**
298
+ * Teams plugin configuration (requires organizations to be enabled)
299
+ */
300
+ teams?: TeamOptions | boolean
301
+ /**
302
+ * Enable or disable Credentials support
303
+ * @default { forgotPassword: true }
304
+ */
305
+ credentials?: boolean | CredentialsOptions
306
+ /**
307
+ * Enable or disable Sign Up form
308
+ * @default { fields: ["name"] }
309
+ */
310
+ signUp?: SignUpOptions | boolean
311
+ } & Partial<
312
+ Omit<
313
+ AuthUIContextType,
314
+ | "authClient"
315
+ | "viewPaths"
316
+ | "localization"
317
+ | "mutators"
318
+ | "toast"
319
+ | "hooks"
320
+ | "avatar"
321
+ | "account"
322
+ | "deleteUser"
323
+ | "credentials"
324
+ | "signUp"
325
+ | "organization"
326
+ | "localizeErrors"
327
+ | "teams"
328
+ | "emailVerification"
329
+ >
330
+ >
331
+
332
+ export const AuthUIContext = createContext<AuthUIContextType>(
333
+ {} as unknown as AuthUIContextType
334
+ )
335
+
336
+ export const AuthUIProvider = ({
337
+ children,
338
+ authClient: authClientProp,
339
+ account: accountProp,
340
+ avatar: avatarProp,
341
+ deleteUser: deleteUserProp,
342
+ social: socialProp,
343
+ genericOAuth: genericOAuthProp,
344
+ basePath = "/auth",
345
+ baseURL = typeof window !== 'undefined' ? window.location.origin : "",
346
+ captcha,
347
+ redirectTo = "/",
348
+ credentials: credentialsProp,
349
+ changeEmail = true,
350
+ freshAge = 60 * 60 * 24,
351
+ hooks: hooksProp,
352
+ mutators: mutatorsProp,
353
+ localization: localizationProp,
354
+ localizeErrors = true,
355
+ nameRequired = true,
356
+ organization: organizationProp,
357
+ teams: teamsProp,
358
+ signUp: signUpProp = true,
359
+ toast = defaultToast,
360
+ viewPaths: viewPathsProp,
361
+ navigate,
362
+ replace,
363
+ Link = DefaultLink,
364
+ emailVerification: emailVerificationProp,
365
+ ...props
366
+ }: AuthUIProviderProps) => {
367
+ const authClient = authClientProp as AuthClient
368
+
369
+ const avatar = useMemo<AvatarOptions | undefined>(() => {
370
+ if (!avatarProp) return
371
+
372
+ if (avatarProp === true) {
373
+ return {
374
+ extension: "png",
375
+ size: 128
376
+ }
377
+ }
378
+
379
+ return {
380
+ upload: avatarProp.upload,
381
+ delete: avatarProp.delete,
382
+ extension: avatarProp.extension || "png",
383
+ size: avatarProp.size || (avatarProp.upload ? 256 : 128),
384
+ Image: avatarProp.Image
385
+ }
386
+ }, [avatarProp])
387
+
388
+ const emailVerification = useMemo<
389
+ EmailVerificationOptions | undefined
390
+ >(() => {
391
+ if (!emailVerificationProp) return
392
+
393
+ if (emailVerificationProp === true) {
394
+ return {
395
+ otp: false
396
+ }
397
+ }
398
+
399
+ return {
400
+ otp: emailVerificationProp.otp ?? false
401
+ }
402
+ }, [emailVerificationProp])
403
+
404
+ const account = useMemo<AccountOptionsContext | undefined>(() => {
405
+ if (accountProp === false) return
406
+
407
+ if (accountProp === true || accountProp === undefined) {
408
+ return {
409
+ basePath: "/account",
410
+ fields: ["image", "name"],
411
+ viewPaths: accountViewPaths
412
+ }
413
+ }
414
+
415
+ // Remove trailing slash from basePath
416
+ const basePath = accountProp.basePath?.endsWith("/")
417
+ ? accountProp.basePath.slice(0, -1)
418
+ : accountProp.basePath
419
+
420
+ return {
421
+ basePath: basePath ?? "/account",
422
+ fields: accountProp.fields || ["image", "name"],
423
+ viewPaths: { ...accountViewPaths, ...accountProp.viewPaths }
424
+ }
425
+ }, [accountProp])
426
+
427
+ const deleteUser = useMemo<DeleteUserOptions | undefined>(() => {
428
+ if (!deleteUserProp) return
429
+
430
+ if (deleteUserProp === true) {
431
+ return {}
432
+ }
433
+
434
+ return deleteUserProp
435
+ }, [deleteUserProp])
436
+
437
+ const social = useMemo<SocialOptions | undefined>(() => {
438
+ if (!socialProp) return
439
+
440
+ return socialProp
441
+ }, [socialProp])
442
+
443
+ const genericOAuth = useMemo<GenericOAuthOptions | undefined>(() => {
444
+ if (!genericOAuthProp) return
445
+
446
+ return genericOAuthProp
447
+ }, [genericOAuthProp])
448
+
449
+ const credentials = useMemo<CredentialsOptions | undefined>(() => {
450
+ if (credentialsProp === false) return
451
+
452
+ if (credentialsProp === true) {
453
+ return {
454
+ forgotPassword: true,
455
+ usernameRequired: true
456
+ }
457
+ }
458
+
459
+ return {
460
+ ...credentialsProp,
461
+ forgotPassword: credentialsProp?.forgotPassword ?? true,
462
+ usernameRequired: credentialsProp?.usernameRequired ?? true
463
+ }
464
+ }, [credentialsProp])
465
+
466
+ const signUp = useMemo<SignUpOptions | undefined>(() => {
467
+ if (signUpProp === false) return
468
+
469
+ if (signUpProp === true || signUpProp === undefined) {
470
+ return {
471
+ fields: ["name"]
472
+ }
473
+ }
474
+
475
+ return {
476
+ fields: signUpProp.fields || ["name"]
477
+ }
478
+ }, [signUpProp])
479
+
480
+ const organization = useMemo<OrganizationOptionsContext | undefined>(() => {
481
+ if (!organizationProp) return
482
+
483
+ if (organizationProp === true) {
484
+ return {
485
+ basePath: "/organization",
486
+ viewPaths: organizationViewPaths,
487
+ customRoles: []
488
+ }
489
+ }
490
+
491
+ let logo: OrganizationOptionsContext["logo"] | undefined
492
+
493
+ if (organizationProp.logo === true) {
494
+ logo = {
495
+ extension: "png",
496
+ size: 128
497
+ }
498
+ } else if (organizationProp.logo) {
499
+ logo = {
500
+ upload: organizationProp.logo.upload,
501
+ delete: organizationProp.logo.delete,
502
+ extension: organizationProp.logo.extension || "png",
503
+ size:
504
+ organizationProp.logo.size ||
505
+ (organizationProp.logo.upload ? 256 : 128)
506
+ }
507
+ }
508
+
509
+ // Remove trailing slash from basePath
510
+ const basePath = organizationProp.basePath?.endsWith("/")
511
+ ? organizationProp.basePath.slice(0, -1)
512
+ : organizationProp.basePath
513
+
514
+ return {
515
+ ...organizationProp,
516
+ logo,
517
+ basePath: basePath ?? "/organization",
518
+ customRoles: organizationProp.customRoles || [],
519
+ viewPaths: {
520
+ ...organizationViewPaths,
521
+ ...organizationProp.viewPaths
522
+ }
523
+ }
524
+ }, [organizationProp])
525
+
526
+ const teams = useMemo<TeamOptionsContext | undefined>(() => {
527
+ if (!teamsProp || !organization) return
528
+
529
+ if (teamsProp === true) {
530
+ return {
531
+ enabled: true,
532
+ customRoles: [],
533
+ colors: {
534
+ count: 5,
535
+ prefix: "team"
536
+ }
537
+ }
538
+ }
539
+
540
+ return {
541
+ enabled: teamsProp.enabled ?? true,
542
+ customRoles: teamsProp.customRoles || [],
543
+ colors: {
544
+ count: teamsProp.colors?.count ?? 5,
545
+ prefix: teamsProp.colors?.prefix ?? "team"
546
+ }
547
+ }
548
+ }, [teamsProp, organization])
549
+
550
+ const defaultMutators = useMemo(() => {
551
+ return {
552
+ deleteApiKey: (params) =>
553
+ authClient.apiKey.delete({
554
+ ...params,
555
+ fetchOptions: { throw: true }
556
+ }),
557
+ deletePasskey: (params) =>
558
+ authClient.passkey.deletePasskey({
559
+ ...params,
560
+ fetchOptions: { throw: true }
561
+ }),
562
+ revokeDeviceSession: (params) =>
563
+ authClient.multiSession.revoke({
564
+ ...params,
565
+ fetchOptions: { throw: true }
566
+ }),
567
+ revokeSession: (params) =>
568
+ authClient.revokeSession({
569
+ ...params,
570
+ fetchOptions: { throw: true }
571
+ }),
572
+ setActiveSession: (params) =>
573
+ authClient.multiSession.setActive({
574
+ ...params,
575
+ fetchOptions: { throw: true }
576
+ }),
577
+ updateOrganization: (params) =>
578
+ authClient.organization.update({
579
+ ...params,
580
+ fetchOptions: { throw: true }
581
+ }),
582
+ updateTeam: (params) =>
583
+ authClient.$fetch("/organization/update-team", {
584
+ method: "POST",
585
+ body: params,
586
+ throw: true
587
+ }),
588
+ updateUser: (params) =>
589
+ authClient.updateUser({
590
+ ...params,
591
+ fetchOptions: { throw: true }
592
+ }),
593
+ unlinkAccount: (params) =>
594
+ authClient.unlinkAccount({
595
+ ...params,
596
+ fetchOptions: { throw: true }
597
+ })
598
+ } as AuthMutators
599
+ }, [authClient])
600
+
601
+ const defaultHooks = useMemo(() => {
602
+ return {
603
+ useSession: authClient.useSession,
604
+ useListAccounts: () =>
605
+ useAuthData({
606
+ queryFn: authClient.listAccounts,
607
+ cacheKey: "listAccounts"
608
+ }),
609
+ useAccountInfo: (params) =>
610
+ useAuthData({
611
+ queryFn: () => authClient.accountInfo(params),
612
+ cacheKey: `accountInfo:${JSON.stringify(params)}`
613
+ }),
614
+ useListDeviceSessions: () =>
615
+ useAuthData({
616
+ queryFn: authClient.multiSession.listDeviceSessions,
617
+ cacheKey: "listDeviceSessions"
618
+ }),
619
+ useListSessions: () =>
620
+ useAuthData({
621
+ queryFn: authClient.listSessions,
622
+ cacheKey: "listSessions"
623
+ }),
624
+ useListPasskeys: authClient.useListPasskeys,
625
+ useListApiKeys: () =>
626
+ useAuthData({
627
+ queryFn: authClient.apiKey.list,
628
+ cacheKey: "listApiKeys"
629
+ }),
630
+ useActiveOrganization: authClient.useActiveOrganization,
631
+ useListOrganizations: authClient.useListOrganizations,
632
+ useHasPermission: (params) =>
633
+ useAuthData({
634
+ queryFn: () =>
635
+ authClient.$fetch("/organization/has-permission", {
636
+ method: "POST",
637
+ body: params
638
+ }),
639
+ cacheKey: `hasPermission:${JSON.stringify(params)}`
640
+ }),
641
+ useInvitation: (params) =>
642
+ useAuthData({
643
+ queryFn: () =>
644
+ authClient.organization.getInvitation(params),
645
+ cacheKey: `invitation:${JSON.stringify(params)}`
646
+ }),
647
+ useListInvitations: (params) =>
648
+ useAuthData({
649
+ queryFn: () =>
650
+ authClient.$fetch(
651
+ `/organization/list-invitations?organizationId=${
652
+ params?.query?.organizationId || ""
653
+ }`
654
+ ),
655
+ cacheKey: `listInvitations:${JSON.stringify(params)}`
656
+ }),
657
+ useListUserInvitations: () =>
658
+ useAuthData({
659
+ queryFn: () =>
660
+ authClient.$fetch(
661
+ "/organization/list-user-invitations"
662
+ ),
663
+ cacheKey: `listUserInvitations`
664
+ }),
665
+ useListMembers: (params) =>
666
+ useAuthData({
667
+ queryFn: () =>
668
+ authClient.$fetch(
669
+ `/organization/list-members?organizationId=${
670
+ params?.query?.organizationId || ""
671
+ }`
672
+ ),
673
+ cacheKey: `listMembers:${JSON.stringify(params)}`
674
+ }),
675
+ useListTeams: (params) =>
676
+ useAuthData({
677
+ queryFn: () =>
678
+ authClient.$fetch(
679
+ `/organization/list-teams?organizationId=${
680
+ params?.organizationId || ""
681
+ }`
682
+ ),
683
+ cacheKey: `listTeams:${JSON.stringify(params)}`
684
+ }),
685
+ useListTeamMembers: (params) =>
686
+ useAuthData({
687
+ queryFn: () =>
688
+ authClient.$fetch("/organization/list-team-members", {
689
+ method: "POST",
690
+ body: params?.teamId
691
+ ? { query: { teamId: params.teamId } }
692
+ : undefined
693
+ }),
694
+ cacheKey: `listTeamMembers:${JSON.stringify(params)}`
695
+ }),
696
+ useListUserTeams: () =>
697
+ useAuthData({
698
+ queryFn: () =>
699
+ authClient.$fetch("/organization/list-user-teams"),
700
+ cacheKey: "listUserTeams"
701
+ })
702
+ } as unknown as AuthHooks
703
+ }, [authClient])
704
+
705
+ const viewPaths = useMemo(() => {
706
+ return { ...authViewPaths, ...viewPathsProp }
707
+ }, [viewPathsProp])
708
+
709
+ const localization = useMemo(() => {
710
+ return { ...authLocalization, ...localizationProp }
711
+ }, [localizationProp])
712
+
713
+ const hooks = useMemo(() => {
714
+ return { ...defaultHooks, ...hooksProp }
715
+ }, [defaultHooks, hooksProp])
716
+
717
+ const mutators = useMemo(() => {
718
+ return { ...defaultMutators, ...mutatorsProp }
719
+ }, [defaultMutators, mutatorsProp])
720
+
721
+ // Remove trailing slash from baseURL
722
+ baseURL = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL
723
+
724
+ // Remove trailing slash from basePath
725
+ basePath = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath
726
+
727
+ const { data: sessionData } = hooks.useSession()
728
+
729
+ return (
730
+ <AuthUIContext.Provider
731
+ value={{
732
+ authClient,
733
+ avatar,
734
+ basePath: basePath === "/" ? "" : basePath,
735
+ baseURL,
736
+ captcha,
737
+ redirectTo,
738
+ changeEmail,
739
+ credentials,
740
+ deleteUser,
741
+ emailVerification,
742
+ freshAge,
743
+ genericOAuth,
744
+ hooks,
745
+ mutators,
746
+ localization,
747
+ localizeErrors,
748
+ nameRequired,
749
+ organization,
750
+ teams,
751
+ account,
752
+ signUp,
753
+ social,
754
+ toast,
755
+ navigate: navigate || defaultNavigate,
756
+ replace: replace || navigate || defaultReplace,
757
+ viewPaths,
758
+ Link,
759
+ ...props
760
+ }}
761
+ >
762
+ {captcha?.provider === "google-recaptcha-v3" ? (
763
+ <RecaptchaV3>{children}</RecaptchaV3>
764
+ ) : (
765
+ children
766
+ )}
767
+ </AuthUIContext.Provider>
768
+ )
769
+ }