diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index a0e7129090..6cf5cceee4 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -37,8 +37,8 @@ import { EyeIcon, FirecrawlIcon, FirefliesIcon, - GitLabIcon, GithubIcon, + GitLabIcon, GmailIcon, GongIcon, GoogleBooksIcon, @@ -71,9 +71,9 @@ import { LinearIcon, LinkedInIcon, LinkupIcon, - MailServerIcon, MailchimpIcon, MailgunIcon, + MailServerIcon, Mem0Icon, MicrosoftDataverseIcon, MicrosoftExcelIcon, @@ -106,8 +106,6 @@ import { ResendIcon, RevenueCatIcon, S3Icon, - SQSIcon, - STTIcon, SalesforceIcon, SearchIcon, SendgridIcon, @@ -119,17 +117,19 @@ import { SimilarwebIcon, SlackIcon, SmtpIcon, + SQSIcon, SshIcon, + STTIcon, StagehandIcon, StripeIcon, SupabaseIcon, - TTSIcon, TavilyIcon, TelegramIcon, TextractIcon, TinybirdIcon, TranslateIcon, TrelloIcon, + TTSIcon, TwilioIcon, TypeformIcon, UpstashIcon, @@ -140,11 +140,11 @@ import { WhatsAppIcon, WikipediaIcon, WordpressIcon, + xIcon, YouTubeIcon, ZendeskIcon, ZepIcon, ZoomIcon, - xIcon, } from '@/components/icons' type IconComponent = ComponentType> diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index b933326cea..5a4f2219f3 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -145,4 +145,4 @@ "zep", "zoom" ] -} \ No newline at end of file +} diff --git a/apps/sim/blocks/blocks/confluence.ts b/apps/sim/blocks/blocks/confluence.ts index 4ab5c690c2..c17f44b89b 100644 --- a/apps/sim/blocks/blocks/confluence.ts +++ b/apps/sim/blocks/blocks/confluence.ts @@ -3,6 +3,7 @@ import type { BlockConfig } from '@/blocks/types' import { AuthMode } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { ConfluenceResponse } from '@/tools/confluence/types' +import { getTrigger } from '@/triggers' export const ConfluenceBlock: BlockConfig = { type: 'confluence', @@ -838,7 +839,46 @@ export const ConfluenceV2Block: BlockConfig = { ], }, }, + + // Trigger subBlocks + ...getTrigger('confluence_page_created').subBlocks, + ...getTrigger('confluence_page_updated').subBlocks, + ...getTrigger('confluence_page_removed').subBlocks, + ...getTrigger('confluence_page_moved').subBlocks, + ...getTrigger('confluence_comment_created').subBlocks, + ...getTrigger('confluence_comment_removed').subBlocks, + ...getTrigger('confluence_blog_created').subBlocks, + ...getTrigger('confluence_blog_updated').subBlocks, + ...getTrigger('confluence_blog_removed').subBlocks, + ...getTrigger('confluence_attachment_created').subBlocks, + ...getTrigger('confluence_attachment_removed').subBlocks, + ...getTrigger('confluence_space_created').subBlocks, + ...getTrigger('confluence_space_updated').subBlocks, + ...getTrigger('confluence_label_added').subBlocks, + ...getTrigger('confluence_label_removed').subBlocks, + ...getTrigger('confluence_webhook').subBlocks, ], + triggers: { + enabled: true, + available: [ + 'confluence_page_created', + 'confluence_page_updated', + 'confluence_page_removed', + 'confluence_page_moved', + 'confluence_comment_created', + 'confluence_comment_removed', + 'confluence_blog_created', + 'confluence_blog_updated', + 'confluence_blog_removed', + 'confluence_attachment_created', + 'confluence_attachment_removed', + 'confluence_space_created', + 'confluence_space_updated', + 'confluence_label_added', + 'confluence_label_removed', + 'confluence_webhook', + ], + }, tools: { access: [ // Page Tools diff --git a/apps/sim/lib/webhooks/processor.ts b/apps/sim/lib/webhooks/processor.ts index 82c8801939..047d862ef7 100644 --- a/apps/sim/lib/webhooks/processor.ts +++ b/apps/sim/lib/webhooks/processor.ts @@ -28,6 +28,7 @@ import { getWorkspaceBilledAccountUserId } from '@/lib/workspaces/utils' import { resolveOAuthAccountId } from '@/app/api/auth/oauth/utils' import { executeWebhookJob } from '@/background/webhook-execution' import { resolveEnvVarReferences } from '@/executor/utils/reference-validation' +import { isConfluencePayloadMatch } from '@/triggers/confluence/utils' import { isGitHubEventMatch } from '@/triggers/github/utils' import { isHubSpotContactEventMatch } from '@/triggers/hubspot/utils' import { isJiraEventMatch } from '@/triggers/jira/utils' @@ -608,7 +609,7 @@ export async function verifyProviderAuth( } if (foundWebhook.provider === 'linear') { - const secret = providerConfig.secret as string | undefined + const secret = providerConfig.webhookSecret as string | undefined if (secret) { const signature = request.headers.get('Linear-Signature') @@ -683,7 +684,7 @@ export async function verifyProviderAuth( } if (foundWebhook.provider === 'jira') { - const secret = providerConfig.secret as string | undefined + const secret = providerConfig.webhookSecret as string | undefined if (secret) { const signature = request.headers.get('X-Hub-Signature') @@ -707,8 +708,33 @@ export async function verifyProviderAuth( } } + if (foundWebhook.provider === 'confluence') { + const secret = providerConfig.webhookSecret as string | undefined + + if (secret) { + const signature = request.headers.get('X-Hub-Signature') + + if (!signature) { + logger.warn(`[${requestId}] Confluence webhook missing signature header`) + return new NextResponse('Unauthorized - Missing Confluence signature', { status: 401 }) + } + + const isValidSignature = validateJiraSignature(secret, signature, rawBody) + + if (!isValidSignature) { + logger.warn(`[${requestId}] Confluence signature verification failed`, { + signatureLength: signature.length, + secretLength: secret.length, + }) + return new NextResponse('Unauthorized - Invalid Confluence signature', { status: 401 }) + } + + logger.debug(`[${requestId}] Confluence signature verified successfully`) + } + } + if (foundWebhook.provider === 'github') { - const secret = providerConfig.secret as string | undefined + const secret = providerConfig.webhookSecret as string | undefined if (secret) { // GitHub supports both SHA-256 (preferred) and SHA-1 (legacy) @@ -930,6 +956,27 @@ export async function queueWebhookExecution( } } + if (foundWebhook.provider === 'confluence') { + const providerConfig = (foundWebhook.providerConfig as Record) || {} + const triggerId = providerConfig.triggerId as string | undefined + + if (triggerId && !isConfluencePayloadMatch(triggerId, body)) { + logger.debug( + `[${options.requestId}] Confluence payload mismatch for trigger ${triggerId}. Skipping execution.`, + { + webhookId: foundWebhook.id, + workflowId: foundWorkflow.id, + triggerId, + bodyKeys: Object.keys(body), + } + ) + + return NextResponse.json({ + message: 'Payload does not match trigger configuration. Ignoring.', + }) + } + } + if (foundWebhook.provider === 'hubspot') { const providerConfig = (foundWebhook.providerConfig as Record) || {} const triggerId = providerConfig.triggerId as string | undefined diff --git a/apps/sim/lib/webhooks/utils.server.ts b/apps/sim/lib/webhooks/utils.server.ts index cb54f57914..8603b5bfbf 100644 --- a/apps/sim/lib/webhooks/utils.server.ts +++ b/apps/sim/lib/webhooks/utils.server.ts @@ -1197,6 +1197,53 @@ export async function formatWebhookInput( return extractIssueData(body) } + if (foundWebhook.provider === 'confluence') { + const { + extractPageData, + extractCommentData, + extractBlogData, + extractAttachmentData, + extractSpaceData, + extractLabelData, + } = await import('@/triggers/confluence/utils') + + const providerConfig = (foundWebhook.providerConfig as Record) || {} + const triggerId = providerConfig.triggerId as string | undefined + + if (triggerId?.startsWith('confluence_comment_')) { + return extractCommentData(body) + } + if (triggerId?.startsWith('confluence_blog_')) { + return extractBlogData(body) + } + if (triggerId?.startsWith('confluence_attachment_')) { + return extractAttachmentData(body) + } + if (triggerId?.startsWith('confluence_space_')) { + return extractSpaceData(body) + } + if (triggerId?.startsWith('confluence_label_')) { + return extractLabelData(body) + } + // Generic webhook — preserve all entity fields since event type varies + if (triggerId === 'confluence_webhook') { + return { + timestamp: body.timestamp, + userAccountId: body.userAccountId, + accountType: body.accountType, + page: body.page || null, + comment: body.comment || null, + blog: body.blog || body.blogpost || null, + attachment: body.attachment || null, + space: body.space || null, + label: body.label || null, + content: body.content || null, + } + } + // Default: page events + return extractPageData(body) + } + if (foundWebhook.provider === 'stripe') { return body } diff --git a/apps/sim/triggers/confluence/attachment_created.ts b/apps/sim/triggers/confluence/attachment_created.ts new file mode 100644 index 0000000000..aab68cd0b6 --- /dev/null +++ b/apps/sim/triggers/confluence/attachment_created.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildAttachmentOutputs, + buildConfluenceAttachmentExtraFields, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Attachment Created Trigger + * + * Triggers when a new attachment is uploaded to a page or blog post in Confluence. + */ +export const confluenceAttachmentCreatedTrigger: TriggerConfig = { + id: 'confluence_attachment_created', + name: 'Confluence Attachment Created', + provider: 'confluence', + description: 'Trigger workflow when an attachment is uploaded in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_attachment_created', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('attachment_created'), + extraFields: buildConfluenceAttachmentExtraFields('confluence_attachment_created'), + }), + + outputs: buildAttachmentOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/attachment_removed.ts b/apps/sim/triggers/confluence/attachment_removed.ts new file mode 100644 index 0000000000..364b63f40a --- /dev/null +++ b/apps/sim/triggers/confluence/attachment_removed.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildAttachmentOutputs, + buildConfluenceAttachmentExtraFields, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Attachment Removed Trigger + * + * Triggers when an attachment is removed or trashed from a page or blog post in Confluence. + */ +export const confluenceAttachmentRemovedTrigger: TriggerConfig = { + id: 'confluence_attachment_removed', + name: 'Confluence Attachment Removed', + provider: 'confluence', + description: 'Trigger workflow when an attachment is removed in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_attachment_removed', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('attachment_removed'), + extraFields: buildConfluenceAttachmentExtraFields('confluence_attachment_removed'), + }), + + outputs: buildAttachmentOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/blog_created.ts b/apps/sim/triggers/confluence/blog_created.ts new file mode 100644 index 0000000000..6c6641f33e --- /dev/null +++ b/apps/sim/triggers/confluence/blog_created.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildBlogOutputs, + buildConfluenceExtraFields, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Blog Post Created Trigger + * + * Triggers when a new blog post is created in Confluence. + */ +export const confluenceBlogCreatedTrigger: TriggerConfig = { + id: 'confluence_blog_created', + name: 'Confluence Blog Post Created', + provider: 'confluence', + description: 'Trigger workflow when a blog post is created in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_blog_created', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('blog_created'), + extraFields: buildConfluenceExtraFields('confluence_blog_created'), + }), + + outputs: buildBlogOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/blog_removed.ts b/apps/sim/triggers/confluence/blog_removed.ts new file mode 100644 index 0000000000..9dbe5ba2a0 --- /dev/null +++ b/apps/sim/triggers/confluence/blog_removed.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildBlogOutputs, + buildConfluenceExtraFields, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Blog Post Removed Trigger + * + * Triggers when a blog post is removed or trashed in Confluence. + */ +export const confluenceBlogRemovedTrigger: TriggerConfig = { + id: 'confluence_blog_removed', + name: 'Confluence Blog Post Removed', + provider: 'confluence', + description: 'Trigger workflow when a blog post is removed in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_blog_removed', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('blog_removed'), + extraFields: buildConfluenceExtraFields('confluence_blog_removed'), + }), + + outputs: buildBlogOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/blog_updated.ts b/apps/sim/triggers/confluence/blog_updated.ts new file mode 100644 index 0000000000..a53f50d114 --- /dev/null +++ b/apps/sim/triggers/confluence/blog_updated.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildBlogOutputs, + buildConfluenceExtraFields, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Blog Post Updated Trigger + * + * Triggers when a blog post is updated in Confluence. + */ +export const confluenceBlogUpdatedTrigger: TriggerConfig = { + id: 'confluence_blog_updated', + name: 'Confluence Blog Post Updated', + provider: 'confluence', + description: 'Trigger workflow when a blog post is updated in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_blog_updated', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('blog_updated'), + extraFields: buildConfluenceExtraFields('confluence_blog_updated'), + }), + + outputs: buildBlogOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/comment_created.ts b/apps/sim/triggers/confluence/comment_created.ts new file mode 100644 index 0000000000..66dea25b5f --- /dev/null +++ b/apps/sim/triggers/confluence/comment_created.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildCommentOutputs, + buildConfluenceExtraFields, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Comment Created Trigger + * + * Triggers when a new comment is created on a page or blog post in Confluence. + */ +export const confluenceCommentCreatedTrigger: TriggerConfig = { + id: 'confluence_comment_created', + name: 'Confluence Comment Created', + provider: 'confluence', + description: 'Trigger workflow when a comment is created in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_comment_created', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('comment_created'), + extraFields: buildConfluenceExtraFields('confluence_comment_created'), + }), + + outputs: buildCommentOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/comment_removed.ts b/apps/sim/triggers/confluence/comment_removed.ts new file mode 100644 index 0000000000..b138311c1b --- /dev/null +++ b/apps/sim/triggers/confluence/comment_removed.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildCommentOutputs, + buildConfluenceExtraFields, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Comment Removed Trigger + * + * Triggers when a comment is removed from a page or blog post in Confluence. + */ +export const confluenceCommentRemovedTrigger: TriggerConfig = { + id: 'confluence_comment_removed', + name: 'Confluence Comment Removed', + provider: 'confluence', + description: 'Trigger workflow when a comment is removed in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_comment_removed', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('comment_removed'), + extraFields: buildConfluenceExtraFields('confluence_comment_removed'), + }), + + outputs: buildCommentOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/index.ts b/apps/sim/triggers/confluence/index.ts new file mode 100644 index 0000000000..ea5c16fa97 --- /dev/null +++ b/apps/sim/triggers/confluence/index.ts @@ -0,0 +1,21 @@ +/** + * Confluence Triggers + * Export all Confluence webhook triggers + */ + +export { confluenceAttachmentCreatedTrigger } from './attachment_created' +export { confluenceAttachmentRemovedTrigger } from './attachment_removed' +export { confluenceBlogCreatedTrigger } from './blog_created' +export { confluenceBlogRemovedTrigger } from './blog_removed' +export { confluenceBlogUpdatedTrigger } from './blog_updated' +export { confluenceCommentCreatedTrigger } from './comment_created' +export { confluenceCommentRemovedTrigger } from './comment_removed' +export { confluenceLabelAddedTrigger } from './label_added' +export { confluenceLabelRemovedTrigger } from './label_removed' +export { confluencePageCreatedTrigger } from './page_created' +export { confluencePageMovedTrigger } from './page_moved' +export { confluencePageRemovedTrigger } from './page_removed' +export { confluencePageUpdatedTrigger } from './page_updated' +export { confluenceSpaceCreatedTrigger } from './space_created' +export { confluenceSpaceUpdatedTrigger } from './space_updated' +export { confluenceWebhookTrigger } from './webhook' diff --git a/apps/sim/triggers/confluence/label_added.ts b/apps/sim/triggers/confluence/label_added.ts new file mode 100644 index 0000000000..9dd13a096a --- /dev/null +++ b/apps/sim/triggers/confluence/label_added.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildConfluenceExtraFields, + buildLabelOutputs, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Label Added Trigger + * + * Triggers when a label is added to a page, blog post, or other content in Confluence. + */ +export const confluenceLabelAddedTrigger: TriggerConfig = { + id: 'confluence_label_added', + name: 'Confluence Label Added', + provider: 'confluence', + description: 'Trigger workflow when a label is added to content in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_label_added', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('label_added'), + extraFields: buildConfluenceExtraFields('confluence_label_added'), + }), + + outputs: buildLabelOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/label_removed.ts b/apps/sim/triggers/confluence/label_removed.ts new file mode 100644 index 0000000000..b418cb9d09 --- /dev/null +++ b/apps/sim/triggers/confluence/label_removed.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildConfluenceExtraFields, + buildLabelOutputs, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Label Removed Trigger + * + * Triggers when a label is removed from a page, blog post, or other content in Confluence. + */ +export const confluenceLabelRemovedTrigger: TriggerConfig = { + id: 'confluence_label_removed', + name: 'Confluence Label Removed', + provider: 'confluence', + description: 'Trigger workflow when a label is removed from content in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_label_removed', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('label_removed'), + extraFields: buildConfluenceExtraFields('confluence_label_removed'), + }), + + outputs: buildLabelOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/page_created.ts b/apps/sim/triggers/confluence/page_created.ts new file mode 100644 index 0000000000..3f0eed060d --- /dev/null +++ b/apps/sim/triggers/confluence/page_created.ts @@ -0,0 +1,43 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildConfluenceExtraFields, + buildPageOutputs, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Page Created Trigger + * + * This is the PRIMARY trigger - it includes the dropdown for selecting trigger type. + * Triggers when a new page is created in Confluence. + */ +export const confluencePageCreatedTrigger: TriggerConfig = { + id: 'confluence_page_created', + name: 'Confluence Page Created', + provider: 'confluence', + description: 'Trigger workflow when a new page is created in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_page_created', + triggerOptions: confluenceTriggerOptions, + includeDropdown: true, + setupInstructions: confluenceSetupInstructions('page_created'), + extraFields: buildConfluenceExtraFields('confluence_page_created'), + }), + + outputs: buildPageOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/page_moved.ts b/apps/sim/triggers/confluence/page_moved.ts new file mode 100644 index 0000000000..6ced23872c --- /dev/null +++ b/apps/sim/triggers/confluence/page_moved.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildConfluenceExtraFields, + buildPageOutputs, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Page Moved Trigger + * + * Triggers when a page is moved to a different space or parent in Confluence. + */ +export const confluencePageMovedTrigger: TriggerConfig = { + id: 'confluence_page_moved', + name: 'Confluence Page Moved', + provider: 'confluence', + description: 'Trigger workflow when a page is moved in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_page_moved', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('page_moved'), + extraFields: buildConfluenceExtraFields('confluence_page_moved'), + }), + + outputs: buildPageOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/page_removed.ts b/apps/sim/triggers/confluence/page_removed.ts new file mode 100644 index 0000000000..cccefd29b9 --- /dev/null +++ b/apps/sim/triggers/confluence/page_removed.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildConfluenceExtraFields, + buildPageOutputs, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Page Removed Trigger + * + * Triggers when a page is removed or trashed in Confluence. + */ +export const confluencePageRemovedTrigger: TriggerConfig = { + id: 'confluence_page_removed', + name: 'Confluence Page Removed', + provider: 'confluence', + description: 'Trigger workflow when a page is removed or trashed in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_page_removed', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('page_removed'), + extraFields: buildConfluenceExtraFields('confluence_page_removed'), + }), + + outputs: buildPageOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/page_updated.ts b/apps/sim/triggers/confluence/page_updated.ts new file mode 100644 index 0000000000..9d393eaaf7 --- /dev/null +++ b/apps/sim/triggers/confluence/page_updated.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildConfluenceExtraFields, + buildPageOutputs, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Page Updated Trigger + * + * Triggers when an existing page is updated in Confluence. + */ +export const confluencePageUpdatedTrigger: TriggerConfig = { + id: 'confluence_page_updated', + name: 'Confluence Page Updated', + provider: 'confluence', + description: 'Trigger workflow when a page is updated in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_page_updated', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('page_updated'), + extraFields: buildConfluenceExtraFields('confluence_page_updated'), + }), + + outputs: buildPageOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/space_created.ts b/apps/sim/triggers/confluence/space_created.ts new file mode 100644 index 0000000000..f5f5483d21 --- /dev/null +++ b/apps/sim/triggers/confluence/space_created.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildConfluenceExtraFields, + buildSpaceOutputs, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Space Created Trigger + * + * Triggers when a new space is created in Confluence. + */ +export const confluenceSpaceCreatedTrigger: TriggerConfig = { + id: 'confluence_space_created', + name: 'Confluence Space Created', + provider: 'confluence', + description: 'Trigger workflow when a new space is created in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_space_created', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('space_created'), + extraFields: buildConfluenceExtraFields('confluence_space_created'), + }), + + outputs: buildSpaceOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/space_updated.ts b/apps/sim/triggers/confluence/space_updated.ts new file mode 100644 index 0000000000..8b2966631f --- /dev/null +++ b/apps/sim/triggers/confluence/space_updated.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildConfluenceExtraFields, + buildSpaceOutputs, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Confluence Space Updated Trigger + * + * Triggers when a space is updated (settings, permissions, etc.) in Confluence. + */ +export const confluenceSpaceUpdatedTrigger: TriggerConfig = { + id: 'confluence_space_updated', + name: 'Confluence Space Updated', + provider: 'confluence', + description: 'Trigger workflow when a space is updated in Confluence', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_space_updated', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('space_updated'), + extraFields: buildConfluenceExtraFields('confluence_space_updated'), + }), + + outputs: buildSpaceOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/confluence/utils.ts b/apps/sim/triggers/confluence/utils.ts new file mode 100644 index 0000000000..95f0caf87e --- /dev/null +++ b/apps/sim/triggers/confluence/utils.ts @@ -0,0 +1,392 @@ +import type { SubBlockConfig } from '@/blocks/types' +import type { TriggerOutput } from '@/triggers/types' + +export const confluenceTriggerOptions = [ + { label: 'Page Created', id: 'confluence_page_created' }, + { label: 'Page Updated', id: 'confluence_page_updated' }, + { label: 'Page Removed', id: 'confluence_page_removed' }, + { label: 'Page Moved', id: 'confluence_page_moved' }, + { label: 'Comment Created', id: 'confluence_comment_created' }, + { label: 'Comment Removed', id: 'confluence_comment_removed' }, + { label: 'Blog Post Created', id: 'confluence_blog_created' }, + { label: 'Blog Post Updated', id: 'confluence_blog_updated' }, + { label: 'Blog Post Removed', id: 'confluence_blog_removed' }, + { label: 'Attachment Created', id: 'confluence_attachment_created' }, + { label: 'Attachment Removed', id: 'confluence_attachment_removed' }, + { label: 'Space Created', id: 'confluence_space_created' }, + { label: 'Space Updated', id: 'confluence_space_updated' }, + { label: 'Label Added', id: 'confluence_label_added' }, + { label: 'Label Removed', id: 'confluence_label_removed' }, + { label: 'Generic Webhook (All Events)', id: 'confluence_webhook' }, +] + +export function confluenceSetupInstructions(eventType: string): string { + const instructions = [ + 'Note: You must have admin permissions in your Confluence workspace to create webhooks. See the Confluence webhook documentation for details.', + 'In Confluence, navigate to Settings > Webhooks.', + 'Click "Create a Webhook" to add a new webhook.', + 'Paste the Webhook URL from above into the URL field.', + 'Optionally, enter the Webhook Secret from above into the secret field for added security.', + `Select the events you want to trigger this workflow. For this trigger, select ${eventType}.`, + 'Click "Create" to activate the webhook.', + ] + + return instructions + .map( + (instruction, index) => + `
${index === 0 ? instruction : `${index}. ${instruction}`}
` + ) + .join('') +} + +export function buildConfluenceExtraFields(triggerId: string): SubBlockConfig[] { + return [ + { + id: 'webhookSecret', + title: 'Webhook Secret', + type: 'short-input', + placeholder: 'Enter a strong secret', + description: + 'Optional secret to validate webhook deliveries from Confluence using HMAC signature', + password: true, + required: false, + mode: 'trigger', + condition: { field: 'selectedTriggerId', value: triggerId }, + }, + { + id: 'confluenceDomain', + title: 'Confluence Domain', + type: 'short-input', + placeholder: 'your-company.atlassian.net', + description: 'Your Confluence Cloud domain', + required: false, + mode: 'trigger', + condition: { field: 'selectedTriggerId', value: triggerId }, + }, + ] +} + +export function buildConfluenceAttachmentExtraFields(triggerId: string): SubBlockConfig[] { + return [ + ...buildConfluenceExtraFields(triggerId), + { + id: 'confluenceEmail', + title: 'Confluence Email', + type: 'short-input', + placeholder: 'user@example.com', + description: + 'Your Atlassian account email. Required together with API token to download attachment files.', + required: false, + mode: 'trigger', + condition: { field: 'selectedTriggerId', value: triggerId }, + }, + { + id: 'confluenceApiToken', + title: 'API Token', + type: 'short-input', + placeholder: 'Enter your Atlassian API token', + description: + 'API token from https://id.atlassian.com/manage-profile/security/api-tokens. Required to download attachment file content.', + password: true, + required: false, + mode: 'trigger', + condition: { field: 'selectedTriggerId', value: triggerId }, + }, + { + id: 'includeFileContent', + title: 'Include File Content', + type: 'switch', + defaultValue: false, + description: + 'Download and include actual file content from attachments. Requires email, API token, and domain.', + required: false, + mode: 'trigger', + condition: { field: 'selectedTriggerId', value: triggerId }, + }, + ] +} + +/** + * Base webhook outputs common to all Confluence triggers. + */ +function buildBaseWebhookOutputs(): Record { + return { + timestamp: { + type: 'number', + description: 'Timestamp of the webhook event (Unix epoch milliseconds)', + }, + userAccountId: { + type: 'string', + description: 'Account ID of the user who triggered the event', + }, + accountType: { + type: 'string', + description: 'Account type (e.g., customer)', + }, + } +} + +/** + * Shared content-entity output fields present on page, blog, comment, and attachment objects. + */ +function buildContentEntityFields(): Record { + return { + id: { type: 'number', description: 'Content ID' }, + title: { type: 'string', description: 'Content title' }, + contentType: { + type: 'string', + description: 'Content type (page, blogpost, comment, attachment)', + }, + version: { type: 'number', description: 'Version number' }, + spaceKey: { type: 'string', description: 'Space key the content belongs to' }, + creatorAccountId: { type: 'string', description: 'Account ID of the creator' }, + lastModifierAccountId: { type: 'string', description: 'Account ID of the last modifier' }, + self: { type: 'string', description: 'URL link to the content' }, + creationDate: { type: 'number', description: 'Creation timestamp (Unix epoch milliseconds)' }, + modificationDate: { + type: 'number', + description: 'Last modification timestamp (Unix epoch milliseconds)', + }, + } +} + +/** Page-related outputs for page events. */ +export function buildPageOutputs(): Record { + return { + ...buildBaseWebhookOutputs(), + page: buildContentEntityFields(), + } +} + +/** Comment-related outputs for comment events. */ +export function buildCommentOutputs(): Record { + return { + ...buildBaseWebhookOutputs(), + comment: { + ...buildContentEntityFields(), + parent: { + id: { type: 'number', description: 'Parent page/blog ID' }, + title: { type: 'string', description: 'Parent page/blog title' }, + contentType: { type: 'string', description: 'Parent content type (page or blogpost)' }, + spaceKey: { type: 'string', description: 'Space key of the parent' }, + self: { type: 'string', description: 'URL link to the parent content' }, + }, + }, + } +} + +/** Blog post outputs for blog events. */ +export function buildBlogOutputs(): Record { + return { + ...buildBaseWebhookOutputs(), + blog: buildContentEntityFields(), + } +} + +/** Attachment-related outputs for attachment events. */ +export function buildAttachmentOutputs(): Record { + return { + ...buildBaseWebhookOutputs(), + attachment: { + ...buildContentEntityFields(), + mediaType: { type: 'string', description: 'MIME type of the attachment' }, + fileSize: { type: 'number', description: 'File size in bytes' }, + parent: { + id: { type: 'number', description: 'Container page/blog ID' }, + title: { type: 'string', description: 'Container page/blog title' }, + contentType: { type: 'string', description: 'Container content type' }, + }, + }, + files: { + type: 'file[]', + description: + 'Attachment file content downloaded from Confluence (if includeFileContent is enabled with credentials)', + }, + } +} + +/** Space-related outputs for space events. */ +export function buildSpaceOutputs(): Record { + return { + ...buildBaseWebhookOutputs(), + space: { + key: { type: 'string', description: 'Space key' }, + name: { type: 'string', description: 'Space name' }, + self: { type: 'string', description: 'URL link to the space' }, + }, + } +} + +/** Label-related outputs for label events. */ +export function buildLabelOutputs(): Record { + return { + ...buildBaseWebhookOutputs(), + label: { + name: { type: 'string', description: 'Label name' }, + id: { type: 'string', description: 'Label ID' }, + prefix: { type: 'string', description: 'Label prefix (global, my, team)' }, + }, + content: { + id: { type: 'number', description: 'Content ID the label was added to or removed from' }, + title: { type: 'string', description: 'Content title' }, + contentType: { type: 'string', description: 'Content type (page, blogpost)' }, + }, + } +} + +/** Combined outputs for the generic webhook trigger (all events). */ +export function buildGenericWebhookOutputs(): Record { + return { + ...buildBaseWebhookOutputs(), + page: { type: 'json', description: 'Page object (present in page events)' }, + comment: { type: 'json', description: 'Comment object (present in comment events)' }, + blog: { type: 'json', description: 'Blog post object (present in blog events)' }, + attachment: { type: 'json', description: 'Attachment object (present in attachment events)' }, + space: { type: 'json', description: 'Space object (present in space events)' }, + label: { type: 'json', description: 'Label object (present in label events)' }, + content: { type: 'json', description: 'Content object (present in label events)' }, + files: { + type: 'file[]', + description: + 'Attachment file content (present in attachment events when includeFileContent is enabled)', + }, + } +} + +export function extractPageData(body: any) { + return { + timestamp: body.timestamp, + userAccountId: body.userAccountId, + accountType: body.accountType, + page: body.page || {}, + } +} + +export function extractCommentData(body: any) { + return { + timestamp: body.timestamp, + userAccountId: body.userAccountId, + accountType: body.accountType, + comment: body.comment || {}, + } +} + +export function extractBlogData(body: any) { + return { + timestamp: body.timestamp, + userAccountId: body.userAccountId, + accountType: body.accountType, + blog: body.blog || body.blogpost || {}, + } +} + +export function extractAttachmentData(body: any) { + return { + timestamp: body.timestamp, + userAccountId: body.userAccountId, + accountType: body.accountType, + attachment: body.attachment || {}, + } +} + +export function extractSpaceData(body: any) { + return { + timestamp: body.timestamp, + userAccountId: body.userAccountId, + accountType: body.accountType, + space: body.space || {}, + } +} + +export function extractLabelData(body: any) { + return { + timestamp: body.timestamp, + userAccountId: body.userAccountId, + accountType: body.accountType, + label: body.label || {}, + content: body.content || body.page || body.blog || {}, + } +} + +/** + * Maps trigger IDs to the exact Confluence event strings they accept. + * Admin REST API webhooks include an `event` field (e.g. `"event": "page_created"`). + * Connect app webhooks do NOT — for those we fall back to entity-category matching. + */ +const TRIGGER_EVENT_MAP: Record = { + confluence_page_created: ['page_created'], + confluence_page_updated: ['page_updated'], + confluence_page_removed: ['page_removed', 'page_trashed'], + confluence_page_moved: ['page_moved'], + confluence_comment_created: ['comment_created'], + confluence_comment_removed: ['comment_removed'], + confluence_blog_created: ['blog_created'], + confluence_blog_updated: ['blog_updated'], + confluence_blog_removed: ['blog_removed', 'blog_trashed'], + confluence_attachment_created: ['attachment_created'], + confluence_attachment_removed: ['attachment_removed', 'attachment_trashed'], + confluence_space_created: ['space_created'], + confluence_space_updated: ['space_updated'], + confluence_label_added: ['label_added', 'label_created'], + confluence_label_removed: ['label_removed', 'label_deleted'], +} + +const TRIGGER_CATEGORY_MAP: Record = { + confluence_page_created: 'page', + confluence_page_updated: 'page', + confluence_page_removed: 'page', + confluence_page_moved: 'page', + confluence_comment_created: 'comment', + confluence_comment_removed: 'comment', + confluence_blog_created: 'blog', + confluence_blog_updated: 'blog', + confluence_blog_removed: 'blog', + confluence_attachment_created: 'attachment', + confluence_attachment_removed: 'attachment', + confluence_space_created: 'space', + confluence_space_updated: 'space', + confluence_label_added: 'label', + confluence_label_removed: 'label', +} + +/** + * Infers the entity category from a Confluence webhook payload by checking + * which entity key is present in the body. + */ +function inferEntityCategory(body: Record): string | null { + if (body.comment) return 'comment' + if (body.attachment) return 'attachment' + if (body.blog || body.blogpost) return 'blog' + if (body.label) return 'label' + if (body.page) return 'page' + if (body.space) return 'space' + return null +} + +/** + * Checks if a Confluence webhook payload matches a trigger. + * + * Admin REST API webhooks (Settings > Webhooks) include an `event` field + * for exact action-level matching. Connect app webhooks omit it, so we + * fall back to entity-category matching (page vs comment vs blog, etc.). + */ +export function isConfluencePayloadMatch( + triggerId: string, + body: Record +): boolean { + if (triggerId === 'confluence_webhook') { + return true + } + + const event = body.event as string | undefined + if (event) { + const acceptedEvents = TRIGGER_EVENT_MAP[triggerId] + return acceptedEvents ? acceptedEvents.includes(event) : false + } + + const expectedCategory = TRIGGER_CATEGORY_MAP[triggerId] + if (!expectedCategory) { + return false + } + return inferEntityCategory(body) === expectedCategory +} diff --git a/apps/sim/triggers/confluence/webhook.ts b/apps/sim/triggers/confluence/webhook.ts new file mode 100644 index 0000000000..1bcb5c718f --- /dev/null +++ b/apps/sim/triggers/confluence/webhook.ts @@ -0,0 +1,41 @@ +import { ConfluenceIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildConfluenceAttachmentExtraFields, + buildGenericWebhookOutputs, + confluenceSetupInstructions, + confluenceTriggerOptions, +} from '@/triggers/confluence/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Generic Confluence Webhook Trigger + * + * Captures all Confluence webhook events without filtering. + */ +export const confluenceWebhookTrigger: TriggerConfig = { + id: 'confluence_webhook', + name: 'Confluence Webhook (All Events)', + provider: 'confluence', + description: 'Trigger workflow on any Confluence webhook event', + version: '1.0.0', + icon: ConfluenceIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'confluence_webhook', + triggerOptions: confluenceTriggerOptions, + setupInstructions: confluenceSetupInstructions('All Events'), + extraFields: buildConfluenceAttachmentExtraFields('confluence_webhook'), + }), + + outputs: buildGenericWebhookOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Hub-Signature': 'sha256=...', + 'X-Atlassian-Webhook-Identifier': 'unique-webhook-id', + }, + }, +} diff --git a/apps/sim/triggers/registry.ts b/apps/sim/triggers/registry.ts index 09f72f3cf3..63d69729fb 100644 --- a/apps/sim/triggers/registry.ts +++ b/apps/sim/triggers/registry.ts @@ -21,6 +21,24 @@ import { circlebackMeetingNotesTrigger, circlebackWebhookTrigger, } from '@/triggers/circleback' +import { + confluenceAttachmentCreatedTrigger, + confluenceAttachmentRemovedTrigger, + confluenceBlogCreatedTrigger, + confluenceBlogRemovedTrigger, + confluenceBlogUpdatedTrigger, + confluenceCommentCreatedTrigger, + confluenceCommentRemovedTrigger, + confluenceLabelAddedTrigger, + confluenceLabelRemovedTrigger, + confluencePageCreatedTrigger, + confluencePageMovedTrigger, + confluencePageRemovedTrigger, + confluencePageUpdatedTrigger, + confluenceSpaceCreatedTrigger, + confluenceSpaceUpdatedTrigger, + confluenceWebhookTrigger, +} from '@/triggers/confluence' import { firefliesTranscriptionCompleteTrigger } from '@/triggers/fireflies' import { genericWebhookTrigger } from '@/triggers/generic' import { @@ -140,6 +158,22 @@ export const TRIGGER_REGISTRY: TriggerRegistry = { calcom_meeting_ended: calcomMeetingEndedTrigger, calcom_recording_ready: calcomRecordingReadyTrigger, calcom_webhook: calcomWebhookTrigger, + confluence_webhook: confluenceWebhookTrigger, + confluence_page_created: confluencePageCreatedTrigger, + confluence_page_updated: confluencePageUpdatedTrigger, + confluence_page_removed: confluencePageRemovedTrigger, + confluence_page_moved: confluencePageMovedTrigger, + confluence_comment_created: confluenceCommentCreatedTrigger, + confluence_comment_removed: confluenceCommentRemovedTrigger, + confluence_blog_created: confluenceBlogCreatedTrigger, + confluence_blog_updated: confluenceBlogUpdatedTrigger, + confluence_blog_removed: confluenceBlogRemovedTrigger, + confluence_attachment_created: confluenceAttachmentCreatedTrigger, + confluence_attachment_removed: confluenceAttachmentRemovedTrigger, + confluence_space_created: confluenceSpaceCreatedTrigger, + confluence_space_updated: confluenceSpaceUpdatedTrigger, + confluence_label_added: confluenceLabelAddedTrigger, + confluence_label_removed: confluenceLabelRemovedTrigger, generic_webhook: genericWebhookTrigger, github_webhook: githubWebhookTrigger, github_issue_opened: githubIssueOpenedTrigger,