@aoxborrow/registrar-client 0.7.0 → 0.9.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.
@@ -216,6 +216,9 @@ export class DynadotRegistrar extends BaseRegistrar {
216
216
  sandbox: 'https://api-sandbox.dynadot.com',
217
217
  }),
218
218
  headers: { Authorization: `Bearer ${credentials.apiKey}` },
219
+ // HTTP 429 can omit Retry-After. Avoid exhausting all attempts inside
220
+ // Dynadot's regular-tier minute window in that case.
221
+ rateLimitFallbackSeconds: 60,
219
222
  },
220
223
  options
221
224
  );
@@ -5,6 +5,7 @@ import type {
5
5
  RegistrarOptions,
6
6
  } from '../types';
7
7
  import { CloudflareRegistrar } from './cloudflare';
8
+ import { Domain101Registrar } from './domain101';
8
9
  import { DynadotRegistrar } from './dynadot';
9
10
  import { GandiRegistrar } from './gandi';
10
11
  import { GoDaddyRegistrar } from './godaddy';
@@ -17,16 +18,17 @@ import { SpaceshipRegistrar } from './spaceship';
17
18
 
18
19
  // the built-in registrar providers, keyed by id
19
20
  export const registrars = {
20
- cloudflare: CloudflareRegistrar,
21
- dynadot: DynadotRegistrar,
22
- gandi: GandiRegistrar,
23
- godaddy: GoDaddyRegistrar,
24
- namebright: NameBrightRegistrar,
25
- namecheap: NamecheapRegistrar,
26
- namecom: NamecomRegistrar,
27
- namesilo: NameSiloRegistrar,
28
- porkbun: PorkbunRegistrar,
29
- spaceship: SpaceshipRegistrar,
21
+ '101domain': Domain101Registrar,
22
+ 'cloudflare': CloudflareRegistrar,
23
+ 'dynadot': DynadotRegistrar,
24
+ 'gandi': GandiRegistrar,
25
+ 'godaddy': GoDaddyRegistrar,
26
+ 'namebright': NameBrightRegistrar,
27
+ 'namecheap': NamecheapRegistrar,
28
+ 'namecom': NamecomRegistrar,
29
+ 'namesilo': NameSiloRegistrar,
30
+ 'porkbun': PorkbunRegistrar,
31
+ 'spaceship': SpaceshipRegistrar,
30
32
  } satisfies Record<string, RegistrarConstructor>;
31
33
 
32
34
  // id of a built-in registrar
@@ -60,6 +60,7 @@ interface NcCheckEl {
60
60
  '@_Available'?: string;
61
61
  '@_IsPremiumName'?: string;
62
62
  '@_PremiumRegistrationPrice'?: string;
63
+ '@_PremiumRenewalPrice'?: string;
63
64
  }
64
65
 
65
66
  // a contact group in namecheap.domains.getContacts (children are text elements)
@@ -367,9 +368,10 @@ export class NamecheapRegistrar extends BaseRegistrar {
367
368
 
368
369
  /**
369
370
  * Availability via domains.check (batched at 50 per request, Namecheap's cap).
370
- * The check response only carries a price for *premium* names
371
- * (`PremiumRegistrationPrice`); regular registration pricing comes from
372
- * `getPricing`, so `price` is set only for premium results.
371
+ * The check response only carries prices for *premium* names
372
+ * (`PremiumRegistrationPrice`, `PremiumRenewalPrice`); regular pricing comes
373
+ * from `getPricing`, so `price` and `renewalPrice` are set only for premium
374
+ * results.
373
375
  */
374
376
  override async checkAvailability(
375
377
  domainNames: string[],
@@ -385,12 +387,16 @@ export class NamecheapRegistrar extends BaseRegistrar {
385
387
  );
386
388
  for (const el of ensureArray(cr.DomainCheckResult)) {
387
389
  const premium = el['@_IsPremiumName'] === 'true';
388
- const premiumPrice = premium ? Number(el['@_PremiumRegistrationPrice']) : NaN;
390
+ const premiumPrice = (attr: string | undefined) => {
391
+ const n = premium ? Number(attr) : NaN;
392
+ return Number.isFinite(n) && n > 0 ? n : undefined;
393
+ };
389
394
  results.push({
390
395
  domainName: el['@_Domain'] ?? '',
391
396
  available: el['@_Available'] === 'true',
392
397
  premium,
393
- price: Number.isFinite(premiumPrice) && premiumPrice > 0 ? premiumPrice : undefined,
398
+ price: premiumPrice(el['@_PremiumRegistrationPrice']),
399
+ renewalPrice: premiumPrice(el['@_PremiumRenewalPrice']),
394
400
  });
395
401
  }
396
402
  }
@@ -108,18 +108,14 @@ class NamecomHttpClient extends HttpClient {
108
108
  }),
109
109
  url
110
110
  );
111
- if (error instanceof RateLimitError) {
112
- const retryAfter = response.headers.get('retry-after');
113
- const seconds = retryAfter == null ? NaN : Number(retryAfter);
114
- const date = retryAfter == null ? NaN : Date.parse(retryAfter);
115
- const reset = response.headers.get('x-ratelimit-reset');
116
- error.retryAfter = Number.isFinite(seconds)
117
- ? Math.max(0, seconds)
118
- : Number.isFinite(date)
119
- ? Math.max(0, (date - Date.now()) / 1000)
120
- : reset != null && Number.isFinite(Number(reset))
121
- ? Math.max(0, Number(reset) - Date.now() / 1000)
122
- : undefined;
111
+ // The shared client has already read Retry-After. Without a usable one,
112
+ // fall back to X-RateLimit-Reset (Unix seconds); otherwise leave it unset
113
+ // so the configured backoff applies.
114
+ if (error instanceof RateLimitError && error.retryAfter === undefined) {
115
+ const reset = response.headers.get('x-ratelimit-reset')?.trim();
116
+ if (reset && /^\d+(?:\.\d+)?$/.test(reset)) {
117
+ error.retryAfter = Math.max(0, Math.ceil(Number(reset) - Date.now() / 1000));
118
+ }
123
119
  }
124
120
  return error;
125
121
  }
package/src/types.ts CHANGED
@@ -80,6 +80,9 @@ export interface ConnectionResult {
80
80
  export interface OperationResult {
81
81
  success: boolean;
82
82
  message: string;
83
+ // Accepted by the registrar but still pending registry processing. Callers
84
+ // must not optimistically display the requested state as already active.
85
+ pending?: boolean;
83
86
  // Present only on a failed write whose request may have reached the
84
87
  // registrar (timed out, connection dropped mid-response, or a 5xx). The
85
88
  // change may or may not have been applied: re-read the domain before trying
@@ -194,6 +197,9 @@ export interface DomainAvailability {
194
197
  premium?: boolean;
195
198
  // registration price in major currency units (e.g. 11.99), when the API reports it
196
199
  price?: number;
200
+ // annual renewal price in major currency units, when the API reports one for
201
+ // this specific name (e.g. a premium name's renewal)
202
+ renewalPrice?: number;
197
203
  // ISO 4217 currency code, e.g. "USD"
198
204
  currency?: string;
199
205
  // the registration period the price covers, in years