99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
import { logger } from "~/services/logger.server";
|
|
import { BasePresenter } from "./basePresenter.server";
|
|
import { type RuntimeEnvironmentType, type ProjectAlertChannel } from "@trigger.dev/database";
|
|
import { decryptSecret } from "~/services/secrets/secretStore.server";
|
|
import { env } from "~/env.server";
|
|
import {
|
|
ProjectAlertEmailProperties,
|
|
ProjectAlertSlackProperties,
|
|
ProjectAlertWebhookProperties,
|
|
} from "~/models/projectAlert.server";
|
|
import { getLimit } from "~/services/platform.v3.server";
|
|
|
|
export type AlertChannelListPresenterData = Awaited<ReturnType<AlertChannelListPresenter["call"]>>;
|
|
export type AlertChannelListPresenterRecord =
|
|
AlertChannelListPresenterData["alertChannels"][number];
|
|
export type AlertChannelListPresenterAlertProperties = NonNullable<
|
|
AlertChannelListPresenterRecord["properties"]
|
|
>;
|
|
|
|
export class AlertChannelListPresenter extends BasePresenter {
|
|
public async call(projectId: string, environmentType?: RuntimeEnvironmentType) {
|
|
logger.debug("AlertChannelListPresenter", { projectId });
|
|
|
|
const alertChannels = await this._prisma.projectAlertChannel.findMany({
|
|
where: {
|
|
projectId,
|
|
},
|
|
orderBy: {
|
|
createdAt: "desc",
|
|
},
|
|
});
|
|
|
|
const organization = await this._replica.project.findFirst({
|
|
where: {
|
|
id: projectId,
|
|
},
|
|
select: {
|
|
organizationId: true,
|
|
},
|
|
});
|
|
|
|
if (!organization) {
|
|
throw new Error(`Project not found: ${projectId}`);
|
|
}
|
|
|
|
const limit = await getLimit(organization.organizationId, "alerts", 100_000_000);
|
|
|
|
const relevantChannels = alertChannels.filter((channel) => {
|
|
if (!environmentType) return true;
|
|
return channel.environmentTypes.includes(environmentType);
|
|
});
|
|
|
|
return {
|
|
alertChannels: await Promise.all(
|
|
relevantChannels.map(async (alertChannel) => ({
|
|
...alertChannel,
|
|
properties: await this.#presentProperties(alertChannel),
|
|
}))
|
|
),
|
|
limits: {
|
|
used: alertChannels.length,
|
|
limit,
|
|
},
|
|
};
|
|
}
|
|
|
|
async #presentProperties(alertChannel: ProjectAlertChannel) {
|
|
if (!alertChannel.properties) {
|
|
return;
|
|
}
|
|
|
|
switch (alertChannel.type) {
|
|
case "WEBHOOK":
|
|
const parsedProperties = ProjectAlertWebhookProperties.parse(alertChannel.properties);
|
|
|
|
const secret = await decryptSecret(env.ENCRYPTION_KEY, parsedProperties.secret);
|
|
|
|
return {
|
|
type: "WEBHOOK" as const,
|
|
url: parsedProperties.url,
|
|
secret,
|
|
};
|
|
case "EMAIL":
|
|
return {
|
|
type: "EMAIL" as const,
|
|
...ProjectAlertEmailProperties.parse(alertChannel.properties),
|
|
};
|
|
case "SLACK": {
|
|
return {
|
|
type: "SLACK" as const,
|
|
...ProjectAlertSlackProperties.parse(alertChannel.properties),
|
|
};
|
|
}
|
|
default:
|
|
throw new Error(`Unsupported alert channel type: ${alertChannel.type}`);
|
|
}
|
|
}
|
|
}
|