feat: outgoing webhooks
Owners and admins can point a project at other systems: a signed JSON POST (HMAC-SHA256 of the body) when tickets, comments, releases or sprints change, filtered by event or family. Deliveries are retried a couple of times, the last one is shown, and a ping can be sent from the settings. Private addresses are refused unless WEBHOOKS_ALLOW_PRIVATE is set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
62
libs/api/tracker/application/src/lib/webhooks.service.ts
Normal file
62
libs/api/tracker/application/src/lib/webhooks.service.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CommandBus, QueryBus } from '@nestjs/cqrs';
|
||||
import { WebhookDelivery } from './ports/outgoing-webhooks.repository';
|
||||
import { WEBHOOK_EVENT_NAMES } from './webhooks/webhook-events';
|
||||
import {
|
||||
CreateWebhookCommand,
|
||||
DeleteWebhookCommand,
|
||||
GetWebhooksQuery,
|
||||
TestWebhookCommand,
|
||||
UpdateWebhookCommand,
|
||||
WebhookView,
|
||||
} from './webhooks/webhooks';
|
||||
|
||||
/** The project's outgoing webhooks (owners and admins). */
|
||||
@Injectable()
|
||||
export class WebhooksService {
|
||||
constructor(
|
||||
private readonly commandBus: CommandBus,
|
||||
private readonly queryBus: QueryBus,
|
||||
) {}
|
||||
|
||||
/** Names other systems can subscribe to (plus `family.*` and `*`). */
|
||||
events(): string[] {
|
||||
return WEBHOOK_EVENT_NAMES;
|
||||
}
|
||||
|
||||
list(viewerId: string, projectId: string): Promise<WebhookView[]> {
|
||||
return this.queryBus.execute(new GetWebhooksQuery(viewerId, projectId));
|
||||
}
|
||||
|
||||
/** The secret comes back only here. */
|
||||
create(
|
||||
actorId: string,
|
||||
projectId: string,
|
||||
url: string,
|
||||
events: string[],
|
||||
): Promise<{ id: string; secret: string }> {
|
||||
return this.commandBus.execute(
|
||||
new CreateWebhookCommand(actorId, projectId, url, events),
|
||||
);
|
||||
}
|
||||
|
||||
update(
|
||||
actorId: string,
|
||||
webhookId: string,
|
||||
changes: { url?: string; events?: string[]; active?: boolean },
|
||||
): Promise<WebhookView> {
|
||||
return this.commandBus.execute(
|
||||
new UpdateWebhookCommand(actorId, webhookId, changes),
|
||||
);
|
||||
}
|
||||
|
||||
delete(actorId: string, webhookId: string): Promise<void> {
|
||||
return this.commandBus.execute(
|
||||
new DeleteWebhookCommand(actorId, webhookId),
|
||||
);
|
||||
}
|
||||
|
||||
test(actorId: string, webhookId: string): Promise<WebhookDelivery> {
|
||||
return this.commandBus.execute(new TestWebhookCommand(actorId, webhookId));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user