Skip to content

2.0.0-beta.49 - DNS Bindings & Output.flatMap

v2.0.0-beta.49 ships runtime DNS record bindings, a new Output.flatMap combinator, and the secret_text fix above.

Same ergonomics as the Tunnel bindings from beta.48: bind a Zone once in Init, and a Worker can manage that zone’s DNS records at runtime through a typed client. Calls take no zoneId — the bound zone fixes it.

const Zone = Cloudflare.Zone("MyZone", { name: "example.com" });
export class DnsWorker extends Cloudflare.Worker<DnsWorker>()(
"DnsWorker",
{ main: import.meta.filename },
Effect.gen(function* () {
// bind the Zone (it's an Effect) — or `yield* Zone` first
const dns = yield* Cloudflare.DnsReadWrite.bind(Zone);
return {
fetch: Effect.gen(function* () {
const { result } = yield* dns.createDnsRecord({
type: "A",
name: "app.example.com",
content: "192.0.2.1",
ttl: 1,
});
yield* dns.deleteDnsRecord(result.id);
return yield* HttpServerResponse.json({ id: result.id });
}),
};
}).pipe(Effect.provide(Cloudflare.DnsReadWriteLive)),
) {}

Pick the surface you need:

  • Cloudflare.DnsReadgetDnsRecord, listDnsRecords
  • Cloudflare.DnsWritecreateDnsRecord, updateDnsRecord, patchDnsRecord, deleteDnsRecord, batchDnsRecords
  • Cloudflare.DnsReadWrite — the full record CRUD surface

(#511)

Output.flatMap resolves an Output<A>, hands the value to f, and flattens the Output<B> that f returns — the missing piece alongside Output.map and Output.mapEffect:

const expr = zone.zoneId.pipe(
Output.flatMap((zoneId) =>
Output.interpolate`com.cloudflare.api.account.zone.${zoneId}`,
),
);

The combinators are now also callable as methods directly on an Output, with apply/effect kept as aliases:

output.map(fn); // ApplyExpr
output.mapEffect(fn); // EffectExpr
output.flatMap(fn); // FlatMapExpr

Like the other combinators, flatMap short-circuits while its source is unresolved, so it composes cleanly in the deploy graph. (#512)

Two related changes land the fix:

  • Yielded Config always binds as secret_text — the Worker now records every Config resolved in Init as a secret binding, so a value can’t slip through as plain text (#510).
  • Don’t unwrap non-redacted values — when reading a bound value back at runtime, Alchemy now only calls Redacted.value on values that are actually Redacted, leaving plain values untouched.