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 { Cluster } from "./Cluster.ts";
6
7/**
8 * Shared scaffolding for AWS DAX 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 builders
12 * below. Everything except the operation and the IAM action list is
13 * boilerplate.
14 */
15
16/**
17 * Build the impl Effect for an account-level operation (cluster monitoring,
18 * event history). The deploy-time half grants `actions` on `*` — these
19 * read-only monitoring actions span every cluster/parameter-group in the
20 * account and the names they filter on are runtime data.
21 */
22export const makeDaxAccountHttpBinding = <I, A, E, R>(options: {
23 /** Fully-qualified binding tag, e.g. `AWS.DAX.DescribeEvents`. */
24 tag: string;
25 /** The distilled operation, invoked with the caller's request as-is. */
26 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
27 /** IAM actions granted on `*`. */
28 actions: readonly string[];
29}) =>
30 Effect.gen(function* () {
31 const op = yield* options.operation;
32
33 return Effect.fn(function* () {
34 if (!globalThis.__ALCHEMY_RUNTIME__) {
35 const host = yield* Binding.Host;
36 if (isBindingHost(host)) {
37 yield* host.bind`Allow(${host}, ${options.tag}())`({
38 policyStatements: [
39 {
40 Effect: "Allow",
41 Action: [...options.actions],
42 Resource: ["*"],
43 },
44 ],
45 });
46 }
47 }
48 return Effect.fn(options.tag)(function* (request?: I) {
49 return yield* op((request ?? {}) as I);
50 });
51 });
52 });
53
54/**
55 * Build the impl Effect for a cluster-scoped operation: the runtime callable
56 * injects the bound {@link Cluster}'s name as `ClusterName` and the
57 * deploy-time half grants `actions` on the cluster ARN.
58 */
59export const makeDaxClusterHttpBinding = <
60 I extends { ClusterName: string },
61 A,
62 E,
63 R,
64>(options: {
65 /** Fully-qualified binding tag, e.g. `AWS.DAX.RebootNode`. */
66 tag: string;
67 /** The distilled operation; `ClusterName` is injected from the cluster. */
68 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
69 /** IAM actions granted on the cluster ARN. */
70 actions: readonly string[];
71}) =>
72 Effect.gen(function* () {
73 const op = yield* options.operation;
74
75 return Effect.fn(function* (cluster: Cluster) {
76 const ClusterName = yield* cluster.clusterName;
77 if (!globalThis.__ALCHEMY_RUNTIME__) {
78 const host = yield* Binding.Host;
79 if (isBindingHost(host)) {
80 yield* host.bind`Allow(${host}, ${options.tag}(${cluster}))`({
81 policyStatements: [
82 {
83 Effect: "Allow",
84 Action: [...options.actions],
85 Resource: [Output.interpolate`${cluster.clusterArn}`],
86 },
87 ],
88 });
89 }
90 }
91 return Effect.fn(`${options.tag}(${cluster.LogicalId})`)(function* (
92 request: Omit<I, "ClusterName">,
93 ) {
94 return yield* op({
95 ...request,
96 ClusterName: yield* ClusterName,
97 } as I);
98 });
99 });
100 });