Skeleton for Booking flow refactor using Factory and services (#23277)

This commit is contained in:
Hariom Balhara
2025-09-02 11:06:31 +00:00
committed by GitHub
parent 16bd52148e
commit 9ceb5ea3c5
17 changed files with 325 additions and 41 deletions
+18 -1
View File
@@ -4,10 +4,10 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import handleNewBooking from "@calcom/features/bookings/lib/handleNewBooking";
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
import getIP from "@calcom/lib/getIP";
import { piiHasher } from "@calcom/lib/server/PiiHasher";
import { checkCfTurnstileToken } from "@calcom/lib/server/checkCfTurnstileToken";
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
import { CreationSource } from "@calcom/prisma/enums";
import { piiHasher } from "@calcom/lib/server/PiiHasher";
async function handler(req: NextApiRequest & { userId?: number }) {
const userIp = getIP(req);
@@ -37,7 +37,24 @@ async function handler(req: NextApiRequest & { userId?: number }) {
hostname: req.headers.host || "",
forcedSlug: req.headers["x-cal-force-slug"] as string | undefined,
});
// const booking = await createBookingThroughFactory();
return booking;
// To be added in the follow-up PR
// async function createBookingThroughFactory() {
// console.log("Creating booking through factory");
// const regularBookingService = getRegularBookingService();
// const booking = await regularBookingService.createBooking({
// bookingData: req.body,
// bookingMeta: {
// userId: session?.user?.id || -1,
// hostname: req.headers.host || "",
// forcedSlug: req.headers["x-cal-force-slug"] as string | undefined,
// },
// });
// return booking;
// }
}
export default defaultResponder(handler, "/api/book/event");
+1 -1
View File
@@ -4,9 +4,9 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import handleInstantMeeting from "@calcom/features/instant-meeting/handleInstantMeeting";
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
import getIP from "@calcom/lib/getIP";
import { piiHasher } from "@calcom/lib/server/PiiHasher";
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
import { CreationSource } from "@calcom/prisma/enums";
import { piiHasher } from "@calcom/lib/server/PiiHasher";
async function handler(req: NextApiRequest & { userId?: number }) {
const userIp = getIP(req);
+1 -1
View File
@@ -5,9 +5,9 @@ import { handleNewRecurringBooking } from "@calcom/features/bookings/lib/handleN
import type { BookingResponse } from "@calcom/features/bookings/types";
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
import getIP from "@calcom/lib/getIP";
import { piiHasher } from "@calcom/lib/server/PiiHasher";
import { checkCfTurnstileToken } from "@calcom/lib/server/checkCfTurnstileToken";
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
import { piiHasher } from "@calcom/lib/server/PiiHasher";
// @TODO: Didn't look at the contents of this function in order to not break old booking page.
@@ -0,0 +1,13 @@
import { createContainer } from "@evyweb/ioctopus";
import { DI_TOKENS } from "@calcom/lib/di/tokens";
import type { InstantBookingCreateService } from "../modules/InstantBookingCreateServiceModule";
import { instantBookingCreateServiceModule } from "../modules/InstantBookingCreateServiceModule";
const container = createContainer();
container.load(DI_TOKENS.INSTANT_BOOKING_CREATE_SERVICE_MODULE, instantBookingCreateServiceModule);
export function getInstantBookingCreateService(): InstantBookingCreateService {
return container.get<InstantBookingCreateService>(DI_TOKENS.INSTANT_BOOKING_CREATE_SERVICE);
}
@@ -0,0 +1,28 @@
import { createContainer } from "@evyweb/ioctopus";
import { bookingRepositoryModule } from "@calcom/lib/di/modules/Booking";
import { cacheModule } from "@calcom/lib/di/modules/Cache";
import { checkBookingAndDurationLimitsModule } from "@calcom/lib/di/modules/CheckBookingAndDurationLimits";
import { checkBookingLimitsModule } from "@calcom/lib/di/modules/CheckBookingLimits";
import { featuresRepositoryModule } from "@calcom/lib/di/modules/Features";
import { DI_TOKENS } from "@calcom/lib/di/tokens";
import { prismaModule } from "@calcom/prisma/prisma.module";
import type { RecurringBookingService } from "../modules/RecurringBookingServiceModule";
import { recurringBookingServiceModule } from "../modules/RecurringBookingServiceModule";
const container = createContainer();
container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
container.load(DI_TOKENS.CACHE_SERVICE_MODULE, cacheModule);
container.load(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE_MODULE, checkBookingLimitsModule);
container.load(DI_TOKENS.FEATURES_REPOSITORY_MODULE, featuresRepositoryModule);
container.load(
DI_TOKENS.CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE_MODULE,
checkBookingAndDurationLimitsModule
);
container.load(DI_TOKENS.RECURRING_BOOKING_SERVICE_MODULE, recurringBookingServiceModule);
export function getRecurringBookingService(): RecurringBookingService {
return container.get<RecurringBookingService>(DI_TOKENS.RECURRING_BOOKING_SERVICE);
}
@@ -0,0 +1,20 @@
import { createContainer } from "@evyweb/ioctopus";
import { DI_TOKENS } from "@calcom/lib/di/tokens";
import type { RegularBookingService } from "../modules/RegularBookingServiceModule";
import {
regularBookingServiceModule,
loadModuleDeps,
moduleToken,
} from "../modules/RegularBookingServiceModule";
const regularBookingServiceContainer = createContainer();
regularBookingServiceContainer.load(DI_TOKENS.REGULAR_BOOKING_SERVICE_MODULE, regularBookingServiceModule);
export function getRegularBookingService(): RegularBookingService {
loadModuleDeps(regularBookingServiceContainer);
return regularBookingServiceContainer.get<RegularBookingService>(moduleToken);
}
@@ -0,0 +1,11 @@
import { createModule } from "@evyweb/ioctopus";
import { InstantBookingCreateService } from "@calcom/features/instant-meeting/handleInstantMeeting";
import { DI_TOKENS } from "@calcom/lib/di/tokens";
export const instantBookingCreateServiceModule = createModule();
instantBookingCreateServiceModule
.bind(DI_TOKENS.INSTANT_BOOKING_CREATE_SERVICE)
.toClass(InstantBookingCreateService);
export type { InstantBookingCreateService };
@@ -0,0 +1,13 @@
import { createModule } from "@evyweb/ioctopus";
import { DI_TOKENS } from "@calcom/lib/di/tokens";
import { RecurringBookingService } from "../../handleNewRecurringBooking";
export const recurringBookingServiceModule = createModule();
recurringBookingServiceModule.bind(DI_TOKENS.RECURRING_BOOKING_SERVICE).toClass(RecurringBookingService, {
regularBookingService: DI_TOKENS.REGULAR_BOOKING_SERVICE,
});
export type { RecurringBookingService };
@@ -0,0 +1,39 @@
import type { Container } from "@evyweb/ioctopus";
import { createModule } from "@evyweb/ioctopus";
import { bookingRepositoryModule } from "@calcom/lib/di/modules/Booking";
import { cacheModule } from "@calcom/lib/di/modules/Cache";
import { checkBookingAndDurationLimitsModule } from "@calcom/lib/di/modules/CheckBookingAndDurationLimits";
import { checkBookingLimitsModule } from "@calcom/lib/di/modules/CheckBookingLimits";
import { featuresRepositoryModule } from "@calcom/lib/di/modules/Features";
import { DI_TOKENS } from "@calcom/lib/di/tokens";
import { prismaModule } from "@calcom/prisma/prisma.module";
import { RegularBookingService } from "../../handleNewBooking";
export const regularBookingServiceModule = createModule();
const moduleToken = DI_TOKENS.REGULAR_BOOKING_SERVICE;
regularBookingServiceModule.bind(moduleToken).toClass(RegularBookingService, {
cacheService: DI_TOKENS.CACHE_SERVICE,
checkBookingAndDurationLimitsService: DI_TOKENS.CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE,
prismaClient: DI_TOKENS.PRISMA_CLIENT,
bookingRepository: DI_TOKENS.BOOKING_REPOSITORY,
featuresRepository: DI_TOKENS.FEATURES_REPOSITORY,
checkBookingLimitsService: DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE,
});
// Load the dependencies defined for the module above
function loadModuleDeps(container: Container) {
container.load(DI_TOKENS.CACHE_SERVICE_MODULE, cacheModule);
container.load(
DI_TOKENS.CHECK_BOOKING_AND_DURATION_LIMITS_SERVICE_MODULE,
checkBookingAndDurationLimitsModule
);
container.load(DI_TOKENS.PRISMA_MODULE, prismaModule);
container.load(DI_TOKENS.BOOKING_REPOSITORY_MODULE, bookingRepositoryModule);
container.load(DI_TOKENS.FEATURES_REPOSITORY_MODULE, featuresRepositoryModule);
container.load(DI_TOKENS.CHECK_BOOKING_LIMITS_SERVICE_MODULE, checkBookingLimitsModule);
}
export { loadModuleDeps, moduleToken };
export type { RegularBookingService };
+51
View File
@@ -0,0 +1,51 @@
/**
* Domain types for BookingCreateService
* These types are framework-agnostic and contain only the data required for booking operations
*/
import type { z } from "zod";
import type getBookingDataSchema from "@calcom/features/bookings/lib/getBookingDataSchema";
import type getBookingDataSchemaForApi from "@calcom/features/bookings/lib/getBookingDataSchemaForApi";
import type { BookingCreateBody as BaseCreateBookingData } from "@calcom/prisma/zod/custom/booking";
import type { extendedBookingCreateBody } from "@calcom/prisma/zod/custom/booking";
export type ExtendedBookingCreateData = z.input<typeof extendedBookingCreateBody>;
export type BookingDataSchemaGetter = typeof getBookingDataSchema | typeof getBookingDataSchemaForApi;
export type CreateRegularBookingData = BaseCreateBookingData;
export type CreateInstantBookingData = BaseCreateBookingData;
export type CreateRecurringBookingData = (BaseCreateBookingData & {
schedulingType?: SchedulingType;
})[];
export type PlatformParams = {
platformClientId?: string;
platformCancelUrl?: string;
platformBookingUrl?: string;
platformRescheduleUrl?: string;
platformBookingLocation?: string;
areCalendarEventsEnabled?: boolean;
};
export type CreateBookingMeta = {
userId?: number;
// These used to come from headers but now we're passing them as params
hostname?: string;
forcedSlug?: string;
noEmail?: boolean;
} & PlatformParams;
export type BookingHandlerInput = {
bookingData: CreateRegularBookingData;
} & CreateBookingMeta;
export type CreateInstantBookingResponse = {
message: string;
meetingTokenId: number;
bookingId: number;
bookingUid: string;
expires: Date;
userId: number | null;
};
@@ -25,14 +25,19 @@ import {
} from "@calcom/emails";
import getICalUID from "@calcom/emails/lib/getICalUID";
import { CalendarEventBuilder } from "@calcom/features/CalendarEventBuilder";
import type { BookingDataSchemaGetter } from "@calcom/features/bookings/lib/dto/types";
import type { CreateRegularBookingData, CreateBookingMeta } from "@calcom/features/bookings/lib/dto/types";
import type { CheckBookingAndDurationLimitsService } from "@calcom/features/bookings/lib/handleNewBooking/checkBookingAndDurationLimits";
import { handleWebhookTrigger } from "@calcom/features/bookings/lib/handleWebhookTrigger";
import { isEventTypeLoggingEnabled } from "@calcom/features/bookings/lib/isEventTypeLoggingEnabled";
import type { CacheService } from "@calcom/features/calendar-cache/lib/getShouldServeCache";
import AssignmentReasonRecorder from "@calcom/features/ee/round-robin/assignmentReason/AssignmentReasonRecorder";
import {
allowDisablingAttendeeConfirmationEmails,
allowDisablingHostConfirmationEmails,
} from "@calcom/features/ee/workflows/lib/allowDisablingStandardEmails";
import { scheduleWorkflowReminders } from "@calcom/features/ee/workflows/lib/reminders/reminderScheduler";
import type { FeaturesRepository } from "@calcom/features/flags/features.repository";
import { getFullName } from "@calcom/features/form-builder/utils";
import { UsersRepository } from "@calcom/features/users/users.repository";
import type { GetSubscriberOptions } from "@calcom/features/webhooks/lib/getWebhooks";
@@ -64,6 +69,7 @@ import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId";
import { getPaymentAppData } from "@calcom/lib/getPaymentAppData";
import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType";
import { HttpError } from "@calcom/lib/http-error";
import type { CheckBookingLimitsService } from "@calcom/lib/intervalLimits/server/checkBookingLimits";
import logger from "@calcom/lib/logger";
import { handlePayment } from "@calcom/lib/payment/handlePayment";
import { getPiiFreeCalendarEvent, getPiiFreeEventType } from "@calcom/lib/piiFreeData";
@@ -73,6 +79,7 @@ import { BookingRepository } from "@calcom/lib/server/repository/booking";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import { HashedLinkService } from "@calcom/lib/server/service/hashedLinkService";
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
import type { PrismaClient } from "@calcom/prisma";
import prisma from "@calcom/prisma";
import type { AssignmentReasonEnum } from "@calcom/prisma/enums";
import { BookingStatus, SchedulingType, WebhookTriggerEvents } from "@calcom/prisma/enums";
@@ -121,6 +128,7 @@ import type { IEventTypePaymentCredentialType, Invitee, IsFixedAwareUser } from
import { validateBookingTimeIsNotOutOfBounds } from "./handleNewBooking/validateBookingTimeIsNotOutOfBounds";
import { validateEventLength } from "./handleNewBooking/validateEventLength";
import handleSeats from "./handleSeats/handleSeats";
import type { IBookingService } from "./interfaces/IBookingService";
const translator = short();
const log = logger.getSubLogger({ prefix: ["[api] book:user"] });
@@ -150,10 +158,6 @@ function getICalSequence(originalRescheduledBooking: BookingType | null) {
return originalRescheduledBooking.iCalSequence + 1;
}
type BookingDataSchemaGetter =
| typeof getBookingDataSchema
| typeof import("@calcom/features/bookings/lib/getBookingDataSchemaForApi").default;
type CreatedBooking = Booking & { appsStatus?: AppsStatus[]; paymentUid?: string; paymentId?: number };
type ReturnTypeCreateBooking = Awaited<ReturnType<typeof createBooking>>;
export const buildDryRunBooking = ({
@@ -2455,3 +2459,38 @@ async function handler(
}
export default handler;
export interface IBookingServiceDependencies {
cacheService: CacheService;
checkBookingAndDurationLimitsService: CheckBookingAndDurationLimitsService;
prismaClient: PrismaClient;
bookingRepository: BookingRepository;
featuresRepository: FeaturesRepository;
checkBookingLimitsService: CheckBookingLimitsService;
}
/**
* Takes care of creating/rescheduling non-recurring, non-instant bookings. Such bookings could be TeamBooking, UserBooking, SeatedUserBooking, SeatedTeamBooking, etc.
* We can't name it CoreBookingService because non-instant booking also creates a booking but it is entirely different from the regular booking.
* We are open to renaming it to something more descriptive.
*/
export class RegularBookingService implements IBookingService {
constructor(private readonly deps: IBookingServiceDependencies) {}
async createBooking(input: { bookingData: CreateRegularBookingData; bookingMeta?: CreateBookingMeta }) {
// deps to be passed to handler in follow-up PR
return handler({ bookingData: input.bookingData, ...input.bookingMeta });
}
async rescheduleBooking(input: { bookingData: CreateRegularBookingData; bookingMeta?: CreateBookingMeta }) {
return handler({ bookingData: input.bookingData, ...input.bookingMeta });
}
async rescheduleBookingForApiV1(input: {
bookingData: CreateRegularBookingData;
bookingMeta?: CreateBookingMeta;
bookingDataSchemaGetter: BookingDataSchemaGetter;
}) {
return handler({ bookingData: input.bookingData, ...input.bookingMeta }, input.bookingDataSchemaGetter);
}
}
@@ -1,25 +1,15 @@
import type { CreateBookingMeta, CreateRecurringBookingData } from "@calcom/features/bookings/lib/dto/types";
import handleNewBooking from "@calcom/features/bookings/lib/handleNewBooking";
import type { BookingResponse } from "@calcom/features/bookings/types";
import { SchedulingType } from "@calcom/prisma/client";
import type { AppsStatus } from "@calcom/types/Calendar";
export type PlatformParams = {
platformClientId?: string;
platformCancelUrl?: string;
platformBookingUrl?: string;
platformRescheduleUrl?: string;
platformBookingLocation?: string;
areCalendarEventsEnabled?: boolean;
};
import type { RegularBookingService } from "./handleNewBooking";
import type { IBookingService } from "./interfaces/IBookingService";
export type BookingHandlerInput = {
bookingData: Record<string, any>[];
userId?: number;
// These used to come from headers but now we're passing them as params
hostname?: string;
forcedSlug?: string;
noEmail?: boolean;
} & PlatformParams;
bookingData: CreateRecurringBookingData;
} & CreateBookingMeta;
export const handleNewRecurringBooking = async (input: BookingHandlerInput): Promise<BookingResponse[]> => {
const data = input.bookingData;
@@ -115,7 +105,7 @@ export const handleNewRecurringBooking = async (input: BookingHandlerInput): Pro
if (!thirdPartyRecurringEventId) {
if (eachRecurringBooking.references && eachRecurringBooking.references.length > 0) {
for (const reference of eachRecurringBooking.references!) {
for (const reference of eachRecurringBooking.references) {
if (reference.thirdPartyRecurringEventId) {
thirdPartyRecurringEventId = reference.thirdPartyRecurringEventId;
break;
@@ -126,3 +116,32 @@ export const handleNewRecurringBooking = async (input: BookingHandlerInput): Pro
}
return createdBookings;
};
export interface IRecurringBookingServiceDependencies {
regularBookingService: RegularBookingService;
}
/**
* Recurring Booking Service takes care of creating/rescheduling recurring bookings.
*/
export class RecurringBookingService implements IBookingService {
constructor(private readonly deps: IRecurringBookingServiceDependencies) {}
async createBooking(input: {
bookingData: CreateRecurringBookingData;
bookingMeta?: CreateBookingMeta;
}): Promise<BookingResponse[]> {
const handlerInput = { bookingData: input.bookingData, ...(input.bookingMeta || {}) };
// FOLLOW-UP: Pass on dependencies to the handler
return handleNewRecurringBooking(handlerInput);
}
async rescheduleBooking(input: {
bookingData: CreateRecurringBookingData;
bookingMeta?: CreateBookingMeta;
}): Promise<BookingResponse[]> {
const handlerInput = { bookingData: input.bookingData, ...(input.bookingMeta || {}) };
// FOLLOW-UP: Pass on dependencies to the handler
return handleNewRecurringBooking(handlerInput);
}
}
@@ -0,0 +1,7 @@
// Defines an interface that could be used by any type of Booking Service
// "Any" types are used because this inteface is used by RecurringBookingService which accepts an array of bookingData and RegularBookingService which accepts a single bookingData
// So, this interface enforces just the methods that must be present but not their parameters and return types
export interface IBookingCreateService {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
createBooking: (...args: any[]) => Promise<any>;
}
@@ -0,0 +1,9 @@
// Defines an interface that could be used by any type of Booking Service
// "Any" types are used because this inteface is used by RecurringBookingService which accepts an array of bookingData and RegularBookingService which accepts a single bookingData
// So, this interface enforces just the methods that must be present but not their parameters and return types
export interface IBookingService {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
createBooking: (...args: any[]) => Promise<any>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rescheduleBooking: (...args: any[]) => Promise<any>;
}
@@ -5,11 +5,16 @@ import short from "short-uuid";
import { v5 as uuidv5 } from "uuid";
import dayjs from "@calcom/dayjs";
import type {
CreateInstantBookingData,
CreateInstantBookingResponse,
} from "@calcom/features/bookings/lib/dto/types";
import getBookingDataSchema from "@calcom/features/bookings/lib/getBookingDataSchema";
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
import { getBookingData } from "@calcom/features/bookings/lib/handleNewBooking/getBookingData";
import { getCustomInputsResponses } from "@calcom/features/bookings/lib/handleNewBooking/getCustomInputsResponses";
import { getEventTypesFromDB } from "@calcom/features/bookings/lib/handleNewBooking/getEventTypesFromDB";
import type { IBookingCreateService } from "@calcom/features/bookings/lib/interfaces/IBookingCreateService";
import { getFullName } from "@calcom/features/form-builder/utils";
import { sendNotification } from "@calcom/features/notifications/sendNotification";
import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload";
@@ -151,17 +156,8 @@ const triggerBrowserNotifications = async (args: {
await Promise.allSettled(promises);
};
export type HandleInstantMeetingResponse = {
message: string;
meetingTokenId: number;
bookingId: number;
bookingUid: string;
expires: Date;
userId: number | null;
};
async function handler(req: NextApiRequest) {
let eventType = await getEventTypesFromDB(req.body.eventTypeId);
async function _handler(bookingData: CreateInstantBookingData) {
let eventType = await getEventTypesFromDB(bookingData.eventTypeId);
const isOrgTeamEvent = !!eventType?.team && !!eventType?.team?.parentId;
eventType = {
...eventType,
@@ -173,11 +169,11 @@ async function handler(req: NextApiRequest) {
}
const schema = getBookingDataSchema({
view: req.body?.rescheduleUid ? "reschedule" : "booking",
view: bookingData?.rescheduleUid ? "reschedule" : "booking",
bookingFields: eventType.bookingFields,
});
const reqBody = await getBookingData({
reqBody: req.body,
reqBody: bookingData,
eventType,
schema,
});
@@ -257,7 +253,7 @@ async function handler(req: NextApiRequest) {
data: attendeesList,
},
},
creationSource: req.body.creationSource,
creationSource: bookingData.creationSource,
};
const createBookingObj = {
@@ -275,7 +271,7 @@ async function handler(req: NextApiRequest) {
const eventTypeWithExpiryTimeOffset = await prisma.eventType.findUniqueOrThrow({
where: {
id: req.body.eventTypeId,
id: bookingData.eventTypeId,
},
select: {
instantMeetingExpiryTimeOffsetInSeconds: true,
@@ -334,7 +330,21 @@ async function handler(req: NextApiRequest) {
bookingUid: newBooking.uid,
expires: instantMeetingToken.expires,
userId: newBooking.userId,
} satisfies HandleInstantMeetingResponse;
} satisfies CreateInstantBookingResponse;
}
export default handler;
/**
* Instant booking service that handles instant/immediate bookings
*/
export class InstantBookingCreateService implements IBookingCreateService {
async createBooking(input: {
bookingData: CreateInstantBookingData;
}): Promise<CreateInstantBookingResponse> {
return _handler(input.bookingData);
}
}
// TODO: Remove it in a follow-up PR
export default async function handler(req: NextApiRequest) {
return _handler(req.body);
}
+6
View File
@@ -51,4 +51,10 @@ export const DI_TOKENS = {
HOST_REPOSITORY_MODULE: Symbol("HostRepositoryModule"),
ATTRIBUTE_REPOSITORY: Symbol("AttributeRepository"),
ATTRIBUTE_REPOSITORY_MODULE: Symbol("AttributeRepositoryModule"),
REGULAR_BOOKING_SERVICE: Symbol("RegularBookingService"),
REGULAR_BOOKING_SERVICE_MODULE: Symbol("RegularBookingServiceModule"),
RECURRING_BOOKING_SERVICE: Symbol("RecurringBookingService"),
RECURRING_BOOKING_SERVICE_MODULE: Symbol("RecurringBookingServiceModule"),
INSTANT_BOOKING_CREATE_SERVICE: Symbol("InstantBookingCreateService"),
INSTANT_BOOKING_CREATE_SERVICE_MODULE: Symbol("InstantBookingCreateServiceModule"),
};
+3 -1
View File
@@ -3,6 +3,7 @@ import z, { ZodNullable, ZodObject, ZodOptional } from "zod";
import { timeZoneSchema } from "@calcom/lib/dayjs/timeZone.schema";
// TODO: Move this out of here. Importing from app-store is a circular package dependency.
import { routingFormResponseInDbSchema } from "@calcom/app-store/routing-forms/zod";
import { CreationSource } from "@calcom/prisma/enums";
export const bookingCreateBodySchema = z.object({
end: z.string().optional(),
@@ -47,7 +48,8 @@ export const bookingCreateBodySchema = z.object({
utm_term: z.string().optional(),
utm_content: z.string().optional(),
}).optional(),
dub_id: z.string().nullish()
dub_id: z.string().nullish(),
creationSource: z.nativeEnum(CreationSource).optional(),
});
export type BookingCreateBody = z.input<typeof bookingCreateBodySchema>;