This commit is contained in:
Philipp Kunz 2025-04-02 15:19:18 +00:00
commit fcc11dd5f6
30 changed files with 14854 additions and 0 deletions

View 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

View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

3
readme.hints.md Normal file
View File

@ -0,0 +1,3 @@
# Project Readme Hints
This is the initial readme hints file.

505
readme.md Normal file
View 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.
[![npm version](https://img.shields.io/npm/v/@apiclient.xyz/namecheap.svg)](https://www.npmjs.com/package/@apiclient.xyz/namecheap)
[![License](https://img.shields.io/npm/l/@apiclient.xyz/namecheap.svg)](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
View 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
}

View 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();

View 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
View 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
View 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();

View 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();

View 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();

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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"
]
}