@stackframe/stack 2.6.26 → 2.6.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 (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/credential-sign-in.js +2 -2
  3. package/dist/components/credential-sign-in.js.map +1 -1
  4. package/dist/components/credential-sign-up.js +3 -3
  5. package/dist/components/credential-sign-up.js.map +1 -1
  6. package/dist/components/elements/maybe-full-page.js +1 -0
  7. package/dist/components/elements/maybe-full-page.js.map +1 -1
  8. package/dist/components/magic-link-sign-in.js +1 -1
  9. package/dist/components/magic-link-sign-in.js.map +1 -1
  10. package/dist/components-page/account-settings.js +6 -6
  11. package/dist/components-page/account-settings.js.map +1 -1
  12. package/dist/components-page/forgot-password.js +1 -1
  13. package/dist/components-page/forgot-password.js.map +1 -1
  14. package/dist/components-page/password-reset.js +1 -1
  15. package/dist/components-page/password-reset.js.map +1 -1
  16. package/dist/esm/components/credential-sign-in.js +3 -3
  17. package/dist/esm/components/credential-sign-in.js.map +1 -1
  18. package/dist/esm/components/credential-sign-up.js +4 -4
  19. package/dist/esm/components/credential-sign-up.js.map +1 -1
  20. package/dist/esm/components/elements/maybe-full-page.js +1 -0
  21. package/dist/esm/components/elements/maybe-full-page.js.map +1 -1
  22. package/dist/esm/components/magic-link-sign-in.js +2 -2
  23. package/dist/esm/components/magic-link-sign-in.js.map +1 -1
  24. package/dist/esm/components-page/account-settings.js +7 -7
  25. package/dist/esm/components-page/account-settings.js.map +1 -1
  26. package/dist/esm/components-page/forgot-password.js +2 -2
  27. package/dist/esm/components-page/forgot-password.js.map +1 -1
  28. package/dist/esm/components-page/password-reset.js +2 -2
  29. package/dist/esm/components-page/password-reset.js.map +1 -1
  30. package/dist/esm/lib/auth.js +7 -4
  31. package/dist/esm/lib/auth.js.map +1 -1
  32. package/dist/esm/lib/stack-app.js +1 -1
  33. package/dist/esm/utils/email.js +2 -2
  34. package/dist/esm/utils/email.js.map +1 -1
  35. package/dist/generated/quetzal-translations.d.mts +2 -2
  36. package/dist/generated/quetzal-translations.d.ts +2 -2
  37. package/dist/lib/auth.js +6 -3
  38. package/dist/lib/auth.js.map +1 -1
  39. package/dist/lib/stack-app.js +1 -1
  40. package/dist/utils/email.js +1 -1
  41. package/dist/utils/email.js.map +1 -1
  42. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from '@stackframe/stack-shared/dist/helpers/password';\nimport { useAsyncCallback } from '@stackframe/stack-shared/dist/hooks/use-async-callback';\nimport { yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { generateRandomValues } from '@stackframe/stack-shared/dist/utils/crypto';\nimport { throwErr } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously, runAsynchronouslyWithAlert } from '@stackframe/stack-shared/dist/utils/promises';\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActionCell, Badge, Button, Input, Label, PasswordInput, Separator, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@stackframe/stack-ui';\nimport { CirclePlus, Contact, Edit, LucideIcon, Settings, ShieldCheck } from 'lucide-react';\nimport { useRouter } from \"next/navigation\";\nimport { TOTPController, createTOTPKeyURI } from \"oslo/otp\";\nimport * as QRCode from 'qrcode';\nimport React, { useEffect, useState } from \"react\";\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { CurrentUser, MessageCard, Project, Team, useStackApp, useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { UserAvatar } from '../components/elements/user-avatar';\nimport { ProfileImageEditor } from \"../components/profile-image-editor\";\nimport { TeamIcon } from '../components/team-icon';\nimport { useTranslation } from \"../lib/translations\";\n\n\nexport function AccountSettings(props: {\n fullPage?: boolean,\n extraItems?: {\n title: string,\n icon: LucideIcon,\n content: React.ReactNode,\n id: string,\n }[],\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const teams = user.useTeams();\n const stackApp = useStackApp();\n const project = stackApp.useProject();\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div className=\"self-stretch flex-grow w-full\">\n <SidebarLayout\n items={([\n {\n title: t('My Profile'),\n type: 'item',\n id: 'profile',\n icon: Contact,\n content: <ProfilePage/>,\n },\n {\n title: t('Emails & Auth'),\n type: 'item',\n id: 'auth',\n icon: ShieldCheck,\n content: <EmailsAndAuthPage/>,\n },\n {\n title: t('Settings'),\n type: 'item',\n id: 'settings',\n icon: Settings,\n content: <SettingsPage/>,\n },\n ...(props.extraItems?.map(item => ({\n title: item.title,\n type: 'item',\n id: item.id,\n icon: item.icon,\n content: item.content,\n } as const)) || []),\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: t('Teams'),\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center w-full'>\n <TeamIcon team={team}/>\n <Typography className=\"max-w-[320px] md:w-[90%] truncate\">{team.displayName}</Typography>\n </div>,\n type: 'item',\n id: `team-${team.id}`,\n content: <TeamPage team={team}/>,\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: t('Create a team'),\n icon: CirclePlus,\n type: 'item',\n id: 'team-creation',\n content: <TeamCreation />,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title={t(\"Account Settings\")}\n />\n </div>\n </MaybeFullPage>\n );\n}\n\nfunction Section(props: { title: string, description?: string, children: React.ReactNode }) {\n return (\n <div className='flex flex-col sm:flex-row gap-2'>\n <div className='sm:flex-1 flex flex-col justify-center'>\n <Typography className='font-medium'>\n {props.title}\n </Typography>\n {props.description && <Typography variant='secondary' type='footnote'>\n {props.description}\n </Typography>}\n </div>\n <div className='sm:flex-1 sm:items-end flex flex-col gap-2 '>\n {props.children}\n </div>\n </div>\n );\n}\n\nfunction PageLayout(props: { children: React.ReactNode }) {\n return (\n <div className='flex flex-col gap-6'>\n <Separator/>\n {React.Children.map(props.children, (child) => (\n child && (\n <>\n {child}\n <Separator/>\n </>\n )\n ))}\n </div>\n );\n}\n\nfunction ProfilePage() {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n\n return (\n <PageLayout>\n <Section\n title={t(\"User name\")}\n description={t(\"This is a display name and is not used for authentication\")}\n >\n <EditableText\n value={user.displayName || ''}\n onSave={async (newDisplayName) => {\n await user.update({ displayName: newDisplayName });\n }}/>\n </Section>\n\n <Section\n title={t(\"Profile image\")}\n description={t(\"Upload your own image as your avatar\")}\n >\n <ProfileImageEditor\n user={user}\n onProfileImageUrlChange={async (profileImageUrl) => {\n await user.update({ profileImageUrl });\n }}\n />\n </Section>\n </PageLayout>\n );\n}\n\nfunction EmailsSection() {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const contactChannels = user.useContactChannels();\n const [addingEmail, setAddingEmail] = useState(contactChannels.length === 0);\n const [addingEmailLoading, setAddingEmailLoading] = useState(false);\n const [addedEmail, setAddedEmail] = useState<string | null>(null);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const isLastEmail = contactChannels.filter(x => x.usedForAuth && x.type === 'email').length === 1;\n\n useEffect(() => {\n if (addedEmail) {\n runAsynchronously(async () => {\n const cc = contactChannels.find(x => x.value === addedEmail);\n if (cc && !cc.isVerified) {\n await cc.sendVerificationEmail();\n }\n setAddedEmail(null);\n });\n }\n }, [contactChannels, addedEmail]);\n\n const emailSchema = yupObject({\n email: yupString()\n .email(t('Please enter a valid email address'))\n .notOneOf(contactChannels.map(x => x.value), t('Email already exists'))\n .defined()\n .nonEmpty(t('Email is required')),\n });\n\n const { register, handleSubmit, formState: { errors }, reset } = useForm({\n resolver: yupResolver(emailSchema)\n });\n\n const onSubmit = async (data: yup.InferType<typeof emailSchema>) => {\n setAddingEmailLoading(true);\n try {\n await user.createContactChannel({ type: 'email', value: data.email, usedForAuth: false });\n setAddedEmail(data.email);\n } finally {\n setAddingEmailLoading(false);\n }\n setAddingEmail(false);\n reset();\n };\n\n return (\n <div>\n <div className='flex flex-col md:flex-row justify-between mb-4 gap-4'>\n <Typography className='font-medium'>{t(\"Emails\")}</Typography>\n {addingEmail ? (\n <form\n onSubmit={(e) => {\n e.preventDefault();\n runAsynchronously(handleSubmit(onSubmit));\n }}\n className='flex flex-col'\n >\n <div className='flex gap-2'>\n <Input\n {...register(\"email\")}\n placeholder={t(\"Enter email\")}\n />\n <Button type=\"submit\" loading={addingEmailLoading}>\n {t(\"Add\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => {\n setAddingEmail(false);\n reset();\n }}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n {errors.email && <FormWarningText text={errors.email.message} />}\n </form>\n ) : (\n <div className='flex md:justify-end'>\n <Button variant='secondary' onClick={() => setAddingEmail(true)}>{t(\"Add an email\")}</Button>\n </div>\n )}\n </div>\n\n {contactChannels.length > 0 ? (\n <div className='border rounded-md'>\n <Table>\n <TableBody>\n {/*eslint-disable-next-line @typescript-eslint/no-unnecessary-condition*/}\n {contactChannels.filter(x => x.type === 'email')\n .sort((a, b) => {\n if (a.isPrimary !== b.isPrimary) return a.isPrimary ? -1 : 1;\n if (a.isVerified !== b.isVerified) return a.isVerified ? -1 : 1;\n return 0;\n })\n .map(x => (\n <TableRow key={x.id}>\n <TableCell>\n <div className='flex flex-col md:flex-row gap-2 md:gap-4'>\n {x.value}\n <div className='flex gap-2'>\n {x.isPrimary ? <Badge>{t(\"Primary\")}</Badge> : null}\n {!x.isVerified ? <Badge variant='destructive'>{t(\"Unverified\")}</Badge> : null}\n {x.usedForAuth ? <Badge variant='outline'>{t(\"Used for sign-in\")}</Badge> : null}\n </div>\n </div>\n </TableCell>\n <TableCell className=\"flex justify-end\">\n <ActionCell items={[\n ...(!x.isVerified ? [{\n item: t(\"Send verification email\"),\n onClick: async () => { await x.sendVerificationEmail(); },\n }] : []),\n ...(!x.isPrimary && x.isVerified ? [{\n item: t(\"Set as primary\"),\n onClick: async () => { await x.update({ isPrimary: true }); },\n }] :\n !x.isPrimary ? [{\n item: t(\"Set as primary\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"Please verify your email first\"),\n }] : []),\n ...(!x.usedForAuth && x.isVerified ? [{\n item: t(\"Use for sign-in\"),\n onClick: async () => { await x.update({ usedForAuth: true }); },\n }] : []),\n ...(x.usedForAuth && !isLastEmail ? [{\n item: t(\"Stop using for sign-in\"),\n onClick: async () => { await x.update({ usedForAuth: false }); },\n }] : x.usedForAuth ? [{\n item: t(\"Stop using for sign-in\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"You can not remove your last sign-in email\"),\n }] : []),\n ...(!isLastEmail || !x.usedForAuth ? [{\n item: t(\"Remove\"),\n onClick: async () => { await x.delete(); },\n danger: true,\n }] : [{\n item: t(\"Remove\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"You can not remove your last sign-in email\"),\n }]),\n ]}/>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction EmailsAndAuthPage() {\n const passwordSection = usePasswordSection();\n const mfaSection = useMfaSection();\n const otpSection = useOtpSection();\n const passkeySection = usePasskeySection();\n\n return (\n <PageLayout>\n <EmailsSection/>\n {passwordSection}\n {passkeySection}\n {otpSection}\n {mfaSection}\n </PageLayout>\n );\n}\n\n\nfunction usePasskeySection() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n const stackApp = useStackApp();\n const project = stackApp.useProject();\n const contactChannels = user.useContactChannels();\n\n\n // passkey is enabled if there is a passkey\n const hasPasskey = user.passkeyAuthEnabled;\n\n const isLastAuth = user.passkeyAuthEnabled && !user.hasPassword && user.oauthProviders.length === 0 && !user.otpAuthEnabled;\n const [showConfirmationModal, setShowConfirmationModal] = useState(false);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const hasValidEmail = contactChannels.filter(x => x.type === 'email' && x.isVerified && x.usedForAuth).length > 0;\n\n if (!project.config.passkeyEnabled) {\n return null;\n }\n\n const handleDeletePasskey = async () => {\n await user.update({ passkeyAuthEnabled: false });\n setShowConfirmationModal(false);\n };\n\n\n const handleAddNewPasskey = async () => {\n await user.registerPasskey();\n };\n\n return (\n <>\n <Section title={t(\"Passkey\")} description={hasPasskey ? t(\"Passkey registered\") : t(\"Register a passkey\")}>\n <div className='flex md:justify-end gap-2'>\n {!hasValidEmail && (\n <Typography variant='secondary' type='label'>{t(\"To enable Passkey sign-in, please add a verified sign-in email.\")}</Typography>\n )}\n {hasValidEmail && hasPasskey && isLastAuth && (\n <Typography variant='secondary' type='label'>{t(\"Passkey sign-in is enabled and cannot be disabled as it is currently the only sign-in method\")}</Typography>\n )}\n {!hasPasskey && hasValidEmail && (\n <div>\n <Button onClick={handleAddNewPasskey} variant='secondary'>{t(\"Add new passkey\")}</Button>\n </div>\n )}\n {hasValidEmail && hasPasskey && !isLastAuth && !showConfirmationModal && (\n <Button\n variant='secondary'\n onClick={() => setShowConfirmationModal(true)}\n >\n {t(\"Delete Passkey\")}\n </Button>\n )}\n {hasValidEmail && hasPasskey && !isLastAuth && showConfirmationModal && (\n <div className='flex flex-col gap-2'>\n <Typography variant='destructive'>\n {t(\"Are you sure you want to disable Passkey sign-in? You will not be able to sign in with your passkey anymore.\")}\n </Typography>\n <div className='flex gap-2'>\n <Button\n variant='destructive'\n onClick={handleDeletePasskey}\n >\n {t(\"Disable\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => setShowConfirmationModal(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </div>\n )}\n </div>\n </Section>\n\n\n </>\n\n );\n}\n\n\nfunction useOtpSection() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n const project = useStackApp().useProject();\n const contactChannels = user.useContactChannels();\n const isLastAuth = user.otpAuthEnabled && !user.hasPassword && user.oauthProviders.length === 0 && !user.passkeyAuthEnabled;\n const [disabling, setDisabling] = useState(false);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const hasValidEmail = contactChannels.filter(x => x.type === 'email' && x.isVerified && x.usedForAuth).length > 0;\n\n if (!project.config.magicLinkEnabled) {\n return null;\n }\n\n const handleDisableOTP = async () => {\n await user.update({ otpAuthEnabled: false });\n setDisabling(false);\n };\n\n return (\n <Section title={t(\"OTP sign-in\")} description={user.otpAuthEnabled ? t(\"OTP/magic link sign-in is currently enabled.\") : t(\"Enable sign-in via magic link or OTP sent to your sign-in emails.\")}>\n <div className='flex md:justify-end'>\n {hasValidEmail ? (\n user.otpAuthEnabled ? (\n !isLastAuth ? (\n !disabling ? (\n <Button\n variant='secondary'\n onClick={() => setDisabling(true)}\n >\n {t(\"Disable OTP\")}\n </Button>\n ) : (\n <div className='flex flex-col gap-2'>\n <Typography variant='destructive'>\n {t(\"Are you sure you want to disable OTP sign-in? You will not be able to sign in with only emails anymore.\")}\n </Typography>\n <div className='flex gap-2'>\n <Button\n variant='destructive'\n onClick={handleDisableOTP}\n >\n {t(\"Disable\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => setDisabling(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </div>\n )\n ) : (\n <Typography variant='secondary' type='label'>{t(\"OTP sign-in is enabled and cannot be disabled as it is currently the only sign-in method\")}</Typography>\n )\n ) : (\n <Button\n variant='secondary'\n onClick={async () => {\n await user.update({ otpAuthEnabled: true });\n }}\n >\n {t(\"Enable OTP\")}\n </Button>\n )\n ) : (\n <Typography variant='secondary' type='label'>{t(\"To enable OTP sign-in, please add a verified sign-in email.\")}</Typography>\n )}\n </div>\n </Section>\n );\n}\n\nfunction SettingsPage() {\n const deleteAccountSection = useDeleteAccountSection();\n const signOutSection = useSignOutSection();\n\n return (\n <PageLayout>\n {deleteAccountSection}\n {signOutSection}\n </PageLayout>\n );\n}\n\nfunction usePasswordSection() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n const contactChannels = user.useContactChannels();\n const [changingPassword, setChangingPassword] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const passwordSchema = yupObject({\n oldPassword: user.hasPassword ? yupString().defined().nonEmpty(t('Please enter your old password')) : yupString(),\n newPassword: yupString().defined().nonEmpty(t('Please enter your password')).test({\n name: 'is-valid-password',\n test: (value, ctx) => {\n const error = getPasswordError(value);\n if (error) {\n return ctx.createError({ message: error.message });\n } else {\n return true;\n }\n }\n }),\n newPasswordRepeat: yupString().nullable().oneOf([yup.ref('newPassword'), \"\", null], t('Passwords do not match')).defined().nonEmpty(t('Please repeat your password'))\n });\n\n const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = useForm({\n resolver: yupResolver(passwordSchema)\n });\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const hasValidEmail = contactChannels.filter(x => x.type === 'email' && x.usedForAuth).length > 0;\n\n const onSubmit = async (data: yup.InferType<typeof passwordSchema>) => {\n setLoading(true);\n try {\n const { oldPassword, newPassword } = data;\n const error = user.hasPassword\n ? await user.updatePassword({ oldPassword: oldPassword!, newPassword })\n : await user.setPassword({ password: newPassword! });\n if (error) {\n setError('oldPassword', { type: 'manual', message: t('Incorrect password') });\n } else {\n reset();\n setChangingPassword(false);\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('newPassword');\n const registerPasswordRepeat = register('newPasswordRepeat');\n\n return (\n <Section\n title={t(\"Password\")}\n description={user.hasPassword ? t(\"Update your password\") : t(\"Set a password for your account\")}\n >\n <div className='flex flex-col gap-4'>\n {!changingPassword ? (\n hasValidEmail ? (\n <Button\n variant='secondary'\n onClick={() => setChangingPassword(true)}\n >\n {user.hasPassword ? t(\"Update password\") : t(\"Set password\")}\n </Button>\n ) : (\n <Typography variant='secondary' type='label'>{t(\"To set a password, please add a sign-in email.\")}</Typography>\n )\n ) : (\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n {user.hasPassword && (\n <>\n <Label htmlFor=\"old-password\" className=\"mb-1\">{t(\"Old password\")}</Label>\n <Input\n id=\"old-password\"\n type=\"password\"\n autoComplete=\"current-password\"\n {...register(\"oldPassword\")}\n />\n <FormWarningText text={errors.oldPassword?.message?.toString()} />\n </>\n )}\n\n <Label htmlFor=\"new-password\" className=\"mt-4 mb-1\">{t(\"New password\")}</Label>\n <PasswordInput\n id=\"new-password\"\n autoComplete=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPassword?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">{t(\"Repeat new password\")}</Label>\n <PasswordInput\n id=\"repeat-password\"\n autoComplete=\"new-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPasswordRepeat?.message?.toString()} />\n\n <div className=\"mt-6 flex gap-4\">\n <Button type=\"submit\" loading={loading}>\n {user.hasPassword ? t(\"Update Password\") : t(\"Set Password\")}\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() => {\n setChangingPassword(false);\n reset();\n }}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </form>\n )}\n </div>\n </Section>\n );\n}\n\nfunction useMfaSection() {\n const { t } = useTranslation();\n const project = useStackApp().useProject();\n const user = useUser({ or: \"throw\" });\n const [generatedSecret, setGeneratedSecret] = useState<Uint8Array | null>(null);\n const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);\n const [mfaCode, setMfaCode] = useState<string>(\"\");\n const [isMaybeWrong, setIsMaybeWrong] = useState(false);\n const isEnabled = user.isMultiFactorRequired;\n\n const [handleSubmit, isLoading] = useAsyncCallback(async () => {\n await user.update({\n totpMultiFactorSecret: generatedSecret,\n });\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }, [generatedSecret, user]);\n\n useEffect(() => {\n setIsMaybeWrong(false);\n runAsynchronouslyWithAlert(async () => {\n if (generatedSecret && await new TOTPController().verify(mfaCode, generatedSecret)) {\n await handleSubmit();\n }\n setIsMaybeWrong(true);\n });\n }, [mfaCode, generatedSecret, handleSubmit]);\n\n return (\n <Section\n title={t(\"Multi-factor authentication\")}\n description={isEnabled\n ? t(\"Multi-factor authentication is currently enabled.\")\n : t(\"Multi-factor authentication is currently disabled.\")}\n >\n <div className='flex flex-col gap-4'>\n {!isEnabled && generatedSecret && (\n <>\n <Typography>{t(\"Scan this QR code with your authenticator app:\")}</Typography>\n <img width={200} height={200} src={qrCodeUrl ?? throwErr(\"TOTP QR code failed to generate\")} alt={t(\"TOTP multi-factor authentication QR code\")} />\n <Typography>{t(\"Then, enter your six-digit MFA code:\")}</Typography>\n <Input\n value={mfaCode}\n onChange={(e) => {\n setIsMaybeWrong(false);\n setMfaCode(e.target.value);\n }}\n placeholder=\"123456\"\n maxLength={6}\n disabled={isLoading}\n />\n {isMaybeWrong && mfaCode.length === 6 && (\n <Typography variant=\"destructive\">{t(\"Incorrect code. Please try again.\")}</Typography>\n )}\n <div className='flex'>\n <Button\n variant='secondary'\n onClick={() => {\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </>\n )}\n <div className='flex gap-2'>\n {isEnabled ? (\n <Button\n variant='secondary'\n onClick={async () => {\n await user.update({\n totpMultiFactorSecret: null,\n });\n }}\n >\n {t(\"Disable MFA\")}\n </Button>\n ) : !generatedSecret && (\n <Button\n variant='secondary'\n onClick={async () => {\n const secret = generateRandomValues(new Uint8Array(20));\n setQrCodeUrl(await generateTotpQrCode(project, user, secret));\n setGeneratedSecret(secret);\n }}\n >\n {t(\"Enable MFA\")}\n </Button>\n )}\n </div>\n </div>\n </Section>\n );\n}\n\nasync function generateTotpQrCode(project: Project, user: CurrentUser, secret: Uint8Array) {\n const uri = createTOTPKeyURI(project.displayName, user.primaryEmail ?? user.id, secret);\n return await QRCode.toDataURL(uri) as any;\n}\n\nfunction useSignOutSection() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n\n return (\n <Section\n title={t(\"Sign out\")}\n description={t(\"End your current session\")}\n >\n <div>\n <Button\n variant='secondary'\n onClick={() => user.signOut()}\n >\n {t(\"Sign out\")}\n </Button>\n </div>\n </Section>\n );\n}\n\nfunction TeamPage(props: { team: Team }) {\n const teamUserProfileSection = useTeamUserProfileSection(props);\n const teamProfileImageSection = useTeamProfileImageSection(props);\n const teamDisplayNameSection = useTeamDisplayNameSection(props);\n const leaveTeamSection = useLeaveTeamSection(props);\n const memberInvitationSection = useMemberInvitationSection(props);\n const memberListSection = useMemberListSection(props);\n\n return (\n <PageLayout>\n {teamUserProfileSection}\n {memberInvitationSection}\n {memberListSection}\n {teamProfileImageSection}\n {teamDisplayNameSection}\n {leaveTeamSection}\n </PageLayout>\n );\n}\n\nfunction useLeaveTeamSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const [leaving, setLeaving] = useState(false);\n\n return (\n <Section\n title={t(\"Leave Team\")}\n description={t(\"leave this team and remove your team profile\")}\n >\n {!leaving ? (\n <div>\n <Button\n variant='secondary'\n onClick={() => setLeaving(true)}\n >\n {t(\"Leave team\")}\n </Button>\n </div>\n ) : (\n <div className='flex flex-col gap-2'>\n <Typography variant='destructive'>\n {t(\"Are you sure you want to leave the team?\")}\n </Typography>\n <div className='flex gap-2'>\n <Button\n variant='destructive'\n onClick={async () => {\n await user.leaveTeam(props.team);\n window.location.reload();\n }}\n >\n {t(\"Leave\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => setLeaving(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </div>\n )}\n </Section>\n );\n}\n\nfunction useTeamProfileImageSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <Section\n title={t(\"Team profile image\")}\n description={t(\"Upload an image for your team\")}\n >\n <ProfileImageEditor\n user={props.team}\n onProfileImageUrlChange={async (profileImageUrl) => {\n await props.team.update({ profileImageUrl });\n }}\n />\n </Section>\n );\n}\n\nfunction useTeamDisplayNameSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <Section\n title={t(\"Team display name\")}\n description={t(\"Change the display name of your team\")}\n >\n <EditableText\n value={props.team.displayName}\n onSave={async (newDisplayName) => await props.team.update({ displayName: newDisplayName })}\n />\n </Section>\n );\n}\n\nfunction useTeamUserProfileSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const profile = user.useTeamProfile(props.team);\n\n return (\n <Section\n title={t(\"Team user name\")}\n description={t(\"Overwrite your user display name in this team\")}\n >\n <EditableText\n value={profile.displayName || ''}\n onSave={async (newDisplayName) => {\n await profile.update({ displayName: newDisplayName });\n }}\n />\n </Section>\n );\n}\n\nfunction useMemberInvitationSection(props: { team: Team }) {\n const { t } = useTranslation();\n\n const invitationSchema = yupObject({\n email: yupString().email().defined().nonEmpty(t('Please enter an email address')),\n });\n\n const user = useUser({ or: 'redirect' });\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!inviteMemberPermission) {\n return null;\n }\n\n const { register, handleSubmit, formState: { errors }, watch } = useForm({\n resolver: yupResolver(invitationSchema)\n });\n const [loading, setLoading] = useState(false);\n const [invitedEmail, setInvitedEmail] = useState<string | null>(null);\n\n const onSubmit = async (data: yup.InferType<typeof invitationSchema>) => {\n setLoading(true);\n\n try {\n await props.team.inviteUser({ email: data.email });\n setInvitedEmail(data.email);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setInvitedEmail(null);\n }, [watch('email')]);\n\n return (\n <Section\n title={t(\"Invite member\")}\n description={t(\"Invite a user to your team through email\")}\n >\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n className='w-full'\n >\n <div className=\"flex flex-col gap-4 sm:flex-row w-full\">\n <Input\n placeholder={t(\"Email\")}\n {...register(\"email\")}\n />\n <Button type=\"submit\" loading={loading}>{t(\"Invite User\")}</Button>\n </div>\n <FormWarningText text={errors.email?.message?.toString()} />\n {invitedEmail && <Typography type='label' variant='secondary'>Invited {invitedEmail}</Typography>}\n </form>\n </Section>\n );\n}\n\n\nfunction useMemberListSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const readMemberPermission = user.usePermission(props.team, '$read_members');\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!readMemberPermission && !inviteMemberPermission) {\n return null;\n }\n\n const users = props.team.useUsers();\n\n if (!readMemberPermission) {\n return null;\n }\n\n return (\n <div>\n <Typography className='font-medium mb-2'>{t(\"Members\")}</Typography>\n <div className='border rounded-md'>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[100px]\">{t(\"User\")}</TableHead>\n <TableHead className=\"w-[200px]\">{t(\"Name\")}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {users.map(({ id, teamProfile }, i) => (\n <TableRow key={id}>\n <TableCell>\n <UserAvatar user={teamProfile}/>\n </TableCell>\n <TableCell>\n <Typography>{teamProfile.displayName}</Typography>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n </div>\n );\n}\n\nexport function TeamCreation() {\n const { t } = useTranslation();\n\n const teamCreationSchema = yupObject({\n displayName: yupString().defined().nonEmpty(t(\"Please enter a team name\")),\n });\n\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(teamCreationSchema)\n });\n const app = useStackApp();\n const project = app.useProject();\n const user = useUser({ or: 'redirect' });\n const router = useRouter();\n const [loading, setLoading] = useState(false);\n\n if (!project.config.clientTeamCreationEnabled) {\n return <MessageCard title={t(\"Team creation is not enabled\")} />;\n }\n\n const onSubmit = async (data: yup.InferType<typeof teamCreationSchema>) => {\n setLoading(true);\n\n let team;\n try {\n team = await user.createTeam({ displayName: data.displayName });\n } finally {\n setLoading(false);\n }\n\n router.push(`#team-${team.id}`);\n };\n\n return (\n <PageLayout>\n <Section title={t(\"Create a Team\")} description={t(\"Enter a display name for your new team\")}>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n className='flex gap-2 flex-col sm:flex-row'\n >\n <div className='flex flex-col flex-1'>\n <Input\n id=\"displayName\"\n type=\"text\"\n {...register(\"displayName\")}\n />\n <FormWarningText text={errors.displayName?.message?.toString()} />\n </div>\n <Button type=\"submit\" loading={loading}>{t(\"Create\")}</Button>\n </form>\n </Section>\n </PageLayout>\n );\n}\n\nexport function useDeleteAccountSection() {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const app = useStackApp();\n const project = app.useProject();\n const [deleting, setDeleting] = useState(false);\n if (!project.config.clientUserDeletionEnabled) {\n return null;\n }\n\n return (\n <Section\n title={t(\"Delete Account\")}\n description={t(\"Permanently remove your account and all associated data\")}\n >\n <div className='stack-scope flex flex-col items-stretch'>\n <Accordion type=\"single\" collapsible className=\"w-full\">\n <AccordionItem value=\"item-1\">\n <AccordionTrigger>{t(\"Danger zone\")}</AccordionTrigger>\n <AccordionContent>\n {!deleting ? (\n <div>\n <Button\n variant='destructive'\n onClick={() => setDeleting(true)}\n >\n {t(\"Delete account\")}\n </Button>\n </div>\n ) : (\n <div className='flex flex-col gap-2'>\n <Typography variant='destructive'>\n {t(\"Are you sure you want to delete your account? This action is IRREVERSIBLE and will delete ALL associated data.\")}\n </Typography>\n <div className='flex gap-2'>\n <Button\n variant='destructive'\n onClick={async () => {\n await user.delete();\n await app.redirectToHome();\n }}\n >\n {t(\"Delete Account\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => setDeleting(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </div>\n )}\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n </div>\n </Section>\n );\n}\n\nexport function EditableText(props: { value: string, onSave?: (value: string) => void | Promise<void> }) {\n const [editing, setEditing] = useState(false);\n const [editingValue, setEditingValue] = useState(props.value);\n const { t } = useTranslation();\n\n return (\n <div className='flex items-center gap-2'>\n {editing ? (\n <>\n <Input\n value={editingValue}\n onChange={(e) => setEditingValue(e.target.value)}\n />\n <Button\n size='sm'\n onClick={async () => {\n await props.onSave?.(editingValue);\n setEditing(false);\n }}\n >\n {t(\"Save\")}\n </Button>\n <Button\n size='sm'\n variant='secondary'\n onClick={() => {\n setEditingValue(props.value);\n setEditing(false);\n }}>\n {t(\"Cancel\")}\n </Button>\n </>\n ) : (\n <>\n <Typography>{props.value}</Typography>\n <Button onClick={() => setEditing(true)} size='icon' variant='ghost'>\n <Edit className=\"w-4 h-4\"/>\n </Button>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from '@stackframe/stack-shared/dist/helpers/password';\nimport { useAsyncCallback } from '@stackframe/stack-shared/dist/hooks/use-async-callback';\nimport { emailSchema, passwordSchema as schemaFieldsPasswordSchema, strictEmailSchema, yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { generateRandomValues } from '@stackframe/stack-shared/dist/utils/crypto';\nimport { throwErr } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously, runAsynchronouslyWithAlert } from '@stackframe/stack-shared/dist/utils/promises';\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActionCell, Badge, Button, Input, Label, PasswordInput, Separator, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@stackframe/stack-ui';\nimport { CirclePlus, Contact, Edit, LucideIcon, Settings, ShieldCheck } from 'lucide-react';\nimport { useRouter } from \"next/navigation\";\nimport { TOTPController, createTOTPKeyURI } from \"oslo/otp\";\nimport * as QRCode from 'qrcode';\nimport React, { useEffect, useState } from \"react\";\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { CurrentUser, MessageCard, Project, Team, useStackApp, useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { UserAvatar } from '../components/elements/user-avatar';\nimport { ProfileImageEditor } from \"../components/profile-image-editor\";\nimport { TeamIcon } from '../components/team-icon';\nimport { useTranslation } from \"../lib/translations\";\n\n\nexport function AccountSettings(props: {\n fullPage?: boolean,\n extraItems?: {\n title: string,\n icon: LucideIcon,\n content: React.ReactNode,\n id: string,\n }[],\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const teams = user.useTeams();\n const stackApp = useStackApp();\n const project = stackApp.useProject();\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div className=\"self-stretch flex-grow w-full\">\n <SidebarLayout\n items={([\n {\n title: t('My Profile'),\n type: 'item',\n id: 'profile',\n icon: Contact,\n content: <ProfilePage/>,\n },\n {\n title: t('Emails & Auth'),\n type: 'item',\n id: 'auth',\n icon: ShieldCheck,\n content: <EmailsAndAuthPage/>,\n },\n {\n title: t('Settings'),\n type: 'item',\n id: 'settings',\n icon: Settings,\n content: <SettingsPage/>,\n },\n ...(props.extraItems?.map(item => ({\n title: item.title,\n type: 'item',\n id: item.id,\n icon: item.icon,\n content: item.content,\n } as const)) || []),\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: t('Teams'),\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center w-full'>\n <TeamIcon team={team}/>\n <Typography className=\"max-w-[320px] md:w-[90%] truncate\">{team.displayName}</Typography>\n </div>,\n type: 'item',\n id: `team-${team.id}`,\n content: <TeamPage team={team}/>,\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: t('Create a team'),\n icon: CirclePlus,\n type: 'item',\n id: 'team-creation',\n content: <TeamCreation />,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title={t(\"Account Settings\")}\n />\n </div>\n </MaybeFullPage>\n );\n}\n\nfunction Section(props: { title: string, description?: string, children: React.ReactNode }) {\n return (\n <div className='flex flex-col sm:flex-row gap-2'>\n <div className='sm:flex-1 flex flex-col justify-center'>\n <Typography className='font-medium'>\n {props.title}\n </Typography>\n {props.description && <Typography variant='secondary' type='footnote'>\n {props.description}\n </Typography>}\n </div>\n <div className='sm:flex-1 sm:items-end flex flex-col gap-2 '>\n {props.children}\n </div>\n </div>\n );\n}\n\nfunction PageLayout(props: { children: React.ReactNode }) {\n return (\n <div className='flex flex-col gap-6'>\n <Separator/>\n {React.Children.map(props.children, (child) => (\n child && (\n <>\n {child}\n <Separator/>\n </>\n )\n ))}\n </div>\n );\n}\n\nfunction ProfilePage() {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n\n return (\n <PageLayout>\n <Section\n title={t(\"User name\")}\n description={t(\"This is a display name and is not used for authentication\")}\n >\n <EditableText\n value={user.displayName || ''}\n onSave={async (newDisplayName) => {\n await user.update({ displayName: newDisplayName });\n }}/>\n </Section>\n\n <Section\n title={t(\"Profile image\")}\n description={t(\"Upload your own image as your avatar\")}\n >\n <ProfileImageEditor\n user={user}\n onProfileImageUrlChange={async (profileImageUrl) => {\n await user.update({ profileImageUrl });\n }}\n />\n </Section>\n </PageLayout>\n );\n}\n\nfunction EmailsSection() {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const contactChannels = user.useContactChannels();\n const [addingEmail, setAddingEmail] = useState(contactChannels.length === 0);\n const [addingEmailLoading, setAddingEmailLoading] = useState(false);\n const [addedEmail, setAddedEmail] = useState<string | null>(null);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const isLastEmail = contactChannels.filter(x => x.usedForAuth && x.type === 'email').length === 1;\n\n useEffect(() => {\n if (addedEmail) {\n runAsynchronously(async () => {\n const cc = contactChannels.find(x => x.value === addedEmail);\n if (cc && !cc.isVerified) {\n await cc.sendVerificationEmail();\n }\n setAddedEmail(null);\n });\n }\n }, [contactChannels, addedEmail]);\n\n const emailSchema = yupObject({\n email: strictEmailSchema(t('Please enter a valid email address'))\n .notOneOf(contactChannels.map(x => x.value), t('Email already exists'))\n .defined()\n .nonEmpty(t('Email is required')),\n });\n\n const { register, handleSubmit, formState: { errors }, reset } = useForm({\n resolver: yupResolver(emailSchema)\n });\n\n const onSubmit = async (data: yup.InferType<typeof emailSchema>) => {\n setAddingEmailLoading(true);\n try {\n await user.createContactChannel({ type: 'email', value: data.email, usedForAuth: false });\n setAddedEmail(data.email);\n } finally {\n setAddingEmailLoading(false);\n }\n setAddingEmail(false);\n reset();\n };\n\n return (\n <div>\n <div className='flex flex-col md:flex-row justify-between mb-4 gap-4'>\n <Typography className='font-medium'>{t(\"Emails\")}</Typography>\n {addingEmail ? (\n <form\n onSubmit={(e) => {\n e.preventDefault();\n runAsynchronously(handleSubmit(onSubmit));\n }}\n className='flex flex-col'\n >\n <div className='flex gap-2'>\n <Input\n {...register(\"email\")}\n placeholder={t(\"Enter email\")}\n />\n <Button type=\"submit\" loading={addingEmailLoading}>\n {t(\"Add\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => {\n setAddingEmail(false);\n reset();\n }}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n {errors.email && <FormWarningText text={errors.email.message} />}\n </form>\n ) : (\n <div className='flex md:justify-end'>\n <Button variant='secondary' onClick={() => setAddingEmail(true)}>{t(\"Add an email\")}</Button>\n </div>\n )}\n </div>\n\n {contactChannels.length > 0 ? (\n <div className='border rounded-md'>\n <Table>\n <TableBody>\n {/*eslint-disable-next-line @typescript-eslint/no-unnecessary-condition*/}\n {contactChannels.filter(x => x.type === 'email')\n .sort((a, b) => {\n if (a.isPrimary !== b.isPrimary) return a.isPrimary ? -1 : 1;\n if (a.isVerified !== b.isVerified) return a.isVerified ? -1 : 1;\n return 0;\n })\n .map(x => (\n <TableRow key={x.id}>\n <TableCell>\n <div className='flex flex-col md:flex-row gap-2 md:gap-4'>\n {x.value}\n <div className='flex gap-2'>\n {x.isPrimary ? <Badge>{t(\"Primary\")}</Badge> : null}\n {!x.isVerified ? <Badge variant='destructive'>{t(\"Unverified\")}</Badge> : null}\n {x.usedForAuth ? <Badge variant='outline'>{t(\"Used for sign-in\")}</Badge> : null}\n </div>\n </div>\n </TableCell>\n <TableCell className=\"flex justify-end\">\n <ActionCell items={[\n ...(!x.isVerified ? [{\n item: t(\"Send verification email\"),\n onClick: async () => { await x.sendVerificationEmail(); },\n }] : []),\n ...(!x.isPrimary && x.isVerified ? [{\n item: t(\"Set as primary\"),\n onClick: async () => { await x.update({ isPrimary: true }); },\n }] :\n !x.isPrimary ? [{\n item: t(\"Set as primary\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"Please verify your email first\"),\n }] : []),\n ...(!x.usedForAuth && x.isVerified ? [{\n item: t(\"Use for sign-in\"),\n onClick: async () => { await x.update({ usedForAuth: true }); },\n }] : []),\n ...(x.usedForAuth && !isLastEmail ? [{\n item: t(\"Stop using for sign-in\"),\n onClick: async () => { await x.update({ usedForAuth: false }); },\n }] : x.usedForAuth ? [{\n item: t(\"Stop using for sign-in\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"You can not remove your last sign-in email\"),\n }] : []),\n ...(!isLastEmail || !x.usedForAuth ? [{\n item: t(\"Remove\"),\n onClick: async () => { await x.delete(); },\n danger: true,\n }] : [{\n item: t(\"Remove\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"You can not remove your last sign-in email\"),\n }]),\n ]}/>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction EmailsAndAuthPage() {\n const passwordSection = usePasswordSection();\n const mfaSection = useMfaSection();\n const otpSection = useOtpSection();\n const passkeySection = usePasskeySection();\n\n return (\n <PageLayout>\n <EmailsSection/>\n {passwordSection}\n {passkeySection}\n {otpSection}\n {mfaSection}\n </PageLayout>\n );\n}\n\n\nfunction usePasskeySection() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n const stackApp = useStackApp();\n const project = stackApp.useProject();\n const contactChannels = user.useContactChannels();\n\n\n // passkey is enabled if there is a passkey\n const hasPasskey = user.passkeyAuthEnabled;\n\n const isLastAuth = user.passkeyAuthEnabled && !user.hasPassword && user.oauthProviders.length === 0 && !user.otpAuthEnabled;\n const [showConfirmationModal, setShowConfirmationModal] = useState(false);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const hasValidEmail = contactChannels.filter(x => x.type === 'email' && x.isVerified && x.usedForAuth).length > 0;\n\n if (!project.config.passkeyEnabled) {\n return null;\n }\n\n const handleDeletePasskey = async () => {\n await user.update({ passkeyAuthEnabled: false });\n setShowConfirmationModal(false);\n };\n\n\n const handleAddNewPasskey = async () => {\n await user.registerPasskey();\n };\n\n return (\n <>\n <Section title={t(\"Passkey\")} description={hasPasskey ? t(\"Passkey registered\") : t(\"Register a passkey\")}>\n <div className='flex md:justify-end gap-2'>\n {!hasValidEmail && (\n <Typography variant='secondary' type='label'>{t(\"To enable Passkey sign-in, please add a verified sign-in email.\")}</Typography>\n )}\n {hasValidEmail && hasPasskey && isLastAuth && (\n <Typography variant='secondary' type='label'>{t(\"Passkey sign-in is enabled and cannot be disabled as it is currently the only sign-in method\")}</Typography>\n )}\n {!hasPasskey && hasValidEmail && (\n <div>\n <Button onClick={handleAddNewPasskey} variant='secondary'>{t(\"Add new passkey\")}</Button>\n </div>\n )}\n {hasValidEmail && hasPasskey && !isLastAuth && !showConfirmationModal && (\n <Button\n variant='secondary'\n onClick={() => setShowConfirmationModal(true)}\n >\n {t(\"Delete Passkey\")}\n </Button>\n )}\n {hasValidEmail && hasPasskey && !isLastAuth && showConfirmationModal && (\n <div className='flex flex-col gap-2'>\n <Typography variant='destructive'>\n {t(\"Are you sure you want to disable Passkey sign-in? You will not be able to sign in with your passkey anymore.\")}\n </Typography>\n <div className='flex gap-2'>\n <Button\n variant='destructive'\n onClick={handleDeletePasskey}\n >\n {t(\"Disable\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => setShowConfirmationModal(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </div>\n )}\n </div>\n </Section>\n\n\n </>\n\n );\n}\n\n\nfunction useOtpSection() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n const project = useStackApp().useProject();\n const contactChannels = user.useContactChannels();\n const isLastAuth = user.otpAuthEnabled && !user.hasPassword && user.oauthProviders.length === 0 && !user.passkeyAuthEnabled;\n const [disabling, setDisabling] = useState(false);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const hasValidEmail = contactChannels.filter(x => x.type === 'email' && x.isVerified && x.usedForAuth).length > 0;\n\n if (!project.config.magicLinkEnabled) {\n return null;\n }\n\n const handleDisableOTP = async () => {\n await user.update({ otpAuthEnabled: false });\n setDisabling(false);\n };\n\n return (\n <Section title={t(\"OTP sign-in\")} description={user.otpAuthEnabled ? t(\"OTP/magic link sign-in is currently enabled.\") : t(\"Enable sign-in via magic link or OTP sent to your sign-in emails.\")}>\n <div className='flex md:justify-end'>\n {hasValidEmail ? (\n user.otpAuthEnabled ? (\n !isLastAuth ? (\n !disabling ? (\n <Button\n variant='secondary'\n onClick={() => setDisabling(true)}\n >\n {t(\"Disable OTP\")}\n </Button>\n ) : (\n <div className='flex flex-col gap-2'>\n <Typography variant='destructive'>\n {t(\"Are you sure you want to disable OTP sign-in? You will not be able to sign in with only emails anymore.\")}\n </Typography>\n <div className='flex gap-2'>\n <Button\n variant='destructive'\n onClick={handleDisableOTP}\n >\n {t(\"Disable\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => setDisabling(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </div>\n )\n ) : (\n <Typography variant='secondary' type='label'>{t(\"OTP sign-in is enabled and cannot be disabled as it is currently the only sign-in method\")}</Typography>\n )\n ) : (\n <Button\n variant='secondary'\n onClick={async () => {\n await user.update({ otpAuthEnabled: true });\n }}\n >\n {t(\"Enable OTP\")}\n </Button>\n )\n ) : (\n <Typography variant='secondary' type='label'>{t(\"To enable OTP sign-in, please add a verified sign-in email.\")}</Typography>\n )}\n </div>\n </Section>\n );\n}\n\nfunction SettingsPage() {\n const deleteAccountSection = useDeleteAccountSection();\n const signOutSection = useSignOutSection();\n\n return (\n <PageLayout>\n {deleteAccountSection}\n {signOutSection}\n </PageLayout>\n );\n}\n\nfunction usePasswordSection() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n const contactChannels = user.useContactChannels();\n const [changingPassword, setChangingPassword] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const passwordSchema = yupObject({\n oldPassword: user.hasPassword ? schemaFieldsPasswordSchema.defined().nonEmpty(t('Please enter your old password')) : yupString(),\n newPassword: schemaFieldsPasswordSchema.defined().nonEmpty(t('Please enter your password')).test({\n name: 'is-valid-password',\n test: (value, ctx) => {\n const error = getPasswordError(value);\n if (error) {\n return ctx.createError({ message: error.message });\n } else {\n return true;\n }\n }\n }),\n newPasswordRepeat: yupString().nullable().oneOf([yup.ref('newPassword'), \"\", null], t('Passwords do not match')).defined().nonEmpty(t('Please repeat your password'))\n });\n\n const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = useForm({\n resolver: yupResolver(passwordSchema)\n });\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const hasValidEmail = contactChannels.filter(x => x.type === 'email' && x.usedForAuth).length > 0;\n\n const onSubmit = async (data: yup.InferType<typeof passwordSchema>) => {\n setLoading(true);\n try {\n const { oldPassword, newPassword } = data;\n const error = user.hasPassword\n ? await user.updatePassword({ oldPassword: oldPassword!, newPassword })\n : await user.setPassword({ password: newPassword! });\n if (error) {\n setError('oldPassword', { type: 'manual', message: t('Incorrect password') });\n } else {\n reset();\n setChangingPassword(false);\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('newPassword');\n const registerPasswordRepeat = register('newPasswordRepeat');\n\n return (\n <Section\n title={t(\"Password\")}\n description={user.hasPassword ? t(\"Update your password\") : t(\"Set a password for your account\")}\n >\n <div className='flex flex-col gap-4'>\n {!changingPassword ? (\n hasValidEmail ? (\n <Button\n variant='secondary'\n onClick={() => setChangingPassword(true)}\n >\n {user.hasPassword ? t(\"Update password\") : t(\"Set password\")}\n </Button>\n ) : (\n <Typography variant='secondary' type='label'>{t(\"To set a password, please add a sign-in email.\")}</Typography>\n )\n ) : (\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n {user.hasPassword && (\n <>\n <Label htmlFor=\"old-password\" className=\"mb-1\">{t(\"Old password\")}</Label>\n <Input\n id=\"old-password\"\n type=\"password\"\n autoComplete=\"current-password\"\n {...register(\"oldPassword\")}\n />\n <FormWarningText text={errors.oldPassword?.message?.toString()} />\n </>\n )}\n\n <Label htmlFor=\"new-password\" className=\"mt-4 mb-1\">{t(\"New password\")}</Label>\n <PasswordInput\n id=\"new-password\"\n autoComplete=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPassword?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">{t(\"Repeat new password\")}</Label>\n <PasswordInput\n id=\"repeat-password\"\n autoComplete=\"new-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPasswordRepeat?.message?.toString()} />\n\n <div className=\"mt-6 flex gap-4\">\n <Button type=\"submit\" loading={loading}>\n {user.hasPassword ? t(\"Update Password\") : t(\"Set Password\")}\n </Button>\n <Button\n variant=\"secondary\"\n onClick={() => {\n setChangingPassword(false);\n reset();\n }}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </form>\n )}\n </div>\n </Section>\n );\n}\n\nfunction useMfaSection() {\n const { t } = useTranslation();\n const project = useStackApp().useProject();\n const user = useUser({ or: \"throw\" });\n const [generatedSecret, setGeneratedSecret] = useState<Uint8Array | null>(null);\n const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);\n const [mfaCode, setMfaCode] = useState<string>(\"\");\n const [isMaybeWrong, setIsMaybeWrong] = useState(false);\n const isEnabled = user.isMultiFactorRequired;\n\n const [handleSubmit, isLoading] = useAsyncCallback(async () => {\n await user.update({\n totpMultiFactorSecret: generatedSecret,\n });\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }, [generatedSecret, user]);\n\n useEffect(() => {\n setIsMaybeWrong(false);\n runAsynchronouslyWithAlert(async () => {\n if (generatedSecret && await new TOTPController().verify(mfaCode, generatedSecret)) {\n await handleSubmit();\n }\n setIsMaybeWrong(true);\n });\n }, [mfaCode, generatedSecret, handleSubmit]);\n\n return (\n <Section\n title={t(\"Multi-factor authentication\")}\n description={isEnabled\n ? t(\"Multi-factor authentication is currently enabled.\")\n : t(\"Multi-factor authentication is currently disabled.\")}\n >\n <div className='flex flex-col gap-4'>\n {!isEnabled && generatedSecret && (\n <>\n <Typography>{t(\"Scan this QR code with your authenticator app:\")}</Typography>\n <img width={200} height={200} src={qrCodeUrl ?? throwErr(\"TOTP QR code failed to generate\")} alt={t(\"TOTP multi-factor authentication QR code\")} />\n <Typography>{t(\"Then, enter your six-digit MFA code:\")}</Typography>\n <Input\n value={mfaCode}\n onChange={(e) => {\n setIsMaybeWrong(false);\n setMfaCode(e.target.value);\n }}\n placeholder=\"123456\"\n maxLength={6}\n disabled={isLoading}\n />\n {isMaybeWrong && mfaCode.length === 6 && (\n <Typography variant=\"destructive\">{t(\"Incorrect code. Please try again.\")}</Typography>\n )}\n <div className='flex'>\n <Button\n variant='secondary'\n onClick={() => {\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </>\n )}\n <div className='flex gap-2'>\n {isEnabled ? (\n <Button\n variant='secondary'\n onClick={async () => {\n await user.update({\n totpMultiFactorSecret: null,\n });\n }}\n >\n {t(\"Disable MFA\")}\n </Button>\n ) : !generatedSecret && (\n <Button\n variant='secondary'\n onClick={async () => {\n const secret = generateRandomValues(new Uint8Array(20));\n setQrCodeUrl(await generateTotpQrCode(project, user, secret));\n setGeneratedSecret(secret);\n }}\n >\n {t(\"Enable MFA\")}\n </Button>\n )}\n </div>\n </div>\n </Section>\n );\n}\n\nasync function generateTotpQrCode(project: Project, user: CurrentUser, secret: Uint8Array) {\n const uri = createTOTPKeyURI(project.displayName, user.primaryEmail ?? user.id, secret);\n return await QRCode.toDataURL(uri) as any;\n}\n\nfunction useSignOutSection() {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\" });\n\n return (\n <Section\n title={t(\"Sign out\")}\n description={t(\"End your current session\")}\n >\n <div>\n <Button\n variant='secondary'\n onClick={() => user.signOut()}\n >\n {t(\"Sign out\")}\n </Button>\n </div>\n </Section>\n );\n}\n\nfunction TeamPage(props: { team: Team }) {\n const teamUserProfileSection = useTeamUserProfileSection(props);\n const teamProfileImageSection = useTeamProfileImageSection(props);\n const teamDisplayNameSection = useTeamDisplayNameSection(props);\n const leaveTeamSection = useLeaveTeamSection(props);\n const memberInvitationSection = useMemberInvitationSection(props);\n const memberListSection = useMemberListSection(props);\n\n return (\n <PageLayout>\n {teamUserProfileSection}\n {memberInvitationSection}\n {memberListSection}\n {teamProfileImageSection}\n {teamDisplayNameSection}\n {leaveTeamSection}\n </PageLayout>\n );\n}\n\nfunction useLeaveTeamSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const [leaving, setLeaving] = useState(false);\n\n return (\n <Section\n title={t(\"Leave Team\")}\n description={t(\"leave this team and remove your team profile\")}\n >\n {!leaving ? (\n <div>\n <Button\n variant='secondary'\n onClick={() => setLeaving(true)}\n >\n {t(\"Leave team\")}\n </Button>\n </div>\n ) : (\n <div className='flex flex-col gap-2'>\n <Typography variant='destructive'>\n {t(\"Are you sure you want to leave the team?\")}\n </Typography>\n <div className='flex gap-2'>\n <Button\n variant='destructive'\n onClick={async () => {\n await user.leaveTeam(props.team);\n window.location.reload();\n }}\n >\n {t(\"Leave\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => setLeaving(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </div>\n )}\n </Section>\n );\n}\n\nfunction useTeamProfileImageSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <Section\n title={t(\"Team profile image\")}\n description={t(\"Upload an image for your team\")}\n >\n <ProfileImageEditor\n user={props.team}\n onProfileImageUrlChange={async (profileImageUrl) => {\n await props.team.update({ profileImageUrl });\n }}\n />\n </Section>\n );\n}\n\nfunction useTeamDisplayNameSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <Section\n title={t(\"Team display name\")}\n description={t(\"Change the display name of your team\")}\n >\n <EditableText\n value={props.team.displayName}\n onSave={async (newDisplayName) => await props.team.update({ displayName: newDisplayName })}\n />\n </Section>\n );\n}\n\nfunction useTeamUserProfileSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const profile = user.useTeamProfile(props.team);\n\n return (\n <Section\n title={t(\"Team user name\")}\n description={t(\"Overwrite your user display name in this team\")}\n >\n <EditableText\n value={profile.displayName || ''}\n onSave={async (newDisplayName) => {\n await profile.update({ displayName: newDisplayName });\n }}\n />\n </Section>\n );\n}\n\nfunction useMemberInvitationSection(props: { team: Team }) {\n const { t } = useTranslation();\n\n const invitationSchema = yupObject({\n email: emailSchema.defined().nonEmpty(t('Please enter an email address')),\n });\n\n const user = useUser({ or: 'redirect' });\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!inviteMemberPermission) {\n return null;\n }\n\n const { register, handleSubmit, formState: { errors }, watch } = useForm({\n resolver: yupResolver(invitationSchema)\n });\n const [loading, setLoading] = useState(false);\n const [invitedEmail, setInvitedEmail] = useState<string | null>(null);\n\n const onSubmit = async (data: yup.InferType<typeof invitationSchema>) => {\n setLoading(true);\n\n try {\n await props.team.inviteUser({ email: data.email });\n setInvitedEmail(data.email);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setInvitedEmail(null);\n }, [watch('email')]);\n\n return (\n <Section\n title={t(\"Invite member\")}\n description={t(\"Invite a user to your team through email\")}\n >\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n className='w-full'\n >\n <div className=\"flex flex-col gap-4 sm:flex-row w-full\">\n <Input\n placeholder={t(\"Email\")}\n {...register(\"email\")}\n />\n <Button type=\"submit\" loading={loading}>{t(\"Invite User\")}</Button>\n </div>\n <FormWarningText text={errors.email?.message?.toString()} />\n {invitedEmail && <Typography type='label' variant='secondary'>Invited {invitedEmail}</Typography>}\n </form>\n </Section>\n );\n}\n\n\nfunction useMemberListSection(props: { team: Team }) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const readMemberPermission = user.usePermission(props.team, '$read_members');\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!readMemberPermission && !inviteMemberPermission) {\n return null;\n }\n\n const users = props.team.useUsers();\n\n if (!readMemberPermission) {\n return null;\n }\n\n return (\n <div>\n <Typography className='font-medium mb-2'>{t(\"Members\")}</Typography>\n <div className='border rounded-md'>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[100px]\">{t(\"User\")}</TableHead>\n <TableHead className=\"w-[200px]\">{t(\"Name\")}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {users.map(({ id, teamProfile }, i) => (\n <TableRow key={id}>\n <TableCell>\n <UserAvatar user={teamProfile}/>\n </TableCell>\n <TableCell>\n <Typography>{teamProfile.displayName}</Typography>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n </div>\n );\n}\n\nexport function TeamCreation() {\n const { t } = useTranslation();\n\n const teamCreationSchema = yupObject({\n displayName: yupString().defined().nonEmpty(t(\"Please enter a team name\")),\n });\n\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(teamCreationSchema)\n });\n const app = useStackApp();\n const project = app.useProject();\n const user = useUser({ or: 'redirect' });\n const router = useRouter();\n const [loading, setLoading] = useState(false);\n\n if (!project.config.clientTeamCreationEnabled) {\n return <MessageCard title={t(\"Team creation is not enabled\")} />;\n }\n\n const onSubmit = async (data: yup.InferType<typeof teamCreationSchema>) => {\n setLoading(true);\n\n let team;\n try {\n team = await user.createTeam({ displayName: data.displayName });\n } finally {\n setLoading(false);\n }\n\n router.push(`#team-${team.id}`);\n };\n\n return (\n <PageLayout>\n <Section title={t(\"Create a Team\")} description={t(\"Enter a display name for your new team\")}>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n className='flex gap-2 flex-col sm:flex-row'\n >\n <div className='flex flex-col flex-1'>\n <Input\n id=\"displayName\"\n type=\"text\"\n {...register(\"displayName\")}\n />\n <FormWarningText text={errors.displayName?.message?.toString()} />\n </div>\n <Button type=\"submit\" loading={loading}>{t(\"Create\")}</Button>\n </form>\n </Section>\n </PageLayout>\n );\n}\n\nexport function useDeleteAccountSection() {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const app = useStackApp();\n const project = app.useProject();\n const [deleting, setDeleting] = useState(false);\n if (!project.config.clientUserDeletionEnabled) {\n return null;\n }\n\n return (\n <Section\n title={t(\"Delete Account\")}\n description={t(\"Permanently remove your account and all associated data\")}\n >\n <div className='stack-scope flex flex-col items-stretch'>\n <Accordion type=\"single\" collapsible className=\"w-full\">\n <AccordionItem value=\"item-1\">\n <AccordionTrigger>{t(\"Danger zone\")}</AccordionTrigger>\n <AccordionContent>\n {!deleting ? (\n <div>\n <Button\n variant='destructive'\n onClick={() => setDeleting(true)}\n >\n {t(\"Delete account\")}\n </Button>\n </div>\n ) : (\n <div className='flex flex-col gap-2'>\n <Typography variant='destructive'>\n {t(\"Are you sure you want to delete your account? This action is IRREVERSIBLE and will delete ALL associated data.\")}\n </Typography>\n <div className='flex gap-2'>\n <Button\n variant='destructive'\n onClick={async () => {\n await user.delete();\n await app.redirectToHome();\n }}\n >\n {t(\"Delete Account\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => setDeleting(false)}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n </div>\n )}\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n </div>\n </Section>\n );\n}\n\nexport function EditableText(props: { value: string, onSave?: (value: string) => void | Promise<void> }) {\n const [editing, setEditing] = useState(false);\n const [editingValue, setEditingValue] = useState(props.value);\n const { t } = useTranslation();\n\n return (\n <div className='flex items-center gap-2'>\n {editing ? (\n <>\n <Input\n value={editingValue}\n onChange={(e) => setEditingValue(e.target.value)}\n />\n <Button\n size='sm'\n onClick={async () => {\n await props.onSave?.(editingValue);\n setEditing(false);\n }}\n >\n {t(\"Save\")}\n </Button>\n <Button\n size='sm'\n variant='secondary'\n onClick={() => {\n setEditingValue(props.value);\n setEditing(false);\n }}>\n {t(\"Cancel\")}\n </Button>\n </>\n ) : (\n <>\n <Typography>{props.value}</Typography>\n <Button onClick={() => setEditing(true)} size='icon' variant='ghost'>\n <Edit className=\"w-4 h-4\"/>\n </Button>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["emailSchema"]}
@@ -3,7 +3,7 @@
3
3
 
4
4
  // src/components-page/forgot-password.tsx
5
5
  import { yupResolver } from "@hookform/resolvers/yup";
6
- import { yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
6
+ import { strictEmailSchema, yupObject } from "@stackframe/stack-shared/dist/schema-fields";
7
7
  import { runAsynchronouslyWithAlert } from "@stackframe/stack-shared/dist/utils/promises";
8
8
  import { Button, Input, Label, StyledLink, Typography, cn } from "@stackframe/stack-ui";
9
9
  import { useState } from "react";
@@ -17,7 +17,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
17
17
  function ForgotPasswordForm({ onSent }) {
18
18
  const { t } = useTranslation();
19
19
  const schema = yupObject({
20
- email: yupString().email(t("Please enter a valid email")).defined().nonEmpty(t("Please enter your email"))
20
+ email: strictEmailSchema(t("Please enter a valid email")).defined().nonEmpty(t("Please enter your email"))
21
21
  });
22
22
  const { register, handleSubmit, formState: { errors }, clearErrors } = useForm({
23
23
  resolver: yupResolver(schema)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components-page/forgot-password.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { yupObject, yupString } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, Label, StyledLink, Typography, cn } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp, useUser } from \"..\";\nimport { FormWarningText } from \"../components/elements/form-warning\";\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { PredefinedMessageCard } from \"../components/message-cards/predefined-message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nexport function ForgotPasswordForm({ onSent }: { onSent?: () => void }) {\n const { t } = useTranslation();\n\n const schema = yupObject({\n email: yupString().email(t(\"Please enter a valid email\")).defined().nonEmpty(t(\"Please enter your email\"))\n });\n\n const { register, handleSubmit, formState: { errors }, clearErrors } = useForm({\n resolver: yupResolver(schema)\n });\n const stackApp = useStackApp();\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof schema>) => {\n setLoading(true);\n try {\n const { email } = data;\n await stackApp.sendForgotPasswordEmail(email);\n onSent?.();\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"email\" className=\"mb-1\">{t(\"Your Email\")}</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register('email')}\n onChange={() => clearErrors('email')}\n />\n <FormWarningText text={errors.email?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n {t(\"Send Email\")}\n </Button>\n </form>\n );\n}\n\n\nexport function ForgotPassword(props: { fullPage?: boolean }) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const user = useUser();\n const [sent, setSent] = useState(false);\n\n if (user) {\n return <PredefinedMessageCard type='signedIn' fullPage={!!props.fullPage} />;\n }\n\n if (sent) {\n return <PredefinedMessageCard type='emailSent' fullPage={!!props.fullPage} />;\n }\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div className={cn(\n \"stack-scope max-w-[380px] flex-basis-[380px]\",\n props.fullPage ? \"p-4\" : \"p-0\"\n )}>\n <div className=\"text-center\">\n <Typography type='h2'>{t(\"Reset Your Password\")}</Typography>\n <Typography>\n {t(\"Don't need to reset?\")}{\" \"}\n <StyledLink href={stackApp.urls['signUp']}>\n {t(\"Sign in\")}\n </StyledLink>\n </Typography>\n </div>\n <div className=\"mt-6\">\n <ForgotPasswordForm onSent={() => setSent(true)} />\n </div>\n </div>\n </MaybeFullPage>\n );\n};\n"],"mappings":";;;AAEA,SAAS,mBAAmB;AAC5B,SAAS,WAAW,iBAAiB;AACrC,SAAS,kCAAkC;AAC3C,SAAS,QAAQ,OAAO,OAAO,YAAY,YAAY,UAAU;AACjE,SAAS,gBAAgB;AACzB,SAAS,eAAe;AAExB,SAAS,aAAa,eAAe;AACrC,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AA2B3B,SAKE,KALF;AAzBG,SAAS,mBAAmB,EAAE,OAAO,GAA4B;AACtE,QAAM,EAAE,EAAE,IAAI,eAAe;AAE7B,QAAM,SAAS,UAAU;AAAA,IACvB,OAAO,UAAU,EAAE,MAAM,EAAE,4BAA4B,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,yBAAyB,CAAC;AAAA,EAC3G,CAAC;AAED,QAAM,EAAE,UAAU,cAAc,WAAW,EAAE,OAAO,GAAG,YAAY,IAAI,QAAQ;AAAA,IAC7E,UAAU,YAAY,MAAM;AAAA,EAC9B,CAAC;AACD,QAAM,WAAW,YAAY;AAC7B,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,WAAW,OAAO,SAAuC;AAC7D,eAAW,IAAI;AACf,QAAI;AACF,YAAM,EAAE,MAAM,IAAI;AAClB,YAAM,SAAS,wBAAwB,KAAK;AAC9C,eAAS;AAAA,IACT,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,UAAU,OAAK,2BAA2B,aAAa,QAAQ,EAAE,CAAC,CAAC;AAAA,MACnE,YAAU;AAAA,MAEV;AAAA,4BAAC,SAAM,SAAQ,SAAQ,WAAU,QAAQ,YAAE,YAAY,GAAE;AAAA,QACzD;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACJ,GAAG,SAAS,OAAO;AAAA,YACpB,UAAU,MAAM,YAAY,OAAO;AAAA;AAAA,QACrC;AAAA,QACA,oBAAC,mBAAgB,MAAM,OAAO,OAAO,SAAS,SAAS,GAAG;AAAA,QAE1D,oBAAC,UAAO,MAAK,UAAS,WAAU,QAAO,SACpC,YAAE,YAAY,GACjB;AAAA;AAAA;AAAA,EACF;AAEJ;AAGO,SAAS,eAAe,OAA+B;AAC5D,QAAM,EAAE,EAAE,IAAI,eAAe;AAC7B,QAAM,WAAW,YAAY;AAC7B,QAAM,OAAO,QAAQ;AACrB,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AAEtC,MAAI,MAAM;AACR,WAAO,oBAAC,yBAAsB,MAAK,YAAW,UAAU,CAAC,CAAC,MAAM,UAAU;AAAA,EAC5E;AAEA,MAAI,MAAM;AACR,WAAO,oBAAC,yBAAsB,MAAK,aAAY,UAAU,CAAC,CAAC,MAAM,UAAU;AAAA,EAC7E;AAEA,SACE,oBAAC,iBAAc,UAAU,CAAC,CAAC,MAAM,UAC/B,+BAAC,SAAI,WAAW;AAAA,IACd;AAAA,IACA,MAAM,WAAW,QAAQ;AAAA,EAC3B,GACE;AAAA,yBAAC,SAAI,WAAU,eACb;AAAA,0BAAC,cAAW,MAAK,MAAM,YAAE,qBAAqB,GAAE;AAAA,MAChD,qBAAC,cACE;AAAA,UAAE,sBAAsB;AAAA,QAAG;AAAA,QAC5B,oBAAC,cAAW,MAAM,SAAS,KAAK,QAAQ,GACrC,YAAE,SAAS,GACd;AAAA,SACF;AAAA,OACF;AAAA,IACA,oBAAC,SAAI,WAAU,QACb,8BAAC,sBAAmB,QAAQ,MAAM,QAAQ,IAAI,GAAG,GACnD;AAAA,KACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components-page/forgot-password.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, Label, StyledLink, Typography, cn } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp, useUser } from \"..\";\nimport { FormWarningText } from \"../components/elements/form-warning\";\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { PredefinedMessageCard } from \"../components/message-cards/predefined-message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nexport function ForgotPasswordForm({ onSent }: { onSent?: () => void }) {\n const { t } = useTranslation();\n\n const schema = yupObject({\n email: strictEmailSchema(t(\"Please enter a valid email\")).defined().nonEmpty(t(\"Please enter your email\"))\n });\n\n const { register, handleSubmit, formState: { errors }, clearErrors } = useForm({\n resolver: yupResolver(schema)\n });\n const stackApp = useStackApp();\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof schema>) => {\n setLoading(true);\n try {\n const { email } = data;\n await stackApp.sendForgotPasswordEmail(email);\n onSent?.();\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"email\" className=\"mb-1\">{t(\"Your Email\")}</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register('email')}\n onChange={() => clearErrors('email')}\n />\n <FormWarningText text={errors.email?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n {t(\"Send Email\")}\n </Button>\n </form>\n );\n}\n\n\nexport function ForgotPassword(props: { fullPage?: boolean }) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const user = useUser();\n const [sent, setSent] = useState(false);\n\n if (user) {\n return <PredefinedMessageCard type='signedIn' fullPage={!!props.fullPage} />;\n }\n\n if (sent) {\n return <PredefinedMessageCard type='emailSent' fullPage={!!props.fullPage} />;\n }\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div className={cn(\n \"stack-scope max-w-[380px] flex-basis-[380px]\",\n props.fullPage ? \"p-4\" : \"p-0\"\n )}>\n <div className=\"text-center\">\n <Typography type='h2'>{t(\"Reset Your Password\")}</Typography>\n <Typography>\n {t(\"Don't need to reset?\")}{\" \"}\n <StyledLink href={stackApp.urls['signUp']}>\n {t(\"Sign in\")}\n </StyledLink>\n </Typography>\n </div>\n <div className=\"mt-6\">\n <ForgotPasswordForm onSent={() => setSent(true)} />\n </div>\n </div>\n </MaybeFullPage>\n );\n};\n"],"mappings":";;;AAEA,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB,iBAAiB;AAC7C,SAAS,kCAAkC;AAC3C,SAAS,QAAQ,OAAO,OAAO,YAAY,YAAY,UAAU;AACjE,SAAS,gBAAgB;AACzB,SAAS,eAAe;AAExB,SAAS,aAAa,eAAe;AACrC,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AA2B3B,SAKE,KALF;AAzBG,SAAS,mBAAmB,EAAE,OAAO,GAA4B;AACtE,QAAM,EAAE,EAAE,IAAI,eAAe;AAE7B,QAAM,SAAS,UAAU;AAAA,IACvB,OAAO,kBAAkB,EAAE,4BAA4B,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,yBAAyB,CAAC;AAAA,EAC3G,CAAC;AAED,QAAM,EAAE,UAAU,cAAc,WAAW,EAAE,OAAO,GAAG,YAAY,IAAI,QAAQ;AAAA,IAC7E,UAAU,YAAY,MAAM;AAAA,EAC9B,CAAC;AACD,QAAM,WAAW,YAAY;AAC7B,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,WAAW,OAAO,SAAuC;AAC7D,eAAW,IAAI;AACf,QAAI;AACF,YAAM,EAAE,MAAM,IAAI;AAClB,YAAM,SAAS,wBAAwB,KAAK;AAC9C,eAAS;AAAA,IACT,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,UAAU,OAAK,2BAA2B,aAAa,QAAQ,EAAE,CAAC,CAAC;AAAA,MACnE,YAAU;AAAA,MAEV;AAAA,4BAAC,SAAM,SAAQ,SAAQ,WAAU,QAAQ,YAAE,YAAY,GAAE;AAAA,QACzD;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACJ,GAAG,SAAS,OAAO;AAAA,YACpB,UAAU,MAAM,YAAY,OAAO;AAAA;AAAA,QACrC;AAAA,QACA,oBAAC,mBAAgB,MAAM,OAAO,OAAO,SAAS,SAAS,GAAG;AAAA,QAE1D,oBAAC,UAAO,MAAK,UAAS,WAAU,QAAO,SACpC,YAAE,YAAY,GACjB;AAAA;AAAA;AAAA,EACF;AAEJ;AAGO,SAAS,eAAe,OAA+B;AAC5D,QAAM,EAAE,EAAE,IAAI,eAAe;AAC7B,QAAM,WAAW,YAAY;AAC7B,QAAM,OAAO,QAAQ;AACrB,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AAEtC,MAAI,MAAM;AACR,WAAO,oBAAC,yBAAsB,MAAK,YAAW,UAAU,CAAC,CAAC,MAAM,UAAU;AAAA,EAC5E;AAEA,MAAI,MAAM;AACR,WAAO,oBAAC,yBAAsB,MAAK,aAAY,UAAU,CAAC,CAAC,MAAM,UAAU;AAAA,EAC7E;AAEA,SACE,oBAAC,iBAAc,UAAU,CAAC,CAAC,MAAM,UAC/B,+BAAC,SAAI,WAAW;AAAA,IACd;AAAA,IACA,MAAM,WAAW,QAAQ;AAAA,EAC3B,GACE;AAAA,yBAAC,SAAI,WAAU,eACb;AAAA,0BAAC,cAAW,MAAK,MAAM,YAAE,qBAAqB,GAAE;AAAA,MAChD,qBAAC,cACE;AAAA,UAAE,sBAAsB;AAAA,QAAG;AAAA,QAC5B,oBAAC,cAAW,MAAM,SAAS,KAAK,QAAQ,GACrC,YAAE,SAAS,GACd;AAAA,SACF;AAAA,OACF;AAAA,IACA,oBAAC,SAAI,WAAU,QACb,8BAAC,sBAAmB,QAAQ,MAAM,QAAQ,IAAI,GAAG,GACnD;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -5,7 +5,7 @@
5
5
  import { yupResolver } from "@hookform/resolvers/yup";
6
6
  import { KnownErrors } from "@stackframe/stack-shared";
7
7
  import { getPasswordError } from "@stackframe/stack-shared/dist/helpers/password";
8
- import { yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
8
+ import { passwordSchema, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
9
9
  import { cacheFunction } from "@stackframe/stack-shared/dist/utils/caches";
10
10
  import { runAsynchronouslyWithAlert } from "@stackframe/stack-shared/dist/utils/promises";
11
11
  import { Button, Label, PasswordInput, Typography, cn } from "@stackframe/stack-ui";
@@ -22,7 +22,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
22
22
  function PasswordResetForm(props) {
23
23
  const { t } = useTranslation();
24
24
  const schema = yupObject({
25
- password: yupString().defined().nonEmpty(t("Please enter your password")).test({
25
+ password: passwordSchema.defined(t("Please enter your password")).nonEmpty(t("Please enter your password")).test({
26
26
  name: "is-valid-password",
27
27
  test: (value, ctx) => {
28
28
  const error = getPasswordError(value);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components-page/password-reset.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport { getPasswordError } from \"@stackframe/stack-shared/dist/helpers/password\";\nimport { yupObject, yupString } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { cacheFunction } from \"@stackframe/stack-shared/dist/utils/caches\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Label, PasswordInput, Typography, cn } from \"@stackframe/stack-ui\";\nimport React, { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { StackClientApp, useStackApp } from \"..\";\nimport { FormWarningText } from \"../components/elements/form-warning\";\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { MessageCard } from \"../components/message-cards/message-card\";\nimport { PredefinedMessageCard } from \"../components/message-cards/predefined-message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nexport default function PasswordResetForm(props: {\n code: string,\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n\n const schema = yupObject({\n password: yupString().defined().nonEmpty(t(\"Please enter your password\")).test({\n name: 'is-valid-password',\n test: (value, ctx) => {\n const error = getPasswordError(value);\n if (error) {\n return ctx.createError({ message: error.message });\n } else {\n return true;\n }\n }\n }),\n passwordRepeat: yupString().nullable().oneOf([yup.ref('password'), null], t(\"Passwords do not match\")).defined().nonEmpty(t(\"Please repeat your password\"))\n });\n\n const { register, handleSubmit, formState: { errors }, clearErrors } = useForm({\n resolver: yupResolver(schema)\n });\n const stackApp = useStackApp();\n const [finished, setFinished] = useState(false);\n const [resetError, setResetError] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof schema>) => {\n setLoading(true);\n try {\n const { password } = data;\n const result = await stackApp.resetPassword({ password, code: props.code });\n if (result.status === 'error') {\n setResetError(true);\n return;\n }\n\n setFinished(true);\n } finally {\n setLoading(false);\n }\n };\n\n if (finished) {\n return <PredefinedMessageCard type='passwordReset' fullPage={!!props.fullPage} />;\n }\n\n if (resetError) {\n return (\n <MessageCard title={t(\"Failed to reset password\")} fullPage={!!props.fullPage}>\n {t(\"Failed to reset password. Please request a new password reset link\")}\n </MessageCard>\n );\n }\n\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div className={cn(\n \"flex flex-col items-stretch max-w-[380px] flex-basis-[380px]\",\n props.fullPage ? \"p-4\" : \"p-0\"\n )}>\n <div className=\"text-center mb-6\">\n <Typography type='h2'>{t(\"Reset Your Password\")}</Typography>\n </div>\n\n <form\n className=\"flex flex-col items-stretch\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"password\" className=\"mb-1\">{t(\"New Password\")}</Label>\n <PasswordInput\n id=\"password\"\n autoComplete=\"new-password\"\n {...register('password')}\n onChange={() => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n }}\n />\n <FormWarningText text={errors.password?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">{t(\"Repeat New Password\")}</Label>\n <PasswordInput\n id=\"repeat-password\"\n autoComplete=\"new-password\"\n {...register('passwordRepeat')}\n onChange={() => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n }}\n />\n <FormWarningText text={errors.passwordRepeat?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n {t(\"Reset Password\")}\n </Button>\n </form>\n </div>\n </MaybeFullPage>\n );\n}\n\n\nconst cachedVerifyPasswordResetCode = cacheFunction(async (stackApp: StackClientApp<true>, code: string) => {\n return await stackApp.verifyPasswordResetCode(code);\n});\n\nexport function PasswordReset({\n searchParams,\n fullPage = false,\n}: {\n searchParams: Record<string, string>,\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n\n const invalidJsx = (\n <MessageCard title={t(\"Invalid Password Reset Link\")} fullPage={fullPage}>\n <Typography>{t(\"Please double check if you have the correct password reset link.\")}</Typography>\n </MessageCard>\n );\n\n const expiredJsx = (\n <MessageCard title={t(\"Expired Password Reset Link\")} fullPage={fullPage}>\n <Typography>{t(\"Your password reset link has expired. Please request a new password reset link from the login page.\")}</Typography>\n </MessageCard>\n );\n\n const usedJsx = (\n <MessageCard title={t(\"Used Password Reset Link\")} fullPage={fullPage}>\n <Typography>{t(\"This password reset link has already been used. If you need to reset your password again, please request a new password reset link from the login page.\")}</Typography>\n </MessageCard>\n );\n\n const code = searchParams.code;\n if (!code) {\n return invalidJsx;\n }\n\n const result = React.use(cachedVerifyPasswordResetCode(stackApp, code));\n\n if (result.status === 'error') {\n if (result.error instanceof KnownErrors.VerificationCodeNotFound) {\n return invalidJsx;\n } else if (result.error instanceof KnownErrors.VerificationCodeExpired) {\n return expiredJsx;\n } else if (result.error instanceof KnownErrors.VerificationCodeAlreadyUsed) {\n return usedJsx;\n } else {\n throw result.error;\n }\n }\n\n return <PasswordResetForm code={code} fullPage={fullPage} />;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components-page/password-reset.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport { getPasswordError } from \"@stackframe/stack-shared/dist/helpers/password\";\nimport { passwordSchema, yupObject, yupString } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { cacheFunction } from \"@stackframe/stack-shared/dist/utils/caches\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Label, PasswordInput, Typography, cn } from \"@stackframe/stack-ui\";\nimport React, { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { StackClientApp, useStackApp } from \"..\";\nimport { FormWarningText } from \"../components/elements/form-warning\";\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { MessageCard } from \"../components/message-cards/message-card\";\nimport { PredefinedMessageCard } from \"../components/message-cards/predefined-message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nexport default function PasswordResetForm(props: {\n code: string,\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n\n const schema = yupObject({\n password: passwordSchema.defined(t(\"Please enter your password\")).nonEmpty(t(\"Please enter your password\")).test({\n name: 'is-valid-password',\n test: (value, ctx) => {\n const error = getPasswordError(value);\n if (error) {\n return ctx.createError({ message: error.message });\n } else {\n return true;\n }\n }\n }),\n passwordRepeat: yupString().nullable().oneOf([yup.ref('password'), null], t(\"Passwords do not match\")).defined().nonEmpty(t(\"Please repeat your password\"))\n });\n\n const { register, handleSubmit, formState: { errors }, clearErrors } = useForm({\n resolver: yupResolver(schema)\n });\n const stackApp = useStackApp();\n const [finished, setFinished] = useState(false);\n const [resetError, setResetError] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof schema>) => {\n setLoading(true);\n try {\n const { password } = data;\n const result = await stackApp.resetPassword({ password, code: props.code });\n if (result.status === 'error') {\n setResetError(true);\n return;\n }\n\n setFinished(true);\n } finally {\n setLoading(false);\n }\n };\n\n if (finished) {\n return <PredefinedMessageCard type='passwordReset' fullPage={!!props.fullPage} />;\n }\n\n if (resetError) {\n return (\n <MessageCard title={t(\"Failed to reset password\")} fullPage={!!props.fullPage}>\n {t(\"Failed to reset password. Please request a new password reset link\")}\n </MessageCard>\n );\n }\n\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div className={cn(\n \"flex flex-col items-stretch max-w-[380px] flex-basis-[380px]\",\n props.fullPage ? \"p-4\" : \"p-0\"\n )}>\n <div className=\"text-center mb-6\">\n <Typography type='h2'>{t(\"Reset Your Password\")}</Typography>\n </div>\n\n <form\n className=\"flex flex-col items-stretch\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"password\" className=\"mb-1\">{t(\"New Password\")}</Label>\n <PasswordInput\n id=\"password\"\n autoComplete=\"new-password\"\n {...register('password')}\n onChange={() => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n }}\n />\n <FormWarningText text={errors.password?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">{t(\"Repeat New Password\")}</Label>\n <PasswordInput\n id=\"repeat-password\"\n autoComplete=\"new-password\"\n {...register('passwordRepeat')}\n onChange={() => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n }}\n />\n <FormWarningText text={errors.passwordRepeat?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n {t(\"Reset Password\")}\n </Button>\n </form>\n </div>\n </MaybeFullPage>\n );\n}\n\n\nconst cachedVerifyPasswordResetCode = cacheFunction(async (stackApp: StackClientApp<true>, code: string) => {\n return await stackApp.verifyPasswordResetCode(code);\n});\n\nexport function PasswordReset({\n searchParams,\n fullPage = false,\n}: {\n searchParams: Record<string, string>,\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n\n const invalidJsx = (\n <MessageCard title={t(\"Invalid Password Reset Link\")} fullPage={fullPage}>\n <Typography>{t(\"Please double check if you have the correct password reset link.\")}</Typography>\n </MessageCard>\n );\n\n const expiredJsx = (\n <MessageCard title={t(\"Expired Password Reset Link\")} fullPage={fullPage}>\n <Typography>{t(\"Your password reset link has expired. Please request a new password reset link from the login page.\")}</Typography>\n </MessageCard>\n );\n\n const usedJsx = (\n <MessageCard title={t(\"Used Password Reset Link\")} fullPage={fullPage}>\n <Typography>{t(\"This password reset link has already been used. If you need to reset your password again, please request a new password reset link from the login page.\")}</Typography>\n </MessageCard>\n );\n\n const code = searchParams.code;\n if (!code) {\n return invalidJsx;\n }\n\n const result = React.use(cachedVerifyPasswordResetCode(stackApp, code));\n\n if (result.status === 'error') {\n if (result.error instanceof KnownErrors.VerificationCodeNotFound) {\n return invalidJsx;\n } else if (result.error instanceof KnownErrors.VerificationCodeExpired) {\n return expiredJsx;\n } else if (result.error instanceof KnownErrors.VerificationCodeAlreadyUsed) {\n return usedJsx;\n } else {\n throw result.error;\n }\n }\n\n return <PasswordResetForm code={code} fullPage={fullPage} />;\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  // src/lib/auth.ts
2
2
  import { KnownError } from "@stackframe/stack-shared";
3
- import { StackAssertionError, captureError, throwErr } from "@stackframe/stack-shared/dist/utils/errors";
3
+ import { StackAssertionError, throwErr } from "@stackframe/stack-shared/dist/utils/errors";
4
4
  import { neverResolve } from "@stackframe/stack-shared/dist/utils/promises";
5
5
  import { Result } from "@stackframe/stack-shared/dist/utils/results";
6
6
  import { deindent } from "@stackframe/stack-shared/dist/utils/strings";
@@ -41,14 +41,14 @@ function consumeOAuthCallbackQueryParams() {
41
41
  const originalUrl = new URL(window.location.href);
42
42
  for (const param of requiredParams) {
43
43
  if (!originalUrl.searchParams.has(param)) {
44
- captureError("consumeOAuthCallbackQueryParams", new Error(`Missing required query parameter on OAuth callback: ${param}`));
44
+ console.warn(new Error(`Missing required query parameter on OAuth callback: ${param}. Maybe you opened or reloaded the oauth-callback page from your history?`));
45
45
  return null;
46
46
  }
47
47
  }
48
48
  const expectedState = originalUrl.searchParams.get("state") ?? throwErr("This should never happen; isn't state required above?");
49
49
  const cookieResult = consumeVerifierAndStateCookie(expectedState);
50
50
  if (!cookieResult) {
51
- captureError("consumeOAuthCallbackQueryParams", new Error(deindent`
51
+ console.warn(deindent`
52
52
  Stack found an outer OAuth callback state in the query parameters, but not in cookies.
53
53
 
54
54
  This could have multiple reasons:
@@ -56,7 +56,10 @@ function consumeOAuthCallbackQueryParams() {
56
56
  - The user's browser deleted the cookie, either manually or because of a very strict cookie policy.
57
57
  - The cookie was already consumed by this page, and the user already logged in.
58
58
  - You are using another OAuth client library with the same callback URL as Stack.
59
- `));
59
+ - The user opened the OAuth callback page from their history.
60
+
61
+ Either way, it is probably safe to ignore this warning unless you are debugging an OAuth issue.
62
+ `);
60
63
  return null;
61
64
  }
62
65
  const newUrl = new URL(originalUrl);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/auth.ts"],"sourcesContent":["import { KnownError, StackClientInterface } from \"@stackframe/stack-shared\";\nimport { InternalSession } from \"@stackframe/stack-shared/dist/sessions\";\nimport { StackAssertionError, captureError, throwErr } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { neverResolve } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport { deindent } from \"@stackframe/stack-shared/dist/utils/strings\";\nimport { constructRedirectUrl } from \"../utils/url\";\nimport { consumeVerifierAndStateCookie, saveVerifierAndState } from \"./cookie\";\n\nexport async function signInWithOAuth(\n iface: StackClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n }\n) {\n const { codeChallenge, state } = await saveVerifierAndState();\n const location = await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl),\n codeChallenge,\n state,\n type: \"authenticate\",\n providerScope: options.providerScope,\n });\n window.location.assign(location);\n await neverResolve();\n}\n\nexport async function addNewOAuthProviderOrScope(\n iface: StackClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n },\n session: InternalSession,\n) {\n const { codeChallenge, state } = await saveVerifierAndState();\n const location = await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl),\n afterCallbackRedirectUrl: constructRedirectUrl(window.location.href),\n codeChallenge,\n state,\n type: \"link\",\n session,\n providerScope: options.providerScope,\n });\n window.location.assign(location);\n await neverResolve();\n}\n\n/**\n * Checks if the current URL has the query parameters for an OAuth callback, and if so, removes them.\n *\n * Must be synchronous for the logic in callOAuthCallback to work without race conditions.\n */\nfunction consumeOAuthCallbackQueryParams() {\n const requiredParams = [\"code\", \"state\"];\n const originalUrl = new URL(window.location.href);\n for (const param of requiredParams) {\n if (!originalUrl.searchParams.has(param)) {\n captureError(\"consumeOAuthCallbackQueryParams\", new Error(`Missing required query parameter on OAuth callback: ${param}`));\n return null;\n }\n }\n\n const expectedState = originalUrl.searchParams.get(\"state\") ?? throwErr(\"This should never happen; isn't state required above?\");\n const cookieResult = consumeVerifierAndStateCookie(expectedState);\n\n if (!cookieResult) {\n // If the state can't be found in the cookies, then the callback wasn't meant for us.\n // Maybe the website uses another OAuth library?\n captureError(\"consumeOAuthCallbackQueryParams\", new Error(deindent`\n Stack found an outer OAuth callback state in the query parameters, but not in cookies.\n \n This could have multiple reasons:\n - The cookie expired, because the OAuth flow took too long.\n - The user's browser deleted the cookie, either manually or because of a very strict cookie policy.\n - The cookie was already consumed by this page, and the user already logged in.\n - You are using another OAuth client library with the same callback URL as Stack.\n `));\n return null;\n }\n\n\n const newUrl = new URL(originalUrl);\n for (const param of requiredParams) {\n newUrl.searchParams.delete(param);\n }\n\n // let's get rid of the authorization code in the history as we\n // don't redirect to `redirectUrl` if there's a validation error\n // (as the redirectUrl might be malicious!).\n //\n // We use history.replaceState instead of location.assign(...) to\n // prevent an unnecessary reload\n window.history.replaceState({}, \"\", newUrl.toString());\n\n return {\n originalUrl,\n codeVerifier: cookieResult.codeVerifier,\n state: expectedState,\n };\n}\n\nexport async function callOAuthCallback(\n iface: StackClientInterface,\n redirectUrl: string,\n) {\n // note: this part of the function (until the return) needs\n // to be synchronous, to prevent race conditions when\n // callOAuthCallback is called multiple times in parallel\n const consumed = consumeOAuthCallbackQueryParams();\n if (!consumed) return Result.ok(undefined);\n\n // the rest can be asynchronous (we now know that we are the\n // intended recipient of the callback, and the only instance\n // of callOAuthCallback that's running)\n try {\n return Result.ok(await iface.callOAuthCallback({\n oauthParams: consumed.originalUrl.searchParams,\n redirectUri: constructRedirectUrl(redirectUrl),\n codeVerifier: consumed.codeVerifier,\n state: consumed.state,\n }));\n } catch (e) {\n if (e instanceof KnownError) {\n throw e;\n }\n throw new StackAssertionError(\"Error signing in during OAuth callback. Please try again.\", { cause: e });\n }\n}\n"],"mappings":";AAAA,SAAS,kBAAwC;AAEjD,SAAS,qBAAqB,cAAc,gBAAgB;AAC5D,SAAS,oBAAoB;AAC7B,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,4BAA4B;AACrC,SAAS,+BAA+B,4BAA4B;AAEpE,eAAsB,gBACpB,OACA,SAMA;AACA,QAAM,EAAE,eAAe,MAAM,IAAI,MAAM,qBAAqB;AAC5D,QAAM,WAAW,MAAM,MAAM,YAAY;AAAA,IACvC,UAAU,QAAQ;AAAA,IAClB,aAAa,qBAAqB,QAAQ,WAAW;AAAA,IACrD,kBAAkB,qBAAqB,QAAQ,gBAAgB;AAAA,IAC/D;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,eAAe,QAAQ;AAAA,EACzB,CAAC;AACD,SAAO,SAAS,OAAO,QAAQ;AAC/B,QAAM,aAAa;AACrB;AAEA,eAAsB,2BACpB,OACA,SAMA,SACA;AACA,QAAM,EAAE,eAAe,MAAM,IAAI,MAAM,qBAAqB;AAC5D,QAAM,WAAW,MAAM,MAAM,YAAY;AAAA,IACvC,UAAU,QAAQ;AAAA,IAClB,aAAa,qBAAqB,QAAQ,WAAW;AAAA,IACrD,kBAAkB,qBAAqB,QAAQ,gBAAgB;AAAA,IAC/D,0BAA0B,qBAAqB,OAAO,SAAS,IAAI;AAAA,IACnE;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,eAAe,QAAQ;AAAA,EACzB,CAAC;AACD,SAAO,SAAS,OAAO,QAAQ;AAC/B,QAAM,aAAa;AACrB;AAOA,SAAS,kCAAkC;AACzC,QAAM,iBAAiB,CAAC,QAAQ,OAAO;AACvC,QAAM,cAAc,IAAI,IAAI,OAAO,SAAS,IAAI;AAChD,aAAW,SAAS,gBAAgB;AAClC,QAAI,CAAC,YAAY,aAAa,IAAI,KAAK,GAAG;AACxC,mBAAa,mCAAmC,IAAI,MAAM,uDAAuD,KAAK,EAAE,CAAC;AACzH,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,gBAAgB,YAAY,aAAa,IAAI,OAAO,KAAK,SAAS,uDAAuD;AAC/H,QAAM,eAAe,8BAA8B,aAAa;AAEhE,MAAI,CAAC,cAAc;AAGjB,iBAAa,mCAAmC,IAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAQzD,CAAC;AACF,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,IAAI,IAAI,WAAW;AAClC,aAAW,SAAS,gBAAgB;AAClC,WAAO,aAAa,OAAO,KAAK;AAAA,EAClC;AAQA,SAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,OAAO,SAAS,CAAC;AAErD,SAAO;AAAA,IACL;AAAA,IACA,cAAc,aAAa;AAAA,IAC3B,OAAO;AAAA,EACT;AACF;AAEA,eAAsB,kBACpB,OACA,aACA;AAIA,QAAM,WAAW,gCAAgC;AACjD,MAAI,CAAC,SAAU,QAAO,OAAO,GAAG,MAAS;AAKzC,MAAI;AACF,WAAO,OAAO,GAAG,MAAM,MAAM,kBAAkB;AAAA,MAC7C,aAAa,SAAS,YAAY;AAAA,MAClC,aAAa,qBAAqB,WAAW;AAAA,MAC7C,cAAc,SAAS;AAAA,MACvB,OAAO,SAAS;AAAA,IAClB,CAAC,CAAC;AAAA,EACJ,SAAS,GAAG;AACV,QAAI,aAAa,YAAY;AAC3B,YAAM;AAAA,IACR;AACA,UAAM,IAAI,oBAAoB,6DAA6D,EAAE,OAAO,EAAE,CAAC;AAAA,EACzG;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/auth.ts"],"sourcesContent":["import { KnownError, StackClientInterface } from \"@stackframe/stack-shared\";\nimport { InternalSession } from \"@stackframe/stack-shared/dist/sessions\";\nimport { StackAssertionError, throwErr } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { neverResolve } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Result } from \"@stackframe/stack-shared/dist/utils/results\";\nimport { deindent } from \"@stackframe/stack-shared/dist/utils/strings\";\nimport { constructRedirectUrl } from \"../utils/url\";\nimport { consumeVerifierAndStateCookie, saveVerifierAndState } from \"./cookie\";\n\nexport async function signInWithOAuth(\n iface: StackClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n }\n) {\n const { codeChallenge, state } = await saveVerifierAndState();\n const location = await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl),\n codeChallenge,\n state,\n type: \"authenticate\",\n providerScope: options.providerScope,\n });\n window.location.assign(location);\n await neverResolve();\n}\n\nexport async function addNewOAuthProviderOrScope(\n iface: StackClientInterface,\n options: {\n provider: string,\n redirectUrl: string,\n errorRedirectUrl: string,\n providerScope?: string,\n },\n session: InternalSession,\n) {\n const { codeChallenge, state } = await saveVerifierAndState();\n const location = await iface.getOAuthUrl({\n provider: options.provider,\n redirectUrl: constructRedirectUrl(options.redirectUrl),\n errorRedirectUrl: constructRedirectUrl(options.errorRedirectUrl),\n afterCallbackRedirectUrl: constructRedirectUrl(window.location.href),\n codeChallenge,\n state,\n type: \"link\",\n session,\n providerScope: options.providerScope,\n });\n window.location.assign(location);\n await neverResolve();\n}\n\n/**\n * Checks if the current URL has the query parameters for an OAuth callback, and if so, removes them.\n *\n * Must be synchronous for the logic in callOAuthCallback to work without race conditions.\n */\nfunction consumeOAuthCallbackQueryParams() {\n const requiredParams = [\"code\", \"state\"];\n const originalUrl = new URL(window.location.href);\n for (const param of requiredParams) {\n if (!originalUrl.searchParams.has(param)) {\n console.warn(new Error(`Missing required query parameter on OAuth callback: ${param}. Maybe you opened or reloaded the oauth-callback page from your history?`));\n return null;\n }\n }\n\n const expectedState = originalUrl.searchParams.get(\"state\") ?? throwErr(\"This should never happen; isn't state required above?\");\n const cookieResult = consumeVerifierAndStateCookie(expectedState);\n\n if (!cookieResult) {\n // If the state can't be found in the cookies, then the callback wasn't meant for us.\n // Maybe the website uses another OAuth library?\n console.warn(deindent`\n Stack found an outer OAuth callback state in the query parameters, but not in cookies.\n \n This could have multiple reasons:\n - The cookie expired, because the OAuth flow took too long.\n - The user's browser deleted the cookie, either manually or because of a very strict cookie policy.\n - The cookie was already consumed by this page, and the user already logged in.\n - You are using another OAuth client library with the same callback URL as Stack.\n - The user opened the OAuth callback page from their history.\n\n Either way, it is probably safe to ignore this warning unless you are debugging an OAuth issue.\n `);\n return null;\n }\n\n\n const newUrl = new URL(originalUrl);\n for (const param of requiredParams) {\n newUrl.searchParams.delete(param);\n }\n\n // let's get rid of the authorization code in the history as we\n // don't redirect to `redirectUrl` if there's a validation error\n // (as the redirectUrl might be malicious!).\n //\n // We use history.replaceState instead of location.assign(...) to\n // prevent an unnecessary reload\n window.history.replaceState({}, \"\", newUrl.toString());\n\n return {\n originalUrl,\n codeVerifier: cookieResult.codeVerifier,\n state: expectedState,\n };\n}\n\nexport async function callOAuthCallback(\n iface: StackClientInterface,\n redirectUrl: string,\n) {\n // note: this part of the function (until the return) needs\n // to be synchronous, to prevent race conditions when\n // callOAuthCallback is called multiple times in parallel\n const consumed = consumeOAuthCallbackQueryParams();\n if (!consumed) return Result.ok(undefined);\n\n // the rest can be asynchronous (we now know that we are the\n // intended recipient of the callback, and the only instance\n // of callOAuthCallback that's running)\n try {\n return Result.ok(await iface.callOAuthCallback({\n oauthParams: consumed.originalUrl.searchParams,\n redirectUri: constructRedirectUrl(redirectUrl),\n codeVerifier: consumed.codeVerifier,\n state: consumed.state,\n }));\n } catch (e) {\n if (e instanceof KnownError) {\n throw e;\n }\n throw new StackAssertionError(\"Error signing in during OAuth callback. Please try again.\", { cause: e });\n }\n}\n"],"mappings":";AAAA,SAAS,kBAAwC;AAEjD,SAAS,qBAAqB,gBAAgB;AAC9C,SAAS,oBAAoB;AAC7B,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,4BAA4B;AACrC,SAAS,+BAA+B,4BAA4B;AAEpE,eAAsB,gBACpB,OACA,SAMA;AACA,QAAM,EAAE,eAAe,MAAM,IAAI,MAAM,qBAAqB;AAC5D,QAAM,WAAW,MAAM,MAAM,YAAY;AAAA,IACvC,UAAU,QAAQ;AAAA,IAClB,aAAa,qBAAqB,QAAQ,WAAW;AAAA,IACrD,kBAAkB,qBAAqB,QAAQ,gBAAgB;AAAA,IAC/D;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,eAAe,QAAQ;AAAA,EACzB,CAAC;AACD,SAAO,SAAS,OAAO,QAAQ;AAC/B,QAAM,aAAa;AACrB;AAEA,eAAsB,2BACpB,OACA,SAMA,SACA;AACA,QAAM,EAAE,eAAe,MAAM,IAAI,MAAM,qBAAqB;AAC5D,QAAM,WAAW,MAAM,MAAM,YAAY;AAAA,IACvC,UAAU,QAAQ;AAAA,IAClB,aAAa,qBAAqB,QAAQ,WAAW;AAAA,IACrD,kBAAkB,qBAAqB,QAAQ,gBAAgB;AAAA,IAC/D,0BAA0B,qBAAqB,OAAO,SAAS,IAAI;AAAA,IACnE;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,eAAe,QAAQ;AAAA,EACzB,CAAC;AACD,SAAO,SAAS,OAAO,QAAQ;AAC/B,QAAM,aAAa;AACrB;AAOA,SAAS,kCAAkC;AACzC,QAAM,iBAAiB,CAAC,QAAQ,OAAO;AACvC,QAAM,cAAc,IAAI,IAAI,OAAO,SAAS,IAAI;AAChD,aAAW,SAAS,gBAAgB;AAClC,QAAI,CAAC,YAAY,aAAa,IAAI,KAAK,GAAG;AACxC,cAAQ,KAAK,IAAI,MAAM,uDAAuD,KAAK,2EAA2E,CAAC;AAC/J,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,gBAAgB,YAAY,aAAa,IAAI,OAAO,KAAK,SAAS,uDAAuD;AAC/H,QAAM,eAAe,8BAA8B,aAAa;AAEhE,MAAI,CAAC,cAAc;AAGjB,YAAQ,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAWZ;AACD,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,IAAI,IAAI,WAAW;AAClC,aAAW,SAAS,gBAAgB;AAClC,WAAO,aAAa,OAAO,KAAK;AAAA,EAClC;AAQA,SAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,OAAO,SAAS,CAAC;AAErD,SAAO;AAAA,IACL;AAAA,IACA,cAAc,aAAa;AAAA,IAC3B,OAAO;AAAA,EACT;AACF;AAEA,eAAsB,kBACpB,OACA,aACA;AAIA,QAAM,WAAW,gCAAgC;AACjD,MAAI,CAAC,SAAU,QAAO,OAAO,GAAG,MAAS;AAKzC,MAAI;AACF,WAAO,OAAO,GAAG,MAAM,MAAM,kBAAkB;AAAA,MAC7C,aAAa,SAAS,YAAY;AAAA,MAClC,aAAa,qBAAqB,WAAW;AAAA,MAC7C,cAAc,SAAS;AAAA,MACvB,OAAO,SAAS;AAAA,IAClB,CAAC,CAAC;AAAA,EACJ,SAAS,GAAG;AACV,QAAI,aAAa,YAAY;AAC3B,YAAM;AAAA,IACR;AACA,UAAM,IAAI,oBAAoB,6DAA6D,EAAE,OAAO,EAAE,CAAC;AAAA,EACzG;AACF;","names":[]}
@@ -25,7 +25,7 @@ import { constructRedirectUrl } from "../utils/url";
25
25
  import { addNewOAuthProviderOrScope, callOAuthCallback, signInWithOAuth } from "./auth";
26
26
  import { createBrowserCookieHelper, createCookieHelper, deleteCookieClient, getCookieClient, setOrDeleteCookie, setOrDeleteCookieClient } from "./cookie";
27
27
  var NextNavigation = scrambleDuringCompileTime(NextNavigationUnscrambled);
28
- var clientVersion = "js @stackframe/stack@2.6.26";
28
+ var clientVersion = "js @stackframe/stack@2.6.28";
29
29
  function getUrls(partial) {
30
30
  const handler = partial.handler ?? "/handler";
31
31
  const home = partial.home ?? "/";
@@ -1,8 +1,8 @@
1
1
  // src/utils/email.tsx
2
- import { yupString } from "@stackframe/stack-shared/dist/schema-fields";
2
+ import { emailSchema } from "@stackframe/stack-shared/dist/schema-fields";
3
3
  function validateEmail(email) {
4
4
  if (typeof email !== "string") throw new Error("Email must be a string");
5
- return yupString().email().isValidSync(email);
5
+ return emailSchema.isValidSync(email);
6
6
  }
7
7
  export {
8
8
  validateEmail
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/email.tsx"],"sourcesContent":["import { yupString } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport * as yup from \"yup\";\n\nexport function validateEmail(email: string): boolean {\n if (typeof email !== \"string\") throw new Error(\"Email must be a string\");\n return yupString().email().isValidSync(email);\n};\n"],"mappings":";AAAA,SAAS,iBAAiB;AAGnB,SAAS,cAAc,OAAwB;AACpD,MAAI,OAAO,UAAU,SAAU,OAAM,IAAI,MAAM,wBAAwB;AACvE,SAAO,UAAU,EAAE,MAAM,EAAE,YAAY,KAAK;AAC9C;","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/email.tsx"],"sourcesContent":["import { emailSchema } from \"@stackframe/stack-shared/dist/schema-fields\";\n\nexport function validateEmail(email: string): boolean {\n if (typeof email !== \"string\") throw new Error(\"Email must be a string\");\n return emailSchema.isValidSync(email);\n};\n"],"mappings":";AAAA,SAAS,mBAAmB;AAErB,SAAS,cAAc,OAAwB;AACpD,MAAI,OAAO,UAAU,SAAU,OAAM,IAAI,MAAM,wBAAwB;AACvE,SAAO,YAAY,YAAY,KAAK;AACtC;","names":[]}