Contributing Guide
Thank you for considering contributing to the Proxy project! This guide will help you get started.
Development Setup
Prerequisites
- Node.js 18+ (18.x, 20.x, or 22.x recommended)
- Redis server
- Git
Local Development
- Clone the repository
git clone https://github.com/theta42/proxy.git cd proxy/nodejs - Install dependencies
npm install - Start Redis (if not already running)
redis-server - Run in development mode
npm run devThis starts the Node.js API with nodemon for auto-reload on file changes.
- Access the API
- API:
http://localhost:3000/api - Web UI:
http://localhost:3000
- API:
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:
- Host lookup algorithm
- Socket buffering logic
- DNS provider contracts
- Custom utility functions
DON’T test:
- Express.js routing
- Redis ORM
- External DNS APIs (use mocks instead)
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
- Use strict mode:
'use strict'; - Use tabs for indentation
- Clear, descriptive variable names
- Comment complex logic
- No trailing whitespace
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
- Classes:
PascalCase - Functions:
camelCase - Constants:
UPPER_SNAKE_CASE - Private methods:
__privateMethod(double underscore prefix)
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
- Run tests - Ensure all tests pass
npm test - Test locally - Verify your changes work
npm run dev -
Update documentation - Keep docs in sync with code changes
- 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
-
Fork the repository
- Create a feature branch
git checkout -b feature/my-new-feature -
Make your changes
- Commit your changes
git add . git commit -m "Description of changes" - Push to your fork
git push origin feature/my-new-feature - Open a Pull Request on GitHub
PR Requirements
- ✅ All tests must pass (CI/CD runs automatically)
- ✅ Tests run on Node.js 18.x, 20.x, and 22.x
- ✅ No merge conflicts with
master - ✅ Code follows project conventions
- ✅ New features include tests
- ✅ Documentation updated if needed
CI/CD Process
When you open a PR:
- GitHub Actions automatically runs tests
- Tests execute on multiple Node.js versions
- PR cannot be merged until all checks pass
- Review from maintainers
- 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
-
Create provider file in
models/dns_provider/yourprovider.js - 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) { } } -
Add to provider list in
models/dns_provider.js -
Add contract tests in
test/integration/dns_provider.test.js - Test your provider
npm run test:integration
Adding API Endpoints
- Add route in appropriate file (
routes/) - Update API documentation (
nodejs/api.md) - Test the endpoint manually and add integration tests if needed
Getting Help
- Questions? Open a GitHub Discussion
- Bug reports Use GitHub Issues
- Security issues Email maintainers directly (see package.json)
Code of Conduct
- Be respectful and inclusive
- Focus on constructive feedback
- Help others learn and grow
- Follow the project’s technical direction
License
By contributing, you agree that your contributions will be licensed under the MIT License.
| ← Back to Home | View on GitHub |