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
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:
@@ -0,0 +1,26 @@
|
||||
import { RootlyIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRootlyAlertOutputs,
|
||||
buildRootlyExtraFields,
|
||||
rootlySetupInstructions,
|
||||
rootlyTriggerOptions,
|
||||
} from '@/triggers/rootly/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const rootlyAlertCreatedTrigger: TriggerConfig = {
|
||||
id: 'rootly_alert_created',
|
||||
name: 'Rootly Alert Created',
|
||||
provider: 'rootly',
|
||||
description: 'Trigger workflow when a new alert is created in Rootly',
|
||||
version: '1.0.0',
|
||||
icon: RootlyIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'rootly_alert_created',
|
||||
triggerOptions: rootlyTriggerOptions,
|
||||
setupInstructions: rootlySetupInstructions('alert.created'),
|
||||
extraFields: buildRootlyExtraFields('rootly_alert_created'),
|
||||
}),
|
||||
outputs: buildRootlyAlertOutputs(),
|
||||
webhook: { method: 'POST', headers: { 'Content-Type': 'application/json' } },
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { RootlyIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRootlyExtraFields,
|
||||
buildRootlyIncidentOutputs,
|
||||
rootlySetupInstructions,
|
||||
rootlyTriggerOptions,
|
||||
} from '@/triggers/rootly/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const rootlyIncidentCreatedTrigger: TriggerConfig = {
|
||||
id: 'rootly_incident_created',
|
||||
name: 'Rootly Incident Created',
|
||||
provider: 'rootly',
|
||||
description: 'Trigger workflow when a new incident is created in Rootly',
|
||||
version: '1.0.0',
|
||||
icon: RootlyIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'rootly_incident_created',
|
||||
triggerOptions: rootlyTriggerOptions,
|
||||
includeDropdown: true,
|
||||
setupInstructions: rootlySetupInstructions('incident.created'),
|
||||
extraFields: buildRootlyExtraFields('rootly_incident_created'),
|
||||
}),
|
||||
outputs: buildRootlyIncidentOutputs(),
|
||||
webhook: { method: 'POST', headers: { 'Content-Type': 'application/json' } },
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { RootlyIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRootlyExtraFields,
|
||||
buildRootlyIncidentOutputs,
|
||||
rootlySetupInstructions,
|
||||
rootlyTriggerOptions,
|
||||
} from '@/triggers/rootly/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const rootlyIncidentResolvedTrigger: TriggerConfig = {
|
||||
id: 'rootly_incident_resolved',
|
||||
name: 'Rootly Incident Resolved',
|
||||
provider: 'rootly',
|
||||
description: 'Trigger workflow when an incident is resolved in Rootly',
|
||||
version: '1.0.0',
|
||||
icon: RootlyIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'rootly_incident_resolved',
|
||||
triggerOptions: rootlyTriggerOptions,
|
||||
setupInstructions: rootlySetupInstructions('incident.resolved'),
|
||||
extraFields: buildRootlyExtraFields('rootly_incident_resolved'),
|
||||
}),
|
||||
outputs: buildRootlyIncidentOutputs(),
|
||||
webhook: { method: 'POST', headers: { 'Content-Type': 'application/json' } },
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { RootlyIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRootlyExtraFields,
|
||||
buildRootlyIncidentOutputs,
|
||||
rootlySetupInstructions,
|
||||
rootlyTriggerOptions,
|
||||
} from '@/triggers/rootly/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const rootlyIncidentUpdatedTrigger: TriggerConfig = {
|
||||
id: 'rootly_incident_updated',
|
||||
name: 'Rootly Incident Updated',
|
||||
provider: 'rootly',
|
||||
description: 'Trigger workflow when an incident is updated in Rootly',
|
||||
version: '1.0.0',
|
||||
icon: RootlyIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'rootly_incident_updated',
|
||||
triggerOptions: rootlyTriggerOptions,
|
||||
setupInstructions: rootlySetupInstructions('incident.updated'),
|
||||
extraFields: buildRootlyExtraFields('rootly_incident_updated'),
|
||||
}),
|
||||
outputs: buildRootlyIncidentOutputs(),
|
||||
webhook: { method: 'POST', headers: { 'Content-Type': 'application/json' } },
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export { rootlyAlertCreatedTrigger } from './alert_created'
|
||||
export { rootlyIncidentCreatedTrigger } from './incident_created'
|
||||
export { rootlyIncidentResolvedTrigger } from './incident_resolved'
|
||||
export { rootlyIncidentUpdatedTrigger } from './incident_updated'
|
||||
@@ -0,0 +1,176 @@
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import type { TriggerOutput } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Shared trigger dropdown options for all Rootly triggers.
|
||||
* IDs map to Rootly webhook event type strings via {@link ROOTLY_EVENT_TYPE_MAP}.
|
||||
*/
|
||||
export const rootlyTriggerOptions = [
|
||||
{ label: 'Incident Created', id: 'rootly_incident_created' },
|
||||
{ label: 'Incident Updated', id: 'rootly_incident_updated' },
|
||||
{ label: 'Incident Resolved', id: 'rootly_incident_resolved' },
|
||||
{ label: 'Alert Created', id: 'rootly_alert_created' },
|
||||
]
|
||||
|
||||
/**
|
||||
* Maps a Sim trigger ID to the exact Rootly webhook event type string.
|
||||
* Source: https://docs.rootly.com/configuration/webhooks
|
||||
*/
|
||||
export const ROOTLY_EVENT_TYPE_MAP: Record<string, string> = {
|
||||
rootly_incident_created: 'incident.created',
|
||||
rootly_incident_updated: 'incident.updated',
|
||||
rootly_incident_resolved: 'incident.resolved',
|
||||
rootly_alert_created: 'alert.created',
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate setup instructions for a specific Rootly event type.
|
||||
* Rootly webhook endpoints are created and torn down programmatically via the
|
||||
* Rootly API, so the user only needs to provide an API key — Sim registers the
|
||||
* endpoint and manages its signing secret automatically.
|
||||
*/
|
||||
export function rootlySetupInstructions(eventType: string): string {
|
||||
const instructions = [
|
||||
'In Rootly, go to <strong>Settings > API Keys</strong> and generate (or copy) an API key.',
|
||||
'Paste the API key into the <strong>API Key</strong> field below.',
|
||||
`When you save, Sim creates a Rootly webhook endpoint subscribed to the <strong>${eventType}</strong> event and verifies request signatures automatically — no manual webhook setup needed.`,
|
||||
'Click "Save" above to activate your trigger.',
|
||||
]
|
||||
return instructions
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the Rootly webhook `event_types` array to subscribe an endpoint to,
|
||||
* based on the configured Sim trigger. Unknown/generic trigger IDs subscribe to
|
||||
* every supported event type.
|
||||
*/
|
||||
export function rootlyEventTypesForTrigger(triggerId: string | undefined): string[] {
|
||||
const mapped = triggerId ? ROOTLY_EVENT_TYPE_MAP[triggerId] : undefined
|
||||
if (mapped) return [mapped]
|
||||
return Object.values(ROOTLY_EVENT_TYPE_MAP)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra config fields for Rootly triggers. The Rootly webhook endpoint is
|
||||
* registered via API, so the user supplies an API key (masked) instead of
|
||||
* pasting a signing secret — Sim generates and stores the secret itself.
|
||||
*/
|
||||
export function buildRootlyExtraFields(triggerId: string): SubBlockConfig[] {
|
||||
return [
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter your Rootly API key',
|
||||
password: true,
|
||||
required: true,
|
||||
paramVisibility: 'user-only',
|
||||
mode: 'trigger',
|
||||
condition: { field: 'selectedTriggerId', value: triggerId },
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Output schema for Rootly incident events (incident.created/updated/resolved).
|
||||
* `data` mirrors the documented Rootly incident resource. Field names are taken
|
||||
* verbatim from https://docs.rootly.com/configuration/event-payloads.
|
||||
*/
|
||||
export function buildRootlyIncidentOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
eventId: { type: 'string', description: 'Unique webhook event ID' },
|
||||
eventType: { type: 'string', description: 'Rootly event type (e.g. incident.created)' },
|
||||
issuedAt: { type: 'string', description: 'When the event was issued (ISO 8601)' },
|
||||
data: {
|
||||
id: { type: 'string', description: 'Incident ID' },
|
||||
sequential_id: { type: 'number', description: 'Sequential incident number' },
|
||||
title: { type: 'string', description: 'Incident title' },
|
||||
public_title: { type: 'string', description: 'Public-facing incident title' },
|
||||
slug: { type: 'string', description: 'Incident slug' },
|
||||
kind: { type: 'string', description: 'Incident kind (normal, test, etc.)' },
|
||||
private: { type: 'boolean', description: 'Whether the incident is private' },
|
||||
summary: { type: 'string', description: 'Incident summary' },
|
||||
status: { type: 'string', description: 'Incident status' },
|
||||
url: { type: 'string', description: 'Incident URL in Rootly' },
|
||||
short_url: { type: 'string', description: 'Shortened incident URL' },
|
||||
mitigation_message: { type: 'string', description: 'Mitigation message' },
|
||||
resolution_message: { type: 'string', description: 'Resolution message' },
|
||||
cancellation_message: { type: 'string', description: 'Cancellation message' },
|
||||
slack_channel_name: { type: 'string', description: 'Linked Slack channel name' },
|
||||
slack_channel_id: { type: 'string', description: 'Linked Slack channel ID' },
|
||||
slack_channel_url: { type: 'string', description: 'Linked Slack channel URL' },
|
||||
started_at: { type: 'string', description: 'When the incident started' },
|
||||
detected_at: { type: 'string', description: 'When the incident was detected' },
|
||||
acknowledged_at: { type: 'string', description: 'When the incident was acknowledged' },
|
||||
mitigated_at: { type: 'string', description: 'When the incident was mitigated' },
|
||||
resolved_at: { type: 'string', description: 'When the incident was resolved' },
|
||||
cancelled_at: { type: 'string', description: 'When the incident was cancelled' },
|
||||
created_at: { type: 'string', description: 'Incident creation timestamp' },
|
||||
updated_at: { type: 'string', description: 'Incident last update timestamp' },
|
||||
labels: { type: 'json', description: 'Incident labels (key-value pairs)' },
|
||||
severity: { type: 'json', description: 'Incident severity object' },
|
||||
user: { type: 'json', description: 'User who owns the incident' },
|
||||
started_by: { type: 'json', description: 'User who started the incident' },
|
||||
mitigated_by: { type: 'json', description: 'User who mitigated the incident' },
|
||||
resolved_by: { type: 'json', description: 'User who resolved the incident' },
|
||||
cancelled_by: { type: 'json', description: 'User who cancelled the incident' },
|
||||
roles: { type: 'json', description: 'Assigned incident roles' },
|
||||
environments: { type: 'json', description: 'Affected environments' },
|
||||
incident_types: { type: 'json', description: 'Incident types' },
|
||||
services: { type: 'json', description: 'Affected services' },
|
||||
functionalities: { type: 'json', description: 'Affected functionalities' },
|
||||
groups: { type: 'json', description: 'Associated teams/groups' },
|
||||
events: { type: 'json', description: 'Timeline events' },
|
||||
action_items: { type: 'json', description: 'Action items' },
|
||||
incident_post_mortem: { type: 'json', description: 'Retrospective/post-mortem object' },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output schema for Rootly alert events (alert.created).
|
||||
* Field names are taken verbatim from the documented Rootly alert resource:
|
||||
* https://docs.rootly.com/configuration/event-payloads.
|
||||
*/
|
||||
export function buildRootlyAlertOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
eventId: { type: 'string', description: 'Unique webhook event ID' },
|
||||
eventType: { type: 'string', description: 'Rootly event type (e.g. alert.created)' },
|
||||
issuedAt: { type: 'string', description: 'When the event was issued (ISO 8601)' },
|
||||
data: {
|
||||
id: { type: 'string', description: 'Alert ID' },
|
||||
team_id: { type: 'number', description: 'Team ID' },
|
||||
source: { type: 'string', description: 'Alert source (e.g. pagerduty)' },
|
||||
summary: { type: 'string', description: 'Alert summary' },
|
||||
labels: { type: 'json', description: 'Alert labels' },
|
||||
data: { type: 'json', description: 'Raw alert payload data' },
|
||||
external_id: { type: 'string', description: 'External alert ID' },
|
||||
external_url: { type: 'string', description: 'External alert URL' },
|
||||
webhook_type: { type: 'string', description: 'Webhook type' },
|
||||
webhook_id: { type: 'string', description: 'Webhook ID' },
|
||||
webhook_idempotency_key: { type: 'string', description: 'Webhook idempotency key' },
|
||||
started_at: { type: 'string', description: 'When the alert started' },
|
||||
ended_at: { type: 'string', description: 'When the alert ended' },
|
||||
deleted_at: { type: 'string', description: 'When the alert was deleted' },
|
||||
created_at: { type: 'string', description: 'Alert creation timestamp' },
|
||||
updated_at: { type: 'string', description: 'Alert last update timestamp' },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an incoming Rootly event type matches the configured trigger.
|
||||
* Unknown trigger IDs are allowed through.
|
||||
*/
|
||||
export function isRootlyEventMatch(triggerId: string, eventType: string): boolean {
|
||||
const expected = ROOTLY_EVENT_TYPE_MAP[triggerId]
|
||||
if (!expected) {
|
||||
return true
|
||||
}
|
||||
return expected === eventType
|
||||
}
|
||||
Reference in New Issue
Block a user