@acarmisc/backstage-plugin-litellm-common 0.6.0 → 0.7.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/budgets.d.ts CHANGED
@@ -11,6 +11,6 @@ export type BudgetStatus = 'ok' | 'near' | 'over';
11
11
  export declare function budgetStatusForPct(pct: number): BudgetStatus;
12
12
  /**
13
13
  * Format a duration string to a human-readable label.
14
- * E.g., "1d" → "1 Day", "7d" → "7 Days".
14
+ * E.g., "1d" → "1 Day", "7d" → "7 Days", "never" → "Never".
15
15
  */
16
16
  export declare function formatDurationLabel(duration: string): string;
package/dist/budgets.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BUDGET_DANGER_PCT = exports.BUDGET_WARNING_PCT = void 0;
4
4
  exports.budgetStatusForPct = budgetStatusForPct;
5
5
  exports.formatDurationLabel = formatDurationLabel;
6
+ const keySchemas_1 = require("./keySchemas");
6
7
  /** Budget warning threshold (percent of cap). */
7
8
  exports.BUDGET_WARNING_PCT = 80;
8
9
  /** Budget danger threshold (percent of cap, at or over cap). */
@@ -20,9 +21,11 @@ function budgetStatusForPct(pct) {
20
21
  }
21
22
  /**
22
23
  * Format a duration string to a human-readable label.
23
- * E.g., "1d" → "1 Day", "7d" → "7 Days".
24
+ * E.g., "1d" → "1 Day", "7d" → "7 Days", "never" → "Never".
24
25
  */
25
26
  function formatDurationLabel(duration) {
27
+ if (duration === keySchemas_1.NEVER_KEY_DURATION)
28
+ return 'Never';
26
29
  const match = /^(\d+)([smhdwy])$/.exec(duration);
27
30
  if (!match)
28
31
  return duration;
package/dist/index.cjs.js CHANGED
@@ -26,6 +26,7 @@ __export(index_exports, {
26
26
  DEFAULT_KEY_BUDGET_DURATIONS: () => DEFAULT_KEY_BUDGET_DURATIONS,
27
27
  DEFAULT_KEY_DURATIONS: () => DEFAULT_KEY_DURATIONS,
28
28
  MCP_SERVER_NAME_RE: () => MCP_SERVER_NAME_RE,
29
+ NEVER_KEY_DURATION: () => NEVER_KEY_DURATION,
29
30
  RESERVED_METADATA_KEYS: () => RESERVED_METADATA_KEYS,
30
31
  budgetStatusForPct: () => budgetStatusForPct,
31
32
  createGenerateKeyInputSchema: () => createGenerateKeyInputSchema,
@@ -180,6 +181,7 @@ function createUpdateKeyInputSchema(config) {
180
181
  }).strict();
181
182
  }
182
183
  var DEFAULT_KEY_DURATIONS = ["1d", "7d", "30d", "90d"];
184
+ var NEVER_KEY_DURATION = "never";
183
185
  var DEFAULT_KEY_BUDGET_DURATIONS = ["1d", "7d", "30d", "1mo"];
184
186
 
185
187
  // src/budgets.ts
@@ -191,6 +193,7 @@ function budgetStatusForPct(pct) {
191
193
  return "ok";
192
194
  }
193
195
  function formatDurationLabel(duration) {
196
+ if (duration === NEVER_KEY_DURATION) return "Never";
194
197
  const match = /^(\d+)([smhdwy])$/.exec(duration);
195
198
  if (!match) return duration;
196
199
  const [, num, unit] = match;
@@ -223,6 +226,7 @@ function isModelAllowed(model, allowed) {
223
226
  DEFAULT_KEY_BUDGET_DURATIONS,
224
227
  DEFAULT_KEY_DURATIONS,
225
228
  MCP_SERVER_NAME_RE,
229
+ NEVER_KEY_DURATION,
226
230
  RESERVED_METADATA_KEYS,
227
231
  budgetStatusForPct,
228
232
  createGenerateKeyInputSchema,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts", "../src/permissions.ts", "../src/keySchemas.ts", "../src/budgets.ts", "../src/modelAccess.ts"],
4
- "sourcesContent": ["export * from './permissions';\nexport * from './keySchemas';\nexport * from './types';\nexport * from './budgets';\nexport * from './modelAccess';\n", "import { createPermission } from '@backstage/plugin-permission-common';\n\nexport const litellmKeyCreatePermission = createPermission({\n name: 'litellm.key.create',\n attributes: { action: 'create' },\n});\n\nexport const litellmKeyRevokePermission = createPermission({\n name: 'litellm.key.revoke',\n attributes: { action: 'delete' },\n});\n\nexport const litellmKeyManagePermission = createPermission({\n name: 'litellm.key.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmKeyResetSpendPermission = createPermission({\n name: 'litellm.key.resetSpend',\n attributes: { action: 'update' },\n});\n\nexport const litellmKeyUnblockPermission = createPermission({\n name: 'litellm.key.unblock',\n attributes: { action: 'update' },\n});\n\nexport const litellmAuditReadPermission = createPermission({\n name: 'litellm.audit.read',\n attributes: { action: 'read' },\n});\n\n// Team-management permissions \u2014 delegated to litellm-team-admins group\nexport const litellmTeamCreatePermission = createPermission({\n name: 'litellm.team.create',\n attributes: { action: 'create' },\n});\n\nexport const litellmTeamManagePermission = createPermission({\n name: 'litellm.team.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmTeamMembersManagePermission = createPermission({\n name: 'litellm.team.members.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmTeamKnowledgebaseManagePermission = createPermission({\n name: 'litellm.team.knowledgebase.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmTeamMcpManagePermission = createPermission({\n name: 'litellm.team.mcp.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmTeamDeletePermission = createPermission({\n name: 'litellm.team.delete',\n attributes: { action: 'delete' },\n});\n\n/**\n * Read the per-member usage breakdown of a team the caller belongs to.\n * Only consulted when `litellm.teamUsage.memberBreakdown.enabled` is true and\n * the permission framework is enabled.\n */\nexport const litellmTeamUsageReadPermission = createPermission({\n name: 'litellm.team.usage.read',\n attributes: { action: 'read' },\n});\n\nexport const litellmPermissions = [\n litellmKeyCreatePermission,\n litellmKeyRevokePermission,\n litellmKeyManagePermission,\n litellmKeyResetSpendPermission,\n litellmKeyUnblockPermission,\n litellmAuditReadPermission,\n litellmTeamCreatePermission,\n litellmTeamManagePermission,\n litellmTeamMembersManagePermission,\n litellmTeamKnowledgebaseManagePermission,\n litellmTeamMcpManagePermission,\n litellmTeamDeletePermission,\n litellmTeamUsageReadPermission,\n];\n", "import { z } from 'zod';\n\n/**\n * Configuration for key validation ceilings and allowed values.\n */\n/**\n * Metadata keys the server owns. Clients must not set them: `blocked_by` /\n * `blocked_at` decide who may unblock a key, and `created_*` / `updated_*`\n * record provenance.\n */\nexport const RESERVED_METADATA_KEYS = ['blocked_by', 'blocked_at'] as const;\nconst RESERVED_METADATA_PREFIXES = ['created_', 'updated_'] as const;\n\nexport function reservedMetadataKeys(metadata: Record<string, unknown>): string[] {\n return Object.keys(metadata).filter(\n k =>\n (RESERVED_METADATA_KEYS as readonly string[]).includes(k) ||\n RESERVED_METADATA_PREFIXES.some(p => k.startsWith(p)),\n );\n}\n\nexport interface KeyValidationConfig {\n maxBudget: number;\n maxTpm: number;\n maxRpm: number;\n allowedDurations: string[];\n /**\n * Allowed `budget_duration` values (how often a key's spend resets). An\n * empty list allows any value matching `<n><s|m|h|d|mo>`. Omitted means\n * {@link DEFAULT_KEY_BUDGET_DURATIONS}.\n */\n allowedBudgetDurations?: string[];\n}\n\n/** Allowed characters in an MCP server name sent to or listed by the bridge. */\nexport const MCP_SERVER_NAME_RE = /^[A-Za-z0-9._-]+$/;\n\n/**\n * Creates a strict Zod schema for GenerateKeyInput validation.\n * Rejects unknown fields and enforces server-side ceilings.\n *\n * @param config Server configuration with ceiling values and allowed durations\n * @returns A Zod object schema that validates the input\n */\nexport function createGenerateKeyInputSchema(config: KeyValidationConfig) {\n // When allowedDurations is set, restrict to that list.\n // Otherwise, allow any string matching the duration format regex.\n const durationSchema = config.allowedDurations.length > 0\n ? z.string().refine(\n (val) => config.allowedDurations.includes(val),\n {\n message: `duration must be one of: ${config.allowedDurations.join(', ')}`,\n },\n )\n : z.string().regex(/^\\d+[smhdwy]$/, {\n message: 'duration must match format <number><unit> (e.g. \"30d\", \"1h\")',\n });\n\n const budgetDurations = config.allowedBudgetDurations ?? DEFAULT_KEY_BUDGET_DURATIONS;\n const budgetDurationSchema = budgetDurations.length > 0\n ? z.string().refine(\n (val) => budgetDurations.includes(val),\n {\n message: `budget_duration must be one of: ${budgetDurations.join(', ')}`,\n },\n )\n : z.string().regex(/^\\d+(s|m|h|d|mo)$/, {\n message: 'budget_duration must match format <number><unit> (e.g. \"30d\", \"1mo\")',\n });\n\n return z\n .object({\n alias: z\n .string()\n .trim()\n .min(1, 'alias is required')\n .max(128, 'alias must be at most 128 characters'),\n models: z\n .array(z.string())\n .max(100, 'models array is too large')\n .optional(),\n duration: durationSchema.optional(),\n max_budget: z\n .number()\n .positive('max_budget must be a positive number')\n .max(config.maxBudget, `max_budget must not exceed ${config.maxBudget}`)\n .nullable()\n .optional(),\n budget_duration: budgetDurationSchema.optional(),\n tpm_limit: z\n .number()\n .int('tpm_limit must be an integer')\n .positive('tpm_limit must be a positive number')\n .max(config.maxTpm, `tpm_limit must not exceed ${config.maxTpm}`)\n .optional(),\n rpm_limit: z\n .number()\n .int('rpm_limit must be an integer')\n .positive('rpm_limit must be a positive number')\n .max(config.maxRpm, `rpm_limit must not exceed ${config.maxRpm}`)\n .optional(),\n team_id: z.string().optional(),\n // MCP servers the key may use; must be a subset of the team's (checked\n // server-side). [] denies every MCP server; omitted leaves LiteLLM's\n // default. Names only, so the value is safe to forward as-is.\n mcp_servers: z\n .array(\n z\n .string()\n .min(1)\n .max(128)\n .regex(MCP_SERVER_NAME_RE, 'mcp_servers entries may only use letters, digits, \".\", \"_\" and \"-\"'),\n )\n .max(50, 'mcp_servers array is too large')\n .optional(),\n // The UI always sends 'llm_api'; no other key type may be requested.\n key_type: z.literal('llm_api').optional(),\n metadata: z\n .record(z.string(), z.string())\n .refine(m => reservedMetadataKeys(m).length === 0, {\n message:\n 'metadata may not set server-owned keys (blocked_by, blocked_at, created_*, updated_*)',\n })\n .optional(),\n })\n .strict();\n}\n\nexport type GenerateKeyInput = z.infer<\n ReturnType<typeof createGenerateKeyInputSchema>\n>;\n\n/**\n * Creates a strict Zod schema for UpdateKeyInput validation.\n * Only allows key_alias, models, max_budget, tpm_limit, and rpm_limit fields.\n * Rejects all other fields including team_id, user_id, spend, blocked, key, and budget_duration.\n *\n * @param config Server configuration with ceiling values\n * @returns A Zod object schema that validates the input\n */\nexport function createUpdateKeyInputSchema(config: KeyValidationConfig) {\n return z\n .object({\n key_alias: z\n .string()\n .trim()\n .min(1, 'key_alias is required')\n .max(128, 'key_alias must be at most 128 characters')\n .optional(),\n models: z\n .array(z.string())\n .max(100, 'models array is too large')\n .optional(),\n max_budget: z\n .number()\n .positive('max_budget must be a positive number')\n .max(config.maxBudget, `max_budget must not exceed ${config.maxBudget}`)\n .nullable()\n .optional(),\n tpm_limit: z\n .number()\n .int('tpm_limit must be an integer')\n .positive('tpm_limit must be a positive number')\n .max(config.maxTpm, `tpm_limit must not exceed ${config.maxTpm}`)\n .optional(),\n rpm_limit: z\n .number()\n .int('rpm_limit must be an integer')\n .positive('rpm_limit must be a positive number')\n .max(config.maxRpm, `rpm_limit must not exceed ${config.maxRpm}`)\n .optional(),\n })\n .strict();\n}\n\nexport type UpdateKeyInput = z.infer<\n ReturnType<typeof createUpdateKeyInputSchema>\n>;\n\n/**\n * Default key duration presets. Used as server-side defaults and UI options.\n */\nexport const DEFAULT_KEY_DURATIONS = ['1d', '7d', '30d', '90d'];\n\n/**\n * Default `budget_duration` values a key may be generated with.\n */\nexport const DEFAULT_KEY_BUDGET_DURATIONS = ['1d', '7d', '30d', '1mo'];\n", "/** Budget warning threshold (percent of cap). */\nexport const BUDGET_WARNING_PCT = 80;\n\n/** Budget danger threshold (percent of cap, at or over cap). */\nexport const BUDGET_DANGER_PCT = 100;\n\n/** Consumption status derived from spend vs. cap. */\nexport type BudgetStatus = 'ok' | 'near' | 'over';\n\n/**\n * Compute budget status from spend percentage of cap.\n * Thresholds: near >= 80%, over >= 100%.\n */\nexport function budgetStatusForPct(pct: number): BudgetStatus {\n if (pct >= BUDGET_DANGER_PCT) return 'over';\n if (pct >= BUDGET_WARNING_PCT) return 'near';\n return 'ok';\n}\n\n/**\n * Format a duration string to a human-readable label.\n * E.g., \"1d\" \u2192 \"1 Day\", \"7d\" \u2192 \"7 Days\".\n */\nexport function formatDurationLabel(duration: string): string {\n const match = /^(\\d+)([smhdwy])$/.exec(duration);\n if (!match) return duration;\n\n const [, num, unit] = match;\n const n = Number(num);\n\n const unitLabels: Record<string, string> = {\n s: 'Second',\n m: 'Minute',\n h: 'Hour',\n d: 'Day',\n w: 'Week',\n y: 'Year',\n };\n\n const label = unitLabels[unit] || unit;\n return n === 1 ? `1 ${label}` : `${n} ${label}s`;\n}\n", "/**\n * LiteLLM sentinel: a team's (or user's) `models` list is `[\"all-proxy-models\"]`\n * when it isn't restricted to specific models.\n */\nexport const ALL_PROXY_MODELS = 'all-proxy-models';\n\n/**\n * Whether a model is allowed by an allow-list. The list is unrestricted when it\n * is empty/missing or contains the `all-proxy-models` sentinel. Entries may be\n * literal model names OR access-group names (litellm model_info.access_groups),\n * so a model also passes when one of its access groups is listed.\n */\nexport function isModelAllowed(\n model: { model_name: string; access_groups?: string[] },\n allowed?: string[],\n): boolean {\n if (!allowed || allowed.length === 0) return true;\n if (allowed.includes(ALL_PROXY_MODELS)) return true;\n if (allowed.includes(model.model_name)) return true;\n return !!model.access_groups?.some(group => allowed.includes(group));\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,sCAAiC;AAE1B,IAAM,iCAA6B,kDAAiB;AAAA,EACzD,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,iCAA6B,kDAAiB;AAAA,EACzD,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,iCAA6B,kDAAiB;AAAA,EACzD,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,qCAAiC,kDAAiB;AAAA,EAC7D,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,kCAA8B,kDAAiB;AAAA,EAC1D,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,iCAA6B,kDAAiB;AAAA,EACzD,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,OAAO;AAC/B,CAAC;AAGM,IAAM,kCAA8B,kDAAiB;AAAA,EAC1D,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,kCAA8B,kDAAiB;AAAA,EAC1D,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,yCAAqC,kDAAiB;AAAA,EACjE,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,+CAA2C,kDAAiB;AAAA,EACvE,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,qCAAiC,kDAAiB;AAAA,EAC7D,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAEM,IAAM,kCAA8B,kDAAiB;AAAA,EAC1D,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,SAAS;AACjC,CAAC;AAOM,IAAM,qCAAiC,kDAAiB;AAAA,EAC7D,MAAM;AAAA,EACN,YAAY,EAAE,QAAQ,OAAO;AAC/B,CAAC;AAEM,IAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ACvFA,iBAAkB;AAUX,IAAM,yBAAyB,CAAC,cAAc,YAAY;AACjE,IAAM,6BAA6B,CAAC,YAAY,UAAU;AAEnD,SAAS,qBAAqB,UAA6C;AAChF,SAAO,OAAO,KAAK,QAAQ,EAAE;AAAA,IAC3B,OACG,uBAA6C,SAAS,CAAC,KACxD,2BAA2B,KAAK,OAAK,EAAE,WAAW,CAAC,CAAC;AAAA,EACxD;AACF;AAgBO,IAAM,qBAAqB;AAS3B,SAAS,6BAA6B,QAA6B;AAGxE,QAAM,iBAAiB,OAAO,iBAAiB,SAAS,IACpD,aAAE,OAAO,EAAE;AAAA,IACT,CAAC,QAAQ,OAAO,iBAAiB,SAAS,GAAG;AAAA,IAC7C;AAAA,MACE,SAAS,4BAA4B,OAAO,iBAAiB,KAAK,IAAI,CAAC;AAAA,IACzE;AAAA,EACF,IACA,aAAE,OAAO,EAAE,MAAM,iBAAiB;AAAA,IAChC,SAAS;AAAA,EACX,CAAC;AAEL,QAAM,kBAAkB,OAAO,0BAA0B;AACzD,QAAM,uBAAuB,gBAAgB,SAAS,IAClD,aAAE,OAAO,EAAE;AAAA,IACT,CAAC,QAAQ,gBAAgB,SAAS,GAAG;AAAA,IACrC;AAAA,MACE,SAAS,mCAAmC,gBAAgB,KAAK,IAAI,CAAC;AAAA,IACxE;AAAA,EACF,IACA,aAAE,OAAO,EAAE,MAAM,qBAAqB;AAAA,IACpC,SAAS;AAAA,EACX,CAAC;AAEL,SAAO,aACJ,OAAO;AAAA,IACN,OAAO,aACJ,OAAO,EACP,KAAK,EACL,IAAI,GAAG,mBAAmB,EAC1B,IAAI,KAAK,sCAAsC;AAAA,IAClD,QAAQ,aACL,MAAM,aAAE,OAAO,CAAC,EAChB,IAAI,KAAK,2BAA2B,EACpC,SAAS;AAAA,IACZ,UAAU,eAAe,SAAS;AAAA,IAClC,YAAY,aACT,OAAO,EACP,SAAS,sCAAsC,EAC/C,IAAI,OAAO,WAAW,8BAA8B,OAAO,SAAS,EAAE,EACtE,SAAS,EACT,SAAS;AAAA,IACZ,iBAAiB,qBAAqB,SAAS;AAAA,IAC/C,WAAW,aACR,OAAO,EACP,IAAI,8BAA8B,EAClC,SAAS,qCAAqC,EAC9C,IAAI,OAAO,QAAQ,6BAA6B,OAAO,MAAM,EAAE,EAC/D,SAAS;AAAA,IACZ,WAAW,aACR,OAAO,EACP,IAAI,8BAA8B,EAClC,SAAS,qCAAqC,EAC9C,IAAI,OAAO,QAAQ,6BAA6B,OAAO,MAAM,EAAE,EAC/D,SAAS;AAAA,IACZ,SAAS,aAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA,IAI7B,aAAa,aACV;AAAA,MACC,aACG,OAAO,EACP,IAAI,CAAC,EACL,IAAI,GAAG,EACP,MAAM,oBAAoB,oEAAoE;AAAA,IACnG,EACC,IAAI,IAAI,gCAAgC,EACxC,SAAS;AAAA;AAAA,IAEZ,UAAU,aAAE,QAAQ,SAAS,EAAE,SAAS;AAAA,IACxC,UAAU,aACP,OAAO,aAAE,OAAO,GAAG,aAAE,OAAO,CAAC,EAC7B,OAAO,OAAK,qBAAqB,CAAC,EAAE,WAAW,GAAG;AAAA,MACjD,SACE;AAAA,IACJ,CAAC,EACA,SAAS;AAAA,EACd,CAAC,EACA,OAAO;AACZ;AAcO,SAAS,2BAA2B,QAA6B;AACtE,SAAO,aACJ,OAAO;AAAA,IACN,WAAW,aACR,OAAO,EACP,KAAK,EACL,IAAI,GAAG,uBAAuB,EAC9B,IAAI,KAAK,0CAA0C,EACnD,SAAS;AAAA,IACZ,QAAQ,aACL,MAAM,aAAE,OAAO,CAAC,EAChB,IAAI,KAAK,2BAA2B,EACpC,SAAS;AAAA,IACZ,YAAY,aACT,OAAO,EACP,SAAS,sCAAsC,EAC/C,IAAI,OAAO,WAAW,8BAA8B,OAAO,SAAS,EAAE,EACtE,SAAS,EACT,SAAS;AAAA,IACZ,WAAW,aACR,OAAO,EACP,IAAI,8BAA8B,EAClC,SAAS,qCAAqC,EAC9C,IAAI,OAAO,QAAQ,6BAA6B,OAAO,MAAM,EAAE,EAC/D,SAAS;AAAA,IACZ,WAAW,aACR,OAAO,EACP,IAAI,8BAA8B,EAClC,SAAS,qCAAqC,EAC9C,IAAI,OAAO,QAAQ,6BAA6B,OAAO,MAAM,EAAE,EAC/D,SAAS;AAAA,EACd,CAAC,EACA,OAAO;AACZ;AASO,IAAM,wBAAwB,CAAC,MAAM,MAAM,OAAO,KAAK;AAKvD,IAAM,+BAA+B,CAAC,MAAM,MAAM,OAAO,KAAK;;;AC1L9D,IAAM,qBAAqB;AAG3B,IAAM,oBAAoB;AAS1B,SAAS,mBAAmB,KAA2B;AAC5D,MAAI,OAAO,kBAAmB,QAAO;AACrC,MAAI,OAAO,mBAAoB,QAAO;AACtC,SAAO;AACT;AAMO,SAAS,oBAAoB,UAA0B;AAC5D,QAAM,QAAQ,oBAAoB,KAAK,QAAQ;AAC/C,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,CAAC,EAAE,KAAK,IAAI,IAAI;AACtB,QAAM,IAAI,OAAO,GAAG;AAEpB,QAAM,aAAqC;AAAA,IACzC,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AAEA,QAAM,QAAQ,WAAW,IAAI,KAAK;AAClC,SAAO,MAAM,IAAI,KAAK,KAAK,KAAK,GAAG,CAAC,IAAI,KAAK;AAC/C;;;ACrCO,IAAM,mBAAmB;AAQzB,SAAS,eACd,OACA,SACS;AACT,MAAI,CAAC,WAAW,QAAQ,WAAW,EAAG,QAAO;AAC7C,MAAI,QAAQ,SAAS,gBAAgB,EAAG,QAAO;AAC/C,MAAI,QAAQ,SAAS,MAAM,UAAU,EAAG,QAAO;AAC/C,SAAO,CAAC,CAAC,MAAM,eAAe,KAAK,WAAS,QAAQ,SAAS,KAAK,CAAC;AACrE;",
4
+ "sourcesContent": ["export * from './permissions';\nexport * from './keySchemas';\nexport * from './types';\nexport * from './budgets';\nexport * from './modelAccess';\n", "import { createPermission } from '@backstage/plugin-permission-common';\n\nexport const litellmKeyCreatePermission = createPermission({\n name: 'litellm.key.create',\n attributes: { action: 'create' },\n});\n\nexport const litellmKeyRevokePermission = createPermission({\n name: 'litellm.key.revoke',\n attributes: { action: 'delete' },\n});\n\nexport const litellmKeyManagePermission = createPermission({\n name: 'litellm.key.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmKeyResetSpendPermission = createPermission({\n name: 'litellm.key.resetSpend',\n attributes: { action: 'update' },\n});\n\nexport const litellmKeyUnblockPermission = createPermission({\n name: 'litellm.key.unblock',\n attributes: { action: 'update' },\n});\n\nexport const litellmAuditReadPermission = createPermission({\n name: 'litellm.audit.read',\n attributes: { action: 'read' },\n});\n\n// Team-management permissions \u2014 delegated to litellm-team-admins group\nexport const litellmTeamCreatePermission = createPermission({\n name: 'litellm.team.create',\n attributes: { action: 'create' },\n});\n\nexport const litellmTeamManagePermission = createPermission({\n name: 'litellm.team.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmTeamMembersManagePermission = createPermission({\n name: 'litellm.team.members.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmTeamKnowledgebaseManagePermission = createPermission({\n name: 'litellm.team.knowledgebase.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmTeamMcpManagePermission = createPermission({\n name: 'litellm.team.mcp.manage',\n attributes: { action: 'update' },\n});\n\nexport const litellmTeamDeletePermission = createPermission({\n name: 'litellm.team.delete',\n attributes: { action: 'delete' },\n});\n\n/**\n * Read the per-member usage breakdown of a team the caller belongs to.\n * Only consulted when `litellm.teamUsage.memberBreakdown.enabled` is true and\n * the permission framework is enabled.\n */\nexport const litellmTeamUsageReadPermission = createPermission({\n name: 'litellm.team.usage.read',\n attributes: { action: 'read' },\n});\n\nexport const litellmPermissions = [\n litellmKeyCreatePermission,\n litellmKeyRevokePermission,\n litellmKeyManagePermission,\n litellmKeyResetSpendPermission,\n litellmKeyUnblockPermission,\n litellmAuditReadPermission,\n litellmTeamCreatePermission,\n litellmTeamManagePermission,\n litellmTeamMembersManagePermission,\n litellmTeamKnowledgebaseManagePermission,\n litellmTeamMcpManagePermission,\n litellmTeamDeletePermission,\n litellmTeamUsageReadPermission,\n];\n", "import { z } from 'zod';\n\n/**\n * Configuration for key validation ceilings and allowed values.\n */\n/**\n * Metadata keys the server owns. Clients must not set them: `blocked_by` /\n * `blocked_at` decide who may unblock a key, and `created_*` / `updated_*`\n * record provenance.\n */\nexport const RESERVED_METADATA_KEYS = ['blocked_by', 'blocked_at'] as const;\nconst RESERVED_METADATA_PREFIXES = ['created_', 'updated_'] as const;\n\nexport function reservedMetadataKeys(metadata: Record<string, unknown>): string[] {\n return Object.keys(metadata).filter(\n k =>\n (RESERVED_METADATA_KEYS as readonly string[]).includes(k) ||\n RESERVED_METADATA_PREFIXES.some(p => k.startsWith(p)),\n );\n}\n\nexport interface KeyValidationConfig {\n maxBudget: number;\n maxTpm: number;\n maxRpm: number;\n allowedDurations: string[];\n /**\n * Allowed `budget_duration` values (how often a key's spend resets). An\n * empty list allows any value matching `<n><s|m|h|d|mo>`. Omitted means\n * {@link DEFAULT_KEY_BUDGET_DURATIONS}.\n */\n allowedBudgetDurations?: string[];\n}\n\n/** Allowed characters in an MCP server name sent to or listed by the bridge. */\nexport const MCP_SERVER_NAME_RE = /^[A-Za-z0-9._-]+$/;\n\n/**\n * Creates a strict Zod schema for GenerateKeyInput validation.\n * Rejects unknown fields and enforces server-side ceilings.\n *\n * @param config Server configuration with ceiling values and allowed durations\n * @returns A Zod object schema that validates the input\n */\nexport function createGenerateKeyInputSchema(config: KeyValidationConfig) {\n // When allowedDurations is set, restrict to that list.\n // Otherwise, allow any string matching the duration format regex.\n const durationSchema = config.allowedDurations.length > 0\n ? z.string().refine(\n (val) => config.allowedDurations.includes(val),\n {\n message: `duration must be one of: ${config.allowedDurations.join(', ')}`,\n },\n )\n : z.string().regex(/^\\d+[smhdwy]$/, {\n message: 'duration must match format <number><unit> (e.g. \"30d\", \"1h\")',\n });\n\n const budgetDurations = config.allowedBudgetDurations ?? DEFAULT_KEY_BUDGET_DURATIONS;\n const budgetDurationSchema = budgetDurations.length > 0\n ? z.string().refine(\n (val) => budgetDurations.includes(val),\n {\n message: `budget_duration must be one of: ${budgetDurations.join(', ')}`,\n },\n )\n : z.string().regex(/^\\d+(s|m|h|d|mo)$/, {\n message: 'budget_duration must match format <number><unit> (e.g. \"30d\", \"1mo\")',\n });\n\n return z\n .object({\n alias: z\n .string()\n .trim()\n .min(1, 'alias is required')\n .max(128, 'alias must be at most 128 characters'),\n models: z\n .array(z.string())\n .max(100, 'models array is too large')\n .optional(),\n duration: durationSchema.optional(),\n max_budget: z\n .number()\n .positive('max_budget must be a positive number')\n .max(config.maxBudget, `max_budget must not exceed ${config.maxBudget}`)\n .nullable()\n .optional(),\n budget_duration: budgetDurationSchema.optional(),\n tpm_limit: z\n .number()\n .int('tpm_limit must be an integer')\n .positive('tpm_limit must be a positive number')\n .max(config.maxTpm, `tpm_limit must not exceed ${config.maxTpm}`)\n .optional(),\n rpm_limit: z\n .number()\n .int('rpm_limit must be an integer')\n .positive('rpm_limit must be a positive number')\n .max(config.maxRpm, `rpm_limit must not exceed ${config.maxRpm}`)\n .optional(),\n team_id: z.string().optional(),\n // MCP servers the key may use; must be a subset of the team's (checked\n // server-side). [] denies every MCP server; omitted leaves LiteLLM's\n // default. Names only, so the value is safe to forward as-is.\n mcp_servers: z\n .array(\n z\n .string()\n .min(1)\n .max(128)\n .regex(MCP_SERVER_NAME_RE, 'mcp_servers entries may only use letters, digits, \".\", \"_\" and \"-\"'),\n )\n .max(50, 'mcp_servers array is too large')\n .optional(),\n // The UI always sends 'llm_api'; no other key type may be requested.\n key_type: z.literal('llm_api').optional(),\n metadata: z\n .record(z.string(), z.string())\n .refine(m => reservedMetadataKeys(m).length === 0, {\n message:\n 'metadata may not set server-owned keys (blocked_by, blocked_at, created_*, updated_*)',\n })\n .optional(),\n })\n .strict();\n}\n\nexport type GenerateKeyInput = z.infer<\n ReturnType<typeof createGenerateKeyInputSchema>\n>;\n\n/**\n * Creates a strict Zod schema for UpdateKeyInput validation.\n * Only allows key_alias, models, max_budget, tpm_limit, and rpm_limit fields.\n * Rejects all other fields including team_id, user_id, spend, blocked, key, and budget_duration.\n *\n * @param config Server configuration with ceiling values\n * @returns A Zod object schema that validates the input\n */\nexport function createUpdateKeyInputSchema(config: KeyValidationConfig) {\n return z\n .object({\n key_alias: z\n .string()\n .trim()\n .min(1, 'key_alias is required')\n .max(128, 'key_alias must be at most 128 characters')\n .optional(),\n models: z\n .array(z.string())\n .max(100, 'models array is too large')\n .optional(),\n max_budget: z\n .number()\n .positive('max_budget must be a positive number')\n .max(config.maxBudget, `max_budget must not exceed ${config.maxBudget}`)\n .nullable()\n .optional(),\n tpm_limit: z\n .number()\n .int('tpm_limit must be an integer')\n .positive('tpm_limit must be a positive number')\n .max(config.maxTpm, `tpm_limit must not exceed ${config.maxTpm}`)\n .optional(),\n rpm_limit: z\n .number()\n .int('rpm_limit must be an integer')\n .positive('rpm_limit must be a positive number')\n .max(config.maxRpm, `rpm_limit must not exceed ${config.maxRpm}`)\n .optional(),\n })\n .strict();\n}\n\nexport type UpdateKeyInput = z.infer<\n ReturnType<typeof createUpdateKeyInputSchema>\n>;\n\n/**\n * Default key duration presets. Used as server-side defaults and UI options.\n */\nexport const DEFAULT_KEY_DURATIONS = ['1d', '7d', '30d', '90d'];\n\n/**\n * Duration value for a key that never expires. Only accepted when listed in\n * `allowedDurations`; the backend then sends LiteLLM no `duration`.\n */\nexport const NEVER_KEY_DURATION = 'never';\n\n/**\n * Default `budget_duration` values a key may be generated with.\n */\nexport const DEFAULT_KEY_BUDGET_DURATIONS = ['1d', '7d', '30d', '1mo'];\n", "import { NEVER_KEY_DURATION } from './keySchemas';\n\n/** Budget warning threshold (percent of cap). */\nexport const BUDGET_WARNING_PCT = 80;\n\n/** Budget danger threshold (percent of cap, at or over cap). */\nexport const BUDGET_DANGER_PCT = 100;\n\n/** Consumption status derived from spend vs. cap. */\nexport type BudgetStatus = 'ok' | 'near' | 'over';\n\n/**\n * Compute budget status from spend percentage of cap.\n * Thresholds: near >= 80%, over >= 100%.\n */\nexport function budgetStatusForPct(pct: number): BudgetStatus {\n if (pct >= BUDGET_DANGER_PCT) return 'over';\n if (pct >= BUDGET_WARNING_PCT) return 'near';\n return 'ok';\n}\n\n/**\n * Format a duration string to a human-readable label.\n * E.g., \"1d\" \u2192 \"1 Day\", \"7d\" \u2192 \"7 Days\", \"never\" \u2192 \"Never\".\n */\nexport function formatDurationLabel(duration: string): string {\n if (duration === NEVER_KEY_DURATION) return 'Never';\n const match = /^(\\d+)([smhdwy])$/.exec(duration);\n if (!match) return duration;\n\n const [, num, unit] = match;\n const n = Number(num);\n\n const unitLabels: Record<string, string> = {\n s: 'Second',\n m: 'Minute',\n h: 'Hour',\n d: 'Day',\n w: 'Week',\n y: 'Year',\n };\n\n const label = unitLabels[unit] || unit;\n return n === 1 ? `1 ${label}` : `${n} ${label}s`;\n}\n", "/**\n * LiteLLM sentinel: a team's (or user's) `models` list is `[\"all-proxy-models\"]`\n * when it isn't restricted to specific models.\n */\nexport const ALL_PROXY_MODELS = 'all-proxy-models';\n\n/**\n * Whether a model is allowed by an allow-list. The list is unrestricted when it\n * is empty/missing or contains the `all-proxy-models` sentinel. Entries may be\n * literal model names OR access-group names (litellm model_info.access_groups),\n * so a model also passes when one of its access groups is listed.\n */\nexport function isModelAllowed(\n model: { model_name: string; access_groups?: string[] },\n allowed?: string[],\n): boolean {\n if (!allowed || allowed.length === 0) return true;\n if (allowed.includes(ALL_PROXY_MODELS)) return true;\n if (allowed.includes(model.model_name)) return true;\n return !!model.access_groups?.some(group => allowed.includes(group));\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -100,6 +100,11 @@ export type UpdateKeyInput = z.infer<ReturnType<typeof createUpdateKeyInputSchem
100
100
  * Default key duration presets. Used as server-side defaults and UI options.
101
101
  */
102
102
  export declare const DEFAULT_KEY_DURATIONS: string[];
103
+ /**
104
+ * Duration value for a key that never expires. Only accepted when listed in
105
+ * `allowedDurations`; the backend then sends LiteLLM no `duration`.
106
+ */
107
+ export declare const NEVER_KEY_DURATION = "never";
103
108
  /**
104
109
  * Default `budget_duration` values a key may be generated with.
105
110
  */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_KEY_BUDGET_DURATIONS = exports.DEFAULT_KEY_DURATIONS = exports.MCP_SERVER_NAME_RE = exports.RESERVED_METADATA_KEYS = void 0;
3
+ exports.DEFAULT_KEY_BUDGET_DURATIONS = exports.NEVER_KEY_DURATION = exports.DEFAULT_KEY_DURATIONS = exports.MCP_SERVER_NAME_RE = exports.RESERVED_METADATA_KEYS = void 0;
4
4
  exports.reservedMetadataKeys = reservedMetadataKeys;
5
5
  exports.createGenerateKeyInputSchema = createGenerateKeyInputSchema;
6
6
  exports.createUpdateKeyInputSchema = createUpdateKeyInputSchema;
@@ -146,6 +146,11 @@ function createUpdateKeyInputSchema(config) {
146
146
  * Default key duration presets. Used as server-side defaults and UI options.
147
147
  */
148
148
  exports.DEFAULT_KEY_DURATIONS = ['1d', '7d', '30d', '90d'];
149
+ /**
150
+ * Duration value for a key that never expires. Only accepted when listed in
151
+ * `allowedDurations`; the backend then sends LiteLLM no `duration`.
152
+ */
153
+ exports.NEVER_KEY_DURATION = 'never';
149
154
  /**
150
155
  * Default `budget_duration` values a key may be generated with.
151
156
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acarmisc/backstage-plugin-litellm-common",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Shared types, permissions, and schemas for the LiteLLM Backstage plugin",
5
5
  "backstage": {
6
6
  "role": "common-library",