@aoxborrow/registrar-client 0.2.0 → 0.4.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/README.md +1 -0
- package/dist/index.cjs +35 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +35 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/client.ts +4 -2
- package/src/registrar.ts +6 -0
- package/src/registrars/dynadot.ts +4 -0
- package/src/registrars/godaddy.ts +25 -13
- package/src/registrars/namesilo.ts +4 -0
- package/src/registrars/spaceship.ts +4 -0
- package/src/types.ts +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aoxborrow/registrar-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "One consistent, fully-typed TypeScript interface to many domain registrar APIs (GoDaddy, Cloudflare, Namecheap, Spaceship, Dynadot, Porkbun, and more) behind a single pluggable multi-provider client",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Aaron Oxborrow",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
13
|
"homepage": "https://github.com/aoxborrow/registrar-client",
|
|
14
|
+
"funding": "https://github.com/sponsors/aoxborrow",
|
|
14
15
|
"repository": {
|
|
15
16
|
"type": "git",
|
|
16
17
|
"url": "git+https://github.com/aoxborrow/registrar-client.git"
|
package/src/client.ts
CHANGED
|
@@ -50,8 +50,10 @@ export class RegistrarClient {
|
|
|
50
50
|
const detail = await this.provider.getDomain(name, opts);
|
|
51
51
|
let merged = { ...domains[index], ...detail };
|
|
52
52
|
// Some providers expose nameservers only via a dedicated endpoint, not
|
|
53
|
-
// on the domain detail — fetch them separately when still empty.
|
|
54
|
-
|
|
53
|
+
// on the domain detail — fetch them separately when still empty. Skip
|
|
54
|
+
// providers whose getNameservers just re-reads getDomain: it would
|
|
55
|
+
// repeat the same call and return the same empty result.
|
|
56
|
+
if (merged.nameservers.length === 0 && this.provider.requiresNameserversFetch) {
|
|
55
57
|
try {
|
|
56
58
|
const nameservers = normalizeNameservers(
|
|
57
59
|
await this.provider.getNameservers(name, opts)
|
package/src/registrar.ts
CHANGED
|
@@ -75,6 +75,12 @@ export abstract class BaseRegistrar implements Registrar {
|
|
|
75
75
|
return this.features.includes(feature);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// See Registrar.requiresNameserversFetch. Defaults true, so a provider
|
|
79
|
+
// whose getNameservers hits a real endpoint keeps the enrichment fallback
|
|
80
|
+
// without opting in; the providers whose getNameservers just re-reads getDomain
|
|
81
|
+
// override this to false to drop the redundant call.
|
|
82
|
+
readonly requiresNameserversFetch: boolean = true;
|
|
83
|
+
|
|
78
84
|
constructor(
|
|
79
85
|
credentials: RegistrarCredentials,
|
|
80
86
|
httpConfig: Omit<HttpClientConfig, 'options'>,
|
|
@@ -321,6 +321,10 @@ export class DynadotRegistrar extends BaseRegistrar {
|
|
|
321
321
|
return data.domain_info;
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
+
// getNameservers re-reads getDomain (domain_info carries NS inline; no separate
|
|
325
|
+
// endpoint), so listing enrichment gains nothing from the fallback — skip it.
|
|
326
|
+
override readonly requiresNameserversFetch = false;
|
|
327
|
+
|
|
324
328
|
override async getNameservers(domainName: string, opts?: RequestOptions): Promise<string[]> {
|
|
325
329
|
// domain_info carries the nameservers inline (empty for Dynadot-DNS-hosted
|
|
326
330
|
// domains, which have no external NS)
|
|
@@ -271,20 +271,28 @@ export class GoDaddyRegistrar extends BaseRegistrar {
|
|
|
271
271
|
static readonly displayName = 'GoDaddy';
|
|
272
272
|
static readonly website = 'godaddy.com';
|
|
273
273
|
static readonly helpText =
|
|
274
|
-
'
|
|
275
|
-
|
|
276
|
-
'
|
|
277
|
-
'
|
|
278
|
-
'
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
274
|
+
'Create a Personal Access Token (PAT) at https://developer.godaddy.com and ' +
|
|
275
|
+
"paste it here. The PAT is GoDaddy's modern credential: it unlocks the v3 " +
|
|
276
|
+
'API (discovery, registration, DNS, nameservers) and also authenticates the ' +
|
|
277
|
+
'legacy v1 API for management operations (renew, transfer, auto-renew, ' +
|
|
278
|
+
'lock, privacy, contacts) — one token covers everything.';
|
|
279
|
+
// Only the PAT is exposed for configuration — it is the sole credential
|
|
280
|
+
// GoDaddy recommends going forward, and it covers every production operation.
|
|
281
|
+
//
|
|
282
|
+
// The legacy `apiKey` + `apiSecret` (sso-key) pair and the `customerId` field
|
|
283
|
+
// are intentionally NOT advertised here. The code that consumes them is kept
|
|
284
|
+
// (see `authHeader`, `useV3`, `resolveCustomerId`, and the forwarding methods)
|
|
285
|
+
// so OTE/sandbox testing and direct programmatic use still work when those
|
|
286
|
+
// values are passed in credentials explicitly. But because they are no longer
|
|
287
|
+
// configurable, two capabilities are effectively unreachable through normal
|
|
288
|
+
// (config-driven) setup:
|
|
289
|
+
// - OTE/sandbox, which needs an sso-key (`apiKey` + `apiSecret`), and
|
|
290
|
+
// - domain forwarding, which needs `customerId` (a customer UUID), plus an
|
|
291
|
+
// sso-key to resolve a numeric shopper ID to that UUID.
|
|
292
|
+
// GoDaddy is deprecating the sso-key scheme in 2026, so this is the direction
|
|
293
|
+
// of travel regardless.
|
|
283
294
|
static readonly configFields: ConfigField[] = [
|
|
284
|
-
{ name: 'apiToken', label: 'API Token (PAT)', type: 'password', required:
|
|
285
|
-
{ name: 'apiKey', label: 'API Key', type: 'password', required: false },
|
|
286
|
-
{ name: 'apiSecret', label: 'API Secret', type: 'password', required: false },
|
|
287
|
-
{ name: 'customerId', label: 'Customer ID or Shopper ID', type: 'text', required: false },
|
|
295
|
+
{ name: 'apiToken', label: 'API Token (PAT)', type: 'password', required: true },
|
|
288
296
|
];
|
|
289
297
|
// GoDaddy's OTE ("Operational Test Environment") is its sandbox
|
|
290
298
|
static readonly supportsSandbox = true;
|
|
@@ -421,6 +429,10 @@ export class GoDaddyRegistrar extends BaseRegistrar {
|
|
|
421
429
|
return this.toDomain(d);
|
|
422
430
|
}
|
|
423
431
|
|
|
432
|
+
// getNameservers re-reads getDomain (GoDaddy has no dedicated NS endpoint), so
|
|
433
|
+
// listing enrichment gains nothing from the fallback — skip it.
|
|
434
|
+
override readonly requiresNameserversFetch = false;
|
|
435
|
+
|
|
424
436
|
override async getNameservers(domainName: string, opts?: RequestOptions): Promise<string[]> {
|
|
425
437
|
const domain = await this.getDomain(domainName, opts);
|
|
426
438
|
return domain.nameservers;
|
|
@@ -286,6 +286,10 @@ export class NameSiloRegistrar extends BaseRegistrar {
|
|
|
286
286
|
});
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
+
// getNameservers re-reads getDomain (getDomainInfo carries NS; no separate
|
|
290
|
+
// endpoint), so listing enrichment gains nothing from the fallback — skip it.
|
|
291
|
+
override readonly requiresNameserversFetch = false;
|
|
292
|
+
|
|
289
293
|
override async getNameservers(domainName: string, opts?: RequestOptions): Promise<string[]> {
|
|
290
294
|
const domain = await this.getDomain(domainName, opts);
|
|
291
295
|
return domain.nameservers;
|
|
@@ -204,6 +204,10 @@ export class SpaceshipRegistrar extends BaseRegistrar {
|
|
|
204
204
|
return this.toDomain(await this.getRaw(domainName, opts));
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
// getNameservers reads the same getRaw payload as getDomain (no dedicated NS
|
|
208
|
+
// endpoint), so listing enrichment gains nothing from the fallback — skip it.
|
|
209
|
+
override readonly requiresNameserversFetch = false;
|
|
210
|
+
|
|
207
211
|
override async getNameservers(domainName: string, opts?: RequestOptions): Promise<string[]> {
|
|
208
212
|
const d = await this.getRaw(domainName, opts);
|
|
209
213
|
return d.nameservers?.hosts ?? [];
|
package/src/types.ts
CHANGED
|
@@ -307,6 +307,13 @@ export interface Registrar {
|
|
|
307
307
|
// the capabilities this provider supports (core contract + its extended features)
|
|
308
308
|
readonly features: readonly RegistrarFeature[];
|
|
309
309
|
|
|
310
|
+
// Whether reading a domain's nameservers needs a getNameservers call beyond
|
|
311
|
+
// getDomain. True when getNameservers hits its own endpoint that can surface
|
|
312
|
+
// nameservers getDomain omits; false when it just re-reads getDomain, so
|
|
313
|
+
// listing enrichment skips the redundant fetch. See BaseRegistrar for the
|
|
314
|
+
// default.
|
|
315
|
+
readonly requiresNameserversFetch: boolean;
|
|
316
|
+
|
|
310
317
|
// whether this provider supports a given capability
|
|
311
318
|
supports(feature: RegistrarFeature): boolean;
|
|
312
319
|
|