@aoxborrow/registrar-client 0.5.0 → 0.6.0

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.js CHANGED
@@ -1026,8 +1026,8 @@ var CloudflareRegistrar = class _CloudflareRegistrar extends BaseRegistrar {
1026
1026
  available: c?.registrable ?? false
1027
1027
  };
1028
1028
  if (c?.tier) availability.premium = c.tier === "premium";
1029
- const price = toPrice(c?.pricing?.registration_cost);
1030
- if (price != null) availability.price = price;
1029
+ const price2 = toPrice(c?.pricing?.registration_cost);
1030
+ if (price2 != null) availability.price = price2;
1031
1031
  if (c?.pricing?.currency) availability.currency = c.pricing.currency;
1032
1032
  return availability;
1033
1033
  });
@@ -1789,14 +1789,14 @@ ${bodyStr}`;
1789
1789
  opts
1790
1790
  );
1791
1791
  for (const r of data.domain_result_list ?? []) {
1792
- const price = oneYearPrice(r.price_list);
1792
+ const price2 = oneYearPrice(r.price_list);
1793
1793
  results.push({
1794
1794
  domainName: r.domain_name ?? "",
1795
1795
  available: r.available === "Yes",
1796
1796
  premium: r.premium != null ? r.premium.toLowerCase() === "yes" : void 0,
1797
- price: price?.registration,
1798
- currency: price?.currency,
1799
- period: price ? 1 : void 0
1797
+ price: price2?.registration,
1798
+ currency: price2?.currency,
1799
+ period: price2 ? 1 : void 0
1800
1800
  });
1801
1801
  }
1802
1802
  }
@@ -1833,13 +1833,13 @@ ${bodyStr}`;
1833
1833
  opts
1834
1834
  );
1835
1835
  const result = (data.domain_result_list ?? [])[0];
1836
- const price = oneYearPrice(result?.price_list);
1836
+ const price2 = oneYearPrice(result?.price_list);
1837
1837
  return {
1838
1838
  tld,
1839
- currency: price?.currency ?? "USD",
1840
- registration: price?.registration,
1841
- renewal: price?.renewal,
1842
- transfer: price?.transfer
1839
+ currency: price2?.currency ?? "USD",
1840
+ registration: price2?.registration,
1841
+ renewal: price2?.renewal,
1842
+ transfer: price2?.transfer
1843
1843
  };
1844
1844
  }
1845
1845
  /**
@@ -2555,17 +2555,17 @@ var GandiRegistrar = class extends BaseRegistrar {
2555
2555
  const products = resp.products ?? [];
2556
2556
  const product = products.find((p) => p.process === "create") ?? products[0];
2557
2557
  const status = product?.status ?? "";
2558
- const price = product?.prices?.[0];
2558
+ const price2 = product?.prices?.[0];
2559
2559
  const result = {
2560
2560
  domainName: product?.name ?? domainName,
2561
2561
  available: status.startsWith("available"),
2562
- premium: status.includes("premium") || price?.type === "premium"
2562
+ premium: status.includes("premium") || price2?.type === "premium"
2563
2563
  };
2564
- const amount = pickPrice(price);
2564
+ const amount = pickPrice(price2);
2565
2565
  if (amount != null) result.price = amount;
2566
2566
  if (resp.currency) result.currency = resp.currency;
2567
- if (price?.duration_unit === "y" && price.min_duration != null) {
2568
- result.period = price.min_duration;
2567
+ if (price2?.duration_unit === "y" && price2.min_duration != null) {
2568
+ result.period = price2.min_duration;
2569
2569
  }
2570
2570
  results.push(result);
2571
2571
  }
@@ -3003,9 +3003,9 @@ function fromGandiContact(c) {
3003
3003
  country: c.country ?? ""
3004
3004
  };
3005
3005
  }
3006
- function pickPrice(price) {
3007
- if (!price) return void 0;
3008
- const value = price.price_after_taxes ?? price.price_before_taxes;
3006
+ function pickPrice(price2) {
3007
+ if (!price2) return void 0;
3008
+ const value = price2.price_after_taxes ?? price2.price_before_taxes;
3009
3009
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
3010
3010
  }
3011
3011
  function parseDsRecord(ds) {
@@ -4089,13 +4089,13 @@ var NameBrightRegistrar = class extends BaseRegistrar {
4089
4089
  { path: `purchase/availability/${encodeURIComponent(domainName)}` },
4090
4090
  opts
4091
4091
  );
4092
- const price = res.Promotion?.PromotionPrice ?? res.UnitPrice;
4092
+ const price2 = res.Promotion?.PromotionPrice ?? res.UnitPrice;
4093
4093
  const result = {
4094
4094
  domainName: res.DomainName ?? domainName,
4095
4095
  available: res.Status === "AvailableForRegistration"
4096
4096
  };
4097
- if (typeof price === "number" && Number.isFinite(price) && price > 0) {
4098
- result.price = price;
4097
+ if (typeof price2 === "number" && Number.isFinite(price2) && price2 > 0) {
4098
+ result.price = price2;
4099
4099
  result.currency = "USD";
4100
4100
  }
4101
4101
  results.push(result);
@@ -4928,9 +4928,9 @@ function splitDomain(domain) {
4928
4928
  const dot = domain.indexOf(".");
4929
4929
  return dot === -1 ? { sld: domain, tld: "" } : { sld: domain.slice(0, dot), tld: domain.slice(dot + 1) };
4930
4930
  }
4931
- function toPrice2(price) {
4932
- if (!price?.["@_Price"]) return void 0;
4933
- const n = Number(price["@_Price"]);
4931
+ function toPrice2(price2) {
4932
+ if (!price2?.["@_Price"]) return void 0;
4933
+ const n = Number(price2["@_Price"]);
4934
4934
  return Number.isFinite(n) ? n : void 0;
4935
4935
  }
4936
4936
  function fromNcContact(c) {
@@ -4969,6 +4969,501 @@ function toNcContactParams(prefix, c) {
4969
4969
  return params;
4970
4970
  }
4971
4971
 
4972
+ // src/registrars/namecom.ts
4973
+ var NamecomHttpClient = class extends HttpClient {
4974
+ async request(req) {
4975
+ try {
4976
+ return await super.request(req);
4977
+ } catch (error) {
4978
+ if (error instanceof ParsingError) throw new ParsingError("namecom: invalid JSON response");
4979
+ if (error instanceof ConnectionError)
4980
+ throw new ConnectionError("namecom: network request failed");
4981
+ throw error;
4982
+ }
4983
+ }
4984
+ async toStatusError(response, url) {
4985
+ await response.body?.cancel().catch(() => void 0);
4986
+ const error = await super.toStatusError(
4987
+ new Response(null, {
4988
+ status: response.status,
4989
+ headers: response.headers
4990
+ }),
4991
+ url
4992
+ );
4993
+ if (error instanceof RateLimitError) {
4994
+ const retryAfter = response.headers.get("retry-after");
4995
+ const seconds = retryAfter == null ? NaN : Number(retryAfter);
4996
+ const date = retryAfter == null ? NaN : Date.parse(retryAfter);
4997
+ const reset = response.headers.get("x-ratelimit-reset");
4998
+ error.retryAfter = Number.isFinite(seconds) ? Math.max(0, seconds) : Number.isFinite(date) ? Math.max(0, (date - Date.now()) / 1e3) : reset != null && Number.isFinite(Number(reset)) ? Math.max(0, Number(reset) - Date.now() / 1e3) : void 0;
4999
+ }
5000
+ return error;
5001
+ }
5002
+ };
5003
+ var NamecomRegistrar = class extends BaseRegistrar {
5004
+ name = "namecom";
5005
+ static displayName = "Name.com";
5006
+ static website = "name.com";
5007
+ static supportsSandbox = true;
5008
+ static configFields = [
5009
+ { name: "username", label: "Username", type: "text", required: true },
5010
+ { name: "apiToken", label: "API token", type: "password", required: true }
5011
+ ];
5012
+ static helpText = "Get an API token at https://www.name.com/account/settings/api. Accounts with 2FA must enable API Access. Sandbox requires your -test username and a separate sandbox token; select the sandbox environment explicitly.";
5013
+ static extendedFeatures = [Feature.GetAuthCode];
5014
+ requiresNameserversFetch = false;
5015
+ constructor(credentials, options) {
5016
+ const username = credentials.username ?? "";
5017
+ if (username.includes(":"))
5018
+ throw new ConfigurationError("namecom: username cannot contain a colon");
5019
+ const auth = btoa(
5020
+ Array.from(
5021
+ new TextEncoder().encode(`${username}:${credentials.apiToken ?? ""}`),
5022
+ (byte) => String.fromCharCode(byte)
5023
+ ).join("")
5024
+ );
5025
+ const config = {
5026
+ baseUrl: selectBaseUrl("namecom", options?.environment, {
5027
+ production: "https://api.name.com/core/v1",
5028
+ sandbox: "https://api.dev.name.com/core/v1"
5029
+ }),
5030
+ headers: { Authorization: `Basic ${auth}` }
5031
+ };
5032
+ super(credentials, config, options);
5033
+ this.http = new NamecomHttpClient({ ...config, options: this.options });
5034
+ }
5035
+ async testConnection(opts) {
5036
+ try {
5037
+ await this.http.request({ path: "/domains", query: { perPage: 1, page: 1 }, ...opts });
5038
+ return { success: true, message: "Connection successful" };
5039
+ } catch (error) {
5040
+ return { success: false, message: toRegistrarError(error).message };
5041
+ }
5042
+ }
5043
+ async listDomains(opts) {
5044
+ const { search, detailed: _detailed, ...requestOpts } = opts ?? {};
5045
+ const domains = await this.pages("/domains", "domains", requestOpts);
5046
+ return filterDomains(
5047
+ domains.map((d) => this.toDomain(d)),
5048
+ search
5049
+ );
5050
+ }
5051
+ async getDomain(domainName, opts) {
5052
+ return this.toDomain(await this.rawDomain(domainName, opts));
5053
+ }
5054
+ async getNameservers(domainName, opts) {
5055
+ return (await this.getDomain(domainName, opts)).nameservers;
5056
+ }
5057
+ async getAuthCode(domainName, opts) {
5058
+ const result = await this.http.request({
5059
+ path: `${domainPath(domainName)}:getAuthCode`,
5060
+ ...opts
5061
+ });
5062
+ if (!result?.authCode) throw new InvalidResponseError("namecom: missing authorization code");
5063
+ return result.authCode;
5064
+ }
5065
+ async checkAvailability(domainNames, opts) {
5066
+ const results = [];
5067
+ for (let i = 0; i < domainNames.length; i += 50) {
5068
+ const res = await this.http.request({
5069
+ method: "POST",
5070
+ path: "/domains:checkAvailability",
5071
+ body: {
5072
+ domainNames: domainNames.slice(i, i + 50).map(normalizeDomain),
5073
+ purchaseType: "registration"
5074
+ },
5075
+ ...opts
5076
+ });
5077
+ if (!Array.isArray(res?.results))
5078
+ throw new InvalidResponseError("namecom: missing availability results");
5079
+ results.push(
5080
+ ...res.results.map((r) => ({
5081
+ domainName: r.domainName,
5082
+ available: (r.purchasable ?? false) && (!r.purchaseType || r.purchaseType === "registration"),
5083
+ premium: r.premium ?? false,
5084
+ price: price(r.purchasePrice),
5085
+ currency: "USD"
5086
+ // Discovery quotes the TLD's minimum term, which isn't always one year.
5087
+ }))
5088
+ );
5089
+ }
5090
+ return results;
5091
+ }
5092
+ async getPricing(tldOrDomain, opts) {
5093
+ const name = normalizeDomain(tldOrDomain);
5094
+ if (name.startsWith(".") || !name.includes(".")) {
5095
+ const tld = name.replace(/^\./, "");
5096
+ const entries = await this.pages("/tldpricing", "pricing", opts, {
5097
+ tlds: tld,
5098
+ duration: 1
5099
+ });
5100
+ const entry = entries.find((p) => p.tld.toLowerCase() === tld && p.duration === 1);
5101
+ if (!entry) throw new NotFoundError(`namecom: no one-year pricing for .${tld}`);
5102
+ return {
5103
+ tld,
5104
+ currency: "USD",
5105
+ registration: price(entry.registrationPrice),
5106
+ renewal: price(entry.renewalPrice),
5107
+ transfer: price(entry.transferInPrice)
5108
+ };
5109
+ }
5110
+ const result = await this.domainPricing(name, 1, opts);
5111
+ return {
5112
+ tld: name.slice(name.indexOf(".") + 1),
5113
+ currency: "USD",
5114
+ registration: price(result.purchasePrice),
5115
+ renewal: price(result.renewalPrice),
5116
+ transfer: price(result.transferPrice)
5117
+ };
5118
+ }
5119
+ async registerDomain(domainName, input, opts) {
5120
+ const years = validYears(input.years ?? 1);
5121
+ if (!input.contacts.registrant)
5122
+ throw new ConfigurationError("namecom: a registrant contact is required");
5123
+ const contacts = toContacts(input.contacts);
5124
+ const availability = (await this.checkAvailability([domainName], opts)).find(
5125
+ (result) => normalizeDomain(result.domainName) === normalizeDomain(domainName)
5126
+ );
5127
+ if (!availability?.available)
5128
+ return { success: false, message: "namecom: domain is not available for registration" };
5129
+ const pricing = await this.domainPricing(domainName, years, opts);
5130
+ const purchasePrice = purchaseQuote(pricing, "purchasePrice", availability.premium);
5131
+ return this.purchase(
5132
+ "/domains",
5133
+ {
5134
+ domain: {
5135
+ domainName: normalizeDomain(domainName),
5136
+ contacts,
5137
+ nameservers: input.nameservers,
5138
+ privacyEnabled: input.privacy,
5139
+ autorenewEnabled: input.autoRenew
5140
+ },
5141
+ purchaseType: "registration",
5142
+ years,
5143
+ purchasePrice
5144
+ },
5145
+ domainName,
5146
+ "registration",
5147
+ opts
5148
+ );
5149
+ }
5150
+ async renewDomain(domainName, years = 1, opts) {
5151
+ validYears(years);
5152
+ const pricing = await this.domainPricing(domainName, years, opts);
5153
+ return this.purchase(
5154
+ `${domainPath(domainName)}:renew`,
5155
+ {
5156
+ years,
5157
+ purchasePrice: purchaseQuote(pricing, "renewalPrice")
5158
+ },
5159
+ domainName,
5160
+ "renewal",
5161
+ opts
5162
+ );
5163
+ }
5164
+ async transferIn(domainName, input, opts) {
5165
+ if (!input.authCode) throw new ConfigurationError("namecom: an authorization code is required");
5166
+ if (input.years != null || input.contacts != null || input.autoRenew != null) {
5167
+ throw new ConfigurationError(
5168
+ "namecom: transferIn does not accept years, contacts or autoRenew; the registry determines the term"
5169
+ );
5170
+ }
5171
+ const pricing = await this.domainPricing(domainName, void 0, opts);
5172
+ return this.purchase(
5173
+ "/transfers",
5174
+ {
5175
+ domainName: normalizeDomain(domainName),
5176
+ authCode: input.authCode,
5177
+ privacyEnabled: input.privacy,
5178
+ purchasePrice: purchaseQuote(pricing, "transferPrice")
5179
+ },
5180
+ domainName,
5181
+ "transfer",
5182
+ opts
5183
+ );
5184
+ }
5185
+ setAutoRenew(domainName, enabled, opts) {
5186
+ return this.patchDomain(domainName, { autorenewEnabled: enabled }, opts);
5187
+ }
5188
+ lockDomain(domainName, opts) {
5189
+ return this.patchDomain(domainName, { locked: true }, opts);
5190
+ }
5191
+ unlockDomain(domainName, opts) {
5192
+ return this.patchDomain(domainName, { locked: false }, opts);
5193
+ }
5194
+ setPrivacy(domainName, enabled, opts) {
5195
+ return this.patchDomain(domainName, { privacyEnabled: enabled }, opts);
5196
+ }
5197
+ updateNameservers(domainName, nameservers, opts) {
5198
+ return this.mutate(
5199
+ { method: "POST", path: `${domainPath(domainName)}:setNameservers`, body: { nameservers } },
5200
+ opts
5201
+ );
5202
+ }
5203
+ async getContacts(domainName, opts) {
5204
+ const result = {};
5205
+ const raw = await this.rawDomain(domainName, opts);
5206
+ for (const role of CONTACT_ROLES) {
5207
+ const c = raw.contacts?.[role];
5208
+ if (c)
5209
+ result[role] = {
5210
+ firstName: c.firstName ?? "",
5211
+ lastName: c.lastName ?? "",
5212
+ organization: c.companyName ?? void 0,
5213
+ email: c.email ?? "",
5214
+ phone: c.phone ?? "",
5215
+ fax: c.fax ?? void 0,
5216
+ address1: c.address1 ?? "",
5217
+ address2: c.address2 ?? void 0,
5218
+ city: c.city ?? "",
5219
+ state: c.state ?? void 0,
5220
+ postalCode: c.zip ?? "",
5221
+ country: c.country ?? ""
5222
+ };
5223
+ }
5224
+ return result;
5225
+ }
5226
+ updateContacts(domainName, contacts, opts) {
5227
+ return this.mutate(
5228
+ {
5229
+ method: "POST",
5230
+ path: `${domainPath(domainName)}:setContacts`,
5231
+ body: { contacts: toContacts(contacts) }
5232
+ },
5233
+ opts
5234
+ );
5235
+ }
5236
+ async getDnsRecords(domainName, opts) {
5237
+ return (await this.pages(`${domainPath(domainName)}/records`, "records", opts)).map(fromRecord);
5238
+ }
5239
+ // No bulk replace endpoint. Reconcile by id: preserve identical records, update
5240
+ // existing type/host pairs, create additions, then delete stale records. This
5241
+ // avoids duplicate-record errors and does not empty the zone before creation.
5242
+ async setDnsRecords(domainName, records, opts) {
5243
+ const desired = records.map(toRecord).filter((record, index, all) => all.findIndex((other) => sameRecord(other, record)) === index);
5244
+ try {
5245
+ const path = `${domainPath(domainName)}/records`;
5246
+ const existing = await this.pages(path, "records", opts);
5247
+ if (existing.some((r) => !Number.isInteger(r.id) || r.id <= 0))
5248
+ throw new InvalidResponseError("namecom: DNS response missing record ids");
5249
+ const remaining = [...existing];
5250
+ const pending = [];
5251
+ for (const record of desired) {
5252
+ const index = remaining.findIndex((r) => sameRecord(r, record));
5253
+ if (index >= 0) remaining.splice(index, 1);
5254
+ else if (!pending.some((r) => sameRecord(r, record))) pending.push(record);
5255
+ }
5256
+ for (const record of pending) {
5257
+ const index = remaining.findIndex((r) => recordKey(r) === recordKey(record));
5258
+ const old = index >= 0 ? remaining.splice(index, 1)[0] : void 0;
5259
+ await this.http.request({
5260
+ ...opts,
5261
+ retries: 0,
5262
+ method: old ? "PUT" : "POST",
5263
+ path: old ? `${path}/${old.id}` : path,
5264
+ body: record
5265
+ });
5266
+ }
5267
+ for (const old of remaining) {
5268
+ await this.http.request({
5269
+ ...opts,
5270
+ retries: 0,
5271
+ method: "DELETE",
5272
+ path: `${path}/${old.id}`
5273
+ });
5274
+ }
5275
+ return { success: true, message: "DNS records updated successfully" };
5276
+ } catch (error) {
5277
+ return {
5278
+ success: false,
5279
+ message: `${toRegistrarError(error).message}. DNS replacement is not atomic; read the zone before retrying.`
5280
+ };
5281
+ }
5282
+ }
5283
+ patchDomain(domainName, body, opts) {
5284
+ return this.mutate({ method: "PATCH", path: domainPath(domainName), body }, opts);
5285
+ }
5286
+ rawDomain(domainName, opts) {
5287
+ return this.http.request({ path: domainPath(domainName), ...opts });
5288
+ }
5289
+ domainPricing(domainName, years, opts) {
5290
+ return this.http.request({
5291
+ path: `${domainPath(domainName)}:getPricing`,
5292
+ query: { years },
5293
+ ...opts
5294
+ });
5295
+ }
5296
+ toDomain(d) {
5297
+ if (!d?.domainName)
5298
+ throw new InvalidResponseError("namecom: domain response missing domainName");
5299
+ return createDomain({
5300
+ domainName: normalizeDomain(d.domainName),
5301
+ registrar: this.name,
5302
+ // Core exposes locks, not a lifecycle status or a scheduled renewal date.
5303
+ status: (d.locks ?? []).join(","),
5304
+ createdDate: d.createDate,
5305
+ expirationDate: d.expireDate,
5306
+ autoRenew: d.autorenewEnabled ?? false,
5307
+ locked: d.locked ?? false,
5308
+ privacy: d.privacyEnabled ?? false,
5309
+ nameservers: d.nameservers
5310
+ });
5311
+ }
5312
+ async pages(path, key, opts, query) {
5313
+ const result = [];
5314
+ let page = 1;
5315
+ while (true) {
5316
+ const res = await this.http.request({
5317
+ path,
5318
+ query: { perPage: 1e3, page, ...query },
5319
+ ...opts
5320
+ });
5321
+ const items = res?.[key];
5322
+ if (!res || items != null && !Array.isArray(items))
5323
+ throw new InvalidResponseError("namecom: invalid list response");
5324
+ result.push(...items ?? []);
5325
+ const next = res.nextPage;
5326
+ if (next == null || next === 0) return result;
5327
+ if (!Number.isInteger(next) || next <= page)
5328
+ throw new InvalidResponseError("namecom: invalid pagination cursor");
5329
+ page = next;
5330
+ }
5331
+ }
5332
+ async mutate(req, opts) {
5333
+ try {
5334
+ await this.http.request({ ...req, ...opts, retries: 0 });
5335
+ return { success: true, message: "Domain updated successfully" };
5336
+ } catch (error) {
5337
+ return { success: false, message: toRegistrarError(error).message };
5338
+ }
5339
+ }
5340
+ async purchase(path, body, domainName, operation, opts) {
5341
+ try {
5342
+ const res = await this.http.request({
5343
+ method: "POST",
5344
+ path,
5345
+ body,
5346
+ ...opts,
5347
+ retries: 0
5348
+ });
5349
+ const returnedName = res?.domain?.domainName ?? res?.transfer?.domainName;
5350
+ if (!Number.isInteger(res?.order) || (res.order ?? 0) <= 0 || !returnedName || normalizeDomain(returnedName) !== normalizeDomain(domainName)) {
5351
+ throw new InvalidResponseError(
5352
+ "namecom: purchase response missing order or matching domain"
5353
+ );
5354
+ }
5355
+ return {
5356
+ success: true,
5357
+ message: `Domain ${operation} request accepted (order ${res.order}); verify final domain/transfer status`
5358
+ };
5359
+ } catch (error) {
5360
+ const e = toRegistrarError(error);
5361
+ const uncertain = e.status < 0 || e.status === 408 || e.status >= 500 || e.name === "AbortError" || e instanceof ParsingError;
5362
+ return {
5363
+ success: false,
5364
+ message: e.message + (uncertain ? ". Outcome unknown; check Name.com orders and domain/transfer status before retrying." : "")
5365
+ };
5366
+ }
5367
+ }
5368
+ };
5369
+ var CONTACT_ROLES = ["registrant", "admin", "tech", "billing"];
5370
+ function toContacts(contacts) {
5371
+ const result = {};
5372
+ for (const role of CONTACT_ROLES) {
5373
+ const c = contacts[role];
5374
+ if (!c) continue;
5375
+ const required = [
5376
+ "firstName",
5377
+ "lastName",
5378
+ "email",
5379
+ "phone",
5380
+ "address1",
5381
+ "city",
5382
+ "state",
5383
+ "postalCode",
5384
+ "country"
5385
+ ];
5386
+ if (required.some((k) => !c[k]?.trim()))
5387
+ throw new ConfigurationError(`namecom: ${role} must be a complete contact, including state`);
5388
+ result[role] = {
5389
+ firstName: c.firstName,
5390
+ lastName: c.lastName,
5391
+ companyName: c.organization,
5392
+ email: c.email,
5393
+ phone: c.phone.replace(".", ""),
5394
+ fax: c.fax?.replace(".", ""),
5395
+ address1: c.address1,
5396
+ address2: c.address2,
5397
+ city: c.city,
5398
+ state: c.state,
5399
+ zip: c.postalCode,
5400
+ country: c.country.toUpperCase()
5401
+ };
5402
+ }
5403
+ if (Object.keys(result).length === 0)
5404
+ throw new ConfigurationError("namecom: at least one contact is required");
5405
+ return result;
5406
+ }
5407
+ function domainPath(domainName) {
5408
+ return `/domains/${encodeURIComponent(normalizeDomain(domainName))}`;
5409
+ }
5410
+ function validYears(years) {
5411
+ if (!Number.isInteger(years) || years < 1 || years > 10)
5412
+ throw new ConfigurationError("namecom: years must be an integer from 1 to 10");
5413
+ return years;
5414
+ }
5415
+ function price(value) {
5416
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
5417
+ }
5418
+ function purchaseQuote(pricing, field, premium = false) {
5419
+ const value = price(pricing?.[field]);
5420
+ if (value == null)
5421
+ throw new RegistrarError(
5422
+ `namecom: ${field} unavailable for the requested term; no purchase submitted`
5423
+ );
5424
+ return premium || pricing.premium ? value : void 0;
5425
+ }
5426
+ var DNS_TYPES = /* @__PURE__ */ new Set(["A", "AAAA", "ANAME", "CNAME", "MX", "NS", "SRV", "TXT"]);
5427
+ function toRecord(r) {
5428
+ const type = r.type.toUpperCase();
5429
+ if (!DNS_TYPES.has(type))
5430
+ throw new ConfigurationError(`namecom: DNS type ${type} is not supported`);
5431
+ const ttl = r.ttl ?? 300;
5432
+ if (!Number.isInteger(ttl) || ttl < 300)
5433
+ throw new ConfigurationError("namecom: DNS TTL must be an integer of at least 300 seconds");
5434
+ for (const value of [r.priority, r.weight, r.port]) {
5435
+ if (value != null && (!Number.isInteger(value) || value < 0 || value > 65535))
5436
+ throw new ConfigurationError("namecom: invalid DNS priority, weight or port");
5437
+ }
5438
+ if (!r.value.trim()) throw new ConfigurationError("namecom: DNS answer is required");
5439
+ return {
5440
+ type,
5441
+ host: !r.name || r.name === "@" ? "" : r.name,
5442
+ answer: type === "SRV" ? `${r.weight ?? 0} ${r.port ?? 0} ${r.value}` : r.value,
5443
+ ttl,
5444
+ ...["MX", "SRV"].includes(type) ? { priority: r.priority ?? 0 } : {}
5445
+ };
5446
+ }
5447
+ function fromRecord(r) {
5448
+ const type = r.type.toUpperCase();
5449
+ const record = { type, name: r.host || "@", value: r.answer, ttl: r.ttl };
5450
+ if (type === "MX" || type === "SRV") record.priority = r.priority ?? 0;
5451
+ if (type === "SRV") {
5452
+ const match = /^(\d+)\s+(\d+)\s+(.+)$/.exec(r.answer);
5453
+ if (!match) throw new InvalidResponseError("namecom: invalid SRV answer");
5454
+ record.weight = Number(match[1]);
5455
+ record.port = Number(match[2]);
5456
+ record.value = match[3];
5457
+ }
5458
+ return record;
5459
+ }
5460
+ function recordKey(r) {
5461
+ return `${r.type.toUpperCase()}\0${(r.host === "@" ? "" : r.host ?? "").toLowerCase()}`;
5462
+ }
5463
+ function sameRecord(a, b) {
5464
+ return recordKey(a) === recordKey(b) && a.answer === b.answer && (a.ttl ?? 300) === (b.ttl ?? 300) && (a.priority ?? 0) === (b.priority ?? 0);
5465
+ }
5466
+
4972
5467
  // src/registrars/namesilo.ts
4973
5468
  var NameSiloRegistrar = class extends BaseRegistrar {
4974
5469
  name = "namesilo";
@@ -5159,13 +5654,13 @@ var NameSiloRegistrar = class extends BaseRegistrar {
5159
5654
  if (!node || typeof node !== "object") {
5160
5655
  throw new NotFoundError(`NameSilo: no pricing found for TLD '${tld}'`);
5161
5656
  }
5162
- const price = node;
5657
+ const price2 = node;
5163
5658
  return {
5164
5659
  tld,
5165
5660
  currency: "USD",
5166
- registration: toPrice3(price.registration),
5167
- renewal: toPrice3(price.renew),
5168
- transfer: toPrice3(price.transfer)
5661
+ registration: toPrice3(price2.registration),
5662
+ renewal: toPrice3(price2.renew),
5663
+ transfer: toPrice3(price2.transfer)
5169
5664
  };
5170
5665
  }
5171
5666
  /**
@@ -5582,8 +6077,8 @@ function extractAvailEntries(group) {
5582
6077
  const premiumRaw = o.premium ?? o["@premium"] ?? o["@_premium"];
5583
6078
  const durationRaw = o.duration ?? o["@duration"] ?? o["@_duration"];
5584
6079
  const entry = { name };
5585
- const price = toPrice3(priceRaw);
5586
- if (price != null && price > 0) entry.price = price;
6080
+ const price2 = toPrice3(priceRaw);
6081
+ if (price2 != null && price2 > 0) entry.price = price2;
5587
6082
  if (premiumRaw != null && text(premiumRaw) !== "") entry.premium = isYes(premiumRaw);
5588
6083
  const duration = toPrice3(durationRaw);
5589
6084
  if (duration != null && duration > 0) entry.duration = duration;
@@ -5827,17 +6322,17 @@ var PorkbunRegistrar = class extends BaseRegistrar {
5827
6322
  async tldPricing(tld, opts) {
5828
6323
  const res = await this.call("/pricing/get", {}, opts);
5829
6324
  if (!isOk3(res)) throw new Error(res.message ?? "API request failed");
5830
- const price = res.pricing?.[tld];
5831
- if (!price) {
6325
+ const price2 = res.pricing?.[tld];
6326
+ if (!price2) {
5832
6327
  throw new NotFoundError(`${this.name}: no pricing found for TLD .${tld}`);
5833
6328
  }
5834
6329
  return {
5835
6330
  tld,
5836
6331
  currency: "USD",
5837
6332
  // Porkbun prices are always quoted in USD
5838
- registration: toPrice4(price.registration),
5839
- renewal: toPrice4(price.renewal),
5840
- transfer: toPrice4(price.transfer)
6333
+ registration: toPrice4(price2.registration),
6334
+ renewal: toPrice4(price2.renewal),
6335
+ transfer: toPrice4(price2.transfer)
5841
6336
  };
5842
6337
  }
5843
6338
  /**
@@ -5877,14 +6372,14 @@ var PorkbunRegistrar = class extends BaseRegistrar {
5877
6372
  );
5878
6373
  if (!isOk3(res)) throw new Error(res.message ?? "API request failed");
5879
6374
  const info = res.response ?? {};
5880
- const price = toPrice4(info.price);
6375
+ const price2 = toPrice4(info.price);
5881
6376
  results.push({
5882
6377
  domainName,
5883
6378
  available: info.avail === "yes",
5884
6379
  premium: info.premium === "yes",
5885
- price,
5886
- currency: price != null ? "USD" : void 0,
5887
- period: price != null ? 1 : void 0
6380
+ price: price2,
6381
+ currency: price2 != null ? "USD" : void 0,
6382
+ period: price2 != null ? 1 : void 0
5888
6383
  });
5889
6384
  }
5890
6385
  return results;
@@ -6570,8 +7065,8 @@ var SpaceshipRegistrar = class extends BaseRegistrar {
6570
7065
  ...opts
6571
7066
  });
6572
7067
  }
6573
- const keep = new Set(items.map((r) => recordKey(r.type, r.name)));
6574
- const stale = existing.filter((r) => (r.group?.type ?? "custom") === "custom").filter((r) => !keep.has(recordKey(r.type, r.name))).map(({ group: _group, ...rr }) => rr);
7068
+ const keep = new Set(items.map((r) => recordKey2(r.type, r.name)));
7069
+ const stale = existing.filter((r) => (r.group?.type ?? "custom") === "custom").filter((r) => !keep.has(recordKey2(r.type, r.name))).map(({ group: _group, ...rr }) => rr);
6575
7070
  if (stale.length > 0) {
6576
7071
  await this.http.request({
6577
7072
  method: "DELETE",
@@ -6730,7 +7225,7 @@ function toSpaceshipRecord(r) {
6730
7225
  }
6731
7226
  return record;
6732
7227
  }
6733
- function recordKey(type, name) {
7228
+ function recordKey2(type, name) {
6734
7229
  return `${(type ?? "").toUpperCase()}\0${name ?? "@"}`;
6735
7230
  }
6736
7231
  function fromSpaceshipContact(c) {
@@ -6774,6 +7269,7 @@ var registrars = {
6774
7269
  godaddy: GoDaddyRegistrar,
6775
7270
  namebright: NameBrightRegistrar,
6776
7271
  namecheap: NamecheapRegistrar,
7272
+ namecom: NamecomRegistrar,
6777
7273
  namesilo: NameSiloRegistrar,
6778
7274
  porkbun: PorkbunRegistrar,
6779
7275
  spaceship: SpaceshipRegistrar
@@ -6783,6 +7279,6 @@ function createRegistrar(name, credentials, options) {
6783
7279
  return new RegistrarClass(credentials, options);
6784
7280
  }
6785
7281
 
6786
- export { ALL_FEATURES, AbortError, AuthenticationError, AuthorizationError, BaseRegistrar, CORE_FEATURES, CloudflareRegistrar, ConfigurationError, ConnectionError, ConsentRequiredError, DEFAULT_OPTIONS, DynadotRegistrar, EXTENDED_FEATURES, Feature, GandiRegistrar, GoDaddyRegistrar, HttpClient, InvalidResponseError, MASKED_FORWARD_UNSUPPORTED, NameBrightRegistrar, NameSiloRegistrar, NamecheapRegistrar, NotFoundError, NotImplementedError, ParsingError, PorkbunRegistrar, RateLimitError, RegistrarClient, RegistrarError, RetryableRegistrarError, SpaceshipRegistrar, TimeoutError, USER_AGENT, backoffDelay, createDomain, createRegistrar, ensureArray, filterDomains, isCoreFeature, listPortfolio, normalizeDomain, normalizeNameservers, parseDate, parseXml, registrars, requireConsent, selectBaseUrl, settableForwards, sleep, toRegistrarError };
7282
+ export { ALL_FEATURES, AbortError, AuthenticationError, AuthorizationError, BaseRegistrar, CORE_FEATURES, CloudflareRegistrar, ConfigurationError, ConnectionError, ConsentRequiredError, DEFAULT_OPTIONS, DynadotRegistrar, EXTENDED_FEATURES, Feature, GandiRegistrar, GoDaddyRegistrar, HttpClient, InvalidResponseError, MASKED_FORWARD_UNSUPPORTED, NameBrightRegistrar, NameSiloRegistrar, NamecheapRegistrar, NamecomRegistrar, NotFoundError, NotImplementedError, ParsingError, PorkbunRegistrar, RateLimitError, RegistrarClient, RegistrarError, RetryableRegistrarError, SpaceshipRegistrar, TimeoutError, USER_AGENT, backoffDelay, createDomain, createRegistrar, ensureArray, filterDomains, isCoreFeature, listPortfolio, normalizeDomain, normalizeNameservers, parseDate, parseXml, registrars, requireConsent, selectBaseUrl, settableForwards, sleep, toRegistrarError };
6787
7283
  //# sourceMappingURL=index.js.map
6788
7284
  //# sourceMappingURL=index.js.map