@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,36 @@
1
+ "use client"
2
+
3
+ import { Loader2 } from "lucide-react"
4
+ import { useContext, useEffect, useRef } from "react"
5
+
6
+ import { useOnSuccessTransition } from "../../hooks/use-success-transition"
7
+ import { AuthUIContext } from "../../lib/auth-ui-provider"
8
+
9
+ export function AuthCallback({ redirectTo }: { redirectTo?: string }) {
10
+ const {
11
+ hooks: { useIsRestoring },
12
+ persistClient
13
+ } = useContext(AuthUIContext)
14
+
15
+ const isRestoring = useIsRestoring?.()
16
+ const isRedirecting = useRef(false)
17
+
18
+ const { onSuccess } = useOnSuccessTransition({ redirectTo })
19
+
20
+ useEffect(() => {
21
+ if (isRedirecting.current) return
22
+
23
+ if (!persistClient) {
24
+ isRedirecting.current = true
25
+ onSuccess()
26
+ return
27
+ }
28
+
29
+ if (isRestoring) return
30
+
31
+ isRedirecting.current = true
32
+ onSuccess()
33
+ }, [isRestoring, persistClient, onSuccess])
34
+
35
+ return <Loader2 className="animate-spin" />
36
+ }
@@ -0,0 +1,310 @@
1
+ "use client"
2
+
3
+ import { useContext, useEffect } from "react"
4
+
5
+ import { AuthUIContext } from "../../lib/auth-ui-provider"
6
+ import { getViewByPath } from "../../lib/utils"
7
+ import type { AuthViewPath } from "../../lib/view-paths"
8
+ import type { AuthLocalization } from "../../localization/auth-localization"
9
+ import { AuthCallback } from "./auth-callback"
10
+ import { EmailOTPForm } from "./forms/email-otp-form"
11
+ import { EmailVerificationForm } from "./forms/email-verification-form"
12
+ import { ForgotPasswordForm } from "./forms/forgot-password-form"
13
+ import { MagicLinkForm } from "./forms/magic-link-form"
14
+ import { RecoverAccountForm } from "./forms/recover-account-form"
15
+ import { ResetPasswordForm } from "./forms/reset-password-form"
16
+ import { SignInForm } from "./forms/sign-in-form"
17
+ import { SignUpForm } from "./forms/sign-up-form"
18
+ import { TwoFactorForm } from "./forms/two-factor-form"
19
+ import { SignOut } from "./sign-out"
20
+
21
+ export type AuthFormClassNames = {
22
+ base?: string
23
+ button?: string
24
+ checkbox?: string
25
+ description?: string
26
+ error?: string
27
+ forgotPasswordLink?: string
28
+ icon?: string
29
+ input?: string
30
+ label?: string
31
+ otpInput?: string
32
+ otpInputContainer?: string
33
+ outlineButton?: string
34
+ primaryButton?: string
35
+ providerButton?: string
36
+ qrCode?: string
37
+ secondaryButton?: string
38
+ }
39
+
40
+ export interface AuthFormProps {
41
+ className?: string
42
+ classNames?: AuthFormClassNames
43
+ callbackURL?: string
44
+ isSubmitting?: boolean
45
+ localization?: Partial<AuthLocalization>
46
+ pathname?: string
47
+ redirectTo?: string
48
+ view?: AuthViewPath
49
+ otpSeparators?: 0 | 1 | 2
50
+ setIsSubmitting?: (isSubmitting: boolean) => void
51
+ }
52
+
53
+ /**
54
+ * Render the appropriate authentication UI view based on component props and AuthUIContext feature flags.
55
+ *
56
+ * The component chooses a view from (in priority): the `view` prop, a view resolved from `pathname`, or `"SIGN_IN"`, then validates that the view is allowed given enabled features and credentials before rendering the corresponding form component.
57
+ *
58
+ * @param className - Optional base CSS class applied to rendered form components
59
+ * @param classNames - Optional object of per-element CSS class overrides for rendered form components
60
+ * @param callbackURL - Optional URL used by flows that require a callback (magic link, email OTP)
61
+ * @param isSubmitting - Whether a form submission is currently in progress
62
+ * @param localization - Optional localization strings that override context-provided localization
63
+ * @param pathname - Optional path to resolve the active auth view when `view` is not provided
64
+ * @param redirectTo - Optional URL to redirect to after successful authentication
65
+ * @param view - Optional explicit view to render; takes precedence over `pathname`
66
+ * @param otpSeparators - Number of visual separators to render between OTP input groups
67
+ * @param setIsSubmitting - Setter to update the submitting state
68
+ * @returns The React element for the selected authentication view, or `null` if no suitable view is available.
69
+ */
70
+ export function AuthForm({
71
+ className,
72
+ classNames,
73
+ callbackURL,
74
+ isSubmitting,
75
+ localization,
76
+ pathname,
77
+ redirectTo,
78
+ view,
79
+ otpSeparators = 0,
80
+ setIsSubmitting
81
+ }: AuthFormProps) {
82
+ const {
83
+ basePath,
84
+ credentials,
85
+ localization: contextLocalization,
86
+ magicLink,
87
+ emailOTP,
88
+ signUp,
89
+ twoFactor: twoFactorEnabled,
90
+ viewPaths,
91
+ replace
92
+ } = useContext(AuthUIContext)
93
+
94
+ const signUpEnabled = !!signUp
95
+
96
+ localization = { ...contextLocalization, ...localization }
97
+
98
+ useEffect(() => {
99
+ if (pathname && !getViewByPath(viewPaths, pathname)) {
100
+ console.error(`Invalid auth view: ${pathname}`)
101
+ replace(`${basePath}/${viewPaths.SIGN_IN}${window.location.search}`)
102
+ }
103
+ }, [pathname, viewPaths, basePath, replace])
104
+
105
+ view =
106
+ view ||
107
+ (getViewByPath(viewPaths, pathname) as AuthViewPath) ||
108
+ "SIGN_IN"
109
+
110
+ // Redirect to appropriate view based on enabled features
111
+ useEffect(() => {
112
+ let isInvalidView = false
113
+
114
+ if (
115
+ view === "MAGIC_LINK" &&
116
+ (!magicLink || (!credentials && !emailOTP))
117
+ ) {
118
+ isInvalidView = true
119
+ }
120
+
121
+ if (
122
+ view === "EMAIL_OTP" &&
123
+ (!emailOTP || (!credentials && !magicLink))
124
+ ) {
125
+ isInvalidView = true
126
+ }
127
+
128
+ if (view === "SIGN_UP" && !signUpEnabled) {
129
+ isInvalidView = true
130
+ }
131
+
132
+ if (
133
+ !credentials &&
134
+ [
135
+ "SIGN_UP",
136
+ "FORGOT_PASSWORD",
137
+ "RESET_PASSWORD",
138
+ "TWO_FACTOR",
139
+ "RECOVER_ACCOUNT"
140
+ ].includes(view)
141
+ ) {
142
+ isInvalidView = true
143
+ }
144
+
145
+ if (
146
+ ["TWO_FACTOR", "RECOVER_ACCOUNT"].includes(view) &&
147
+ !twoFactorEnabled
148
+ ) {
149
+ isInvalidView = true
150
+ }
151
+
152
+ if (isInvalidView) {
153
+ replace(`${basePath}/${viewPaths.SIGN_IN}${window.location.search}`)
154
+ }
155
+ }, [
156
+ basePath,
157
+ view,
158
+ viewPaths,
159
+ credentials,
160
+ replace,
161
+ emailOTP,
162
+ signUpEnabled,
163
+ magicLink,
164
+ twoFactorEnabled
165
+ ])
166
+
167
+ if (view === "SIGN_OUT") return <SignOut redirectTo={redirectTo} />
168
+ if (view === "CALLBACK") return <AuthCallback redirectTo={redirectTo} />
169
+
170
+ if (view === "SIGN_IN") {
171
+ return credentials ? (
172
+ <SignInForm
173
+ className={className}
174
+ classNames={classNames}
175
+ localization={localization}
176
+ redirectTo={redirectTo}
177
+ isSubmitting={isSubmitting}
178
+ setIsSubmitting={setIsSubmitting}
179
+ />
180
+ ) : magicLink ? (
181
+ <MagicLinkForm
182
+ className={className}
183
+ classNames={classNames}
184
+ callbackURL={callbackURL}
185
+ localization={localization}
186
+ redirectTo={redirectTo}
187
+ isSubmitting={isSubmitting}
188
+ setIsSubmitting={setIsSubmitting}
189
+ />
190
+ ) : emailOTP ? (
191
+ <EmailOTPForm
192
+ className={className}
193
+ classNames={classNames}
194
+ callbackURL={callbackURL}
195
+ localization={localization}
196
+ redirectTo={redirectTo}
197
+ isSubmitting={isSubmitting}
198
+ setIsSubmitting={setIsSubmitting}
199
+ />
200
+ ) : null
201
+ }
202
+
203
+ if (view === "TWO_FACTOR") {
204
+ return (
205
+ <TwoFactorForm
206
+ className={className}
207
+ classNames={classNames}
208
+ localization={localization}
209
+ otpSeparators={otpSeparators}
210
+ redirectTo={redirectTo}
211
+ isSubmitting={isSubmitting}
212
+ setIsSubmitting={setIsSubmitting}
213
+ />
214
+ )
215
+ }
216
+
217
+ if (view === "RECOVER_ACCOUNT") {
218
+ return (
219
+ <RecoverAccountForm
220
+ className={className}
221
+ classNames={classNames}
222
+ localization={localization}
223
+ redirectTo={redirectTo}
224
+ isSubmitting={isSubmitting}
225
+ setIsSubmitting={setIsSubmitting}
226
+ />
227
+ )
228
+ }
229
+
230
+ if (view === "MAGIC_LINK") {
231
+ return (
232
+ <MagicLinkForm
233
+ className={className}
234
+ classNames={classNames}
235
+ callbackURL={callbackURL}
236
+ localization={localization}
237
+ redirectTo={redirectTo}
238
+ isSubmitting={isSubmitting}
239
+ setIsSubmitting={setIsSubmitting}
240
+ />
241
+ )
242
+ }
243
+
244
+ if (view === "EMAIL_OTP") {
245
+ return (
246
+ <EmailOTPForm
247
+ className={className}
248
+ classNames={classNames}
249
+ callbackURL={callbackURL}
250
+ localization={localization}
251
+ redirectTo={redirectTo}
252
+ isSubmitting={isSubmitting}
253
+ setIsSubmitting={setIsSubmitting}
254
+ />
255
+ )
256
+ }
257
+
258
+ if (view === "EMAIL_VERIFICATION") {
259
+ return (
260
+ <EmailVerificationForm
261
+ className={className}
262
+ classNames={classNames}
263
+ callbackURL={callbackURL}
264
+ localization={localization}
265
+ otpSeparators={otpSeparators}
266
+ redirectTo={redirectTo}
267
+ isSubmitting={isSubmitting}
268
+ setIsSubmitting={setIsSubmitting}
269
+ />
270
+ )
271
+ }
272
+
273
+ if (view === "FORGOT_PASSWORD") {
274
+ return (
275
+ <ForgotPasswordForm
276
+ className={className}
277
+ classNames={classNames}
278
+ localization={localization}
279
+ isSubmitting={isSubmitting}
280
+ setIsSubmitting={setIsSubmitting}
281
+ />
282
+ )
283
+ }
284
+
285
+ if (view === "RESET_PASSWORD") {
286
+ return (
287
+ <ResetPasswordForm
288
+ className={className}
289
+ classNames={classNames}
290
+ localization={localization}
291
+ />
292
+ )
293
+ }
294
+
295
+ if (view === "SIGN_UP") {
296
+ return (
297
+ signUpEnabled && (
298
+ <SignUpForm
299
+ className={className}
300
+ classNames={classNames}
301
+ callbackURL={callbackURL}
302
+ localization={localization}
303
+ redirectTo={redirectTo}
304
+ isSubmitting={isSubmitting}
305
+ setIsSubmitting={setIsSubmitting}
306
+ />
307
+ )
308
+ )
309
+ }
310
+ }