refactor(triggers): consolidate v2 Linear triggers into same files as v1 (#4010)

* refactor(triggers): consolidate v2 Linear triggers into same files as v1

Move v2 trigger exports from separate _v2.ts files into their
corresponding v1 files, matching the block v2 convention where
LinearV2Block lives alongside LinearBlock in the same file.

* updated

* fix: restore staging registry entries accidentally removed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs

* fix: restore integrations.json to staging version

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(generate-docs): extract all trigger configs from multi-export files

The buildTriggerRegistry function used a single regex exec per file,
which only captured the first TriggerConfig export. Files that export
both v1 and v2 triggers (consolidated same-file convention) had their
v2 triggers silently dropped from integrations.json.

Split each file into segments per export and parse each independently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: restore staging linear handler and utils with teamId support

Restores the staging version of linear provider handler and trigger
utils that were accidentally regressed. Key restorations:
- teamId sub-block and allPublicTeams fallback in createSubscription
- Timestamp skew validation in verifyAuth
- actorType renaming in formatInput (avoids TriggerOutput collision)
- url field in formatInput and all output builders
- edited field in comment outputs
- externalId validation after webhook creation
- isLinearEventMatch returns false (not true) for unknown triggers

Adds extractIdempotencyId to the linear provider handler for webhook
deduplication support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: restore non-Linear files accidentally modified

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove redundant extractIdempotencyId from linear handler

The idempotency service already uses the Linear-Delivery header
(which Linear always sends) as the primary dedup key. The body-based
fallback was unnecessary defensive code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* idempotency

* tets

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Waleed
2026-04-06 22:13:48 -07:00
committed by GitHub
parent 779358388d
commit 68df7320bd
39 changed files with 579 additions and 611 deletions

View File

@@ -4015,8 +4015,14 @@
}
],
"operationCount": 12,
"triggers": [],
"triggerCount": 0,
"triggers": [
{
"id": "gmail_poller",
"name": "Gmail Email Trigger",
"description": "Triggers when new emails are received in Gmail (requires Gmail credentials)"
}
],
"triggerCount": 1,
"authType": "oauth",
"category": "tools",
"integrationType": "email",
@@ -7256,7 +7262,7 @@
{
"id": "linear_webhook_v2",
"name": "Linear Webhook",
"description": "Trigger workflow from Linear data-change events included in this webhook subscription (Issues, Comments, Projects, etc.—not every Linear model)."
"description": "Trigger workflow from Linear events you select when creating the webhook in Linear (not guaranteed to be every model or event type)."
}
],
"triggerCount": 15,
@@ -8580,8 +8586,14 @@
}
],
"operationCount": 9,
"triggers": [],
"triggerCount": 0,
"triggers": [
{
"id": "outlook_poller",
"name": "Outlook Email Trigger",
"description": "Triggers when new emails are received in Outlook (requires Microsoft credentials)"
}
],
"triggerCount": 1,
"authType": "oauth",
"category": "tools",
"integrationType": "email",

View File

@@ -422,7 +422,9 @@ export class IdempotencyService {
normalizedHeaders?.['x-teams-notification-id'] ||
normalizedHeaders?.['svix-id'] ||
normalizedHeaders?.['linear-delivery'] ||
normalizedHeaders?.['greenhouse-event-id']
normalizedHeaders?.['greenhouse-event-id'] ||
normalizedHeaders?.['x-zm-request-id'] ||
normalizedHeaders?.['idempotency-key']
if (webhookIdHeader) {
return `${webhookId}:${webhookIdHeader}`

View File

@@ -33,6 +33,15 @@ function validateAshbySignature(secretToken: string, signature: string, body: st
}
export const ashbyHandler: WebhookProviderHandler = {
extractIdempotencyId(body: unknown): string | null {
const obj = body as Record<string, unknown>
const webhookActionId = obj.webhookActionId
if (typeof webhookActionId === 'string' && webhookActionId) {
return `ashby:${webhookActionId}`
}
return null
},
async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
const b = body as Record<string, unknown>
return {

View File

@@ -123,6 +123,20 @@ export async function verifyGongJwtAuth(ctx: AuthContext): Promise<NextResponse
export const gongHandler: WebhookProviderHandler = {
verifyAuth: verifyGongJwtAuth,
extractIdempotencyId(body: unknown): string | null {
const obj = body as Record<string, unknown>
const callData = obj.callData as Record<string, unknown> | undefined
const metaData = callData?.metaData as Record<string, unknown> | undefined
const id = metaData?.id
if (typeof id === 'string' && id) {
return `gong:${id}`
}
if (typeof id === 'number') {
return `gong:${id}`
}
return null
},
async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
const b = body as Record<string, unknown>
const callData = b.callData as Record<string, unknown> | undefined

View File

@@ -23,6 +23,15 @@ export const telegramHandler: WebhookProviderHandler = {
return null
},
extractIdempotencyId(body: unknown): string | null {
const obj = body as Record<string, unknown>
const updateId = obj.update_id
if (typeof updateId === 'number') {
return `telegram:${updateId}`
}
return null
},
async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
const b = body as Record<string, unknown>
const rawMessage = (b?.message ||

View File

@@ -27,29 +27,8 @@ describe('Zoom webhook provider', () => {
expect(validateZoomSignature(secret, hashA, timestamp, rawB)).toBe(false)
})
it('extractIdempotencyId prefers meeting uuid', () => {
const zid = zoomHandler.extractIdempotencyId!({
event: 'meeting.started',
event_ts: 123,
payload: { object: { uuid: 'u1', id: 55 } },
})
expect(zid).toBe('zoom:meeting.started:123:u1')
})
it('extractIdempotencyId uses participant identity when available', () => {
const zid = zoomHandler.extractIdempotencyId!({
event: 'meeting.participant_joined',
event_ts: 123,
payload: {
object: {
uuid: 'meeting-uuid',
participant: {
user_id: 'participant-1',
},
},
},
})
expect(zid).toBe('zoom:meeting.participant_joined:123:participant-1')
it('does not implement extractIdempotencyId (x-zm-request-id handled at service level)', () => {
expect(zoomHandler.extractIdempotencyId).toBeUndefined()
})
it('formatInput passes through the Zoom webhook envelope', async () => {

View File

@@ -128,36 +128,6 @@ export const zoomHandler: WebhookProviderHandler = {
return null
},
extractIdempotencyId(body: unknown): string | null {
const obj = body as Record<string, unknown>
const event = obj.event
const ts = obj.event_ts
if (typeof event !== 'string' || ts === undefined || ts === null) {
return null
}
const payload = obj.payload as Record<string, unknown> | undefined
const inner = payload?.object as Record<string, unknown> | undefined
const participant =
inner?.participant &&
typeof inner.participant === 'object' &&
!Array.isArray(inner.participant)
? (inner.participant as Record<string, unknown>)
: null
const participantStable =
(typeof participant?.user_id === 'string' && participant.user_id) ||
(typeof participant?.id === 'string' && participant.id) ||
(typeof participant?.email === 'string' && participant.email) ||
(typeof participant?.join_time === 'string' && participant.join_time) ||
(typeof participant?.leave_time === 'string' && participant.leave_time) ||
''
const stable =
participantStable ||
(typeof inner?.uuid === 'string' && inner.uuid) ||
(inner?.id !== undefined && inner.id !== null ? String(inner.id) : '') ||
''
return `zoom:${event}:${String(ts)}:${stable}`
},
async matchEvent({ webhook: wh, workflow, body, requestId, providerConfig }: EventMatchContext) {
const triggerId = providerConfig.triggerId as string | undefined
const obj = body as Record<string, unknown>

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildCommentOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildCommentOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCommentCreatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearCommentCreatedTrigger: TriggerConfig = {
},
},
}
export const linearCommentCreatedV2Trigger: TriggerConfig = {
id: 'linear_comment_created_v2',
name: 'Linear Comment Created',
provider: 'linear',
description: 'Trigger workflow when a new comment is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_comment_created_v2',
eventType: 'Comment (create)',
}),
outputs: buildCommentOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Comment',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildCommentOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCommentCreatedV2Trigger: TriggerConfig = {
id: 'linear_comment_created_v2',
name: 'Linear Comment Created',
provider: 'linear',
description: 'Trigger workflow when a new comment is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_comment_created_v2',
eventType: 'Comment (create)',
}),
outputs: buildCommentOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Comment',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildCommentOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildCommentOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCommentUpdatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearCommentUpdatedTrigger: TriggerConfig = {
},
},
}
export const linearCommentUpdatedV2Trigger: TriggerConfig = {
id: 'linear_comment_updated_v2',
name: 'Linear Comment Updated',
provider: 'linear',
description: 'Trigger workflow when a comment is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_comment_updated_v2',
eventType: 'Comment (update)',
}),
outputs: buildCommentOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Comment',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildCommentOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCommentUpdatedV2Trigger: TriggerConfig = {
id: 'linear_comment_updated_v2',
name: 'Linear Comment Updated',
provider: 'linear',
description: 'Trigger workflow when a comment is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_comment_updated_v2',
eventType: 'Comment (update)',
}),
outputs: buildCommentOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Comment',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildCustomerRequestOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildCustomerRequestOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCustomerRequestCreatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearCustomerRequestCreatedTrigger: TriggerConfig = {
},
},
}
export const linearCustomerRequestCreatedV2Trigger: TriggerConfig = {
id: 'linear_customer_request_created_v2',
name: 'Linear Customer Request Created',
provider: 'linear',
description: 'Trigger workflow when a new customer request is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_customer_request_created_v2',
eventType: 'Customer Requests',
}),
outputs: buildCustomerRequestOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'CustomerNeed',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildCustomerRequestOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCustomerRequestCreatedV2Trigger: TriggerConfig = {
id: 'linear_customer_request_created_v2',
name: 'Linear Customer Request Created',
provider: 'linear',
description: 'Trigger workflow when a new customer request is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_customer_request_created_v2',
eventType: 'Customer Requests',
}),
outputs: buildCustomerRequestOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'CustomerNeed',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildCustomerRequestOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildCustomerRequestOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCustomerRequestUpdatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearCustomerRequestUpdatedTrigger: TriggerConfig = {
},
},
}
export const linearCustomerRequestUpdatedV2Trigger: TriggerConfig = {
id: 'linear_customer_request_updated_v2',
name: 'Linear Customer Request Updated',
provider: 'linear',
description: 'Trigger workflow when a customer request is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_customer_request_updated_v2',
eventType: 'CustomerNeed (update)',
}),
outputs: buildCustomerRequestOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'CustomerNeed',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildCustomerRequestOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCustomerRequestUpdatedV2Trigger: TriggerConfig = {
id: 'linear_customer_request_updated_v2',
name: 'Linear Customer Request Updated',
provider: 'linear',
description: 'Trigger workflow when a customer request is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_customer_request_updated_v2',
eventType: 'CustomerNeed (update)',
}),
outputs: buildCustomerRequestOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'CustomerNeed',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildCycleOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildCycleOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCycleCreatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearCycleCreatedTrigger: TriggerConfig = {
},
},
}
export const linearCycleCreatedV2Trigger: TriggerConfig = {
id: 'linear_cycle_created_v2',
name: 'Linear Cycle Created',
provider: 'linear',
description: 'Trigger workflow when a new cycle is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_cycle_created_v2',
eventType: 'Cycle (create)',
}),
outputs: buildCycleOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Cycle',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildCycleOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCycleCreatedV2Trigger: TriggerConfig = {
id: 'linear_cycle_created_v2',
name: 'Linear Cycle Created',
provider: 'linear',
description: 'Trigger workflow when a new cycle is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_cycle_created_v2',
eventType: 'Cycle (create)',
}),
outputs: buildCycleOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Cycle',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildCycleOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildCycleOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCycleUpdatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearCycleUpdatedTrigger: TriggerConfig = {
},
},
}
export const linearCycleUpdatedV2Trigger: TriggerConfig = {
id: 'linear_cycle_updated_v2',
name: 'Linear Cycle Updated',
provider: 'linear',
description: 'Trigger workflow when a cycle is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_cycle_updated_v2',
eventType: 'Cycle (update)',
}),
outputs: buildCycleOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Cycle',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildCycleOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearCycleUpdatedV2Trigger: TriggerConfig = {
id: 'linear_cycle_updated_v2',
name: 'Linear Cycle Updated',
provider: 'linear',
description: 'Trigger workflow when a cycle is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_cycle_updated_v2',
eventType: 'Cycle (update)',
}),
outputs: buildCycleOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Cycle',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +1,24 @@
export { linearCommentCreatedTrigger } from './comment_created'
export { linearCommentCreatedV2Trigger } from './comment_created_v2'
export { linearCommentUpdatedTrigger } from './comment_updated'
export { linearCommentUpdatedV2Trigger } from './comment_updated_v2'
export { linearCustomerRequestCreatedTrigger } from './customer_request_created'
export { linearCustomerRequestCreatedV2Trigger } from './customer_request_created_v2'
export { linearCustomerRequestUpdatedTrigger } from './customer_request_updated'
export { linearCustomerRequestUpdatedV2Trigger } from './customer_request_updated_v2'
export { linearCycleCreatedTrigger } from './cycle_created'
export { linearCycleCreatedV2Trigger } from './cycle_created_v2'
export { linearCycleUpdatedTrigger } from './cycle_updated'
export { linearCycleUpdatedV2Trigger } from './cycle_updated_v2'
export { linearIssueCreatedTrigger } from './issue_created'
export { linearIssueCreatedV2Trigger } from './issue_created_v2'
export { linearIssueRemovedTrigger } from './issue_removed'
export { linearIssueRemovedV2Trigger } from './issue_removed_v2'
export { linearIssueUpdatedTrigger } from './issue_updated'
export { linearIssueUpdatedV2Trigger } from './issue_updated_v2'
export { linearLabelCreatedTrigger } from './label_created'
export { linearLabelCreatedV2Trigger } from './label_created_v2'
export { linearLabelUpdatedTrigger } from './label_updated'
export { linearLabelUpdatedV2Trigger } from './label_updated_v2'
export { linearProjectCreatedTrigger } from './project_created'
export { linearProjectCreatedV2Trigger } from './project_created_v2'
export { linearProjectUpdateCreatedTrigger } from './project_update_created'
export { linearProjectUpdateCreatedV2Trigger } from './project_update_created_v2'
export { linearProjectUpdatedTrigger } from './project_updated'
export { linearProjectUpdatedV2Trigger } from './project_updated_v2'
export { linearWebhookTrigger } from './webhook'
export { linearWebhookV2Trigger } from './webhook_v2'
export { linearCommentCreatedTrigger, linearCommentCreatedV2Trigger } from './comment_created'
export { linearCommentUpdatedTrigger, linearCommentUpdatedV2Trigger } from './comment_updated'
export {
linearCustomerRequestCreatedTrigger,
linearCustomerRequestCreatedV2Trigger,
} from './customer_request_created'
export {
linearCustomerRequestUpdatedTrigger,
linearCustomerRequestUpdatedV2Trigger,
} from './customer_request_updated'
export { linearCycleCreatedTrigger, linearCycleCreatedV2Trigger } from './cycle_created'
export { linearCycleUpdatedTrigger, linearCycleUpdatedV2Trigger } from './cycle_updated'
export { linearIssueCreatedTrigger, linearIssueCreatedV2Trigger } from './issue_created'
export { linearIssueRemovedTrigger, linearIssueRemovedV2Trigger } from './issue_removed'
export { linearIssueUpdatedTrigger, linearIssueUpdatedV2Trigger } from './issue_updated'
export { linearLabelCreatedTrigger, linearLabelCreatedV2Trigger } from './label_created'
export { linearLabelUpdatedTrigger, linearLabelUpdatedV2Trigger } from './label_updated'
export { linearProjectCreatedTrigger, linearProjectCreatedV2Trigger } from './project_created'
export {
linearProjectUpdateCreatedTrigger,
linearProjectUpdateCreatedV2Trigger,
} from './project_update_created'
export { linearProjectUpdatedTrigger, linearProjectUpdatedV2Trigger } from './project_updated'
export { linearWebhookTrigger, linearWebhookV2Trigger } from './webhook'

View File

@@ -1,6 +1,7 @@
import { LinearIcon } from '@/components/icons'
import {
buildIssueOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
linearTriggerOptions,
} from '@/triggers/linear/utils'
@@ -91,3 +92,28 @@ export const linearIssueCreatedTrigger: TriggerConfig = {
},
},
}
export const linearIssueCreatedV2Trigger: TriggerConfig = {
id: 'linear_issue_created_v2',
name: 'Linear Issue Created',
provider: 'linear',
description: 'Trigger workflow when a new issue is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_issue_created_v2',
eventType: 'Issue (create)',
includeDropdown: true,
}),
outputs: buildIssueOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Issue',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,37 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildIssueOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
/**
* Linear Issue Created Trigger (v2)
*
* Primary trigger - includes the dropdown for selecting trigger type.
* Uses automatic webhook registration via the Linear GraphQL API.
*/
export const linearIssueCreatedV2Trigger: TriggerConfig = {
id: 'linear_issue_created_v2',
name: 'Linear Issue Created',
provider: 'linear',
description: 'Trigger workflow when a new issue is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_issue_created_v2',
eventType: 'Issue (create)',
includeDropdown: true,
}),
outputs: buildIssueOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Issue',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildIssueOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildIssueOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearIssueRemovedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearIssueRemovedTrigger: TriggerConfig = {
},
},
}
export const linearIssueRemovedV2Trigger: TriggerConfig = {
id: 'linear_issue_removed_v2',
name: 'Linear Issue Removed',
provider: 'linear',
description: 'Trigger workflow when an issue is removed/deleted in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_issue_removed_v2',
eventType: 'Issue (remove)',
}),
outputs: buildIssueOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Issue',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildIssueOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearIssueRemovedV2Trigger: TriggerConfig = {
id: 'linear_issue_removed_v2',
name: 'Linear Issue Removed',
provider: 'linear',
description: 'Trigger workflow when an issue is removed/deleted in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_issue_removed_v2',
eventType: 'Issue (remove)',
}),
outputs: buildIssueOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Issue',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildIssueOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildIssueOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearIssueUpdatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearIssueUpdatedTrigger: TriggerConfig = {
},
},
}
export const linearIssueUpdatedV2Trigger: TriggerConfig = {
id: 'linear_issue_updated_v2',
name: 'Linear Issue Updated',
provider: 'linear',
description: 'Trigger workflow when an issue is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_issue_updated_v2',
eventType: 'Issue (update)',
}),
outputs: buildIssueOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Issue',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildIssueOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearIssueUpdatedV2Trigger: TriggerConfig = {
id: 'linear_issue_updated_v2',
name: 'Linear Issue Updated',
provider: 'linear',
description: 'Trigger workflow when an issue is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_issue_updated_v2',
eventType: 'Issue (update)',
}),
outputs: buildIssueOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Issue',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildLabelOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildLabelOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearLabelCreatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearLabelCreatedTrigger: TriggerConfig = {
},
},
}
export const linearLabelCreatedV2Trigger: TriggerConfig = {
id: 'linear_label_created_v2',
name: 'Linear Label Created',
provider: 'linear',
description: 'Trigger workflow when a new label is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_label_created_v2',
eventType: 'IssueLabel (create)',
}),
outputs: buildLabelOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'IssueLabel',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildLabelOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearLabelCreatedV2Trigger: TriggerConfig = {
id: 'linear_label_created_v2',
name: 'Linear Label Created',
provider: 'linear',
description: 'Trigger workflow when a new label is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_label_created_v2',
eventType: 'IssueLabel (create)',
}),
outputs: buildLabelOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'IssueLabel',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildLabelOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildLabelOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearLabelUpdatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearLabelUpdatedTrigger: TriggerConfig = {
},
},
}
export const linearLabelUpdatedV2Trigger: TriggerConfig = {
id: 'linear_label_updated_v2',
name: 'Linear Label Updated',
provider: 'linear',
description: 'Trigger workflow when a label is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_label_updated_v2',
eventType: 'IssueLabel (update)',
}),
outputs: buildLabelOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'IssueLabel',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildLabelOutputs, buildLinearV2SubBlocks } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearLabelUpdatedV2Trigger: TriggerConfig = {
id: 'linear_label_updated_v2',
name: 'Linear Label Updated',
provider: 'linear',
description: 'Trigger workflow when a label is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_label_updated_v2',
eventType: 'IssueLabel (update)',
}),
outputs: buildLabelOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'IssueLabel',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildProjectOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildLinearV2SubBlocks,
buildProjectOutputs,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearProjectCreatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearProjectCreatedTrigger: TriggerConfig = {
},
},
}
export const linearProjectCreatedV2Trigger: TriggerConfig = {
id: 'linear_project_created_v2',
name: 'Linear Project Created',
provider: 'linear',
description: 'Trigger workflow when a new project is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_project_created_v2',
eventType: 'Project (create)',
}),
outputs: buildProjectOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Project',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildLinearV2SubBlocks, buildProjectOutputs } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearProjectCreatedV2Trigger: TriggerConfig = {
id: 'linear_project_created_v2',
name: 'Linear Project Created',
provider: 'linear',
description: 'Trigger workflow when a new project is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_project_created_v2',
eventType: 'Project (create)',
}),
outputs: buildProjectOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Project',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildProjectUpdateOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildLinearV2SubBlocks,
buildProjectUpdateOutputs,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearProjectUpdateCreatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearProjectUpdateCreatedTrigger: TriggerConfig = {
},
},
}
export const linearProjectUpdateCreatedV2Trigger: TriggerConfig = {
id: 'linear_project_update_created_v2',
name: 'Linear Project Update Created',
provider: 'linear',
description: 'Trigger workflow when a new project update is posted in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_project_update_created_v2',
eventType: 'ProjectUpdate (create)',
}),
outputs: buildProjectUpdateOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'ProjectUpdate',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildLinearV2SubBlocks, buildProjectUpdateOutputs } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearProjectUpdateCreatedV2Trigger: TriggerConfig = {
id: 'linear_project_update_created_v2',
name: 'Linear Project Update Created',
provider: 'linear',
description: 'Trigger workflow when a new project update is posted in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_project_update_created_v2',
eventType: 'ProjectUpdate (create)',
}),
outputs: buildProjectUpdateOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'ProjectUpdate',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildProjectOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildLinearV2SubBlocks,
buildProjectOutputs,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearProjectUpdatedTrigger: TriggerConfig = {
@@ -78,3 +82,27 @@ export const linearProjectUpdatedTrigger: TriggerConfig = {
},
},
}
export const linearProjectUpdatedV2Trigger: TriggerConfig = {
id: 'linear_project_updated_v2',
name: 'Linear Project Updated',
provider: 'linear',
description: 'Trigger workflow when a project is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_project_updated_v2',
eventType: 'Project (update)',
}),
outputs: buildProjectOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Project',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,30 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildLinearV2SubBlocks, buildProjectOutputs } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearProjectUpdatedV2Trigger: TriggerConfig = {
id: 'linear_project_updated_v2',
name: 'Linear Project Updated',
provider: 'linear',
description: 'Trigger workflow when a project is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_project_updated_v2',
eventType: 'Project (update)',
}),
outputs: buildProjectOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Project',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { linearSetupInstructions, userOutputs } from '@/triggers/linear/utils'
import {
buildLinearV2SubBlocks,
linearSetupInstructions,
userOutputs,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearWebhookTrigger: TriggerConfig = {
@@ -120,3 +124,68 @@ export const linearWebhookTrigger: TriggerConfig = {
},
},
}
export const linearWebhookV2Trigger: TriggerConfig = {
id: 'linear_webhook_v2',
name: 'Linear Webhook',
provider: 'linear',
description:
'Trigger workflow from Linear events you select when creating the webhook in Linear (not guaranteed to be every model or event type).',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_webhook_v2',
eventType: 'All Events',
additionalNotes:
'This webhook will receive all Linear events. Use the <code>type</code> and <code>action</code> fields in the payload to filter and handle different event types.',
}),
outputs: {
action: {
type: 'string',
description: 'Action performed (create, update, remove)',
},
type: {
type: 'string',
description: 'Entity type (Issue, Comment, Project, Cycle, IssueLabel, ProjectUpdate, etc.)',
},
webhookId: {
type: 'string',
description: 'Webhook ID',
},
webhookTimestamp: {
type: 'number',
description: 'Webhook timestamp (milliseconds)',
},
organizationId: {
type: 'string',
description: 'Organization ID',
},
createdAt: {
type: 'string',
description: 'Event creation timestamp',
},
url: {
type: 'string',
description: 'URL of the subject entity in Linear (top-level webhook payload)',
},
actor: userOutputs,
data: {
type: 'object',
description: 'Complete entity data object',
},
updatedFrom: {
type: 'object',
description: 'Previous values for changed fields (only present on update)',
},
},
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Issue',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -1,71 +0,0 @@
import { LinearIcon } from '@/components/icons'
import { buildLinearV2SubBlocks, userOutputs } from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'
export const linearWebhookV2Trigger: TriggerConfig = {
id: 'linear_webhook_v2',
name: 'Linear Webhook',
provider: 'linear',
description:
'Trigger workflow from Linear data-change events included in this webhook subscription (Issues, Comments, Projects, etc.—not every Linear model).',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_webhook_v2',
eventType: 'All Events',
additionalNotes:
'Sim registers this webhook for Issues, Comments, Projects, Cycles, Issue labels, Project updates, and Customer requests—matching what the Linear API allows in one subscription. It does not include every model Linear documents separately (e.g. Documents, Reactions). Use <code>type</code> and <code>action</code> in the payload to filter.',
}),
outputs: {
action: {
type: 'string',
description: 'Action performed (create, update, remove)',
},
type: {
type: 'string',
description: 'Entity type (Issue, Comment, Project, Cycle, IssueLabel, ProjectUpdate, etc.)',
},
webhookId: {
type: 'string',
description: 'Webhook ID',
},
webhookTimestamp: {
type: 'number',
description: 'Webhook timestamp (milliseconds)',
},
organizationId: {
type: 'string',
description: 'Organization ID',
},
createdAt: {
type: 'string',
description: 'Event creation timestamp',
},
url: {
type: 'string',
description: 'URL of the subject entity in Linear (top-level webhook payload)',
},
actor: userOutputs,
data: {
type: 'object',
description: 'Complete entity data object',
},
updatedFrom: {
type: 'object',
description: 'Previous values for changed fields (only present on update)',
},
},
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Issue',
'Linear-Delivery': '234d1a4e-b617-4388-90fe-adc3633d6b72',
'Linear-Signature': '766e1d90a96e2f5ecec342a99c5552999dd95d49250171b902d703fd674f5086',
'User-Agent': 'Linear-Webhook',
},
},
}

View File

@@ -491,17 +491,35 @@ async function buildTriggerRegistry(): Promise<Map<string, TriggerInfo>> {
try {
const content = fs.readFileSync(file, 'utf-8')
// Each trigger file exports a single TriggerConfig with id, name, description
const idMatch = /\bid\s*:\s*['"]([^'"]+)['"]/.exec(content)
const nameMatch = /\bname\s*:\s*['"]([^'"]+)['"]/.exec(content)
const descMatch = /\bdescription\s*:\s*['"]([^'"]+)['"]/.exec(content)
// A file may export multiple TriggerConfig objects (e.g. v1 + v2 in
// the same file). Extract all exported configs by splitting on the
// export boundaries and parsing each one independently.
const exportRegex = /export\s+const\s+\w+\s*:\s*TriggerConfig\s*=\s*\{/g
let exportMatch
const exportStarts: number[] = []
if (idMatch && nameMatch) {
registry.set(idMatch[1], {
id: idMatch[1],
name: nameMatch[1],
description: descMatch?.[1] ?? '',
})
while ((exportMatch = exportRegex.exec(content)) !== null) {
exportStarts.push(exportMatch.index)
}
// If no typed exports found, fall back to simple regex on whole file
const segments =
exportStarts.length > 0
? exportStarts.map((start, i) => content.substring(start, exportStarts[i + 1]))
: [content]
for (const segment of segments) {
const idMatch = /\bid\s*:\s*['"]([^'"]+)['"]/.exec(segment)
const nameMatch = /\bname\s*:\s*['"]([^'"]+)['"]/.exec(segment)
const descMatch = /\bdescription\s*:\s*['"]([^'"]+)['"]/.exec(segment)
if (idMatch && nameMatch) {
registry.set(idMatch[1], {
id: idMatch[1],
name: nameMatch[1],
description: descMatch?.[1] ?? '',
})
}
}
} catch {
// skip unreadable files silently