1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import { isBindingHost } from "../Lambda/Function.ts";
4import { pinNotificationsRegion } from "./internal.ts";
5import type { NotificationConfiguration } from "./NotificationConfiguration.ts";
6
7/**
8 * Shared HTTP scaffolding for the AWS User Notifications runtime 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, the IAM action, and (for the
13 * configuration-scoped builder) the injected ARN is boilerplate.
14 *
15 * User Notifications is a global service managed from `us-east-1` (other
16 * regions reject management calls), so every operation is resolved with the
17 * Region pinned via {@link pinNotificationsRegion} — exactly like the
18 * resource providers in `internal.ts`.
19 *
20 * Per the `notifications` service authorization reference, the event/read
21 * query actions authorize on event/configuration ARN patterns that are not
22 * known until runtime, so the account-level builder grants on
23 * `Resource: ["*"]`. `notifications:ListChannels` authorizes on the
24 * notification configuration, so the configuration-scoped builder grants on
25 * the bound configuration's ARN.
26 */
27
28/**
29 * Build the impl Effect for an account-level User Notifications operation
30 * (the notification-event and managed-notification read APIs — none of
31 * which are scoped to a caller-owned resource).
32 */
33export const makeNotificationsHttpBinding = <
34 I extends object,
35 A,
36 E,
37 R,
38>(options: {
39 /**
40 * Short capability name used in the binding sid and runtime span, e.g.
41 * `"ListNotificationEvents"`.
42 */
43 capability: string;
44 /** IAM actions granted on `Resource: ["*"]`. */
45 iamActions: readonly string[];
46 /** The distilled operation implementing the capability. */
47 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
48}) =>
49 Effect.gen(function* () {
50 const op = yield* pinNotificationsRegion(options.operation);
51
52 return Effect.fn(function* () {
53 if (!globalThis.__ALCHEMY_RUNTIME__) {
54 const host = yield* Binding.Host;
55 if (isBindingHost(host)) {
56 yield* host.bind`Allow(${host}, AWS.Notifications.${options.capability}())`(
57 {
58 policyStatements: [
59 {
60 Effect: "Allow",
61 Action: [...options.iamActions],
62 Resource: ["*"],
63 },
64 ],
65 },
66 );
67 }
68 }
69 return Effect.fn(`AWS.Notifications.${options.capability}`)(function* (
70 request?: I,
71 ) {
72 // The region must also be pinned at the call site: the yield-time
73 // snapshot is only a fallback — the calling fiber's ambient Region
74 // (the host Function's own region) wins over it.
75 return yield* pinNotificationsRegion(op((request ?? {}) as I));
76 });
77 });
78 });
79
80/**
81 * Build the impl Effect for an operation scoped to one
82 * {@link NotificationConfiguration}. The runtime callable injects the bound
83 * configuration's ARN as the request's `notificationConfigurationArn`; the
84 * deploy-time half grants `iamActions` on the configuration's ARN.
85 */
86export const makeNotificationConfigurationHttpBinding = <
87 I extends { notificationConfigurationArn?: string },
88 A,
89 E,
90 R,
91>(options: {
92 /**
93 * Short capability name used in the binding sid and runtime span, e.g.
94 * `"ListChannels"`.
95 */
96 capability: string;
97 /** IAM actions granted on the configuration ARN. */
98 iamActions: readonly string[];
99 /** The distilled operation; `notificationConfigurationArn` is injected. */
100 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
101}) =>
102 Effect.gen(function* () {
103 const op = yield* pinNotificationsRegion(options.operation);
104
105 return Effect.fn(function* (configuration: NotificationConfiguration) {
106 const configurationArn =
107 yield* configuration.notificationConfigurationArn;
108 if (!globalThis.__ALCHEMY_RUNTIME__) {
109 const host = yield* Binding.Host;
110 if (isBindingHost(host)) {
111 yield* host.bind`Allow(${host}, AWS.Notifications.${options.capability}(${configuration}))`(
112 {
113 policyStatements: [
114 {
115 Effect: "Allow",
116 Action: [...options.iamActions],
117 Resource: [configuration.notificationConfigurationArn],
118 },
119 ],
120 },
121 );
122 }
123 }
124 return Effect.fn(
125 `AWS.Notifications.${options.capability}(${configuration.LogicalId})`,
126 )(function* (request?: Omit<I, "notificationConfigurationArn">) {
127 // Call-site region pin — see makeNotificationsHttpBinding above.
128 return yield* pinNotificationsRegion(
129 op({
130 ...request,
131 notificationConfigurationArn: yield* configurationArn,
132 } as I),
133 );
134 });
135 });
136 });