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 { Domain } from "./Domain.ts";
6import type { Environment } from "./Environment.ts";
7
8/**
9 * Shared scaffolding for Amazon DataZone HTTP 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 builders
13 * below. Everything except the operation and the IAM action list is
14 * boilerplate: DataZone authorizes every action on the domain resource, so
15 * the deploy-time half always grants `actions` on the bound domain's ARN.
16 */
17
18/**
19 * Build the impl Effect for a domain-scoped DataZone operation: the runtime
20 * callable injects the bound {@link Domain}'s id as `domainIdentifier` into
21 * every request, and the deploy-time half grants `actions` on the domain ARN.
22 */
23export const makeDataZoneDomainHttpBinding = <
24 I extends { domainIdentifier: string },
25 A,
26 E,
27 R,
28>(options: {
29 /** Fully-qualified binding tag, e.g. `AWS.DataZone.Search`. */
30 tag: string;
31 /** The distilled operation; `domainIdentifier` is injected. */
32 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
33 /** IAM actions granted on the domain ARN. */
34 actions: readonly string[];
35}) =>
36 Effect.gen(function* () {
37 const op = yield* options.operation;
38
39 return Effect.fn(function* (domain: Domain) {
40 const DomainId = yield* domain.domainId;
41 if (!globalThis.__ALCHEMY_RUNTIME__) {
42 const host = yield* Binding.Host;
43 if (isBindingHost(host)) {
44 yield* host.bind`Allow(${host}, ${options.tag}(${domain}))`({
45 policyStatements: [
46 {
47 Effect: "Allow",
48 Action: [...options.actions],
49 Resource: [domain.domainArn],
50 },
51 ],
52 });
53 }
54 }
55 return Effect.fn(`${options.tag}(${domain.LogicalId})`)(function* (
56 request?: Omit<I, "domainIdentifier">,
57 ) {
58 const domainIdentifier = yield* DomainId;
59 return yield* op({ ...request, domainIdentifier } as I);
60 });
61 });
62 });
63
64/**
65 * Build the impl Effect for an environment-scoped DataZone operation: the
66 * runtime callable injects the bound {@link Environment}'s domain id and
67 * environment id, and the deploy-time half grants `actions` on the parent
68 * domain's ARN (DataZone authorizes every action on the domain resource).
69 */
70export const makeDataZoneEnvironmentHttpBinding = <
71 I extends { domainIdentifier: string; environmentIdentifier: string },
72 A,
73 E,
74 R,
75>(options: {
76 /** Fully-qualified binding tag, e.g. `AWS.DataZone.GetEnvironmentCredentials`. */
77 tag: string;
78 /** The distilled operation; both identifiers are injected. */
79 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
80 /** IAM actions granted on the parent domain ARN. */
81 actions: readonly string[];
82}) =>
83 Effect.gen(function* () {
84 const op = yield* options.operation;
85
86 return Effect.fn(function* (environment: Environment) {
87 const DomainId = yield* environment.domainId;
88 const EnvironmentId = yield* environment.environmentId;
89 if (!globalThis.__ALCHEMY_RUNTIME__) {
90 const host = yield* Binding.Host;
91 if (isBindingHost(host)) {
92 yield* host.bind`Allow(${host}, ${options.tag}(${environment}))`({
93 policyStatements: [
94 {
95 Effect: "Allow",
96 Action: [...options.actions],
97 Resource: [
98 Output.interpolate`arn:aws:datazone:*:*:domain/${environment.domainId}`,
99 ],
100 },
101 ],
102 });
103 }
104 }
105 return Effect.fn(`${options.tag}(${environment.LogicalId})`)(function* (
106 request?: Omit<I, "domainIdentifier" | "environmentIdentifier">,
107 ) {
108 return yield* op({
109 ...request,
110 domainIdentifier: yield* DomainId,
111 environmentIdentifier: yield* EnvironmentId,
112 } as I);
113 });
114 });
115 });