diff --git a/apps/dashboard/src/components/forms/notifications/form-ms-teams.tsx b/apps/dashboard/src/components/forms/notifications/form-ms-teams.tsx new file mode 100644 index 00000000..edce21c8 --- /dev/null +++ b/apps/dashboard/src/components/forms/notifications/form-ms-teams.tsx @@ -0,0 +1,220 @@ +"use client"; + +import { CheckboxTree } from "@/components/ui/checkbox-tree"; +import { + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@openstatus/ui/components/ui/form"; + +import { + FormCardContent, + FormCardSeparator, +} from "@/components/forms/form-card"; +import { useTRPC } from "@/lib/trpc/client"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Button } from "@openstatus/ui/components/ui/button"; +import { Form } from "@openstatus/ui/components/ui/form"; +import { Input } from "@openstatus/ui/components/ui/input"; +import { cn } from "@openstatus/ui/lib/utils"; +import { safeUrlSchema } from "@openstatus/utils"; +import { useMutation } from "@tanstack/react-query"; +import { isTRPCClientError } from "@trpc/client"; +import React, { useTransition } from "react"; +import { useForm } from "react-hook-form"; +import { toast } from "sonner"; +import { z } from "zod"; +import { useFormSheetDirty } from "../form-sheet"; + +const schema = z.object({ + name: z.string(), + provider: z.literal("ms-teams"), + data: z.object({ + webhookUrl: safeUrlSchema, + }), + monitors: z.array(z.number()), +}); + +type FormValues = z.infer; + +export function FormMsTeams({ + defaultValues, + onSubmit, + className, + monitors, + ...props +}: Omit, "onSubmit"> & { + defaultValues?: FormValues; + onSubmit: (values: FormValues) => Promise; + monitors: { id: number; name: string }[]; +}) { + const form = useForm({ + resolver: zodResolver(schema), + defaultValues: defaultValues ?? { + name: "", + provider: "ms-teams", + data: { webhookUrl: "" }, + monitors: [], + }, + }); + const [isPending, startTransition] = useTransition(); + const { setIsDirty } = useFormSheetDirty(); + + const trpc = useTRPC(); + + const sendTestMutation = useMutation( + trpc.notification.sendTest.mutationOptions(), + ); + + const formIsDirty = form.formState.isDirty; + React.useEffect(() => { + setIsDirty(formIsDirty); + }, [formIsDirty, setIsDirty]); + + function submitAction(values: FormValues) { + if (isPending) return; + + startTransition(async () => { + try { + const promise = onSubmit(values); + toast.promise(promise, { + loading: "Saving...", + success: "Saved", + error: (error) => { + if (isTRPCClientError(error)) { + return error.message; + } + return "Failed to save"; + }, + }); + await promise; + } catch (error) { + console.error(error); + } + }); + } + + function testAction() { + if (isPending) return; + + startTransition(async () => { + try { + const provider = form.getValues("provider"); + const data = form.getValues("data"); + const promise = sendTestMutation.mutateAsync({ + provider, + data: { + "ms-teams": data, + }, + }); + toast.promise(promise, { + loading: "Sending test...", + success: "Test sent", + error: (error) => { + if (error instanceof Error) { + return error.message; + } + return "Failed to send test"; + }, + }); + await promise; + } catch (error) { + console.error(error); + } + }); + } + + return ( +
+ + + ( + + Name + + + + + + Enter a descriptive name for your notifier. + + + )} + /> + ( + + Microsoft Teams Workflow URL + + + + + + Create a "Post to a channel when a webhook request is + received" workflow in Teams, then paste the URL here. + + + )} + /> +
+ +
+
+ + + ( + + Monitors + + Select the monitors you want to notify. + + + ({ + id: m.id, + label: m.name, + })), + }, + ]} + value={field.value ?? []} + onValueChange={field.onChange} + /> + + + + )} + /> + + + + ); +} diff --git a/apps/dashboard/src/components/forms/notifications/form.tsx b/apps/dashboard/src/components/forms/notifications/form.tsx index c80275a9..dbe198b3 100644 --- a/apps/dashboard/src/components/forms/notifications/form.tsx +++ b/apps/dashboard/src/components/forms/notifications/form.tsx @@ -23,6 +23,7 @@ const schema = z.object({ name: z.string(), provider: z.enum([ "slack", + "ms-teams", "discord", "email", "sms", diff --git a/apps/dashboard/src/data/notifications.client.ts b/apps/dashboard/src/data/notifications.client.ts index 171cc35a..bbccee1f 100644 --- a/apps/dashboard/src/data/notifications.client.ts +++ b/apps/dashboard/src/data/notifications.client.ts @@ -2,6 +2,7 @@ import { FormDiscord } from "@/components/forms/notifications/form-discord"; import { FormEmail } from "@/components/forms/notifications/form-email"; import { FormGoogleChat } from "@/components/forms/notifications/form-google-chat"; import { FormGrafanaOncall } from "@/components/forms/notifications/form-grafana-oncall"; +import { FormMsTeams } from "@/components/forms/notifications/form-ms-teams"; import { FormNtfy } from "@/components/forms/notifications/form-ntfy"; import { FormOpsGenie } from "@/components/forms/notifications/form-opsgenie"; import { FormPagerDuty } from "@/components/forms/notifications/form-pagerduty"; @@ -14,6 +15,7 @@ import { DiscordIcon, GoogleIcon, GrafanaIcon, + MicrosoftTeamsIcon, TelegramIcon, WhatsappIcon, } from "@openstatus/icons"; @@ -63,6 +65,11 @@ export const config = { label: "Slack", form: FormSlack, }, + "ms-teams": { + icon: MicrosoftTeamsIcon, + label: "Microsoft Teams", + form: FormMsTeams, + }, discord: { icon: DiscordIcon, label: "Discord", diff --git a/apps/server/Dockerfile b/apps/server/Dockerfile index 41a0cf17..16a3cc0f 100644 --- a/apps/server/Dockerfile +++ b/apps/server/Dockerfile @@ -22,6 +22,7 @@ RUN \ --mount=type=bind,target=packages/notifications/email/package.json,source=packages/notifications/email/package.json \ --mount=type=bind,target=packages/notifications/grafana-oncall/package.json,source=packages/notifications/grafana-oncall/package.json \ --mount=type=bind,target=packages/notifications/google-chat/package.json,source=packages/notifications/google-chat/package.json \ + --mount=type=bind,target=packages/notifications/ms-teams/package.json,source=packages/notifications/ms-teams/package.json \ --mount=type=bind,target=packages/notifications/ntfy/package.json,source=packages/notifications/ntfy/package.json \ --mount=type=bind,target=packages/notifications/opsgenie/package.json,source=packages/notifications/opsgenie/package.json \ --mount=type=bind,target=packages/notifications/pagerduty/package.json,source=packages/notifications/pagerduty/package.json \ diff --git a/apps/server/dofigen.lock b/apps/server/dofigen.lock index fe07d09c..1d9f8fe5 100644 --- a/apps/server/dofigen.lock +++ b/apps/server/dofigen.lock @@ -15,8 +15,8 @@ effective: | path: oven/bun digest: sha256:f20d9cf365ab35529384f1717687c739c92e6f39157a35a95ef06f4049a10e4a label: - org.opencontainers.image.stage: build org.opencontainers.image.base.name: docker.io/oven/bun:1.3.6 + org.opencontainers.image.stage: build org.opencontainers.image.base.digest: sha256:f20d9cf365ab35529384f1717687c739c92e6f39157a35a95ef06f4049a10e4a workdir: /app/apps/server env: @@ -36,9 +36,9 @@ effective: | path: oven/bun digest: sha256:f20d9cf365ab35529384f1717687c739c92e6f39157a35a95ef06f4049a10e4a label: - org.opencontainers.image.stage: install org.opencontainers.image.base.name: docker.io/oven/bun:1.3.6 org.opencontainers.image.base.digest: sha256:f20d9cf365ab35529384f1717687c739c92e6f39157a35a95ef06f4049a10e4a + org.opencontainers.image.stage: install workdir: /app/ run: - bun install --production --frozen-lockfile --verbose @@ -69,6 +69,8 @@ effective: | source: packages/notifications/grafana-oncall/package.json - target: packages/notifications/google-chat/package.json source: packages/notifications/google-chat/package.json + - target: packages/notifications/ms-teams/package.json + source: packages/notifications/ms-teams/package.json - target: packages/notifications/ntfy/package.json source: packages/notifications/ntfy/package.json - target: packages/notifications/opsgenie/package.json @@ -115,14 +117,14 @@ effective: | path: debian digest: sha256:1a4701c321b1d28b1ff5f0230e766791e4b79b1d4c6c7a70064f4b297b1a330f label: + org.opencontainers.image.base.name: docker.io/debian:bullseye-slim + org.opencontainers.image.title: OpenStatus Server org.opencontainers.image.vendor: OpenStatus - org.opencontainers.image.source: https://github.com/openstatusHQ/openstatus org.opencontainers.image.base.digest: sha256:1a4701c321b1d28b1ff5f0230e766791e4b79b1d4c6c7a70064f4b297b1a330f - org.opencontainers.image.authors: OpenStatus Team org.opencontainers.image.description: REST API server with Hono framework for OpenStatus - org.opencontainers.image.base.name: docker.io/debian:bullseye-slim - org.opencontainers.image.title: OpenStatus Server + org.opencontainers.image.source: https://github.com/openstatusHQ/openstatus io.dofigen.version: 2.6.0 + org.opencontainers.image.authors: OpenStatus Team user: user: '1000' group: '1000' @@ -159,7 +161,7 @@ images: digest: sha256:f20d9cf365ab35529384f1717687c739c92e6f39157a35a95ef06f4049a10e4a resources: dofigen.yml: - hash: 1759a213e33b260058574d435c45eadd2a9c2b2468f09644d06b78765abc076a + hash: c9490c75001074e3e201504aa5b4251e3e96ba6648b5512dfbaf497e56a57cbc content: | # Files to exclude from Docker context ignore: @@ -193,6 +195,7 @@ resources: - packages/notifications/email/package.json - packages/notifications/grafana-oncall/package.json - packages/notifications/google-chat/package.json + - packages/notifications/ms-teams/package.json - packages/notifications/ntfy/package.json - packages/notifications/opsgenie/package.json - packages/notifications/pagerduty/package.json diff --git a/apps/server/dofigen.yml b/apps/server/dofigen.yml index bcde7172..f5958049 100644 --- a/apps/server/dofigen.yml +++ b/apps/server/dofigen.yml @@ -30,6 +30,7 @@ builders: - packages/notifications/email/package.json - packages/notifications/grafana-oncall/package.json - packages/notifications/google-chat/package.json + - packages/notifications/ms-teams/package.json - packages/notifications/ntfy/package.json - packages/notifications/opsgenie/package.json - packages/notifications/pagerduty/package.json diff --git a/apps/server/package.json b/apps/server/package.json index da35f20d..581eab52 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -32,6 +32,7 @@ "@openstatus/notification-discord": "workspace:*", "@openstatus/notification-google-chat": "workspace:*", "@openstatus/notification-grafana-oncall": "workspace:*", + "@openstatus/notification-ms-teams": "workspace:*", "@openstatus/notification-ntfy": "workspace:*", "@openstatus/notification-opsgenie": "workspace:*", "@openstatus/notification-pagerduty": "workspace:*", diff --git a/apps/server/src/routes/rpc/handlers/notification/converters.ts b/apps/server/src/routes/rpc/handlers/notification/converters.ts index 9ffe3872..13abc84d 100644 --- a/apps/server/src/routes/rpc/handlers/notification/converters.ts +++ b/apps/server/src/routes/rpc/handlers/notification/converters.ts @@ -35,6 +35,7 @@ export function dbProviderToProto( email: NotificationProvider.EMAIL, "google-chat": NotificationProvider.GOOGLE_CHAT, "grafana-oncall": NotificationProvider.GRAFANA_ONCALL, + "ms-teams": NotificationProvider.MS_TEAMS, ntfy: NotificationProvider.NTFY, pagerduty: NotificationProvider.PAGERDUTY, opsgenie: NotificationProvider.OPSGENIE, @@ -58,6 +59,7 @@ export function getExpectedDataCase( [NotificationProvider.EMAIL]: "email", [NotificationProvider.GOOGLE_CHAT]: "googleChat", [NotificationProvider.GRAFANA_ONCALL]: "grafanaOncall", + [NotificationProvider.MS_TEAMS]: "msTeams", [NotificationProvider.NTFY]: "ntfy", [NotificationProvider.PAGERDUTY]: "pagerduty", [NotificationProvider.OPSGENIE]: "opsgenie", @@ -114,6 +116,7 @@ export function protoProviderToDb( [NotificationProvider.EMAIL]: "email", [NotificationProvider.GOOGLE_CHAT]: "google-chat", [NotificationProvider.GRAFANA_ONCALL]: "grafana-oncall", + [NotificationProvider.MS_TEAMS]: "ms-teams", [NotificationProvider.NTFY]: "ntfy", [NotificationProvider.PAGERDUTY]: "pagerduty", [NotificationProvider.OPSGENIE]: "opsgenie", @@ -193,6 +196,17 @@ export function dbDataToProto( }; } break; + case "ms-teams": + if (data["ms-teams"]) { + protoData.data = { + case: "msTeams", + value: { + $typeName: "openstatus.notification.v1.MsTeamsData", + webhookUrl: data["ms-teams"].webhookUrl, + }, + }; + } + break; case "ntfy": if (data.ntfy) { protoData.data = { @@ -329,6 +343,10 @@ export function protoDataToDb( return JSON.stringify({ "grafana-oncall": { webhookUrl: data.data.value.webhookUrl }, }); + case "msTeams": + return JSON.stringify({ + "ms-teams": { webhookUrl: data.data.value.webhookUrl }, + }); case "ntfy": return JSON.stringify({ ntfy: { diff --git a/apps/server/src/routes/rpc/handlers/notification/limits.ts b/apps/server/src/routes/rpc/handlers/notification/limits.ts index f243a143..b8e05226 100644 --- a/apps/server/src/routes/rpc/handlers/notification/limits.ts +++ b/apps/server/src/routes/rpc/handlers/notification/limits.ts @@ -53,6 +53,8 @@ function providerToDisplayName(provider: NotificationProvider): string { return "Google Chat"; case NotificationProvider.GRAFANA_ONCALL: return "Grafana OnCall"; + case NotificationProvider.MS_TEAMS: + return "Microsoft Teams"; case NotificationProvider.NTFY: return "Ntfy"; case NotificationProvider.PAGERDUTY: diff --git a/apps/server/src/routes/rpc/handlers/notification/test-providers.ts b/apps/server/src/routes/rpc/handlers/notification/test-providers.ts index e179424c..76dc24ff 100644 --- a/apps/server/src/routes/rpc/handlers/notification/test-providers.ts +++ b/apps/server/src/routes/rpc/handlers/notification/test-providers.ts @@ -2,6 +2,7 @@ import { sendTest as sendWhatsAppTest } from "@openstatus/notification-bird-what import { sendTestDiscordMessage } from "@openstatus/notification-discord"; import { sendTest as sendGoogleChatTest } from "@openstatus/notification-google-chat"; import { sendTest as sendGrafanaTest } from "@openstatus/notification-grafana-oncall"; +import { sendTest as sendMsTeamsTest } from "@openstatus/notification-ms-teams"; import { sendTest as sendNtfyTest } from "@openstatus/notification-ntfy"; import { sendTest as sendOpsgenieTest } from "@openstatus/notification-opsgenie"; import { sendTest as sendPagerDutyTest } from "@openstatus/notification-pagerduty"; @@ -73,6 +74,16 @@ export async function sendTestNotification( return { success: true }; } + case NotificationProvider.MS_TEAMS: { + if (data.data.case !== "msTeams") { + throw invalidNotificationDataError( + "Expected ms_teams data for Microsoft Teams provider", + ); + } + await sendMsTeamsTest({ webhookUrl: data.data.value.webhookUrl }); + return { success: true }; + } + case NotificationProvider.DISCORD: { if (data.data.case !== "discord") { throw invalidNotificationDataError( diff --git a/apps/server/static/openapi-v1.json b/apps/server/static/openapi-v1.json index 2df06660..21414856 100644 --- a/apps/server/static/openapi-v1.json +++ b/apps/server/static/openapi-v1.json @@ -967,6 +967,7 @@ "email", "google-chat", "grafana-oncall", + "ms-teams", "ntfy", "pagerduty", "opsgenie", @@ -1017,6 +1018,22 @@ }, "required": ["grafana-oncall"] }, + { + "type": "object", + "properties": { + "ms-teams": { + "type": "object", + "properties": { + "webhookUrl": { + "type": "string", + "format": "uri" + } + }, + "required": ["webhookUrl"] + } + }, + "required": ["ms-teams"] + }, { "type": "object", "properties": { @@ -7483,6 +7500,22 @@ }, "required": ["grafana-oncall"] }, + { + "type": "object", + "properties": { + "ms-teams": { + "type": "object", + "properties": { + "webhookUrl": { + "type": "string", + "format": "uri" + } + }, + "required": ["webhookUrl"] + } + }, + "required": ["ms-teams"] + }, { "type": "object", "properties": { diff --git a/apps/server/static/openapi.yaml b/apps/server/static/openapi.yaml index ebddda9e..7214ec42 100644 --- a/apps/server/static/openapi.yaml +++ b/apps/server/static/openapi.yaml @@ -1877,6 +1877,19 @@ components: title: ListNotificationsResponse additionalProperties: false description: ListNotificationsResponse is the response containing notification channels. + openstatus.notification.v1.MsTeamsData: + type: object + properties: + webhookUrl: + type: string + examples: + - https://prod-00.westeurope.logic.azure.com:443/workflows/abc/triggers/manual/paths/invoke + title: webhook_url + format: uri + description: Microsoft Teams webhook URL (Power Automate Workflows). + title: MsTeamsData + additionalProperties: false + description: MsTeamsData contains configuration for Microsoft Teams notifications. openstatus.notification.v1.Notification: type: object properties: @@ -1952,6 +1965,15 @@ components: title: grafana_oncall required: - grafanaOncall + - type: object + properties: + msTeams: + title: ms_teams + description: Microsoft Teams configuration. + $ref: '#/components/schemas/openstatus.notification.v1.MsTeamsData' + title: ms_teams + required: + - msTeams - type: object properties: ntfy: @@ -2044,6 +2066,7 @@ components: - NOTIFICATION_PROVIDER_TELEGRAM - NOTIFICATION_PROVIDER_WEBHOOK - NOTIFICATION_PROVIDER_WHATSAPP + - NOTIFICATION_PROVIDER_MS_TEAMS description: NotificationProvider represents the supported notification channel types. openstatus.notification.v1.NotificationSummary: type: object diff --git a/apps/web/public/assets/changelog/microsoft-teams.png b/apps/web/public/assets/changelog/microsoft-teams.png new file mode 100644 index 0000000000000000000000000000000000000000..d958ebff43240c68afc84dabcd4f709434d84653 GIT binary patch literal 116582 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 literal 0 HcmV?d00001 diff --git a/apps/web/src/content/pages/changelog/microsoft-teams-notifications.mdx b/apps/web/src/content/pages/changelog/microsoft-teams-notifications.mdx new file mode 100644 index 00000000..ad4e838e --- /dev/null +++ b/apps/web/src/content/pages/changelog/microsoft-teams-notifications.mdx @@ -0,0 +1,10 @@ +--- +title: "Microsoft Teams Notifications" +description: "openstatus now supports Microsoft Teams notifications. Receive uptime monitoring alerts as rich Adaptive Cards directly in your Teams channels." +image: "/assets/changelog/microsoft-teams.png" +publishedAt: "2026-05-11" +author: "openstatus" +category: "notifications" +--- + +You can now receive your uptime notifications in Microsoft Teams as rich Adaptive Cards. Set it up via a Power Automate workflow in your channel. diff --git a/apps/workflows/package.json b/apps/workflows/package.json index 2a5b8608..271500aa 100644 --- a/apps/workflows/package.json +++ b/apps/workflows/package.json @@ -19,6 +19,7 @@ "@openstatus/notification-emails": "workspace:*", "@openstatus/notification-google-chat": "workspace:*", "@openstatus/notification-grafana-oncall": "workspace:*", + "@openstatus/notification-ms-teams": "workspace:*", "@openstatus/notification-ntfy": "workspace:*", "@openstatus/notification-opsgenie": "workspace:*", "@openstatus/notification-pagerduty": "workspace:*", diff --git a/apps/workflows/src/checker/alerting.test.ts b/apps/workflows/src/checker/alerting.test.ts index 884e6a14..26dc758d 100644 --- a/apps/workflows/src/checker/alerting.test.ts +++ b/apps/workflows/src/checker/alerting.test.ts @@ -61,6 +61,11 @@ mock.module("./utils", () => ({ sendRecovery: mock(), sendDegraded: mock(), }, + "ms-teams": { + sendAlert: mock(), + sendRecovery: mock(), + sendDegraded: mock(), + }, whatsapp: { sendAlert: mock(), sendRecovery: mock(), sendDegraded: mock() }, }, })); diff --git a/apps/workflows/src/checker/utils.ts b/apps/workflows/src/checker/utils.ts index 09d6c794..0e33dfe5 100644 --- a/apps/workflows/src/checker/utils.ts +++ b/apps/workflows/src/checker/utils.ts @@ -25,6 +25,11 @@ import { sendDegraded as sendGrafanaOncallDegraded, sendRecovery as sendGrafanaOncallRecovery, } from "@openstatus/notification-grafana-oncall"; +import { + sendAlert as sendMsTeamsAlert, + sendDegraded as sendMsTeamsDegraded, + sendRecovery as sendMsTeamsRecovery, +} from "@openstatus/notification-ms-teams"; import { sendAlert as sendNtfyAlert, sendDegraded as sendNtfyDegraded, @@ -90,6 +95,11 @@ export const providerToFunction: Record = { sendRecovery: sendGrafanaOncallRecovery, sendDegraded: sendGrafanaOncallDegraded, }, + "ms-teams": { + sendAlert: sendMsTeamsAlert, + sendRecovery: sendMsTeamsRecovery, + sendDegraded: sendMsTeamsDegraded, + }, ntfy: { sendAlert: sendNtfyAlert, sendRecovery: sendNtfyRecovery, diff --git a/packages/api/package.json b/packages/api/package.json index 02447c5f..233863f2 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -18,6 +18,7 @@ "@openstatus/notification-discord": "workspace:*", "@openstatus/notification-google-chat": "workspace:*", "@openstatus/notification-grafana-oncall": "workspace:*", + "@openstatus/notification-ms-teams": "workspace:*", "@openstatus/notification-ntfy": "workspace:*", "@openstatus/notification-opsgenie": "workspace:*", "@openstatus/notification-pagerduty": "workspace:*", diff --git a/packages/api/src/router/notification.ts b/packages/api/src/router/notification.ts index 5d22e0ff..e097ac05 100644 --- a/packages/api/src/router/notification.ts +++ b/packages/api/src/router/notification.ts @@ -5,6 +5,7 @@ import { discordDataSchema, googleChatDataSchema, grafanaOncallDataSchema, + msTeamsDataSchema, notificationProvider, ntfyDataSchema, opsgenieDataSchema, @@ -29,6 +30,7 @@ import { sendTest as sendWhatsAppTest } from "@openstatus/notification-bird-what import { sendTestDiscordMessage as sendDiscordTest } from "@openstatus/notification-discord"; import { sendTest as sendGoogleChatTest } from "@openstatus/notification-google-chat"; import { sendTest as sendGrafanaTest } from "@openstatus/notification-grafana-oncall"; +import { sendTest as sendMsTeamsTest } from "@openstatus/notification-ms-teams"; import { sendTest as sendNtfyTest } from "@openstatus/notification-ntfy"; import { sendTest as sendOpsGenieTest } from "@openstatus/notification-opsgenie"; import { @@ -195,6 +197,20 @@ export const notificationRouter = createTRPCRouter({ await sendGrafanaTest(_data.data["grafana-oncall"]); return; } + if (opts.input.provider === "ms-teams") { + const _data = msTeamsDataSchema.safeParse(opts.input.data); + if (!_data.success) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: SchemaError.fromZod(_data.error, opts.input).message, + }); + } + + await sendMsTeamsTest({ + webhookUrl: _data.data["ms-teams"].webhookUrl, + }); + return; + } if (opts.input.provider === "discord") { const _data = discordDataSchema.safeParse(opts.input.data); if (!_data.success) { diff --git a/packages/db/src/schema/notifications/constants.ts b/packages/db/src/schema/notifications/constants.ts index 8ba9adbf..fe5f64a9 100644 --- a/packages/db/src/schema/notifications/constants.ts +++ b/packages/db/src/schema/notifications/constants.ts @@ -3,6 +3,7 @@ export const notificationProvider = [ "email", "google-chat", "grafana-oncall", + "ms-teams", "ntfy", "pagerduty", "opsgenie", diff --git a/packages/db/src/schema/notifications/validation.ts b/packages/db/src/schema/notifications/validation.ts index e051e46b..063384b0 100644 --- a/packages/db/src/schema/notifications/validation.ts +++ b/packages/db/src/schema/notifications/validation.ts @@ -74,6 +74,12 @@ export const grafanaOncallDataSchema = z.object({ }), }); +export const msTeamsDataSchema = z.object({ + "ms-teams": z.object({ + webhookUrl: safeUrlSchema, + }), +}); + export const whatsappDataSchema = z.object({ whatsapp: phoneSchema, }); @@ -82,6 +88,7 @@ export const NotificationDataSchema = z.union([ discordDataSchema, emailDataSchema, grafanaOncallDataSchema, + msTeamsDataSchema, ntfyDataSchema, opsgenieDataSchema, pagerdutyDataSchema, @@ -120,6 +127,12 @@ export const InsertNotificationWithDataSchema = z.discriminatedUnion( data: grafanaOncallDataSchema, }).shape, ), + insertNotificationSchema.extend( + z.object({ + provider: z.literal("ms-teams"), + data: msTeamsDataSchema, + }).shape, + ), insertNotificationSchema.extend( z.object({ provider: z.literal("ntfy"), diff --git a/packages/icons/src/index.tsx b/packages/icons/src/index.tsx index c23fa28a..8138a420 100644 --- a/packages/icons/src/index.tsx +++ b/packages/icons/src/index.tsx @@ -11,6 +11,7 @@ export * from "./koyeb"; export * from "./telegram"; export * from "./whatsapp"; export * from "./markdown"; +export * from "./ms-teams"; export * from "./statuspage"; export * from "./betterstack"; export * from "./instatus"; diff --git a/packages/icons/src/ms-teams.tsx b/packages/icons/src/ms-teams.tsx new file mode 100644 index 00000000..a07c7f48 --- /dev/null +++ b/packages/icons/src/ms-teams.tsx @@ -0,0 +1,19 @@ +export function MicrosoftTeamsIcon(props: React.ComponentProps<"svg">) { + return ( + + Microsoft Teams + + + + ); +} diff --git a/packages/notifications/ms-teams/package.json b/packages/notifications/ms-teams/package.json new file mode 100644 index 00000000..d31350c4 --- /dev/null +++ b/packages/notifications/ms-teams/package.json @@ -0,0 +1,21 @@ +{ + "name": "@openstatus/notification-ms-teams", + "version": "0.0.0", + "main": "src/index.ts", + "scripts": { + "test": "bun test", + "tsc": "tsc" + }, + "dependencies": { + "@openstatus/db": "workspace:*", + "@openstatus/notification-base": "workspace:*", + "@openstatus/utils": "workspace:*", + "zod": "4.1.13" + }, + "devDependencies": { + "@openstatus/tsconfig": "workspace:*", + "@types/node": "24.0.8", + "bun-types": "1.3.1", + "typescript": "5.9.3" + } +} diff --git a/packages/notifications/ms-teams/src/card.ts b/packages/notifications/ms-teams/src/card.ts new file mode 100644 index 00000000..a9e1d26e --- /dev/null +++ b/packages/notifications/ms-teams/src/card.ts @@ -0,0 +1,279 @@ +import type { FormattedMessageData } from "@openstatus/notification-base"; + +type AdaptiveCardContainerStyle = "attention" | "warning" | "good"; +type AdaptiveCardTextColor = + | "Default" + | "Dark" + | "Light" + | "Accent" + | "Good" + | "Warning" + | "Attention"; + +type AdaptiveCardTextBlock = { + type: "TextBlock"; + text: string; + weight?: "Default" | "Lighter" | "Bolder"; + size?: "Default" | "Small" | "Medium" | "Large" | "ExtraLarge"; + color?: AdaptiveCardTextColor; + isSubtle?: boolean; + fontType?: "Default" | "Monospace"; + spacing?: "None" | "Small" | "Default" | "Medium" | "Large"; + horizontalAlignment?: "Left" | "Center" | "Right"; + wrap?: boolean; +}; + +type AdaptiveCardFact = { title: string; value: string }; + +type AdaptiveCardFactSet = { + type: "FactSet"; + facts: AdaptiveCardFact[]; +}; + +type AdaptiveCardContainer = { + type: "Container"; + style?: AdaptiveCardContainerStyle; + items: AdaptiveCardBodyElement[]; +}; + +type AdaptiveCardBodyElement = + | AdaptiveCardTextBlock + | AdaptiveCardFactSet + | AdaptiveCardContainer; + +type AdaptiveCardOpenUrlAction = { + type: "Action.OpenUrl"; + title: string; + url: string; +}; + +export type AdaptiveCard = { + type: "AdaptiveCard"; + $schema: "https://adaptivecards.io/schemas/adaptive-card.json"; + version: "1.5"; + body: AdaptiveCardBodyElement[]; + actions: AdaptiveCardOpenUrlAction[]; +}; + +const SCHEMA_URL = "https://adaptivecards.io/schemas/adaptive-card.json"; +const CARD_VERSION = "1.5"; +const FOOTER_TEXT = "openstatus"; + +function buildUrlText(data: FormattedMessageData): string { + if (data.monitorMethod && data.monitorJobType === "http") { + return `${data.monitorMethod} ${data.monitorUrl}`; + } + return data.monitorUrl; +} + +function buildHeader( + data: FormattedMessageData, + style: AdaptiveCardContainerStyle, + titleColor: AdaptiveCardTextColor, + title: string, +): AdaptiveCardContainer { + return { + type: "Container", + style, + items: [ + { + type: "TextBlock", + text: title, + weight: "Bolder", + size: "Large", + color: titleColor, + wrap: true, + }, + { + type: "TextBlock", + text: buildUrlText(data), + fontType: "Monospace", + spacing: "None", + isSubtle: true, + wrap: true, + }, + ], + }; +} + +function buildFactSet(data: FormattedMessageData): AdaptiveCardFactSet { + return { + type: "FactSet", + facts: [ + { title: "Status code", value: data.statusCodeFormatted }, + { title: "Regions", value: data.regionsDisplay }, + { title: "Latency", value: data.latencyDisplay }, + { title: "Timestamp", value: data.timestampFormatted }, + ], + }; +} + +function buildFooter(): AdaptiveCardTextBlock { + return { + type: "TextBlock", + text: FOOTER_TEXT, + size: "Small", + isSubtle: true, + horizontalAlignment: "Right", + wrap: false, + }; +} + +function buildIncidentDurationBlock( + label: string, + duration: string, +): AdaptiveCardTextBlock { + return { + type: "TextBlock", + text: `**${label}:** ${duration}`, + wrap: true, + spacing: "Medium", + }; +} + +export function buildAlertCard(data: FormattedMessageData): AdaptiveCard { + const body: AdaptiveCardBodyElement[] = [ + buildHeader( + data, + "attention", + "Attention", + `${data.monitorName} is failing`, + ), + buildFactSet(data), + { + type: "Container", + items: [ + { type: "TextBlock", text: "**Error message**", wrap: true }, + { + type: "TextBlock", + text: data.errorMessage, + fontType: "Monospace", + wrap: true, + }, + ], + }, + buildFooter(), + ]; + + return { + type: "AdaptiveCard", + $schema: SCHEMA_URL, + version: CARD_VERSION, + body, + actions: [ + { + type: "Action.OpenUrl", + title: "View dashboard", + url: data.dashboardUrl, + }, + ], + }; +} + +export function buildRecoveryCard(data: FormattedMessageData): AdaptiveCard { + const body: AdaptiveCardBodyElement[] = [ + buildHeader(data, "good", "Good", `${data.monitorName} is recovered`), + ]; + + if (data.incidentDuration) { + body.push(buildIncidentDurationBlock("Downtime", data.incidentDuration)); + } + + body.push(buildFactSet(data), buildFooter()); + + return { + type: "AdaptiveCard", + $schema: SCHEMA_URL, + version: CARD_VERSION, + body, + actions: [ + { + type: "Action.OpenUrl", + title: "View dashboard", + url: data.dashboardUrl, + }, + ], + }; +} + +export function buildDegradedCard(data: FormattedMessageData): AdaptiveCard { + const body: AdaptiveCardBodyElement[] = [ + buildHeader(data, "warning", "Warning", `${data.monitorName} is degraded`), + ]; + + if (data.incidentDuration) { + body.push( + buildIncidentDurationBlock( + "Previous incident duration", + data.incidentDuration, + ), + ); + } + + body.push(buildFactSet(data), buildFooter()); + + return { + type: "AdaptiveCard", + $schema: SCHEMA_URL, + version: CARD_VERSION, + body, + actions: [ + { + type: "Action.OpenUrl", + title: "View dashboard", + url: data.dashboardUrl, + }, + ], + }; +} + +export function buildTestCard(): AdaptiveCard { + return { + type: "AdaptiveCard", + $schema: SCHEMA_URL, + version: CARD_VERSION, + body: [ + { + type: "Container", + style: "good", + items: [ + { + type: "TextBlock", + text: "Test notification", + weight: "Bolder", + size: "Large", + color: "Good", + wrap: true, + }, + { + type: "TextBlock", + text: "Your Microsoft Teams webhook is configured correctly.", + spacing: "None", + isSubtle: true, + wrap: true, + }, + ], + }, + { + type: "FactSet", + facts: [ + { title: "Status", value: "Webhook Connected" }, + { title: "Type", value: "Test Notification" }, + ], + }, + { + type: "TextBlock", + text: "You will receive notifications here when your monitors trigger fail, recover, or degrade.", + wrap: true, + }, + buildFooter(), + ], + actions: [ + { + type: "Action.OpenUrl", + title: "View dashboard", + url: "https://app.openstatus.dev", + }, + ], + }; +} diff --git a/packages/notifications/ms-teams/src/index.test.ts b/packages/notifications/ms-teams/src/index.test.ts new file mode 100644 index 00000000..ca080ed9 --- /dev/null +++ b/packages/notifications/ms-teams/src/index.test.ts @@ -0,0 +1,338 @@ +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"; +import type { Incident, Monitor } from "@openstatus/db/src/schema"; +import { selectNotificationSchema } from "@openstatus/db/src/schema"; +import { sendAlert, sendDegraded, sendRecovery, sendTest } from "./index"; + +type FetchMock = ReturnType>; + +type AdaptiveCardElement = { + type: string; + text?: string; + color?: string; + style?: string; + items?: AdaptiveCardElement[]; + facts?: Array<{ title: string; value: string }>; +}; + +type AdaptiveCardAction = { + type: string; + title: string; + url: string; +}; + +type AdaptiveCardPayload = { + type: string; + version: string; + body: AdaptiveCardElement[]; + actions: AdaptiveCardAction[]; +}; + +type MessagePayload = { + type: string; + attachments: Array<{ + contentType: string; + content: AdaptiveCardPayload; + }>; +}; + +describe("Microsoft Teams Notifications", () => { + let fetchMock: FetchMock; + + beforeEach(() => { + // @ts-expect-error spyOn typing requires the full `typeof fetch` (incl. preconnect) + fetchMock = spyOn(globalThis, "fetch").mockImplementation(() => + Promise.resolve(new Response(null, { status: 200 })), + ); + }); + + afterEach(() => { + fetchMock.mockRestore(); + }); + + const createMockMonitor = (): Monitor => ({ + id: 1, + name: "API Health Check", + url: "https://api.example.com/health", + jobType: "http", + periodicity: "5m", + status: "active", + active: true, + public: true, + createdAt: new Date(), + updatedAt: new Date(), + regions: ["iad"], + description: "", + headers: [], + body: "", + workspaceId: 1, + timeout: 45000, + degradedAfter: null, + assertions: null, + method: "GET", + deletedAt: null, + externalName: null, + otelEndpoint: null, + otelHeaders: [], + retry: 3, + followRedirects: false, + }); + + const createMockNotification = () => ({ + id: 1, + name: "Microsoft Teams Notification", + provider: "ms-teams" as const, + workspaceId: 1, + createdAt: new Date(), + updatedAt: new Date(), + data: JSON.stringify({ + "ms-teams": { + webhookUrl: + "https://prod-00.westeurope.logic.azure.com:443/workflows/test/triggers/manual/paths/invoke", + }, + }), + }); + + const createMockResolvedIncident = (): Incident => ({ + id: 1, + title: "", + summary: "", + status: "resolved", + monitorId: 1, + workspaceId: 1, + startedAt: new Date("2026-01-22T10:00:00.000Z"), + acknowledgedAt: null, + acknowledgedBy: null, + resolvedAt: new Date("2026-01-22T12:15:30.000Z"), + resolvedBy: null, + incidentScreenshotUrl: null, + recoveryScreenshotUrl: null, + autoResolved: true, + createdAt: new Date("2026-01-22T10:00:00.000Z"), + updatedAt: new Date("2026-01-22T12:15:30.000Z"), + }); + + const readMessagePayload = (): MessagePayload => { + const calls = fetchMock.mock.calls; + const init = calls[0][1]; + if (!init || typeof init.body !== "string") { + throw new Error("expected string body"); + } + return JSON.parse(init.body) as MessagePayload; + }; + + const getCard = (msg: MessagePayload): AdaptiveCardPayload => { + return msg.attachments[0].content; + }; + + const findContainerByStyle = ( + card: AdaptiveCardPayload, + style: string, + ): AdaptiveCardElement | undefined => { + return card.body.find( + (el) => el.type === "Container" && el.style === style, + ); + }; + + const findFactSet = ( + card: AdaptiveCardPayload, + ): AdaptiveCardElement | undefined => { + return card.body.find((el) => el.type === "FactSet"); + }; + + const findTextBlockContaining = ( + card: AdaptiveCardPayload, + needle: string, + ): AdaptiveCardElement | undefined => { + return card.body.find( + (el) => + el.type === "TextBlock" && + typeof el.text === "string" && + el.text.includes(needle), + ); + }; + + test("Send Alert", async () => { + const monitor = createMockMonitor(); + const notification = selectNotificationSchema.parse( + createMockNotification(), + ); + + await sendAlert({ + monitor, + notification, + statusCode: 500, + message: "Something went wrong", + cronTimestamp: Date.now(), + latency: 1500, + regions: ["iad"], + }); + + expect(fetchMock).toHaveBeenCalledTimes(1); + const [url, init] = fetchMock.mock.calls[0]; + expect(String(url)).toContain("logic.azure.com"); + expect(init?.method).toBe("POST"); + + const msg = readMessagePayload(); + expect(msg.type).toBe("message"); + expect(msg.attachments[0].contentType).toBe( + "application/vnd.microsoft.card.adaptive", + ); + + const card = getCard(msg); + expect(card.type).toBe("AdaptiveCard"); + expect(card.version).toBe("1.5"); + + const header = findContainerByStyle(card, "attention"); + expect(header).toBeDefined(); + const title = header?.items?.[0]; + expect(title?.text).toContain("API Health Check"); + expect(title?.text).toContain("is failing"); + expect(title?.color).toBe("Attention"); + + const factSet = findFactSet(card); + expect(factSet?.facts).toHaveLength(4); + expect(factSet?.facts?.[0]).toEqual({ + title: "Status code", + value: "500 Internal Server Error", + }); + + const action = card.actions[0]; + expect(action.type).toBe("Action.OpenUrl"); + expect(action.title).toBe("View dashboard"); + expect(action.url).toBe("https://app.openstatus.dev/monitors/1"); + }); + + test("Send Recovery (no incident)", async () => { + const monitor = createMockMonitor(); + const notification = selectNotificationSchema.parse( + createMockNotification(), + ); + + await sendRecovery({ + monitor, + notification, + statusCode: 200, + cronTimestamp: Date.now(), + latency: 150, + regions: ["iad"], + }); + + const card = getCard(readMessagePayload()); + const header = findContainerByStyle(card, "good"); + expect(header).toBeDefined(); + expect(header?.items?.[0]?.text).toContain("is recovered"); + expect(findTextBlockContaining(card, "Downtime:")).toBeUndefined(); + }); + + test("Send Recovery (with resolved incident)", async () => { + const monitor = createMockMonitor(); + const notification = selectNotificationSchema.parse( + createMockNotification(), + ); + + await sendRecovery({ + monitor, + notification, + statusCode: 200, + cronTimestamp: Date.now(), + latency: 150, + regions: ["iad"], + incident: createMockResolvedIncident(), + }); + + const card = getCard(readMessagePayload()); + const downtime = findTextBlockContaining(card, "Downtime:"); + expect(downtime).toBeDefined(); + expect(downtime?.text).toContain("2h 15m 30s"); + }); + + test("Send Degraded (no incident)", async () => { + const monitor = createMockMonitor(); + const notification = selectNotificationSchema.parse( + createMockNotification(), + ); + + await sendDegraded({ + monitor, + notification, + statusCode: 504, + message: "slow", + cronTimestamp: Date.now(), + latency: 5234, + regions: ["iad"], + }); + + const card = getCard(readMessagePayload()); + const header = findContainerByStyle(card, "warning"); + expect(header).toBeDefined(); + expect(header?.items?.[0]?.text).toContain("is degraded"); + expect( + findTextBlockContaining(card, "Previous incident duration:"), + ).toBeUndefined(); + }); + + test("Send Degraded (with incident)", async () => { + const monitor = createMockMonitor(); + const notification = selectNotificationSchema.parse( + createMockNotification(), + ); + + await sendDegraded({ + monitor, + notification, + statusCode: 504, + message: "slow", + cronTimestamp: Date.now(), + latency: 5234, + regions: ["iad"], + incident: createMockResolvedIncident(), + }); + + const card = getCard(readMessagePayload()); + const block = findTextBlockContaining(card, "Previous incident duration:"); + expect(block).toBeDefined(); + expect(block?.text).toContain("2h 15m 30s"); + }); + + test("Send Test", async () => { + await sendTest({ + webhookUrl: + "https://prod-00.westeurope.logic.azure.com:443/workflows/test/triggers/manual/paths/invoke", + }); + + expect(fetchMock).toHaveBeenCalledTimes(1); + const card = getCard(readMessagePayload()); + const header = findContainerByStyle(card, "good"); + expect(header?.items?.[0]?.text).toBe("Test notification"); + expect(card.actions[0].url).toBe("https://app.openstatus.dev"); + }); + + test("Send Test with empty webhookUrl", async () => { + await expect(sendTest({ webhookUrl: "" })).rejects.toThrow(); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + test("Handle fetch error", async () => { + // @ts-expect-error see beforeEach + fetchMock.mockImplementation(() => + Promise.reject(new Error("Network error")), + ); + + const monitor = createMockMonitor(); + const notification = selectNotificationSchema.parse( + createMockNotification(), + ); + + await expect( + sendAlert({ + monitor, + notification, + statusCode: 500, + message: "boom", + cronTimestamp: Date.now(), + latency: 1000, + regions: ["iad"], + }), + ).rejects.toThrow(); + }); +}); diff --git a/packages/notifications/ms-teams/src/index.ts b/packages/notifications/ms-teams/src/index.ts new file mode 100644 index 00000000..e1cfeaa0 --- /dev/null +++ b/packages/notifications/ms-teams/src/index.ts @@ -0,0 +1,71 @@ +import { msTeamsDataSchema } from "@openstatus/db/src/schema"; +import { + type NotificationContext, + buildCommonMessageData, +} from "@openstatus/notification-base"; +import { assertSafeUrl } from "@openstatus/utils"; +import { + type AdaptiveCard, + buildAlertCard, + buildDegradedCard, + buildRecoveryCard, + buildTestCard, +} from "./card"; + +const postCard = async ( + card: AdaptiveCard, + webhookUrl: string, +): Promise => { + if (!webhookUrl || webhookUrl.trim() === "") { + throw new Error("Microsoft Teams webhook URL is required"); + } + + await assertSafeUrl(webhookUrl); + + const res = await fetch(webhookUrl, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + type: "message", + attachments: [ + { + contentType: "application/vnd.microsoft.card.adaptive", + contentUrl: null, + content: card, + }, + ], + }), + }); + + if (!res.ok) { + throw new Error( + `Failed to send Microsoft Teams notification: ${res.status} ${res.statusText}`, + ); + } +}; + +export const sendAlert = async (ctx: NotificationContext): Promise => { + const config = msTeamsDataSchema.parse(JSON.parse(ctx.notification.data)); + const data = buildCommonMessageData(ctx); + await postCard(buildAlertCard(data), config["ms-teams"].webhookUrl); +}; + +export const sendRecovery = async (ctx: NotificationContext): Promise => { + const config = msTeamsDataSchema.parse(JSON.parse(ctx.notification.data)); + const data = buildCommonMessageData(ctx, { incident: ctx.incident }); + await postCard(buildRecoveryCard(data), config["ms-teams"].webhookUrl); +}; + +export const sendDegraded = async (ctx: NotificationContext): Promise => { + const config = msTeamsDataSchema.parse(JSON.parse(ctx.notification.data)); + const data = buildCommonMessageData(ctx, { incident: ctx.incident }); + await postCard(buildDegradedCard(data), config["ms-teams"].webhookUrl); +}; + +export const sendTest = async ({ + webhookUrl, +}: { + webhookUrl: string; +}): Promise => { + await postCard(buildTestCard(), webhookUrl); +}; diff --git a/packages/notifications/ms-teams/src/mock.ts b/packages/notifications/ms-teams/src/mock.ts new file mode 100644 index 00000000..6ed50cc3 --- /dev/null +++ b/packages/notifications/ms-teams/src/mock.ts @@ -0,0 +1,94 @@ +import type { Monitor, Notification } from "@openstatus/db/src/schema"; +import { sendAlert, sendDegraded, sendRecovery, sendTest } from "./index"; + +function requireWebhookUrl(): string { + const url = process.env.MS_TEAMS_WEBHOOK; + if (!url) { + throw new Error("MS_TEAMS_WEBHOOK env var is required"); + } + return url; +} + +const webhookUrl = requireWebhookUrl(); + +const monitor: Monitor = { + id: 1, + name: "OpenStatus Docs", + url: "https://docs.openstatus.dev", + periodicity: "10m", + jobType: "http", + active: true, + public: true, + createdAt: null, + updatedAt: null, + regions: ["ams", "fra"], + description: "Monitor Description", + headers: [], + body: "", + workspaceId: 1, + timeout: 45000, + degradedAfter: null, + assertions: null, + status: "active", + method: "GET", + deletedAt: null, + externalName: null, + otelEndpoint: null, + otelHeaders: [], + retry: 3, + followRedirects: false, +}; + +const notification: Notification = { + id: 1, + name: "Microsoft Teams", + data: JSON.stringify({ "ms-teams": { webhookUrl } }), + provider: "ms-teams", + workspaceId: 1, + createdAt: null, + updatedAt: null, +}; + +async function main() { + console.log("Sending alert..."); + await sendAlert({ + monitor, + notification, + statusCode: 503, + message: "Connection timeout", + cronTimestamp: Date.now(), + latency: 2450, + regions: ["ams"], + }); + + console.log("Sending degraded..."); + await sendDegraded({ + monitor, + notification, + statusCode: 504, + message: "Slow response", + cronTimestamp: Date.now(), + latency: 5234, + regions: ["ams"], + }); + + console.log("Sending recovery..."); + await sendRecovery({ + monitor, + notification, + statusCode: 200, + cronTimestamp: Date.now(), + latency: 156, + regions: ["ams"], + }); + + console.log("Sending test..."); + await sendTest({ webhookUrl }); + + console.log("Done."); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/packages/notifications/ms-teams/tsconfig.json b/packages/notifications/ms-teams/tsconfig.json new file mode 100644 index 00000000..b4382e67 --- /dev/null +++ b/packages/notifications/ms-teams/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@openstatus/tsconfig/nextjs.json", + "include": ["src", "*.ts"], + "compilerOptions": { + "types": ["bun-types"] + } +} diff --git a/packages/proto/api/openstatus/notification/v1/providers.proto b/packages/proto/api/openstatus/notification/v1/providers.proto index a81d2a87..7e68031e 100644 --- a/packages/proto/api/openstatus/notification/v1/providers.proto +++ b/packages/proto/api/openstatus/notification/v1/providers.proto @@ -35,6 +35,8 @@ enum NotificationProvider { NOTIFICATION_PROVIDER_WEBHOOK = 11; // WhatsApp notification. NOTIFICATION_PROVIDER_WHATSAPP = 12; + // Microsoft Teams notification. + NOTIFICATION_PROVIDER_MS_TEAMS = 13; } // DiscordData contains configuration for Discord notifications. @@ -159,6 +161,15 @@ message WhatsappData { string phone_number = 1 [(buf.validate.field).string.min_len = 1]; } +// MsTeamsData contains configuration for Microsoft Teams notifications. +message MsTeamsData { + // Microsoft Teams webhook URL (Power Automate Workflows). + string webhook_url = 1 [ + (buf.validate.field).string.uri = true, + (gnostic.openapi.v3.property) = {example: {yaml: "https://prod-00.westeurope.logic.azure.com:443/workflows/abc/triggers/manual/paths/invoke"}} + ]; +} + // NotificationData is a union of provider-specific configuration. message NotificationData { oneof data { @@ -186,5 +197,7 @@ message NotificationData { WebhookData webhook = 11; // WhatsApp configuration. WhatsappData whatsapp = 12; + // Microsoft Teams configuration. + MsTeamsData ms_teams = 13; } } diff --git a/packages/proto/gen/openapi.yaml b/packages/proto/gen/openapi.yaml index ebddda9e..7214ec42 100644 --- a/packages/proto/gen/openapi.yaml +++ b/packages/proto/gen/openapi.yaml @@ -1877,6 +1877,19 @@ components: title: ListNotificationsResponse additionalProperties: false description: ListNotificationsResponse is the response containing notification channels. + openstatus.notification.v1.MsTeamsData: + type: object + properties: + webhookUrl: + type: string + examples: + - https://prod-00.westeurope.logic.azure.com:443/workflows/abc/triggers/manual/paths/invoke + title: webhook_url + format: uri + description: Microsoft Teams webhook URL (Power Automate Workflows). + title: MsTeamsData + additionalProperties: false + description: MsTeamsData contains configuration for Microsoft Teams notifications. openstatus.notification.v1.Notification: type: object properties: @@ -1952,6 +1965,15 @@ components: title: grafana_oncall required: - grafanaOncall + - type: object + properties: + msTeams: + title: ms_teams + description: Microsoft Teams configuration. + $ref: '#/components/schemas/openstatus.notification.v1.MsTeamsData' + title: ms_teams + required: + - msTeams - type: object properties: ntfy: @@ -2044,6 +2066,7 @@ components: - NOTIFICATION_PROVIDER_TELEGRAM - NOTIFICATION_PROVIDER_WEBHOOK - NOTIFICATION_PROVIDER_WHATSAPP + - NOTIFICATION_PROVIDER_MS_TEAMS description: NotificationProvider represents the supported notification channel types. openstatus.notification.v1.NotificationSummary: type: object diff --git a/packages/proto/gen/ts/openstatus/notification/v1/providers_pb.ts b/packages/proto/gen/ts/openstatus/notification/v1/providers_pb.ts index b415085e..2e4795a7 100644 --- a/packages/proto/gen/ts/openstatus/notification/v1/providers_pb.ts +++ b/packages/proto/gen/ts/openstatus/notification/v1/providers_pb.ts @@ -12,7 +12,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file openstatus/notification/v1/providers.proto. */ export const file_openstatus_notification_v1_providers: GenFile = /*@__PURE__*/ - fileDesc("CipvcGVuc3RhdHVzL25vdGlmaWNhdGlvbi92MS9wcm92aWRlcnMucHJvdG8SGm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxIlsKC0Rpc2NvcmREYXRhEkwKC3dlYmhvb2tfdXJsGAEgASgJQje6Ryw6KhIoaHR0cHM6Ly9kaXNjb3JkLmNvbS9hcGkvd2ViaG9va3MvMTIzL2FiY7pIBXIDiAEBIj4KCUVtYWlsRGF0YRIxCgVlbWFpbBgBIAEoCUIiukcYOhYSFG9wcy10ZWFtQGV4YW1wbGUuY29tukgEcgJgASIvCg5Hb29nbGVDaGF0RGF0YRIdCgt3ZWJob29rX3VybBgBIAEoCUIIukgFcgOIAQEiMgoRR3JhZmFuYU9uY2FsbERhdGESHQoLd2ViaG9va191cmwYASABKAlCCLpIBXIDiAEBImwKCE50ZnlEYXRhEi4KBXRvcGljGAEgASgJQh+6RxU6ExIRb3BlbnN0YXR1cy1hbGVydHO6SARyAhABEhIKCnNlcnZlcl91cmwYAiABKAkSEgoFdG9rZW4YAyABKAlIAIgBAUIICgZfdG9rZW4iTAoNUGFnZXJEdXR5RGF0YRI7Cg9pbnRlZ3JhdGlvbl9rZXkYASABKAlCIrpHGDoWEhRhMWIyYzNkNGU1ZjZnN2g4aTlqMLpIBHICEAEibgoMT3BzZ2VuaWVEYXRhEhgKB2FwaV9rZXkYASABKAlCB7pIBHICEAESRAoGcmVnaW9uGAIgASgOMioub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuT3BzZ2VuaWVSZWdpb25CCLpIBYIBAhABIl0KCVNsYWNrRGF0YRJQCgt3ZWJob29rX3VybBgBIAEoCUI7ukcwOi4SLGh0dHBzOi8vaG9va3Muc2xhY2suY29tL3NlcnZpY2VzL1QwMC9CMDAveHh4ukgFcgOIAQEiOwoHU21zRGF0YRIwCgxwaG9uZV9udW1iZXIYASABKAlCGrpHEDoOEgwrMTQxNTU1NTEyMzS6SARyAhABIj0KDFRlbGVncmFtRGF0YRItCgdjaGF0X2lkGAEgASgJQhy6RxI6EBIOLTEwMDEyMzQ1Njc4OTC6SARyAhABIjQKDVdlYmhvb2tIZWFkZXISFAoDa2V5GAEgASgJQge6SARyAhABEg0KBXZhbHVlGAIgASgJIpcBCgtXZWJob29rRGF0YRJMCghlbmRwb2ludBgBIAEoCUI6ukcvOi0SK2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tL3dlYmhvb2tzL29wZW5zdGF0dXO6SAVyA4gBARI6CgdoZWFkZXJzGAIgAygLMikub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuV2ViaG9va0hlYWRlciItCgxXaGF0c2FwcERhdGESHQoMcGhvbmVfbnVtYmVyGAEgASgJQge6SARyAhABIvIFChBOb3RpZmljYXRpb25EYXRhEjoKB2Rpc2NvcmQYASABKAsyJy5vcGVuc3RhdHVzLm5vdGlmaWNhdGlvbi52MS5EaXNjb3JkRGF0YUgAEjYKBWVtYWlsGAIgASgLMiUub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuRW1haWxEYXRhSAASQQoLZ29vZ2xlX2NoYXQYAyABKAsyKi5vcGVuc3RhdHVzLm5vdGlmaWNhdGlvbi52MS5Hb29nbGVDaGF0RGF0YUgAEkcKDmdyYWZhbmFfb25jYWxsGAQgASgLMi0ub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuR3JhZmFuYU9uY2FsbERhdGFIABI0CgRudGZ5GAUgASgLMiQub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuTnRmeURhdGFIABI+CglwYWdlcmR1dHkYBiABKAsyKS5vcGVuc3RhdHVzLm5vdGlmaWNhdGlvbi52MS5QYWdlckR1dHlEYXRhSAASPAoIb3BzZ2VuaWUYByABKAsyKC5vcGVuc3RhdHVzLm5vdGlmaWNhdGlvbi52MS5PcHNnZW5pZURhdGFIABI2CgVzbGFjaxgIIAEoCzIlLm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxLlNsYWNrRGF0YUgAEjIKA3NtcxgJIAEoCzIjLm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxLlNtc0RhdGFIABI8Cgh0ZWxlZ3JhbRgKIAEoCzIoLm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxLlRlbGVncmFtRGF0YUgAEjoKB3dlYmhvb2sYCyABKAsyJy5vcGVuc3RhdHVzLm5vdGlmaWNhdGlvbi52MS5XZWJob29rRGF0YUgAEjwKCHdoYXRzYXBwGAwgASgLMigub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuV2hhdHNhcHBEYXRhSABCBgoEZGF0YSrmAwoUTm90aWZpY2F0aW9uUHJvdmlkZXISJQohTk9USUZJQ0FUSU9OX1BST1ZJREVSX1VOU1BFQ0lGSUVEEAASIQodTk9USUZJQ0FUSU9OX1BST1ZJREVSX0RJU0NPUkQQARIfChtOT1RJRklDQVRJT05fUFJPVklERVJfRU1BSUwQAhIlCiFOT1RJRklDQVRJT05fUFJPVklERVJfR09PR0xFX0NIQVQQAxIoCiROT1RJRklDQVRJT05fUFJPVklERVJfR1JBRkFOQV9PTkNBTEwQBBIeChpOT1RJRklDQVRJT05fUFJPVklERVJfTlRGWRAFEiMKH05PVElGSUNBVElPTl9QUk9WSURFUl9QQUdFUkRVVFkQBhIiCh5OT1RJRklDQVRJT05fUFJPVklERVJfT1BTR0VOSUUQBxIfChtOT1RJRklDQVRJT05fUFJPVklERVJfU0xBQ0sQCBIdChlOT1RJRklDQVRJT05fUFJPVklERVJfU01TEAkSIgoeTk9USUZJQ0FUSU9OX1BST1ZJREVSX1RFTEVHUkFNEAoSIQodTk9USUZJQ0FUSU9OX1BST1ZJREVSX1dFQkhPT0sQCxIiCh5OT1RJRklDQVRJT05fUFJPVklERVJfV0hBVFNBUFAQDCphCg5PcHNnZW5pZVJlZ2lvbhIfChtPUFNHRU5JRV9SRUdJT05fVU5TUEVDSUZJRUQQABIWChJPUFNHRU5JRV9SRUdJT05fVVMQARIWChJPUFNHRU5JRV9SRUdJT05fRVUQAkJdWltnaXRodWIuY29tL29wZW5zdGF0dXNocS9vcGVuc3RhdHVzL3BhY2thZ2VzL3Byb3RvL29wZW5zdGF0dXMvbm90aWZpY2F0aW9uL3YxO25vdGlmaWNhdGlvbnYxYgZwcm90bzM", [file_buf_validate_validate, file_gnostic_openapi_v3_annotations]); + fileDesc("CipvcGVuc3RhdHVzL25vdGlmaWNhdGlvbi92MS9wcm92aWRlcnMucHJvdG8SGm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxIlsKC0Rpc2NvcmREYXRhEkwKC3dlYmhvb2tfdXJsGAEgASgJQje6Ryw6KhIoaHR0cHM6Ly9kaXNjb3JkLmNvbS9hcGkvd2ViaG9va3MvMTIzL2FiY7pIBXIDiAEBIj4KCUVtYWlsRGF0YRIxCgVlbWFpbBgBIAEoCUIiukcYOhYSFG9wcy10ZWFtQGV4YW1wbGUuY29tukgEcgJgASIvCg5Hb29nbGVDaGF0RGF0YRIdCgt3ZWJob29rX3VybBgBIAEoCUIIukgFcgOIAQEiMgoRR3JhZmFuYU9uY2FsbERhdGESHQoLd2ViaG9va191cmwYASABKAlCCLpIBXIDiAEBImwKCE50ZnlEYXRhEi4KBXRvcGljGAEgASgJQh+6RxU6ExIRb3BlbnN0YXR1cy1hbGVydHO6SARyAhABEhIKCnNlcnZlcl91cmwYAiABKAkSEgoFdG9rZW4YAyABKAlIAIgBAUIICgZfdG9rZW4iTAoNUGFnZXJEdXR5RGF0YRI7Cg9pbnRlZ3JhdGlvbl9rZXkYASABKAlCIrpHGDoWEhRhMWIyYzNkNGU1ZjZnN2g4aTlqMLpIBHICEAEibgoMT3BzZ2VuaWVEYXRhEhgKB2FwaV9rZXkYASABKAlCB7pIBHICEAESRAoGcmVnaW9uGAIgASgOMioub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuT3BzZ2VuaWVSZWdpb25CCLpIBYIBAhABIl0KCVNsYWNrRGF0YRJQCgt3ZWJob29rX3VybBgBIAEoCUI7ukcwOi4SLGh0dHBzOi8vaG9va3Muc2xhY2suY29tL3NlcnZpY2VzL1QwMC9CMDAveHh4ukgFcgOIAQEiOwoHU21zRGF0YRIwCgxwaG9uZV9udW1iZXIYASABKAlCGrpHEDoOEgwrMTQxNTU1NTEyMzS6SARyAhABIj0KDFRlbGVncmFtRGF0YRItCgdjaGF0X2lkGAEgASgJQhy6RxI6EBIOLTEwMDEyMzQ1Njc4OTC6SARyAhABIjQKDVdlYmhvb2tIZWFkZXISFAoDa2V5GAEgASgJQge6SARyAhABEg0KBXZhbHVlGAIgASgJIpcBCgtXZWJob29rRGF0YRJMCghlbmRwb2ludBgBIAEoCUI6ukcvOi0SK2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tL3dlYmhvb2tzL29wZW5zdGF0dXO6SAVyA4gBARI6CgdoZWFkZXJzGAIgAygLMikub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuV2ViaG9va0hlYWRlciItCgxXaGF0c2FwcERhdGESHQoMcGhvbmVfbnVtYmVyGAEgASgJQge6SARyAhABIowBCgtNc1RlYW1zRGF0YRJ9Cgt3ZWJob29rX3VybBgBIAEoCUJoukddOlsSWWh0dHBzOi8vcHJvZC0wMC53ZXN0ZXVyb3BlLmxvZ2ljLmF6dXJlLmNvbTo0NDMvd29ya2Zsb3dzL2FiYy90cmlnZ2Vycy9tYW51YWwvcGF0aHMvaW52b2tlukgFcgOIAQEirwYKEE5vdGlmaWNhdGlvbkRhdGESOgoHZGlzY29yZBgBIAEoCzInLm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxLkRpc2NvcmREYXRhSAASNgoFZW1haWwYAiABKAsyJS5vcGVuc3RhdHVzLm5vdGlmaWNhdGlvbi52MS5FbWFpbERhdGFIABJBCgtnb29nbGVfY2hhdBgDIAEoCzIqLm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxLkdvb2dsZUNoYXREYXRhSAASRwoOZ3JhZmFuYV9vbmNhbGwYBCABKAsyLS5vcGVuc3RhdHVzLm5vdGlmaWNhdGlvbi52MS5HcmFmYW5hT25jYWxsRGF0YUgAEjQKBG50ZnkYBSABKAsyJC5vcGVuc3RhdHVzLm5vdGlmaWNhdGlvbi52MS5OdGZ5RGF0YUgAEj4KCXBhZ2VyZHV0eRgGIAEoCzIpLm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxLlBhZ2VyRHV0eURhdGFIABI8CghvcHNnZW5pZRgHIAEoCzIoLm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxLk9wc2dlbmllRGF0YUgAEjYKBXNsYWNrGAggASgLMiUub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuU2xhY2tEYXRhSAASMgoDc21zGAkgASgLMiMub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuU21zRGF0YUgAEjwKCHRlbGVncmFtGAogASgLMigub3BlbnN0YXR1cy5ub3RpZmljYXRpb24udjEuVGVsZWdyYW1EYXRhSAASOgoHd2ViaG9vaxgLIAEoCzInLm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxLldlYmhvb2tEYXRhSAASPAoId2hhdHNhcHAYDCABKAsyKC5vcGVuc3RhdHVzLm5vdGlmaWNhdGlvbi52MS5XaGF0c2FwcERhdGFIABI7Cghtc190ZWFtcxgNIAEoCzInLm9wZW5zdGF0dXMubm90aWZpY2F0aW9uLnYxLk1zVGVhbXNEYXRhSABCBgoEZGF0YSqKBAoUTm90aWZpY2F0aW9uUHJvdmlkZXISJQohTk9USUZJQ0FUSU9OX1BST1ZJREVSX1VOU1BFQ0lGSUVEEAASIQodTk9USUZJQ0FUSU9OX1BST1ZJREVSX0RJU0NPUkQQARIfChtOT1RJRklDQVRJT05fUFJPVklERVJfRU1BSUwQAhIlCiFOT1RJRklDQVRJT05fUFJPVklERVJfR09PR0xFX0NIQVQQAxIoCiROT1RJRklDQVRJT05fUFJPVklERVJfR1JBRkFOQV9PTkNBTEwQBBIeChpOT1RJRklDQVRJT05fUFJPVklERVJfTlRGWRAFEiMKH05PVElGSUNBVElPTl9QUk9WSURFUl9QQUdFUkRVVFkQBhIiCh5OT1RJRklDQVRJT05fUFJPVklERVJfT1BTR0VOSUUQBxIfChtOT1RJRklDQVRJT05fUFJPVklERVJfU0xBQ0sQCBIdChlOT1RJRklDQVRJT05fUFJPVklERVJfU01TEAkSIgoeTk9USUZJQ0FUSU9OX1BST1ZJREVSX1RFTEVHUkFNEAoSIQodTk9USUZJQ0FUSU9OX1BST1ZJREVSX1dFQkhPT0sQCxIiCh5OT1RJRklDQVRJT05fUFJPVklERVJfV0hBVFNBUFAQDBIiCh5OT1RJRklDQVRJT05fUFJPVklERVJfTVNfVEVBTVMQDSphCg5PcHNnZW5pZVJlZ2lvbhIfChtPUFNHRU5JRV9SRUdJT05fVU5TUEVDSUZJRUQQABIWChJPUFNHRU5JRV9SRUdJT05fVVMQARIWChJPUFNHRU5JRV9SRUdJT05fRVUQAkJdWltnaXRodWIuY29tL29wZW5zdGF0dXNocS9vcGVuc3RhdHVzL3BhY2thZ2VzL3Byb3RvL29wZW5zdGF0dXMvbm90aWZpY2F0aW9uL3YxO25vdGlmaWNhdGlvbnYxYgZwcm90bzM", [file_buf_validate_validate, file_gnostic_openapi_v3_annotations]); /** * DiscordData contains configuration for Discord notifications. @@ -322,6 +322,27 @@ export type WhatsappData = Message<"openstatus.notification.v1.WhatsappData"> & export const WhatsappDataSchema: GenMessage = /*@__PURE__*/ messageDesc(file_openstatus_notification_v1_providers, 12); +/** + * MsTeamsData contains configuration for Microsoft Teams notifications. + * + * @generated from message openstatus.notification.v1.MsTeamsData + */ +export type MsTeamsData = Message<"openstatus.notification.v1.MsTeamsData"> & { + /** + * Microsoft Teams webhook URL (Power Automate Workflows). + * + * @generated from field: string webhook_url = 1; + */ + webhookUrl: string; +}; + +/** + * Describes the message openstatus.notification.v1.MsTeamsData. + * Use `create(MsTeamsDataSchema)` to create a new message. + */ +export const MsTeamsDataSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_openstatus_notification_v1_providers, 13); + /** * NotificationData is a union of provider-specific configuration. * @@ -427,6 +448,14 @@ export type NotificationData = Message<"openstatus.notification.v1.NotificationD */ value: WhatsappData; case: "whatsapp"; + } | { + /** + * Microsoft Teams configuration. + * + * @generated from field: openstatus.notification.v1.MsTeamsData ms_teams = 13; + */ + value: MsTeamsData; + case: "msTeams"; } | { case: undefined; value?: undefined }; }; @@ -435,7 +464,7 @@ export type NotificationData = Message<"openstatus.notification.v1.NotificationD * Use `create(NotificationDataSchema)` to create a new message. */ export const NotificationDataSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_openstatus_notification_v1_providers, 13); + messageDesc(file_openstatus_notification_v1_providers, 14); /** * NotificationProvider represents the supported notification channel types. @@ -533,6 +562,13 @@ export enum NotificationProvider { * @generated from enum value: NOTIFICATION_PROVIDER_WHATSAPP = 12; */ WHATSAPP = 12, + + /** + * Microsoft Teams notification. + * + * @generated from enum value: NOTIFICATION_PROVIDER_MS_TEAMS = 13; + */ + MS_TEAMS = 13, } /** diff --git a/packages/services/src/notification/internal.ts b/packages/services/src/notification/internal.ts index 8b27d3e7..8705c6e7 100644 --- a/packages/services/src/notification/internal.ts +++ b/packages/services/src/notification/internal.ts @@ -6,6 +6,7 @@ import { emailDataSchema, googleChatDataSchema, grafanaOncallDataSchema, + msTeamsDataSchema, ntfyDataSchema, opsgenieDataSchema, pagerdutyDataSchema, @@ -116,6 +117,7 @@ const providerDataSchemas = { email: emailDataSchema, "google-chat": googleChatDataSchema, "grafana-oncall": grafanaOncallDataSchema, + "ms-teams": msTeamsDataSchema, ntfy: ntfyDataSchema, opsgenie: opsgenieDataSchema, pagerduty: pagerdutyDataSchema, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f4e11533..3d3adbd3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -497,6 +497,9 @@ importers: '@openstatus/notification-grafana-oncall': specifier: workspace:* version: link:../../packages/notifications/grafana-oncall + '@openstatus/notification-ms-teams': + specifier: workspace:* + version: link:../../packages/notifications/ms-teams '@openstatus/notification-ntfy': specifier: workspace:* version: link:../../packages/notifications/ntfy @@ -1154,6 +1157,9 @@ importers: '@openstatus/notification-grafana-oncall': specifier: workspace:* version: link:../../packages/notifications/grafana-oncall + '@openstatus/notification-ms-teams': + specifier: workspace:* + version: link:../../packages/notifications/ms-teams '@openstatus/notification-ntfy': specifier: workspace:* version: link:../../packages/notifications/ntfy @@ -1273,6 +1279,9 @@ importers: '@openstatus/notification-grafana-oncall': specifier: workspace:* version: link:../notifications/grafana-oncall + '@openstatus/notification-ms-teams': + specifier: workspace:* + version: link:../notifications/ms-teams '@openstatus/notification-ntfy': specifier: workspace:* version: link:../notifications/ntfy @@ -1741,6 +1750,34 @@ importers: specifier: 5.9.3 version: 5.9.3 + packages/notifications/ms-teams: + dependencies: + '@openstatus/db': + specifier: workspace:* + version: link:../../db + '@openstatus/notification-base': + specifier: workspace:* + version: link:../base + '@openstatus/utils': + specifier: workspace:* + version: link:../../utils + zod: + specifier: 4.1.13 + version: 4.1.13 + devDependencies: + '@openstatus/tsconfig': + specifier: workspace:* + version: link:../../tsconfig + '@types/node': + specifier: 24.0.8 + version: 24.0.8 + bun-types: + specifier: 1.3.1 + version: 1.3.1(@types/react@19.2.2) + typescript: + specifier: 5.9.3 + version: 5.9.3 + packages/notifications/ntfy: dependencies: '@openstatus/db':