1import * as devopsguru from "@distilled.cloud/aws/devops-guru";
2import * as Effect from "effect/Effect";
3import * as Schedule from "effect/Schedule";
4import { Unowned } from "../../AdoptPolicy.ts";
5import * as Provider from "../../Provider.ts";
6import { Resource } from "../../Resource.ts";
7import type { Providers } from "../Providers.ts";
8
9export interface EventSourcesConfigProps {
10 /**
11 * Consume Amazon CodeGuru Profiler recommendations as an event source so
12 * DevOps Guru can surface them as proactive insights.
13 * @default false
14 */
15 amazonCodeGuruProfiler?: boolean;
16}
17
18export interface EventSourcesConfig extends Resource<
19 "AWS.DevOpsGuru.EventSourcesConfig",
20 EventSourcesConfigProps,
21 {
22 /** Whether CodeGuru Profiler recommendations are consumed. */
23 amazonCodeGuruProfiler: boolean;
24 },
25 never,
26 Providers
27> {}
28
29/**
30 * The DevOps Guru event sources configuration — the account/region singleton
31 * that controls which integrated services DevOps Guru consumes
32 * recommendations from as event sources. The one supported source is Amazon
33 * CodeGuru Profiler: when enabled, profiler recommendations surface as
34 * DevOps Guru proactive insights.
35 *
36 * An account has exactly one configuration, so this resource is a
37 * capture-and-restore singleton: adopting an enabled configuration that
38 * Alchemy did not create requires `--adopt`. Destroying the resource
39 * restores the default (disabled).
40 *
41 * ### Enabling Event Sources
42 * **Example:** Consume CodeGuru Profiler Recommendations
43 * ```typescript
44 * const eventSources = yield* DevOpsGuru.EventSourcesConfig("EventSources", {
45 * amazonCodeGuruProfiler: true,
46 * });
47 * ```
48 *
49 * @resource
50 */
51export const EventSourcesConfig = Resource<EventSourcesConfig>(
52 "AWS.DevOpsGuru.EventSourcesConfig",
53);
54
55/**
56 * Concurrent `UpdateEventSourcesConfig` calls conflict server-side — retry
57 * the typed conflict tag on a short bounded schedule.
58 *
59 * Explicitly typed: inlining `Effect.retry` with options in provider
60 * lifecycle code can widen the provider layer to `unknown` in declaration
61 * emit.
62 *
63 * @internal
64 */
65const retryUpdateConflict = <A, E extends { readonly _tag: string }, R>(
66 self: Effect.Effect<A, E, R>,
67): Effect.Effect<A, E, R> =>
68 Effect.retry(self, {
69 while: (e) => e._tag === "ConflictException",
70 schedule: Schedule.max([Schedule.fixed("2 seconds"), Schedule.recurs(8)]),
71 });
72
73export const EventSourcesConfigProvider = () =>
74 Provider.effect(
75 EventSourcesConfig,
76 Effect.gen(function* () {
77 // Observe the live configuration. An absent section or status means
78 // the account default (disabled).
79 const observe = Effect.gen(function* () {
80 const { EventSources } = yield* devopsguru.describeEventSourcesConfig(
81 {},
82 );
83 return {
84 amazonCodeGuruProfiler:
85 EventSources?.AmazonCodeGuruProfiler?.Status === "ENABLED",
86 };
87 });
88
89 const setProfiler = Effect.fn(function* (
90 status: devopsguru.EventSourceOptInStatus,
91 ) {
92 yield* retryUpdateConflict(
93 devopsguru.updateEventSourcesConfig({
94 EventSources: { AmazonCodeGuruProfiler: { Status: status } },
95 }),
96 );
97 });
98
99 return {
100 // Account/region singleton — surfaced only when non-default.
101 list: () =>
102 observe.pipe(
103 Effect.map((observed) =>
104 observed.amazonCodeGuruProfiler ? [observed] : [],
105 ),
106 ),
107
108 read: Effect.fn(function* ({ output }) {
109 const observed = yield* observe;
110 if (!observed.amazonCodeGuruProfiler) {
111 return undefined;
112 }
113 // The configuration can't carry ownership tags — an enabled
114 // configuration we have no record of belongs to someone else
115 // until explicitly adopted.
116 return output !== undefined ? observed : Unowned(observed);
117 }),
118
119 reconcile: Effect.fn(function* ({ news, session }) {
120 // 1. OBSERVE — the live configuration is authoritative.
121 const observed = yield* observe;
122
123 // 2. SYNC — apply only when drifted.
124 const desired = news.amazonCodeGuruProfiler ?? false;
125 if (observed.amazonCodeGuruProfiler !== desired) {
126 yield* setProfiler(desired ? "ENABLED" : "DISABLED");
127 }
128
129 // 3. RETURN fresh attributes.
130 const final = yield* observe;
131 yield* session.note(
132 `amazonCodeGuruProfiler: ${final.amazonCodeGuruProfiler}`,
133 );
134 return final;
135 }),
136
137 // "Deleting" the singleton restores the default (disabled).
138 delete: Effect.fn(function* () {
139 const observed = yield* observe;
140 if (observed.amazonCodeGuruProfiler) {
141 yield* setProfiler("DISABLED");
142 }
143 }),
144 };
145 }),
146 );