litellmts-core 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.
Files changed (73) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +266 -0
  3. package/dist/auth/anthropic.d.ts +7 -0
  4. package/dist/auth/anthropic.js +83 -0
  5. package/dist/auth/copilot.d.ts +9 -0
  6. package/dist/auth/copilot.js +138 -0
  7. package/dist/auth/index.d.ts +6 -0
  8. package/dist/auth/index.js +14 -0
  9. package/dist/auth/refresh.d.ts +2 -0
  10. package/dist/auth/refresh.js +54 -0
  11. package/dist/auth/store.d.ts +19 -0
  12. package/dist/auth/store.js +91 -0
  13. package/dist/bin/litellm.d.ts +2 -0
  14. package/dist/bin/litellm.js +45 -0
  15. package/dist/completion.d.ts +24 -0
  16. package/dist/completion.js +15 -0
  17. package/dist/embedding.d.ts +15 -0
  18. package/dist/embedding.js +26 -0
  19. package/dist/handlers/ai21.d.ts +2 -0
  20. package/dist/handlers/ai21.js +87 -0
  21. package/dist/handlers/anthropic.d.ts +2 -0
  22. package/dist/handlers/anthropic.js +85 -0
  23. package/dist/handlers/cohere.d.ts +2 -0
  24. package/dist/handlers/cohere.js +85 -0
  25. package/dist/handlers/copilot.d.ts +2 -0
  26. package/dist/handlers/copilot.js +136 -0
  27. package/dist/handlers/deepinfra.d.ts +2 -0
  28. package/dist/handlers/deepinfra.js +56 -0
  29. package/dist/handlers/gemini.d.ts +2 -0
  30. package/dist/handlers/gemini.js +102 -0
  31. package/dist/handlers/geminiEmbedding.d.ts +2 -0
  32. package/dist/handlers/geminiEmbedding.js +29 -0
  33. package/dist/handlers/getHandler.d.ts +11 -0
  34. package/dist/handlers/getHandler.js +24 -0
  35. package/dist/handlers/index.d.ts +16 -0
  36. package/dist/handlers/index.js +18 -0
  37. package/dist/handlers/mistral.d.ts +2 -0
  38. package/dist/handlers/mistral.js +56 -0
  39. package/dist/handlers/mistralEmbedding.d.ts +2 -0
  40. package/dist/handlers/mistralEmbedding.js +31 -0
  41. package/dist/handlers/ollama.d.ts +2 -0
  42. package/dist/handlers/ollama.js +89 -0
  43. package/dist/handlers/ollamaEmbedding.d.ts +2 -0
  44. package/dist/handlers/ollamaEmbedding.js +36 -0
  45. package/dist/handlers/openai.d.ts +2 -0
  46. package/dist/handlers/openai.js +76 -0
  47. package/dist/handlers/openaiEmbedding.d.ts +2 -0
  48. package/dist/handlers/openaiEmbedding.js +18 -0
  49. package/dist/handlers/openaiLike.d.ts +3 -0
  50. package/dist/handlers/openaiLike.js +22 -0
  51. package/dist/handlers/openaiLikeEmbedding.d.ts +3 -0
  52. package/dist/handlers/openaiLikeEmbedding.js +22 -0
  53. package/dist/handlers/replicate.d.ts +2 -0
  54. package/dist/handlers/replicate.js +98 -0
  55. package/dist/index.d.ts +10 -0
  56. package/dist/index.js +19 -0
  57. package/dist/mappings/openaiLike.d.ts +6 -0
  58. package/dist/mappings/openaiLike.js +190 -0
  59. package/dist/registry.d.ts +15 -0
  60. package/dist/registry.js +30 -0
  61. package/dist/types.d.ts +104 -0
  62. package/dist/types.js +2 -0
  63. package/dist/utils/combinePrompts.d.ts +10 -0
  64. package/dist/utils/combinePrompts.js +19 -0
  65. package/dist/utils/encoders.d.ts +2 -0
  66. package/dist/utils/encoders.js +9 -0
  67. package/dist/utils/getUnixTimestamp.d.ts +1 -0
  68. package/dist/utils/getUnixTimestamp.js +6 -0
  69. package/dist/utils/sse.d.ts +12 -0
  70. package/dist/utils/sse.js +41 -0
  71. package/dist/utils/toUsage.d.ts +12 -0
  72. package/dist/utils/toUsage.js +35 -0
  73. package/package.json +63 -0
package/README.md ADDED
@@ -0,0 +1,266 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/madkoding/litellmTS/main/.github/banner.png" alt="LiteLLM.ts" width="600"/>
3
+ </p>
4
+
5
+ <p align="center">
6
+ <strong>Unified TypeScript interface for 45+ LLM providers</strong><br>
7
+ One API. Every model. Zero boilerplate.
8
+ </p>
9
+
10
+ <p align="center">
11
+ <a href="https://github.com/madkoding/litellmTS/blob/main/LICENSE">
12
+ <img src="https://img.shields.io/badge/license-GPLv3-blue.svg" alt="License"/>
13
+ </a>
14
+ <a href="https://github.com/madkoding/litellmTS">
15
+ <img src="https://img.shields.io/github/v/release/madkoding/litellmTS" alt="GitHub Release"/>
16
+ </a>
17
+ <a href="https://nodejs.org/">
18
+ <img src="https://img.shields.io/badge/node-%3E%3D22-brightgreen" alt="Node"/>
19
+ </a>
20
+ </p>
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ ### From GitHub (recommended)
27
+
28
+ Add this to your `package.json`:
29
+
30
+ ```json
31
+ {
32
+ "dependencies": {
33
+ "@litellmts/core": "github:madkoding/litellmTS"
34
+ }
35
+ }
36
+ ```
37
+
38
+ Then install:
39
+
40
+ ```bash
41
+ npm install
42
+ ```
43
+
44
+ ### Alternative — npm (when published)
45
+
46
+ ```bash
47
+ npm install @litellmts/core
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ ```ts
53
+ import { completion } from '@litellmts/core';
54
+
55
+ const response = await completion({
56
+ model: 'gpt-4o-mini',
57
+ messages: [{ role: 'user', content: 'Hello!' }],
58
+ });
59
+
60
+ console.log(response.choices[0].message.content);
61
+ ```
62
+
63
+ Swap providers by changing just the model string:
64
+
65
+ ```ts
66
+ // Same code, different provider:
67
+ await completion({ model: 'claude-sonnet-4-20250514', ... });
68
+ await completion({ model: 'gemini/gemini-2.5-pro', ... });
69
+ await completion({ model: 'groq/llama-3.3-70b', ... });
70
+ await completion({ model: 'deepseek/deepseek-chat', ... });
71
+ ```
72
+
73
+ ## Features
74
+
75
+ - **Unified API** — same `completion()` / `embedding()` for every provider
76
+ - **Streaming** — all providers support `stream: true`
77
+ - **TypeScript first** — full type safety with auto-completion
78
+ - **45+ providers** — from OpenAI to niche OpenAI-compatible APIs
79
+ - **No SDK sprawl** — one dependency replaces 10+ vendor SDKs
80
+ - **CLI auth** — built-in OAuth device flow for GitHub Copilot
81
+ - **Persistent auth store** — `~/.litellm/auth.json`
82
+
83
+ ## Usage
84
+
85
+ ### Non-streaming
86
+
87
+ ```ts
88
+ import { completion } from '@litellmts/core';
89
+
90
+ const response = await completion({
91
+ model: 'gpt-4o-mini',
92
+ messages: [
93
+ { role: 'system', content: 'You are a helpful assistant.' },
94
+ { role: 'user', content: 'What is TypeScript?' },
95
+ ],
96
+ temperature: 0.7,
97
+ max_tokens: 500,
98
+ });
99
+
100
+ console.log(response.choices[0].message.content);
101
+ // { role: 'assistant', content: 'TypeScript is...' }
102
+ console.log(response.usage);
103
+ // { prompt_tokens: 25, completion_tokens: 120, total_tokens: 145 }
104
+ ```
105
+
106
+ ### Streaming
107
+
108
+ ```ts
109
+ const stream = await completion({
110
+ model: 'claude-sonnet-4-20250514',
111
+ messages: [{ role: 'user', content: 'Write a poem' }],
112
+ stream: true,
113
+ });
114
+
115
+ for await (const chunk of stream) {
116
+ process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
117
+ }
118
+ ```
119
+
120
+ ### Embeddings
121
+
122
+ ```ts
123
+ import { embedding } from '@litellmts/core';
124
+
125
+ const result = await embedding({
126
+ model: 'text-embedding-3-small',
127
+ input: 'Hello world',
128
+ });
129
+
130
+ console.log(result.data[0].embedding); // number[]
131
+ ```
132
+
133
+ ### API Keys
134
+
135
+ Keys are read from environment variables by default:
136
+
137
+ ```bash
138
+ export OPENAI_API_KEY=sk-...
139
+ export ANTHROPIC_API_KEY=sk-ant-...
140
+ export GROQ_API_KEY=gsk_...
141
+ ```
142
+
143
+ Or pass them inline:
144
+
145
+ ```ts
146
+ await completion({
147
+ model: 'groq/llama-3.3-70b',
148
+ messages: [],
149
+ apiKey: 'gsk_...',
150
+ });
151
+ ```
152
+
153
+ ### CLI Auth
154
+
155
+ ```bash
156
+ # GitHub Copilot (OAuth device flow)
157
+ npx litellm login copilot
158
+
159
+ # Anthropic (API key prompt)
160
+ npx litellm login anthropic
161
+ ```
162
+
163
+ ## Supported Providers
164
+
165
+ ### Dedicated Handlers
166
+
167
+ | Provider | Prefix | Completion | Streaming | Embedding | API Key Env |
168
+ |---|---|---|---|---|---|
169
+ | OpenAI | `gpt-*`, `openai/` | ✅ | ✅ | ✅ | `OPENAI_API_KEY` |
170
+ | Anthropic | `claude-*` | ✅ | ✅ | ❌ | `ANTHROPIC_API_KEY` |
171
+ | Google Gemini | `gemini/` | ✅ | ✅ | ✅ | `GEMINI_API_KEY` |
172
+ | GitHub Copilot | `copilot/` | ✅ | ✅ | ❌ | (OAuth) |
173
+ | Mistral | `mistral/` | ✅ | ✅ | ✅ | `MISTRAL_API_KEY` |
174
+ | Cohere | `command*` | ✅ | ✅ | ❌ | `COHERE_API_KEY` |
175
+ | DeepInfra | `deepinfra/` | ✅ | ✅ | ❌ | `DEEPINFRA_API_KEY` |
176
+ | Replicate | `replicate/` | ✅ | ✅ | ❌ | `REPLICATE_API_KEY` |
177
+ | AI21 Labs | `j2-*`, `ai21/` | ✅ | ✅ | ❌ | `AI21_API_KEY` |
178
+ | Ollama (local) | `ollama/` | ✅ | ✅ | ✅ | — |
179
+
180
+ ### OpenAI-Compatible (38 providers)
181
+
182
+ | Provider | Prefix | API Key Env |
183
+ |---|---|---|
184
+ | Groq | `groq/` | `GROQ_API_KEY` |
185
+ | DeepSeek | `deepseek/` | `DEEPSEEK_API_KEY` |
186
+ | Perplexity | `perplexity/` | `PERPLEXITY_API_KEY` |
187
+ | X AI (Grok) | `xai/` | `XAI_API_KEY` |
188
+ | OpenRouter | `openrouter/` | `OPENROUTER_API_KEY` |
189
+ | Together AI | `together/` | `TOGETHER_API_KEY` |
190
+ | Fireworks AI | `fireworks/` | `FIREWORKS_API_KEY` |
191
+ | Cerebras | `cerebras/` | `CEREBRAS_API_KEY` |
192
+ | SambaNova | `sambanova/` | `SAMBANOVA_API_KEY` |
193
+ | Nebius AI | `nebius/` | `NEBIUS_API_KEY` |
194
+ | Hyperbolic | `hyperbolic/` | `HYPERBOLIC_API_KEY` |
195
+ | Novita AI | `novita/` | `NOVITA_API_KEY` |
196
+ | GitHub Models | `github/` | `GITHUB_TOKEN` |
197
+ | Anyscale | `anyscale/` | `ANYSCALE_API_KEY` |
198
+ | NVIDIA NIM | `nvidia_nim/` | `NVIDIA_API_KEY` |
199
+ | Codestral | `codestral/` | `CODESTRAL_API_KEY` |
200
+ | Moonshot | `moonshot/` | `MOONSHOT_API_KEY` |
201
+ | DashScope (Alibaba) | `dashscope/` | `DASHSCOPE_API_KEY` |
202
+ | Meta Llama | `meta_llama/` | `LLAMA_API_KEY` |
203
+ | Featherless AI | `featherless/` | `FEATHERLESS_API_KEY` |
204
+ | Nscale | `nscale/` | `NSCALE_API_KEY` |
205
+ | Inception Labs | `inception/` | `INCEPTION_API_KEY` |
206
+ | Morph LLM | `morph/` | `MORPH_API_KEY` |
207
+ | Lambda AI | `lambda/` | `LAMBDA_API_KEY` |
208
+ | AIML API | `aiml/` | `AIML_API_KEY` |
209
+ | Weights & Biases | `wandb/` | `WANDB_API_KEY` |
210
+ | Volcengine | `volcengine/` | `VOLCENGINE_API_KEY` |
211
+ | Galadriel | `galadriel/` | `GALADRIEL_API_KEY` |
212
+ | Empower | `empower/` | `EMPOWER_API_KEY` |
213
+ | Friendli AI | `friendliai/` | `FRIENDLI_API_KEY` |
214
+ | Helicone | `helicone/` | `HELICONE_API_KEY` |
215
+ | Vercel AI Gateway | `vercel_ai/` | `VERCEL_AI_GATEWAY_API_KEY` |
216
+ | Clarifai | `clarifai/` | `CLARIFAI_API_KEY` |
217
+ | Baseten | `baseten/` | `BASETEN_API_KEY` |
218
+ | PublicAI | `publicai/` | `PUBLICAI_API_KEY` |
219
+ | Venice AI | `venice/` | `VENICE_API_KEY` |
220
+
221
+ ## Architecture
222
+
223
+ ```
224
+ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐
225
+ │ completion() │────▶│ getHandler() │────▶│ OpenAIHandler │
226
+ │ embedding() │ │ (prefix │ │ AnthropicHandler│
227
+ │ │ │ matching) │ │ GeminiHandler │
228
+ │ │ │ │ │ OpenAILikeHandler│
229
+ └──────────────┘ └──────────────┘ └─────────────────┘
230
+
231
+ ┌──────┴──────┐
232
+ │ Model Map │
233
+ │ groq/ → ... │
234
+ │ claude- → . │
235
+ │ gpt- → ... │
236
+ └─────────────┘
237
+ ```
238
+
239
+ ## Development
240
+
241
+ ```bash
242
+ # Clone
243
+ git clone https://github.com/madkoding/litellmTS.git
244
+ cd litellmTS
245
+
246
+ # Install
247
+ npm install
248
+
249
+ # Run unit tests
250
+ npm t
251
+
252
+ # Run E2E tests (requires API keys in .env)
253
+ cp .example.env .env
254
+ npm run test:e2e
255
+
256
+ # Build
257
+ npm run build
258
+ ```
259
+
260
+ ## License
261
+
262
+ GNU General Public License v3.0 — see [LICENSE](LICENSE).
263
+
264
+ ## Why not just use the Python version?
265
+
266
+ litellmTS is a native TypeScript implementation designed for Node.js/Deno/Bun environments. It has zero Python dependencies and integrates naturally with the TypeScript ecosystem (type safety, IDE autocompletion, etc.). Think of it as litellm, but for the JS/TS world.
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Interactive CLI prompt to configure and validate an Anthropic API key.
3
+ *
4
+ * Prompts the user to paste a key, validates it with a lightweight API call,
5
+ * and persists to `~/.litellm/auth.json`.
6
+ */
7
+ export declare function loginAnthropic(): Promise<void>;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.loginAnthropic = loginAnthropic;
37
+ /* eslint-disable no-console */
38
+ const readline = __importStar(require("node:readline/promises"));
39
+ const node_process_1 = require("node:process");
40
+ const store_1 = require("./store");
41
+ /**
42
+ * Interactive CLI prompt to configure and validate an Anthropic API key.
43
+ *
44
+ * Prompts the user to paste a key, validates it with a lightweight API call,
45
+ * and persists to `~/.litellm/auth.json`.
46
+ */
47
+ async function loginAnthropic() {
48
+ console.log('\n🔑 Configurando clave API de Anthropic...\n');
49
+ console.log(' 1. Abre https://console.anthropic.com/ en tu navegador');
50
+ console.log(' 2. Ve a API Keys → Create Key');
51
+ console.log(' 3. Copia la key (comienza con "sk-ant-")\n');
52
+ const rl = readline.createInterface({ input: node_process_1.stdin, output: node_process_1.stdout });
53
+ const apiKey = await rl.question('✏️ Pega tu API key: ');
54
+ rl.close();
55
+ const trimmed = apiKey.trim();
56
+ if (!trimmed) {
57
+ throw new Error('No se ingresó ninguna key');
58
+ }
59
+ if (!trimmed.startsWith('sk-ant-')) {
60
+ console.warn('⚠️ La key no comienza con "sk-ant-". Asegúrate de haber copiado la key correcta.');
61
+ }
62
+ // Validate with a lightweight API call
63
+ console.log('🔄 Validando key...');
64
+ const res = await fetch('https://api.anthropic.com/v1/messages', {
65
+ method: 'POST',
66
+ headers: {
67
+ 'Content-Type': 'application/json',
68
+ 'x-api-key': trimmed,
69
+ 'anthropic-version': '2023-06-01',
70
+ },
71
+ body: JSON.stringify({
72
+ model: 'claude-3-haiku-20240307',
73
+ max_tokens: 1,
74
+ messages: [{ role: 'user', content: 'hi' }],
75
+ }),
76
+ });
77
+ if (!res.ok) {
78
+ const text = await res.text();
79
+ throw new Error(`Key inválida. Respuesta de Anthropic: ${res.status} ${res.statusText}\n${text}`);
80
+ }
81
+ await (0, store_1.setAnthropicCredentials)({ apiKey: trimmed });
82
+ console.log('✅ Key de Anthropic guardada exitosamente en ~/.litellm/auth.json');
83
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Start the GitHub Copilot OAuth device-code login flow.
3
+ *
4
+ * Opens the browser for user authorization, polls for the GitHub access token,
5
+ * exchanges it for a Copilot token, and persists credentials to `~/.litellm/auth.json`.
6
+ *
7
+ * @param deployment - GitHub deployment URL (default: `'github.com'`)
8
+ */
9
+ export declare function login(deployment?: string): Promise<void>;
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.login = login;
4
+ /* eslint-disable no-console */
5
+ const node_child_process_1 = require("node:child_process");
6
+ const store_1 = require("./store");
7
+ const CLIENT_ID = 'Iv1.b507a08c87ecfe98';
8
+ const SCOPES = 'read:user';
9
+ const COPILOT_API = 'https://api.githubcopilot.com';
10
+ const USER_AGENT = 'GitHubCopilotChat/0.35.0';
11
+ const EDITOR_VERSION = 'vscode/1.107.0';
12
+ const EDITOR_PLUGIN_VERSION = 'copilot-chat/0.35.0';
13
+ const COPILOT_INTEGRATION_ID = 'vscode-chat';
14
+ async function sleep(ms) {
15
+ return new Promise((resolve) => setTimeout(resolve, ms));
16
+ }
17
+ function openBrowser(url) {
18
+ const platform = process.platform;
19
+ try {
20
+ if (platform === 'darwin') {
21
+ (0, node_child_process_1.execSync)(`open "${url}"`, { stdio: 'ignore' });
22
+ }
23
+ else if (platform === 'win32') {
24
+ (0, node_child_process_1.execSync)(`start "" "${url}"`, { stdio: 'ignore' });
25
+ }
26
+ else {
27
+ (0, node_child_process_1.execSync)(`xdg-open "${url}" 2>/dev/null || sensible-browser "${url}" 2>/dev/null || x-www-browser "${url}"`, { stdio: 'ignore' });
28
+ }
29
+ }
30
+ catch {
31
+ // browser open failed, user can open manually
32
+ }
33
+ }
34
+ async function requestDeviceCode() {
35
+ const res = await fetch('https://github.com/login/device/code', {
36
+ method: 'POST',
37
+ headers: {
38
+ Accept: 'application/json',
39
+ 'Content-Type': 'application/json',
40
+ 'User-Agent': USER_AGENT,
41
+ },
42
+ body: JSON.stringify({
43
+ client_id: CLIENT_ID,
44
+ scope: SCOPES,
45
+ }),
46
+ });
47
+ if (!res.ok) {
48
+ throw new Error(`Error al solicitar device code: ${res.status}`);
49
+ }
50
+ return res.json();
51
+ }
52
+ async function pollAccessToken(deviceCode, interval) {
53
+ const body = {
54
+ client_id: CLIENT_ID,
55
+ device_code: deviceCode,
56
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
57
+ };
58
+ let attempts = 0;
59
+ const maxAttempts = 120; // ~10 min max
60
+ while (attempts < maxAttempts) {
61
+ attempts++;
62
+ await sleep(interval * 1000);
63
+ const res = await fetch('https://github.com/login/oauth/access_token', {
64
+ method: 'POST',
65
+ headers: {
66
+ Accept: 'application/json',
67
+ 'Content-Type': 'application/json',
68
+ 'User-Agent': USER_AGENT,
69
+ },
70
+ body: JSON.stringify(body),
71
+ });
72
+ if (!res.ok) {
73
+ throw new Error(`Error en polling: ${res.status}`);
74
+ }
75
+ const data = (await res.json());
76
+ if (data.access_token) {
77
+ return data.access_token;
78
+ }
79
+ if (data.error === 'authorization_pending') {
80
+ continue;
81
+ }
82
+ if (data.error === 'slow_down') {
83
+ interval += 5;
84
+ continue;
85
+ }
86
+ if (data.error === 'expired_token' ||
87
+ data.error === 'access_denied') {
88
+ throw new Error(data.error_description ?? `Autenticación cancelada: ${data.error}`);
89
+ }
90
+ }
91
+ throw new Error('Tiempo de espera agotado para la autenticación');
92
+ }
93
+ async function exchangeCopilotToken(githubToken) {
94
+ const res = await fetch(`${COPILOT_API}/copilot_internal/v2/token`, {
95
+ headers: {
96
+ Authorization: `Bearer ${githubToken}`,
97
+ 'User-Agent': USER_AGENT,
98
+ 'Editor-Version': EDITOR_VERSION,
99
+ 'Editor-Plugin-Version': EDITOR_PLUGIN_VERSION,
100
+ 'Copilot-Integration-Id': COPILOT_INTEGRATION_ID,
101
+ },
102
+ });
103
+ if (!res.ok) {
104
+ throw new Error(`Error al obtener token de Copilot: ${res.status} ${res.statusText}`);
105
+ }
106
+ const data = (await res.json());
107
+ if (data.error) {
108
+ throw new Error(data.error_description ?? `Error de Copilot: ${data.error}`);
109
+ }
110
+ return { token: data.token, expires_at: data.expires_at };
111
+ }
112
+ /**
113
+ * Start the GitHub Copilot OAuth device-code login flow.
114
+ *
115
+ * Opens the browser for user authorization, polls for the GitHub access token,
116
+ * exchanges it for a Copilot token, and persists credentials to `~/.litellm/auth.json`.
117
+ *
118
+ * @param deployment - GitHub deployment URL (default: `'github.com'`)
119
+ */
120
+ async function login(deployment = 'github.com') {
121
+ console.log('\n🔐 Iniciando sesión en GitHub Copilot...\n');
122
+ const deviceCode = await requestDeviceCode();
123
+ console.log(`✏️ Código de verificación: ${deviceCode.user_code}`);
124
+ console.log(`🌐 Abriendo ${deviceCode.verification_uri} en tu navegador...\n`);
125
+ openBrowser(deviceCode.verification_uri);
126
+ console.log('⏳ Esperando autorización...');
127
+ const githubToken = await pollAccessToken(deviceCode.device_code, deviceCode.interval);
128
+ console.log('✅ Autorización de GitHub exitosa');
129
+ console.log('🔄 Obteniendo token de Copilot...');
130
+ const copilotToken = await exchangeCopilotToken(githubToken);
131
+ await (0, store_1.setCopilotCredentials)({
132
+ githubToken,
133
+ copilotToken: copilotToken.token,
134
+ expiresAt: copilotToken.expires_at * 1000,
135
+ enterpriseUrl: deployment !== 'github.com' ? deployment : undefined,
136
+ });
137
+ console.log('✅ Autenticación con GitHub Copilot completada exitosamente');
138
+ }
@@ -0,0 +1,6 @@
1
+ export { login } from './copilot';
2
+ export { loginAnthropic } from './anthropic';
3
+ export { getValidToken, getAnthropicKey } from './refresh';
4
+ export { clearCredentials, getProviderCredentials, setProviderCredentials, } from './store';
5
+ /** @deprecated Import named functions directly from '@litellmts/core' */
6
+ export type { CopilotCredentials, AnthropicCredentials } from './store';
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setProviderCredentials = exports.getProviderCredentials = exports.clearCredentials = exports.getAnthropicKey = exports.getValidToken = exports.loginAnthropic = exports.login = void 0;
4
+ var copilot_1 = require("./copilot");
5
+ Object.defineProperty(exports, "login", { enumerable: true, get: function () { return copilot_1.login; } });
6
+ var anthropic_1 = require("./anthropic");
7
+ Object.defineProperty(exports, "loginAnthropic", { enumerable: true, get: function () { return anthropic_1.loginAnthropic; } });
8
+ var refresh_1 = require("./refresh");
9
+ Object.defineProperty(exports, "getValidToken", { enumerable: true, get: function () { return refresh_1.getValidToken; } });
10
+ Object.defineProperty(exports, "getAnthropicKey", { enumerable: true, get: function () { return refresh_1.getAnthropicKey; } });
11
+ var store_1 = require("./store");
12
+ Object.defineProperty(exports, "clearCredentials", { enumerable: true, get: function () { return store_1.clearCredentials; } });
13
+ Object.defineProperty(exports, "getProviderCredentials", { enumerable: true, get: function () { return store_1.getProviderCredentials; } });
14
+ Object.defineProperty(exports, "setProviderCredentials", { enumerable: true, get: function () { return store_1.setProviderCredentials; } });
@@ -0,0 +1,2 @@
1
+ export declare function getValidToken(): Promise<string | null>;
2
+ export declare function getAnthropicKey(): Promise<string | null>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getValidToken = getValidToken;
4
+ exports.getAnthropicKey = getAnthropicKey;
5
+ const store_1 = require("./store");
6
+ const COPILOT_API = 'https://api.githubcopilot.com';
7
+ const USER_AGENT = 'GitHubCopilotChat/0.35.0';
8
+ const EDITOR_VERSION = 'vscode/1.107.0';
9
+ const EDITOR_PLUGIN_VERSION = 'copilot-chat/0.35.0';
10
+ const COPILOT_INTEGRATION_ID = 'vscode-chat';
11
+ async function exchangeCopilotToken(githubToken) {
12
+ const res = await fetch(`${COPILOT_API}/copilot_internal/v2/token`, {
13
+ headers: {
14
+ Authorization: `Bearer ${githubToken}`,
15
+ 'User-Agent': USER_AGENT,
16
+ 'Editor-Version': EDITOR_VERSION,
17
+ 'Editor-Plugin-Version': EDITOR_PLUGIN_VERSION,
18
+ 'Copilot-Integration-Id': COPILOT_INTEGRATION_ID,
19
+ },
20
+ });
21
+ if (!res.ok) {
22
+ throw new Error(`Error al refrescar token de Copilot: ${res.status} ${res.statusText}`);
23
+ }
24
+ const data = (await res.json());
25
+ if (data.error) {
26
+ throw new Error(`Error al refrescar token: ${data.error}`);
27
+ }
28
+ return { token: data.token, expires_at: data.expires_at };
29
+ }
30
+ async function getValidToken() {
31
+ const creds = await (0, store_1.getCopilotCredentials)();
32
+ if (!creds?.copilotToken || !creds?.githubToken) {
33
+ return null;
34
+ }
35
+ if (creds.expiresAt - 5 * 60 * 1000 < Date.now()) {
36
+ try {
37
+ const newToken = await exchangeCopilotToken(creds.githubToken);
38
+ await (0, store_1.setCopilotCredentials)({
39
+ ...creds,
40
+ copilotToken: newToken.token,
41
+ expiresAt: newToken.expires_at * 1000,
42
+ });
43
+ return newToken.token;
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
49
+ return creds.copilotToken;
50
+ }
51
+ async function getAnthropicKey() {
52
+ const creds = await (0, store_1.getAnthropicCredentials)();
53
+ return creds?.apiKey ?? null;
54
+ }
@@ -0,0 +1,19 @@
1
+ /** GitHub Copilot OAuth credentials. */
2
+ export interface CopilotCredentials {
3
+ githubToken: string;
4
+ copilotToken: string;
5
+ expiresAt: number;
6
+ enterpriseUrl?: string;
7
+ }
8
+ /** Stored Anthropic API key. */
9
+ export interface AnthropicCredentials {
10
+ apiKey: string;
11
+ }
12
+ export type ProviderCredentials = Record<string, unknown>;
13
+ export declare function getProviderCredentials<T>(provider: string): Promise<T | null>;
14
+ export declare function setProviderCredentials(provider: string, creds: Record<string, unknown>): Promise<void>;
15
+ export declare function getCopilotCredentials(): Promise<CopilotCredentials | null>;
16
+ export declare function setCopilotCredentials(creds: CopilotCredentials): Promise<void>;
17
+ export declare function getAnthropicCredentials(): Promise<AnthropicCredentials | null>;
18
+ export declare function setAnthropicCredentials(creds: AnthropicCredentials): Promise<void>;
19
+ export declare function clearCredentials(): Promise<void>;