1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import { isBindingHost } from "../Lambda/Function.ts";
4import type { View } from "./View.ts";
5
6/**
7 * Shared HTTP scaffolding for the AWS Resource Explorer runtime bindings.
8 *
9 * NOT exported from `index.ts` — every thin `{Op}Http.ts` in this service
10 * is a `Layer.effect(Cap, make…HttpBinding({ … }))` over one of the two
11 * builders below. Everything except the operation and the IAM action list
12 * is boilerplate.
13 */
14
15/**
16 * Build the impl Effect for a Resource Explorer operation scoped to a
17 * {@link View}: the deploy-time half grants `actions` on the bound view's
18 * ARN, and the runtime half injects the view's `ViewArn` into every
19 * request.
20 */
21export const makeResourceExplorerViewHttpBinding = <
22 I extends { ViewArn?: string },
23 A,
24 E,
25 R,
26>(options: {
27 /** Fully-qualified binding tag, e.g. `AWS.ResourceExplorer.Search`. */
28 tag: string;
29 /** The distilled operation. */
30 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
31 /** IAM actions granted on the view ARN. */
32 actions: readonly string[];
33}) =>
34 Effect.gen(function* () {
35 const op = yield* options.operation;
36
37 return Effect.fn(function* <V extends View>(view: V) {
38 const ViewArn = yield* view.viewArn;
39 if (!globalThis.__ALCHEMY_RUNTIME__) {
40 const host = yield* Binding.Host;
41 if (isBindingHost(host)) {
42 yield* host.bind`Allow(${host}, ${options.tag}(${view}))`({
43 policyStatements: [
44 {
45 Effect: "Allow",
46 Action: [...options.actions],
47 Resource: [view.viewArn],
48 },
49 ],
50 });
51 }
52 }
53 return Effect.fn(`${options.tag}(${view.LogicalId})`)(function* (
54 request?: Omit<I, "ViewArn">,
55 ) {
56 const viewArn = yield* ViewArn;
57 return yield* op({ ...request, ViewArn: viewArn } as I);
58 });
59 });
60 });
61
62/**
63 * Build the impl Effect for an account-level Resource Explorer operation
64 * (e.g. enumerating the searchable resource types). The deploy-time half
65 * grants `actions` on `*` — these operations are not scoped to a single
66 * Resource Explorer resource.
67 */
68export const makeResourceExplorerAccountHttpBinding = <I, A, E, R>(options: {
69 /**
70 * Fully-qualified binding tag, e.g.
71 * `AWS.ResourceExplorer.ListSupportedResourceTypes`.
72 */
73 tag: string;
74 /** The distilled operation, invoked with the caller's request as-is. */
75 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
76 /** IAM actions granted on `*`. */
77 actions: readonly string[];
78}) =>
79 Effect.gen(function* () {
80 const op = yield* options.operation;
81
82 return Effect.fn(function* () {
83 if (!globalThis.__ALCHEMY_RUNTIME__) {
84 const host = yield* Binding.Host;
85 if (isBindingHost(host)) {
86 yield* host.bind`Allow(${host}, ${options.tag}())`({
87 policyStatements: [
88 {
89 Effect: "Allow",
90 Action: [...options.actions],
91 Resource: ["*"],
92 },
93 ],
94 });
95 }
96 }
97 return Effect.fn(options.tag)(function* (request?: I) {
98 return yield* op((request ?? {}) as I);
99 });
100 });
101 });