@r8s/librechat 0.2.0 → 0.3.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/index.d.ts +144 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +219 -0
- package/dist/index.js.map +1 -0
- package/package.json +14 -7
- package/__tests__/librechat.test.ts +0 -545
- package/examples/basic.tsx +0 -17
- package/src/index.tsx +0 -384
- package/tsconfig.json +0 -15
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { SecretRef } from '@r8s/recipes';
|
|
2
|
+
export interface MongoConnection {
|
|
3
|
+
/** MongoDB host (cluster-internal service or external host) */
|
|
4
|
+
host: string;
|
|
5
|
+
/** MongoDB port (defaults to 27017) */
|
|
6
|
+
port?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Database username. Inlined as a plain env var — usernames are
|
|
9
|
+
* identifiers, not secrets (same convention as the n8n/outline DB
|
|
10
|
+
* recipes). When omitted, the username is read from the password
|
|
11
|
+
* secret (key: `username`).
|
|
12
|
+
*/
|
|
13
|
+
username?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Name of an existing Secret holding the MongoDB credentials.
|
|
16
|
+
* Keys: `username`, `password`.
|
|
17
|
+
*/
|
|
18
|
+
passwordSecret: string;
|
|
19
|
+
/**
|
|
20
|
+
* authSource query parameter appended to MONGO_URI when set
|
|
21
|
+
* (e.g. 'admin' for databases authenticating against the admin db).
|
|
22
|
+
*/
|
|
23
|
+
authSource?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface LibreChatProps {
|
|
26
|
+
/** Resource name (defaults to 'librechat') */
|
|
27
|
+
name?: string;
|
|
28
|
+
/** Kubernetes namespace (defaults to 'default') */
|
|
29
|
+
namespace?: string;
|
|
30
|
+
/** Container image tag (defaults to 'latest' — pin a version in production) */
|
|
31
|
+
version?: string;
|
|
32
|
+
/** Public hostname for the chat UI (required) */
|
|
33
|
+
host: string;
|
|
34
|
+
/** Port the app listens on in-container (defaults to 3080) */
|
|
35
|
+
port?: number;
|
|
36
|
+
/** Number of replicas (defaults to 1) */
|
|
37
|
+
replicas?: number;
|
|
38
|
+
/**
|
|
39
|
+
* External MongoDB connection (REQUIRED). LibreChat stores users,
|
|
40
|
+
* conversations and messages in MongoDB — this component does NOT
|
|
41
|
+
* provision it. Run MongoDB separately (replica-set StatefulSet,
|
|
42
|
+
* operator or managed service) and point this prop at it.
|
|
43
|
+
*/
|
|
44
|
+
mongodb: MongoConnection;
|
|
45
|
+
/** Provision a redis replication group for session caching (default: true) */
|
|
46
|
+
cache?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Add a Meilisearch sidecar service for full-text / RAG search
|
|
49
|
+
* (default: false). MEILI_MASTER_KEY is shared from the app secrets
|
|
50
|
+
* bundle (key: meiliMasterKey). Sets SEARCH=true on the app so it
|
|
51
|
+
* actually queries the meilisearch instance.
|
|
52
|
+
*/
|
|
53
|
+
search?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* OIDC SSO client — register LibreChat as a client in Keycloak (the
|
|
56
|
+
* Auth recipe) and reference the client secret through the backend.
|
|
57
|
+
* Uses the upstream OPENID_* env names; ALLOW_SOCIAL_LOGIN plus
|
|
58
|
+
* DOMAIN_SERVER/DOMAIN_CLIENT are set from `host`.
|
|
59
|
+
*/
|
|
60
|
+
sso?: {
|
|
61
|
+
issuer: string;
|
|
62
|
+
clientId: string;
|
|
63
|
+
clientSecretRef: SecretRef;
|
|
64
|
+
scopes?: string;
|
|
65
|
+
};
|
|
66
|
+
/** OpenAI-compatible API base URL for model calls (defaults to https://api.berget.ai/v1) */
|
|
67
|
+
backend?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Name of an existing Secret holding `secretKey`, `modelApiKey`,
|
|
70
|
+
* the multi-user session credentials `jwtSecret`, `jwtRefreshSecret`,
|
|
71
|
+
* `credsKey`, `credsIv` — and `meiliMasterKey` when `search` is enabled.
|
|
72
|
+
*
|
|
73
|
+
* Hex sizing: jwtSecret / jwtRefreshSecret / credsKey are 64 hex chars
|
|
74
|
+
* (32 bytes); credsIv is 32 hex chars (16 bytes — AES-IV).
|
|
75
|
+
*
|
|
76
|
+
* Required unless a secrets backend (openbao/vault) is configured on
|
|
77
|
+
* the surrounding Platform — the backend then provisions them.
|
|
78
|
+
* Plaintext secrets are not supported.
|
|
79
|
+
*/
|
|
80
|
+
secretsName?: string;
|
|
81
|
+
/** Requested resources */
|
|
82
|
+
resources?: {
|
|
83
|
+
requests?: {
|
|
84
|
+
cpu?: string;
|
|
85
|
+
memory?: string;
|
|
86
|
+
};
|
|
87
|
+
limits?: {
|
|
88
|
+
cpu?: string;
|
|
89
|
+
memory?: string;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
/** TLS configuration (defaults to letsencrypt-prod cluster issuer) */
|
|
93
|
+
tls?: {
|
|
94
|
+
secretName: string;
|
|
95
|
+
clusterIssuer: string;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* LibreChat — multi-model AI chat UI with external MongoDB, Redis
|
|
100
|
+
* sessions, optional Meilisearch and OIDC SSO.
|
|
101
|
+
*
|
|
102
|
+
* @title LibreChat
|
|
103
|
+
* @category AI & Chat
|
|
104
|
+
*
|
|
105
|
+
* Composes:
|
|
106
|
+
* - LibreChat Deployment + Service + Endpoint (MongoDB is provisioned
|
|
107
|
+
* externally — pass its coordinates via the required `mongodb` prop)
|
|
108
|
+
* - Redis replication group for session caching (default on, service
|
|
109
|
+
* ${name}-redis; USE_REDIS=true points sessions at it)
|
|
110
|
+
* - Optional Meilisearch Deployment + Service for message/RAG search
|
|
111
|
+
* (SEARCH=true wires the app to it)
|
|
112
|
+
* - SECRET_KEY / OPENAI_API_KEY / JWT + CREDS session credentials /
|
|
113
|
+
* MEILI_MASTER_KEY provisioned through the Platform secrets backend
|
|
114
|
+
* (openbao / vault), or referenced from an existing Secret
|
|
115
|
+
* - OIDC SSO against the Keycloak `Auth` recipe
|
|
116
|
+
*
|
|
117
|
+
* Wrap the component in `<Platform secrets={{ backend: 'openbao' }}>` and
|
|
118
|
+
* the app secrets bundle (keys: secretKey, modelApiKey, jwtSecret,
|
|
119
|
+
* jwtRefreshSecret, credsKey, credsIv, meiliMasterKey) is provisioned
|
|
120
|
+
* for you. Without a backend you must point `secretsName` at a
|
|
121
|
+
* pre-created Secret. MongoDB itself is NOT provisioned here — run it
|
|
122
|
+
* separately and connect via `mongodb`.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* import { Platform } from '@r8s/recipes'
|
|
126
|
+
* import { LibreChat } from '@r8s/librechat'
|
|
127
|
+
*
|
|
128
|
+
* export default (
|
|
129
|
+
* <Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'apps' }}>
|
|
130
|
+
* <LibreChat
|
|
131
|
+
* name="chat"
|
|
132
|
+
* host="chat.example.com"
|
|
133
|
+
* mongodb={{ host: 'mongo.data.svc.cluster.local', passwordSecret: 'chat-mongodb-credentials' }}
|
|
134
|
+
* sso={{
|
|
135
|
+
* issuer: 'https://keycloak.example.com/realms/platform',
|
|
136
|
+
* clientId: 'librechat',
|
|
137
|
+
* clientSecretRef: { secret: 'librechat-sso', key: 'clientSecret' },
|
|
138
|
+
* }}
|
|
139
|
+
* />
|
|
140
|
+
* </Platform>
|
|
141
|
+
* )
|
|
142
|
+
*/
|
|
143
|
+
export declare function LibreChat(props: LibreChatProps): import("@r8s/core").r8sElement;
|
|
144
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAG7C,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,OAAO,EAAE,eAAe,CAAA;IACxB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;;;OAKG;IACH,GAAG,CAAC,EAAE;QACJ,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,MAAM,CAAA;QAChB,eAAe,EAAE,SAAS,CAAA;QAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,4FAA4F;IAC5F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,0BAA0B;IAC1B,SAAS,CAAC,EAAE;QACV,QAAQ,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QAC5C,MAAM,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAC3C,CAAA;IACD,sEAAsE;IACtE,GAAG,CAAC,EAAE;QACJ,UAAU,EAAE,MAAM,CAAA;QAClB,aAAa,EAAE,MAAM,CAAA;KACtB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,kCA4O9C"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LibreChat = LibreChat;
|
|
4
|
+
const jsx_runtime_1 = require("@r8s/core/jsx-runtime");
|
|
5
|
+
const core_1 = require("@r8s/core");
|
|
6
|
+
const defaults_1 = require("@r8s/core/defaults");
|
|
7
|
+
const recipes_1 = require("@r8s/recipes");
|
|
8
|
+
const redis_1 = require("@r8s/crds/redis");
|
|
9
|
+
const operator_redis_1 = require("@r8s/operator-redis");
|
|
10
|
+
/**
|
|
11
|
+
* LibreChat — multi-model AI chat UI with external MongoDB, Redis
|
|
12
|
+
* sessions, optional Meilisearch and OIDC SSO.
|
|
13
|
+
*
|
|
14
|
+
* @title LibreChat
|
|
15
|
+
* @category AI & Chat
|
|
16
|
+
*
|
|
17
|
+
* Composes:
|
|
18
|
+
* - LibreChat Deployment + Service + Endpoint (MongoDB is provisioned
|
|
19
|
+
* externally — pass its coordinates via the required `mongodb` prop)
|
|
20
|
+
* - Redis replication group for session caching (default on, service
|
|
21
|
+
* ${name}-redis; USE_REDIS=true points sessions at it)
|
|
22
|
+
* - Optional Meilisearch Deployment + Service for message/RAG search
|
|
23
|
+
* (SEARCH=true wires the app to it)
|
|
24
|
+
* - SECRET_KEY / OPENAI_API_KEY / JWT + CREDS session credentials /
|
|
25
|
+
* MEILI_MASTER_KEY provisioned through the Platform secrets backend
|
|
26
|
+
* (openbao / vault), or referenced from an existing Secret
|
|
27
|
+
* - OIDC SSO against the Keycloak `Auth` recipe
|
|
28
|
+
*
|
|
29
|
+
* Wrap the component in `<Platform secrets={{ backend: 'openbao' }}>` and
|
|
30
|
+
* the app secrets bundle (keys: secretKey, modelApiKey, jwtSecret,
|
|
31
|
+
* jwtRefreshSecret, credsKey, credsIv, meiliMasterKey) is provisioned
|
|
32
|
+
* for you. Without a backend you must point `secretsName` at a
|
|
33
|
+
* pre-created Secret. MongoDB itself is NOT provisioned here — run it
|
|
34
|
+
* separately and connect via `mongodb`.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* import { Platform } from '@r8s/recipes'
|
|
38
|
+
* import { LibreChat } from '@r8s/librechat'
|
|
39
|
+
*
|
|
40
|
+
* export default (
|
|
41
|
+
* <Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'apps' }}>
|
|
42
|
+
* <LibreChat
|
|
43
|
+
* name="chat"
|
|
44
|
+
* host="chat.example.com"
|
|
45
|
+
* mongodb={{ host: 'mongo.data.svc.cluster.local', passwordSecret: 'chat-mongodb-credentials' }}
|
|
46
|
+
* sso={{
|
|
47
|
+
* issuer: 'https://keycloak.example.com/realms/platform',
|
|
48
|
+
* clientId: 'librechat',
|
|
49
|
+
* clientSecretRef: { secret: 'librechat-sso', key: 'clientSecret' },
|
|
50
|
+
* }}
|
|
51
|
+
* />
|
|
52
|
+
* </Platform>
|
|
53
|
+
* )
|
|
54
|
+
*/
|
|
55
|
+
function LibreChat(props) {
|
|
56
|
+
const { name = 'librechat', namespace = 'default', version = 'latest', host, port = 3080, replicas = 1, mongodb, cache = true, search = false, sso, backend = 'https://api.berget.ai/v1', secretsName, resources = {
|
|
57
|
+
requests: { memory: '512Mi', cpu: '250m' },
|
|
58
|
+
limits: { memory: '2Gi', cpu: '1000m' },
|
|
59
|
+
}, tls = { secretName: `${name}-tls`, clusterIssuer: 'letsencrypt-prod' }, } = props;
|
|
60
|
+
const sharedOperators = (0, core_1.useContext)(defaults_1.OperatorContext);
|
|
61
|
+
const secretProvider = (0, core_1.useContext)(defaults_1.SecretContext);
|
|
62
|
+
const resources_ = [];
|
|
63
|
+
const appSecretsName = secretsName ?? `${name}-secrets`;
|
|
64
|
+
// --- Secret provisioning ---------------------------------------------------
|
|
65
|
+
// SECRET_KEY signs sessions, modelApiKey pays for inference, the JWT +
|
|
66
|
+
// CREDS keys carry multi-user login state and meiliMasterKey guards the
|
|
67
|
+
// search index — none of them may be rendered as plaintext. With a
|
|
68
|
+
// secrets backend the bundle (keys: secretKey, modelApiKey, jwtSecret,
|
|
69
|
+
// jwtRefreshSecret, credsKey, credsIv, meiliMasterKey) is provisioned
|
|
70
|
+
// through the backend; otherwise reference a pre-created Secret.
|
|
71
|
+
if (!secretsName) {
|
|
72
|
+
if (!secretProvider ||
|
|
73
|
+
(secretProvider.backend !== 'vault' && secretProvider.backend !== 'openbao')) {
|
|
74
|
+
throw new Error(`LibreChat "${name}" requires application secrets (SECRET_KEY, modelApiKey).\n` +
|
|
75
|
+
`\n` +
|
|
76
|
+
`These must not be rendered as plaintext.\n` +
|
|
77
|
+
`\n` +
|
|
78
|
+
`Fix: configure a secrets backend on the Platform:\n` +
|
|
79
|
+
` <Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'apps' }}>\n` +
|
|
80
|
+
` <LibreChat name="${name}" host="${host}" />\n` +
|
|
81
|
+
` </Platform>\n` +
|
|
82
|
+
`\n` +
|
|
83
|
+
`Or reference a pre-created Secret (keys: secretKey, modelApiKey, jwtSecret, jwtRefreshSecret, credsKey, credsIv` +
|
|
84
|
+
`${search ? ', meiliMasterKey' : ''}):\n` +
|
|
85
|
+
` <LibreChat name="${name}" host="${host}" secretsName="${name}-secrets" />`);
|
|
86
|
+
}
|
|
87
|
+
const spec = {
|
|
88
|
+
...(secretProvider.backend === 'vault'
|
|
89
|
+
? { vaultAuthRef: secretProvider.authRef }
|
|
90
|
+
: { openbaoAuthRef: secretProvider.authRef }),
|
|
91
|
+
mount: secretProvider.mount,
|
|
92
|
+
type: 'kv-v2',
|
|
93
|
+
path: `${secretProvider.path ?? name}/${name}/secrets`,
|
|
94
|
+
destination: { create: true, name: appSecretsName },
|
|
95
|
+
};
|
|
96
|
+
resources_.push(secretProvider.backend === 'vault'
|
|
97
|
+
? (0, core_1.jsx)('VaultStaticSecret', {
|
|
98
|
+
apiVersion: 'secrets.hashicorp.com/v1beta1',
|
|
99
|
+
kind: 'VaultStaticSecret',
|
|
100
|
+
metadata: { name: `${name}-secrets`, namespace },
|
|
101
|
+
spec,
|
|
102
|
+
})
|
|
103
|
+
: (0, core_1.jsx)('OpenBaoStaticSecret', {
|
|
104
|
+
apiVersion: 'secrets.openbao.org/v1beta1',
|
|
105
|
+
kind: 'OpenBaoStaticSecret',
|
|
106
|
+
metadata: { name: `${name}-secrets`, namespace },
|
|
107
|
+
spec,
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
// --- Operators --------------------------------------------------------------
|
|
111
|
+
if (cache) {
|
|
112
|
+
resources_.push(...(0, operator_redis_1.declareIfMissing)(sharedOperators));
|
|
113
|
+
}
|
|
114
|
+
// Redis — session cache (OT-Container-Kit operator). A replication group
|
|
115
|
+
// so the single ${name}-redis master service fronts a 3-node set.
|
|
116
|
+
if (cache) {
|
|
117
|
+
resources_.push((0, redis_1.RedisReplicationComponent)({
|
|
118
|
+
metadata: { name: `${name}-redis`, namespace },
|
|
119
|
+
spec: {
|
|
120
|
+
clusterSize: 3,
|
|
121
|
+
kubernetesConfig: { image: 'redis:7.2-alpine' },
|
|
122
|
+
},
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
// --- Env wiring ----------------------------------------------------------------
|
|
126
|
+
// Every credential is referenced via secretKeyRef — no plaintext and no
|
|
127
|
+
// redundant $(VAR) self-echoes in the manifest. The WebService declares
|
|
128
|
+
// secret-backed vars before plain env vars, so dependent expansion on
|
|
129
|
+
// MONGO_URI resolves.
|
|
130
|
+
const mongoPort = mongodb.port ?? 27017;
|
|
131
|
+
const env = {
|
|
132
|
+
HOST: '0.0.0.0',
|
|
133
|
+
PORT: String(port),
|
|
134
|
+
// Deterministic parts inlined; credentials arrive via MONGO_USERNAME /
|
|
135
|
+
// MONGO_PASSWORD declared earlier through secretKeyRef
|
|
136
|
+
MONGO_URI: `mongodb://$(MONGO_USERNAME):$(MONGO_PASSWORD)@${mongodb.host}:${mongoPort}/${name}` +
|
|
137
|
+
(mongodb.authSource ? `?authSource=${mongodb.authSource}` : ''),
|
|
138
|
+
// LibreChat speaks to OpenAI-compatible backends through its reverse
|
|
139
|
+
// proxy (there is no OPENAI_API_BASE_URL env upstream)
|
|
140
|
+
OPENAI_REVERSE_PROXY: `${backend}/chat/completions`,
|
|
141
|
+
...(cache ? { USE_REDIS: 'true', REDIS_URI: `redis://${name}-redis:6379` } : {}),
|
|
142
|
+
...(search
|
|
143
|
+
? {
|
|
144
|
+
SEARCH: 'true',
|
|
145
|
+
MEILI_HOST: `http://${name}-meilisearch:7700`,
|
|
146
|
+
MEILI_NO_SYNC: 'false',
|
|
147
|
+
}
|
|
148
|
+
: {}),
|
|
149
|
+
...(sso
|
|
150
|
+
? {
|
|
151
|
+
ALLOW_SOCIAL_LOGIN: 'true',
|
|
152
|
+
DOMAIN_SERVER: `https://${host}`,
|
|
153
|
+
DOMAIN_CLIENT: `https://${host}`,
|
|
154
|
+
OPENID_ISSUER: sso.issuer,
|
|
155
|
+
OPENID_CLIENT_ID: sso.clientId,
|
|
156
|
+
OPENID_SCOPES: sso.scopes ?? 'openid profile email',
|
|
157
|
+
OPENID_CALLBACK_URL: `https://${host}/oauth/openid/callback`,
|
|
158
|
+
}
|
|
159
|
+
: {}),
|
|
160
|
+
};
|
|
161
|
+
// The username is an identifier, not a secret — when the caller supplies
|
|
162
|
+
// it explicitly it is inlined as plain env; otherwise it is read from the
|
|
163
|
+
// MongoDB credentials secret (key: username) like the password.
|
|
164
|
+
if (mongodb.username) {
|
|
165
|
+
env.MONGO_USERNAME = mongodb.username;
|
|
166
|
+
}
|
|
167
|
+
// Credentials delivered via secretKeyRef (runtime injection). JWT_SECRET /
|
|
168
|
+
// JWT_REFRESH_SECRET / CREDS_KEY / CREDS_IV back multi-user sessions:
|
|
169
|
+
// per-user message encryption and refresh-token issuance need shared
|
|
170
|
+
// random values across replicas. Hex sizing: jwtSecret, jwtRefreshSecret
|
|
171
|
+
// and credsKey are 64 hex chars (32 bytes); credsIv is 32 hex chars
|
|
172
|
+
// (16 bytes).
|
|
173
|
+
const secrets = {
|
|
174
|
+
...(mongodb.username
|
|
175
|
+
? {}
|
|
176
|
+
: { MONGO_USERNAME: { secret: mongodb.passwordSecret, key: 'username' } }),
|
|
177
|
+
MONGO_PASSWORD: { secret: mongodb.passwordSecret, key: 'password' },
|
|
178
|
+
SECRET_KEY: { secret: appSecretsName, key: 'secretKey' },
|
|
179
|
+
OPENAI_API_KEY: { secret: appSecretsName, key: 'modelApiKey' },
|
|
180
|
+
JWT_SECRET: { secret: appSecretsName, key: 'jwtSecret' },
|
|
181
|
+
JWT_REFRESH_SECRET: { secret: appSecretsName, key: 'jwtRefreshSecret' },
|
|
182
|
+
CREDS_KEY: { secret: appSecretsName, key: 'credsKey' },
|
|
183
|
+
CREDS_IV: { secret: appSecretsName, key: 'credsIv' },
|
|
184
|
+
...(search ? { MEILI_MASTER_KEY: { secret: appSecretsName, key: 'meiliMasterKey' } } : {}),
|
|
185
|
+
...(sso ? { OPENID_CLIENT_SECRET: sso.clientSecretRef } : {}),
|
|
186
|
+
};
|
|
187
|
+
// --- Runtime config (non-secret) -------------------------------------------
|
|
188
|
+
// REFRESH_TOKEN_EXPIRY is a plain TTL (7 days), not a credential — it is
|
|
189
|
+
// rendered as a ConfigMap and injected via configMapKeyRef, keeping
|
|
190
|
+
// plaintext env wiring (and the no-plaintext-secrets guardrail) clean.
|
|
191
|
+
const configMapName = `${name}-config`;
|
|
192
|
+
const configMap = {
|
|
193
|
+
apiVersion: 'v1',
|
|
194
|
+
kind: 'ConfigMap',
|
|
195
|
+
metadata: { name: configMapName, namespace },
|
|
196
|
+
data: { REFRESH_TOKEN_EXPIRY: '604800' },
|
|
197
|
+
};
|
|
198
|
+
resources_.push((0, core_1.jsx)('ConfigMap', configMap));
|
|
199
|
+
// --- App + optional Meilisearch + endpoint --------------------------------------
|
|
200
|
+
resources_.push((0, jsx_runtime_1.jsx)(recipes_1.WebService, { name: name, namespace: namespace, image: `ghcr.io/danny-avila/librechat:${version}`, port: port, replicas: replicas, resources: resources, env: env, secrets: secrets, rawEnv: [
|
|
201
|
+
{
|
|
202
|
+
name: 'REFRESH_TOKEN_EXPIRY',
|
|
203
|
+
valueFrom: { configMapKeyRef: { name: configMapName, key: 'REFRESH_TOKEN_EXPIRY' } },
|
|
204
|
+
},
|
|
205
|
+
] }));
|
|
206
|
+
if (search) {
|
|
207
|
+
resources_.push((0, jsx_runtime_1.jsx)(recipes_1.WebService, { name: `${name}-meilisearch`, namespace: namespace, image: "getmeili/meilisearch:v1.6", port: 7700, replicas: 1, env: { MEILI_NO_ANALYTICS: 'true', MEILI_ENV: 'production' }, secrets: { MEILI_MASTER_KEY: { secret: appSecretsName, key: 'meiliMasterKey' } }, probes: { liveness: { path: '/health' }, readiness: { path: '/health' } }, resources: {
|
|
208
|
+
requests: { memory: '256Mi', cpu: '100m' },
|
|
209
|
+
limits: { memory: '1Gi', cpu: '500m' },
|
|
210
|
+
} }));
|
|
211
|
+
}
|
|
212
|
+
resources_.push((0, jsx_runtime_1.jsx)(recipes_1.Endpoint, { name: `${name}-endpoint`, namespace: namespace, host: host, serviceName: name, servicePort: port, tls: tls, annotations: {
|
|
213
|
+
'nginx.ingress.kubernetes.io/proxy-read-timeout': '300',
|
|
214
|
+
'nginx.ingress.kubernetes.io/proxy-send-timeout': '300',
|
|
215
|
+
'nginx.ingress.kubernetes.io/proxy-buffering': 'off',
|
|
216
|
+
} }));
|
|
217
|
+
return (0, core_1.jsx)(core_1.Fragment, { children: resources_ });
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":";;AAiJA,8BA4OC;;AA7XD,oCAAsE;AACtE,iDAAmE;AACnE,0CAAmD;AACnD,2CAA2D;AAC3D,wDAAsD;AAgGtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,SAAgB,SAAS,CAAC,KAAqB;IAC7C,MAAM,EACJ,IAAI,GAAG,WAAW,EAClB,SAAS,GAAG,SAAS,EACrB,OAAO,GAAG,QAAQ,EAClB,IAAI,EACJ,IAAI,GAAG,IAAI,EACX,QAAQ,GAAG,CAAC,EACZ,OAAO,EACP,KAAK,GAAG,IAAI,EACZ,MAAM,GAAG,KAAK,EACd,GAAG,EACH,OAAO,GAAG,0BAA0B,EACpC,WAAW,EACX,SAAS,GAAG;QACV,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE;QAC1C,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE;KACxC,EACD,GAAG,GAAG,EAAE,UAAU,EAAE,GAAG,IAAI,MAAM,EAAE,aAAa,EAAE,kBAAkB,EAAE,GACvE,GAAG,KAAK,CAAA;IAET,MAAM,eAAe,GAAG,IAAA,iBAAU,EAAC,0BAAe,CAAC,CAAA;IACnD,MAAM,cAAc,GAAG,IAAA,iBAAU,EAAC,wBAAa,CAAC,CAAA;IAChD,MAAM,UAAU,GAA6B,EAAE,CAAA;IAE/C,MAAM,cAAc,GAAG,WAAW,IAAI,GAAG,IAAI,UAAU,CAAA;IAEvD,8EAA8E;IAC9E,uEAAuE;IACvE,wEAAwE;IACxE,mEAAmE;IACnE,uEAAuE;IACvE,sEAAsE;IACtE,iEAAiE;IACjE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,IACE,CAAC,cAAc;YACf,CAAC,cAAc,CAAC,OAAO,KAAK,OAAO,IAAI,cAAc,CAAC,OAAO,KAAK,SAAS,CAAC,EAC5E,CAAC;YACD,MAAM,IAAI,KAAK,CACb,cAAc,IAAI,6DAA6D;gBAC7E,IAAI;gBACJ,4CAA4C;gBAC5C,IAAI;gBACJ,qDAAqD;gBACrD,4EAA4E;gBAC5E,wBAAwB,IAAI,WAAW,IAAI,QAAQ;gBACnD,iBAAiB;gBACjB,IAAI;gBACJ,iHAAiH;gBACjH,GAAG,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,MAAM;gBACzC,sBAAsB,IAAI,WAAW,IAAI,kBAAkB,IAAI,cAAc,CAChF,CAAA;QACH,CAAC;QAED,MAAM,IAAI,GAAG;YACX,GAAG,CAAC,cAAc,CAAC,OAAO,KAAK,OAAO;gBACpC,CAAC,CAAC,EAAE,YAAY,EAAE,cAAc,CAAC,OAAO,EAAE;gBAC1C,CAAC,CAAC,EAAE,cAAc,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC;YAC/C,KAAK,EAAE,cAAc,CAAC,KAAK;YAC3B,IAAI,EAAE,OAAgB;YACtB,IAAI,EAAE,GAAG,cAAc,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,UAAU;YACtD,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE;SACpD,CAAA;QACD,UAAU,CAAC,IAAI,CACb,cAAc,CAAC,OAAO,KAAK,OAAO;YAChC,CAAC,CAAC,IAAA,UAAG,EAAC,mBAAmB,EAAE;gBACvB,UAAU,EAAE,+BAA+B;gBAC3C,IAAI,EAAE,mBAAmB;gBACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,UAAU,EAAE,SAAS,EAAE;gBAChD,IAAI;aACL,CAAC;YACJ,CAAC,CAAC,IAAA,UAAG,EAAC,qBAAqB,EAAE;gBACzB,UAAU,EAAE,6BAA6B;gBACzC,IAAI,EAAE,qBAAqB;gBAC3B,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,UAAU,EAAE,SAAS,EAAE;gBAChD,IAAI;aACL,CAAC,CACP,CAAA;IACH,CAAC;IAED,+EAA+E;IAC/E,IAAI,KAAK,EAAE,CAAC;QACV,UAAU,CAAC,IAAI,CAAC,GAAG,IAAA,iCAAgB,EAAC,eAAe,CAAC,CAAC,CAAA;IACvD,CAAC;IAED,yEAAyE;IACzE,kEAAkE;IAClE,IAAI,KAAK,EAAE,CAAC;QACV,UAAU,CAAC,IAAI,CACb,IAAA,iCAAyB,EAAC;YACxB,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,QAAQ,EAAE,SAAS,EAAE;YAC9C,IAAI,EAAE;gBACJ,WAAW,EAAE,CAAC;gBACd,gBAAgB,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE;aAChD;SACF,CAAC,CACH,CAAA;IACH,CAAC;IAED,kFAAkF;IAClF,wEAAwE;IACxE,wEAAwE;IACxE,sEAAsE;IACtE,sBAAsB;IACtB,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,IAAI,KAAK,CAAA;IAEvC,MAAM,GAAG,GAA2B;QAClC,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;QAClB,uEAAuE;QACvE,uDAAuD;QACvD,SAAS,EACP,iDAAiD,OAAO,CAAC,IAAI,IAAI,SAAS,IAAI,IAAI,EAAE;YACpF,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,eAAe,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,qEAAqE;QACrE,uDAAuD;QACvD,oBAAoB,EAAE,GAAG,OAAO,mBAAmB;QACnD,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,GAAG,CAAC,MAAM;YACR,CAAC,CAAC;gBACE,MAAM,EAAE,MAAM;gBACd,UAAU,EAAE,UAAU,IAAI,mBAAmB;gBAC7C,aAAa,EAAE,OAAO;aACvB;YACH,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,GAAG;YACL,CAAC,CAAC;gBACE,kBAAkB,EAAE,MAAM;gBAC1B,aAAa,EAAE,WAAW,IAAI,EAAE;gBAChC,aAAa,EAAE,WAAW,IAAI,EAAE;gBAChC,aAAa,EAAE,GAAG,CAAC,MAAM;gBACzB,gBAAgB,EAAE,GAAG,CAAC,QAAQ;gBAC9B,aAAa,EAAE,GAAG,CAAC,MAAM,IAAI,sBAAsB;gBACnD,mBAAmB,EAAE,WAAW,IAAI,wBAAwB;aAC7D;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAA;IAED,yEAAyE;IACzE,0EAA0E;IAC1E,gEAAgE;IAChE,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,GAAG,CAAC,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAA;IACvC,CAAC;IAED,2EAA2E;IAC3E,sEAAsE;IACtE,qEAAqE;IACrE,yEAAyE;IACzE,oEAAoE;IACpE,cAAc;IACd,MAAM,OAAO,GAAuC;QAClD,GAAG,CAAC,OAAO,CAAC,QAAQ;YAClB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,CAAC;QAC5E,cAAc,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,cAAc,EAAE,GAAG,EAAE,UAAU,EAAE;QACnE,UAAU,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,WAAW,EAAE;QACxD,cAAc,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,EAAE;QAC9D,UAAU,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,WAAW,EAAE;QACxD,kBAAkB,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,kBAAkB,EAAE;QACvE,SAAS,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,UAAU,EAAE;QACtD,QAAQ,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,SAAS,EAAE;QACpD,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9D,CAAA;IAED,8EAA8E;IAC9E,yEAAyE;IACzE,oEAAoE;IACpE,uEAAuE;IACvE,MAAM,aAAa,GAAG,GAAG,IAAI,SAAS,CAAA;IACtC,MAAM,SAAS,GAAc;QAC3B,UAAU,EAAE,IAAI;QAChB,IAAI,EAAE,WAAW;QACjB,QAAQ,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE;QAC5C,IAAI,EAAE,EAAE,oBAAoB,EAAE,QAAQ,EAAE;KACzC,CAAA;IACD,UAAU,CAAC,IAAI,CAAC,IAAA,UAAG,EAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAA;IAE5C,mFAAmF;IACnF,UAAU,CAAC,IAAI,CACb,uBAAC,oBAAU,IACT,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,iCAAiC,OAAO,EAAE,EACjD,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,sBAAsB;gBAC5B,SAAS,EAAE,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,sBAAsB,EAAE,EAAE;aAC3E;SACZ,GACD,CACH,CAAA;IAED,IAAI,MAAM,EAAE,CAAC;QACX,UAAU,CAAC,IAAI,CACb,uBAAC,oBAAU,IACT,IAAI,EAAE,GAAG,IAAI,cAAc,EAC3B,SAAS,EAAE,SAAS,EACpB,KAAK,EAAC,2BAA2B,EACjC,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,CAAC,EACX,GAAG,EAAE,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,EAC5D,OAAO,EAAE,EAAE,gBAAgB,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,gBAAgB,EAAE,EAAE,EAChF,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EACzE,SAAS,EAAE;gBACT,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE;gBAC1C,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE;aACvC,GACD,CACH,CAAA;IACH,CAAC;IAED,UAAU,CAAC,IAAI,CACb,uBAAC,kBAAQ,IACP,IAAI,EAAE,GAAG,IAAI,WAAW,EACxB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,IAAI,EACjB,WAAW,EAAE,IAAI,EACjB,GAAG,EAAE,GAAG,EACR,WAAW,EAAE;YACX,gDAAgD,EAAE,KAAK;YACvD,gDAAgD,EAAE,KAAK;YACvD,6CAA6C,EAAE,KAAK;SACrD,GACD,CACH,CAAA;IAED,OAAO,IAAA,UAAG,EAAC,eAAQ,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAA;AAChD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@r8s/librechat",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "LibreChat multi-model AI chat
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "LibreChat multi-model AI chat \u2014 MongoDB (provisioned externally), Redis sessions, optional Meilisearch, OIDC SSO",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Berget AI AB",
|
|
7
7
|
"homepage": "https://r8s.berget.ai",
|
|
@@ -29,13 +29,20 @@
|
|
|
29
29
|
},
|
|
30
30
|
"category": "AI & Assistants",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@r8s/core": "^0.
|
|
33
|
-
"@r8s/crds": "^0.
|
|
34
|
-
"@r8s/k8s-types": "^0.
|
|
35
|
-
"@r8s/recipes": "^0.
|
|
32
|
+
"@r8s/core": "^0.3.0",
|
|
33
|
+
"@r8s/crds": "^0.3.0",
|
|
34
|
+
"@r8s/k8s-types": "^0.3.0",
|
|
35
|
+
"@r8s/recipes": "^0.3.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"typescript": "^5.3.0",
|
|
39
|
-
"vitest": "^1.0.0"
|
|
39
|
+
"vitest": "^1.0.0",
|
|
40
|
+
"@r8s/operator-redis": "^0.22.0"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist"
|
|
44
|
+
],
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@r8s/operator-redis": "^0.22.0"
|
|
40
47
|
}
|
|
41
48
|
}
|