@better-auth-ui/heroui 1.6.8 → 1.6.10

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 (195) hide show
  1. package/dist/components/auth/api-key/api-key.d.ts +5 -1
  2. package/dist/components/auth/api-key/api-keys-empty.d.ts +3 -1
  3. package/dist/components/auth/api-key/api-keys.d.ts +9 -1
  4. package/dist/components/auth/api-key/create-api-key-dialog.d.ts +3 -1
  5. package/dist/components/auth/api-key/delete-api-key-dialog.d.ts +3 -1
  6. package/dist/components/auth/api-key/organization-api-keys.d.ts +14 -0
  7. package/dist/components/auth/delete-user/danger-zone.d.ts +1 -1
  8. package/dist/components/auth/delete-user/{delete-user.d.ts → delete-account.d.ts} +2 -2
  9. package/dist/components/auth/email/organization-invitation-email.d.ts +3 -0
  10. package/dist/components/auth/multi-session/switch-account-submenu-content.d.ts +3 -1
  11. package/dist/components/auth/multi-session/switch-account-submenu-item.d.ts +2 -1
  12. package/dist/components/auth/multi-session/switch-account-submenu.d.ts +2 -1
  13. package/dist/components/auth/organization/change-organization-logo.d.ts +4 -0
  14. package/dist/components/auth/organization/create-organization-dialog.d.ts +13 -0
  15. package/dist/components/auth/organization/delete-organization-dialog.d.ts +7 -0
  16. package/dist/components/auth/organization/delete-organization-skeleton.d.ts +4 -0
  17. package/dist/components/auth/organization/delete-organization.d.ts +5 -0
  18. package/dist/components/auth/organization/invite-member-dialog.d.ts +13 -0
  19. package/dist/components/auth/organization/leave-organization-dialog.d.ts +7 -0
  20. package/dist/components/auth/organization/leave-organization.d.ts +4 -0
  21. package/dist/components/auth/organization/organization-danger-zone.d.ts +16 -0
  22. package/dist/components/auth/organization/organization-invitation-row-skeleton.d.ts +5 -0
  23. package/dist/components/auth/organization/organization-invitation-row.d.ts +5 -0
  24. package/dist/components/auth/organization/organization-invitations-empty.d.ts +8 -0
  25. package/dist/components/auth/organization/organization-invitations.d.ts +9 -0
  26. package/dist/components/auth/organization/organization-logo.d.ts +15 -0
  27. package/dist/components/auth/organization/organization-member-row-skeleton.d.ts +4 -0
  28. package/dist/components/auth/organization/organization-member-row.d.ts +9 -0
  29. package/dist/components/auth/organization/organization-members.d.ts +9 -0
  30. package/dist/components/auth/organization/organization-people.d.ts +10 -0
  31. package/dist/components/auth/organization/organization-profile.d.ts +9 -0
  32. package/dist/components/auth/organization/organization-row.d.ts +8 -0
  33. package/dist/components/auth/organization/organization-settings.d.ts +12 -0
  34. package/dist/components/auth/organization/organization-switcher.d.ts +20 -0
  35. package/dist/components/auth/organization/organization-view-skeleton.d.ts +6 -0
  36. package/dist/components/auth/organization/organization-view.d.ts +15 -0
  37. package/dist/components/auth/organization/organization.d.ts +17 -0
  38. package/dist/components/auth/organization/organizations-empty.d.ts +4 -0
  39. package/dist/components/auth/organization/organizations-settings.d.ts +17 -0
  40. package/dist/components/auth/organization/organizations.d.ts +10 -0
  41. package/dist/components/auth/organization/remove-member-dialog.d.ts +9 -0
  42. package/dist/components/auth/organization/slug-field.d.ts +19 -0
  43. package/dist/components/auth/organization/user-invitation-row-skeleton.d.ts +4 -0
  44. package/dist/components/auth/organization/user-invitation-row.d.ts +10 -0
  45. package/dist/components/auth/organization/user-invitations-empty.d.ts +4 -0
  46. package/dist/components/auth/organization/user-invitations.d.ts +10 -0
  47. package/dist/components/auth/settings/settings.d.ts +1 -1
  48. package/dist/components/auth/user/user-avatar.d.ts +1 -1
  49. package/dist/components/auth/user/user-button.d.ts +4 -5
  50. package/dist/components/auth/user/user-view.d.ts +10 -4
  51. package/dist/email.d.ts +1 -0
  52. package/dist/email.js +211 -8
  53. package/dist/index.js +1682 -22
  54. package/dist/lib/auth/api-key-plugin.d.ts +5 -2
  55. package/dist/lib/auth/auth-plugin.d.ts +6 -2
  56. package/dist/lib/auth/delete-user-plugin.d.ts +4 -4
  57. package/dist/lib/auth/magic-link-plugin.d.ts +2 -2
  58. package/dist/lib/auth/multi-session-plugin.d.ts +2 -2
  59. package/dist/lib/auth/organization-plugin.d.ts +37 -0
  60. package/dist/lib/auth/passkey-plugin.d.ts +2 -2
  61. package/dist/lib/auth/theme-plugin.d.ts +3 -3
  62. package/dist/lib/auth/username-plugin.d.ts +8 -8
  63. package/dist/plugins.d.ts +25 -1
  64. package/dist/plugins.js +2824 -22
  65. package/dist/user-view--47tVtJ3.js +113 -0
  66. package/package.json +23 -18
  67. package/src/components/auth/api-key/api-key.tsx +25 -16
  68. package/src/components/auth/api-key/api-keys-empty.tsx +8 -4
  69. package/src/components/auth/api-key/api-keys.tsx +52 -14
  70. package/src/components/auth/api-key/create-api-key-dialog.tsx +15 -2
  71. package/src/components/auth/api-key/delete-api-key-dialog.tsx +10 -2
  72. package/src/components/auth/api-key/organization-api-keys.tsx +55 -0
  73. package/src/components/auth/delete-user/danger-zone.tsx +3 -3
  74. package/src/components/auth/delete-user/{delete-user.tsx → delete-account.tsx} +9 -9
  75. package/src/components/auth/email/organization-invitation-email.tsx +38 -0
  76. package/src/components/auth/error-toaster.tsx +28 -10
  77. package/src/components/auth/forgot-password.tsx +10 -2
  78. package/src/components/auth/multi-session/manage-accounts.tsx +1 -1
  79. package/src/components/auth/multi-session/switch-account-submenu-content.tsx +7 -2
  80. package/src/components/auth/multi-session/switch-account-submenu-item.tsx +4 -2
  81. package/src/components/auth/multi-session/switch-account-submenu.tsx +8 -4
  82. package/src/components/auth/organization/change-organization-logo.tsx +171 -0
  83. package/src/components/auth/organization/create-organization-dialog.tsx +133 -0
  84. package/src/components/auth/organization/delete-organization-dialog.tsx +97 -0
  85. package/src/components/auth/organization/delete-organization-skeleton.tsx +17 -0
  86. package/src/components/auth/organization/delete-organization.tsx +77 -0
  87. package/src/components/auth/organization/invite-member-dialog.tsx +177 -0
  88. package/src/components/auth/organization/leave-organization-dialog.tsx +95 -0
  89. package/src/components/auth/organization/leave-organization.tsx +59 -0
  90. package/src/components/auth/organization/organization-danger-zone.tsx +68 -0
  91. package/src/components/auth/organization/organization-invitation-row-skeleton.tsx +29 -0
  92. package/src/components/auth/organization/organization-invitation-row.tsx +97 -0
  93. package/src/components/auth/organization/organization-invitations-empty.tsx +39 -0
  94. package/src/components/auth/organization/organization-invitations.tsx +351 -0
  95. package/src/components/auth/organization/organization-logo.tsx +64 -0
  96. package/src/components/auth/organization/organization-member-row-skeleton.tsx +24 -0
  97. package/src/components/auth/organization/organization-member-row.tsx +157 -0
  98. package/src/components/auth/organization/organization-members.tsx +284 -0
  99. package/src/components/auth/organization/organization-people.tsx +26 -0
  100. package/src/components/auth/organization/organization-profile.tsx +141 -0
  101. package/src/components/auth/organization/organization-row.tsx +66 -0
  102. package/src/components/auth/organization/organization-settings.tsx +38 -0
  103. package/src/components/auth/organization/organization-switcher.tsx +233 -0
  104. package/src/components/auth/organization/organization-view-skeleton.tsx +36 -0
  105. package/src/components/auth/organization/organization-view.tsx +109 -0
  106. package/src/components/auth/organization/organization.tsx +162 -0
  107. package/src/components/auth/organization/organizations-empty.tsx +35 -0
  108. package/src/components/auth/organization/organizations-settings.tsx +36 -0
  109. package/src/components/auth/organization/organizations.tsx +80 -0
  110. package/src/components/auth/organization/remove-member-dialog.tsx +95 -0
  111. package/src/components/auth/organization/slug-field.tsx +111 -0
  112. package/src/components/auth/organization/user-invitation-row-skeleton.tsx +17 -0
  113. package/src/components/auth/organization/user-invitation-row.tsx +90 -0
  114. package/src/components/auth/organization/user-invitations-empty.tsx +30 -0
  115. package/src/components/auth/organization/user-invitations.tsx +59 -0
  116. package/src/components/auth/settings/account/change-email.tsx +1 -1
  117. package/src/components/auth/settings/account/user-profile.tsx +5 -5
  118. package/src/components/auth/settings/security/active-sessions.tsx +6 -4
  119. package/src/components/auth/settings/security/linked-accounts.tsx +2 -2
  120. package/src/components/auth/settings/settings.tsx +77 -14
  121. package/src/components/auth/user/user-avatar.tsx +4 -1
  122. package/src/components/auth/user/user-button.tsx +14 -11
  123. package/src/components/auth/user/user-view.tsx +32 -12
  124. package/src/email.ts +1 -0
  125. package/src/lib/auth/api-key-plugin.ts +10 -4
  126. package/src/lib/auth/auth-plugin.ts +6 -1
  127. package/src/lib/auth/organization-plugin.tsx +32 -0
  128. package/src/plugins.ts +25 -1
  129. package/dist/components/auth/additional-field.js +0 -270
  130. package/dist/components/auth/api-key/api-key-skeleton.js +0 -21
  131. package/dist/components/auth/api-key/api-key.js +0 -55
  132. package/dist/components/auth/api-key/api-keys-empty.js +0 -35
  133. package/dist/components/auth/api-key/api-keys.js +0 -41
  134. package/dist/components/auth/api-key/create-api-key-dialog.js +0 -74
  135. package/dist/components/auth/api-key/delete-api-key-dialog.js +0 -51
  136. package/dist/components/auth/api-key/new-api-key-dialog.js +0 -60
  137. package/dist/components/auth/auth-provider.js +0 -17
  138. package/dist/components/auth/auth.js +0 -63
  139. package/dist/components/auth/delete-user/danger-zone.js +0 -18
  140. package/dist/components/auth/delete-user/delete-user.js +0 -95
  141. package/dist/components/auth/email/email-changed-email.js +0 -30
  142. package/dist/components/auth/email/email-verification-email.js +0 -30
  143. package/dist/components/auth/email/magic-link-email.js +0 -30
  144. package/dist/components/auth/email/new-device-email.js +0 -30
  145. package/dist/components/auth/email/otp-email.js +0 -29
  146. package/dist/components/auth/email/password-changed-email.js +0 -30
  147. package/dist/components/auth/email/reset-password-email.js +0 -30
  148. package/dist/components/auth/error-toaster.js +0 -17
  149. package/dist/components/auth/field-separator.js +0 -18
  150. package/dist/components/auth/forgot-password.js +0 -89
  151. package/dist/components/auth/magic-link/magic-link-button.js +0 -20
  152. package/dist/components/auth/magic-link/magic-link.js +0 -87
  153. package/dist/components/auth/multi-session/manage-account.js +0 -49
  154. package/dist/components/auth/multi-session/manage-accounts.js +0 -34
  155. package/dist/components/auth/multi-session/switch-account-submenu-content.js +0 -28
  156. package/dist/components/auth/multi-session/switch-account-submenu-item.js +0 -20
  157. package/dist/components/auth/multi-session/switch-account-submenu.js +0 -24
  158. package/dist/components/auth/passkey/add-passkey-dialog.js +0 -65
  159. package/dist/components/auth/passkey/delete-passkey-dialog.js +0 -47
  160. package/dist/components/auth/passkey/passkey-button.js +0 -24
  161. package/dist/components/auth/passkey/passkey-skeleton.js +0 -17
  162. package/dist/components/auth/passkey/passkey.js +0 -48
  163. package/dist/components/auth/passkey/passkeys-empty.js +0 -35
  164. package/dist/components/auth/passkey/passkeys.js +0 -42
  165. package/dist/components/auth/provider-button.js +0 -25
  166. package/dist/components/auth/provider-buttons.js +0 -19
  167. package/dist/components/auth/reset-password.js +0 -147
  168. package/dist/components/auth/settings/account/account-settings.js +0 -20
  169. package/dist/components/auth/settings/account/change-avatar.js +0 -89
  170. package/dist/components/auth/settings/account/change-email.js +0 -54
  171. package/dist/components/auth/settings/account/user-profile.js +0 -86
  172. package/dist/components/auth/settings/security/active-session.js +0 -59
  173. package/dist/components/auth/settings/security/active-sessions.js +0 -34
  174. package/dist/components/auth/settings/security/change-password.js +0 -189
  175. package/dist/components/auth/settings/security/linked-account.js +0 -56
  176. package/dist/components/auth/settings/security/linked-accounts.js +0 -45
  177. package/dist/components/auth/settings/security/security-settings.js +0 -22
  178. package/dist/components/auth/settings/settings.js +0 -45
  179. package/dist/components/auth/sign-in.js +0 -133
  180. package/dist/components/auth/sign-out.js +0 -27
  181. package/dist/components/auth/sign-up.js +0 -212
  182. package/dist/components/auth/theme/appearance.js +0 -72
  183. package/dist/components/auth/theme/theme-toggle-item.js +0 -62
  184. package/dist/components/auth/user/user-avatar.js +0 -29
  185. package/dist/components/auth/user/user-button.js +0 -74
  186. package/dist/components/auth/user/user-view.js +0 -37
  187. package/dist/components/auth/username/sign-in-username.js +0 -148
  188. package/dist/components/auth/username/username-field.js +0 -53
  189. package/dist/lib/auth/api-key-plugin.js +0 -10
  190. package/dist/lib/auth/delete-user-plugin.js +0 -10
  191. package/dist/lib/auth/magic-link-plugin.js +0 -13
  192. package/dist/lib/auth/multi-session-plugin.js +0 -12
  193. package/dist/lib/auth/passkey-plugin.js +0 -12
  194. package/dist/lib/auth/theme-plugin.js +0 -23
  195. package/dist/lib/auth/username-plugin.js +0 -18
@@ -0,0 +1,113 @@
1
+ import { authMutationKeys as e, getProviderName as t } from "@better-auth-ui/core";
2
+ import { providerIcons as n, useAuth as r, useSession as i, useSignInSocial as a } from "@better-auth-ui/react";
3
+ import { Person as o } from "@gravity-ui/icons";
4
+ import { Avatar as s, Button as c, Separator as l, Skeleton as u, Spinner as d, cn as f } from "@heroui/react";
5
+ import { useMemo as p } from "react";
6
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
7
+ import { useIsMutating as g } from "@tanstack/react-query";
8
+ //#region src/components/auth/field-separator.tsx
9
+ function _({ children: e }) {
10
+ return /* @__PURE__ */ h("div", {
11
+ className: "flex items-center gap-4",
12
+ children: [
13
+ /* @__PURE__ */ m(l, { className: "flex-1" }),
14
+ /* @__PURE__ */ m("p", {
15
+ className: "text-xs text-muted shrink-0",
16
+ children: e
17
+ }),
18
+ /* @__PURE__ */ m(l, { className: "flex-1" })
19
+ ]
20
+ });
21
+ }
22
+ //#endregion
23
+ //#region src/components/auth/provider-button.tsx
24
+ function v({ provider: i, display: o = "full", variant: s = "tertiary", ...l }) {
25
+ let { authClient: u, baseURL: f, localization: p, redirectTo: _ } = r(), v = `${f}${_}`, { mutate: y, isPending: b } = a(u), x = n[i];
26
+ return /* @__PURE__ */ h(c, {
27
+ variant: s,
28
+ isPending: g({ mutationKey: e.signIn.all }) + g({ mutationKey: e.signUp.all }) > 0,
29
+ onPress: () => y({
30
+ provider: i,
31
+ callbackURL: v
32
+ }),
33
+ ...l,
34
+ "aria-label": t(i),
35
+ children: [b ? /* @__PURE__ */ m(d, {
36
+ color: "current",
37
+ size: "sm"
38
+ }) : /* @__PURE__ */ m(x, {}), o === "full" ? p.auth.continueWith.replace("{{provider}}", t(i)) : o === "name" ? t(i) : null]
39
+ });
40
+ }
41
+ //#endregion
42
+ //#region src/components/auth/provider-buttons.tsx
43
+ function y({ socialLayout: e = "auto" }) {
44
+ let { socialProviders: t } = r(), n = p(() => e === "auto" ? t?.length && t.length >= 4 ? "horizontal" : "vertical" : e, [e, t?.length]);
45
+ return /* @__PURE__ */ m("div", {
46
+ className: f("gap-3", n === "grid" && "grid grid-cols-2", n === "vertical" && "flex flex-col", n === "horizontal" && "flex flex-wrap"),
47
+ children: t?.map((e) => /* @__PURE__ */ m(v, {
48
+ provider: e,
49
+ display: n === "vertical" ? "full" : n === "grid" ? "name" : "icon",
50
+ className: f("w-full", n === "horizontal" && "flex-1")
51
+ }, e))
52
+ });
53
+ }
54
+ //#endregion
55
+ //#region src/components/auth/user/user-avatar.tsx
56
+ function b({ className: e, fallback: t, isPending: n, user: a, size: c = "sm", style: l, ...d }) {
57
+ let { authClient: p } = r(), { data: g, isPending: _ } = i(p, { enabled: !a && !n });
58
+ if ((n || _) && !a) return /* @__PURE__ */ m(u, {
59
+ className: f("rounded-full", c === "sm" ? "size-8" : c === "md" ? "size-10" : "size-12", e),
60
+ style: l
61
+ });
62
+ let v = a ?? g?.user, y = (v?.username || v?.name || v?.email)?.slice(0, 2).toUpperCase();
63
+ return /* @__PURE__ */ h(s, {
64
+ size: c,
65
+ className: f("rounded-full", e),
66
+ style: l,
67
+ ...d,
68
+ children: [/* @__PURE__ */ m(s.Image, {
69
+ alt: v?.displayUsername || v?.name || v?.email,
70
+ src: v?.image ?? void 0
71
+ }), /* @__PURE__ */ m(s.Fallback, {
72
+ className: f(c === "lg" ? "text-xl" : c === "md" ? "text-base" : "text-sm"),
73
+ delayMs: v?.image ? 600 : void 0,
74
+ children: t || y || /* @__PURE__ */ m(o, { className: "size-4" })
75
+ })]
76
+ });
77
+ }
78
+ //#endregion
79
+ //#region src/components/auth/user/user-view.tsx
80
+ function x({ className: e, isPending: t, size: n = "md", hideSubtitle: a = !1, user: o, ...s }) {
81
+ let { authClient: c } = r(), { data: l, isPending: d } = i(c, { enabled: !o && !t }), p = o ?? l?.user;
82
+ return (t || d) && !o ? /* @__PURE__ */ h("div", {
83
+ className: f("flex items-center gap-2 min-w-0", e),
84
+ ...s,
85
+ children: [/* @__PURE__ */ m(b, {
86
+ isPending: !0,
87
+ className: n === "sm" ? "size-5 [&>span]:text-xs" : void 0,
88
+ size: n === "lg" ? "md" : "sm"
89
+ }), /* @__PURE__ */ h("div", {
90
+ className: "flex flex-col gap-1 min-w-0",
91
+ children: [/* @__PURE__ */ m(u, { className: "h-3.5 w-24 rounded-lg" }), a ? null : /* @__PURE__ */ m(u, { className: "h-3 w-32 rounded-lg" })]
92
+ })]
93
+ }) : /* @__PURE__ */ h("div", {
94
+ className: f("flex items-center gap-2 min-w-0", e),
95
+ ...s,
96
+ children: [/* @__PURE__ */ m(b, {
97
+ className: n === "sm" ? "size-5 [&>span]:text-xs" : void 0,
98
+ user: p,
99
+ size: n === "lg" ? "md" : "sm"
100
+ }), /* @__PURE__ */ h("div", {
101
+ className: "flex flex-col min-w-0",
102
+ children: [/* @__PURE__ */ m("p", {
103
+ className: "text-foreground text-sm font-medium leading-tight truncate",
104
+ children: p?.displayUsername || p?.name || p?.email
105
+ }), !a && (p?.displayUsername || p?.name) ? /* @__PURE__ */ m("p", {
106
+ className: "text-muted text-xs leading-tight truncate overflow-x-hidden",
107
+ children: p?.email
108
+ }) : null]
109
+ })]
110
+ });
111
+ }
112
+ //#endregion
113
+ export { _ as a, v as i, b as n, y as r, x as t };
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "@better-auth-ui/heroui",
3
- "version": "1.6.8",
3
+ "version": "1.6.10",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "vite build",
7
- "dev": "tsc --watch",
8
7
  "test": "vitest"
9
8
  },
10
9
  "files": [
@@ -13,48 +12,54 @@
13
12
  ],
14
13
  "exports": {
15
14
  ".": {
15
+ "development": "./src/index.tsx",
16
16
  "types": "./dist/index.d.ts",
17
17
  "import": "./dist/index.js"
18
18
  },
19
19
  "./email": {
20
+ "development": "./src/email.ts",
20
21
  "types": "./dist/email.d.ts",
21
22
  "import": "./dist/email.js"
22
23
  },
23
24
  "./plugins": {
25
+ "development": "./src/plugins.ts",
24
26
  "types": "./dist/plugins.d.ts",
25
27
  "import": "./dist/plugins.js"
26
28
  },
27
- "./styles": "./dist/styles.css"
29
+ "./styles": {
30
+ "development": "./src/styles.css",
31
+ "default": "./dist/styles.css"
32
+ }
28
33
  },
29
34
  "devDependencies": {
30
35
  "@gravity-ui/icons": "^2.18.0",
31
- "@heroui/react": "^3.0.4",
32
- "@heroui/styles": "^3.0.4",
36
+ "@heroui/react": "^3.1.0",
37
+ "@heroui/styles": "^3.1.0",
33
38
  "@internationalized/date": "^3.12.1",
34
- "@tanstack/react-pacer": "^0.22.0",
35
- "@tanstack/react-query": "^5.100.9",
39
+ "@tanstack/react-pacer": "^0.22.1",
40
+ "@tanstack/react-query": "^5.100.14",
36
41
  "@testing-library/react": "^16.3.2",
37
42
  "@testing-library/user-event": "^14.5.2",
38
- "@types/react": "^19.2.14",
39
- "@vitejs/plugin-react": "^6.0.1",
40
- "@vitest/browser-playwright": "^4.1.5",
41
- "better-auth": "^1.6.10",
43
+ "@types/react": "^19.2.15",
44
+ "@vitejs/plugin-react": "^6.0.2",
45
+ "@vitest/browser-playwright": "^4.1.7",
46
+ "better-auth": "^1.6.11",
42
47
  "bowser": "^2.11.0",
43
- "playwright": "^1.59.1",
48
+ "playwright": "^1.60.0",
44
49
  "react": "^19.2.6",
45
50
  "react-dom": "^19.2.6",
46
- "vitest": "^4.1.5"
51
+ "vitest": "^4.1.7"
47
52
  },
48
53
  "peerDependencies": {
49
54
  "@better-auth-ui/core": "*",
50
55
  "@better-auth-ui/react": "*",
51
56
  "@gravity-ui/icons": ">=2.18.0",
52
- "@heroui/react": ">=3.0.4",
53
- "@heroui/styles": ">=3.0.4",
57
+ "@heroui/react": ">=3.1.0",
58
+ "@heroui/styles": ">=3.1.0",
54
59
  "@internationalized/date": ">=3.12.1",
55
- "@tanstack/react-pacer": ">=0.22.0",
56
- "@tanstack/react-query": ">=5.100.9",
57
- "better-auth": ">=1.6.10",
60
+ "@tanstack/react-pacer": ">=0.22.1",
61
+ "@tanstack/react-query": ">=5.100.14",
62
+ "better-auth": ">=1.6.11",
58
63
  "react": ">=19.2.6",
59
64
  "react-dom": ">=19.2.6",
60
65
  "bowser": ">=2.11.0"
@@ -12,9 +12,13 @@ import { DeleteApiKeyDialog } from "./delete-api-key-dialog"
12
12
 
13
13
  export type ApiKeyProps = {
14
14
  apiKey: ListedApiKey
15
+ /** Hide the row's delete button (e.g., when caller lacks `apiKey:delete`). */
16
+ hideDelete?: boolean
17
+ /** Scope the delete payload to an organization (sets `configId`). */
18
+ organizationId?: string
15
19
  }
16
20
 
17
- export function ApiKey({ apiKey }: ApiKeyProps) {
21
+ export function ApiKey({ apiKey, hideDelete, organizationId }: ApiKeyProps) {
18
22
  const { localization } = useAuth()
19
23
  const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
20
24
  const [deleteOpen, setDeleteOpen] = useState(false)
@@ -42,23 +46,28 @@ export function ApiKey({ apiKey }: ApiKeyProps) {
42
46
  </span>
43
47
  </div>
44
48
 
45
- <Button
46
- className="ml-auto shrink-0"
47
- variant="outline"
48
- size="sm"
49
- onPress={() => setDeleteOpen(true)}
50
- aria-label={apiKeyLocalization.deleteApiKey}
51
- >
52
- <Xmark />
49
+ {!hideDelete && (
50
+ <>
51
+ <Button
52
+ className="ml-auto shrink-0"
53
+ variant="outline"
54
+ size="sm"
55
+ onPress={() => setDeleteOpen(true)}
56
+ aria-label={apiKeyLocalization.deleteApiKey}
57
+ >
58
+ <Xmark />
53
59
 
54
- {localization.settings.delete}
55
- </Button>
60
+ {localization.settings.delete}
61
+ </Button>
56
62
 
57
- <DeleteApiKeyDialog
58
- isOpen={deleteOpen}
59
- onOpenChange={setDeleteOpen}
60
- apiKey={apiKey}
61
- />
63
+ <DeleteApiKeyDialog
64
+ isOpen={deleteOpen}
65
+ onOpenChange={setDeleteOpen}
66
+ apiKey={apiKey}
67
+ organizationId={organizationId}
68
+ />
69
+ </>
70
+ )}
62
71
  </div>
63
72
  )
64
73
  }
@@ -6,9 +6,11 @@ import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin"
6
6
 
7
7
  export type ApiKeysEmptyProps = {
8
8
  onCreatePress: () => void
9
+ /** Hide the empty-state "Create API key" button. */
10
+ hideCreate?: boolean
9
11
  }
10
12
 
11
- export function ApiKeysEmpty({ onCreatePress }: ApiKeysEmptyProps) {
13
+ export function ApiKeysEmpty({ onCreatePress, hideCreate }: ApiKeysEmptyProps) {
12
14
  const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
13
15
 
14
16
  return (
@@ -25,9 +27,11 @@ export function ApiKeysEmpty({ onCreatePress }: ApiKeysEmptyProps) {
25
27
  </p>
26
28
  </div>
27
29
 
28
- <Button size="sm" onPress={onCreatePress}>
29
- {apiKeyLocalization.createApiKey}
30
- </Button>
30
+ {!hideCreate && (
31
+ <Button size="sm" onPress={onCreatePress}>
32
+ {apiKeyLocalization.createApiKey}
33
+ </Button>
34
+ )}
31
35
  </div>
32
36
  )
33
37
  }
@@ -16,16 +16,39 @@ import { CreateApiKeyDialog } from "./create-api-key-dialog"
16
16
  export type ApiKeysProps = {
17
17
  className?: string
18
18
  variant?: CardProps["variant"]
19
+ /** Scope the list and create payload to an organization. */
20
+ organizationId?: string
21
+ /** Force the loading skeleton and disable the list query. */
22
+ isPending?: boolean
23
+ /** Hide the "Create API key" button (header + empty state). */
24
+ hideCreate?: boolean
25
+ /** Hide the per-row delete button on listed keys. */
26
+ hideDelete?: boolean
19
27
  }
20
28
 
21
- export function ApiKeys({ className, variant }: ApiKeysProps) {
29
+ export function ApiKeys({
30
+ className,
31
+ variant,
32
+ organizationId,
33
+ isPending: isPendingProp,
34
+ hideCreate,
35
+ hideDelete
36
+ }: ApiKeysProps) {
22
37
  const { authClient } = useAuth()
23
38
  const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
24
39
 
25
- const { data: listData, isPending } = useListApiKeys(
26
- authClient as ApiKeyAuthClient
40
+ const { data: listData, isPending: isListPending } = useListApiKeys(
41
+ authClient as ApiKeyAuthClient,
42
+ {
43
+ enabled: !isPendingProp,
44
+ ...(organizationId
45
+ ? { query: { organizationId, configId: "organization" } }
46
+ : {})
47
+ }
27
48
  )
28
49
 
50
+ const isPending = isPendingProp || isListPending
51
+
29
52
  const [createOpen, setCreateOpen] = useState(false)
30
53
 
31
54
  return (
@@ -35,14 +58,16 @@ export function ApiKeys({ className, variant }: ApiKeysProps) {
35
58
  {apiKeyLocalization.apiKeys}
36
59
  </h2>
37
60
 
38
- <Button
39
- className="shrink-0"
40
- size="sm"
41
- isDisabled={isPending}
42
- onPress={() => setCreateOpen(true)}
43
- >
44
- {apiKeyLocalization.createApiKey}
45
- </Button>
61
+ {!hideCreate && (
62
+ <Button
63
+ className="shrink-0"
64
+ size="sm"
65
+ isDisabled={isPending}
66
+ onPress={() => setCreateOpen(true)}
67
+ >
68
+ {apiKeyLocalization.createApiKey}
69
+ </Button>
70
+ )}
46
71
  </div>
47
72
 
48
73
  <Card variant={variant}>
@@ -50,7 +75,10 @@ export function ApiKeys({ className, variant }: ApiKeysProps) {
50
75
  {isPending ? (
51
76
  <ApiKeySkeleton />
52
77
  ) : !listData?.apiKeys.length ? (
53
- <ApiKeysEmpty onCreatePress={() => setCreateOpen(true)} />
78
+ <ApiKeysEmpty
79
+ onCreatePress={() => setCreateOpen(true)}
80
+ hideCreate={hideCreate}
81
+ />
54
82
  ) : (
55
83
  listData?.apiKeys.map((key, index) => (
56
84
  <div key={key.id}>
@@ -58,14 +86,24 @@ export function ApiKeys({ className, variant }: ApiKeysProps) {
58
86
  <div className="border-b border-dashed -mx-4 my-4" />
59
87
  )}
60
88
 
61
- <ApiKey apiKey={key} />
89
+ <ApiKey
90
+ apiKey={key}
91
+ hideDelete={hideDelete}
92
+ organizationId={organizationId}
93
+ />
62
94
  </div>
63
95
  ))
64
96
  )}
65
97
  </Card.Content>
66
98
  </Card>
67
99
 
68
- <CreateApiKeyDialog isOpen={createOpen} onOpenChange={setCreateOpen} />
100
+ {!hideCreate && (
101
+ <CreateApiKeyDialog
102
+ isOpen={createOpen}
103
+ onOpenChange={setCreateOpen}
104
+ organizationId={organizationId}
105
+ />
106
+ )}
69
107
  </div>
70
108
  )
71
109
  }
@@ -24,11 +24,14 @@ import { NewApiKeyDialog } from "./new-api-key-dialog"
24
24
  export type CreateApiKeyDialogProps = {
25
25
  isOpen: boolean
26
26
  onOpenChange: (open: boolean) => void
27
+ /** Create an organization-owned key by passing the organization id. */
28
+ organizationId?: string
27
29
  }
28
30
 
29
31
  export function CreateApiKeyDialog({
30
32
  isOpen,
31
- onOpenChange
33
+ onOpenChange,
34
+ organizationId
32
35
  }: CreateApiKeyDialogProps) {
33
36
  const { authClient, localization } = useAuth()
34
37
  const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
@@ -56,7 +59,17 @@ export function CreateApiKeyDialog({
56
59
  const formData = new FormData(e.target as HTMLFormElement)
57
60
  const name = (formData.get("name") as string)?.trim()
58
61
 
59
- createApiKey(name ? { name } : undefined, {
62
+ const payload =
63
+ name || organizationId
64
+ ? {
65
+ ...(name ? { name } : {}),
66
+ ...(organizationId
67
+ ? { organizationId, configId: "organization" }
68
+ : {})
69
+ }
70
+ : undefined
71
+
72
+ createApiKey(payload, {
60
73
  onSuccess: (result) => {
61
74
  handleOpenChange(false)
62
75
  setKeyName(name)
@@ -21,12 +21,15 @@ export type DeleteApiKeyDialogProps = {
21
21
  isOpen: boolean
22
22
  onOpenChange: (open: boolean) => void
23
23
  apiKey: ListedApiKey
24
+ /** Scope the delete payload to an organization (sets `configId`). */
25
+ organizationId?: string
24
26
  }
25
27
 
26
28
  export function DeleteApiKeyDialog({
27
29
  isOpen,
28
30
  onOpenChange,
29
- apiKey
31
+ apiKey,
32
+ organizationId
30
33
  }: DeleteApiKeyDialogProps) {
31
34
  const { authClient, localization } = useAuth()
32
35
  const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
@@ -77,7 +80,12 @@ export function DeleteApiKeyDialog({
77
80
 
78
81
  <Button
79
82
  variant="danger"
80
- onPress={() => deleteApiKey({ keyId: apiKey.id })}
83
+ onPress={() =>
84
+ deleteApiKey({
85
+ keyId: apiKey.id,
86
+ ...(organizationId ? { configId: "organization" } : {})
87
+ })
88
+ }
81
89
  isPending={isDeleting}
82
90
  >
83
91
  {isDeleting && <Spinner color="current" size="sm" />}
@@ -0,0 +1,55 @@
1
+ import {
2
+ type OrganizationAuthClient,
3
+ useActiveOrganization,
4
+ useAuth,
5
+ useListOrganizationMembers,
6
+ useSession
7
+ } from "@better-auth-ui/react"
8
+ import type { CardProps } from "@heroui/react"
9
+
10
+ import { ApiKeys } from "./api-keys"
11
+
12
+ export type OrganizationApiKeysProps = {
13
+ className?: string
14
+ variant?: CardProps["variant"]
15
+ }
16
+
17
+ /**
18
+ * {@link ApiKeys} scoped to the active organization.
19
+ *
20
+ * Hidden for members whose role isn't `owner`. Better Auth's
21
+ * `/organization/has-permission` endpoint isn't usable for `apiKey:*` checks
22
+ * (it doesn't pass `allowCreatorAllPermissions` and the default org AC has no
23
+ * `apiKey` statements), so we gate on role directly.
24
+ */
25
+ export function OrganizationApiKeys({
26
+ className,
27
+ variant
28
+ }: OrganizationApiKeysProps) {
29
+ const { authClient } = useAuth()
30
+ const { data: session } = useSession(authClient)
31
+
32
+ const { data: activeOrganization, isPending: activeOrganizationPending } =
33
+ useActiveOrganization(authClient as OrganizationAuthClient)
34
+
35
+ const { data: membersData } = useListOrganizationMembers(
36
+ authClient as OrganizationAuthClient
37
+ )
38
+
39
+ const canManageApiKeys = membersData?.members.some(
40
+ (member) => member.role === "owner" && member.userId === session?.user.id
41
+ )
42
+
43
+ if (!canManageApiKeys) {
44
+ return null
45
+ }
46
+
47
+ return (
48
+ <ApiKeys
49
+ className={className}
50
+ variant={variant}
51
+ organizationId={activeOrganization?.id}
52
+ isPending={activeOrganizationPending}
53
+ />
54
+ )
55
+ }
@@ -2,7 +2,7 @@ import { useAuth } from "@better-auth-ui/react"
2
2
  import { type CardProps, cn } from "@heroui/react"
3
3
  import type { ComponentProps } from "react"
4
4
 
5
- import { DeleteUser } from "./delete-user"
5
+ import { DeleteAccount } from "./delete-account"
6
6
 
7
7
  export type DangerZoneProps = {
8
8
  className?: string
@@ -10,7 +10,7 @@ export type DangerZoneProps = {
10
10
  }
11
11
 
12
12
  /**
13
- * Renders the danger zone heading and {@link DeleteUser}.
13
+ * Renders the danger zone heading and {@link DeleteAccount}.
14
14
  * Registered as a `securityCard` by `deleteUserPlugin()`; gate by registering the plugin.
15
15
  */
16
16
  export function DangerZone({
@@ -26,7 +26,7 @@ export function DangerZone({
26
26
  {localization.settings.dangerZone}
27
27
  </h2>
28
28
 
29
- <DeleteUser variant={variant} />
29
+ <DeleteAccount variant={variant} />
30
30
  </div>
31
31
  )
32
32
  }
@@ -24,7 +24,7 @@ import { type SyntheticEvent, useState } from "react"
24
24
 
25
25
  import { deleteUserPlugin } from "../../../lib/auth/delete-user-plugin"
26
26
 
27
- export type DeleteUserProps = {
27
+ export type DeleteAccountProps = {
28
28
  className?: string
29
29
  variant?: CardProps["variant"]
30
30
  }
@@ -32,11 +32,11 @@ export type DeleteUserProps = {
32
32
  /**
33
33
  * Danger-zone card to delete the authenticated account, with a confirmation dialog and toasts.
34
34
  */
35
- export function DeleteUser({
35
+ export function DeleteAccount({
36
36
  className,
37
37
  variant,
38
38
  ...props
39
- }: DeleteUserProps & Omit<CardProps, "children">) {
39
+ }: DeleteAccountProps & Omit<CardProps, "children">) {
40
40
  const { authClient, basePaths, localization, navigate, viewPaths } = useAuth()
41
41
 
42
42
  const {
@@ -94,11 +94,11 @@ export function DeleteUser({
94
94
  <Card.Content className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
95
95
  <div>
96
96
  <p className="text-sm font-medium leading-tight">
97
- {deleteUserLocalization.deleteUser}
97
+ {deleteUserLocalization.deleteAccount}
98
98
  </p>
99
99
 
100
100
  <p className="text-muted text-xs mt-0.5">
101
- {deleteUserLocalization.deleteUserDescription}
101
+ {deleteUserLocalization.deleteAccountDescription}
102
102
  </p>
103
103
  </div>
104
104
 
@@ -109,7 +109,7 @@ export function DeleteUser({
109
109
  variant="danger-soft"
110
110
  onPress={() => setConfirmOpen(true)}
111
111
  >
112
- {deleteUserLocalization.deleteUser}
112
+ {deleteUserLocalization.deleteAccount}
113
113
  </Button>
114
114
 
115
115
  <AlertDialog.Backdrop
@@ -127,13 +127,13 @@ export function DeleteUser({
127
127
  </AlertDialog.Icon>
128
128
 
129
129
  <AlertDialog.Heading>
130
- {deleteUserLocalization.deleteUser}
130
+ {deleteUserLocalization.deleteAccount}
131
131
  </AlertDialog.Heading>
132
132
  </AlertDialog.Header>
133
133
 
134
134
  <AlertDialog.Body className="overflow-visible">
135
135
  <p className="text-muted text-sm">
136
- {deleteUserLocalization.deleteUserDescription}
136
+ {deleteUserLocalization.deleteAccountDescription}
137
137
  </p>
138
138
 
139
139
  {needsPassword && (
@@ -175,7 +175,7 @@ export function DeleteUser({
175
175
  >
176
176
  {isPending && <Spinner color="current" size="sm" />}
177
177
 
178
- {deleteUserLocalization.deleteUser}
178
+ {deleteUserLocalization.deleteAccount}
179
179
  </Button>
180
180
  </AlertDialog.Footer>
181
181
  </Form>
@@ -0,0 +1,38 @@
1
+ import {
2
+ OrganizationInvitationEmail as OrganizationInvitationEmailPrimitive,
3
+ type OrganizationInvitationEmailProps
4
+ } from "@better-auth-ui/react/email"
5
+ import { cn } from "@heroui/react"
6
+
7
+ export type { OrganizationInvitationEmailProps } from "@better-auth-ui/react/email"
8
+
9
+ export function OrganizationInvitationEmail({
10
+ colors,
11
+ classNames,
12
+ ...props
13
+ }: OrganizationInvitationEmailProps) {
14
+ return (
15
+ <OrganizationInvitationEmailPrimitive
16
+ colors={{
17
+ light: {
18
+ background: "#F5F5F5",
19
+ primary: "#0285F7",
20
+ primaryForeground: "#FCFCFC",
21
+ ...colors?.light
22
+ },
23
+ dark: {
24
+ background: "#060607",
25
+ primary: "#0584F6",
26
+ primaryForeground: "#FCFCFC",
27
+ ...colors?.dark
28
+ }
29
+ }}
30
+ classNames={{
31
+ ...classNames,
32
+ card: cn("border-none rounded-3xl", classNames?.card),
33
+ button: cn("rounded-full", classNames?.button)
34
+ }}
35
+ {...props}
36
+ />
37
+ )
38
+ }