initial
This commit is contained in:
commit
fcc11dd5f6
66
.gitea/workflows/default_nottags.yaml
Normal file
66
.gitea/workflows/default_nottags.yaml
Normal file
@ -0,0 +1,66 @@
|
||||
name: Default (not tags)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags-ignore:
|
||||
- '**'
|
||||
|
||||
env:
|
||||
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
|
||||
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
|
||||
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install pnpm and npmci
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
|
||||
- name: Run npm prepare
|
||||
run: npmci npm prepare
|
||||
|
||||
- name: Audit production dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --prod
|
||||
continue-on-error: true
|
||||
|
||||
- name: Audit development dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --dev
|
||||
continue-on-error: true
|
||||
|
||||
test:
|
||||
if: ${{ always() }}
|
||||
needs: security
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Test stable
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm test
|
||||
|
||||
- name: Test build
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm build
|
124
.gitea/workflows/default_tags.yaml
Normal file
124
.gitea/workflows/default_tags.yaml
Normal file
@ -0,0 +1,124 @@
|
||||
name: Default (tags)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
|
||||
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
|
||||
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Audit production dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --prod
|
||||
continue-on-error: true
|
||||
|
||||
- name: Audit development dependencies
|
||||
run: |
|
||||
npmci command npm config set registry https://registry.npmjs.org
|
||||
npmci command pnpm audit --audit-level=high --dev
|
||||
continue-on-error: true
|
||||
|
||||
test:
|
||||
if: ${{ always() }}
|
||||
needs: security
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Test stable
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm test
|
||||
|
||||
- name: Test build
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
npmci npm build
|
||||
|
||||
release:
|
||||
needs: test
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Release
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm publish
|
||||
|
||||
metadata:
|
||||
needs: test
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ env.IMAGE }}
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
pnpm install -g pnpm
|
||||
pnpm install -g @ship.zone/npmci
|
||||
npmci npm prepare
|
||||
|
||||
- name: Code quality
|
||||
run: |
|
||||
npmci command npm install -g typescript
|
||||
npmci npm install
|
||||
|
||||
- name: Trigger
|
||||
run: npmci trigger
|
||||
|
||||
- name: Build docs and upload artifacts
|
||||
run: |
|
||||
npmci node install stable
|
||||
npmci npm install
|
||||
pnpm install -g @git.zone/tsdoc
|
||||
npmci command tsdoc
|
||||
continue-on-error: true
|
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
.nogit/
|
||||
|
||||
# artifacts
|
||||
coverage/
|
||||
public/
|
||||
|
||||
# installs
|
||||
node_modules/
|
||||
|
||||
# caches
|
||||
.yarn/
|
||||
.cache/
|
||||
.rpt2_cache
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_*/
|
||||
|
||||
#------# custom
|
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "npm test",
|
||||
"name": "Run npm test",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": ["/npmextra.json"],
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"npmci": {
|
||||
"type": "object",
|
||||
"description": "settings for npmci"
|
||||
},
|
||||
"gitzone": {
|
||||
"type": "object",
|
||||
"description": "settings for gitzone",
|
||||
"properties": {
|
||||
"projectType": {
|
||||
"type": "string",
|
||||
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
18
npmextra.json
Normal file
18
npmextra.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"gitzone": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "code.foss.global",
|
||||
"gitscope": "apiclient.xyz",
|
||||
"gitrepo": "namecheap",
|
||||
"description": "unofficial namecheap API client",
|
||||
"npmPackagename": "@apiclient.xyz/namecheap",
|
||||
"license": "MIT",
|
||||
"projectDomain": "apiclient.xyz"
|
||||
}
|
||||
},
|
||||
"npmci": {
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public"
|
||||
}
|
||||
}
|
55
package.json
Normal file
55
package.json
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "@apiclient.xyz/namecheap",
|
||||
"version": "1.0.1",
|
||||
"private": false,
|
||||
"description": "unofficial namecheap API client",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"type": "module",
|
||||
"author": "Task Venture Capital GmbH",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "(tstest test/ --web)",
|
||||
"build": "(tsbuild --web --allowimplicitany)",
|
||||
"buildDocs": "(tsdoc)"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^2.1.25",
|
||||
"@git.zone/tsbundle": "^2.0.5",
|
||||
"@git.zone/tsrun": "^1.2.46",
|
||||
"@git.zone/tstest": "^1.0.44",
|
||||
"@push.rocks/tapbundle": "^5.0.15",
|
||||
"@types/node": "^20.8.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@push.rocks/qenv": "^6.1.0",
|
||||
"@push.rocks/smartpath": "^5.0.18",
|
||||
"@types/xml2js": "^0.4.14",
|
||||
"axios": "^1.8.4",
|
||||
"xml2js": "^0.6.2"
|
||||
},
|
||||
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://code.foss.global/apiclient.xyz/namecheap.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://code.foss.global/apiclient.xyz/namecheap/issues"
|
||||
},
|
||||
"homepage": "https://code.foss.global/apiclient.xyz/namecheap#readme",
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
"ts_web/**/*",
|
||||
"dist/**/*",
|
||||
"dist_*/**/*",
|
||||
"dist_ts/**/*",
|
||||
"dist_ts_web/**/*",
|
||||
"assets/**/*",
|
||||
"cli.js",
|
||||
"npmextra.json",
|
||||
"readme.md"
|
||||
],
|
||||
"pnpm": {
|
||||
"overrides": {}
|
||||
}
|
||||
}
|
9932
pnpm-lock.yaml
generated
Normal file
9932
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
3
readme.hints.md
Normal file
3
readme.hints.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Project Readme Hints
|
||||
|
||||
This is the initial readme hints file.
|
505
readme.md
Normal file
505
readme.md
Normal file
@ -0,0 +1,505 @@
|
||||
# Namecheap API Client
|
||||
|
||||
A comprehensive TypeScript client for the Namecheap API, providing a clean, type-safe interface for domain management, DNS configuration, and domain transfers.
|
||||
|
||||
[](https://www.npmjs.com/package/@apiclient.xyz/namecheap)
|
||||
[](https://github.com/apiclient-xyz/namecheap/blob/main/LICENSE)
|
||||
|
||||
## Features
|
||||
|
||||
- **Complete API Coverage**: Supports all major Namecheap API endpoints
|
||||
- **Type Safety**: Full TypeScript definitions for all API requests and responses
|
||||
- **Error Handling**: Comprehensive error handling with detailed error messages
|
||||
- **Sandbox Support**: Test your integration with the Namecheap sandbox environment
|
||||
- **Modular Design**: Organized into logical modules for different API functionalities
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Using npm
|
||||
npm install @apiclient.xyz/namecheap
|
||||
|
||||
# Using yarn
|
||||
yarn add @apiclient.xyz/namecheap
|
||||
|
||||
# Using pnpm
|
||||
pnpm add @apiclient.xyz/namecheap
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { NamecheapClient } from '@apiclient.xyz/namecheap';
|
||||
|
||||
// Create a new client instance
|
||||
const client = new NamecheapClient({
|
||||
apiUser: 'your-api-username',
|
||||
apiKey: 'your-api-key',
|
||||
userName: 'your-username', // Often the same as apiUser
|
||||
clientIp: 'your-ip-address'
|
||||
}, true); // true for sandbox mode, false for production
|
||||
|
||||
// Check if a domain is available
|
||||
const availability = await client.domains.check('example.com');
|
||||
console.log(`Domain is ${availability[0].available ? 'available' : 'not available'}`);
|
||||
|
||||
// Get a list of domains in your account
|
||||
const domainList = await client.domains.getList();
|
||||
console.log(`You have ${domainList.domains.length} domains`);
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
|
||||
### Client Initialization
|
||||
|
||||
```typescript
|
||||
// Create a client for production use
|
||||
const productionClient = new NamecheapClient({
|
||||
apiUser: 'your-api-username',
|
||||
apiKey: 'your-api-key',
|
||||
userName: 'your-username',
|
||||
clientIp: 'your-ip-address'
|
||||
});
|
||||
|
||||
// Create a client for sandbox testing
|
||||
const sandboxClient = new NamecheapClient({
|
||||
apiUser: 'your-api-username',
|
||||
apiKey: 'your-api-key',
|
||||
userName: 'your-username',
|
||||
clientIp: 'your-ip-address'
|
||||
}, true);
|
||||
|
||||
// Switch between sandbox and production
|
||||
client.enableSandbox(); // Switch to sandbox
|
||||
client.disableSandbox(); // Switch to production
|
||||
|
||||
// Set request timeout (in milliseconds)
|
||||
client.setTimeout(30000); // 30 seconds
|
||||
```
|
||||
|
||||
### Domain Management
|
||||
|
||||
#### Check Domain Availability
|
||||
|
||||
```typescript
|
||||
// Check a single domain
|
||||
const singleResult = await client.domains.check('example.com');
|
||||
console.log(`Domain is ${singleResult[0].available ? 'available' : 'not available'}`);
|
||||
|
||||
// Check multiple domains
|
||||
const multipleResults = await client.domains.check(['example.com', 'example.org', 'example.net']);
|
||||
multipleResults.forEach(result => {
|
||||
console.log(`${result.domain} is ${result.available ? 'available' : 'not available'}`);
|
||||
|
||||
if (result.isPremium) {
|
||||
console.log(`Premium domain: Registration price: ${result.premiumRegistrationPrice}`);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Get Domain List
|
||||
|
||||
```typescript
|
||||
// Get all domains
|
||||
const allDomains = await client.domains.getList();
|
||||
|
||||
// Get with pagination
|
||||
const page2 = await client.domains.getList({
|
||||
Page: 2,
|
||||
PageSize: 20
|
||||
});
|
||||
|
||||
// Filter domains
|
||||
const expiringDomains = await client.domains.getList({
|
||||
ListType: 'EXPIRING'
|
||||
});
|
||||
|
||||
// Search domains
|
||||
const searchResults = await client.domains.getList({
|
||||
SearchTerm: 'example'
|
||||
});
|
||||
|
||||
// Sort domains
|
||||
const sortedDomains = await client.domains.getList({
|
||||
SortBy: 'EXPIREDATE_DESC'
|
||||
});
|
||||
```
|
||||
|
||||
#### Get Domain Information
|
||||
|
||||
```typescript
|
||||
// Get detailed information about a domain
|
||||
const domainInfo = await client.domains.getInfo('example.com');
|
||||
|
||||
console.log(`Domain: ${domainInfo.domainName}`);
|
||||
console.log(`Created: ${domainInfo.createdDate}`);
|
||||
console.log(`Expires: ${domainInfo.expiredDate}`);
|
||||
console.log(`WhoisGuard: ${domainInfo.whoisGuard.enabled ? 'Enabled' : 'Disabled'}`);
|
||||
```
|
||||
|
||||
#### Domain Contact Management
|
||||
|
||||
```typescript
|
||||
// Get contact information for a domain
|
||||
const contacts = await client.domains.getContacts('example.com');
|
||||
|
||||
console.log('Registrant:', contacts.registrant);
|
||||
console.log('Technical Contact:', contacts.tech);
|
||||
console.log('Admin Contact:', contacts.admin);
|
||||
console.log('Billing Contact:', contacts.auxBilling);
|
||||
|
||||
// Update contact information
|
||||
const updatedContacts = {
|
||||
registrant: {
|
||||
FirstName: 'John',
|
||||
LastName: 'Doe',
|
||||
Address1: '123 Main St',
|
||||
City: 'Anytown',
|
||||
StateProvince: 'CA',
|
||||
PostalCode: '12345',
|
||||
Country: 'US',
|
||||
Phone: '+1.5555555555',
|
||||
EmailAddress: 'john.doe@example.com'
|
||||
},
|
||||
// You can update any or all contact types
|
||||
tech: { /* ... */ },
|
||||
admin: { /* ... */ },
|
||||
auxBilling: { /* ... */ }
|
||||
};
|
||||
|
||||
const success = await client.domains.setContacts('example.com', updatedContacts);
|
||||
```
|
||||
|
||||
#### Register a Domain
|
||||
|
||||
```typescript
|
||||
// Register a new domain
|
||||
const registrationResult = await client.domains.create({
|
||||
domainName: 'example.com',
|
||||
years: 1,
|
||||
contacts: {
|
||||
registrant: {
|
||||
FirstName: 'John',
|
||||
LastName: 'Doe',
|
||||
Address1: '123 Main St',
|
||||
City: 'Anytown',
|
||||
StateProvince: 'CA',
|
||||
PostalCode: '12345',
|
||||
Country: 'US',
|
||||
Phone: '+1.5555555555',
|
||||
EmailAddress: 'john.doe@example.com'
|
||||
},
|
||||
tech: { /* Same structure as registrant */ },
|
||||
admin: { /* Same structure as registrant */ },
|
||||
auxBilling: { /* Same structure as registrant */ }
|
||||
},
|
||||
nameservers: ['dns1.namecheaphosting.com', 'dns2.namecheaphosting.com'],
|
||||
addFreeWhoisguard: true,
|
||||
whoisguardPrivacy: true
|
||||
});
|
||||
|
||||
console.log(`Domain registered: ${registrationResult.domain}`);
|
||||
console.log(`Order ID: ${registrationResult.orderId}`);
|
||||
```
|
||||
|
||||
#### Renew a Domain
|
||||
|
||||
```typescript
|
||||
// Renew a domain registration
|
||||
const renewalResult = await client.domains.renew('example.com', 1);
|
||||
|
||||
console.log(`Domain renewed: ${renewalResult.domainName}`);
|
||||
console.log(`New expiry date: ${renewalResult.expireDate}`);
|
||||
```
|
||||
|
||||
#### Reactivate an Expired Domain
|
||||
|
||||
```typescript
|
||||
// Reactivate an expired domain
|
||||
const reactivationResult = await client.domains.reactivate('example.com');
|
||||
|
||||
console.log(`Domain reactivated: ${reactivationResult.domain}`);
|
||||
console.log(`Order ID: ${reactivationResult.orderId}`);
|
||||
```
|
||||
|
||||
#### Registrar Lock Management
|
||||
|
||||
```typescript
|
||||
// Get the registrar lock status
|
||||
const isLocked = await client.domains.getRegistrarLock('example.com');
|
||||
console.log(`Domain is ${isLocked ? 'locked' : 'unlocked'}`);
|
||||
|
||||
// Set the registrar lock status
|
||||
await client.domains.setRegistrarLock('example.com', true); // Lock the domain
|
||||
await client.domains.setRegistrarLock('example.com', false); // Unlock the domain
|
||||
```
|
||||
|
||||
#### Get Available TLDs
|
||||
|
||||
```typescript
|
||||
// Get a list of available TLDs
|
||||
const tlds = await client.domains.getTldList();
|
||||
console.log(`Available TLDs: ${tlds.join(', ')}`);
|
||||
```
|
||||
|
||||
### DNS Management
|
||||
|
||||
#### Get DNS Host Records
|
||||
|
||||
```typescript
|
||||
// Get all DNS records for a domain
|
||||
const hostRecords = await client.dns.getHosts('example.com');
|
||||
|
||||
hostRecords.forEach(record => {
|
||||
console.log(`${record.name} (${record.type}): ${record.address} (TTL: ${record.ttl})`);
|
||||
});
|
||||
```
|
||||
|
||||
#### Set DNS Host Records
|
||||
|
||||
```typescript
|
||||
// Set DNS records for a domain
|
||||
const newRecords = [
|
||||
{
|
||||
hostName: '@',
|
||||
recordType: 'A',
|
||||
address: '192.0.2.1',
|
||||
ttl: 300
|
||||
},
|
||||
{
|
||||
hostName: 'www',
|
||||
recordType: 'CNAME',
|
||||
address: '@',
|
||||
ttl: 300
|
||||
},
|
||||
{
|
||||
hostName: 'mail',
|
||||
recordType: 'MX',
|
||||
address: 'mail.example.com',
|
||||
mxPref: 10,
|
||||
ttl: 300
|
||||
}
|
||||
];
|
||||
|
||||
const success = await client.dns.setHosts('example.com', newRecords);
|
||||
```
|
||||
|
||||
#### Set Custom Nameservers
|
||||
|
||||
```typescript
|
||||
// Set custom nameservers for a domain
|
||||
const nameservers = [
|
||||
'ns1.example.com',
|
||||
'ns2.example.com'
|
||||
];
|
||||
|
||||
const success = await client.dns.setCustom('example.com', nameservers);
|
||||
```
|
||||
|
||||
#### Email Forwarding
|
||||
|
||||
```typescript
|
||||
// Get email forwarding settings
|
||||
const forwardings = await client.dns.getEmailForwarding('example.com');
|
||||
|
||||
forwardings.forEach(forward => {
|
||||
console.log(`${forward.from}@example.com → ${forward.to}`);
|
||||
});
|
||||
|
||||
// Set email forwarding
|
||||
const newForwardings = [
|
||||
{
|
||||
from: 'info',
|
||||
to: 'your-email@gmail.com'
|
||||
},
|
||||
{
|
||||
from: 'sales',
|
||||
to: 'sales@company.com'
|
||||
}
|
||||
];
|
||||
|
||||
const success = await client.dns.setEmailForwarding('example.com', newForwardings);
|
||||
```
|
||||
|
||||
#### Get DNS Servers
|
||||
|
||||
```typescript
|
||||
// Get a list of DNS servers for a domain
|
||||
const dnsServers = await client.dns.getList('example', 'com');
|
||||
console.log(`DNS Servers: ${dnsServers.join(', ')}`);
|
||||
```
|
||||
|
||||
### Nameserver Management
|
||||
|
||||
#### Create a Nameserver
|
||||
|
||||
```typescript
|
||||
// Create a new nameserver
|
||||
const success = await client.ns.create(
|
||||
'example', // SLD (Second-Level Domain)
|
||||
'com', // TLD (Top-Level Domain)
|
||||
'ns1.example.com', // Nameserver hostname
|
||||
'192.0.2.1' // IP address
|
||||
);
|
||||
```
|
||||
|
||||
#### Delete a Nameserver
|
||||
|
||||
```typescript
|
||||
// Delete a nameserver
|
||||
const success = await client.ns.delete(
|
||||
'example', // SLD
|
||||
'com', // TLD
|
||||
'ns1.example.com' // Nameserver hostname
|
||||
);
|
||||
```
|
||||
|
||||
#### Get Nameserver Information
|
||||
|
||||
```typescript
|
||||
// Get information about a nameserver
|
||||
const nsInfo = await client.ns.getInfo(
|
||||
'example', // SLD
|
||||
'com', // TLD
|
||||
'ns1.example.com' // Nameserver hostname
|
||||
);
|
||||
|
||||
console.log(`Nameserver: ${nsInfo.nameserver}`);
|
||||
console.log(`IP: ${nsInfo.ip}`);
|
||||
console.log(`Statuses: ${nsInfo.statuses.join(', ')}`);
|
||||
```
|
||||
|
||||
#### Update a Nameserver
|
||||
|
||||
```typescript
|
||||
// Update a nameserver's IP address
|
||||
const success = await client.ns.update(
|
||||
'example', // SLD
|
||||
'com', // TLD
|
||||
'ns1.example.com', // Nameserver hostname
|
||||
'192.0.2.1', // Old IP address
|
||||
'192.0.2.2' // New IP address
|
||||
);
|
||||
```
|
||||
|
||||
### Domain Transfers
|
||||
|
||||
#### Get Transfer List
|
||||
|
||||
```typescript
|
||||
// Get a list of domain transfers
|
||||
const transfers = await client.transfer.getList();
|
||||
|
||||
transfers.transfers.forEach(transfer => {
|
||||
console.log(`${transfer.domainName} (Status: ${transfer.status})`);
|
||||
});
|
||||
|
||||
// With pagination
|
||||
const page2 = await client.transfer.getList(2, 20);
|
||||
|
||||
// Filter by status
|
||||
const inProgress = await client.transfer.getList(1, 20, 'INPROGRESS');
|
||||
```
|
||||
|
||||
#### Get Transfer Status
|
||||
|
||||
```typescript
|
||||
// Get the status of a specific transfer
|
||||
const status = await client.transfer.getStatus(12345); // Transfer ID
|
||||
|
||||
console.log(`Domain: ${status.domainName}`);
|
||||
console.log(`Status: ${status.status}`);
|
||||
console.log(`Description: ${status.statusDescription}`);
|
||||
```
|
||||
|
||||
#### Create a Transfer
|
||||
|
||||
```typescript
|
||||
// Initiate a domain transfer to Namecheap
|
||||
const transferResult = await client.transfer.create(
|
||||
'example.com', // Domain name
|
||||
1, // Number of years to renew for
|
||||
'AUTH_CODE', // Authorization code from current registrar
|
||||
{
|
||||
addFreeWhoisguard: true,
|
||||
whoisguardEnable: true
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`Transfer initiated: ${transferResult.transferId}`);
|
||||
console.log(`Status: ${transferResult.transferStatus}`);
|
||||
```
|
||||
|
||||
#### Update Transfer Status
|
||||
|
||||
```typescript
|
||||
// Update the status of a transfer (e.g., to resubmit)
|
||||
const success = await client.transfer.updateStatus(12345, true); // Transfer ID, resubmit flag
|
||||
```
|
||||
|
||||
#### Get Transfer Information
|
||||
|
||||
```typescript
|
||||
// Get detailed information about a transfer
|
||||
const transferInfo = await client.transfer.getInfo(12345); // Transfer ID
|
||||
|
||||
console.log(`Domain: ${transferInfo.domainName}`);
|
||||
console.log(`Status: ${transferInfo.status}`);
|
||||
console.log(`Order Date: ${transferInfo.orderDate}`);
|
||||
console.log(`WhoisGuard Status: ${transferInfo.whoisguardStatus}`);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The client provides detailed error messages for API errors:
|
||||
|
||||
```typescript
|
||||
try {
|
||||
await client.domains.getInfo('example.com');
|
||||
} catch (error) {
|
||||
console.error('API Error:', error.message);
|
||||
|
||||
// For more detailed error information
|
||||
if (error.errors) {
|
||||
error.errors.forEach(err => console.error(' - ', err));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Sandbox Testing
|
||||
|
||||
Namecheap provides a sandbox environment for testing API integrations. To use it:
|
||||
|
||||
1. Register for a sandbox account at [https://www.sandbox.namecheap.com/](https://www.sandbox.namecheap.com/)
|
||||
2. Enable API access in your sandbox account
|
||||
3. Get your API key from the profile settings
|
||||
4. Whitelist your IP address in the API settings
|
||||
5. Create a client with sandbox mode enabled:
|
||||
|
||||
```typescript
|
||||
const client = new NamecheapClient({
|
||||
apiUser: 'your-sandbox-username',
|
||||
apiKey: 'your-sandbox-api-key',
|
||||
userName: 'your-sandbox-username',
|
||||
clientIp: 'your-whitelisted-ip'
|
||||
}, true); // true enables sandbox mode
|
||||
```
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
102
test/config.ts
Normal file
102
test/config.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import { NamecheapClient } from '../ts/index.js';
|
||||
import * as qenv from '@push.rocks/qenv';
|
||||
|
||||
// Define the auth interface to match what the client expects
|
||||
interface INamecheapAuth {
|
||||
apiUser: string;
|
||||
apiKey: string;
|
||||
userName: string; // Make userName required to match the client's expectation
|
||||
clientIp: string;
|
||||
}
|
||||
|
||||
// Test domains - use these in your tests
|
||||
export const TEST_DOMAINS = {
|
||||
// Use this domain for availability checks (should be available in sandbox)
|
||||
CHECK: 'test-domain-availability-check.com',
|
||||
|
||||
// Use this domain for domain info tests (should exist in your sandbox account)
|
||||
INFO: 'bleu.de',
|
||||
|
||||
// Use this domain for DNS tests (should exist in your sandbox account)
|
||||
DNS: 'bleu.de',
|
||||
|
||||
// Use this for domain registration tests
|
||||
REGISTER: 'test-domain-registration.net'
|
||||
};
|
||||
|
||||
// Load environment variables from .nogit directory
|
||||
const testQenv = new qenv.Qenv('./', '.nogit/');
|
||||
|
||||
// Initialize sandbox configuration with default values
|
||||
let sandboxConfig: INamecheapAuth = {
|
||||
apiUser: '',
|
||||
apiKey: '',
|
||||
userName: '',
|
||||
clientIp: '127.0.0.1'
|
||||
};
|
||||
|
||||
// Load sandbox configuration asynchronously
|
||||
async function loadSandboxConfig() {
|
||||
try {
|
||||
const username = await testQenv.getEnvVarOnDemand('SANDBOX_USERNAME');
|
||||
const apiKey = await testQenv.getEnvVarOnDemand('SANDBOX_APIKEY');
|
||||
const clientIp = await testQenv.getEnvVarOnDemand('CLIENT_IP') || '127.0.0.1';
|
||||
|
||||
sandboxConfig = {
|
||||
apiUser: username,
|
||||
apiKey: apiKey,
|
||||
userName: username,
|
||||
clientIp: clientIp
|
||||
};
|
||||
|
||||
console.log('Sandbox configuration loaded successfully');
|
||||
} catch (error) {
|
||||
console.warn('Failed to load sandbox configuration:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to load sandbox configuration immediately
|
||||
loadSandboxConfig().catch(console.error);
|
||||
|
||||
// Default mock configuration (for tests that don't need real API access)
|
||||
const mockConfig: INamecheapAuth = {
|
||||
apiUser: 'testuser',
|
||||
apiKey: 'testapikey',
|
||||
userName: 'testuser',
|
||||
clientIp: '127.0.0.1'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get API configuration for tests
|
||||
* @param useMock If true, returns mock config even if real credentials are available
|
||||
* @returns Namecheap API configuration
|
||||
*/
|
||||
export function getApiConfig(useMock: boolean = false): INamecheapAuth {
|
||||
// If mock config is requested or no real credentials are available, use mock config
|
||||
if (useMock || !hasRealCredentials()) {
|
||||
return mockConfig;
|
||||
}
|
||||
|
||||
// Otherwise use sandbox configuration
|
||||
return sandboxConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have real API credentials
|
||||
* @returns True if real credentials are available
|
||||
*/
|
||||
export function hasRealCredentials(): boolean {
|
||||
return !!(sandboxConfig.apiUser &&
|
||||
sandboxConfig.apiKey &&
|
||||
sandboxConfig.clientIp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Namecheap client for testing
|
||||
* @param useMock If true, uses mock config instead of real credentials
|
||||
* @returns Configured Namecheap client
|
||||
*/
|
||||
export function createTestClient(useMock: boolean = false): NamecheapClient {
|
||||
const config = getApiConfig(useMock);
|
||||
return new NamecheapClient(config, true); // Always use sandbox mode for tests
|
||||
}
|
110
test/test.domains.availability.ts
Normal file
110
test/test.domains.availability.ts
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Test file for Namecheap domain availability checks
|
||||
*/
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import { createTestClient, TEST_DOMAINS, hasRealCredentials } from './config.js';
|
||||
|
||||
// Skip live API tests if no real credentials
|
||||
const skipLiveTests = !hasRealCredentials();
|
||||
|
||||
// Always run this test to ensure the file doesn't fail when all other tests are skipped
|
||||
tap.test('Availability - Basic Client Test', async () => {
|
||||
// Create a client with mock credentials
|
||||
const client = createTestClient(true);
|
||||
|
||||
// Verify the client has the expected methods
|
||||
expect(client.domains.check).toBeTypeOf('function');
|
||||
|
||||
// This test always passes
|
||||
expect(true).toBeTrue();
|
||||
});
|
||||
|
||||
// Test domain availability checks
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Domain Availability - Check Single Domain', async () => {
|
||||
// This test is skipped when no real credentials are available
|
||||
console.log('Skipping domain availability test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Domain Availability - Check Single Domain', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(10000); // 10 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Check a single domain
|
||||
const result = await client.domains.check(TEST_DOMAINS.CHECK);
|
||||
|
||||
// Validate the result
|
||||
expect(result).toBeTypeOf('object');
|
||||
expect(Array.isArray(result)).toBeTrue();
|
||||
expect(result.length).toEqual(1);
|
||||
|
||||
const domainInfo = result[0];
|
||||
expect(domainInfo.domain).toEqual(TEST_DOMAINS.CHECK);
|
||||
expect(domainInfo.available).toBeTypeOf('boolean');
|
||||
|
||||
// Log the result with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Domain ${domainInfo.domain} is ${domainInfo.available ? 'available' : 'not available'} for registration`,
|
||||
domainInfo.available ? 'green' : 'blue'
|
||||
));
|
||||
|
||||
if (domainInfo.isPremium) {
|
||||
console.log(await tools.coloredString(
|
||||
`Premium domain details:
|
||||
- Registration price: ${domainInfo.premiumRegistrationPrice}
|
||||
- Renewal price: ${domainInfo.premiumRenewalPrice}
|
||||
- ICANN fee: ${domainInfo.icannFee}
|
||||
`,
|
||||
'blue'
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Test multiple domains
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Domain Availability - Check Multiple Domains', async () => {
|
||||
// This test is skipped when no real credentials are available
|
||||
console.log('Skipping multiple domains test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Domain Availability - Check Multiple Domains', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(10000); // 10 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Check multiple domains
|
||||
const domains = [
|
||||
TEST_DOMAINS.CHECK,
|
||||
'example.com',
|
||||
'test-multiple-domains.org'
|
||||
];
|
||||
|
||||
const results = await client.domains.check(domains);
|
||||
|
||||
// Validate the results
|
||||
expect(Array.isArray(results)).toBeTrue();
|
||||
expect(results.length).toEqual(domains.length);
|
||||
|
||||
// Each result should have the correct structure
|
||||
results.forEach(async (result) => {
|
||||
expect(result.domain).toBeTypeOf('string');
|
||||
expect(result.available).toBeTypeOf('boolean');
|
||||
expect(result.errorNo).toBeTypeOf('number');
|
||||
|
||||
// Log the result with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Domain ${result.domain} is ${result.available ? 'available' : 'not available'} for registration`,
|
||||
result.available ? 'green' : 'blue'
|
||||
));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Start the tests
|
||||
tap.start();
|
249
test/test.domains.contacts.ts
Normal file
249
test/test.domains.contacts.ts
Normal file
@ -0,0 +1,249 @@
|
||||
/**
|
||||
* Test file for Namecheap domain contact management
|
||||
*/
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import { createTestClient, TEST_DOMAINS, hasRealCredentials } from './config.js';
|
||||
|
||||
// Define a simplified contact info interface for the test
|
||||
interface IContactInfo {
|
||||
FirstName?: string;
|
||||
LastName?: string;
|
||||
Address1?: string;
|
||||
Address2?: string;
|
||||
City?: string;
|
||||
StateProvince?: string;
|
||||
PostalCode?: string;
|
||||
Country?: string;
|
||||
Phone?: string;
|
||||
EmailAddress?: string;
|
||||
[key: string]: string | undefined;
|
||||
}
|
||||
|
||||
// Skip live API tests if no real credentials
|
||||
const skipLiveTests = !hasRealCredentials();
|
||||
|
||||
// Always run this test to ensure the file doesn't fail when all other tests are skipped
|
||||
tap.test('Contacts - Basic Client Test', async () => {
|
||||
// Create a client with mock credentials
|
||||
const client = createTestClient(true);
|
||||
|
||||
// Verify the client has the expected methods
|
||||
expect(client.domains.getContacts).toBeTypeOf('function');
|
||||
expect(client.domains.setContacts).toBeTypeOf('function');
|
||||
|
||||
// This test always passes
|
||||
expect(true).toBeTrue();
|
||||
});
|
||||
|
||||
// Test getting domain contacts
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Contacts - Get Domain Contacts', async () => {
|
||||
console.log('Skipping get contacts test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Contacts - Get Domain Contacts', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(15000); // 15 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
try {
|
||||
console.log(await tools.coloredString(
|
||||
`Getting contacts for domain: ${TEST_DOMAINS.INFO}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Get contact information for a domain
|
||||
const contacts = await client.domains.getContacts(TEST_DOMAINS.INFO);
|
||||
|
||||
// Validate the result
|
||||
expect(contacts).toBeTypeOf('object');
|
||||
expect(contacts.registrant).toBeTypeOf('object');
|
||||
expect(contacts.tech).toBeTypeOf('object');
|
||||
expect(contacts.admin).toBeTypeOf('object');
|
||||
expect(contacts.auxBilling).toBeTypeOf('object');
|
||||
|
||||
// Log the contact information with colored output
|
||||
console.log(await tools.coloredString('Registrant Contact:', 'green'));
|
||||
logContactInfo(tools, contacts.registrant);
|
||||
|
||||
console.log(await tools.coloredString('Technical Contact:', 'green'));
|
||||
logContactInfo(tools, contacts.tech);
|
||||
|
||||
console.log(await tools.coloredString('Administrative Contact:', 'green'));
|
||||
logContactInfo(tools, contacts.admin);
|
||||
|
||||
console.log(await tools.coloredString('Billing Contact:', 'green'));
|
||||
logContactInfo(tools, contacts.auxBilling);
|
||||
} catch (error) {
|
||||
console.error('Error getting domain contacts:', error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Test setting domain contacts
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Contacts - Set Domain Contacts', async () => {
|
||||
console.log('Skipping set contacts test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Contacts - Set Domain Contacts', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(30000); // 30 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
try {
|
||||
// First, get the current contacts to use as a base
|
||||
console.log(await tools.coloredString(
|
||||
`Getting current contacts for domain: ${TEST_DOMAINS.INFO}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
const currentContacts = await client.domains.getContacts(TEST_DOMAINS.INFO);
|
||||
|
||||
// Make a copy of the contacts to modify
|
||||
const updatedContacts = {
|
||||
registrant: { ...currentContacts.registrant },
|
||||
tech: { ...currentContacts.tech },
|
||||
admin: { ...currentContacts.admin },
|
||||
auxBilling: { ...currentContacts.auxBilling }
|
||||
};
|
||||
|
||||
// Update the phone number for all contacts
|
||||
// This is a safe change that shouldn't cause issues
|
||||
const timestamp = Date.now();
|
||||
const newPhone = `+1.555${timestamp.toString().slice(-7)}`;
|
||||
|
||||
updatedContacts.registrant.Phone = newPhone;
|
||||
updatedContacts.tech.Phone = newPhone;
|
||||
updatedContacts.admin.Phone = newPhone;
|
||||
updatedContacts.auxBilling.Phone = newPhone;
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Updating contacts with new phone number: ${newPhone}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Set the updated contacts
|
||||
const success = await client.domains.setContacts(TEST_DOMAINS.INFO, updatedContacts);
|
||||
|
||||
// Validate the result
|
||||
expect(success).toBeTrue();
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
'Successfully updated domain contacts',
|
||||
'green'
|
||||
));
|
||||
|
||||
// Verify the changes
|
||||
console.log(await tools.coloredString(
|
||||
'Verifying contact changes...',
|
||||
'cyan'
|
||||
));
|
||||
|
||||
const verifyContacts = await client.domains.getContacts(TEST_DOMAINS.INFO);
|
||||
|
||||
expect(verifyContacts.registrant.Phone).toEqual(newPhone);
|
||||
expect(verifyContacts.tech.Phone).toEqual(newPhone);
|
||||
expect(verifyContacts.admin.Phone).toEqual(newPhone);
|
||||
expect(verifyContacts.auxBilling.Phone).toEqual(newPhone);
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
'Contact changes verified successfully',
|
||||
'green'
|
||||
));
|
||||
} catch (error) {
|
||||
console.error('Error setting domain contacts:', error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Test validation of contact information
|
||||
tap.test('Contacts - Validate Contact Information', async () => {
|
||||
// Create a client with mock credentials
|
||||
const client = createTestClient(true);
|
||||
|
||||
// Create incomplete contact information
|
||||
const incompleteContacts = {
|
||||
registrant: {
|
||||
FirstName: 'Test',
|
||||
LastName: 'User'
|
||||
// Missing required fields
|
||||
}
|
||||
};
|
||||
|
||||
// Attempt to set contacts with incomplete information
|
||||
let validationError: Error | null = null;
|
||||
try {
|
||||
await client.domains.setContacts('example.com', incompleteContacts);
|
||||
// If we get here, the validation failed to catch the incomplete information
|
||||
expect(false).toBeTrue(); // This should never execute
|
||||
} catch (error) {
|
||||
validationError = error as Error;
|
||||
}
|
||||
|
||||
// Verify we got an error
|
||||
expect(validationError).not.toBeNull();
|
||||
|
||||
// Create complete contact information
|
||||
const completeContacts = {
|
||||
registrant: {
|
||||
FirstName: 'Test',
|
||||
LastName: 'User',
|
||||
Address1: '123 Test St',
|
||||
City: 'Test City',
|
||||
StateProvince: 'CA',
|
||||
PostalCode: '12345',
|
||||
Country: 'US',
|
||||
Phone: '+1.5555555555',
|
||||
EmailAddress: 'test@example.com'
|
||||
}
|
||||
};
|
||||
|
||||
// This should not throw a validation error
|
||||
// (though it will fail at the API level since we're using mock credentials)
|
||||
let apiError: Error | null = null;
|
||||
try {
|
||||
await client.domains.setContacts('example.com', completeContacts);
|
||||
} catch (error) {
|
||||
apiError = error as Error;
|
||||
}
|
||||
|
||||
// Verify we got an error (API error, not validation error)
|
||||
expect(apiError).not.toBeNull();
|
||||
});
|
||||
|
||||
// Helper function to log contact information
|
||||
async function logContactInfo(tools: any, contact: IContactInfo): Promise<void> {
|
||||
if (!contact) {
|
||||
console.log(await tools.coloredString('No contact information available', 'blue'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (contact.FirstName && contact.LastName) {
|
||||
console.log(await tools.coloredString(`Name: ${contact.FirstName} ${contact.LastName}`, 'blue'));
|
||||
}
|
||||
|
||||
if (contact.EmailAddress) {
|
||||
console.log(await tools.coloredString(`Email: ${contact.EmailAddress}`, 'blue'));
|
||||
}
|
||||
|
||||
if (contact.Phone) {
|
||||
console.log(await tools.coloredString(`Phone: ${contact.Phone}`, 'blue'));
|
||||
}
|
||||
|
||||
if (contact.Address1) {
|
||||
console.log(await tools.coloredString(
|
||||
`Address: ${contact.Address1}${contact.Address2 ? ', ' + contact.Address2 : ''}, ${contact.City}, ${contact.StateProvince}, ${contact.PostalCode}, ${contact.Country}`,
|
||||
'blue'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Start the tests
|
||||
tap.start();
|
196
test/test.domains.dns.ts
Normal file
196
test/test.domains.dns.ts
Normal file
@ -0,0 +1,196 @@
|
||||
/**
|
||||
* Test file for Namecheap DNS operations
|
||||
*/
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import { createTestClient, TEST_DOMAINS, hasRealCredentials } from './config.js';
|
||||
|
||||
// Skip live API tests if no real credentials
|
||||
const skipLiveTests = !hasRealCredentials();
|
||||
|
||||
// Always run this test to ensure the file doesn't fail when all other tests are skipped
|
||||
tap.test('DNS - Basic Client Test', async () => {
|
||||
// Create a client with mock credentials
|
||||
const client = createTestClient(true);
|
||||
|
||||
// Verify the client has the expected methods
|
||||
expect(client.dns.getHosts).toBeTypeOf('function');
|
||||
expect(client.dns.setHosts).toBeTypeOf('function');
|
||||
expect(client.dns.setCustom).toBeTypeOf('function');
|
||||
expect(client.dns.getEmailForwarding).toBeTypeOf('function');
|
||||
expect(client.dns.setEmailForwarding).toBeTypeOf('function');
|
||||
expect(client.dns.getList).toBeTypeOf('function');
|
||||
|
||||
// This test always passes
|
||||
expect(true).toBeTrue();
|
||||
});
|
||||
|
||||
// Test DNS host records retrieval
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('DNS - Get Host Records', async () => {
|
||||
console.log('Skipping DNS host records test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('DNS - Get Host Records', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(15000); // 15 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Get DNS host records for a domain
|
||||
const hosts = await client.dns.getHosts(TEST_DOMAINS.DNS);
|
||||
|
||||
// Validate the result
|
||||
expect(Array.isArray(hosts)).toBeTrue();
|
||||
|
||||
// Log the host records with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Found ${hosts.length} DNS records for ${TEST_DOMAINS.DNS}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
for (const host of hosts) {
|
||||
console.log(await tools.coloredString(
|
||||
`- ${host.name} (${host.type}): ${host.address} (TTL: ${host.ttl})`,
|
||||
host.type === 'A' ? 'green' :
|
||||
host.type === 'CNAME' ? 'blue' :
|
||||
host.type === 'MX' ? 'red' : 'cyan'
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Test DNS host records modification
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('DNS - Set Host Records', async () => {
|
||||
console.log('Skipping DNS host modification test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('DNS - Set Host Records', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(30000); // 30 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
try {
|
||||
// First, get the current host records
|
||||
const currentHosts = await client.dns.getHosts(TEST_DOMAINS.DNS);
|
||||
|
||||
// Create a new test record
|
||||
const testRecordName = `test-${Date.now()}`;
|
||||
const newHosts = [
|
||||
{
|
||||
hostName: testRecordName,
|
||||
recordType: 'A' as const,
|
||||
address: '192.168.1.1',
|
||||
ttl: 300
|
||||
},
|
||||
// Include all existing records to avoid losing them
|
||||
...currentHosts.map(host => ({
|
||||
hostName: host.name,
|
||||
recordType: host.type as any,
|
||||
address: host.address,
|
||||
mxPref: host.type === 'MX' ? host.mxPref : undefined,
|
||||
ttl: host.ttl
|
||||
}))
|
||||
];
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Adding test record: ${testRecordName}.${TEST_DOMAINS.DNS} -> 192.168.1.1`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Set the host records
|
||||
const success = await client.dns.setHosts(TEST_DOMAINS.DNS, newHosts);
|
||||
|
||||
// Validate the result
|
||||
expect(success).toBeTrue();
|
||||
|
||||
// Verify the new record was added
|
||||
const updatedHosts = await client.dns.getHosts(TEST_DOMAINS.DNS);
|
||||
const newRecord = updatedHosts.find(host => host.name === testRecordName);
|
||||
|
||||
expect(newRecord).toBeDefined();
|
||||
expect(newRecord?.address).toEqual('192.168.1.1');
|
||||
expect(newRecord?.ttl).toEqual(300);
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Successfully added test record: ${testRecordName}`,
|
||||
'green'
|
||||
));
|
||||
|
||||
// Clean up by removing the test record
|
||||
const cleanupHosts = currentHosts.map(host => ({
|
||||
hostName: host.name,
|
||||
recordType: host.type as any,
|
||||
address: host.address,
|
||||
mxPref: host.type === 'MX' ? host.mxPref : undefined,
|
||||
ttl: host.ttl
|
||||
}));
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Cleaning up test record: ${testRecordName}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Restore the original host records
|
||||
const cleanupSuccess = await client.dns.setHosts(TEST_DOMAINS.DNS, cleanupHosts);
|
||||
expect(cleanupSuccess).toBeTrue();
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Successfully cleaned up test record`,
|
||||
'green'
|
||||
));
|
||||
} catch (error) {
|
||||
console.error('Error in DNS host records test:', error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Test email forwarding
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('DNS - Get Email Forwarding', async () => {
|
||||
console.log('Skipping email forwarding test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('DNS - Get Email Forwarding', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(15000); // 15 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
try {
|
||||
// Get email forwarding settings
|
||||
const forwardings = await client.dns.getEmailForwarding(TEST_DOMAINS.DNS);
|
||||
|
||||
// Validate the result
|
||||
expect(Array.isArray(forwardings)).toBeTrue();
|
||||
|
||||
// Log the email forwardings with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Found ${forwardings.length} email forwardings for ${TEST_DOMAINS.DNS}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
for (const forward of forwardings) {
|
||||
console.log(await tools.coloredString(
|
||||
`- ${forward.from}@${TEST_DOMAINS.DNS} → ${forward.to}`,
|
||||
'green'
|
||||
));
|
||||
}
|
||||
} catch (error) {
|
||||
// Email forwarding might not be enabled for the domain
|
||||
console.log(await tools.coloredString(
|
||||
`Email forwarding not available for ${TEST_DOMAINS.DNS}`,
|
||||
'blue'
|
||||
));
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Start the tests
|
||||
tap.start();
|
155
test/test.domains.info.ts
Normal file
155
test/test.domains.info.ts
Normal file
@ -0,0 +1,155 @@
|
||||
/**
|
||||
* Test file for Namecheap domain information retrieval
|
||||
*/
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import { createTestClient, TEST_DOMAINS, hasRealCredentials } from './config.js';
|
||||
|
||||
// Skip live API tests if no real credentials
|
||||
const skipLiveTests = !hasRealCredentials();
|
||||
|
||||
// Always run this test to ensure the file doesn't fail when all other tests are skipped
|
||||
tap.test('Info - Basic Client Test', async () => {
|
||||
// Create a client with mock credentials
|
||||
const client = createTestClient(true);
|
||||
|
||||
// Verify the client has the expected methods
|
||||
expect(client.domains.getList).toBeTypeOf('function');
|
||||
expect(client.domains.getInfo).toBeTypeOf('function');
|
||||
expect(client.domains.getContacts).toBeTypeOf('function');
|
||||
|
||||
// This test always passes
|
||||
expect(true).toBeTrue();
|
||||
});
|
||||
|
||||
// Test domain list retrieval
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Domain Info - Get Domain List', async () => {
|
||||
console.log('Skipping domain list test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Domain Info - Get Domain List', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(15000); // 15 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Get list of domains
|
||||
const result = await client.domains.getList();
|
||||
|
||||
// Validate the result
|
||||
expect(result).toBeTypeOf('object');
|
||||
expect(Array.isArray(result.domains)).toBeTrue();
|
||||
expect(result.paging).toBeTypeOf('object');
|
||||
|
||||
// Log the results with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Found ${result.domains.length} domains in your account`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Page ${result.paging.currentPage} of ${Math.ceil(result.paging.totalItems / result.paging.pageSize)}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Display the first few domains
|
||||
for (const domain of result.domains.slice(0, 3)) {
|
||||
console.log(await tools.coloredString(
|
||||
`- ${domain.Name} (expires: ${domain.Expires})`,
|
||||
'green'
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Test domain info retrieval
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Domain Info - Get Domain Info', async () => {
|
||||
console.log('Skipping domain info test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Domain Info - Get Domain Info', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(15000); // 15 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Get information about a specific domain
|
||||
const domainInfo = await client.domains.getInfo(TEST_DOMAINS.INFO);
|
||||
|
||||
// Validate the result
|
||||
expect(domainInfo).toBeTypeOf('object');
|
||||
expect(domainInfo.domainName).toEqual(TEST_DOMAINS.INFO);
|
||||
expect(domainInfo.status).toBeTypeOf('string');
|
||||
expect(domainInfo.createdDate).toBeTypeOf('string');
|
||||
expect(domainInfo.expiredDate).toBeTypeOf('string');
|
||||
|
||||
// Log the domain information with colored output
|
||||
console.log(await tools.coloredString(`Domain: ${domainInfo.domainName}`, 'cyan'));
|
||||
console.log(await tools.coloredString(`Status: ${domainInfo.status}`, 'cyan'));
|
||||
console.log(await tools.coloredString(`Created: ${domainInfo.createdDate}`, 'cyan'));
|
||||
console.log(await tools.coloredString(`Expires: ${domainInfo.expiredDate}`, 'cyan'));
|
||||
console.log(await tools.coloredString(
|
||||
`WhoisGuard: ${domainInfo.whoisGuard.enabled ? 'Enabled' : 'Disabled'}`,
|
||||
domainInfo.whoisGuard.enabled ? 'green' : 'blue'
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
// Test domain contacts retrieval
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Domain Info - Get Domain Contacts', async () => {
|
||||
console.log('Skipping domain contacts test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Domain Info - Get Domain Contacts', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(15000); // 15 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Get contact information for a domain
|
||||
const contacts = await client.domains.getContacts(TEST_DOMAINS.INFO);
|
||||
|
||||
// Validate the result
|
||||
expect(contacts).toBeTypeOf('object');
|
||||
expect(contacts.registrant).toBeTypeOf('object');
|
||||
|
||||
// Log the registrant contact information with colored output
|
||||
console.log(await tools.coloredString('Registrant Contact Information:', 'cyan'));
|
||||
|
||||
if (contacts.registrant.FirstName && contacts.registrant.LastName) {
|
||||
console.log(await tools.coloredString(
|
||||
`Name: ${contacts.registrant.FirstName} ${contacts.registrant.LastName}`,
|
||||
'green'
|
||||
));
|
||||
}
|
||||
|
||||
if (contacts.registrant.EmailAddress) {
|
||||
console.log(await tools.coloredString(
|
||||
`Email: ${contacts.registrant.EmailAddress}`,
|
||||
'green'
|
||||
));
|
||||
}
|
||||
|
||||
if (contacts.registrant.Phone) {
|
||||
console.log(await tools.coloredString(
|
||||
`Phone: ${contacts.registrant.Phone}`,
|
||||
'green'
|
||||
));
|
||||
}
|
||||
|
||||
if (contacts.registrant.Address1 && contacts.registrant.City) {
|
||||
console.log(await tools.coloredString(
|
||||
`Address: ${contacts.registrant.Address1}, ${contacts.registrant.City}, ${contacts.registrant.StateProvince || ''}, ${contacts.registrant.PostalCode || ''}, ${contacts.registrant.Country}`,
|
||||
'green'
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Start the tests
|
||||
tap.start();
|
217
test/test.domains.nameservers.ts
Normal file
217
test/test.domains.nameservers.ts
Normal file
@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Test file for Namecheap nameserver operations
|
||||
*/
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import { createTestClient, TEST_DOMAINS, hasRealCredentials } from './config.js';
|
||||
|
||||
// Skip live API tests if no real credentials
|
||||
const skipLiveTests = !hasRealCredentials();
|
||||
|
||||
// Always run this test to ensure the file doesn't fail when all other tests are skipped
|
||||
tap.test('Nameservers - Basic Client Test', async () => {
|
||||
// Create a client with mock credentials
|
||||
const client = createTestClient(true);
|
||||
|
||||
// Verify the client has the expected methods
|
||||
expect(client.ns.create).toBeTypeOf('function');
|
||||
expect(client.ns.delete).toBeTypeOf('function');
|
||||
expect(client.ns.getInfo).toBeTypeOf('function');
|
||||
expect(client.ns.update).toBeTypeOf('function');
|
||||
|
||||
// This test always passes
|
||||
expect(true).toBeTrue();
|
||||
});
|
||||
|
||||
// Parse domain into SLD and TLD
|
||||
function parseDomain(domain: string): { sld: string, tld: string } {
|
||||
const parts = domain.split('.');
|
||||
const tld = parts.pop() || '';
|
||||
const sld = parts.join('.');
|
||||
return { sld, tld };
|
||||
}
|
||||
|
||||
// Test nameserver creation and deletion
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Nameservers - Create and Delete Custom Nameserver', async () => {
|
||||
console.log('Skipping nameserver creation test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Nameservers - Create and Delete Custom Nameserver', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(60000); // 60 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Parse the test domain
|
||||
const { sld, tld } = parseDomain(TEST_DOMAINS.DNS);
|
||||
|
||||
// Create a unique nameserver name
|
||||
const nsName = `ns${Date.now()}.${TEST_DOMAINS.DNS}`;
|
||||
const nsIp = '192.168.1.1';
|
||||
|
||||
try {
|
||||
console.log(await tools.coloredString(
|
||||
`Creating nameserver: ${nsName} with IP: ${nsIp}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Create a new nameserver
|
||||
const createResult = await client.ns.create(sld, tld, nsName, nsIp);
|
||||
|
||||
// Validate the result
|
||||
expect(createResult).toBeTrue();
|
||||
console.log(await tools.coloredString(
|
||||
`Successfully created nameserver: ${nsName} with IP: ${nsIp}`,
|
||||
'green'
|
||||
));
|
||||
|
||||
// Get nameserver info
|
||||
const nsInfo = await client.ns.getInfo(sld, tld, nsName);
|
||||
|
||||
// Validate the info
|
||||
expect(nsInfo).toBeTypeOf('object');
|
||||
expect(nsInfo.nameserver).toEqual(nsName);
|
||||
expect(nsInfo.ip).toEqual(nsIp);
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Nameserver info:
|
||||
- Name: ${nsInfo.nameserver}
|
||||
- IP: ${nsInfo.ip}
|
||||
- Statuses: ${nsInfo.statuses.join(', ')}
|
||||
`,
|
||||
'green'
|
||||
));
|
||||
|
||||
// Update the nameserver IP
|
||||
const newIp = '192.168.1.2';
|
||||
console.log(await tools.coloredString(
|
||||
`Updating nameserver IP from ${nsIp} to ${newIp}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
const updateResult = await client.ns.update(sld, tld, nsName, nsIp, newIp);
|
||||
|
||||
// Validate the update result
|
||||
expect(updateResult).toBeTrue();
|
||||
console.log(await tools.coloredString(
|
||||
`Successfully updated nameserver IP from ${nsIp} to ${newIp}`,
|
||||
'green'
|
||||
));
|
||||
|
||||
// Verify the update
|
||||
const updatedInfo = await client.ns.getInfo(sld, tld, nsName);
|
||||
expect(updatedInfo.ip).toEqual(newIp);
|
||||
|
||||
// Delete the nameserver
|
||||
console.log(await tools.coloredString(
|
||||
`Deleting nameserver: ${nsName}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
const deleteResult = await client.ns.delete(sld, tld, nsName);
|
||||
|
||||
// Validate the delete result
|
||||
expect(deleteResult).toBeTrue();
|
||||
console.log(await tools.coloredString(
|
||||
`Successfully deleted nameserver: ${nsName}`,
|
||||
'green'
|
||||
));
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error in nameserver operations:', error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Test custom nameservers for domain
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Nameservers - Set Custom Nameservers for Domain', async () => {
|
||||
console.log('Skipping custom nameservers test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Nameservers - Set Custom Nameservers for Domain', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(60000); // 60 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Get current DNS settings to restore later
|
||||
const currentHosts = await client.dns.getHosts(TEST_DOMAINS.DNS);
|
||||
|
||||
try {
|
||||
// Set custom nameservers
|
||||
const customNameservers = [
|
||||
'dns1.namecheaphosting.com',
|
||||
'dns2.namecheaphosting.com'
|
||||
];
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Setting custom nameservers for ${TEST_DOMAINS.DNS}: ${customNameservers.join(', ')}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
const result = await client.dns.setCustom(TEST_DOMAINS.DNS, customNameservers);
|
||||
|
||||
// Validate the result
|
||||
expect(result).toBeTrue();
|
||||
console.log(await tools.coloredString(
|
||||
`Successfully set custom nameservers for ${TEST_DOMAINS.DNS}`,
|
||||
'green'
|
||||
));
|
||||
|
||||
// Now restore the original DNS settings
|
||||
console.log(await tools.coloredString(
|
||||
`Restoring original DNS settings for ${TEST_DOMAINS.DNS}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
const restoreResult = await client.dns.setHosts(
|
||||
TEST_DOMAINS.DNS,
|
||||
currentHosts.map(host => ({
|
||||
hostName: host.name,
|
||||
recordType: host.type as any,
|
||||
address: host.address,
|
||||
mxPref: host.type === 'MX' ? host.mxPref : undefined,
|
||||
ttl: host.ttl
|
||||
}))
|
||||
);
|
||||
|
||||
expect(restoreResult).toBeTrue();
|
||||
console.log(await tools.coloredString(
|
||||
`Successfully restored original DNS settings for ${TEST_DOMAINS.DNS}`,
|
||||
'green'
|
||||
));
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error in custom nameserver operations:', error);
|
||||
|
||||
// Try to restore original settings if there was an error
|
||||
try {
|
||||
await client.dns.setHosts(
|
||||
TEST_DOMAINS.DNS,
|
||||
currentHosts.map(host => ({
|
||||
hostName: host.name,
|
||||
recordType: host.type as any,
|
||||
address: host.address,
|
||||
mxPref: host.type === 'MX' ? host.mxPref : undefined,
|
||||
ttl: host.ttl
|
||||
}))
|
||||
);
|
||||
console.log(await tools.coloredString(
|
||||
'Restored original DNS settings after error',
|
||||
'yellow'
|
||||
));
|
||||
} catch (restoreError) {
|
||||
console.error('Failed to restore original DNS settings:', restoreError);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Start the tests
|
||||
tap.start();
|
198
test/test.domains.registration.ts
Normal file
198
test/test.domains.registration.ts
Normal file
@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Test file for Namecheap domain registration operations
|
||||
*
|
||||
* IMPORTANT: These tests can incur charges even in sandbox mode!
|
||||
* Only run these tests if you understand the implications.
|
||||
*/
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import { createTestClient, TEST_DOMAINS, hasRealCredentials } from './config.js';
|
||||
|
||||
// Skip live API tests if no real credentials or if ENABLE_REGISTRATION_TESTS is not set
|
||||
const skipLiveTests = !hasRealCredentials() || process.env.ENABLE_REGISTRATION_TESTS !== 'true';
|
||||
|
||||
// Always run this test to ensure the file doesn't fail when all other tests are skipped
|
||||
tap.test('Registration - Basic Client Test', async () => {
|
||||
// Create a client with mock credentials
|
||||
const client = createTestClient(true);
|
||||
|
||||
// Verify the client has the expected methods
|
||||
expect(client.domains.create).toBeTypeOf('function');
|
||||
expect(client.domains.renew).toBeTypeOf('function');
|
||||
expect(client.domains.reactivate).toBeTypeOf('function');
|
||||
expect(client.domains.getTldList).toBeTypeOf('function');
|
||||
|
||||
// This test always passes
|
||||
expect(true).toBeTrue();
|
||||
});
|
||||
|
||||
// Test TLD list retrieval
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Registration - Check TLD List', async () => {
|
||||
console.log('Skipping TLD list test - no credentials or registration tests disabled');
|
||||
});
|
||||
} else {
|
||||
tap.test('Registration - Check TLD List', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(15000); // 15 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Get list of available TLDs
|
||||
const tlds = await client.domains.getTldList();
|
||||
|
||||
// Validate the result
|
||||
expect(Array.isArray(tlds)).toBeTrue();
|
||||
expect(tlds.length).toBeGreaterThan(0);
|
||||
|
||||
// Log some of the available TLDs with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Available TLDs: ${tlds.slice(0, 10).join(', ')}...`,
|
||||
'cyan'
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
// Test domain registration
|
||||
// This test is always skipped by default because it costs money
|
||||
tap.skip.test('Registration - Register Domain', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(60000); // 60 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Sample contact information (required for registration)
|
||||
const contacts = {
|
||||
registrant: {
|
||||
FirstName: 'Test',
|
||||
LastName: 'User',
|
||||
Address1: '123 Test St',
|
||||
City: 'Test City',
|
||||
StateProvince: 'CA',
|
||||
PostalCode: '12345',
|
||||
Country: 'US',
|
||||
Phone: '+1.5555555555',
|
||||
EmailAddress: 'test@example.com'
|
||||
},
|
||||
tech: {
|
||||
FirstName: 'Test',
|
||||
LastName: 'User',
|
||||
Address1: '123 Test St',
|
||||
City: 'Test City',
|
||||
StateProvince: 'CA',
|
||||
PostalCode: '12345',
|
||||
Country: 'US',
|
||||
Phone: '+1.5555555555',
|
||||
EmailAddress: 'test@example.com'
|
||||
},
|
||||
admin: {
|
||||
FirstName: 'Test',
|
||||
LastName: 'User',
|
||||
Address1: '123 Test St',
|
||||
City: 'Test City',
|
||||
StateProvince: 'CA',
|
||||
PostalCode: '12345',
|
||||
Country: 'US',
|
||||
Phone: '+1.5555555555',
|
||||
EmailAddress: 'test@example.com'
|
||||
},
|
||||
auxBilling: {
|
||||
FirstName: 'Test',
|
||||
LastName: 'User',
|
||||
Address1: '123 Test St',
|
||||
City: 'Test City',
|
||||
StateProvince: 'CA',
|
||||
PostalCode: '12345',
|
||||
Country: 'US',
|
||||
Phone: '+1.5555555555',
|
||||
EmailAddress: 'test@example.com'
|
||||
}
|
||||
};
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Registering domain: ${TEST_DOMAINS.REGISTER}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Register a new domain
|
||||
const result = await client.domains.create({
|
||||
domainName: TEST_DOMAINS.REGISTER,
|
||||
years: 1,
|
||||
contacts,
|
||||
nameservers: ['dns1.namecheaphosting.com', 'dns2.namecheaphosting.com'],
|
||||
addFreeWhoisguard: true,
|
||||
whoisguardPrivacy: true
|
||||
});
|
||||
|
||||
// Validate the result
|
||||
expect(result).toBeTypeOf('object');
|
||||
expect(result.registered).toBeTrue();
|
||||
expect(result.domain).toEqual(TEST_DOMAINS.REGISTER);
|
||||
|
||||
// Log the registration result with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Domain ${result.domain} registered successfully`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Transaction ID: ${result.transactionId}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Order ID: ${result.orderId}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Charged Amount: ${result.chargedAmount}`,
|
||||
'green'
|
||||
));
|
||||
});
|
||||
|
||||
// Test domain renewal
|
||||
// This test is always skipped by default because it costs money
|
||||
tap.skip.test('Registration - Renew Domain', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(60000); // 60 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Renewing domain: ${TEST_DOMAINS.INFO}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Renew a domain
|
||||
const result = await client.domains.renew(TEST_DOMAINS.INFO, 1);
|
||||
|
||||
// Validate the result
|
||||
expect(result).toBeTypeOf('object');
|
||||
expect(result.renewed).toBeTrue();
|
||||
expect(result.domainName).toEqual(TEST_DOMAINS.INFO);
|
||||
|
||||
// Log the renewal result with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Domain ${result.domainName} renewed successfully`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Transaction ID: ${result.transactionId}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Order ID: ${result.orderId}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Charged Amount: ${result.chargedAmount}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`New Expiry Date: ${result.expireDate}`,
|
||||
'green'
|
||||
));
|
||||
});
|
||||
|
||||
// Start the tests
|
||||
tap.start();
|
186
test/test.domains.transfer.ts
Normal file
186
test/test.domains.transfer.ts
Normal file
@ -0,0 +1,186 @@
|
||||
/**
|
||||
* Test file for Namecheap domain transfer operations
|
||||
*
|
||||
* IMPORTANT: These tests can incur charges even in sandbox mode!
|
||||
* Only run these tests if you understand the implications.
|
||||
*/
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import { createTestClient, hasRealCredentials } from './config.js';
|
||||
|
||||
// Skip live API tests if no real credentials or if ENABLE_TRANSFER_TESTS is not set
|
||||
const skipLiveTests = !hasRealCredentials() || process.env.ENABLE_TRANSFER_TESTS !== 'true';
|
||||
|
||||
// Always run this test to ensure the file doesn't fail when all other tests are skipped
|
||||
tap.test('Transfer - Basic Client Test', async () => {
|
||||
// Create a client with mock credentials
|
||||
const client = createTestClient(true);
|
||||
|
||||
// Verify the client has the expected methods
|
||||
expect(client.transfer.getList).toBeTypeOf('function');
|
||||
expect(client.transfer.getStatus).toBeTypeOf('function');
|
||||
expect(client.transfer.create).toBeTypeOf('function');
|
||||
expect(client.transfer.updateStatus).toBeTypeOf('function');
|
||||
expect(client.transfer.getInfo).toBeTypeOf('function');
|
||||
|
||||
// This test always passes
|
||||
expect(true).toBeTrue();
|
||||
});
|
||||
|
||||
// Test transfer list retrieval
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Transfer - Get Transfer List', async () => {
|
||||
console.log('Skipping transfer list test - no credentials or transfer tests disabled');
|
||||
});
|
||||
} else {
|
||||
tap.test('Transfer - Get Transfer List', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(15000); // 15 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Get list of domain transfers
|
||||
const result = await client.transfer.getList();
|
||||
|
||||
// Validate the result
|
||||
expect(result).toBeTypeOf('object');
|
||||
expect(Array.isArray(result.transfers)).toBeTrue();
|
||||
expect(result.paging).toBeTypeOf('object');
|
||||
|
||||
// Log the results with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Found ${result.transfers.length} domain transfers in your account`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Display the first few transfers
|
||||
for (const transfer of result.transfers.slice(0, 3)) {
|
||||
console.log(await tools.coloredString(
|
||||
`- ${transfer.domainName} (Status: ${transfer.status})`,
|
||||
transfer.status.toLowerCase().includes('success') ? 'green' :
|
||||
transfer.status.toLowerCase().includes('fail') ? 'red' : 'blue'
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Test domain transfer creation
|
||||
// This test is always skipped by default because it costs money
|
||||
tap.skip.test('Transfer - Create Transfer', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(60000); // 60 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Initiating transfer for domain: domain-to-transfer.com`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Create a domain transfer
|
||||
// You need a valid EPP/Auth code from the current registrar
|
||||
const result = await client.transfer.create(
|
||||
'domain-to-transfer.com', // Domain to transfer
|
||||
1, // Number of years to renew for
|
||||
'EPP_AUTH_CODE_HERE', // EPP/Auth code from current registrar
|
||||
{
|
||||
addFreeWhoisguard: true,
|
||||
whoisguardEnable: true
|
||||
}
|
||||
);
|
||||
|
||||
// Validate the result
|
||||
expect(result).toBeTypeOf('object');
|
||||
expect(result.isSuccess).toBeTrue();
|
||||
|
||||
// Log the transfer result with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Domain transfer initiated successfully`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Transfer ID: ${result.transferId}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Order ID: ${result.transferOrderId}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Status: ${result.transferStatus}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Description: ${result.statusDescription}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Charged Amount: ${result.chargedAmount}`,
|
||||
'green'
|
||||
));
|
||||
});
|
||||
|
||||
// Test transfer status retrieval
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Transfer - Get Transfer Status', async () => {
|
||||
console.log('Skipping transfer status test - no credentials or transfer tests disabled');
|
||||
});
|
||||
} else {
|
||||
tap.test('Transfer - Get Transfer Status', async (tools) => {
|
||||
// This test requires an existing transfer ID
|
||||
// If you don't have one, it will be skipped
|
||||
const transferId = process.env.TEST_TRANSFER_ID ? parseInt(process.env.TEST_TRANSFER_ID) : null;
|
||||
|
||||
if (!transferId) {
|
||||
console.log(await tools.coloredString(
|
||||
'Skipping transfer status test - no TEST_TRANSFER_ID provided',
|
||||
'blue'
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set a timeout for the test
|
||||
tools.timeout(15000); // 15 seconds timeout
|
||||
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
console.log(await tools.coloredString(
|
||||
`Getting status for transfer ID: ${transferId}`,
|
||||
'cyan'
|
||||
));
|
||||
|
||||
// Get transfer status
|
||||
const status = await client.transfer.getStatus(transferId);
|
||||
|
||||
// Validate the result
|
||||
expect(status).toBeTypeOf('object');
|
||||
expect(status.id).toEqual(transferId);
|
||||
|
||||
// Log the transfer status with colored output
|
||||
console.log(await tools.coloredString(
|
||||
`Transfer ID: ${status.id}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Domain: ${status.domainName}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Status: ${status.status}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Description: ${status.statusDescription}`,
|
||||
'green'
|
||||
));
|
||||
console.log(await tools.coloredString(
|
||||
`Date: ${status.date}`,
|
||||
'green'
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
// Start the tests
|
||||
tap.start();
|
130
test/test.ts
Normal file
130
test/test.ts
Normal file
@ -0,0 +1,130 @@
|
||||
import { expect, expectAsync, tap } from '@push.rocks/tapbundle';
|
||||
import { createTestClient, TEST_DOMAINS, hasRealCredentials } from './config.js';
|
||||
|
||||
const testDomain = TEST_DOMAINS.INFO; // Use the test domain from config
|
||||
|
||||
// Skip live API tests if no real credentials
|
||||
const skipLiveTests = !hasRealCredentials();
|
||||
|
||||
// Test suite for Namecheap API client
|
||||
tap.test('Namecheap API Client - Configuration', async () => {
|
||||
// Create a new client instance
|
||||
const client = createTestClient()
|
||||
|
||||
// Test that the client was created successfully
|
||||
expect(client).toBeTypeOf('object');
|
||||
expect(client.domains).toBeTypeOf('object');
|
||||
expect(client.dns).toBeTypeOf('object');
|
||||
expect(client.ns).toBeTypeOf('object');
|
||||
expect(client.transfer).toBeTypeOf('object');
|
||||
|
||||
// Test configuration methods
|
||||
expect(client.enableSandbox).toBeTypeOf('function');
|
||||
expect(client.disableSandbox).toBeTypeOf('function');
|
||||
expect(client.setTimeout).toBeTypeOf('function');
|
||||
});
|
||||
|
||||
tap.test('Namecheap API Client - Domain Methods', async () => {
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Test that domain methods exist
|
||||
expect(client.domains.getList).toBeTypeOf('function');
|
||||
expect(client.domains.check).toBeTypeOf('function');
|
||||
expect(client.domains.getInfo).toBeTypeOf('function');
|
||||
expect(client.domains.getContacts).toBeTypeOf('function');
|
||||
expect(client.domains.setContacts).toBeTypeOf('function');
|
||||
expect(client.domains.create).toBeTypeOf('function');
|
||||
expect(client.domains.renew).toBeTypeOf('function');
|
||||
expect(client.domains.reactivate).toBeTypeOf('function');
|
||||
expect(client.domains.getRegistrarLock).toBeTypeOf('function');
|
||||
expect(client.domains.setRegistrarLock).toBeTypeOf('function');
|
||||
expect(client.domains.getTldList).toBeTypeOf('function');
|
||||
});
|
||||
|
||||
tap.test('Namecheap API Client - DNS Methods', async () => {
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Test that DNS methods exist
|
||||
expect(client.dns.getHosts).toBeTypeOf('function');
|
||||
expect(client.dns.setHosts).toBeTypeOf('function');
|
||||
expect(client.dns.setCustom).toBeTypeOf('function');
|
||||
expect(client.dns.getEmailForwarding).toBeTypeOf('function');
|
||||
expect(client.dns.setEmailForwarding).toBeTypeOf('function');
|
||||
expect(client.dns.getList).toBeTypeOf('function');
|
||||
});
|
||||
|
||||
tap.test('Namecheap API Client - Nameserver Methods', async () => {
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Test that nameserver methods exist
|
||||
expect(client.ns.create).toBeTypeOf('function');
|
||||
expect(client.ns.delete).toBeTypeOf('function');
|
||||
expect(client.ns.getInfo).toBeTypeOf('function');
|
||||
expect(client.ns.update).toBeTypeOf('function');
|
||||
});
|
||||
|
||||
tap.test('Namecheap API Client - Transfer Methods', async () => {
|
||||
// Create a new client instance
|
||||
const client = createTestClient();
|
||||
|
||||
// Test that transfer methods exist
|
||||
expect(client.transfer.getList).toBeTypeOf('function');
|
||||
expect(client.transfer.getStatus).toBeTypeOf('function');
|
||||
expect(client.transfer.create).toBeTypeOf('function');
|
||||
expect(client.transfer.updateStatus).toBeTypeOf('function');
|
||||
expect(client.transfer.getInfo).toBeTypeOf('function');
|
||||
});
|
||||
|
||||
// This test uses expectAsync to demonstrate async testing
|
||||
tap.test('Namecheap API Client - Async Test', async () => {
|
||||
// Create a simple async function that returns a string
|
||||
const asyncFunction = async () => {
|
||||
return `Testing domain: ${testDomain}`;
|
||||
};
|
||||
|
||||
// Use expectAsync to test the async function
|
||||
const result = await asyncFunction();
|
||||
expect(result).toEqual(`Testing domain: ${testDomain}`);
|
||||
|
||||
// Test that the function returns a Promise
|
||||
expectAsync(asyncFunction());
|
||||
});
|
||||
|
||||
// Domain availability tests
|
||||
if (skipLiveTests) {
|
||||
tap.skip.test('Domain Availability - Check Single Domain', async () => {
|
||||
// This test is skipped when no real credentials are available
|
||||
console.log('Skipping domain availability test - no credentials');
|
||||
});
|
||||
} else {
|
||||
tap.test('Domain Availability - Check Single Domain', async (tools) => {
|
||||
// Set a timeout for the test
|
||||
tools.timeout(10000); // 10 seconds timeout
|
||||
|
||||
// Log test information with colored output
|
||||
console.log(await tools.coloredString(`Testing domain: ${testDomain}`, 'cyan'));
|
||||
|
||||
// Create a new client instance with real credentials
|
||||
const client = createTestClient();
|
||||
|
||||
// Check if the test domain is available
|
||||
const availability = await client.domains.check(testDomain);
|
||||
|
||||
// Log the result
|
||||
const isAvailable = availability[0].available;
|
||||
console.log(await tools.coloredString(
|
||||
`Domain ${testDomain} is ${isAvailable ? 'available' : 'not available'} for registration`,
|
||||
isAvailable ? 'green' : 'blue'
|
||||
));
|
||||
|
||||
// We don't assert on the result since availability can change
|
||||
// Just verify that the call completes without errors
|
||||
expect(availability).toBeTypeOf('object');
|
||||
expect(availability.length).toBeGreaterThan(0);
|
||||
});
|
||||
}
|
||||
|
||||
tap.start();
|
100
ts/config.ts
Normal file
100
ts/config.ts
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Namecheap API Client - Configuration
|
||||
*/
|
||||
import type { INamecheapAuth } from './types.js';
|
||||
|
||||
export class NamecheapConfig implements INamecheapAuth {
|
||||
// Required authentication properties
|
||||
apiUser: string;
|
||||
apiKey: string;
|
||||
userName: string;
|
||||
clientIp: string;
|
||||
|
||||
// API endpoint configuration
|
||||
baseUrl: string = 'https://api.namecheap.com/xml.response';
|
||||
|
||||
// Whether to use sandbox environment (for testing)
|
||||
useSandbox: boolean = false;
|
||||
|
||||
// Default request timeout in milliseconds
|
||||
timeout: number = 30000;
|
||||
|
||||
/**
|
||||
* Create a new Namecheap API configuration
|
||||
*/
|
||||
constructor(config: INamecheapAuth) {
|
||||
this.apiUser = config.apiUser;
|
||||
this.apiKey = config.apiKey;
|
||||
this.userName = config.userName || config.apiUser; // Default userName to apiUser if not provided
|
||||
this.clientIp = config.clientIp;
|
||||
|
||||
this.validateConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate configuration parameters
|
||||
* @throws Error if configuration is invalid
|
||||
*/
|
||||
private validateConfig(): void {
|
||||
if (!this.apiUser) {
|
||||
throw new Error('Namecheap API User is required');
|
||||
}
|
||||
|
||||
if (!this.apiKey) {
|
||||
throw new Error('Namecheap API Key is required');
|
||||
}
|
||||
|
||||
if (!this.userName) {
|
||||
throw new Error('Namecheap User Name is required');
|
||||
}
|
||||
|
||||
if (!this.clientIp) {
|
||||
throw new Error('Client IP address is required');
|
||||
}
|
||||
|
||||
// Validate IP address format
|
||||
const ipRegex = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
|
||||
if (!ipRegex.test(this.clientIp)) {
|
||||
throw new Error('Invalid IP address format');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable sandbox mode for testing
|
||||
*/
|
||||
enableSandbox(): void {
|
||||
this.useSandbox = true;
|
||||
this.baseUrl = 'https://api.sandbox.namecheap.com/xml.response';
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable sandbox mode
|
||||
*/
|
||||
disableSandbox(): void {
|
||||
this.useSandbox = false;
|
||||
this.baseUrl = 'https://api.namecheap.com/xml.response';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set request timeout
|
||||
* @param ms Timeout in milliseconds
|
||||
*/
|
||||
setTimeout(ms: number): void {
|
||||
this.timeout = ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base parameters that should be included in every API request
|
||||
* @param command API command to execute
|
||||
* @returns Base parameters object
|
||||
*/
|
||||
getBaseParams(command: string): Record<string, string | number> {
|
||||
return {
|
||||
ApiUser: this.apiUser,
|
||||
ApiKey: this.apiKey,
|
||||
UserName: this.userName,
|
||||
ClientIp: this.clientIp,
|
||||
Command: command
|
||||
};
|
||||
}
|
||||
}
|
245
ts/domains-dns.ts
Normal file
245
ts/domains-dns.ts
Normal file
@ -0,0 +1,245 @@
|
||||
/**
|
||||
* Namecheap API Client - Domains DNS Module
|
||||
*/
|
||||
import { HttpClient } from './http-client.js';
|
||||
import type {
|
||||
IDnsDomainHostsResponse,
|
||||
IDnsHost,
|
||||
IDnsSetHostsResponse,
|
||||
IDnsSetCustomResponse,
|
||||
IDnsGetEmailForwardingResponse,
|
||||
IDnsSetEmailForwardingResponse,
|
||||
IDnsGetListResponse,
|
||||
IDnsRecord
|
||||
} from './types.js';
|
||||
|
||||
export class DomainsDns {
|
||||
private client: HttpClient;
|
||||
|
||||
/**
|
||||
* Create a new Domains DNS API handler
|
||||
* @param client HTTP client instance
|
||||
*/
|
||||
constructor(client: HttpClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of DNS hosts for a domain
|
||||
* @param domainName Domain name to get hosts for
|
||||
* @param sld Second-level domain (optional)
|
||||
* @param tld Top-level domain (optional)
|
||||
* @returns Array of DNS host records
|
||||
*/
|
||||
async getHosts(domainName: string, sld?: string, tld?: string): Promise<IDnsHost[]> {
|
||||
// Prepare the request parameters
|
||||
const params: Record<string, string> = {};
|
||||
|
||||
// If SLD and TLD are provided, use them instead of DomainName
|
||||
if (sld && tld) {
|
||||
params.SLD = sld;
|
||||
params.TLD = tld;
|
||||
} else {
|
||||
params.DomainName = domainName;
|
||||
}
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDnsDomainHostsResponse>(
|
||||
'namecheap.domains.dns.getHosts',
|
||||
params
|
||||
);
|
||||
|
||||
// Extract host records from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const hosts = commandResponse.DomainDNSGetHostsResult[0].host || [];
|
||||
|
||||
// Convert the parsed XML structure to a more usable format
|
||||
return hosts.map(host => ({
|
||||
id: parseInt(host.$.HostId, 10),
|
||||
name: host.$.Name,
|
||||
type: host.$.Type,
|
||||
address: host.$.Address,
|
||||
mxPref: host.$.MXPref ? parseInt(host.$.MXPref, 10) : 0,
|
||||
ttl: parseInt(host.$.TTL, 10),
|
||||
isActive: host.$.IsActive?.toLowerCase() === 'true',
|
||||
isDDNSEnabled: host.$.IsDDNSEnabled?.toLowerCase() === 'true'
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set DNS host records for a domain
|
||||
* @param domainName Domain name to set hosts for
|
||||
* @param hosts Array of host records to set
|
||||
* @param sld Second-level domain (optional)
|
||||
* @param tld Top-level domain (optional)
|
||||
* @returns Success status
|
||||
*/
|
||||
async setHosts(
|
||||
domainName: string,
|
||||
hosts: Array<{
|
||||
hostName: string;
|
||||
recordType: 'A' | 'AAAA' | 'CNAME' | 'MX' | 'TXT' | 'URL' | 'FRAME' | 'NS';
|
||||
address: string;
|
||||
mxPref?: number;
|
||||
ttl?: number;
|
||||
}>,
|
||||
sld?: string,
|
||||
tld?: string
|
||||
): Promise<boolean> {
|
||||
// Prepare the request parameters
|
||||
const params: Record<string, string | number> = {};
|
||||
|
||||
// If SLD and TLD are provided, use them instead of DomainName
|
||||
if (sld && tld) {
|
||||
params.SLD = sld;
|
||||
params.TLD = tld;
|
||||
} else {
|
||||
params.DomainName = domainName;
|
||||
}
|
||||
|
||||
// Add host records to the parameters
|
||||
hosts.forEach((host, index) => {
|
||||
params[`HostName${index + 1}`] = host.hostName;
|
||||
params[`RecordType${index + 1}`] = host.recordType;
|
||||
params[`Address${index + 1}`] = host.address;
|
||||
|
||||
if (host.mxPref !== undefined) {
|
||||
params[`MXPref${index + 1}`] = host.mxPref;
|
||||
}
|
||||
|
||||
if (host.ttl !== undefined) {
|
||||
params[`TTL${index + 1}`] = host.ttl;
|
||||
}
|
||||
});
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDnsSetHostsResponse>(
|
||||
'namecheap.domains.dns.setHosts',
|
||||
params
|
||||
);
|
||||
|
||||
// Check if the operation was successful
|
||||
return response.ApiResponse.$.Status === 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom nameservers for a domain
|
||||
* @param domainName Domain name to set nameservers for
|
||||
* @param nameservers Array of nameserver hostnames
|
||||
* @param sld Second-level domain (optional)
|
||||
* @param tld Top-level domain (optional)
|
||||
* @returns Success status
|
||||
*/
|
||||
async setCustom(
|
||||
domainName: string,
|
||||
nameservers: string[],
|
||||
sld?: string,
|
||||
tld?: string
|
||||
): Promise<boolean> {
|
||||
// Prepare the request parameters
|
||||
const params: Record<string, string> = {};
|
||||
|
||||
// If SLD and TLD are provided, use them instead of DomainName
|
||||
if (sld && tld) {
|
||||
params.SLD = sld;
|
||||
params.TLD = tld;
|
||||
} else {
|
||||
params.DomainName = domainName;
|
||||
}
|
||||
|
||||
// Add nameservers to the parameters
|
||||
params.Nameservers = nameservers.join(',');
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDnsSetCustomResponse>(
|
||||
'namecheap.domains.dns.setCustom',
|
||||
params
|
||||
);
|
||||
|
||||
// Check if the operation was successful
|
||||
return response.ApiResponse.$.Status === 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get email forwarding settings for a domain
|
||||
* @param domainName Domain name to get email forwarding for
|
||||
* @returns Email forwarding settings
|
||||
*/
|
||||
async getEmailForwarding(domainName: string): Promise<Array<{
|
||||
from: string;
|
||||
to: string;
|
||||
}>> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDnsGetEmailForwardingResponse>(
|
||||
'namecheap.domains.dns.getEmailForwarding',
|
||||
{ DomainName: domainName }
|
||||
);
|
||||
|
||||
// Extract email forwarding settings from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const forwardings = commandResponse.DomainDNSGetEmailForwardingResult[0].forward || [];
|
||||
|
||||
// Convert the parsed XML structure to a more usable format
|
||||
return forwardings.map(forward => ({
|
||||
from: forward.$.from,
|
||||
to: forward.$.to
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set email forwarding settings for a domain
|
||||
* @param domainName Domain name to set email forwarding for
|
||||
* @param forwardings Array of email forwarding settings
|
||||
* @returns Success status
|
||||
*/
|
||||
async setEmailForwarding(
|
||||
domainName: string,
|
||||
forwardings: Array<{
|
||||
from: string;
|
||||
to: string;
|
||||
}>
|
||||
): Promise<boolean> {
|
||||
// Prepare the request parameters
|
||||
const params: Record<string, string> = {
|
||||
DomainName: domainName
|
||||
};
|
||||
|
||||
// Add email forwarding settings to the parameters
|
||||
forwardings.forEach((forward, index) => {
|
||||
params[`MailBox${index + 1}`] = forward.from;
|
||||
params[`ForwardTo${index + 1}`] = forward.to;
|
||||
});
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDnsSetEmailForwardingResponse>(
|
||||
'namecheap.domains.dns.setEmailForwarding',
|
||||
params
|
||||
);
|
||||
|
||||
// Check if the operation was successful
|
||||
return response.ApiResponse.$.Status === 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of DNS servers for a domain
|
||||
* @param sld Second-level domain
|
||||
* @param tld Top-level domain
|
||||
* @returns Array of DNS server names
|
||||
*/
|
||||
async getList(sld: string, tld: string): Promise<string[]> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDnsGetListResponse>(
|
||||
'namecheap.domains.dns.getList',
|
||||
{
|
||||
SLD: sld,
|
||||
TLD: tld
|
||||
}
|
||||
);
|
||||
|
||||
// Extract DNS server list from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const dnsServers = commandResponse.DomainDNSGetListResult[0].Nameserver || [];
|
||||
|
||||
return dnsServers;
|
||||
}
|
||||
}
|
130
ts/domains-ns.ts
Normal file
130
ts/domains-ns.ts
Normal file
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Namecheap API Client - Domains Nameservers Module
|
||||
*/
|
||||
import { HttpClient } from './http-client.js';
|
||||
import type {
|
||||
INsCreateResponse,
|
||||
INsDeleteResponse,
|
||||
INsGetInfoResponse,
|
||||
INsUpdateResponse,
|
||||
INsInfo
|
||||
} from './types.js';
|
||||
|
||||
export class DomainsNs {
|
||||
private client: HttpClient;
|
||||
|
||||
/**
|
||||
* Create a new Domains Nameservers API handler
|
||||
* @param client HTTP client instance
|
||||
*/
|
||||
constructor(client: HttpClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new nameserver
|
||||
* @param sld Second-level domain
|
||||
* @param tld Top-level domain
|
||||
* @param nameserver Nameserver hostname
|
||||
* @param ip Nameserver IP address
|
||||
* @returns Success status
|
||||
*/
|
||||
async create(sld: string, tld: string, nameserver: string, ip: string): Promise<boolean> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<INsCreateResponse>(
|
||||
'namecheap.domains.ns.create',
|
||||
{
|
||||
SLD: sld,
|
||||
TLD: tld,
|
||||
Nameserver: nameserver,
|
||||
IP: ip
|
||||
}
|
||||
);
|
||||
|
||||
// Check if the operation was successful
|
||||
return response.ApiResponse.$.Status === 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a nameserver
|
||||
* @param sld Second-level domain
|
||||
* @param tld Top-level domain
|
||||
* @param nameserver Nameserver hostname
|
||||
* @returns Success status
|
||||
*/
|
||||
async delete(sld: string, tld: string, nameserver: string): Promise<boolean> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<INsDeleteResponse>(
|
||||
'namecheap.domains.ns.delete',
|
||||
{
|
||||
SLD: sld,
|
||||
TLD: tld,
|
||||
Nameserver: nameserver
|
||||
}
|
||||
);
|
||||
|
||||
// Check if the operation was successful
|
||||
return response.ApiResponse.$.Status === 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about a nameserver
|
||||
* @param sld Second-level domain
|
||||
* @param tld Top-level domain
|
||||
* @param nameserver Nameserver hostname
|
||||
* @returns Nameserver information
|
||||
*/
|
||||
async getInfo(sld: string, tld: string, nameserver: string): Promise<INsInfo> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<INsGetInfoResponse>(
|
||||
'namecheap.domains.ns.getInfo',
|
||||
{
|
||||
SLD: sld,
|
||||
TLD: tld,
|
||||
Nameserver: nameserver
|
||||
}
|
||||
);
|
||||
|
||||
// Extract nameserver information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const nsInfo = commandResponse.DomainNSInfoResult[0].$;
|
||||
|
||||
return {
|
||||
nameserver: nsInfo.Nameserver,
|
||||
ip: nsInfo.IP,
|
||||
statuses: nsInfo.Statuses?.split(',') || []
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a nameserver's IP address
|
||||
* @param sld Second-level domain
|
||||
* @param tld Top-level domain
|
||||
* @param nameserver Nameserver hostname
|
||||
* @param oldIp Old IP address
|
||||
* @param newIp New IP address
|
||||
* @returns Success status
|
||||
*/
|
||||
async update(
|
||||
sld: string,
|
||||
tld: string,
|
||||
nameserver: string,
|
||||
oldIp: string,
|
||||
newIp: string
|
||||
): Promise<boolean> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<INsUpdateResponse>(
|
||||
'namecheap.domains.ns.update',
|
||||
{
|
||||
SLD: sld,
|
||||
TLD: tld,
|
||||
Nameserver: nameserver,
|
||||
OldIP: oldIp,
|
||||
IP: newIp
|
||||
}
|
||||
);
|
||||
|
||||
// Check if the operation was successful
|
||||
return response.ApiResponse.$.Status === 'OK';
|
||||
}
|
||||
}
|
261
ts/domains-transfer.ts
Normal file
261
ts/domains-transfer.ts
Normal file
@ -0,0 +1,261 @@
|
||||
/**
|
||||
* Namecheap API Client - Domains Transfer Module
|
||||
*/
|
||||
import { HttpClient } from './http-client.js';
|
||||
import type {
|
||||
ITransferGetListResponse,
|
||||
ITransferGetStatusResponse,
|
||||
ITransferCreateResponse,
|
||||
ITransferUpdateStatusResponse,
|
||||
ITransferGetInfoResponse,
|
||||
ITransferInfo,
|
||||
ITransferStatusInfo
|
||||
} from './types.js';
|
||||
|
||||
export class DomainsTransfer {
|
||||
private client: HttpClient;
|
||||
|
||||
/**
|
||||
* Create a new Domains Transfer API handler
|
||||
* @param client HTTP client instance
|
||||
*/
|
||||
constructor(client: HttpClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of domain transfers
|
||||
* @param page Page number
|
||||
* @param pageSize Number of items per page
|
||||
* @param listType Type of transfers to list
|
||||
* @returns List of domain transfers
|
||||
*/
|
||||
async getList(
|
||||
page: number = 1,
|
||||
pageSize: number = 20,
|
||||
listType: 'ALL' | 'INPROGRESS' | 'COMPLETED' | 'FAILED' = 'ALL'
|
||||
): Promise<{
|
||||
transfers: ITransferInfo[];
|
||||
paging: {
|
||||
totalItems: number;
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
};
|
||||
}> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<ITransferGetListResponse>(
|
||||
'namecheap.domains.transfer.getList',
|
||||
{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
ListType: listType
|
||||
}
|
||||
);
|
||||
|
||||
// Extract transfer information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const transferList = commandResponse.TransferGetListResult[0];
|
||||
const paging = commandResponse.Paging[0];
|
||||
|
||||
// Convert the parsed XML structure to a more usable format
|
||||
const transfers = (transferList.Transfer || []).map(transfer => ({
|
||||
id: parseInt(transfer.$.ID, 10),
|
||||
domainName: transfer.$.DomainName,
|
||||
status: transfer.$.Status,
|
||||
statusDescription: transfer.$.StatusDescription,
|
||||
date: transfer.$.Date,
|
||||
lockTransferDate: transfer.$.LockTransferDate || null,
|
||||
transferOrderDetailId: parseInt(transfer.$.TransferOrderDetailID || '0', 10),
|
||||
isLocked: transfer.$.IsLocked?.toLowerCase() === 'true',
|
||||
authInfo: transfer.$.AuthInfo || null
|
||||
}));
|
||||
|
||||
// Convert paging information
|
||||
const pagingInfo = paging ? {
|
||||
totalItems: parseInt(paging.TotalItems[0], 10),
|
||||
currentPage: parseInt(paging.CurrentPage[0], 10),
|
||||
pageSize: parseInt(paging.PageSize[0], 10)
|
||||
} : {
|
||||
totalItems: transfers.length,
|
||||
currentPage: 1,
|
||||
pageSize: transfers.length
|
||||
};
|
||||
|
||||
return {
|
||||
transfers,
|
||||
paging: pagingInfo
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status of a domain transfer
|
||||
* @param transferId Transfer ID
|
||||
* @returns Transfer status information
|
||||
*/
|
||||
async getStatus(transferId: number): Promise<ITransferStatusInfo> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<ITransferGetStatusResponse>(
|
||||
'namecheap.domains.transfer.getStatus',
|
||||
{ TransferID: transferId }
|
||||
);
|
||||
|
||||
// Extract status information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const statusInfo = commandResponse.TransferGetStatusResult[0].$;
|
||||
|
||||
return {
|
||||
id: parseInt(statusInfo.TransferID, 10),
|
||||
status: statusInfo.Status,
|
||||
statusDescription: statusInfo.StatusDescription,
|
||||
domainName: statusInfo.DomainName,
|
||||
date: statusInfo.Date,
|
||||
lockTransferDate: statusInfo.LockTransferDate || null,
|
||||
transferOrderDetailId: parseInt(statusInfo.TransferOrderDetailID || '0', 10),
|
||||
isLocked: statusInfo.IsLocked?.toLowerCase() === 'true',
|
||||
authInfo: statusInfo.AuthInfo || null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new domain transfer
|
||||
* @param domainName Domain name to transfer
|
||||
* @param years Number of years to renew for
|
||||
* @param authCode Authorization code from current registrar
|
||||
* @param options Additional options
|
||||
* @returns Transfer creation result
|
||||
*/
|
||||
async create(
|
||||
domainName: string,
|
||||
years: number,
|
||||
authCode: string,
|
||||
options?: {
|
||||
promotionCode?: string;
|
||||
addFreeWhoisguard?: boolean;
|
||||
whoisguardEnable?: boolean;
|
||||
idnCode?: string;
|
||||
premiumPrice?: number;
|
||||
eapFee?: number;
|
||||
}
|
||||
): Promise<{
|
||||
transferId: number;
|
||||
transferOrderId: number;
|
||||
isSuccess: boolean;
|
||||
transferStatus: string;
|
||||
statusDescription: string;
|
||||
chargedAmount: number;
|
||||
}> {
|
||||
// Prepare the request parameters
|
||||
const params: Record<string, string | number | boolean> = {
|
||||
DomainName: domainName,
|
||||
Years: years,
|
||||
EPPCode: authCode
|
||||
};
|
||||
|
||||
// Add optional parameters
|
||||
if (options) {
|
||||
if (options.promotionCode) {
|
||||
params.PromotionCode = options.promotionCode;
|
||||
}
|
||||
|
||||
if (options.addFreeWhoisguard !== undefined) {
|
||||
params.AddFreeWhoisguard = options.addFreeWhoisguard;
|
||||
}
|
||||
|
||||
if (options.whoisguardEnable !== undefined) {
|
||||
params.WGEnable = options.whoisguardEnable;
|
||||
}
|
||||
|
||||
if (options.idnCode) {
|
||||
params.IdnCode = options.idnCode;
|
||||
}
|
||||
|
||||
if (options.premiumPrice !== undefined) {
|
||||
params.PremiumPrice = options.premiumPrice;
|
||||
}
|
||||
|
||||
if (options.eapFee !== undefined) {
|
||||
params.EapFee = options.eapFee;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<ITransferCreateResponse>(
|
||||
'namecheap.domains.transfer.create',
|
||||
params
|
||||
);
|
||||
|
||||
// Extract creation information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const result = commandResponse.DomainTransferCreateResult[0].$;
|
||||
|
||||
return {
|
||||
transferId: parseInt(result.TransferID, 10),
|
||||
transferOrderId: parseInt(result.OrderID, 10),
|
||||
isSuccess: result.IsSuccess?.toLowerCase() === 'true',
|
||||
transferStatus: result.Status,
|
||||
statusDescription: result.StatusDescription,
|
||||
chargedAmount: parseFloat(result.ChargedAmount)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the status of a domain transfer
|
||||
* @param transferId Transfer ID
|
||||
* @param resubmit Whether to resubmit the transfer
|
||||
* @returns Success status
|
||||
*/
|
||||
async updateStatus(transferId: number, resubmit: boolean): Promise<boolean> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<ITransferUpdateStatusResponse>(
|
||||
'namecheap.domains.transfer.updateStatus',
|
||||
{
|
||||
TransferID: transferId,
|
||||
Resubmit: resubmit
|
||||
}
|
||||
);
|
||||
|
||||
// Check if the operation was successful
|
||||
return response.ApiResponse.$.Status === 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get detailed information about a domain transfer
|
||||
* @param transferId Transfer ID
|
||||
* @returns Detailed transfer information
|
||||
*/
|
||||
async getInfo(transferId: number): Promise<{
|
||||
transferId: number;
|
||||
domainName: string;
|
||||
status: string;
|
||||
statusDescription: string;
|
||||
authInfo: string;
|
||||
date: string;
|
||||
whoisguardStatus: string;
|
||||
orderDate: string;
|
||||
orderId: number;
|
||||
transferOrderDetailId: number;
|
||||
}> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<ITransferGetInfoResponse>(
|
||||
'namecheap.domains.transfer.getInfo',
|
||||
{ TransferID: transferId }
|
||||
);
|
||||
|
||||
// Extract detailed information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const info = commandResponse.TransferGetInfoResult[0].$;
|
||||
|
||||
return {
|
||||
transferId: parseInt(info.TransferID, 10),
|
||||
domainName: info.DomainName,
|
||||
status: info.Status,
|
||||
statusDescription: info.StatusDescription,
|
||||
authInfo: info.AuthInfo || '',
|
||||
date: info.Date,
|
||||
whoisguardStatus: info.WhoisguardStatus || '',
|
||||
orderDate: info.OrderDate,
|
||||
orderId: parseInt(info.OrderID, 10),
|
||||
transferOrderDetailId: parseInt(info.TransferOrderDetailID, 10)
|
||||
};
|
||||
}
|
||||
}
|
577
ts/domains.ts
Normal file
577
ts/domains.ts
Normal file
@ -0,0 +1,577 @@
|
||||
/**
|
||||
* Namecheap API Client - Domains Module
|
||||
*/
|
||||
import { HttpClient } from './http-client.js';
|
||||
import type {
|
||||
IDomainsGetListParams,
|
||||
IDomainsGetListResponse,
|
||||
IDomainInfo,
|
||||
IDomainCheckResponse,
|
||||
IDomainCheckResult,
|
||||
IDomainAvailability,
|
||||
IDomainCreateParams,
|
||||
IDomainCreateResponse,
|
||||
IDomainGetInfoResponse,
|
||||
IDomainInfoResult,
|
||||
IDomainContacts,
|
||||
IDomainGetContactsResponse,
|
||||
IDomainSetContactsParams,
|
||||
IDomainRenewResponse,
|
||||
IDomainRenewResult,
|
||||
IRegistrarLockResponse,
|
||||
IDomainTldListResponse,
|
||||
IContactInfo
|
||||
} from './types.js';
|
||||
|
||||
export class Domains {
|
||||
private client: HttpClient;
|
||||
|
||||
/**
|
||||
* Create a new Domains API handler
|
||||
* @param client HTTP client instance
|
||||
*/
|
||||
constructor(client: HttpClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of domains in the Namecheap account
|
||||
* @param params Optional parameters for filtering and pagination
|
||||
* @returns Array of domain information objects
|
||||
*/
|
||||
async getList(params: IDomainsGetListParams = {}): Promise<{
|
||||
domains: IDomainInfo[];
|
||||
paging: {
|
||||
totalItems: number;
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
};
|
||||
}> {
|
||||
// Convert parameters to the format expected by the API
|
||||
const requestParams: Record<string, string | number | boolean> = {};
|
||||
|
||||
// Add optional parameters if provided
|
||||
if (params.Page !== undefined) {
|
||||
requestParams.Page = params.Page;
|
||||
}
|
||||
|
||||
if (params.PageSize !== undefined) {
|
||||
requestParams.PageSize = params.PageSize;
|
||||
}
|
||||
|
||||
if (params.SortBy !== undefined) {
|
||||
requestParams.SortBy = params.SortBy;
|
||||
}
|
||||
|
||||
if (params.ListType !== undefined) {
|
||||
requestParams.ListType = params.ListType;
|
||||
}
|
||||
|
||||
if (params.SearchTerm !== undefined) {
|
||||
requestParams.SearchTerm = params.SearchTerm;
|
||||
}
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDomainsGetListResponse>(
|
||||
'namecheap.domains.getList',
|
||||
requestParams
|
||||
);
|
||||
|
||||
// Extract domain information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const domainListResult = commandResponse.DomainGetListResult[0];
|
||||
const paging = commandResponse.Paging[0];
|
||||
|
||||
// Convert the parsed XML structure to a more usable format
|
||||
const domains = (domainListResult.Domain || []).map(domain => {
|
||||
const domainInfo: IDomainInfo = {
|
||||
...domain.$,
|
||||
// Convert string boolean values to actual booleans
|
||||
IsExpired: String(domain.$.IsExpired).toLowerCase() === 'true',
|
||||
IsLocked: String(domain.$.IsLocked).toLowerCase() === 'true',
|
||||
AutoRenew: String(domain.$.AutoRenew).toLowerCase() === 'true',
|
||||
IsPremium: String(domain.$.IsPremium).toLowerCase() === 'true',
|
||||
IsOurDNS: String(domain.$.IsOurDNS).toLowerCase() === 'true',
|
||||
// Join nameservers array with commas if it exists
|
||||
Nameservers: Array.isArray(domain.Nameservers) && domain.Nameservers.length > 0 ?
|
||||
domain.Nameservers[0] : ''
|
||||
};
|
||||
|
||||
return domainInfo;
|
||||
});
|
||||
|
||||
// Convert paging information
|
||||
const pagingInfo = paging ? {
|
||||
totalItems: parseInt(paging.TotalItems[0], 10),
|
||||
currentPage: parseInt(paging.CurrentPage[0], 10),
|
||||
pageSize: parseInt(paging.PageSize[0], 10)
|
||||
} : {
|
||||
totalItems: domains.length,
|
||||
currentPage: 1,
|
||||
pageSize: domains.length
|
||||
};
|
||||
|
||||
return {
|
||||
domains,
|
||||
paging: pagingInfo
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if domains are available for registration
|
||||
* @param domainNames Domain name(s) to check (single string or array of strings)
|
||||
* @returns Domain availability information
|
||||
*/
|
||||
async check(domainNames: string | string[]): Promise<IDomainAvailability[]> {
|
||||
// Convert single domain to array if needed
|
||||
const domains = Array.isArray(domainNames) ? domainNames : [domainNames];
|
||||
|
||||
// Join domains with comma for the API request
|
||||
const domainList = domains.join(',');
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDomainCheckResponse>(
|
||||
'namecheap.domains.check',
|
||||
{ DomainList: domainList }
|
||||
);
|
||||
|
||||
// Parse the response to determine availability
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const results: IDomainCheckResult[] = Array.isArray(commandResponse.DomainCheckResult)
|
||||
? commandResponse.DomainCheckResult
|
||||
: [commandResponse.DomainCheckResult];
|
||||
|
||||
// Convert the results to a more usable format
|
||||
return results.map(result => ({
|
||||
domain: result.$.Domain,
|
||||
available: String(result.$.Available).toLowerCase() === 'true',
|
||||
errorNo: parseInt(result.$.ErrorNo || '0', 10),
|
||||
description: result.$.Description || '',
|
||||
isPremium: String(result.$.IsPremiumName).toLowerCase() === 'true',
|
||||
premiumRegistrationPrice: parseFloat(result.$.PremiumRegistrationPrice || '0'),
|
||||
premiumRenewalPrice: parseFloat(result.$.PremiumRenewalPrice || '0'),
|
||||
premiumRestorePrice: parseFloat(result.$.PremiumRestorePrice || '0'),
|
||||
premiumTransferPrice: parseFloat(result.$.PremiumTransferPrice || '0'),
|
||||
icannFee: parseFloat(result.$.IcannFee || '0'),
|
||||
eapFee: parseFloat(result.$.EapFee || '0')
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get detailed information about a specific domain
|
||||
* @param domainName Domain name to get information for
|
||||
* @param hostName Optional host name for hosted domains
|
||||
* @returns Detailed domain information
|
||||
*/
|
||||
async getInfo(domainName: string, hostName?: string): Promise<IDomainInfoResult> {
|
||||
const params: Record<string, string> = { DomainName: domainName };
|
||||
|
||||
if (hostName) {
|
||||
params.HostName = hostName;
|
||||
}
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDomainGetInfoResponse>(
|
||||
'namecheap.domains.getInfo',
|
||||
params
|
||||
);
|
||||
|
||||
// Extract domain information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const domainInfo = commandResponse.DomainGetInfoResult[0];
|
||||
|
||||
// Convert string boolean values to actual booleans
|
||||
const result: IDomainInfoResult = {
|
||||
status: domainInfo.$.Status,
|
||||
id: parseInt(domainInfo.$.ID, 10),
|
||||
domainName: domainInfo.$.DomainName,
|
||||
ownerName: domainInfo.$.OwnerName,
|
||||
isOwner: String(domainInfo.$.IsOwner).toLowerCase() === 'true',
|
||||
isPremium: String(domainInfo.$.IsPremium).toLowerCase() === 'true',
|
||||
createdDate: domainInfo.DomainDetails?.[0]?.CreatedDate?.[0] || '',
|
||||
expiredDate: domainInfo.DomainDetails?.[0]?.ExpiredDate?.[0] || '',
|
||||
whoisGuard: {
|
||||
enabled: domainInfo.Whoisguard?.[0]?.$.Enabled?.toLowerCase() === 'true' || false,
|
||||
id: domainInfo.Whoisguard?.[0]?.ID?.[0] ? parseInt(domainInfo.Whoisguard[0].ID[0], 10) : 0,
|
||||
expiredDate: domainInfo.Whoisguard?.[0]?.ExpiredDate?.[0] || ''
|
||||
},
|
||||
dnsProvider: domainInfo.DnsDetails?.[0]?.$.ProviderType || '',
|
||||
modificationRights: {
|
||||
all: domainInfo.Modificationrights?.[0]?.$.All?.toLowerCase() === 'true' || false
|
||||
}
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contact information for a domain
|
||||
* @param domainName Domain name to get contacts for
|
||||
* @returns Domain contact information
|
||||
* @throws Error if the domain name is invalid or the API request fails
|
||||
*/
|
||||
async getContacts(domainName: string): Promise<IDomainContacts> {
|
||||
if (!domainName) {
|
||||
throw new Error('Domain name is required');
|
||||
}
|
||||
|
||||
try {
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDomainGetContactsResponse>(
|
||||
'namecheap.domains.getContacts',
|
||||
{ DomainName: domainName }
|
||||
);
|
||||
|
||||
// Check for API errors
|
||||
if (response.ApiResponse.$.Status !== 'OK') {
|
||||
const errors = response.ApiResponse.Errors;
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
const error = errors[0] as { Error?: string[] };
|
||||
if (error.Error && error.Error.length > 0) {
|
||||
throw new Error(`API Error: ${error.Error.join(', ')}`);
|
||||
}
|
||||
}
|
||||
throw new Error('Failed to get domain contacts');
|
||||
}
|
||||
|
||||
// Extract contact information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const contacts = commandResponse.DomainContactsResult[0];
|
||||
|
||||
// Convert the parsed XML structure to a more usable format
|
||||
return {
|
||||
registrant: this.parseContact(contacts.Registrant?.[0]),
|
||||
tech: this.parseContact(contacts.Tech?.[0]),
|
||||
admin: this.parseContact(contacts.Admin?.[0]),
|
||||
auxBilling: this.parseContact(contacts.AuxBilling?.[0])
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw error;
|
||||
}
|
||||
throw new Error(`Failed to get domain contacts: ${String(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set contact information for a domain
|
||||
* @param domainName Domain name to set contacts for
|
||||
* @param contacts Contact information to set
|
||||
* @returns Success status
|
||||
* @throws Error if the domain name is invalid, contacts are missing, or the API request fails
|
||||
*/
|
||||
async setContacts(domainName: string, contacts: IDomainSetContactsParams): Promise<boolean> {
|
||||
// Validate inputs
|
||||
if (!domainName) {
|
||||
throw new Error('Domain name is required');
|
||||
}
|
||||
|
||||
if (!contacts || Object.keys(contacts).length === 0) {
|
||||
throw new Error('Contact information is required');
|
||||
}
|
||||
|
||||
// Ensure at least one contact type is provided
|
||||
if (!contacts.registrant && !contacts.tech && !contacts.admin && !contacts.auxBilling) {
|
||||
throw new Error('At least one contact type (registrant, tech, admin, or auxBilling) is required');
|
||||
}
|
||||
|
||||
try {
|
||||
// Prepare the request parameters
|
||||
const params: Record<string, string> = {
|
||||
DomainName: domainName,
|
||||
...this.flattenContacts(contacts)
|
||||
};
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request(
|
||||
'namecheap.domains.setContacts',
|
||||
params
|
||||
);
|
||||
|
||||
// Check for API errors
|
||||
if (response.ApiResponse.$.Status !== 'OK') {
|
||||
const errors = response.ApiResponse.Errors;
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
const error = errors[0] as { Error?: string[] };
|
||||
if (error.Error && error.Error.length > 0) {
|
||||
throw new Error(`API Error: ${error.Error.join(', ')}`);
|
||||
}
|
||||
}
|
||||
throw new Error('Failed to set domain contacts');
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw error;
|
||||
}
|
||||
throw new Error(`Failed to set domain contacts: ${String(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new domain
|
||||
* @param params Domain registration parameters
|
||||
* @returns Registration result
|
||||
*/
|
||||
async create(params: IDomainCreateParams): Promise<{
|
||||
domain: string;
|
||||
registered: boolean;
|
||||
chargedAmount: number;
|
||||
transactionId: number;
|
||||
orderId: number;
|
||||
}> {
|
||||
// Prepare the request parameters
|
||||
const requestParams: Record<string, string | number | boolean> = {
|
||||
DomainName: params.domainName,
|
||||
Years: params.years,
|
||||
...this.flattenContacts(params.contacts)
|
||||
};
|
||||
|
||||
// Add nameservers if provided
|
||||
if (params.nameservers && params.nameservers.length > 0) {
|
||||
requestParams.Nameservers = params.nameservers.join(',');
|
||||
}
|
||||
|
||||
// Add additional parameters
|
||||
if (params.addFreeWhoisguard !== undefined) {
|
||||
requestParams.AddFreeWhoisguard = params.addFreeWhoisguard;
|
||||
}
|
||||
|
||||
if (params.whoisguardPrivacy !== undefined) {
|
||||
requestParams.WGEnabled = params.whoisguardPrivacy;
|
||||
}
|
||||
|
||||
if (params.premiumPrice !== undefined) {
|
||||
requestParams.PremiumPrice = params.premiumPrice;
|
||||
}
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDomainCreateResponse>(
|
||||
'namecheap.domains.create',
|
||||
requestParams
|
||||
);
|
||||
|
||||
// Extract registration information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const domainCreateResult = commandResponse.DomainCreateResult[0];
|
||||
|
||||
return {
|
||||
domain: domainCreateResult.$.Domain,
|
||||
registered: String(domainCreateResult.$.Registered).toLowerCase() === 'true',
|
||||
chargedAmount: parseFloat(domainCreateResult.$.ChargedAmount),
|
||||
transactionId: parseInt(domainCreateResult.$.TransactionID, 10),
|
||||
orderId: parseInt(domainCreateResult.$.OrderID, 10)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Renew a domain registration
|
||||
* @param domainName Domain name to renew
|
||||
* @param years Number of years to renew for
|
||||
* @param premiumPrice Optional premium price for premium domains
|
||||
* @returns Renewal result
|
||||
*/
|
||||
async renew(domainName: string, years: number, premiumPrice?: number): Promise<IDomainRenewResult> {
|
||||
// Prepare the request parameters
|
||||
const params: Record<string, string | number | boolean> = {
|
||||
DomainName: domainName,
|
||||
Years: years
|
||||
};
|
||||
|
||||
if (premiumPrice !== undefined) {
|
||||
params.PremiumPrice = premiumPrice;
|
||||
}
|
||||
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDomainRenewResponse>(
|
||||
'namecheap.domains.renew',
|
||||
params
|
||||
);
|
||||
|
||||
// Extract renewal information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const renewResult = commandResponse.DomainRenewResult[0].$;
|
||||
|
||||
return {
|
||||
domainName: renewResult.DomainName,
|
||||
domainId: parseInt(renewResult.DomainID, 10),
|
||||
renewed: String(renewResult.Renewed).toLowerCase() === 'true',
|
||||
chargedAmount: parseFloat(renewResult.ChargedAmount),
|
||||
transactionId: parseInt(renewResult.TransactionID, 10),
|
||||
orderId: parseInt(renewResult.OrderID, 10),
|
||||
expireDate: renewResult.DomainDetails?.ExpiredDate || ''
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reactivate an expired domain
|
||||
* @param domainName Domain name to reactivate
|
||||
* @returns Reactivation result
|
||||
*/
|
||||
async reactivate(domainName: string): Promise<{
|
||||
domain: string;
|
||||
reactivated: boolean;
|
||||
chargedAmount: number;
|
||||
orderId: number;
|
||||
transactionId: number;
|
||||
}> {
|
||||
// Make the API request
|
||||
const response = await this.client.request(
|
||||
'namecheap.domains.reactivate',
|
||||
{ DomainName: domainName }
|
||||
);
|
||||
|
||||
// Extract reactivation information from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const reactivateResult = commandResponse.DomainReactivateResult[0].$;
|
||||
|
||||
return {
|
||||
domain: reactivateResult.Domain,
|
||||
reactivated: String(reactivateResult.IsSuccess).toLowerCase() === 'true',
|
||||
chargedAmount: parseFloat(reactivateResult.ChargedAmount),
|
||||
orderId: parseInt(reactivateResult.OrderID, 10),
|
||||
transactionId: parseInt(reactivateResult.TransactionID, 10)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the registrar lock status for a domain
|
||||
* @param domainName Domain name to check
|
||||
* @returns Lock status
|
||||
*/
|
||||
async getRegistrarLock(domainName: string): Promise<boolean> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<IRegistrarLockResponse>(
|
||||
'namecheap.domains.getRegistrarLock',
|
||||
{ DomainName: domainName }
|
||||
);
|
||||
|
||||
// Extract lock status from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const lockStatus = commandResponse.DomainGetRegistrarLockResult[0];
|
||||
|
||||
return String(lockStatus.$.RegistrarLockStatus).toLowerCase() === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the registrar lock status for a domain
|
||||
* @param domainName Domain name to update
|
||||
* @param lockStatus New lock status (true to lock, false to unlock)
|
||||
* @returns Success status
|
||||
*/
|
||||
async setRegistrarLock(domainName: string, lockStatus: boolean): Promise<boolean> {
|
||||
// Make the API request
|
||||
const response = await this.client.request(
|
||||
'namecheap.domains.setRegistrarLock',
|
||||
{
|
||||
DomainName: domainName,
|
||||
LockAction: lockStatus ? 'LOCK' : 'UNLOCK'
|
||||
}
|
||||
);
|
||||
|
||||
// Check if the operation was successful
|
||||
return response.ApiResponse.$.Status === 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of available TLDs
|
||||
* @returns List of TLDs
|
||||
*/
|
||||
async getTldList(): Promise<string[]> {
|
||||
// Make the API request
|
||||
const response = await this.client.request<IDomainTldListResponse>(
|
||||
'namecheap.domains.getTldList'
|
||||
);
|
||||
|
||||
// Extract TLD list from the response
|
||||
const commandResponse = response.ApiResponse.CommandResponse[0];
|
||||
const tlds = commandResponse.Tlds[0].Tld || [];
|
||||
|
||||
return tlds.map(tld => tld.$.Name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to parse contact information
|
||||
* @param contactData Contact data from API response
|
||||
* @returns Parsed contact information
|
||||
*/
|
||||
private parseContact(contactData: any): IContactInfo {
|
||||
if (!contactData) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const contact: IContactInfo = {};
|
||||
|
||||
// Map all contact fields
|
||||
Object.keys(contactData).forEach(key => {
|
||||
if (Array.isArray(contactData[key]) && contactData[key].length > 0) {
|
||||
// Use type assertion to handle dynamic property assignment
|
||||
(contact as any)[key] = contactData[key][0];
|
||||
}
|
||||
});
|
||||
|
||||
return contact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to flatten contact information for API requests
|
||||
* @param contacts Contact information object
|
||||
* @returns Flattened contact parameters
|
||||
*/
|
||||
private flattenContacts(contacts: IDomainSetContactsParams): Record<string, string> {
|
||||
const params: Record<string, string> = {};
|
||||
|
||||
// Process each contact type
|
||||
['Registrant', 'Tech', 'Admin', 'AuxBilling'].forEach(type => {
|
||||
const contactType = type.toLowerCase() as keyof typeof contacts;
|
||||
const contactInfo = contacts[contactType];
|
||||
|
||||
if (contactInfo) {
|
||||
// Ensure all required fields are present
|
||||
this.validateContactInfo(contactInfo, type);
|
||||
|
||||
// Add each field to the params with the appropriate prefix
|
||||
Object.entries(contactInfo).forEach(([field, value]) => {
|
||||
if (value !== undefined && value !== null) {
|
||||
params[`${type}${field}`] = String(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate contact information to ensure required fields are present
|
||||
* @param contactInfo Contact information to validate
|
||||
* @param contactType Type of contact (Registrant, Tech, Admin, AuxBilling)
|
||||
* @throws Error if required fields are missing
|
||||
*/
|
||||
private validateContactInfo(contactInfo: IContactInfo, contactType: string): void {
|
||||
// Required fields for all contact types
|
||||
const requiredFields = [
|
||||
'FirstName',
|
||||
'LastName',
|
||||
'Address1',
|
||||
'City',
|
||||
'StateProvince',
|
||||
'PostalCode',
|
||||
'Country',
|
||||
'Phone',
|
||||
'EmailAddress'
|
||||
];
|
||||
|
||||
// Check for missing required fields
|
||||
const missingFields = requiredFields.filter(field => {
|
||||
return !contactInfo[field as keyof IContactInfo];
|
||||
});
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
throw new Error(
|
||||
`Missing required fields for ${contactType} contact: ${missingFields.join(', ')}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
158
ts/http-client.ts
Normal file
158
ts/http-client.ts
Normal file
@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Namecheap API Client - HTTP Client
|
||||
*/
|
||||
import axios from 'axios';
|
||||
import type { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { parseStringPromise } from 'xml2js';
|
||||
import { NamecheapConfig } from './config.js';
|
||||
import type { IApiResponse, IErrorResponse } from './types.js';
|
||||
|
||||
export class HttpClient {
|
||||
private client: AxiosInstance;
|
||||
private config: NamecheapConfig;
|
||||
|
||||
/**
|
||||
* Create a new HTTP client for Namecheap API
|
||||
* @param config Namecheap API configuration
|
||||
*/
|
||||
constructor(config: NamecheapConfig) {
|
||||
this.config = config;
|
||||
|
||||
// Initialize axios instance with default config
|
||||
this.client = axios.create({
|
||||
baseURL: config.baseUrl,
|
||||
timeout: config.timeout,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Accept': 'application/xml'
|
||||
}
|
||||
});
|
||||
|
||||
// Add response interceptor for global error handling
|
||||
this.client.interceptors.response.use(
|
||||
response => response,
|
||||
error => this.handleAxiosError(error)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request to the Namecheap API
|
||||
* @param command API command to execute
|
||||
* @param params Additional parameters
|
||||
* @returns Parsed API response
|
||||
*/
|
||||
async request<T extends IApiResponse>(
|
||||
command: string,
|
||||
params: Record<string, string | number | boolean> = {}
|
||||
): Promise<T> {
|
||||
try {
|
||||
// Get base parameters that all requests need
|
||||
const baseParams = this.config.getBaseParams(command);
|
||||
|
||||
// Merge base params with additional params
|
||||
const requestParams = {
|
||||
...baseParams,
|
||||
...params
|
||||
};
|
||||
|
||||
// Send request to the API
|
||||
const response = await this.client.get('', {
|
||||
params: requestParams
|
||||
});
|
||||
|
||||
// Parse XML response to JavaScript object
|
||||
const parsedResponse = await this.parseXmlResponse<T>(response);
|
||||
|
||||
// Check for API errors
|
||||
this.checkApiErrors(parsedResponse);
|
||||
|
||||
return parsedResponse;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw error;
|
||||
} else {
|
||||
throw new Error('Unknown error occurred');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse XML response to JavaScript object
|
||||
* @param response Axios response object
|
||||
* @returns Parsed response
|
||||
*/
|
||||
private async parseXmlResponse<T>(response: AxiosResponse): Promise<T> {
|
||||
try {
|
||||
const xmlData = response.data;
|
||||
|
||||
// Parse XML to JavaScript object with some options for better formatting
|
||||
const result = await parseStringPromise(xmlData, {
|
||||
explicitArray: true,
|
||||
explicitRoot: true,
|
||||
mergeAttrs: false,
|
||||
attrkey: '$'
|
||||
});
|
||||
|
||||
return result as T;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to parse XML response: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for API errors in the response
|
||||
* @param response Parsed API response
|
||||
* @throws Error if API returned an error
|
||||
*/
|
||||
private checkApiErrors(response: IApiResponse): void {
|
||||
// Check if response status is ERROR
|
||||
if (response.ApiResponse.$.Status === 'ERROR') {
|
||||
const errors = response.ApiResponse.Errors[0];
|
||||
|
||||
if (errors && 'Error' in errors) {
|
||||
const errorMessages = errors.Error;
|
||||
throw new Error(`Namecheap API Error: ${errorMessages.join(', ')}`);
|
||||
} else {
|
||||
throw new Error('Namecheap API returned an error without details');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle axios errors
|
||||
* @param error Axios error object
|
||||
* @throws Formatted error
|
||||
*/
|
||||
private handleAxiosError(error: any): never {
|
||||
let errorResponse: IErrorResponse = {
|
||||
message: 'Request to Namecheap API failed'
|
||||
};
|
||||
|
||||
if (error.response) {
|
||||
// Server responded with a status code outside of 2xx range
|
||||
errorResponse.message = `Namecheap API request failed with status ${error.response.status}`;
|
||||
|
||||
// Try to parse error response if it's XML
|
||||
if (error.response.data && typeof error.response.data === 'string') {
|
||||
try {
|
||||
const xmlError = error.response.data;
|
||||
errorResponse.message = `API Error: ${xmlError}`;
|
||||
} catch (parseError) {
|
||||
// Couldn't parse error response, use default message
|
||||
}
|
||||
}
|
||||
} else if (error.request) {
|
||||
// Request was made but no response received
|
||||
errorResponse.message = 'No response received from Namecheap API';
|
||||
|
||||
if (error.code === 'ECONNABORTED') {
|
||||
errorResponse.message = `Request timed out after ${this.config.timeout}ms`;
|
||||
}
|
||||
} else {
|
||||
// Error setting up the request
|
||||
errorResponse.message = error.message || 'Error setting up the request';
|
||||
}
|
||||
|
||||
throw new Error(errorResponse.message);
|
||||
}
|
||||
}
|
102
ts/index.ts
Normal file
102
ts/index.ts
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Namecheap API Client - Main Entry Point
|
||||
*/
|
||||
import { NamecheapConfig } from './config.js';
|
||||
import { HttpClient } from './http-client.js';
|
||||
import { Domains } from './domains.js';
|
||||
import { DomainsDns } from './domains-dns.js';
|
||||
import { DomainsNs } from './domains-ns.js';
|
||||
import { DomainsTransfer } from './domains-transfer.js';
|
||||
import type { INamecheapAuth } from './types.js';
|
||||
|
||||
// Re-export types for library consumers
|
||||
export * from './types.js';
|
||||
export { NamecheapConfig } from './config.js';
|
||||
export { Domains } from './domains.js';
|
||||
export { DomainsDns } from './domains-dns.js';
|
||||
export { DomainsNs } from './domains-ns.js';
|
||||
export { DomainsTransfer } from './domains-transfer.js';
|
||||
|
||||
/**
|
||||
* Main Namecheap API client class
|
||||
*/
|
||||
export class NamecheapClient {
|
||||
private config: NamecheapConfig;
|
||||
private httpClient: HttpClient;
|
||||
|
||||
/**
|
||||
* Domains API module
|
||||
*/
|
||||
public domains: Domains;
|
||||
|
||||
/**
|
||||
* Domains DNS API module
|
||||
*/
|
||||
public dns: DomainsDns;
|
||||
|
||||
/**
|
||||
* Domains Nameservers API module
|
||||
*/
|
||||
public ns: DomainsNs;
|
||||
|
||||
/**
|
||||
* Domains Transfer API module
|
||||
*/
|
||||
public transfer: DomainsTransfer;
|
||||
|
||||
/**
|
||||
* Create a new Namecheap API client
|
||||
* @param auth Authentication details
|
||||
* @param useSandbox Whether to use the sandbox environment (default: false)
|
||||
*/
|
||||
constructor(auth: INamecheapAuth, useSandbox: boolean = false) {
|
||||
// Initialize configuration
|
||||
this.config = new NamecheapConfig(auth);
|
||||
|
||||
// Set sandbox mode if requested
|
||||
if (useSandbox) {
|
||||
this.config.enableSandbox();
|
||||
}
|
||||
|
||||
// Create HTTP client
|
||||
this.httpClient = new HttpClient(this.config);
|
||||
|
||||
// Initialize API modules
|
||||
this.domains = new Domains(this.httpClient);
|
||||
this.dns = new DomainsDns(this.httpClient);
|
||||
this.ns = new DomainsNs(this.httpClient);
|
||||
this.transfer = new DomainsTransfer(this.httpClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable sandbox mode for testing
|
||||
*/
|
||||
enableSandbox(): void {
|
||||
this.config.enableSandbox();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable sandbox mode
|
||||
*/
|
||||
disableSandbox(): void {
|
||||
this.config.disableSandbox();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set request timeout
|
||||
* @param ms Timeout in milliseconds
|
||||
*/
|
||||
setTimeout(ms: number): void {
|
||||
this.config.setTimeout(ms);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Namecheap API client instance
|
||||
* @param auth Authentication details
|
||||
* @param useSandbox Whether to use the sandbox environment
|
||||
* @returns Namecheap API client
|
||||
*/
|
||||
export function createClient(auth: INamecheapAuth, useSandbox: boolean = false): NamecheapClient {
|
||||
return new NamecheapClient(auth, useSandbox);
|
||||
}
|
5
ts/paths.ts
Normal file
5
ts/paths.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import * as plugins from './plugins.js';
|
||||
export const packageDir = plugins.path.join(
|
||||
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
||||
'../',
|
||||
);
|
9
ts/plugins.ts
Normal file
9
ts/plugins.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// native scope
|
||||
import * as path from 'path';
|
||||
|
||||
export { path };
|
||||
|
||||
// @push.rocks scope
|
||||
import * as smartpath from '@push.rocks/smartpath';
|
||||
|
||||
export { smartpath };
|
948
ts/types.ts
Normal file
948
ts/types.ts
Normal file
@ -0,0 +1,948 @@
|
||||
/**
|
||||
* Namecheap API Client - Type Definitions
|
||||
*/
|
||||
|
||||
// Base interface for API authentication
|
||||
export interface INamecheapAuth {
|
||||
apiUser: string;
|
||||
apiKey: string;
|
||||
userName: string;
|
||||
clientIp: string;
|
||||
}
|
||||
|
||||
// Base parameters that all API calls require
|
||||
export interface TBaseParams {
|
||||
ApiUser: string;
|
||||
ApiKey: string;
|
||||
UserName: string;
|
||||
ClientIp: string;
|
||||
Command: string;
|
||||
}
|
||||
|
||||
// Response status types
|
||||
export type TApiResponseStatus = 'OK' | 'ERROR';
|
||||
|
||||
// Base API response structure
|
||||
export interface IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
[key: string]: any;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Domain List Parameters
|
||||
export interface IDomainsGetListParams {
|
||||
Page?: number;
|
||||
PageSize?: number;
|
||||
SortBy?: 'NAME' | 'NAME_DESC' | 'EXPIREDATE' | 'EXPIREDATE_DESC' | 'CREATEDATE' | 'CREATEDATE_DESC';
|
||||
ListType?: 'ALL' | 'EXPIRING' | 'EXPIRED';
|
||||
SearchTerm?: string;
|
||||
}
|
||||
|
||||
// Domain information returned from getList
|
||||
export interface IDomainInfo {
|
||||
ID: string;
|
||||
Name: string;
|
||||
User: string;
|
||||
Created: string;
|
||||
Expires: string;
|
||||
IsExpired: boolean;
|
||||
IsLocked: boolean;
|
||||
AutoRenew: boolean;
|
||||
WhoisGuard: 'ENABLED' | 'DISABLED' | 'NOTPRESENT';
|
||||
IsPremium: boolean;
|
||||
IsOurDNS: boolean;
|
||||
Nameservers: string;
|
||||
}
|
||||
|
||||
// GetList response
|
||||
export interface IDomainsGetListResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainGetListResult: Array<{
|
||||
Domain: Array<{
|
||||
$: IDomainInfo;
|
||||
Nameservers: string[];
|
||||
}>;
|
||||
}>;
|
||||
Paging: Array<{
|
||||
TotalItems: string[];
|
||||
CurrentPage: string[];
|
||||
PageSize: string[];
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Domain Check Response
|
||||
export interface IDomainCheckResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainCheckResult: IDomainCheckResult | IDomainCheckResult[];
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Domain Check Result
|
||||
export interface IDomainCheckResult {
|
||||
$: {
|
||||
Domain: string;
|
||||
Available: string;
|
||||
ErrorNo: string;
|
||||
Description: string;
|
||||
IsPremiumName: string;
|
||||
PremiumRegistrationPrice: string;
|
||||
PremiumRenewalPrice: string;
|
||||
PremiumRestorePrice: string;
|
||||
PremiumTransferPrice: string;
|
||||
IcannFee: string;
|
||||
EapFee: string;
|
||||
};
|
||||
}
|
||||
|
||||
// Domain Availability (processed result)
|
||||
export interface IDomainAvailability {
|
||||
domain: string;
|
||||
available: boolean;
|
||||
errorNo: number;
|
||||
description: string;
|
||||
isPremium: boolean;
|
||||
premiumRegistrationPrice: number;
|
||||
premiumRenewalPrice: number;
|
||||
premiumRestorePrice: number;
|
||||
premiumTransferPrice: number;
|
||||
icannFee: number;
|
||||
eapFee: number;
|
||||
}
|
||||
|
||||
// Domain Get Info Response
|
||||
export interface IDomainGetInfoResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainGetInfoResult: Array<{
|
||||
$: {
|
||||
Status: string;
|
||||
ID: string;
|
||||
DomainName: string;
|
||||
OwnerName: string;
|
||||
IsOwner: string;
|
||||
IsPremium: string;
|
||||
};
|
||||
DomainDetails?: Array<{
|
||||
CreatedDate: string[];
|
||||
ExpiredDate: string[];
|
||||
}>;
|
||||
LockDetails?: any[];
|
||||
Whoisguard?: Array<{
|
||||
$: {
|
||||
Enabled: string;
|
||||
};
|
||||
ID: string[];
|
||||
ExpiredDate: string[];
|
||||
}>;
|
||||
DnsDetails?: Array<{
|
||||
$: {
|
||||
ProviderType: string;
|
||||
};
|
||||
}>;
|
||||
Modificationrights?: Array<{
|
||||
$: {
|
||||
All: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Domain Info Result (processed)
|
||||
export interface IDomainInfoResult {
|
||||
status: string;
|
||||
id: number;
|
||||
domainName: string;
|
||||
ownerName: string;
|
||||
isOwner: boolean;
|
||||
isPremium: boolean;
|
||||
createdDate: string;
|
||||
expiredDate: string;
|
||||
whoisGuard: {
|
||||
enabled: boolean;
|
||||
id: number;
|
||||
expiredDate: string;
|
||||
};
|
||||
dnsProvider: string;
|
||||
modificationRights: {
|
||||
all: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
// Domain Get Contacts Response
|
||||
export interface IDomainGetContactsResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainContactsResult: Array<{
|
||||
Registrant?: Array<Record<string, string[]>>;
|
||||
Tech?: Array<Record<string, string[]>>;
|
||||
Admin?: Array<Record<string, string[]>>;
|
||||
AuxBilling?: Array<Record<string, string[]>>;
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Contact information structure
|
||||
export interface IContactInfo {
|
||||
FirstName?: string;
|
||||
LastName?: string;
|
||||
Address1?: string;
|
||||
Address2?: string;
|
||||
City?: string;
|
||||
StateProvince?: string;
|
||||
StateProvinceChoice?: string;
|
||||
PostalCode?: string;
|
||||
Country?: string;
|
||||
Phone?: string;
|
||||
PhoneExt?: string;
|
||||
Fax?: string;
|
||||
EmailAddress?: string;
|
||||
OrganizationName?: string;
|
||||
JobTitle?: string;
|
||||
}
|
||||
|
||||
// Domain Contacts
|
||||
export interface IDomainContacts {
|
||||
registrant: IContactInfo;
|
||||
tech: IContactInfo;
|
||||
admin: IContactInfo;
|
||||
auxBilling: IContactInfo;
|
||||
}
|
||||
|
||||
// Domain Set Contacts Parameters
|
||||
export interface IDomainSetContactsParams {
|
||||
registrant?: IContactInfo;
|
||||
tech?: IContactInfo;
|
||||
admin?: IContactInfo;
|
||||
auxBilling?: IContactInfo;
|
||||
}
|
||||
|
||||
// Domain Create Parameters
|
||||
export interface IDomainCreateParams {
|
||||
domainName: string;
|
||||
years: number;
|
||||
contacts: IDomainSetContactsParams;
|
||||
nameservers?: string[];
|
||||
addFreeWhoisguard?: boolean;
|
||||
whoisguardPrivacy?: boolean;
|
||||
premiumPrice?: number;
|
||||
}
|
||||
|
||||
// Domain Create Response
|
||||
export interface IDomainCreateResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainCreateResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
Registered: string;
|
||||
ChargedAmount: string;
|
||||
TransactionID: string;
|
||||
OrderID: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Domain Renew Parameters
|
||||
export interface IDomainRenewParams {
|
||||
DomainName: string;
|
||||
Years: number;
|
||||
PremiumPrice?: number;
|
||||
}
|
||||
|
||||
// Domain Renew Response
|
||||
export interface IDomainRenewResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainRenewResult: Array<{
|
||||
$: {
|
||||
DomainName: string;
|
||||
DomainID: string;
|
||||
Renewed: string;
|
||||
ChargedAmount: string;
|
||||
TransactionID: string;
|
||||
OrderID: string;
|
||||
DomainDetails?: {
|
||||
ExpiredDate: string;
|
||||
};
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Domain Renew Result (processed)
|
||||
export interface IDomainRenewResult {
|
||||
domainName: string;
|
||||
domainId: number;
|
||||
renewed: boolean;
|
||||
chargedAmount: number;
|
||||
transactionId: number;
|
||||
orderId: number;
|
||||
expireDate: string;
|
||||
}
|
||||
|
||||
// Registrar Lock Response
|
||||
export interface IRegistrarLockResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainGetRegistrarLockResult: Array<{
|
||||
$: {
|
||||
RegistrarLockStatus: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Domain TLD List Response
|
||||
export interface IDomainTldListResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
Tlds: Array<{
|
||||
Tld: Array<{
|
||||
$: {
|
||||
Name: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// DNS Host Record
|
||||
export interface IDnsHost {
|
||||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
address: string;
|
||||
mxPref: number;
|
||||
ttl: number;
|
||||
isActive: boolean;
|
||||
isDDNSEnabled: boolean;
|
||||
}
|
||||
|
||||
// DNS Record
|
||||
export interface IDnsRecord {
|
||||
name: string;
|
||||
type: string;
|
||||
address: string;
|
||||
mxPref?: number;
|
||||
ttl?: number;
|
||||
}
|
||||
|
||||
// DNS Get Hosts Response
|
||||
export interface IDnsDomainHostsResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainDNSGetHostsResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
IsUsingOurDNS: string;
|
||||
};
|
||||
host: Array<{
|
||||
$: {
|
||||
HostId: string;
|
||||
Name: string;
|
||||
Type: string;
|
||||
Address: string;
|
||||
MXPref?: string;
|
||||
TTL: string;
|
||||
IsActive?: string;
|
||||
IsDDNSEnabled?: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// DNS Set Hosts Response
|
||||
export interface IDnsSetHostsResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainDNSSetHostsResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
IsSuccess: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// DNS Set Custom Response
|
||||
export interface IDnsSetCustomResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainDNSSetCustomResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
Updated: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// DNS Get Email Forwarding Response
|
||||
export interface IDnsGetEmailForwardingResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainDNSGetEmailForwardingResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
};
|
||||
forward: Array<{
|
||||
$: {
|
||||
from: string;
|
||||
to: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// DNS Set Email Forwarding Response
|
||||
export interface IDnsSetEmailForwardingResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainDNSSetEmailForwardingResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
IsSuccess: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// DNS Get List Response
|
||||
export interface IDnsGetListResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainDNSGetListResult: Array<{
|
||||
Nameserver: string[];
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Transfer Info
|
||||
export interface ITransferInfo {
|
||||
id: number;
|
||||
domainName: string;
|
||||
status: string;
|
||||
statusDescription: string;
|
||||
date: string;
|
||||
lockTransferDate: string | null;
|
||||
transferOrderDetailId: number;
|
||||
isLocked: boolean;
|
||||
authInfo: string | null;
|
||||
}
|
||||
|
||||
// Transfer Status Info
|
||||
export interface ITransferStatusInfo extends ITransferInfo {}
|
||||
|
||||
// Transfer Get List Response
|
||||
export interface ITransferGetListResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
TransferGetListResult: Array<{
|
||||
Transfer: Array<{
|
||||
$: {
|
||||
ID: string;
|
||||
DomainName: string;
|
||||
Status: string;
|
||||
StatusDescription: string;
|
||||
Date: string;
|
||||
LockTransferDate?: string;
|
||||
TransferOrderDetailID?: string;
|
||||
IsLocked?: string;
|
||||
AuthInfo?: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Paging: Array<{
|
||||
TotalItems: string[];
|
||||
CurrentPage: string[];
|
||||
PageSize: string[];
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Transfer Get Status Response
|
||||
export interface ITransferGetStatusResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
TransferGetStatusResult: Array<{
|
||||
$: {
|
||||
TransferID: string;
|
||||
Status: string;
|
||||
StatusDescription: string;
|
||||
DomainName: string;
|
||||
Date: string;
|
||||
LockTransferDate?: string;
|
||||
TransferOrderDetailID?: string;
|
||||
IsLocked?: string;
|
||||
AuthInfo?: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Transfer Create Response
|
||||
export interface ITransferCreateResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainTransferCreateResult: Array<{
|
||||
$: {
|
||||
TransferID: string;
|
||||
OrderID: string;
|
||||
IsSuccess?: string;
|
||||
Status: string;
|
||||
StatusDescription: string;
|
||||
ChargedAmount: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Transfer Update Status Response
|
||||
export interface ITransferUpdateStatusResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
TransferUpdateStatusResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
Updated: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Transfer Get Info Response
|
||||
export interface ITransferGetInfoResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
TransferGetInfoResult: Array<{
|
||||
$: {
|
||||
TransferID: string;
|
||||
DomainName: string;
|
||||
Status: string;
|
||||
StatusDescription: string;
|
||||
AuthInfo?: string;
|
||||
Date: string;
|
||||
WhoisguardStatus?: string;
|
||||
OrderDate: string;
|
||||
OrderID: string;
|
||||
TransferOrderDetailID: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Nameserver Info
|
||||
export interface INsInfo {
|
||||
nameserver: string;
|
||||
ip: string;
|
||||
statuses: string[];
|
||||
}
|
||||
|
||||
// Nameserver Create Response
|
||||
export interface INsCreateResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainNSCreateResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
Nameserver: string;
|
||||
IP: string;
|
||||
IsSuccess: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Nameserver Delete Response
|
||||
export interface INsDeleteResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainNSDeleteResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
Nameserver: string;
|
||||
IsSuccess: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Nameserver Get Info Response
|
||||
export interface INsGetInfoResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainNSInfoResult: Array<{
|
||||
$: {
|
||||
Nameserver: string;
|
||||
IP: string;
|
||||
Statuses?: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Nameserver Update Response
|
||||
export interface INsUpdateResponse extends IApiResponse {
|
||||
ApiResponse: {
|
||||
$: {
|
||||
Status: TApiResponseStatus;
|
||||
xmlns: string;
|
||||
};
|
||||
Errors: Array<{ Error: string[] }> | [{}];
|
||||
Warnings: Array<{ Warning: string[] }> | [{}];
|
||||
RequestedCommand: string[];
|
||||
CommandResponse: Array<{
|
||||
$: {
|
||||
Type: string;
|
||||
};
|
||||
DomainNSUpdateResult: Array<{
|
||||
$: {
|
||||
Domain: string;
|
||||
Nameserver: string;
|
||||
OldIP: string;
|
||||
IP: string;
|
||||
IsSuccess: string;
|
||||
};
|
||||
}>;
|
||||
}>;
|
||||
Server: string[];
|
||||
GMTTimeDifference: string[];
|
||||
ExecutionTime: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Error response
|
||||
export interface IErrorResponse {
|
||||
message: string;
|
||||
errors?: string[];
|
||||
}
|
17
tsconfig.json
Normal file
17
tsconfig.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {}
|
||||
},
|
||||
"exclude": [
|
||||
"dist_*/**/*.d.ts"
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user