import type { SubBlockConfig } from '@/blocks/types' import type { TriggerOutput } from '@/triggers/types' /** * Maps trigger IDs to the Zoom webhook event names they should match. */ const ZOOM_TRIGGER_EVENT_MAP: Record = { zoom_meeting_started: ['meeting.started'], zoom_meeting_ended: ['meeting.ended'], zoom_participant_joined: ['meeting.participant_joined'], zoom_participant_left: ['meeting.participant_left'], zoom_recording_completed: ['recording.completed'], } /** * Checks whether a Zoom webhook payload matches the configured trigger type. * Returns true for the generic `zoom_webhook` trigger (accepts all events). */ export function isZoomEventMatch(triggerId: string, event: string): boolean { if (triggerId === 'zoom_webhook') { return true } const allowedEvents = ZOOM_TRIGGER_EVENT_MAP[triggerId] if (!allowedEvents) { return false } const ev = event?.trim() if (!ev) { return false } return allowedEvents.includes(ev) } /** * Dropdown options for the Zoom trigger type selector. */ export const zoomTriggerOptions = [ { label: 'Meeting Started', id: 'zoom_meeting_started' }, { label: 'Meeting Ended', id: 'zoom_meeting_ended' }, { label: 'Participant Joined', id: 'zoom_participant_joined' }, { label: 'Participant Left', id: 'zoom_participant_left' }, { label: 'Recording Completed', id: 'zoom_recording_completed' }, { label: 'Generic Webhook (All Events)', id: 'zoom_webhook' }, ] type ZoomEventType = | 'meeting_started' | 'meeting_ended' | 'participant_joined' | 'participant_left' | 'recording_completed' | 'generic' /** * Generates setup instructions HTML for Zoom triggers. */ export function zoomSetupInstructions(eventType: ZoomEventType): string { const eventNames: Record = { meeting_started: 'meeting.started', meeting_ended: 'meeting.ended', participant_joined: 'meeting.participant_joined', participant_left: 'meeting.participant_left', recording_completed: 'recording.completed', generic: 'your desired event type(s)', } const instructions = [ 'Copy the Webhook URL above.', 'Go to the Zoom Marketplace and create or open a Webhook-only or general app with Event Subscriptions enabled (Meeting / Recording events as needed). Admin approval may be required for account-level webhooks.', "Copy the Secret Token from your Zoom app's Features page and paste it in the Secret Token field above.", 'Click "Save Configuration" above to activate the trigger.', 'Navigate to Features > Event Subscriptions and click Add Event Subscription.', 'Enter a subscription name and paste the webhook URL into the Event notification endpoint URL field.', 'Click Validate to verify the endpoint.', `Click Add Events and select the ${eventNames[eventType]} event type.`, 'Save the event subscription in Zoom.', ] return instructions .map( (instruction, index) => `
${index + 1}. ${instruction}
` ) .join('') } /** * Creates the secret token field subBlock for a Zoom trigger. */ export function zoomSecretTokenField(triggerId: string): SubBlockConfig { return { id: 'secretToken', title: 'Secret Token', type: 'short-input', placeholder: 'Enter your Zoom app Secret Token', description: "Found in your Zoom app's Features page. Required for endpoint validation and webhook signature verification.", password: true, required: true, mode: 'trigger', condition: { field: 'selectedTriggerId', value: triggerId, }, } } /** * Builds outputs for meeting lifecycle events (started/ended). */ export function buildMeetingOutputs(): Record { return { event: { type: 'string', description: 'The webhook event type (e.g., meeting.started)', }, event_ts: { type: 'number', description: 'Unix timestamp in milliseconds when the event occurred', }, payload: { account_id: { type: 'string', description: 'Zoom account ID', }, object: { type: 'object', description: 'Meeting details (shape aligns with Zoom Meetings webhook object fields)', id: { type: 'number', description: 'Meeting ID' }, uuid: { type: 'string', description: 'Meeting UUID' }, topic: { type: 'string', description: 'Meeting topic' }, meeting_type: { type: 'number', description: 'Meeting type (1=instant, 2=scheduled, etc.; maps to Zoom `type`)', }, host_id: { type: 'string', description: 'Host user ID' }, host_email: { type: 'string', description: 'Host email address (when provided by Zoom)', }, start_time: { type: 'string', description: 'Meeting start time (ISO 8601)' }, end_time: { type: 'string', description: 'Meeting end time (ISO 8601, present on meeting.ended)', }, timezone: { type: 'string', description: 'Meeting timezone' }, duration: { type: 'number', description: 'Meeting duration in minutes' }, agenda: { type: 'string', description: 'Meeting agenda or description (when provided)', }, join_url: { type: 'string', description: 'URL for participants to join (when provided)', }, password: { type: 'string', description: 'Meeting password (when provided)', }, status: { type: 'string', description: 'Meeting status (e.g. waiting, started; when provided)', }, created_at: { type: 'string', description: 'Creation timestamp in ISO 8601 format (when provided)', }, }, }, } } /** * Builds outputs for participant events (joined/left). */ export function buildParticipantOutputs(): Record { return { event: { type: 'string', description: 'The webhook event type (e.g., meeting.participant_joined)', }, event_ts: { type: 'number', description: 'Unix timestamp in milliseconds when the event occurred', }, payload: { account_id: { type: 'string', description: 'Zoom account ID', }, object: { type: 'object', description: 'Meeting and participant details', id: { type: 'number', description: 'Meeting ID' }, uuid: { type: 'string', description: 'Meeting UUID' }, topic: { type: 'string', description: 'Meeting topic' }, host_id: { type: 'string', description: 'Host user ID' }, join_url: { type: 'string', description: 'URL for participants to join (when provided)', }, participant: { type: 'object', description: 'Participant details', id: { type: 'string', description: 'Participant identifier' }, user_id: { type: 'string', description: 'Participant user ID (when a Zoom user)' }, user_name: { type: 'string', description: 'Participant display name' }, email: { type: 'string', description: 'Participant email (when available)' }, join_time: { type: 'string', description: 'Time participant joined (ISO 8601)' }, leave_time: { type: 'string', description: 'Time participant left (ISO 8601, present on participant_left)', }, duration: { type: 'number', description: 'Seconds the participant was in the meeting (when provided)', }, }, }, }, } } /** * Builds outputs for recording completed events. */ export function buildRecordingOutputs(): Record { return { event: { type: 'string', description: 'The webhook event type (recording.completed)', }, event_ts: { type: 'number', description: 'Unix timestamp in milliseconds when the event occurred', }, payload: { account_id: { type: 'string', description: 'Zoom account ID', }, object: { type: 'object', description: 'Cloud recording details (aligns with Zoom cloud recording objects)', id: { type: 'number', description: 'Meeting ID' }, uuid: { type: 'string', description: 'Meeting UUID' }, topic: { type: 'string', description: 'Meeting topic' }, meeting_type: { type: 'number', description: 'Meeting type (when provided; maps to Zoom `type`)', }, host_id: { type: 'string', description: 'Host user ID' }, host_email: { type: 'string', description: 'Host email' }, start_time: { type: 'string', description: 'Recording start time (ISO 8601)' }, timezone: { type: 'string', description: 'Meeting timezone (when provided)' }, agenda: { type: 'string', description: 'Meeting agenda (when provided)', }, duration: { type: 'number', description: 'Recording duration in minutes' }, total_size: { type: 'number', description: 'Total recording size in bytes' }, recording_count: { type: 'number', description: 'Number of recording files' }, share_url: { type: 'string', description: 'URL to share the recording' }, recording_files: { type: 'json', description: 'Array of recording file objects (e.g. id, file_type, play_url, download_url) per Zoom cloud recording payloads', }, }, }, } } /** * Builds outputs for generic webhook (any event type). */ export function buildGenericOutputs(): Record { return { event: { type: 'string', description: 'The webhook event type (e.g., meeting.started, recording.completed)', }, event_ts: { type: 'number', description: 'Unix timestamp in milliseconds when the event occurred', }, payload: { type: 'json', description: 'Complete webhook payload (structure varies by event type)', }, } }