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 { Workspace } from "./Workspace.ts";
6
7/**
8 * Shared scaffolding for AWS Managed Grafana HTTP bindings.
9 *
10 * NOT exported from `index.ts` — every `{Op}Http.ts` in this service is a
11 * thin `Layer.effect(Cap, make…HttpBinding({ … }))` over one of the builders
12 * below. Everything except the operation and the IAM action list is
13 * boilerplate.
14 */
15
16/**
17 * Build the impl Effect for an account-level operation (e.g. listing the
18 * available Grafana versions). The deploy-time half grants `actions` on `*`.
19 */
20export const makeGrafanaAccountHttpBinding = <I, A, E, R>(options: {
21 /** Fully-qualified binding tag, e.g. `AWS.Grafana.ListVersions`. */
22 tag: string;
23 /** The distilled operation, invoked with the caller's request as-is. */
24 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
25 /** IAM actions granted on `*`. */
26 actions: readonly string[];
27}) =>
28 Effect.gen(function* () {
29 const op = yield* options.operation;
30
31 return Effect.fn(function* () {
32 if (!globalThis.__ALCHEMY_RUNTIME__) {
33 const host = yield* Binding.Host;
34 if (isBindingHost(host)) {
35 yield* host.bind`Allow(${host}, ${options.tag}())`({
36 policyStatements: [
37 {
38 Effect: "Allow",
39 Action: [...options.actions],
40 Resource: ["*"],
41 },
42 ],
43 });
44 }
45 }
46 return Effect.fn(options.tag)(function* (request?: I) {
47 return yield* op((request ?? {}) as I);
48 });
49 });
50 });
51
52/**
53 * Build the impl Effect for a workspace-scoped operation: the runtime
54 * callable injects the bound {@link Workspace}'s id as `workspaceId` and the
55 * deploy-time half grants `actions` on the workspace ARN.
56 */
57export const makeGrafanaWorkspaceHttpBinding = <
58 I extends { workspaceId: string },
59 A,
60 E,
61 R,
62>(options: {
63 /** Fully-qualified binding tag, e.g. `AWS.Grafana.ListPermissions`. */
64 tag: string;
65 /** The distilled operation; `workspaceId` is injected from the workspace. */
66 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
67 /** IAM actions granted on the workspace ARN. */
68 actions: readonly string[];
69}) =>
70 Effect.gen(function* () {
71 const op = yield* options.operation;
72
73 return Effect.fn(function* (workspace: Workspace) {
74 const workspaceId = yield* workspace.workspaceId;
75 if (!globalThis.__ALCHEMY_RUNTIME__) {
76 const host = yield* Binding.Host;
77 if (isBindingHost(host)) {
78 yield* host.bind`Allow(${host}, ${options.tag}(${workspace}))`({
79 policyStatements: [
80 {
81 Effect: "Allow",
82 Action: [...options.actions],
83 Resource: [Output.interpolate`${workspace.workspaceArn}`],
84 },
85 ],
86 });
87 }
88 }
89 return Effect.fn(`${options.tag}(${workspace.LogicalId})`)(function* (
90 request?: Omit<I, "workspaceId">,
91 ) {
92 return yield* op({
93 ...(request ?? {}),
94 workspaceId: yield* workspaceId,
95 } as I);
96 });
97 });
98 });