pool-anything 0.1.0 → 0.1.1

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 CHANGED
@@ -11,7 +11,7 @@
11
11
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License" /></a>
12
12
  <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D22.5-brightgreen.svg" alt="Node" /></a>
13
13
  <a href="tsconfig.json"><img src="https://img.shields.io/badge/TypeScript-strict-blue.svg" alt="TypeScript" /></a>
14
- <a href="package.json"><img src="https://img.shields.io/badge/dependencies-0-brightgreen.svg" alt="Dependencies" /></a>
14
+ <a href="package.json"><img src="https://img.shields.io/badge/server%20core-0%20dependencies-brightgreen.svg" alt="Server core dependencies" /></a>
15
15
  </p>
16
16
 
17
17
  <p align="center">
@@ -29,7 +29,7 @@ Most AI/API providers hand you a free tier: a rate limit, a daily quota, a handf
29
29
  - 🌐 **Drop-in HTTP proxy** — point your client at pool-anything; it forwards with the right key, header, and auth scheme
30
30
  - 🔌 **36 providers preconfigured** — Groq, OpenRouter, Gemini, OpenAI, Anthropic, and more (plus any custom provider)
31
31
  - 🖥️ **Built-in web UI** — search providers, gather keys, watch usage on the Analytics dashboard
32
- - 🧰 **Zero runtime dependencies** — Node built-ins + TypeScript only, `node:sqlite` for storage
32
+ - 🧰 **Dependency-free server core** — the proxy, API, and web UI run on Node built-ins + `node:sqlite` only; the interactive shell adds Ink + React
33
33
 
34
34
  ## Quick start
35
35
 
@@ -45,6 +45,8 @@ That's it — an interactive assistant shell opens (`pool-anything >`). Type pla
45
45
  ```bash
46
46
  pool-anything serve --port 4000 --open # web UI + API on :4000, open the browser
47
47
  pool-anything "list pools" # run one command without the shell
48
+ pool-anything "update" # upgrade to the latest version (also an Update pill in the web UI header)
49
+ pool-anything "uninstall" # remove the global CLI (shell only, asks to confirm)
48
50
  echo "gsk_abc" | pool-anything -e "add keys to groq" # pipe keys in
49
51
  pool-anything --help # all options (serve, -e/--exec, -p/--port, -H/--host, --db, --data-dir, --open)
50
52
  ```
@@ -62,8 +64,10 @@ No subcommands to memorize — just say what you want:
62
64
  | `watch groq` | Live usage, 2s refresh (`q` exits) |
63
65
  | `next for groq` / `consume 100 on groq` | Rotate / record usage |
64
66
  | `serve` | Start the web UI + API from inside the shell |
67
+ | `update` (or `/update`) | Check npm and upgrade to the latest version |
68
+ | `uninstall` (or `/uninstall`, CLI only) | Remove the global CLI (asks to confirm; pools/keys in SQLite stay) |
65
69
 
66
- Keys always print masked (`gsk_…ab`); misunderstood input gets a "Did you mean …?" nudge.
70
+ Keys always print masked (`gsk_…ab`); misunderstood input gets a "Did you mean …?" nudge. The shell is a rich terminal UI (colors, bordered panels, live `watch` view, `↑`/`↓` history) with a plain-text fallback when Ink can't initialize.
67
71
 
68
72
  ### Run from source
69
73
 
@@ -140,6 +144,7 @@ All responses are JSON. `:id` is a pool ID.
140
144
  | `GET` | `/api/pools/:id/next` | Rotate: return the next key (masked — never the raw key) |
141
145
  | `POST` | `/api/pools/:id/consume` | Record usage — `{ tokens: <positive int ≤ 1000000>, key_id? }` (with `key_id`, bills that key without rotating) |
142
146
  | `GET` | `/api/pools/:id/usage` | Usage rollup — `{ used, usedInWindow, quota, quotaWindow, remaining, perKey }` (`used` is lifetime; `remaining`/`usedInWindow`/`perKey` are windowed for monthly quotas) |
147
+ | `GET` | `/api/pools/:id/calls?limit=` | Recent upstream attempts — status, tokens, response body (4000 chars text, ~2MB retained media), per key (default 50, max 200) |
143
148
  | `POST` | `/api/pools/:id/proxy` | Proxy a request through the pool (see below) |
144
149
 
145
150
  ### Keys
@@ -183,6 +188,8 @@ The response reports which key was used and the upstream status:
183
188
  | `GET` | `/health` | Liveness check → `ok` |
184
189
  | `GET` | `/api/db/ping` | SQLite reachability → `{ ok: true }` |
185
190
  | `GET` | `/api/analytics` | Totals + 7-day deltas + 14-day daily series (drives the dashboard) |
191
+ | `GET` | `/api/version` | Current vs latest npm version + `updateAvailable` (drives the header Update pill) |
192
+ | `POST` | `/api/update` | Self-update via `npm install -g pool-anything@latest` (needs `POOL_API_TOKEN` bearer when auth is on) |
186
193
 
187
194
  ## Web UI
188
195
 
@@ -222,6 +229,7 @@ Open the Pages URL with `?api=https://your-backend` once (or use the Backend pil
222
229
  | `LOCAL_DB_PATH` | `data/pool-anything.db` (checkout) / `~/.pool-anything/*.db` (global) | SQLite database location (exact file; `--db` flag equivalent) |
223
230
  | `POOL_DATA_DIR` | _(unset)_ | Data directory holding the SQLite file (`<dir>/pool-anything.db`; `--data-dir` flag equivalent) |
224
231
  | `PROXY_TIMEOUT_MS` | `30000` | Per-attempt upstream timeout for `/proxy` |
232
+ | `POOL_DEBUG` | _(unset)_ | `1` logs per-request proxy traces (`[proxy] METHOD path pool=N tried=[...]`) to stderr — no bodies/keys; playground also keeps a per-session Debug log pane |
225
233
  | `ALLOW_PRIVATE_UPSTREAM` | _(unset)_ | `1` disables SSRF protections — tests/loopback only, never in prod |
226
234
 
227
235
  Providers are defined in [`data/providers.json`](data/providers.json). See [CONTRIBUTING.md](CONTRIBUTING.md#adding-a-provider) for the schema — adding a provider is a one-line JSON edit, no code changes.
@@ -232,7 +240,8 @@ Providers are defined in [`data/providers.json`](data/providers.json). See [CONT
232
240
  src/
233
241
  server.ts Thin HTTP front door (delegates to router/admin/observability)
234
242
  cli.ts Entry dispatch: assistant shell (default) vs `serve` vs one-shot
235
- cli/ Interactive shell — nl.ts (natural-language parser), ui.ts (terminal rendering), repl.ts (loop, key import, watch)
243
+ cli/ Interactive shell — commands.ts (presentation-free core), nl.ts (parser), ui.ts (text rendering), repl.ts (plain fallback + one-shot), tui.tsx (Ink shell)
244
+ version.ts Self-update (npm version check / install / uninstall) shared by the CLI and the web UI
236
245
  router/api.ts Route matchers + abuse caps (MAX_POOLS / MAX_KEYS_PER_POOL)
237
246
  admin/branding.ts Logo version, docs URL, sidebar icons
238
247
  admin/shell.ts Shared shell CSS/nav/JS
@@ -13,7 +13,7 @@
13
13
  {"id":"perplexity","name":"Perplexity","baseUrl":"https://api.perplexity.ai","keyHeader":"Authorization","keyPrefix":"Bearer ","extraHeaders":{},"quota":"$5 credit on signup","docsUrl":"https://docs.perplexity.ai/getting-started/quickstart","keyFields":["api_key"],"hint":"perplexity.ai/settings/api, pplx-…","logo":"public/logos/perplexity.svg"},
14
14
  {"id":"anyscale","name":"Anyscale Endpoints","baseUrl":"https://api.endpoints.anyscale.com/v1","keyHeader":"Authorization","keyPrefix":"Bearer ","extraHeaders":{},"quota":"legacy, deprecated","docsUrl":"https://docs.anyscale.com/endpoints/overview","keyFields":["api_key"],"hint":"app.endpoints.anyscale.com/credentials","logo":"public/logos/anyscale.svg"},
15
15
  {"id":"elevenlabs","name":"ElevenLabs","baseUrl":"https://api.elevenlabs.io/v1","keyHeader":"xi-api-key","keyPrefix":"","extraHeaders":{},"quota":"10k credits/mo free","docsUrl":"https://elevenlabs.io/docs","keyFields":["api_key"],"hint":"elevenlabs.io API key","logo":"public/logos/elevenlabs.svg"},
16
- {"id":"deepgram","name":"Deepgram","baseUrl":"https://api.deepgram.com/v1","keyHeader":"Authorization","keyPrefix":"Token ","extraHeaders":{},"quota":"$200 credit on signup","docsUrl":"https://developers.deepgram.com/docs","keyFields":["api_key"],"hint":"Authorization: Token …","logo":"public/logos/deepgram.svg"},
16
+ {"id":"deepgram","name":"Deepgram","baseUrl":"https://api.deepgram.com","keyHeader":"Authorization","keyPrefix":"Token ","extraHeaders":{},"quota":"$200 credit on signup","docsUrl":"https://developers.deepgram.com/docs","keyFields":["api_key"],"hint":"Authorization: Token …","logo":"public/logos/deepgram.svg"},
17
17
  {"id":"cartesia","name":"Cartesia","baseUrl":"https://api.cartesia.ai","keyHeader":"X-API-Key","keyPrefix":"","extraHeaders":{"Cartesia-Version":"2024-06-10"},"quota":"20,000 free tokens","docsUrl":"https://docs.cartesia.ai","keyFields":["api_key"],"hint":"Paste a Cartesia API key","logo":"public/logos/cartesia.svg"},
18
18
  {"id":"tavily","name":"Tavily","baseUrl":"https://api.tavily.com","keyHeader":"Authorization","keyPrefix":"Bearer ","extraHeaders":{},"quota":"1,000 credits/mo free","docsUrl":"https://docs.tavily.com/documentation/api-reference/endpoint/search","keyFields":["api_key"],"hint":"app.tavily.com/home, tvly-…","logo":"public/logos/tavily.svg"},
19
19
  {"id":"brave-search","name":"Brave Search","baseUrl":"https://api.search.brave.com/res/v1","keyHeader":"X-Subscription-Token","keyPrefix":"","extraHeaders":{},"quota":"2,000 queries/mo free","docsUrl":"https://brave.com/search/api/","keyFields":["api_key"],"hint":"brave.com/search/api/","logo":"public/logos/brave.svg"},
@@ -21,6 +21,7 @@ export const ICONS = {
21
21
  keys: svgIcon('<circle cx="8" cy="16" r="4.5"/><path d="m11.2 12.8 8.3-8.3"/><path d="M17 5.5l2.5 2.5M14.5 8l2.5 2.5"/>'),
22
22
  analytics: svgIcon('<path d="M3 21h18"/><path d="M6 21v-7M11 21V5M16 21v-11M21 21v-4"/>'),
23
23
  playground: svgIcon('<circle cx="12" cy="12" r="9"/><path d="m10 8.5 5 3.5-5 3.5v-7Z"/>'),
24
+ history: svgIcon('<path d="M3.5 12a8.5 8.5 0 1 1 2.4 6"/><path d="M3.5 12H7"/><path d="M3.5 12V8.5"/><path d="M12 7.5V12l3 2"/>'),
24
25
  docs: svgIcon('<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>'),
25
26
  /** Attach-row media icons: same 24px stroke family as sidebar (currentColor, 1.8, round).
26
27
  * Sized down to 14px via `.filebtn svg` in playground CSS. */