1import type {
2 AddZoneRrsetRecordsError,
3 AddZoneRrsetRecordsRequest,
4 AddZoneRrsetRecordsResponse,
5 ChangeZoneRrsetProtectionError,
6 ChangeZoneRrsetProtectionResponse,
7 ChangeZoneRrsetTtlError,
8 ChangeZoneRrsetTtlResponse,
9 RemoveZoneRrsetRecordsError,
10 RemoveZoneRrsetRecordsRequest,
11 RemoveZoneRrsetRecordsResponse,
12 SetZoneRrsetRecordsError,
13 SetZoneRrsetRecordsRequest,
14 SetZoneRrsetRecordsResponse,
15 UpdateZoneRrsetRecordsError,
16 UpdateZoneRrsetRecordsRequest,
17 UpdateZoneRrsetRecordsResponse,
18} from "@distilled.cloud/hetzner/zone_rrset_actions";
19import type {
20 CreateZoneRrsetError,
21 CreateZoneRrsetRequest,
22 CreateZoneRrsetResponse,
23 DeleteZoneRrsetError,
24 DeleteZoneRrsetResponse,
25 UpdateZoneRrsetError,
26 UpdateZoneRrsetRequest,
27 UpdateZoneRrsetResponse,
28} from "@distilled.cloud/hetzner/zone_rrsets";
29import * as Effect from "effect/Effect";
30import * as Binding from "../Binding.ts";
31import type { RuntimeContext } from "../RuntimeContext.ts";
32import type { Zone } from "./Zone.ts";
33
34/**
35 * Binding that lets runtime code create, update, and delete Hetzner Cloud
36 * DNS RRSets.
37 *
38 * Authenticates with the ambient `HCLOUD_TOKEN`. A read-only token is
39 * rejected on these methods as `Forbidden`. The zone is fixed by
40 * `WriteDns(zone)` so calls take no zone id. Provide {@link WriteDnsHttp}
41 * on the Action / Function Effect.
42 *
43 * Mutating RRSet endpoints are asynchronous — they return an `action`
44 * that must reach `success` before a subsequent read is guaranteed to
45 * see the change. Poll with {@link waitForZoneAction}.
46 *
47 *
48 * ### Mutating RRSets at runtime
49 * **Example:** Create, replace records, and delete from an Action
50 * Bind the client in the Action's Init phase and provide {@link WriteDnsHttp}.
51 * ```typescript
52 * import * as Alchemy from "alchemy";
53 * import * as Hetzner from "alchemy/Hetzner";
54 * import * as Effect from "effect/Effect";
55 *
56 * const Seed = Alchemy.Action(
57 * "Seed",
58 * Effect.gen(function* () {
59 * const dns = yield* Hetzner.WriteDns(zone);
60 * return Effect.fn(function* () {
61 * const created = yield* dns.createRecordSet({
62 * name: "app",
63 * type: "A",
64 * records: [{ value: "192.0.2.1" }],
65 * ttl: 300,
66 * });
67 * yield* Hetzner.waitForZoneAction(created.action);
68 * yield* dns.setRecordSetRecords("app", "A", {
69 * records: [{ value: "192.0.2.2" }],
70 * });
71 * yield* dns.deleteRecordSet("app", "A");
72 * return created.rrset.id;
73 * });
74 * }).pipe(Effect.provide(Hetzner.WriteDnsHttp)),
75 * );
76 * ```
77 *
78 * @binding
79 * @product DNS
80 */
81export interface WriteDns extends Binding.Service<
82 WriteDns,
83 "Hetzner.DNS.WriteDns",
84 (zone: Zone) => Effect.Effect<WriteDnsClient>
85> {}
86
87export const WriteDns = Binding.Service<WriteDns>("Hetzner.DNS.WriteDns");
88
89/** Create-RRSet request, minus the zone id (bound at `WriteDns(zone)` time). */
90export type CreateRecordSetRequestInput = Omit<
91 CreateZoneRrsetRequest,
92 "id_or_name"
93>;
94
95/** Update-RRSet (labels) request, minus the zone id and RRSet identity. */
96export type UpdateRecordSetRequestInput = Omit<
97 UpdateZoneRrsetRequest,
98 "id_or_name" | "rr_name" | "rr_type"
99>;
100
101/** Add-records request, minus the zone id and RRSet identity. */
102export type AddRecordSetRecordsRequestInput = Omit<
103 AddZoneRrsetRecordsRequest,
104 "id_or_name" | "rr_name" | "rr_type"
105>;
106
107/** Remove-records request, minus the zone id and RRSet identity. */
108export type RemoveRecordSetRecordsRequestInput = Omit<
109 RemoveZoneRrsetRecordsRequest,
110 "id_or_name" | "rr_name" | "rr_type"
111>;
112
113/** Set-records request, minus the zone id and RRSet identity. */
114export type SetRecordSetRecordsRequestInput = Omit<
115 SetZoneRrsetRecordsRequest,
116 "id_or_name" | "rr_name" | "rr_type"
117>;
118
119/** Update-record-comments request, minus the zone id and RRSet identity. */
120export type UpdateRecordSetRecordsRequestInput = Omit<
121 UpdateZoneRrsetRecordsRequest,
122 "id_or_name" | "rr_name" | "rr_type"
123>;
124
125/**
126 * Mutating DNS RRSet operations. The zone is fixed when the client is
127 * bound, so no `id_or_name` is passed per call.
128 */
129export interface WriteDnsClient {
130 /** Create an RRSet. */
131 createRecordSet(
132 request: CreateRecordSetRequestInput,
133 ): Effect.Effect<
134 CreateZoneRrsetResponse,
135 CreateZoneRrsetError,
136 RuntimeContext
137 >;
138 /** Overwrite the RRSet's labels (PUT). */
139 updateRecordSet(
140 name: string,
141 type: string,
142 request?: UpdateRecordSetRequestInput,
143 ): Effect.Effect<
144 UpdateZoneRrsetResponse,
145 UpdateZoneRrsetError,
146 RuntimeContext
147 >;
148 /** Delete an RRSet by name and type. */
149 deleteRecordSet(
150 name: string,
151 type: string,
152 ): Effect.Effect<
153 DeleteZoneRrsetResponse,
154 DeleteZoneRrsetError,
155 RuntimeContext
156 >;
157 /** Append records to an RRSet (creates the RRSet if it is missing). */
158 addRecordSetRecords(
159 name: string,
160 type: string,
161 request: AddRecordSetRecordsRequestInput,
162 ): Effect.Effect<
163 AddZoneRrsetRecordsResponse,
164 AddZoneRrsetRecordsError,
165 RuntimeContext
166 >;
167 /** Remove records from an RRSet (deletes it if it becomes empty). */
168 removeRecordSetRecords(
169 name: string,
170 type: string,
171 request: RemoveRecordSetRecordsRequestInput,
172 ): Effect.Effect<
173 RemoveZoneRrsetRecordsResponse,
174 RemoveZoneRrsetRecordsError,
175 RuntimeContext
176 >;
177 /** Replace every record in an existing RRSet. */
178 setRecordSetRecords(
179 name: string,
180 type: string,
181 request: SetRecordSetRecordsRequestInput,
182 ): Effect.Effect<
183 SetZoneRrsetRecordsResponse,
184 SetZoneRrsetRecordsError,
185 RuntimeContext
186 >;
187 /** Update comments on existing records. */
188 updateRecordSetRecords(
189 name: string,
190 type: string,
191 request: UpdateRecordSetRecordsRequestInput,
192 ): Effect.Effect<
193 UpdateZoneRrsetRecordsResponse,
194 UpdateZoneRrsetRecordsError,
195 RuntimeContext
196 >;
197 /** Change the RRSet TTL. Pass `null` to inherit the zone default. */
198 changeRecordSetTtl(
199 name: string,
200 type: string,
201 ttl: number | null,
202 ): Effect.Effect<
203 ChangeZoneRrsetTtlResponse,
204 ChangeZoneRrsetTtlError,
205 RuntimeContext
206 >;
207 /** Enable or disable change protection on the RRSet. */
208 changeRecordSetProtection(
209 name: string,
210 type: string,
211 change: boolean,
212 ): Effect.Effect<
213 ChangeZoneRrsetProtectionResponse,
214 ChangeZoneRrsetProtectionError,
215 RuntimeContext
216 >;
217}