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 { FileSystem } from "./FileSystem.ts";
6
7/**
8 * Shared scaffolding for the FSx runtime bindings.
9 *
10 * NOT exported from `index.ts` — every `{Op}Http.ts` in this service is a
11 * thin `Layer.effect(Cap, makeFSx…HttpBinding({ … }))` over one of the two
12 * builders below. Everything except the operation, the IAM action list, and
13 * (for file-system-scoped operations) the injected file system id is
14 * boilerplate.
15 */
16
17/**
18 * Build the impl Effect for a file-system-scoped FSx operation: the runtime
19 * callable injects the bound {@link FileSystem}'s id (as `FileSystemId`, or
20 * as `FileSystemIds: [id]` for the describe operation) and the deploy-time
21 * half grants `actions` on the file system's ARN.
22 */
23export const makeFSxFileSystemHttpBinding = <
24 I extends { FileSystemId?: string; FileSystemIds?: string[] },
25 A,
26 E,
27 R,
28>(options: {
29 /** Fully-qualified binding tag, e.g. `AWS.FSx.CreateBackup`. */
30 tag: string;
31 /** The distilled operation; the file system id is injected. */
32 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
33 /** IAM actions granted on the file system ARN (+ `extraResourceArns`). */
34 actions: readonly string[];
35 /**
36 * How the bound file system's id is injected into the request:
37 * `FileSystemId` (default) or `FileSystemIds` (`DescribeFileSystems`
38 * takes a plural array).
39 * @default "FileSystemId"
40 */
41 requestKey?: "FileSystemId" | "FileSystemIds";
42 /**
43 * Additional ARN patterns granted alongside the file system ARN. Used for
44 * operations that also authorize on a resource created by the call itself
45 * (e.g. `CreateBackup` authorizes on the new backup's ARN, unknowable at
46 * deploy time — grant `arn:aws:fsx:*:*:backup/*`).
47 */
48 extraResourceArns?: readonly string[];
49}) =>
50 Effect.gen(function* () {
51 const op = yield* options.operation;
52
53 return Effect.fn(function* (fileSystem: FileSystem) {
54 const FileSystemId = yield* fileSystem.fileSystemId;
55 if (!globalThis.__ALCHEMY_RUNTIME__) {
56 const host = yield* Binding.Host;
57 if (isBindingHost(host)) {
58 yield* host.bind`Allow(${host}, ${options.tag}(${fileSystem}))`({
59 policyStatements: [
60 {
61 Effect: "Allow",
62 Action: [...options.actions],
63 Resource: [
64 Output.interpolate`${fileSystem.fileSystemArn}`,
65 ...(options.extraResourceArns ?? []),
66 ],
67 },
68 ],
69 });
70 }
71 }
72 return Effect.fn(`${options.tag}(${fileSystem.LogicalId})`)(function* (
73 request?: Omit<I, "FileSystemId" | "FileSystemIds">,
74 ) {
75 const id = yield* FileSystemId;
76 return yield* op({
77 ...request,
78 ...(options.requestKey === "FileSystemIds"
79 ? { FileSystemIds: [id] }
80 : { FileSystemId: id }),
81 } as I);
82 });
83 });
84 });
85
86/**
87 * Build the impl Effect for an account-level FSx operation (no file-system
88 * argument): the deploy-time half grants `actions` on `*`. Used for
89 * operations that authorize against ARNs unknowable at deploy time (e.g.
90 * backups, snapshots, and data repository tasks created at runtime) and for
91 * account-wide describes.
92 */
93export const makeFSxAccountHttpBinding = <I, A, E, R>(options: {
94 /** Fully-qualified binding tag, e.g. `AWS.FSx.DescribeBackups`. */
95 tag: string;
96 /** The distilled operation, invoked with the caller's request as-is. */
97 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
98 /** IAM actions granted on `*`. */
99 actions: readonly string[];
100}) =>
101 Effect.gen(function* () {
102 const op = yield* options.operation;
103
104 return Effect.fn(function* () {
105 if (!globalThis.__ALCHEMY_RUNTIME__) {
106 const host = yield* Binding.Host;
107 if (isBindingHost(host)) {
108 yield* host.bind`Allow(${host}, ${options.tag}())`({
109 policyStatements: [
110 {
111 Effect: "Allow",
112 Action: [...options.actions],
113 Resource: ["*"],
114 },
115 ],
116 });
117 }
118 }
119 return Effect.fn(options.tag)(function* (request?: I) {
120 return yield* op((request ?? {}) as I);
121 });
122 });
123 });