@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/index.esm.js CHANGED
@@ -96,9 +96,6 @@ var init_api = __esm({
96
96
  async deleteKey(keyId) {
97
97
  return this.del(`/keys/${encodeURIComponent(keyId)}`);
98
98
  }
99
- async rotateKey(keyId) {
100
- return this.post(`/keys/${encodeURIComponent(keyId)}/regenerate`, {});
101
- }
102
99
  async blockKey(keyId) {
103
100
  await this.post(`/keys/${encodeURIComponent(keyId)}/block`, {});
104
101
  }
@@ -316,9 +313,7 @@ var init_KeysTable = __esm({
316
313
  tpm_limit: void 0,
317
314
  rpm_limit: void 0,
318
315
  team_id: void 0,
319
- key_type: "llm_api",
320
- auto_rotate: false,
321
- rotation_interval_days: void 0
316
+ key_type: "llm_api"
322
317
  });
323
318
  keyToEditForm = (k) => ({
324
319
  key_alias: k.key_alias ?? "",
@@ -334,7 +329,6 @@ var init_KeysTable = __esm({
334
329
  loading,
335
330
  onGenerateKey,
336
331
  onUpdateKey,
337
- onRotateKey,
338
332
  onBlockKey,
339
333
  onUnblockKey,
340
334
  onResetKeySpend,
@@ -352,8 +346,6 @@ var init_KeysTable = __esm({
352
346
  const [editingKey, setEditingKey] = useState(null);
353
347
  const [editForm, setEditForm] = useState({});
354
348
  const [editSubmitting, setEditSubmitting] = useState(false);
355
- const [rotatingKeyId, setRotatingKeyId] = useState(null);
356
- const [rotatedKeyValue, setRotatedKeyValue] = useState(null);
357
349
  const [blockingKeyId, setBlockingKeyId] = useState(null);
358
350
  const [deleteConfirmId, setDeleteConfirmId] = useState(null);
359
351
  const [deleteSubmitting, setDeleteSubmitting] = useState(false);
@@ -433,17 +425,6 @@ var init_KeysTable = __esm({
433
425
  setEditSubmitting(false);
434
426
  }
435
427
  };
436
- const handleRotate = async (keyId) => {
437
- setRotatingKeyId(keyId);
438
- try {
439
- const response = await onRotateKey(keyId);
440
- setRotatedKeyValue(response.key);
441
- } catch (error) {
442
- console.error("Failed to rotate key:", error);
443
- } finally {
444
- setRotatingKeyId(null);
445
- }
446
- };
447
428
  const handleToggleBlock = async (key) => {
448
429
  const keyId = key.token ?? key.key;
449
430
  setBlockingKeyId(keyId);
@@ -548,7 +529,6 @@ var init_KeysTable = __esm({
548
529
  "Generate Your First Key"
549
530
  )))) : filteredKeys.map((key) => {
550
531
  const keyId = key.token ?? key.key;
551
- const isRotating = rotatingKeyId === keyId;
552
532
  const isBlocking = blockingKeyId === keyId;
553
533
  return /* @__PURE__ */ React2.createElement(TableRow, { key: keyId, sx: key.blocked ? { bgcolor: "action.disabledBackground" } : void 0 }, /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(Box2, { display: "flex", alignItems: "center", gap: 0.5 }, key.key_alias || "-", key.blocked && /* @__PURE__ */ React2.createElement(Chip2, { label: "Blocked", color: "error", size: "small" }))), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(Box2, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ React2.createElement(
554
534
  Typography2,
@@ -567,14 +547,6 @@ var init_KeysTable = __esm({
567
547
  },
568
548
  shortKeyId(keyId)
569
549
  ), /* @__PURE__ */ React2.createElement(IconButton, { size: "small", onClick: () => copyToClipboard(keyId), title: "Copy Key ID" }, /* @__PURE__ */ React2.createElement(ContentCopy, { fontSize: "small" })))), /* @__PURE__ */ React2.createElement(TableCell, null, formatDate(key.created_at)), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(ExpiryChip, { expiresAt: key.expires_at })), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(BudgetCell, { spend: key.spend ?? 0, maxBudget: key.max_budget })), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2" }, key.tpm_limit ?? "-", " / ", key.rpm_limit ?? "-")), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(Box2, { display: "flex", gap: 0.5, flexWrap: "wrap" }, key.models?.slice(0, 2).map((model) => /* @__PURE__ */ React2.createElement(Chip2, { key: model, label: model, size: "small" })), (key.models?.length || 0) > 2 && /* @__PURE__ */ React2.createElement(Chip2, { label: `+${(key.models?.length || 0) - 2}`, size: "small", variant: "outlined" }))), /* @__PURE__ */ React2.createElement(TableCell, { align: "right" }, /* @__PURE__ */ React2.createElement(IconButton, { onClick: () => handleOpenEdit(key), title: "Edit key" }, /* @__PURE__ */ React2.createElement(Edit, { fontSize: "small" })), /* @__PURE__ */ React2.createElement(
570
- IconButton,
571
- {
572
- onClick: () => handleRotate(keyId),
573
- disabled: isRotating,
574
- title: "Rotate key \u2014 generates a new secret, same settings"
575
- },
576
- isRotating ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 18 }) : /* @__PURE__ */ React2.createElement(Autorenew, { fontSize: "small" })
577
- ), /* @__PURE__ */ React2.createElement(
578
550
  IconButton,
579
551
  {
580
552
  onClick: () => handleToggleBlock(key),
@@ -721,36 +693,7 @@ var init_KeysTable = __esm({
721
693
  onChange: (e) => setFormData({ ...formData, rpm_limit: e.target.value ? Number(e.target.value) : void 0 }),
722
694
  fullWidth: true
723
695
  }
724
- ), /* @__PURE__ */ React2.createElement(
725
- FormControlLabel,
726
- {
727
- control: /* @__PURE__ */ React2.createElement(
728
- Checkbox,
729
- {
730
- checked: !!formData.auto_rotate,
731
- onChange: (e) => setFormData({
732
- ...formData,
733
- auto_rotate: e.target.checked,
734
- rotation_interval_days: e.target.checked ? formData.rotation_interval_days ?? 90 : void 0
735
- })
736
- }
737
- ),
738
- label: "Auto-rotate (LiteLLM rotates the secret on a schedule)"
739
- }
740
- ), formData.auto_rotate && /* @__PURE__ */ React2.createElement(
741
- TextField,
742
- {
743
- label: "Rotate every (days)",
744
- type: "number",
745
- value: formData.rotation_interval_days ?? "",
746
- onChange: (e) => setFormData({
747
- ...formData,
748
- rotation_interval_days: e.target.value ? Number(e.target.value) : void 0
749
- }),
750
- helperText: "LiteLLM enforces this interval server-side; the old secret stops working the moment it rotates.",
751
- fullWidth: true
752
- }
753
- ))), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseModal }, newKeyValue ? "Done" : "Cancel"), !newKeyValue && /* @__PURE__ */ React2.createElement(
696
+ ))), /* @__PURE__ */ React2.createElement(DialogActions, null, newKeyValue ? /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseModal, variant: "contained", color: "success" }, "Done") : /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseModal }, "Cancel"), /* @__PURE__ */ React2.createElement(
754
697
  Button,
755
698
  {
756
699
  onClick: handleGenerate,
@@ -759,7 +702,7 @@ var init_KeysTable = __esm({
759
702
  disabled: !canGenerate
760
703
  },
761
704
  submitting ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 24 }) : "Generate"
762
- ), newKeyValue && /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseModal, variant: "contained", color: "success" }, "Done"))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!editingKey, onClose: handleCloseEdit, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Edit Key"), /* @__PURE__ */ React2.createElement(DialogContent, null, editingKey && /* @__PURE__ */ React2.createElement(Box2, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ React2.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editingKey.key))), /* @__PURE__ */ React2.createElement(
705
+ )))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!editingKey, onClose: handleCloseEdit, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Edit Key"), /* @__PURE__ */ React2.createElement(DialogContent, null, editingKey && /* @__PURE__ */ React2.createElement(Box2, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ React2.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editingKey.key))), /* @__PURE__ */ React2.createElement(
763
706
  TextField,
764
707
  {
765
708
  label: "Alias",
@@ -825,26 +768,7 @@ var init_KeysTable = __esm({
825
768
  onClick: handleResetSpend
826
769
  },
827
770
  resetSpendSubmitting ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 16 }) : "Confirm"
828
- ), /* @__PURE__ */ React2.createElement(Button, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel"))))), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseEdit }, "Cancel"), /* @__PURE__ */ React2.createElement(Button, { onClick: handleUpdate, variant: "contained", color: "primary", disabled: editSubmitting }, editSubmitting ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 24 }) : "Save"))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!rotatedKeyValue, onClose: () => setRotatedKeyValue(null), maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Key Rotated"), /* @__PURE__ */ React2.createElement(DialogContent, null, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2", color: "text.secondary", gutterBottom: true }, "The old secret is now invalid. Copy the new one \u2014 you won't see it again."), /* @__PURE__ */ React2.createElement(
829
- Box2,
830
- {
831
- display: "flex",
832
- alignItems: "center",
833
- gap: 1,
834
- mt: 2,
835
- p: 2,
836
- sx: { backgroundColor: "action.hover", border: "1px solid", borderColor: "divider", borderRadius: 1 }
837
- },
838
- /* @__PURE__ */ React2.createElement(
839
- Typography2,
840
- {
841
- component: "code",
842
- sx: { fontFamily: "monospace", wordBreak: "break-all", flex: 1 }
843
- },
844
- rotatedKeyValue
845
- ),
846
- /* @__PURE__ */ React2.createElement(IconButton, { onClick: () => copyToClipboard(rotatedKeyValue) }, /* @__PURE__ */ React2.createElement(ContentCopy, null))
847
- )), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: () => setRotatedKeyValue(null), variant: "contained", color: "success" }, "Done"))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Revoke Key?"), /* @__PURE__ */ React2.createElement(DialogContent, null, /* @__PURE__ */ React2.createElement(Typography2, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ React2.createElement(
771
+ ), /* @__PURE__ */ React2.createElement(Button, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel"))))), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseEdit }, "Cancel"), /* @__PURE__ */ React2.createElement(Button, { onClick: handleUpdate, variant: "contained", color: "primary", disabled: editSubmitting }, editSubmitting ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 24 }) : "Save"))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Revoke Key?"), /* @__PURE__ */ React2.createElement(DialogContent, null, /* @__PURE__ */ React2.createElement(Typography2, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ React2.createElement(
848
772
  Button,
849
773
  {
850
774
  onClick: handleConfirmDelete,
@@ -1584,15 +1508,6 @@ var init_LiteLLMPage = __esm({
1584
1508
  },
1585
1509
  [api, refreshKeys]
1586
1510
  );
1587
- const handleRotateKey = useCallback2(
1588
- async (keyId) => {
1589
- const response = await api.rotateKey(keyId);
1590
- setSnackbar({ message: "Key rotated \u2014 copy the new secret now", severity: "success" });
1591
- refreshKeys();
1592
- return response;
1593
- },
1594
- [api, refreshKeys]
1595
- );
1596
1511
  const handleDeleteKey = useCallback2(
1597
1512
  async (keyId) => {
1598
1513
  try {
@@ -1662,7 +1577,6 @@ var init_LiteLLMPage = __esm({
1662
1577
  loading: keysLoading || modelsLoading,
1663
1578
  onGenerateKey: handleGenerateKey,
1664
1579
  onUpdateKey: handleUpdateKey,
1665
- onRotateKey: handleRotateKey,
1666
1580
  onBlockKey: handleBlockKey,
1667
1581
  onUnblockKey: handleUnblockKey,
1668
1582
  onResetKeySpend: handleResetKeySpend,