@fwgapps/namecheap 0.6.0 → 1.0.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 CHANGED
@@ -1,98 +1,352 @@
1
1
  # @fwgapps/namecheap
2
2
 
3
- <!-- STATUS -->
4
3
  [![CI/CD Pipeline](https://github.com/fwgapps/namecheap/actions/workflows/publish.yml/badge.svg)](https://github.com/fwgapps/namecheap/actions/workflows/publish.yml)
5
4
  [![Codecov](https://codecov.io/gh/fwgapps/namecheap/branch/main/graph/badge.svg)](https://codecov.io/gh/fwgapps/namecheap)
6
- ![Maintenance](https://img.shields.io/maintenance/yes/2025)
7
-
8
- <!-- NPM -->
9
5
  [![npm](https://img.shields.io/npm/v/@fwgapps/namecheap)](https://www.npmjs.com/package/@fwgapps/namecheap)
10
- ![npm downloads](https://img.shields.io/npm/dm/@fwgapps/namecheap)
11
- [![bundlephobia](https://img.shields.io/bundlephobia/minzip/@fwgapps/namecheap)](https://bundlephobia.com/result?p=@fwgapps/namecheap)
12
- [![dependencies](https://img.shields.io/librariesio/release/npm/@fwgapps/namecheap)](https://libraries.io/npm/@fwgapps/namecheap)
13
-
14
- <!-- META -->
15
6
  ![license](https://img.shields.io/npm/l/@fwgapps/namecheap)
16
7
  ![TypeScript](https://img.shields.io/badge/typescript-%233178C6.svg?logo=typescript)
17
- ![issues](https://img.shields.io/github/issues/fwgapps/namecheap)
18
- ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)
19
- [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
20
8
 
21
- A clean and simple TypeScript wrapper for the Namecheap API, with strongly typed responses and modern developer ergonomics.
9
+ A typed, zero-dependency client for the [Namecheap XML API](https://www.namecheap.com/support/api/intro/). Every command returns a plain, fully typed object instead of raw XML.
10
+
11
+ > Upgrading from 0.x? Read [MIGRATION.md](./MIGRATION.md). Version 1.0 is a complete rewrite and is not backwards compatible.
22
12
 
23
- ## Table of Contents
13
+ ## Table of contents
24
14
 
25
- - [Description](#description)
26
15
  - [Features](#features)
27
16
  - [Installation](#installation)
17
+ - [Quick start](#quick-start)
18
+ - [Configuration](#configuration)
28
19
  - [Usage](#usage)
20
+ - [Using a single command (tree shaking)](#using-a-single-command-tree-shaking)
21
+ - [Error handling](#error-handling)
22
+ - [Safety notes](#safety-notes)
23
+ - [Testing with a fake fetch](#testing-with-a-fake-fetch)
24
+ - [Known gaps](#known-gaps)
29
25
  - [Examples](#examples)
30
- - [Running Tests](#running-tests)
31
- - [Scripts](#scripts)
32
- - [API Coverage](#api-coverage)
33
- - [License](#license)
34
- - [Contributing](#contributing)
35
-
36
- ## Description
37
- A lightweight and developer-friendly TypeScript client for the Namecheap API. Designed for both Node.js and browser environments, it provides full type safety with comprehensive TypeScript definitions. This library simplifies and automates domain management tasks, enabling developers to integrate Namecheap's services seamlessly into their applications.
26
+ - [API coverage](#api-coverage)
27
+ - [Contributing and license](#contributing-and-license)
28
+ - [Attribution](#attribution)
38
29
 
39
30
  ## Features
40
- * Fully typed API responses using TypeScript
41
- * Supports both ESM and CommonJS projects
42
- * Easy-to-use, object-oriented interface
43
- * Works in Node.js and modern runtimes
44
- * Includes real-world usage examples with Express.js
31
+
32
+ - Fully typed parameters and results for 59 Namecheap commands.
33
+ - Zero runtime dependencies: the XML parser is built in (no DTD or external entity support).
34
+ - ESM and CommonJS builds with bundled type declarations.
35
+ - Tree-shakeable: import just the commands you use (see [Using a single command](#using-a-single-command-tree-shaking)).
36
+ - Node.js >= 20 and edge runtimes that provide `fetch` (Cloudflare Workers, Deno, Bun, ...).
37
+ - No automatic retries and no logging.
38
+ - **No browser support, on purpose.** The API key must never reach a browser, and Namecheap only accepts requests from an allow-listed server IP. Call this library from your backend.
45
39
 
46
40
  ## Installation
47
- You can install the library via npm or yarn:
48
41
 
49
- ### Using npm
50
42
  ```bash
51
43
  npm install @fwgapps/namecheap
44
+ # or
45
+ yarn add @fwgapps/namecheap
52
46
  ```
53
47
 
54
- ### Using yarn
55
- ```bash
56
- yarn add @fwgapps/namecheap
48
+ ## Quick start
49
+
50
+ ```ts
51
+ import { Namecheap } from "@fwgapps/namecheap";
52
+
53
+ const nc = new Namecheap({
54
+ apiUser: "your-api-user",
55
+ apiKey: process.env.NAMECHEAP_API_KEY ?? "",
56
+ clientIp: "203.0.113.10", // the public IP you whitelisted at Namecheap
57
+ sandbox: true, // use the sandbox while you experiment
58
+ });
59
+
60
+ const { domains, paging } = await nc.domains.getList({ pageSize: 20 });
61
+ console.log(paging.totalItems, domains.map((d) => d.name));
62
+
63
+ const results = await nc.domains.check({ domainList: "example.com,example.net" });
64
+ console.log(results.map((r) => `${r.domain}: ${r.available}`));
65
+ ```
66
+
67
+ `Namecheap` is both the default export and a named export.
68
+
69
+ ## Configuration
70
+
71
+ ```ts
72
+ const nc = new Namecheap({
73
+ apiUser: "your-api-user", // string, required: your API user name
74
+ apiKey: "your-api-key", // string, required: your API key
75
+ clientIp: "203.0.113.10", // string, required: the whitelisted IP the requests come from
76
+ userName: "account-name", // string, optional: the account to act on, defaults to apiUser
77
+ sandbox: true, // boolean, optional: defaults to false (PRODUCTION)
78
+ fetch: globalThis.fetch, // optional: your own fetch implementation
79
+ timeoutMs: 15_000, // number, optional: abort a request after this many milliseconds
80
+ });
57
81
  ```
58
82
 
59
- ### Browser / CDN Usage
83
+ | Field | Type | Default | Notes |
84
+ | ----------- | --------------------- | ------------------ | --------------------------------------------------------------------------------------- |
85
+ | `apiUser` | `string` | required | Sent as `ApiUser`. |
86
+ | `apiKey` | `string` | required | Sent as `ApiKey`, in the POST body only. |
87
+ | `clientIp` | `string` | required | Sent as `ClientIp`. Must match an IP on your Namecheap API whitelist. |
88
+ | `userName` | `string` | `apiUser` | Sent as `UserName`. Use it when acting on a different account than the API user. |
89
+ | `sandbox` | `boolean` | `false` | Must be a boolean. `true` talks to `api.sandbox.namecheap.com`; `false` or omitted talks to **production**. Any other value throws a `TypeError`. |
90
+ | `fetch` | `typeof fetch` | `globalThis.fetch` | Inject a custom or fake `fetch` (tests, proxies, edge runtimes). |
91
+ | `timeoutMs` | `number` | no timeout | Implemented with `AbortSignal.timeout`; a timeout surfaces as a `NamecheapHttpError`. |
60
92
 
61
- You can also use the library directly in the browser via CDN without bundlers or Node.js.
93
+ > **WARNING: `sandbox` defaults to `false`, which means PRODUCTION.** Forgetting it sends real, billed commands (registrations, renewals, transfers) and changes real DNS. Set `sandbox: true` explicitly while developing. `sandbox` must be a real boolean: a string such as `"true"` throws a `TypeError` at construction instead of silently selecting production, so convert environment variables yourself (`sandbox: process.env.NAMECHEAP_SANDBOX === "true"`).
62
94
 
63
- Just include this script tag in your HTML:
95
+ > **IP whitelist.** Namecheap rejects requests from IP addresses that are not on your API whitelist, in the sandbox and in production. Enable API access and add your server's public IP in the Namecheap dashboard (Profile, Tools, Namecheap API Access), and pass the same address as `clientIp`.
64
96
 
65
- ```html
66
- <script src="https://cdn.jsdelivr.net/npm/@fwgapps/namecheap/dist/index.global.js"></script>
97
+ ## Usage
98
+
99
+ Every group is a property of the client, and every method takes a single params object. Optional parameters can be left out; a method with only optional parameters can be called with no argument.
100
+
101
+ The snippets below assume `nc` is the client from the [Quick start](#quick-start).
102
+
103
+ ### domains
104
+
105
+ ```ts
106
+ const { domains, paging } = await nc.domains.getList({ listType: "EXPIRING", page: 1, pageSize: 50 });
107
+ const availability = await nc.domains.check({ domainList: "example.com,example.org" });
108
+ const info = await nc.domains.getInfo({ domainName: "example.com" });
109
+ const lock = await nc.domains.getRegistrarLock({ domainName: "example.com" });
110
+ await nc.domains.setRegistrarLock({ domainName: "example.com", lockAction: "LOCK" });
111
+ const tlds = await nc.domains.getTldList();
112
+ console.log(domains.length, paging.totalItems, availability[0]?.available, info.domainName, lock.registrarLockStatus, tlds.length);
67
113
  ```
68
114
 
69
- ## Examples
70
- The repository contains real examples, including usage with Express.js:
71
- ```bash
72
- git clone git@github.com:fwgapps/namecheap.git
73
- cd examples/express
74
- yarn
75
- yarn run dev
115
+ `domains.create`, `domains.renew`, `domains.reactivate` and `domains.setContacts` are billed or change ownership data; see the [API coverage](#api-coverage) table and the type definitions for their parameters.
116
+
117
+ ### dns
118
+
119
+ ```ts
120
+ const dnsList = await nc.dns.getList({ sld: "example", tld: "com" });
121
+ const current = await nc.dns.getHosts({ sld: "example", tld: "com" });
122
+ console.log(dnsList.nameservers, current.hosts.length);
123
+
124
+ // Replaces the WHOLE zone, see "Safety notes".
125
+ await nc.dns.setHosts({
126
+ sld: "example",
127
+ tld: "com",
128
+ emailType: "MX",
129
+ hosts: [
130
+ { hostName: "@", recordType: "A", address: "203.0.113.5", ttl: 1800 },
131
+ { hostName: "www", recordType: "CNAME", address: "example.com.", ttl: 1800 },
132
+ { hostName: "@", recordType: "MX", address: "mail.example.com.", mxPref: 10 },
133
+ ],
134
+ });
135
+
136
+ await nc.dns.setDefault({ sld: "example", tld: "com" });
137
+ await nc.dns.setCustom({ sld: "example", tld: "com", nameservers: "ns1.example.net,ns2.example.net" });
138
+ await nc.dns.setEmailForwarding({
139
+ domainName: "example.com",
140
+ forwards: [{ mailBox: "info", forwardTo: "me@example.net" }],
141
+ });
142
+ const forwarding = await nc.dns.getEmailForwarding({ domainName: "example.com" });
143
+ console.log(forwarding.forwards);
76
144
  ```
77
145
 
78
- ## Running Tests
79
- We use Vitest for unit testing:
80
- ```bash
81
- yarn test
146
+ ### ns
147
+
148
+ ```ts
149
+ await nc.ns.create({ sld: "example", tld: "com", nameserver: "ns1.example.com", ip: "203.0.113.20" });
150
+ const ns = await nc.ns.getInfo({ sld: "example", tld: "com", nameserver: "ns1.example.com" });
151
+ await nc.ns.update({ sld: "example", tld: "com", nameserver: "ns1.example.com", oldIP: "203.0.113.20", ip: "203.0.113.21" });
152
+ await nc.ns.delete({ sld: "example", tld: "com", nameserver: "ns1.example.com" });
153
+ console.log(ns.ip);
154
+ ```
155
+
156
+ ### transfer
157
+
158
+ ```ts
159
+ const started = await nc.transfer.create({ domainName: "example.com", years: 1, eppCode: "the-epp-code" });
160
+ const status = await nc.transfer.getStatus({ transferID: started.transferID });
161
+ const { transfers } = await nc.transfer.getList({ listType: "INPROGRESS" });
162
+ await nc.transfer.updateStatus({ transferID: started.transferID, resubmit: true });
163
+ console.log(status.status, transfers.length);
164
+ ```
165
+
166
+ ### ssl
167
+
168
+ ```ts
169
+ const csrInfo = await nc.ssl.parseCSR({ csr: "-----BEGIN CERTIFICATE REQUEST-----\n..." });
170
+ const { certificates } = await nc.ssl.getList({ listType: "Active" });
171
+ const emails = await nc.ssl.getApproverEmailList({ domainName: "example.com", certificateType: "PositiveSSL" });
172
+ const cert = await nc.ssl.getInfo({ certificateID: 12345 });
173
+ console.log(csrInfo.commonName, certificates.length, emails.genericEmails, cert.status);
174
+ ```
175
+
176
+ Activation, reissue, renewal and purchase (`ssl.create`, `ssl.activate`, `ssl.reissue`, `ssl.renew`, `ssl.purchaseMoreSans`) are available too; see [Known gaps](#known-gaps) before relying on the activation flow.
177
+
178
+ ### users
179
+
180
+ ```ts
181
+ const balances = await nc.users.getBalances();
182
+ const pricing = await nc.users.getPricing({ productType: "DOMAIN", productCategory: "DOMAINS", actionName: "REGISTER", productName: "COM" });
183
+ const funds = await nc.users.createAddFundsRequest({ paymentType: "Creditcard", amount: 50, returnUrl: "https://example.com/funds-done" });
184
+ const fundsStatus = await nc.users.getAddFundsStatus({ tokenId: funds.tokenID });
185
+ console.log(balances.availableBalance, pricing.productTypes.length, fundsStatus.status);
186
+ ```
187
+
188
+ ### usersAddress
189
+
190
+ ```ts
191
+ const addresses = await nc.usersAddress.getList();
192
+ const first = addresses[0];
193
+ if (first) {
194
+ const address = await nc.usersAddress.getInfo({ addressId: first.addressId });
195
+ await nc.usersAddress.setDefault({ addressId: first.addressId });
196
+ console.log(address.addressName);
197
+ }
198
+ ```
199
+
200
+ ### whoisGuard
201
+
202
+ The client property is `whoisGuard`. The 0.x name `whoIsGuard` is gone; see the migration guide.
203
+
204
+ ```ts
205
+ const { whoisguards } = await nc.whoisGuard.getList({ listType: "ALLOTED" });
206
+ const subscription = whoisguards[0];
207
+ if (subscription) {
208
+ await nc.whoisGuard.enable({ whoisguardID: subscription.id, forwardedToEmail: "me@example.net" });
209
+ await nc.whoisGuard.changeEmailAddress({ whoisguardID: subscription.id });
210
+ await nc.whoisGuard.disable({ whoisguardID: subscription.id });
211
+ }
212
+ ```
213
+
214
+ ## Using a single command (tree shaking)
215
+
216
+ `new Namecheap(...)` is the convenient entry point, but it carries all 59 commands, because the client object exposes every group. If you only need a few commands (a serverless function, an edge worker), import them one by one and run them with `run`. A bundler then keeps only what you use:
217
+
218
+ ```ts
219
+ import { createTransport, domainsCheck, run } from "@fwgapps/namecheap";
220
+
221
+ const send = createTransport({ apiUser: "user", apiKey: "key", clientIp: "203.0.113.10", sandbox: true });
222
+
223
+ const result = await run(domainsCheck, send, { domainList: "example.com,example.net" });
224
+ ```
225
+
226
+ Every command is also exported on its own, named `<group><Method>`: `domainsCheck`, `dnsSetHosts`, `nsDelete`, `transferGetList`, `sslGetList`, `sslParseCSR`, `usersGetBalances`, `usersAddressCreate`, `whoisGuardRenew`, and so on (the group is the same name you use on the client, with the method capitalized). `run` behaves exactly like the client methods: same validation, same errors, same typing of the parameters.
227
+
228
+ Approximate sizes of a minified bundle (esbuild, measured on this package):
229
+
230
+ | What you import | Minified | Gzip |
231
+ | ---------------------------------------------- | -------: | -----: |
232
+ | only the error classes | ~0.3 KB | ~0.2 KB |
233
+ | `createTransport` + one command + `run` | ~9.4 KB | ~3.8 KB |
234
+ | `createTransport` + two commands + `run` | ~9.9 KB | ~4.0 KB |
235
+ | the `Namecheap` class (any use of it) | ~29.6 KB | ~8.4 KB |
236
+
237
+ The package declares `"sideEffects": false`, and a test in this repository bundles a single-command consumer to make sure the other commands stay out of the bundle.
238
+
239
+ ## Error handling
240
+
241
+ All API, HTTP and response failures are instances of one of three `Error` subclasses, exported from the package. Programmer or configuration mistakes (an invalid `sandbox`, `dns.setHosts` validation, serializer rejections, reserved parameter names) throw a plain `TypeError` instead.
242
+
243
+ | Class | Thrown when | Useful fields |
244
+ | ---------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------- |
245
+ | `NamecheapError` | The API answered with `Status="ERROR"`. | `code` (first error number), `errors` (all) |
246
+ | `NamecheapHttpError` | The request failed (network, timeout, redirect) or the HTTP status is not 2xx. | `status`, `statusText`, `cause` |
247
+ | `NamecheapParseError` | The body is not valid XML, is not a Namecheap envelope, or lacks a documented field. | `message`, `cause` |
248
+
249
+ ```ts
250
+ import { Namecheap, NamecheapError, NamecheapHttpError, NamecheapParseError } from "@fwgapps/namecheap";
251
+
252
+ const nc = new Namecheap({ apiUser: "user", apiKey: "key", clientIp: "203.0.113.10", sandbox: true });
253
+
254
+ try {
255
+ await nc.dns.getHosts({ sld: "example", tld: "com" });
256
+ } catch (error) {
257
+ if (error instanceof NamecheapError) {
258
+ console.error(error.code, error.message, error.errors);
259
+ } else if (error instanceof NamecheapHttpError) {
260
+ console.error(error.status, error.statusText);
261
+ } else if (error instanceof NamecheapParseError) {
262
+ console.error("Unexpected response shape:", error.message);
263
+ } else {
264
+ throw error;
265
+ }
266
+ }
267
+ ```
268
+
269
+ Error messages never contain request data or credentials. Apart from `NamecheapError`, whose message is Namecheap's own error text, they contain at most short fragments of the response (element or attribute names, a truncated entity name).
270
+
271
+ **There are no automatic retries, on purpose.** Many commands are billed (register, renew, transfer, purchase). Retrying a request whose outcome is unknown could charge you twice. Decide per call whether a retry is safe; read-only commands such as `getList` or `check` usually are.
272
+
273
+ After a billed or account-changing command, a `NamecheapParseError` (Namecheap answered OK but the response could not be read) or a `timeoutMs` abort means the outcome is **unknown**: the action may have been performed. Reconcile with `getList` or `getInfo` before retrying.
274
+
275
+ **HTTP 405 means rate limiting.** Namecheap answers 405 when you exceed its request limits, so a `NamecheapHttpError` with `status === 405` is a signal to slow down, not a bug in your request.
276
+
277
+ ## Safety notes
278
+
279
+ - `dns.setHosts` **replaces the whole zone**: every record you do not list is deleted. Read the current records with `dns.getHosts` first and send the complete desired list. The library rejects an empty `hosts` list with a `TypeError` before sending anything.
280
+ - `dns.setHosts` with `emailType` other than `MX`: the reference says MX records are silently discarded unless the resulting email mode is `MX`. Because `setHosts` replaces the whole zone, listing MX hosts under another mode loses your mail routing.
281
+ - Credentials travel in the POST body (`application/x-www-form-urlencoded`), never in the URL, so they do not end up in access logs or proxies that record URLs.
282
+ - The library never logs anything. Do not log the client config or error `cause` objects from your own code in production.
283
+ - `sandbox` defaults to production. See the [warning above](#configuration).
284
+
285
+ ## Testing with a fake fetch
286
+
287
+ Pass your own `fetch` to test your code without network access or credentials:
288
+
289
+ ```ts
290
+ import { Namecheap } from "@fwgapps/namecheap";
291
+
292
+ const xml = `<?xml version="1.0" encoding="utf-8"?>
293
+ <ApiResponse Status="OK" xmlns="http://api.namecheap.com/xml.response">
294
+ <Errors />
295
+ <RequestedCommand>namecheap.domains.dns.setDefault</RequestedCommand>
296
+ <CommandResponse Type="namecheap.domains.dns.setDefault">
297
+ <DomainDNSSetDefaultResult Domain="example.com" Updated="true" />
298
+ </CommandResponse>
299
+ </ApiResponse>`;
300
+
301
+ const calls: Array<{ url: string; body: string }> = [];
302
+ const fakeFetch: typeof fetch = async (input, init) => {
303
+ calls.push({ url: String(input), body: String(init?.body) });
304
+ return new Response(xml, { status: 200 });
305
+ };
306
+
307
+ const nc = new Namecheap({ apiUser: "u", apiKey: "k", clientIp: "127.0.0.1", sandbox: true, fetch: fakeFetch });
308
+ const result = await nc.dns.setDefault({ sld: "example", tld: "com" });
309
+ console.log(result.updated, calls[0]?.url);
82
310
  ```
83
311
 
84
- ## Scripts
85
- * `build`: Compile the code using tsup
86
- * `test`: Run tests with Vitest
87
- * `lint`: Lint code using ESLint
88
- * `release`: Release a new version using semantic-release
312
+ ## Known gaps
313
+
314
+ 1. `ssl.activate` and `ssl.reissue` do not expose domain control validation (DCV) parameters or the 0.6 OV/EV organisation option sets (organisation, department, admin address, company registration fields), because the API reference does not document them. Confirm the activation flow in the sandbox before relying on it.
315
+ 2. `users.create`, `users.login`, `users.resetPassword`, `whoisGuard.renew`, `ssl.create`, `ssl.renew` and `ssl.purchaseMoreSans` have undocumented response shapes. They return loosely typed results parsed tolerantly: they never throw on an unexpected shape, and fields that cannot be read are simply absent.
316
+ 3. `dns.setEmailForwarding` sends `MailBox<n>` as spelled in the API reference; the Go SDK sends lowercase. This is unverified against the live API.
317
+ 4. CAA (`Flag`/`Tag`) records are not supported by `dns.setHosts`.
318
+ 5. `ssl.getInfo` accepts `returnCertificate` and sends it, but 1.0 does not parse the certificate body (its response shape is undocumented), so the result never contains the certificate.
319
+ 6. WhoisGuard `allot`, `unallot` and `discard` are not implemented.
320
+ 7. `domains.create` no longer exposes `idnCode`, the billing contact and `extendedAttributes`, which 0.6 did. IDN registrations and some ccTLDs (such as .us, .ca, .eu) need them, and the API reference does not document them. Unknown extra keys still pass through the serializer, so you can try a workaround such as `nc.domains.create({ ...params, ExtendedAttributes: "..." } as never)`, unverified against the live API.
321
+ 8. Test fixtures marked `source: docs` or `source: go-namecheap-sdk` have not all been verified against the live sandbox. `scripts/record-fixtures.mjs` re-records them from a real sandbox account.
322
+
323
+ ## Examples
324
+
325
+ [`examples/express`](./examples/express) is a REST bridge that exposes the client through Express routes and maps the three error classes to HTTP status codes. It is an example, not a service: it has no authentication.
326
+
327
+ ## API coverage
328
+
329
+ 59 commands, all reachable as `nc.<group>.<method>`.
330
+
331
+ The package also exports the command tables behind each group (`domainsCommands`, `dnsCommands`, and so on) for custom integrations. They are advanced API: they are not covered by semver stability, so prefer `nc.<group>.<method>`.
332
+
333
+ | Group (`nc.`) | Methods | Count |
334
+ | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----: |
335
+ | `domains` | `getList`, `check`, `getRegistrarLock`, `setRegistrarLock`, `reactivate`, `renew`, `setContacts`, `create`, `getTldList`, `getContacts`, `getInfo` | 11 |
336
+ | `dns` | `setDefault`, `setCustom`, `getList`, `getHosts`, `getEmailForwarding`, `setEmailForwarding`, `setHosts` | 7 |
337
+ | `ns` | `create`, `delete`, `getInfo`, `update` | 4 |
338
+ | `transfer` | `create`, `getStatus`, `updateStatus`, `getList` | 4 |
339
+ | `ssl` | `create`, `getList`, `parseCSR`, `getApproverEmailList`, `activate`, `resendApproverEmail`, `reissue`, `resendFulfillmentEmail`, `editDCVMethod`, `getInfo`, `renew`, `purchaseMoreSans`, `revokeCertificate` | 13 |
340
+ | `users` | `getBalances`, `getPricing`, `changePassword`, `update`, `createAddFundsRequest`, `getAddFundsStatus`, `create`, `login`, `resetPassword` | 9 |
341
+ | `usersAddress` | `create`, `delete`, `getInfo`, `getList`, `setDefault`, `update` | 6 |
342
+ | `whoisGuard` | `changeEmailAddress`, `enable`, `disable`, `getList`, `renew` | 5 |
343
+
344
+ ## Contributing and license
89
345
 
90
- ## API Coverage
91
- Check the [API Docs](https://www.namecheap.com/support/api/methods) for full endpoint support. This library aims to cover the most-used endpoints first, with plans to expand.
346
+ Issues and pull requests are welcome. The project uses Conventional Commits (`yarn commit` starts Commitizen) and semantic-release. Before opening a pull request run `yarn lint && yarn typecheck && yarn test --run --coverage && yarn build`.
92
347
 
93
- ## License
94
- This project is licensed under the [ISC License](./LICENSE).
348
+ Licensed under the [ISC license](./LICENSE).
95
349
 
96
- ## Contributing
97
- Feel free to open an issue or submit a pull request if you'd like to contribute!
350
+ ## Attribution
98
351
 
352
+ Some test fixtures are copied or derived from [namecheap/go-namecheap-sdk](https://github.com/namecheap/go-namecheap-sdk), licensed under Apache-2.0. See [NOTICE](./NOTICE).