1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import { isBindingHost } from "../Lambda/Function.ts";
4import type { DataLake } from "./DataLake.ts";
5
6/**
7 * Shared scaffolding for Amazon Security Lake HTTP bindings.
8 *
9 * NOT exported from `index.ts` — every thin `{Op}Http.ts` in this service is
10 * a `Layer.effect(Cap, makeSecurityLakeDataLakeHttpBinding({ … }))` over the
11 * builder below. Everything except the operation and the IAM action list is
12 * boilerplate.
13 */
14
15/**
16 * Build the impl Effect for a Security Lake operation scoped to the account's
17 * {@link DataLake}: the deploy-time half grants `actions` on the bound data
18 * lake's ARN, and the runtime half invokes the operation with the caller's
19 * request as-is (Security Lake's monitoring operations take no resource
20 * parameter — the data lake is implicit in the account/Region).
21 */
22export const makeSecurityLakeDataLakeHttpBinding = <I, A, E, R>(options: {
23 /** Fully-qualified binding tag, e.g. `AWS.SecurityLake.GetDataLakeSources`. */
24 tag: string;
25 /** The distilled operation. */
26 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
27 /** IAM actions granted on the data lake ARN. */
28 actions: readonly string[];
29}) =>
30 Effect.gen(function* () {
31 const op = yield* options.operation;
32
33 return Effect.fn(function* (lake: DataLake) {
34 if (!globalThis.__ALCHEMY_RUNTIME__) {
35 const host = yield* Binding.Host;
36 if (isBindingHost(host)) {
37 yield* host.bind`Allow(${host}, ${options.tag}(${lake}))`({
38 policyStatements: [
39 {
40 Effect: "Allow",
41 Action: [...options.actions],
42 Resource: [lake.dataLakeArn],
43 },
44 ],
45 });
46 }
47 }
48 return Effect.fn(`${options.tag}(${lake.LogicalId})`)(function* (
49 request?: I,
50 ) {
51 return yield* op((request ?? {}) as I);
52 });
53 });
54 });