@better-auth-ui/heroui 1.6.5 → 1.6.7

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 (49) hide show
  1. package/dist/components/auth/api-key/api-key-skeleton.d.ts +1 -0
  2. package/dist/components/auth/api-key/api-key-skeleton.js +21 -0
  3. package/dist/components/auth/api-key/api-key.d.ts +5 -0
  4. package/dist/components/auth/api-key/api-key.js +55 -0
  5. package/dist/components/auth/api-key/api-keys-empty.d.ts +4 -0
  6. package/dist/components/auth/api-key/api-keys-empty.js +35 -0
  7. package/dist/components/auth/api-key/api-keys.d.ts +6 -0
  8. package/dist/components/auth/api-key/api-keys.js +41 -0
  9. package/dist/components/auth/api-key/create-api-key-dialog.d.ts +5 -0
  10. package/dist/components/auth/api-key/create-api-key-dialog.js +74 -0
  11. package/dist/components/auth/api-key/delete-api-key-dialog.d.ts +7 -0
  12. package/dist/components/auth/api-key/delete-api-key-dialog.js +51 -0
  13. package/dist/components/auth/api-key/new-api-key-dialog.d.ts +7 -0
  14. package/dist/components/auth/api-key/new-api-key-dialog.js +60 -0
  15. package/dist/components/auth/delete-user/danger-zone.js +1 -1
  16. package/dist/components/auth/delete-user/delete-user.js +53 -53
  17. package/dist/components/auth/multi-session/switch-account-submenu-content.js +14 -15
  18. package/dist/components/auth/passkey/add-passkey-dialog.d.ts +0 -0
  19. package/dist/components/auth/passkey/delete-passkey-dialog.d.ts +0 -0
  20. package/dist/components/auth/passkey/passkey-skeleton.d.ts +0 -0
  21. package/dist/components/auth/passkey/passkeys-empty.d.ts +0 -0
  22. package/dist/components/auth/settings/security/linked-account.js +1 -1
  23. package/dist/components/auth/theme/theme-toggle-item.js +50 -46
  24. package/dist/components/auth/user/user-button.d.ts +27 -2
  25. package/dist/components/auth/user/user-button.js +48 -29
  26. package/dist/lib/auth/api-key-plugin.d.ts +23 -0
  27. package/dist/lib/auth/api-key-plugin.js +10 -0
  28. package/dist/plugins.d.ts +2 -0
  29. package/dist/plugins.js +22 -20
  30. package/package.json +14 -14
  31. package/src/components/auth/api-key/api-key-skeleton.tsx +17 -0
  32. package/src/components/auth/api-key/api-key.tsx +64 -0
  33. package/src/components/auth/api-key/api-keys-empty.tsx +33 -0
  34. package/src/components/auth/api-key/api-keys.tsx +71 -0
  35. package/src/components/auth/api-key/create-api-key-dialog.tsx +134 -0
  36. package/src/components/auth/api-key/delete-api-key-dialog.tsx +92 -0
  37. package/src/components/auth/api-key/new-api-key-dialog.tsx +94 -0
  38. package/src/components/auth/delete-user/danger-zone.tsx +1 -1
  39. package/src/components/auth/delete-user/delete-user.tsx +2 -7
  40. package/src/components/auth/multi-session/switch-account-submenu-content.tsx +1 -3
  41. package/src/components/auth/passkey/add-passkey-dialog.tsx +0 -0
  42. package/src/components/auth/passkey/delete-passkey-dialog.tsx +0 -0
  43. package/src/components/auth/passkey/passkey-skeleton.tsx +0 -0
  44. package/src/components/auth/passkey/passkeys-empty.tsx +0 -0
  45. package/src/components/auth/settings/security/linked-account.tsx +2 -4
  46. package/src/components/auth/theme/theme-toggle-item.tsx +2 -1
  47. package/src/components/auth/user/user-button.tsx +80 -13
  48. package/src/lib/auth/api-key-plugin.ts +15 -0
  49. package/src/plugins.ts +2 -0
@@ -0,0 +1,134 @@
1
+ import {
2
+ type ApiKeyAuthClient,
3
+ useAuth,
4
+ useAuthPlugin,
5
+ useCreateApiKey
6
+ } from "@better-auth-ui/react"
7
+ import { Key } from "@gravity-ui/icons"
8
+ import {
9
+ AlertDialog,
10
+ Button,
11
+ FieldError,
12
+ Form,
13
+ Input,
14
+ Label,
15
+ Spinner,
16
+ TextField
17
+ } from "@heroui/react"
18
+ import { type SyntheticEvent, useState } from "react"
19
+
20
+ import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin"
21
+
22
+ import { NewApiKeyDialog } from "./new-api-key-dialog"
23
+
24
+ export type CreateApiKeyDialogProps = {
25
+ isOpen: boolean
26
+ onOpenChange: (open: boolean) => void
27
+ }
28
+
29
+ export function CreateApiKeyDialog({
30
+ isOpen,
31
+ onOpenChange
32
+ }: CreateApiKeyDialogProps) {
33
+ const { authClient, localization } = useAuth()
34
+ const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
35
+
36
+ const { mutate: createApiKey, isPending: isCreating } = useCreateApiKey(
37
+ authClient as ApiKeyAuthClient
38
+ )
39
+
40
+ const [isNewKeyDialogOpen, setIsNewKeyDialogOpen] = useState(false)
41
+ const [keyName, setKeyName] = useState<string | null>(null)
42
+ const [secretKey, setSecretKey] = useState<string | null>(null)
43
+
44
+ const handleOpenChange = (open: boolean) => {
45
+ if (!open) {
46
+ setKeyName(null)
47
+ setSecretKey(null)
48
+ }
49
+
50
+ onOpenChange(open)
51
+ }
52
+
53
+ const handleSubmit = (e: SyntheticEvent<HTMLFormElement>) => {
54
+ e.preventDefault()
55
+
56
+ const formData = new FormData(e.target as HTMLFormElement)
57
+ const name = formData.get("name") as string
58
+
59
+ createApiKey(name ? { name: name.trim() } : undefined, {
60
+ onSuccess: (result) => {
61
+ handleOpenChange(false)
62
+ setKeyName(name)
63
+ setSecretKey(result.key)
64
+ setIsNewKeyDialogOpen(true)
65
+ }
66
+ })
67
+ }
68
+
69
+ return (
70
+ <>
71
+ <AlertDialog.Backdrop isOpen={isOpen} onOpenChange={handleOpenChange}>
72
+ <AlertDialog.Container>
73
+ <AlertDialog.Dialog>
74
+ <Form onSubmit={handleSubmit}>
75
+ <AlertDialog.CloseTrigger />
76
+
77
+ <AlertDialog.Header>
78
+ <AlertDialog.Icon status="default">
79
+ <Key />
80
+ </AlertDialog.Icon>
81
+
82
+ <AlertDialog.Heading>
83
+ {apiKeyLocalization.createApiKey}
84
+ </AlertDialog.Heading>
85
+ </AlertDialog.Header>
86
+
87
+ <AlertDialog.Body className="overflow-visible">
88
+ <p className="text-muted text-sm">
89
+ {apiKeyLocalization.apiKeysDescription}
90
+ </p>
91
+
92
+ <TextField
93
+ className="mt-4"
94
+ id="name"
95
+ name="name"
96
+ isDisabled={isCreating}
97
+ >
98
+ <Label>{apiKeyLocalization.name}</Label>
99
+
100
+ <Input
101
+ autoFocus
102
+ placeholder={localization.settings.optional}
103
+ variant="secondary"
104
+ />
105
+
106
+ <FieldError />
107
+ </TextField>
108
+ </AlertDialog.Body>
109
+
110
+ <AlertDialog.Footer>
111
+ <Button slot="close" variant="tertiary" isDisabled={isCreating}>
112
+ {localization.settings.cancel}
113
+ </Button>
114
+
115
+ <Button type="submit" isPending={isCreating}>
116
+ {isCreating && <Spinner color="current" size="sm" />}
117
+
118
+ {apiKeyLocalization.createApiKey}
119
+ </Button>
120
+ </AlertDialog.Footer>
121
+ </Form>
122
+ </AlertDialog.Dialog>
123
+ </AlertDialog.Container>
124
+ </AlertDialog.Backdrop>
125
+
126
+ <NewApiKeyDialog
127
+ isOpen={isNewKeyDialogOpen}
128
+ onOpenChange={setIsNewKeyDialogOpen}
129
+ secretKey={secretKey}
130
+ name={keyName}
131
+ />
132
+ </>
133
+ )
134
+ }
@@ -0,0 +1,92 @@
1
+ import {
2
+ type ApiKeyAuthClient,
3
+ type ListedApiKey,
4
+ useAuth,
5
+ useAuthPlugin,
6
+ useDeleteApiKey
7
+ } from "@better-auth-ui/react"
8
+ import { Key } from "@gravity-ui/icons"
9
+ import {
10
+ AlertDialog,
11
+ Button,
12
+ Input,
13
+ Label,
14
+ Spinner,
15
+ TextField
16
+ } from "@heroui/react"
17
+
18
+ import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin"
19
+
20
+ export type DeleteApiKeyDialogProps = {
21
+ isOpen: boolean
22
+ onOpenChange: (open: boolean) => void
23
+ apiKey: ListedApiKey
24
+ }
25
+
26
+ export function DeleteApiKeyDialog({
27
+ isOpen,
28
+ onOpenChange,
29
+ apiKey
30
+ }: DeleteApiKeyDialogProps) {
31
+ const { authClient, localization } = useAuth()
32
+ const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
33
+ const preview = `${apiKey.start}${"*".repeat(16)}`
34
+ const { mutate: deleteApiKey, isPending: isDeleting } = useDeleteApiKey(
35
+ authClient as ApiKeyAuthClient,
36
+ {
37
+ onSuccess: () => onOpenChange(false)
38
+ }
39
+ )
40
+
41
+ return (
42
+ <AlertDialog.Backdrop isOpen={isOpen} onOpenChange={onOpenChange}>
43
+ <AlertDialog.Container>
44
+ <AlertDialog.Dialog>
45
+ <AlertDialog.CloseTrigger />
46
+
47
+ <AlertDialog.Header>
48
+ <AlertDialog.Icon status="danger">
49
+ <Key />
50
+ </AlertDialog.Icon>
51
+
52
+ <AlertDialog.Heading>
53
+ {apiKeyLocalization.deleteApiKey}
54
+ </AlertDialog.Heading>
55
+ </AlertDialog.Header>
56
+
57
+ <AlertDialog.Body className="flex flex-col gap-4 overflow-visible">
58
+ <p className="text-muted text-sm">
59
+ {apiKeyLocalization.deleteApiKeyWarning}
60
+ </p>
61
+
62
+ <TextField
63
+ value={preview}
64
+ className="font-mono text-xs"
65
+ variant="secondary"
66
+ >
67
+ <Label>{apiKey.name || apiKeyLocalization.apiKey}</Label>
68
+
69
+ <Input readOnly className="font-mono text-xs" />
70
+ </TextField>
71
+ </AlertDialog.Body>
72
+
73
+ <AlertDialog.Footer>
74
+ <Button slot="close" variant="tertiary" isDisabled={isDeleting}>
75
+ {localization.settings.cancel}
76
+ </Button>
77
+
78
+ <Button
79
+ variant="danger"
80
+ onPress={() => deleteApiKey({ keyId: apiKey.id })}
81
+ isPending={isDeleting}
82
+ >
83
+ {isDeleting && <Spinner color="current" size="sm" />}
84
+
85
+ {apiKeyLocalization.deleteApiKey}
86
+ </Button>
87
+ </AlertDialog.Footer>
88
+ </AlertDialog.Dialog>
89
+ </AlertDialog.Container>
90
+ </AlertDialog.Backdrop>
91
+ )
92
+ }
@@ -0,0 +1,94 @@
1
+ import { useAuth, useAuthPlugin } from "@better-auth-ui/react"
2
+ import { Check, Copy, Key } from "@gravity-ui/icons"
3
+ import {
4
+ AlertDialog,
5
+ Button,
6
+ InputGroup,
7
+ Label,
8
+ TextField,
9
+ toast
10
+ } from "@heroui/react"
11
+ import { useState } from "react"
12
+
13
+ import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin"
14
+
15
+ export type NewApiKeyDialogProps = {
16
+ isOpen: boolean
17
+ onOpenChange: (open: boolean) => void
18
+ name: string | null
19
+ secretKey: string | null
20
+ }
21
+
22
+ export function NewApiKeyDialog({
23
+ isOpen,
24
+ onOpenChange,
25
+ name,
26
+ secretKey
27
+ }: NewApiKeyDialogProps) {
28
+ const { localization } = useAuth()
29
+ const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
30
+
31
+ const [copied, setCopied] = useState(false)
32
+
33
+ const copySecretKey = async () => {
34
+ if (!secretKey) return
35
+
36
+ try {
37
+ await navigator.clipboard.writeText(secretKey)
38
+ setCopied(true)
39
+ setTimeout(() => setCopied(false), 1500)
40
+ } catch (error) {
41
+ toast.danger(error instanceof Error ? error.message : String(error))
42
+ }
43
+ }
44
+
45
+ return (
46
+ <AlertDialog.Backdrop isOpen={isOpen} onOpenChange={onOpenChange}>
47
+ <AlertDialog.Container>
48
+ <AlertDialog.Dialog>
49
+ <AlertDialog.CloseTrigger />
50
+
51
+ <AlertDialog.Header>
52
+ <AlertDialog.Icon status="warning">
53
+ <Key />
54
+ </AlertDialog.Icon>
55
+
56
+ <AlertDialog.Heading>
57
+ {apiKeyLocalization.newApiKey}
58
+ </AlertDialog.Heading>
59
+ </AlertDialog.Header>
60
+
61
+ <AlertDialog.Body className="flex flex-col gap-4 overflow-visible">
62
+ <p className="text-muted text-sm">
63
+ {apiKeyLocalization.newApiKeyWarning}
64
+ </p>
65
+
66
+ <TextField value={secretKey ?? ""} className="font-mono text-xs">
67
+ <Label>{name || apiKeyLocalization.apiKey}</Label>
68
+
69
+ <InputGroup variant="secondary">
70
+ <InputGroup.Input readOnly className="font-mono text-xs" />
71
+
72
+ <InputGroup.Suffix className="px-0">
73
+ <Button
74
+ isIconOnly
75
+ aria-label={localization.settings.copyToClipboard}
76
+ size="sm"
77
+ variant="ghost"
78
+ onPress={copySecretKey}
79
+ >
80
+ {copied ? <Check /> : <Copy />}
81
+ </Button>
82
+ </InputGroup.Suffix>
83
+ </InputGroup>
84
+ </TextField>
85
+ </AlertDialog.Body>
86
+
87
+ <AlertDialog.Footer>
88
+ <Button slot="close">{apiKeyLocalization.dismissNewKey}</Button>
89
+ </AlertDialog.Footer>
90
+ </AlertDialog.Dialog>
91
+ </AlertDialog.Container>
92
+ </AlertDialog.Backdrop>
93
+ )
94
+ }
@@ -22,7 +22,7 @@ export function DangerZone({
22
22
 
23
23
  return (
24
24
  <div className={cn("flex w-full flex-col", className)} {...props}>
25
- <h2 className={cn("text-sm font-semibold mb-3")}>
25
+ <h2 className={cn("text-sm font-semibold mb-3 text-danger")}>
26
26
  {localization.settings.dangerZone}
27
27
  </h2>
28
28
 
@@ -11,7 +11,6 @@ import {
11
11
  Button,
12
12
  Card,
13
13
  type CardProps,
14
- cn,
15
14
  FieldError,
16
15
  Form,
17
16
  Input,
@@ -91,11 +90,7 @@ export function DeleteUser({
91
90
  }
92
91
 
93
92
  return (
94
- <Card
95
- className={cn("border border-danger", className)}
96
- variant={variant}
97
- {...props}
98
- >
93
+ <Card className={className} variant={variant} {...props}>
99
94
  <Card.Content className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
100
95
  <div>
101
96
  <p className="text-sm font-medium leading-tight">
@@ -111,7 +106,7 @@ export function DeleteUser({
111
106
  <Button
112
107
  isDisabled={!accounts}
113
108
  size="sm"
114
- variant="danger"
109
+ variant="danger-soft"
115
110
  onPress={() => setConfirmOpen(true)}
116
111
  >
117
112
  {deleteUserLocalization.deleteUser}
@@ -6,7 +6,7 @@ import {
6
6
  useSession
7
7
  } from "@better-auth-ui/react"
8
8
  import { Check, CirclePlus } from "@gravity-ui/icons"
9
- import { Dropdown, Label, Separator } from "@heroui/react"
9
+ import { Dropdown, Label } from "@heroui/react"
10
10
 
11
11
  import { multiSessionPlugin } from "../../../lib/auth/multi-session-plugin"
12
12
  import { UserView } from "../user/user-view"
@@ -50,8 +50,6 @@ export function SwitchAccountSubmenuContent() {
50
50
  />
51
51
  ))}
52
52
 
53
- <Separator />
54
-
55
53
  <Dropdown.Item
56
54
  textValue={multiSessionLocalization.addAccount}
57
55
  href={`${basePaths.auth}/${viewPaths.auth.signIn}`}
File without changes
@@ -60,11 +60,9 @@ export function LinkedAccount({ account, provider }: LinkedAccountProps) {
60
60
  )}
61
61
  >
62
62
  {ProviderIcon ? (
63
- <ProviderIcon className={cn("size-4.5", !account && "opacity-50")} />
63
+ <ProviderIcon className="size-4.5" />
64
64
  ) : (
65
- <PlugConnection
66
- className={cn("size-4.5", !account && "opacity-50")}
67
- />
65
+ <PlugConnection className="size-4.5" />
68
66
  )}
69
67
  </div>
70
68
 
@@ -1,5 +1,5 @@
1
1
  import { useAuthPlugin } from "@better-auth-ui/react"
2
- import { Display, Moon, Sun } from "@gravity-ui/icons"
2
+ import { Display, Moon, Palette, Sun } from "@gravity-ui/icons"
3
3
  import { Dropdown, Label, Tabs } from "@heroui/react"
4
4
 
5
5
  import { themePlugin } from "../../../lib/auth/theme-plugin"
@@ -67,6 +67,7 @@ export function ThemeToggleItem() {
67
67
  // menu-item activation.
68
68
  shouldCloseOnSelect={false}
69
69
  >
70
+ <Palette className="text-muted" />
70
71
  <Label>{localization.theme}</Label>
71
72
 
72
73
  <Tabs
@@ -11,14 +11,38 @@ import {
11
11
  type ButtonProps,
12
12
  cn,
13
13
  Dropdown,
14
+ type DropdownItemProps,
14
15
  type DropdownPopoverProps,
15
- Label,
16
- Separator
16
+ Label
17
17
  } from "@heroui/react"
18
+ import { isValidElement, type ReactElement, type ReactNode } from "react"
18
19
 
19
20
  import { UserAvatar } from "./user-avatar"
20
21
  import { UserView } from "./user-view"
21
22
 
23
+ /** Auth states a `UserButton` link can be visible in. */
24
+ export type UserButtonLinkVisibility =
25
+ | "authenticated"
26
+ | "unauthenticated"
27
+ | "always"
28
+
29
+ /** A simple link entry rendered as a `Dropdown.Item` in the `UserButton` menu. */
30
+ export type UserButtonLink = {
31
+ /** Visible label. */
32
+ label: ReactNode
33
+ /** Destination URL. */
34
+ href: string
35
+ /** Optional leading icon. Sized/coloured to match built-in items. */
36
+ icon?: ReactNode
37
+ /** Forwarded to the underlying `Dropdown.Item`. */
38
+ variant?: DropdownItemProps["variant"]
39
+ /**
40
+ * When this link is visible based on auth state.
41
+ * @default "always"
42
+ */
43
+ visibility?: UserButtonLinkVisibility
44
+ }
45
+
22
46
  export type UserButtonProps = {
23
47
  className?: string
24
48
  size?: "default" | "icon"
@@ -28,6 +52,30 @@ export type UserButtonProps = {
28
52
  */
29
53
  placement?: DropdownPopoverProps["placement"]
30
54
  variant?: ButtonProps["variant"]
55
+ /** Additional menu entries rendered above the built-in items. */
56
+ links?: (UserButtonLink | ReactElement)[]
57
+ /** Hide the built-in "Settings" link. Useful when replacing it via `links`. */
58
+ hideSettings?: boolean
59
+ }
60
+
61
+ function renderUserLink(
62
+ link: UserButtonLink | ReactElement,
63
+ fallbackKey: string
64
+ ): ReactNode {
65
+ if (isValidElement(link)) return link
66
+
67
+ const { label, href, icon, variant } = link
68
+ return (
69
+ <Dropdown.Item
70
+ key={fallbackKey}
71
+ href={href}
72
+ variant={variant}
73
+ textValue={typeof label === "string" ? label : undefined}
74
+ >
75
+ {icon}
76
+ <Label>{label}</Label>
77
+ </Dropdown.Item>
78
+ )
31
79
  }
32
80
 
33
81
  /**
@@ -37,13 +85,17 @@ export type UserButtonProps = {
37
85
  * @param placement - Dropdown popover placement (e.g., "bottom", "top-start", "bottom-end")
38
86
  * @param size - "icon" renders an avatar-only trigger; "default" renders a button with label and chevron
39
87
  * @param variant - Button visual variant passed to the underlying Button component
88
+ * @param links - Additional menu entries rendered above the built-in items
89
+ * @param hideSettings - Hide the built-in "Settings" link
40
90
  * @returns The user button and its dropdown menu as a JSX element
41
91
  */
42
92
  export function UserButton({
43
93
  className,
44
94
  placement = "bottom",
45
95
  size = "default",
46
- variant = "ghost"
96
+ variant = "ghost",
97
+ links,
98
+ hideSettings = false
47
99
  }: UserButtonProps) {
48
100
  const { authClient, basePaths, viewPaths, localization, plugins } = useAuth()
49
101
 
@@ -55,6 +107,16 @@ export function UserButton({
55
107
  <Item key={`${plugin.id}-${index.toString()}`} />
56
108
  )) ?? []
57
109
  )
110
+
111
+ const userLinks = links?.flatMap((link, index) => {
112
+ if (!isValidElement(link)) {
113
+ const visibility = link.visibility ?? "always"
114
+ if (visibility === "authenticated" && !session) return []
115
+ if (visibility === "unauthenticated" && session) return []
116
+ }
117
+ return [renderUserLink(link, `user-button-link-${index.toString()}`)]
118
+ })
119
+
58
120
  return (
59
121
  <Dropdown>
60
122
  {size === "icon" ? (
@@ -96,30 +158,35 @@ export function UserButton({
96
158
  <Dropdown.Menu>
97
159
  {session ? (
98
160
  <>
99
- <Dropdown.Item
100
- textValue={localization.settings.settings}
101
- href={`${basePaths.settings}/${viewPaths.settings.account}`}
102
- >
103
- <Gear className="text-muted" />
161
+ {userLinks}
104
162
 
105
- <Label>{localization.settings.settings}</Label>
106
- </Dropdown.Item>
163
+ {!hideSettings && (
164
+ <Dropdown.Item
165
+ textValue={localization.settings.settings}
166
+ href={`${basePaths.settings}/${viewPaths.settings.account}`}
167
+ >
168
+ <Gear className="text-muted" />
107
169
 
108
- {userMenuItems}
170
+ <Label>{localization.settings.settings}</Label>
171
+ </Dropdown.Item>
172
+ )}
109
173
 
110
- <Separator />
174
+ {userMenuItems}
111
175
 
112
176
  <Dropdown.Item
113
177
  textValue={localization.auth.signOut}
114
178
  href={`${basePaths.auth}/${viewPaths.auth.signOut}`}
179
+ variant="danger"
115
180
  >
116
- <ArrowRightFromSquare className="text-muted" />
181
+ <ArrowRightFromSquare className="text-danger" />
117
182
 
118
183
  <Label>{localization.auth.signOut}</Label>
119
184
  </Dropdown.Item>
120
185
  </>
121
186
  ) : (
122
187
  <>
188
+ {userLinks}
189
+
123
190
  <Dropdown.Item
124
191
  textValue={localization.auth.signIn}
125
192
  href={`${basePaths.auth}/${viewPaths.auth.signIn}`}
@@ -0,0 +1,15 @@
1
+ import { createAuthPlugin } from "@better-auth-ui/core"
2
+ import {
3
+ type ApiKeyPluginOptions,
4
+ apiKeyPlugin as coreApiKeyPlugin
5
+ } from "@better-auth-ui/core/plugins"
6
+
7
+ import { ApiKeys } from "../../components/auth/api-key/api-keys"
8
+
9
+ export const apiKeyPlugin = createAuthPlugin(
10
+ coreApiKeyPlugin.id,
11
+ (options: ApiKeyPluginOptions = {}) => ({
12
+ ...coreApiKeyPlugin(options),
13
+ securityCards: [ApiKeys]
14
+ })
15
+ )
package/src/plugins.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  "use client"
2
2
 
3
+ export * from "./components/auth/api-key/api-keys"
3
4
  export * from "./components/auth/delete-user/danger-zone"
4
5
  export * from "./components/auth/delete-user/delete-user"
5
6
  // Plugin-contributed components that may be used standalone
@@ -14,6 +15,7 @@ export * from "./components/auth/theme/appearance"
14
15
  export * from "./components/auth/theme/theme-toggle-item"
15
16
  export * from "./components/auth/username/sign-in-username"
16
17
  export * from "./components/auth/username/username-field"
18
+ export * from "./lib/auth/api-key-plugin"
17
19
  export * from "./lib/auth/auth-plugin"
18
20
  export * from "./lib/auth/delete-user-plugin"
19
21
  export * from "./lib/auth/magic-link-plugin"