@acarmisc/backstage-plugin-litellm 0.10.0 → 0.10.1
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/api.d.ts +0 -2
- package/dist/components/KeysTable.d.ts +0 -1
- package/dist/index.cjs.js +4 -90
- package/dist/index.cjs.js.map +2 -2
- package/dist/index.esm.js +4 -90
- package/dist/index.esm.js.map +2 -2
- package/dist/types.d.ts +0 -4
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -8,7 +8,6 @@ export interface LiteLlmApiInterface {
|
|
|
8
8
|
deleteKey(keyId: string): Promise<{
|
|
9
9
|
success: boolean;
|
|
10
10
|
}>;
|
|
11
|
-
rotateKey(keyId: string): Promise<GenerateKeyResponse>;
|
|
12
11
|
blockKey(keyId: string): Promise<void>;
|
|
13
12
|
unblockKey(keyId: string): Promise<void>;
|
|
14
13
|
resetKeySpend(keyId: string): Promise<void>;
|
|
@@ -40,7 +39,6 @@ export declare class LiteLlmApi implements LiteLlmApiInterface {
|
|
|
40
39
|
deleteKey(keyId: string): Promise<{
|
|
41
40
|
success: boolean;
|
|
42
41
|
}>;
|
|
43
|
-
rotateKey(keyId: string): Promise<GenerateKeyResponse>;
|
|
44
42
|
blockKey(keyId: string): Promise<void>;
|
|
45
43
|
unblockKey(keyId: string): Promise<void>;
|
|
46
44
|
resetKeySpend(keyId: string): Promise<void>;
|
|
@@ -7,7 +7,6 @@ interface KeysTableProps {
|
|
|
7
7
|
loading: boolean;
|
|
8
8
|
onGenerateKey: (request: GenerateKeyRequest) => Promise<GenerateKeyResponse>;
|
|
9
9
|
onUpdateKey: (keyId: string, request: UpdateKeyRequest) => Promise<void>;
|
|
10
|
-
onRotateKey: (keyId: string) => Promise<GenerateKeyResponse>;
|
|
11
10
|
onBlockKey: (keyId: string) => Promise<void>;
|
|
12
11
|
onUnblockKey: (keyId: string) => Promise<void>;
|
|
13
12
|
onResetKeySpend: (keyId: string) => Promise<void>;
|
package/dist/index.cjs.js
CHANGED
|
@@ -118,9 +118,6 @@ var init_api = __esm({
|
|
|
118
118
|
async deleteKey(keyId) {
|
|
119
119
|
return this.del(`/keys/${encodeURIComponent(keyId)}`);
|
|
120
120
|
}
|
|
121
|
-
async rotateKey(keyId) {
|
|
122
|
-
return this.post(`/keys/${encodeURIComponent(keyId)}/regenerate`, {});
|
|
123
|
-
}
|
|
124
121
|
async blockKey(keyId) {
|
|
125
122
|
await this.post(`/keys/${encodeURIComponent(keyId)}/block`, {});
|
|
126
123
|
}
|
|
@@ -311,9 +308,7 @@ var init_KeysTable = __esm({
|
|
|
311
308
|
tpm_limit: void 0,
|
|
312
309
|
rpm_limit: void 0,
|
|
313
310
|
team_id: void 0,
|
|
314
|
-
key_type: "llm_api"
|
|
315
|
-
auto_rotate: false,
|
|
316
|
-
rotation_interval_days: void 0
|
|
311
|
+
key_type: "llm_api"
|
|
317
312
|
});
|
|
318
313
|
keyToEditForm = (k) => ({
|
|
319
314
|
key_alias: k.key_alias ?? "",
|
|
@@ -329,7 +324,6 @@ var init_KeysTable = __esm({
|
|
|
329
324
|
loading,
|
|
330
325
|
onGenerateKey,
|
|
331
326
|
onUpdateKey,
|
|
332
|
-
onRotateKey,
|
|
333
327
|
onBlockKey,
|
|
334
328
|
onUnblockKey,
|
|
335
329
|
onResetKeySpend,
|
|
@@ -347,8 +341,6 @@ var init_KeysTable = __esm({
|
|
|
347
341
|
const [editingKey, setEditingKey] = (0, import_react2.useState)(null);
|
|
348
342
|
const [editForm, setEditForm] = (0, import_react2.useState)({});
|
|
349
343
|
const [editSubmitting, setEditSubmitting] = (0, import_react2.useState)(false);
|
|
350
|
-
const [rotatingKeyId, setRotatingKeyId] = (0, import_react2.useState)(null);
|
|
351
|
-
const [rotatedKeyValue, setRotatedKeyValue] = (0, import_react2.useState)(null);
|
|
352
344
|
const [blockingKeyId, setBlockingKeyId] = (0, import_react2.useState)(null);
|
|
353
345
|
const [deleteConfirmId, setDeleteConfirmId] = (0, import_react2.useState)(null);
|
|
354
346
|
const [deleteSubmitting, setDeleteSubmitting] = (0, import_react2.useState)(false);
|
|
@@ -428,17 +420,6 @@ var init_KeysTable = __esm({
|
|
|
428
420
|
setEditSubmitting(false);
|
|
429
421
|
}
|
|
430
422
|
};
|
|
431
|
-
const handleRotate = async (keyId) => {
|
|
432
|
-
setRotatingKeyId(keyId);
|
|
433
|
-
try {
|
|
434
|
-
const response = await onRotateKey(keyId);
|
|
435
|
-
setRotatedKeyValue(response.key);
|
|
436
|
-
} catch (error) {
|
|
437
|
-
console.error("Failed to rotate key:", error);
|
|
438
|
-
} finally {
|
|
439
|
-
setRotatingKeyId(null);
|
|
440
|
-
}
|
|
441
|
-
};
|
|
442
423
|
const handleToggleBlock = async (key) => {
|
|
443
424
|
const keyId = key.token ?? key.key;
|
|
444
425
|
setBlockingKeyId(keyId);
|
|
@@ -543,7 +524,6 @@ var init_KeysTable = __esm({
|
|
|
543
524
|
"Generate Your First Key"
|
|
544
525
|
)))) : filteredKeys.map((key) => {
|
|
545
526
|
const keyId = key.token ?? key.key;
|
|
546
|
-
const isRotating = rotatingKeyId === keyId;
|
|
547
527
|
const isBlocking = blockingKeyId === keyId;
|
|
548
528
|
return /* @__PURE__ */ import_react2.default.createElement(import_material2.TableRow, { key: keyId, sx: key.blocked ? { bgcolor: "action.disabledBackground" } : void 0 }, /* @__PURE__ */ import_react2.default.createElement(import_material2.TableCell, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Box, { display: "flex", alignItems: "center", gap: 0.5 }, key.key_alias || "-", key.blocked && /* @__PURE__ */ import_react2.default.createElement(import_material2.Chip, { label: "Blocked", color: "error", size: "small" }))), /* @__PURE__ */ import_react2.default.createElement(import_material2.TableCell, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Box, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ import_react2.default.createElement(
|
|
549
529
|
import_material2.Typography,
|
|
@@ -562,14 +542,6 @@ var init_KeysTable = __esm({
|
|
|
562
542
|
},
|
|
563
543
|
shortKeyId(keyId)
|
|
564
544
|
), /* @__PURE__ */ import_react2.default.createElement(import_material2.IconButton, { size: "small", onClick: () => copyToClipboard(keyId), title: "Copy Key ID" }, /* @__PURE__ */ import_react2.default.createElement(import_icons_material.ContentCopy, { fontSize: "small" })))), /* @__PURE__ */ import_react2.default.createElement(import_material2.TableCell, null, formatDate(key.created_at)), /* @__PURE__ */ import_react2.default.createElement(import_material2.TableCell, null, /* @__PURE__ */ import_react2.default.createElement(ExpiryChip, { expiresAt: key.expires_at })), /* @__PURE__ */ import_react2.default.createElement(import_material2.TableCell, null, /* @__PURE__ */ import_react2.default.createElement(BudgetCell, { spend: key.spend ?? 0, maxBudget: key.max_budget })), /* @__PURE__ */ import_react2.default.createElement(import_material2.TableCell, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Typography, { variant: "body2" }, key.tpm_limit ?? "-", " / ", key.rpm_limit ?? "-")), /* @__PURE__ */ import_react2.default.createElement(import_material2.TableCell, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Box, { display: "flex", gap: 0.5, flexWrap: "wrap" }, key.models?.slice(0, 2).map((model) => /* @__PURE__ */ import_react2.default.createElement(import_material2.Chip, { key: model, label: model, size: "small" })), (key.models?.length || 0) > 2 && /* @__PURE__ */ import_react2.default.createElement(import_material2.Chip, { label: `+${(key.models?.length || 0) - 2}`, size: "small", variant: "outlined" }))), /* @__PURE__ */ import_react2.default.createElement(import_material2.TableCell, { align: "right" }, /* @__PURE__ */ import_react2.default.createElement(import_material2.IconButton, { onClick: () => handleOpenEdit(key), title: "Edit key" }, /* @__PURE__ */ import_react2.default.createElement(import_icons_material.Edit, { fontSize: "small" })), /* @__PURE__ */ import_react2.default.createElement(
|
|
565
|
-
import_material2.IconButton,
|
|
566
|
-
{
|
|
567
|
-
onClick: () => handleRotate(keyId),
|
|
568
|
-
disabled: isRotating,
|
|
569
|
-
title: "Rotate key \u2014 generates a new secret, same settings"
|
|
570
|
-
},
|
|
571
|
-
isRotating ? /* @__PURE__ */ import_react2.default.createElement(import_material2.CircularProgress, { size: 18 }) : /* @__PURE__ */ import_react2.default.createElement(import_icons_material.Autorenew, { fontSize: "small" })
|
|
572
|
-
), /* @__PURE__ */ import_react2.default.createElement(
|
|
573
545
|
import_material2.IconButton,
|
|
574
546
|
{
|
|
575
547
|
onClick: () => handleToggleBlock(key),
|
|
@@ -716,36 +688,7 @@ var init_KeysTable = __esm({
|
|
|
716
688
|
onChange: (e) => setFormData({ ...formData, rpm_limit: e.target.value ? Number(e.target.value) : void 0 }),
|
|
717
689
|
fullWidth: true
|
|
718
690
|
}
|
|
719
|
-
), /* @__PURE__ */ import_react2.default.createElement(
|
|
720
|
-
import_material2.FormControlLabel,
|
|
721
|
-
{
|
|
722
|
-
control: /* @__PURE__ */ import_react2.default.createElement(
|
|
723
|
-
import_material2.Checkbox,
|
|
724
|
-
{
|
|
725
|
-
checked: !!formData.auto_rotate,
|
|
726
|
-
onChange: (e) => setFormData({
|
|
727
|
-
...formData,
|
|
728
|
-
auto_rotate: e.target.checked,
|
|
729
|
-
rotation_interval_days: e.target.checked ? formData.rotation_interval_days ?? 90 : void 0
|
|
730
|
-
})
|
|
731
|
-
}
|
|
732
|
-
),
|
|
733
|
-
label: "Auto-rotate (LiteLLM rotates the secret on a schedule)"
|
|
734
|
-
}
|
|
735
|
-
), formData.auto_rotate && /* @__PURE__ */ import_react2.default.createElement(
|
|
736
|
-
import_material2.TextField,
|
|
737
|
-
{
|
|
738
|
-
label: "Rotate every (days)",
|
|
739
|
-
type: "number",
|
|
740
|
-
value: formData.rotation_interval_days ?? "",
|
|
741
|
-
onChange: (e) => setFormData({
|
|
742
|
-
...formData,
|
|
743
|
-
rotation_interval_days: e.target.value ? Number(e.target.value) : void 0
|
|
744
|
-
}),
|
|
745
|
-
helperText: "LiteLLM enforces this interval server-side; the old secret stops working the moment it rotates.",
|
|
746
|
-
fullWidth: true
|
|
747
|
-
}
|
|
748
|
-
))), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogActions, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: handleCloseModal }, newKeyValue ? "Done" : "Cancel"), !newKeyValue && /* @__PURE__ */ import_react2.default.createElement(
|
|
691
|
+
))), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogActions, null, newKeyValue ? /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: handleCloseModal, variant: "contained", color: "success" }, "Done") : /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: handleCloseModal }, "Cancel"), /* @__PURE__ */ import_react2.default.createElement(
|
|
749
692
|
import_material2.Button,
|
|
750
693
|
{
|
|
751
694
|
onClick: handleGenerate,
|
|
@@ -754,7 +697,7 @@ var init_KeysTable = __esm({
|
|
|
754
697
|
disabled: !canGenerate
|
|
755
698
|
},
|
|
756
699
|
submitting ? /* @__PURE__ */ import_react2.default.createElement(import_material2.CircularProgress, { size: 24 }) : "Generate"
|
|
757
|
-
)
|
|
700
|
+
)))), /* @__PURE__ */ import_react2.default.createElement(import_material2.Dialog, { open: !!editingKey, onClose: handleCloseEdit, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogTitle, null, "Edit Key"), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogContent, null, editingKey && /* @__PURE__ */ import_react2.default.createElement(import_material2.Box, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, /* @__PURE__ */ import_react2.default.createElement(import_material2.Typography, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ import_react2.default.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editingKey.key))), /* @__PURE__ */ import_react2.default.createElement(
|
|
758
701
|
import_material2.TextField,
|
|
759
702
|
{
|
|
760
703
|
label: "Alias",
|
|
@@ -820,26 +763,7 @@ var init_KeysTable = __esm({
|
|
|
820
763
|
onClick: handleResetSpend
|
|
821
764
|
},
|
|
822
765
|
resetSpendSubmitting ? /* @__PURE__ */ import_react2.default.createElement(import_material2.CircularProgress, { size: 16 }) : "Confirm"
|
|
823
|
-
), /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel"))))), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogActions, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: handleCloseEdit }, "Cancel"), /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: handleUpdate, variant: "contained", color: "primary", disabled: editSubmitting }, editSubmitting ? /* @__PURE__ */ import_react2.default.createElement(import_material2.CircularProgress, { size: 24 }) : "Save"))), /* @__PURE__ */ import_react2.default.createElement(import_material2.Dialog, { open: !!
|
|
824
|
-
import_material2.Box,
|
|
825
|
-
{
|
|
826
|
-
display: "flex",
|
|
827
|
-
alignItems: "center",
|
|
828
|
-
gap: 1,
|
|
829
|
-
mt: 2,
|
|
830
|
-
p: 2,
|
|
831
|
-
sx: { backgroundColor: "action.hover", border: "1px solid", borderColor: "divider", borderRadius: 1 }
|
|
832
|
-
},
|
|
833
|
-
/* @__PURE__ */ import_react2.default.createElement(
|
|
834
|
-
import_material2.Typography,
|
|
835
|
-
{
|
|
836
|
-
component: "code",
|
|
837
|
-
sx: { fontFamily: "monospace", wordBreak: "break-all", flex: 1 }
|
|
838
|
-
},
|
|
839
|
-
rotatedKeyValue
|
|
840
|
-
),
|
|
841
|
-
/* @__PURE__ */ import_react2.default.createElement(import_material2.IconButton, { onClick: () => copyToClipboard(rotatedKeyValue) }, /* @__PURE__ */ import_react2.default.createElement(import_icons_material.ContentCopy, null))
|
|
842
|
-
)), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogActions, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: () => setRotatedKeyValue(null), variant: "contained", color: "success" }, "Done"))), /* @__PURE__ */ import_react2.default.createElement(import_material2.Dialog, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogTitle, null, "Revoke Key?"), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogContent, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Typography, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogActions, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ import_react2.default.createElement(
|
|
766
|
+
), /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel"))))), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogActions, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: handleCloseEdit }, "Cancel"), /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: handleUpdate, variant: "contained", color: "primary", disabled: editSubmitting }, editSubmitting ? /* @__PURE__ */ import_react2.default.createElement(import_material2.CircularProgress, { size: 24 }) : "Save"))), /* @__PURE__ */ import_react2.default.createElement(import_material2.Dialog, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogTitle, null, "Revoke Key?"), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogContent, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Typography, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogActions, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ import_react2.default.createElement(
|
|
843
767
|
import_material2.Button,
|
|
844
768
|
{
|
|
845
769
|
onClick: handleConfirmDelete,
|
|
@@ -1500,15 +1424,6 @@ var init_LiteLLMPage = __esm({
|
|
|
1500
1424
|
},
|
|
1501
1425
|
[api, refreshKeys]
|
|
1502
1426
|
);
|
|
1503
|
-
const handleRotateKey = (0, import_react6.useCallback)(
|
|
1504
|
-
async (keyId) => {
|
|
1505
|
-
const response = await api.rotateKey(keyId);
|
|
1506
|
-
setSnackbar({ message: "Key rotated \u2014 copy the new secret now", severity: "success" });
|
|
1507
|
-
refreshKeys();
|
|
1508
|
-
return response;
|
|
1509
|
-
},
|
|
1510
|
-
[api, refreshKeys]
|
|
1511
|
-
);
|
|
1512
1427
|
const handleDeleteKey = (0, import_react6.useCallback)(
|
|
1513
1428
|
async (keyId) => {
|
|
1514
1429
|
try {
|
|
@@ -1578,7 +1493,6 @@ var init_LiteLLMPage = __esm({
|
|
|
1578
1493
|
loading: keysLoading || modelsLoading,
|
|
1579
1494
|
onGenerateKey: handleGenerateKey,
|
|
1580
1495
|
onUpdateKey: handleUpdateKey,
|
|
1581
|
-
onRotateKey: handleRotateKey,
|
|
1582
1496
|
onBlockKey: handleBlockKey,
|
|
1583
1497
|
onUnblockKey: handleUnblockKey,
|
|
1584
1498
|
onResetKeySpend: handleResetKeySpend,
|