From cae8c2dc3651de41f8a3b8ef15a8b4bd00b4448b Mon Sep 17 00:00:00 2001 From: caballeto Date: Mon, 8 Jun 2026 18:22:17 +0200 Subject: [PATCH] feat: add 13 new alert channel integrations + fix showSubscribeButton Regenerated API types from latest monorepo spec. Added YAML schema interfaces for Telegram, Google Chat, Pushover, Mattermost, Splunk On-Call, Pushbullet, Linear, Incident.io, Rootly, Zapier, Datadog, Jira, and GitLab channel types. Fixed showSubscribeButton property missing from status page branding handlers. Co-authored-by: Cursor --- docs/openapi/monitoring-api.json | 648 +++++++++++++++++++++++++++- src/lib/api-zod.generated.ts | 176 +++++++- src/lib/api.generated.ts | 196 ++++++++- src/lib/spec-facts.generated.ts | 4 +- src/lib/yaml/handlers.ts | 1 + src/lib/yaml/schema.ts | 86 ++++ src/lib/yaml/transform.ts | 1 + test/yaml/spec-field-parity.test.ts | 2 +- 8 files changed, 1087 insertions(+), 27 deletions(-) diff --git a/docs/openapi/monitoring-api.json b/docs/openapi/monitoring-api.json index ce1a576..22b4050 100644 --- a/docs/openapi/monitoring-api.json +++ b/docs/openapi/monitoring-api.json @@ -183,7 +183,20 @@ "pagerduty", "opsgenie", "teams", - "discord" + "discord", + "telegram", + "google_chat", + "pushover", + "mattermost", + "splunk_oncall", + "pushbullet", + "linear", + "incident_io", + "rootly", + "zapier", + "datadog", + "jira", + "gitlab" ] } }, @@ -5187,7 +5200,7 @@ "Invites" ], "summary": "Resend invite", - "operationId": "resend", + "operationId": "resend_1", "parameters": [ { "name": "inviteId", @@ -13234,7 +13247,7 @@ "Service Subscriptions" ], "summary": "Update alert sensitivity for a subscription", - "description": "Controls which external incidents trigger alerts: ALL (any status change), INCIDENTS_ONLY (real vendor incidents, default), MAJOR_ONLY (only DOWN-level incidents).", + "description": "Controls which external incidents trigger alerts and whether they page anyone: ALL (any status change, paged), INCIDENTS_ONLY (real vendor incidents, paged), MAJOR_ONLY (only DOWN-level incidents, paged), AWARENESS (real vendor incidents tracked silently — visible on the dashboard but no alert channels fire; default for new subscriptions).", "operationId": "updateAlertSensitivity", "parameters": [ { @@ -13357,7 +13370,7 @@ "Service Subscriptions" ], "summary": "Subscribe to a service or a component of a service", - "description": "Idempotent — returns the existing subscription if an identical one exists. Omit the request body or set componentId to null for a whole-service subscription. Free tier: max 10 subscriptions. Paid tier: unlimited.", + "description": "Idempotent — returns the existing subscription if an identical one exists. Omit the request body or set componentId to null for a whole-service subscription. When alertSensitivity is omitted, new subscriptions default to AWARENESS (silent tracking — the incident appears on the dashboard but no alert channels fire). PATCH /alert-sensitivity to opt in to paging. Free tier: max 10 subscriptions. Paid tier: unlimited.", "operationId": "subscribe_1", "parameters": [ { @@ -21733,6 +21746,56 @@ }, "description": "Custom HTTP headers for webhook requests", "nullable": true + }, + "chatId": { + "type": "string", + "description": "Telegram chat ID", + "nullable": true + }, + "priority": { + "type": "string", + "description": "Pushover notification priority override", + "nullable": true + }, + "channel": { + "type": "string", + "description": "Mattermost channel override", + "nullable": true + }, + "routingKey": { + "type": "string", + "description": "Splunk On-Call routing key", + "nullable": true + }, + "deviceIden": { + "type": "string", + "description": "Pushbullet target device identifier", + "nullable": true + }, + "teamId": { + "type": "string", + "description": "Linear team ID for issue creation", + "nullable": true + }, + "visibility": { + "type": "string", + "description": "incident.io incident visibility", + "nullable": true + }, + "severity": { + "type": "string", + "description": "Rootly incident severity slug", + "nullable": true + }, + "site": { + "type": "string", + "description": "Datadog site region", + "nullable": true + }, + "projectKey": { + "type": "string", + "description": "Jira project key", + "nullable": true } }, "description": "Non-sensitive alert channel configuration metadata" @@ -21766,7 +21829,20 @@ "pagerduty", "opsgenie", "teams", - "discord" + "discord", + "telegram", + "google_chat", + "pushover", + "mattermost", + "splunk_oncall", + "pushbullet", + "linear", + "incident_io", + "rootly", + "zapier", + "datadog", + "jira", + "gitlab" ] }, "displayConfig": { @@ -22982,26 +23058,65 @@ }, "config": { "oneOf": [ + { + "$ref": "#/components/schemas/DatadogChannelConfig" + }, { "$ref": "#/components/schemas/DiscordChannelConfig" }, { "$ref": "#/components/schemas/EmailChannelConfig" }, + { + "$ref": "#/components/schemas/GitLabChannelConfig" + }, + { + "$ref": "#/components/schemas/GoogleChatChannelConfig" + }, + { + "$ref": "#/components/schemas/IncidentIoChannelConfig" + }, + { + "$ref": "#/components/schemas/JiraChannelConfig" + }, + { + "$ref": "#/components/schemas/LinearChannelConfig" + }, + { + "$ref": "#/components/schemas/MattermostChannelConfig" + }, { "$ref": "#/components/schemas/OpsGenieChannelConfig" }, { "$ref": "#/components/schemas/PagerDutyChannelConfig" }, + { + "$ref": "#/components/schemas/PushbulletChannelConfig" + }, + { + "$ref": "#/components/schemas/PushoverChannelConfig" + }, + { + "$ref": "#/components/schemas/RootlyChannelConfig" + }, { "$ref": "#/components/schemas/SlackChannelConfig" }, + { + "$ref": "#/components/schemas/SplunkOnCallChannelConfig" + }, { "$ref": "#/components/schemas/TeamsChannelConfig" }, + { + "$ref": "#/components/schemas/TelegramChannelConfig" + }, { "$ref": "#/components/schemas/WebhookChannelConfig" + }, + { + "$ref": "#/components/schemas/ZapierChannelConfig" } ] }, @@ -24102,6 +24217,36 @@ }, "description": "Combined dashboard overview for monitors and incidents" }, + "DatadogChannelConfig": { + "required": [ + "channelType", + "apiKey" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "datadog" + ] + }, + "apiKey": { + "minLength": 1, + "type": "string", + "description": "Datadog API key" + }, + "site": { + "type": "string", + "description": "Datadog site region (e.g. datadoghq.com, datadoghq.eu, us3.datadoghq.com)", + "nullable": true + }, + "tags": { + "type": "string", + "description": "Comma-separated tags to attach to events", + "nullable": true + } + } + }, "DayIncident": { "required": [ "affectedComponentNames", @@ -24873,6 +25018,33 @@ }, "description": "Environment with variable substitutions for monitor configs" }, + "ErrorEntry": { + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "minLength": 1, + "type": "string", + "description": "Stable machine-readable code; see ValidationErrorCode for the registry", + "example": "MONITOR_HEARTBEAT_GRACE_EXCEEDS_INTERVAL" + }, + "field": { + "type": "string", + "description": "JSON-pointer-like path to the offending field, or null for request-wide errors", + "nullable": true, + "example": "config.gracePeriod" + }, + "message": { + "minLength": 1, + "type": "string", + "description": "Human-readable message; safe to surface to end users" + } + }, + "description": "One structured validation rejection" + }, "ErrorResponse": { "required": [ "code", @@ -24909,6 +25081,19 @@ "description": "Opaque per-request id; same value as the X-Request-Id response header. Use in support tickets.", "nullable": true, "example": "5b6f7a8c-1234-4d5e-9f0a-1b2c3d4e5f6a" + }, + "errors": { + "type": "array", + "description": "Structured per-field rejections; populated for validation errors, null otherwise", + "nullable": true, + "items": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/ErrorEntry" + } + ] + } } }, "description": "Uniform error envelope returned for every non-2xx response", @@ -25004,6 +25189,32 @@ }, "description": "Details about a single monitor that failed the bulk action" }, + "GitLabChannelConfig": { + "required": [ + "channelType", + "endpointUrl", + "authorizationKey" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "gitlab" + ] + }, + "endpointUrl": { + "minLength": 1, + "type": "string", + "description": "GitLab alert integration endpoint URL" + }, + "authorizationKey": { + "minLength": 1, + "type": "string", + "description": "Authorization key from GitLab alert integration settings" + } + } + }, "GlobalStatusSummaryDto": { "required": [ "servicesWithIssues", @@ -25068,6 +25279,26 @@ }, "description": "Global status summary across all subscribed vendor services" }, + "GoogleChatChannelConfig": { + "required": [ + "channelType", + "webhookUrl" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "google_chat" + ] + }, + "webhookUrl": { + "minLength": 1, + "type": "string", + "description": "Google Chat space webhook URL" + } + } + }, "GroupComponentOrder": { "required": [ "groupId", @@ -25872,6 +26103,36 @@ "size" ] }, + "IncidentIoChannelConfig": { + "required": [ + "channelType", + "apiKey" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "incident_io" + ] + }, + "apiKey": { + "minLength": 1, + "type": "string", + "description": "incident.io API key with 'Create incidents' permission" + }, + "severityId": { + "type": "string", + "description": "Severity ID for created incidents (from List Severities API)", + "nullable": true + }, + "visibility": { + "type": "string", + "description": "Incident visibility: public or private (default: public)", + "nullable": true + } + } + }, "IncidentPolicyDto": { "required": [ "confirmation", @@ -26324,6 +26585,49 @@ }, "description": "Organization invite sent to an email address" }, + "JiraChannelConfig": { + "required": [ + "channelType", + "domain", + "email", + "apiToken", + "projectKey" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "jira" + ] + }, + "domain": { + "minLength": 1, + "type": "string", + "description": "Atlassian instance domain (e.g. yourteam.atlassian.net)" + }, + "email": { + "minLength": 1, + "type": "string", + "description": "Atlassian account email for API authentication" + }, + "apiToken": { + "minLength": 1, + "type": "string", + "description": "Atlassian API token" + }, + "projectKey": { + "minLength": 1, + "type": "string", + "description": "Jira project key where issues are created (e.g. OPS)" + }, + "issueType": { + "type": "string", + "description": "Issue type name (e.g. Bug, Task, Incident)", + "nullable": true + } + } + }, "JsonPathAssertion": { "required": [ "type", @@ -26400,6 +26704,37 @@ }, "description": "API key metadata" }, + "LinearChannelConfig": { + "required": [ + "channelType", + "apiKey", + "teamId" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "linear" + ] + }, + "apiKey": { + "minLength": 1, + "type": "string", + "description": "Linear API key" + }, + "teamId": { + "minLength": 1, + "type": "string", + "description": "Team ID to create issues in" + }, + "labelId": { + "type": "string", + "description": "Label ID to attach to created issues", + "nullable": true + } + } + }, "LinkedStatusPageIncidentDto": { "required": [ "id", @@ -26628,6 +26963,36 @@ }, "description": "Match rules to evaluate (all must pass; omit or empty for catch-all)" }, + "MattermostChannelConfig": { + "required": [ + "channelType", + "webhookUrl" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "mattermost" + ] + }, + "webhookUrl": { + "minLength": 1, + "type": "string", + "description": "Mattermost incoming webhook URL" + }, + "channel": { + "type": "string", + "description": "Override channel (if webhook allows)", + "nullable": true + }, + "iconUrl": { + "type": "string", + "description": "Custom bot icon URL", + "nullable": true + } + } + }, "McpConnectsAssertion": { "type": "object", "properties": { @@ -28230,6 +28595,67 @@ } } }, + "PushbulletChannelConfig": { + "required": [ + "channelType", + "accessToken" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "pushbullet" + ] + }, + "accessToken": { + "minLength": 1, + "type": "string", + "description": "Pushbullet access token" + }, + "deviceIden": { + "type": "string", + "description": "Target device identifier (broadcasts to all if empty)", + "nullable": true + } + } + }, + "PushoverChannelConfig": { + "required": [ + "channelType", + "userKey", + "appToken" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "pushover" + ] + }, + "userKey": { + "minLength": 1, + "type": "string", + "description": "Pushover user or group key" + }, + "appToken": { + "minLength": 1, + "type": "string", + "description": "Pushover application API token" + }, + "priority": { + "type": "string", + "description": "Notification priority override (-2 to 2)", + "nullable": true + }, + "sound": { + "type": "string", + "description": "Notification sound override", + "nullable": true + } + } + }, "RateLimitInfo": { "type": "object", "properties": { @@ -28920,6 +29346,31 @@ }, "description": "Default retry strategy for member monitors; null clears" }, + "RootlyChannelConfig": { + "required": [ + "channelType", + "apiKey" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "rootly" + ] + }, + "apiKey": { + "minLength": 1, + "type": "string", + "description": "Rootly API token with incident creation permission" + }, + "severity": { + "type": "string", + "description": "Severity slug override (e.g. sev0, sev1)", + "nullable": true + } + } + }, "RuleEvaluationDto": { "required": [ "checkId", @@ -29175,6 +29626,7 @@ "createdAt", "dataCompleteness", "id", + "lifecycleStatus", "name", "slug", "updatedAt", @@ -29219,6 +29671,16 @@ "type": "integer", "format": "int32" }, + "lifecycleStatus": { + "type": "string", + "description": "Service lifecycle state: ACTIVE, DEGRADED, DEPRECATED, or RETIRED", + "enum": [ + "ACTIVE", + "DEGRADED", + "DEPRECATED", + "RETIRED" + ] + }, "enabled": { "type": "boolean" }, @@ -29439,6 +29901,7 @@ "createdAt", "dataCompleteness", "id", + "lifecycleStatus", "name", "recentIncidents", "slug", @@ -29481,6 +29944,16 @@ "type": "integer", "format": "int32" }, + "lifecycleStatus": { + "type": "string", + "description": "Service lifecycle state: ACTIVE, DEGRADED, DEPRECATED, or RETIRED", + "enum": [ + "ACTIVE", + "DEGRADED", + "DEPRECATED", + "RETIRED" + ] + }, "enabled": { "type": "boolean" }, @@ -29880,8 +30353,9 @@ "nullable": true }, "alertSensitivity": { + "pattern": "ALL|AWARENESS|INCIDENTS_ONLY|MAJOR_ONLY", "type": "string", - "description": "Alert sensitivity level. Defaults to INCIDENTS_ONLY when not provided.", + "description": "Alert sensitivity: ALL (any status change), INCIDENTS_ONLY (real vendor incidents, page on every one), MAJOR_ONLY (only DOWN-level incidents), AWARENESS (track silently — show on dashboard, never send alerts). Defaults to AWARENESS when not provided — silent tracking is the friendliest first-run choice; switch to one of the paging modes to opt in to alert-channel fan-out.", "nullable": true } }, @@ -29965,9 +30439,10 @@ "alertSensitivity": { "minLength": 1, "type": "string", - "description": "Alert sensitivity: ALL (synthetic + real incidents), INCIDENTS_ONLY (real vendor incidents, default), MAJOR_ONLY (real + DOWN severity)", + "description": "Alert sensitivity: ALL (synthetic + real incidents, paged), INCIDENTS_ONLY (real vendor incidents, paged), MAJOR_ONLY (real + DOWN severity, paged), AWARENESS (real vendor incidents tracked silently — visible on dashboard, never paged; default for new subscriptions)", "enum": [ "ALL", + "AWARENESS", "INCIDENTS_ONLY", "MAJOR_ONLY" ] @@ -30709,6 +31184,32 @@ } } }, + "SplunkOnCallChannelConfig": { + "required": [ + "channelType", + "apiKey", + "routingKey" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "splunk_oncall" + ] + }, + "apiKey": { + "minLength": 1, + "type": "string", + "description": "Splunk On-Call REST API key" + }, + "routingKey": { + "minLength": 1, + "type": "string", + "description": "Routing key for alert routing" + } + } + }, "SslExpiryAssertion": { "type": "object", "properties": { @@ -30865,6 +31366,11 @@ "description": "Whether to hide the 'Powered by DevHelm' footer badge (default: false)", "default": false }, + "showSubscribeButton": { + "type": "boolean", + "description": "Whether to show the 'Subscribe' button in the header (default: true)", + "default": true + }, "customCss": { "maxLength": 50000, "minLength": 0, @@ -32788,6 +33294,32 @@ } } }, + "TelegramChannelConfig": { + "required": [ + "channelType", + "botToken", + "chatId" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "telegram" + ] + }, + "botToken": { + "minLength": 1, + "type": "string", + "description": "Telegram bot token from @BotFather" + }, + "chatId": { + "minLength": 1, + "type": "string", + "description": "Chat, group, or channel ID to send alerts to" + } + } + }, "TestAlertChannelRequest": { "required": [ "config" @@ -32796,26 +33328,65 @@ "properties": { "config": { "oneOf": [ + { + "$ref": "#/components/schemas/DatadogChannelConfig" + }, { "$ref": "#/components/schemas/DiscordChannelConfig" }, { "$ref": "#/components/schemas/EmailChannelConfig" }, + { + "$ref": "#/components/schemas/GitLabChannelConfig" + }, + { + "$ref": "#/components/schemas/GoogleChatChannelConfig" + }, + { + "$ref": "#/components/schemas/IncidentIoChannelConfig" + }, + { + "$ref": "#/components/schemas/JiraChannelConfig" + }, + { + "$ref": "#/components/schemas/LinearChannelConfig" + }, + { + "$ref": "#/components/schemas/MattermostChannelConfig" + }, { "$ref": "#/components/schemas/OpsGenieChannelConfig" }, { "$ref": "#/components/schemas/PagerDutyChannelConfig" }, + { + "$ref": "#/components/schemas/PushbulletChannelConfig" + }, + { + "$ref": "#/components/schemas/PushoverChannelConfig" + }, + { + "$ref": "#/components/schemas/RootlyChannelConfig" + }, { "$ref": "#/components/schemas/SlackChannelConfig" }, + { + "$ref": "#/components/schemas/SplunkOnCallChannelConfig" + }, { "$ref": "#/components/schemas/TeamsChannelConfig" }, + { + "$ref": "#/components/schemas/TelegramChannelConfig" + }, { "$ref": "#/components/schemas/WebhookChannelConfig" + }, + { + "$ref": "#/components/schemas/ZapierChannelConfig" } ] } @@ -33129,26 +33700,65 @@ }, "config": { "oneOf": [ + { + "$ref": "#/components/schemas/DatadogChannelConfig" + }, { "$ref": "#/components/schemas/DiscordChannelConfig" }, { "$ref": "#/components/schemas/EmailChannelConfig" }, + { + "$ref": "#/components/schemas/GitLabChannelConfig" + }, + { + "$ref": "#/components/schemas/GoogleChatChannelConfig" + }, + { + "$ref": "#/components/schemas/IncidentIoChannelConfig" + }, + { + "$ref": "#/components/schemas/JiraChannelConfig" + }, + { + "$ref": "#/components/schemas/LinearChannelConfig" + }, + { + "$ref": "#/components/schemas/MattermostChannelConfig" + }, { "$ref": "#/components/schemas/OpsGenieChannelConfig" }, { "$ref": "#/components/schemas/PagerDutyChannelConfig" }, + { + "$ref": "#/components/schemas/PushbulletChannelConfig" + }, + { + "$ref": "#/components/schemas/PushoverChannelConfig" + }, + { + "$ref": "#/components/schemas/RootlyChannelConfig" + }, { "$ref": "#/components/schemas/SlackChannelConfig" }, + { + "$ref": "#/components/schemas/SplunkOnCallChannelConfig" + }, { "$ref": "#/components/schemas/TeamsChannelConfig" }, + { + "$ref": "#/components/schemas/TelegramChannelConfig" + }, { "$ref": "#/components/schemas/WebhookChannelConfig" + }, + { + "$ref": "#/components/schemas/ZapierChannelConfig" } ] }, @@ -33174,9 +33784,9 @@ "properties": { "alertSensitivity": { "minLength": 1, - "pattern": "ALL|INCIDENTS_ONLY|MAJOR_ONLY", + "pattern": "ALL|AWARENESS|INCIDENTS_ONLY|MAJOR_ONLY", "type": "string", - "description": "Alert sensitivity: ALL (any status change), INCIDENTS_ONLY (real vendor incidents, default), MAJOR_ONLY (only DOWN-level incidents)" + "description": "Alert sensitivity: ALL (any status change), INCIDENTS_ONLY (real vendor incidents, page on every one), MAJOR_ONLY (only DOWN-level incidents), AWARENESS (track silently — show on dashboard, never send alerts; default for new subscriptions)" } }, "description": "Request body for updating alert sensitivity on a service subscription" @@ -34445,6 +35055,26 @@ } }, "description": "Workspace within an organization" + }, + "ZapierChannelConfig": { + "required": [ + "channelType", + "webhookUrl" + ], + "type": "object", + "properties": { + "channelType": { + "type": "string", + "enum": [ + "zapier" + ] + }, + "webhookUrl": { + "minLength": 1, + "type": "string", + "description": "Zapier/n8n/Make catch webhook URL" + } + } } }, "securitySchemes": { diff --git a/src/lib/api-zod.generated.ts b/src/lib/api-zod.generated.ts index f8a5fbc..46915c0 100644 --- a/src/lib/api-zod.generated.ts +++ b/src/lib/api-zod.generated.ts @@ -9,6 +9,13 @@ const pageable = z sort: z.array(z.string()), }) .strict(); +const ErrorEntry = z + .object({ + code: z.string().min(1), + field: z.string().nullish(), + message: z.string().min(1), + }) + .strict(); const ErrorResponse = z .object({ status: z.number().int(), @@ -16,6 +23,15 @@ const ErrorResponse = z message: z.string(), timestamp: z.number().int(), requestId: z.string().nullish(), + errors: z.array(ErrorEntry.nullable()).nullish(), + }) + .strict(); +const DatadogChannelConfig = z + .object({ + channelType: z.literal("datadog"), + apiKey: z.string().min(1), + site: z.string().nullish(), + tags: z.string().nullish(), }) .strict(); const DiscordChannelConfig = z @@ -31,6 +47,53 @@ const EmailChannelConfig = z recipients: z.array(z.string().email()).min(1), }) .strict(); +const GitLabChannelConfig = z + .object({ + channelType: z.literal("gitlab"), + endpointUrl: z.string().min(1), + authorizationKey: z.string().min(1), + }) + .strict(); +const GoogleChatChannelConfig = z + .object({ + channelType: z.literal("google_chat"), + webhookUrl: z.string().min(1), + }) + .strict(); +const IncidentIoChannelConfig = z + .object({ + channelType: z.literal("incident_io"), + apiKey: z.string().min(1), + severityId: z.string().nullish(), + visibility: z.string().nullish(), + }) + .strict(); +const JiraChannelConfig = z + .object({ + channelType: z.literal("jira"), + domain: z.string().min(1), + email: z.string().min(1), + apiToken: z.string().min(1), + projectKey: z.string().min(1), + issueType: z.string().nullish(), + }) + .strict(); +const LinearChannelConfig = z + .object({ + channelType: z.literal("linear"), + apiKey: z.string().min(1), + teamId: z.string().min(1), + labelId: z.string().nullish(), + }) + .strict(); +const MattermostChannelConfig = z + .object({ + channelType: z.literal("mattermost"), + webhookUrl: z.string().min(1), + channel: z.string().nullish(), + iconUrl: z.string().nullish(), + }) + .strict(); const OpsGenieChannelConfig = z .object({ channelType: z.literal("opsgenie"), @@ -45,6 +108,29 @@ const PagerDutyChannelConfig = z severityOverride: z.string().nullish(), }) .strict(); +const PushbulletChannelConfig = z + .object({ + channelType: z.literal("pushbullet"), + accessToken: z.string().min(1), + deviceIden: z.string().nullish(), + }) + .strict(); +const PushoverChannelConfig = z + .object({ + channelType: z.literal("pushover"), + userKey: z.string().min(1), + appToken: z.string().min(1), + priority: z.string().nullish(), + sound: z.string().nullish(), + }) + .strict(); +const RootlyChannelConfig = z + .object({ + channelType: z.literal("rootly"), + apiKey: z.string().min(1), + severity: z.string().nullish(), + }) + .strict(); const SlackChannelConfig = z .object({ channelType: z.literal("slack"), @@ -52,9 +138,23 @@ const SlackChannelConfig = z mentionText: z.string().nullish(), }) .strict(); +const SplunkOnCallChannelConfig = z + .object({ + channelType: z.literal("splunk_oncall"), + apiKey: z.string().min(1), + routingKey: z.string().min(1), + }) + .strict(); const TeamsChannelConfig = z .object({ channelType: z.literal("teams"), webhookUrl: z.string().min(1) }) .strict(); +const TelegramChannelConfig = z + .object({ + channelType: z.literal("telegram"), + botToken: z.string().min(1), + chatId: z.string().min(1), + }) + .strict(); const WebhookChannelConfig = z .object({ channelType: z.literal("webhook"), @@ -63,17 +163,33 @@ const WebhookChannelConfig = z customHeaders: z.record(z.string().nullable()).nullish(), }) .strict(); +const ZapierChannelConfig = z + .object({ channelType: z.literal("zapier"), webhookUrl: z.string().min(1) }) + .strict(); const CreateAlertChannelRequest = z .object({ name: z.string().min(0).max(255), config: z.union([ + DatadogChannelConfig, DiscordChannelConfig, EmailChannelConfig, + GitLabChannelConfig, + GoogleChatChannelConfig, + IncidentIoChannelConfig, + JiraChannelConfig, + LinearChannelConfig, + MattermostChannelConfig, OpsGenieChannelConfig, PagerDutyChannelConfig, + PushbulletChannelConfig, + PushoverChannelConfig, + RootlyChannelConfig, SlackChannelConfig, + SplunkOnCallChannelConfig, TeamsChannelConfig, + TelegramChannelConfig, WebhookChannelConfig, + ZapierChannelConfig, ]), managedBy: z .enum(["DASHBOARD", "CLI", "TERRAFORM", "MCP", "API"]) @@ -84,13 +200,26 @@ const UpdateAlertChannelRequest = z .object({ name: z.string().min(0).max(255), config: z.union([ + DatadogChannelConfig, DiscordChannelConfig, EmailChannelConfig, + GitLabChannelConfig, + GoogleChatChannelConfig, + IncidentIoChannelConfig, + JiraChannelConfig, + LinearChannelConfig, + MattermostChannelConfig, OpsGenieChannelConfig, PagerDutyChannelConfig, + PushbulletChannelConfig, + PushoverChannelConfig, + RootlyChannelConfig, SlackChannelConfig, + SplunkOnCallChannelConfig, TeamsChannelConfig, + TelegramChannelConfig, WebhookChannelConfig, + ZapierChannelConfig, ]), managedBy: z .enum(["DASHBOARD", "CLI", "TERRAFORM", "MCP", "API"]) @@ -100,13 +229,26 @@ const UpdateAlertChannelRequest = z const TestAlertChannelRequest = z .object({ config: z.union([ + DatadogChannelConfig, DiscordChannelConfig, EmailChannelConfig, + GitLabChannelConfig, + GoogleChatChannelConfig, + IncidentIoChannelConfig, + JiraChannelConfig, + LinearChannelConfig, + MattermostChannelConfig, OpsGenieChannelConfig, PagerDutyChannelConfig, + PushbulletChannelConfig, + PushoverChannelConfig, + RootlyChannelConfig, SlackChannelConfig, + SplunkOnCallChannelConfig, TeamsChannelConfig, + TelegramChannelConfig, WebhookChannelConfig, + ZapierChannelConfig, ]), }) .strict(); @@ -951,13 +1093,16 @@ const UpdateAlertSensitivityRequest = z alertSensitivity: z .string() .min(1) - .regex(/ALL|INCIDENTS_ONLY|MAJOR_ONLY/), + .regex(/ALL|AWARENESS|INCIDENTS_ONLY|MAJOR_ONLY/), }) .strict(); const ServiceSubscribeRequest = z .object({ componentId: z.string().uuid().nullable(), - alertSensitivity: z.string().nullable(), + alertSensitivity: z + .string() + .regex(/ALL|AWARENESS|INCIDENTS_ONLY|MAJOR_ONLY/) + .nullable(), }) .partial() .strict(); @@ -1014,6 +1159,7 @@ const StatusPageBranding = z .regex(/^https?:\/\/.*/) .nullable(), hidePoweredBy: z.boolean().default(false), + showSubscribeButton: z.boolean().default(true), customCss: z.string().min(0).max(50000).nullable(), customHeadHtml: z.string().min(0).max(50000).nullable(), }) @@ -1287,6 +1433,16 @@ const AlertChannelDisplayConfig = z severityOverride: z.string().nullable(), mentionRoleId: z.string().nullable(), customHeaders: z.record(z.string().nullable()).nullable(), + chatId: z.string().nullable(), + priority: z.string().nullable(), + channel: z.string().nullable(), + routingKey: z.string().nullable(), + deviceIden: z.string().nullable(), + teamId: z.string().nullable(), + visibility: z.string().nullable(), + severity: z.string().nullable(), + site: z.string().nullable(), + projectKey: z.string().nullable(), }) .partial() .strict(); @@ -1689,6 +1845,7 @@ const ServiceCatalogDto = z logoUrl: z.string().nullish(), adapterType: z.string(), pollingIntervalSeconds: z.number().int(), + lifecycleStatus: z.string(), enabled: z.boolean(), published: z.boolean(), overallStatus: z.string().nullish(), @@ -2408,6 +2565,7 @@ const ServiceDetailDto = z logoUrl: z.string().nullish(), adapterType: z.string(), pollingIntervalSeconds: z.number().int(), + lifecycleStatus: z.string(), enabled: z.boolean(), createdAt: z.string().datetime({ offset: true }), updatedAt: z.string().datetime({ offset: true }), @@ -3175,14 +3333,28 @@ const WebhookEventCatalogResponse = z export const schemas = { pageable, + ErrorEntry, ErrorResponse, + DatadogChannelConfig, DiscordChannelConfig, EmailChannelConfig, + GitLabChannelConfig, + GoogleChatChannelConfig, + IncidentIoChannelConfig, + JiraChannelConfig, + LinearChannelConfig, + MattermostChannelConfig, OpsGenieChannelConfig, PagerDutyChannelConfig, + PushbulletChannelConfig, + PushoverChannelConfig, + RootlyChannelConfig, SlackChannelConfig, + SplunkOnCallChannelConfig, TeamsChannelConfig, + TelegramChannelConfig, WebhookChannelConfig, + ZapierChannelConfig, CreateAlertChannelRequest, UpdateAlertChannelRequest, TestAlertChannelRequest, diff --git a/src/lib/api.generated.ts b/src/lib/api.generated.ts index ba8d61a..49262d1 100644 --- a/src/lib/api.generated.ts +++ b/src/lib/api.generated.ts @@ -618,7 +618,7 @@ export interface paths { get?: never; put?: never; /** Resend invite */ - post: operations["resend"]; + post: operations["resend_1"]; delete?: never; options?: never; head?: never; @@ -1521,7 +1521,7 @@ export interface paths { head?: never; /** * Update alert sensitivity for a subscription - * @description Controls which external incidents trigger alerts: ALL (any status change), INCIDENTS_ONLY (real vendor incidents, default), MAJOR_ONLY (only DOWN-level incidents). + * @description Controls which external incidents trigger alerts and whether they page anyone: ALL (any status change, paged), INCIDENTS_ONLY (real vendor incidents, paged), MAJOR_ONLY (only DOWN-level incidents, paged), AWARENESS (real vendor incidents tracked silently — visible on the dashboard but no alert channels fire; default for new subscriptions). */ patch: operations["updateAlertSensitivity"]; trace?: never; @@ -1537,7 +1537,7 @@ export interface paths { put?: never; /** * Subscribe to a service or a component of a service - * @description Idempotent — returns the existing subscription if an identical one exists. Omit the request body or set componentId to null for a whole-service subscription. Free tier: max 10 subscriptions. Paid tier: unlimited. + * @description Idempotent — returns the existing subscription if an identical one exists. Omit the request body or set componentId to null for a whole-service subscription. When alertSensitivity is omitted, new subscriptions default to AWARENESS (silent tracking — the incident appears on the dashboard but no alert channels fire). PATCH /alert-sensitivity to opt in to paging. Free tier: max 10 subscriptions. Paid tier: unlimited. */ post: operations["subscribe_1"]; delete?: never; @@ -2480,6 +2480,26 @@ export interface components { customHeaders?: { [key: string]: string | null; } | null; + /** @description Telegram chat ID */ + chatId?: string | null; + /** @description Pushover notification priority override */ + priority?: string | null; + /** @description Mattermost channel override */ + channel?: string | null; + /** @description Splunk On-Call routing key */ + routingKey?: string | null; + /** @description Pushbullet target device identifier */ + deviceIden?: string | null; + /** @description Linear team ID for issue creation */ + teamId?: string | null; + /** @description incident.io incident visibility */ + visibility?: string | null; + /** @description Rootly incident severity slug */ + severity?: string | null; + /** @description Datadog site region */ + site?: string | null; + /** @description Jira project key */ + projectKey?: string | null; }; /** @description Alert channel with non-sensitive configuration metadata */ AlertChannelDto: { @@ -2494,7 +2514,7 @@ export interface components { * @description Channel integration type (e.g. SLACK, PAGERDUTY, EMAIL) * @enum {string} */ - channelType: "email" | "webhook" | "slack" | "pagerduty" | "opsgenie" | "teams" | "discord"; + channelType: "email" | "webhook" | "slack" | "pagerduty" | "opsgenie" | "teams" | "discord" | "telegram" | "google_chat" | "pushover" | "mattermost" | "splunk_oncall" | "pushbullet" | "linear" | "incident_io" | "rootly" | "zapier" | "datadog" | "jira" | "gitlab"; displayConfig?: components["schemas"]["AlertChannelDisplayConfig"] | null; /** * Format: date-time @@ -3096,7 +3116,7 @@ export interface components { CreateAlertChannelRequest: { /** @description Human-readable name for this alert channel */ name: string; - config: components["schemas"]["DiscordChannelConfig"] | components["schemas"]["EmailChannelConfig"] | components["schemas"]["OpsGenieChannelConfig"] | components["schemas"]["PagerDutyChannelConfig"] | components["schemas"]["SlackChannelConfig"] | components["schemas"]["TeamsChannelConfig"] | components["schemas"]["WebhookChannelConfig"]; + config: components["schemas"]["DatadogChannelConfig"] | components["schemas"]["DiscordChannelConfig"] | components["schemas"]["EmailChannelConfig"] | components["schemas"]["GitLabChannelConfig"] | components["schemas"]["GoogleChatChannelConfig"] | components["schemas"]["IncidentIoChannelConfig"] | components["schemas"]["JiraChannelConfig"] | components["schemas"]["LinearChannelConfig"] | components["schemas"]["MattermostChannelConfig"] | components["schemas"]["OpsGenieChannelConfig"] | components["schemas"]["PagerDutyChannelConfig"] | components["schemas"]["PushbulletChannelConfig"] | components["schemas"]["PushoverChannelConfig"] | components["schemas"]["RootlyChannelConfig"] | components["schemas"]["SlackChannelConfig"] | components["schemas"]["SplunkOnCallChannelConfig"] | components["schemas"]["TeamsChannelConfig"] | components["schemas"]["TelegramChannelConfig"] | components["schemas"]["WebhookChannelConfig"] | components["schemas"]["ZapierChannelConfig"]; /** * @description Source creating this channel: DASHBOARD, CLI, TERRAFORM, MCP, or API. Defaults to API when omitted. * @enum {string|null} @@ -3475,6 +3495,16 @@ export interface components { monitors: components["schemas"]["MonitorsSummaryDto"]; incidents: components["schemas"]["IncidentsSummaryDto"]; }; + DatadogChannelConfig: { + /** @enum {string} */ + channelType: "datadog"; + /** @description Datadog API key */ + apiKey: string; + /** @description Datadog site region (e.g. datadoghq.com, datadoghq.eu, us3.datadoghq.com) */ + site?: string | null; + /** @description Comma-separated tags to attach to events */ + tags?: string | null; + }; /** @description Incident that overlapped the day */ DayIncident: { /** @@ -3817,6 +3847,21 @@ export interface components { /** @description Whether this is the default environment for new monitors */ isDefault: boolean; }; + /** @description One structured validation rejection */ + ErrorEntry: { + /** + * @description Stable machine-readable code; see ValidationErrorCode for the registry + * @example MONITOR_HEARTBEAT_GRACE_EXCEEDS_INTERVAL + */ + code: string; + /** + * @description JSON-pointer-like path to the offending field, or null for request-wide errors + * @example config.gracePeriod + */ + field?: string | null; + /** @description Human-readable message; safe to surface to end users */ + message: string; + }; /** * @description Uniform error envelope returned for every non-2xx response * @example { @@ -3855,6 +3900,8 @@ export interface components { * @example 5b6f7a8c-1234-4d5e-9f0a-1b2c3d4e5f6a */ requestId?: string | null; + /** @description Structured per-field rejections; populated for validation errors, null otherwise */ + errors?: (components["schemas"]["ErrorEntry"] | null)[] | null; }; /** @description Escalation chain defining which channels to notify; null preserves current */ EscalationChain: { @@ -3892,6 +3939,14 @@ export interface components { /** @description Human-readable reason for the failure */ reason: string; }; + GitLabChannelConfig: { + /** @enum {string} */ + channelType: "gitlab"; + /** @description GitLab alert integration endpoint URL */ + endpointUrl: string; + /** @description Authorization key from GitLab alert integration settings */ + authorizationKey: string; + }; /** @description Global status summary across all subscribed vendor services */ GlobalStatusSummaryDto: { /** @@ -3937,6 +3992,12 @@ export interface components { /** @description Services that are not fully operational */ servicesWithIssues: components["schemas"]["ServiceCatalogDto"][]; }; + GoogleChatChannelConfig: { + /** @enum {string} */ + channelType: "google_chat"; + /** @description Google Chat space webhook URL */ + webhookUrl: string; + }; /** @description Component ordering within a single group */ GroupComponentOrder: { /** @@ -4348,6 +4409,16 @@ export interface components { */ size: number; }; + IncidentIoChannelConfig: { + /** @enum {string} */ + channelType: "incident_io"; + /** @description incident.io API key with 'Create incidents' permission */ + apiKey: string; + /** @description Severity ID for created incidents (from List Severities API) */ + severityId?: string | null; + /** @description Incident visibility: public or private (default: public) */ + visibility?: string | null; + }; /** @description Incident detection, confirmation, and recovery policy for a monitor */ IncidentPolicyDto: { /** @@ -4529,6 +4600,20 @@ export interface components { */ revokedAt?: string | null; }; + JiraChannelConfig: { + /** @enum {string} */ + channelType: "jira"; + /** @description Atlassian instance domain (e.g. yourteam.atlassian.net) */ + domain: string; + /** @description Atlassian account email for API authentication */ + email: string; + /** @description Atlassian API token */ + apiToken: string; + /** @description Jira project key where issues are created (e.g. OPS) */ + projectKey: string; + /** @description Issue type name (e.g. Bug, Task, Incident) */ + issueType?: string | null; + }; JsonPathAssertion: { /** @enum {string} */ type: "json_path"; @@ -4567,6 +4652,16 @@ export interface components { */ lastUsedAt?: string | null; }; + LinearChannelConfig: { + /** @enum {string} */ + channelType: "linear"; + /** @description Linear API key */ + apiKey: string; + /** @description Team ID to create issues in */ + teamId: string; + /** @description Label ID to attach to created issues */ + labelId?: string | null; + }; LinkedStatusPageIncidentDto: { /** Format: uuid */ id: string; @@ -4667,6 +4762,16 @@ export interface components { /** @description Values list for multi-value rules like monitor_type_in */ values?: string[] | null; }; + MattermostChannelConfig: { + /** @enum {string} */ + channelType: "mattermost"; + /** @description Mattermost incoming webhook URL */ + webhookUrl: string; + /** @description Override channel (if webhook allows) */ + channel?: string | null; + /** @description Custom bot icon URL */ + iconUrl?: string | null; + }; McpConnectsAssertion: { /** @enum {string} */ type: "mcp_connects"; @@ -5299,6 +5404,26 @@ export interface components { /** @description Whether to notify subscribers (default: true) */ notifySubscribers?: boolean | null; }; + PushbulletChannelConfig: { + /** @enum {string} */ + channelType: "pushbullet"; + /** @description Pushbullet access token */ + accessToken: string; + /** @description Target device identifier (broadcasts to all if empty) */ + deviceIden?: string | null; + }; + PushoverChannelConfig: { + /** @enum {string} */ + channelType: "pushover"; + /** @description Pushover user or group key */ + userKey: string; + /** @description Pushover application API token */ + appToken: string; + /** @description Notification priority override (-2 to 2) */ + priority?: string | null; + /** @description Notification sound override */ + sound?: string | null; + }; /** @description Rate-limit quota for the current sliding window */ RateLimitInfo: { /** @@ -5655,6 +5780,14 @@ export interface components { */ interval: number; }; + RootlyChannelConfig: { + /** @enum {string} */ + channelType: "rootly"; + /** @description Rootly API token with incident creation permission */ + apiKey: string; + /** @description Severity slug override (e.g. sev0, sev1) */ + severity?: string | null; + }; /** @description All rule evaluations that ran for this check */ RuleEvaluationDto: { /** @@ -5799,6 +5932,11 @@ export interface components { adapterType: string; /** Format: int32 */ pollingIntervalSeconds: number; + /** + * @description Service lifecycle state: ACTIVE, DEGRADED, DEPRECATED, or RETIRED + * @enum {string} + */ + lifecycleStatus: "ACTIVE" | "DEGRADED" | "DEPRECATED" | "RETIRED"; enabled: boolean; published: boolean; overallStatus?: string | null; @@ -5907,6 +6045,11 @@ export interface components { adapterType: string; /** Format: int32 */ pollingIntervalSeconds: number; + /** + * @description Service lifecycle state: ACTIVE, DEGRADED, DEPRECATED, or RETIRED + * @enum {string} + */ + lifecycleStatus: "ACTIVE" | "DEGRADED" | "DEPRECATED" | "RETIRED"; enabled: boolean; /** Format: date-time */ createdAt: string; @@ -6081,7 +6224,7 @@ export interface components { * @description ID of the component to subscribe to. Omit or null for whole-service subscription. */ componentId?: string | null; - /** @description Alert sensitivity level. Defaults to INCIDENTS_ONLY when not provided. */ + /** @description Alert sensitivity: ALL (any status change), INCIDENTS_ONLY (real vendor incidents, page on every one), MAJOR_ONLY (only DOWN-level incidents), AWARENESS (track silently — show on dashboard, never send alerts). Defaults to AWARENESS when not provided — silent tracking is the friendliest first-run choice; switch to one of the paging modes to opt in to alert-channel fan-out. */ alertSensitivity?: string | null; }; /** @description An org-level service subscription with current status information */ @@ -6115,10 +6258,10 @@ export interface components { componentId?: string | null; component?: components["schemas"]["ServiceComponentDto"] | null; /** - * @description Alert sensitivity: ALL (synthetic + real incidents), INCIDENTS_ONLY (real vendor incidents, default), MAJOR_ONLY (real + DOWN severity) + * @description Alert sensitivity: ALL (synthetic + real incidents, paged), INCIDENTS_ONLY (real vendor incidents, paged), MAJOR_ONLY (real + DOWN severity, paged), AWARENESS (real vendor incidents tracked silently — visible on dashboard, never paged; default for new subscriptions) * @enum {string} */ - alertSensitivity: "ALL" | "INCIDENTS_ONLY" | "MAJOR_ONLY"; + alertSensitivity: "ALL" | "AWARENESS" | "INCIDENTS_ONLY" | "MAJOR_ONLY"; /** * Format: date-time * @description When the organization subscribed to this service @@ -6336,6 +6479,14 @@ export interface components { /** @description Optional mention text included in notifications, e.g. @channel */ mentionText?: string | null; }; + SplunkOnCallChannelConfig: { + /** @enum {string} */ + channelType: "splunk_oncall"; + /** @description Splunk On-Call REST API key */ + apiKey: string; + /** @description Routing key for alert routing */ + routingKey: string; + }; SslExpiryAssertion: { /** @enum {string} */ type: "ssl_expiry"; @@ -6391,6 +6542,11 @@ export interface components { * @default false */ hidePoweredBy: boolean; + /** + * @description Whether to show the 'Subscribe' button in the header (default: true) + * @default true + */ + showSubscribeButton: boolean; /** @description Custom CSS injected via