1import * as transcribe from "@distilled.cloud/aws/transcribe";
2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";
4import * as Binding from "../../Binding.ts";
5import * as Output from "../../Output.ts";
6import type { Role } from "../IAM/Role.ts";
7import { isBindingHost } from "../Lambda/Function.ts";
8import {
9 CreateLanguageModel,
10 type CreateLanguageModelRequest,
11} from "./CreateLanguageModel.ts";
12
13// Bespoke (not makeTranscribeRoleHttpBinding): CreateLanguageModel nests the
14// data-access role inside `InputDataConfig.DataAccessRoleArn` rather than as
15// a top-level request field.
16export const CreateLanguageModelHttp = Layer.effect(
17 CreateLanguageModel,
18 Effect.gen(function* () {
19 const createLanguageModel = yield* transcribe.createLanguageModel;
20
21 return Effect.fn(function* <Rl extends Role>(dataAccessRole: Rl) {
22 const RoleArn = yield* dataAccessRole.roleArn;
23 if (!globalThis.__ALCHEMY_RUNTIME__) {
24 const host = yield* Binding.Host;
25 if (isBindingHost(host)) {
26 yield* host.bind`Allow(${host}, AWS.Transcribe.CreateLanguageModel(${dataAccessRole}))`(
27 {
28 policyStatements: [
29 {
30 Effect: "Allow",
31 Action: ["transcribe:CreateLanguageModel"],
32 Resource: ["*"],
33 },
34 // CRITICAL: without iam:PassRole on the data-access role,
35 // CreateLanguageModel fails only at runtime with an
36 // AccessDenied.
37 {
38 Effect: "Allow",
39 Action: ["iam:PassRole"],
40 Resource: [Output.interpolate`${dataAccessRole.roleArn}`],
41 Condition: {
42 StringEquals: {
43 "iam:PassedToService": "transcribe.amazonaws.com",
44 },
45 },
46 },
47 ],
48 },
49 );
50 }
51 }
52 return Effect.fn(
53 `AWS.Transcribe.CreateLanguageModel(${dataAccessRole.LogicalId})`,
54 )(function* (request: CreateLanguageModelRequest) {
55 return yield* createLanguageModel({
56 ...request,
57 InputDataConfig: {
58 ...request.InputDataConfig,
59 DataAccessRoleArn:
60 request.InputDataConfig.DataAccessRoleArn ?? (yield* RoleArn),
61 },
62 });
63 });
64 });
65 }),
66);