1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import type { PolicyStatement } from "../IAM/Policy.ts";
4import { isBindingHost } from "../Lambda/Function.ts";
5
6/**
7 * Shared HTTP scaffolding for the AWS RAM runtime bindings.
8 *
9 * RAM (Resource Access Manager) is an account-scoped sharing service: every
10 * runtime operation targets resource shares, invitations, permissions, or
11 * shared resources that are chosen per request at runtime (invitation ARNs
12 * arrive from *other* accounts and are unknowable at deploy time), so every
13 * binding is account-level and grants its action(s) on `Resource: ["*"]`.
14 *
15 * NOT exported from `index.ts` — every thin `{Op}Http.ts` in this service is
16 * a `Layer.effect(Cap, makeRAMHttpBinding({ … }))` over the builder below.
17 * Everything except the operation and the IAM action list is boilerplate.
18 */
19export const makeRAMHttpBinding = <I, A, E, R>(options: {
20 /**
21 * Short capability name used in the binding sid and runtime span, e.g.
22 * `"GetResourceShares"`.
23 */
24 capability: string;
25 /**
26 * IAM actions granted on `Resource: ["*"]` (the target shares/invitations
27 * are chosen per request at runtime and unknowable at deploy time).
28 */
29 iamActions: readonly string[];
30 /**
31 * The distilled operation implementing the capability.
32 */
33 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
34}) =>
35 Effect.gen(function* () {
36 const op = yield* options.operation;
37
38 return Effect.fn(function* () {
39 if (!globalThis.__ALCHEMY_RUNTIME__) {
40 const host = yield* Binding.Host;
41 if (isBindingHost(host)) {
42 const policyStatements: PolicyStatement[] = [
43 {
44 Effect: "Allow",
45 Action: [...options.iamActions],
46 // The target shares/invitations/permissions are chosen per
47 // request at runtime.
48 Resource: ["*"],
49 },
50 ];
51 yield* host.bind`Allow(${host}, AWS.RAM.${options.capability}())`({
52 policyStatements,
53 });
54 }
55 }
56 return Effect.fn(`AWS.RAM.${options.capability}`)(function* (
57 request?: I,
58 ) {
59 return yield* op((request ?? {}) as I);
60 });
61 });
62 });