feat(integrations): add Gotify notifications integration (#5847)
* feat(integrations): add Gotify notifications integration Closes #4186 > "It would be really useful if Homarr could integrate with Gotify — > view notifications from Gotify right inside the Homarr dashboard, > maybe as a widget or a small panel. A widget that displays the latest > messages from Gotify (with title, message, time)." > — #4186: feat: Gotify Integration - display notifications in Homarr - `gotify/gotify-schema.ts` — Zod schema validating the `GET /message` API response from the Gotify server, including id, date, title, message body, and optional priority fields. - `gotify/gotify-integration.ts` — `GotifyIntegration` class extending the base `Integration` and implementing `INotificationsIntegration`. Authenticates via HTTP Basic Auth (username + password) and fetches the latest 100 messages from the `/message` endpoint. Connection testing hits `/health`. - `index.ts` — exports `GotifyIntegration` from the package public API. - `base/creator.ts` — registers `GotifyIntegration` in the integration creator map so it can be instantiated at runtime. - `integration.ts` — registers the `gotify` integration definition with: - `secretKinds: [["username", "password"]]` (Basic Auth credentials) - `category: ["notifications"]` (picked up automatically by the Notifications widget via `getIntegrationKindsByCategory`) - Icon sourced from `homarr-labs/dashboard-icons` - Documentation URL pointing to `/docs/integrations/gotify` - `docs/homarr-docs-sitemap.ts` — adds `/docs/integrations/gotify` to the `HomarrDocumentationPath` union type so the documentation link passes the TypeScript path validation check. Because `gotify` is registered under the `notifications` category, the existing Notifications widget automatically supports it with no widget code changes required. Users add the integration via Settings → Integrations, supply their Gotify server URL, username, and password, then attach it to a Notifications widget on any board. * refactor(integrations): inline json parse and add error handling in Gotify integration Address PR review feedback: remove intermediate `as unknown` cast by inlining response.json() directly, and use safeParseAsync to handle deserialization failures gracefully instead of throwing unhandled.
This commit is contained in:
1 parent
a4f0eda4a0
commit
5a1967bdd4
6 files changed
+66
No files matched your search
@@ -0,0 +1,41 @@
|
||||
import { ResponseError } from "@homarr/common/server";
|
||||
import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http";
|
||||
|
||||
import { Integration } from "../base/integration";
|
||||
import type { IntegrationTestingInput } from "../base/integration";
|
||||
import type { TestingResult } from "../base/test-connection/test-connection-service";
|
||||
import type { Notification } from "../interfaces/notifications/notification-types";
|
||||
import type { INotificationsIntegration } from "../interfaces/notifications/notifications-integration";
|
||||
import { gotifyMessagesResponseSchema } from "./gotify-schema";
|
||||
|
||||
export class GotifyIntegration extends Integration implements INotificationsIntegration {
|
||||
public async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
|
||||
await input.fetchAsync(this.url("/health"), { headers: this.getHeaders() });
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
private getHeaders() {
|
||||
const credentials = Buffer.from(
|
||||
`${super.getSecretValue("username")}:${super.getSecretValue("password")}`,
|
||||
).toString("base64");
|
||||
return { Authorization: `Basic ${credentials}` };
|
||||
}
|
||||
|
||||
public async getNotificationsAsync(): Promise<Notification[]> {
|
||||
const url = this.url("/message", { limit: 100 });
|
||||
const response = await fetchWithTrustedCertificatesAsync(url, { headers: this.getHeaders() });
|
||||
|
||||
if (!response.ok) throw new ResponseError(response);
|
||||
|
||||
const result = await gotifyMessagesResponseSchema.safeParseAsync(await response.json());
|
||||
if (!result.success) throw new Error(`Failed to parse Gotify response: ${result.error.message}`);
|
||||
const parsed = result.data;
|
||||
|
||||
return parsed.messages.map((message): Notification => ({
|
||||
id: String(message.id),
|
||||
time: new Date(message.date),
|
||||
title: message.title,
|
||||
body: message.message,
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
// See: https://gotify.net/api-docs#/message/getMessages
|
||||
export const gotifyMessageSchema = z.object({
|
||||
id: z.number(),
|
||||
date: z.string(),
|
||||
title: z.string(),
|
||||
message: z.string(),
|
||||
priority: z.number().optional(),
|
||||
});
|
||||
|
||||
export const gotifyMessagesResponseSchema = z.object({
|
||||
messages: z.array(gotifyMessageSchema),
|
||||
});
|
||||
Reference in new issue
Block a user