@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.
- package/dist/index.cjs +351 -42
- package/dist/index.d.cts +96 -1
- package/dist/index.d.ts +96 -1
- package/dist/index.js +340 -38
- package/ee/{markdown.ts → chunking/markdown.ts} +2 -2
- package/ee/python/README.md +295 -0
- package/ee/python/documents/processing/README.md +155 -0
- package/ee/{documents → python/documents}/processing/doc_processor.ts +25 -17
- package/ee/{documents/processing/pdf_to_markdown.py → python/documents/processing/document_to_markdown.py} +3 -10
- package/ee/python/setup.sh +180 -0
- package/package.json +14 -3
- package/scripts/postinstall.cjs +149 -0
- package/.agents/skills/mintlify/SKILL.md +0 -347
- package/.editorconfig +0 -15
- package/.eslintrc.json +0 -52
- package/.github/workflows/release-backend.yml +0 -38
- package/.husky/commit-msg +0 -1
- package/.jscpd.json +0 -18
- package/.mcp.json +0 -25
- package/.nvmrc +0 -1
- package/.prettierignore +0 -5
- package/.prettierrc.json +0 -12
- package/CHANGELOG.md +0 -8
- package/SECURITY.md +0 -5
- package/commitlint.config.js +0 -4
- package/devops/documentation/patch-older-releases.md +0 -42
- package/ee/documents/processing/build_pdf_processor.sh +0 -35
- package/ee/documents/processing/chunk_markdown.py +0 -263
- package/ee/documents/processing/pdf_processor.spec +0 -115
- package/eslint.config.js +0 -88
- package/jest.config.ts +0 -25
- package/mintlify-docs/.mintignore +0 -7
- package/mintlify-docs/AGENTS.md +0 -33
- package/mintlify-docs/CLAUDE.MD +0 -50
- package/mintlify-docs/CONTRIBUTING.md +0 -32
- package/mintlify-docs/LICENSE +0 -21
- package/mintlify-docs/README.md +0 -55
- package/mintlify-docs/ai-tools/claude-code.mdx +0 -43
- package/mintlify-docs/ai-tools/cursor.mdx +0 -39
- package/mintlify-docs/ai-tools/windsurf.mdx +0 -39
- package/mintlify-docs/api-reference/core-types/agent-types.mdx +0 -110
- package/mintlify-docs/api-reference/core-types/analytics-types.mdx +0 -95
- package/mintlify-docs/api-reference/core-types/configuration-types.mdx +0 -83
- package/mintlify-docs/api-reference/core-types/evaluation-types.mdx +0 -106
- package/mintlify-docs/api-reference/core-types/job-types.mdx +0 -135
- package/mintlify-docs/api-reference/core-types/overview.mdx +0 -73
- package/mintlify-docs/api-reference/core-types/prompt-types.mdx +0 -102
- package/mintlify-docs/api-reference/core-types/rbac-types.mdx +0 -163
- package/mintlify-docs/api-reference/core-types/session-types.mdx +0 -77
- package/mintlify-docs/api-reference/core-types/user-management.mdx +0 -112
- package/mintlify-docs/api-reference/core-types/workflow-types.mdx +0 -88
- package/mintlify-docs/api-reference/core-types.mdx +0 -585
- package/mintlify-docs/api-reference/dynamic-types.mdx +0 -851
- package/mintlify-docs/api-reference/endpoint/create.mdx +0 -4
- package/mintlify-docs/api-reference/endpoint/delete.mdx +0 -4
- package/mintlify-docs/api-reference/endpoint/get.mdx +0 -4
- package/mintlify-docs/api-reference/endpoint/webhook.mdx +0 -4
- package/mintlify-docs/api-reference/introduction.mdx +0 -661
- package/mintlify-docs/api-reference/mutations.mdx +0 -1012
- package/mintlify-docs/api-reference/openapi.json +0 -217
- package/mintlify-docs/api-reference/queries.mdx +0 -1154
- package/mintlify-docs/backend/introduction.mdx +0 -218
- package/mintlify-docs/changelog.mdx +0 -387
- package/mintlify-docs/community-edition.mdx +0 -304
- package/mintlify-docs/core/exulu-agent/api-reference.mdx +0 -894
- package/mintlify-docs/core/exulu-agent/configuration.mdx +0 -690
- package/mintlify-docs/core/exulu-agent/introduction.mdx +0 -552
- package/mintlify-docs/core/exulu-app/api-reference.mdx +0 -481
- package/mintlify-docs/core/exulu-app/configuration.mdx +0 -319
- package/mintlify-docs/core/exulu-app/introduction.mdx +0 -117
- package/mintlify-docs/core/exulu-authentication.mdx +0 -810
- package/mintlify-docs/core/exulu-chunkers/api-reference.mdx +0 -1011
- package/mintlify-docs/core/exulu-chunkers/configuration.mdx +0 -596
- package/mintlify-docs/core/exulu-chunkers/introduction.mdx +0 -403
- package/mintlify-docs/core/exulu-context/api-reference.mdx +0 -911
- package/mintlify-docs/core/exulu-context/configuration.mdx +0 -648
- package/mintlify-docs/core/exulu-context/introduction.mdx +0 -394
- package/mintlify-docs/core/exulu-database.mdx +0 -811
- package/mintlify-docs/core/exulu-default-agents.mdx +0 -545
- package/mintlify-docs/core/exulu-eval/api-reference.mdx +0 -772
- package/mintlify-docs/core/exulu-eval/configuration.mdx +0 -680
- package/mintlify-docs/core/exulu-eval/introduction.mdx +0 -459
- package/mintlify-docs/core/exulu-logging.mdx +0 -464
- package/mintlify-docs/core/exulu-otel.mdx +0 -670
- package/mintlify-docs/core/exulu-queues/api-reference.mdx +0 -648
- package/mintlify-docs/core/exulu-queues/configuration.mdx +0 -650
- package/mintlify-docs/core/exulu-queues/introduction.mdx +0 -474
- package/mintlify-docs/core/exulu-reranker/api-reference.mdx +0 -630
- package/mintlify-docs/core/exulu-reranker/configuration.mdx +0 -663
- package/mintlify-docs/core/exulu-reranker/introduction.mdx +0 -516
- package/mintlify-docs/core/exulu-tool/api-reference.mdx +0 -723
- package/mintlify-docs/core/exulu-tool/configuration.mdx +0 -805
- package/mintlify-docs/core/exulu-tool/introduction.mdx +0 -539
- package/mintlify-docs/core/exulu-variables/api-reference.mdx +0 -699
- package/mintlify-docs/core/exulu-variables/configuration.mdx +0 -736
- package/mintlify-docs/core/exulu-variables/introduction.mdx +0 -511
- package/mintlify-docs/development.mdx +0 -94
- package/mintlify-docs/docs.json +0 -248
- package/mintlify-docs/enterprise-edition.mdx +0 -538
- package/mintlify-docs/essentials/code.mdx +0 -35
- package/mintlify-docs/essentials/images.mdx +0 -59
- package/mintlify-docs/essentials/markdown.mdx +0 -88
- package/mintlify-docs/essentials/navigation.mdx +0 -87
- package/mintlify-docs/essentials/reusable-snippets.mdx +0 -110
- package/mintlify-docs/essentials/settings.mdx +0 -318
- package/mintlify-docs/favicon.svg +0 -3
- package/mintlify-docs/frontend/introduction.mdx +0 -39
- package/mintlify-docs/getting-started.mdx +0 -267
- package/mintlify-docs/guides/custom-agent.mdx +0 -608
- package/mintlify-docs/guides/first-agent.mdx +0 -315
- package/mintlify-docs/images/admin_ui.png +0 -0
- package/mintlify-docs/images/contexts.png +0 -0
- package/mintlify-docs/images/create_agents.png +0 -0
- package/mintlify-docs/images/evals.png +0 -0
- package/mintlify-docs/images/graphql.png +0 -0
- package/mintlify-docs/images/graphql_api.png +0 -0
- package/mintlify-docs/images/hero-dark.png +0 -0
- package/mintlify-docs/images/hero-light.png +0 -0
- package/mintlify-docs/images/hero.png +0 -0
- package/mintlify-docs/images/knowledge_sources.png +0 -0
- package/mintlify-docs/images/mcp.png +0 -0
- package/mintlify-docs/images/scaling.png +0 -0
- package/mintlify-docs/index.mdx +0 -411
- package/mintlify-docs/logo/dark.svg +0 -9
- package/mintlify-docs/logo/light.svg +0 -9
- package/mintlify-docs/partners.mdx +0 -558
- package/mintlify-docs/products.mdx +0 -77
- package/mintlify-docs/snippets/snippet-intro.mdx +0 -4
- package/mintlify-docs/styles.css +0 -207
- package/ngrok.bash +0 -1
- package/ngrok.md +0 -6
- package/ngrok.yml +0 -10
- package/release.config.cjs +0 -15
- package/skills-lock.json +0 -10
- package/types/context-processor.ts +0 -45
- package/types/enums/eval-types.ts +0 -5
- package/types/enums/field-types.ts +0 -1
- package/types/enums/jobs.ts +0 -11
- package/types/enums/statistics.ts +0 -13
- package/types/exulu-table-definition.ts +0 -79
- package/types/file-types.ts +0 -18
- package/types/models/agent-session.ts +0 -27
- package/types/models/agent.ts +0 -68
- package/types/models/context.ts +0 -53
- package/types/models/embedding.ts +0 -17
- package/types/models/eval-run.ts +0 -40
- package/types/models/exulu-agent-tool-config.ts +0 -11
- package/types/models/item.ts +0 -21
- package/types/models/job.ts +0 -8
- package/types/models/project.ts +0 -16
- package/types/models/rate-limiter-rules.ts +0 -7
- package/types/models/test-case.ts +0 -25
- package/types/models/tool.ts +0 -9
- package/types/models/user-role.ts +0 -12
- package/types/models/user.ts +0 -20
- package/types/models/variable.ts +0 -8
- package/types/models/vector-methods.ts +0 -7
- package/types/provider-config.ts +0 -21
- package/types/queue-config.ts +0 -16
- package/types/rbac-rights-modes.ts +0 -1
- package/types/statistics.ts +0 -20
- package/types/workflow.ts +0 -31
- /package/ee/{documents → python/documents}/THIRD_PARTY_LICENSES/docling.txt +0 -0
- /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>
|