# Galactus Relay

Transport layer for client-authoritative architecture. Forwards HTTP requests and WebSocket connections between client applications and external APIs.

## In This Monorepo

This app lives in `apps/relay`. Run from the **repo root** so that `@galactus/shared` is built first:

```bash
npm run relay:dev
```

## Purpose

The relay server provides:

- **CORS Solution**: Allows browser clients to access external APIs
- **Byte-Faithful Forwarding**: Preserves request signatures exactly
- **Zero Business Logic**: Pure transport layer, no interpretation
- **Multiplexing**: Support for multiple WebSocket streams per client

## Architecture

```text
Client → Relay Server → External API (e.g. Kalshi API)
```

The relay server:

- Does NOT sign requests (client does this)
- Does NOT store credentials
- Does NOT interpret messages
- Does NOT make decisions

It simply forwards bytes exactly as received.

## Endpoints

### HTTP Relay

**POST** `/relay/http`

Forwards HTTP requests to external APIs.

**Request:**

```json
{
  "id": "req-123",
  "method": "POST",
  "url": "https://api.elections.kalshi.com/trade-api/v2/portfolio/orders",
  "headers": {
    "KALSHI-ACCESS-KEY": "...",
    "KALSHI-ACCESS-SIGNATURE": "...",
    "KALSHI-ACCESS-TIMESTAMP": "...",
    "Content-Type": "application/json"
  },
  "body": "{\"ticker\":\"MARKET-123\",...}"
}
```

**Response:**

```json
{
  "id": "req-123",
  "status": 200,
  "headers": {...},
  "body": "{\"order\":{...}}"
}
```

### WebSocket Relay

**WS** `/relay/ws`

Forwards WebSocket connections to external APIs.

**Client → Relay:**

```json
{
  "op": "connect",
  "id": "stream-1",
  "url": "wss://api.elections.kalshi.com/trade-api/v2/ws",
  "headers": {...}
}
```

**Relay → Client:**

```json
{
  "id": "stream-1",
  "type": "message",
  "data": {...}
}
```

### Health Check

**GET** `/health`

Returns server health status.

## Configuration

Environment variables can be set via:

- **`.env` in this directory** – copied from `.env.example` and loaded at startup (recommended for local or server deploy).
- **PM2 ecosystem file** or **shell exports** – if you prefer not to use a `.env` file.

See `.env.example` for the list of variables.

### PM2 startup (survive reboots)

To have the relay come back after a server reboot, run once per account:

1. `pm2 startup` and run the command it prints (systemd/user setup).
2. After starting the relay: `pm2 save`.

Then PM2 will resurrect the relay on boot.

For deploy and why `ecosystem.config.cjs` is required, see [docs/devops.md](../../docs/devops.md).

## Development

From the monorepo root:

```bash
npm run relay:dev
```

This builds `@galactus/shared` and then starts the relay server with watch mode on `http://localhost:8787`.

From this directory (requires shared to be built first):

```bash
# From repo root:
npm run build --workspace=@galactus/shared

# Then from this directory:
npm run dev
```

## Environment Variables

| Variable                    | Description                               |
| --------------------------- | ----------------------------------------- |
| `PORT`                      | Server port (default: 8787)               |
| `NODE_ENV`                  | Environment (development/production)      |
| `CORS_ORIGIN`               | CORS origin (default: \* in dev)          |
| `HTTP_TIMEOUT_MS`           | HTTP timeout (default: 30000)             |
| `WS_RECONNECT_DELAY_MS`     | WebSocket reconnect delay (default: 1000) |
| `WS_MAX_RECONNECT_ATTEMPTS` | Max reconnect attempts (default: 5)       |
| `REQUEST_SIZE_LIMIT`        | Max request size in bytes (default: 10MB) |

## Testing

From the monorepo root:

```bash
npm run relay:test
```

From this directory:

```bash
# Unit tests
npm test

# Integration tests
npm run test:integration

# Watch mode
npm run test:watch
```
