Socket
Book a DemoInstallSign in
Socket

domainly-sdk

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

domainly-sdk

Official TypeScript SDK for Domainly External SaaS API - Manage multi-tenant custom domains with ease

latest
Source
npmnpm
Version
1.0.1
Version published
Maintainers
1
Created
Source

Domainly SDK

npm version TypeScript License: MIT

Official TypeScript/JavaScript SDK for the Domainly External SaaS API. Easily manage multi-tenant custom domains, subdomains, and SSL certificates for your SaaS application.

🆕 What's New in v1.0.1

  • Enhanced Webhook Testing: Test webhook endpoints with custom URLs
  • Webhook Retry Functionality: Retry failed webhook deliveries
  • Webhook Signature Verification: Built-in utilities for secure webhook handling
  • Improved Error Handling: Better error messages and retry logic
  • Enhanced Validation: Comprehensive input validation utilities
  • Updated Type Definitions: Types now match the latest API implementation
  • Webhook Event Monitoring: Tools for monitoring webhook delivery health

🚀 Features

  • Complete TypeScript Support - Full type definitions for all API operations
  • Multi-tenant Management - Create and manage tenants with ease
  • Custom Domain Handling - Add, verify, and manage custom domains
  • Subdomain Operations - Create and manage subdomains for your tenants
  • Webhook Integration - Configure webhooks for real-time notifications
  • Automatic Retries - Built-in retry logic for failed requests
  • Error Handling - Comprehensive error handling with detailed error types
  • Validation Utilities - Input validation helpers for common operations
  • Multiple Output Formats - CommonJS, ES Modules, and UMD builds

📦 Installation

npm install domainly-sdk
yarn add domainly-sdk
pnpm add domainly-sdk

🏃 Quick Start

import { DomainlyClient } from 'domainly-sdk';

// Initialize the client
const client = new DomainlyClient({
  apiKey: 'dom_your_api_key_here'
});

// Create a tenant with subdomain
const tenant = await client.createTenant({
  name: 'Acme Corporation',
  createSubdomain: true,
  subdomainName: 'acme',
  metadata: { 
    plan: 'premium',
    industry: 'technology'
  }
});

// Add a custom domain
const domain = await client.createDomain({
  customDomain: 'app.acme.com',
  subdomain: 'acme',
  tenantId: tenant.data.id,
  verificationMethod: 'cname'
});

console.log('Setup complete!', { tenant, domain });

🔧 Configuration

Basic Configuration

import { DomainlyClient } from 'domainly-sdk';

const client = new DomainlyClient({
  apiKey: 'dom_your_api_key_here',
  // Optional configuration
  baseURL: 'https://api.domainly.dev/external/api', // Default
  timeout: 30000, // Default: 30 seconds
  retries: 3, // Default: 3 retries
  retryDelay: 1000, // Default: 1 second
});

Using Environment Variables

// Set environment variable
process.env.DOMAINLY_API_KEY = 'dom_your_api_key_here';

const client = new DomainlyClient({
  apiKey: process.env.DOMAINLY_API_KEY!
});

📚 API Reference

Tenant Operations

Create Tenant

const tenant = await client.createTenant({
  name: 'Customer Company',
  createSubdomain: true, // Optional
  subdomainName: 'customer', // Optional
  metadata: { // Optional
    plan: 'enterprise',
    industry: 'finance'
  }
});

Get All Tenants

const tenants = await client.getTenants();
console.log(tenants.data); // Array of tenants

Get Specific Tenant

const tenant = await client.getTenant('tenant-id');
console.log(tenant.data);

Update Tenant

const updatedTenant = await client.updateTenant('tenant-id', {
  name: 'Updated Company Name',
  status: 'ACTIVE',
  metadata: { plan: 'premium' }
});

Delete Tenant

await client.deleteTenant('tenant-id');

Domain Operations

Create Custom Domain

const domain = await client.createDomain({
  customDomain: 'app.customer.com',
  subdomain: 'customer-subdomain', // Optional
  tenantId: 'tenant-id', // Optional
  verificationMethod: 'cname', // 'cname' | 'txt' | 'http'
  autoRenewSSL: true // Optional
});

Verify Domain

const verification = await client.verifyDomain('domain-id');
console.log('Verified:', verification.data.verified);

Get CNAME Records

const records = await client.getCNAMERecords('domain-id');
console.log('CNAME records:', records.data);

List All Domains

const domains = await client.getDomains();
console.log(domains.data);

Subdomain Operations

Create Subdomain

const subdomain = await client.createSubdomain({
  subdomain: 'store',
  tenantId: 'tenant-id', // Optional
  description: 'E-commerce store subdomain'
});

Check Subdomain Availability

const availability = await client.checkSubdomainAvailability('desired-subdomain');
console.log('Available:', availability.data.available);

Webhook Management

Configure Webhooks

await client.configureWebhook({
  webhookUrl: 'https://your-app.com/webhooks/domainly',
  secret: 'your-webhook-secret',
  events: [
    'tenant.created',
    'domain.verified',
    'ssl.provisioned'
  ]
});

Get Webhook Configuration

const config = await client.getWebhookConfig();
console.log(config.data);

Test Webhook

const testResult = await client.testWebhook({
  webhookUrl: 'https://your-app.com/webhooks/domainly'
});
console.log('Webhook test:', testResult.data.success);

Get Webhook Logs

const logs = await client.getWebhookLogs({ limit: 20, offset: 0 });
console.log('Recent webhook deliveries:', logs.data.logs);
console.log('Total events:', logs.data.total);

Retry Failed Webhook

const result = await client.retryWebhook('webhook-event-id');
console.log('Retry successful:', result.success);

🛠 Utility Functions

The SDK includes utility functions for common operations:

Domain Setup Workflow

import { DomainlyUtils } from 'domainly-sdk';

const utils = new DomainlyUtils(client);

// Complete setup with tenant, subdomain, and domain
const setup = await utils.createCompleteSetup({
  tenantName: 'Acme Corporation',
  subdomainName: 'acme',
  customDomain: 'app.acme.com',
  verificationMethod: 'cname',
  metadata: { plan: 'enterprise' }
});

console.log('Setup result:', setup);

Wait for Domain Verification

// Wait for domain to be verified with polling
const verifiedDomain = await utils.waitForDomainVerification('domain-id', {
  maxAttempts: 30,
  pollInterval: 5000, // 5 seconds
  timeout: 300000 // 5 minutes
});

console.log('Domain verified!', verifiedDomain);

Batch Operations

// Create multiple tenants at once
const batchResult = await utils.batchCreateTenants([
  { name: 'Company A', createSubdomain: true, subdomainName: 'company-a' },
  { name: 'Company B', createSubdomain: true, subdomainName: 'company-b' },
  { name: 'Company C', createSubdomain: true, subdomainName: 'company-c' }
], {
  concurrency: 3,
  continueOnError: true
});

console.log(`Created ${batchResult.successful} tenants`);

✅ Validation Utilities

Input Validation

import { DomainUtils, SubdomainUtils, ValidationUtils } from 'domainly-sdk';

// Validate domain format
const domainValidation = DomainUtils.validateDomain('app.example.com');
if (!domainValidation.valid) {
  console.error('Invalid domain:', domainValidation.error);
}

// Validate subdomain format
const subdomainValidation = SubdomainUtils.validateSubdomain('my-app');
if (!subdomainValidation.valid) {
  console.error('Invalid subdomain:', subdomainValidation.error);
}

// Validate complete requests
const tenantRequestValidation = ValidationUtils.validateCreateTenantRequest({
  name: 'Test Company',
  subdomainName: 'test-company'
});

if (!tenantRequestValidation.valid) {
  console.error('Validation errors:', tenantRequestValidation.errors);
}

🎯 Helper Functions

import { SubdomainUtils, DomainUtils, ErrorUtils } from 'domainly-sdk';

// Generate slug from company name
const slug = SubdomainUtils.generateSlug('My Company Inc!');
console.log(slug); // 'my-company-inc'

// Check domain status
const isVerified = DomainUtils.isDomainVerified(domain);
const hasSSL = DomainUtils.isSSLActive(domain);

// Get verification instructions
const instructions = DomainUtils.getVerificationInstructions(domain);
console.log(instructions);

// Handle errors gracefully
if (ErrorUtils.isRetryableError(error)) {
  // Implement retry logic
}

🔄 Error Handling

The SDK provides comprehensive error handling:

import { DomainlyClient, ErrorUtils } from 'domainly-sdk';

try {
  const tenant = await client.createTenant({
    name: 'Test Company'
  });
} catch (error) {
  if (error.name === 'DomainlyError') {
    console.error('API Error:', {
      message: error.message,
      status: error.status,
      code: error.code,
      details: error.details
    });
    
    // Check if error is retryable
    if (ErrorUtils.isRetryableError(error)) {
      console.log('This error can be retried');
    }
    
    // Get user-friendly error message
    const readableError = ErrorUtils.getReadableError(error);
    console.log('User message:', readableError);
  } else {
    console.error('Unexpected error:', error);
  }
}

🔗 Webhook Events

Configure webhooks to receive real-time notifications:

Available Events

  • Tenant Events: tenant.created, tenant.updated, tenant.deleted
  • Subdomain Events: subdomain.created, subdomain.updated, subdomain.deleted
  • Domain Events: domain.created, domain.updated, domain.deleted, domain.verified, domain.failed
  • SSL Events: ssl.provisioned, ssl.expired, ssl.renewed

Webhook Payload Example

{
  "event": "domain.verified",
  "timestamp": "2024-01-15T12:00:00Z",
  "projectId": "project-789",
  "domainId": "domain-123",
  "data": {
    "customDomain": "app.customer.com",
    "status": "verified",
    "message": "Domain verification completed successfully",
    "timestamp": "2024-01-15T12:00:00Z"
  }
}

For webhook tests, the payload will include:

{
  "event": "webhook.test",
  "projectId": "your-project-id",
  "domainId": "test-domain-id",
  "data": {
    "customDomain": "test.example.com",
    "status": "verified",
    "message": "This is a test webhook from Domainly",
    "timestamp": "2024-01-15T12:00:00Z"
  },
  "timestamp": "2024-01-15T12:00:00Z"
}

Webhook Event Monitoring

import { DomainlyClient, WebhookUtils } from 'domainly-sdk';

class WebhookMonitor {
  private client: DomainlyClient;

  constructor(apiKey: string) {
    this.client = new DomainlyClient({ apiKey });
  }

  async checkWebhookHealth() {
    try {
      // Test webhook connectivity
      const testResult = await this.client.testWebhook({
        webhookUrl: 'https://your-app.com/webhooks/domainly'
      });
      
      if (testResult.data.success) {
        console.log('✅ Webhook endpoint is healthy');
      }
    } catch (error) {
      console.error('❌ Webhook test failed:', error.message);
    }
  }

  async getFailedWebhooks() {
    const logs = await this.client.getWebhookLogs({ limit: 100 });
    
    const failedEvents = logs.data.logs.filter(log => log.status === 'FAILED');
    
    console.log(`Found ${failedEvents.length} failed webhook deliveries`);
    
    return failedEvents;
  }

  async retryFailedWebhooks() {
    const failedEvents = await this.getFailedWebhooks();
    
    for (const event of failedEvents) {
      try {
        await this.client.retryWebhook(event.id);
        console.log(`✅ Retried webhook ${event.id}`);
      } catch (error) {
        console.error(`❌ Failed to retry webhook ${event.id}:`, error.message);
      }
    }
  }
}

// Usage
const monitor = new WebhookMonitor('dom_your_api_key');
await monitor.checkWebhookHealth();
await monitor.retryFailedWebhooks();

Webhook Security

Verify webhook signatures using the built-in utility:

import { WebhookUtils } from 'domainly-sdk';

// In your webhook endpoint
app.post('/webhooks/domainly', express.raw({ type: 'application/json' }), (req, res) => {
  const payload = req.body.toString();
  const signature = req.headers['x-webhook-signature'];
  const secret = process.env.DOMAINLY_WEBHOOK_SECRET;

  // Verify the webhook signature
  if (!WebhookUtils.verifySignature(payload, signature, secret)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Parse the webhook payload
  const webhookData = WebhookUtils.parsePayload(payload);
  if (!webhookData) {
    return res.status(400).json({ error: 'Invalid payload' });
  }

  // Process the webhook
  console.log('Received webhook:', webhookData.event);
  res.json({ success: true });
});

🌍 Real-world Examples

SaaS Multi-tenant Setup

import { DomainlyClient, DomainlyUtils } from 'domainly-sdk';

class SaaSIntegration {
  private domainly: DomainlyClient;
  private utils: DomainlyUtils;

  constructor(apiKey: string) {
    this.domainly = new DomainlyClient({ apiKey });
    this.utils = new DomainlyUtils(this.domainly);
  }

  async onboardCustomer(customerData: {
    name: string;
    subdomain: string;
    customDomain?: string;
  }) {
    try {
      // Create tenant with subdomain
      const tenant = await this.domainly.createTenant({
        name: customerData.name,
        createSubdomain: true,
        subdomainName: customerData.subdomain,
        metadata: { 
          onboardedAt: new Date().toISOString(),
          plan: 'starter'
        }
      });

      let domain = null;
      
      // Add custom domain if provided
      if (customerData.customDomain) {
        domain = await this.domainly.createDomain({
          customDomain: customerData.customDomain,
          subdomain: customerData.subdomain,
          tenantId: tenant.data.id,
          verificationMethod: 'cname'
        });

        // Wait for verification
        const verifiedDomain = await this.utils.waitForDomainVerification(
          domain.data.id,
          { timeout: 300000 }
        );
        
        console.log('Domain verified:', verifiedDomain.customDomain);
      }

      return {
        success: true,
        tenant: tenant.data,
        domain: domain?.data,
        accessUrl: domain?.data?.customDomain || `${customerData.subdomain}.your-app.com`
      };
    } catch (error) {
      console.error('Customer onboarding failed:', error);
      return { success: false, error: error.message };
    }
  }

  async getCustomerSummary() {
    const summary = await this.utils.getResourcesSummary();
    return summary;
  }
}

// Usage
const saas = new SaaSIntegration('dom_your_api_key');

const result = await saas.onboardCustomer({
  name: 'Acme Corporation',
  subdomain: 'acme',
  customDomain: 'app.acme.com'
});

console.log('Onboarding result:', result);

Domain Verification Flow

async function setupCustomDomain(customDomain: string, subdomain: string) {
  const client = new DomainlyClient({
    apiKey: process.env.DOMAINLY_API_KEY!
  });

  // 1. Create domain
  const domain = await client.createDomain({
    customDomain,
    subdomain,
    verificationMethod: 'cname'
  });

  // 2. Get verification records
  const records = await client.getCNAMERecords(domain.data.id);
  
  console.log('Add these DNS records:');
  records.data.forEach(record => {
    console.log(`${record.name} CNAME ${record.value}`);
  });

  // 3. Poll for verification
  console.log('Waiting for DNS propagation...');
  
  const utils = new DomainlyUtils(client);
  try {
    const verifiedDomain = await utils.waitForDomainVerification(domain.data.id, {
      maxAttempts: 60, // 5 minutes with 5-second intervals
      pollInterval: 5000
    });
    
    console.log('✅ Domain verified successfully!');
    console.log('🔒 SSL certificate will be provisioned automatically');
    
    return verifiedDomain;
  } catch (error) {
    console.error('❌ Domain verification failed:', error.message);
    throw error;
  }
}

📈 Rate Limiting

The SDK automatically handles rate limiting with exponential backoff:

  • General API calls: 1000 per hour
  • Tenant creation: 100 per hour
  • Domain creation: 20 per hour
  • DNS verification: 50 per hour

Rate limit exceeded responses (429) are automatically retried.

🔒 Security Best Practices

  • Store API keys securely - Never commit API keys to version control
  • Use environment variables - Store keys in environment variables or secure vaults
  • Verify webhook signatures - Always verify webhook payloads using HMAC-SHA256
  • Use HTTPS - Only configure HTTPS webhook endpoints
  • Rotate API keys - Regularly rotate your API keys

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🆘 Support

Made with ❤️ by the Domainly Team

Keywords

domainly

FAQs

Package last updated on 27 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts