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 Elemental MediaConvert runtime
8 * bindings.
9 *
10 * MediaConvert jobs are created *at runtime* with server-assigned ids, so
11 * their ARNs are unknowable at deploy time — every binding is account-level
12 * and grants its action(s) on `Resource: ["*"]`. The only variation between
13 * bindings is the distilled operation, the IAM action, and whether the
14 * operation passes an S3-access role to the service (`CreateJob`, which
15 * additionally needs `iam:PassRole` conditioned to
16 * `mediaconvert.amazonaws.com`).
17 *
18 * NOT exported from `index.ts` — every thin `{Op}Http.ts` in this service is
19 * a `Layer.effect(Cap, makeMediaConvertHttpBinding({ … }))`.
20 */
21export const makeMediaConvertHttpBinding = <I, A, E, R>(options: {
22 /**
23 * Short capability name used in the binding sid and runtime span, e.g.
24 * `"CreateJob"`.
25 */
26 capability: string;
27 /**
28 * IAM actions granted on `Resource: ["*"]` (job ARNs are server-assigned
29 * at runtime and unknowable at deploy time).
30 */
31 iamActions: readonly string[];
32 /**
33 * The distilled operation implementing the capability.
34 */
35 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
36 /**
37 * Grant `iam:PassRole` (conditioned to `mediaconvert.amazonaws.com`) so
38 * the function can hand the service the role it assumes to read the input
39 * from and write the output to S3. Set on `CreateJob`.
40 */
41 passRole?: boolean;
42}) =>
43 Effect.gen(function* () {
44 const op = yield* options.operation;
45
46 return Effect.fn(function* () {
47 if (!globalThis.__ALCHEMY_RUNTIME__) {
48 const host = yield* Binding.Host;
49 if (isBindingHost(host)) {
50 const policyStatements: PolicyStatement[] = [
51 {
52 Effect: "Allow",
53 Action: [...options.iamActions],
54 // Job ARNs are server-assigned at runtime; queue/preset/template
55 // references inside a job are resolved by the service.
56 Resource: ["*"],
57 },
58 ];
59 if (options.passRole) {
60 policyStatements.push({
61 Effect: "Allow",
62 Action: ["iam:PassRole"],
63 Resource: ["*"],
64 Condition: {
65 StringEquals: {
66 "iam:PassedToService": "mediaconvert.amazonaws.com",
67 },
68 },
69 });
70 }
71 yield* host.bind`Allow(${host}, AWS.MediaConvert.${options.capability}())`(
72 { policyStatements },
73 );
74 }
75 }
76 return Effect.fn(`AWS.MediaConvert.${options.capability}`)(function* (
77 request?: I,
78 ) {
79 return yield* op((request ?? {}) as I);
80 });
81 });
82 });