Skip to content

Store one API key per backend and let /typesafe login take a backend - #34

Merged
DevMortimer merged 4 commits into
mainfrom
carvel/login-per-backend
Oct 24, 2026
Merged

DevMortimer merged 4 commits into
mainfrom
carvel/login-per-backend

Conversation

@DevMortimer

@DevMortimer DevMortimer commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

A backend's key could only come from its environment variable; only TypeSafe had /typesafe login. The store held a single TypeSafe key because a login verified against api.typesafe.ai.

Now the store keeps one key per backend — a registry name, or an endpoint's keyEnv — and keySituation, authState, and ensureApiKey read it for every backend. The environment variable still wins when it is set, and a key stored for one backend is never read for another.

/typesafe login [backend] prompts with that backend's name, proves the key, and saves it under that backend. The proof differs because a public model list accepts any key: TypeSafe and Liquid AI are proved with their model list, while SubQ, OpenRouter, and Command Code are proved with one judge request. /typesafe logout [backend] removes one key and leaves the others; with no backend named, both commands act on the session's own backend.

The old { "apiKey": "..." } file reads as the TypeSafe key and is rewritten in the new shape on the next save.

This changes a public export: usesTypesafeKey is gone, since every backend now has a login store. Nothing else in the public API changed. A minor release fits: 0.12.0.

Verification: npm run check passes, 186 tests. New tests cover two backends kept apart, an endpoint keyed by its keyEnv, the legacy file, clearing one key while keeping another, and an OpenRouter login proved with one request and stored under its own name. ask now sets its deadline with a real timer, cleared when the ask settles, instead of AbortSignal.timeout: that signal's timer is unref'd, so on Node 22.19 a deadline that was the only pending work never fired and the earlier CI run reported the test as never settling.

… backend

Every backend's key came from its own environment variable, and only TypeSafe could be stored, because the store held one TypeSafe key. Now the store keeps one key per backend — a registry name, or an endpoint's keyEnv — and keySituation, authState, and ensureApiKey read it for every backend. The environment still wins.

/typesafe login [backend] prompts with that backend's name, proves the key before saving, and stores it under that backend. A backend whose model list checks the key is proved with the list; a public list accepts any key, so SubQ, OpenRouter, and Command Code are proved with one judge request instead. /typesafe logout [backend] removes one key and leaves the others.

The store reads the old {apiKey} shape as the TypeSafe key and rewrites it on the next save. A key stored for one backend is never read for another.
AbortSignal.timeout's timer is unref'd, so a call whose only pending work was
the deadline never settled: node:test on Node 22.19.0 reported the ask promise as
'Promise resolution is still pending but the event loop has already resolved'
(CI run 39945731438), while Node 24 passed on timing alone. The deadline is now
a ref'd timer, cleared when the ask settles, so timeoutMs bounds the call on
every supported Node version and the assertion stands unchanged.
One stored key per judgment backend, /typesafe login and logout taking a backend
name, and the removal of the usesTypesafeKey export: a minor bump, per
CONTRIBUTING. Also records the store's downgrade behaviour.
/typesafe login asks for the named backend's key, so the prompt must name that
backend; only the TypeSafe default was asserted.
@DevMortimer
DevMortimer force-pushed the carvel/login-per-backend branch from d47cb35 to 0bcfa25 Compare October 24, 2026 02:14
@DevMortimer
DevMortimer merged commit 3d21cbb into main Oct 24, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant