Skip to the content.

Contributing Guide

← Back to Home

Thank you for considering contributing to the Proxy project! This guide will help you get started.

Development Setup

Prerequisites

Local Development

  1. Clone the repository
    git clone https://github.com/theta42/proxy.git
    cd proxy/nodejs
    
  2. Install dependencies
    npm install
    
  3. Start Redis (if not already running)
    redis-server
    
  4. Run in development mode
    npm run dev
    

    This starts the Node.js API with nodemon for auto-reload on file changes.

  5. Access the API
    • API: http://localhost:3000/api
    • Web UI: http://localhost:3000

Testing

The project uses Node.js built-in test runner (requires Node 18+).

Running Tests

# Run all tests
npm test

# Run only unit tests
npm run test:unit

# Run only integration tests
npm run test:integration

# Watch mode for development
npm run test:watch

Test Structure

test/
├── unit/                       # Unit tests for isolated components
│   ├── callback_queue.test.js
│   ├── host_lookup.test.js
│   └── unix_socket.test.js
├── integration/                # Integration tests
│   └── dns_provider.test.js
└── helpers/                    # Test utilities
    └── dns_provider_contract.js

Writing Tests

We test custom logic, not third-party libraries:

DO test:

DON’T test:

Adding DNS Provider Tests

When adding a new DNS provider, you must add contract tests:

describe('NewProvider Provider', () => {
    const NewProvider = require('../../models/dns_provider/newprovider');

    test('should meet DNS provider contract', () => {
        const mockCredentials = {api_key: 'mock-key'};
        const instance = validateDnsProviderContract(NewProvider, mockCredentials);
        assert.ok(instance);
    });

    test('should have valid method signatures', () => {
        const instance = new NewProvider({api_key: 'mock'});
        validateMethodSignatures(instance);
    });

    test('should validate key mapping', () => {
        const instance = new NewProvider({api_key: 'mock'});
        validateKeyMapping(instance);
    });

    test('should validate type checking', () => {
        const instance = new NewProvider({api_key: 'mock'});
        validateTypeChecking(instance);
    });
});

See test/integration/dns_provider.test.js for examples.

Code Style

General Guidelines

File Organization

'use strict';

// 1. Node.js built-ins
const fs = require('fs');
const path = require('path');

// 2. Third-party modules
const express = require('express');
const redis = require('redis');

// 3. Local modules
const {Host} = require('./models');
const middleware = require('./middleware/auth');

// 4. Code...

Naming Conventions

Project Structure

Understanding the codebase:

nodejs/
├── models/              # Data models (Host, User, DNS providers)
├── routes/              # API route handlers
├── services/            # Background services (lookup, scheduler)
├── middleware/          # Express middleware
├── utils/               # Utility functions
├── public/              # Static web assets
├── views/               # EJS templates
└── test/                # Test suite

Pull Request Process

Before Submitting

  1. Run tests - Ensure all tests pass
    npm test
    
  2. Test locally - Verify your changes work
    npm run dev
    
  3. Update documentation - Keep docs in sync with code changes

  4. Commit messages - Use clear, descriptive messages
    Add DNS provider for Route53
    
    - Implement Route53 DNS API client
    - Add contract tests for Route53
    - Update documentation with Route53 setup
    

Submitting a PR

  1. Fork the repository

  2. Create a feature branch
    git checkout -b feature/my-new-feature
    
  3. Make your changes

  4. Commit your changes
    git add .
    git commit -m "Description of changes"
    
  5. Push to your fork
    git push origin feature/my-new-feature
    
  6. Open a Pull Request on GitHub

PR Requirements

CI/CD Process

When you open a PR:

  1. GitHub Actions automatically runs tests
  2. Tests execute on multiple Node.js versions
  3. PR cannot be merged until all checks pass
  4. Review from maintainers
  5. Merge to master

Data Models

The project uses model-redis as the ORM for Redis data storage. All models extend the Table class and use a declarative schema via _keyMap.

Example Model:

const Table = require('../utils/redis_model');

class Host extends Table {
    static _key = 'host';  // Primary key field
    static _keyMap = {
        'host': {isRequired: true, type: 'string', min: 3, max: 500},
        'ip': {isRequired: true, type: 'string', min: 3, max: 500},
        'targetPort': {isRequired: true, type: 'number', min: 0, max: 65535},
        'forcessl': {default: true, type: 'boolean'},
        'created_on': {default: () => Date.now(), type: 'number'}
    };
}

Learn more: model-redis documentation

Adding Features

Adding a DNS Provider

  1. Create provider file in models/dns_provider/yourprovider.js

  2. Extend DnsApi base class
    const {DnsApi} = require('./common');
    
    class YourProvider extends DnsApi {
        static _keyMap = {
            api_key: {isRequired: true, type: 'string', isPrivate: true}
        };
    
        // Implement required methods
        async listDomains() { }
        async getRecords(domain, options) { }
        async createRecord(domain, options) { }
        async deleteRecords(domain, options) { }
    }
    
  3. Add to provider list in models/dns_provider.js

  4. Add contract tests in test/integration/dns_provider.test.js

  5. Test your provider
    npm run test:integration
    

Adding API Endpoints

  1. Add route in appropriate file (routes/)
  2. Update API documentation (nodejs/api.md)
  3. Test the endpoint manually and add integration tests if needed

Getting Help

Code of Conduct

License

By contributing, you agree that your contributions will be licensed under the MIT License.


← Back to Home View on GitHub