Files
docs/core-private-routes.md
T
2026-05-10 02:29:38 +03:00

117 lines
3.2 KiB
Markdown

# Core Private Node Routes
These routes are consumed only by the node agent and require the `x-node-auth-key` header.
## Authentication
- `POST /node/register` is the only public route in this group.
- All other routes require a valid node auth key.
- The auth key is issued by Core during registration and persisted on the node side.
## Route table
| Method | Route | Input | Output / Notes |
| --- | --- | --- | --- |
| `POST` | `/node/register` | `RegisterNodeDto` | Returns `{ authKey, nodeId }` |
| `POST` | `/node/heartbeat` | `NodeHeartbeatDto` | Returns `{ ok: true, needSync }` |
| `POST` | `/node/usage` | `NodeUsageDto` | Returns `{ ok: true }` |
| `POST` | `/node/outbound-usage` | `NodeOutboundUsageDto` | Returns `{ ok: true }` |
| `POST` | `/node/session-events` | `SessionEventsDto` | Returns `{ ok: true }` |
| `GET` | `/node/config/latest` | none | Returns `NodeConfig` |
| `POST` | `/node/config/applied` | `NodeConfigAppliedDto` | Returns `{ ok: true }` |
| `POST` | `/node/error` | `NodeErrorDto` | Returns `{ ok: true }` |
## Request payloads
### `RegisterNodeDto`
- `code: string`
- `name: string`
- `host: string`
- `ip: string`
- `region: string`
### `NodeHeartbeatDto`
- `ip?: string`
- `revision?: number`
The node sends its current revision in heartbeats. Core uses it to decide whether a sync is needed.
### `NodeUsageDto`
- `entries: UsageEntryDto[]`
`UsageEntryDto` fields:
- `userId: number`
- `subscriptionId?: number | null`
- `nodeProtocolId: number`
- `bytesUp: number`
- `bytesDown: number`
- `recordedAt: string`
### `NodeOutboundUsageDto`
- `items: OutboundUsageItem[]`
`OutboundUsageItem` fields:
- `tag: string`
- `bytesUp: number`
- `bytesDown: number`
### `SessionEventsDto`
- `events: SessionEventEntryDto[]`
`SessionEventEntryDto` fields:
- `userId: number`
- `protocol: VpnProtocol`
- `eventType: SessionEventType`
- `occurredAt: string`
- `ipAddress?: string`
### `NodeConfigAppliedDto`
- `revision: number`
### `NodeErrorDto`
- `message: string`
- `code?: string`
- `details?: Record<string, unknown>`
## `NodeConfig`
The config returned by `GET /node/config/latest` has this structure:
```ts
{
revision: number
clientMap: Record<string, { userId: number; subscriptionId: number | null }>
services: {
xray?: XrayServiceConfig
mtproto?: MtProtoServiceConfig
}
}
```
Important notes:
- `clientMap` maps subscription link UUIDs to the user and subscription used for traffic attribution.
- `services.xray` contains the Xray inbounds, routing, and outbounds for the node.
- `services.mtproto` contains MTProto inbounds for `telemt`.
- the node stores the current revision and client map locally after a successful apply
## Route semantics
- `POST /node/heartbeat` updates `lastSeenAt` and can request a sync when the node revision is behind.
- `POST /node/usage` stores per-minute usage rows and increments subscription traffic counters.
- `POST /node/outbound-usage` increments `node_outbounds.traffic_bytes_up/down`.
- `POST /node/session-events` stores online/offline events in `session_events`.
- `POST /node/config/applied` marks the node sync status as `synced`.
- `POST /node/error` marks the node as `error` and the sync status as `failed`.