diff --git a/logo-coop.png b/logo-coop.png deleted file mode 100644 index 6327812..0000000 Binary files a/logo-coop.png and /dev/null differ diff --git a/logo.png b/logo.png deleted file mode 100644 index 6327812..0000000 Binary files a/logo.png and /dev/null differ diff --git a/logo.svg b/logo.svg deleted file mode 100644 index f810cd9..0000000 --- a/logo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/patches/keyBroker.js b/patches/keyBroker.js deleted file mode 100644 index 079d91a..0000000 --- a/patches/keyBroker.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Key broker sync — automatically provision a member's gateway key at SSO login. - * - * Inference Cooperative patch (MIT, same as LibreChat). When KEY_BROKER_URL is - * set, an OpenID (Cloudron SSO) login fetches-or-creates the member's chat key - * via the member portal's broker and stores it as the user's LibreChat key for - * the configured endpoint — so members never paste a key and all usage bills - * to their own LiteLLM team/budget. - * - * Env: - * KEY_BROKER_URL e.g. https://portal.inference.coop - * KEY_BROKER_SECRET the portal's BROKER_SECRET (x-broker-secret header) - * KEY_BROKER_KEY_NAME portal-side key name, default "chat" - * KEY_BROKER_ENDPOINT LibreChat endpoint (user-key) name, default "Inference Co-op" - * - * Semantics: create-on-first-login. If the member already has a portal-side - * "chat" key but LibreChat lost its stored copy, we deliberately do NOT rotate - * (rotation would silently break the member's own API scripts); they can - * rotate from the dashboard and log in again. - */ -const { updateUserKey, getUserKeyExpiry } = require('~/models'); -const { logger } = require('@librechat/data-schemas'); - -async function syncBrokerUserKey(user) { - const base = process.env.KEY_BROKER_URL; - const secret = process.env.KEY_BROKER_SECRET; - const userId = user?._id?.toString?.() || user?.id; - if (!base || !secret || !userId || !user?.email) return; - const keyName = process.env.KEY_BROKER_KEY_NAME || 'chat'; - const endpointName = process.env.KEY_BROKER_ENDPOINT || 'Inference Co-op'; - const headers = { - 'x-broker-secret': secret, - 'x-member-email': user.email, - }; - - // Does the member already have a portal-side chat key? - const listRes = await fetch(`${base}/broker/keys`, { headers }); - if (!listRes.ok) throw new Error(`broker list ${listRes.status}`); - const list = await listRes.json(); - const exists = (list.keys || []).some((k) => k.name === keyName); - - if (!exists) { - const createRes = await fetch(`${base}/broker/keys`, { - method: 'POST', - headers: { ...headers, 'content-type': 'application/json' }, - body: JSON.stringify({ name: keyName }), - }); - if (!createRes.ok) throw new Error(`broker create ${createRes.status}`); - const created = await createRes.json(); - if (!created.sk_token) throw new Error('broker returned no sk_token'); - // Store the key in LibreChat (JSON string as required by LibreChat storage) - await updateUserKey({ - userId: userId, - name: endpointName, - value: JSON.stringify({ apiKey: created.sk_token }), - expiresAt: null, - }); - logger.info(`[KeyBroker] provisioned "${keyName}" key for ${user.email} (endpoint: ${endpointName})`); - return; - } - - // Portal-side key exists — check whether LibreChat still holds a stored copy. - try { - const stored = await getUserKeyExpiry({ userId: user.id, name: endpointName }); - if (!stored) { - logger.warn( - `[KeyBroker] ${user.email} has a portal "${keyName}" key but no stored copy for endpoint "${endpointName}". ` + - 'Rotate the key on the dashboard and log in again (manual rotation avoids breaking their API scripts).', - ); - } - } catch (e) { - logger.warn(`[KeyBroker] stored-key check failed for ${user.email}: ${e.message}`); - } -} - -module.exports = { syncBrokerUserKey };