npm package: @relayer-ws/mtls-proxy-sdk
Description: Cloudflare Worker SDK for mTLS Proxy
Author: relayer.ws
Latest version: 1.0.1

# mTLS Proxy SDK for Cloudflare Workers

A TypeScript SDK that makes it easy to use mTLS proxy functionality from Cloudflare Workers. This SDK handles certificate management and automatic header configuration for proxying requests through an mTLS-enabled Lambda function.

## Features

- 🔐 **mTLS Support**: Automatic client certificate handling
- 🌐 **Cloudflare Worker Compatible**: Built specifically for Cloudflare Workers
- 📦 **TypeScript First**: Full TypeScript support with comprehensive type definitions
- 🚀 **Easy to Use**: Simple API with convenient helper methods
- ⚡ **Performance**: Optimized for Cloudflare Workers runtime
- 🔧 **Flexible**: Support for all HTTP methods and custom headers

## Installation

```bash
npm install @relayer-ws/mtls-proxy-sdk
```

## Quick Start

### Using the Fetch API (Recommended)

The easiest way to use the SDK is with the fetch-like API:

```typescript
import { createMtlsFetch } from '@relayer-ws/mtls-proxy-sdk';

// Create an mTLS fetch function
const mtlsFetch = createMtlsFetch({
  clientCert: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
  clientKey: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----'
});

// Use it just like the native fetch API
const response = await mtlsFetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer your-token',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ message: 'Hello World' })
});

const data = await response.json();
console.log(data);
```

### Using the Client Class

```typescript
import { MtlsProxyClient } from '@relayer-ws/mtls-proxy-sdk';

// Create a proxy client with default proxy URL (https://gw.relayer.ws/mtls)
const proxy = new MtlsProxyClient({
  clientCert: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
  clientKey: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----'
});

// Or with custom proxy URL
const proxy = new MtlsProxyClient({
  proxyUrl: 'https://your-lambda-url.amazonaws.com',
  clientCert: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
  clientKey: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----'
});

// Make a proxied request
const response = await proxy.get('https://api.example.com/data', {
  'Authorization': 'Bearer your-token'
});

console.log(response.status); // 200
console.log(response.body);   // Response data
```

### Using Environment Variables

```typescript
import { createMtlsFetch } from '@relayer-ws/mtls-proxy-sdk';

// In your Cloudflare Worker
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Create mTLS fetch from environment variables
    const mtlsFetch = createMtlsFetch({
      proxyUrl: env.MTLS_PROXY_URL, // Optional - defaults to https://gw.relayer.ws/mtls
      clientCert: env.MTLS_CLIENT_CERT,
      clientKey: env.MTLS_CLIENT_KEY,
      timeout: env.MTLS_TIMEOUT ? parseInt(env.MTLS_TIMEOUT, 10) : undefined,
      userAgent: env.MTLS_USER_AGENT
    });
    
    // Use it just like fetch
    const response = await mtlsFetch('https://api.example.com/webhook', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ message: 'Hello World' })
    });
    
    return response;
  }
};
```

## API Reference

### createMtlsFetch

Creates an mTLS fetch function that works exactly like the native fetch API.

```typescript
function createMtlsFetch(config: MtlsProxyConfig): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>
```

**Parameters:**
- `config`: Configuration object (same as MtlsProxyClient)

**Returns:** A fetch-like function that can be used exactly like the native fetch API.

**Example:**
```typescript
const mtlsFetch = createMtlsFetch({
  clientCert: '-----BEGIN CERTIFICATE-----...',
  clientKey: '-----BEGIN PRIVATE KEY-----...'
});

// Use exactly like fetch
const response = await mtlsFetch('https://api.example.com/data', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ data: 'value' })
});

const result = await response.json();
```


### MtlsProxyClient

The main client class for making mTLS proxy requests.

#### Constructor

```typescript
new MtlsProxyClient(config: MtlsProxyConfig)
```

#### Configuration

```typescript
interface MtlsProxyConfig {
  /** The URL of the mTLS proxy Lambda function (default: https://gw.relayer.ws/mtls) */
  proxyUrl?: string;
  /** Client certificate in PEM format */
  clientCert: string;
  /** Client private key in PEM format */
  clientKey: string;
  /** Optional timeout for requests (default: 30000ms) */
  timeout?: number;
  /** Optional user agent string */
  userAgent?: string;
}
```

#### Methods

##### `request(options: ProxyRequestOptions): Promise<ProxyResponse>`

Make a custom proxied request.

```typescript
const response = await proxy.request({
  targetUrl: 'https://api.example.com',
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ data: 'value' }),
  timeout: 10000
});
```

##### `get(targetUrl: string, headers?: Record<string, string>): Promise<ProxyResponse>`

Make a GET request.

```typescript
const response = await proxy.get('https://api.example.com/users');
```

##### `post(targetUrl: string, body?: string | ArrayBuffer | ReadableStream, headers?: Record<string, string>): Promise<ProxyResponse>`

Make a POST request.

```typescript
const response = await proxy.post(
  'https://api.example.com/users',
  JSON.stringify({ name: 'John Doe' }),
  { 'Content-Type': 'application/json' }
);
```

##### `put(targetUrl: string, body?: string | ArrayBuffer | ReadableStream, headers?: Record<string, string>): Promise<ProxyResponse>`

Make a PUT request.

##### `delete(targetUrl: string, headers?: Record<string, string>): Promise<ProxyResponse>`

Make a DELETE request.

##### `patch(targetUrl: string, body?: string | ArrayBuffer | ReadableStream, headers?: Record<string, string>): Promise<ProxyResponse>`

Make a PATCH request.

### Response Format

```typescript
interface ProxyResponse {
  /** HTTP status code */
  status: number;
  /** HTTP status text */
  statusText: string;
  /** Response headers */
  headers: Record<string, string>;
  /** Response body */
  body: string;
  /** Whether the response body is base64 encoded */
  isBase64Encoded: boolean;
}
```

## Cloudflare Worker Example

Here's a complete example of using the SDK in a Cloudflare Worker:

```typescript
import { createMtlsProxyClientFromEnv } from '@relayer-ws/mtls-proxy-sdk';

interface Env {
  MTLS_PROXY_URL?: string;  // Optional - defaults to https://gw.relayer.ws/mtls
  MTLS_CLIENT_CERT: string;
  MTLS_CLIENT_KEY: string;
  MTLS_TIMEOUT?: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    try {
      // Create proxy client from environment variables
      const proxy = createMtlsProxyClientFromEnv(env);
      
      // Parse the incoming request
      const url = new URL(request.url);
      const targetUrl = url.searchParams.get('target');
      
      if (!targetUrl) {
        return new Response('Missing target parameter', { status: 400 });
      }
      
      // Forward the request through the mTLS proxy
      const response = await proxy.request({
        targetUrl,
        method: request.method,
        headers: Object.fromEntries(request.headers.entries()),
        body: request.body
      });
      
      // Return the proxied response
      return new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: response.headers
      });
      
    } catch (error) {
      console.error('Proxy error:', error);
      return new Response('Internal Server Error', { status: 500 });
    }
  }
};
```

## Error Handling

The SDK provides comprehensive error handling:

```typescript
try {
  const response = await proxy.get('https://api.example.com');
} catch (error) {
  if (error.message.includes('timeout')) {
    console.error('Request timed out');
  } else if (error.message.includes('Invalid targetUrl')) {
    console.error('Invalid URL provided');
  } else {
    console.error('Request failed:', error.message);
  }
}
```

## Security Considerations

- **Certificate Storage**: Store your client certificates securely in Cloudflare Workers secrets or environment variables
- **HTTPS Only**: Always use HTTPS URLs for both the proxy and target endpoints
- **Certificate Validation**: The SDK validates certificate format but doesn't validate certificate chains
- **Header Filtering**: Sensitive headers like `X-Mtls-Cert` and `X-Mtls-Key` are automatically filtered from upstream requests

## Browser Testing

You can test the SDK functionality in your browser using the included test page:

```bash
# Start the test server
npm run test:browser

# Or from the root directory
yarn test:mtls
```

This will open a browser test page at `http://localhost:3001` where you can:
- Configure the SDK settings
- Test different HTTP methods
- See simulated responses
- Experiment with the API before implementing in your Cloudflare Worker

## License

MIT