@acarmisc/backstage-plugin-litellm-backend 0.26.1 → 0.27.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/dist/index.cjs.js +125 -42
- package/dist/index.cjs.js.map +2 -2
- package/dist/routes/teamUsage.js +104 -54
- package/dist/teamMemberUsage.d.ts +9 -1
- package/dist/teamMemberUsage.js +50 -0
- package/dist/types.cjs.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +2 -2
package/dist/routes/teamUsage.js
CHANGED
|
@@ -72,75 +72,95 @@ function registerTeamUsageRoutes(router, ctx) {
|
|
|
72
72
|
(0, errors_1.sendError)(res, error, logger, 'fetch team usage');
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
|
-
//
|
|
75
|
+
// Shared gate of the per-member routes. Opt-in (404 when disabled) and
|
|
76
76
|
// fail-closed: the caller must be a manager of the team (owning_group), or
|
|
77
77
|
// a member who holds one of memberBreakdown.viewerRoles in the team or is
|
|
78
|
-
// granted litellm.team.usage.read.
|
|
79
|
-
|
|
78
|
+
// granted litellm.team.usage.read. Scoped to the one team in the path, so
|
|
79
|
+
// leading a team never reveals another. Replies and returns null on refusal.
|
|
80
|
+
async function authorizeMemberView(req, res) {
|
|
80
81
|
const cfg = ctx.memberBreakdownCfg;
|
|
81
82
|
if (!cfg.enabled) {
|
|
82
83
|
res.status(404).json({ error: 'Not found' });
|
|
83
|
-
return;
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const { teamId } = req.params;
|
|
87
|
+
const { start_date, end_date } = req.query;
|
|
88
|
+
if (!start_date || !end_date) {
|
|
89
|
+
res.status(400).json({ error: 'start_date and end_date are required' });
|
|
90
|
+
return null;
|
|
84
91
|
}
|
|
92
|
+
const tokenEntityRef = res.locals.tokenEntityRef;
|
|
93
|
+
const userInfo = await (0, withUser_1.getProvisionedUser)(ctx, res);
|
|
94
|
+
const callerId = res.locals.userId;
|
|
95
|
+
const isMember = userInfo?.teams?.includes(teamId) ?? false;
|
|
96
|
+
let team;
|
|
85
97
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
const tokenEntityRef = res.locals.tokenEntityRef;
|
|
93
|
-
const userInfo = await (0, withUser_1.getProvisionedUser)(ctx, res);
|
|
94
|
-
const callerId = res.locals.userId;
|
|
95
|
-
const isMember = userInfo?.teams?.includes(teamId) ?? false;
|
|
96
|
-
let team;
|
|
97
|
-
try {
|
|
98
|
-
team = await (0, teamFetch_1.withTeamFetchRetry)(() => client.getTeamInfo(teamId));
|
|
99
|
-
}
|
|
100
|
-
catch (err) {
|
|
101
|
-
if (err instanceof client_1.LiteLLMUpstreamError && err.status === 404) {
|
|
102
|
-
res.status(404).json({ error: 'Team not found' });
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
throw err;
|
|
106
|
-
}
|
|
107
|
-
const owningGroup = typeof team.metadata?.owning_group === 'string' ? team.metadata.owning_group : undefined;
|
|
108
|
-
const isManager = ctx.teamMgmtEnabled &&
|
|
109
|
-
!!owningGroup &&
|
|
110
|
-
(await (0, provisioning_1.isUserMemberOfGroup)(tokenEntityRef, owningGroup, catalogClient, auth, logger));
|
|
111
|
-
if (!isMember && !isManager) {
|
|
98
|
+
team = await (0, teamFetch_1.withTeamFetchRetry)(() => client.getTeamInfo(teamId));
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
if (err instanceof client_1.LiteLLMUpstreamError && err.status === 404) {
|
|
112
102
|
res.status(404).json({ error: 'Team not found' });
|
|
113
|
-
return;
|
|
103
|
+
return null;
|
|
114
104
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
const owningGroup = typeof team.metadata?.owning_group === 'string' ? team.metadata.owning_group : undefined;
|
|
108
|
+
const isManager = ctx.teamMgmtEnabled &&
|
|
109
|
+
!!owningGroup &&
|
|
110
|
+
(await (0, provisioning_1.isUserMemberOfGroup)(tokenEntityRef, owningGroup, catalogClient, auth, logger));
|
|
111
|
+
if (!isMember && !isManager) {
|
|
112
|
+
res.status(404).json({ error: 'Team not found' });
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const role = team.members_with_roles?.find(m => m.user_id === callerId)?.role;
|
|
116
|
+
const viaRole = isMember && !!role && cfg.viewerRoles.includes(role);
|
|
117
|
+
const allowed = isManager ||
|
|
118
|
+
viaRole ||
|
|
119
|
+
(isMember &&
|
|
120
|
+
cfg.permissionEnabled &&
|
|
121
|
+
(await ctx.assertPermission(req, backstage_plugin_litellm_common_1.litellmTeamUsageReadPermission)));
|
|
122
|
+
if (!allowed) {
|
|
123
|
+
res.status(403).json({
|
|
124
|
+
error: 'Access denied: viewing per-member usage needs a team role or permission',
|
|
125
|
+
});
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
let via = 'permission';
|
|
129
|
+
if (isManager)
|
|
130
|
+
via = 'manager';
|
|
131
|
+
else if (viaRole)
|
|
132
|
+
via = 'teamRole';
|
|
133
|
+
return {
|
|
134
|
+
teamId,
|
|
135
|
+
team,
|
|
136
|
+
startDate: start_date,
|
|
137
|
+
endDate: end_date,
|
|
138
|
+
isManager,
|
|
139
|
+
via,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const hideFor = (isManager) => isManager
|
|
143
|
+
? teamBudgetVisibility.hideTeamBudgetForManagers
|
|
144
|
+
: teamBudgetVisibility.hideTeamBudgetForMembers;
|
|
145
|
+
// Per-member breakdown of a team's usage.
|
|
146
|
+
router.get('/teams/:teamId/usage/members', requireUser, async (req, res) => {
|
|
147
|
+
try {
|
|
148
|
+
const gate = await authorizeMemberView(req, res);
|
|
149
|
+
if (!gate)
|
|
126
150
|
return;
|
|
127
|
-
}
|
|
151
|
+
const { teamId, team, startDate, endDate, isManager, via } = gate;
|
|
128
152
|
const [usage, keys] = await Promise.all([
|
|
129
|
-
client.getTeamUsage(teamId,
|
|
153
|
+
client.getTeamUsage(teamId, startDate, endDate),
|
|
130
154
|
client.listTeamKeys(teamId),
|
|
131
155
|
]);
|
|
132
156
|
const profiles = await lookupProfiles((0, teamMemberUsage_1.memberEmails)(team, keys));
|
|
133
157
|
const breakdown = (0, teamMemberUsage_1.buildTeamMemberUsage)(teamId, usage, keys, team, profiles);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const hide = isManager
|
|
141
|
-
? teamBudgetVisibility.hideTeamBudgetForManagers
|
|
142
|
-
: teamBudgetVisibility.hideTeamBudgetForMembers;
|
|
143
|
-
res.json(hide ? (0, teamMemberUsage_1.redactTeamMemberUsage)(breakdown) : breakdown);
|
|
158
|
+
logger.info('team.usage.members.read', {
|
|
159
|
+
actor: res.locals.tokenEntityRef,
|
|
160
|
+
teamId,
|
|
161
|
+
via,
|
|
162
|
+
});
|
|
163
|
+
res.json(hideFor(isManager) ? (0, teamMemberUsage_1.redactTeamMemberUsage)(breakdown) : breakdown);
|
|
144
164
|
}
|
|
145
165
|
catch (error) {
|
|
146
166
|
if (error instanceof provisioning_1.ProvisioningError) {
|
|
@@ -150,6 +170,36 @@ function registerTeamUsageRoutes(router, ctx) {
|
|
|
150
170
|
(0, errors_1.sendError)(res, error, logger, 'fetch team member usage');
|
|
151
171
|
}
|
|
152
172
|
});
|
|
173
|
+
// The team's keys (alias, owner, status, budget) with per-key usage, so a
|
|
174
|
+
// team lead sees the members' keys and their consumption. Same gate and
|
|
175
|
+
// redaction as the per-member breakdown.
|
|
176
|
+
router.get('/teams/:teamId/usage/keys', requireUser, async (req, res) => {
|
|
177
|
+
try {
|
|
178
|
+
const gate = await authorizeMemberView(req, res);
|
|
179
|
+
if (!gate)
|
|
180
|
+
return;
|
|
181
|
+
const { teamId, team, startDate, endDate, isManager, via } = gate;
|
|
182
|
+
const [usage, keys] = await Promise.all([
|
|
183
|
+
client.getTeamUsage(teamId, startDate, endDate),
|
|
184
|
+
client.listTeamKeys(teamId),
|
|
185
|
+
]);
|
|
186
|
+
const profiles = await lookupProfiles((0, teamMemberUsage_1.memberEmails)(team, keys));
|
|
187
|
+
const keyUsage = (0, teamMemberUsage_1.buildTeamKeyUsage)(teamId, usage, keys, team, profiles);
|
|
188
|
+
logger.info('team.usage.keys.read', {
|
|
189
|
+
actor: res.locals.tokenEntityRef,
|
|
190
|
+
teamId,
|
|
191
|
+
via,
|
|
192
|
+
});
|
|
193
|
+
res.json(hideFor(isManager) ? (0, teamMemberUsage_1.redactTeamKeyUsage)(keyUsage) : keyUsage);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (error instanceof provisioning_1.ProvisioningError) {
|
|
197
|
+
res.status(error.status).json(error.body);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
(0, errors_1.sendError)(res, error, logger, 'fetch team key usage');
|
|
201
|
+
}
|
|
202
|
+
});
|
|
153
203
|
// Display names from catalog User entities with these emails. Best effort:
|
|
154
204
|
// a catalog failure only drops the names.
|
|
155
205
|
async function lookupProfiles(emails) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Config } from '@backstage/config';
|
|
2
|
-
import { TeamInfo, TeamMemberUsage, UsageMetrics, VirtualKey } from './types';
|
|
2
|
+
import { TeamInfo, TeamKeyUsage, TeamMemberUsage, UsageMetrics, VirtualKey } from './types';
|
|
3
3
|
/** `litellm.teamUsage.memberBreakdown`: who may see a team's per-member usage. */
|
|
4
4
|
export interface MemberBreakdownConfig {
|
|
5
5
|
/** Off by default: the route returns 404 and the UI hides the table. */
|
|
@@ -32,3 +32,11 @@ export declare function buildTeamMemberUsage(teamId: string, usage: UsageMetrics
|
|
|
32
32
|
* way to compare members. Tokens and requests are kept.
|
|
33
33
|
*/
|
|
34
34
|
export declare function redactTeamMemberUsage(usage: TeamMemberUsage): TeamMemberUsage;
|
|
35
|
+
/**
|
|
36
|
+
* Lists a team's keys with their usage over the period, credited by key hash
|
|
37
|
+
* from the team's daily activity. Only fields safe to show a team lead are
|
|
38
|
+
* copied: no secret, hash or metadata. Keys without activity get zero rows.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildTeamKeyUsage(teamId: string, usage: UsageMetrics, keys: VirtualKey[], team: TeamInfo, profiles?: MemberProfiles): TeamKeyUsage;
|
|
41
|
+
/** Hides dollar amounts (period spend and key budgets); tokens and requests stay. */
|
|
42
|
+
export declare function redactTeamKeyUsage(usage: TeamKeyUsage): TeamKeyUsage;
|
package/dist/teamMemberUsage.js
CHANGED
|
@@ -4,6 +4,8 @@ exports.readMemberBreakdownConfig = readMemberBreakdownConfig;
|
|
|
4
4
|
exports.memberEmails = memberEmails;
|
|
5
5
|
exports.buildTeamMemberUsage = buildTeamMemberUsage;
|
|
6
6
|
exports.redactTeamMemberUsage = redactTeamMemberUsage;
|
|
7
|
+
exports.buildTeamKeyUsage = buildTeamKeyUsage;
|
|
8
|
+
exports.redactTeamKeyUsage = redactTeamKeyUsage;
|
|
7
9
|
function readMemberBreakdownConfig(config) {
|
|
8
10
|
return {
|
|
9
11
|
enabled: config.getOptionalBoolean('litellm.teamUsage.memberBreakdown.enabled') ?? false,
|
|
@@ -112,3 +114,51 @@ function redactTeamMemberUsage(usage) {
|
|
|
112
114
|
members: usage.members.map(m => ({ ...m, spend: 0 })),
|
|
113
115
|
};
|
|
114
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Lists a team's keys with their usage over the period, credited by key hash
|
|
119
|
+
* from the team's daily activity. Only fields safe to show a team lead are
|
|
120
|
+
* copied: no secret, hash or metadata. Keys without activity get zero rows.
|
|
121
|
+
*/
|
|
122
|
+
function buildTeamKeyUsage(teamId, usage, keys, team, profiles = new Map()) {
|
|
123
|
+
const emailById = new Map();
|
|
124
|
+
for (const m of team.members_with_roles ?? []) {
|
|
125
|
+
if (m.user_id && m.user_email)
|
|
126
|
+
emailById.set(m.user_id, m.user_email);
|
|
127
|
+
}
|
|
128
|
+
const rows = keys.map(k => {
|
|
129
|
+
const u = (k.token && usage.usage_by_key?.[k.token]) || undefined;
|
|
130
|
+
const userId = k.user_id ?? null;
|
|
131
|
+
const email = (userId && emailById.get(userId)) || (userId?.includes('@') ? userId : undefined);
|
|
132
|
+
const displayName = email && profiles.get(email.toLowerCase())?.displayName;
|
|
133
|
+
return {
|
|
134
|
+
key: k.key,
|
|
135
|
+
...(k.key_alias && { key_alias: k.key_alias }),
|
|
136
|
+
user_id: userId,
|
|
137
|
+
...(email && { user_email: email }),
|
|
138
|
+
...(displayName && { display_name: displayName }),
|
|
139
|
+
created_at: k.created_at,
|
|
140
|
+
...(k.expires_at && { expires_at: k.expires_at }),
|
|
141
|
+
blocked: k.blocked === true,
|
|
142
|
+
...(k.max_budget !== undefined && { max_budget: k.max_budget }),
|
|
143
|
+
spend: u?.total_spend ?? 0,
|
|
144
|
+
prompt_tokens: u?.prompt_tokens ?? 0,
|
|
145
|
+
completion_tokens: u?.completion_tokens ?? 0,
|
|
146
|
+
total_tokens: u?.total_tokens ?? 0,
|
|
147
|
+
api_requests: u?.api_requests ?? 0,
|
|
148
|
+
successful_requests: u?.successful_requests ?? 0,
|
|
149
|
+
failed_requests: u?.failed_requests ?? 0,
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
rows.sort((a, b) => b.spend - a.spend ||
|
|
153
|
+
b.total_tokens - a.total_tokens ||
|
|
154
|
+
a.key.localeCompare(b.key));
|
|
155
|
+
return { team_id: teamId, keys: rows };
|
|
156
|
+
}
|
|
157
|
+
/** Hides dollar amounts (period spend and key budgets); tokens and requests stay. */
|
|
158
|
+
function redactTeamKeyUsage(usage) {
|
|
159
|
+
return {
|
|
160
|
+
...usage,
|
|
161
|
+
budget_hidden: true,
|
|
162
|
+
keys: usage.keys.map(({ max_budget: _hidden, ...k }) => ({ ...k, spend: 0 })),
|
|
163
|
+
};
|
|
164
|
+
}
|
package/dist/types.cjs.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/types.ts"],
|
|
4
|
-
"sourcesContent": ["// Re-export common types for backward compatibility\nexport {\n type UserInfo,\n type TeamMember,\n type TeamObjectPermission,\n type TeamInfo,\n type CreateTeamResponse,\n type VirtualKey,\n type ModelInfo,\n type UsageModelBreakdown,\n type UsageKeyBreakdown,\n type UsageDailyPoint,\n type UsageDailyModelPoint,\n type UsageMetrics,\n type TeamMemberUsage,\n type TeamMemberUsageRow,\n type GenerateKeyRequest,\n type UpdateKeyRequest,\n type GenerateKeyResponse,\n type AuditLogEntry,\n type PaginatedAuditLogs,\n type SpendLogEntry,\n type SpendLogsParams,\n type PaginatedSpendLogs,\n type QualityByModel,\n type QualityScore,\n type QualitySummary,\n type QualityResponse,\n} from '@acarmisc/backstage-plugin-litellm-common';\n\nexport interface CreateTeamRequest {\n team_alias: string;\n models?: string[];\n max_budget?: number;\n budget_duration?: string;\n tpm_limit?: number;\n rpm_limit?: number;\n metadata?: Record<string, unknown>;\n object_permission?: {\n vector_stores?: string[];\n mcp_servers?: string[];\n mcp_access_groups?: string[];\n };\n}\n\nexport interface UpdateTeamRequest extends Partial<CreateTeamRequest> {\n team_id: string;\n blocked?: boolean;\n}\n\n/**\n * Shape of a single entry inside LiteLLM's `/user/info` `keys` array.\n * Differs from VirtualKey: uses `expires` (not `expires_at`), exposes\n * both a hashed `token` and a masked `key_name`, and fields are nullable\n * rather than optional.\n */\nexport interface LiteLLMUserKey {\n token: string;\n key_name?: string;\n key_alias?: string | null;\n spend?: number;\n expires?: string | null;\n models?: string[];\n tpm_limit?: number | null;\n rpm_limit?: number | null;\n max_budget?: number | null;\n budget_duration?: string | null;\n user_id?: string | null;\n team_id?: string | null;\n created_at: string;\n blocked?: boolean | null;\n /** Arbitrary metadata stored on the key record. */\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface DeleteKeyRequest {\n keys: string[];\n}\n\nexport interface LiteLLMConfig {\n baseUrl: string;\n masterKey: string;\n}\n\nexport interface ProvisioningDefaults {\n maxBudget: number;\n budgetDuration: string;\n models: string[];\n teams: string[];\n tpmLimit?: number;\n rpmLimit?: number;\n /**\n * LiteLLM user role applied on /user/new. Defaults to \"internal_user\"\n * which grants self-service Create/Delete/View on the user's own keys.\n * Valid values: proxy_admin, proxy_admin_viewer, internal_user,\n * internal_user_viewer, team.\n */\n userRole?: string;\n metadata: Record<string, string>;\n}\n\nexport interface RoleConfig {\n group: string;\n maxBudget?: number;\n budgetDuration?: string;\n models?: string[];\n teams?: string[];\n tpmLimit?: number;\n rpmLimit?: number;\n userRole?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface CreateUserRequest {\n user_id: string;\n user_email?: string;\n user_alias?: string;\n user_role?: string;\n max_budget?: number;\n budget_duration?: string;\n models?: string[];\n teams?: string[];\n tpm_limit?: number;\n rpm_limit?: number;\n metadata?: Record<string, string>;\n auto_create_key?: boolean;\n}\n\nexport interface CreateUserResponse {\n user_id: string;\n user_email?: string;\n max_budget?: number;\n models?: string[];\n teams?: string[];\n}\n\n\nexport interface AuditLogsParams {\n page?: number;\n page_size?: number;\n start_date?: string;\n end_date?: string;\n action?: string;\n table_name?: string;\n changed_by?: string;\n sort_by?: string;\n sort_order?: 'asc' | 'desc';\n}\n"],
|
|
4
|
+
"sourcesContent": ["// Re-export common types for backward compatibility\nexport {\n type UserInfo,\n type TeamMember,\n type TeamObjectPermission,\n type TeamInfo,\n type CreateTeamResponse,\n type VirtualKey,\n type ModelInfo,\n type UsageModelBreakdown,\n type UsageKeyBreakdown,\n type UsageDailyPoint,\n type UsageDailyModelPoint,\n type UsageMetrics,\n type TeamMemberUsage,\n type TeamMemberUsageRow,\n type TeamKeyUsage,\n type TeamKeyUsageRow,\n type GenerateKeyRequest,\n type UpdateKeyRequest,\n type GenerateKeyResponse,\n type AuditLogEntry,\n type PaginatedAuditLogs,\n type SpendLogEntry,\n type SpendLogsParams,\n type PaginatedSpendLogs,\n type QualityByModel,\n type QualityScore,\n type QualitySummary,\n type QualityResponse,\n} from '@acarmisc/backstage-plugin-litellm-common';\n\nexport interface CreateTeamRequest {\n team_alias: string;\n models?: string[];\n max_budget?: number;\n budget_duration?: string;\n tpm_limit?: number;\n rpm_limit?: number;\n metadata?: Record<string, unknown>;\n object_permission?: {\n vector_stores?: string[];\n mcp_servers?: string[];\n mcp_access_groups?: string[];\n };\n}\n\nexport interface UpdateTeamRequest extends Partial<CreateTeamRequest> {\n team_id: string;\n blocked?: boolean;\n}\n\n/**\n * Shape of a single entry inside LiteLLM's `/user/info` `keys` array.\n * Differs from VirtualKey: uses `expires` (not `expires_at`), exposes\n * both a hashed `token` and a masked `key_name`, and fields are nullable\n * rather than optional.\n */\nexport interface LiteLLMUserKey {\n token: string;\n key_name?: string;\n key_alias?: string | null;\n spend?: number;\n expires?: string | null;\n models?: string[];\n tpm_limit?: number | null;\n rpm_limit?: number | null;\n max_budget?: number | null;\n budget_duration?: string | null;\n user_id?: string | null;\n team_id?: string | null;\n created_at: string;\n blocked?: boolean | null;\n /** Arbitrary metadata stored on the key record. */\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface DeleteKeyRequest {\n keys: string[];\n}\n\nexport interface LiteLLMConfig {\n baseUrl: string;\n masterKey: string;\n}\n\nexport interface ProvisioningDefaults {\n maxBudget: number;\n budgetDuration: string;\n models: string[];\n teams: string[];\n tpmLimit?: number;\n rpmLimit?: number;\n /**\n * LiteLLM user role applied on /user/new. Defaults to \"internal_user\"\n * which grants self-service Create/Delete/View on the user's own keys.\n * Valid values: proxy_admin, proxy_admin_viewer, internal_user,\n * internal_user_viewer, team.\n */\n userRole?: string;\n metadata: Record<string, string>;\n}\n\nexport interface RoleConfig {\n group: string;\n maxBudget?: number;\n budgetDuration?: string;\n models?: string[];\n teams?: string[];\n tpmLimit?: number;\n rpmLimit?: number;\n userRole?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface CreateUserRequest {\n user_id: string;\n user_email?: string;\n user_alias?: string;\n user_role?: string;\n max_budget?: number;\n budget_duration?: string;\n models?: string[];\n teams?: string[];\n tpm_limit?: number;\n rpm_limit?: number;\n metadata?: Record<string, string>;\n auto_create_key?: boolean;\n}\n\nexport interface CreateUserResponse {\n user_id: string;\n user_email?: string;\n max_budget?: number;\n models?: string[];\n teams?: string[];\n}\n\n\nexport interface AuditLogsParams {\n page?: number;\n page_size?: number;\n start_date?: string;\n end_date?: string;\n action?: string;\n table_name?: string;\n changed_by?: string;\n sort_by?: string;\n sort_order?: 'asc' | 'desc';\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { type UserInfo, type TeamMember, type TeamObjectPermission, type TeamInfo, type CreateTeamResponse, type VirtualKey, type ModelInfo, type UsageModelBreakdown, type UsageKeyBreakdown, type UsageDailyPoint, type UsageDailyModelPoint, type UsageMetrics, type TeamMemberUsage, type TeamMemberUsageRow, type GenerateKeyRequest, type UpdateKeyRequest, type GenerateKeyResponse, type AuditLogEntry, type PaginatedAuditLogs, type SpendLogEntry, type SpendLogsParams, type PaginatedSpendLogs, type QualityByModel, type QualityScore, type QualitySummary, type QualityResponse, } from '@acarmisc/backstage-plugin-litellm-common';
|
|
1
|
+
export { type UserInfo, type TeamMember, type TeamObjectPermission, type TeamInfo, type CreateTeamResponse, type VirtualKey, type ModelInfo, type UsageModelBreakdown, type UsageKeyBreakdown, type UsageDailyPoint, type UsageDailyModelPoint, type UsageMetrics, type TeamMemberUsage, type TeamMemberUsageRow, type TeamKeyUsage, type TeamKeyUsageRow, type GenerateKeyRequest, type UpdateKeyRequest, type GenerateKeyResponse, type AuditLogEntry, type PaginatedAuditLogs, type SpendLogEntry, type SpendLogsParams, type PaginatedSpendLogs, type QualityByModel, type QualityScore, type QualitySummary, type QualityResponse, } from '@acarmisc/backstage-plugin-litellm-common';
|
|
2
2
|
export interface CreateTeamRequest {
|
|
3
3
|
team_alias: string;
|
|
4
4
|
models?: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acarmisc/backstage-plugin-litellm-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "The Backstage backend plugin for LiteLLM governance",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "backend-plugin",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"prepack": "npm run build"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@acarmisc/backstage-plugin-litellm-common": "0.
|
|
38
|
+
"@acarmisc/backstage-plugin-litellm-common": "0.6.0",
|
|
39
39
|
"@backstage/backend-plugin-api": "^1.9.1",
|
|
40
40
|
"@backstage/catalog-client": "^1.9.0",
|
|
41
41
|
"@backstage/config": "^1.3.0",
|