import { generateId } from './_helpers'; import type { ManifestFunction } from './manifest-function'; import type { ManifestComponentDeletion, ManifestScope } from './manifest-builder'; export type WorkflowAutomationEventType = | 'AUTOMATION_EVENT_TYPE_BUSINESS' | 'AUTOMATION_EVENT_TYPE_RECORD_CHANGE' | 'AUTOMATION_EVENT_TYPE_SCHEDULED' | 'AUTOMATION_EVENT_TYPE_MANUAL' | 'AUTOMATION_EVENT_TYPE_DATE_RELATIVE'; export type WorkflowRecordChangeOperationType = | 'RECORD_CHANGE_OPERATION_TYPE_CREATE' | 'RECORD_CHANGE_OPERATION_TYPE_UPDATE' | 'RECORD_CHANGE_OPERATION_TYPE_DELETE' | 'RECORD_CHANGE_OPERATION_TYPE_CREATE_OR_UPDATE'; export type WorkflowDateRelativeOperatorType = | 'DATE_RELATIVE_TRIGGER_OPERATOR_TYPE_EQ' | 'DATE_RELATIVE_TRIGGER_OPERATOR_TYPE_WITHIN' | 'DATE_RELATIVE_TRIGGER_OPERATOR_TYPE_BETWEEN'; export type WorkflowScheduledFrequencyType = | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_DAILY' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_WEEKDAY_DAILY' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_WEEKLY' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_BIWEEKLY' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_MONTHLY' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_MONTHLY_ON_DAY_OF_WEEK' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_ONE_TIME' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_QUARTERLY' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_ANNUALLY' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_CUSTOM' | 'SCHEDULED_TRIGGER_FREQUENCY_TYPE_CRON'; export type WorkflowCustomScheduleFrequencyUnit = | 'CUSTOM_SCHEDULE_TRIGGER_FREQUENCY_UNIT_DAYS' | 'CUSTOM_SCHEDULE_TRIGGER_FREQUENCY_UNIT_WEEKS' | 'CUSTOM_SCHEDULE_TRIGGER_FREQUENCY_UNIT_MONTHS' | 'CUSTOM_SCHEDULE_TRIGGER_FREQUENCY_UNIT_YEARS' | 'CUSTOM_SCHEDULE_TRIGGER_FREQUENCY_UNIT_HOURS' | 'CUSTOM_SCHEDULE_TRIGGER_FREQUENCY_UNIT_MINUTES'; export interface WorkflowTimeOfDaySchedule { hour_of_day: number; minute_of_hour?: number; } export interface WorkflowOneTimeSchedule extends WorkflowTimeOfDaySchedule { year: number; month_of_year: number; day_of_month: number; } export interface WorkflowWeeklySchedule extends WorkflowTimeOfDaySchedule { day_of_week: number[]; } export interface WorkflowMonthlySchedule extends WorkflowTimeOfDaySchedule { day_of_month: number; start_month?: number; } export interface WorkflowMonthlyOnDayOfWeekSchedule extends WorkflowTimeOfDaySchedule { day_of_week: number; day_of_month: number; } export interface WorkflowQuarterlySchedule extends WorkflowTimeOfDaySchedule { day_of_month: number; month_of_year: number; } export interface WorkflowAnnualSchedule extends WorkflowTimeOfDaySchedule { day_of_month: number; month_of_year: number; start_month?: number; } export interface WorkflowCronSchedule { cron_expression: string; } export interface WorkflowCustomSchedule extends WorkflowTimeOfDaySchedule { custom_schedule_frequency: WorkflowCustomScheduleFrequencyUnit; custom_schedule_frequency_value: number; daily_schedule?: WorkflowTimeOfDaySchedule; weekly_schedule?: WorkflowWeeklySchedule; monthly_schedule?: WorkflowMonthlySchedule; annual_schedule?: WorkflowAnnualSchedule; } export interface WorkflowTriggerBase { automation_event_type: WorkflowAutomationEventType; og_module?: string; base_model?: string; rql_formula?: string; is_basic_workflow?: boolean; og_category?: string; condition_builder_mode?: string; conditions_tree?: string; } export interface WorkflowBusinessTrigger extends WorkflowTriggerBase { automation_event_type: 'AUTOMATION_EVENT_TYPE_BUSINESS'; event_name: string; business_event_trigger?: { navigation_path?: string; }; } export interface WorkflowRecordChangeTrigger extends WorkflowTriggerBase { automation_event_type: 'AUTOMATION_EVENT_TYPE_RECORD_CHANGE'; record_change_operation_type: WorkflowRecordChangeOperationType; } export interface WorkflowDateRelativeTrigger extends WorkflowTriggerBase { automation_event_type: 'AUTOMATION_EVENT_TYPE_DATE_RELATIVE'; date_relative_trigger: { hour_of_day: number; minute_of_hour?: number; timezone?: string; base_model_date_field_rql_path?: string; trigger_on_anniversary?: boolean; date_range_operator?: WorkflowDateRelativeOperatorType; should_trigger_exactly_once_per_trigger_object?: boolean; operands?: Array<{ time_delta?: { days: number } }>; }; } export interface WorkflowScheduledTrigger extends WorkflowTriggerBase { automation_event_type: 'AUTOMATION_EVENT_TYPE_SCHEDULED'; scheduled_trigger: { frequency: WorkflowScheduledFrequencyType; timezone: string; daily_schedule?: WorkflowTimeOfDaySchedule; weekday_schedule?: WorkflowTimeOfDaySchedule; one_time_schedule?: WorkflowOneTimeSchedule; weekly_schedule?: WorkflowWeeklySchedule; bi_weekly_schedule?: WorkflowWeeklySchedule; monthly_schedule?: WorkflowMonthlySchedule; monthly_on_day_of_week_schedule?: WorkflowMonthlyOnDayOfWeekSchedule; quarterly_schedule?: WorkflowQuarterlySchedule; annual_schedule?: WorkflowAnnualSchedule; cron_schedule?: WorkflowCronSchedule; custom_schedule?: WorkflowCustomSchedule; }; } export interface WorkflowManualTrigger extends WorkflowTriggerBase { automation_event_type: 'AUTOMATION_EVENT_TYPE_MANUAL'; } export type WorkflowTrigger = | WorkflowBusinessTrigger | WorkflowRecordChangeTrigger | WorkflowDateRelativeTrigger | WorkflowScheduledTrigger | WorkflowManualTrigger; export interface WorkflowDeletionIdentifier { definitionId: string; } export interface WorkflowProps { /** * Stable workflow definition id. Auto-generated when omitted. */ definitionId?: string; /** * Workflow title shown to admins. */ title: string; /** * Short workflow description shown to admins. */ description: string; /** * The function this workflow runs. Pass a live {@link ManifestFunction} reference, * or a raw api_name string for functions defined outside this manifest. * * Required. */ function: ManifestFunction | string; /** * Trigger definition in the workflows v2 proto JSON shape. */ trigger: WorkflowTrigger; } /** * Defines a simple Workflow Studio workflow and registers it with the manifest. * * This intentionally models only the authoring inputs we need today: workflow * metadata, trigger JSON, and the function reference. The installer/backend can * derive the graph from these fields later. */ export class Workflow { static readonly componentType = 'WORKFLOW_DEFINITION' as const; static toDeletionIdentifier(identifier: WorkflowDeletionIdentifier | string): ManifestComponentDeletion { const definitionId = typeof identifier === 'string' ? identifier : identifier.definitionId; return { type: Workflow.componentType, definition_id: definitionId, }; } private readonly _definitionId: string; private readonly _title: string; private readonly _description: string; private readonly _functionApiName: string; private readonly _trigger: WorkflowTrigger; constructor(scope: ManifestScope, props: WorkflowProps) { if (!props.function) throw new Error('function is required'); this._definitionId = props.definitionId ?? generateId('workflow'); this._title = props.title; this._description = props.description; this._functionApiName = typeof props.function === 'string' ? props.function : props.function.getApiName(); this._trigger = props.trigger; scope._register(this); } getDefinitionId(): string { return this._definitionId; } toDict(): Record { const component: Record = { type: Workflow.componentType, definition_id: this._definitionId, version_status: 'VERSION_STATUS_DRAFT', trigger_status: 'TRIGGER_STATUS_INACTIVE', trigger: this._trigger, workflow_meta: { name: this._title, description: this._description, }, function_api_name: this._functionApiName, }; return component; } }