@stackframe/stack 2.8.12 → 2.8.16

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 (228) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/components/api-key-dialogs.js +5 -4
  3. package/dist/components/api-key-dialogs.js.map +1 -1
  4. package/dist/components/credential-sign-in.js +4 -4
  5. package/dist/components/credential-sign-up.js +3 -3
  6. package/dist/components/elements/maybe-full-page.js +1 -1
  7. package/dist/components/elements/sidebar-layout.js +1 -1
  8. package/dist/components/magic-link-sign-in.js +3 -3
  9. package/dist/components/message-cards/known-error-message-card.js +2 -2
  10. package/dist/components/message-cards/message-card.js +1 -1
  11. package/dist/components/message-cards/predefined-message-card.js +3 -3
  12. package/dist/components/oauth-button-group.js +2 -2
  13. package/dist/components/oauth-button.js +27 -16
  14. package/dist/components/oauth-button.js.map +1 -1
  15. package/dist/components/passkey-button.js +2 -2
  16. package/dist/components/profile-image-editor.js +87 -34
  17. package/dist/components/profile-image-editor.js.map +1 -1
  18. package/dist/components/selected-team-switcher.js +41 -9
  19. package/dist/components/selected-team-switcher.js.map +1 -1
  20. package/dist/components/{iframe-preventer.js → use-in-iframe.js} +9 -19
  21. package/dist/components/use-in-iframe.js.map +1 -0
  22. package/dist/components/user-button.js +41 -8
  23. package/dist/components/user-button.js.map +1 -1
  24. package/dist/components-page/account-settings/active-sessions/active-sessions-page.js +57 -12
  25. package/dist/components-page/account-settings/active-sessions/active-sessions-page.js.map +1 -1
  26. package/dist/components-page/account-settings/api-keys/api-keys-page.js +100 -12
  27. package/dist/components-page/account-settings/api-keys/api-keys-page.js.map +1 -1
  28. package/dist/components-page/account-settings/editable-text.js +1 -1
  29. package/dist/components-page/account-settings/email-and-auth/email-and-auth-page.js +12 -12
  30. package/dist/components-page/account-settings/email-and-auth/email-and-auth-page.js.map +1 -1
  31. package/dist/components-page/account-settings/email-and-auth/emails-section.js +14 -5
  32. package/dist/components-page/account-settings/email-and-auth/emails-section.js.map +1 -1
  33. package/dist/components-page/account-settings/email-and-auth/mfa-section.js +18 -5
  34. package/dist/components-page/account-settings/email-and-auth/mfa-section.js.map +1 -1
  35. package/dist/components-page/account-settings/email-and-auth/otp-section.js +18 -5
  36. package/dist/components-page/account-settings/email-and-auth/otp-section.js.map +1 -1
  37. package/dist/components-page/account-settings/email-and-auth/passkey-section.js +19 -6
  38. package/dist/components-page/account-settings/email-and-auth/passkey-section.js.map +1 -1
  39. package/dist/components-page/account-settings/email-and-auth/password-section.js +20 -7
  40. package/dist/components-page/account-settings/email-and-auth/password-section.js.map +1 -1
  41. package/dist/components-page/account-settings/profile-page/profile-page.js +18 -8
  42. package/dist/components-page/account-settings/profile-page/profile-page.js.map +1 -1
  43. package/dist/components-page/account-settings/settings/delete-account-section.js +19 -10
  44. package/dist/components-page/account-settings/settings/delete-account-section.js.map +1 -1
  45. package/dist/components-page/account-settings/settings/settings-page.js +6 -6
  46. package/dist/components-page/account-settings/settings/settings-page.js.map +1 -1
  47. package/dist/components-page/account-settings/settings/sign-out-section.js +15 -6
  48. package/dist/components-page/account-settings/settings/sign-out-section.js.map +1 -1
  49. package/dist/components-page/account-settings/teams/leave-team-section.js +3 -3
  50. package/dist/components-page/account-settings/teams/team-api-keys-section.js +5 -5
  51. package/dist/components-page/account-settings/teams/team-creation-page.js +19 -10
  52. package/dist/components-page/account-settings/teams/team-creation-page.js.map +1 -1
  53. package/dist/components-page/account-settings/teams/team-display-name-section.js +4 -4
  54. package/dist/components-page/account-settings/teams/team-member-invitation-section.js +4 -4
  55. package/dist/components-page/account-settings/teams/team-member-list-section.js +3 -3
  56. package/dist/components-page/account-settings/teams/team-page.js +8 -8
  57. package/dist/components-page/account-settings/teams/team-profile-image-section.js +4 -4
  58. package/dist/components-page/account-settings/teams/team-profile-user-section.js +4 -4
  59. package/dist/components-page/account-settings.js +29 -21
  60. package/dist/components-page/account-settings.js.map +1 -1
  61. package/dist/components-page/auth-page.js +11 -12
  62. package/dist/components-page/auth-page.js.map +1 -1
  63. package/dist/components-page/cli-auth-confirm.js +3 -3
  64. package/dist/components-page/email-verification.js +3 -3
  65. package/dist/components-page/error-page.js +6 -6
  66. package/dist/components-page/error-page.js.map +1 -1
  67. package/dist/components-page/forgot-password.js +6 -6
  68. package/dist/components-page/magic-link-callback.js +4 -4
  69. package/dist/components-page/mfa.js +190 -0
  70. package/dist/components-page/mfa.js.map +1 -0
  71. package/dist/components-page/oauth-callback.js +4 -4
  72. package/dist/components-page/password-reset.js +6 -6
  73. package/dist/components-page/sign-in.js +3 -2
  74. package/dist/components-page/sign-in.js.map +1 -1
  75. package/dist/components-page/sign-out.js +2 -2
  76. package/dist/components-page/sign-up.js +1 -1
  77. package/dist/components-page/stack-handler.js +25 -14
  78. package/dist/components-page/stack-handler.js.map +1 -1
  79. package/dist/components-page/team-creation.js +4 -4
  80. package/dist/components-page/team-invitation.js +3 -3
  81. package/dist/esm/components/api-key-dialogs.js +5 -4
  82. package/dist/esm/components/api-key-dialogs.js.map +1 -1
  83. package/dist/esm/components/credential-sign-in.js +4 -4
  84. package/dist/esm/components/credential-sign-up.js +3 -3
  85. package/dist/esm/components/elements/maybe-full-page.js +1 -1
  86. package/dist/esm/components/elements/sidebar-layout.js +1 -1
  87. package/dist/esm/components/magic-link-sign-in.js +3 -3
  88. package/dist/esm/components/message-cards/known-error-message-card.js +2 -2
  89. package/dist/esm/components/message-cards/message-card.js +1 -1
  90. package/dist/esm/components/message-cards/predefined-message-card.js +3 -3
  91. package/dist/esm/components/oauth-button-group.js +2 -2
  92. package/dist/esm/components/oauth-button.js +28 -17
  93. package/dist/esm/components/oauth-button.js.map +1 -1
  94. package/dist/esm/components/passkey-button.js +2 -2
  95. package/dist/esm/components/profile-image-editor.js +86 -34
  96. package/dist/esm/components/profile-image-editor.js.map +1 -1
  97. package/dist/esm/components/selected-team-switcher.js +41 -9
  98. package/dist/esm/components/selected-team-switcher.js.map +1 -1
  99. package/dist/esm/components/use-in-iframe.js +18 -0
  100. package/dist/esm/components/use-in-iframe.js.map +1 -0
  101. package/dist/esm/components/user-button.js +41 -8
  102. package/dist/esm/components/user-button.js.map +1 -1
  103. package/dist/esm/components-page/account-settings/active-sessions/active-sessions-page.js +57 -12
  104. package/dist/esm/components-page/account-settings/active-sessions/active-sessions-page.js.map +1 -1
  105. package/dist/esm/components-page/account-settings/api-keys/api-keys-page.js +100 -12
  106. package/dist/esm/components-page/account-settings/api-keys/api-keys-page.js.map +1 -1
  107. package/dist/esm/components-page/account-settings/editable-text.js +1 -1
  108. package/dist/esm/components-page/account-settings/email-and-auth/email-and-auth-page.js +12 -12
  109. package/dist/esm/components-page/account-settings/email-and-auth/email-and-auth-page.js.map +1 -1
  110. package/dist/esm/components-page/account-settings/email-and-auth/emails-section.js +14 -5
  111. package/dist/esm/components-page/account-settings/email-and-auth/emails-section.js.map +1 -1
  112. package/dist/esm/components-page/account-settings/email-and-auth/mfa-section.js +18 -5
  113. package/dist/esm/components-page/account-settings/email-and-auth/mfa-section.js.map +1 -1
  114. package/dist/esm/components-page/account-settings/email-and-auth/otp-section.js +18 -5
  115. package/dist/esm/components-page/account-settings/email-and-auth/otp-section.js.map +1 -1
  116. package/dist/esm/components-page/account-settings/email-and-auth/passkey-section.js +19 -6
  117. package/dist/esm/components-page/account-settings/email-and-auth/passkey-section.js.map +1 -1
  118. package/dist/esm/components-page/account-settings/email-and-auth/password-section.js +20 -7
  119. package/dist/esm/components-page/account-settings/email-and-auth/password-section.js.map +1 -1
  120. package/dist/esm/components-page/account-settings/profile-page/profile-page.js +18 -8
  121. package/dist/esm/components-page/account-settings/profile-page/profile-page.js.map +1 -1
  122. package/dist/esm/components-page/account-settings/settings/delete-account-section.js +19 -10
  123. package/dist/esm/components-page/account-settings/settings/delete-account-section.js.map +1 -1
  124. package/dist/esm/components-page/account-settings/settings/settings-page.js +6 -6
  125. package/dist/esm/components-page/account-settings/settings/settings-page.js.map +1 -1
  126. package/dist/esm/components-page/account-settings/settings/sign-out-section.js +15 -6
  127. package/dist/esm/components-page/account-settings/settings/sign-out-section.js.map +1 -1
  128. package/dist/esm/components-page/account-settings/teams/leave-team-section.js +3 -3
  129. package/dist/esm/components-page/account-settings/teams/team-api-keys-section.js +5 -5
  130. package/dist/esm/components-page/account-settings/teams/team-creation-page.js +19 -10
  131. package/dist/esm/components-page/account-settings/teams/team-creation-page.js.map +1 -1
  132. package/dist/esm/components-page/account-settings/teams/team-display-name-section.js +4 -4
  133. package/dist/esm/components-page/account-settings/teams/team-member-invitation-section.js +4 -4
  134. package/dist/esm/components-page/account-settings/teams/team-member-list-section.js +3 -3
  135. package/dist/esm/components-page/account-settings/teams/team-page.js +8 -8
  136. package/dist/esm/components-page/account-settings/teams/team-profile-image-section.js +4 -4
  137. package/dist/esm/components-page/account-settings/teams/team-profile-user-section.js +4 -4
  138. package/dist/esm/components-page/account-settings.js +29 -21
  139. package/dist/esm/components-page/account-settings.js.map +1 -1
  140. package/dist/esm/components-page/auth-page.js +11 -12
  141. package/dist/esm/components-page/auth-page.js.map +1 -1
  142. package/dist/esm/components-page/cli-auth-confirm.js +3 -3
  143. package/dist/esm/components-page/email-verification.js +3 -3
  144. package/dist/esm/components-page/error-page.js +6 -6
  145. package/dist/esm/components-page/error-page.js.map +1 -1
  146. package/dist/esm/components-page/forgot-password.js +6 -6
  147. package/dist/esm/components-page/magic-link-callback.js +4 -4
  148. package/dist/esm/components-page/mfa.js +174 -0
  149. package/dist/esm/components-page/mfa.js.map +1 -0
  150. package/dist/esm/components-page/oauth-callback.js +4 -4
  151. package/dist/esm/components-page/password-reset.js +6 -6
  152. package/dist/esm/components-page/sign-in.js +3 -2
  153. package/dist/esm/components-page/sign-in.js.map +1 -1
  154. package/dist/esm/components-page/sign-out.js +2 -2
  155. package/dist/esm/components-page/sign-up.js +1 -1
  156. package/dist/esm/components-page/stack-handler.js +25 -14
  157. package/dist/esm/components-page/stack-handler.js.map +1 -1
  158. package/dist/esm/components-page/team-creation.js +4 -4
  159. package/dist/esm/components-page/team-invitation.js +3 -3
  160. package/dist/esm/generated/global-css.js +1 -1
  161. package/dist/esm/generated/global-css.js.map +1 -1
  162. package/dist/esm/generated/quetzal-translations.js +3574 -2364
  163. package/dist/esm/generated/quetzal-translations.js.map +1 -1
  164. package/dist/esm/index.js +22 -22
  165. package/dist/esm/lib/auth.js +2 -2
  166. package/dist/esm/lib/cookie.js +1 -129
  167. package/dist/esm/lib/cookie.js.map +1 -1
  168. package/dist/esm/lib/hooks.js +1 -1
  169. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js +8 -8
  170. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  171. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +52 -21
  172. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  173. package/dist/esm/lib/stack-app/apps/implementations/common.js +2 -1
  174. package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
  175. package/dist/esm/lib/stack-app/apps/implementations/index.js +3 -3
  176. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +8 -8
  177. package/dist/esm/lib/stack-app/apps/index.js +3 -3
  178. package/dist/esm/lib/stack-app/apps/interfaces/admin-app.js +1 -1
  179. package/dist/esm/lib/stack-app/apps/interfaces/client-app.js +1 -1
  180. package/dist/esm/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
  181. package/dist/esm/lib/stack-app/apps/interfaces/server-app.js +1 -1
  182. package/dist/esm/lib/stack-app/common.js.map +1 -1
  183. package/dist/esm/lib/stack-app/index.js +2 -2
  184. package/dist/esm/lib/stack-app/internal-api-keys/index.js.map +1 -1
  185. package/dist/esm/lib/translations.js +1 -1
  186. package/dist/esm/providers/stack-provider-client.js +2 -2
  187. package/dist/esm/providers/stack-provider.js +3 -3
  188. package/dist/esm/providers/theme-provider.js +3 -3
  189. package/dist/esm/providers/translation-provider.js +2 -2
  190. package/dist/esm/utils/browser-script.js +1 -1
  191. package/dist/generated/global-css.js +1 -1
  192. package/dist/generated/global-css.js.map +1 -1
  193. package/dist/generated/quetzal-translations.js +3574 -2364
  194. package/dist/generated/quetzal-translations.js.map +1 -1
  195. package/dist/index.d.mts +71 -2
  196. package/dist/index.d.ts +71 -2
  197. package/dist/index.js +23 -23
  198. package/dist/index.js.map +1 -1
  199. package/dist/lib/auth.js +2 -2
  200. package/dist/lib/cookie.js +4 -132
  201. package/dist/lib/cookie.js.map +1 -1
  202. package/dist/lib/hooks.js +1 -1
  203. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js +8 -8
  204. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  205. package/dist/lib/stack-app/apps/implementations/client-app-impl.js +52 -21
  206. package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  207. package/dist/lib/stack-app/apps/implementations/common.js +2 -1
  208. package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
  209. package/dist/lib/stack-app/apps/implementations/index.js +3 -3
  210. package/dist/lib/stack-app/apps/implementations/server-app-impl.js +8 -8
  211. package/dist/lib/stack-app/apps/index.js +3 -3
  212. package/dist/lib/stack-app/apps/interfaces/admin-app.js +1 -1
  213. package/dist/lib/stack-app/apps/interfaces/client-app.js +1 -1
  214. package/dist/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
  215. package/dist/lib/stack-app/apps/interfaces/server-app.js +1 -1
  216. package/dist/lib/stack-app/common.js.map +1 -1
  217. package/dist/lib/stack-app/index.js +2 -2
  218. package/dist/lib/stack-app/internal-api-keys/index.js.map +1 -1
  219. package/dist/lib/translations.js +1 -1
  220. package/dist/providers/stack-provider-client.js +2 -2
  221. package/dist/providers/stack-provider.js +3 -3
  222. package/dist/providers/theme-provider.js +3 -3
  223. package/dist/providers/translation-provider.js +2 -2
  224. package/dist/utils/browser-script.js +1 -1
  225. package/package.json +5 -5
  226. package/dist/components/iframe-preventer.js.map +0 -1
  227. package/dist/esm/components/iframe-preventer.js +0 -28
  228. package/dist/esm/components/iframe-preventer.js.map +0 -1
@@ -29,9 +29,9 @@ var import_promises = require("@stackframe/stack-shared/dist/utils/promises");
29
29
  var import_stack_ui = require("@stackframe/stack-ui");
30
30
  var import_lucide_react = require("lucide-react");
31
31
  var import_react = require("react");
32
- var import__ = require("..");
33
- var import_translations = require("../lib/translations");
34
- var import_team_icon = require("./team-icon");
32
+ var import__ = require("../index.js");
33
+ var import_translations = require("../lib/translations.js");
34
+ var import_team_icon = require("./team-icon.js");
35
35
  var import_jsx_runtime = require("react/jsx-runtime");
36
36
  function SelectedTeamSwitcher(props) {
37
37
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Fallback, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Inner, { ...props }) });
@@ -41,23 +41,38 @@ function Fallback() {
41
41
  }
42
42
  function Inner(props) {
43
43
  const { t } = (0, import_translations.useTranslation)();
44
- const app = (0, import__.useStackApp)();
45
- const user = (0, import__.useUser)();
44
+ const appFromHook = (0, import__.useStackApp)();
45
+ const userFromHook = (0, import__.useUser)();
46
+ const app = props.mockUser ? {
47
+ useProject: () => props.mockProject || { config: { clientTeamCreationEnabled: false } },
48
+ useNavigate: () => () => {
49
+ },
50
+ // Mock navigate function
51
+ urls: { accountSettings: "/account-settings" }
52
+ } : appFromHook;
53
+ const user = props.mockUser ? {
54
+ selectedTeam: props.mockUser.selectedTeam,
55
+ useTeams: () => props.mockTeams || [],
56
+ setSelectedTeam: async () => {
57
+ }
58
+ // Mock function
59
+ } : userFromHook;
46
60
  const project = app.useProject();
47
61
  const navigate = app.useNavigate();
48
62
  const selectedTeam = user?.selectedTeam || props.selectedTeam;
49
63
  const rawTeams = user?.useTeams();
50
64
  const teams = (0, import_react.useMemo)(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);
51
65
  (0, import_react.useEffect)(() => {
52
- if (!props.noUpdateSelectedTeam && props.selectedTeam) {
66
+ if (!props.noUpdateSelectedTeam && props.selectedTeam && !props.mockUser) {
53
67
  (0, import_promises.runAsynchronouslyWithAlert)(user?.setSelectedTeam(props.selectedTeam));
54
68
  }
55
- }, [props.noUpdateSelectedTeam, props.selectedTeam]);
69
+ }, [props.noUpdateSelectedTeam, props.selectedTeam, props.mockUser]);
56
70
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
57
71
  import_stack_ui.Select,
58
72
  {
59
73
  value: selectedTeam?.id,
60
74
  onValueChange: (value) => {
75
+ if (props.mockUser) return;
61
76
  (0, import_promises.runAsynchronouslyWithAlert)(async () => {
62
77
  const team = teams?.find((team2) => team2.id === value);
63
78
  if (!team) {
@@ -77,7 +92,20 @@ function Inner(props) {
77
92
  user?.selectedTeam ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.SelectGroup, { children: [
78
93
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.SelectLabel, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
79
94
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("Current team") }),
80
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { variant: "ghost", size: "icon", className: "h-6 w-6", onClick: () => navigate(`${app.urls.accountSettings}#team-${user.selectedTeam?.id}`), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Settings, { className: "h-4 w-4" }) })
95
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
96
+ import_stack_ui.Button,
97
+ {
98
+ variant: "ghost",
99
+ size: "icon",
100
+ className: "h-6 w-6",
101
+ onClick: () => {
102
+ if (!props.mockUser) {
103
+ navigate(`${app.urls.accountSettings}#team-${user.selectedTeam?.id}`);
104
+ }
105
+ },
106
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Settings, { className: "h-4 w-4" })
107
+ }
108
+ )
81
109
  ] }) }),
82
110
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.SelectItem, { value: user.selectedTeam.id, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
83
111
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_team_icon.TeamIcon, { team: user.selectedTeam }),
@@ -96,7 +124,11 @@ function Inner(props) {
96
124
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
97
125
  import_stack_ui.Button,
98
126
  {
99
- onClick: () => navigate(`${app.urls.accountSettings}#team-creation`),
127
+ onClick: () => {
128
+ if (!props.mockUser) {
129
+ navigate(`${app.urls.accountSettings}#team-creation`);
130
+ }
131
+ },
100
132
  className: "w-full",
101
133
  variant: "ghost",
102
134
  children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/selected-team-switcher.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport {\n Button,\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Typography\n} from \"@stackframe/stack-ui\";\nimport { PlusCircle, Settings } from \"lucide-react\";\nimport { Suspense, useEffect, useMemo } from \"react\";\nimport { Team, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { TeamIcon } from \"./team-icon\";\n\ntype SelectedTeamSwitcherProps = {\n urlMap?: (team: Team) => string,\n selectedTeam?: Team,\n noUpdateSelectedTeam?: boolean,\n};\n\nexport function SelectedTeamSwitcher(props: SelectedTeamSwitcherProps) {\n return <Suspense fallback={<Fallback />}>\n <Inner {...props} />\n </Suspense>;\n}\n\nfunction Fallback() {\n return <Skeleton className=\"h-9 w-full max-w-64 stack-scope\" />;\n}\n\nfunction Inner(props: SelectedTeamSwitcherProps) {\n const { t } = useTranslation();\n const app = useStackApp();\n const user = useUser();\n const project = app.useProject();\n const navigate = app.useNavigate();\n const selectedTeam = user?.selectedTeam || props.selectedTeam;\n const rawTeams = user?.useTeams();\n const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);\n\n useEffect(() => {\n if (!props.noUpdateSelectedTeam && props.selectedTeam) {\n runAsynchronouslyWithAlert(user?.setSelectedTeam(props.selectedTeam));\n }\n }, [props.noUpdateSelectedTeam, props.selectedTeam]);\n\n return (\n <Select\n value={selectedTeam?.id}\n onValueChange={(value) => {\n runAsynchronouslyWithAlert(async () => {\n const team = teams?.find(team => team.id === value);\n if (!team) {\n throw new Error('Team not found, this should not happen');\n }\n\n if (!props.noUpdateSelectedTeam) {\n await user?.setSelectedTeam(team);\n }\n if (props.urlMap) {\n navigate(props.urlMap(team));\n }\n });\n }}\n >\n <SelectTrigger className=\"stack-scope max-w-64\">\n <SelectValue placeholder=\"Select team\"/>\n </SelectTrigger>\n <SelectContent className=\"stack-scope\">\n {user?.selectedTeam ? <SelectGroup>\n <SelectLabel>\n <div className=\"flex items-center justify-between\">\n <span>\n {t('Current team')}\n </span>\n <Button variant='ghost' size='icon' className=\"h-6 w-6\" onClick={() => navigate(`${app.urls.accountSettings}#team-${user.selectedTeam?.id}`)}>\n <Settings className=\"h-4 w-4\"/>\n </Button>\n </div>\n </SelectLabel>\n <SelectItem value={user.selectedTeam.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={user.selectedTeam} />\n <Typography className=\"max-w-40 truncate\">{user.selectedTeam.displayName}</Typography>\n </div>\n </SelectItem>\n </SelectGroup> : undefined}\n\n {teams?.length ?\n <SelectGroup>\n <SelectLabel>{t('Other teams')}</SelectLabel>\n {teams.filter(team => team.id !== user?.selectedTeam?.id)\n .map(team => (\n <SelectItem value={team.id} key={team.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={team} />\n <Typography className=\"max-w-64 truncate\">{team.displayName}</Typography>\n </div>\n </SelectItem>\n ))}\n </SelectGroup> :\n <SelectGroup>\n <SelectLabel>{t('No teams yet')}</SelectLabel>\n </SelectGroup>}\n\n {project.config.clientTeamCreationEnabled && <>\n <SelectSeparator/>\n <div>\n <Button\n onClick={() => navigate(`${app.urls.accountSettings}#team-creation`)}\n className=\"w-full\"\n variant='ghost'\n >\n <PlusCircle className=\"mr-2 h-4 w-4\"/> {t('Create a team')}\n </Button>\n </div>\n </>}\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,sBAA2C;AAC3C,sBAYO;AACP,0BAAqC;AACrC,mBAA6C;AAC7C,eAA2C;AAC3C,0BAA+B;AAC/B,uBAAyB;AASI;AADtB,SAAS,qBAAqB,OAAkC;AACrE,SAAO,4CAAC,yBAAS,UAAU,4CAAC,YAAS,GACnC,sDAAC,SAAO,GAAG,OAAO,GACpB;AACF;AAEA,SAAS,WAAW;AAClB,SAAO,4CAAC,4BAAS,WAAU,mCAAkC;AAC/D;AAEA,SAAS,MAAM,OAAkC;AAC/C,QAAM,EAAE,EAAE,QAAI,oCAAe;AAC7B,QAAM,UAAM,sBAAY;AACxB,QAAM,WAAO,kBAAQ;AACrB,QAAM,UAAU,IAAI,WAAW;AAC/B,QAAM,WAAW,IAAI,YAAY;AACjC,QAAM,eAAe,MAAM,gBAAgB,MAAM;AACjD,QAAM,WAAW,MAAM,SAAS;AAChC,QAAM,YAAQ,sBAAQ,MAAM,UAAU,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,cAAc,KAAK,IAAI,EAAE,GAAG,CAAC,UAAU,YAAY,CAAC;AAElH,8BAAU,MAAM;AACd,QAAI,CAAC,MAAM,wBAAwB,MAAM,cAAc;AACrD,sDAA2B,MAAM,gBAAgB,MAAM,YAAY,CAAC;AAAA,IACtE;AAAA,EACF,GAAG,CAAC,MAAM,sBAAsB,MAAM,YAAY,CAAC;AAEnD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,cAAc;AAAA,MACrB,eAAe,CAAC,UAAU;AACxB,wDAA2B,YAAY;AACrC,gBAAM,OAAO,OAAO,KAAK,CAAAA,UAAQA,MAAK,OAAO,KAAK;AAClD,cAAI,CAAC,MAAM;AACT,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC1D;AAEA,cAAI,CAAC,MAAM,sBAAsB;AAC/B,kBAAM,MAAM,gBAAgB,IAAI;AAAA,UAClC;AACA,cAAI,MAAM,QAAQ;AAChB,qBAAS,MAAM,OAAO,IAAI,CAAC;AAAA,UAC7B;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA;AAAA,oDAAC,iCAAc,WAAU,wBACvB,sDAAC,+BAAY,aAAY,eAAa,GACxC;AAAA,QACA,6CAAC,iCAAc,WAAU,eACtB;AAAA,gBAAM,eAAe,6CAAC,+BACrB;AAAA,wDAAC,+BACC,uDAAC,SAAI,WAAU,qCACb;AAAA,0DAAC,UACE,YAAE,cAAc,GACnB;AAAA,cACA,4CAAC,0BAAO,SAAQ,SAAQ,MAAK,QAAO,WAAU,WAAU,SAAS,MAAM,SAAS,GAAG,IAAI,KAAK,eAAe,SAAS,KAAK,cAAc,EAAE,EAAE,GACzI,sDAAC,gCAAS,WAAU,WAAS,GAC/B;AAAA,eACF,GACF;AAAA,YACA,4CAAC,8BAAW,OAAO,KAAK,aAAa,IACnC,uDAAC,SAAI,WAAU,2BACb;AAAA,0DAAC,6BAAS,MAAM,KAAK,cAAc;AAAA,cACnC,4CAAC,8BAAW,WAAU,qBAAqB,eAAK,aAAa,aAAY;AAAA,eAC3E,GACF;AAAA,aACF,IAAiB;AAAA,UAEhB,OAAO,SACN,6CAAC,+BACC;AAAA,wDAAC,+BAAa,YAAE,aAAa,GAAE;AAAA,YAC9B,MAAM,OAAO,UAAQ,KAAK,OAAO,MAAM,cAAc,EAAE,EACrD,IAAI,UACH,4CAAC,8BAAW,OAAO,KAAK,IACtB,uDAAC,SAAI,WAAU,2BACb;AAAA,0DAAC,6BAAS,MAAY;AAAA,cACtB,4CAAC,8BAAW,WAAU,qBAAqB,eAAK,aAAY;AAAA,eAC9D,KAJ+B,KAAK,EAKtC,CACD;AAAA,aACL,IACA,4CAAC,+BACC,sDAAC,+BAAa,YAAE,cAAc,GAAE,GAClC;AAAA,UAED,QAAQ,OAAO,6BAA6B,4EAC3C;AAAA,wDAAC,mCAAe;AAAA,YAChB,4CAAC,SACC;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS,MAAM,SAAS,GAAG,IAAI,KAAK,eAAe,gBAAgB;AAAA,gBACnE,WAAU;AAAA,gBACV,SAAQ;AAAA,gBAER;AAAA,8DAAC,kCAAW,WAAU,gBAAc;AAAA,kBAAE;AAAA,kBAAE,EAAE,eAAe;AAAA;AAAA;AAAA,YAC3D,GACF;AAAA,aACF;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;","names":["team"]}
1
+ {"version":3,"sources":["../../src/components/selected-team-switcher.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport {\n Button,\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Typography\n} from \"@stackframe/stack-ui\";\nimport { PlusCircle, Settings } from \"lucide-react\";\nimport { Suspense, useEffect, useMemo } from \"react\";\nimport { Team, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { TeamIcon } from \"./team-icon\";\n\ntype MockTeam = {\n id: string,\n displayName: string,\n profileImageUrl?: string | null,\n};\n\ntype SelectedTeamSwitcherProps = {\n urlMap?: (team: Team) => string,\n selectedTeam?: Team,\n noUpdateSelectedTeam?: boolean,\n // Mock data props\n mockUser?: {\n selectedTeam?: MockTeam,\n },\n mockTeams?: MockTeam[],\n mockProject?: {\n config: {\n clientTeamCreationEnabled: boolean,\n },\n },\n};\n\nexport function SelectedTeamSwitcher(props: SelectedTeamSwitcherProps) {\n return <Suspense fallback={<Fallback />}>\n <Inner {...props} />\n </Suspense>;\n}\n\nfunction Fallback() {\n return <Skeleton className=\"h-9 w-full max-w-64 stack-scope\" />;\n}\n\nfunction Inner(props: SelectedTeamSwitcherProps) {\n const { t } = useTranslation();\n const appFromHook = useStackApp();\n const userFromHook = useUser();\n\n // Use mock data if provided, otherwise use real data\n const app = props.mockUser ? {\n useProject: () => props.mockProject || { config: { clientTeamCreationEnabled: false } },\n useNavigate: () => () => {}, // Mock navigate function\n urls: { accountSettings: '/account-settings' },\n } : appFromHook;\n\n const user = props.mockUser ? {\n selectedTeam: props.mockUser.selectedTeam,\n useTeams: () => props.mockTeams || [],\n setSelectedTeam: async () => {}, // Mock function\n } : userFromHook;\n\n const project = app.useProject();\n const navigate = app.useNavigate();\n const selectedTeam = user?.selectedTeam || props.selectedTeam;\n const rawTeams = user?.useTeams();\n const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);\n\n useEffect(() => {\n if (!props.noUpdateSelectedTeam && props.selectedTeam && !props.mockUser) {\n runAsynchronouslyWithAlert(user?.setSelectedTeam(props.selectedTeam));\n }\n }, [props.noUpdateSelectedTeam, props.selectedTeam, props.mockUser]);\n\n return (\n <Select\n value={selectedTeam?.id}\n onValueChange={(value) => {\n // Skip actual navigation/updates in mock mode\n if (props.mockUser) return;\n\n runAsynchronouslyWithAlert(async () => {\n const team = teams?.find(team => team.id === value);\n if (!team) {\n throw new Error('Team not found, this should not happen');\n }\n\n if (!props.noUpdateSelectedTeam) {\n await user?.setSelectedTeam(team as Team);\n }\n if (props.urlMap) {\n navigate(props.urlMap(team as Team));\n }\n });\n }}\n >\n <SelectTrigger className=\"stack-scope max-w-64\">\n <SelectValue placeholder=\"Select team\"/>\n </SelectTrigger>\n <SelectContent className=\"stack-scope\">\n {user?.selectedTeam ? <SelectGroup>\n <SelectLabel>\n <div className=\"flex items-center justify-between\">\n <span>\n {t('Current team')}\n </span>\n <Button\n variant='ghost'\n size='icon'\n className=\"h-6 w-6\"\n onClick={() => {\n // Skip navigation in mock mode\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-${user.selectedTeam?.id}`);\n }\n }}\n >\n <Settings className=\"h-4 w-4\"/>\n </Button>\n </div>\n </SelectLabel>\n <SelectItem value={user.selectedTeam.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={user.selectedTeam as Team} />\n <Typography className=\"max-w-40 truncate\">{user.selectedTeam.displayName}</Typography>\n </div>\n </SelectItem>\n </SelectGroup> : undefined}\n\n {teams?.length ?\n <SelectGroup>\n <SelectLabel>{t('Other teams')}</SelectLabel>\n {teams.filter(team => team.id !== user?.selectedTeam?.id)\n .map(team => (\n <SelectItem value={team.id} key={team.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={team as Team} />\n <Typography className=\"max-w-64 truncate\">{team.displayName}</Typography>\n </div>\n </SelectItem>\n ))}\n </SelectGroup> :\n <SelectGroup>\n <SelectLabel>{t('No teams yet')}</SelectLabel>\n </SelectGroup>}\n\n {project.config.clientTeamCreationEnabled && <>\n <SelectSeparator/>\n <div>\n <Button\n onClick={() => {\n // Skip navigation in mock mode\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-creation`);\n }\n }}\n className=\"w-full\"\n variant='ghost'\n >\n <PlusCircle className=\"mr-2 h-4 w-4\"/> {t('Create a team')}\n </Button>\n </div>\n </>}\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":"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","names":["team"]}
@@ -19,34 +19,24 @@ var __copyProps = (to, from, except, desc) => {
19
19
  };
20
20
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
21
 
22
- // src/components/iframe-preventer.tsx
23
- var iframe_preventer_exports = {};
24
- __export(iframe_preventer_exports, {
25
- IframePreventer: () => IframePreventer
22
+ // src/components/use-in-iframe.tsx
23
+ var use_in_iframe_exports = {};
24
+ __export(use_in_iframe_exports, {
25
+ useInIframe: () => useInIframe
26
26
  });
27
- module.exports = __toCommonJS(iframe_preventer_exports);
27
+ module.exports = __toCommonJS(use_in_iframe_exports);
28
28
  var import_react = require("react");
29
- var import_jsx_runtime = require("react/jsx-runtime");
30
- function IframePreventer({ children }) {
29
+ function useInIframe() {
31
30
  const [isIframe, setIsIframe] = (0, import_react.useState)(false);
32
31
  (0, import_react.useEffect)(() => {
33
32
  if (window.self !== window.top) {
34
33
  setIsIframe(true);
35
34
  }
36
35
  }, []);
37
- if (isIframe) {
38
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
39
- "Stack Auth components may not run in an ",
40
- "<",
41
- "iframe",
42
- ">",
43
- "."
44
- ] });
45
- }
46
- return children;
36
+ return isIframe;
47
37
  }
48
38
  // Annotate the CommonJS export names for ESM import in node:
49
39
  0 && (module.exports = {
50
- IframePreventer
40
+ useInIframe
51
41
  });
52
- //# sourceMappingURL=iframe-preventer.js.map
42
+ //# sourceMappingURL=use-in-iframe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/use-in-iframe.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { useEffect, useState } from \"react\";\n\nexport function useInIframe() {\n const [isIframe, setIsIframe] = useState(false);\n useEffect(() => {\n if (window.self !== window.top) {\n setIsIframe(true);\n }\n }, []);\n\n return isIframe;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,mBAAoC;AAE7B,SAAS,cAAc;AAC5B,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAC9C,8BAAU,MAAM;AACd,QAAI,OAAO,SAAS,OAAO,KAAK;AAC9B,kBAAY,IAAI;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;","names":[]}
@@ -29,9 +29,9 @@ var import_promises = require("@stackframe/stack-shared/dist/utils/promises");
29
29
  var import_stack_ui = require("@stackframe/stack-ui");
30
30
  var import_lucide_react = require("lucide-react");
31
31
  var import_react = require("react");
32
- var import__ = require("..");
33
- var import_translations = require("../lib/translations");
34
- var import_user_avatar = require("./elements/user-avatar");
32
+ var import__ = require("../index.js");
33
+ var import_translations = require("../lib/translations.js");
34
+ var import_user_avatar = require("./elements/user-avatar.js");
35
35
  var import_jsx_runtime = require("react/jsx-runtime");
36
36
  function Item(props) {
37
37
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DropdownMenuItem, { onClick: () => (0, import_promises.runAsynchronouslyWithAlert)(props.onClick), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2 items-center", children: [
@@ -43,7 +43,16 @@ function UserButton(props) {
43
43
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-[34px] w-[34px] rounded-full stack-scope" }), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UserButtonInner, { ...props }) });
44
44
  }
45
45
  function UserButtonInner(props) {
46
- const user = (0, import__.useUser)();
46
+ const userFromHook = (0, import__.useUser)();
47
+ const user = props.mockUser ? {
48
+ displayName: props.mockUser.displayName || "Mock User",
49
+ primaryEmail: props.mockUser.primaryEmail || "mock@example.com",
50
+ profileImageUrl: props.mockUser.profileImageUrl,
51
+ signOut: () => {
52
+ console.log("Mock sign out - no action taken in demo mode");
53
+ return Promise.resolve();
54
+ }
55
+ } : userFromHook;
47
56
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UserButtonInnerInner, { ...props, user });
48
57
  }
49
58
  function UserButtonInnerInner(props) {
@@ -73,7 +82,13 @@ function UserButtonInnerInner(props) {
73
82
  Item,
74
83
  {
75
84
  text: t("Account settings"),
76
- onClick: async () => await app.redirectToAccountSettings(),
85
+ onClick: async () => {
86
+ if (props.mockUser) {
87
+ console.log("Mock account settings - no navigation in demo mode");
88
+ } else {
89
+ await app.redirectToAccountSettings();
90
+ }
91
+ },
77
92
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.CircleUser, { ...iconProps })
78
93
  }
79
94
  ),
@@ -81,7 +96,13 @@ function UserButtonInnerInner(props) {
81
96
  Item,
82
97
  {
83
98
  text: t("Sign in"),
84
- onClick: async () => await app.redirectToSignIn(),
99
+ onClick: async () => {
100
+ if (props.mockUser) {
101
+ console.log("Mock sign in - no navigation in demo mode");
102
+ } else {
103
+ await app.redirectToSignIn();
104
+ }
105
+ },
85
106
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.LogIn, { ...iconProps })
86
107
  }
87
108
  ),
@@ -89,7 +110,13 @@ function UserButtonInnerInner(props) {
89
110
  Item,
90
111
  {
91
112
  text: t("Sign up"),
92
- onClick: async () => await app.redirectToSignUp(),
113
+ onClick: async () => {
114
+ if (props.mockUser) {
115
+ console.log("Mock sign up - no navigation in demo mode");
116
+ } else {
117
+ await app.redirectToSignUp();
118
+ }
119
+ },
93
120
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.UserPlus, { ...iconProps })
94
121
  }
95
122
  ),
@@ -106,7 +133,13 @@ function UserButtonInnerInner(props) {
106
133
  Item,
107
134
  {
108
135
  text: t("Sign out"),
109
- onClick: () => user.signOut(),
136
+ onClick: async () => {
137
+ if (props.mockUser) {
138
+ console.log("Mock sign out - no action taken in demo mode");
139
+ } else {
140
+ await user.signOut();
141
+ }
142
+ },
110
143
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.LogOut, { ...iconProps })
111
144
  }
112
145
  )
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/user-button.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Skeleton, Typography } from \"@stackframe/stack-ui\";\nimport { CircleUser, LogIn, LogOut, SunMoon, UserPlus } from \"lucide-react\";\nimport React, { Suspense } from \"react\";\nimport { CurrentUser, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { UserAvatar } from \"./elements/user-avatar\";\n\nfunction Item(props: { text: string, icon: React.ReactNode, onClick: () => void | Promise<void> }) {\n return (\n <DropdownMenuItem onClick={() => runAsynchronouslyWithAlert(props.onClick)}>\n <div className=\"flex gap-2 items-center\">\n {props.icon}\n <Typography>{props.text}</Typography>\n </div>\n </DropdownMenuItem>\n );\n}\n\ntype UserButtonProps = {\n showUserInfo?: boolean,\n colorModeToggle?: () => void | Promise<void>,\n extraItems?: {\n text: string,\n icon: React.ReactNode,\n onClick: () => void | Promise<void>,\n }[],\n};\n\nexport function UserButton(props: UserButtonProps) {\n return (\n <Suspense fallback={<Skeleton className=\"h-[34px] w-[34px] rounded-full stack-scope\" />}>\n <UserButtonInner {...props} />\n </Suspense>\n );\n}\n\nfunction UserButtonInner(props: UserButtonProps) {\n const user = useUser();\n return <UserButtonInnerInner {...props} user={user} />;\n}\n\n\nfunction UserButtonInnerInner(props: UserButtonProps & { user: CurrentUser | null }) {\n const { t } = useTranslation();\n const user = props.user;\n const app = useStackApp();\n\n const iconProps = { size: 20, className: 'h-4 w-4' };\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger className=\"outline-none stack-scope\">\n <div className=\"flex gap-2 items-center\">\n <UserAvatar user={user} />\n {user && props.showUserInfo &&\n <div className=\"flex flex-col justify-center text-left\">\n <Typography className=\"max-w-40 truncate\">{user.displayName}</Typography>\n <Typography className=\"max-w-40 truncate\" variant=\"secondary\" type='label'>{user.primaryEmail}</Typography>\n </div>\n }\n </div>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"stack-scope\">\n <DropdownMenuLabel>\n <div className=\"flex gap-2 items-center\">\n <UserAvatar user={user} />\n <div>\n {user && <Typography className=\"max-w-40 truncate\">{user.displayName}</Typography>}\n {user && <Typography className=\"max-w-40 truncate\" variant=\"secondary\" type='label'>{user.primaryEmail}</Typography>}\n {!user && <Typography>{t('Not signed in')}</Typography>}\n </div>\n </div>\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n {user && <Item\n text={t('Account settings')}\n onClick={async () => await app.redirectToAccountSettings()}\n icon={<CircleUser {...iconProps} />}\n />}\n {!user && <Item\n text={t('Sign in')}\n onClick={async () => await app.redirectToSignIn()}\n icon={<LogIn {...iconProps} />}\n />}\n {!user && <Item\n text={t('Sign up')}\n onClick={async () => await app.redirectToSignUp()}\n icon={<UserPlus {...iconProps}/> }\n />}\n {user && props.extraItems && props.extraItems.map((item, index) => (\n <Item key={index} {...item} />\n ))}\n {props.colorModeToggle && (\n <Item\n text={t('Toggle theme')}\n onClick={props.colorModeToggle}\n icon={<SunMoon {...iconProps} />}\n />\n )}\n {user && <Item\n text={t('Sign out')}\n onClick={() => user.signOut()}\n icon={<LogOut {...iconProps} />}\n />}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/user-button.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Skeleton, Typography } from \"@stackframe/stack-ui\";\nimport { CircleUser, LogIn, LogOut, SunMoon, UserPlus } from \"lucide-react\";\nimport React, { Suspense } from \"react\";\nimport { CurrentUser, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { UserAvatar } from \"./elements/user-avatar\";\n\nfunction Item(props: { text: string, icon: React.ReactNode, onClick: () => void | Promise<void> }) {\n return (\n <DropdownMenuItem onClick={() => runAsynchronouslyWithAlert(props.onClick)}>\n <div className=\"flex gap-2 items-center\">\n {props.icon}\n <Typography>{props.text}</Typography>\n </div>\n </DropdownMenuItem>\n );\n}\n\ntype UserButtonProps = {\n showUserInfo?: boolean,\n colorModeToggle?: () => void | Promise<void>,\n extraItems?: {\n text: string,\n icon: React.ReactNode,\n onClick: () => void | Promise<void>,\n }[],\n mockUser?: {\n displayName?: string,\n primaryEmail?: string,\n profileImageUrl?: string,\n },\n};\n\nexport function UserButton(props: UserButtonProps) {\n return (\n <Suspense fallback={<Skeleton className=\"h-[34px] w-[34px] rounded-full stack-scope\" />}>\n <UserButtonInner {...props} />\n </Suspense>\n );\n}\n\nfunction UserButtonInner(props: UserButtonProps) {\n const userFromHook = useUser();\n\n // Use mock user if provided, otherwise use real user\n const user = props.mockUser ? {\n displayName: props.mockUser.displayName || 'Mock User',\n primaryEmail: props.mockUser.primaryEmail || 'mock@example.com',\n profileImageUrl: props.mockUser.profileImageUrl,\n signOut: () => {\n console.log('Mock sign out - no action taken in demo mode');\n return Promise.resolve();\n }\n } as CurrentUser : userFromHook;\n\n return <UserButtonInnerInner {...props} user={user} />;\n}\n\n\nfunction UserButtonInnerInner(props: UserButtonProps & { user: CurrentUser | null }) {\n const { t } = useTranslation();\n const user = props.user;\n const app = useStackApp();\n\n const iconProps = { size: 20, className: 'h-4 w-4' };\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger className=\"outline-none stack-scope\">\n <div className=\"flex gap-2 items-center\">\n <UserAvatar user={user} />\n {user && props.showUserInfo &&\n <div className=\"flex flex-col justify-center text-left\">\n <Typography className=\"max-w-40 truncate\">{user.displayName}</Typography>\n <Typography className=\"max-w-40 truncate\" variant=\"secondary\" type='label'>{user.primaryEmail}</Typography>\n </div>\n }\n </div>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"stack-scope\">\n <DropdownMenuLabel>\n <div className=\"flex gap-2 items-center\">\n <UserAvatar user={user} />\n <div>\n {user && <Typography className=\"max-w-40 truncate\">{user.displayName}</Typography>}\n {user && <Typography className=\"max-w-40 truncate\" variant=\"secondary\" type='label'>{user.primaryEmail}</Typography>}\n {!user && <Typography>{t('Not signed in')}</Typography>}\n </div>\n </div>\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n {user && <Item\n text={t('Account settings')}\n onClick={async () => {\n if (props.mockUser) {\n console.log('Mock account settings - no navigation in demo mode');\n } else {\n await app.redirectToAccountSettings();\n }\n }}\n icon={<CircleUser {...iconProps} />}\n />}\n {!user && <Item\n text={t('Sign in')}\n onClick={async () => {\n if (props.mockUser) {\n console.log('Mock sign in - no navigation in demo mode');\n } else {\n await app.redirectToSignIn();\n }\n }}\n icon={<LogIn {...iconProps} />}\n />}\n {!user && <Item\n text={t('Sign up')}\n onClick={async () => {\n if (props.mockUser) {\n console.log('Mock sign up - no navigation in demo mode');\n } else {\n await app.redirectToSignUp();\n }\n }}\n icon={<UserPlus {...iconProps}/> }\n />}\n {user && props.extraItems && props.extraItems.map((item, index) => (\n <Item key={index} {...item} />\n ))}\n {props.colorModeToggle && (\n <Item\n text={t('Toggle theme')}\n onClick={props.colorModeToggle}\n icon={<SunMoon {...iconProps} />}\n />\n )}\n {user && <Item\n text={t('Sign out')}\n onClick={async () => {\n if (props.mockUser) {\n console.log('Mock sign out - no action taken in demo mode');\n } else {\n await user.signOut();\n }\n }}\n icon={<LogOut {...iconProps} />}\n />}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":"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","names":[]}
@@ -28,29 +28,70 @@ var import_errors = require("@stackframe/stack-shared/dist/utils/errors");
28
28
  var import_promises = require("@stackframe/stack-shared/dist/utils/promises");
29
29
  var import_stack_ui = require("@stackframe/stack-ui");
30
30
  var import_react = require("react");
31
- var import_hooks = require("../../../lib/hooks");
32
- var import_translations = require("../../../lib/translations");
33
- var import_page_layout = require("../page-layout");
31
+ var import_hooks = require("../../../lib/hooks.js");
32
+ var import_translations = require("../../../lib/translations.js");
33
+ var import_page_layout = require("../page-layout.js");
34
34
  var import_jsx_runtime = require("react/jsx-runtime");
35
- function ActiveSessionsPage() {
35
+ function ActiveSessionsPage(props) {
36
36
  const { t } = (0, import_translations.useTranslation)();
37
- const user = (0, import_hooks.useUser)({ or: "throw" });
38
- const [isLoading, setIsLoading] = (0, import_react.useState)(true);
37
+ const userFromHook = (0, import_hooks.useUser)({ or: props?.mockSessions || props?.mockMode ? "return-null" : "throw" });
38
+ const [isLoading, setIsLoading] = (0, import_react.useState)(!props?.mockSessions);
39
39
  const [isRevokingAll, setIsRevokingAll] = (0, import_react.useState)(false);
40
40
  const [sessions, setSessions] = (0, import_react.useState)([]);
41
41
  const [showConfirmRevokeAll, setShowConfirmRevokeAll] = (0, import_react.useState)(false);
42
+ const mockSessionsData = props?.mockSessions ? props.mockSessions.map((session) => ({
43
+ id: session.id,
44
+ isCurrentSession: session.isCurrentSession,
45
+ isImpersonation: session.isImpersonation || false,
46
+ createdAt: session.createdAt,
47
+ lastUsedAt: session.lastUsedAt,
48
+ geoInfo: session.geoInfo
49
+ })) : [
50
+ {
51
+ id: "current-session",
52
+ isCurrentSession: true,
53
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
54
+ lastUsedAt: (/* @__PURE__ */ new Date()).toISOString(),
55
+ geoInfo: { ip: "192.168.1.1", cityName: "San Francisco" }
56
+ },
57
+ {
58
+ id: "mobile-session",
59
+ isCurrentSession: false,
60
+ createdAt: new Date(Date.now() - 864e5).toISOString(),
61
+ // 1 day ago
62
+ lastUsedAt: new Date(Date.now() - 72e5).toISOString(),
63
+ // 2 hours ago
64
+ geoInfo: { ip: "10.0.0.1", cityName: "New York" }
65
+ }
66
+ ];
42
67
  (0, import_react.useEffect)(() => {
68
+ if (props?.mockSessions) {
69
+ setSessions(mockSessionsData);
70
+ setIsLoading(false);
71
+ return;
72
+ }
73
+ if (props?.mockMode && !userFromHook) {
74
+ setSessions(mockSessionsData);
75
+ setIsLoading(false);
76
+ return;
77
+ }
78
+ if (!userFromHook) return;
43
79
  (0, import_promises.runAsynchronously)(async () => {
44
80
  setIsLoading(true);
45
- const sessionsData = await user.getActiveSessions();
81
+ const sessionsData = await userFromHook.getActiveSessions();
46
82
  const enhancedSessions = sessionsData;
47
83
  setSessions(enhancedSessions);
48
84
  setIsLoading(false);
49
85
  });
50
- }, [user]);
86
+ }, [userFromHook, props?.mockSessions]);
51
87
  const handleRevokeSession = async (sessionId) => {
88
+ if (props?.mockSessions) {
89
+ setSessions((prev) => prev.filter((session) => session.id !== sessionId));
90
+ return;
91
+ }
92
+ if (!userFromHook) return;
52
93
  try {
53
- await user.revokeSession(sessionId);
94
+ await userFromHook.revokeSession(sessionId);
54
95
  setSessions((prev) => prev.filter((session) => session.id !== sessionId));
55
96
  } catch (error) {
56
97
  (0, import_errors.captureError)("Failed to revoke session", { sessionId, error });
@@ -60,9 +101,13 @@ function ActiveSessionsPage() {
60
101
  const handleRevokeAllSessions = async () => {
61
102
  setIsRevokingAll(true);
62
103
  try {
63
- const deletionPromises = sessions.filter((session) => !session.isCurrentSession).map((session) => user.revokeSession(session.id));
64
- await Promise.all(deletionPromises);
65
- setSessions((prevSessions) => prevSessions.filter((session) => session.isCurrentSession));
104
+ if (props?.mockSessions) {
105
+ setSessions((prevSessions) => prevSessions.filter((session) => session.isCurrentSession));
106
+ } else if (userFromHook) {
107
+ const deletionPromises = sessions.filter((session) => !session.isCurrentSession).map((session) => userFromHook.revokeSession(session.id));
108
+ await Promise.all(deletionPromises);
109
+ setSessions((prevSessions) => prevSessions.filter((session) => session.isCurrentSession));
110
+ }
66
111
  } catch (error) {
67
112
  (0, import_errors.captureError)("Failed to revoke all sessions", { error, sessionIds: sessions.map((session) => session.id) });
68
113
  throw error;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components-page/account-settings/active-sessions/active-sessions-page.tsx"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { fromNow } from \"@stackframe/stack-shared/dist/utils/dates\";\nimport { captureError } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { runAsynchronously } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { ActionCell, Badge, Button, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from \"@stackframe/stack-ui\";\nimport { useEffect, useState } from \"react\";\nimport { useUser } from \"../../../lib/hooks\";\nimport { ActiveSession } from \"../../../lib/stack-app/users\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { PageLayout } from \"../page-layout\";\n\nexport function ActiveSessionsPage() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n const [isLoading, setIsLoading] = useState(true);\n const [isRevokingAll, setIsRevokingAll] = useState(false);\n const [sessions, setSessions] = useState<ActiveSession[]>([]);\n const [showConfirmRevokeAll, setShowConfirmRevokeAll] = useState(false);\n\n // Fetch sessions when component mounts\n useEffect(() => {\n runAsynchronously(async () => {\n setIsLoading(true);\n const sessionsData = await user.getActiveSessions();\n const enhancedSessions = sessionsData;\n setSessions(enhancedSessions);\n setIsLoading(false);\n });\n }, [user]);\n\n const handleRevokeSession = async (sessionId: string) => {\n try {\n await user.revokeSession(sessionId);\n\n // Remove the session from the list\n setSessions(prev => prev.filter(session => session.id !== sessionId));\n } catch (error) {\n captureError(\"Failed to revoke session\", { sessionId ,error });\n throw error;\n }\n };\n\n const handleRevokeAllSessions = async () => {\n setIsRevokingAll(true);\n try {\n const deletionPromises = sessions\n .filter(session => !session.isCurrentSession)\n .map(session => user.revokeSession(session.id));\n await Promise.all(deletionPromises);\n setSessions(prevSessions => prevSessions.filter(session => session.isCurrentSession));\n } catch (error) {\n captureError(\"Failed to revoke all sessions\", { error, sessionIds: sessions.map(session => session.id) });\n throw error;\n } finally {\n setIsRevokingAll(false);\n setShowConfirmRevokeAll(false);\n }\n };\n\n return (\n <PageLayout>\n <div>\n <div className=\"flex justify-between items-center mb-2\">\n <Typography className='font-medium'>{t(\"Active Sessions\")}</Typography>\n {sessions.filter(s => !s.isCurrentSession).length > 0 && !isLoading && (\n showConfirmRevokeAll ? (\n <div className=\"flex gap-2\">\n <Button\n variant=\"destructive\"\n size=\"sm\"\n loading={isRevokingAll}\n onClick={handleRevokeAllSessions}\n >\n {t(\"Confirm\")}\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n disabled={isRevokingAll}\n onClick={() => setShowConfirmRevokeAll(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n ) : (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setShowConfirmRevokeAll(true)}\n >\n {t(\"Revoke All Other Sessions\")}\n </Button>\n )\n )}\n </div>\n <Typography variant='secondary' type='footnote' className=\"mb-4\">\n {t(\"These are devices where you're currently logged in. You can revoke access to end a session.\")}\n </Typography>\n\n {isLoading ? (\n <Skeleton className=\"h-[300px] w-full rounded-md\" />\n ) : (\n <div className='border rounded-md'>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[200px]\">{t(\"Session\")}</TableHead>\n <TableHead className=\"w-[150px]\">{t(\"IP Address\")}</TableHead>\n <TableHead className=\"w-[150px]\">{t(\"Location\")}</TableHead>\n <TableHead className=\"w-[150px]\">{t(\"Last used\")}</TableHead>\n <TableHead className=\"w-[80px]\"></TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {sessions.length === 0 ? (\n <TableRow>\n <TableCell colSpan={5} className=\"text-center py-6\">\n <Typography variant=\"secondary\">{t(\"No active sessions found\")}</Typography>\n </TableCell>\n </TableRow>\n ) : (\n sessions.map((session) => (\n <TableRow key={session.id}>\n <TableCell>\n <div className=\"flex flex-col\">\n {/* We currently do not save any usefull information about the user, in the future, the name should probably say what kind of session it is (e.g. cli, browser, maybe what auth method was used) */}\n <Typography>{session.isCurrentSession ? t(\"Current Session\") : t(\"Other Session\")}</Typography>\n {session.isImpersonation && <Badge variant=\"secondary\" className=\"w-fit mt-1\">{t(\"Impersonation\")}</Badge>}\n <Typography variant='secondary' type='footnote'>\n {t(\"Signed in {time}\", { time: new Date(session.createdAt).toLocaleDateString() })}\n </Typography>\n </div>\n </TableCell>\n <TableCell>\n <Typography>{session.geoInfo?.ip || t('-')}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{session.geoInfo?.cityName || t('Unknown')}</Typography>\n </TableCell>\n <TableCell>\n <div className=\"flex flex-col\">\n <Typography>{session.lastUsedAt ? fromNow(new Date(session.lastUsedAt)) : t(\"Never\")}</Typography>\n <Typography variant='secondary' type='footnote' title={session.lastUsedAt ? new Date(session.lastUsedAt).toLocaleString() : \"\"}>\n {session.lastUsedAt ? new Date(session.lastUsedAt).toLocaleDateString() : \"\"}\n </Typography>\n </div>\n </TableCell>\n <TableCell align=\"right\">\n <ActionCell\n items={[\n {\n item: t(\"Revoke\"),\n onClick: () => handleRevokeSession(session.id),\n danger: true,\n disabled: session.isCurrentSession,\n disabledTooltip: session.isCurrentSession ? t(\"You cannot revoke your current session\") : undefined,\n },\n ]}\n />\n </TableCell>\n </TableRow>\n ))\n )}\n </TableBody>\n </Table>\n </div>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/components-page/account-settings/active-sessions/active-sessions-page.tsx"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { fromNow } from \"@stackframe/stack-shared/dist/utils/dates\";\nimport { captureError } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { runAsynchronously } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { ActionCell, Badge, Button, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from \"@stackframe/stack-ui\";\nimport { useEffect, useState } from \"react\";\nimport { useUser } from \"../../../lib/hooks\";\nimport { ActiveSession } from \"../../../lib/stack-app/users\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { PageLayout } from \"../page-layout\";\n\nexport function ActiveSessionsPage(props?: {\n mockSessions?: Array<{\n id: string,\n isCurrentSession: boolean,\n isImpersonation?: boolean,\n createdAt: string,\n lastUsedAt?: string,\n geoInfo?: {\n ip?: string,\n cityName?: string,\n },\n }>,\n mockMode?: boolean,\n}) {\n const { t } = useTranslation();\n const userFromHook = useUser({ or: (props?.mockSessions || props?.mockMode) ? 'return-null' : 'throw' });\n const [isLoading, setIsLoading] = useState(!props?.mockSessions);\n const [isRevokingAll, setIsRevokingAll] = useState(false);\n const [sessions, setSessions] = useState<ActiveSession[]>([]);\n const [showConfirmRevokeAll, setShowConfirmRevokeAll] = useState(false);\n\n // Use mock data if provided\n const mockSessionsData = props?.mockSessions ? props.mockSessions.map(session => ({\n id: session.id,\n isCurrentSession: session.isCurrentSession,\n isImpersonation: session.isImpersonation || false,\n createdAt: session.createdAt,\n lastUsedAt: session.lastUsedAt,\n geoInfo: session.geoInfo,\n })) : [\n {\n id: 'current-session',\n isCurrentSession: true,\n createdAt: new Date().toISOString(),\n lastUsedAt: new Date().toISOString(),\n geoInfo: { ip: '192.168.1.1', cityName: 'San Francisco' }\n },\n {\n id: 'mobile-session',\n isCurrentSession: false,\n createdAt: new Date(Date.now() - 86400000).toISOString(), // 1 day ago\n lastUsedAt: new Date(Date.now() - 7200000).toISOString(), // 2 hours ago\n geoInfo: { ip: '10.0.0.1', cityName: 'New York' }\n }\n ];\n\n // Fetch sessions when component mounts (only if not using mock data)\n useEffect(() => {\n if (props?.mockSessions) {\n setSessions(mockSessionsData as any);\n setIsLoading(false);\n return;\n }\n\n // If in mock mode but no mock sessions provided, use default mock data\n if (props?.mockMode && !userFromHook) {\n setSessions(mockSessionsData as any);\n setIsLoading(false);\n return;\n }\n\n if (!userFromHook) return;\n\n runAsynchronously(async () => {\n setIsLoading(true);\n const sessionsData = await userFromHook.getActiveSessions();\n const enhancedSessions = sessionsData;\n setSessions(enhancedSessions);\n setIsLoading(false);\n });\n }, [userFromHook, props?.mockSessions]);\n\n const handleRevokeSession = async (sessionId: string) => {\n if (props?.mockSessions) {\n // Mock revoke - just remove from list\n setSessions(prev => prev.filter(session => session.id !== sessionId));\n return;\n }\n\n if (!userFromHook) return;\n\n try {\n await userFromHook.revokeSession(sessionId);\n setSessions(prev => prev.filter(session => session.id !== sessionId));\n } catch (error) {\n captureError(\"Failed to revoke session\", { sessionId ,error });\n throw error;\n }\n };\n\n const handleRevokeAllSessions = async () => {\n setIsRevokingAll(true);\n try {\n if (props?.mockSessions) {\n // Mock revoke all - just keep current session\n setSessions(prevSessions => prevSessions.filter(session => session.isCurrentSession));\n } else if (userFromHook) {\n const deletionPromises = sessions\n .filter(session => !session.isCurrentSession)\n .map(session => userFromHook.revokeSession(session.id));\n await Promise.all(deletionPromises);\n setSessions(prevSessions => prevSessions.filter(session => session.isCurrentSession));\n }\n } catch (error) {\n captureError(\"Failed to revoke all sessions\", { error, sessionIds: sessions.map(session => session.id) });\n throw error;\n } finally {\n setIsRevokingAll(false);\n setShowConfirmRevokeAll(false);\n }\n };\n\n return (\n <PageLayout>\n <div>\n <div className=\"flex justify-between items-center mb-2\">\n <Typography className='font-medium'>{t(\"Active Sessions\")}</Typography>\n {sessions.filter(s => !s.isCurrentSession).length > 0 && !isLoading && (\n showConfirmRevokeAll ? (\n <div className=\"flex gap-2\">\n <Button\n variant=\"destructive\"\n size=\"sm\"\n loading={isRevokingAll}\n onClick={handleRevokeAllSessions}\n >\n {t(\"Confirm\")}\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n disabled={isRevokingAll}\n onClick={() => setShowConfirmRevokeAll(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n ) : (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setShowConfirmRevokeAll(true)}\n >\n {t(\"Revoke All Other Sessions\")}\n </Button>\n )\n )}\n </div>\n <Typography variant='secondary' type='footnote' className=\"mb-4\">\n {t(\"These are devices where you're currently logged in. You can revoke access to end a session.\")}\n </Typography>\n\n {isLoading ? (\n <Skeleton className=\"h-[300px] w-full rounded-md\" />\n ) : (\n <div className='border rounded-md'>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[200px]\">{t(\"Session\")}</TableHead>\n <TableHead className=\"w-[150px]\">{t(\"IP Address\")}</TableHead>\n <TableHead className=\"w-[150px]\">{t(\"Location\")}</TableHead>\n <TableHead className=\"w-[150px]\">{t(\"Last used\")}</TableHead>\n <TableHead className=\"w-[80px]\"></TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {sessions.length === 0 ? (\n <TableRow>\n <TableCell colSpan={5} className=\"text-center py-6\">\n <Typography variant=\"secondary\">{t(\"No active sessions found\")}</Typography>\n </TableCell>\n </TableRow>\n ) : (\n sessions.map((session) => (\n <TableRow key={session.id}>\n <TableCell>\n <div className=\"flex flex-col\">\n {/* We currently do not save any usefull information about the user, in the future, the name should probably say what kind of session it is (e.g. cli, browser, maybe what auth method was used) */}\n <Typography>{session.isCurrentSession ? t(\"Current Session\") : t(\"Other Session\")}</Typography>\n {session.isImpersonation && <Badge variant=\"secondary\" className=\"w-fit mt-1\">{t(\"Impersonation\")}</Badge>}\n <Typography variant='secondary' type='footnote'>\n {t(\"Signed in {time}\", { time: new Date(session.createdAt).toLocaleDateString() })}\n </Typography>\n </div>\n </TableCell>\n <TableCell>\n <Typography>{session.geoInfo?.ip || t('-')}</Typography>\n </TableCell>\n <TableCell>\n <Typography>{session.geoInfo?.cityName || t('Unknown')}</Typography>\n </TableCell>\n <TableCell>\n <div className=\"flex flex-col\">\n <Typography>{session.lastUsedAt ? fromNow(new Date(session.lastUsedAt)) : t(\"Never\")}</Typography>\n <Typography variant='secondary' type='footnote' title={session.lastUsedAt ? new Date(session.lastUsedAt).toLocaleString() : \"\"}>\n {session.lastUsedAt ? new Date(session.lastUsedAt).toLocaleDateString() : \"\"}\n </Typography>\n </div>\n </TableCell>\n <TableCell align=\"right\">\n <ActionCell\n items={[\n {\n item: t(\"Revoke\"),\n onClick: () => handleRevokeSession(session.id),\n danger: true,\n disabled: session.isCurrentSession,\n disabledTooltip: session.isCurrentSession ? t(\"You cannot revoke your current session\") : undefined,\n },\n ]}\n />\n </TableCell>\n </TableRow>\n ))\n )}\n </TableBody>\n </Table>\n </div>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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","names":[]}
@@ -25,20 +25,110 @@ __export(api_keys_page_exports, {
25
25
  module.exports = __toCommonJS(api_keys_page_exports);
26
26
  var import_stack_ui = require("@stackframe/stack-ui");
27
27
  var import_react = require("react");
28
- var import_api_key_dialogs = require("../../../components/api-key-dialogs");
29
- var import_api_key_table = require("../../../components/api-key-table");
30
- var import_hooks = require("../../../lib/hooks");
31
- var import_translations = require("../../../lib/translations");
32
- var import_page_layout = require("../page-layout");
28
+ var import_api_key_dialogs = require("../../../components/api-key-dialogs.js");
29
+ var import_api_key_table = require("../../../components/api-key-table.js");
30
+ var import_hooks = require("../../../lib/hooks.js");
31
+ var import_translations = require("../../../lib/translations.js");
32
+ var import_page_layout = require("../page-layout.js");
33
33
  var import_jsx_runtime = require("react/jsx-runtime");
34
- function ApiKeysPage() {
34
+ function ApiKeysPage(props) {
35
35
  const { t } = (0, import_translations.useTranslation)();
36
- const user = (0, import_hooks.useUser)({ or: "redirect" });
37
- const apiKeys = user.useApiKeys();
36
+ const isInMockMode = !!(props?.mockApiKeys || props?.mockMode);
37
+ const userFromHook = (0, import_hooks.useUser)({ or: isInMockMode ? "return-null" : "redirect" });
38
+ if (isInMockMode && !userFromHook) {
39
+ }
40
+ if (!isInMockMode && !userFromHook) {
41
+ return null;
42
+ }
43
+ const mockApiKeysData = props?.mockApiKeys ? props.mockApiKeys.map((mockKey) => ({
44
+ id: mockKey.id,
45
+ description: mockKey.description,
46
+ createdAt: new Date(mockKey.createdAt),
47
+ expiresAt: mockKey.expiresAt ? new Date(mockKey.expiresAt) : void 0,
48
+ manuallyRevokedAt: mockKey.manuallyRevokedAt ? new Date(mockKey.manuallyRevokedAt) : null,
49
+ value: {
50
+ lastFour: mockKey.id.slice(-4).padStart(4, "0")
51
+ // Use last 4 chars of ID or pad with zeros
52
+ },
53
+ type: "user",
54
+ userId: "mock-user-id",
55
+ update: async () => {
56
+ console.log("Mock API key update called");
57
+ },
58
+ revoke: async () => {
59
+ console.log("Mock API key revoke called");
60
+ },
61
+ isValid: () => {
62
+ const now = /* @__PURE__ */ new Date();
63
+ const isExpired = mockKey.expiresAt ? new Date(mockKey.expiresAt) < now : false;
64
+ const isRevoked = !!mockKey.manuallyRevokedAt;
65
+ return !isExpired && !isRevoked;
66
+ },
67
+ whyInvalid: () => {
68
+ const now = /* @__PURE__ */ new Date();
69
+ if (mockKey.manuallyRevokedAt) return "manually-revoked";
70
+ if (mockKey.expiresAt && new Date(mockKey.expiresAt) < now) return "expired";
71
+ return null;
72
+ }
73
+ })) : [
74
+ {
75
+ id: "key-1",
76
+ description: "Development Key",
77
+ createdAt: new Date(Date.now() - 1728e5),
78
+ // 2 days ago
79
+ expiresAt: void 0,
80
+ manuallyRevokedAt: null,
81
+ value: {
82
+ lastFour: "ey-1".slice(-4).padStart(4, "0")
83
+ },
84
+ type: "user",
85
+ userId: "mock-user-id",
86
+ update: async () => {
87
+ console.log("Mock API key update called");
88
+ },
89
+ revoke: async () => {
90
+ console.log("Mock API key revoke called");
91
+ },
92
+ isValid: () => true,
93
+ whyInvalid: () => null
94
+ }
95
+ ];
96
+ let apiKeys;
97
+ if (isInMockMode) {
98
+ apiKeys = mockApiKeysData;
99
+ } else if (userFromHook) {
100
+ apiKeys = userFromHook.useApiKeys();
101
+ } else {
102
+ apiKeys = [];
103
+ }
38
104
  const [isNewApiKeyDialogOpen, setIsNewApiKeyDialogOpen] = (0, import_react.useState)(false);
39
105
  const [returnedApiKey, setReturnedApiKey] = (0, import_react.useState)(null);
40
106
  const CreateDialog = import_api_key_dialogs.CreateApiKeyDialog;
41
107
  const ShowDialog = import_api_key_dialogs.ShowApiKeyDialog;
108
+ const handleCreateApiKey = async (data) => {
109
+ if (isInMockMode) {
110
+ const mockApiKey = {
111
+ id: `key-${Date.now()}`,
112
+ description: data.description,
113
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
114
+ expiresAt: data.expiresAt?.toISOString(),
115
+ value: "sk_dev_mock_key_" + Math.random().toString(36).substring(2),
116
+ update: async () => {
117
+ console.log("Mock API key update called");
118
+ },
119
+ revoke: async () => {
120
+ console.log("Mock API key revoke called");
121
+ },
122
+ isValid: () => true,
123
+ whyInvalid: () => null,
124
+ type: "user",
125
+ userId: "mock-user-id"
126
+ };
127
+ return mockApiKey;
128
+ }
129
+ if (!userFromHook) throw new Error("User not available");
130
+ return await userFromHook.createApiKey(data);
131
+ };
42
132
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_page_layout.PageLayout, { children: [
43
133
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: () => setIsNewApiKeyDialogOpen(true), children: t("Create API Key") }),
44
134
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_api_key_table.ApiKeyTable, { apiKeys }),
@@ -48,10 +138,8 @@ function ApiKeysPage() {
48
138
  open: isNewApiKeyDialogOpen,
49
139
  onOpenChange: setIsNewApiKeyDialogOpen,
50
140
  onKeyCreated: setReturnedApiKey,
51
- createApiKey: async (data) => {
52
- const apiKey = await user.createApiKey(data);
53
- return apiKey;
54
- }
141
+ createApiKey: handleCreateApiKey,
142
+ mockMode: isInMockMode
55
143
  }
56
144
  ),
57
145
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(