byok-llm 1.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 ADDED
@@ -0,0 +1,242 @@
1
+ # byok-llm
2
+
3
+ Unified API key management for AI-powered apps. Zero dependencies.
4
+
5
+ Resolve, store, validate, and manage API keys across **8 AI providers** with a single interface. Built for CLI tools, agentic apps, and any Node.js project that needs to work with multiple AI services.
6
+
7
+ ```bash
8
+ npm install byok-llm
9
+ ```
10
+
11
+ ## Why
12
+
13
+ Every AI-powered app needs API keys. Most hardcode `process.env.OPENAI_API_KEY` and call it a day. But real apps need:
14
+
15
+ - **Multiple providers** — Anthropic, OpenAI, Google, Groq, OpenRouter, xAI, Mistral, DeepSeek
16
+ - **Fallback chains** — if one provider is down, try the next
17
+ - **Key validation** — catch bad keys before they cause 401s at runtime
18
+ - **User setup** — a wizard that walks users through key configuration
19
+ - **Secure storage** — file permissions, never logged, XDG-compliant paths
20
+ - **No lock-in** — returns raw keys/headers/URLs, works with any HTTP client or SDK
21
+
22
+ `byok-ai` does all of this in a single zero-dependency package.
23
+
24
+ ## Quick Start
25
+
26
+ ```typescript
27
+ import { init } from 'byok-llm';
28
+
29
+ // Finds a configured provider, or runs the setup wizard
30
+ const provider = await init({
31
+ providers: ['anthropic', 'openai', 'openrouter'],
32
+ appName: 'my-cli-tool',
33
+ });
34
+
35
+ if (provider) {
36
+ // provider.key, provider.headers, provider.baseUrl — ready to use
37
+ const response = await fetch(`${provider.baseUrl}/v1/messages`, {
38
+ method: 'POST',
39
+ headers: { ...provider.headers, 'Content-Type': 'application/json' },
40
+ body: JSON.stringify({
41
+ model: 'claude-sonnet-4-20250514',
42
+ max_tokens: 100,
43
+ messages: [{ role: 'user', content: 'Hello!' }],
44
+ }),
45
+ });
46
+ }
47
+ ```
48
+
49
+ ## Works with Any SDK
50
+
51
+ ```typescript
52
+ import OpenAI from 'openai';
53
+ import { getOpenAICompatibleConfig } from 'byok-llm';
54
+
55
+ // Works with OpenRouter, Groq, xAI, Mistral, DeepSeek — anything OpenAI-compatible
56
+ const client = new OpenAI(await getOpenAICompatibleConfig('groq'));
57
+ ```
58
+
59
+ ## Key Resolution
60
+
61
+ Keys are resolved from multiple sources, highest priority first:
62
+
63
+ 1. **Runtime options** — passed directly in code
64
+ 2. **Environment variables** — `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc.
65
+ 3. **Project config** — `.byokrc.json`, `.byokrc`, `byok.config.json`, or `byok` field in `package.json`
66
+ 4. **User config** — `~/.config/byok-ai/config.json`
67
+ 5. **Stored keys** — `~/.config/byok-ai/keys.json` (0600 permissions)
68
+
69
+ ```typescript
70
+ import { resolveKey } from 'byok-llm';
71
+
72
+ const key = await resolveKey('anthropic');
73
+ // Checks all layers, returns { key, source, providerId } or null
74
+ ```
75
+
76
+ ## Fallback Chains
77
+
78
+ Try multiple providers in order, use the first one with a valid key:
79
+
80
+ ```typescript
81
+ import { resolveWithFallback } from 'byok-llm';
82
+
83
+ const provider = await resolveWithFallback(['anthropic', 'openai', 'openrouter']);
84
+ // Returns the first provider that has a key configured
85
+ ```
86
+
87
+ ## Key Validation
88
+
89
+ Validate keys before using them — format check + live API ping:
90
+
91
+ ```typescript
92
+ import { validateKey } from 'byok-llm';
93
+
94
+ const result = await validateKey('openai', 'sk-...');
95
+ // { valid: true } or { valid: false, error: 'Invalid key format' }
96
+ ```
97
+
98
+ Validation is lightweight (hits `/v1/models` or equivalent), times out after 10 seconds, and gracefully falls back to format-only checks if the network is unreachable.
99
+
100
+ ## Setup Wizard
101
+
102
+ Interactive terminal wizard for first-run key configuration:
103
+
104
+ ```typescript
105
+ import { setupWizard } from 'byok-llm';
106
+
107
+ await setupWizard({
108
+ providers: ['anthropic', 'openai', 'openrouter'],
109
+ required: ['anthropic'],
110
+ appName: 'my-app',
111
+ });
112
+ ```
113
+
114
+ The wizard shows already-configured providers, links to docs for getting keys, validates on entry, and stores keys securely.
115
+
116
+ ## Config Files
117
+
118
+ Create a `.byokrc.json` in your project:
119
+
120
+ ```json
121
+ {
122
+ "defaultProvider": "anthropic",
123
+ "fallbackOrder": ["anthropic", "openai", "groq"],
124
+ "providers": {
125
+ "anthropic": {
126
+ "apiKey": "{env:MY_ANTHROPIC_KEY}"
127
+ },
128
+ "openrouter": {
129
+ "baseUrl": "https://openrouter.ai/api/v1"
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ Values support `{env:VAR_NAME}` and `{file:/path/to/key}` placeholders.
136
+
137
+ ## Custom Providers
138
+
139
+ Register any OpenAI-compatible or custom provider:
140
+
141
+ ```typescript
142
+ import { registerProvider, resolveKey } from 'byok-llm';
143
+
144
+ registerProvider({
145
+ id: 'my-ollama',
146
+ name: 'Local Ollama',
147
+ envKeys: ['OLLAMA_API_KEY'],
148
+ baseUrl: 'http://localhost:11434',
149
+ docsUrl: 'https://ollama.ai',
150
+ authStyle: 'bearer',
151
+ openaiCompatible: true,
152
+ });
153
+
154
+ const key = await resolveKey('my-ollama');
155
+ ```
156
+
157
+ ## Status Report
158
+
159
+ Check which providers are configured:
160
+
161
+ ```typescript
162
+ import { printStatus } from 'byok-llm';
163
+
164
+ await printStatus();
165
+ // Prints a colored table of all providers and their status
166
+ ```
167
+
168
+ ## Secure Storage
169
+
170
+ Keys stored via the wizard or `storeKey()` go to `~/.config/byok-ai/keys.json` with **0600 file permissions** (owner read/write only). The directory is created with 0700 permissions. Keys are never logged.
171
+
172
+ ```typescript
173
+ import { storeKey, getKey, removeKey } from 'byok-llm';
174
+
175
+ await storeKey('anthropic', 'sk-ant-...');
176
+ const key = await getKey('anthropic');
177
+ await removeKey('anthropic');
178
+ ```
179
+
180
+ ## Built-in Providers
181
+
182
+ | Provider | ID | Env Variable | Auth Style |
183
+ |----------|-----|-------------|------------|
184
+ | Anthropic | `anthropic` | `ANTHROPIC_API_KEY` | `x-api-key` |
185
+ | OpenAI | `openai` | `OPENAI_API_KEY` | `bearer` |
186
+ | OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | `bearer` |
187
+ | Google Gemini | `google` | `GOOGLE_API_KEY` | `query-param` |
188
+ | Groq | `groq` | `GROQ_API_KEY` | `bearer` |
189
+ | xAI | `xai` | `XAI_API_KEY` | `bearer` |
190
+ | Mistral | `mistral` | `MISTRAL_API_KEY` | `bearer` |
191
+ | DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `bearer` |
192
+
193
+ All providers except Anthropic and Google are OpenAI-SDK-compatible.
194
+
195
+ ## API Reference
196
+
197
+ ### Initialization
198
+ - **`init(options?)`** — All-in-one: load config, resolve key, run wizard if needed
199
+ - **`initConfig(options?)`** — Initialize config cache manually
200
+
201
+ ### Key Resolution
202
+ - **`resolveKey(provider, runtimeKey?)`** — Resolve a key from all layers
203
+ - **`resolveWithFallback(providers?)`** — Try providers in order, return first match
204
+ - **`getConfiguredProviders()`** — List all providers with keys configured
205
+
206
+ ### Validation
207
+ - **`validateKey(provider, key)`** — Format check + API ping
208
+ - **`validateKeyFormat(provider, key)`** — Format check only
209
+ - **`validateAllKeys()`** — Validate all configured keys
210
+
211
+ ### Storage
212
+ - **`storeKey(provider, key)`** — Store a key securely
213
+ - **`getKey(provider)`** — Retrieve a stored key
214
+ - **`removeKey(provider)`** — Delete a stored key
215
+ - **`listStoredKeys()`** — List all stored provider IDs
216
+ - **`clearAllKeys()`** — Delete all stored keys
217
+
218
+ ### Integration Helpers
219
+ - **`getProviderHeaders(provider)`** — Get auth headers for a provider
220
+ - **`getProviderBaseUrl(provider)`** — Get the base URL
221
+ - **`getOpenAICompatibleConfig(provider)`** — Get `{ apiKey, baseURL }` for the OpenAI SDK
222
+
223
+ ### Provider Registry
224
+ - **`registerProvider(definition)`** — Register a custom provider
225
+ - **`getProvider(id)`** — Get a provider definition
226
+ - **`listProviders()`** — List all registered providers
227
+ - **`hasProvider(id)`** — Check if a provider is registered
228
+
229
+ ### Environment
230
+ - **`hasEnvKey(provider)`** — Check if an env var is set
231
+ - **`getEnvKey(provider)`** — Get the env var value
232
+ - **`getEnvVarName(provider)`** — Get the primary env var name
233
+ - **`generateEnvTemplate(providers?)`** — Generate a `.env` template
234
+
235
+ ### UI
236
+ - **`setupWizard(options?)`** — Run the interactive setup wizard
237
+ - **`getStatus(providers?)`** — Get provider statuses as data
238
+ - **`printStatus(providers?)`** — Print colored status to terminal
239
+
240
+ ## License
241
+
242
+ MIT