@acarmisc/backstage-plugin-litellm-backend 0.16.1 → 0.17.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.cjs.js CHANGED
@@ -568,9 +568,9 @@ var require_index_cjs = __commonJS({
568
568
  }
569
569
  });
570
570
 
571
- // ../../node_modules/webidl-conversions/lib/index.js
571
+ // ../../node_modules/node-fetch/node_modules/webidl-conversions/lib/index.js
572
572
  var require_lib = __commonJS({
573
- "../../node_modules/webidl-conversions/lib/index.js"(exports2, module2) {
573
+ "../../node_modules/node-fetch/node_modules/webidl-conversions/lib/index.js"(exports2, module2) {
574
574
  "use strict";
575
575
  var conversions = {};
576
576
  module2.exports = conversions;
@@ -721,9 +721,9 @@ var require_lib = __commonJS({
721
721
  }
722
722
  });
723
723
 
724
- // ../../node_modules/whatwg-url/lib/utils.js
724
+ // ../../node_modules/node-fetch/node_modules/whatwg-url/lib/utils.js
725
725
  var require_utils = __commonJS({
726
- "../../node_modules/whatwg-url/lib/utils.js"(exports2, module2) {
726
+ "../../node_modules/node-fetch/node_modules/whatwg-url/lib/utils.js"(exports2, module2) {
727
727
  "use strict";
728
728
  module2.exports.mixin = function mixin(target, source) {
729
729
  const keys = Object.getOwnPropertyNames(source);
@@ -910,9 +910,9 @@ var require_tr46 = __commonJS({
910
910
  }
911
911
  });
912
912
 
913
- // ../../node_modules/whatwg-url/lib/url-state-machine.js
913
+ // ../../node_modules/node-fetch/node_modules/whatwg-url/lib/url-state-machine.js
914
914
  var require_url_state_machine = __commonJS({
915
- "../../node_modules/whatwg-url/lib/url-state-machine.js"(exports2, module2) {
915
+ "../../node_modules/node-fetch/node_modules/whatwg-url/lib/url-state-machine.js"(exports2, module2) {
916
916
  "use strict";
917
917
  var punycode = require("punycode");
918
918
  var tr46 = require_tr46();
@@ -1982,9 +1982,9 @@ var require_url_state_machine = __commonJS({
1982
1982
  }
1983
1983
  });
1984
1984
 
1985
- // ../../node_modules/whatwg-url/lib/URL-impl.js
1985
+ // ../../node_modules/node-fetch/node_modules/whatwg-url/lib/URL-impl.js
1986
1986
  var require_URL_impl = __commonJS({
1987
- "../../node_modules/whatwg-url/lib/URL-impl.js"(exports2) {
1987
+ "../../node_modules/node-fetch/node_modules/whatwg-url/lib/URL-impl.js"(exports2) {
1988
1988
  "use strict";
1989
1989
  var usm = require_url_state_machine();
1990
1990
  exports2.implementation = class URLImpl {
@@ -2139,9 +2139,9 @@ var require_URL_impl = __commonJS({
2139
2139
  }
2140
2140
  });
2141
2141
 
2142
- // ../../node_modules/whatwg-url/lib/URL.js
2142
+ // ../../node_modules/node-fetch/node_modules/whatwg-url/lib/URL.js
2143
2143
  var require_URL = __commonJS({
2144
- "../../node_modules/whatwg-url/lib/URL.js"(exports2, module2) {
2144
+ "../../node_modules/node-fetch/node_modules/whatwg-url/lib/URL.js"(exports2, module2) {
2145
2145
  "use strict";
2146
2146
  var conversions = require_lib();
2147
2147
  var utils = require_utils();
@@ -2321,9 +2321,9 @@ var require_URL = __commonJS({
2321
2321
  }
2322
2322
  });
2323
2323
 
2324
- // ../../node_modules/whatwg-url/lib/public-api.js
2324
+ // ../../node_modules/node-fetch/node_modules/whatwg-url/lib/public-api.js
2325
2325
  var require_public_api = __commonJS({
2326
- "../../node_modules/whatwg-url/lib/public-api.js"(exports2) {
2326
+ "../../node_modules/node-fetch/node_modules/whatwg-url/lib/public-api.js"(exports2) {
2327
2327
  "use strict";
2328
2328
  exports2.URL = require_URL().interface;
2329
2329
  exports2.serializeURL = require_url_state_machine().serializeURL;
@@ -8123,6 +8123,48 @@ var LiteLLMClient = class {
8123
8123
  throw err;
8124
8124
  }
8125
8125
  }
8126
+ /**
8127
+ * Searches for an existing user by email address. Returns the first matching
8128
+ * user or null if none found. Handles both response shapes: a bare array
8129
+ * or `{ users: [...] }`. Matching is case-insensitive on the email address.
8130
+ */
8131
+ async getUserByEmail(email) {
8132
+ try {
8133
+ const raw = await this.request(
8134
+ `/user/list?user_email=${encodeURIComponent(email)}`
8135
+ );
8136
+ let users = [];
8137
+ if (Array.isArray(raw)) {
8138
+ users = raw;
8139
+ } else if (Array.isArray(raw?.users)) {
8140
+ users = raw.users;
8141
+ }
8142
+ if (!users.length) return null;
8143
+ const found = users.find(
8144
+ (u) => (u.user_email ?? u.email ?? "").toLowerCase() === email.toLowerCase()
8145
+ );
8146
+ if (!found) return null;
8147
+ const inner = found.user_info ?? {};
8148
+ const teamIds = Array.isArray(found.teams) ? found.teams.map((t) => typeof t === "string" ? t : t?.team_id).filter((t) => typeof t === "string") : [];
8149
+ return {
8150
+ user_id: found.user_id ?? inner.user_id ?? "",
8151
+ user_email: inner.user_email ?? found.user_email,
8152
+ email: inner.email ?? found.email,
8153
+ teams: teamIds,
8154
+ models: inner.models ?? found.models,
8155
+ max_budget: inner.max_budget ?? found.max_budget,
8156
+ budget_duration: inner.budget_duration ?? found.budget_duration,
8157
+ budget_reset_at: inner.budget_reset_at ?? found.budget_reset_at,
8158
+ spend: inner.spend ?? found.spend,
8159
+ current_spend: inner.current_spend ?? found.current_spend,
8160
+ soft_limit: inner.soft_limit ?? found.soft_limit,
8161
+ hard_limit: inner.hard_limit ?? found.hard_limit
8162
+ };
8163
+ } catch (err) {
8164
+ if (err instanceof LiteLLMUpstreamError && err.status === 404) return null;
8165
+ throw err;
8166
+ }
8167
+ }
8126
8168
  async createUser(payload) {
8127
8169
  return this.request("/user/new", {
8128
8170
  method: "POST",
@@ -10292,12 +10334,9 @@ function registerKeysRoutes(router, ctx) {
10292
10334
  try {
10293
10335
  const { keyId } = req.params;
10294
10336
  const { tokenEntityRef, key } = await authorizeKeyAction(req, keyId);
10295
- const isOwnerUnblockingOwnBlock = key.metadata?.blocked_by === tokenEntityRef;
10296
- if (!isOwnerUnblockingOwnBlock) {
10297
- if (!await assertPermission(req, import_backstage_plugin_litellm_common3.litellmKeyUnblockPermission)) {
10298
- sendPermissionDenied(res, import_backstage_plugin_litellm_common3.litellmKeyUnblockPermission);
10299
- return;
10300
- }
10337
+ if (!await assertPermission(req, import_backstage_plugin_litellm_common3.litellmKeyUnblockPermission)) {
10338
+ sendPermissionDenied(res, import_backstage_plugin_litellm_common3.litellmKeyUnblockPermission);
10339
+ return;
10301
10340
  }
10302
10341
  await client.unblockKey(keyId);
10303
10342
  const updatedMetadata = {
@@ -11275,10 +11314,10 @@ function registerTeamUsageRoutes(router, ctx) {
11275
11314
  });
11276
11315
  }
11277
11316
 
11278
- // node_modules/jose/dist/node/esm/runtime/base64url.js
11317
+ // ../../node_modules/jose/dist/node/esm/runtime/base64url.js
11279
11318
  var import_node_buffer = require("node:buffer");
11280
11319
 
11281
- // node_modules/jose/dist/node/esm/lib/buffer_utils.js
11320
+ // ../../node_modules/jose/dist/node/esm/lib/buffer_utils.js
11282
11321
  var encoder = new TextEncoder();
11283
11322
  var decoder = new TextDecoder();
11284
11323
  var MAX_INT32 = 2 ** 32;
@@ -11293,7 +11332,7 @@ function concat(...buffers) {
11293
11332
  return buf;
11294
11333
  }
11295
11334
 
11296
- // node_modules/jose/dist/node/esm/runtime/base64url.js
11335
+ // ../../node_modules/jose/dist/node/esm/runtime/base64url.js
11297
11336
  function normalize(input) {
11298
11337
  let encoded = input;
11299
11338
  if (encoded instanceof Uint8Array) {
@@ -11303,7 +11342,7 @@ function normalize(input) {
11303
11342
  }
11304
11343
  var decode = (input) => new Uint8Array(import_node_buffer.Buffer.from(normalize(input), "base64url"));
11305
11344
 
11306
- // node_modules/jose/dist/node/esm/util/errors.js
11345
+ // ../../node_modules/jose/dist/node/esm/util/errors.js
11307
11346
  var JOSEError = class extends Error {
11308
11347
  static code = "ERR_JOSE_GENERIC";
11309
11348
  code = "ERR_JOSE_GENERIC";
@@ -11389,18 +11428,18 @@ var JWSSignatureVerificationFailed = class extends JOSEError {
11389
11428
  }
11390
11429
  };
11391
11430
 
11392
- // node_modules/jose/dist/node/esm/runtime/is_key_object.js
11431
+ // ../../node_modules/jose/dist/node/esm/runtime/is_key_object.js
11393
11432
  var util = __toESM(require("node:util"), 1);
11394
11433
  var is_key_object_default = (obj) => util.types.isKeyObject(obj);
11395
11434
 
11396
- // node_modules/jose/dist/node/esm/runtime/webcrypto.js
11435
+ // ../../node_modules/jose/dist/node/esm/runtime/webcrypto.js
11397
11436
  var crypto = __toESM(require("node:crypto"), 1);
11398
11437
  var util2 = __toESM(require("node:util"), 1);
11399
11438
  var webcrypto2 = crypto.webcrypto;
11400
11439
  var webcrypto_default = webcrypto2;
11401
11440
  var isCryptoKey = (key) => util2.types.isCryptoKey(key);
11402
11441
 
11403
- // node_modules/jose/dist/node/esm/lib/crypto_key.js
11442
+ // ../../node_modules/jose/dist/node/esm/lib/crypto_key.js
11404
11443
  function unusable(name, prop = "algorithm.name") {
11405
11444
  return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
11406
11445
  }
@@ -11499,7 +11538,7 @@ function checkSigCryptoKey(key, alg, ...usages) {
11499
11538
  checkUsage(key, usages);
11500
11539
  }
11501
11540
 
11502
- // node_modules/jose/dist/node/esm/lib/invalid_key_input.js
11541
+ // ../../node_modules/jose/dist/node/esm/lib/invalid_key_input.js
11503
11542
  function message(msg, actual, ...types4) {
11504
11543
  types4 = types4.filter(Boolean);
11505
11544
  if (types4.length > 2) {
@@ -11528,14 +11567,14 @@ function withAlg(alg, actual, ...types4) {
11528
11567
  return message(`Key for the ${alg} algorithm must be `, actual, ...types4);
11529
11568
  }
11530
11569
 
11531
- // node_modules/jose/dist/node/esm/runtime/is_key_like.js
11570
+ // ../../node_modules/jose/dist/node/esm/runtime/is_key_like.js
11532
11571
  var is_key_like_default = (key) => is_key_object_default(key) || isCryptoKey(key);
11533
11572
  var types3 = ["KeyObject"];
11534
11573
  if (globalThis.CryptoKey || webcrypto_default?.CryptoKey) {
11535
11574
  types3.push("CryptoKey");
11536
11575
  }
11537
11576
 
11538
- // node_modules/jose/dist/node/esm/lib/is_disjoint.js
11577
+ // ../../node_modules/jose/dist/node/esm/lib/is_disjoint.js
11539
11578
  var isDisjoint = (...headers) => {
11540
11579
  const sources = headers.filter(Boolean);
11541
11580
  if (sources.length === 0 || sources.length === 1) {
@@ -11559,7 +11598,7 @@ var isDisjoint = (...headers) => {
11559
11598
  };
11560
11599
  var is_disjoint_default = isDisjoint;
11561
11600
 
11562
- // node_modules/jose/dist/node/esm/lib/is_object.js
11601
+ // ../../node_modules/jose/dist/node/esm/lib/is_object.js
11563
11602
  function isObjectLike(value) {
11564
11603
  return typeof value === "object" && value !== null;
11565
11604
  }
@@ -11577,10 +11616,10 @@ function isObject(input) {
11577
11616
  return Object.getPrototypeOf(input) === proto;
11578
11617
  }
11579
11618
 
11580
- // node_modules/jose/dist/node/esm/runtime/get_named_curve.js
11619
+ // ../../node_modules/jose/dist/node/esm/runtime/get_named_curve.js
11581
11620
  var import_node_crypto = require("node:crypto");
11582
11621
 
11583
- // node_modules/jose/dist/node/esm/lib/is_jwk.js
11622
+ // ../../node_modules/jose/dist/node/esm/lib/is_jwk.js
11584
11623
  function isJWK(key) {
11585
11624
  return isObject(key) && typeof key.kty === "string";
11586
11625
  }
@@ -11594,7 +11633,7 @@ function isSecretJWK(key) {
11594
11633
  return isJWK(key) && key.kty === "oct" && typeof key.k === "string";
11595
11634
  }
11596
11635
 
11597
- // node_modules/jose/dist/node/esm/runtime/get_named_curve.js
11636
+ // ../../node_modules/jose/dist/node/esm/runtime/get_named_curve.js
11598
11637
  var namedCurveToJOSE = (namedCurve) => {
11599
11638
  switch (namedCurve) {
11600
11639
  case "prime256v1":
@@ -11643,7 +11682,7 @@ var getNamedCurve2 = (kee, raw) => {
11643
11682
  };
11644
11683
  var get_named_curve_default = getNamedCurve2;
11645
11684
 
11646
- // node_modules/jose/dist/node/esm/runtime/check_key_length.js
11685
+ // ../../node_modules/jose/dist/node/esm/runtime/check_key_length.js
11647
11686
  var import_node_crypto2 = require("node:crypto");
11648
11687
  var check_key_length_default = (key, alg) => {
11649
11688
  let modulusLength;
@@ -11660,7 +11699,7 @@ var check_key_length_default = (key, alg) => {
11660
11699
  }
11661
11700
  };
11662
11701
 
11663
- // node_modules/jose/dist/node/esm/runtime/jwk_to_key.js
11702
+ // ../../node_modules/jose/dist/node/esm/runtime/jwk_to_key.js
11664
11703
  var import_node_crypto3 = require("node:crypto");
11665
11704
  var parse = (key) => {
11666
11705
  if (key.d) {
@@ -11670,7 +11709,7 @@ var parse = (key) => {
11670
11709
  };
11671
11710
  var jwk_to_key_default = parse;
11672
11711
 
11673
- // node_modules/jose/dist/node/esm/key/import.js
11712
+ // ../../node_modules/jose/dist/node/esm/key/import.js
11674
11713
  async function importJWK(jwk, alg) {
11675
11714
  if (!isObject(jwk)) {
11676
11715
  throw new TypeError("JWK must be an object");
@@ -11694,7 +11733,7 @@ async function importJWK(jwk, alg) {
11694
11733
  }
11695
11734
  }
11696
11735
 
11697
- // node_modules/jose/dist/node/esm/lib/check_key_type.js
11736
+ // ../../node_modules/jose/dist/node/esm/lib/check_key_type.js
11698
11737
  var tag = (key) => key?.[Symbol.toStringTag];
11699
11738
  var jwkMatchesOp = (alg, key, usage) => {
11700
11739
  if (key.use !== void 0 && key.use !== "sig") {
@@ -11766,7 +11805,7 @@ function checkKeyType(allowJwk, alg, key, usage) {
11766
11805
  var check_key_type_default = checkKeyType.bind(void 0, false);
11767
11806
  var checkKeyTypeWithJwk = checkKeyType.bind(void 0, true);
11768
11807
 
11769
- // node_modules/jose/dist/node/esm/lib/validate_crit.js
11808
+ // ../../node_modules/jose/dist/node/esm/lib/validate_crit.js
11770
11809
  function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
11771
11810
  if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) {
11772
11811
  throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
@@ -11798,7 +11837,7 @@ function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader,
11798
11837
  }
11799
11838
  var validate_crit_default = validateCrit;
11800
11839
 
11801
- // node_modules/jose/dist/node/esm/lib/validate_algorithms.js
11840
+ // ../../node_modules/jose/dist/node/esm/lib/validate_algorithms.js
11802
11841
  var validateAlgorithms = (option, algorithms) => {
11803
11842
  if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== "string"))) {
11804
11843
  throw new TypeError(`"${option}" option must be an array of strings`);
@@ -11810,11 +11849,11 @@ var validateAlgorithms = (option, algorithms) => {
11810
11849
  };
11811
11850
  var validate_algorithms_default = validateAlgorithms;
11812
11851
 
11813
- // node_modules/jose/dist/node/esm/runtime/verify.js
11852
+ // ../../node_modules/jose/dist/node/esm/runtime/verify.js
11814
11853
  var crypto3 = __toESM(require("node:crypto"), 1);
11815
11854
  var import_node_util2 = require("node:util");
11816
11855
 
11817
- // node_modules/jose/dist/node/esm/runtime/dsa_digest.js
11856
+ // ../../node_modules/jose/dist/node/esm/runtime/dsa_digest.js
11818
11857
  function dsaDigest(alg) {
11819
11858
  switch (alg) {
11820
11859
  case "PS256":
@@ -11838,7 +11877,7 @@ function dsaDigest(alg) {
11838
11877
  }
11839
11878
  }
11840
11879
 
11841
- // node_modules/jose/dist/node/esm/runtime/node_key.js
11880
+ // ../../node_modules/jose/dist/node/esm/runtime/node_key.js
11842
11881
  var import_node_crypto4 = require("node:crypto");
11843
11882
  var ecCurveAlgMap = /* @__PURE__ */ new Map([
11844
11883
  ["ES256", "P-256"],
@@ -11942,11 +11981,11 @@ function keyForCrypto(alg, key) {
11942
11981
  return options ? { ...options, key } : key;
11943
11982
  }
11944
11983
 
11945
- // node_modules/jose/dist/node/esm/runtime/sign.js
11984
+ // ../../node_modules/jose/dist/node/esm/runtime/sign.js
11946
11985
  var crypto2 = __toESM(require("node:crypto"), 1);
11947
11986
  var import_node_util = require("node:util");
11948
11987
 
11949
- // node_modules/jose/dist/node/esm/runtime/hmac_digest.js
11988
+ // ../../node_modules/jose/dist/node/esm/runtime/hmac_digest.js
11950
11989
  function hmacDigest(alg) {
11951
11990
  switch (alg) {
11952
11991
  case "HS256":
@@ -11960,7 +11999,7 @@ function hmacDigest(alg) {
11960
11999
  }
11961
12000
  }
11962
12001
 
11963
- // node_modules/jose/dist/node/esm/runtime/get_sign_verify_key.js
12002
+ // ../../node_modules/jose/dist/node/esm/runtime/get_sign_verify_key.js
11964
12003
  var import_node_crypto5 = require("node:crypto");
11965
12004
  function getSignVerifyKey(alg, key, usage) {
11966
12005
  if (key instanceof Uint8Array) {
@@ -11985,7 +12024,7 @@ function getSignVerifyKey(alg, key, usage) {
11985
12024
  throw new TypeError(invalid_key_input_default(key, ...types3, "Uint8Array", "JSON Web Key"));
11986
12025
  }
11987
12026
 
11988
- // node_modules/jose/dist/node/esm/runtime/sign.js
12027
+ // ../../node_modules/jose/dist/node/esm/runtime/sign.js
11989
12028
  var oneShotSign = (0, import_node_util.promisify)(crypto2.sign);
11990
12029
  var sign2 = async (alg, key, data) => {
11991
12030
  const k = getSignVerifyKey(alg, key, "sign");
@@ -11998,7 +12037,7 @@ var sign2 = async (alg, key, data) => {
11998
12037
  };
11999
12038
  var sign_default = sign2;
12000
12039
 
12001
- // node_modules/jose/dist/node/esm/runtime/verify.js
12040
+ // ../../node_modules/jose/dist/node/esm/runtime/verify.js
12002
12041
  var oneShotVerify = (0, import_node_util2.promisify)(crypto3.verify);
12003
12042
  var verify2 = async (alg, key, signature, data) => {
12004
12043
  const k = getSignVerifyKey(alg, key, "verify");
@@ -12021,7 +12060,7 @@ var verify2 = async (alg, key, signature, data) => {
12021
12060
  };
12022
12061
  var verify_default = verify2;
12023
12062
 
12024
- // node_modules/jose/dist/node/esm/jws/flattened/verify.js
12063
+ // ../../node_modules/jose/dist/node/esm/jws/flattened/verify.js
12025
12064
  async function flattenedVerify(jws, key, options) {
12026
12065
  if (!isObject(jws)) {
12027
12066
  throw new JWSInvalid("Flattened JWS must be an object");
@@ -12127,7 +12166,7 @@ async function flattenedVerify(jws, key, options) {
12127
12166
  return result;
12128
12167
  }
12129
12168
 
12130
- // node_modules/jose/dist/node/esm/jws/compact/verify.js
12169
+ // ../../node_modules/jose/dist/node/esm/jws/compact/verify.js
12131
12170
  async function compactVerify(jws, key, options) {
12132
12171
  if (jws instanceof Uint8Array) {
12133
12172
  jws = decoder.decode(jws);
@@ -12147,10 +12186,10 @@ async function compactVerify(jws, key, options) {
12147
12186
  return result;
12148
12187
  }
12149
12188
 
12150
- // node_modules/jose/dist/node/esm/lib/epoch.js
12189
+ // ../../node_modules/jose/dist/node/esm/lib/epoch.js
12151
12190
  var epoch_default = (date) => Math.floor(date.getTime() / 1e3);
12152
12191
 
12153
- // node_modules/jose/dist/node/esm/lib/secs.js
12192
+ // ../../node_modules/jose/dist/node/esm/lib/secs.js
12154
12193
  var minute = 60;
12155
12194
  var hour = minute * 60;
12156
12195
  var day = hour * 24;
@@ -12207,7 +12246,7 @@ var secs_default = (str) => {
12207
12246
  return numericDate;
12208
12247
  };
12209
12248
 
12210
- // node_modules/jose/dist/node/esm/lib/jwt_claims_set.js
12249
+ // ../../node_modules/jose/dist/node/esm/lib/jwt_claims_set.js
12211
12250
  var normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, "");
12212
12251
  var checkAudiencePresence = (audPayload, audOption) => {
12213
12252
  if (typeof audPayload === "string") {
@@ -12303,7 +12342,7 @@ var jwt_claims_set_default = (protectedHeader, encodedPayload, options = {}) =>
12303
12342
  return payload;
12304
12343
  };
12305
12344
 
12306
- // node_modules/jose/dist/node/esm/jwt/verify.js
12345
+ // ../../node_modules/jose/dist/node/esm/jwt/verify.js
12307
12346
  async function jwtVerify(jwt, key, options) {
12308
12347
  const verified = await compactVerify(jwt, key, options);
12309
12348
  if (verified.protectedHeader.crit?.includes("b64") && verified.protectedHeader.b64 === false) {
@@ -12317,7 +12356,7 @@ async function jwtVerify(jwt, key, options) {
12317
12356
  return result;
12318
12357
  }
12319
12358
 
12320
- // node_modules/jose/dist/node/esm/jwks/local.js
12359
+ // ../../node_modules/jose/dist/node/esm/jwks/local.js
12321
12360
  function getKtyFromAlg(alg) {
12322
12361
  switch (typeof alg === "string" && alg.slice(0, 2)) {
12323
12362
  case "RS":
@@ -12438,7 +12477,7 @@ function createLocalJWKSet(jwks) {
12438
12477
  return localJWKSet;
12439
12478
  }
12440
12479
 
12441
- // node_modules/jose/dist/node/esm/runtime/fetch_jwks.js
12480
+ // ../../node_modules/jose/dist/node/esm/runtime/fetch_jwks.js
12442
12481
  var http = __toESM(require("node:http"), 1);
12443
12482
  var https = __toESM(require("node:https"), 1);
12444
12483
  var import_node_events = require("node:events");
@@ -12480,7 +12519,7 @@ var fetchJwks = async (url, timeout, options) => {
12480
12519
  };
12481
12520
  var fetch_jwks_default = fetchJwks;
12482
12521
 
12483
- // node_modules/jose/dist/node/esm/jwks/remote.js
12522
+ // ../../node_modules/jose/dist/node/esm/jwks/remote.js
12484
12523
  function isCloudflareWorkers() {
12485
12524
  return typeof WebSocketPair !== "undefined" || typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers" || typeof EdgeRuntime !== "undefined" && EdgeRuntime === "vercel";
12486
12525
  }
@@ -12721,13 +12760,32 @@ function resolveBridgeUserId(claims, identity) {
12721
12760
  `email domain mismatch: "${domain}" is not allowed for this deployment`
12722
12761
  );
12723
12762
  }
12724
- const name = claims.preferred_username?.trim() || emailLocalPart;
12763
+ let name = claims.preferred_username?.trim();
12764
+ if (name && name.includes("@")) {
12765
+ const usernameParts = name.split("@");
12766
+ if (usernameParts.length === 2 && usernameParts[0]) {
12767
+ const [userLocal, userDomain] = usernameParts;
12768
+ if (trusted.includes(userDomain.toLowerCase())) {
12769
+ name = userLocal;
12770
+ }
12771
+ }
12772
+ }
12773
+ name = name || emailLocalPart;
12725
12774
  return toLiteLLMUserId(name, userIdDomain);
12726
12775
  }
12727
12776
  async function getOrProvisionUserFromClaims(client, claims, provisioningEnabled, provisioningDefaults, logger, userIdDomain) {
12728
12777
  const userId = resolveBridgeUserId(claims, userIdDomain);
12729
12778
  const existing = await client.getUserInfo(userId);
12730
12779
  if (existing) return existing;
12780
+ if (claims.email) {
12781
+ const byEmail = await client.getUserByEmail(claims.email);
12782
+ if (byEmail) {
12783
+ logger.info(
12784
+ `Found existing LiteLLM user ${byEmail.user_id} by email ${claims.email}, reusing for ${userId}`
12785
+ );
12786
+ return byEmail;
12787
+ }
12788
+ }
12731
12789
  if (!provisioningEnabled) {
12732
12790
  throw new ProvisioningError(
12733
12791
  "User not found in LiteLLM",
@@ -12758,7 +12816,7 @@ async function getOrProvisionUserFromClaims(client, claims, provisioningEnabled,
12758
12816
  return created;
12759
12817
  }
12760
12818
  async function bridgeListKeys(client, claims, provisioningEnabled, provisioningDefaults, logger, userIdDomain) {
12761
- await getOrProvisionUserFromClaims(
12819
+ const user = await getOrProvisionUserFromClaims(
12762
12820
  client,
12763
12821
  claims,
12764
12822
  provisioningEnabled,
@@ -12766,10 +12824,10 @@ async function bridgeListKeys(client, claims, provisioningEnabled, provisioningD
12766
12824
  logger,
12767
12825
  userIdDomain
12768
12826
  );
12769
- return client.listKeys(resolveBridgeUserId(claims, userIdDomain));
12827
+ return client.listKeys(user.user_id);
12770
12828
  }
12771
12829
  async function bridgeGenerateKey(client, claims, provisioningEnabled, provisioningDefaults, logger, request, userIdDomain) {
12772
- await getOrProvisionUserFromClaims(
12830
+ const user = await getOrProvisionUserFromClaims(
12773
12831
  client,
12774
12832
  claims,
12775
12833
  provisioningEnabled,
@@ -12777,14 +12835,13 @@ async function bridgeGenerateKey(client, claims, provisioningEnabled, provisioni
12777
12835
  logger,
12778
12836
  userIdDomain
12779
12837
  );
12780
- const userId = resolveBridgeUserId(claims, userIdDomain);
12781
12838
  const enriched = {
12782
12839
  ...request,
12783
- user_id: userId,
12840
+ user_id: user.user_id,
12784
12841
  metadata: {
12785
12842
  ...request.metadata ?? {},
12786
12843
  created_via: "abby-cli",
12787
- created_by: userId,
12844
+ created_by: user.user_id,
12788
12845
  created_at_iso: (/* @__PURE__ */ new Date()).toISOString()
12789
12846
  }
12790
12847
  };