1import * as cloudwatch from "@distilled.cloud/aws/cloudwatch";
2import * as Effect from "effect/Effect";
3import * as Binding from "../../Binding.ts";
4import * as Layer from "effect/Layer";
5import { isBindingHost } from "../Lambda/Function.ts";
6import { type AlarmResource, sortAlarmResources } from "./binding-common.ts";
7import {
8 DescribeAlarms,
9 type DescribeAlarmsRequest,
10} from "./DescribeAlarms.ts";
11
12export const DescribeAlarmsHttp = Layer.effect(
13 DescribeAlarms,
14 Effect.gen(function* () {
15 const describeAlarms = yield* cloudwatch.describeAlarms;
16
17 return Effect.fn(function* (...alarms: AlarmResources) {
18 const sorted = sortAlarmResources(alarms);
19 const AlarmNames = yield* Effect.forEach(sorted, (alarm) =>
20 alarm.alarmName.asEffect(),
21 );
22 if (!globalThis.__ALCHEMY_RUNTIME__) {
23 const host = yield* Binding.Host;
24 if (isBindingHost(host)) {
25 yield* host.bind`Allow(${host}, AWS.CloudWatch.DescribeAlarms(${sorted}))`(
26 {
27 policyStatements: [
28 {
29 Effect: "Allow",
30 Action: ["cloudwatch:DescribeAlarms"],
31 // AWS requires "*" here to return composite alarms.
32 Resource: ["*"],
33 },
34 ],
35 },
36 );
37 }
38 }
39
40 return Effect.fn(`AWS.CloudWatch.DescribeAlarms(${sorted})`)(function* (
41 request: DescribeAlarmsRequest = {},
42 ) {
43 return yield* describeAlarms({
44 ...request,
45 AlarmTypes: getAlarmTypes(sorted),
46 AlarmNames: yield* Effect.forEach(
47 AlarmNames,
48 (alarmName) => alarmName,
49 ),
50 });
51 });
52 });
53 }),
54);
55
56type AlarmResources = [AlarmResource, ...AlarmResource[]];
57
58const getAlarmTypes = (alarms: AlarmResources) =>
59 [
60 ...new Set(
61 alarms.map((alarm) =>
62 alarm.Type === "AWS.CloudWatch.CompositeAlarm"
63 ? "CompositeAlarm"
64 : "MetricAlarm",
65 ),
66 ),
67 ] as cloudwatch.AlarmType[];