fest-gateway 0.1.0 → 0.3.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 +235 -184
- package/dist/cli/login.js +8 -2
- package/dist/cli/login.js.map +1 -1
- package/dist/server/api/auth.js +6 -0
- package/dist/server/api/auth.js.map +1 -1
- package/dist/server/api/cli-auth.js +243 -0
- package/dist/server/api/cli-auth.js.map +1 -0
- package/dist/server/api/oauth.js +35 -24
- package/dist/server/api/oauth.js.map +1 -1
- package/dist/server/auth/oauth.js +16 -0
- package/dist/server/auth/oauth.js.map +1 -1
- package/dist/server/config.js +1 -0
- package/dist/server/config.js.map +1 -1
- package/dist/web/dist/assets/index-AEUYX58m.css +2 -0
- package/dist/web/dist/assets/index-DznOpmye.js +56 -0
- package/dist/web/dist/assets/index-DznOpmye.js.map +1 -0
- package/dist/web/dist/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/dist/assets/index-8HlKsJqt.css +0 -2
- package/dist/web/dist/assets/index-DQ7fyPVm.js +0 -56
- package/dist/web/dist/assets/index-DQ7fyPVm.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,199 +1,119 @@
|
|
|
1
1
|
# Fest
|
|
2
2
|
|
|
3
|
+
[](https://github.com/cliftonc/fest-gateway/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/fest-gateway)
|
|
5
|
+
|
|
3
6
|
A self-hosted gateway for Claude Code. Teams point their Claude Code at Fest the
|
|
4
7
|
way they'd point at Bedrock, so one place can monitor requests, tokens and cost —
|
|
5
8
|
and route to different models without Claude Code knowing the difference.
|
|
6
9
|
|
|
7
10
|
**The distinguishing goal: Claude Max / Team subscription support.** Each
|
|
8
|
-
developer authenticates with their *own* subscription. Fest relays
|
|
11
|
+
developer authenticates with their *own* subscription. Fest relays that
|
|
9
12
|
credential and never stores it. Per-user pass-through, never pooling.
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
> Max subscription runs through Fest, is attributed to its developer, metered
|
|
13
|
-
> into SQLite, and shown on a dashboard behind a login. Model routing and
|
|
14
|
-
> substitution work and are visible. Phase 0 cleared both gates
|
|
15
|
-
> ([results](docs/PHASE0-RESULTS.md)), and `npm run canary` re-checks them
|
|
16
|
-
> against each new Claude Code release.
|
|
14
|
+
Three ways to read this, depending on what you want:
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
| | |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| [**Use it**](#use-it) | Someone runs a Fest; you want Claude Code going through it. |
|
|
19
|
+
| [**Run it**](#run-it) | You are standing one up for a team. |
|
|
20
|
+
| [**How it works**](#how-it-works) | What it can see, what it keeps, and what will bite you. |
|
|
21
|
+
| [**Develop it**](#develop-it) | Changing Fest itself. |
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
---
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN \
|
|
28
|
-
ANTHROPIC_BASE_URL=http://fest.corp:8787/t/<token> claude
|
|
29
|
-
```
|
|
25
|
+
## Use it
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
Install the CLI. The package is `fest-gateway`; the command it installs is
|
|
28
|
+
`fest`, because plain `fest` was already taken on npm.
|
|
33
29
|
|
|
34
30
|
```bash
|
|
35
|
-
npm install -g fest-gateway
|
|
36
|
-
|
|
37
|
-
fest login --server http://fest.corp:8787 # opens a browser, stores a token in ~/.fest
|
|
38
|
-
fest claude # runs `claude`, env set up for you
|
|
39
|
-
fest whoami # what's logged in, and whether it's still live
|
|
31
|
+
npm install -g fest-gateway
|
|
40
32
|
```
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
binary it installs is `fest`. Without installing anything, `npx fest-gateway
|
|
44
|
-
login …` does the same job.
|
|
45
|
-
|
|
46
|
-
From a clone of this repo the CLI runs straight off the TypeScript instead:
|
|
47
|
-
`npm run cli -- login …` (note the `--`), or `node server/bin/fest.ts login …`.
|
|
48
|
-
|
|
49
|
-
Or without Docker:
|
|
34
|
+
Sign in to your team's gateway, then start a session:
|
|
50
35
|
|
|
51
36
|
```bash
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
FEST_REQUIRE_IDENTITY=1 node server/bin/fest.ts serve
|
|
37
|
+
fest login --server https://fest.corp.test # opens a browser, stores a token in ~/.fest
|
|
38
|
+
fest claude # runs `claude`, environment set up for you
|
|
55
39
|
```
|
|
56
40
|
|
|
57
|
-
|
|
41
|
+
That's it. `fest claude` spawns the real `claude` binary with the environment
|
|
42
|
+
already pointed at the gateway, on **your own Anthropic subscription** — Fest
|
|
43
|
+
meters the usage and never sees your Anthropic credential at rest.
|
|
58
44
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Max/Team and Fest receives `Authorization: Bearer sk-ant-oat…`. Confirmed both
|
|
62
|
-
by reading the binary and by running it — see
|
|
63
|
-
[docs/PHASE0-RESULTS.md](docs/PHASE0-RESULTS.md).
|
|
45
|
+
If your browser is already signed in to the dashboard, `fest login` is a single
|
|
46
|
+
approval click; otherwise it shows the gateway's login screen first.
|
|
64
47
|
|
|
65
|
-
|
|
66
|
-
`ANTHROPIC_BASE_URL`. So Fest **forwards and forgets**: it never stores,
|
|
67
|
-
refreshes or holds a subscription credential. That is a genuine security
|
|
68
|
-
advantage over any "store the team's key" design, not just a side effect.
|
|
69
|
-
|
|
70
|
-
## Two things that will bite you
|
|
48
|
+
Other commands:
|
|
71
49
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
subscriptions onto a server-held key, and the failure is invisible.
|
|
78
|
-
|
|
79
|
-
**2. This is supported-by-absence, not by design.** There is no *documented*
|
|
80
|
-
path for relaying a subscription bearer through a third-party gateway. It works
|
|
81
|
-
because no guard exists. Treat it as a version-pinned dependency, and settle the
|
|
82
|
-
policy question with Anthropic before a team-wide rollout.
|
|
50
|
+
```bash
|
|
51
|
+
fest whoami # what's logged in, and whether the token is still live
|
|
52
|
+
fest logout # forget the local token (does not revoke it server-side)
|
|
53
|
+
fest claude gw # force org credentials + the gateway's extra models
|
|
54
|
+
```
|
|
83
55
|
|
|
84
|
-
|
|
85
|
-
re-runs both load-bearing Phase 0 experiments against the installed release and
|
|
86
|
-
refuses the rollout if either has changed. See [docs/CANARY.md](docs/CANARY.md);
|
|
87
|
-
verdicts are recorded per version in `docs/canary-history.jsonl`.
|
|
56
|
+
Without installing anything, `npx fest-gateway login …` does the same job.
|
|
88
57
|
|
|
89
|
-
|
|
90
|
-
`claude gateway --help`) with central metering, pricing and managed policies. It
|
|
91
|
-
authenticates via OIDC and holds provider credentials itself, so it cannot do
|
|
92
|
-
subscription pass-through — but if that requirement ever softens, it is the
|
|
93
|
-
supported product.
|
|
58
|
+
### If your operator hasn't set up OAuth
|
|
94
59
|
|
|
95
|
-
|
|
60
|
+
They can mint you a token by hand instead, and you point Claude Code at it
|
|
61
|
+
directly:
|
|
96
62
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
- **`cache_control` forwarded verbatim.** Stripping it silently destroys prompt
|
|
101
|
-
caching and inflates every developer's token bill.
|
|
102
|
-
- **Metadata only.** Token counts, models, latency, status — never prompt or
|
|
103
|
-
completion content.
|
|
104
|
-
- **No credential is persistable.** Not by policy, by construction: there is no
|
|
105
|
-
store to put one in. Only fingerprints, enforced by tests.
|
|
106
|
-
|
|
107
|
-
## Layout
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
server/bin/fest.ts CLI: serve | migrate | token | admin | seed |
|
|
111
|
-
login | whoami | claude | logout
|
|
112
|
-
server/pipeline/ passthrough (byte-for-byte) — the subscription path
|
|
113
|
-
server/http/ sse parser, tee, header discipline, errors, routing
|
|
114
|
-
server/store/ SQLite schema, write path, identity tokens
|
|
115
|
-
server/usage/ accumulator, lean pricing, nullable cost algebra
|
|
116
|
-
server/secret/ credential classification + redaction
|
|
117
|
-
server/auth/oauth.ts Google/GitHub provider construction
|
|
118
|
-
server/api/oauth.ts /api/auth/oauth/* and /api/auth/identity
|
|
119
|
-
cli/ the developer half of the CLI — no DB access, ever.
|
|
120
|
-
login (loopback OAuth flow) | whoami | claude | logout,
|
|
121
|
-
and the ~/.fest config they share
|
|
122
|
-
shared/types.ts the contracts both halves agree on
|
|
123
|
-
shared/demotion-vars.ts env vars that silently kill subscription auth
|
|
124
|
-
tools/capture-server.ts Phase 0 diagnostic (throwaway)
|
|
125
|
-
docs/PHASE0.md the gating experiment runbook
|
|
126
|
-
docs/CLI-AUTH.md OAuth setup and the fest login/whoami/claude flow
|
|
127
|
-
test/ node --test
|
|
63
|
+
```bash
|
|
64
|
+
env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN \
|
|
65
|
+
ANTHROPIC_BASE_URL=https://fest.corp.test/t/<token> claude
|
|
128
66
|
```
|
|
129
67
|
|
|
130
|
-
|
|
68
|
+
> **Never set `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN` yourself.** Either
|
|
69
|
+
> one silently drops you off your own subscription onto whatever credential the
|
|
70
|
+
> server holds. `fest claude` clears them for you; the raw form above does it
|
|
71
|
+
> with `env -u`.
|
|
131
72
|
|
|
132
|
-
|
|
133
|
-
and cache writes; context size is the sum. Folding cache reads into input is
|
|
134
|
-
an order-of-magnitude error on a cache-heavy agent workload — and Claude Code
|
|
135
|
-
is one (a trivial `-p` call here showed ~16k cache reads and ~12k one-hour
|
|
136
|
-
cache writes).
|
|
137
|
-
- **`null` cost means unavailable, never zero.** A subscription request is real
|
|
138
|
-
usage with *no org spend*; an unknown model is unpriced, not free. Rollups
|
|
139
|
-
therefore carry a priced sum plus `unpriced_requests` and
|
|
140
|
-
`subscription_requests` separately, so a total renders honestly as
|
|
141
|
-
`$12.3456 (+3 n/a)`.
|
|
142
|
-
- **For a subscription developer, quota is the scarce resource, not dollars.**
|
|
143
|
-
Anthropic returns 5h/7d utilisation on every response, so that is what the
|
|
144
|
-
dashboard shows rather than an invented dollar figure.
|
|
73
|
+
---
|
|
145
74
|
|
|
146
|
-
##
|
|
75
|
+
## Run it
|
|
147
76
|
|
|
148
|
-
|
|
149
|
-
being exact about what that means rather than reassuring.
|
|
150
|
-
|
|
151
|
-
**Fest sees everything, because it has to.** A request body arrives at this
|
|
152
|
-
process in full: prompts, file contents you asked Claude about, tool results,
|
|
153
|
-
the lot. That is unavoidable for anything sitting on the wire, and no wording
|
|
154
|
-
changes it.
|
|
77
|
+
### Getting started
|
|
155
78
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
how many tokens in each of the four buckets, latency, HTTP status, error type,
|
|
159
|
-
and the session id Claude Code already sends. There is no column anywhere in
|
|
160
|
-
the schema for prompt or completion text — not disabled, absent — so "turn off
|
|
161
|
-
content capture" is not a setting that could be misconfigured.
|
|
79
|
+
An owner account must exist before Fest will serve on anything but loopback, so
|
|
80
|
+
that comes first:
|
|
162
81
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
secret-shaped strings.
|
|
82
|
+
```bash
|
|
83
|
+
docker compose run --rm fest admin create you@corp.test # password shown once
|
|
84
|
+
docker compose up -d
|
|
85
|
+
```
|
|
168
86
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
per-developer detail.
|
|
87
|
+
Then either let developers self-serve with `fest login` (configure OAuth below),
|
|
88
|
+
or mint tokens for them:
|
|
172
89
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
traffic, enforced in the query layer rather than in the UI.
|
|
90
|
+
```bash
|
|
91
|
+
docker compose run --rm fest token create dev@corp.test laptop # shown once
|
|
92
|
+
```
|
|
177
93
|
|
|
178
|
-
|
|
94
|
+
Put Fest behind your own TLS proxy and set `FEST_SECURE_COOKIES=1` when you do:
|
|
95
|
+
the server only ever sees plain HTTP and cannot detect this for itself.
|
|
179
96
|
|
|
180
|
-
|
|
181
|
-
dependencies — Node runs the TypeScript directly — so it is Node plus this
|
|
182
|
-
repository.
|
|
97
|
+
### Accounts
|
|
183
98
|
|
|
184
|
-
The dashboard needs a sign-in: scrypt passwords, an opaque session cookie
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
`
|
|
188
|
-
|
|
99
|
+
The dashboard needs a sign-in: scrypt passwords, an opaque session cookie hashed
|
|
100
|
+
at rest, an origin check on every mutating endpoint, and an audit log of
|
|
101
|
+
administrative actions. Accounts are granted from the host with `fest admin
|
|
102
|
+
create` — there is no self-registration and no email reset, because a gateway
|
|
103
|
+
should not need mail credentials to run.
|
|
189
104
|
|
|
190
105
|
Before anyone has run `fest admin create`, Fest serves the dashboard **open on
|
|
191
106
|
loopback and refuses to start on any other interface**. A single-developer trial
|
|
192
107
|
needs no setup, and "bound it to 0.0.0.0 and forgot the password" cannot happen
|
|
193
108
|
quietly.
|
|
194
109
|
|
|
195
|
-
|
|
196
|
-
|
|
110
|
+
```bash
|
|
111
|
+
docker compose run --rm fest admin create <email> [--role owner|admin|member]
|
|
112
|
+
docker compose run --rm fest admin list | admin passwd <email> | admin disable <email>
|
|
113
|
+
docker compose run --rm fest token list | token revoke <id>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Configuration
|
|
197
117
|
|
|
198
118
|
| | |
|
|
199
119
|
| --- | --- |
|
|
@@ -201,29 +121,28 @@ the server only ever sees plain HTTP and cannot detect this for itself.
|
|
|
201
121
|
| `FEST_DB`, `FEST_USAGE_LOG` | SQLite path, and the greppable JSONL trail. |
|
|
202
122
|
| `FEST_REQUIRE_IDENTITY` | refuse unattributed requests. Off by default; **on** for a team. |
|
|
203
123
|
| `FEST_SECURE_COOKIES` | set behind HTTPS. |
|
|
204
|
-
| `FEST_ROUTES` | routing table path. Absent means everything passes through. |
|
|
124
|
+
| `FEST_ROUTES` | routing table path. Absent means everything passes through. See [docs/ROUTING.md](docs/ROUTING.md). |
|
|
205
125
|
| `FEST_UPSTREAM_BASE_URL`, `FEST_LOG_LEVEL` | |
|
|
206
126
|
| `FEST_PRICING_REFRESH` | set `0` to never fetch prices. Rates then come only from the vendored snapshot, which is always sufficient. |
|
|
207
127
|
| `FEST_PRICING_URL` | internal mirror of litellm's price file. |
|
|
128
|
+
| `FEST_PUBLIC_URL` | base URL Fest is reachable at. Builds the OAuth redirect URI, and its path sets the mount point. Defaults to `http://<host>:<port>`. |
|
|
129
|
+
| `FEST_BASE_PATH` | mount path, if Fest is not at the root of its origin. Defaults to the path of `FEST_PUBLIC_URL`, so setting that is usually enough. |
|
|
208
130
|
| `FEST_GOOGLE_CLIENT_ID`, `FEST_GOOGLE_CLIENT_SECRET` | Google OAuth, for `fest login` and the dashboard. Absent means Google sign-in is off. |
|
|
209
131
|
| `FEST_GITHUB_CLIENT_ID`, `FEST_GITHUB_CLIENT_SECRET` | GitHub OAuth, same idea. |
|
|
210
132
|
| `FEST_ALLOWED_EMAIL_DOMAINS` | comma-separated. **Required to enable OAuth at all** — empty refuses every OAuth login rather than allowing any Google/GitHub account. |
|
|
211
|
-
| `
|
|
212
|
-
| `FEST_BASE_PATH` | mount path, if Fest is not at the root of its origin. Defaults to the path of `FEST_PUBLIC_URL`, so setting that is usually enough. |
|
|
133
|
+
| `FEST_DASHBOARD_URL` | **dev only.** Where the dashboard is when it isn't this server; `npm run dev` puts it on Vite's port. Leave unset in production. |
|
|
213
134
|
|
|
214
|
-
|
|
215
|
-
`fest login`'s loopback flow works.
|
|
135
|
+
For the full OAuth setup, see [docs/CLI-AUTH.md](docs/CLI-AUTH.md).
|
|
216
136
|
|
|
217
|
-
### Behind
|
|
137
|
+
### Behind a reverse proxy, on a path
|
|
218
138
|
|
|
219
|
-
Fest can be mounted under a path rather than on its own hostname
|
|
220
|
-
`
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
against it.
|
|
139
|
+
Fest can be mounted under a path rather than on its own hostname. Set
|
|
140
|
+
`FEST_PUBLIC_URL` to the full URL including that path and Fest takes the mount
|
|
141
|
+
point from it: the dashboard's `<base href>` is rewritten to match, and the
|
|
142
|
+
OAuth redirect URI is built against it.
|
|
224
143
|
|
|
225
144
|
```caddyfile
|
|
226
|
-
|
|
145
|
+
fest.corp.test {
|
|
227
146
|
handle_path /fest/* {
|
|
228
147
|
reverse_proxy 127.0.0.1:8787 {
|
|
229
148
|
# SSE: /api/live is a long-lived event stream, and a buffering
|
|
@@ -235,40 +154,172 @@ lastlight.nearform.dev {
|
|
|
235
154
|
```
|
|
236
155
|
|
|
237
156
|
```bash
|
|
238
|
-
FEST_PUBLIC_URL=https://
|
|
157
|
+
FEST_PUBLIC_URL=https://fest.corp.test/fest
|
|
239
158
|
FEST_SECURE_COOKIES=1
|
|
240
159
|
```
|
|
241
160
|
|
|
242
161
|
`handle_path` strips the `/fest` prefix before proxying. A plain `handle` +
|
|
243
|
-
`reverse_proxy`, which does not strip it, works too — Fest removes its own
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
162
|
+
`reverse_proxy`, which does not strip it, works too — Fest removes its own mount
|
|
163
|
+
path from an incoming request when it is still there, so either spelling routes.
|
|
164
|
+
Caddy passes the original `Host` upstream by default, which the CSRF origin
|
|
165
|
+
check needs; on nginx that is `proxy_set_header Host $host`, plus
|
|
247
166
|
`proxy_buffering off` for the event stream.
|
|
248
167
|
|
|
249
168
|
The registered OAuth redirect URI must include the path —
|
|
250
|
-
`https://
|
|
251
|
-
|
|
252
|
-
(`fest login --server https://lastlight.nearform.dev/fest`).
|
|
169
|
+
`https://fest.corp.test/fest/api/auth/oauth/google/callback`. Developers point
|
|
170
|
+
both Claude Code and the CLI at the full prefixed URL.
|
|
253
171
|
|
|
254
|
-
|
|
172
|
+
---
|
|
255
173
|
|
|
256
|
-
|
|
257
|
-
|
|
174
|
+
## How it works
|
|
175
|
+
|
|
176
|
+
### Why this is possible
|
|
177
|
+
|
|
178
|
+
Claude Code's inference client attaches the subscription OAuth bearer with **no
|
|
179
|
+
host check** against `ANTHROPIC_BASE_URL`. Point it at Fest while logged in with
|
|
180
|
+
Max/Team and Fest receives `Authorization: Bearer sk-ant-oat…`. Confirmed both by
|
|
181
|
+
reading the binary and by running it — see
|
|
182
|
+
[docs/PHASE0-RESULTS.md](docs/PHASE0-RESULTS.md).
|
|
258
183
|
|
|
259
|
-
|
|
184
|
+
Token refresh happens client-side against `api.anthropic.com`, outside
|
|
185
|
+
`ANTHROPIC_BASE_URL`. So Fest **forwards and forgets**: it never stores,
|
|
186
|
+
refreshes or holds a subscription credential. That is a genuine security
|
|
187
|
+
advantage over any "store the team's key" design, not a side effect.
|
|
188
|
+
|
|
189
|
+
### Two things that will bite you
|
|
190
|
+
|
|
191
|
+
**1. `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` silently kill the
|
|
192
|
+
subscription.** Claude Code demotes off OAuth if *any* Anthropic-issued
|
|
193
|
+
credential is present — including an `apiKeyHelper`. So Fest's identity token
|
|
194
|
+
never goes in those variables; it rides in the URL path prefix or a custom
|
|
195
|
+
header. A design that ignores this moves a whole team off their subscriptions
|
|
196
|
+
onto a server-held key, invisibly.
|
|
197
|
+
|
|
198
|
+
**2. This is supported-by-absence, not by design.** There is no *documented*
|
|
199
|
+
path for relaying a subscription bearer through a third-party gateway. It works
|
|
200
|
+
because no guard exists. Treat it as a version-pinned dependency, and settle the
|
|
201
|
+
policy question with Anthropic before a team-wide rollout.
|
|
202
|
+
|
|
203
|
+
That dependency is enforced rather than remembered: `npm run canary` re-runs both
|
|
204
|
+
load-bearing Phase 0 experiments against the installed Claude Code release and
|
|
205
|
+
refuses the rollout if either has changed. See [docs/CANARY.md](docs/CANARY.md);
|
|
206
|
+
verdicts are recorded per version in `docs/canary-history.jsonl`.
|
|
207
|
+
|
|
208
|
+
Worth knowing: Anthropic ships its own self-hostable `claude gateway` with
|
|
209
|
+
central metering, pricing and managed policies. It authenticates via OIDC and
|
|
210
|
+
holds provider credentials itself, so it cannot do subscription pass-through —
|
|
211
|
+
but if that requirement ever softens, it is the supported product.
|
|
212
|
+
|
|
213
|
+
### What Fest can see, and what it keeps
|
|
214
|
+
|
|
215
|
+
This is a gateway every prompt a team writes passes through, so it is worth being
|
|
216
|
+
exact rather than reassuring.
|
|
217
|
+
|
|
218
|
+
**Fest sees everything, because it has to.** A request body arrives at this
|
|
219
|
+
process in full: prompts, file contents, tool results, the lot. That is
|
|
220
|
+
unavoidable for anything sitting on the wire.
|
|
221
|
+
|
|
222
|
+
**Fest keeps none of it.** Request bodies are relayed as opaque bytes and never
|
|
223
|
+
parsed for storage. What is written down is metadata: who, when, which model, how
|
|
224
|
+
many tokens in each of the four buckets, latency, HTTP status, error type, and
|
|
225
|
+
the session id Claude Code already sends. There is no column anywhere in the
|
|
226
|
+
schema for prompt or completion text — not disabled, *absent* — so "turn off
|
|
227
|
+
content capture" is not a setting that could be misconfigured.
|
|
228
|
+
|
|
229
|
+
**No credential is persistable, by construction rather than by policy.** A
|
|
230
|
+
subscription bearer is forwarded and forgotten; there is no table to put one in.
|
|
231
|
+
What is stored of a Fest identity token or a dashboard password is a hash. The
|
|
232
|
+
leak tests grep the entire database, every log line and every API response for
|
|
233
|
+
secret-shaped strings.
|
|
234
|
+
|
|
235
|
+
**An admin can see who used what, and when.** That is the point of a team
|
|
236
|
+
gateway, and developers pointing their editors at it should be told so plainly.
|
|
237
|
+
They cannot see each other: a `member` account sees only its own traffic,
|
|
238
|
+
enforced in the query layer rather than in the UI.
|
|
239
|
+
|
|
240
|
+
**Raw per-request rows age out after 30 days.** The hourly rollups, which are
|
|
241
|
+
aggregate, are kept for 400, so a year of trends does not require a year of
|
|
242
|
+
per-developer detail.
|
|
243
|
+
|
|
244
|
+
### Design commitments
|
|
245
|
+
|
|
246
|
+
- **Byte-for-byte pass-through.** Subscription tokens are validated against
|
|
247
|
+
request shape, so the body is relayed as opaque bytes — never parsed and
|
|
248
|
+
re-serialised. No model rewriting or prompt shaping on that path.
|
|
249
|
+
- **`cache_control` forwarded verbatim.** Stripping it silently destroys prompt
|
|
250
|
+
caching and inflates every developer's token bill.
|
|
251
|
+
- **The four token buckets are disjoint.** `input_tokens` excludes cache reads
|
|
252
|
+
and cache writes; context size is the sum. Folding cache reads into input is an
|
|
253
|
+
order-of-magnitude error on a cache-heavy agent workload — and Claude Code is
|
|
254
|
+
one.
|
|
255
|
+
- **`null` cost means unavailable, never zero.** A subscription request is real
|
|
256
|
+
usage with *no org spend*; an unknown model is unpriced, not free. Totals
|
|
257
|
+
therefore render honestly as `$12.3456 (+3 n/a)`. See
|
|
258
|
+
[docs/PRICING.md](docs/PRICING.md).
|
|
259
|
+
- **For a subscription developer, quota is the scarce resource, not dollars.**
|
|
260
|
+
Anthropic returns 5h/7d utilisation on every response, so that is what the
|
|
261
|
+
dashboard shows rather than an invented dollar figure.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Develop it
|
|
266
|
+
|
|
267
|
+
Node >= 22.18. There is **no build step for the server** — Node runs the
|
|
268
|
+
TypeScript directly via native type stripping. Only the dashboard is built, and
|
|
269
|
+
only the published npm package is compiled (Node refuses to strip types under
|
|
270
|
+
`node_modules`).
|
|
260
271
|
|
|
261
272
|
```bash
|
|
262
|
-
npm
|
|
263
|
-
npm run
|
|
264
|
-
npm
|
|
265
|
-
npm run typecheck
|
|
266
|
-
npm run
|
|
267
|
-
npm run
|
|
273
|
+
npm install
|
|
274
|
+
npm run dev # gateway (node --watch) + dashboard (Vite, HMR), one terminal
|
|
275
|
+
npm test # node --test
|
|
276
|
+
npm run typecheck # tsc --noEmit, root then web/
|
|
277
|
+
npm run demo # synthetic traffic in a scratch database, then dev
|
|
278
|
+
npm run canary # version gate: re-run before rolling out a Claude Code release
|
|
268
279
|
```
|
|
269
280
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
281
|
+
Both `npm test` and `npm run typecheck` must be clean before committing. From a
|
|
282
|
+
clone the CLI runs straight off the TypeScript: `npm run cli -- login …` (note
|
|
283
|
+
the `--`).
|
|
284
|
+
|
|
285
|
+
### Layout
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
server/bin/fest.ts CLI entrypoint: serve | migrate | token | admin | seed |
|
|
289
|
+
login | whoami | claude | logout
|
|
290
|
+
server/pipeline/ passthrough (byte-for-byte) — the subscription path
|
|
291
|
+
server/http/ sse parser, tee, header discipline, errors, routing
|
|
292
|
+
server/store/ SQLite schema, write path, identity tokens
|
|
293
|
+
server/usage/ accumulator, pricing, nullable cost algebra
|
|
294
|
+
server/secret/ credential classification + redaction
|
|
295
|
+
server/auth/, server/api/ sessions, OAuth, the dashboard's JSON API
|
|
296
|
+
cli/ the developer half of the CLI — no DB access, ever
|
|
297
|
+
shared/ contracts both halves agree on, and the env vars that
|
|
298
|
+
silently kill subscription auth
|
|
299
|
+
web/ the dashboard (Vite + React) — the only build step
|
|
300
|
+
tools/ dev runner, canary, Phase 0 capture, price sync
|
|
301
|
+
test/ node --test, flat
|
|
274
302
|
```
|
|
303
|
+
|
|
304
|
+
There is one `CLAUDE.md` per top-level folder with the conventions that apply
|
|
305
|
+
inside it — read the relevant one before working there.
|
|
306
|
+
|
|
307
|
+
### Docs
|
|
308
|
+
|
|
309
|
+
| | |
|
|
310
|
+
| --- | --- |
|
|
311
|
+
| [CLI-AUTH.md](docs/CLI-AUTH.md) | OAuth setup and the `fest login` flow end to end |
|
|
312
|
+
| [ROUTING.md](docs/ROUTING.md) | the routing table format and the substitute path |
|
|
313
|
+
| [PRICING.md](docs/PRICING.md) | where rates come from, and spend vs. value |
|
|
314
|
+
| [POSTURES.md](docs/POSTURES.md) | subscription vs. key posture |
|
|
315
|
+
| [CANARY.md](docs/CANARY.md) | the version-upgrade gate |
|
|
316
|
+
| [PHASE0.md](docs/PHASE0.md) · [PHASE0-RESULTS.md](docs/PHASE0-RESULTS.md) | the gating experiment, and what it found |
|
|
317
|
+
| [CLIENT-GATEWAY-PROTOCOL.md](docs/CLIENT-GATEWAY-PROTOCOL.md) | what Claude Code actually sends |
|
|
318
|
+
| [FRONTEND.md](docs/FRONTEND.md) | the dashboard's screens and data flow |
|
|
319
|
+
|
|
320
|
+
### Releasing
|
|
321
|
+
|
|
322
|
+
Bump `version` in `package.json`, then publish a GitHub Release tagged
|
|
323
|
+
`v<version>`. CI publishes to npm over trusted publishing (OIDC) — there is no
|
|
324
|
+
token in the repository — and refuses to publish if the tag and `package.json`
|
|
325
|
+
disagree.
|
package/dist/cli/login.js
CHANGED
|
@@ -100,8 +100,14 @@ export async function runLogin(opts) {
|
|
|
100
100
|
});
|
|
101
101
|
try {
|
|
102
102
|
const callbackUrl = `http://127.0.0.1:${port}/callback`;
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
// Not the provider's start URL directly. This asks the GATEWAY first, which
|
|
104
|
+
// can see the browser's session cookie where this process cannot: already
|
|
105
|
+
// signed in means one approval click instead of a provider round trip, and
|
|
106
|
+
// if there is no session it hands off to the dashboard's own login screen —
|
|
107
|
+
// which is why `--provider` is not passed here. It still records which
|
|
108
|
+
// provider was asked for in the stored config.
|
|
109
|
+
const startUrl = `${serverUrl}/api/auth/cli/authorize?cli_redirect_uri=${encodeURIComponent(callbackUrl)}`;
|
|
110
|
+
process.stdout.write("Opening your browser to authorise this CLI...\n");
|
|
105
111
|
process.stdout.write(`If it doesn't open, visit:\n ${startUrl}\n`);
|
|
106
112
|
(opts.openBrowser ?? open)(startUrl).catch(() => { });
|
|
107
113
|
const timeout = new Promise((resolve) => {
|
package/dist/cli/login.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../cli/login.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../cli/login.ts"],"names":[],"mappings":"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"}
|
package/dist/server/api/auth.js
CHANGED
|
@@ -11,6 +11,7 @@ import { originAllowed, clientIp, sessionFromRequest } from "../auth/guard.js";
|
|
|
11
11
|
import { recordAudit } from "../store/audit.js";
|
|
12
12
|
import { log } from "../log.js";
|
|
13
13
|
import { handleOauth } from "./oauth.js";
|
|
14
|
+
import { handleCliAuth } from "./cli-auth.js";
|
|
14
15
|
import { configuredProviders } from "../auth/oauth.js";
|
|
15
16
|
const MAX_BODY_BYTES = 4 * 1024;
|
|
16
17
|
function json(res, status, body, extra = {}) {
|
|
@@ -88,6 +89,11 @@ export async function handleAuth(req, res, path, deps, session) {
|
|
|
88
89
|
if (await handleOauth(req, res, path, { store: deps.store, orgId: deps.orgId, config: deps.config })) {
|
|
89
90
|
return true;
|
|
90
91
|
}
|
|
92
|
+
// Before the method and origin gates below: `authorize` is a GET that renders
|
|
93
|
+
// a page, and `approve` applies both checks itself for its own reasons.
|
|
94
|
+
if (await handleCliAuth(req, res, path, { store: deps.store, orgId: deps.orgId, config: deps.config }, session)) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
91
97
|
if (path === "/api/auth/me" && method === "GET") {
|
|
92
98
|
json(res, 200, {
|
|
93
99
|
// Not 401: "am I signed in" is a question an anonymous caller is allowed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/api/auth.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/api/auth.ts"],"names":[],"mappings":"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"}
|