chore: import upstream snapshot with attribution
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
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -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',
},
},
}
@@ -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',
},
},
}
@@ -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 Updated Trigger
*
* Triggers when an attachment is updated (new version uploaded) in Confluence.
*/
export const confluenceAttachmentUpdatedTrigger: TriggerConfig = {
id: 'confluence_attachment_updated',
name: 'Confluence Attachment Updated',
provider: 'confluence',
description: 'Trigger workflow when an attachment is updated in Confluence',
version: '1.0.0',
icon: ConfluenceIcon,
subBlocks: buildTriggerSubBlocks({
triggerId: 'confluence_attachment_updated',
triggerOptions: confluenceTriggerOptions,
setupInstructions: confluenceSetupInstructions('attachment_updated'),
extraFields: buildConfluenceAttachmentExtraFields('confluence_attachment_updated'),
}),
outputs: buildAttachmentOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Hub-Signature': 'sha256=...',
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
},
},
}
@@ -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',
},
},
}
@@ -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',
},
},
}
@@ -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 Restored Trigger
*
* Triggers when a blog post is restored from trash in Confluence.
*/
export const confluenceBlogRestoredTrigger: TriggerConfig = {
id: 'confluence_blog_restored',
name: 'Confluence Blog Post Restored',
provider: 'confluence',
description: 'Trigger workflow when a blog post is restored from trash in Confluence',
version: '1.0.0',
icon: ConfluenceIcon,
subBlocks: buildTriggerSubBlocks({
triggerId: 'confluence_blog_restored',
triggerOptions: confluenceTriggerOptions,
setupInstructions: confluenceSetupInstructions('blog_restored'),
extraFields: buildConfluenceExtraFields('confluence_blog_restored'),
}),
outputs: buildBlogOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Hub-Signature': 'sha256=...',
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
},
},
}
@@ -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',
},
},
}
@@ -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',
},
},
}
@@ -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',
},
},
}
@@ -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 Updated Trigger
*
* Triggers when a comment on a page or blog post is updated/edited in Confluence.
*/
export const confluenceCommentUpdatedTrigger: TriggerConfig = {
id: 'confluence_comment_updated',
name: 'Confluence Comment Updated',
provider: 'confluence',
description: 'Trigger workflow when a comment is updated in Confluence',
version: '1.0.0',
icon: ConfluenceIcon,
subBlocks: buildTriggerSubBlocks({
triggerId: 'confluence_comment_updated',
triggerOptions: confluenceTriggerOptions,
setupInstructions: confluenceSetupInstructions('comment_updated'),
extraFields: buildConfluenceExtraFields('confluence_comment_updated'),
}),
outputs: buildCommentOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Hub-Signature': 'sha256=...',
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
},
},
}
+28
View File
@@ -0,0 +1,28 @@
/**
* Confluence Triggers
* Export all Confluence webhook triggers
*/
export { confluenceAttachmentCreatedTrigger } from './attachment_created'
export { confluenceAttachmentRemovedTrigger } from './attachment_removed'
export { confluenceAttachmentUpdatedTrigger } from './attachment_updated'
export { confluenceBlogCreatedTrigger } from './blog_created'
export { confluenceBlogRemovedTrigger } from './blog_removed'
export { confluenceBlogRestoredTrigger } from './blog_restored'
export { confluenceBlogUpdatedTrigger } from './blog_updated'
export { confluenceCommentCreatedTrigger } from './comment_created'
export { confluenceCommentRemovedTrigger } from './comment_removed'
export { confluenceCommentUpdatedTrigger } from './comment_updated'
export { confluenceLabelAddedTrigger } from './label_added'
export { confluenceLabelRemovedTrigger } from './label_removed'
export { confluencePageCreatedTrigger } from './page_created'
export { confluencePageMovedTrigger } from './page_moved'
export { confluencePagePermissionsUpdatedTrigger } from './page_permissions_updated'
export { confluencePageRemovedTrigger } from './page_removed'
export { confluencePageRestoredTrigger } from './page_restored'
export { confluencePageUpdatedTrigger } from './page_updated'
export { confluenceSpaceCreatedTrigger } from './space_created'
export { confluenceSpaceRemovedTrigger } from './space_removed'
export { confluenceSpaceUpdatedTrigger } from './space_updated'
export { confluenceUserCreatedTrigger } from './user_created'
export { confluenceWebhookTrigger } from './webhook'
@@ -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',
},
},
}
@@ -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',
},
},
}
@@ -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',
},
},
}
@@ -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',
},
},
}
@@ -0,0 +1,41 @@
import { ConfluenceIcon } from '@/components/icons'
import { buildTriggerSubBlocks } from '@/triggers'
import {
buildConfluenceExtraFields,
buildPagePermissionsOutputs,
confluenceSetupInstructions,
confluenceTriggerOptions,
} from '@/triggers/confluence/utils'
import type { TriggerConfig } from '@/triggers/types'
/**
* Confluence Page Permissions Updated Trigger
*
* Triggers when page permissions are changed in Confluence.
*/
export const confluencePagePermissionsUpdatedTrigger: TriggerConfig = {
id: 'confluence_page_permissions_updated',
name: 'Confluence Page Permissions Updated',
provider: 'confluence',
description: 'Trigger workflow when page permissions are changed in Confluence',
version: '1.0.0',
icon: ConfluenceIcon,
subBlocks: buildTriggerSubBlocks({
triggerId: 'confluence_page_permissions_updated',
triggerOptions: confluenceTriggerOptions,
setupInstructions: confluenceSetupInstructions('content_permissions_updated'),
extraFields: buildConfluenceExtraFields('confluence_page_permissions_updated'),
}),
outputs: buildPagePermissionsOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Hub-Signature': 'sha256=...',
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
},
},
}
@@ -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',
},
},
}
@@ -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 Restored Trigger
*
* Triggers when a page is restored from trash in Confluence.
*/
export const confluencePageRestoredTrigger: TriggerConfig = {
id: 'confluence_page_restored',
name: 'Confluence Page Restored',
provider: 'confluence',
description: 'Trigger workflow when a page is restored from trash in Confluence',
version: '1.0.0',
icon: ConfluenceIcon,
subBlocks: buildTriggerSubBlocks({
triggerId: 'confluence_page_restored',
triggerOptions: confluenceTriggerOptions,
setupInstructions: confluenceSetupInstructions('page_restored'),
extraFields: buildConfluenceExtraFields('confluence_page_restored'),
}),
outputs: buildPageOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Hub-Signature': 'sha256=...',
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
},
},
}
@@ -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',
},
},
}
@@ -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',
},
},
}
@@ -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 Removed Trigger
*
* Triggers when a space is deleted/removed in Confluence.
*/
export const confluenceSpaceRemovedTrigger: TriggerConfig = {
id: 'confluence_space_removed',
name: 'Confluence Space Removed',
provider: 'confluence',
description: 'Trigger workflow when a space is removed in Confluence',
version: '1.0.0',
icon: ConfluenceIcon,
subBlocks: buildTriggerSubBlocks({
triggerId: 'confluence_space_removed',
triggerOptions: confluenceTriggerOptions,
setupInstructions: confluenceSetupInstructions('space_removed'),
extraFields: buildConfluenceExtraFields('confluence_space_removed'),
}),
outputs: buildSpaceOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Hub-Signature': 'sha256=...',
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
},
},
}
@@ -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',
},
},
}
@@ -0,0 +1,41 @@
import { ConfluenceIcon } from '@/components/icons'
import { buildTriggerSubBlocks } from '@/triggers'
import {
buildConfluenceExtraFields,
buildUserOutputs,
confluenceSetupInstructions,
confluenceTriggerOptions,
} from '@/triggers/confluence/utils'
import type { TriggerConfig } from '@/triggers/types'
/**
* Confluence User Created Trigger
*
* Triggers when a new user is added to Confluence.
*/
export const confluenceUserCreatedTrigger: TriggerConfig = {
id: 'confluence_user_created',
name: 'Confluence User Created',
provider: 'confluence',
description: 'Trigger workflow when a new user is added to Confluence',
version: '1.0.0',
icon: ConfluenceIcon,
subBlocks: buildTriggerSubBlocks({
triggerId: 'confluence_user_created',
triggerOptions: confluenceTriggerOptions,
setupInstructions: confluenceSetupInstructions('user_created'),
extraFields: buildConfluenceExtraFields('confluence_user_created'),
}),
outputs: buildUserOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Hub-Signature': 'sha256=...',
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
},
},
}
+466
View File
@@ -0,0 +1,466 @@
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: 'Comment Updated', id: 'confluence_comment_updated' },
{ label: 'Attachment Updated', id: 'confluence_attachment_updated' },
{ label: 'Page Restored', id: 'confluence_page_restored' },
{ label: 'Blog Post Restored', id: 'confluence_blog_restored' },
{ label: 'Space Removed', id: 'confluence_space_removed' },
{ label: 'Page Permissions Updated', id: 'confluence_page_permissions_updated' },
{ label: 'User Created', id: 'confluence_user_created' },
{ label: 'Generic Webhook (All Events)', id: 'confluence_webhook' },
]
export function confluenceSetupInstructions(eventType: string): string {
const instructions = [
'<strong>Note:</strong> You must have admin permissions in your Confluence workspace to create webhooks. See the <a href="https://developer.atlassian.com/cloud/confluence/modules/webhook/" target="_blank" rel="noopener noreferrer">Confluence webhook documentation</a> for details.',
'In Confluence, navigate to <strong>Settings > Webhooks</strong>.',
'Click <strong>"Create a Webhook"</strong> to add a new webhook.',
'Paste the <strong>Webhook URL</strong> from above into the URL field.',
'Optionally, enter the <strong>Webhook Secret</strong> from above into the secret field for added security.',
`Select the events you want to trigger this workflow. For this trigger, select <strong>${eventType}</strong>.`,
'Click <strong>"Create"</strong> to activate the webhook.',
]
return instructions
.map(
(instruction, index) =>
`<div class="mb-3">${index === 0 ? instruction : `<strong>${index}.</strong> ${instruction}`}</div>`
)
.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<string, TriggerOutput> {
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<string, TriggerOutput> {
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<string, TriggerOutput> {
return {
...buildBaseWebhookOutputs(),
page: buildContentEntityFields(),
}
}
/** Comment-related outputs for comment events. */
export function buildCommentOutputs(): Record<string, TriggerOutput> {
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<string, TriggerOutput> {
return {
...buildBaseWebhookOutputs(),
blog: buildContentEntityFields(),
}
}
/** Attachment-related outputs for attachment events. */
export function buildAttachmentOutputs(): Record<string, TriggerOutput> {
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<string, TriggerOutput> {
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<string, TriggerOutput> {
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)' },
},
}
}
/** Page permissions outputs for permission change events. */
export function buildPagePermissionsOutputs(): Record<string, TriggerOutput> {
return {
...buildBaseWebhookOutputs(),
page: {
...buildContentEntityFields(),
permissions: {
type: 'json',
description: 'Updated permissions object for the page',
},
},
}
}
/** User-related outputs for user events. */
export function buildUserOutputs(): Record<string, TriggerOutput> {
return {
...buildBaseWebhookOutputs(),
user: {
accountId: { type: 'string', description: 'Account ID of the new user' },
accountType: { type: 'string', description: 'Account type (e.g., atlassian, app)' },
displayName: { type: 'string', description: 'Display name of the user' },
emailAddress: {
type: 'string',
description:
'Email address of the user (may not be available due to GDPR/privacy settings)',
},
publicName: { type: 'string', description: 'Public name of the user' },
self: { type: 'string', description: 'URL link to the user profile' },
},
}
}
/** Combined outputs for the generic webhook trigger (all events). */
export function buildGenericWebhookOutputs(): Record<string, TriggerOutput> {
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)' },
user: { type: 'json', description: 'User object (present in user 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 || {},
}
}
export function extractPagePermissionsData(body: Record<string, unknown>) {
return {
timestamp: body.timestamp,
userAccountId: body.userAccountId,
accountType: body.accountType,
page: body.page || {},
}
}
export function extractUserData(body: Record<string, unknown>) {
return {
timestamp: body.timestamp,
userAccountId: body.userAccountId,
accountType: body.accountType,
user: body.user || {},
}
}
/**
* 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<string, string[]> = {
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'],
confluence_comment_updated: ['comment_updated'],
confluence_attachment_updated: ['attachment_updated'],
confluence_page_restored: ['page_restored'],
confluence_blog_restored: ['blog_restored'],
confluence_space_removed: ['space_removed'],
confluence_page_permissions_updated: ['content_permissions_updated'],
confluence_user_created: ['user_created', 'user_reactivated'],
}
const TRIGGER_CATEGORY_MAP: Record<string, string> = {
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',
confluence_comment_updated: 'comment',
confluence_attachment_updated: 'attachment',
confluence_page_restored: 'page',
confluence_blog_restored: 'blog',
confluence_space_removed: 'space',
confluence_page_permissions_updated: 'page',
confluence_user_created: 'user',
}
/**
* Infers the entity category from a Confluence webhook payload by checking
* which entity key is present in the body.
*/
function inferEntityCategory(body: Record<string, unknown>): 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'
if (body.user) return 'user'
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<string, unknown>
): 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
}
+41
View File
@@ -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',
},
},
}