synapse-gateway 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +385 -0
- package/bin/synapse.js +242 -0
- package/docs/PLAN.md +1723 -0
- package/docs/PRD.md +1799 -0
- package/drizzle.config.ts +12 -0
- package/next.config.ts +8 -0
- package/package.json +82 -0
- package/postcss.config.mjs +7 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/src/app/api/analytics/cost/route.ts +13 -0
- package/src/app/api/analytics/usage/route.ts +16 -0
- package/src/app/api/auth/login/route.ts +42 -0
- package/src/app/api/cache/route.ts +19 -0
- package/src/app/api/dashboard/route.ts +35 -0
- package/src/app/api/distill/route.ts +10 -0
- package/src/app/api/events/route.ts +54 -0
- package/src/app/api/health/route.ts +10 -0
- package/src/app/api/intelligence/forensics/route.ts +23 -0
- package/src/app/api/intelligence/neural-router/route.ts +23 -0
- package/src/app/api/keys/route.ts +34 -0
- package/src/app/api/mcp/route.ts +49 -0
- package/src/app/api/memory/route.ts +10 -0
- package/src/app/api/models/benchmark/route.ts +13 -0
- package/src/app/api/models/route.ts +39 -0
- package/src/app/api/namespace/route.ts +25 -0
- package/src/app/api/plugins/route.ts +41 -0
- package/src/app/api/providers/accounts/route.ts +91 -0
- package/src/app/api/providers/fetch-models/route.ts +52 -0
- package/src/app/api/providers/health/route.ts +10 -0
- package/src/app/api/providers/route.ts +46 -0
- package/src/app/api/routes/pipeline/route.ts +20 -0
- package/src/app/api/settings/route.ts +33 -0
- package/src/app/api/skills/route.ts +39 -0
- package/src/app/api/v1/chat/completions/route.ts +156 -0
- package/src/app/api/v1/models/route.ts +44 -0
- package/src/app/dashboard/intelligence/loading.tsx +14 -0
- package/src/app/dashboard/intelligence/page.tsx +125 -0
- package/src/app/dashboard/layout.tsx +143 -0
- package/src/app/dashboard/loading.tsx +17 -0
- package/src/app/dashboard/memory/loading.tsx +15 -0
- package/src/app/dashboard/memory/page.tsx +71 -0
- package/src/app/dashboard/models/loading.tsx +13 -0
- package/src/app/dashboard/models/page.tsx +107 -0
- package/src/app/dashboard/page.tsx +183 -0
- package/src/app/dashboard/playground/loading.tsx +17 -0
- package/src/app/dashboard/playground/page.tsx +212 -0
- package/src/app/dashboard/providers/loading.tsx +15 -0
- package/src/app/dashboard/providers/page.tsx +248 -0
- package/src/app/dashboard/routes/loading.tsx +15 -0
- package/src/app/dashboard/routes/page.tsx +72 -0
- package/src/app/dashboard/settings/loading.tsx +20 -0
- package/src/app/dashboard/settings/page.tsx +208 -0
- package/src/app/dashboard/skills/loading.tsx +26 -0
- package/src/app/dashboard/skills/page.tsx +137 -0
- package/src/app/dashboard/vault/loading.tsx +18 -0
- package/src/app/dashboard/vault/page.tsx +139 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +59 -0
- package/src/app/layout.tsx +32 -0
- package/src/app/login/page.tsx +87 -0
- package/src/app/page.tsx +5 -0
- package/src/components/ui/badge.tsx +32 -0
- package/src/components/ui/button.tsx +38 -0
- package/src/components/ui/card.tsx +50 -0
- package/src/components/ui/error-boundary.tsx +47 -0
- package/src/components/ui/index.ts +11 -0
- package/src/components/ui/input.tsx +26 -0
- package/src/components/ui/select.tsx +24 -0
- package/src/components/ui/skeleton.tsx +53 -0
- package/src/components/ui/toast.tsx +51 -0
- package/src/instrumentation.ts +6 -0
- package/src/lib/__tests__/auth.test.ts +42 -0
- package/src/lib/__tests__/format.test.ts +94 -0
- package/src/lib/__tests__/namespace.test.ts +102 -0
- package/src/lib/__tests__/squeezer.test.ts +93 -0
- package/src/lib/__tests__/utils.test.ts +28 -0
- package/src/lib/analytics/index.ts +187 -0
- package/src/lib/auth/guard.tsx +71 -0
- package/src/lib/auth/index.ts +105 -0
- package/src/lib/auth/middleware.ts +64 -0
- package/src/lib/benchmark/index.ts +137 -0
- package/src/lib/bootstrap.ts +122 -0
- package/src/lib/cache/index.ts +1 -0
- package/src/lib/cache/semantic.ts +211 -0
- package/src/lib/config/defaults.ts +61 -0
- package/src/lib/config/index.ts +72 -0
- package/src/lib/config/schema.ts +63 -0
- package/src/lib/db/index.ts +22 -0
- package/src/lib/db/migrate.ts +327 -0
- package/src/lib/db/schema.ts +303 -0
- package/src/lib/distiller/index.ts +331 -0
- package/src/lib/fallback/index.ts +153 -0
- package/src/lib/forensics/index.ts +188 -0
- package/src/lib/format/anthropic.ts +139 -0
- package/src/lib/format/gemini.ts +130 -0
- package/src/lib/format/index.ts +3 -0
- package/src/lib/format/openai.ts +78 -0
- package/src/lib/health/index.ts +158 -0
- package/src/lib/mcp/builtin.ts +83 -0
- package/src/lib/mcp/index.ts +1 -0
- package/src/lib/mcp/registry.ts +49 -0
- package/src/lib/memory/index.ts +3 -0
- package/src/lib/memory/store.ts +215 -0
- package/src/lib/memory/types.ts +56 -0
- package/src/lib/namespace/index.ts +89 -0
- package/src/lib/neural/features.ts +74 -0
- package/src/lib/neural/index.ts +85 -0
- package/src/lib/neural/strategies.ts +124 -0
- package/src/lib/pipeline/index.ts +84 -0
- package/src/lib/pipeline/types.ts +77 -0
- package/src/lib/plugins/builtin.ts +79 -0
- package/src/lib/plugins/index.ts +65 -0
- package/src/lib/prediction/index.ts +113 -0
- package/src/lib/providers/api-key/anthropic.ts +96 -0
- package/src/lib/providers/api-key/deepseek.ts +108 -0
- package/src/lib/providers/api-key/gemini.ts +112 -0
- package/src/lib/providers/api-key/openai.ts +122 -0
- package/src/lib/providers/api-key/openrouter.ts +112 -0
- package/src/lib/providers/base-adapter.ts +122 -0
- package/src/lib/providers/registry.ts +46 -0
- package/src/lib/providers/types.ts +121 -0
- package/src/lib/router/index.ts +82 -0
- package/src/lib/skills/forge.ts +57 -0
- package/src/lib/skills/index.ts +3 -0
- package/src/lib/skills/registry.ts +195 -0
- package/src/lib/skills/types.ts +44 -0
- package/src/lib/squeezer/index.ts +158 -0
- package/src/lib/utils/cn.ts +6 -0
- package/src/lib/utils/logger.ts +16 -0
- package/src/middleware.ts +60 -0
- package/tsconfig.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="screenshots/01-command-center.png" alt="Synapse Dashboard" width="100%">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">⚡ Synapse — AI Gateway & Intelligence Platform</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>The neural hub for all your AI providers.</strong><br>
|
|
9
|
+
Route requests intelligently, cache semantically, compress tokens, learn from experience, and manage 5+ AI providers through a single beautiful dashboard.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<img src="https://img.shields.io/badge/Next.js-16-black?logo=next.js" alt="Next.js 16" />
|
|
14
|
+
<img src="https://img.shields.io/badge/TypeScript-Strict-blue?logo=typescript" alt="TypeScript" />
|
|
15
|
+
<img src="https://img.shields.io/badge/SQLite-Embedded-003B57?logo=sqlite" alt="SQLite" />
|
|
16
|
+
<img src="https://img.shields.io/badge/Tests-76%20passing-brightgreen" alt="Tests" />
|
|
17
|
+
<img src="https://img.shields.io/badge/License-MIT-green" alt="License" />
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<a href="#-quick-start">Quick Start</a> •
|
|
22
|
+
<a href="#-21-breakthrough-features">Features</a> •
|
|
23
|
+
<a href="#-screenshots">Screenshots</a> •
|
|
24
|
+
<a href="#-api-reference">API</a> •
|
|
25
|
+
<a href="#-tech-stack">Tech Stack</a>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 📸 Screenshots
|
|
31
|
+
|
|
32
|
+
### Authentication
|
|
33
|
+
|
|
34
|
+
<p align="center">
|
|
35
|
+
<img src="screenshots/00-login.png" alt="Login" width="80%">
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
### Dashboard — All 10 Pages
|
|
39
|
+
|
|
40
|
+
<table>
|
|
41
|
+
<tr>
|
|
42
|
+
<td align="center"><b>📊 Command Center</b></td>
|
|
43
|
+
<td align="center"><b>🔌 Providers</b></td>
|
|
44
|
+
</tr>
|
|
45
|
+
<tr>
|
|
46
|
+
<td><img src="screenshots/01-command-center.png" alt="Command Center" width="100%"></td>
|
|
47
|
+
<td><img src="screenshots/02-providers.png" alt="Providers" width="100%"></td>
|
|
48
|
+
</tr>
|
|
49
|
+
<tr>
|
|
50
|
+
<td align="center"><b>🧠 Models</b></td>
|
|
51
|
+
<td align="center"><b>🔀 Routes</b></td>
|
|
52
|
+
</tr>
|
|
53
|
+
<tr>
|
|
54
|
+
<td><img src="screenshots/03-models.png" alt="Models" width="100%"></td>
|
|
55
|
+
<td><img src="screenshots/04-routes.png" alt="Routes" width="100%"></td>
|
|
56
|
+
</tr>
|
|
57
|
+
<tr>
|
|
58
|
+
<td align="center"><b>🛠️ Skills</b></td>
|
|
59
|
+
<td align="center"><b>✨ Intelligence</b></td>
|
|
60
|
+
</tr>
|
|
61
|
+
<tr>
|
|
62
|
+
<td><img src="screenshots/05-skills.png" alt="Skills" width="100%"></td>
|
|
63
|
+
<td><img src="screenshots/06-intelligence.png" alt="Intelligence" width="100%"></td>
|
|
64
|
+
</tr>
|
|
65
|
+
<tr>
|
|
66
|
+
<td align="center"><b>💬 Playground</b></td>
|
|
67
|
+
<td align="center"><b>💾 Memory</b></td>
|
|
68
|
+
</tr>
|
|
69
|
+
<tr>
|
|
70
|
+
<td><img src="screenshots/07-playground.png" alt="Playground" width="100%"></td>
|
|
71
|
+
<td><img src="screenshots/08-memory.png" alt="Memory" width="100%"></td>
|
|
72
|
+
</tr>
|
|
73
|
+
<tr>
|
|
74
|
+
<td align="center"><b>🔐 Vault</b></td>
|
|
75
|
+
<td align="center"><b>⚙️ Settings</b></td>
|
|
76
|
+
</tr>
|
|
77
|
+
<tr>
|
|
78
|
+
<td><img src="screenshots/09-vault.png" alt="Vault" width="100%"></td>
|
|
79
|
+
<td><img src="screenshots/10-settings.png" alt="Settings" width="100%"></td>
|
|
80
|
+
</tr>
|
|
81
|
+
</table>
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 🧠 21 Breakthrough Features
|
|
86
|
+
|
|
87
|
+
| # | Feature | Description |
|
|
88
|
+
|---|---------|-------------|
|
|
89
|
+
| 1 | **Neural Router** | AI-powered request routing with 5 strategies (priority, latency, cost, round-robin, hybrid) |
|
|
90
|
+
| 2 | **Semantic Cache** | LRU + SQLite persisted cache with SHA-256 hashing and TTL expiry |
|
|
91
|
+
| 3 | **Adaptive Token Squeezer** | 4 compression levels (none → aggressive), auto-classifies code vs text |
|
|
92
|
+
| 4 | **Persistent Memory** | 3-layer store: Episodic (90-day), Semantic (permanent), Procedural (rules) |
|
|
93
|
+
| 5 | **Self-Learning (Distiller)** | Runs every 6h, extracts patterns, generates rules from request history |
|
|
94
|
+
| 6 | **Dynamic Skill Rotation** | 5 strategies: round-robin, quality-based, weighted-random, task-match, schedule |
|
|
95
|
+
| 7 | **Skill Forge** | Create skills from recipes, import from OpenClaw format |
|
|
96
|
+
| 8 | **Universal Namespace** | 8 aliases (`best`, `fast`, `cheap`, `code`, `reason`...) + auto task detection |
|
|
97
|
+
| 9 | **Predictive Cost Engine** | Monthly forecast, budget manager, model cost comparison |
|
|
98
|
+
| 10 | **Provider Health Monitor** | Tracks latency, error rate, consecutive failures every 5 minutes |
|
|
99
|
+
| 11 | **Request Forensics** | Timeline, root cause analysis, latency breakdown, optimization suggestions |
|
|
100
|
+
| 12 | **MCP Gateway** | Model Context Protocol server with 6 tools + 2 resources |
|
|
101
|
+
| 13 | **Plugin System** | Pre/post request hooks with PII redactor + response validator built-in |
|
|
102
|
+
| 14 | **Benchmark Engine** | Shadow testing, quality scoring, A/B model comparison |
|
|
103
|
+
| 15 | **Pipeline Builder** | 11 node types, visual pipeline construction |
|
|
104
|
+
| 16 | **Format Translation** | Bidirectional converters for OpenAI, Anthropic, Gemini |
|
|
105
|
+
| 17 | **Fallback Engine** | Candidate ranking, exponential backoff, timeout management |
|
|
106
|
+
| 18 | **Auth System** | JWT login + API key management (`syn_` prefixed keys, SHA-256 hashed) |
|
|
107
|
+
| 19 | **Analytics Aggregator** | Usage stats, 30-day time series, top models, provider performance |
|
|
108
|
+
| 20 | **Provider Management** | 5 adapters (OpenAI, Anthropic, Gemini, DeepSeek, OpenRouter) |
|
|
109
|
+
| 21 | **Real-time Dashboard** | 10 pages with live data, SSE streaming, auto-refresh |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 🏗️ Architecture
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
synapse/
|
|
117
|
+
├── src/
|
|
118
|
+
│ ├── app/
|
|
119
|
+
│ │ ├── api/ # 42 API Routes
|
|
120
|
+
│ │ │ ├── v1/ # OpenAI-compatible endpoints
|
|
121
|
+
│ │ │ │ ├── chat/completions
|
|
122
|
+
│ │ │ │ └── models
|
|
123
|
+
│ │ │ ├── providers/ # Provider + account management
|
|
124
|
+
│ │ │ ├── models/ # Model registry + benchmark
|
|
125
|
+
│ │ │ ├── skills/ # Skill CRUD + rotation
|
|
126
|
+
│ │ │ ├── memory/ # 3-layer memory store
|
|
127
|
+
│ │ │ ├── cache/ # Semantic cache stats
|
|
128
|
+
│ │ │ ├── intelligence/ # Neural router + forensics
|
|
129
|
+
│ │ │ ├── analytics/ # Usage + cost analytics
|
|
130
|
+
│ │ │ ├── auth/ # JWT login
|
|
131
|
+
│ │ │ ├── keys/ # API key management
|
|
132
|
+
│ │ │ ├── mcp/ # MCP gateway
|
|
133
|
+
│ │ │ ├── namespace/ # Universal model aliases
|
|
134
|
+
│ │ │ ├── plugins/ # Plugin management
|
|
135
|
+
│ │ │ ├── routes/pipeline/ # Pipeline builder
|
|
136
|
+
│ │ │ ├── settings/ # App configuration
|
|
137
|
+
│ │ │ ├── dashboard/ # Dashboard data
|
|
138
|
+
│ │ │ ├── distill/ # Experience distiller
|
|
139
|
+
│ │ │ └── events/ # SSE stream
|
|
140
|
+
│ │ ├── dashboard/ # 10 Dashboard Pages
|
|
141
|
+
│ │ │ ├── page.tsx # Command Center
|
|
142
|
+
│ │ │ ├── providers/ # Provider management
|
|
143
|
+
│ │ │ ├── models/ # Model browser
|
|
144
|
+
│ │ │ ├── routes/ # Pipeline routes
|
|
145
|
+
│ │ │ ├── skills/ # Skill management
|
|
146
|
+
│ │ │ ├── intelligence/ # Neural router + forensics
|
|
147
|
+
│ │ │ ├── playground/ # SSE streaming chat
|
|
148
|
+
│ │ │ ├── memory/ # 3-layer memory
|
|
149
|
+
│ │ │ ├── vault/ # API keys
|
|
150
|
+
│ │ │ └── settings/ # Configuration
|
|
151
|
+
│ │ └── login/ # Auth page
|
|
152
|
+
│ ├── lib/
|
|
153
|
+
│ │ ├── providers/ # 5 Provider Adapters
|
|
154
|
+
│ │ ├── router/ # Core request router
|
|
155
|
+
│ │ ├── fallback/ # Fallback engine
|
|
156
|
+
│ │ ├── format/ # Format translators
|
|
157
|
+
│ │ ├── cache/ # Semantic cache
|
|
158
|
+
│ │ ├── memory/ # Persistent memory
|
|
159
|
+
│ │ ├── skills/ # Skill system
|
|
160
|
+
│ │ ├── neural/ # Neural router
|
|
161
|
+
│ │ ├── squeezer/ # Token compression
|
|
162
|
+
│ │ ├── prediction/ # Cost forecasting
|
|
163
|
+
│ │ ├── health/ # Health checker
|
|
164
|
+
│ │ ├── namespace/ # Universal namespace
|
|
165
|
+
│ │ ├── benchmark/ # Model benchmark
|
|
166
|
+
│ │ ├── pipeline/ # Pipeline builder
|
|
167
|
+
│ │ ├── mcp/ # MCP gateway
|
|
168
|
+
│ │ ├── plugins/ # Plugin system
|
|
169
|
+
│ │ ├── forensics/ # Request forensics
|
|
170
|
+
│ │ ├── distiller/ # Experience distiller
|
|
171
|
+
│ │ ├── analytics/ # Analytics aggregator
|
|
172
|
+
│ │ ├── auth/ # JWT + API keys
|
|
173
|
+
│ │ ├── db/ # SQLite + Drizzle ORM (21 tables)
|
|
174
|
+
│ │ └── config/ # Zod schema config
|
|
175
|
+
│ └── components/ui/ # Reusable UI components
|
|
176
|
+
├── e2e/ # Playwright E2E tests
|
|
177
|
+
├── docs/ # PRD + Implementation Plan
|
|
178
|
+
└── screenshots/ # README screenshots
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🚀 Quick Start
|
|
184
|
+
|
|
185
|
+
### Prerequisites
|
|
186
|
+
- **Node.js** 20+
|
|
187
|
+
- **npm** or **git**
|
|
188
|
+
|
|
189
|
+
### Option 1: Clone & Run (Recommended)
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
git clone https://github.com/kevindoni/Synapse.git
|
|
193
|
+
cd Synapse
|
|
194
|
+
npm install
|
|
195
|
+
synapse start
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Open **http://localhost:3000** → login with password `changeme`.
|
|
199
|
+
|
|
200
|
+
### Option 2: Development Mode
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
git clone https://github.com/kevindoni/Synapse.git
|
|
204
|
+
cd Synapse
|
|
205
|
+
npm install
|
|
206
|
+
synapse dev # Hot reload, auto-restart
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Option 3: Production (PM2 / systemd)
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
git clone https://github.com/kevindoni/Synapse.git
|
|
213
|
+
cd Synapse
|
|
214
|
+
npm install
|
|
215
|
+
npm run build
|
|
216
|
+
|
|
217
|
+
# Start with PM2
|
|
218
|
+
npx pm2 start .next/standalone/server.js --name synapse
|
|
219
|
+
npx pm2 save
|
|
220
|
+
|
|
221
|
+
# Or with systemd (Linux)
|
|
222
|
+
sudo cp deploy/synapse.service /etc/systemd/system/
|
|
223
|
+
sudo systemctl enable synapse
|
|
224
|
+
sudo systemctl start synapse
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### CLI Commands
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
synapse start # Start production server (auto-build if needed)
|
|
231
|
+
synapse stop # Stop server
|
|
232
|
+
synapse restart # Restart server
|
|
233
|
+
synapse status # Check if running
|
|
234
|
+
synapse dev # Development mode (hot reload)
|
|
235
|
+
synapse build # Build for production
|
|
236
|
+
synapse version # Show version
|
|
237
|
+
synapse help # Show all commands
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Environment Variables
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Custom port
|
|
244
|
+
PORT=8080 synapse start
|
|
245
|
+
|
|
246
|
+
# Custom password
|
|
247
|
+
SYNAPSE_PASSWORD=my-secret synapse start
|
|
248
|
+
|
|
249
|
+
# Custom data dir
|
|
250
|
+
DATA_DIR=/var/lib/synapse synapse start
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Connect AI Providers
|
|
254
|
+
|
|
255
|
+
1. Login → open **Providers** in the sidebar
|
|
256
|
+
2. Click **Manage** on a provider (e.g., OpenAI)
|
|
257
|
+
3. Click **Add Account** → paste your API key
|
|
258
|
+
4. Click **Fetch Models** to populate the model list
|
|
259
|
+
5. Start chatting in the **Playground**
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 🔌 Supported Providers
|
|
264
|
+
|
|
265
|
+
| Provider | Prefix | Models |
|
|
266
|
+
|----------|--------|--------|
|
|
267
|
+
| **OpenAI** | `oa/` | GPT-4o, GPT-4o-mini, o3, o3-mini |
|
|
268
|
+
| **Anthropic** | `an/` | Claude Sonnet 4, Claude Opus 4.7, Claude Haiku 3.5 |
|
|
269
|
+
| **Google Gemini** | `gm/` | Gemini 2.5 Pro, Gemini 2.5 Flash |
|
|
270
|
+
| **DeepSeek** | `ds/` | DeepSeek Chat, DeepSeek Reasoner |
|
|
271
|
+
| **OpenRouter** | `or/` | 200+ models via single API |
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 🧪 Testing
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
npm test # Unit tests (46 tests — Vitest)
|
|
279
|
+
npm run test:e2e # E2E tests (30 tests — Playwright)
|
|
280
|
+
npm run test:all # Run everything
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## ⚙️ Environment Variables
|
|
286
|
+
|
|
287
|
+
```env
|
|
288
|
+
JWT_SECRET=your-jwt-secret
|
|
289
|
+
SYNAPSE_PASSWORD=your-admin-password
|
|
290
|
+
DATA_DIR=/path/to/data # default: ~/.synapse
|
|
291
|
+
OPENAI_API_KEY=sk-...
|
|
292
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
293
|
+
GEMINI_API_KEY=AIza...
|
|
294
|
+
DEEPSEEK_API_KEY=sk-...
|
|
295
|
+
OPENROUTER_API_KEY=sk-or-...
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## 🔐 Security
|
|
301
|
+
|
|
302
|
+
- JWT authentication with 7-day expiry
|
|
303
|
+
- API keys prefixed with `syn_`, stored as SHA-256 hashes
|
|
304
|
+
- Rate limiting (100 req/min via middleware)
|
|
305
|
+
- CORS configurable
|
|
306
|
+
- PII redaction plugin built-in
|
|
307
|
+
- Request forensics for auditing
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## 🗄️ Database
|
|
312
|
+
|
|
313
|
+
**SQLite** (via better-sqlite3) + **Drizzle ORM** — zero external dependencies.
|
|
314
|
+
|
|
315
|
+
- 21 tables with 8 indexes
|
|
316
|
+
- WAL mode for concurrent reads
|
|
317
|
+
- Auto-migration on startup
|
|
318
|
+
- Stored at `~/.synapse/synapse.db`
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 🛠️ Tech Stack
|
|
323
|
+
|
|
324
|
+
| Layer | Technology |
|
|
325
|
+
|-------|-----------|
|
|
326
|
+
| Framework | Next.js 16 (App Router) |
|
|
327
|
+
| Language | TypeScript (strict) |
|
|
328
|
+
| Styling | Tailwind CSS v4 |
|
|
329
|
+
| Database | SQLite + Drizzle ORM |
|
|
330
|
+
| Auth | JWT (jose) + SHA-256 |
|
|
331
|
+
| Testing | Vitest + Playwright |
|
|
332
|
+
| AI Providers | OpenAI, Anthropic, Gemini, DeepSeek, OpenRouter |
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 📄 API Reference
|
|
337
|
+
|
|
338
|
+
### OpenAI-Compatible
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
POST /api/v1/chat/completions # Chat completion (SSE streaming supported)
|
|
342
|
+
GET /api/v1/models # List models (OpenAI format)
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Management
|
|
346
|
+
|
|
347
|
+
```
|
|
348
|
+
GET /api/providers # List providers
|
|
349
|
+
POST /api/providers # Add provider
|
|
350
|
+
GET /api/providers/health # Health status
|
|
351
|
+
POST /api/providers/accounts # Add API key
|
|
352
|
+
POST /api/providers/fetch-models # Fetch models from provider
|
|
353
|
+
GET /api/models # List all models
|
|
354
|
+
GET /api/skills # List skills + groups
|
|
355
|
+
POST /api/skills # Create skill
|
|
356
|
+
GET /api/memory # Memory stats
|
|
357
|
+
GET /api/cache # Cache stats
|
|
358
|
+
DELETE /api/cache # Clear cache
|
|
359
|
+
GET /api/settings # Get settings
|
|
360
|
+
PUT /api/settings # Update settings
|
|
361
|
+
GET /api/analytics/usage # Usage stats
|
|
362
|
+
GET /api/analytics/cost # Cost forecast
|
|
363
|
+
GET /api/namespace?model=best # Resolve model alias
|
|
364
|
+
GET /api/intelligence/neural-router # Neural router status
|
|
365
|
+
GET /api/intelligence/forensics # Request forensics
|
|
366
|
+
POST /api/distill # Trigger experience distillation
|
|
367
|
+
POST /api/auth/login # JWT login
|
|
368
|
+
GET /api/keys # List API keys
|
|
369
|
+
POST /api/keys # Generate API key
|
|
370
|
+
DELETE /api/keys # Revoke API key
|
|
371
|
+
POST /api/mcp # MCP JSON-RPC
|
|
372
|
+
GET /api/dashboard # Dashboard data
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## 📜 License
|
|
378
|
+
|
|
379
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
<p align="center">
|
|
384
|
+
Built with ⚡ by <a href="https://github.com/kevindoni">kevindoni</a>
|
|
385
|
+
</p>
|
package/bin/synapse.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn, execSync } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const command = args[0] || 'start';
|
|
10
|
+
|
|
11
|
+
const PORT = process.env.PORT || process.env.SYNAPSE_PORT || 3000;
|
|
12
|
+
|
|
13
|
+
function getPkgDir() {
|
|
14
|
+
return path.resolve(__dirname, '..');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getPidFile() {
|
|
18
|
+
const dataDir = process.env.DATA_DIR || path.join(os.homedir(), '.synapse');
|
|
19
|
+
return path.join(dataDir, 'synapse.pid');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isRunning() {
|
|
23
|
+
const pidFile = getPidFile();
|
|
24
|
+
if (!fs.existsSync(pidFile)) return false;
|
|
25
|
+
try {
|
|
26
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim());
|
|
27
|
+
process.kill(pid, 0);
|
|
28
|
+
return true;
|
|
29
|
+
} catch {
|
|
30
|
+
try { fs.unlinkSync(pidFile); } catch {}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function ensureDataDir() {
|
|
36
|
+
const dataDir = process.env.DATA_DIR || path.join(os.homedir(), '.synapse');
|
|
37
|
+
if (!fs.existsSync(dataDir)) {
|
|
38
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function copyDir(src, dest) {
|
|
43
|
+
if (!fs.existsSync(src)) return;
|
|
44
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
45
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
46
|
+
const srcPath = path.join(src, entry.name);
|
|
47
|
+
const destPath = path.join(dest, entry.name);
|
|
48
|
+
if (entry.isDirectory()) {
|
|
49
|
+
copyDir(srcPath, destPath);
|
|
50
|
+
} else {
|
|
51
|
+
fs.copyFileSync(srcPath, destPath);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function buildIfNeeded() {
|
|
57
|
+
const PKG_DIR = getPkgDir();
|
|
58
|
+
const standaloneDir = path.join(PKG_DIR, '.next', 'standalone');
|
|
59
|
+
if (fs.existsSync(path.join(standaloneDir, 'server.js')) &&
|
|
60
|
+
fs.existsSync(path.join(standaloneDir, 'public'))) return;
|
|
61
|
+
|
|
62
|
+
console.log('⚡ Building Synapse (first time)...');
|
|
63
|
+
try {
|
|
64
|
+
const nextBin = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
65
|
+
execSync(`"${nextBin}" next build`, { cwd: PKG_DIR, stdio: 'inherit' });
|
|
66
|
+
copyDir(
|
|
67
|
+
path.join(PKG_DIR, '.next', 'static'),
|
|
68
|
+
path.join(standaloneDir, '.next', 'static')
|
|
69
|
+
);
|
|
70
|
+
copyDir(
|
|
71
|
+
path.join(PKG_DIR, 'public'),
|
|
72
|
+
path.join(standaloneDir, 'public')
|
|
73
|
+
);
|
|
74
|
+
console.log('⚡ Build complete!');
|
|
75
|
+
} catch {
|
|
76
|
+
console.error('❌ Build failed. Try running manually: npm run build');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function startServer() {
|
|
82
|
+
if (isRunning()) {
|
|
83
|
+
console.log(`⚡ Synapse is already running on http://localhost:${PORT}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
ensureDataDir();
|
|
88
|
+
buildIfNeeded();
|
|
89
|
+
|
|
90
|
+
const PKG_DIR = getPkgDir();
|
|
91
|
+
const standaloneDir = path.join(PKG_DIR, '.next', 'standalone');
|
|
92
|
+
const standaloneServer = path.join(standaloneDir, 'server.js');
|
|
93
|
+
|
|
94
|
+
const env = {
|
|
95
|
+
...process.env,
|
|
96
|
+
PORT,
|
|
97
|
+
HOSTNAME: '0.0.0.0',
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const child = spawn(process.execPath, [standaloneServer], {
|
|
101
|
+
cwd: standaloneDir,
|
|
102
|
+
detached: true,
|
|
103
|
+
stdio: 'ignore',
|
|
104
|
+
env,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
child.unref();
|
|
108
|
+
|
|
109
|
+
const pidFile = getPidFile();
|
|
110
|
+
fs.writeFileSync(pidFile, child.pid.toString());
|
|
111
|
+
|
|
112
|
+
console.log(``);
|
|
113
|
+
console.log(` ⚡ Synapse started`);
|
|
114
|
+
console.log(` ─────────────────────────`);
|
|
115
|
+
console.log(` URL: http://localhost:${PORT}`);
|
|
116
|
+
console.log(` Login: http://localhost:${PORT}/login`);
|
|
117
|
+
console.log(` PID: ${child.pid}`);
|
|
118
|
+
console.log(` Data: ${process.env.DATA_DIR || path.join(os.homedir(), '.synapse')}`);
|
|
119
|
+
console.log(``);
|
|
120
|
+
console.log(` Use "synapse stop" to stop.`);
|
|
121
|
+
console.log(``);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function stopServer() {
|
|
125
|
+
if (!isRunning()) {
|
|
126
|
+
console.log('⚡ Synapse is not running');
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const pid = parseInt(fs.readFileSync(getPidFile(), 'utf8').trim());
|
|
131
|
+
process.kill(pid);
|
|
132
|
+
try { fs.unlinkSync(getPidFile()); } catch {}
|
|
133
|
+
console.log('⚡ Synapse stopped');
|
|
134
|
+
} catch {
|
|
135
|
+
try { fs.unlinkSync(getPidFile()); } catch {}
|
|
136
|
+
console.log('⚡ Synapse is not running');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function showStatus() {
|
|
141
|
+
if (isRunning()) {
|
|
142
|
+
const pid = fs.readFileSync(getPidFile(), 'utf8').trim();
|
|
143
|
+
console.log(`⚡ Synapse is running`);
|
|
144
|
+
console.log(` URL: http://localhost:${PORT}`);
|
|
145
|
+
console.log(` PID: ${pid}`);
|
|
146
|
+
console.log(` Data: ${process.env.DATA_DIR || path.join(os.homedir(), '.synapse')}`);
|
|
147
|
+
} else {
|
|
148
|
+
console.log('⚡ Synapse is not running');
|
|
149
|
+
console.log(' Run "synapse start" to start');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function showHelp() {
|
|
154
|
+
console.log(`
|
|
155
|
+
⚡ Synapse — AI Gateway & Intelligence Platform
|
|
156
|
+
|
|
157
|
+
Usage:
|
|
158
|
+
synapse <command>
|
|
159
|
+
|
|
160
|
+
Commands:
|
|
161
|
+
start Start server (production)
|
|
162
|
+
stop Stop server
|
|
163
|
+
restart Restart server
|
|
164
|
+
status Show server status
|
|
165
|
+
dev Start in development mode (hot reload)
|
|
166
|
+
build Build for production
|
|
167
|
+
version Show version
|
|
168
|
+
help Show this help
|
|
169
|
+
|
|
170
|
+
Environment:
|
|
171
|
+
PORT Server port (default: 3000)
|
|
172
|
+
SYNAPSE_PASSWORD Login password (default: changeme)
|
|
173
|
+
JWT_SECRET JWT secret key
|
|
174
|
+
DATA_DIR Data directory (default: ~/.synapse)
|
|
175
|
+
|
|
176
|
+
Examples:
|
|
177
|
+
synapse Start on port 3000
|
|
178
|
+
PORT=8080 synapse start Start on port 8080
|
|
179
|
+
synapse dev Development mode
|
|
180
|
+
synapse stop Stop server
|
|
181
|
+
synapse status Check if running
|
|
182
|
+
`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function showVersion() {
|
|
186
|
+
try {
|
|
187
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(getPkgDir(), 'package.json'), 'utf8'));
|
|
188
|
+
console.log(`⚡ Synapse v${pkg.version}`);
|
|
189
|
+
} catch {
|
|
190
|
+
console.log('⚡ Synapse v2.0.0');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function startDev() {
|
|
195
|
+
const PKG_DIR = getPkgDir();
|
|
196
|
+
console.log(`⚡ Starting Synapse in dev mode on http://localhost:${PORT}`);
|
|
197
|
+
const cmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
198
|
+
const child = spawn(cmd, ['next', 'dev', '-p', PORT], {
|
|
199
|
+
cwd: PKG_DIR,
|
|
200
|
+
stdio: 'inherit',
|
|
201
|
+
env: { ...process.env, PORT },
|
|
202
|
+
});
|
|
203
|
+
child.on('close', (code) => process.exit(code));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function runBuild() {
|
|
207
|
+
buildIfNeeded();
|
|
208
|
+
console.log('⚡ Build complete!');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
switch (command) {
|
|
212
|
+
case 'start':
|
|
213
|
+
startServer();
|
|
214
|
+
break;
|
|
215
|
+
case 'stop':
|
|
216
|
+
stopServer();
|
|
217
|
+
break;
|
|
218
|
+
case 'restart':
|
|
219
|
+
stopServer();
|
|
220
|
+
setTimeout(() => startServer(), 500);
|
|
221
|
+
break;
|
|
222
|
+
case 'status':
|
|
223
|
+
showStatus();
|
|
224
|
+
break;
|
|
225
|
+
case 'dev':
|
|
226
|
+
startDev();
|
|
227
|
+
break;
|
|
228
|
+
case 'build':
|
|
229
|
+
runBuild();
|
|
230
|
+
break;
|
|
231
|
+
case 'version':
|
|
232
|
+
case '-v':
|
|
233
|
+
case '--version':
|
|
234
|
+
showVersion();
|
|
235
|
+
break;
|
|
236
|
+
case 'help':
|
|
237
|
+
case '-h':
|
|
238
|
+
case '--help':
|
|
239
|
+
default:
|
|
240
|
+
showHelp();
|
|
241
|
+
break;
|
|
242
|
+
}
|