@aoxborrow/registrar-client 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -871,6 +871,40 @@ declare const registrars: {
871
871
  type RegistrarName = keyof typeof registrars;
872
872
  declare function createRegistrar(name: RegistrarName, credentials: RegistrarCredentials, options?: RegistrarOptions): Registrar;
873
873
 
874
+ declare class DnsSyntaxError extends Error {
875
+ constructor(message: string);
876
+ }
877
+ interface DnsEntry {
878
+ owner: string;
879
+ kind: string;
880
+ ttl: number;
881
+ rdata: string;
882
+ }
883
+ interface RecordClash {
884
+ owner: string;
885
+ kind: string;
886
+ detail: string;
887
+ }
888
+ type NameRole = 'owner' | 'target';
889
+ type LabelMapper = (label: string) => string | null;
890
+ interface DelegationSigner {
891
+ keyTag: number;
892
+ algorithm: number;
893
+ digestType: number;
894
+ digest: string;
895
+ }
896
+ declare function useLabelMapper(mapper: LabelMapper): void;
897
+ declare function resetLabelMapper(): void;
898
+ declare function prepareName(input: string, role?: NameRole): string;
899
+ declare function isIpv4(text: string): boolean;
900
+ declare function isIpv6(text: string): boolean;
901
+ declare function readDelegationSigner(rdata: string): DelegationSigner;
902
+ declare function prepareRdata(kind: string, rdata: string, owner?: string): string;
903
+ declare function prepareEntry(entry: DnsEntry): DnsEntry;
904
+ declare function findCnameConflicts(entries: readonly DnsEntry[]): RecordClash[];
905
+ declare function findRepeatedRecords(entries: readonly DnsEntry[]): RecordClash[];
906
+ declare function toDnsEntry(record: DnsRecord, defaultTtl?: number): DnsEntry;
907
+
874
908
  declare function parseXml<T = unknown>(xml: string, options?: Partial<X2jOptions>): T;
875
909
  declare function ensureArray<T>(value: T | T[] | undefined | null): T[];
876
910
 
@@ -892,4 +926,4 @@ declare function normalizeNameservers(nameservers: unknown): string[];
892
926
  declare function createDomain(data?: DomainInput): Domain;
893
927
  declare function asRead<T extends RequestOptions>(opts?: T): T;
894
928
 
895
- export { ALL_FEATURES, AbortError, AuthenticationError, AuthorizationError, BaseRegistrar, CORE_FEATURES, CloudflareRegistrar, type ConfigField, ConfigurationError, ConnectionError, type ConnectionResult, ConsentRequiredError, type Contact, type ContactSet, DEFAULT_OPTIONS, type DnsRecord, type DnssecStatus, type Domain, Domain101Registrar, type DomainAvailability, type DomainForward, type DomainForwardType, type DomainInput, type DomainSource, type DsRecord, DynadotRegistrar, EXTENDED_FEATURES, type EmailForward, FEATURE_CALLS, Feature, type FeatureCall, GandiRegistrar, GoDaddyRegistrar, HttpClient, type HttpClientConfig, InvalidResponseError, type ListDomainsOptions, MASKED_FORWARD_UNSUPPORTED, NameBrightRegistrar, NameSiloRegistrar, NamecheapRegistrar, NamecomRegistrar, NotFoundError, NotImplementedError, type OperationResult, OutcomeUnknownError, ParsingError, PorkbunRegistrar, type PortfolioError, type PortfolioResult, REST_SAFE_METHODS, RateLimitError, type RegisterDomainInput, type Registrar, RegistrarClient, type RegistrarClientOptions, type RegistrarConstructor, type RegistrarCredentials, type RegistrarEnvironment, RegistrarError, type RegistrarFeature, type RegistrarName, type RegistrarOptions, type RegistrationConsent, type RequestConfig, type RequestIntent, type RequestOptions, RetryableRegistrarError, type SettableDomainForward, SpaceshipRegistrar, TimeoutError, type TldPricing, type TransferDomainInput, USER_AGENT, asRead, backoffDelay, createDomain, createRegistrar, ensureArray, filterDomains, isCoreFeature, listPortfolio, markNotSent, normalizeDomain, normalizeNameservers, parseDate, parseXml, registrars, requireConsent, selectBaseUrl, settableForwards, sleep, toRegistrarError, wasNotSent };
929
+ export { ALL_FEATURES, AbortError, AuthenticationError, AuthorizationError, BaseRegistrar, CORE_FEATURES, CloudflareRegistrar, type ConfigField, ConfigurationError, ConnectionError, type ConnectionResult, ConsentRequiredError, type Contact, type ContactSet, DEFAULT_OPTIONS, type DelegationSigner, type DnsEntry, type DnsRecord, DnsSyntaxError, type DnssecStatus, type Domain, Domain101Registrar, type DomainAvailability, type DomainForward, type DomainForwardType, type DomainInput, type DomainSource, type DsRecord, DynadotRegistrar, EXTENDED_FEATURES, type EmailForward, FEATURE_CALLS, Feature, type FeatureCall, GandiRegistrar, GoDaddyRegistrar, HttpClient, type HttpClientConfig, InvalidResponseError, type LabelMapper, type ListDomainsOptions, MASKED_FORWARD_UNSUPPORTED, NameBrightRegistrar, type NameRole, NameSiloRegistrar, NamecheapRegistrar, NamecomRegistrar, NotFoundError, NotImplementedError, type OperationResult, OutcomeUnknownError, ParsingError, PorkbunRegistrar, type PortfolioError, type PortfolioResult, REST_SAFE_METHODS, RateLimitError, type RecordClash, type RegisterDomainInput, type Registrar, RegistrarClient, type RegistrarClientOptions, type RegistrarConstructor, type RegistrarCredentials, type RegistrarEnvironment, RegistrarError, type RegistrarFeature, type RegistrarName, type RegistrarOptions, type RegistrationConsent, type RequestConfig, type RequestIntent, type RequestOptions, RetryableRegistrarError, type SettableDomainForward, SpaceshipRegistrar, TimeoutError, type TldPricing, type TransferDomainInput, USER_AGENT, asRead, backoffDelay, createDomain, createRegistrar, ensureArray, filterDomains, findCnameConflicts, findRepeatedRecords, isCoreFeature, isIpv4, isIpv6, listPortfolio, markNotSent, normalizeDomain, normalizeNameservers, parseDate, parseXml, prepareEntry, prepareName, prepareRdata, readDelegationSigner, registrars, requireConsent, resetLabelMapper, selectBaseUrl, settableForwards, sleep, toDnsEntry, toRegistrarError, useLabelMapper, wasNotSent };
package/dist/index.d.ts CHANGED
@@ -871,6 +871,40 @@ declare const registrars: {
871
871
  type RegistrarName = keyof typeof registrars;
872
872
  declare function createRegistrar(name: RegistrarName, credentials: RegistrarCredentials, options?: RegistrarOptions): Registrar;
873
873
 
874
+ declare class DnsSyntaxError extends Error {
875
+ constructor(message: string);
876
+ }
877
+ interface DnsEntry {
878
+ owner: string;
879
+ kind: string;
880
+ ttl: number;
881
+ rdata: string;
882
+ }
883
+ interface RecordClash {
884
+ owner: string;
885
+ kind: string;
886
+ detail: string;
887
+ }
888
+ type NameRole = 'owner' | 'target';
889
+ type LabelMapper = (label: string) => string | null;
890
+ interface DelegationSigner {
891
+ keyTag: number;
892
+ algorithm: number;
893
+ digestType: number;
894
+ digest: string;
895
+ }
896
+ declare function useLabelMapper(mapper: LabelMapper): void;
897
+ declare function resetLabelMapper(): void;
898
+ declare function prepareName(input: string, role?: NameRole): string;
899
+ declare function isIpv4(text: string): boolean;
900
+ declare function isIpv6(text: string): boolean;
901
+ declare function readDelegationSigner(rdata: string): DelegationSigner;
902
+ declare function prepareRdata(kind: string, rdata: string, owner?: string): string;
903
+ declare function prepareEntry(entry: DnsEntry): DnsEntry;
904
+ declare function findCnameConflicts(entries: readonly DnsEntry[]): RecordClash[];
905
+ declare function findRepeatedRecords(entries: readonly DnsEntry[]): RecordClash[];
906
+ declare function toDnsEntry(record: DnsRecord, defaultTtl?: number): DnsEntry;
907
+
874
908
  declare function parseXml<T = unknown>(xml: string, options?: Partial<X2jOptions>): T;
875
909
  declare function ensureArray<T>(value: T | T[] | undefined | null): T[];
876
910
 
@@ -892,4 +926,4 @@ declare function normalizeNameservers(nameservers: unknown): string[];
892
926
  declare function createDomain(data?: DomainInput): Domain;
893
927
  declare function asRead<T extends RequestOptions>(opts?: T): T;
894
928
 
895
- export { ALL_FEATURES, AbortError, AuthenticationError, AuthorizationError, BaseRegistrar, CORE_FEATURES, CloudflareRegistrar, type ConfigField, ConfigurationError, ConnectionError, type ConnectionResult, ConsentRequiredError, type Contact, type ContactSet, DEFAULT_OPTIONS, type DnsRecord, type DnssecStatus, type Domain, Domain101Registrar, type DomainAvailability, type DomainForward, type DomainForwardType, type DomainInput, type DomainSource, type DsRecord, DynadotRegistrar, EXTENDED_FEATURES, type EmailForward, FEATURE_CALLS, Feature, type FeatureCall, GandiRegistrar, GoDaddyRegistrar, HttpClient, type HttpClientConfig, InvalidResponseError, type ListDomainsOptions, MASKED_FORWARD_UNSUPPORTED, NameBrightRegistrar, NameSiloRegistrar, NamecheapRegistrar, NamecomRegistrar, NotFoundError, NotImplementedError, type OperationResult, OutcomeUnknownError, ParsingError, PorkbunRegistrar, type PortfolioError, type PortfolioResult, REST_SAFE_METHODS, RateLimitError, type RegisterDomainInput, type Registrar, RegistrarClient, type RegistrarClientOptions, type RegistrarConstructor, type RegistrarCredentials, type RegistrarEnvironment, RegistrarError, type RegistrarFeature, type RegistrarName, type RegistrarOptions, type RegistrationConsent, type RequestConfig, type RequestIntent, type RequestOptions, RetryableRegistrarError, type SettableDomainForward, SpaceshipRegistrar, TimeoutError, type TldPricing, type TransferDomainInput, USER_AGENT, asRead, backoffDelay, createDomain, createRegistrar, ensureArray, filterDomains, isCoreFeature, listPortfolio, markNotSent, normalizeDomain, normalizeNameservers, parseDate, parseXml, registrars, requireConsent, selectBaseUrl, settableForwards, sleep, toRegistrarError, wasNotSent };
929
+ export { ALL_FEATURES, AbortError, AuthenticationError, AuthorizationError, BaseRegistrar, CORE_FEATURES, CloudflareRegistrar, type ConfigField, ConfigurationError, ConnectionError, type ConnectionResult, ConsentRequiredError, type Contact, type ContactSet, DEFAULT_OPTIONS, type DelegationSigner, type DnsEntry, type DnsRecord, DnsSyntaxError, type DnssecStatus, type Domain, Domain101Registrar, type DomainAvailability, type DomainForward, type DomainForwardType, type DomainInput, type DomainSource, type DsRecord, DynadotRegistrar, EXTENDED_FEATURES, type EmailForward, FEATURE_CALLS, Feature, type FeatureCall, GandiRegistrar, GoDaddyRegistrar, HttpClient, type HttpClientConfig, InvalidResponseError, type LabelMapper, type ListDomainsOptions, MASKED_FORWARD_UNSUPPORTED, NameBrightRegistrar, type NameRole, NameSiloRegistrar, NamecheapRegistrar, NamecomRegistrar, NotFoundError, NotImplementedError, type OperationResult, OutcomeUnknownError, ParsingError, PorkbunRegistrar, type PortfolioError, type PortfolioResult, REST_SAFE_METHODS, RateLimitError, type RecordClash, type RegisterDomainInput, type Registrar, RegistrarClient, type RegistrarClientOptions, type RegistrarConstructor, type RegistrarCredentials, type RegistrarEnvironment, RegistrarError, type RegistrarFeature, type RegistrarName, type RegistrarOptions, type RegistrationConsent, type RequestConfig, type RequestIntent, type RequestOptions, RetryableRegistrarError, type SettableDomainForward, SpaceshipRegistrar, TimeoutError, type TldPricing, type TransferDomainInput, USER_AGENT, asRead, backoffDelay, createDomain, createRegistrar, ensureArray, filterDomains, findCnameConflicts, findRepeatedRecords, isCoreFeature, isIpv4, isIpv6, listPortfolio, markNotSent, normalizeDomain, normalizeNameservers, parseDate, parseXml, prepareEntry, prepareName, prepareRdata, readDelegationSigner, registrars, requireConsent, resetLabelMapper, selectBaseUrl, settableForwards, sleep, toDnsEntry, toRegistrarError, useLabelMapper, wasNotSent };
package/dist/index.js CHANGED
@@ -2236,20 +2236,32 @@ function fromRecord(raw) {
2236
2236
  if (raw.type === "MX") {
2237
2237
  const match = /^(\d+)\s+(.+)$/.exec(raw.value);
2238
2238
  if (!match) throw invalid("MX record");
2239
- return { ...common, value: match[2], priority: Number(match[1]) };
2239
+ return { ...common, value: canonicalValue("MX", match[2]), priority: Number(match[1]) };
2240
2240
  }
2241
2241
  if (raw.type === "SRV") {
2242
2242
  const match = /^(\d+)\s+(\d+)\s+(\d+)\s+(.+)$/.exec(raw.value);
2243
2243
  if (!match) throw invalid("SRV record");
2244
2244
  return {
2245
2245
  ...common,
2246
- value: match[4],
2246
+ value: canonicalValue("SRV", match[4]),
2247
2247
  priority: Number(match[1]),
2248
2248
  weight: Number(match[2]),
2249
2249
  port: Number(match[3])
2250
2250
  };
2251
2251
  }
2252
- return { ...common, value: raw.value };
2252
+ return { ...common, value: canonicalValue(raw.type, raw.value) };
2253
+ }
2254
+ function canonicalValue(type, value) {
2255
+ const kind = type.toUpperCase();
2256
+ if (kind === "TXT") return unquoteTxt(value);
2257
+ if (["CNAME", "NS", "MX", "SRV"].includes(kind))
2258
+ return value === "." ? "." : value.replace(/\.$/, "");
2259
+ return value;
2260
+ }
2261
+ function unquoteTxt(value) {
2262
+ const chunk = /"((?:[^"\\]|\\.)*)"/g;
2263
+ if (!/^\s*"(?:[^"\\]|\\.)*"(?:\s+"(?:[^"\\]|\\.)*")*\s*$/.test(value)) return value;
2264
+ return [...value.matchAll(chunk)].map((m) => m[1].replace(/\\(.)/g, "$1")).join("");
2253
2265
  }
2254
2266
  function recordSpec(record, domain, strict = true) {
2255
2267
  const type = record.type.toUpperCase();
@@ -2270,7 +2282,7 @@ function recordSpec(record, domain, strict = true) {
2270
2282
  if (!Number.isInteger(record.priority) || record.priority < 0 || record.priority > 65535)
2271
2283
  reject("MX/SRV priority is required");
2272
2284
  result.priority = record.priority;
2273
- result.target = record.value;
2285
+ result.target = canonicalValue(type, record.value);
2274
2286
  if (type === "SRV") {
2275
2287
  if (![record.weight, record.port].every((n) => Number.isInteger(n) && n >= 0 && n <= 65535))
2276
2288
  reject("SRV weight and port are required");
@@ -2287,7 +2299,7 @@ function recordSpec(record, domain, strict = true) {
2287
2299
  result.tag = match[2];
2288
2300
  result.value = match[3];
2289
2301
  }
2290
- } else result.value = record.value;
2302
+ } else result.value = canonicalValue(type, record.value);
2291
2303
  return result;
2292
2304
  }
2293
2305
  function recordSignature(record) {
@@ -4625,6 +4637,80 @@ function dnsFieldsDiffer(a, b) {
4625
4637
 
4626
4638
  // src/registrars/namebright.ts
4627
4639
  var TOKEN_URL = "https://api.namebright.com/auth/token";
4640
+ var NB_KEYS = new Map(
4641
+ [
4642
+ // domains
4643
+ "DomainName",
4644
+ "Status",
4645
+ "ExpirationDate",
4646
+ "RegistrationDate",
4647
+ "AutoRenew",
4648
+ "Locked",
4649
+ "WhoIsPrivacy",
4650
+ "AuthCode",
4651
+ "Category",
4652
+ "UpgradedDomain",
4653
+ "ResultsTotal",
4654
+ "CurrentPage",
4655
+ "Domains",
4656
+ "NameServers",
4657
+ // contacts
4658
+ "RegistrantContact",
4659
+ "AdministrativeContact",
4660
+ "TechnicalContact",
4661
+ "FirstName",
4662
+ "LastName",
4663
+ "Organization",
4664
+ "Department",
4665
+ "Email",
4666
+ "Address1",
4667
+ "Address2",
4668
+ "City",
4669
+ "Region",
4670
+ "Country",
4671
+ "PostalCode",
4672
+ "PhoneCountry",
4673
+ "Phone",
4674
+ "FaxCountry",
4675
+ "Fax",
4676
+ // host records
4677
+ "ARecords",
4678
+ "AAAARecords",
4679
+ "CNAMERecords",
4680
+ "MXRecords",
4681
+ "TXTRecords",
4682
+ "SRVRecords",
4683
+ "RecordId",
4684
+ "Subdomain",
4685
+ "IPV4Address",
4686
+ "IPV6Address",
4687
+ "RedirectDomain",
4688
+ "MailServer",
4689
+ "Priority",
4690
+ "TextRecord",
4691
+ "Service",
4692
+ "Protocol",
4693
+ "Weight",
4694
+ "Port",
4695
+ "Target",
4696
+ // availability + orders
4697
+ "ProductTypeName",
4698
+ "UnitPrice",
4699
+ "Promotion",
4700
+ "PromotionPrice",
4701
+ "Discount",
4702
+ "Description",
4703
+ "OrderId",
4704
+ "TotalPrice"
4705
+ ].map((k) => [k.toLowerCase(), k])
4706
+ );
4707
+ function canonicalKeys(value) {
4708
+ if (Array.isArray(value)) return value.map(canonicalKeys);
4709
+ if (value === null || typeof value !== "object") return value;
4710
+ return Object.fromEntries(
4711
+ Object.entries(value).map(([k, v]) => [NB_KEYS.get(k.toLowerCase()) ?? k, canonicalKeys(v)])
4712
+ );
4713
+ }
4628
4714
  var NameBrightRegistrar = class extends BaseRegistrar {
4629
4715
  name = "namebright";
4630
4716
  // a REST API: GET and HEAD never change state
@@ -4678,14 +4764,16 @@ var NameBrightRegistrar = class extends BaseRegistrar {
4678
4764
  this.tokenExpiresAt = now + ttlMs - 6e4;
4679
4765
  return this.token;
4680
4766
  }
4681
- // issue an authenticated REST request, attaching a fresh bearer token
4767
+ // issue an authenticated REST request, attaching a fresh bearer token. The
4768
+ // response's keys are normalized to PascalCase (see NB_KEYS).
4682
4769
  async authed(config, opts) {
4683
4770
  const token = await this.getToken(opts);
4684
- return this.http.request({
4771
+ const res = await this.http.request({
4685
4772
  ...config,
4686
4773
  headers: { Authorization: `Bearer ${token}` },
4687
4774
  ...opts
4688
4775
  });
4776
+ return canonicalKeys(res);
4689
4777
  }
4690
4778
  async testConnection(opts) {
4691
4779
  try {
@@ -4706,8 +4794,8 @@ var NameBrightRegistrar = class extends BaseRegistrar {
4706
4794
  { path: "account/domains", query: { page, domainsPerPage: perPage } },
4707
4795
  reqOpts
4708
4796
  );
4709
- const list = Array.isArray(data) ? data : data?.Domains ?? data?.domains ?? [];
4710
- for (const d of list) domains.push(this.toDomain(d));
4797
+ const list = Array.isArray(data) ? data : data?.Domains ?? [];
4798
+ for (const d of list) if (d.DomainName) domains.push(this.toDomain(d));
4711
4799
  hasMore = list.length === perPage;
4712
4800
  page++;
4713
4801
  }
@@ -4744,7 +4832,7 @@ var NameBrightRegistrar = class extends BaseRegistrar {
4744
4832
  opts
4745
4833
  );
4746
4834
  if (Array.isArray(res)) return res.map(String);
4747
- return (res.NameServers ?? res.Nameservers ?? res.nameservers ?? []).map(String);
4835
+ return (res.NameServers ?? []).map(String);
4748
4836
  }
4749
4837
  /**
4750
4838
  * Read the registrant/admin/tech contacts via GET
@@ -4881,10 +4969,10 @@ var NameBrightRegistrar = class extends BaseRegistrar {
4881
4969
  async setDomainFlag(domainName, change, successMessage, opts) {
4882
4970
  try {
4883
4971
  const path = `account/domains/${encodeURIComponent(domainName)}`;
4884
- const current = await this.authed(
4885
- { path },
4886
- opts
4887
- );
4972
+ const current = await this.authed({ path }, opts);
4973
+ if (!current.DomainName) {
4974
+ return { success: false, message: `NameBright: could not read ${domainName} to update it` };
4975
+ }
4888
4976
  const body = {
4889
4977
  DomainName: current.DomainName,
4890
4978
  Status: current.Status,
@@ -4961,7 +5049,7 @@ var NameBrightRegistrar = class extends BaseRegistrar {
4961
5049
  // normalized Domain shape. Neither endpoint returns nameservers.
4962
5050
  toDomain(d) {
4963
5051
  return createDomain({
4964
- domainName: d.DomainName ?? d.domain,
5052
+ domainName: d.DomainName,
4965
5053
  registrar: this.name,
4966
5054
  status: d.Status ?? "ok",
4967
5055
  createdDate: d.RegistrationDate,
@@ -8004,6 +8092,330 @@ function createRegistrar(name, credentials, options) {
8004
8092
  return new RegistrarClass(credentials, options);
8005
8093
  }
8006
8094
 
8007
- export { ALL_FEATURES, AbortError, AuthenticationError, AuthorizationError, BaseRegistrar, CORE_FEATURES, CloudflareRegistrar, ConfigurationError, ConnectionError, ConsentRequiredError, DEFAULT_OPTIONS, Domain101Registrar, DynadotRegistrar, EXTENDED_FEATURES, FEATURE_CALLS, Feature, GandiRegistrar, GoDaddyRegistrar, HttpClient, InvalidResponseError, MASKED_FORWARD_UNSUPPORTED, NameBrightRegistrar, NameSiloRegistrar, NamecheapRegistrar, NamecomRegistrar, NotFoundError, NotImplementedError, OutcomeUnknownError, ParsingError, PorkbunRegistrar, REST_SAFE_METHODS, RateLimitError, RegistrarClient, RegistrarError, RetryableRegistrarError, SpaceshipRegistrar, TimeoutError, USER_AGENT, asRead, backoffDelay, createDomain, createRegistrar, ensureArray, filterDomains, isCoreFeature, listPortfolio, markNotSent, normalizeDomain, normalizeNameservers, parseDate, parseXml, registrars, requireConsent, selectBaseUrl, settableForwards, sleep, toRegistrarError, wasNotSent };
8095
+ // src/dns-records.ts
8096
+ var DnsSyntaxError = class extends Error {
8097
+ constructor(message) {
8098
+ super(message);
8099
+ this.name = "DnsSyntaxError";
8100
+ }
8101
+ };
8102
+ var NAME_LIMIT = 253;
8103
+ var LABEL_LIMIT = 63;
8104
+ var TTL_LIMIT = 2147483647;
8105
+ var TEXT_OCTETS = 255;
8106
+ var TEXT_TOTAL_OCTETS = 65535 - Math.ceil(65535 / (TEXT_OCTETS + 1));
8107
+ var UINT16_MAX = 65535;
8108
+ var DIGEST_HEX_LENGTH = {
8109
+ 1: 40,
8110
+ 2: 64,
8111
+ 3: 64,
8112
+ 4: 96
8113
+ };
8114
+ var KINDS_ALLOWED_BESIDE_CNAME = /* @__PURE__ */ new Set(["CNAME", "RRSIG", "NSEC", "NSEC3"]);
8115
+ function mapAsciiLabel(label) {
8116
+ const folded = label.toLowerCase();
8117
+ if (folded.length < 1 || folded.length > LABEL_LIMIT) return null;
8118
+ if (!/^[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9_])?$/.test(folded)) return null;
8119
+ return folded;
8120
+ }
8121
+ var labelMapper = mapAsciiLabel;
8122
+ function useLabelMapper(mapper) {
8123
+ labelMapper = mapper;
8124
+ }
8125
+ function resetLabelMapper() {
8126
+ labelMapper = mapAsciiLabel;
8127
+ }
8128
+ function prepareName(input, role = "owner") {
8129
+ const trimmed = input.trim();
8130
+ if (!trimmed) throw new DnsSyntaxError("Name is empty");
8131
+ const bare = trimmed.endsWith(".") ? trimmed.slice(0, -1) : trimmed;
8132
+ if (!bare) throw new DnsSyntaxError("Name is empty");
8133
+ if (bare === "@") {
8134
+ if (role === "target") throw new DnsSyntaxError("Origin token @ cannot be a record target");
8135
+ return "@";
8136
+ }
8137
+ const labels = bare.split(".");
8138
+ if (labels.some((label) => label.length === 0)) {
8139
+ throw new DnsSyntaxError("Name contains an empty label");
8140
+ }
8141
+ const starLabels = labels.filter((label) => label.includes("*"));
8142
+ if (starLabels.length > 0) {
8143
+ if (role !== "owner") {
8144
+ throw new DnsSyntaxError("A wildcard is only valid as an owner name");
8145
+ }
8146
+ const starCount = starLabels.reduce(
8147
+ (count, label) => count + (label.match(/\*/g)?.length ?? 0),
8148
+ 0
8149
+ );
8150
+ if (starCount > 1) throw new DnsSyntaxError("A name can contain only one wildcard");
8151
+ if (labels[0] !== "*") throw new DnsSyntaxError("A wildcard must be its own leftmost label");
8152
+ }
8153
+ const mapped = labels.map((label) => {
8154
+ if (label === "*") return "*";
8155
+ const ascii = labelMapper(label);
8156
+ if (!ascii) throw new DnsSyntaxError(`Label is not a valid DNS label: ${label}`);
8157
+ return ascii.toLowerCase();
8158
+ });
8159
+ const name = mapped.join(".");
8160
+ if (name.length > NAME_LIMIT) throw new DnsSyntaxError("Name is longer than 253 characters");
8161
+ return name;
8162
+ }
8163
+ function isIpv4(text2) {
8164
+ const octets = text2.split(".");
8165
+ if (octets.length !== 4) return false;
8166
+ return octets.every((octet) => {
8167
+ if (!/^\d{1,3}$/.test(octet)) return false;
8168
+ const value = Number(octet);
8169
+ return value >= 0 && value <= 255 && String(value) === octet;
8170
+ });
8171
+ }
8172
+ function isIpv6(text2) {
8173
+ let body = text2;
8174
+ const embedded = text2.match(/^(.+):(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
8175
+ if (embedded) {
8176
+ if (!isIpv4(embedded[2])) return false;
8177
+ body = `${embedded[1]}:0:0`;
8178
+ }
8179
+ const compressedAt = body.indexOf("::");
8180
+ if (compressedAt !== -1) {
8181
+ if (body.indexOf("::", compressedAt + 1) !== -1) return false;
8182
+ const groupsOf = (side) => side === "" ? [] : side.split(":");
8183
+ const head = groupsOf(body.slice(0, compressedAt));
8184
+ const tail = groupsOf(body.slice(compressedAt + 2));
8185
+ if (head.length + tail.length > 7) return false;
8186
+ return [...head, ...tail].every((group) => /^[0-9a-fA-F]{1,4}$/.test(group));
8187
+ }
8188
+ const groups = body.split(":");
8189
+ return groups.length === 8 && groups.every((group) => /^[0-9a-fA-F]{1,4}$/.test(group));
8190
+ }
8191
+ function utf8OctetCount(text2) {
8192
+ let count = 0;
8193
+ for (const char of text2) {
8194
+ const code = char.codePointAt(0) ?? 0;
8195
+ if (code <= 127) count += 1;
8196
+ else if (code <= 2047) count += 2;
8197
+ else if (code <= 65535) count += 3;
8198
+ else count += 4;
8199
+ }
8200
+ return count;
8201
+ }
8202
+ function decimalInRange(token, limit) {
8203
+ if (!/^(0|[1-9][0-9]*)$/.test(token)) return null;
8204
+ const value = Number(token);
8205
+ if (value > limit) return null;
8206
+ return value;
8207
+ }
8208
+ function prepareIpv4(text2) {
8209
+ if (!isIpv4(text2)) throw new DnsSyntaxError("IPv4 address is invalid");
8210
+ return text2;
8211
+ }
8212
+ function prepareIpv6(text2) {
8213
+ if (!isIpv6(text2)) throw new DnsSyntaxError("IPv6 address is invalid");
8214
+ return text2.toLowerCase();
8215
+ }
8216
+ function prepareHostTarget(text2, owner, rejectSelf) {
8217
+ const withoutDot = text2.endsWith(".") ? text2.slice(0, -1) : text2;
8218
+ if (isIpv4(withoutDot) || isIpv6(withoutDot)) {
8219
+ throw new DnsSyntaxError("Target must be a domain name, not an address");
8220
+ }
8221
+ const target = prepareName(text2, "target");
8222
+ if (rejectSelf && owner !== void 0 && prepareName(owner, "owner") === target) {
8223
+ throw new DnsSyntaxError("CNAME target is the same name as its owner");
8224
+ }
8225
+ return target;
8226
+ }
8227
+ function prepareMailExchange(text2) {
8228
+ const parts = text2.split(/\s+/);
8229
+ if (parts.length !== 2) {
8230
+ throw new DnsSyntaxError('MX data must be "<priority> <mail host>"');
8231
+ }
8232
+ const priority = decimalInRange(parts[0], UINT16_MAX);
8233
+ if (priority === null) throw new DnsSyntaxError("MX priority must be an integer from 0 to 65535");
8234
+ return `${priority} ${prepareServiceHost(parts[1])}`;
8235
+ }
8236
+ function prepareServiceHost(text2) {
8237
+ return text2 === "." ? "." : prepareHostTarget(text2, void 0, false);
8238
+ }
8239
+ function prepareService(text2) {
8240
+ const parts = text2.split(/\s+/);
8241
+ if (parts.length !== 4) {
8242
+ throw new DnsSyntaxError('SRV data must be "<priority> <weight> <port> <target>"');
8243
+ }
8244
+ const [priority, weight, port] = parts.slice(0, 3).map((part) => decimalInRange(part, UINT16_MAX));
8245
+ if (priority === null)
8246
+ throw new DnsSyntaxError("SRV priority must be an integer from 0 to 65535");
8247
+ if (weight === null) throw new DnsSyntaxError("SRV weight must be an integer from 0 to 65535");
8248
+ if (port === null) throw new DnsSyntaxError("SRV port must be an integer from 0 to 65535");
8249
+ return `${priority} ${weight} ${port} ${prepareServiceHost(parts[3])}`;
8250
+ }
8251
+ function prepareAuthorization(text2) {
8252
+ const match = /^(\S+)\s+(\S+)\s+([\s\S]+)$/.exec(text2);
8253
+ if (!match) throw new DnsSyntaxError('CAA data must be "<flags> <tag> <value>"');
8254
+ const flags = decimalInRange(match[1], 255);
8255
+ if (flags === null) throw new DnsSyntaxError("CAA flags must be an integer from 0 to 255");
8256
+ if (!/^[a-z0-9]{1,15}$/i.test(match[2])) {
8257
+ throw new DnsSyntaxError("CAA tag must be 1 to 15 letters or digits");
8258
+ }
8259
+ const quoted = /^"((?:[^"\\]|\\.)*)"$/.exec(match[3]);
8260
+ const value = quoted ? quoted[1] : match[3];
8261
+ if (!quoted && value.includes('"')) {
8262
+ throw new DnsSyntaxError("CAA value must be one quoted or unquoted string");
8263
+ }
8264
+ return `${flags} ${match[2].toLowerCase()} "${value}"`;
8265
+ }
8266
+ function prepareText(text2) {
8267
+ if (utf8OctetCount(text2) > TEXT_TOTAL_OCTETS) {
8268
+ throw new DnsSyntaxError(`TXT data is longer than ${TEXT_TOTAL_OCTETS} octets`);
8269
+ }
8270
+ return text2;
8271
+ }
8272
+ function readSignerFields(text2) {
8273
+ const parts = text2.trim().split(/\s+/);
8274
+ if (parts.length !== 4)
8275
+ throw new DnsSyntaxError('DS data must be "<key tag> <algorithm> <digest type> <digest>"');
8276
+ const keyTag = decimalInRange(parts[0], UINT16_MAX);
8277
+ const algorithm = decimalInRange(parts[1], 255);
8278
+ const digestType = decimalInRange(parts[2], 255);
8279
+ if (keyTag === null || algorithm === null || digestType === null || !parts[3]) {
8280
+ throw new DnsSyntaxError('DS data must be "<key tag> <algorithm> <digest type> <digest>"');
8281
+ }
8282
+ const digest = parts[3].toLowerCase();
8283
+ if (!/^[0-9a-f]+$/.test(digest)) throw new DnsSyntaxError("DS digest must be hexadecimal");
8284
+ const expectedLength = DIGEST_HEX_LENGTH[digestType];
8285
+ if (expectedLength !== void 0 && digest.length !== expectedLength) {
8286
+ throw new DnsSyntaxError(
8287
+ `DS digest must be ${expectedLength} hex characters for digest type ${digestType}`
8288
+ );
8289
+ }
8290
+ return { keyTag, algorithm, digestType, digest };
8291
+ }
8292
+ function readDelegationSigner(rdata) {
8293
+ return readSignerFields(rdata);
8294
+ }
8295
+ function prepareSignerText(text2) {
8296
+ const signer = readSignerFields(text2);
8297
+ return `${signer.keyTag} ${signer.algorithm} ${signer.digestType} ${signer.digest}`;
8298
+ }
8299
+ function prepareRdata(kind, rdata, owner) {
8300
+ const token = kind.trim().toUpperCase();
8301
+ const text2 = rdata.trim();
8302
+ if (!text2) throw new DnsSyntaxError("Record data is empty");
8303
+ switch (token) {
8304
+ case "A":
8305
+ return prepareIpv4(text2);
8306
+ case "AAAA":
8307
+ return prepareIpv6(text2);
8308
+ case "CNAME":
8309
+ return prepareHostTarget(text2, owner, true);
8310
+ case "NS":
8311
+ return prepareHostTarget(text2, void 0, false);
8312
+ case "MX":
8313
+ return prepareMailExchange(text2);
8314
+ case "TXT":
8315
+ return prepareText(text2);
8316
+ case "SRV":
8317
+ return prepareService(text2);
8318
+ case "CAA":
8319
+ return prepareAuthorization(text2);
8320
+ case "DS":
8321
+ return prepareSignerText(text2);
8322
+ default:
8323
+ return text2;
8324
+ }
8325
+ }
8326
+ function prepareEntry(entry) {
8327
+ if (!Number.isInteger(entry.ttl) || entry.ttl < 0 || entry.ttl > TTL_LIMIT) {
8328
+ throw new DnsSyntaxError("TTL must be an integer from 0 to 2147483647");
8329
+ }
8330
+ const kind = entry.kind.trim().toUpperCase();
8331
+ if (!kind) throw new DnsSyntaxError("Record type is empty");
8332
+ return {
8333
+ owner: prepareName(entry.owner, "owner"),
8334
+ kind,
8335
+ ttl: entry.ttl,
8336
+ rdata: prepareRdata(kind, entry.rdata, entry.owner)
8337
+ };
8338
+ }
8339
+ function syntaxClash(entry, error) {
8340
+ const detail = error instanceof Error ? error.message : "Invalid record";
8341
+ return { owner: entry.owner, kind: entry.kind, detail };
8342
+ }
8343
+ function findCnameConflicts(entries) {
8344
+ const clashes = [];
8345
+ const byOwner = /* @__PURE__ */ new Map();
8346
+ for (const entry of entries) {
8347
+ let owner;
8348
+ let kind;
8349
+ try {
8350
+ owner = prepareName(entry.owner, "owner");
8351
+ kind = entry.kind.trim().toUpperCase();
8352
+ if (!kind) throw new DnsSyntaxError("Record type is empty");
8353
+ } catch (error) {
8354
+ clashes.push(syntaxClash(entry, error));
8355
+ continue;
8356
+ }
8357
+ const group = byOwner.get(owner) ?? [];
8358
+ group.push({ ...entry, owner, kind });
8359
+ byOwner.set(owner, group);
8360
+ }
8361
+ for (const [owner, group] of byOwner) {
8362
+ const aliasCount = group.filter((entry) => entry.kind === "CNAME").length;
8363
+ if (aliasCount === 0) continue;
8364
+ if (aliasCount > 1) {
8365
+ clashes.push({
8366
+ owner,
8367
+ kind: "CNAME",
8368
+ detail: "A name can have only one CNAME target"
8369
+ });
8370
+ }
8371
+ const others = [...new Set(group.map((entry) => entry.kind))].filter(
8372
+ (kind) => !KINDS_ALLOWED_BESIDE_CNAME.has(kind)
8373
+ );
8374
+ if (others.length > 0) {
8375
+ clashes.push({
8376
+ owner,
8377
+ kind: "CNAME",
8378
+ detail: `A CNAME cannot share a name with ${others.join(", ")}`
8379
+ });
8380
+ }
8381
+ }
8382
+ return clashes;
8383
+ }
8384
+ function findRepeatedRecords(entries) {
8385
+ const clashes = [];
8386
+ const seen = /* @__PURE__ */ new Set();
8387
+ for (const entry of entries) {
8388
+ let prepared;
8389
+ try {
8390
+ prepared = prepareEntry(entry);
8391
+ } catch (error) {
8392
+ clashes.push(syntaxClash(entry, error));
8393
+ continue;
8394
+ }
8395
+ if (prepared.kind === "CNAME") continue;
8396
+ const key = `${prepared.owner}\0${prepared.kind}\0${prepared.rdata}`;
8397
+ if (seen.has(key)) {
8398
+ clashes.push({
8399
+ owner: prepared.owner,
8400
+ kind: prepared.kind,
8401
+ detail: `Repeated ${prepared.kind} data at this name`
8402
+ });
8403
+ }
8404
+ seen.add(key);
8405
+ }
8406
+ return clashes;
8407
+ }
8408
+ function toDnsEntry(record, defaultTtl = 3600) {
8409
+ const kind = record.type.trim().toUpperCase();
8410
+ const numbers = kind === "MX" ? [record.priority] : kind === "SRV" ? [record.priority, record.weight, record.port] : [];
8411
+ return {
8412
+ owner: record.name,
8413
+ kind,
8414
+ ttl: record.ttl ?? defaultTtl,
8415
+ rdata: [...numbers.map((n) => n === void 0 ? "" : String(n)), record.value.trim()].join(" ")
8416
+ };
8417
+ }
8418
+
8419
+ export { ALL_FEATURES, AbortError, AuthenticationError, AuthorizationError, BaseRegistrar, CORE_FEATURES, CloudflareRegistrar, ConfigurationError, ConnectionError, ConsentRequiredError, DEFAULT_OPTIONS, DnsSyntaxError, Domain101Registrar, DynadotRegistrar, EXTENDED_FEATURES, FEATURE_CALLS, Feature, GandiRegistrar, GoDaddyRegistrar, HttpClient, InvalidResponseError, MASKED_FORWARD_UNSUPPORTED, NameBrightRegistrar, NameSiloRegistrar, NamecheapRegistrar, NamecomRegistrar, NotFoundError, NotImplementedError, OutcomeUnknownError, ParsingError, PorkbunRegistrar, REST_SAFE_METHODS, RateLimitError, RegistrarClient, RegistrarError, RetryableRegistrarError, SpaceshipRegistrar, TimeoutError, USER_AGENT, asRead, backoffDelay, createDomain, createRegistrar, ensureArray, filterDomains, findCnameConflicts, findRepeatedRecords, isCoreFeature, isIpv4, isIpv6, listPortfolio, markNotSent, normalizeDomain, normalizeNameservers, parseDate, parseXml, prepareEntry, prepareName, prepareRdata, readDelegationSigner, registrars, requireConsent, resetLabelMapper, selectBaseUrl, settableForwards, sleep, toDnsEntry, toRegistrarError, useLabelMapper, wasNotSent };
8008
8420
  //# sourceMappingURL=index.js.map
8009
8421
  //# sourceMappingURL=index.js.map