From 615b373fd641e1f2ae1a3c44d5896ad552016c5f Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Mon, 29 Jan 2024 16:14:05 +0100 Subject: [PATCH] Migrate wasp/client/auth API --- .../src/auth/pages/createAuthRequiredPage.jsx | 2 +- .../templates/sdk/auth/email/actions/login.ts | 1 + .../sdk/auth/email/actions/passwordReset.ts | 2 + .../sdk/auth/email/actions/signup.ts | 1 + .../sdk/auth/email/actions/verifyEmail.ts | 1 + .../templates/sdk/auth/forms/Auth.tsx | 2 + .../sdk/auth/forms/ForgotPassword.tsx | 1 + .../templates/sdk/auth/forms/Login.tsx | 1 + .../sdk/auth/forms/ResetPassword.tsx | 1 + .../templates/sdk/auth/forms/Signup.tsx | 1 + .../templates/sdk/auth/forms/VerifyEmail.tsx | 1 + .../sdk/auth/forms/internal/Form.tsx | 7 ++ .../sdk/auth/forms/internal/Message.tsx | 3 + .../forms/internal/common/LoginSignupForm.tsx | 2 + .../internal/email/ForgotPasswordForm.tsx | 1 + .../internal/email/ResetPasswordForm.tsx | 1 + .../forms/internal/email/VerifyEmailForm.tsx | 1 + .../sdk/auth/forms/internal/email/useEmail.ts | 1 + .../forms/internal/social/SocialButton.tsx | 1 + .../forms/internal/social/SocialIcons.tsx | 2 + .../useUsernameAndPassword.ts | 1 + .../templates/sdk/auth/forms/types.ts | 7 ++ .../templates/sdk/auth/helpers/Generic.tsx | 2 + .../templates/sdk/auth/helpers/user.ts | 1 + .../Generator/templates/sdk/auth/index.ts | 2 - .../data/Generator/templates/sdk/auth/jwt.ts | 2 + .../Generator/templates/sdk/auth/logout.ts | 1 + .../Generator/templates/sdk/auth/lucia.ts | 1 + .../Generator/templates/sdk/auth/useAuth.ts | 2 + .../data/Generator/templates/sdk/auth/user.ts | 4 + .../templates/sdk/client/auth/email.ts | 5 ++ .../templates/sdk/client/auth/github.ts | 2 + .../templates/sdk/client/auth/google.ts | 2 + .../templates/sdk/client/auth/index.ts | 20 +++++ .../Generator/templates/sdk/client/auth/ui.ts | 23 +++++ .../templates/sdk/client/auth/username.ts | 2 + .../data/Generator/templates/sdk/package.json | 27 +----- .../.wasp/out/sdk/wasp/package.json | 15 +--- .../examples/todo-typescript/src/MainPage.tsx | 3 +- .../todo-typescript/src/Todo.test.tsx | 2 +- .../todo-typescript/src/user/auth.tsx | 31 +++---- waspc/src/Wasp/Generator/SdkGenerator.hs | 3 + .../Generator/SdkGenerator/Client/AuthG.hs | 87 +++++++++++++++++++ waspc/waspc.cabal | 1 + 44 files changed, 220 insertions(+), 59 deletions(-) create mode 100644 waspc/data/Generator/templates/sdk/client/auth/email.ts create mode 100644 waspc/data/Generator/templates/sdk/client/auth/github.ts create mode 100644 waspc/data/Generator/templates/sdk/client/auth/google.ts create mode 100644 waspc/data/Generator/templates/sdk/client/auth/index.ts create mode 100644 waspc/data/Generator/templates/sdk/client/auth/ui.ts create mode 100644 waspc/data/Generator/templates/sdk/client/auth/username.ts create mode 100644 waspc/src/Wasp/Generator/SdkGenerator/Client/AuthG.hs diff --git a/waspc/data/Generator/templates/react-app/src/auth/pages/createAuthRequiredPage.jsx b/waspc/data/Generator/templates/react-app/src/auth/pages/createAuthRequiredPage.jsx index 8725da183..7458dd470 100644 --- a/waspc/data/Generator/templates/react-app/src/auth/pages/createAuthRequiredPage.jsx +++ b/waspc/data/Generator/templates/react-app/src/auth/pages/createAuthRequiredPage.jsx @@ -2,7 +2,7 @@ import React from 'react' import { Redirect } from 'react-router-dom' -import useAuth from 'wasp/auth/useAuth' +import { useAuth } from 'wasp/client/auth' const createAuthRequiredPage = (Page) => { diff --git a/waspc/data/Generator/templates/sdk/auth/email/actions/login.ts b/waspc/data/Generator/templates/sdk/auth/email/actions/login.ts index 2f2cfb477..6a2cbbad1 100644 --- a/waspc/data/Generator/templates/sdk/auth/email/actions/login.ts +++ b/waspc/data/Generator/templates/sdk/auth/email/actions/login.ts @@ -2,6 +2,7 @@ import { api, handleApiError } from 'wasp/client/api'; import { initSession } from '../../helpers/user'; +// PUBLIC API export async function login(data: { email: string; password: string }): Promise { try { const response = await api.post('{= loginPath =}', data); diff --git a/waspc/data/Generator/templates/sdk/auth/email/actions/passwordReset.ts b/waspc/data/Generator/templates/sdk/auth/email/actions/passwordReset.ts index ac721f210..ca48bbf98 100644 --- a/waspc/data/Generator/templates/sdk/auth/email/actions/passwordReset.ts +++ b/waspc/data/Generator/templates/sdk/auth/email/actions/passwordReset.ts @@ -1,6 +1,7 @@ {{={= =}=}} import { api, handleApiError } from 'wasp/client/api'; +// PUBLIC API export async function requestPasswordReset(data: { email: string; }): Promise<{ success: boolean }> { try { const response = await api.post('{= requestPasswordResetPath =}', data); @@ -10,6 +11,7 @@ export async function requestPasswordReset(data: { email: string; }): Promise<{ } } +// PUBLIC API export async function resetPassword(data: { token: string; password: string; }): Promise<{ success: boolean }> { try { const response = await api.post('{= resetPasswordPath =}', data); diff --git a/waspc/data/Generator/templates/sdk/auth/email/actions/signup.ts b/waspc/data/Generator/templates/sdk/auth/email/actions/signup.ts index cf882b2f7..797af04a2 100644 --- a/waspc/data/Generator/templates/sdk/auth/email/actions/signup.ts +++ b/waspc/data/Generator/templates/sdk/auth/email/actions/signup.ts @@ -1,6 +1,7 @@ {{={= =}=}} import { api, handleApiError } from 'wasp/client/api'; +// PUBLIC API export async function signup(data: { email: string; password: string }): Promise<{ success: boolean }> { try { const response = await api.post('{= signupPath =}', data); diff --git a/waspc/data/Generator/templates/sdk/auth/email/actions/verifyEmail.ts b/waspc/data/Generator/templates/sdk/auth/email/actions/verifyEmail.ts index fa96569bb..80c7c4ceb 100644 --- a/waspc/data/Generator/templates/sdk/auth/email/actions/verifyEmail.ts +++ b/waspc/data/Generator/templates/sdk/auth/email/actions/verifyEmail.ts @@ -1,6 +1,7 @@ {{={= =}=}} import { api, handleApiError } from 'wasp/client/api' +// PUBLIC API export async function verifyEmail(data: { token: string }): Promise<{ success: boolean; reason?: string }> { diff --git a/waspc/data/Generator/templates/sdk/auth/forms/Auth.tsx b/waspc/data/Generator/templates/sdk/auth/forms/Auth.tsx index 99568c40d..e14ebab30 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/Auth.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/Auth.tsx @@ -33,6 +33,7 @@ const HeaderText = styled('h2', { }) +// PRIVATE API export const AuthContext = createContext({ isLoading: false, setIsLoading: (isLoading: boolean) => {}, @@ -98,4 +99,5 @@ function Auth ({ state, appearance, logo, socialLayout = 'horizontal', additiona ) } +// PRIVATE API export default Auth; diff --git a/waspc/data/Generator/templates/sdk/auth/forms/ForgotPassword.tsx b/waspc/data/Generator/templates/sdk/auth/forms/ForgotPassword.tsx index f0bb2623a..e0893beba 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/ForgotPassword.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/ForgotPassword.tsx @@ -1,6 +1,7 @@ import Auth from './Auth' import { type CustomizationOptions, State } from './types' +// PUBLIC API export function ForgotPasswordForm({ appearance, logo, diff --git a/waspc/data/Generator/templates/sdk/auth/forms/Login.tsx b/waspc/data/Generator/templates/sdk/auth/forms/Login.tsx index 2ea532d9c..f8fca6608 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/Login.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/Login.tsx @@ -1,6 +1,7 @@ import Auth from './Auth' import { type CustomizationOptions, State } from './types' +// PUBLIC API export function LoginForm({ appearance, logo, diff --git a/waspc/data/Generator/templates/sdk/auth/forms/ResetPassword.tsx b/waspc/data/Generator/templates/sdk/auth/forms/ResetPassword.tsx index daa14ebae..8457b238f 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/ResetPassword.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/ResetPassword.tsx @@ -1,6 +1,7 @@ import Auth from './Auth' import { type CustomizationOptions, State } from './types' +// PUBLIC API export function ResetPasswordForm({ appearance, logo, diff --git a/waspc/data/Generator/templates/sdk/auth/forms/Signup.tsx b/waspc/data/Generator/templates/sdk/auth/forms/Signup.tsx index 66ffab450..32c7afc38 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/Signup.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/Signup.tsx @@ -5,6 +5,7 @@ import { State, } from './types' +// PUBLIC API export function SignupForm({ appearance, logo, diff --git a/waspc/data/Generator/templates/sdk/auth/forms/VerifyEmail.tsx b/waspc/data/Generator/templates/sdk/auth/forms/VerifyEmail.tsx index 29dae0708..1c81e0e24 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/VerifyEmail.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/VerifyEmail.tsx @@ -1,6 +1,7 @@ import Auth from './Auth' import { type CustomizationOptions, State } from './types' +// PUBLIC API export function VerifyEmailForm({ appearance, logo, diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/Form.tsx b/waspc/data/Generator/templates/sdk/auth/forms/internal/Form.tsx index 781c75a0a..163430742 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/Form.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/Form.tsx @@ -1,15 +1,18 @@ import { styled } from 'wasp/core/stitches.config' +// PRIVATE API export const Form = styled('form', { marginTop: '1.5rem', }) +// PUBLIC API export const FormItemGroup = styled('div', { '& + div': { marginTop: '1.5rem', }, }) +// PUBLIC API export const FormLabel = styled('label', { display: 'block', fontSize: '$sm', @@ -48,10 +51,13 @@ const commonInputStyles = { margin: 0, } +// PUBLIC API export const FormInput = styled('input', commonInputStyles) +// PUBLIC API export const FormTextarea = styled('textarea', commonInputStyles) +// PUBLIC API export const FormError = styled('div', { display: 'block', fontSize: '$sm', @@ -60,6 +66,7 @@ export const FormError = styled('div', { marginTop: '0.5rem', }) +// PRIVATE API export const SubmitButton = styled('button', { display: 'flex', justifyContent: 'center', diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/Message.tsx b/waspc/data/Generator/templates/sdk/auth/forms/internal/Message.tsx index 7279ed252..362ff9dfd 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/Message.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/Message.tsx @@ -1,5 +1,6 @@ import { styled } from 'wasp/core/stitches.config' +// PRIVATE API export const Message = styled('div', { padding: '0.5rem 0.75rem', borderRadius: '0.375rem', @@ -7,11 +8,13 @@ export const Message = styled('div', { background: '$gray400', }) +// PRIVATE API export const MessageError = styled(Message, { background: '$errorBackground', color: '$errorText', }) +// PRIVATE API export const MessageSuccess = styled(Message, { background: '$successBackground', color: '$successText', diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/common/LoginSignupForm.tsx b/waspc/data/Generator/templates/sdk/auth/forms/internal/common/LoginSignupForm.tsx index e76e56bb7..8c96121dd 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/common/LoginSignupForm.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/common/LoginSignupForm.tsx @@ -117,10 +117,12 @@ const gitHubSignInUrl = `${config.apiUrl}{= gitHubSignInPath =}` // know the exact shape of the form values. We are assuming that the form values // will be a flat object with string values. =} +// PRIVATE API export type LoginSignupFormFields = { [key: string]: string; } +// PRIVATE API export const LoginSignupForm = ({ state, socialButtonsDirection = 'horizontal', diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/email/ForgotPasswordForm.tsx b/waspc/data/Generator/templates/sdk/auth/forms/internal/email/ForgotPasswordForm.tsx index e20328a4b..b2ad9ae7d 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/email/ForgotPasswordForm.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/email/ForgotPasswordForm.tsx @@ -4,6 +4,7 @@ import { requestPasswordReset } from '../../../email/actions/passwordReset.js' import { Form, FormItemGroup, FormLabel, FormInput, SubmitButton, FormError } from '../Form' import { AuthContext } from '../../Auth' +// PRIVATE API export const ForgotPasswordForm = () => { const { register, handleSubmit, reset, formState: { errors } } = useForm<{ email: string }>() const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } = useContext(AuthContext) diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/email/ResetPasswordForm.tsx b/waspc/data/Generator/templates/sdk/auth/forms/internal/email/ResetPasswordForm.tsx index a3535d57d..ba3cd2f0c 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/email/ResetPasswordForm.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/email/ResetPasswordForm.tsx @@ -5,6 +5,7 @@ import { useLocation } from 'react-router-dom' import { Form, FormItemGroup, FormLabel, FormInput, SubmitButton, FormError } from '../Form' import { AuthContext } from '../../Auth' +// PRIVATE API export const ResetPasswordForm = () => { const { register, handleSubmit, reset, formState: { errors } } = useForm<{ password: string; passwordConfirmation: string }>() const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } = useContext(AuthContext) diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/email/VerifyEmailForm.tsx b/waspc/data/Generator/templates/sdk/auth/forms/internal/email/VerifyEmailForm.tsx index 3d8444985..dd5b5d677 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/email/VerifyEmailForm.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/email/VerifyEmailForm.tsx @@ -4,6 +4,7 @@ import { verifyEmail } from '../../../email/actions/verifyEmail.js' import { Message } from '../Message' import { AuthContext } from '../../Auth' +// PRIVATE API export const VerifyEmailForm = () => { const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } = useContext(AuthContext) const location = useLocation() diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/email/useEmail.ts b/waspc/data/Generator/templates/sdk/auth/forms/internal/email/useEmail.ts index 4d8b792ba..3cd191b91 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/email/useEmail.ts +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/email/useEmail.ts @@ -1,6 +1,7 @@ import { signup } from '../../../email/actions/signup' import { login } from '../../../email/actions/login' +// PRIVATE API export function useEmail({ onError, showEmailVerificationPending, diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialButton.tsx b/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialButton.tsx index 47044884b..cd2cf4885 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialButton.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialButton.tsx @@ -1,5 +1,6 @@ import { styled } from 'wasp/core/stitches.config' +// PRIVATE API export const SocialButton = styled('a', { display: 'flex', justifyContent: 'center', diff --git a/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialIcons.tsx b/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialIcons.tsx index aac1f53ff..7192e457b 100644 --- a/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialIcons.tsx +++ b/waspc/data/Generator/templates/sdk/auth/forms/internal/social/SocialIcons.tsx @@ -5,6 +5,7 @@ const defaultStyles = css({ height: '1.25rem', }) +// PRIVATE API export const Google = () => ( ( ) +// PRIVATE API export const GitHub = () => ( [0] } +// PRIVATE API export type ErrorMessage = { title: string description?: string } +// PRIVATE API export type FormState = { isLoading: boolean } +// PRIVATE API export type AdditionalSignupFieldRenderFn = ( hookForm: UseFormReturn, formState: FormState ) => React.ReactNode +// PRIVATE API export type AdditionalSignupField = { name: string label: string @@ -40,6 +46,7 @@ export type AdditionalSignupField = { validations?: RegisterOptions } +// PRIVATE API export type AdditionalSignupFields = | (AdditionalSignupField | AdditionalSignupFieldRenderFn)[] | AdditionalSignupFieldRenderFn diff --git a/waspc/data/Generator/templates/sdk/auth/helpers/Generic.tsx b/waspc/data/Generator/templates/sdk/auth/helpers/Generic.tsx index b54464da1..21922f31b 100644 --- a/waspc/data/Generator/templates/sdk/auth/helpers/Generic.tsx +++ b/waspc/data/Generator/templates/sdk/auth/helpers/Generic.tsx @@ -4,8 +4,10 @@ import config from 'wasp/core/config' import { SocialButton } from '../forms/internal/social/SocialButton' import * as SocialIcons from '../forms/internal/social/SocialIcons' +// PUBLIC API export const signInUrl = `${config.apiUrl}{= signInPath =}` +// PUBLIC API export function SignInButton() { return ( diff --git a/waspc/data/Generator/templates/sdk/auth/helpers/user.ts b/waspc/data/Generator/templates/sdk/auth/helpers/user.ts index 259a4c34b..050dd3f32 100644 --- a/waspc/data/Generator/templates/sdk/auth/helpers/user.ts +++ b/waspc/data/Generator/templates/sdk/auth/helpers/user.ts @@ -1,6 +1,7 @@ import { setSessionId } from 'wasp/client/api' import { invalidateAndRemoveQueries } from 'wasp/operations/resources' +// PRIVATE API export async function initSession(sessionId: string): Promise { setSessionId(sessionId) // We need to invalidate queries after login in order to get the correct user diff --git a/waspc/data/Generator/templates/sdk/auth/index.ts b/waspc/data/Generator/templates/sdk/auth/index.ts index 56d03e4d8..83cfcc27c 100644 --- a/waspc/data/Generator/templates/sdk/auth/index.ts +++ b/waspc/data/Generator/templates/sdk/auth/index.ts @@ -1,7 +1,5 @@ export { defineUserSignupFields } from './providers/types.js'; -// PUBLIC export type { AuthUser } from '../server/_types' -// PUBLIC export { getEmail, getUsername, getFirstProviderUserId, findUserIdentity } from './user.js' diff --git a/waspc/data/Generator/templates/sdk/auth/jwt.ts b/waspc/data/Generator/templates/sdk/auth/jwt.ts index cb7f33725..8ed702e4c 100644 --- a/waspc/data/Generator/templates/sdk/auth/jwt.ts +++ b/waspc/data/Generator/templates/sdk/auth/jwt.ts @@ -8,5 +8,7 @@ const jwtVerify = util.promisify(jwt.verify) const JWT_SECRET = config.auth.jwtSecret +// PRIVATE API export const signData = (data, options) => jwtSign(data, JWT_SECRET, options) +// PRIVATE API export const verify = (token) => jwtVerify(token, JWT_SECRET) diff --git a/waspc/data/Generator/templates/sdk/auth/logout.ts b/waspc/data/Generator/templates/sdk/auth/logout.ts index 7f40b0cbf..4a5181756 100644 --- a/waspc/data/Generator/templates/sdk/auth/logout.ts +++ b/waspc/data/Generator/templates/sdk/auth/logout.ts @@ -1,6 +1,7 @@ import { api, removeLocalUserData } from 'wasp/client/api' import { invalidateAndRemoveQueries } from 'wasp/operations/resources' +// PUBLIC API export default async function logout(): Promise { try { await api.post('/auth/logout') diff --git a/waspc/data/Generator/templates/sdk/auth/lucia.ts b/waspc/data/Generator/templates/sdk/auth/lucia.ts index eabf63523..3a9126351 100644 --- a/waspc/data/Generator/templates/sdk/auth/lucia.ts +++ b/waspc/data/Generator/templates/sdk/auth/lucia.ts @@ -12,6 +12,7 @@ const prismaAdapter = new PrismaAdapter( prisma.{= authEntityLower =} as any ); +// PRIVATE API /** * We are using Lucia for session management. * diff --git a/waspc/data/Generator/templates/sdk/auth/useAuth.ts b/waspc/data/Generator/templates/sdk/auth/useAuth.ts index c7b02273c..5038c40d7 100644 --- a/waspc/data/Generator/templates/sdk/auth/useAuth.ts +++ b/waspc/data/Generator/templates/sdk/auth/useAuth.ts @@ -6,8 +6,10 @@ import { HttpMethod } from 'wasp/types' import type { AuthUser } from './types' import { addMetadataToQuery } from 'wasp/rpc/queries' +// PUBLIC API export const getMe = createUserGetter() +// PUBLIC API export default function useAuth(queryFnArgs?: unknown, config?: any) { return useQuery(getMe, queryFnArgs, config) } diff --git a/waspc/data/Generator/templates/sdk/auth/user.ts b/waspc/data/Generator/templates/sdk/auth/user.ts index 0de50de6d..f9bc6d39a 100644 --- a/waspc/data/Generator/templates/sdk/auth/user.ts +++ b/waspc/data/Generator/templates/sdk/auth/user.ts @@ -1,13 +1,16 @@ import type { AuthUser, ProviderName, DeserializedAuthIdentity } from './types' +// PUBLIC API export function getEmail(user: AuthUser): string | null { return findUserIdentity(user, "email")?.providerUserId ?? null; } +// PUBLIC API export function getUsername(user: AuthUser): string | null { return findUserIdentity(user, "username")?.providerUserId ?? null; } +// PUBLIC API export function getFirstProviderUserId(user?: AuthUser): string | null { if (!user || !user.auth || !user.auth.identities || user.auth.identities.length === 0) { return null; @@ -16,6 +19,7 @@ export function getFirstProviderUserId(user?: AuthUser): string | null { return user.auth.identities[0].providerUserId ?? null; } +// PUBLIC API export function findUserIdentity(user: AuthUser, providerName: ProviderName): DeserializedAuthIdentity | undefined { return user.auth.identities.find( (identity) => identity.providerName === providerName diff --git a/waspc/data/Generator/templates/sdk/client/auth/email.ts b/waspc/data/Generator/templates/sdk/client/auth/email.ts new file mode 100644 index 000000000..244e4a5e2 --- /dev/null +++ b/waspc/data/Generator/templates/sdk/client/auth/email.ts @@ -0,0 +1,5 @@ +// PUBLIC API +export { login } from '../../auth/email/actions/login' +export { signup } from '../../auth/email/actions/signup' +export { requestPasswordReset, resetPassword } from '../../auth/email/actions/passwordReset' +export { verifyEmail } from '../../auth/email/actions/verifyEmail' diff --git a/waspc/data/Generator/templates/sdk/client/auth/github.ts b/waspc/data/Generator/templates/sdk/client/auth/github.ts new file mode 100644 index 000000000..a749c0f78 --- /dev/null +++ b/waspc/data/Generator/templates/sdk/client/auth/github.ts @@ -0,0 +1,2 @@ +// PUBLIC API +export { signInUrl as githubSignInUrl } from '../../auth/helpers/Github' diff --git a/waspc/data/Generator/templates/sdk/client/auth/google.ts b/waspc/data/Generator/templates/sdk/client/auth/google.ts new file mode 100644 index 000000000..a3f0a98ac --- /dev/null +++ b/waspc/data/Generator/templates/sdk/client/auth/google.ts @@ -0,0 +1,2 @@ +// PUBLIC API +export { signInUrl as googleSignInUrl } from '../../auth/helpers/Google' diff --git a/waspc/data/Generator/templates/sdk/client/auth/index.ts b/waspc/data/Generator/templates/sdk/client/auth/index.ts new file mode 100644 index 000000000..14b2ea392 --- /dev/null +++ b/waspc/data/Generator/templates/sdk/client/auth/index.ts @@ -0,0 +1,20 @@ +{{={= =}=}} +export * from './ui' +{=# isEmailAuthEnabled =} +export * from './email' +{=/ isEmailAuthEnabled =} +{=# isUsernameAndPasswordAuthEnabled =} +export * from './username' +{=/ isUsernameAndPasswordAuthEnabled =} +{=# isGoogleAuthEnabled =} +export * from './google' +{=/ isGoogleAuthEnabled =} +{=# isGithubAuthEnabled =} +export * from './github' +{=/ isGithubAuthEnabled =} +export { + default as useAuth, + getMe, +} from '../../auth/useAuth' + +export { default as logout } from '../../auth/logout' diff --git a/waspc/data/Generator/templates/sdk/client/auth/ui.ts b/waspc/data/Generator/templates/sdk/client/auth/ui.ts new file mode 100644 index 000000000..d1567ec58 --- /dev/null +++ b/waspc/data/Generator/templates/sdk/client/auth/ui.ts @@ -0,0 +1,23 @@ +{{={= =}=}} +// PUBLIC API +export { LoginForm } from '../../auth/forms/Login' +export { SignupForm } from '../../auth/forms/Signup' +{=# isEmailAuthEnabled =} +export { ForgotPasswordForm } from '../../auth/forms/ForgotPassword' +export { VerifyEmailForm } from '../../auth/forms/VerifyEmail' +export { ResetPasswordForm } from '../../auth/forms/ResetPassword' +{=/ isEmailAuthEnabled =} +export type { CustomizationOptions } from '../../auth/forms/types' +{=# isGoogleAuthEnabled =} +export { SignInButton as GoogleSignInButton } from '../../auth/helpers/Google' +{=/ isGoogleAuthEnabled =} +{=# isGithubAuthEnabled =} +export { SignInButton as GithubSignInButton } from '../../auth/helpers/Github' +{=/ isGithubAuthEnabled =} +export { + FormError, + FormInput, + FormTextarea, + FormItemGroup, + FormLabel, +} from '../../auth/forms/internal/Form' diff --git a/waspc/data/Generator/templates/sdk/client/auth/username.ts b/waspc/data/Generator/templates/sdk/client/auth/username.ts new file mode 100644 index 000000000..f83e89683 --- /dev/null +++ b/waspc/data/Generator/templates/sdk/client/auth/username.ts @@ -0,0 +1,2 @@ +export { default as login } from '../../auth/login' +export { default as signup } from '../../auth/signup' diff --git a/waspc/data/Generator/templates/sdk/package.json b/waspc/data/Generator/templates/sdk/package.json index 847d6a1b8..f5c02c6af 100644 --- a/waspc/data/Generator/templates/sdk/package.json +++ b/waspc/data/Generator/templates/sdk/package.json @@ -37,16 +37,6 @@ "./rpc/queryClient": "./dist/rpc/queryClient.js", {=! Used by users, documented. =} "./types": "./dist/types/index.js", - {=! Used by users, documented. =} - "./auth/login": "./dist/auth/login.js", - {=! Used by users, documented. =} - "./auth/logout": "./dist/auth/logout.js", - {=! Used by users, documented. =} - "./auth/signup": "./dist/auth/signup.js", - {=! Used by users, documented. =} - "./auth/useAuth": "./dist/auth/useAuth.js", - {=! Used by users, documented. =} - "./auth/email": "./dist/auth/email/index.js", {=! Used by our code, uncodumented (but accessible) for users. =} "./auth/helpers/user": "./dist/auth/helpers/user.js", {=! Used by our code, uncodumented (but accessible) for users. =} @@ -61,20 +51,6 @@ "./auth/jwt": "./dist/auth/jwt.js", {=! Used by user, documented. =} "./auth/validation": "./dist/auth/validation.js", - {=! Used by users, documented. =} - "./auth/forms/Login": "./dist/auth/forms/Login.jsx", - {=! Used by users, documented. =} - "./auth/forms/Signup": "./dist/auth/forms/Signup.jsx", - {=! Used by users, documented. =} - "./auth/forms/VerifyEmail": "./dist/auth/forms/VerifyEmail.jsx", - {=! Used by users, documented. =} - "./auth/forms/ForgotPassword": "./dist/auth/forms/ForgotPassword.jsx", - {=! Used by users, documented. =} - "./auth/forms/ResetPassword": "./dist/auth/forms/ResetPassword.jsx", - {=! Used by users, documented. =} - "./auth/forms/internal/Form": "./dist/auth/forms/internal/Form.jsx", - {=! Used by users, documented. =} - "./auth/helpers/*": "./dist/auth/helpers/*.jsx", {=! Used by our code, uncodumented (but accessible) for users. =} "./auth/pages/createAuthRequiredPage": "./dist/auth/pages/createAuthRequiredPage.jsx", {=! Used by our framework code (Websockets), undocumented (but accessible) for users. =} @@ -145,7 +121,8 @@ {=! Public: { api } =} {=! Private: [sdk] =} "./client/api": "./dist/api/index.js", - "./auth": "./dist/auth/index.js" + "./auth": "./dist/auth/index.js", + "./client/auth": "./dist/client/auth/index.js" }, {=! TypeScript doesn't care about the redirects we define above in "exports" field; those diff --git a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/package.json b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/package.json index 8e954a849..3545ebabf 100644 --- a/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/package.json +++ b/waspc/examples/todo-typescript/.wasp/out/sdk/wasp/package.json @@ -21,11 +21,6 @@ "./rpc/actions/core": "./dist/rpc/actions/core.js", "./rpc/queryClient": "./dist/rpc/queryClient.js", "./types": "./dist/types/index.js", - "./auth/login": "./dist/auth/login.js", - "./auth/logout": "./dist/auth/logout.js", - "./auth/signup": "./dist/auth/signup.js", - "./auth/useAuth": "./dist/auth/useAuth.js", - "./auth/email": "./dist/auth/email/index.js", "./auth/helpers/user": "./dist/auth/helpers/user.js", "./auth/session": "./dist/auth/session.js", "./auth/providers/types": "./dist/auth/providers/types.js", @@ -33,13 +28,6 @@ "./auth/password": "./dist/auth/password.js", "./auth/jwt": "./dist/auth/jwt.js", "./auth/validation": "./dist/auth/validation.js", - "./auth/forms/Login": "./dist/auth/forms/Login.jsx", - "./auth/forms/Signup": "./dist/auth/forms/Signup.jsx", - "./auth/forms/VerifyEmail": "./dist/auth/forms/VerifyEmail.jsx", - "./auth/forms/ForgotPassword": "./dist/auth/forms/ForgotPassword.jsx", - "./auth/forms/ResetPassword": "./dist/auth/forms/ResetPassword.jsx", - "./auth/forms/internal/Form": "./dist/auth/forms/internal/Form.jsx", - "./auth/helpers/*": "./dist/auth/helpers/*.jsx", "./auth/pages/createAuthRequiredPage": "./dist/auth/pages/createAuthRequiredPage.jsx", "./api/events": "./dist/api/events.js", "./operations": "./dist/operations/index.js", @@ -73,7 +61,8 @@ "./server": "./dist/server/index.js", "./server/api": "./dist/server/api/index.js", "./client/api": "./dist/api/index.js", - "./auth": "./dist/auth/index.js" + "./auth": "./dist/auth/index.js", + "./client/auth": "./dist/client/auth/index.js" }, "typesVersions": { "*": { diff --git a/waspc/examples/todo-typescript/src/MainPage.tsx b/waspc/examples/todo-typescript/src/MainPage.tsx index 9e89cbf44..cc400853b 100644 --- a/waspc/examples/todo-typescript/src/MainPage.tsx +++ b/waspc/examples/todo-typescript/src/MainPage.tsx @@ -1,6 +1,5 @@ import './Main.css' import React, { useEffect, FormEventHandler, FormEvent } from 'react' -import logout from 'wasp/auth/logout' import { useQuery, useAction } from 'wasp/rpc' // Wasp uses a thin wrapper around react-query import { getTasks } from 'wasp/rpc/queries' import { @@ -16,8 +15,8 @@ import { Link } from 'react-router-dom' import { Tasks } from 'wasp/crud/Tasks' // import login from 'wasp/auth/login' // import signup from 'wasp/auth/signup' -import useAuth from 'wasp/auth/useAuth' import { Todo } from './Todo' +import { logout, useAuth } from 'wasp/client/auth' export const MainPage = ({ user }: { user: AuthUser }) => { const { data: tasks, isLoading, error } = useQuery(getTasks) diff --git a/waspc/examples/todo-typescript/src/Todo.test.tsx b/waspc/examples/todo-typescript/src/Todo.test.tsx index 151554bce..b515530f0 100644 --- a/waspc/examples/todo-typescript/src/Todo.test.tsx +++ b/waspc/examples/todo-typescript/src/Todo.test.tsx @@ -6,7 +6,7 @@ import { getTasks } from 'wasp/rpc/queries' import { Todo, areThereAnyTasks } from './Todo' import { MainPage } from './MainPage' import type { AuthUser } from 'wasp/auth' -import { getMe } from 'wasp/auth/useAuth' +import { getMe } from 'wasp/client/auth' import { Tasks } from 'wasp/crud/Tasks' const mockTasks = [ diff --git a/waspc/examples/todo-typescript/src/user/auth.tsx b/waspc/examples/todo-typescript/src/user/auth.tsx index 2d6b341aa..9a1582546 100644 --- a/waspc/examples/todo-typescript/src/user/auth.tsx +++ b/waspc/examples/todo-typescript/src/user/auth.tsx @@ -1,13 +1,15 @@ -import { ResetPasswordForm } from "wasp/auth/forms/ResetPassword"; -import { LoginForm } from "wasp/auth/forms/Login"; -import { VerifyEmailForm } from "wasp/auth/forms/VerifyEmail"; -import { SignupForm } from "wasp/auth/forms/Signup"; import { + LoginForm, + SignupForm, + VerifyEmailForm, + ResetPasswordForm, + ForgotPasswordForm, FormError, FormInput, FormItemGroup, FormLabel, -} from "wasp/auth/forms/internal/Form"; +} from 'wasp/client/auth' + // import { // SignInButton as GitHubSignInButton, // signInUrl as gitHubSignInUrl, @@ -17,8 +19,7 @@ import { // signInUrl as googleSignInUrl, // } from "wasp/auth/helpers/Google"; -import { ForgotPasswordForm } from "wasp/auth/forms/ForgotPassword"; -import { Link, routes } from "wasp/router"; +import { Link, routes } from 'wasp/router' export function SignupPage() { return ( @@ -32,15 +33,15 @@ export function SignupPage() { Address {errors.address && ( {errors.address.message} )} - ); + ) }} /> {/*
@@ -55,7 +56,7 @@ export function SignupPage() { The link to the login page is {routes.LoginRoute.build()}. - ); + ) } export function LoginPage() { @@ -70,17 +71,17 @@ export function LoginPage() { I don't have an account yet (go to signup). - ); + ) } export function RequestPasswordResetPage() { - return ; + return } export function PasswordResetPage() { - return ; + return } export function EmailVerificationPage() { - return ; + return } diff --git a/waspc/src/Wasp/Generator/SdkGenerator.hs b/waspc/src/Wasp/Generator/SdkGenerator.hs index 363a1ad11..e3f168a9d 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator.hs @@ -37,6 +37,7 @@ import Wasp.Generator.Job.Process (runNodeCommandAsJob) import Wasp.Generator.Monad (Generator) import qualified Wasp.Generator.NpmDependencies as N import Wasp.Generator.SdkGenerator.AuthG (genAuth) +import Wasp.Generator.SdkGenerator.Client.AuthG (genNewClientAuth) import qualified Wasp.Generator.SdkGenerator.Common as C import Wasp.Generator.SdkGenerator.CrudG (genCrud) import Wasp.Generator.SdkGenerator.EmailSenderG (depsRequiredByEmail, genEmailSender) @@ -112,6 +113,8 @@ genSdkReal spec = <++> genMiddleware spec <++> genExportedTypesDir spec <++> genEmailSender spec + -- New API + <++> genNewClientAuth spec where genFileCopy = return . C.mkTmplFd diff --git a/waspc/src/Wasp/Generator/SdkGenerator/Client/AuthG.hs b/waspc/src/Wasp/Generator/SdkGenerator/Client/AuthG.hs new file mode 100644 index 000000000..12fe44a5a --- /dev/null +++ b/waspc/src/Wasp/Generator/SdkGenerator/Client/AuthG.hs @@ -0,0 +1,87 @@ +module Wasp.Generator.SdkGenerator.Client.AuthG + ( genNewClientAuth, + ) +where + +import Data.Aeson (object, (.=)) +import qualified Data.Aeson as Aeson +import StrongPath (File', Path', Rel, relfile) +import Wasp.AppSpec (AppSpec) +import qualified Wasp.AppSpec.App as AS.App +import qualified Wasp.AppSpec.App.Auth as AS.Auth +import Wasp.AppSpec.Valid (getApp) +import Wasp.Generator.FileDraft (FileDraft) +import Wasp.Generator.Monad (Generator) +import Wasp.Generator.SdkGenerator.Common (SdkTemplatesDir) +import qualified Wasp.Generator.SdkGenerator.Common as C +import Wasp.Util ((<++>)) + +genNewClientAuth :: AppSpec -> Generator [FileDraft] +genNewClientAuth spec = + case maybeAuth of + Nothing -> return [] + Just auth -> + sequence + [ genAuthIndex auth, + genAuthUI auth + ] + <++> genAuthEmail auth + <++> genAuthUsername auth + <++> genAuthGoogle auth + <++> genAuthGitHub auth + where + maybeAuth = AS.App.auth $ snd $ getApp spec + +genAuthIndex :: AS.Auth.Auth -> Generator FileDraft +genAuthIndex auth = + return $ + C.mkTmplFdWithData + [relfile|client/auth/index.ts|] + tmplData + where + tmplData = getAuthProvidersJson auth + +genAuthUI :: AS.Auth.Auth -> Generator FileDraft +genAuthUI auth = + return $ + C.mkTmplFdWithData + [relfile|client/auth/ui.ts|] + tmplData + where + tmplData = getAuthProvidersJson auth + +genAuthEmail :: AS.Auth.Auth -> Generator [FileDraft] +genAuthEmail auth = + if AS.Auth.isEmailAuthEnabled auth + then sequence [genFileCopy [relfile|client/auth/email.ts|]] + else return [] + +genAuthUsername :: AS.Auth.Auth -> Generator [FileDraft] +genAuthUsername auth = + if AS.Auth.isUsernameAndPasswordAuthEnabled auth + then sequence [genFileCopy [relfile|client/auth/username.ts|]] + else return [] + +genAuthGoogle :: AS.Auth.Auth -> Generator [FileDraft] +genAuthGoogle auth = + if AS.Auth.isGoogleAuthEnabled auth + then sequence [genFileCopy [relfile|client/auth/google.ts|]] + else return [] + +genAuthGitHub :: AS.Auth.Auth -> Generator [FileDraft] +genAuthGitHub auth = + if AS.Auth.isGitHubAuthEnabled auth + then sequence [genFileCopy [relfile|client/auth/github.ts|]] + else return [] + +getAuthProvidersJson :: AS.Auth.Auth -> Aeson.Value +getAuthProvidersJson auth = + object + [ "isGoogleAuthEnabled" .= AS.Auth.isGoogleAuthEnabled auth, + "isGitHubAuthEnabled" .= AS.Auth.isGitHubAuthEnabled auth, + "isUsernameAndPasswordAuthEnabled" .= AS.Auth.isUsernameAndPasswordAuthEnabled auth, + "isEmailAuthEnabled" .= AS.Auth.isEmailAuthEnabled auth + ] + +genFileCopy :: Path' (Rel SdkTemplatesDir) File' -> Generator FileDraft +genFileCopy = return . C.mkTmplFd diff --git a/waspc/waspc.cabal b/waspc/waspc.cabal index d560ef184..c617e90d6 100644 --- a/waspc/waspc.cabal +++ b/waspc/waspc.cabal @@ -308,6 +308,7 @@ library Wasp.Generator.SdkGenerator.EmailSender.Providers Wasp.Generator.SdkGenerator.WebSocketGenerator Wasp.Generator.SdkGenerator.RouterGenerator + Wasp.Generator.SdkGenerator.Client.AuthG Wasp.Generator.ServerGenerator Wasp.Generator.ServerGenerator.JsImport Wasp.Generator.ServerGenerator.ApiRoutesG