| 1 | import 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"; |
| 19 | import type { |
| 20 | CreateZoneRrsetError, |
| 21 | CreateZoneRrsetRequest, |
| 22 | CreateZoneRrsetResponse, |
| 23 | DeleteZoneRrsetError, |
| 24 | DeleteZoneRrsetResponse, |
| 25 | UpdateZoneRrsetError, |
| 26 | UpdateZoneRrsetRequest, |
| 27 | UpdateZoneRrsetResponse, |
| 28 | } from "@distilled.cloud/hetzner/zone_rrsets"; |
| 29 | import * as Effect from "effect/Effect"; |
| 30 | import * as Binding from "../Binding.ts"; |
| 31 | import type { RuntimeContext } from "../RuntimeContext.ts"; |
| 32 | import 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 | */ |
| 81 | export interface WriteDns extends Binding.Service< |
| 82 | WriteDns, |
| 83 | "Hetzner.DNS.WriteDns", |
| 84 | (zone: Zone) => Effect.Effect<WriteDnsClient> |
| 85 | > {} |
| 86 | |
| 87 | export const WriteDns = Binding.Service<WriteDns>("Hetzner.DNS.WriteDns"); |
| 88 | |
| 89 | /** Create-RRSet request, minus the zone id (bound at `WriteDns(zone)` time). */ |
| 90 | export type CreateRecordSetRequestInput = Omit< |
| 91 | CreateZoneRrsetRequest, |
| 92 | "id_or_name" |
| 93 | >; |
| 94 | |
| 95 | /** Update-RRSet (labels) request, minus the zone id and RRSet identity. */ |
| 96 | export 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. */ |
| 102 | export 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. */ |
| 108 | export 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. */ |
| 114 | export 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. */ |
| 120 | export 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 | */ |
| 129 | export 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 | } |