Skip to content

Commit

Permalink
Fixes some of the @ts-ignored types
Browse files Browse the repository at this point in the history
  • Loading branch information
infomiho committed Nov 21, 2024
1 parent a509762 commit 4a88a94
Show file tree
Hide file tree
Showing 17 changed files with 54 additions and 52 deletions.
2 changes: 0 additions & 2 deletions waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ function createUserGetter(): Query<void, AuthUser | null> {
try {
const response = await api.get(getMeRoute.path)
const userData = superjsonDeserialize<AuthUserData | null>(response.data)
// TODO: figure out why overloading is not working
// @ts-ignore
return makeAuthUserIfPossible(userData)
} catch (error) {
if (error.response?.status === 401) {
Expand Down
1 change: 1 addition & 0 deletions waspc/data/Generator/templates/sdk/wasp/auth/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export type { AuthUserData, AuthUser } from '../server/auth/user.js'
// PRIVATE API (used in SDK and server)
export function makeAuthUserIfPossible(user: null): null
export function makeAuthUserIfPossible(user: AuthUserData): AuthUser
export function makeAuthUserIfPossible(user: AuthUserData | null): AuthUser | null
export function makeAuthUserIfPossible(
user: AuthUserData | null,
): AuthUser | null {
Expand Down
37 changes: 22 additions & 15 deletions waspc/data/Generator/templates/sdk/wasp/auth/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export async function updateAuthIdentityProviderData<PN extends ProviderName>(
): Promise<{= authIdentityEntityUpper =}> {
// We are doing the sanitization here only on updates to avoid
// hashing the password multiple times.
const sanitizedProviderDataUpdates = await sanitizeProviderData(providerDataUpdates);
const sanitizedProviderDataUpdates = await ensurePasswordIsHashed(providerDataUpdates);
const newProviderData = {
...existingProviderData,
...sanitizedProviderDataUpdates,
Expand Down Expand Up @@ -261,38 +261,45 @@ export async function validateAndGetUserFields(
}

// PUBLIC API
export function deserializeAndSanitizeProviderData<PN extends ProviderName>(
export function getProviderData<PN extends ProviderName>(
providerData: string,
): Omit<PossibleProviderData[PN], 'hashedPassword'> {
return sanitizeProviderData(getProviderDataWithPassword(providerData));
}

// PUBLIC API
export function getProviderDataWithPassword<PN extends ProviderName>(
providerData: string,
{ shouldRemovePasswordField = false }: { shouldRemovePasswordField?: boolean } = {},
): PossibleProviderData[PN] {
// NOTE: We are letting JSON.parse throw an error if the providerData is not valid JSON.
let data = JSON.parse(providerData) as PossibleProviderData[PN];

if (providerDataHasPasswordField(data) && shouldRemovePasswordField) {
// TODO: we are removing the password from the runtime data, but we are not
// signaling that in the type system. The return type of this function should
// be different when `shouldRemovePasswordField` is true.
// @ts-ignore
delete data.hashedPassword;
}
return JSON.parse(providerData) as PossibleProviderData[PN];
}

return data;
function sanitizeProviderData<PN extends ProviderName>(
providerData: PossibleProviderData[PN],
): Omit<PossibleProviderData[PN], 'hashedPassword'> {
if (providerDataHasPasswordField(providerData)) {
const { hashedPassword, ...rest } = providerData;
return rest;
} else {
return providerData;
}
}

// PUBLIC API
export async function sanitizeAndSerializeProviderData<PN extends ProviderName>(
providerData: PossibleProviderData[PN],
): Promise<string> {
return serializeProviderData(
await sanitizeProviderData(providerData)
await ensurePasswordIsHashed(providerData)
);
}

function serializeProviderData<PN extends ProviderName>(providerData: PossibleProviderData[PN]): string {
return JSON.stringify(providerData);
}

async function sanitizeProviderData<PN extends ProviderName>(
async function ensurePasswordIsHashed<PN extends ProviderName>(
providerData: PossibleProviderData[PN],
): Promise<PossibleProviderData[PN]> {
const data = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ export function useQuery<Input, Output>(
// todo: The full queryCacheKey is constructed in two places, both here and
// inside the Query. See https://github.com/wasp-lang/wasp/issues/2017
queryKey: makeQueryCacheKey(query, queryFnArgs),
queryFn: () => query(queryFnArgs),
// FIXME: query fns don't handle the `undefined` case correctly
// https://github.com/wasp-lang/wasp/issues/2017
queryFn: () => query(queryFnArgs as Input),
...options,
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,4 @@ type ClientOperationWithNonAnyInput<Input, Output> =
? (args?: unknown) => Promise<Output>
: [Input] extends [void]
? () => Promise<Output>
: (args?: Input) => Promise<Output>
: (args: Input) => Promise<Output>
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
createProviderId,
updateAuthIdentityProviderData,
findAuthIdentity,
deserializeAndSanitizeProviderData,
getProviderDataWithPassword,
type EmailProviderData,
} from 'wasp/auth/utils';
import { config as waspServerConfig } from 'wasp/server';
Expand Down Expand Up @@ -69,7 +69,7 @@ async function sendEmailAndSaveMetadata(
throw new Error(`User with email: ${email} not found.`);
}

const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData);
const providerData = getProviderDataWithPassword<'email'>(authIdentity.providerData);
await updateAuthIdentityProviderData<'email'>(providerId, providerData, metadata);

emailSender.send(content).catch((e) => {
Expand Down
3 changes: 2 additions & 1 deletion waspc/data/Generator/templates/sdk/wasp/server/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ export {
createProviderId,
sanitizeAndSerializeProviderData,
updateAuthIdentityProviderData,
deserializeAndSanitizeProviderData,
getProviderData,
getProviderDataWithPassword,
findAuthIdentity,
createUser,
type ProviderId,
Expand Down
6 changes: 2 additions & 4 deletions waspc/data/Generator/templates/sdk/wasp/server/auth/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from '../../entities/index.js'
import {
type PossibleProviderData,
deserializeAndSanitizeProviderData
getProviderData,
} from '../../auth/utils.js'
import { type ProviderName } from '../_types/index.js'
import { Expand } from '../../universal/types.js'
Expand Down Expand Up @@ -129,9 +129,7 @@ function getProviderInfo<PN extends ProviderName>(
return null
}
return {
...deserializeAndSanitizeProviderData<PN>(identity.providerData, {
shouldRemovePasswordField: true,
}),
...getProviderData<PN>(identity.providerData),
id: identity.providerUserId,
}
}
Expand Down
5 changes: 2 additions & 3 deletions waspc/data/Generator/templates/sdk/wasp/server/email/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import { EmailSender } from "./core/types.js";
// TODO: We need to validate all the env variables
// For now, we are letting the runtime throw if they are not provided
{=# isSmtpProviderUsed =}
const emailProvider = {
const emailProvider = {
type: "smtp",
host: process.env.SMTP_HOST!,
// @ts-ignore
port: parseInt(process.env.SMTP_PORT, 10),
port: parseInt(process.env.SMTP_PORT!, 10),
username: process.env.SMTP_USERNAME!,
password: process.env.SMTP_PASSWORD!,
} as const;
Expand Down
4 changes: 0 additions & 4 deletions waspc/data/Generator/templates/sdk/wasp/server/jobs/_job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ export type {= typeName =}<Input extends JSONObject, Output extends JSONValue |
export const {= jobName =} = createJobDefinition({
jobName: '{= jobName =}',
defaultJobOptions: {=& jobPerformOptions =},
// TODO: jobSchdule template variable is a JSON string
// and the "args" field is outputted as "null" but it should be "undefined"
// when the value is not provided
// @ts-ignore
jobSchedule: {=& jobSchedule =},
entities,
})
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
createProviderId,
findAuthIdentity,
findAuthWithUserBy,
deserializeAndSanitizeProviderData,
getProviderDataWithPassword,
} from 'wasp/auth/utils'
import { createSession } from 'wasp/auth/session'
import { ensureValidEmail, ensurePasswordIsPresent } from 'wasp/auth/validation'
Expand All @@ -24,7 +24,7 @@ export function getLoginRoute() {
if (!authIdentity) {
throw createInvalidCredentialsError()
}
const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData)
const providerData = getProviderDataWithPassword<'email'>(authIdentity.providerData)
if (!providerData.isEmailVerified) {
throw createInvalidCredentialsError()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
createProviderId,
findAuthIdentity,
doFakeWork,
deserializeAndSanitizeProviderData,
getProviderDataWithPassword,
} from 'wasp/auth/utils';
import {
createPasswordResetLink,
Expand Down Expand Up @@ -46,7 +46,7 @@ export function getRequestPasswordResetRoute({
return res.json({ success: true });
}

const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData);
const providerData = getProviderDataWithPassword<'email'>(authIdentity.providerData);
const { isResendAllowed, timeLeft } = isEmailResendAllowed(providerData, 'passwordResetSentAt');
if (!isResendAllowed) {
throw new HttpError(400, `Please wait ${timeLeft} secs before trying again.`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
createProviderId,
findAuthIdentity,
updateAuthIdentityProviderData,
deserializeAndSanitizeProviderData,
getProviderDataWithPassword,
} from 'wasp/auth/utils';
import { validateJWT } from 'wasp/auth/jwt'
import { ensureTokenIsPresent, ensurePasswordIsPresent, ensureValidPassword } from 'wasp/auth/validation';
Expand All @@ -28,7 +28,7 @@ export async function resetPassword(
throw new HttpError(400, "Password reset failed, invalid token");
}

const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData);
const providerData = getProviderDataWithPassword<'email'>(authIdentity.providerData);

await updateAuthIdentityProviderData(providerId, providerData, {
// The act of resetting the password verifies the email
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
findAuthIdentity,
deleteUserByAuthId,
doFakeWork,
deserializeAndSanitizeProviderData,
getProviderDataWithPassword,
sanitizeAndSerializeProviderData,
rethrowPossibleAuthError,
} from 'wasp/auth/utils'
Expand Down Expand Up @@ -74,7 +74,7 @@ export function getSignupRoute({
* address unavailable for later account creation (by real owner).
*/
if (existingAuthIdentity) {
const providerData = deserializeAndSanitizeProviderData<'email'>(
const providerData = getProviderDataWithPassword<'email'>(
existingAuthIdentity.providerData,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
createProviderId,
findAuthIdentity,
updateAuthIdentityProviderData,
deserializeAndSanitizeProviderData,
getProviderDataWithPassword,
} from 'wasp/auth/utils';
import { validateJWT } from 'wasp/auth/jwt'
import { HttpError } from 'wasp/server';
Expand All @@ -25,7 +25,7 @@ export async function verifyEmail(
throw new HttpError(400, "Email verification failed, invalid token");
}

const providerData = deserializeAndSanitizeProviderData<'email'>(authIdentity.providerData);
const providerData = getProviderDataWithPassword<'email'>(authIdentity.providerData);

await updateAuthIdentityProviderData(providerId, providerData, {
isEmailVerified: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
createProviderId,
findAuthIdentity,
findAuthWithUserBy,
deserializeAndSanitizeProviderData,
getProviderDataWithPassword,
} from 'wasp/auth/utils'
import { createSession } from 'wasp/auth/session'
import { ensureValidUsername, ensurePasswordIsPresent } from 'wasp/auth/validation'
Expand All @@ -24,7 +24,7 @@ export default handleRejection(async (req, res) => {
}

try {
const providerData = deserializeAndSanitizeProviderData<'username'>(authIdentity.providerData)
const providerData = getProviderDataWithPassword<'username'>(authIdentity.providerData)

await verifyPassword(providerData.hashedPassword, fields.password)
} catch(e) {
Expand Down
14 changes: 7 additions & 7 deletions waspc/examples/todoApp/src/testTypes/operations/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,30 @@ import { Expect, Equal } from '../helpers'
import { QueryMetadata } from 'wasp/client/operations/rpc'

type TestCases = [
Expect<Equal<typeof taskToTaskSpecified, (args?: Task) => Promise<Task>>>,
Expect<Equal<typeof taskToTaskSpecified, (args: Task) => Promise<Task>>>,
Expect<
Equal<
typeof taskToTaskUnspecified,
(args?: Task) => ReturnType<typeof taskToTaskUnspecifiedDefinition>
(args: Task) => ReturnType<typeof taskToTaskUnspecifiedDefinition>
>
>,
Expect<
Equal<
typeof taskToTaskSatisfies,
(args?: Task) => ReturnType<typeof taskToTaskSatisfiesDefinition>
(args: Task) => ReturnType<typeof taskToTaskSatisfiesDefinition>
>
>,
Expect<
Equal<typeof unspecifiedToNumber, (args?: unknown) => Promise<number>>
>,
Expect<Equal<typeof voidToStringNoAuth, () => Promise<string>>>,
Expect<
Equal<typeof boolToStringNoAuth, (payload?: boolean) => Promise<string>>
Equal<typeof boolToStringNoAuth, (payload: boolean) => Promise<string>>
>,
Expect<Equal<typeof voidToStringAuth, () => Promise<string>>>,
Expect<Equal<typeof boolToStringAuth, (payload?: boolean) => Promise<string>>>,
Expect<Equal<typeof boolToVoidNoAuth, (payload?: boolean) => Promise<void>>>,
Expect<Equal<typeof boolToVoidAuth, (payload?: boolean) => Promise<void>>>,
Expect<Equal<typeof boolToStringAuth, (payload: boolean) => Promise<string>>>,
Expect<Equal<typeof boolToVoidNoAuth, (payload: boolean) => Promise<void>>>,
Expect<Equal<typeof boolToVoidAuth, (payload: boolean) => Promise<void>>>,
Expect<Equal<typeof getDate, QueryMetadata & (() => Promise<Date>)>>,
Expect<
Equal<
Expand Down

0 comments on commit 4a88a94

Please sign in to comment.