1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import { isBindingHost } from "../Lambda/Function.ts";
4import { pinFms } from "./AdminAccount.ts";
5
6/**
7 * Shared HTTP scaffolding for the AWS Firewall Manager runtime bindings.
8 *
9 * NOT exported from `index.ts` — every `{Op}Http.ts` in this service is a
10 * thin `Layer.effect(Cap, makeFmsHttpBinding({ … }))` over the builder
11 * below. Everything except the operation and the IAM action is boilerplate.
12 *
13 * All Firewall Manager operations are account-level: they act on the
14 * policies, lists, resource sets, and compliance data of the calling
15 * (administrator) account rather than on one bound Alchemy resource, so the
16 * builder grants the IAM actions on `Resource: ["*"]` and the runtime
17 * callable takes the raw request.
18 *
19 * Policy, list, resource-set, and compliance operations are regional (a
20 * Firewall Manager policy lives in the region it was created in), so they
21 * resolve against the ambient region. The organization-level administrator
22 * management reads (`GetAdminScope`, `ListAdminAccountsForOrganization`,
23 * `ListAdminsManagingAccount`) belong to the same global admin-account
24 * family as the {@link AdminAccount} resource APIs, so they are pinned to
25 * the us-east-1 endpoint via {@link pinFms}.
26 */
27export const makeFmsHttpBinding = <I extends object, A, E, R>(options: {
28 /**
29 * Short capability name used in the binding sid and runtime span, e.g.
30 * `"ListPolicies"`.
31 */
32 capability: string;
33 /** IAM actions granted on `Resource: ["*"]`. */
34 iamActions: readonly string[];
35 /** The distilled operation implementing the capability. */
36 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
37 /**
38 * Pin the operation to the us-east-1 endpoint — set for the
39 * organization-level administrator-management operations, which are
40 * served from the global admin-account endpoint like the
41 * {@link AdminAccount} resource APIs.
42 */
43 pinToAdminRegion?: boolean;
44}) =>
45 Effect.gen(function* () {
46 const op = options.pinToAdminRegion
47 ? yield* pinFms(options.operation)
48 : yield* options.operation;
49
50 return Effect.fn(function* () {
51 if (!globalThis.__ALCHEMY_RUNTIME__) {
52 const host = yield* Binding.Host;
53 if (isBindingHost(host)) {
54 yield* host.bind`Allow(${host}, AWS.FMS.${options.capability}())`({
55 policyStatements: [
56 {
57 Effect: "Allow",
58 Action: [...options.iamActions],
59 Resource: ["*"],
60 },
61 ],
62 });
63 }
64 }
65 return Effect.fn(`AWS.FMS.${options.capability}`)(function* (
66 request?: I,
67 ) {
68 // The admin-region pin must also be applied at the call site: the
69 // yield-time snapshot is only a fallback — the calling fiber's
70 // ambient Region (the host Function's own region) wins over it.
71 const call = op((request ?? {}) as I);
72 return yield* options.pinToAdminRegion ? pinFms(call) : call;
73 });
74 });
75 });