1import { Credentials } from "@distilled.cloud/hetzner";
2import * as Effect from "effect/Effect";
3import type * as HttpClient from "effect/http/HttpClient";
4import type { RuntimeContext } from "../RuntimeContext.ts";
5import type { Zone } from "./Zone.ts";
6
7/**
8 * Shared scaffolding for the HTTP-backed Hetzner DNS bindings.
9 *
10 * Hetzner Cloud tokens are project-scoped (`HCLOUD_TOKEN`) and issued
11 * read-write or read-only — there is no per-permission token API. This
12 * layer captures the ambient credentials available during stack-eval and
13 * builds a {@link DnsAuth} that provides them to distilled RRSet ops. The
14 * zone is fixed at `bind(zone)` time so callers never pass `id_or_name`.
15 *
16 * NOT exported from `index.ts`.
17 */
18export const makeHttpDnsBinding = <Client>(options: {
19 makeClient: (auth: DnsAuth, zoneId: Effect.Effect<number>) => Client;
20}) =>
21 Effect.gen(function* () {
22 const context = yield* Effect.context<
23 Credentials | HttpClient.HttpClient
24 >();
25
26 return Effect.fn(function* (zone: Zone) {
27 const zoneId = yield* zone.zoneId;
28 const auth: DnsAuth = {
29 authorize: (eff) => eff.pipe(Effect.provideContext(context)),
30 };
31 return options.makeClient(auth, zoneId);
32 });
33 });
34
35/**
36 * Injectable auth for the DNS HTTP client builders. Supplies an `authorize`
37 * that provides `Credentials` + `HttpClient` to a raw SDK op.
38 */
39export interface DnsAuth {
40 authorize: <A, E>(
41 eff: Effect.Effect<A, E, Credentials | HttpClient.HttpClient>,
42 ) => Effect.Effect<A, E, RuntimeContext>;
43}