d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
296 lines
10 KiB
TypeScript
296 lines
10 KiB
TypeScript
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<string, string[]> = {
|
|
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<ZoomEventType, string> = {
|
|
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 <strong>Webhook URL</strong> above.',
|
|
'Go to the <a href="https://marketplace.zoom.us/" target="_blank" rel="noopener noreferrer">Zoom Marketplace</a> and create or open a <strong>Webhook-only</strong> or general app with <strong>Event Subscriptions</strong> enabled (Meeting / Recording events as needed). Admin approval may be required for account-level webhooks.',
|
|
"Copy the <strong>Secret Token</strong> from your Zoom app's <strong>Features</strong> page and paste it in the <strong>Secret Token</strong> field above.",
|
|
'Click <strong>"Save Configuration"</strong> above to activate the trigger.',
|
|
'Navigate to <strong>Features > Event Subscriptions</strong> and click <strong>Add Event Subscription</strong>.',
|
|
'Enter a subscription name and paste the webhook URL into the <strong>Event notification endpoint URL</strong> field.',
|
|
'Click <strong>Validate</strong> to verify the endpoint.',
|
|
`Click <strong>Add Events</strong> and select the <strong>${eventNames[eventType]}</strong> event type.`,
|
|
'Save the event subscription in Zoom.',
|
|
]
|
|
|
|
return instructions
|
|
.map(
|
|
(instruction, index) =>
|
|
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
|
)
|
|
.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<string, TriggerOutput> {
|
|
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<string, TriggerOutput> {
|
|
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<string, TriggerOutput> {
|
|
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<string, TriggerOutput> {
|
|
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)',
|
|
},
|
|
}
|
|
}
|