diff --git a/apps/api/v1/lib/validations/booking.ts b/apps/api/v1/lib/validations/booking.ts index acba26f724..202c8f3c9d 100644 --- a/apps/api/v1/lib/validations/booking.ts +++ b/apps/api/v1/lib/validations/booking.ts @@ -8,7 +8,8 @@ import { _TeamModel, _UserModel, } from "@calcom/prisma/zod"; -import { extendedBookingCreateBody, iso8601 } from "@calcom/prisma/zod-utils"; +import { iso8601 } from "@calcom/prisma/zod-utils"; +import { extendedBookingCreateBody } from "@calcom/prisma/zod/custom/booking"; import { schemaQueryUserId } from "./shared/queryUserId"; diff --git a/packages/features/bookings/lib/getBookingDataSchema.ts b/packages/features/bookings/lib/getBookingDataSchema.ts index 25f379f0b2..ad32844939 100644 --- a/packages/features/bookings/lib/getBookingDataSchema.ts +++ b/packages/features/bookings/lib/getBookingDataSchema.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { extendedBookingCreateBody } from "@calcom/prisma/zod-utils"; +import { extendedBookingCreateBody } from "@calcom/prisma/zod/custom/booking"; import type { getBookingFieldsWithSystemFields } from "./getBookingFields"; import getBookingResponsesSchema from "./getBookingResponsesSchema"; diff --git a/packages/features/bookings/lib/getBookingDataSchemaForApi.ts b/packages/features/bookings/lib/getBookingDataSchemaForApi.ts index 94c2aaf207..2fc84231d0 100644 --- a/packages/features/bookings/lib/getBookingDataSchemaForApi.ts +++ b/packages/features/bookings/lib/getBookingDataSchemaForApi.ts @@ -3,7 +3,7 @@ import { z } from "zod"; import { bookingCreateBodySchemaForApi, bookingCreateSchemaLegacyPropsForApi, -} from "@calcom/prisma/zod-utils"; +} from "@calcom/prisma/zod/custom/booking"; import type { getBookingFieldsWithSystemFields } from "./getBookingFields"; import getBookingResponsesSchema from "./getBookingResponsesSchema"; diff --git a/packages/features/bookings/lib/handleNewBooking/getBookingData.ts b/packages/features/bookings/lib/handleNewBooking/getBookingData.ts index 1a2fffa542..2360ff6661 100644 --- a/packages/features/bookings/lib/handleNewBooking/getBookingData.ts +++ b/packages/features/bookings/lib/handleNewBooking/getBookingData.ts @@ -5,7 +5,7 @@ import type z from "zod"; import dayjs from "@calcom/dayjs"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { ErrorCode } from "@calcom/lib/errorCodes"; -import { bookingCreateSchemaLegacyPropsForApi } from "@calcom/prisma/zod-utils"; +import { bookingCreateSchemaLegacyPropsForApi } from "@calcom/prisma/zod/custom/booking"; import type { TgetBookingDataSchema } from "../getBookingDataSchema"; import { handleCustomInputs } from "./handleCustomInputs"; diff --git a/packages/features/bookings/lib/handleNewBooking/getCustomInputsResponses.ts b/packages/features/bookings/lib/handleNewBooking/getCustomInputsResponses.ts index 76e34fb83e..3cf9f15718 100644 --- a/packages/features/bookings/lib/handleNewBooking/getCustomInputsResponses.ts +++ b/packages/features/bookings/lib/handleNewBooking/getCustomInputsResponses.ts @@ -1,7 +1,7 @@ import type z from "zod"; import { slugify } from "@calcom/lib/slugify"; -import type { bookingCreateSchemaLegacyPropsForApi } from "@calcom/prisma/zod-utils"; +import type { bookingCreateSchemaLegacyPropsForApi } from "@calcom/prisma/zod/custom/booking"; import type { CalendarEvent } from "@calcom/types/Calendar"; import type { getEventTypeResponse } from "./types"; diff --git a/packages/features/bookings/types.ts b/packages/features/bookings/types.ts index 7f68486f48..783f01810c 100644 --- a/packages/features/bookings/types.ts +++ b/packages/features/bookings/types.ts @@ -1,7 +1,7 @@ import type { SchedulingType } from "@prisma/client"; import type { ErrorOption, FieldPath } from "react-hook-form"; -import type { BookingCreateBody } from "@calcom/prisma/zod-utils"; +import type { BookingCreateBody } from "@calcom/prisma/zod/custom/booking"; import type { RouterOutputs } from "@calcom/trpc/react"; import type { AppsStatus } from "@calcom/types/Calendar"; diff --git a/packages/platform/atoms/hooks/bookings/useCreateBooking.ts b/packages/platform/atoms/hooks/bookings/useCreateBooking.ts index dc3dc73f21..4d3ac0f870 100644 --- a/packages/platform/atoms/hooks/bookings/useCreateBooking.ts +++ b/packages/platform/atoms/hooks/bookings/useCreateBooking.ts @@ -3,7 +3,7 @@ import { useMutation } from "@tanstack/react-query"; import { SUCCESS_STATUS } from "@calcom/platform-constants"; import type { BookingResponse } from "@calcom/platform-libraries"; import type { ApiResponse, ApiErrorResponse, ApiSuccessResponse } from "@calcom/platform-types"; -import type { BookingCreateBody } from "@calcom/prisma/zod-utils"; +import type { BookingCreateBody } from "@calcom/prisma/zod/custom/booking"; import http from "../../lib/http"; diff --git a/packages/platform/atoms/hooks/bookings/useCreateInstantBooking.ts b/packages/platform/atoms/hooks/bookings/useCreateInstantBooking.ts index 834f75204a..61dd41a595 100644 --- a/packages/platform/atoms/hooks/bookings/useCreateInstantBooking.ts +++ b/packages/platform/atoms/hooks/bookings/useCreateInstantBooking.ts @@ -3,7 +3,7 @@ import { useMutation } from "@tanstack/react-query"; import { SUCCESS_STATUS } from "@calcom/platform-constants"; import type { BookingResponse } from "@calcom/platform-libraries"; import type { ApiResponse, ApiErrorResponse, ApiSuccessResponse } from "@calcom/platform-types"; -import type { BookingCreateBody } from "@calcom/prisma/zod-utils"; +import type { BookingCreateBody } from "@calcom/prisma/zod/custom/booking"; import http from "../../lib/http"; diff --git a/packages/platform/atoms/hooks/bookings/useHandleBookEvent.ts b/packages/platform/atoms/hooks/bookings/useHandleBookEvent.ts index 062555c178..a24dbfd62d 100644 --- a/packages/platform/atoms/hooks/bookings/useHandleBookEvent.ts +++ b/packages/platform/atoms/hooks/bookings/useHandleBookEvent.ts @@ -7,7 +7,7 @@ import { mapBookingToMutationInput, mapRecurringBookingToMutationInput } from "@ import type { BookerEvent } from "@calcom/features/bookings/types"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { RoutingFormSearchParams } from "@calcom/platform-types"; -import type { BookingCreateBody } from "@calcom/prisma/zod-utils"; +import type { BookingCreateBody } from "@calcom/prisma/zod/custom/booking"; import { showToast } from "@calcom/ui"; import type { UseCreateBookingInput } from "./useCreateBooking"; diff --git a/packages/prisma/zod-utils.ts b/packages/prisma/zod-utils.ts index 45b93c2ef5..627ff17c2c 100644 --- a/packages/prisma/zod-utils.ts +++ b/packages/prisma/zod-utils.ts @@ -13,12 +13,10 @@ import type { } from "zod"; import { appDataSchemas } from "@calcom/app-store/apps.schemas.generated"; -import { routingFormResponseInDbSchema } from "@calcom/app-store/routing-forms/zod"; import dayjs from "@calcom/dayjs"; import { isPasswordValid } from "@calcom/features/auth/lib/isPasswordValid"; import type { FieldType as FormBuilderFieldType } from "@calcom/features/form-builder/schema"; import { fieldsSchema as formBuilderFieldsSchema } from "@calcom/features/form-builder/schema"; -import { isSupportedTimeZone } from "@calcom/lib/date-fns"; import { emailSchema as emailRegexSchema, emailRegex } from "@calcom/lib/emailSchema"; import type { IntervalLimit } from "@calcom/lib/intervalLimits/intervalLimitSchema"; import { zodAttributesQueryValue } from "@calcom/lib/raqb/zod"; @@ -243,43 +241,6 @@ export const stringToDayjs = (val: string) => { export const stringToDayjsZod = z.string().transform(stringToDayjs); -export const bookingCreateBodySchema = z.object({ - end: z.string().optional(), - eventTypeId: z.number(), - eventTypeSlug: z.string().optional(), - rescheduleUid: z.string().optional(), - recurringEventId: z.string().optional(), - rescheduledBy: z.string().email({ message: "Invalid email" }).optional(), - start: z.string(), - timeZone: z.string().refine((value: string) => isSupportedTimeZone(value), { message: "Invalid timezone" }), - user: z.union([z.string(), z.array(z.string())]).optional(), - language: z.string(), - bookingUid: z.string().optional(), - metadata: z.record(z.string()), - hasHashedBookingLink: z.boolean().optional(), - hashedLink: z.string().nullish(), - seatReferenceUid: z.string().optional(), - orgSlug: z.string().optional(), - teamMemberEmail: z.string().nullish(), - crmOwnerRecordType: z.string().nullish(), - routedTeamMemberIds: z.array(z.number()).nullish(), - routingFormResponseId: z.number().optional(), - skipContactOwner: z.boolean().optional(), - crmAppSlug: z.string().nullish().optional(), - cfToken: z.string().nullish().optional(), - - /** - * Holds the corrected responses of the Form for a booking, provided during rerouting - */ - reroutingFormResponses: routingFormResponseInDbSchema.optional(), - /** - * Used to identify if the booking is a dry run. - */ - _isDryRun: z.boolean().optional(), - /** Whether to override the cache */ - _shouldServeCache: z.boolean().optional(), -}); - export const requiredCustomInputSchema = z.union([ // string must be given & nonempty z.string().trim().min(1), @@ -287,8 +248,6 @@ export const requiredCustomInputSchema = z.union([ z.boolean().refine((v) => v === true), ]); -export type BookingCreateBody = z.input; - const PlatformClientParamsSchema = z.object({ platformClientId: z.string().optional(), platformRescheduleUrl: z.string().nullable().optional(), @@ -308,54 +267,6 @@ export const bookingConfirmPatchBodySchema = z.object({ platformClientParams: PlatformClientParamsSchema.optional(), }); -// `responses` is merged with it during handleNewBooking call because `responses` schema is dynamic and depends on eventType -export const extendedBookingCreateBody = bookingCreateBodySchema.merge( - z.object({ - noEmail: z.boolean().optional(), - recurringCount: z.number().optional(), - allRecurringDates: z - .array( - z.object({ - start: z.string(), - end: z.string(), - }) - ) - .optional(), - currentRecurringIndex: z.number().optional(), - appsStatus: z - .array( - z.object({ - appName: z.string(), - success: z.number(), - failures: z.number(), - type: z.string(), - errors: z.string().array(), - warnings: z.string().array().optional(), - }) - ) - .optional(), - luckyUsers: z.array(z.number()).optional(), - customInputs: z.undefined().optional(), - }) -); - -// It has only the legacy props that are part of `responses` now. The API can still hit old props -export const bookingCreateSchemaLegacyPropsForApi = z.object({ - email: z.string(), - name: z.string(), - guests: z.array(z.string()).optional(), - notes: z.string().optional(), - location: z.string(), - smsReminderNumber: z.string().optional().nullable(), - rescheduleReason: z.string().optional(), - customInputs: z.array(z.object({ label: z.string(), value: z.union([z.string(), z.boolean()]) })), -}); - -// This is the schema that is used for the API. It has all the legacy props that are part of `responses` now. -export const bookingCreateBodySchemaForApi = extendedBookingCreateBody.merge( - bookingCreateSchemaLegacyPropsForApi.partial() -); - export const bookingCancelSchema = z.object({ id: z.number().optional(), uid: z.string().optional(), diff --git a/packages/prisma/zod/custom/booking.ts b/packages/prisma/zod/custom/booking.ts new file mode 100644 index 0000000000..19163913f5 --- /dev/null +++ b/packages/prisma/zod/custom/booking.ts @@ -0,0 +1,91 @@ +// `responses` is merged with it during handleNewBooking call because `responses` schema is dynamic and depends on eventType +import z, { ZodNullable, ZodObject, ZodOptional } from "zod"; +import { isSupportedTimeZone } from "@calcom/lib/date-fns"; +// TODO: Move this out of here. Importing from app-store is a circular package dependency. +import { routingFormResponseInDbSchema } from "@calcom/app-store/routing-forms/zod"; + +export const bookingCreateBodySchema = z.object({ + end: z.string().optional(), + eventTypeId: z.number(), + eventTypeSlug: z.string().optional(), + rescheduleUid: z.string().optional(), + recurringEventId: z.string().optional(), + rescheduledBy: z.string().email({ message: "Invalid email" }).optional(), + start: z.string(), + timeZone: z.string().refine((value: string) => isSupportedTimeZone(value), { message: "Invalid timezone" }), + user: z.union([z.string(), z.array(z.string())]).optional(), + language: z.string(), + bookingUid: z.string().optional(), + metadata: z.record(z.string()), + hasHashedBookingLink: z.boolean().optional(), + hashedLink: z.string().nullish(), + seatReferenceUid: z.string().optional(), + orgSlug: z.string().optional(), + teamMemberEmail: z.string().nullish(), + crmOwnerRecordType: z.string().nullish(), + routedTeamMemberIds: z.array(z.number()).nullish(), + routingFormResponseId: z.number().optional(), + skipContactOwner: z.boolean().optional(), + crmAppSlug: z.string().nullish().optional(), + cfToken: z.string().nullish().optional(), + + /** + * Holds the corrected responses of the Form for a booking, provided during rerouting + */ + reroutingFormResponses: routingFormResponseInDbSchema.optional(), + /** + * Used to identify if the booking is a dry run. + */ + _isDryRun: z.boolean().optional(), + /** Whether to override the cache */ + _shouldServeCache: z.boolean().optional(), +}); + +export type BookingCreateBody = z.input; + +export const extendedBookingCreateBody = bookingCreateBodySchema.merge( + z.object({ + noEmail: z.boolean().optional(), + recurringCount: z.number().optional(), + allRecurringDates: z + .array( + z.object({ + start: z.string(), + end: z.string(), + }) + ) + .optional(), + currentRecurringIndex: z.number().optional(), + appsStatus: z + .array( + z.object({ + appName: z.string(), + success: z.number(), + failures: z.number(), + type: z.string(), + errors: z.string().array(), + warnings: z.string().array().optional(), + }) + ) + .optional(), + luckyUsers: z.array(z.number()).optional(), + customInputs: z.undefined().optional(), + }) +); + +// It has only the legacy props that are part of `responses` now. The API can still hit old props +export const bookingCreateSchemaLegacyPropsForApi = z.object({ + email: z.string(), + name: z.string(), + guests: z.array(z.string()).optional(), + notes: z.string().optional(), + location: z.string(), + smsReminderNumber: z.string().optional().nullable(), + rescheduleReason: z.string().optional(), + customInputs: z.array(z.object({ label: z.string(), value: z.union([z.string(), z.boolean()]) })), +}); + +// This is the schema that is used for the API. It has all the legacy props that are part of `responses` now. +export const bookingCreateBodySchemaForApi = extendedBookingCreateBody.merge( + bookingCreateSchemaLegacyPropsForApi.partial() +);