@stackframe/stack 2.7.26 → 2.7.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/link.js.map +1 -1
  3. package/dist/components/oauth-button-group.js +9 -1
  4. package/dist/components/oauth-button-group.js.map +1 -1
  5. package/dist/components/oauth-button.js +3 -2
  6. package/dist/components/oauth-button.js.map +1 -1
  7. package/dist/components-page/account-settings.js +131 -0
  8. package/dist/components-page/account-settings.js.map +1 -1
  9. package/dist/components-page/cli-auth-confirm.js +123 -0
  10. package/dist/components-page/cli-auth-confirm.js.map +1 -0
  11. package/dist/components-page/forgot-password.js +1 -1
  12. package/dist/components-page/forgot-password.js.map +1 -1
  13. package/dist/components-page/stack-handler.js +11 -0
  14. package/dist/components-page/stack-handler.js.map +1 -1
  15. package/dist/esm/components/link.js.map +1 -1
  16. package/dist/esm/components/oauth-button-group.js +9 -1
  17. package/dist/esm/components/oauth-button-group.js.map +1 -1
  18. package/dist/esm/components/oauth-button.js +3 -2
  19. package/dist/esm/components/oauth-button.js.map +1 -1
  20. package/dist/esm/components-page/account-settings.js +132 -1
  21. package/dist/esm/components-page/account-settings.js.map +1 -1
  22. package/dist/esm/components-page/cli-auth-confirm.js +99 -0
  23. package/dist/esm/components-page/cli-auth-confirm.js.map +1 -0
  24. package/dist/esm/components-page/forgot-password.js +1 -1
  25. package/dist/esm/components-page/forgot-password.js.map +1 -1
  26. package/dist/esm/components-page/stack-handler.js +11 -0
  27. package/dist/esm/components-page/stack-handler.js.map +1 -1
  28. package/dist/esm/generated/global-css.js +1 -1
  29. package/dist/esm/generated/global-css.js.map +1 -1
  30. package/dist/esm/lib/cookie.js.map +1 -1
  31. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js +14 -1
  32. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  33. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +23 -2
  34. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  35. package/dist/esm/lib/stack-app/apps/implementations/common.js +5 -1
  36. package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
  37. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +26 -5
  38. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  39. package/dist/esm/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
  40. package/dist/esm/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
  41. package/dist/esm/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
  42. package/dist/esm/lib/stack-app/common.js.map +1 -1
  43. package/dist/esm/lib/stack-app/contact-channels/index.js +5 -2
  44. package/dist/esm/lib/stack-app/contact-channels/index.js.map +1 -1
  45. package/dist/esm/lib/stack-app/email/index.js +1 -0
  46. package/dist/esm/lib/stack-app/email/index.js.map +1 -0
  47. package/dist/esm/lib/stack-app/index.js.map +1 -1
  48. package/dist/esm/lib/stack-app/teams/index.js.map +1 -1
  49. package/dist/esm/lib/stack-app/users/index.js.map +1 -1
  50. package/dist/esm/lib/translations.js.map +1 -1
  51. package/dist/generated/global-css.js +1 -1
  52. package/dist/generated/global-css.js.map +1 -1
  53. package/dist/index.d.mts +34 -2
  54. package/dist/index.d.ts +34 -2
  55. package/dist/lib/cookie.js.map +1 -1
  56. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js +14 -1
  57. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  58. package/dist/lib/stack-app/apps/implementations/client-app-impl.js +22 -1
  59. package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  60. package/dist/lib/stack-app/apps/implementations/common.js +6 -1
  61. package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
  62. package/dist/lib/stack-app/apps/implementations/server-app-impl.js +26 -5
  63. package/dist/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  64. package/dist/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
  65. package/dist/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
  66. package/dist/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
  67. package/dist/lib/stack-app/common.js.map +1 -1
  68. package/dist/lib/stack-app/connected-accounts/index.js.map +1 -1
  69. package/dist/lib/stack-app/contact-channels/index.js +5 -2
  70. package/dist/lib/stack-app/contact-channels/index.js.map +1 -1
  71. package/dist/lib/stack-app/email/index.js +19 -0
  72. package/dist/lib/stack-app/email/index.js.map +1 -0
  73. package/dist/lib/stack-app/index.js.map +1 -1
  74. package/dist/lib/stack-app/teams/index.js.map +1 -1
  75. package/dist/lib/stack-app/users/index.js.map +1 -1
  76. package/dist/lib/translations.js.map +1 -1
  77. package/package.json +4 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @stackframe/stack
2
2
 
3
+ ## 2.7.28
4
+
5
+ ### Patch Changes
6
+
7
+ - Various changes
8
+ - Updated dependencies
9
+ - @stackframe/stack-shared@2.7.28
10
+ - @stackframe/stack-ui@2.7.28
11
+ - @stackframe/stack-sc@2.7.28
12
+
13
+ ## 2.7.27
14
+
15
+ ### Patch Changes
16
+
17
+ - Various changes
18
+ - Updated dependencies
19
+ - @stackframe/stack-shared@2.7.27
20
+ - @stackframe/stack-ui@2.7.27
21
+ - @stackframe/stack-sc@2.7.27
22
+
3
23
  ## 2.7.26
4
24
 
5
25
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/link.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { cn } from \"@stackframe/stack-ui\";\nimport NextLink from 'next/link';\n\ntype LinkProps = {\n href: string,\n children: React.ReactNode,\n className?: string,\n target?: string,\n onClick?: React.MouseEventHandler<HTMLAnchorElement>,\n prefetch?: boolean,\n};\n\nfunction Link(props: LinkProps) {\n return <NextLink\n href={props.href}\n target={props.target}\n className={props.className}\n prefetch={props.prefetch}\n onClick={props.onClick}\n >\n {props.children}\n </NextLink>;\n}\n\nfunction StyledLink(props: LinkProps) {\n return (\n <Link {...props} className={cn(\"underline font-medium\", props.className)}>\n {props.children}\n </Link>\n );\n}\n\nexport { Link, StyledLink };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,sBAAmB;AACnB,kBAAqB;AAYZ;AADT,SAAS,KAAK,OAAkB;AAC9B,SAAO;AAAA,IAAC,YAAAA;AAAA,IAAA;AAAA,MACN,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,UAAU,MAAM;AAAA,MAChB,SAAS,MAAM;AAAA,MAEd,gBAAM;AAAA;AAAA,EACT;AACF;AAEA,SAAS,WAAW,OAAkB;AACpC,SACE,4CAAC,QAAM,GAAG,OAAO,eAAW,oBAAG,yBAAyB,MAAM,SAAS,GACpE,gBAAM,UACT;AAEJ;","names":["NextLink"]}
1
+ {"version":3,"sources":["../../src/components/link.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { cn } from \"@stackframe/stack-ui\";\nimport NextLink from 'next/link'; // THIS_LINE_PLATFORM next\n\ntype LinkProps = {\n href: string,\n children: React.ReactNode,\n className?: string,\n target?: string,\n onClick?: React.MouseEventHandler<HTMLAnchorElement>,\n prefetch?: boolean,\n};\n\nfunction Link(props: LinkProps) {\n return <NextLink\n href={props.href}\n target={props.target}\n className={props.className}\n prefetch={props.prefetch}\n onClick={props.onClick}\n >\n {props.children}\n </NextLink>;\n}\n\nfunction StyledLink(props: LinkProps) {\n return (\n <Link {...props} className={cn(\"underline font-medium\", props.className)}>\n {props.children}\n </Link>\n );\n}\n\nexport { Link, StyledLink };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,sBAAmB;AACnB,kBAAqB;AAYZ;AADT,SAAS,KAAK,OAAkB;AAC9B,SAAO;AAAA,IAAC,YAAAA;AAAA,IAAA;AAAA,MACN,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,UAAU,MAAM;AAAA,MAChB,SAAS,MAAM;AAAA,MAEd,gBAAM;AAAA;AAAA,EACT;AACF;AAEA,SAAS,WAAW,OAAkB;AACpC,SACE,4CAAC,QAAM,GAAG,OAAO,eAAW,oBAAG,yBAAyB,MAAM,SAAS,GACpE,gBAAM,UACT;AAEJ;","names":["NextLink"]}
@@ -34,7 +34,15 @@ function OAuthButtonGroup({
34
34
  }) {
35
35
  const stackApp = (0, import_hooks.useStackApp)();
36
36
  const project = mockProject || stackApp.useProject();
37
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gap-4 flex flex-col items-stretch stack-scope", children: project.config.oauthProviders.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_oauth_button.OAuthButton, { provider: p.id, type }, p.id)) });
37
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gap-4 flex flex-col items-stretch stack-scope", children: project.config.oauthProviders.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
38
+ import_oauth_button.OAuthButton,
39
+ {
40
+ provider: p.id,
41
+ type,
42
+ isMock: !!mockProject
43
+ },
44
+ p.id
45
+ )) });
38
46
  }
39
47
  // Annotate the CommonJS export names for ESM import in node:
40
48
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/oauth-button-group.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { useStackApp } from \"../lib/hooks\";\nimport { OAuthButton } from \"./oauth-button\";\n\nexport function OAuthButtonGroup({\n type,\n mockProject,\n}: {\n type: 'sign-in' | 'sign-up',\n mockProject?: {\n config: {\n oauthProviders: {\n id: string,\n }[],\n },\n },\n}) {\n const stackApp = useStackApp();\n const project = mockProject || stackApp.useProject();\n return (\n <div className='gap-4 flex flex-col items-stretch stack-scope'>\n {project.config.oauthProviders.map(p => (\n <OAuthButton key={p.id} provider={p.id} type={type}/>\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,mBAA4B;AAC5B,0BAA4B;AAoBpB;AAlBD,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AACF,GASG;AACD,QAAM,eAAW,0BAAY;AAC7B,QAAM,UAAU,eAAe,SAAS,WAAW;AACnD,SACE,4CAAC,SAAI,WAAU,iDACZ,kBAAQ,OAAO,eAAe,IAAI,OACjC,4CAAC,mCAAuB,UAAU,EAAE,IAAI,QAAtB,EAAE,EAA+B,CACpD,GACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/oauth-button-group.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { useStackApp } from \"../lib/hooks\";\nimport { OAuthButton } from \"./oauth-button\";\n\nexport function OAuthButtonGroup({\n type,\n mockProject,\n}: {\n type: 'sign-in' | 'sign-up',\n mockProject?: {\n config: {\n oauthProviders: {\n id: string,\n }[],\n },\n },\n}) {\n const stackApp = useStackApp();\n const project = mockProject || stackApp.useProject();\n return (\n <div className='gap-4 flex flex-col items-stretch stack-scope'>\n {project.config.oauthProviders.map(p => (\n <OAuthButton key={p.id} provider={p.id} type={type}\n isMock={!!mockProject}\n />\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,mBAA4B;AAC5B,0BAA4B;AAoBpB;AAlBD,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AACF,GASG;AACD,QAAM,eAAW,0BAAY;AAC7B,QAAM,UAAU,eAAe,SAAS,WAAW;AACnD,SACE,4CAAC,SAAI,WAAU,iDACZ,kBAAQ,OAAO,eAAe,IAAI,OACjC;AAAA,IAAC;AAAA;AAAA,MAAuB,UAAU,EAAE;AAAA,MAAI;AAAA,MACtC,QAAQ,CAAC,CAAC;AAAA;AAAA,IADM,EAAE;AAAA,EAEpB,CACD,GACH;AAEJ;","names":[]}
@@ -50,7 +50,8 @@ var changeColor = (c, value) => {
50
50
  };
51
51
  function OAuthButton({
52
52
  provider,
53
- type
53
+ type,
54
+ isMock = false
54
55
  }) {
55
56
  const { t } = (0, import_translations.useTranslation)();
56
57
  const stackApp = (0, import__.useStackApp)();
@@ -193,7 +194,7 @@ function OAuthButton({
193
194
  },
194
195
  className: `stack-oauth-button-${styleId} stack-scope relative`,
195
196
  children: [
196
- lastUsed === provider && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute -top-2 -right-2 bg-blue-500 text-white text-xs px-2 py-1 rounded-md", children: "last" }),
197
+ !isMock && lastUsed === provider && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute -top-2 -right-2 bg-blue-500 text-white text-xs px-2 py-1 rounded-md", children: "last" }),
197
198
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center w-full gap-4", children: [
198
199
  style.icon,
199
200
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex-1", children: type === "sign-up" ? t("Sign up with {provider}", { provider: style.name }) : t("Sign in with {provider}", { provider: style.name }) })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/oauth-button.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { BrandIcons, Button } from '@stackframe/stack-ui';\nimport Color from 'color';\nimport { useEffect, useId, useState } from 'react';\nimport { useStackApp } from '..';\nimport { useTranslation } from '../lib/translations';\n\nconst iconSize = 22;\n\nconst changeColor = (c: Color, value: number) => {\n if (c.isLight()) {\n value = -value;\n }\n return c.hsl(c.hue(), c.saturationl(), c.lightness() + value).toString();\n};\n\nexport function OAuthButton({\n provider,\n type,\n}: {\n provider: string,\n type: 'sign-in' | 'sign-up',\n}) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const styleId = useId().replaceAll(':', '-');\n\n const [lastUsed, setLastUsed] = useState<string | null>(null);\n useEffect(() => {\n setLastUsed(localStorage.getItem('_STACK_AUTH.lastUsed'));\n }, []);\n\n let style : {\n backgroundColor?: string,\n textColor?: string,\n name: string,\n icon: JSX.Element | null,\n border?: string,\n };\n switch (provider) {\n case 'google': {\n style = {\n backgroundColor: '#fff',\n textColor: '#000',\n name: 'Google',\n border: '1px solid #ddd',\n icon: <BrandIcons.Google iconSize={iconSize} />,\n };\n break;\n }\n case 'github': {\n style = {\n backgroundColor: '#111',\n textColor: '#fff',\n border: '1px solid #333',\n name: 'GitHub',\n icon: <BrandIcons.GitHub iconSize={iconSize} />,\n };\n break;\n }\n case 'facebook': {\n style = {\n backgroundColor: '#1877F2',\n textColor: '#fff',\n name: 'Facebook',\n icon: <BrandIcons.Facebook iconSize={iconSize} />,\n };\n break;\n }\n case 'microsoft': {\n style = {\n backgroundColor: '#2f2f2f',\n textColor: '#fff',\n name: 'Microsoft',\n icon: <BrandIcons.Microsoft iconSize={iconSize} />,\n };\n break;\n }\n case 'spotify': {\n style = {\n backgroundColor: '#1DB954',\n textColor: '#fff',\n name: 'Spotify',\n icon: <BrandIcons.Spotify iconSize={iconSize} />,\n };\n break;\n }\n case 'discord': {\n style = {\n backgroundColor: '#5865F2',\n textColor: '#fff',\n name: 'Discord',\n icon: <BrandIcons.Discord iconSize={iconSize} />,\n };\n break;\n }\n case 'gitlab': {\n style = {\n backgroundColor: \"#111\",\n textColor: \"#fff\",\n border: \"1px solid #333\",\n name: \"Gitlab\",\n icon: <BrandIcons.Gitlab iconSize={iconSize} />,\n };\n break;\n }\n case 'apple': {\n style = {\n backgroundColor: \"#000\",\n textColor: \"#fff\",\n border: \"1px solid #333\",\n name: \"Apple\",\n icon: <BrandIcons.Apple iconSize={iconSize} />,\n };\n break;\n }\n case \"bitbucket\": {\n style = {\n backgroundColor: \"#fff\",\n textColor: \"#000\",\n border: \"1px solid #ddd\",\n name: \"Bitbucket\",\n icon: <BrandIcons.Bitbucket iconSize={iconSize} />,\n };\n break;\n }\n case 'linkedin': {\n style = {\n backgroundColor: \"#0073b1\",\n textColor: \"#fff\",\n name: \"LinkedIn\",\n icon: <BrandIcons.LinkedIn iconSize={iconSize} />,\n };\n break;\n }\n case 'x': {\n style = {\n backgroundColor: \"#000\",\n textColor: \"#fff\",\n name: \"X\",\n icon: <BrandIcons.X iconSize={iconSize} />,\n };\n break;\n }\n default: {\n style = {\n name: provider,\n icon: null,\n };\n }\n }\n\n const styleSheet = `\n .stack-oauth-button-${styleId} {\n background-color: ${style.backgroundColor} !important;\n color: ${style.textColor} !important;\n border: ${style.border} !important;\n }\n .stack-oauth-button-${styleId}:hover {\n background-color: ${changeColor(Color(style.backgroundColor), 10)} !important;\n }\n `;\n\n return (\n <>\n <style>{styleSheet}</style>\n <Button\n onClick={async () => {\n localStorage.setItem('_STACK_AUTH.lastUsed', provider);\n await stackApp.signInWithOAuth(provider);\n }}\n className={`stack-oauth-button-${styleId} stack-scope relative`}\n >\n {lastUsed === provider && (\n <span className=\"absolute -top-2 -right-2 bg-blue-500 text-white text-xs px-2 py-1 rounded-md\">\n last\n </span>\n )}\n <div className='flex items-center w-full gap-4'>\n {style.icon}\n <span className='flex-1'>\n {type === 'sign-up' ?\n t('Sign up with {provider}', { provider: style.name }) :\n t('Sign in with {provider}', { provider: style.name })\n }\n </span>\n </div>\n </Button>\n </>\n );\n}\n"],"mappings":"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","names":["Color"]}
1
+ {"version":3,"sources":["../../src/components/oauth-button.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { BrandIcons, Button } from '@stackframe/stack-ui';\nimport Color from 'color';\nimport { useEffect, useId, useState } from 'react';\nimport { useStackApp } from '..';\nimport { useTranslation } from '../lib/translations';\n\nconst iconSize = 22;\n\nconst changeColor = (c: Color, value: number) => {\n if (c.isLight()) {\n value = -value;\n }\n return c.hsl(c.hue(), c.saturationl(), c.lightness() + value).toString();\n};\n\nexport function OAuthButton({\n provider,\n type,\n isMock = false,\n}: {\n provider: string,\n type: 'sign-in' | 'sign-up',\n isMock?: boolean,\n}) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const styleId = useId().replaceAll(':', '-');\n\n const [lastUsed, setLastUsed] = useState<string | null>(null);\n useEffect(() => {\n setLastUsed(localStorage.getItem('_STACK_AUTH.lastUsed'));\n }, []);\n\n let style : {\n backgroundColor?: string,\n textColor?: string,\n name: string,\n icon: JSX.Element | null,\n border?: string,\n };\n switch (provider) {\n case 'google': {\n style = {\n backgroundColor: '#fff',\n textColor: '#000',\n name: 'Google',\n border: '1px solid #ddd',\n icon: <BrandIcons.Google iconSize={iconSize} />,\n };\n break;\n }\n case 'github': {\n style = {\n backgroundColor: '#111',\n textColor: '#fff',\n border: '1px solid #333',\n name: 'GitHub',\n icon: <BrandIcons.GitHub iconSize={iconSize} />,\n };\n break;\n }\n case 'facebook': {\n style = {\n backgroundColor: '#1877F2',\n textColor: '#fff',\n name: 'Facebook',\n icon: <BrandIcons.Facebook iconSize={iconSize} />,\n };\n break;\n }\n case 'microsoft': {\n style = {\n backgroundColor: '#2f2f2f',\n textColor: '#fff',\n name: 'Microsoft',\n icon: <BrandIcons.Microsoft iconSize={iconSize} />,\n };\n break;\n }\n case 'spotify': {\n style = {\n backgroundColor: '#1DB954',\n textColor: '#fff',\n name: 'Spotify',\n icon: <BrandIcons.Spotify iconSize={iconSize} />,\n };\n break;\n }\n case 'discord': {\n style = {\n backgroundColor: '#5865F2',\n textColor: '#fff',\n name: 'Discord',\n icon: <BrandIcons.Discord iconSize={iconSize} />,\n };\n break;\n }\n case 'gitlab': {\n style = {\n backgroundColor: \"#111\",\n textColor: \"#fff\",\n border: \"1px solid #333\",\n name: \"Gitlab\",\n icon: <BrandIcons.Gitlab iconSize={iconSize} />,\n };\n break;\n }\n case 'apple': {\n style = {\n backgroundColor: \"#000\",\n textColor: \"#fff\",\n border: \"1px solid #333\",\n name: \"Apple\",\n icon: <BrandIcons.Apple iconSize={iconSize} />,\n };\n break;\n }\n case \"bitbucket\": {\n style = {\n backgroundColor: \"#fff\",\n textColor: \"#000\",\n border: \"1px solid #ddd\",\n name: \"Bitbucket\",\n icon: <BrandIcons.Bitbucket iconSize={iconSize} />,\n };\n break;\n }\n case 'linkedin': {\n style = {\n backgroundColor: \"#0073b1\",\n textColor: \"#fff\",\n name: \"LinkedIn\",\n icon: <BrandIcons.LinkedIn iconSize={iconSize} />,\n };\n break;\n }\n case 'x': {\n style = {\n backgroundColor: \"#000\",\n textColor: \"#fff\",\n name: \"X\",\n icon: <BrandIcons.X iconSize={iconSize} />,\n };\n break;\n }\n default: {\n style = {\n name: provider,\n icon: null,\n };\n }\n }\n\n const styleSheet = `\n .stack-oauth-button-${styleId} {\n background-color: ${style.backgroundColor} !important;\n color: ${style.textColor} !important;\n border: ${style.border} !important;\n }\n .stack-oauth-button-${styleId}:hover {\n background-color: ${changeColor(Color(style.backgroundColor), 10)} !important;\n }\n `;\n\n return (\n <>\n <style>{styleSheet}</style>\n <Button\n onClick={async () => {\n localStorage.setItem('_STACK_AUTH.lastUsed', provider);\n await stackApp.signInWithOAuth(provider);\n }}\n className={`stack-oauth-button-${styleId} stack-scope relative`}\n >\n {!isMock && lastUsed === provider && (\n <span className=\"absolute -top-2 -right-2 bg-blue-500 text-white text-xs px-2 py-1 rounded-md\">\n last\n </span>\n )}\n <div className='flex items-center w-full gap-4'>\n {style.icon}\n <span className='flex-1'>\n {type === 'sign-up' ?\n t('Sign up with {provider}', { provider: style.name }) :\n t('Sign in with {provider}', { provider: style.name })\n }\n </span>\n </div>\n </Button>\n </>\n );\n}\n"],"mappings":"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","names":["Color"]}
@@ -42,6 +42,7 @@ var import_password = require("@stackframe/stack-shared/dist/helpers/password");
42
42
  var import_use_async_callback = require("@stackframe/stack-shared/dist/hooks/use-async-callback");
43
43
  var import_schema_fields = require("@stackframe/stack-shared/dist/schema-fields");
44
44
  var import_crypto = require("@stackframe/stack-shared/dist/utils/crypto");
45
+ var import_dates = require("@stackframe/stack-shared/dist/utils/dates");
45
46
  var import_errors = require("@stackframe/stack-shared/dist/utils/errors");
46
47
  var import_promises = require("@stackframe/stack-shared/dist/utils/promises");
47
48
  var import_stack_ui = require("@stackframe/stack-ui");
@@ -88,6 +89,13 @@ function AccountSettings(props) {
88
89
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "ShieldCheck" }),
89
90
  content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmailsAndAuthPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmailsAndAuthPage, {}) })
90
91
  },
92
+ {
93
+ title: t("Active Sessions"),
94
+ type: "item",
95
+ id: "sessions",
96
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "Monitor" }),
97
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActiveSessionsPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActiveSessionsPage, {}) })
98
+ },
91
99
  {
92
100
  title: t("Settings"),
93
101
  type: "item",
@@ -344,6 +352,118 @@ function EmailsAndAuthPage() {
344
352
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MfaSection, {})
345
353
  ] });
346
354
  }
355
+ function ActiveSessionsPage() {
356
+ const { t } = (0, import_translations.useTranslation)();
357
+ const user = (0, import__.useUser)({ or: "throw" });
358
+ const [isLoading, setIsLoading] = (0, import_react.useState)(true);
359
+ const [isRevokingAll, setIsRevokingAll] = (0, import_react.useState)(false);
360
+ const [sessions, setSessions] = (0, import_react.useState)([]);
361
+ const [showConfirmRevokeAll, setShowConfirmRevokeAll] = (0, import_react.useState)(false);
362
+ (0, import_react.useEffect)(() => {
363
+ (0, import_promises.runAsynchronously)(async () => {
364
+ setIsLoading(true);
365
+ const sessionsData = await user.getActiveSessions();
366
+ const enhancedSessions = sessionsData;
367
+ setSessions(enhancedSessions);
368
+ setIsLoading(false);
369
+ });
370
+ }, [user]);
371
+ const handleRevokeSession = async (sessionId) => {
372
+ try {
373
+ await user.revokeSession(sessionId);
374
+ setSessions(sessions.filter((session) => session.id !== sessionId));
375
+ } catch (error) {
376
+ (0, import_errors.captureError)("Failed to revoke session", { sessionId, error });
377
+ throw error;
378
+ }
379
+ };
380
+ const handleRevokeAllSessions = async () => {
381
+ setIsRevokingAll(true);
382
+ try {
383
+ const deletionPromises = sessions.filter((session) => !session.isCurrentSession).map((session) => user.revokeSession(session.id));
384
+ await Promise.all(deletionPromises);
385
+ setSessions((prevSessions) => prevSessions.filter((session) => session.isCurrentSession));
386
+ } catch (error) {
387
+ (0, import_errors.captureError)("Failed to revoke all sessions", { error, sessionIds: sessions.map((session) => session.id) });
388
+ throw error;
389
+ } finally {
390
+ setIsRevokingAll(false);
391
+ setShowConfirmRevokeAll(false);
392
+ }
393
+ };
394
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PageLayout, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
395
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [
396
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { className: "font-medium", children: t("Active Sessions") }),
397
+ sessions.filter((s) => !s.isCurrentSession).length > 0 && !isLoading && (showConfirmRevokeAll ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2", children: [
398
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
399
+ import_stack_ui.Button,
400
+ {
401
+ variant: "destructive",
402
+ size: "sm",
403
+ loading: isRevokingAll,
404
+ onClick: handleRevokeAllSessions,
405
+ children: t("Confirm")
406
+ }
407
+ ),
408
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
409
+ import_stack_ui.Button,
410
+ {
411
+ variant: "secondary",
412
+ size: "sm",
413
+ disabled: isRevokingAll,
414
+ onClick: () => setShowConfirmRevokeAll(false),
415
+ children: t("Cancel")
416
+ }
417
+ )
418
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
419
+ import_stack_ui.Button,
420
+ {
421
+ variant: "outline",
422
+ size: "sm",
423
+ onClick: () => setShowConfirmRevokeAll(true),
424
+ children: t("Revoke All Other Sessions")
425
+ }
426
+ ))
427
+ ] }),
428
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", type: "footnote", className: "mb-4", children: t("These are devices where you're currently logged in. You can revoke access to end a session.") }),
429
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-[300px] w-full rounded-md" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "border rounded-md", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Table, { children: [
430
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableRow, { children: [
431
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[200px]", children: t("Session") }),
432
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[150px]", children: t("IP Address") }),
433
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[150px]", children: t("Location") }),
434
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[150px]", children: t("Last used") }),
435
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[80px]" })
436
+ ] }) }),
437
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableBody, { children: sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { colSpan: 5, className: "text-center py-6", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", children: t("No active sessions found") }) }) }) : sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableRow, { children: [
438
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
439
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: session.isCurrentSession ? t("Current Session") : t("Other Session") }),
440
+ session.isImpersonation && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Badge, { variant: "secondary", className: "w-fit mt-1", children: t("Impersonation") }),
441
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", type: "footnote", children: t("Signed in {time}", { time: new Date(session.createdAt).toLocaleDateString() }) })
442
+ ] }) }),
443
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: session.geoInfo?.ip || t("-") }) }),
444
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: session.geoInfo?.cityName || t("Unknown") }) }),
445
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col", children: [
446
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: session.lastUsedAt ? (0, import_dates.fromNow)(new Date(session.lastUsedAt)) : t("Never") }),
447
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", type: "footnote", title: session.lastUsedAt ? new Date(session.lastUsedAt).toLocaleString() : "", children: session.lastUsedAt ? new Date(session.lastUsedAt).toLocaleDateString() : "" })
448
+ ] }) }),
449
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { align: "right", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
450
+ import_stack_ui.ActionCell,
451
+ {
452
+ items: [
453
+ {
454
+ item: t("Revoke"),
455
+ onClick: () => handleRevokeSession(session.id),
456
+ danger: true,
457
+ disabled: session.isCurrentSession,
458
+ disabledTooltip: session.isCurrentSession ? t("You cannot revoke your current session") : void 0
459
+ }
460
+ ]
461
+ }
462
+ ) })
463
+ ] }, session.id)) })
464
+ ] }) })
465
+ ] }) });
466
+ }
347
467
  function EmailsAndAuthPageSkeleton() {
348
468
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
349
469
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
@@ -352,6 +472,13 @@ function EmailsAndAuthPageSkeleton() {
352
472
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" })
353
473
  ] });
354
474
  }
475
+ function ActiveSessionsPageSkeleton() {
476
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
477
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-6 w-48 mb-2" }),
478
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-4 w-full mb-4" }),
479
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-[200px] w-full mt-1 rounded-md" })
480
+ ] });
481
+ }
355
482
  function PasskeySection() {
356
483
  const { t } = (0, import_translations.useTranslation)();
357
484
  const user = (0, import__.useUser)({ or: "throw" });
@@ -472,6 +599,7 @@ function PasswordSection() {
472
599
  const contactChannels = user.useContactChannels();
473
600
  const [changingPassword, setChangingPassword] = (0, import_react.useState)(false);
474
601
  const [loading, setLoading] = (0, import_react.useState)(false);
602
+ const project = (0, import__.useStackApp)().useProject();
475
603
  const passwordSchema = (0, import_schema_fields.yupObject)({
476
604
  oldPassword: user.hasPassword ? import_schema_fields.passwordSchema.defined().nonEmpty(t("Please enter your old password")) : (0, import_schema_fields.yupString)(),
477
605
  newPassword: import_schema_fields.passwordSchema.defined().nonEmpty(t("Please enter your password")).test({
@@ -508,6 +636,9 @@ function PasswordSection() {
508
636
  };
509
637
  const registerPassword = register("newPassword");
510
638
  const registerPasswordRepeat = register("newPasswordRepeat");
639
+ if (!project.config.credentialEnabled) {
640
+ return null;
641
+ }
511
642
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
512
643
  Section,
513
644
  {