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 { PlaybackConfiguration } from "./PlaybackConfiguration.ts";
6
7/**
8 * Shared HTTP scaffolding for the AWS Elemental MediaTailor runtime
9 * bindings.
10 *
11 * NOT exported from `index.ts` — every thin `{Op}Http.ts` in this service is
12 * a `Layer.effect(Cap, make…HttpBinding({ … }))` over one of the two
13 * builders below. Everything except the operation, the identifier resolver,
14 * and the IAM action list is boilerplate.
15 */
16
17/**
18 * Builder for account-level MediaTailor bindings (channel assembly control
19 * and reads). Channel/program names are runtime request parameters, so the
20 * deploy-time half grants `iamActions` on `Resource: ["*"]` and the runtime
21 * callable passes the request through unchanged.
22 */
23export const makeMediaTailorHttpBinding = <I, A, E, R>(options: {
24 /** Short capability name used in the binding sid and runtime span. */
25 capability: string;
26 /** IAM actions granted on `Resource: ["*"]`. */
27 iamActions: readonly string[];
28 /** The distilled operation implementing the capability. */
29 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
30}) =>
31 Effect.gen(function* () {
32 const op = yield* options.operation;
33
34 return Effect.fn(function* () {
35 if (!globalThis.__ALCHEMY_RUNTIME__) {
36 const host = yield* Binding.Host;
37 if (isBindingHost(host)) {
38 yield* host.bind`Allow(${host}, AWS.MediaTailor.${options.capability}())`(
39 {
40 policyStatements: [
41 {
42 Effect: "Allow",
43 Action: [...options.iamActions],
44 // Channel-assembly resource names are runtime parameters;
45 // their ARNs are unknowable at deploy time.
46 Resource: ["*"],
47 },
48 ],
49 },
50 );
51 }
52 }
53 return Effect.fn(`AWS.MediaTailor.${options.capability}`)(function* (
54 request: I,
55 ) {
56 return yield* op(request);
57 });
58 });
59 });
60
61/**
62 * Builder for bindings scoped to a {@link PlaybackConfiguration} (the
63 * prefetch-schedule data plane). The runtime callable injects the bound
64 * configuration's name as `PlaybackConfigurationName`, and the deploy-time
65 * half grants `iamActions` on the configuration's ARN and the derived
66 * `…:prefetchSchedule/{name}/*` ARN space.
67 */
68export const makeMediaTailorPlaybackHttpBinding = <
69 I extends { PlaybackConfigurationName: string },
70 A,
71 E,
72 R,
73>(options: {
74 /** Short capability name used in the binding sid and runtime span. */
75 capability: string;
76 /** IAM actions granted on the configuration + prefetch-schedule ARNs. */
77 iamActions: readonly string[];
78 /**
79 * The distilled operation; `PlaybackConfigurationName` is injected from
80 * the bound configuration.
81 */
82 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
83}) =>
84 Effect.gen(function* () {
85 const op = yield* options.operation;
86
87 return Effect.fn(function* (config: PlaybackConfiguration) {
88 const name = yield* config.name;
89 if (!globalThis.__ALCHEMY_RUNTIME__) {
90 const host = yield* Binding.Host;
91 if (isBindingHost(host)) {
92 yield* host.bind`Allow(${host}, AWS.MediaTailor.${options.capability}(${config}))`(
93 {
94 policyStatements: [
95 {
96 Effect: "Allow",
97 Action: [...options.iamActions],
98 Resource: [
99 Output.interpolate`${config.playbackConfigurationArn}`,
100 // Prefetch schedules live in a sibling ARN space:
101 // arn:…:prefetchSchedule/{configurationName}/{name}
102 Output.map(
103 config.playbackConfigurationArn,
104 (arn) =>
105 `${arn.replace(":playbackConfiguration/", ":prefetchSchedule/")}/*`,
106 ),
107 // ListPrefetchSchedules is authorized against the bare
108 // account/region wildcard `…:prefetchSchedule/*` (the
109 // configuration name is not part of the authorization
110 // resource), so every prefetch binding also grants it.
111 Output.map(config.playbackConfigurationArn, (arn) =>
112 arn.replace(
113 /:playbackConfiguration\/.*$/,
114 ":prefetchSchedule/*",
115 ),
116 ),
117 ],
118 },
119 ],
120 },
121 );
122 }
123 }
124 return Effect.fn(
125 `AWS.MediaTailor.${options.capability}(${config.LogicalId})`,
126 )(function* (request: Omit<I, "PlaybackConfigurationName">) {
127 return yield* op({
128 ...request,
129 PlaybackConfigurationName: yield* name,
130 } as I);
131 });
132 });
133 });