@aoxborrow/registrar-client 0.11.0 → 0.12.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 +10 -7
- package/dist/index.cjs +163 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +163 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/registrars/gandi.ts +91 -3
- package/src/registrars/godaddy.ts +136 -8
package/dist/index.d.cts
CHANGED
|
@@ -594,6 +594,10 @@ declare class GandiRegistrar extends BaseRegistrar {
|
|
|
594
594
|
lockDomain(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
595
595
|
unlockDomain(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
596
596
|
getAuthCode(domainName: string, opts?: RequestOptions): Promise<string>;
|
|
597
|
+
getTransferOut(domainName: string, opts?: RequestOptions): Promise<TransferOut | null>;
|
|
598
|
+
approveTransferOut(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
599
|
+
rejectTransferOut(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
600
|
+
private answerTransferOut;
|
|
597
601
|
getDnssec(domainName: string, opts?: RequestOptions): Promise<DnssecStatus>;
|
|
598
602
|
disableDnssec(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
599
603
|
getEmailForwarding(domainName: string, opts?: RequestOptions): Promise<EmailForward[]>;
|
|
@@ -653,6 +657,11 @@ declare class GoDaddyRegistrar extends BaseRegistrar {
|
|
|
653
657
|
getDomainForwarding(domainName: string, opts?: RequestOptions): Promise<DomainForward[]>;
|
|
654
658
|
setDomainForwarding(domainName: string, forwards: DomainForward[], opts?: RequestOptions): Promise<OperationResult>;
|
|
655
659
|
private forwardPath;
|
|
660
|
+
private domainPathV2;
|
|
661
|
+
getTransferOut(domainName: string, opts?: RequestOptions): Promise<TransferOut | null>;
|
|
662
|
+
approveTransferOut(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
663
|
+
rejectTransferOut(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
664
|
+
private answerTransferOut;
|
|
656
665
|
getAuthCode(domainName: string, opts?: RequestOptions): Promise<string>;
|
|
657
666
|
private toDomain;
|
|
658
667
|
private toDomainV3;
|
package/dist/index.d.ts
CHANGED
|
@@ -594,6 +594,10 @@ declare class GandiRegistrar extends BaseRegistrar {
|
|
|
594
594
|
lockDomain(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
595
595
|
unlockDomain(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
596
596
|
getAuthCode(domainName: string, opts?: RequestOptions): Promise<string>;
|
|
597
|
+
getTransferOut(domainName: string, opts?: RequestOptions): Promise<TransferOut | null>;
|
|
598
|
+
approveTransferOut(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
599
|
+
rejectTransferOut(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
600
|
+
private answerTransferOut;
|
|
597
601
|
getDnssec(domainName: string, opts?: RequestOptions): Promise<DnssecStatus>;
|
|
598
602
|
disableDnssec(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
599
603
|
getEmailForwarding(domainName: string, opts?: RequestOptions): Promise<EmailForward[]>;
|
|
@@ -653,6 +657,11 @@ declare class GoDaddyRegistrar extends BaseRegistrar {
|
|
|
653
657
|
getDomainForwarding(domainName: string, opts?: RequestOptions): Promise<DomainForward[]>;
|
|
654
658
|
setDomainForwarding(domainName: string, forwards: DomainForward[], opts?: RequestOptions): Promise<OperationResult>;
|
|
655
659
|
private forwardPath;
|
|
660
|
+
private domainPathV2;
|
|
661
|
+
getTransferOut(domainName: string, opts?: RequestOptions): Promise<TransferOut | null>;
|
|
662
|
+
approveTransferOut(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
663
|
+
rejectTransferOut(domainName: string, opts?: RequestOptions): Promise<OperationResult>;
|
|
664
|
+
private answerTransferOut;
|
|
656
665
|
getAuthCode(domainName: string, opts?: RequestOptions): Promise<string>;
|
|
657
666
|
private toDomain;
|
|
658
667
|
private toDomainV3;
|
package/dist/index.js
CHANGED
|
@@ -3210,9 +3210,9 @@ var GandiRegistrar = class extends BaseRegistrar {
|
|
|
3210
3210
|
];
|
|
3211
3211
|
// Gandi's v5 API offers a sandbox at api.sandbox.gandi.net (separate account)
|
|
3212
3212
|
static supportsSandbox = true;
|
|
3213
|
-
// On top of core: transfer-out auth code (`authinfo`), DNSSEC
|
|
3214
|
-
// (LiveDNS keys), email forwarding, and web/URL forwarding
|
|
3215
|
-
// per host, apex included). Note core `setPrivacy` disabling is a no-op for
|
|
3213
|
+
// On top of core: transfer-out auth code (`authinfo`) and approval, DNSSEC
|
|
3214
|
+
// read/disable (LiveDNS keys), email forwarding, and web/URL forwarding
|
|
3215
|
+
// (webredirs; per host, apex included). Note core `setPrivacy` disabling is a no-op for
|
|
3216
3216
|
// individual (natural-person) registrants — Gandi keeps WHOIS obfuscation on
|
|
3217
3217
|
// for GDPR regardless of the request.
|
|
3218
3218
|
static extendedFeatures = [
|
|
@@ -3222,7 +3222,10 @@ var GandiRegistrar = class extends BaseRegistrar {
|
|
|
3222
3222
|
Feature.GetEmailForwarding,
|
|
3223
3223
|
Feature.SetEmailForwarding,
|
|
3224
3224
|
Feature.GetDomainForwarding,
|
|
3225
|
-
Feature.SetDomainForwarding
|
|
3225
|
+
Feature.SetDomainForwarding,
|
|
3226
|
+
Feature.GetTransferOut,
|
|
3227
|
+
Feature.ApproveTransferOut,
|
|
3228
|
+
Feature.RejectTransferOut
|
|
3226
3229
|
];
|
|
3227
3230
|
constructor(credentials, options) {
|
|
3228
3231
|
super(
|
|
@@ -3474,6 +3477,58 @@ var GandiRegistrar = class extends BaseRegistrar {
|
|
|
3474
3477
|
});
|
|
3475
3478
|
return d.authinfo ?? "";
|
|
3476
3479
|
}
|
|
3480
|
+
/**
|
|
3481
|
+
* The domain's pending outbound transfer. Gandi has no transfer-out resource
|
|
3482
|
+
* to read: a domain in the account carries the documented `pendingTransfer`
|
|
3483
|
+
* EPP status while another registrar's request waits (inbound transfers live
|
|
3484
|
+
* under /domain/transferin, so on a domain you hold it's outbound — inferred,
|
|
3485
|
+
* not documented). Gandi reports no dates for it, and nothing once it's
|
|
3486
|
+
* answered or done, so this reads `pending` or null.
|
|
3487
|
+
*/
|
|
3488
|
+
async getTransferOut(domainName, opts) {
|
|
3489
|
+
const d = await this.http.request({
|
|
3490
|
+
path: `/domain/domains/${domainName}`,
|
|
3491
|
+
...opts
|
|
3492
|
+
});
|
|
3493
|
+
return pendingTransferOut(d);
|
|
3494
|
+
}
|
|
3495
|
+
/**
|
|
3496
|
+
* Approves the pending outbound transfer, releasing the domain now instead of
|
|
3497
|
+
* after Gandi's five days: POST .../transferout with `accept: true` and the
|
|
3498
|
+
* domain's current auth code, which Gandi requires back (→ 202).
|
|
3499
|
+
*/
|
|
3500
|
+
async approveTransferOut(domainName, opts) {
|
|
3501
|
+
return this.answerTransferOut(domainName, true, opts);
|
|
3502
|
+
}
|
|
3503
|
+
// Declines the pending outbound transfer (`accept: false`, no reason); the
|
|
3504
|
+
// domain stays in the account.
|
|
3505
|
+
async rejectTransferOut(domainName, opts) {
|
|
3506
|
+
return this.answerTransferOut(domainName, false, opts);
|
|
3507
|
+
}
|
|
3508
|
+
// One read for both the pending status and the auth code the answer needs.
|
|
3509
|
+
async answerTransferOut(domainName, accept, opts) {
|
|
3510
|
+
let d;
|
|
3511
|
+
try {
|
|
3512
|
+
d = await this.http.request({
|
|
3513
|
+
path: `/domain/domains/${domainName}`,
|
|
3514
|
+
...opts
|
|
3515
|
+
});
|
|
3516
|
+
} catch (error) {
|
|
3517
|
+
return { success: false, message: toRegistrarError(error).message };
|
|
3518
|
+
}
|
|
3519
|
+
if (!pendingTransferOut(d)) {
|
|
3520
|
+
return { success: false, message: `No transfer-out of ${domainName} to answer` };
|
|
3521
|
+
}
|
|
3522
|
+
return this.mutate(
|
|
3523
|
+
{
|
|
3524
|
+
method: "POST",
|
|
3525
|
+
path: `/domain/domains/${domainName}/transferout`,
|
|
3526
|
+
body: { accept, authinfo: d.authinfo ?? "" }
|
|
3527
|
+
},
|
|
3528
|
+
`Transfer of ${domainName} ${accept ? "approved" : "rejected"}`,
|
|
3529
|
+
opts
|
|
3530
|
+
);
|
|
3531
|
+
}
|
|
3477
3532
|
/**
|
|
3478
3533
|
* DNSSEC status via Gandi LiveDNS keys (GET /livedns/domains/{fqdn}/keys). A
|
|
3479
3534
|
* non-deleted key means DNSSEC is enabled; each key's `ds` field is the full DS
|
|
@@ -3841,6 +3896,17 @@ var GandiRegistrar = class extends BaseRegistrar {
|
|
|
3841
3896
|
}
|
|
3842
3897
|
}
|
|
3843
3898
|
};
|
|
3899
|
+
function pendingTransferOut(d) {
|
|
3900
|
+
const statuses = Array.isArray(d.status) ? d.status : d.status ? [d.status] : [];
|
|
3901
|
+
if (!statuses.includes("pendingTransfer")) return null;
|
|
3902
|
+
return {
|
|
3903
|
+
status: "pending",
|
|
3904
|
+
rawStatus: "pendingTransfer",
|
|
3905
|
+
requestedDate: null,
|
|
3906
|
+
expirationDate: null,
|
|
3907
|
+
completedDate: null
|
|
3908
|
+
};
|
|
3909
|
+
}
|
|
3844
3910
|
function toGandiContact(c) {
|
|
3845
3911
|
const contact = {
|
|
3846
3912
|
given: c.firstName,
|
|
@@ -3981,17 +4047,22 @@ var GoDaddyRegistrar = class _GoDaddyRegistrar extends BaseRegistrar {
|
|
|
3981
4047
|
];
|
|
3982
4048
|
// GoDaddy's OTE ("Operational Test Environment") is its sandbox
|
|
3983
4049
|
static supportsSandbox = true;
|
|
3984
|
-
// Beyond core: domain forwarding
|
|
3985
|
-
// field on the v1 domain-detail response)
|
|
3986
|
-
// customer-scoped route
|
|
3987
|
-
//
|
|
3988
|
-
//
|
|
4050
|
+
// Beyond core: domain forwarding, transfer-out auth code (the `authCode`
|
|
4051
|
+
// field on the v1 domain-detail response) and transfer-out approval.
|
|
4052
|
+
// Forwarding uses the v2 customer-scoped route
|
|
4053
|
+
// /v2/customers/{customerId}/domains/forwards/{fqdn} (the old v1
|
|
4054
|
+
// /v1/domains/forwards routes now 404); it requires `customerId` to be
|
|
4055
|
+
// configured — verified live 2026-08-29. Transfer-out approval is v2
|
|
4056
|
+
// customer-scoped too, so it needs `customerId` as well. DNSSEC has no dedicated
|
|
3989
4057
|
// endpoint (DS records go through the generic DNS API), and there's no
|
|
3990
4058
|
// glue-record, email, or push-webhook API.
|
|
3991
4059
|
static extendedFeatures = [
|
|
3992
4060
|
Feature.GetAuthCode,
|
|
3993
4061
|
Feature.GetDomainForwarding,
|
|
3994
|
-
Feature.SetDomainForwarding
|
|
4062
|
+
Feature.SetDomainForwarding,
|
|
4063
|
+
Feature.GetTransferOut,
|
|
4064
|
+
Feature.ApproveTransferOut,
|
|
4065
|
+
Feature.RejectTransferOut
|
|
3995
4066
|
];
|
|
3996
4067
|
// true → prefer the v3 API (production + PAT). false → all calls use v1
|
|
3997
4068
|
// (sso-key auth, or OTE/sandbox where v3 does not exist).
|
|
@@ -4592,7 +4663,7 @@ var GoDaddyRegistrar = class _GoDaddyRegistrar extends BaseRegistrar {
|
|
|
4592
4663
|
const configured = this.credentials.customerId?.trim();
|
|
4593
4664
|
if (!configured) {
|
|
4594
4665
|
throw new ConfigurationError(
|
|
4595
|
-
`${this.name}: domain forwarding
|
|
4666
|
+
`${this.name}: domain forwarding and transfer-out approval use the v2 customer-scoped API, which requires a customer ID. Set \`customerId\` to your GoDaddy customer UUID (or your numeric shopper/account ID, which will be resolved to the UUID).`
|
|
4596
4667
|
);
|
|
4597
4668
|
}
|
|
4598
4669
|
if (UUID_RE.test(configured)) return configured;
|
|
@@ -4692,6 +4763,52 @@ var GoDaddyRegistrar = class _GoDaddyRegistrar extends BaseRegistrar {
|
|
|
4692
4763
|
forwardPath(customerId, fqdn) {
|
|
4693
4764
|
return `/v2/customers/${encodeURIComponent(customerId)}/domains/forwards/${encodeURIComponent(fqdn)}`;
|
|
4694
4765
|
}
|
|
4766
|
+
// the v2 customer-scoped path for a domain
|
|
4767
|
+
domainPathV2(customerId, domainName) {
|
|
4768
|
+
return `/v2/customers/${encodeURIComponent(customerId)}/domains/${encodeURIComponent(domainName)}`;
|
|
4769
|
+
}
|
|
4770
|
+
/**
|
|
4771
|
+
* The domain's latest outbound transfer, read from its recent actions
|
|
4772
|
+
* (GET /v2/customers/{customerId}/domains/{domain}/actions): the TRANSFER_OUT
|
|
4773
|
+
* action, and an accept or reject logged after it. Null when there is no
|
|
4774
|
+
* TRANSFER_OUT on record. GoDaddy reports no expiry; left alone, it releases
|
|
4775
|
+
* the domain within seven days. Shapes from the published v2 spec; a real
|
|
4776
|
+
* transfer-out is not yet seen live.
|
|
4777
|
+
*/
|
|
4778
|
+
async getTransferOut(domainName, opts) {
|
|
4779
|
+
const customerId = await this.resolveCustomerId(opts);
|
|
4780
|
+
const actions = await this.http.request({
|
|
4781
|
+
path: `${this.domainPathV2(customerId, domainName)}/actions`,
|
|
4782
|
+
...opts
|
|
4783
|
+
});
|
|
4784
|
+
return toTransferOut2(Array.isArray(actions) ? actions : []);
|
|
4785
|
+
}
|
|
4786
|
+
/**
|
|
4787
|
+
* Approves the pending outbound transfer, releasing the domain now
|
|
4788
|
+
* (POST .../transferOutAccept → 202). GoDaddy answers 409 when none is
|
|
4789
|
+
* pending.
|
|
4790
|
+
*/
|
|
4791
|
+
async approveTransferOut(domainName, opts) {
|
|
4792
|
+
return this.answerTransferOut(domainName, "transferOutAccept", "approved", opts);
|
|
4793
|
+
}
|
|
4794
|
+
// Rejects the pending outbound transfer (POST .../transferOutReject, with no
|
|
4795
|
+
// reason); the domain stays in the account.
|
|
4796
|
+
async rejectTransferOut(domainName, opts) {
|
|
4797
|
+
return this.answerTransferOut(domainName, "transferOutReject", "rejected", opts);
|
|
4798
|
+
}
|
|
4799
|
+
async answerTransferOut(domainName, action, answer, opts) {
|
|
4800
|
+
let customerId;
|
|
4801
|
+
try {
|
|
4802
|
+
customerId = await this.resolveCustomerId(opts);
|
|
4803
|
+
} catch (error) {
|
|
4804
|
+
return { success: false, message: toRegistrarError(error).message };
|
|
4805
|
+
}
|
|
4806
|
+
return this.mutate(
|
|
4807
|
+
{ method: "POST", path: `${this.domainPathV2(customerId, domainName)}/${action}` },
|
|
4808
|
+
`Transfer of ${domainName} ${answer}`,
|
|
4809
|
+
opts
|
|
4810
|
+
);
|
|
4811
|
+
}
|
|
4695
4812
|
/**
|
|
4696
4813
|
* Transfer authorization (EPP) code. GoDaddy exposes it as the `authCode`
|
|
4697
4814
|
* field on the v1 domain-detail response; transfers were never moved to v3,
|
|
@@ -4748,6 +4865,41 @@ var GoDaddyRegistrar = class _GoDaddyRegistrar extends BaseRegistrar {
|
|
|
4748
4865
|
}
|
|
4749
4866
|
}
|
|
4750
4867
|
};
|
|
4868
|
+
function toTransferOut2(actions) {
|
|
4869
|
+
const time = (a) => parseDate(a.createdAt)?.getTime() ?? 0;
|
|
4870
|
+
const byLatest = (types) => actions.filter((a) => types.includes(a.type ?? "")).sort((a, b) => time(b) - time(a));
|
|
4871
|
+
const transfer = byLatest(["TRANSFER_OUT"])[0];
|
|
4872
|
+
if (!transfer) return null;
|
|
4873
|
+
const answer = byLatest(["TRANSFER_OUT_ACCEPT", "TRANSFER_OUT_REJECT"]).find(
|
|
4874
|
+
(a) => time(a) >= time(transfer) && !/^(FAILED|CANCELLED)$/i.test(a.status ?? "")
|
|
4875
|
+
);
|
|
4876
|
+
const rejected = answer?.type === "TRANSFER_OUT_REJECT";
|
|
4877
|
+
const rawStatus = transfer.status ?? "";
|
|
4878
|
+
let status;
|
|
4879
|
+
switch (rawStatus.toUpperCase()) {
|
|
4880
|
+
case "ACCEPTED":
|
|
4881
|
+
case "AWAITING":
|
|
4882
|
+
case "PENDING":
|
|
4883
|
+
status = !answer ? "pending" : rejected ? "rejected" : "approved";
|
|
4884
|
+
break;
|
|
4885
|
+
case "SUCCESS":
|
|
4886
|
+
status = "completed";
|
|
4887
|
+
break;
|
|
4888
|
+
case "FAILED":
|
|
4889
|
+
case "CANCELLED":
|
|
4890
|
+
status = rejected ? "rejected" : "cancelled";
|
|
4891
|
+
break;
|
|
4892
|
+
default:
|
|
4893
|
+
status = "unknown";
|
|
4894
|
+
}
|
|
4895
|
+
return {
|
|
4896
|
+
status,
|
|
4897
|
+
rawStatus,
|
|
4898
|
+
requestedDate: parseDate(transfer.createdAt),
|
|
4899
|
+
expirationDate: null,
|
|
4900
|
+
completedDate: status === "completed" ? parseDate(transfer.completedAt) : null
|
|
4901
|
+
};
|
|
4902
|
+
}
|
|
4751
4903
|
function fromGoDaddyContact(c) {
|
|
4752
4904
|
if (!c) return void 0;
|
|
4753
4905
|
const a = c.addressMailing ?? {};
|