@erikey/react 0.4.33 → 0.4.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erikey/react",
3
- "version": "0.4.33",
3
+ "version": "0.4.35",
4
4
  "description": "React SDK for Erikey - B2B authentication and user management. UI components based on better-auth-ui.",
5
5
  "main": "./dist/index.mjs",
6
6
  "module": "./dist/index.mjs",
@@ -1,6 +1,12 @@
1
1
  "use client"
2
2
 
3
- import { type ReactNode, useCallback, useMemo, useState } from "react"
3
+ import {
4
+ type ReactNode,
5
+ type MouseEvent,
6
+ useCallback,
7
+ useMemo,
8
+ useState
9
+ } from "react"
4
10
 
5
11
  import { AuthUIContext, AuthUIProvider } from "../../lib/auth-ui-provider"
6
12
  import type { AuthUIProviderProps } from "../../lib/auth-ui-provider"
@@ -80,7 +86,9 @@ const flowViewToPathKey: Record<AuthFlowView, keyof AuthViewPaths> = {
80
86
  TWO_FACTOR: "TWO_FACTOR",
81
87
  FORGOT_PASSWORD: "FORGOT_PASSWORD",
82
88
  RESET_PASSWORD: "RESET_PASSWORD",
83
- MAGIC_LINK: "MAGIC_LINK"
89
+ MAGIC_LINK: "MAGIC_LINK",
90
+ EMAIL_OTP: "EMAIL_OTP",
91
+ RECOVER_ACCOUNT: "RECOVER_ACCOUNT"
84
92
  }
85
93
 
86
94
  /**
@@ -109,6 +117,12 @@ function parsePathToView(path: string): { view: AuthFlowView; email?: string } {
109
117
  if (pathname.includes("magic-link")) {
110
118
  return { view: "MAGIC_LINK", email }
111
119
  }
120
+ if (pathname.includes("email-otp")) {
121
+ return { view: "SIGN_IN", email } // EMAIL_OTP is a sign-in variant
122
+ }
123
+ if (pathname.includes("recover-account")) {
124
+ return { view: "TWO_FACTOR", email } // Recover account is part of 2FA flow
125
+ }
112
126
  return { view: "SIGN_IN", email }
113
127
  }
114
128
 
@@ -144,6 +158,24 @@ function parsePathToView(path: string): { view: AuthFlowView; email?: string } {
144
158
  * basePath="/auth"
145
159
  * />
146
160
  */
161
+ /**
162
+ * Check if a path is an auth-related path that should be intercepted
163
+ * These match the viewPaths defined in view-paths.ts
164
+ */
165
+ function isAuthPath(href: string): boolean {
166
+ return (
167
+ href.includes("sign-in") ||
168
+ href.includes("sign-up") ||
169
+ href.includes("email-verification") ||
170
+ href.includes("two-factor") ||
171
+ href.includes("forgot-password") ||
172
+ href.includes("reset-password") ||
173
+ href.includes("magic-link") ||
174
+ href.includes("email-otp") ||
175
+ href.includes("recover-account")
176
+ )
177
+ }
178
+
147
179
  export function AuthFlow({
148
180
  mode = "internal",
149
181
  onEvent,
@@ -159,6 +191,7 @@ export function AuthFlow({
159
191
  // AuthUIProvider props
160
192
  authClient,
161
193
  basePath = "/auth",
194
+ Link: ExternalLink,
162
195
  ...providerProps
163
196
  }: AuthFlowProps) {
164
197
  // Internal state for "internal" mode
@@ -192,6 +225,70 @@ export function AuthFlow({
192
225
  [mode, externalNavigate, onEvent]
193
226
  )
194
227
 
228
+ // Custom Link component for internal mode that intercepts auth paths
229
+ const InternalLink = useCallback(
230
+ ({
231
+ href,
232
+ children,
233
+ className: linkClassName,
234
+ ...rest
235
+ }: {
236
+ href: string
237
+ children: ReactNode
238
+ className?: string
239
+ }) => {
240
+ const handleClick = (e: MouseEvent<HTMLAnchorElement>) => {
241
+ // In internal mode, intercept auth-related links
242
+ if (mode === "internal" && isAuthPath(href)) {
243
+ e.preventDefault()
244
+ handleNavigate(href)
245
+ }
246
+ // In route mode, or for non-auth paths, let the link work normally
247
+ }
248
+
249
+ // In internal mode for auth paths, ALWAYS use plain <a> that we control
250
+ // This avoids relying on external Link components forwarding onClick
251
+ if (mode === "internal" && isAuthPath(href)) {
252
+ return (
253
+ <a
254
+ href={href}
255
+ className={linkClassName}
256
+ onClick={handleClick}
257
+ {...rest}
258
+ >
259
+ {children}
260
+ </a>
261
+ )
262
+ }
263
+
264
+ // For non-auth paths or route mode, use external Link if provided
265
+ if (ExternalLink) {
266
+ return (
267
+ <ExternalLink
268
+ href={href}
269
+ className={linkClassName}
270
+ {...rest}
271
+ >
272
+ {children}
273
+ </ExternalLink>
274
+ )
275
+ }
276
+
277
+ // Default to anchor tag
278
+ return (
279
+ <a
280
+ href={href}
281
+ className={linkClassName}
282
+ onClick={handleClick}
283
+ {...rest}
284
+ >
285
+ {children}
286
+ </a>
287
+ )
288
+ },
289
+ [mode, handleNavigate, ExternalLink]
290
+ )
291
+
195
292
  // Combined event handler that wraps user's onEvent
196
293
  const handleAuthEvent = useCallback(
197
294
  (event: AuthFlowEvent) => {
@@ -225,6 +322,7 @@ export function AuthFlow({
225
322
  navigate={handleNavigate}
226
323
  onAuthEvent={handleAuthEvent}
227
324
  redirectTo={redirectTo}
325
+ Link={InternalLink}
228
326
  {...providerProps}
229
327
  >
230
328
  <AuthViewComponent
@@ -16,6 +16,8 @@ export type AuthFlowView =
16
16
  | "FORGOT_PASSWORD"
17
17
  | "RESET_PASSWORD"
18
18
  | "MAGIC_LINK"
19
+ | "EMAIL_OTP"
20
+ | "RECOVER_ACCOUNT"
19
21
 
20
22
  /**
21
23
  * Error information included in error events