/** * Host name resolution, DNS queries, and DNS record values. * * `lookup` resolves a host name to the addresses used to connect to it, * `resolve` queries DNS records of one type, and `reverse` looks up the names * of an address. Runtime packages provide the `Dns` service from the host * platform's resolver, whose `lookup` uses the operating system resolver * (`getaddrinfo`) and therefore also reads the hosts file and other system * sources, not only DNS. `AddressResolver` builds on `lookup` to resolve * `host:port` endpoints. * * @stability experimental * @since 4.0.0 */ import * as Arr from "../Array.ts"; import * as Context from "../Context.ts"; import * as Duration from "../Duration.ts"; import * as Effect from "../Effect.ts"; import * as Equal from "../Equal.ts"; import * as Hash from "../Hash.ts"; import * as Inspectable from "../Inspectable.ts"; import * as Layer from "../Layer.ts"; import type { ReadonlyRecord } from "../Record.ts"; import * as Result from "../Result.ts"; import * as Host from "./Host.ts"; import * as NetAddress from "./NetAddress.ts"; declare const RecordTypeId: "~effect/net/Dns/DnsRecord"; interface RecordProto extends Equal.Equal, Hash.Hash, Inspectable.Inspectable { readonly _tag: Tag; readonly [RecordTypeId]: typeof RecordTypeId; } /** * An IPv4 address record. * * @stability experimental * @category models * @since 4.0.0 */ export interface A extends RecordProto<"A"> { readonly address: NetAddress.Ipv4Address; } /** * An IPv6 address record. * * @stability experimental * @category models * @since 4.0.0 */ export interface Aaaa extends RecordProto<"AAAA"> { readonly address: NetAddress.Ipv6Address; } /** * A certification authority authorization record. * * @stability experimental * @category models * @since 4.0.0 */ export interface Caa extends RecordProto<"CAA"> { readonly critical: boolean; readonly tag: string; readonly value: string; } /** * A canonical name (alias) record. * * @stability experimental * @category models * @since 4.0.0 */ export interface Cname extends RecordProto<"CNAME"> { readonly target: Host.DomainName; } /** * A mail exchange record. * * @stability experimental * @category models * @since 4.0.0 */ export interface Mx extends RecordProto<"MX"> { readonly exchange: Host.DomainName; readonly priority: number; } /** * A naming authority pointer record. * * @stability experimental * @category models * @since 4.0.0 */ export interface Naptr extends RecordProto<"NAPTR"> { readonly order: number; readonly preference: number; readonly flags: string; readonly service: string; readonly regexp: string; readonly replacement: Host.DomainName; } /** * A name server record. * * @stability experimental * @category models * @since 4.0.0 */ export interface Ns extends RecordProto<"NS"> { readonly host: Host.DomainName; } /** * A pointer record, used for reverse lookups and DNS service discovery. * * **Details** * * `host` is a fully qualified name. It is a host name for reverse lookups, * but may be a DNS-SD service instance name containing spaces or other * characters, such as `EPSON TM-m30III._ipp._tcp.local.`. Labels are UTF-8 * text, with dots and backslashes inside a label escaped as `\.` and `\\`. * * @stability experimental * @category models * @since 4.0.0 */ export interface Ptr extends RecordProto<"PTR"> { readonly host: string; } /** * A start of authority record. * * **Details** * * `admin` is the administrator mailbox written as a domain name, such as * `hostmaster.example.com`. A dot inside the mailbox's local part is escaped, * as in `john\.doe.example.com`, so `admin` is a plain string rather than a * `Host.DomainName`. Labels are UTF-8 text, with dots and backslashes inside * a label escaped as `\.` and `\\`. * * @stability experimental * @category models * @since 4.0.0 */ export interface Soa extends RecordProto<"SOA"> { readonly primary: Host.DomainName; readonly admin: string; readonly serial: number; readonly refresh: Duration.Duration; readonly retry: Duration.Duration; readonly expire: Duration.Duration; readonly minimum: Duration.Duration; } /** * A service location record. * * @stability experimental * @category models * @since 4.0.0 */ export interface Srv extends RecordProto<"SRV"> { readonly target: Host.DomainName; readonly port: number; readonly priority: number; readonly weight: number; } /** * A TLS authentication record (RFC 6698), which pins the certificate or public * key that a TLS service presents, for DNS-Based Authentication of Named * Entities (DANE). Records are published at a name made of the service's port * and protocol, such as `_443._tcp.example.com`. * * **Details** * * `certUsage` says how the record constrains the certificate chain (0 to 3: * PKIX-TA, PKIX-EE, DANE-TA, DANE-EE), `selector` whether `data` matches the * full certificate (0) or its public key (1), and `matchingType` whether * `data` holds the selected content itself (0) or its SHA-256 (1) or SHA-512 * (2) digest. Unassigned values are kept as they are. * * **Gotchas** * * `data` is a copy of the bytes the record was made from, but typed arrays * cannot be frozen; treat it as read-only, because changing it changes the * record's equality. * * @stability experimental * @category models * @since 4.0.0 */ export interface Tlsa extends RecordProto<"TLSA"> { readonly certUsage: number; readonly selector: number; readonly matchingType: number; readonly data: Uint8Array; } /** * A text record. DNS stores text as one or more character strings, which are * kept as separate chunks; protocols such as SPF read them joined, for example * with `record.chunks.join("")`. * * **Details** * * Platform services decode each character string as UTF-8, replacing bytes * that are not valid UTF-8 with U+FFFD, and `formatRecord` writes chunks back * as UTF-8 bytes. * * @stability experimental * @category models * @since 4.0.0 */ export interface Txt extends RecordProto<"TXT"> { readonly chunks: Arr.NonEmptyReadonlyArray; } /** * Any supported DNS record value. * * **Details** * * Records are immutable values tagged by record type, compared and hashed by * their fields. They hold the record data only: owner names and TTLs are not * included because platform resolvers do not report them consistently. Names * returned by platform services are fully qualified and end with a dot, so * passing them back to the resolver does not apply search domains. * * @stability experimental * @category models * @since 4.0.0 */ export type DnsRecord = A | Aaaa | Caa | Cname | Mx | Naptr | Ns | Ptr | Soa | Srv | Tlsa | Txt; /** * The type of a DNS record, such as `"A"` or `"SRV"`. * * @stability experimental * @category models * @since 4.0.0 */ export type RecordType = "A" | "AAAA" | "CAA" | "CNAME" | "MX" | "NAPTR" | "NS" | "PTR" | "SOA" | "SRV" | "TLSA" | "TXT"; /** * The record value for a record type. * * @stability experimental * @category models * @since 4.0.0 */ export type RecordFor = Extract; /** * The fields of a record type, without its `_tag`. * * @see {@link makeRecord} * @stability experimental * @category models * @since 4.0.0 */ export type RecordFields = T extends RecordType ? Omit, keyof RecordProto> : never; /** * Every supported record type. * * @stability experimental * @category constants * @since 4.0.0 */ export declare const recordTypes: Arr.NonEmptyReadonlyArray; /** * Returns `true` when a value is a supported record type. * * @stability experimental * @category guards * @since 4.0.0 */ export declare const isRecordType: (u: unknown) => u is RecordType; /** * Returns `true` when a value is a DNS record. * * @stability experimental * @category guards * @since 4.0.0 */ export declare const isDnsRecord: (u: unknown) => u is DnsRecord; /** * Creates a checked DNS record of a record type from its fields. * * **Details** * * Every field is checked at runtime: addresses must belong to the record's * address family, names must be normalized domain names, priorities, weights, * and ports must be 16-bit unsigned integers, the SOA serial and timers must be * 32-bit unsigned integers (the timers in whole seconds), the TLSA fields must * be 8-bit unsigned integers with non-empty `data`, which is copied, TXT * records need at least one chunk, and CAA property tags must be alphanumeric. * Fields that do not belong to the record type are ignored. * * **Example** (Creating a service record) * * ```ts import.meta.vitest * import { Result } from "effect" * import { Dns, Host } from "effect/net" * * const record = Result.getOrThrow(Dns.makeRecord("SRV", { * target: Host.domainNameFromStringUnsafe("db.internal"), * port: 5432, * priority: 10, * weight: 5 * })) * Dns.formatRecord(record) // => "SRV 10 5 5432 db.internal" * ``` * * @stability experimental * @category constructors * @since 4.0.0 */ export declare const makeRecord: (type: T, fields: RecordFields) => Result.Result, NetAddress.NetAddressError>; /** * Creates a trusted DNS record of a record type from its fields, throwing on * failure. * * @stability experimental * @category unsafe * @since 4.0.0 */ export declare const makeRecordUnsafe: (type: T, fields: RecordFields) => RecordFor; /** * Formats a record in DNS presentation format, prefixed by its type. * * @stability experimental * @category encoding * @since 4.0.0 */ export declare const formatRecord: (self: DnsRecord) => string; /** * Returns the reverse-lookup domain name for an IP address, in `in-addr.arpa` * for IPv4 or `ip6.arpa` for IPv6. * * **Example** (Building reverse-lookup names) * * ```ts import.meta.vitest * import { Dns, NetAddress } from "effect/net" * * Dns.reverseName(NetAddress.ipFromStringUnsafe("192.0.2.1")) // => "1.2.0.192.in-addr.arpa" * ``` * * @stability experimental * @category converting * @since 4.0.0 */ export declare const reverseName: (address: NetAddress.IpAddress) => Host.DomainName; /** * Parses the address of a name server: an IP address, which uses port 53, or * an IP address and port. * * **Details** * * IPv6 addresses with a port are written in brackets, and IPv6 addresses * without one are not. * * **Example** (Parsing name server addresses) * * ```ts import.meta.vitest * import { Result } from "effect" * import { Dns, NetAddress } from "effect/net" * * const format = (input: string) => Result.map(Dns.nameServerFromString(input), NetAddress.formatInet) * * format("192.0.2.53") // => Result.succeed("192.0.2.53:53") * format("2001:db8::53") // => Result.succeed("[2001:db8::53]:53") * format("[2001:db8::53]:5353") // => Result.succeed("[2001:db8::53]:5353") * Result.isFailure(format("ns.example")) // => true * ``` * * @stability experimental * @category decoding * @since 4.0.0 */ export declare const nameServerFromString: (input: string) => Result.Result; /** * Converts a name server to the internet address to query. Strings are parsed * like `nameServerFromString`, internet addresses and address parts with a * port are converted like `NetAddress.inetAddressFromInput`, and other IP * address inputs are converted like `NetAddress.ipFromInput` and use port 53. * * @stability experimental * @category constructors * @since 4.0.0 */ export declare const nameServerFromInput: (input: NetAddress.IpAddressInput | NetAddress.InetAddressInput) => Result.Result; /** * The normalized reason for a failed name resolution. * * **Details** * * - `NotFound`: no records were found, either because the name does not exist * or because it has no records of the requested type or address family. * Like Go's `DNSError.IsNotFound`, the two cases are not distinguished * because not every platform resolver can tell them apart. * - `Timeout`, `Temporary`, and `ServerFailure`: transient failures that may * succeed when retried. * - `Refused`: the server refused the query or could not be reached. * - `BadName`: the name was rejected as malformed. * - `InvalidResponse`: the platform returned data that could not be converted * into record values. * - `Unsupported`: the platform does not support the operation or record type. * * @stability experimental * @category errors * @since 4.0.0 */ export type DnsErrorReason = "NotFound" | "Timeout" | "Temporary" | "Refused" | "ServerFailure" | "BadName" | "InvalidResponse" | "Unsupported" | "Unknown"; declare const DnsError_base: new = {}>(args: import("../Types.ts").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("../Cause.ts").YieldableError & { readonly _tag: "DnsError"; } & Readonly; /** * A failed lookup, query, or reverse lookup. * * @stability experimental * @category errors * @since 4.0.0 */ export declare class DnsError extends DnsError_base<{ readonly reason: DnsErrorReason; readonly method: "lookup" | "resolve" | "reverse"; readonly hostname: string; readonly recordType?: RecordType | undefined; readonly cause?: unknown; }> { /** * Formats the reason, operation, and name of the failed resolution. * * @since 4.0.0 */ get message(): string; /** * Whether the failure is transient and the operation may succeed if retried. * * @since 4.0.0 */ get isTemporary(): boolean; } /** * Options for address lookups. Without a `family`, addresses of both families * are returned. * * @stability experimental * @category models * @since 4.0.0 */ export interface LookupOptions { readonly family?: NetAddress.IpFamily | undefined; } declare const Dns_base: Context.ServiceClass(host: Host.DomainNameInput, options: { readonly family: F; }): Effect.Effect>, DnsError>; lookup(host: Host.DomainNameInput, options?: LookupOptions): Effect.Effect, DnsError>; /** * Queries the DNS records of one type for a name. * Names are parsed and normalized; invalid names fail with `BadName`. */ resolve(name: Host.DomainNameInput, type: T): Effect.Effect>, DnsError>; /** * Looks up the host names of an address with a reverse DNS query. * * **Details** * * Addresses given as strings are parsed; invalid addresses fail with * `BadName`. Names that are not valid host names are skipped, including * names with non-ASCII labels, which are not converted to their ASCII * (`xn--`) form because that form is a different DNS name. When every * returned name is skipped, the lookup fails with `InvalidResponse`. */ reverse(address: NetAddress.IpAddressInput): Effect.Effect, DnsError>; }>; /** * Service that resolves names to addresses, queries DNS records, and looks up * the names of addresses. * * **Details** * * Every operation either returns at least one result or fails with a * {@link DnsError}. * * @stability experimental * @category services * @since 4.0.0 */ export declare class Dns extends Dns_base { } /** * Creates a `Dns` service from platform resolver operations. * * **Details** * * Lookup and query names are parsed and normalized, and reverse lookup * addresses are parsed, before platform callbacks receive them. Invalid names * and addresses fail with `BadName`. * * The constructor filters lookups by the requested address family, keeps only * records of the requested type, removes duplicates, and turns empty results * into `NotFound` failures. `reverse` receives the names of an address and * keeps those that are valid host names, failing with `InvalidResponse` when * there are names but none is valid. Without a `reverse` operation, the names * are those of the PTR records at the address's `reverseName`, and failures of * that query are reported as failures of `reverse`. * * Only `lookup` is required. Platforms that can resolve addresses but cannot * query records, such as browsers, omit `resolve`; record queries, and reverse * lookups without a `reverse` operation, then fail with `Unsupported`. * * @stability experimental * @category constructors * @since 4.0.0 */ export declare const make: (impl: { readonly lookup: (host: Host.DomainName, family: NetAddress.IpFamily | undefined) => Effect.Effect, DnsError>; readonly resolve?: ((name: Host.DomainName, type: RecordType) => Effect.Effect, DnsError>) | undefined; readonly reverse?: ((address: NetAddress.IpAddress) => Effect.Effect, DnsError>) | undefined; }) => Dns["Service"]; /** * Fixed names, addresses, and records for a static resolver. * * **Details** * * `hosts` works like a hosts file: its entries are used by `lookup` and * `reverse`, but not by `resolve`. `records` holds DNS records by owner name and * is used by all three operations. Names are normalized like * `Host.domainNameFromString`, and a trailing dot is ignored. Addresses are * converted like `NetAddress.ipFromInput`. * * @stability experimental * @category models * @since 4.0.0 */ export interface StaticZone { readonly hosts?: ReadonlyRecord> | undefined; readonly records?: ReadonlyRecord> | undefined; } /** * Creates a `Dns` service that answers from fixed data. * * **When to use** * * Use to test code that depends on `Dns`, or to provide fixed names on * platforms without a resolver. * * **Details** * * Names without matching addresses or records fail with `NotFound`. CNAME * records are returned by `CNAME` queries but are not followed. * * **Example** (Looking up a name with a static resolver) * * ```ts import.meta.vitest * import { Effect, Result } from "effect" * import { Dns, NetAddress } from "effect/net" * * const dns = Result.getOrThrow(Dns.makeStatic({ * hosts: { "db.internal": ["10.0.0.5"] } * })) * * const program = dns.lookup("db.internal").pipe( * Effect.map((addresses) => addresses.map(NetAddress.formatIp)) * ) * * await Effect.runPromise(program) // => ["10.0.0.5"] * ``` * * @see {@link layerStatic} * @stability experimental * @category constructors * @since 4.0.0 */ export declare const makeStatic: (zone: StaticZone) => Result.Result; /** * Creates a layer that provides a `Dns` service answering from fixed data. * * @see {@link makeStatic} for the resolution rules * @stability experimental * @category layers * @since 4.0.0 */ export declare const layerStatic: (zone: StaticZone) => Layer.Layer; export {}; //# sourceMappingURL=Dns.d.ts.map