@exulu/backend 1.48.2 → 1.49.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.
Files changed (164) hide show
  1. package/dist/index.cjs +351 -42
  2. package/dist/index.d.cts +96 -1
  3. package/dist/index.d.ts +96 -1
  4. package/dist/index.js +340 -38
  5. package/ee/{markdown.ts → chunking/markdown.ts} +2 -2
  6. package/ee/python/README.md +295 -0
  7. package/ee/python/documents/processing/README.md +155 -0
  8. package/ee/{documents → python/documents}/processing/doc_processor.ts +25 -17
  9. package/ee/{documents/processing/pdf_to_markdown.py → python/documents/processing/document_to_markdown.py} +3 -10
  10. package/ee/python/setup.sh +180 -0
  11. package/package.json +14 -3
  12. package/scripts/postinstall.cjs +149 -0
  13. package/.agents/skills/mintlify/SKILL.md +0 -347
  14. package/.editorconfig +0 -15
  15. package/.eslintrc.json +0 -52
  16. package/.github/workflows/release-backend.yml +0 -38
  17. package/.husky/commit-msg +0 -1
  18. package/.jscpd.json +0 -18
  19. package/.mcp.json +0 -25
  20. package/.nvmrc +0 -1
  21. package/.prettierignore +0 -5
  22. package/.prettierrc.json +0 -12
  23. package/CHANGELOG.md +0 -8
  24. package/SECURITY.md +0 -5
  25. package/commitlint.config.js +0 -4
  26. package/devops/documentation/patch-older-releases.md +0 -42
  27. package/ee/documents/processing/build_pdf_processor.sh +0 -35
  28. package/ee/documents/processing/chunk_markdown.py +0 -263
  29. package/ee/documents/processing/pdf_processor.spec +0 -115
  30. package/eslint.config.js +0 -88
  31. package/jest.config.ts +0 -25
  32. package/mintlify-docs/.mintignore +0 -7
  33. package/mintlify-docs/AGENTS.md +0 -33
  34. package/mintlify-docs/CLAUDE.MD +0 -50
  35. package/mintlify-docs/CONTRIBUTING.md +0 -32
  36. package/mintlify-docs/LICENSE +0 -21
  37. package/mintlify-docs/README.md +0 -55
  38. package/mintlify-docs/ai-tools/claude-code.mdx +0 -43
  39. package/mintlify-docs/ai-tools/cursor.mdx +0 -39
  40. package/mintlify-docs/ai-tools/windsurf.mdx +0 -39
  41. package/mintlify-docs/api-reference/core-types/agent-types.mdx +0 -110
  42. package/mintlify-docs/api-reference/core-types/analytics-types.mdx +0 -95
  43. package/mintlify-docs/api-reference/core-types/configuration-types.mdx +0 -83
  44. package/mintlify-docs/api-reference/core-types/evaluation-types.mdx +0 -106
  45. package/mintlify-docs/api-reference/core-types/job-types.mdx +0 -135
  46. package/mintlify-docs/api-reference/core-types/overview.mdx +0 -73
  47. package/mintlify-docs/api-reference/core-types/prompt-types.mdx +0 -102
  48. package/mintlify-docs/api-reference/core-types/rbac-types.mdx +0 -163
  49. package/mintlify-docs/api-reference/core-types/session-types.mdx +0 -77
  50. package/mintlify-docs/api-reference/core-types/user-management.mdx +0 -112
  51. package/mintlify-docs/api-reference/core-types/workflow-types.mdx +0 -88
  52. package/mintlify-docs/api-reference/core-types.mdx +0 -585
  53. package/mintlify-docs/api-reference/dynamic-types.mdx +0 -851
  54. package/mintlify-docs/api-reference/endpoint/create.mdx +0 -4
  55. package/mintlify-docs/api-reference/endpoint/delete.mdx +0 -4
  56. package/mintlify-docs/api-reference/endpoint/get.mdx +0 -4
  57. package/mintlify-docs/api-reference/endpoint/webhook.mdx +0 -4
  58. package/mintlify-docs/api-reference/introduction.mdx +0 -661
  59. package/mintlify-docs/api-reference/mutations.mdx +0 -1012
  60. package/mintlify-docs/api-reference/openapi.json +0 -217
  61. package/mintlify-docs/api-reference/queries.mdx +0 -1154
  62. package/mintlify-docs/backend/introduction.mdx +0 -218
  63. package/mintlify-docs/changelog.mdx +0 -387
  64. package/mintlify-docs/community-edition.mdx +0 -304
  65. package/mintlify-docs/core/exulu-agent/api-reference.mdx +0 -894
  66. package/mintlify-docs/core/exulu-agent/configuration.mdx +0 -690
  67. package/mintlify-docs/core/exulu-agent/introduction.mdx +0 -552
  68. package/mintlify-docs/core/exulu-app/api-reference.mdx +0 -481
  69. package/mintlify-docs/core/exulu-app/configuration.mdx +0 -319
  70. package/mintlify-docs/core/exulu-app/introduction.mdx +0 -117
  71. package/mintlify-docs/core/exulu-authentication.mdx +0 -810
  72. package/mintlify-docs/core/exulu-chunkers/api-reference.mdx +0 -1011
  73. package/mintlify-docs/core/exulu-chunkers/configuration.mdx +0 -596
  74. package/mintlify-docs/core/exulu-chunkers/introduction.mdx +0 -403
  75. package/mintlify-docs/core/exulu-context/api-reference.mdx +0 -911
  76. package/mintlify-docs/core/exulu-context/configuration.mdx +0 -648
  77. package/mintlify-docs/core/exulu-context/introduction.mdx +0 -394
  78. package/mintlify-docs/core/exulu-database.mdx +0 -811
  79. package/mintlify-docs/core/exulu-default-agents.mdx +0 -545
  80. package/mintlify-docs/core/exulu-eval/api-reference.mdx +0 -772
  81. package/mintlify-docs/core/exulu-eval/configuration.mdx +0 -680
  82. package/mintlify-docs/core/exulu-eval/introduction.mdx +0 -459
  83. package/mintlify-docs/core/exulu-logging.mdx +0 -464
  84. package/mintlify-docs/core/exulu-otel.mdx +0 -670
  85. package/mintlify-docs/core/exulu-queues/api-reference.mdx +0 -648
  86. package/mintlify-docs/core/exulu-queues/configuration.mdx +0 -650
  87. package/mintlify-docs/core/exulu-queues/introduction.mdx +0 -474
  88. package/mintlify-docs/core/exulu-reranker/api-reference.mdx +0 -630
  89. package/mintlify-docs/core/exulu-reranker/configuration.mdx +0 -663
  90. package/mintlify-docs/core/exulu-reranker/introduction.mdx +0 -516
  91. package/mintlify-docs/core/exulu-tool/api-reference.mdx +0 -723
  92. package/mintlify-docs/core/exulu-tool/configuration.mdx +0 -805
  93. package/mintlify-docs/core/exulu-tool/introduction.mdx +0 -539
  94. package/mintlify-docs/core/exulu-variables/api-reference.mdx +0 -699
  95. package/mintlify-docs/core/exulu-variables/configuration.mdx +0 -736
  96. package/mintlify-docs/core/exulu-variables/introduction.mdx +0 -511
  97. package/mintlify-docs/development.mdx +0 -94
  98. package/mintlify-docs/docs.json +0 -248
  99. package/mintlify-docs/enterprise-edition.mdx +0 -538
  100. package/mintlify-docs/essentials/code.mdx +0 -35
  101. package/mintlify-docs/essentials/images.mdx +0 -59
  102. package/mintlify-docs/essentials/markdown.mdx +0 -88
  103. package/mintlify-docs/essentials/navigation.mdx +0 -87
  104. package/mintlify-docs/essentials/reusable-snippets.mdx +0 -110
  105. package/mintlify-docs/essentials/settings.mdx +0 -318
  106. package/mintlify-docs/favicon.svg +0 -3
  107. package/mintlify-docs/frontend/introduction.mdx +0 -39
  108. package/mintlify-docs/getting-started.mdx +0 -267
  109. package/mintlify-docs/guides/custom-agent.mdx +0 -608
  110. package/mintlify-docs/guides/first-agent.mdx +0 -315
  111. package/mintlify-docs/images/admin_ui.png +0 -0
  112. package/mintlify-docs/images/contexts.png +0 -0
  113. package/mintlify-docs/images/create_agents.png +0 -0
  114. package/mintlify-docs/images/evals.png +0 -0
  115. package/mintlify-docs/images/graphql.png +0 -0
  116. package/mintlify-docs/images/graphql_api.png +0 -0
  117. package/mintlify-docs/images/hero-dark.png +0 -0
  118. package/mintlify-docs/images/hero-light.png +0 -0
  119. package/mintlify-docs/images/hero.png +0 -0
  120. package/mintlify-docs/images/knowledge_sources.png +0 -0
  121. package/mintlify-docs/images/mcp.png +0 -0
  122. package/mintlify-docs/images/scaling.png +0 -0
  123. package/mintlify-docs/index.mdx +0 -411
  124. package/mintlify-docs/logo/dark.svg +0 -9
  125. package/mintlify-docs/logo/light.svg +0 -9
  126. package/mintlify-docs/partners.mdx +0 -558
  127. package/mintlify-docs/products.mdx +0 -77
  128. package/mintlify-docs/snippets/snippet-intro.mdx +0 -4
  129. package/mintlify-docs/styles.css +0 -207
  130. package/ngrok.bash +0 -1
  131. package/ngrok.md +0 -6
  132. package/ngrok.yml +0 -10
  133. package/release.config.cjs +0 -15
  134. package/skills-lock.json +0 -10
  135. package/types/context-processor.ts +0 -45
  136. package/types/enums/eval-types.ts +0 -5
  137. package/types/enums/field-types.ts +0 -1
  138. package/types/enums/jobs.ts +0 -11
  139. package/types/enums/statistics.ts +0 -13
  140. package/types/exulu-table-definition.ts +0 -79
  141. package/types/file-types.ts +0 -18
  142. package/types/models/agent-session.ts +0 -27
  143. package/types/models/agent.ts +0 -68
  144. package/types/models/context.ts +0 -53
  145. package/types/models/embedding.ts +0 -17
  146. package/types/models/eval-run.ts +0 -40
  147. package/types/models/exulu-agent-tool-config.ts +0 -11
  148. package/types/models/item.ts +0 -21
  149. package/types/models/job.ts +0 -8
  150. package/types/models/project.ts +0 -16
  151. package/types/models/rate-limiter-rules.ts +0 -7
  152. package/types/models/test-case.ts +0 -25
  153. package/types/models/tool.ts +0 -9
  154. package/types/models/user-role.ts +0 -12
  155. package/types/models/user.ts +0 -20
  156. package/types/models/variable.ts +0 -8
  157. package/types/models/vector-methods.ts +0 -7
  158. package/types/provider-config.ts +0 -21
  159. package/types/queue-config.ts +0 -16
  160. package/types/rbac-rights-modes.ts +0 -1
  161. package/types/statistics.ts +0 -20
  162. package/types/workflow.ts +0 -31
  163. /package/ee/{documents → python/documents}/THIRD_PARTY_LICENSES/docling.txt +0 -0
  164. /package/ee/{documents/processing → python}/requirements.txt +0 -0
@@ -1,736 +0,0 @@
1
- ---
2
- title: "Configuration"
3
- description: "Complete guide to setting up and managing ExuluVariables"
4
- ---
5
-
6
- ## Database setup
7
-
8
- ExuluVariables requires a PostgreSQL table to store variables.
9
-
10
- ### Table schema
11
-
12
- ```sql
13
- CREATE TABLE variables (
14
- name VARCHAR(255) PRIMARY KEY,
15
- value TEXT NOT NULL,
16
- encrypted BOOLEAN DEFAULT false,
17
- created_at TIMESTAMP DEFAULT NOW(),
18
- updated_at TIMESTAMP DEFAULT NOW()
19
- );
20
- ```
21
-
22
- <ParamField path="name" type="VARCHAR(255)" required>
23
- Unique variable identifier (primary key)
24
- </ParamField>
25
-
26
- <ParamField path="value" type="TEXT" required>
27
- The variable value (encrypted if `encrypted` is true)
28
- </ParamField>
29
-
30
- <ParamField path="encrypted" type="BOOLEAN" default={false}>
31
- Whether the value is encrypted at rest (default: false)
32
- </ParamField>
33
-
34
- <ParamField path="created_at" type="TIMESTAMP">
35
- Timestamp when the variable was created
36
- </ParamField>
37
-
38
- <ParamField path="updated_at" type="TIMESTAMP">
39
- Timestamp when the variable was last updated
40
- </ParamField>
41
-
42
- ### Creating the table
43
-
44
- Run this migration in your PostgreSQL database:
45
-
46
- ```sql
47
- -- Create variables table
48
- CREATE TABLE IF NOT EXISTS variables (
49
- name VARCHAR(255) PRIMARY KEY,
50
- value TEXT NOT NULL,
51
- encrypted BOOLEAN DEFAULT false,
52
- created_at TIMESTAMP DEFAULT NOW(),
53
- updated_at TIMESTAMP DEFAULT NOW()
54
- );
55
-
56
- -- Add indexes for performance
57
- CREATE INDEX idx_variables_encrypted ON variables(encrypted);
58
- CREATE INDEX idx_variables_created_at ON variables(created_at);
59
-
60
- -- Optional: Add audit columns
61
- ALTER TABLE variables ADD COLUMN created_by VARCHAR(255);
62
- ALTER TABLE variables ADD COLUMN updated_by VARCHAR(255);
63
- ```
64
-
65
- ## Environment setup
66
-
67
- ### Required environment variables
68
-
69
- <ParamField path="NEXTAUTH_SECRET" type="string" required>
70
- Secret key used for AES encryption/decryption of variable values
71
- </ParamField>
72
-
73
- ```bash
74
- # .env file
75
- NEXTAUTH_SECRET=your-long-random-secret-key-here
76
- ```
77
-
78
- <Warning>
79
- **Critical**: This secret must be:
80
- - At least 32 characters long
81
- - Randomly generated (use `openssl rand -base64 32`)
82
- - Kept secure and never committed to version control
83
- - Consistent across all deployments (production, staging, etc.)
84
- </Warning>
85
-
86
- **Generate a secure secret:**
87
-
88
- ```bash
89
- # Using OpenSSL
90
- openssl rand -base64 32
91
-
92
- # Using Node.js
93
- node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
94
- ```
95
-
96
- ### Database connection
97
-
98
- ExuluVariables uses your PostgreSQL connection configured in `postgresClient`:
99
-
100
- ```typescript
101
- // Ensure your database connection is configured
102
- import { postgresClient } from "@exulu/backend";
103
-
104
- const { db } = await postgresClient();
105
- ```
106
-
107
- Connection settings are typically configured via environment variables:
108
-
109
- ```bash
110
- # .env file
111
- DATABASE_URL=postgresql://user:password@localhost:5432/database
112
- # or
113
- POSTGRES_HOST=localhost
114
- POSTGRES_PORT=5432
115
- POSTGRES_USER=user
116
- POSTGRES_PASSWORD=password
117
- POSTGRES_DATABASE=database
118
- ```
119
-
120
- ## Creating variables
121
-
122
- ### Via SQL
123
-
124
- ```sql
125
- -- Create an encrypted variable
126
- INSERT INTO variables (name, value, encrypted)
127
- VALUES ('openai_api_key', 'sk-...', true);
128
-
129
- -- Create a non-encrypted variable
130
- INSERT INTO variables (name, value, encrypted)
131
- VALUES ('app_name', 'My App', false);
132
-
133
- -- Bulk insert
134
- INSERT INTO variables (name, value, encrypted) VALUES
135
- ('openai_api_key', 'sk-...', true),
136
- ('anthropic_api_key', 'sk-ant-...', true),
137
- ('google_api_key', 'AIza...', true),
138
- ('app_version', '1.0.0', false);
139
- ```
140
-
141
- <Note>
142
- When inserting via SQL with `encrypted: true`, you must manually encrypt the value first using the same encryption method (AES with `NEXTAUTH_SECRET`).
143
- </Note>
144
-
145
- ### Via API
146
-
147
- Create a REST API endpoint to manage variables:
148
-
149
- ```typescript
150
- import { postgresClient, ExuluVariables } from "@exulu/backend";
151
- import CryptoJS from "crypto-js";
152
- import express from "express";
153
-
154
- const app = express();
155
- app.use(express.json());
156
-
157
- // Create variable
158
- app.post("/api/variables", async (req, res) => {
159
- const { name, value, encrypted = true } = req.body;
160
-
161
- const { db } = await postgresClient();
162
-
163
- // Encrypt if needed
164
- const finalValue = encrypted
165
- ? CryptoJS.AES.encrypt(value, process.env.NEXTAUTH_SECRET).toString()
166
- : value;
167
-
168
- await db.into("variables").insert({
169
- name,
170
- value: finalValue,
171
- encrypted
172
- });
173
-
174
- res.json({ success: true, name });
175
- });
176
-
177
- // Update variable
178
- app.put("/api/variables/:name", async (req, res) => {
179
- const { name } = req.params;
180
- const { value, encrypted } = req.body;
181
-
182
- const { db } = await postgresClient();
183
-
184
- const finalValue = encrypted
185
- ? CryptoJS.AES.encrypt(value, process.env.NEXTAUTH_SECRET).toString()
186
- : value;
187
-
188
- await db("variables")
189
- .where({ name })
190
- .update({
191
- value: finalValue,
192
- encrypted,
193
- updated_at: new Date()
194
- });
195
-
196
- res.json({ success: true, name });
197
- });
198
-
199
- // Delete variable
200
- app.delete("/api/variables/:name", async (req, res) => {
201
- const { name } = req.params;
202
- const { db } = await postgresClient();
203
-
204
- await db("variables").where({ name }).delete();
205
-
206
- res.json({ success: true, name });
207
- });
208
-
209
- // List variables (without values)
210
- app.get("/api/variables", async (req, res) => {
211
- const { db } = await postgresClient();
212
-
213
- const variables = await db
214
- .from("variables")
215
- .select("name", "encrypted", "created_at", "updated_at");
216
-
217
- res.json(variables);
218
- });
219
- ```
220
-
221
- <Warning>
222
- Never expose variable values through a public API. The above example shows creation/update but should be protected with authentication and authorization.
223
- </Warning>
224
-
225
- ### Via UI
226
-
227
- Build a UI for managing variables:
228
-
229
- ```typescript
230
- // Frontend component (React example)
231
- import { useState } from "react";
232
-
233
- function VariableManager() {
234
- const [name, setName] = useState("");
235
- const [value, setValue] = useState("");
236
- const [encrypted, setEncrypted] = useState(true);
237
-
238
- const handleCreate = async () => {
239
- const response = await fetch("/api/variables", {
240
- method: "POST",
241
- headers: { "Content-Type": "application/json" },
242
- body: JSON.stringify({ name, value, encrypted })
243
- });
244
-
245
- if (response.ok) {
246
- alert("Variable created successfully!");
247
- setName("");
248
- setValue("");
249
- }
250
- };
251
-
252
- return (
253
- <div>
254
- <h2>Create Variable</h2>
255
- <input
256
- type="text"
257
- placeholder="Variable name"
258
- value={name}
259
- onChange={(e) => setName(e.target.value)}
260
- />
261
- <textarea
262
- placeholder="Variable value"
263
- value={value}
264
- onChange={(e) => setValue(e.target.value)}
265
- />
266
- <label>
267
- <input
268
- type="checkbox"
269
- checked={encrypted}
270
- onChange={(e) => setEncrypted(e.target.checked)}
271
- />
272
- Encrypt value
273
- </label>
274
- <button onClick={handleCreate}>Create</button>
275
- </div>
276
- );
277
- }
278
- ```
279
-
280
- ## Variable configuration patterns
281
-
282
- ### API keys (encrypted)
283
-
284
- ```sql
285
- -- OpenAI
286
- INSERT INTO variables (name, value, encrypted)
287
- VALUES ('openai_api_key', 'sk-proj-...', true);
288
-
289
- -- Anthropic
290
- INSERT INTO variables (name, value, encrypted)
291
- VALUES ('anthropic_api_key', 'sk-ant-api03-...', true);
292
-
293
- -- Google
294
- INSERT INTO variables (name, value, encrypted)
295
- VALUES ('google_api_key', 'AIza...', true);
296
-
297
- -- Cohere
298
- INSERT INTO variables (name, value, encrypted)
299
- VALUES ('cohere_api_key', 'abc123...', true);
300
- ```
301
-
302
- ### Database credentials (encrypted)
303
-
304
- ```sql
305
- -- Full connection string
306
- INSERT INTO variables (name, value, encrypted)
307
- VALUES ('postgres_url', 'postgresql://user:pass@host:5432/db', true);
308
-
309
- -- Redis connection
310
- INSERT INTO variables (name, value, encrypted)
311
- VALUES ('redis_url', 'redis://:password@localhost:6379', true);
312
- ```
313
-
314
- ### Service tokens (encrypted)
315
-
316
- ```sql
317
- -- GitHub
318
- INSERT INTO variables (name, value, encrypted)
319
- VALUES ('github_token', 'ghp_...', true);
320
-
321
- -- Stripe
322
- INSERT INTO variables (name, value, encrypted)
323
- VALUES ('stripe_secret_key', 'sk_live_...', true);
324
-
325
- -- SendGrid
326
- INSERT INTO variables (name, value, encrypted)
327
- VALUES ('sendgrid_api_key', 'SG....', true);
328
- ```
329
-
330
- ### Configuration values (non-encrypted)
331
-
332
- ```sql
333
- -- App metadata
334
- INSERT INTO variables (name, value, encrypted)
335
- VALUES ('app_name', 'My Application', false);
336
-
337
- INSERT INTO variables (name, value, encrypted)
338
- VALUES ('app_version', '1.0.0', false);
339
-
340
- -- Feature flags
341
- INSERT INTO variables (name, value, encrypted)
342
- VALUES ('feature_analytics', 'true', false);
343
-
344
- -- Limits and quotas
345
- INSERT INTO variables (name, value, encrypted)
346
- VALUES ('max_requests_per_minute', '100', false);
347
- ```
348
-
349
- ### Multi-environment variables
350
-
351
- ```sql
352
- -- Development
353
- INSERT INTO variables (name, value, encrypted)
354
- VALUES ('dev_openai_api_key', 'sk-...', true);
355
-
356
- -- Staging
357
- INSERT INTO variables (name, value, encrypted)
358
- VALUES ('staging_openai_api_key', 'sk-...', true);
359
-
360
- -- Production
361
- INSERT INTO variables (name, value, encrypted)
362
- VALUES ('prod_openai_api_key', 'sk-...', true);
363
- ```
364
-
365
- Usage:
366
-
367
- ```typescript
368
- const env = process.env.NODE_ENV || "dev";
369
- const apiKey = await ExuluVariables.get(`${env}_openai_api_key`);
370
- ```
371
-
372
- ### Multi-tenant variables
373
-
374
- ```sql
375
- -- Per-tenant API keys
376
- INSERT INTO variables (name, value, encrypted) VALUES
377
- ('tenant_acme_openai_key', 'sk-...', true),
378
- ('tenant_globex_openai_key', 'sk-...', true),
379
- ('tenant_initech_openai_key', 'sk-...', true);
380
- ```
381
-
382
- Usage:
383
-
384
- ```typescript
385
- async function getTenantApiKey(tenantId: string) {
386
- return await ExuluVariables.get(`tenant_${tenantId}_openai_key`);
387
- }
388
- ```
389
-
390
- ## Encryption management
391
-
392
- ### Manual encryption (when inserting via SQL)
393
-
394
- If you need to insert encrypted variables directly via SQL:
395
-
396
- ```typescript
397
- import CryptoJS from "crypto-js";
398
-
399
- // Encrypt a value
400
- const plaintext = "sk-proj-abc123...";
401
- const encrypted = CryptoJS.AES.encrypt(
402
- plaintext,
403
- process.env.NEXTAUTH_SECRET
404
- ).toString();
405
-
406
- console.log(encrypted);
407
- // Use this encrypted value in your INSERT statement
408
- ```
409
-
410
- ```sql
411
- INSERT INTO variables (name, value, encrypted)
412
- VALUES ('openai_api_key', 'U2FsdGVkX1...', true);
413
- ```
414
-
415
- ### Manual decryption (for testing)
416
-
417
- ```typescript
418
- import CryptoJS from "crypto-js";
419
-
420
- const encrypted = "U2FsdGVkX1...";
421
- const bytes = CryptoJS.AES.decrypt(encrypted, process.env.NEXTAUTH_SECRET);
422
- const decrypted = bytes.toString(CryptoJS.enc.Utf8);
423
-
424
- console.log(decrypted); // "sk-proj-abc123..."
425
- ```
426
-
427
- ### Rotating the encryption key
428
-
429
- If you need to change your `NEXTAUTH_SECRET`:
430
-
431
- <Steps>
432
- <Step title="Retrieve all encrypted variables">
433
- ```typescript
434
- import { postgresClient, ExuluVariables } from "@exulu/backend";
435
-
436
- const { db } = await postgresClient();
437
- const encrypted = await db.from("variables").where({ encrypted: true });
438
-
439
- // Decrypt all with old key
440
- const decrypted = await Promise.all(
441
- encrypted.map(async (v) => ({
442
- name: v.name,
443
- value: await ExuluVariables.get(v.name) // Uses old key
444
- }))
445
- );
446
- ```
447
- </Step>
448
-
449
- <Step title="Update NEXTAUTH_SECRET">
450
- ```bash
451
- # Update your .env file
452
- NEXTAUTH_SECRET=new-secret-key-here
453
- ```
454
- </Step>
455
-
456
- <Step title="Re-encrypt variables">
457
- ```typescript
458
- import CryptoJS from "crypto-js";
459
-
460
- for (const { name, value } of decrypted) {
461
- const encrypted = CryptoJS.AES.encrypt(
462
- value,
463
- process.env.NEXTAUTH_SECRET // New key
464
- ).toString();
465
-
466
- await db("variables")
467
- .where({ name })
468
- .update({ value: encrypted });
469
- }
470
- ```
471
- </Step>
472
-
473
- <Step title="Verify">
474
- ```typescript
475
- // Test retrieval with new key
476
- const testValue = await ExuluVariables.get("openai_api_key");
477
- console.log("Success:", testValue);
478
- ```
479
- </Step>
480
- </Steps>
481
-
482
- <Warning>
483
- Rotating encryption keys is risky. Test thoroughly and have backups before proceeding.
484
- </Warning>
485
-
486
- ## Migration from .env files
487
-
488
- ### Step 1: Identify secrets
489
-
490
- List all secrets currently in `.env`:
491
-
492
- ```bash
493
- # .env
494
- OPENAI_API_KEY=sk-...
495
- ANTHROPIC_API_KEY=sk-ant-...
496
- DATABASE_URL=postgresql://...
497
- REDIS_URL=redis://...
498
- ```
499
-
500
- ### Step 2: Create variables
501
-
502
- ```typescript
503
- import { postgresClient } from "@exulu/backend";
504
- import CryptoJS from "crypto-js";
505
- import dotenv from "dotenv";
506
-
507
- dotenv.config();
508
-
509
- async function migrateFromEnv() {
510
- const { db } = await postgresClient();
511
-
512
- const secrets = [
513
- { name: "openai_api_key", envKey: "OPENAI_API_KEY" },
514
- { name: "anthropic_api_key", envKey: "ANTHROPIC_API_KEY" },
515
- { name: "database_url", envKey: "DATABASE_URL" },
516
- { name: "redis_url", envKey: "REDIS_URL" }
517
- ];
518
-
519
- for (const { name, envKey } of secrets) {
520
- const value = process.env[envKey];
521
- if (!value) continue;
522
-
523
- const encrypted = CryptoJS.AES.encrypt(
524
- value,
525
- process.env.NEXTAUTH_SECRET
526
- ).toString();
527
-
528
- await db.into("variables").insert({
529
- name,
530
- value: encrypted,
531
- encrypted: true
532
- });
533
-
534
- console.log(`Migrated ${name}`);
535
- }
536
- }
537
-
538
- migrateFromEnv();
539
- ```
540
-
541
- ### Step 3: Update code
542
-
543
- Replace `process.env` with `ExuluVariables.get()`:
544
-
545
- ```typescript
546
- // Before
547
- const apiKey = process.env.OPENAI_API_KEY;
548
-
549
- // After
550
- import { ExuluVariables } from "@exulu/backend";
551
- const apiKey = await ExuluVariables.get("openai_api_key");
552
- ```
553
-
554
- ### Step 4: Remove from .env
555
-
556
- After verifying everything works, remove secrets from `.env`:
557
-
558
- ```bash
559
- # .env (keep only NEXTAUTH_SECRET and non-secret config)
560
- NEXTAUTH_SECRET=your-secret
561
- NODE_ENV=production
562
- PORT=3000
563
- ```
564
-
565
- ## Best practices
566
-
567
- <AccordionGroup>
568
- <Accordion title="Always encrypt sensitive data">
569
- Set `encrypted: true` for API keys, tokens, passwords, connection strings, and any other secrets.
570
-
571
- ```sql
572
- -- ✅ Good
573
- INSERT INTO variables (name, value, encrypted)
574
- VALUES ('api_key', 'sk-...', true);
575
-
576
- -- ❌ Bad
577
- INSERT INTO variables (name, value, encrypted)
578
- VALUES ('api_key', 'sk-...', false);
579
- ```
580
- </Accordion>
581
-
582
- <Accordion title="Use descriptive, namespaced names">
583
- Variable names should be clear and avoid conflicts.
584
-
585
- ```sql
586
- -- ✅ Good
587
- 'openai_api_key'
588
- 'tenant_123_stripe_key'
589
- 'prod_database_url'
590
-
591
- -- ❌ Bad
592
- 'key1'
593
- 'api'
594
- 'secret'
595
- ```
596
- </Accordion>
597
-
598
- <Accordion title="Document required variables">
599
- Maintain a list of required variables for your application.
600
-
601
- ```typescript
602
- // config/variables.ts
603
- export const REQUIRED_VARIABLES = [
604
- "openai_api_key",
605
- "anthropic_api_key",
606
- "database_url",
607
- "redis_url"
608
- ];
609
-
610
- // Validate on startup
611
- async function validateVariables() {
612
- for (const name of REQUIRED_VARIABLES) {
613
- try {
614
- await ExuluVariables.get(name);
615
- } catch (error) {
616
- throw new Error(`Missing required variable: ${name}`);
617
- }
618
- }
619
- }
620
- ```
621
- </Accordion>
622
-
623
- <Accordion title="Backup encrypted variables">
624
- Regularly backup the `variables` table and keep your `NEXTAUTH_SECRET` secure.
625
-
626
- ```bash
627
- # Backup variables table
628
- pg_dump -U user -d database -t variables > variables_backup.sql
629
-
630
- # Store NEXTAUTH_SECRET separately in secure location
631
- echo "NEXTAUTH_SECRET=..." > .secret.backup
632
- ```
633
- </Accordion>
634
-
635
- <Accordion title="Limit access to variables table">
636
- Restrict database access to the `variables` table.
637
-
638
- ```sql
639
- -- Create read-only user for application
640
- CREATE USER app_user WITH PASSWORD 'secure_password';
641
- GRANT SELECT ON variables TO app_user;
642
-
643
- -- Admin user can create/update/delete
644
- GRANT ALL PRIVILEGES ON variables TO admin_user;
645
- ```
646
- </Accordion>
647
-
648
- <Accordion title="Validate on retrieval">
649
- Always wrap `ExuluVariables.get()` in try/catch.
650
-
651
- ```typescript
652
- try {
653
- const apiKey = await ExuluVariables.get("openai_api_key");
654
- // Use apiKey
655
- } catch (error) {
656
- console.error("Failed to retrieve API key:", error);
657
- // Handle error (use fallback, alert admin, etc.)
658
- }
659
- ```
660
- </Accordion>
661
- </AccordionGroup>
662
-
663
- ## Troubleshooting
664
-
665
- ### Variable not found
666
-
667
- ```typescript
668
- // Error: Variable my_api_key not found.
669
- ```
670
-
671
- **Solution**: Ensure the variable exists in the database:
672
-
673
- ```sql
674
- SELECT * FROM variables WHERE name = 'my_api_key';
675
- ```
676
-
677
- If missing, create it:
678
-
679
- ```sql
680
- INSERT INTO variables (name, value, encrypted)
681
- VALUES ('my_api_key', 'value', true);
682
- ```
683
-
684
- ### Decryption fails
685
-
686
- ```typescript
687
- // Error: Malformed UTF-8 data
688
- ```
689
-
690
- **Causes:**
691
- - Wrong `NEXTAUTH_SECRET` (different from when variable was encrypted)
692
- - Variable was not actually encrypted but `encrypted: true` is set
693
- - Corrupted encrypted value
694
-
695
- **Solution**: Re-encrypt the variable with the correct secret.
696
-
697
- ### Database connection error
698
-
699
- ```typescript
700
- // Error: Connection refused
701
- ```
702
-
703
- **Solution**: Verify your database connection settings:
704
-
705
- ```bash
706
- # Check environment variables
707
- echo $DATABASE_URL
708
-
709
- # Test connection
710
- psql $DATABASE_URL -c "SELECT 1"
711
- ```
712
-
713
- ### Encryption key too short
714
-
715
- If using a short `NEXTAUTH_SECRET`:
716
-
717
- ```typescript
718
- // Weak encryption with short key
719
- ```
720
-
721
- **Solution**: Use a properly generated secret:
722
-
723
- ```bash
724
- openssl rand -base64 32
725
- ```
726
-
727
- ## Next steps
728
-
729
- <CardGroup cols={2}>
730
- <Card title="API reference" icon="code" href="/core/exulu-variables/api-reference">
731
- Explore methods and usage
732
- </Card>
733
- <Card title="Overview" icon="book" href="/core/exulu-variables/introduction">
734
- Learn about variable concepts
735
- </Card>
736
- </CardGroup>