@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.
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/__tests__/auth-client.test.ts +105 -0
- package/src/__tests__/security/localStorage-encryption.test.ts +171 -0
- package/src/auth-client.ts +158 -0
- package/src/dashboard-client.ts +60 -0
- package/src/index.ts +88 -0
- package/src/kv-client.ts +316 -0
- package/src/lib/cross-origin-auth.ts +99 -0
- package/src/stubs/captcha.ts +24 -0
- package/src/stubs/hashes.ts +16 -0
- package/src/stubs/index.ts +17 -0
- package/src/stubs/passkey.ts +12 -0
- package/src/stubs/qr-code.ts +10 -0
- package/src/stubs/query.ts +16 -0
- package/src/stubs/realtime.ts +17 -0
- package/src/stubs/use-sync-external-store.ts +12 -0
- package/src/styles.css +141 -0
- package/src/types.ts +14 -0
- package/src/ui/components/auth/auth-callback.tsx +36 -0
- package/src/ui/components/auth/auth-form.tsx +310 -0
- package/src/ui/components/auth/auth-view.tsx +435 -0
- package/src/ui/components/auth/email-otp-button.tsx +53 -0
- package/src/ui/components/auth/forms/email-otp-form.tsx +312 -0
- package/src/ui/components/auth/forms/email-verification-form.tsx +271 -0
- package/src/ui/components/auth/forms/forgot-password-form.tsx +173 -0
- package/src/ui/components/auth/forms/magic-link-form.tsx +196 -0
- package/src/ui/components/auth/forms/recover-account-form.tsx +143 -0
- package/src/ui/components/auth/forms/reset-password-form.tsx +220 -0
- package/src/ui/components/auth/forms/sign-in-form.tsx +323 -0
- package/src/ui/components/auth/forms/sign-up-form.tsx +820 -0
- package/src/ui/components/auth/forms/two-factor-form.tsx +381 -0
- package/src/ui/components/auth/magic-link-button.tsx +54 -0
- package/src/ui/components/auth/one-tap.tsx +53 -0
- package/src/ui/components/auth/otp-input-group.tsx +65 -0
- package/src/ui/components/auth/passkey-button.tsx +91 -0
- package/src/ui/components/auth/provider-button.tsx +155 -0
- package/src/ui/components/auth/sign-out.tsx +25 -0
- package/src/ui/components/auth/wallet-button.tsx +192 -0
- package/src/ui/components/auth-loading.tsx +21 -0
- package/src/ui/components/captcha/captcha.tsx +91 -0
- package/src/ui/components/captcha/recaptcha-badge.tsx +61 -0
- package/src/ui/components/captcha/recaptcha-v2.tsx +58 -0
- package/src/ui/components/captcha/recaptcha-v3.tsx +73 -0
- package/src/ui/components/email/email-template.tsx +216 -0
- package/src/ui/components/form-error.tsx +27 -0
- package/src/ui/components/password-input.tsx +56 -0
- package/src/ui/components/provider-icons.tsx +404 -0
- package/src/ui/components/redirect-to-sign-in.tsx +16 -0
- package/src/ui/components/redirect-to-sign-up.tsx +16 -0
- package/src/ui/components/signed-in.tsx +20 -0
- package/src/ui/components/signed-out.tsx +20 -0
- package/src/ui/components/ui/alert.tsx +66 -0
- package/src/ui/components/ui/button.tsx +70 -0
- package/src/ui/components/ui/card.tsx +92 -0
- package/src/ui/components/ui/checkbox.tsx +66 -0
- package/src/ui/components/ui/field.tsx +248 -0
- package/src/ui/components/ui/form.tsx +165 -0
- package/src/ui/components/ui/input-otp.tsx +77 -0
- package/src/ui/components/ui/input.tsx +21 -0
- package/src/ui/components/ui/label.tsx +23 -0
- package/src/ui/components/ui/separator.tsx +34 -0
- package/src/ui/components/ui/skeleton.tsx +13 -0
- package/src/ui/components/ui/textarea.tsx +18 -0
- package/src/ui/components/user-avatar.tsx +151 -0
- package/src/ui/hooks/use-auth-data.ts +193 -0
- package/src/ui/hooks/use-authenticate.ts +64 -0
- package/src/ui/hooks/use-captcha.tsx +151 -0
- package/src/ui/hooks/use-hydrated.ts +13 -0
- package/src/ui/hooks/use-lang.ts +32 -0
- package/src/ui/hooks/use-success-transition.ts +41 -0
- package/src/ui/hooks/use-theme.ts +39 -0
- package/src/ui/index.ts +46 -0
- package/src/ui/instantdb.ts +1 -0
- package/src/ui/lib/auth-data-cache.ts +90 -0
- package/src/ui/lib/auth-ui-provider.tsx +769 -0
- package/src/ui/lib/gravatar-utils.ts +58 -0
- package/src/ui/lib/image-utils.ts +55 -0
- package/src/ui/lib/instantdb/model-names.ts +24 -0
- package/src/ui/lib/instantdb/use-instant-options.ts +98 -0
- package/src/ui/lib/instantdb/use-list-accounts.ts +38 -0
- package/src/ui/lib/instantdb/use-list-sessions.ts +53 -0
- package/src/ui/lib/instantdb/use-session.ts +55 -0
- package/src/ui/lib/social-providers.ts +150 -0
- package/src/ui/lib/tanstack/auth-ui-provider-tanstack.tsx +49 -0
- package/src/ui/lib/tanstack/use-tanstack-options.ts +112 -0
- package/src/ui/lib/triplit/model-names.ts +24 -0
- package/src/ui/lib/triplit/use-conditional-query.ts +82 -0
- package/src/ui/lib/triplit/use-list-accounts.ts +31 -0
- package/src/ui/lib/triplit/use-list-sessions.ts +33 -0
- package/src/ui/lib/triplit/use-session.ts +42 -0
- package/src/ui/lib/triplit/use-triplit-hooks.ts +68 -0
- package/src/ui/lib/triplit/use-triplit-token.ts +44 -0
- package/src/ui/lib/utils.ts +119 -0
- package/src/ui/lib/view-paths.ts +61 -0
- package/src/ui/lib/wallet.ts +129 -0
- package/src/ui/localization/admin-error-codes.ts +20 -0
- package/src/ui/localization/anonymous-error-codes.ts +6 -0
- package/src/ui/localization/api-key-error-codes.ts +32 -0
- package/src/ui/localization/auth-localization.ts +865 -0
- package/src/ui/localization/base-error-codes.ts +27 -0
- package/src/ui/localization/captcha-error-codes.ts +17 -0
- package/src/ui/localization/email-otp-error-codes.ts +7 -0
- package/src/ui/localization/generic-oauth-error-codes.ts +3 -0
- package/src/ui/localization/haveibeenpwned-error-codes.ts +4 -0
- package/src/ui/localization/multi-session-error-codes.ts +3 -0
- package/src/ui/localization/organization-error-codes.ts +57 -0
- package/src/ui/localization/passkey-error-codes.ts +10 -0
- package/src/ui/localization/phone-number-error-codes.ts +10 -0
- package/src/ui/localization/stripe-localization.ts +12 -0
- package/src/ui/localization/team-error-codes.ts +12 -0
- package/src/ui/localization/two-factor-error-codes.ts +12 -0
- package/src/ui/localization/username-error-codes.ts +9 -0
- package/src/ui/server.ts +4 -0
- package/src/ui/style.css +146 -0
- package/src/ui/tanstack.ts +1 -0
- package/src/ui/triplit.ts +1 -0
- package/src/ui/types/account-options.ts +35 -0
- package/src/ui/types/additional-fields.ts +21 -0
- package/src/ui/types/any-auth-client.ts +6 -0
- package/src/ui/types/api-key.ts +9 -0
- package/src/ui/types/auth-client.ts +41 -0
- package/src/ui/types/auth-hooks.ts +81 -0
- package/src/ui/types/auth-mutators.ts +21 -0
- package/src/ui/types/avatar-options.ts +29 -0
- package/src/ui/types/captcha-options.ts +32 -0
- package/src/ui/types/captcha-provider.ts +7 -0
- package/src/ui/types/credentials-options.ts +38 -0
- package/src/ui/types/delete-user-options.ts +7 -0
- package/src/ui/types/email-verification-options.ts +7 -0
- package/src/ui/types/fetch-error.ts +6 -0
- package/src/ui/types/generic-oauth-options.ts +16 -0
- package/src/ui/types/gravatar-options.ts +21 -0
- package/src/ui/types/image.ts +7 -0
- package/src/ui/types/invitation.ts +10 -0
- package/src/ui/types/link.ts +7 -0
- package/src/ui/types/organization-options.ts +106 -0
- package/src/ui/types/password-validation.ts +16 -0
- package/src/ui/types/profile.ts +15 -0
- package/src/ui/types/refetch.ts +1 -0
- package/src/ui/types/render-toast.ts +9 -0
- package/src/ui/types/sign-up-options.ts +7 -0
- package/src/ui/types/social-options.ts +16 -0
- 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
|
+
}
|