Files
calendar/packages/features/webhooks/lib/interface/WebhookProducerService.ts
Syed Ali ShahbazGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Hariom Balhara
5d65df9c05 chore: migrate booking requested webhook trigger (#27546)
* init

* wiring up

* fix type

* feat: implement DI pattern for webhook producer in API v2

- Export IWebhookProducerService and getWebhookProducer from platform-libraries
- Add WEBHOOK_PRODUCER token and useFactory provider in RegularBookingModule
- Inject webhookProducer in RegularBookingService and pass to base class

This follows the composition root pattern where only the NestJS module
knows about getWebhookProducer(), and all consumers depend only on the
IWebhookProducerService interface via constructor injection.

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* test: migrate BOOKING_REQUESTED tests to new webhook architecture

- Remove failing BOOKING_REQUESTED tests from fresh-booking.test.ts (4 tests)
- Remove failing BOOKING_REQUESTED tests from reschedule.test.ts (2 tests)
- Remove failing BOOKING_REQUESTED test from collective-scheduling.test.ts (1 test)
- Replace WebhookTaskConsumer.test.ts with placeholder (constructor changed)
- Create new webhook architecture test suite:
  - producer/WebhookTaskerProducerService.test.ts (14 tests)
  - consumer/WebhookTaskConsumer.test.ts (8 tests)
  - consumer/triggers/booking-requested.test.ts (8 tests)

The new test suite is organized by trigger type for extensibility as more
triggers are migrated to the producer/consumer pattern.

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* test: remove paid events BOOKING_REQUESTED test (moved to new architecture)

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* wrap webhook in own try-catch

* wire datafetcher

* fix

* fix v2

* fix circular dependency

* --

* merge-conflict-resolve

* mreg-conflict-resolve

* remove early return

* test: add integration tests for BOOKING_REQUESTED webhook producer invocation

Cover all 8 scenarios verifying the booking flow correctly invokes
the webhook producer for BOOKING_REQUESTED:

1. Basic confirmation → queueBookingRequestedWebhook called
2. Booker-is-organizer + confirmation → still called
3. Confirmation threshold NOT met → not called (BOOKING_CREATED instead)
4. Confirmation threshold IS met → called
5. Paid event + confirmation → called after payment succeeds
6. Reschedule + confirmation (non-organizer) → called (not BOOKING_RESCHEDULED)
7. Reschedule + confirmation (organizer) → not called (BOOKING_RESCHEDULED instead)
8. Collective scheduling + confirmation → called

Adds reusable MockWebhookProducer helper in @calcom/testing for
extendable use as more webhook triggers migrate to the new architecture.

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* fix bug

* fix conditional check

* remove unnecessary comment

* add missing expect

* remove empty test

* clean up

* tasker config

* --

* fix missing metadata

* remove faulty if else

* test: add payload content verification tests for BOOKING_REQUESTED webhook

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* remove unnecessary tests

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Hariom Balhara <1780212+hariombalhara@users.noreply.github.com>
2026-02-19 20:21:26 +04:00

176 lines
4.6 KiB
TypeScript

/**
* Base parameters common to all webhook queue operations
*/
interface BaseQueueWebhookParams {
/** Unique identifier for this webhook operation (generated if not provided) */
operationId?: string;
/** Additional context data (kept minimal) */
metadata?: Record<string, unknown>;
}
/**
* Parameters for queueing booking-related webhooks
* Used for: BOOKING_CREATED, BOOKING_CANCELLED, BOOKING_RESCHEDULED,
* BOOKING_REQUESTED, BOOKING_REJECTED, BOOKING_NO_SHOW_UPDATED
*/
export interface QueueBookingWebhookParams extends BaseQueueWebhookParams {
bookingUid: string;
eventTypeId?: number;
teamId?: number | null;
userId?: number;
orgId?: number;
oAuthClientId?: string | null;
}
/**
* Parameters for queueing payment-related webhooks
* Used for: BOOKING_PAYMENT_INITIATED, BOOKING_PAID
*/
export interface QueuePaymentWebhookParams extends BaseQueueWebhookParams {
/** Booking UID (required) */
bookingUid: string;
/** Event Type ID */
eventTypeId?: number;
/** Team ID */
teamId?: number | null;
/** User ID */
userId?: number;
/** Organization ID */
orgId?: number;
/** OAuth Client ID (for platform webhooks) */
oAuthClientId?: string | null;
}
/**
* Parameters for queueing form-related webhooks
* Used for: FORM_SUBMITTED
*/
export interface QueueFormWebhookParams extends BaseQueueWebhookParams {
/** Form ID (required) */
formId: string;
/** Team ID */
teamId?: number | null;
/** User ID */
userId?: number;
/** OAuth Client ID (for platform webhooks) */
oAuthClientId?: string | null;
}
/**
* Parameters for queueing recording-related webhooks
* Used for: RECORDING_READY, RECORDING_TRANSCRIPTION_GENERATED
*/
export interface QueueRecordingWebhookParams extends BaseQueueWebhookParams {
/** Recording ID (required) */
recordingId: string;
/** Booking UID (required) */
bookingUid: string;
/** Event Type ID */
eventTypeId?: number;
/** Team ID */
teamId?: number | null;
/** User ID */
userId?: number;
/** OAuth Client ID (for platform webhooks) */
oAuthClientId?: string | null;
}
/**
* Parameters for queueing OOO-related webhooks
* Used for: OOO_CREATED
*/
export interface QueueOOOWebhookParams extends BaseQueueWebhookParams {
/** OOO Entry ID (required) */
oooEntryId: number;
/** User ID (required) */
userId: number;
/** Team ID */
teamId?: number | null;
/** OAuth Client ID (for platform webhooks) */
oAuthClientId?: string | null;
}
/**
* Lightweight Producer Service for queueing webhook delivery tasks.
*
* This service has NO heavy dependencies (no Prisma, no repositories).
* It only queues tasks via Tasker, which will be processed by WebhookTaskConsumer.
*
* This allows the producer to stay in the main app while the consumer
* can be deployed to trigger.dev for scalability.
*/
export interface IWebhookProducerService {
/**
* Queue a webhook delivery task for BOOKING_CREATED event
*/
queueBookingCreatedWebhook(params: QueueBookingWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for BOOKING_CANCELLED event
*/
queueBookingCancelledWebhook(params: QueueBookingWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for BOOKING_RESCHEDULED event
*/
queueBookingRescheduledWebhook(params: QueueBookingWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for BOOKING_REQUESTED event
*
* Note: This fires when bookings require confirmation (status = PENDING)
*/
queueBookingRequestedWebhook(params: QueueBookingWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for BOOKING_REJECTED event
*/
queueBookingRejectedWebhook(params: QueueBookingWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for BOOKING_PAYMENT_INITIATED event
*/
queueBookingPaymentInitiatedWebhook(params: QueuePaymentWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for BOOKING_PAID event
*/
queueBookingPaidWebhook(params: QueuePaymentWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for BOOKING_NO_SHOW_UPDATED event
*/
queueBookingNoShowUpdatedWebhook(params: QueueBookingWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for FORM_SUBMITTED event
*/
queueFormSubmittedWebhook(params: QueueFormWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for RECORDING_READY event
*/
queueRecordingReadyWebhook(params: QueueRecordingWebhookParams): Promise<void>;
/**
* Queue a webhook delivery task for OOO_CREATED event
*/
queueOOOCreatedWebhook(params: QueueOOOWebhookParams): Promise<void>;
}