@aoxborrow/registrar-client 0.1.0 → 0.3.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 +4 -2
- package/dist/index.cjs +27 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +27 -1
- 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/cloudflare.ts +1 -0
- package/src/registrars/dynadot.ts +5 -0
- package/src/registrars/gandi.ts +1 -0
- package/src/registrars/godaddy.ts +5 -0
- package/src/registrars/namebright.ts +1 -0
- package/src/registrars/namecheap.ts +1 -0
- package/src/registrars/namesilo.ts +5 -0
- package/src/registrars/porkbun.ts +1 -0
- package/src/registrars/spaceship.ts +5 -0
- package/src/types.ts +11 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aoxborrow/registrar-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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'>,
|
|
@@ -175,6 +175,7 @@ export class CloudflareRegistrar extends BaseRegistrar {
|
|
|
175
175
|
readonly name = 'cloudflare';
|
|
176
176
|
|
|
177
177
|
static readonly displayName = 'Cloudflare';
|
|
178
|
+
static readonly website = 'cloudflare.com';
|
|
178
179
|
static readonly helpText =
|
|
179
180
|
'Create an API token in your Cloudflare dashboard under My Profile > API Tokens. ' +
|
|
180
181
|
'The token needs "Account.Registrar" read/write permissions. Find your Account ID ' +
|
|
@@ -180,6 +180,7 @@ export class DynadotRegistrar extends BaseRegistrar {
|
|
|
180
180
|
readonly name = 'dynadot';
|
|
181
181
|
|
|
182
182
|
static readonly displayName = 'Dynadot';
|
|
183
|
+
static readonly website = 'dynadot.com';
|
|
183
184
|
static readonly helpText =
|
|
184
185
|
'Under Tools > API in your Dynadot account, generate an API Key and API Secret. ' +
|
|
185
186
|
'The account must be unlocked with API access enabled. The key identifies you; ' +
|
|
@@ -320,6 +321,10 @@ export class DynadotRegistrar extends BaseRegistrar {
|
|
|
320
321
|
return data.domain_info;
|
|
321
322
|
}
|
|
322
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
|
+
|
|
323
328
|
override async getNameservers(domainName: string, opts?: RequestOptions): Promise<string[]> {
|
|
324
329
|
// domain_info carries the nameservers inline (empty for Dynadot-DNS-hosted
|
|
325
330
|
// domains, which have no external NS)
|
package/src/registrars/gandi.ts
CHANGED
|
@@ -161,6 +161,7 @@ export class GandiRegistrar extends BaseRegistrar {
|
|
|
161
161
|
readonly name = 'gandi';
|
|
162
162
|
|
|
163
163
|
static readonly displayName = 'Gandi.net';
|
|
164
|
+
static readonly website = 'gandi.net';
|
|
164
165
|
static readonly helpText =
|
|
165
166
|
'Generate a Personal Access Token (PAT) in your Gandi account under Account ' +
|
|
166
167
|
'Settings > Security. The token needs permission to manage domains. (Gandi has ' +
|
|
@@ -269,6 +269,7 @@ export class GoDaddyRegistrar extends BaseRegistrar {
|
|
|
269
269
|
readonly name = 'godaddy';
|
|
270
270
|
|
|
271
271
|
static readonly displayName = 'GoDaddy';
|
|
272
|
+
static readonly website = 'godaddy.com';
|
|
272
273
|
static readonly helpText =
|
|
273
274
|
'Authenticate one of two ways. For production, create a Personal Access ' +
|
|
274
275
|
'Token (PAT) at https://developer.godaddy.com and pass it as `apiToken` — ' +
|
|
@@ -420,6 +421,10 @@ export class GoDaddyRegistrar extends BaseRegistrar {
|
|
|
420
421
|
return this.toDomain(d);
|
|
421
422
|
}
|
|
422
423
|
|
|
424
|
+
// getNameservers re-reads getDomain (GoDaddy has no dedicated NS endpoint), so
|
|
425
|
+
// listing enrichment gains nothing from the fallback — skip it.
|
|
426
|
+
override readonly requiresNameserversFetch = false;
|
|
427
|
+
|
|
423
428
|
override async getNameservers(domainName: string, opts?: RequestOptions): Promise<string[]> {
|
|
424
429
|
const domain = await this.getDomain(domainName, opts);
|
|
425
430
|
return domain.nameservers;
|
|
@@ -198,6 +198,7 @@ export class NameBrightRegistrar extends BaseRegistrar {
|
|
|
198
198
|
readonly name = 'namebright';
|
|
199
199
|
|
|
200
200
|
static readonly displayName = 'NameBright';
|
|
201
|
+
static readonly website = 'namebright.com';
|
|
201
202
|
static readonly helpText =
|
|
202
203
|
'API access is not enabled by default — you must request it from NameBright ' +
|
|
203
204
|
'(contact support / your account manager) before the API Management page is ' +
|
|
@@ -188,6 +188,7 @@ export class NamecheapRegistrar extends BaseRegistrar {
|
|
|
188
188
|
readonly name = 'namecheap';
|
|
189
189
|
|
|
190
190
|
static readonly displayName = 'Namecheap';
|
|
191
|
+
static readonly website = 'namecheap.com';
|
|
191
192
|
static readonly helpText =
|
|
192
193
|
'Enable API access in your Namecheap account under Profile > Tools > API Access, ' +
|
|
193
194
|
'generate an API key, and whitelist your request IP(s) in the API settings. ' +
|
|
@@ -157,6 +157,7 @@ export class NameSiloRegistrar extends BaseRegistrar {
|
|
|
157
157
|
readonly name = 'namesilo';
|
|
158
158
|
|
|
159
159
|
static readonly displayName = 'NameSilo';
|
|
160
|
+
static readonly website = 'namesilo.com';
|
|
160
161
|
static readonly helpText =
|
|
161
162
|
'Generate an API key in your NameSilo account under Account Options > API Manager. ' +
|
|
162
163
|
'You can optionally restrict the key to specific IP addresses there. For sandbox ' +
|
|
@@ -285,6 +286,10 @@ export class NameSiloRegistrar extends BaseRegistrar {
|
|
|
285
286
|
});
|
|
286
287
|
}
|
|
287
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
|
+
|
|
288
293
|
override async getNameservers(domainName: string, opts?: RequestOptions): Promise<string[]> {
|
|
289
294
|
const domain = await this.getDomain(domainName, opts);
|
|
290
295
|
return domain.nameservers;
|
|
@@ -182,6 +182,7 @@ export class PorkbunRegistrar extends BaseRegistrar {
|
|
|
182
182
|
readonly name = 'porkbun';
|
|
183
183
|
|
|
184
184
|
static readonly displayName = 'Porkbun';
|
|
185
|
+
static readonly website = 'porkbun.com';
|
|
185
186
|
static readonly helpText =
|
|
186
187
|
'Create an API key and secret in your Porkbun account under Account > API Access, ' +
|
|
187
188
|
'then enable "API Access" on each domain you want to manage (per-domain toggle in ' +
|
|
@@ -133,6 +133,7 @@ export class SpaceshipRegistrar extends BaseRegistrar {
|
|
|
133
133
|
readonly name = 'spaceship';
|
|
134
134
|
|
|
135
135
|
static readonly displayName = 'Spaceship';
|
|
136
|
+
static readonly website = 'spaceship.com';
|
|
136
137
|
static readonly helpText =
|
|
137
138
|
'Generate your API key and secret in the API Manager at Spaceship using the ' +
|
|
138
139
|
'"New API key" button. The API requires both X-API-Key and X-API-Secret headers.';
|
|
@@ -203,6 +204,10 @@ export class SpaceshipRegistrar extends BaseRegistrar {
|
|
|
203
204
|
return this.toDomain(await this.getRaw(domainName, opts));
|
|
204
205
|
}
|
|
205
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
|
+
|
|
206
211
|
override async getNameservers(domainName: string, opts?: RequestOptions): Promise<string[]> {
|
|
207
212
|
const d = await this.getRaw(domainName, opts);
|
|
208
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
|
|
|
@@ -431,11 +438,13 @@ export interface Registrar {
|
|
|
431
438
|
}
|
|
432
439
|
|
|
433
440
|
// static side of a registrar class: the constructor plus discovery metadata
|
|
434
|
-
// (display name, the credential fields it needs, where to get
|
|
435
|
-
// it offers a sandbox/test environment).
|
|
441
|
+
// (display name, public website, the credential fields it needs, where to get
|
|
442
|
+
// them, and whether it offers a sandbox/test environment).
|
|
436
443
|
export interface RegistrarConstructor {
|
|
437
444
|
new (credentials: RegistrarCredentials, options?: RegistrarOptions): Registrar;
|
|
438
445
|
readonly displayName: string;
|
|
446
|
+
// the provider's public website domain, e.g. "gandi.net"
|
|
447
|
+
readonly website: string;
|
|
439
448
|
readonly configFields: ConfigField[];
|
|
440
449
|
readonly helpText: string;
|
|
441
450
|
readonly supportsSandbox: boolean;
|