-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add userSignupFields
types to public signup
functions
#2641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@@ -25,7 +30,7 @@ export type ProviderConfig = { | |||
export type RequestWithWasp = Request & { wasp?: { [key: string]: any } } | |||
|
|||
// PRIVATE API | |||
export type PossibleUserFields = Expand<Partial<UserEntityCreateInput>> | |||
export type PossibleUserFields = Expand<Partial<Exclude<UserEntityCreateInput, 'auth'>>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prisma always ships this field. Do we want to keep it?
import { onBeforeSignupHook, onAfterSignupHook } from '../../hooks.js'; | ||
|
||
export function getSignupRoute({ | ||
userSignupFields, | ||
}: { | ||
userSignupFields?: UserSignupFields; | ||
}) { | ||
return handleRejection(async function signup(req, res) { | ||
return handleRejection(async function signup( | ||
req: Request<{ username: string; password: string } & UserSignupFieldsData>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't really use types here, but it will help once we hopefully escape this template madness.
OAuth thingies are done on server out of the reach of the user. Don't think we have anything to do there. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should approach this from a different angle because I think the current implementation lies with types 😄
The types lie
Let's say that my User
model looks like this:
model User {
id Int @id @default(autoincrement())
isOnAfterSignupHookCalled Boolean @default(false)
isOnAfterLoginHookCalled Boolean @default(false)
tasks Task[]
address String?
votes TaskVote[]
}
I get the following extra fields on the signup
fn:
type UserSignupFieldsData = {
isOnAfterSignupHookCalled?: boolean | undefined;
isOnAfterLoginHookCalled?: boolean | undefined;
address?: string | null | undefined;
tasks?: Prisma.TaskCreateNestedManyWithoutUserInput | undefined;
votes?: Prisma.TaskVoteCreateNestedManyWithoutUserInput | undefined;
}
But my extra user signup fields are defined like this:
export const userSignupFields = defineUserSignupFields({
address: (data) => {
if (typeof data.address !== 'string') {
throw new Error('Address is required.')
}
if (data.address.length < 10) {
throw new Error('Address must be at least 10 characters long.')
}
return data.address
},
})
On the client, I can call the signup
fn like this:
await signup({ email, password, isOnAfterLoginHookCalled: true })
without any type errors. But the runtime code won't save the isOnAfterSignupHookCalled
field value.
I'd advise maybe getting the type of the userSignupFields
user-defined fn to get the correct types.
address
should ideally be required
One extra thing to note here, address
is validated in userSignupFields
but I guess we can't infer that it should be required unless we redefine how users provide us validation for the extra fields (e.g. providing us with a Zod schema).
await signup({ email, password, address: undefined })
That's out of scope for this PR, but we might want to define an issue for that if we can formulate it clearly.
# Conflicts: # waspc/data/Generator/templates/sdk/wasp/auth/signup.ts
// PUBLIC API | ||
export function defineUserSignupFields(fields: UserSignupFields): UserSignupFields { | ||
export function defineUserSignupFields<T extends UserSignupFields>( | ||
fields: T & LimitTo<T, UserSignupFields> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throws error if user uses keys outside of UserSignupFields.
Required since we use generics now.
? { | ||
[K in keyof T]: T[K] extends (data: any) => infer R ? R : never | ||
} | ||
: {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On fail its {}
so it doesn't change the type of objects which extend this type.
defineUserSignupFields, | ||
} from "wasp/server/auth"; | ||
} from 'wasp/server/auth' | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someone didn't use prettier, should I exclude these changes from this PR?
Type should be inferred properly now while keeping the type guard at Reminder for myself not to import |
Fixes #2592