3.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Sub Router is a Surge proxy subscription management system. It aggregates nodes from upstream subscriptions, allows adding custom static nodes and rules, and generates a combined Surge configuration file served at /surge.
Commands
# Development (starts both server and web dev server concurrently)
npm run dev
# Server only (port 3456, hot-reload via tsx watch)
npm run dev:server
# Frontend only (port 5173, proxies /api and /surge to :3456)
npm run dev:web
# Build frontend for production
npm run build:web
# Production start (serves built frontend + API on port 3456)
npm run start
# Type check frontend
cd web && npx tsc --noEmit
# Docker
docker compose up -d
Architecture
Monorepo with NPM Workspaces: server/ (Express + better-sqlite3) and web/ (React + Vite). In production, Express serves the built frontend static files and API from a single port (3456).
Key data flow
- User adds upstream subscription URLs → backend fetches and parses nodes into
fetched_nodestable - User adds static nodes via URI (ss://, vmess://, trojan://) → parsed and stored in
static_nodestable GET /surge→generator.tsrebuilds the Surge config:- Takes first enabled subscription's
raw_configas base template - Replaces
[Proxy]section entirely with only enabled nodes (static first, then fetched) - Rebuilds
[Proxy Group]select groups with only enabled node names - Injects user rules at the top of
[Rule]section - Rewrites
#!MANAGED-CONFIGURL
- Takes first enabled subscription's
Auth model
/surge endpoint requires no auth (for Surge client access). All /api/* routes require Bearer token auth, except /api/auth/login and /api/auth/status. Password is stored in the config table. Token is the raw password sent via Authorization: Bearer <password>.
Database
SQLite with WAL mode at server/data/sub-router.db. Five tables: subscriptions, fetched_nodes (FK to subscriptions, CASCADE delete), static_nodes, rules, config (KV store for password).
Parsers (server/src/parsers/)
Convert protocol URIs to Surge proxy lines. Each parser returns { name, type, server, port, surgeLine }. The subscription content parser handles both base64-encoded URI lists and raw Surge config format (extracting from [Proxy] section).
- SS: No TLS wrapping (Surge doesn't support SS over TLS; SS 2022 has built-in encryption)
- VMess/Trojan:
skip-cert-verify=false(strict TLS verification)
Frontend
Five panels: Subscriptions (CRUD + fetch trigger), Static Nodes (paste URI, custom naming, double-click to rename), Node Selector (per-subscription toggle with regex batch operations), Rules (CRUD + drag reorder), Output (subscription URL + config preview). Dark cyberpunk theme with CSS variables, JetBrains Mono font.
Route ordering matters
In server/src/routes/: specific paths like /reorder and /fetched/batch must be registered before parameterized /:id routes to avoid being captured by Express route matching.
Deployment
The Content-Disposition header on /surge controls the config profile name in Surge client (currently IPLC.MAX.conf). Docker mounts ./data volume for SQLite persistence. Certificate renewal uses acme.sh with dns_cf (Cloudflare DNS API validation).