@stackframe/stack 2.6.26 → 2.6.27
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.
- package/CHANGELOG.md +10 -0
- package/dist/components/credential-sign-in.js +2 -2
- package/dist/components/credential-sign-in.js.map +1 -1
- package/dist/components/credential-sign-up.js +3 -3
- package/dist/components/credential-sign-up.js.map +1 -1
- package/dist/components/elements/maybe-full-page.js +1 -0
- package/dist/components/elements/maybe-full-page.js.map +1 -1
- package/dist/components/magic-link-sign-in.js +1 -1
- package/dist/components/magic-link-sign-in.js.map +1 -1
- package/dist/components-page/account-settings.js +6 -6
- package/dist/components-page/account-settings.js.map +1 -1
- package/dist/components-page/forgot-password.js +1 -1
- package/dist/components-page/forgot-password.js.map +1 -1
- package/dist/components-page/password-reset.js +1 -1
- package/dist/components-page/password-reset.js.map +1 -1
- package/dist/esm/components/credential-sign-in.js +3 -3
- package/dist/esm/components/credential-sign-in.js.map +1 -1
- package/dist/esm/components/credential-sign-up.js +4 -4
- package/dist/esm/components/credential-sign-up.js.map +1 -1
- package/dist/esm/components/elements/maybe-full-page.js +1 -0
- package/dist/esm/components/elements/maybe-full-page.js.map +1 -1
- package/dist/esm/components/magic-link-sign-in.js +2 -2
- package/dist/esm/components/magic-link-sign-in.js.map +1 -1
- package/dist/esm/components-page/account-settings.js +7 -7
- package/dist/esm/components-page/account-settings.js.map +1 -1
- package/dist/esm/components-page/forgot-password.js +2 -2
- package/dist/esm/components-page/forgot-password.js.map +1 -1
- package/dist/esm/components-page/password-reset.js +2 -2
- package/dist/esm/components-page/password-reset.js.map +1 -1
- package/dist/esm/lib/auth.js +5 -2
- package/dist/esm/lib/auth.js.map +1 -1
- package/dist/esm/lib/stack-app.js +1 -1
- package/dist/esm/utils/email.js +2 -2
- package/dist/esm/utils/email.js.map +1 -1
- package/dist/generated/quetzal-translations.d.mts +2 -2
- package/dist/generated/quetzal-translations.d.ts +2 -2
- package/dist/lib/auth.js +5 -2
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/stack-app.js +1 -1
- package/dist/utils/email.js +1 -1
- package/dist/utils/email.js.map +1 -1
- package/package.json +4 -4
|
@@ -56,7 +56,7 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
56
56
|
function PasswordResetForm(props) {
|
|
57
57
|
const { t } = (0, import_translations.useTranslation)();
|
|
58
58
|
const schema = (0, import_schema_fields.yupObject)({
|
|
59
|
-
password:
|
|
59
|
+
password: import_schema_fields.passwordSchema.defined(t("Please enter your password")).nonEmpty(t("Please enter your password")).test({
|
|
60
60
|
name: "is-valid-password",
|
|
61
61
|
test: (value, ctx) => {
|
|
62
62
|
const error = (0, import_password.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:
|
|
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":["React"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
// src/components/credential-sign-in.tsx
|
|
5
5
|
import { yupResolver } from "@hookform/resolvers/yup";
|
|
6
|
-
import {
|
|
6
|
+
import { passwordSchema, 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, PasswordInput, StyledLink } from "@stackframe/stack-ui";
|
|
9
9
|
import { useState } from "react";
|
|
@@ -15,8 +15,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
15
15
|
function CredentialSignIn() {
|
|
16
16
|
const { t } = useTranslation();
|
|
17
17
|
const schema = yupObject({
|
|
18
|
-
email:
|
|
19
|
-
password:
|
|
18
|
+
email: strictEmailSchema(t("Please enter a valid email")).defined().nonEmpty(t("Please enter your email")),
|
|
19
|
+
password: passwordSchema.defined().nonEmpty(t("Please enter your password"))
|
|
20
20
|
});
|
|
21
21
|
const { register, handleSubmit, setError, formState: { errors } } = useForm({
|
|
22
22
|
resolver: yupResolver(schema)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/credential-sign-in.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/components/credential-sign-in.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { passwordSchema, strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, Label, PasswordInput, StyledLink } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { FormWarningText } from \"./elements/form-warning\";\n\nexport function CredentialSignIn() {\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 password: passwordSchema.defined().nonEmpty(t('Please enter your password'))\n });\n\n const { register, handleSubmit, setError, formState: { errors } } = useForm({\n resolver: yupResolver(schema)\n });\n const app = useStackApp();\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof schema>) => {\n setLoading(true);\n\n try {\n const { email, password } = data;\n const result = await app.signInWithCredential({\n email,\n password,\n });\n if (result.status === 'error') {\n setError('email', { type: 'manual', message: result.error.message });\n }\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('Email')}</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register('email')}\n />\n <FormWarningText text={errors.email?.message?.toString()} />\n\n <Label htmlFor=\"password\" className=\"mt-4 mb-1\">{t('Password')}</Label>\n <PasswordInput\n id=\"password\"\n autoComplete=\"current-password\"\n {...register('password')}\n />\n <FormWarningText text={errors.password?.message?.toString()} />\n\n <StyledLink href={app.urls.forgotPassword} className=\"mt-1 text-sm\">\n {t('Forgot password?')}\n </StyledLink>\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n {t('Sign In')}\n </Button>\n </form>\n );\n}\n"],"mappings":";;;AAEA,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB,mBAAmB,iBAAiB;AAC7D,SAAS,kCAAkC;AAC3C,SAAS,QAAQ,OAAO,OAAO,eAAe,kBAAkB;AAChE,SAAS,gBAAgB;AACzB,SAAS,eAAe;AAExB,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAkC5B,SAKE,KALF;AAhCG,SAAS,mBAAmB;AACjC,QAAM,EAAE,EAAE,IAAI,eAAe;AAE7B,QAAM,SAAS,UAAU;AAAA,IACvB,OAAO,kBAAkB,EAAE,4BAA4B,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,yBAAyB,CAAC;AAAA,IACzG,UAAU,eAAe,QAAQ,EAAE,SAAS,EAAE,4BAA4B,CAAC;AAAA,EAC7E,CAAC;AAED,QAAM,EAAE,UAAU,cAAc,UAAU,WAAW,EAAE,OAAO,EAAE,IAAI,QAAQ;AAAA,IAC1E,UAAU,YAAY,MAAM;AAAA,EAC9B,CAAC;AACD,QAAM,MAAM,YAAY;AACxB,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,WAAW,OAAO,SAAuC;AAC7D,eAAW,IAAI;AAEf,QAAI;AACF,YAAM,EAAE,OAAO,SAAS,IAAI;AAC5B,YAAM,SAAS,MAAM,IAAI,qBAAqB;AAAA,QAC5C;AAAA,QACA;AAAA,MACF,CAAC;AACD,UAAI,OAAO,WAAW,SAAS;AAC7B,iBAAS,SAAS,EAAE,MAAM,UAAU,SAAS,OAAO,MAAM,QAAQ,CAAC;AAAA,MACrE;AAAA,IACF,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,OAAO,GAAE;AAAA,QACpD;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACJ,GAAG,SAAS,OAAO;AAAA;AAAA,QACtB;AAAA,QACA,oBAAC,mBAAgB,MAAM,OAAO,OAAO,SAAS,SAAS,GAAG;AAAA,QAE1D,oBAAC,SAAM,SAAQ,YAAW,WAAU,aAAa,YAAE,UAAU,GAAE;AAAA,QAC/D;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,cAAa;AAAA,YACZ,GAAG,SAAS,UAAU;AAAA;AAAA,QACzB;AAAA,QACA,oBAAC,mBAAgB,MAAM,OAAO,UAAU,SAAS,SAAS,GAAG;AAAA,QAE7D,oBAAC,cAAW,MAAM,IAAI,KAAK,gBAAgB,WAAU,gBAClD,YAAE,kBAAkB,GACvB;AAAA,QAEA,oBAAC,UAAO,MAAK,UAAS,WAAU,QAAO,SACpC,YAAE,SAAS,GACd;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// src/components/credential-sign-up.tsx
|
|
5
5
|
import { yupResolver } from "@hookform/resolvers/yup";
|
|
6
6
|
import { getPasswordError } from "@stackframe/stack-shared/dist/helpers/password";
|
|
7
|
-
import {
|
|
7
|
+
import { passwordSchema, strictEmailSchema, yupObject } from "@stackframe/stack-shared/dist/schema-fields";
|
|
8
8
|
import { runAsynchronously, runAsynchronouslyWithAlert } from "@stackframe/stack-shared/dist/utils/promises";
|
|
9
9
|
import { Button, Input, Label, PasswordInput } from "@stackframe/stack-ui";
|
|
10
10
|
import { useState } from "react";
|
|
@@ -17,8 +17,8 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
17
17
|
function CredentialSignUp(props) {
|
|
18
18
|
const { t } = useTranslation();
|
|
19
19
|
const schema = yupObject({
|
|
20
|
-
email:
|
|
21
|
-
password:
|
|
20
|
+
email: strictEmailSchema(t("Please enter a valid email")).defined().nonEmpty(t("Please enter your email")),
|
|
21
|
+
password: passwordSchema.defined().nonEmpty(t("Please enter your password")).test({
|
|
22
22
|
name: "is-valid-password",
|
|
23
23
|
test: (value, ctx) => {
|
|
24
24
|
const error = getPasswordError(value);
|
|
@@ -30,7 +30,7 @@ function CredentialSignUp(props) {
|
|
|
30
30
|
}
|
|
31
31
|
}),
|
|
32
32
|
...!props.noPasswordRepeat && {
|
|
33
|
-
passwordRepeat:
|
|
33
|
+
passwordRepeat: passwordSchema.nullable().oneOf([yup.ref("password"), "", null], t("Passwords do not match")).nonEmpty(t("Please repeat your password"))
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
const { register, handleSubmit, setError, formState: { errors }, clearErrors } = useForm({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/credential-sign-up.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from \"@stackframe/stack-shared/dist/helpers/password\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/components/credential-sign-up.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from \"@stackframe/stack-shared/dist/helpers/password\";\nimport { passwordSchema, strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronously, runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, Label, PasswordInput } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { FormWarningText } from \"./elements/form-warning\";\n\nexport function CredentialSignUp(props: { noPasswordRepeat?: boolean }) {\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 password: passwordSchema.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 ...(!props.noPasswordRepeat && {\n passwordRepeat: passwordSchema.nullable().oneOf([yup.ref('password'), \"\", null], t('Passwords do not match')).nonEmpty(t('Please repeat your password'))\n })\n });\n\n const { register, handleSubmit, setError, formState: { errors }, clearErrors } = useForm({\n resolver: yupResolver(schema)\n });\n const app = 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, password } = data;\n const result = await app.signUpWithCredential({ email, password });\n if (result.status === 'error') {\n setError('email', { type: 'manual', message: result.error.message });\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('password');\n const registerPasswordRepeat = register('passwordRepeat');\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('Email')}</Label>\n <Input id=\"email\" type=\"email\" {...register('email')}/>\n <FormWarningText text={errors.email?.message?.toString()} />\n\n <Label htmlFor=\"password\" className=\"mt-4 mb-1\">{t('Password')}</Label>\n <PasswordInput\n id=\"password\"\n autoComplete=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.password?.message?.toString()} />\n {\n !props.noPasswordRepeat && (\n <>\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">{t('Repeat Password')}</Label>\n <PasswordInput\n id=\"repeat-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.passwordRepeat?.message?.toString()} />\n </>\n )\n }\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n {t('Sign Up')}\n </Button>\n </form>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/elements/maybe-full-page.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useId } from \"react\";\nimport { SsrScript } from \"./ssr-layout-effect\";\n\nexport function MaybeFullPage({\n children,\n fullPage,\n}: {\n children: React.ReactNode,\n fullPage: boolean,\n size?: number,\n containerClassName?: string,\n}) {\n const uniqueId = useId();\n const id = `stack-full-page-container-${uniqueId}`;\n\n const scriptString = `(([id]) => {\n const el = document.getElementById(id);\n if (!el) {\n // component is not full page\n return;\n }\n const offset = el.getBoundingClientRect().top + document.documentElement.scrollTop;\n el.style.minHeight = \\`calc(100vh - \\${offset}px)\\`;\n })(${JSON.stringify([id])})`;\n\n if (fullPage) {\n return (\n <>\n <div\n id={id}\n style={{\n minHeight: '100vh',\n alignSelf: 'stretch',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n }}\n className=\"stack-scope\"\n >\n {children}\n </div>\n <SsrScript script={scriptString} />\n </>\n );\n } else {\n return <>\n {children}\n </>;\n }\n\n}\n"],"mappings":";;;AAEA,SAAgB,aAAa;AAC7B,SAAS,iBAAiB;AA0BpB,mBACE,KADF;AAxBC,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AACF,GAKG;AACD,QAAM,WAAW,MAAM;AACvB,QAAM,KAAK,6BAA6B,QAAQ;AAEhD,QAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAQhB,KAAK,UAAU,CAAC,EAAE,CAAC,CAAC;AAEzB,MAAI,UAAU;AACZ,WACE,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,OAAO;AAAA,YACL,WAAW;AAAA,YACX,WAAW;AAAA,YACX,SAAS;AAAA,YACT,gBAAgB;AAAA,YAChB,YAAY;AAAA,UACd;AAAA,UACA,WAAU;AAAA,UAET;AAAA;AAAA,MACH;AAAA,MACA,oBAAC,aAAU,QAAQ,cAAc;AAAA,OACnC;AAAA,EAEJ,OAAO;AACL,WAAO,gCACJ,UACH;AAAA,EACF;AAEF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/elements/maybe-full-page.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useId } from \"react\";\nimport { SsrScript } from \"./ssr-layout-effect\";\n\nexport function MaybeFullPage({\n children,\n fullPage,\n}: {\n children: React.ReactNode,\n fullPage: boolean,\n size?: number,\n containerClassName?: string,\n}) {\n const uniqueId = useId();\n const id = `stack-full-page-container-${uniqueId}`;\n\n const scriptString = `(([id]) => {\n const el = document.getElementById(id);\n if (!el) {\n // component is not full page\n return;\n }\n const offset = el.getBoundingClientRect().top + document.documentElement.scrollTop;\n el.style.minHeight = \\`calc(100vh - \\${offset}px)\\`;\n })(${JSON.stringify([id])})`;\n\n if (fullPage) {\n return (\n <>\n <div\n suppressHydrationWarning\n id={id}\n style={{\n minHeight: '100vh',\n alignSelf: 'stretch',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n }}\n className=\"stack-scope\"\n >\n {children}\n </div>\n <SsrScript script={scriptString} />\n </>\n );\n } else {\n return <>\n {children}\n </>;\n }\n\n}\n"],"mappings":";;;AAEA,SAAgB,aAAa;AAC7B,SAAS,iBAAiB;AA0BpB,mBACE,KADF;AAxBC,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AACF,GAKG;AACD,QAAM,WAAW,MAAM;AACvB,QAAM,KAAK,6BAA6B,QAAQ;AAEhD,QAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAQhB,KAAK,UAAU,CAAC,EAAE,CAAC,CAAC;AAEzB,MAAI,UAAU;AACZ,WACE,iCACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,0BAAwB;AAAA,UACxB;AAAA,UACA,OAAO;AAAA,YACL,WAAW;AAAA,YACX,WAAW;AAAA,YACX,SAAS;AAAA,YACT,gBAAgB;AAAA,YAChB,YAAY;AAAA,UACd;AAAA,UACA,WAAU;AAAA,UAET;AAAA;AAAA,MACH;AAAA,MACA,oBAAC,aAAU,QAAQ,cAAc;AAAA,OACnC;AAAA,EAEJ,OAAO;AACL,WAAO,gCACJ,UACH;AAAA,EACF;AAEF;","names":[]}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// src/components/magic-link-sign-in.tsx
|
|
5
5
|
import { yupResolver } from "@hookform/resolvers/yup";
|
|
6
6
|
import { KnownErrors } from "@stackframe/stack-shared";
|
|
7
|
-
import {
|
|
7
|
+
import { strictEmailSchema, yupObject } from "@stackframe/stack-shared/dist/schema-fields";
|
|
8
8
|
import { runAsynchronouslyWithAlert } from "@stackframe/stack-shared/dist/utils/promises";
|
|
9
9
|
import { Button, Input, InputOTP, InputOTPGroup, InputOTPSlot, Label, Typography } from "@stackframe/stack-ui";
|
|
10
10
|
import { useEffect, useState } from "react";
|
|
@@ -66,7 +66,7 @@ function MagicLinkSignIn() {
|
|
|
66
66
|
const [loading, setLoading] = useState(false);
|
|
67
67
|
const [nonce, setNonce] = useState(null);
|
|
68
68
|
const schema = yupObject({
|
|
69
|
-
email:
|
|
69
|
+
email: strictEmailSchema(t("Please enter a valid email")).defined().nonEmpty(t("Please enter your email"))
|
|
70
70
|
});
|
|
71
71
|
const { register, handleSubmit, setError, formState: { errors } } = useForm({
|
|
72
72
|
resolver: yupResolver(schema)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/magic-link-sign-in.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/components/magic-link-sign-in.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport { strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, InputOTP, InputOTPGroup, InputOTPSlot, Label, Typography } from \"@stackframe/stack-ui\";\nimport { useEffect, useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { FormWarningText } from \"./elements/form-warning\";\n\nfunction OTP(props: {\n onBack: () => void,\n nonce: string,\n}) {\n const { t } = useTranslation();\n const [otp, setOtp] = useState<string>('');\n const [submitting, setSubmitting] = useState<boolean>(false);\n const stackApp = useStackApp();\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (otp.length === 6 && !submitting) {\n setSubmitting(true);\n stackApp.signInWithMagicLink(otp + props.nonce)\n .then(result => {\n if (result.status === 'error') {\n if (result.error instanceof KnownErrors.VerificationCodeError) {\n setError(t(\"Invalid code\"));\n } else if (result.error instanceof KnownErrors.InvalidTotpCode) {\n setError(t(\"Invalid TOTP code\"));\n } else {\n throw result.error;\n }\n }\n })\n .catch(e => console.error(e))\n .finally(() => {\n setSubmitting(false);\n setOtp('');\n });\n }\n if (otp.length !== 0 && otp.length !== 6) {\n setError(null);\n }\n }, [otp, submitting]);\n\n return (\n <div className=\"flex flex-col items-stretch stack-scope\">\n <form className='w-full flex flex-col items-center mb-2'>\n <Typography className='mb-2' >{t('Enter the code from your email')}</Typography>\n <InputOTP\n maxLength={6}\n pattern={\"^[a-zA-Z0-9]+$\"}\n value={otp}\n onChange={value => setOtp(value.toUpperCase())}\n disabled={submitting}\n >\n <InputOTPGroup>\n {[0, 1, 2, 3, 4, 5].map((index) => (\n <InputOTPSlot key={index} index={index} size='lg' />\n ))}\n </InputOTPGroup>\n </InputOTP>\n {error && <FormWarningText text={error} />}\n </form>\n <Button variant='link' onClick={props.onBack} className='underline'>{t('Cancel')}</Button>\n </div>\n );\n}\n\nexport function MagicLinkSignIn() {\n const { t } = useTranslation();\n const app = useStackApp();\n const [loading, setLoading] = useState(false);\n const [nonce, setNonce] = useState<string | null>(null);\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, setError, formState: { errors } } = useForm({\n resolver: yupResolver(schema)\n });\n\n const onSubmit = async (data: yup.InferType<typeof schema>) => {\n setLoading(true);\n try {\n const { email } = data;\n const result = await app.sendMagicLinkEmail(email);\n if (result.status === 'error') {\n setError('email', { type: 'manual', message: result.error.message });\n return;\n } else {\n setNonce(result.data.nonce);\n }\n } catch (e) {\n if (e instanceof KnownErrors.SignUpNotEnabled) {\n setError('email', { type: 'manual', message: t('New account registration is not allowed') });\n } else {\n throw e;\n }\n } finally {\n setLoading(false);\n }\n };\n\n if (nonce) {\n return <OTP nonce={nonce} onBack={() => setNonce(null)} />;\n } else {\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('Email')}</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register('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"],"mappings":"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","names":[]}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { yupResolver } from "@hookform/resolvers/yup";
|
|
6
6
|
import { getPasswordError } from "@stackframe/stack-shared/dist/helpers/password";
|
|
7
7
|
import { useAsyncCallback } from "@stackframe/stack-shared/dist/hooks/use-async-callback";
|
|
8
|
-
import { yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
|
8
|
+
import { emailSchema, passwordSchema as schemaFieldsPasswordSchema, strictEmailSchema, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
|
|
9
9
|
import { generateRandomValues } from "@stackframe/stack-shared/dist/utils/crypto";
|
|
10
10
|
import { throwErr } from "@stackframe/stack-shared/dist/utils/errors";
|
|
11
11
|
import { runAsynchronously, runAsynchronouslyWithAlert } from "@stackframe/stack-shared/dist/utils/promises";
|
|
@@ -164,11 +164,11 @@ function EmailsSection() {
|
|
|
164
164
|
});
|
|
165
165
|
}
|
|
166
166
|
}, [contactChannels, addedEmail]);
|
|
167
|
-
const
|
|
168
|
-
email:
|
|
167
|
+
const emailSchema2 = yupObject({
|
|
168
|
+
email: strictEmailSchema(t("Please enter a valid email address")).notOneOf(contactChannels.map((x) => x.value), t("Email already exists")).defined().nonEmpty(t("Email is required"))
|
|
169
169
|
});
|
|
170
170
|
const { register, handleSubmit, formState: { errors }, reset } = useForm({
|
|
171
|
-
resolver: yupResolver(
|
|
171
|
+
resolver: yupResolver(emailSchema2)
|
|
172
172
|
});
|
|
173
173
|
const onSubmit = async (data) => {
|
|
174
174
|
setAddingEmailLoading(true);
|
|
@@ -422,8 +422,8 @@ function usePasswordSection() {
|
|
|
422
422
|
const [changingPassword, setChangingPassword] = useState(false);
|
|
423
423
|
const [loading, setLoading] = useState(false);
|
|
424
424
|
const passwordSchema = yupObject({
|
|
425
|
-
oldPassword: user.hasPassword ?
|
|
426
|
-
newPassword:
|
|
425
|
+
oldPassword: user.hasPassword ? schemaFieldsPasswordSchema.defined().nonEmpty(t("Please enter your old password")) : yupString(),
|
|
426
|
+
newPassword: schemaFieldsPasswordSchema.defined().nonEmpty(t("Please enter your password")).test({
|
|
427
427
|
name: "is-valid-password",
|
|
428
428
|
test: (value, ctx) => {
|
|
429
429
|
const error = getPasswordError(value);
|
|
@@ -780,7 +780,7 @@ function useTeamUserProfileSection(props) {
|
|
|
780
780
|
function useMemberInvitationSection(props) {
|
|
781
781
|
const { t } = useTranslation();
|
|
782
782
|
const invitationSchema = yupObject({
|
|
783
|
-
email:
|
|
783
|
+
email: emailSchema.defined().nonEmpty(t("Please enter an email address"))
|
|
784
784
|
});
|
|
785
785
|
const user = useUser({ or: "redirect" });
|
|
786
786
|
const inviteMemberPermission = user.usePermission(props.team, "$invite_members");
|