@acarmisc/backstage-plugin-litellm-backend 0.1.14 → 0.1.16

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/dist/client.js DELETED
@@ -1,252 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LiteLLMClient = void 0;
4
- const DEFAULT_TIMEOUT = 30000;
5
- class LiteLLMClient {
6
- constructor(config, timeout = DEFAULT_TIMEOUT) {
7
- this.baseUrl = config.baseUrl.replace(/\/$/, '');
8
- this.masterKey = config.masterKey;
9
- this.timeout = timeout;
10
- }
11
- async request(path, options = {}) {
12
- const controller = new AbortController();
13
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
14
- try {
15
- const response = await fetch(`${this.baseUrl}${path}`, {
16
- ...options,
17
- signal: controller.signal,
18
- headers: {
19
- 'Content-Type': 'application/json',
20
- 'Authorization': `Bearer ${this.masterKey}`,
21
- ...options.headers,
22
- },
23
- });
24
- if (!response.ok) {
25
- const errorBody = await response.text();
26
- const err = new Error(`LiteLLM API error: ${response.status} ${response.statusText} - ${errorBody}`);
27
- err.status = response.status;
28
- throw err;
29
- }
30
- return response.json();
31
- }
32
- finally {
33
- clearTimeout(timeoutId);
34
- }
35
- }
36
- /**
37
- * Returns null when the user is not found in LiteLLM (404).
38
- * Throws on all other errors so callers know something went wrong.
39
- */
40
- async getUserInfo(userId) {
41
- const query = userId ? `?user_id=${encodeURIComponent(userId)}` : '';
42
- try {
43
- return await this.request(`/user/info${query}`);
44
- }
45
- catch (err) {
46
- if (err.status === 404)
47
- return null;
48
- throw err;
49
- }
50
- }
51
- async createUser(payload) {
52
- return this.request('/user/new', {
53
- method: 'POST',
54
- body: JSON.stringify(payload),
55
- });
56
- }
57
- async listKeys(userId) {
58
- const query = userId ? `?user_id=${encodeURIComponent(userId)}` : '';
59
- try {
60
- const response = await this.request(`/key/info${query}`);
61
- return Array.isArray(response) ? response : (response.info ?? []);
62
- }
63
- catch (err) {
64
- if (err.status === 404 || err.message.includes('not found')) {
65
- return [];
66
- }
67
- throw err;
68
- }
69
- }
70
- async generateKey(request) {
71
- return this.request('/key/generate', {
72
- method: 'POST',
73
- body: JSON.stringify({ json: request }),
74
- });
75
- }
76
- async updateKey(request) {
77
- return this.request('/key/update', {
78
- method: 'POST',
79
- body: JSON.stringify(request),
80
- });
81
- }
82
- async deleteKeys(request) {
83
- return this.request('/key/delete', {
84
- method: 'POST',
85
- body: JSON.stringify(request),
86
- });
87
- }
88
- async listModels() {
89
- const response = await this.request('/models');
90
- return Array.isArray(response) ? response : (response.data ?? []);
91
- }
92
- async getTeamInfo(teamId) {
93
- return this.request(`/team/info?team_id=${encodeURIComponent(teamId)}`);
94
- }
95
- emptyUsage() {
96
- return {
97
- total_spend: 0,
98
- total_tokens: 0,
99
- prompt_tokens: 0,
100
- completion_tokens: 0,
101
- api_requests: 0,
102
- successful_requests: 0,
103
- failed_requests: 0,
104
- usage_by_model: {},
105
- usage_by_key: {},
106
- daily_usage: [],
107
- daily_by_model: [],
108
- };
109
- }
110
- /**
111
- * Transforms LiteLLM's SpendAnalyticsPaginatedResponse into the flatter
112
- * UsageMetrics shape consumed by the frontend charts.
113
- *
114
- * Source shape (per result row):
115
- * { date, metrics, breakdown: { models: { [name]: { metrics, api_key_breakdown: { [keyHash]: { metrics, metadata } } } } } }
116
- *
117
- * We fan that out into three views the UI consumes:
118
- * - daily_usage → spend + request trends over time
119
- * - usage_by_model → which models drove cost / traffic
120
- * - usage_by_key → which keys drove cost / traffic (with key_alias + team_id from metadata)
121
- */
122
- transformDailyActivity(response) {
123
- const results = Array.isArray(response?.results) ? response.results : [];
124
- const meta = response?.metadata ?? {};
125
- const daily_usage = results
126
- .map(r => ({
127
- date: r.date,
128
- spend: r.metrics?.spend ?? 0,
129
- total_tokens: r.metrics?.total_tokens ?? 0,
130
- prompt_tokens: r.metrics?.prompt_tokens ?? 0,
131
- completion_tokens: r.metrics?.completion_tokens ?? 0,
132
- api_requests: r.metrics?.api_requests ?? 0,
133
- successful_requests: r.metrics?.successful_requests ?? 0,
134
- failed_requests: r.metrics?.failed_requests ?? 0,
135
- }))
136
- .sort((a, b) => a.date.localeCompare(b.date));
137
- const usage_by_model = {};
138
- const usage_by_key = {};
139
- const daily_by_model = [];
140
- const emptyModelBucket = () => ({
141
- total_spend: 0,
142
- total_tokens: 0,
143
- prompt_tokens: 0,
144
- completion_tokens: 0,
145
- api_requests: 0,
146
- successful_requests: 0,
147
- failed_requests: 0,
148
- });
149
- for (const r of results) {
150
- const models = r.breakdown?.models ?? {};
151
- for (const [name, entry] of Object.entries(models)) {
152
- const m = entry?.metrics ?? {};
153
- const bucket = usage_by_model[name] ?? emptyModelBucket();
154
- bucket.total_spend += m.spend ?? 0;
155
- bucket.total_tokens += m.total_tokens ?? 0;
156
- bucket.prompt_tokens += m.prompt_tokens ?? 0;
157
- bucket.completion_tokens += m.completion_tokens ?? 0;
158
- bucket.api_requests += m.api_requests ?? 0;
159
- bucket.successful_requests += m.successful_requests ?? 0;
160
- bucket.failed_requests += m.failed_requests ?? 0;
161
- usage_by_model[name] = bucket;
162
- daily_by_model.push({
163
- date: r.date,
164
- model: name,
165
- spend: m.spend ?? 0,
166
- prompt_tokens: m.prompt_tokens ?? 0,
167
- completion_tokens: m.completion_tokens ?? 0,
168
- total_tokens: m.total_tokens ?? 0,
169
- api_requests: m.api_requests ?? 0,
170
- successful_requests: m.successful_requests ?? 0,
171
- failed_requests: m.failed_requests ?? 0,
172
- });
173
- const keyMap = entry?.api_key_breakdown ?? {};
174
- for (const [keyHash, keyEntry] of Object.entries(keyMap)) {
175
- const km = keyEntry?.metrics ?? {};
176
- const kmeta = keyEntry?.metadata ?? {};
177
- const kb = usage_by_key[keyHash] ?? {
178
- key_alias: kmeta.key_alias,
179
- team_id: kmeta.team_id ?? null,
180
- models: [],
181
- ...emptyModelBucket(),
182
- };
183
- if (!kb.key_alias && kmeta.key_alias)
184
- kb.key_alias = kmeta.key_alias;
185
- if (kb.team_id == null && kmeta.team_id)
186
- kb.team_id = kmeta.team_id;
187
- if (!kb.models.includes(name))
188
- kb.models.push(name);
189
- kb.total_spend += km.spend ?? 0;
190
- kb.total_tokens += km.total_tokens ?? 0;
191
- kb.prompt_tokens += km.prompt_tokens ?? 0;
192
- kb.completion_tokens += km.completion_tokens ?? 0;
193
- kb.api_requests += km.api_requests ?? 0;
194
- kb.successful_requests += km.successful_requests ?? 0;
195
- kb.failed_requests += km.failed_requests ?? 0;
196
- usage_by_key[keyHash] = kb;
197
- }
198
- }
199
- }
200
- return {
201
- total_spend: meta.total_spend ?? 0,
202
- total_tokens: meta.total_tokens ?? 0,
203
- prompt_tokens: meta.total_prompt_tokens ?? 0,
204
- completion_tokens: meta.total_completion_tokens ?? 0,
205
- api_requests: meta.total_api_requests ?? 0,
206
- successful_requests: meta.total_successful_requests ?? 0,
207
- failed_requests: meta.total_failed_requests ?? 0,
208
- usage_by_model,
209
- usage_by_key,
210
- daily_usage,
211
- daily_by_model,
212
- };
213
- }
214
- async getUsage(startDate, endDate, userId, _groupBy) {
215
- const params = new URLSearchParams({
216
- start_date: startDate,
217
- end_date: endDate,
218
- page_size: '100',
219
- });
220
- if (userId)
221
- params.append('user_id', userId);
222
- try {
223
- const response = await this.request(`/user/daily/activity?${params.toString()}`);
224
- return this.transformDailyActivity(response);
225
- }
226
- catch (err) {
227
- if (err.status === 404 || err.message.includes('not found')) {
228
- return this.emptyUsage();
229
- }
230
- throw err;
231
- }
232
- }
233
- async getTeamUsage(teamId, startDate, endDate) {
234
- const params = new URLSearchParams({
235
- start_date: startDate,
236
- end_date: endDate,
237
- team_ids: teamId,
238
- page_size: '100',
239
- });
240
- try {
241
- const response = await this.request(`/team/daily/activity?${params.toString()}`);
242
- return this.transformDailyActivity(response);
243
- }
244
- catch (err) {
245
- if (err.status === 404 || err.message.includes('not found')) {
246
- return this.emptyUsage();
247
- }
248
- throw err;
249
- }
250
- }
251
- }
252
- exports.LiteLLMClient = LiteLLMClient;
package/dist/index.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export { litellmPlugin } from './plugin';
2
- export { createRouter } from './router';
3
- export * from './types';
4
- export { LiteLLMClient } from './client';
package/dist/index.esm.js DELETED
@@ -1,323 +0,0 @@
1
- // src/plugin.ts
2
- import { coreServices, createBackendPlugin } from "@backstage/backend-plugin-api";
3
-
4
- // src/router.ts
5
- import { Router } from "express";
6
-
7
- // src/client.ts
8
- var DEFAULT_TIMEOUT = 3e4;
9
- var LiteLLMClient = class {
10
- constructor(config, timeout = DEFAULT_TIMEOUT) {
11
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
12
- this.masterKey = config.masterKey;
13
- this.timeout = timeout;
14
- }
15
- async request(path, options = {}) {
16
- const controller = new AbortController();
17
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
18
- try {
19
- const response = await fetch(`${this.baseUrl}${path}`, {
20
- ...options,
21
- signal: controller.signal,
22
- headers: {
23
- "Content-Type": "application/json",
24
- "Authorization": `Bearer ${this.masterKey}`,
25
- ...options.headers
26
- }
27
- });
28
- if (!response.ok) {
29
- const errorBody = await response.text();
30
- const err = new Error(`LiteLLM API error: ${response.status} ${response.statusText} - ${errorBody}`);
31
- err.status = response.status;
32
- throw err;
33
- }
34
- return response.json();
35
- } finally {
36
- clearTimeout(timeoutId);
37
- }
38
- }
39
- /**
40
- * Returns null when the user is not found in LiteLLM (404).
41
- * Throws on all other errors so callers know something went wrong.
42
- */
43
- async getUserInfo(userId) {
44
- const query = userId ? `?user_id=${encodeURIComponent(userId)}` : "";
45
- try {
46
- return await this.request(`/user/info${query}`);
47
- } catch (err) {
48
- if (err.status === 404) return null;
49
- throw err;
50
- }
51
- }
52
- async createUser(payload) {
53
- return this.request("/user/new", {
54
- method: "POST",
55
- body: JSON.stringify(payload)
56
- });
57
- }
58
- async listKeys(userId) {
59
- const query = userId ? `?user_id=${encodeURIComponent(userId)}` : "";
60
- const response = await this.request(`/key/info${query}`);
61
- return Array.isArray(response) ? response : response.info ?? [];
62
- }
63
- async generateKey(request) {
64
- return this.request("/key/generate", {
65
- method: "POST",
66
- body: JSON.stringify(request)
67
- });
68
- }
69
- async deleteKeys(request) {
70
- return this.request("/key/delete", {
71
- method: "POST",
72
- body: JSON.stringify(request)
73
- });
74
- }
75
- async listModels() {
76
- const response = await this.request("/models");
77
- return Array.isArray(response) ? response : response.data ?? [];
78
- }
79
- async getTeamInfo(teamId) {
80
- return this.request(`/team/info?team_id=${encodeURIComponent(teamId)}`);
81
- }
82
- async getUsage(startDate, endDate, userId, groupBy) {
83
- const params = new URLSearchParams({ start_date: startDate, end_date: endDate });
84
- if (userId) params.append("user_id", userId);
85
- if (groupBy) params.append("group_by", groupBy);
86
- return this.request(`/usage/keys?${params.toString()}`);
87
- }
88
- async getTeamUsage(teamId, startDate, endDate) {
89
- const params = new URLSearchParams({ start_date: startDate, end_date: endDate, team_id: teamId });
90
- return this.request(`/usage/keys?${params.toString()}`);
91
- }
92
- };
93
-
94
- // src/router.ts
95
- function readProvisioningDefaults(config) {
96
- const enabled = config.getOptionalBoolean("litellm.provisioning.enabled") ?? false;
97
- const defaults = {
98
- maxBudget: config.getOptionalNumber("litellm.provisioning.defaults.maxBudget") ?? 10,
99
- budgetDuration: config.getOptionalString("litellm.provisioning.defaults.budgetDuration") ?? "30d",
100
- models: config.getOptionalStringArray("litellm.provisioning.defaults.models") ?? [],
101
- teams: config.getOptionalStringArray("litellm.provisioning.defaults.teams") ?? [],
102
- tpmLimit: config.getOptionalNumber("litellm.provisioning.defaults.tpmLimit"),
103
- rpmLimit: config.getOptionalNumber("litellm.provisioning.defaults.rpmLimit"),
104
- metadata: config.getOptional("litellm.provisioning.defaults.metadata") ?? {}
105
- };
106
- return { enabled, defaults };
107
- }
108
- async function resolveUserId(req, auth) {
109
- const rawToken = req.headers.authorization?.slice(7);
110
- if (!rawToken) return void 0;
111
- try {
112
- const credentials = await auth.authenticate(rawToken);
113
- const principal = credentials.principal;
114
- if (principal?.type === "user") {
115
- return principal.userEntityRef;
116
- }
117
- } catch {
118
- }
119
- return void 0;
120
- }
121
- async function provisionUser(client, userId, defaults, logger) {
122
- const payload = {
123
- user_id: userId,
124
- max_budget: defaults.maxBudget,
125
- budget_duration: defaults.budgetDuration,
126
- models: defaults.models,
127
- teams: defaults.teams,
128
- ...defaults.tpmLimit !== void 0 && { tpm_limit: defaults.tpmLimit },
129
- ...defaults.rpmLimit !== void 0 && { rpm_limit: defaults.rpmLimit },
130
- metadata: {
131
- ...defaults.metadata,
132
- provisioned_by: "backstage",
133
- provisioned_at: (/* @__PURE__ */ new Date()).toISOString(),
134
- backstage_entity: userId
135
- }
136
- };
137
- logger.info(`Provisioning new LiteLLM user for Backstage identity: ${userId}`);
138
- try {
139
- await client.createUser(payload);
140
- return await client.getUserInfo(userId);
141
- } catch (err) {
142
- logger.error(`Failed to provision LiteLLM user ${userId}: ${err.message}`);
143
- return null;
144
- }
145
- }
146
- async function createRouter(options) {
147
- const { config, logger, auth } = options;
148
- const baseUrl = config.getString("litellm.baseUrl");
149
- const masterKey = config.getString("litellm.masterKey");
150
- const client = new LiteLLMClient({ baseUrl, masterKey });
151
- const { enabled: provisioningEnabled, defaults: provisioningDefaults } = readProvisioningDefaults(config);
152
- if (provisioningEnabled) {
153
- logger.info(
154
- `LiteLLM auto-provisioning enabled \u2014 defaults: budget=$${provisioningDefaults.maxBudget}/${provisioningDefaults.budgetDuration}, models=${provisioningDefaults.models.length ? provisioningDefaults.models.join(",") : "all"}, teams=[${provisioningDefaults.teams.join(",")}]`
155
- );
156
- }
157
- const router = Router();
158
- router.get("/health", (_req, res) => {
159
- res.json({ status: "ok", provisioning: provisioningEnabled });
160
- });
161
- router.get("/user/info", async (req, res) => {
162
- try {
163
- const tokenUserId = await resolveUserId(req, auth);
164
- const userId = tokenUserId ?? req.query.user_id;
165
- let userInfo = await client.getUserInfo(userId);
166
- if (!userInfo) {
167
- if (provisioningEnabled && userId) {
168
- userInfo = await provisionUser(client, userId, provisioningDefaults, logger);
169
- }
170
- if (!userInfo) {
171
- res.status(404).json({
172
- error: "User not found in LiteLLM",
173
- provisioning: provisioningEnabled,
174
- hint: provisioningEnabled ? "Provisioning attempted but failed \u2014 check LiteLLM logs" : "Enable litellm.provisioning.enabled in app-config.yaml or create the user manually"
175
- });
176
- return;
177
- }
178
- }
179
- res.json(userInfo);
180
- } catch (error) {
181
- logger.error("Failed to fetch user info", error);
182
- res.status(500).json({ error: error.message });
183
- }
184
- });
185
- router.get("/keys", async (req, res) => {
186
- try {
187
- const tokenUserId = await resolveUserId(req, auth);
188
- const userId = tokenUserId ?? req.query.user_id;
189
- const keys = await client.listKeys(userId);
190
- res.json(keys);
191
- } catch (error) {
192
- logger.error("Failed to list keys", error);
193
- res.status(500).json({ error: error.message });
194
- }
195
- });
196
- router.post("/keys/generate", async (req, res) => {
197
- try {
198
- const tokenUserId = await resolveUserId(req, auth);
199
- const request = {
200
- ...req.body,
201
- ...tokenUserId && { user_id: tokenUserId }
202
- };
203
- const result = await client.generateKey(request);
204
- res.json(result);
205
- } catch (error) {
206
- logger.error("Failed to generate key", error);
207
- res.status(500).json({ error: error.message });
208
- }
209
- });
210
- router.delete("/keys/:keyId", async (req, res) => {
211
- try {
212
- const { keyId } = req.params;
213
- if (!keyId) {
214
- res.status(400).json({ error: "keyId is required" });
215
- return;
216
- }
217
- await client.deleteKeys({ keys: [keyId] });
218
- res.json({ success: true });
219
- } catch (error) {
220
- logger.error("Failed to delete key", error);
221
- res.status(500).json({ error: error.message });
222
- }
223
- });
224
- router.get("/models", async (_req, res) => {
225
- try {
226
- const models = await client.listModels();
227
- res.json(models);
228
- } catch (error) {
229
- logger.error("Failed to list models", error);
230
- res.status(500).json({ error: error.message });
231
- }
232
- });
233
- router.get("/teams", async (req, res) => {
234
- try {
235
- const tokenUserId = await resolveUserId(req, auth);
236
- const userId = tokenUserId ?? req.query.user_id;
237
- const userInfo = await client.getUserInfo(userId);
238
- if (!userInfo?.teams?.length) {
239
- res.json([]);
240
- return;
241
- }
242
- const teams = await Promise.all(
243
- userInfo.teams.map(
244
- (teamId) => client.getTeamInfo(teamId).catch((err) => {
245
- logger.warn(`Failed to fetch team ${teamId}: ${err.message}`);
246
- return null;
247
- })
248
- )
249
- );
250
- res.json(teams.filter(Boolean));
251
- } catch (error) {
252
- logger.error("Failed to fetch teams", error);
253
- res.status(500).json({ error: error.message });
254
- }
255
- });
256
- router.get("/teams/:teamId/usage", async (req, res) => {
257
- try {
258
- const { teamId } = req.params;
259
- const { start_date, end_date } = req.query;
260
- if (!start_date || !end_date) {
261
- res.status(400).json({ error: "start_date and end_date are required" });
262
- return;
263
- }
264
- const usage = await client.getTeamUsage(
265
- teamId,
266
- start_date,
267
- end_date
268
- );
269
- res.json(usage);
270
- } catch (error) {
271
- logger.error("Failed to fetch team usage", error);
272
- res.status(500).json({ error: error.message });
273
- }
274
- });
275
- router.get("/usage", async (req, res) => {
276
- try {
277
- const { start_date, end_date, group_by } = req.query;
278
- if (!start_date || !end_date) {
279
- res.status(400).json({ error: "start_date and end_date are required" });
280
- return;
281
- }
282
- const tokenUserId = await resolveUserId(req, auth);
283
- const userId = tokenUserId ?? req.query.user_id;
284
- const usage = await client.getUsage(
285
- start_date,
286
- end_date,
287
- userId,
288
- group_by
289
- );
290
- res.json(usage);
291
- } catch (error) {
292
- logger.error("Failed to fetch usage", error);
293
- res.status(500).json({ error: error.message });
294
- }
295
- });
296
- return router;
297
- }
298
-
299
- // src/plugin.ts
300
- var litellmPlugin = createBackendPlugin({
301
- pluginId: "litellm",
302
- register(reg) {
303
- reg.registerInit({
304
- deps: {
305
- httpRouter: coreServices.httpRouter,
306
- config: coreServices.rootConfig,
307
- logger: coreServices.logger,
308
- auth: coreServices.auth,
309
- discovery: coreServices.discovery
310
- },
311
- async init({ httpRouter, config, logger, auth }) {
312
- const router = await createRouter({ config, logger, auth });
313
- httpRouter.use(router);
314
- }
315
- });
316
- }
317
- });
318
- export {
319
- LiteLLMClient,
320
- createRouter,
321
- litellmPlugin
322
- };
323
- //# sourceMappingURL=index.esm.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/plugin.ts", "../src/router.ts", "../src/client.ts"],
4
- "sourcesContent": ["import { coreServices, createBackendPlugin } from '@backstage/backend-plugin-api';\nimport { createRouter } from './router';\n\nexport const litellmPlugin = createBackendPlugin({\n pluginId: 'litellm',\n register(reg) {\n reg.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n auth: coreServices.auth,\n discovery: coreServices.discovery,\n },\n async init({ httpRouter, config, logger, auth }) {\n const router = await createRouter({ config, logger, auth });\n httpRouter.use(router);\n },\n });\n },\n});\n", "import { Router, Request, Response } from 'express';\nimport { Config } from '@backstage/config';\nimport { AuthService } from '@backstage/backend-plugin-api';\nimport { LiteLLMClient } from './client';\nimport {\n UserInfo,\n VirtualKey,\n ModelInfo,\n UsageMetrics,\n TeamInfo,\n GenerateKeyRequest,\n GenerateKeyResponse,\n ProvisioningDefaults,\n} from './types';\n\nexport interface RouterOptions {\n config: Config;\n logger: any;\n auth: AuthService;\n}\n\n/**\n * Reads the provisioning block from config, applying safe defaults for every\n * field so the feature works out-of-the-box without any YAML required.\n *\n * Safe defaults rationale:\n * maxBudget: $10 \u2014 prevents runaway spend on a forgotten test account\n * budgetDuration: 30d \u2014 monthly reset, aligns with typical billing cycles\n * models: [] \u2014 empty means all proxy models are allowed;\n * restrict here or at team level for tighter control\n * teams: [] \u2014 no automatic team assignment; add IDs to enrol users\n * tpmLimit: none \u2014 LiteLLM global / team limits still apply\n * rpmLimit: none \u2014 same\n * metadata: backstage source tag only\n */\nfunction readProvisioningDefaults(config: Config): { enabled: boolean; defaults: ProvisioningDefaults } {\n const enabled = config.getOptionalBoolean('litellm.provisioning.enabled') ?? false;\n const defaults: ProvisioningDefaults = {\n maxBudget: config.getOptionalNumber('litellm.provisioning.defaults.maxBudget') ?? 10,\n budgetDuration: config.getOptionalString('litellm.provisioning.defaults.budgetDuration') ?? '30d',\n models: config.getOptionalStringArray('litellm.provisioning.defaults.models') ?? [],\n teams: config.getOptionalStringArray('litellm.provisioning.defaults.teams') ?? [],\n tpmLimit: config.getOptionalNumber('litellm.provisioning.defaults.tpmLimit'),\n rpmLimit: config.getOptionalNumber('litellm.provisioning.defaults.rpmLimit'),\n metadata: (config.getOptional<Record<string, string>>('litellm.provisioning.defaults.metadata') ?? {}),\n };\n return { enabled, defaults };\n}\n\n/**\n * Extracts the authenticated Backstage user identity from the request token.\n * Returns the userEntityRef (e.g. \"user:default/john.doe\") or undefined when\n * the request carries no user credential (service-to-service calls).\n */\nasync function resolveUserId(req: Request, auth: AuthService): Promise<string | undefined> {\n const rawToken = req.headers.authorization?.slice(7);\n if (!rawToken) return undefined;\n try {\n const credentials = await auth.authenticate(rawToken);\n const principal = credentials.principal as any;\n if (principal?.type === 'user') {\n return principal.userEntityRef as string;\n }\n } catch {\n // invalid or service token \u2014 caller gets query-param fallback\n }\n return undefined;\n}\n\n/**\n * Creates a LiteLLM user for the given Backstage identity using the configured\n * defaults. Returns the UserInfo of the newly created account.\n */\nasync function provisionUser(\n client: LiteLLMClient,\n userId: string,\n defaults: ProvisioningDefaults,\n logger: any,\n): Promise<UserInfo | null> {\n const payload = {\n user_id: userId,\n max_budget: defaults.maxBudget,\n budget_duration: defaults.budgetDuration,\n models: defaults.models,\n teams: defaults.teams,\n ...(defaults.tpmLimit !== undefined && { tpm_limit: defaults.tpmLimit }),\n ...(defaults.rpmLimit !== undefined && { rpm_limit: defaults.rpmLimit }),\n metadata: {\n ...defaults.metadata,\n provisioned_by: 'backstage',\n provisioned_at: new Date().toISOString(),\n backstage_entity: userId,\n },\n };\n\n logger.info(`Provisioning new LiteLLM user for Backstage identity: ${userId}`);\n try {\n await client.createUser(payload);\n // Fetch the freshly-created user record to return consistent UserInfo shape\n return await client.getUserInfo(userId);\n } catch (err: any) {\n logger.error(`Failed to provision LiteLLM user ${userId}: ${err.message}`);\n return null;\n }\n}\n\nexport async function createRouter(options: RouterOptions): Promise<Router> {\n const { config, logger, auth } = options;\n\n const baseUrl = config.getString('litellm.baseUrl');\n const masterKey = config.getString('litellm.masterKey');\n const client = new LiteLLMClient({ baseUrl, masterKey });\n const { enabled: provisioningEnabled, defaults: provisioningDefaults } = readProvisioningDefaults(config);\n\n if (provisioningEnabled) {\n logger.info(\n `LiteLLM auto-provisioning enabled \u2014 defaults: budget=$${provisioningDefaults.maxBudget}/${provisioningDefaults.budgetDuration}, models=${provisioningDefaults.models.length ? provisioningDefaults.models.join(',') : 'all'}, teams=[${provisioningDefaults.teams.join(',')}]`,\n );\n }\n\n const router = Router();\n\n router.get('/health', (_req: Request, res: Response) => {\n res.json({ status: 'ok', provisioning: provisioningEnabled });\n });\n\n router.get('/user/info', async (req: Request, res: Response) => {\n try {\n const tokenUserId = await resolveUserId(req, auth);\n const userId = tokenUserId ?? (req.query.user_id as string | undefined);\n\n let userInfo: UserInfo | null = await client.getUserInfo(userId);\n\n if (!userInfo) {\n if (provisioningEnabled && userId) {\n userInfo = await provisionUser(client, userId, provisioningDefaults, logger);\n }\n\n if (!userInfo) {\n res.status(404).json({\n error: 'User not found in LiteLLM',\n provisioning: provisioningEnabled,\n hint: provisioningEnabled\n ? 'Provisioning attempted but failed \u2014 check LiteLLM logs'\n : 'Enable litellm.provisioning.enabled in app-config.yaml or create the user manually',\n });\n return;\n }\n }\n\n res.json(userInfo);\n } catch (error: any) {\n logger.error('Failed to fetch user info', error);\n res.status(500).json({ error: error.message });\n }\n });\n\n router.get('/keys', async (req: Request, res: Response) => {\n try {\n const tokenUserId = await resolveUserId(req, auth);\n const userId = tokenUserId ?? (req.query.user_id as string | undefined);\n const keys: VirtualKey[] = await client.listKeys(userId);\n res.json(keys);\n } catch (error: any) {\n logger.error('Failed to list keys', error);\n res.status(500).json({ error: error.message });\n }\n });\n\n router.post('/keys/generate', async (req: Request, res: Response) => {\n try {\n const tokenUserId = await resolveUserId(req, auth);\n const request: GenerateKeyRequest = {\n ...req.body,\n ...(tokenUserId && { user_id: tokenUserId }),\n };\n const result: GenerateKeyResponse = await client.generateKey(request);\n res.json(result);\n } catch (error: any) {\n logger.error('Failed to generate key', error);\n res.status(500).json({ error: error.message });\n }\n });\n\n router.delete('/keys/:keyId', async (req: Request, res: Response) => {\n try {\n const { keyId } = req.params;\n if (!keyId) {\n res.status(400).json({ error: 'keyId is required' });\n return;\n }\n await client.deleteKeys({ keys: [keyId] });\n res.json({ success: true });\n } catch (error: any) {\n logger.error('Failed to delete key', error);\n res.status(500).json({ error: error.message });\n }\n });\n\n router.get('/models', async (_req: Request, res: Response) => {\n try {\n const models: ModelInfo[] = await client.listModels();\n res.json(models);\n } catch (error: any) {\n logger.error('Failed to list models', error);\n res.status(500).json({ error: error.message });\n }\n });\n\n router.get('/teams', async (req: Request, res: Response) => {\n try {\n const tokenUserId = await resolveUserId(req, auth);\n const userId = tokenUserId ?? (req.query.user_id as string | undefined);\n const userInfo: UserInfo | null = await client.getUserInfo(userId);\n\n if (!userInfo?.teams?.length) {\n res.json([]);\n return;\n }\n\n const teams = await Promise.all(\n userInfo.teams.map(teamId =>\n client.getTeamInfo(teamId).catch(err => {\n logger.warn(`Failed to fetch team ${teamId}: ${err.message}`);\n return null;\n }),\n ),\n );\n res.json(teams.filter(Boolean) as TeamInfo[]);\n } catch (error: any) {\n logger.error('Failed to fetch teams', error);\n res.status(500).json({ error: error.message });\n }\n });\n\n router.get('/teams/:teamId/usage', async (req: Request, res: Response) => {\n try {\n const { teamId } = req.params;\n const { start_date, end_date } = req.query;\n if (!start_date || !end_date) {\n res.status(400).json({ error: 'start_date and end_date are required' });\n return;\n }\n const usage: UsageMetrics = await client.getTeamUsage(\n teamId,\n start_date as string,\n end_date as string,\n );\n res.json(usage);\n } catch (error: any) {\n logger.error('Failed to fetch team usage', error);\n res.status(500).json({ error: error.message });\n }\n });\n\n router.get('/usage', async (req: Request, res: Response) => {\n try {\n const { start_date, end_date, group_by } = req.query;\n if (!start_date || !end_date) {\n res.status(400).json({ error: 'start_date and end_date are required' });\n return;\n }\n const tokenUserId = await resolveUserId(req, auth);\n const userId = tokenUserId ?? (req.query.user_id as string | undefined);\n const usage: UsageMetrics = await client.getUsage(\n start_date as string,\n end_date as string,\n userId,\n group_by as string | undefined,\n );\n res.json(usage);\n } catch (error: any) {\n logger.error('Failed to fetch usage', error);\n res.status(500).json({ error: error.message });\n }\n });\n\n return router;\n}\n", "import {\n LiteLLMConfig,\n UserInfo,\n VirtualKey,\n ModelInfo,\n UsageMetrics,\n TeamInfo,\n GenerateKeyRequest,\n GenerateKeyResponse,\n DeleteKeyRequest,\n CreateUserRequest,\n CreateUserResponse,\n} from './types';\n\nconst DEFAULT_TIMEOUT = 30000;\n\nexport class LiteLLMClient {\n private baseUrl: string;\n private masterKey: string;\n private timeout: number;\n\n constructor(config: LiteLLMConfig, timeout = DEFAULT_TIMEOUT) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.masterKey = config.masterKey;\n this.timeout = timeout;\n }\n\n private async request<T>(path: string, options: RequestInit = {}): Promise<T> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...options,\n signal: controller.signal,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.masterKey}`,\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const errorBody = await response.text();\n const err = new Error(`LiteLLM API error: ${response.status} ${response.statusText} - ${errorBody}`);\n (err as any).status = response.status;\n throw err;\n }\n\n return response.json();\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Returns null when the user is not found in LiteLLM (404).\n * Throws on all other errors so callers know something went wrong.\n */\n async getUserInfo(userId?: string): Promise<UserInfo | null> {\n const query = userId ? `?user_id=${encodeURIComponent(userId)}` : '';\n try {\n return await this.request<UserInfo>(`/user/info${query}`);\n } catch (err: any) {\n if (err.status === 404) return null;\n throw err;\n }\n }\n\n async createUser(payload: CreateUserRequest): Promise<CreateUserResponse> {\n return this.request<CreateUserResponse>('/user/new', {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n }\n\n async listKeys(userId?: string): Promise<VirtualKey[]> {\n const query = userId ? `?user_id=${encodeURIComponent(userId)}` : '';\n const response = await this.request<{ info: VirtualKey[] } | VirtualKey[]>(`/key/info${query}`);\n return Array.isArray(response) ? response : (response.info ?? []);\n }\n\n async generateKey(request: GenerateKeyRequest): Promise<GenerateKeyResponse> {\n return this.request<GenerateKeyResponse>('/key/generate', {\n method: 'POST',\n body: JSON.stringify(request),\n });\n }\n\n async deleteKeys(request: DeleteKeyRequest): Promise<{ success: boolean }> {\n return this.request<{ success: boolean }>('/key/delete', {\n method: 'POST',\n body: JSON.stringify(request),\n });\n }\n\n async listModels(): Promise<ModelInfo[]> {\n const response = await this.request<{ data: ModelInfo[] } | ModelInfo[]>('/models');\n return Array.isArray(response) ? response : (response.data ?? []);\n }\n\n async getTeamInfo(teamId: string): Promise<TeamInfo> {\n return this.request<TeamInfo>(`/team/info?team_id=${encodeURIComponent(teamId)}`);\n }\n\n async getUsage(startDate: string, endDate: string, userId?: string, groupBy?: string): Promise<UsageMetrics> {\n const params = new URLSearchParams({ start_date: startDate, end_date: endDate });\n if (userId) params.append('user_id', userId);\n if (groupBy) params.append('group_by', groupBy);\n return this.request<UsageMetrics>(`/usage/keys?${params.toString()}`);\n }\n\n async getTeamUsage(teamId: string, startDate: string, endDate: string): Promise<UsageMetrics> {\n const params = new URLSearchParams({ start_date: startDate, end_date: endDate, team_id: teamId });\n return this.request<UsageMetrics>(`/usage/keys?${params.toString()}`);\n }\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
package/dist/index.js DELETED
@@ -1,24 +0,0 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.LiteLLMClient = exports.createRouter = exports.litellmPlugin = void 0;
18
- var plugin_1 = require("./plugin");
19
- Object.defineProperty(exports, "litellmPlugin", { enumerable: true, get: function () { return plugin_1.litellmPlugin; } });
20
- var router_1 = require("./router");
21
- Object.defineProperty(exports, "createRouter", { enumerable: true, get: function () { return router_1.createRouter; } });
22
- __exportStar(require("./types"), exports);
23
- var client_1 = require("./client");
24
- Object.defineProperty(exports, "LiteLLMClient", { enumerable: true, get: function () { return client_1.LiteLLMClient; } });
package/dist/plugin.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare const litellmPlugin: import("@backstage/backend-plugin-api").BackendFeature;