1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import * as Output from "../../Output.ts";
4import { isBindingHost } from "../Lambda/Function.ts";
5import type { Monitor } from "./Monitor.ts";
6
7/**
8 * Shared scaffolding for Amazon CloudWatch Internet Monitor HTTP bindings.
9 *
10 * NOT exported from `index.ts` — every `{Op}Http.ts` in this service is a
11 * thin `Layer.effect(Cap, make…HttpBinding({ … }))` over one of the two
12 * builders below. Everything except the operation and the IAM action is
13 * boilerplate:
14 *
15 * - {@link makeInternetMonitorMonitorHttpBinding} — operations scoped to one
16 * bound {@link Monitor} (`ListHealthEvents`, `GetHealthEvent`, the query
17 * interface). The runtime callable injects the monitor's name as the
18 * request's `MonitorName`; the deploy-time half grants `actions` on the
19 * monitor ARN plus its sub-resources (health events are addressed as
20 * `{monitorArn}/health-event/{id}`).
21 * - {@link makeInternetMonitorAccountHttpBinding} — account-level operations
22 * (`GetInternetEvent`, `ListInternetEvents`). Internet events are global
23 * outage records, not ARN-addressable resources, so the deploy-time half
24 * grants `actions` on `*`.
25 */
26
27/**
28 * Build the impl Effect for an operation scoped to a single bound
29 * {@link Monitor}. The runtime callable injects the monitor's name as the
30 * request's `MonitorName`; the deploy-time half grants `actions` on the
31 * monitor ARN and its sub-resources.
32 */
33export const makeInternetMonitorMonitorHttpBinding = <
34 I extends { MonitorName: string },
35 A,
36 E,
37 R,
38>(options: {
39 /** Fully-qualified binding tag, e.g. `AWS.InternetMonitor.ListHealthEvents`. */
40 tag: string;
41 /** The distilled operation; `MonitorName` is injected from the resource. */
42 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
43 /** IAM actions granted on the monitor ARN (and its sub-resources). */
44 actions: readonly string[];
45}) =>
46 Effect.gen(function* () {
47 const op = yield* options.operation;
48
49 return Effect.fn(function* (monitor: Monitor) {
50 const MonitorName = yield* monitor.monitorName;
51 if (!globalThis.__ALCHEMY_RUNTIME__) {
52 const host = yield* Binding.Host;
53 if (isBindingHost(host)) {
54 yield* host.bind`Allow(${host}, ${options.tag}(${monitor}))`({
55 policyStatements: [
56 {
57 Effect: "Allow",
58 Action: [...options.actions],
59 // Health events (and other per-monitor entities) are
60 // addressed as sub-resources of the monitor ARN, e.g.
61 // `{monitorArn}/health-event/{eventId}`.
62 Resource: [
63 monitor.monitorArn,
64 Output.interpolate`${monitor.monitorArn}/*`,
65 ],
66 },
67 ],
68 });
69 }
70 }
71 return Effect.fn(`${options.tag}(${monitor.LogicalId})`)(function* (
72 request?: Omit<I, "MonitorName">,
73 ) {
74 return yield* op({
75 ...request,
76 MonitorName: yield* MonitorName,
77 } as I);
78 });
79 });
80 });
81
82/**
83 * Build the impl Effect for an account-level Internet Monitor operation. The
84 * runtime callable passes the caller's request through unchanged; the
85 * deploy-time half grants `actions` on `*` (internet events do not support
86 * resource-level permissions).
87 */
88export const makeInternetMonitorAccountHttpBinding = <I, A, E, R>(options: {
89 /** Fully-qualified binding tag, e.g. `AWS.InternetMonitor.ListInternetEvents`. */
90 tag: string;
91 /** The distilled operation, invoked with the caller's request as-is. */
92 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
93 /** IAM actions granted on `*`. */
94 actions: readonly string[];
95}) =>
96 Effect.gen(function* () {
97 const op = yield* options.operation;
98
99 return Effect.fn(function* () {
100 if (!globalThis.__ALCHEMY_RUNTIME__) {
101 const host = yield* Binding.Host;
102 if (isBindingHost(host)) {
103 yield* host.bind`Allow(${host}, ${options.tag}())`({
104 policyStatements: [
105 {
106 Effect: "Allow",
107 Action: [...options.actions],
108 Resource: ["*"],
109 },
110 ],
111 });
112 }
113 }
114 return Effect.fn(options.tag)(function* (request?: I) {
115 return yield* op((request ?? {}) as I);
116 });
117 });
118 });