data-primals-engine 1.6.2-rc1 → 1.6.3
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/README.md +61 -20
- package/client/src/Dashboard.jsx +1 -1
- package/client/src/WorkflowEditor.jsx +101 -0
- package/client/src/WorkflowEditor.scss +29 -4
- package/package.json +145 -142
- package/src/client.js +4 -0
- package/src/defaultModels +1628 -0
- package/src/defaultModels.js +14 -0
- package/src/filter.js +170 -1
- package/src/modules/assistant/assistant.js +38 -56
- package/src/modules/assistant/providers.js +38 -0
- package/src/modules/data/data.history.js +7 -6
- package/src/modules/data/data.operations.js +20 -5
- package/src/modules/user.js +57 -25
- package/src/modules/workflow.js +53 -178
- package/src/providers.js +1 -1
- package/test/assistant.test.js +207 -0
- package/test/config.test.js +41 -0
- package/test/data.history.integration.test.js +144 -20
- package/test/user.test.js +195 -278
- package/test/workflow.integration.test.js +8 -0
package/README.md
CHANGED
|
@@ -153,6 +153,46 @@ The engine includes a pluggable system for user management. For development and
|
|
|
153
153
|
|
|
154
154
|
For production environments, you should use SSO providers as seen in the page below, or extend the base `UserProvider` class to connect to your actual user database (e.g., another MongoDB collection, a SQL database, or an external authentication service). This allows you to implement your own logic for finding and creating users.
|
|
155
155
|
|
|
156
|
+
### Permission System
|
|
157
|
+
|
|
158
|
+
The engine features a powerful dual-mode permission system, providing both granular, database-driven control and a lightweight, simplified approach.
|
|
159
|
+
|
|
160
|
+
#### 1. The Complete System (for Local Users)
|
|
161
|
+
|
|
162
|
+
This is the full-featured Role-Based Access Control (RBAC) system designed for application users. It relies on three core models:
|
|
163
|
+
|
|
164
|
+
- **`permission`**: Defines a single action (e.g., `API_EDIT_DATA_product`) and can include a JSON-based **filter** to restrict its scope (e.g., only edit products where `status` is `'draft'`).
|
|
165
|
+
- **`role`**: A group of permissions (e.g., an "Editor" role that includes `API_EDIT_DATA_product` and `API_SEARCH_DATA_product`).
|
|
166
|
+
- **`userPermission`**: Manages exceptions for individual users, allowing you to grant or revoke specific permissions, or even override a permission's filter for a single user.
|
|
167
|
+
|
|
168
|
+
When `hasPermission()` is called for a "local user" (a standard user stored in the database), the engine performs a detailed aggregation to compute the final set of active permissions and their corresponding filters.
|
|
169
|
+
|
|
170
|
+
#### 2. The Simplified System (for System/Non-Local Users)
|
|
171
|
+
|
|
172
|
+
For internal processes, system users, or temporary "demo" users, the full database-driven permission system can be overkill. The engine offers an "extremely simplified" mode for these cases.
|
|
173
|
+
|
|
174
|
+
**How it works:**
|
|
175
|
+
|
|
176
|
+
If a user object is not a "local user" (i.e., it does not have `_model: 'user'`), the permission check becomes a simple string comparison. The `hasPermission()` function will just check if the permission name you are testing exists directly in the user's `roles` array.
|
|
177
|
+
|
|
178
|
+
**Use Case:** This is perfect for system-level scripts or internal services that need specific, hard-coded permissions without the overhead of database lookups.
|
|
179
|
+
|
|
180
|
+
**Example:**
|
|
181
|
+
|
|
182
|
+
Consider a system user defined directly in your code:
|
|
183
|
+
|
|
184
|
+
```javascript
|
|
185
|
+
const systemUser = {
|
|
186
|
+
username: 'internal-service',
|
|
187
|
+
roles: ['API_SEARCH_DATA_product', 'API_ADD_DATA_order']
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
await hasPermission('API_SEARCH_DATA_product', systemUser); // Returns true
|
|
191
|
+
await hasPermission('API_DELETE_DATA_product', systemUser); // Returns false
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
This dual approach gives you the flexibility to use a robust, granular system for your end-users while maintaining a simple, performant mechanism for internal and system-level tasks.
|
|
195
|
+
|
|
156
196
|
### Model generation
|
|
157
197
|
Models are the way to handle structured data. They organize data and they can be declared in JSON.
|
|
158
198
|
|
|
@@ -898,26 +938,27 @@ Event.Listen("OnDataAdded", (engine, data) => {
|
|
|
898
938
|
}, "event", "system");
|
|
899
939
|
```
|
|
900
940
|
|
|
901
|
-
| Event | Description | Scope
|
|
902
|
-
|
|
903
|
-
| OnServerStart | Triggered once the HTTP server is started and listening. | System
|
|
904
|
-
| OnServerStop | Triggered right after the HTTP server is stopped. | System
|
|
905
|
-
| OnModelsLoaded | Triggered after the initial models are loaded and validated at startup. | System
|
|
906
|
-
| OnModelsDeleted | Triggered after all models are deleted via the reset function. | System
|
|
907
|
-
| OnUserDataDumped | Triggered after a user's data has been backed up (dumped). | System
|
|
908
|
-
| OnDataRestored | Triggered after a user's data has been restored from a backup. | System
|
|
909
|
-
| OnPackInstalled | Triggered after a data pack has been successfully installed. | System
|
|
910
|
-
| OnModelEdited | Triggered after a model definition has been modified. | System
|
|
911
|
-
| OnDataAdded | Triggered after new data has been inserted. | System
|
|
912
|
-
|
|
|
913
|
-
|
|
|
914
|
-
|
|
|
915
|
-
|
|
|
916
|
-
|
|
|
917
|
-
|
|
|
918
|
-
|
|
|
919
|
-
|
|
|
920
|
-
|
|
|
941
|
+
| Event | Description | Scope | Triggered by | Arguments (Payload) |
|
|
942
|
+
|:-----------------|:------------------------------------------------------------------------|:-------|:-------------------------|:---------------------------------------------------------------------|
|
|
943
|
+
| OnServerStart | Triggered once the HTTP server is started and listening. | System | engine.start() | engine |
|
|
944
|
+
| OnServerStop | Triggered right after the HTTP server is stopped. | System | engine.stop() | engine |
|
|
945
|
+
| OnModelsLoaded | Triggered after the initial models are loaded and validated at startup. | System | setupInitialModels() | engine, dbModels |
|
|
946
|
+
| OnModelsDeleted | Triggered after all models are deleted via the reset function. | System | engine.resetModels() | engine |
|
|
947
|
+
| OnUserDataDumped | Triggered after a user's data has been backed up (dumped). | System | jobDumpUserData() | engine |
|
|
948
|
+
| OnDataRestored | Triggered after a user's data has been restored from a backup. | System | loadFromDump() | (none) |
|
|
949
|
+
| OnPackInstalled | Triggered after a data pack has been successfully installed. | System | installPack() | pack |
|
|
950
|
+
| OnModelEdited | Triggered after a model definition has been modified. | System | editModel() | newModel |
|
|
951
|
+
| OnDataAdded | Triggered after new data has been inserted. | System | insertData() | engine, insertedDocs |
|
|
952
|
+
| OnDataEdited | Triggered after data has been edited. | System | editData() / patchData() | engine, {modelName, before, after} |
|
|
953
|
+
| OnDataDeleted | Triggered just after data is actually deleted. | System | deleteData() | engine, {model, filter} |
|
|
954
|
+
| OnDataSearched | Triggered after a data search. | System | searchData() | engine, {data, count} |
|
|
955
|
+
| OnDataExported | Triggered after a data export. | User | exportData() | exportResults, modelsToExport |
|
|
956
|
+
| OnDataInsert | Triggered just before data insertion. It will use the overrided data. | System | internal | data |
|
|
957
|
+
| OnDataValidate | Triggered to override validation check. | System | internal | value, field, data |
|
|
958
|
+
| OnDataFilter | Triggered to override data filtering operation. | System | internal | filteredValue, field, data |
|
|
959
|
+
| OnEmailTemplate | Triggered to override custom email templates | System | internal | templateData, lang |
|
|
960
|
+
| OnSystemPrompt | Triggered to override assistant system prompt | User | handleChatRequest | user |
|
|
961
|
+
| OnChatAction | Triggered when an action is created by the AI | User | handleChatRequest | action, params, parsedResponse, command, llmOptions, user, reqParams |
|
|
921
962
|
|
|
922
963
|
### Triggering events
|
|
923
964
|
|
package/client/src/Dashboard.jsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, {useState, useMemo, useEffect} from 'react';
|
|
2
2
|
import { Trans, useTranslation } from 'react-i18next';
|
|
3
|
-
import {FaPlus, FaSpinner, FaCog} from "react-icons/fa"; // Ajout FaTrash
|
|
3
|
+
import {FaPlus, FaSpinner, FaCog, FaEye} from "react-icons/fa"; // Ajout FaTrash
|
|
4
4
|
|
|
5
5
|
import "./Dashboard.scss"
|
|
6
6
|
import {useMutation, useQuery, useQueryClient} from "react-query";
|
|
@@ -12,6 +12,7 @@ import { useModelContext } from './contexts/ModelContext';
|
|
|
12
12
|
import { useAuthContext } from './contexts/AuthContext';
|
|
13
13
|
import { Trans, useTranslation } from 'react-i18next';
|
|
14
14
|
import { CodeField } from "./Field.jsx";
|
|
15
|
+
import { useData } from './hooks/data.js';
|
|
15
16
|
import { useQuery } from 'react-query';
|
|
16
17
|
|
|
17
18
|
import "./WorkflowEditor.scss"
|
|
@@ -32,6 +33,23 @@ const WorkflowEditor = ({ workflowId }) => {
|
|
|
32
33
|
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
|
33
34
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
34
35
|
const [selectedNode, setSelectedNode] = useState(null);
|
|
36
|
+
const [highlightedElements, setHighlightedElements] = useState({ nodes: new Set(), edges: new Set() });
|
|
37
|
+
const [workflowRuns, setWorkflowRuns] = useState([]);
|
|
38
|
+
const [selectedRun, setSelectedRun] = useState(null);
|
|
39
|
+
|
|
40
|
+
// --- CORRECTION ---
|
|
41
|
+
// On utilise le hook `useData` comme prévu, en lui passant directement les paramètres de la requête.
|
|
42
|
+
// Cela corrige l'erreur "Cannot read properties of undefined (reading 'queryKey')".
|
|
43
|
+
const { data: runsData, refetch: refetchRuns } = useData(
|
|
44
|
+
'workflowRun', // queryKey
|
|
45
|
+
{ model: 'workflowRun', filter: { workflow: workflowId }, sort: 'startedAt:DESC', limit: 10 }, // queryParams
|
|
46
|
+
{
|
|
47
|
+
queryKey: ['workflowRuns', workflowId],
|
|
48
|
+
enabled: !!workflowId,
|
|
49
|
+
// --- CORRECTION ---
|
|
50
|
+
// Le hook `useData` retourne déjà le tableau de données. On utilise donc `data` directement.
|
|
51
|
+
onSuccess: (data) => setWorkflowRuns(data || [])
|
|
52
|
+
});
|
|
35
53
|
const [panelWidth, setPanelWidth] = useState(300);
|
|
36
54
|
const resizeData = useRef({ isResizing: false, initialX: 0, initialWidth: 0 });
|
|
37
55
|
|
|
@@ -157,6 +175,7 @@ const WorkflowEditor = ({ workflowId }) => {
|
|
|
157
175
|
const nodePosition = { x: parentPosition.x, y: parentPosition.y + 120 };
|
|
158
176
|
initialNodes.push({
|
|
159
177
|
id: step._id,
|
|
178
|
+
// --- NOUVEAU --- Ajout d'une classe de base pour le styling
|
|
160
179
|
type: 'default',
|
|
161
180
|
className: 'workflow-step-node',
|
|
162
181
|
position: nodePosition,
|
|
@@ -182,6 +201,7 @@ const WorkflowEditor = ({ workflowId }) => {
|
|
|
182
201
|
initialNodes.push({
|
|
183
202
|
id: action._id,
|
|
184
203
|
type: 'default',
|
|
204
|
+
// --- NOUVEAU --- Ajout d'une classe de base pour le styling
|
|
185
205
|
className: 'workflow-action-node',
|
|
186
206
|
position: actionNodePosition,
|
|
187
207
|
data: {
|
|
@@ -220,6 +240,62 @@ const WorkflowEditor = ({ workflowId }) => {
|
|
|
220
240
|
}
|
|
221
241
|
}, [mainWorkflowData, workflowStepsData, workflowActionsData, setNodes, setEdges, t]);
|
|
222
242
|
|
|
243
|
+
// --- NOUVEAU ---
|
|
244
|
+
// Ce `useEffect` est le cœur de la nouvelle fonctionnalité.
|
|
245
|
+
// Il s'exécute chaque fois que l'utilisateur sélectionne un `workflowRun` différent.
|
|
246
|
+
useEffect(() => {
|
|
247
|
+
if (!selectedRun) {
|
|
248
|
+
// Si aucun run n'est sélectionné, on réinitialise tous les styles.
|
|
249
|
+
setNodes((nds) =>
|
|
250
|
+
nds.map((node) => ({
|
|
251
|
+
...node,
|
|
252
|
+
className: node.className?.split(' ')[0] // Garde seulement la classe de base (ex: 'workflow-step-node')
|
|
253
|
+
}))
|
|
254
|
+
);
|
|
255
|
+
setEdges((eds) =>
|
|
256
|
+
eds.map((edge) => ({
|
|
257
|
+
...edge,
|
|
258
|
+
animated: false,
|
|
259
|
+
className: ''
|
|
260
|
+
}))
|
|
261
|
+
);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 1. Identifier tous les IDs des nœuds (étapes et actions) qui ont été exécutés.
|
|
266
|
+
const executedStepIds = new Set(selectedRun.history.map(h => h.stepId));
|
|
267
|
+
const executedActionIds = new Set(selectedRun.history.flatMap(h => h.actions?.map(a => a.actionId) || []));
|
|
268
|
+
const allExecutedNodeIds = new Set([
|
|
269
|
+
`workflow-start-${mainWorkflowData._id}`, // Toujours inclure le nœud de départ
|
|
270
|
+
...executedStepIds,
|
|
271
|
+
...executedActionIds
|
|
272
|
+
]);
|
|
273
|
+
|
|
274
|
+
// 2. Mettre à jour les nœuds pour ajouter une classe 'executed'.
|
|
275
|
+
setNodes((nds) =>
|
|
276
|
+
nds.map((node) => {
|
|
277
|
+
const baseClass = node.className?.split(' ')[0] || '';
|
|
278
|
+
if (allExecutedNodeIds.has(node.id)) {
|
|
279
|
+
return { ...node, className: `${baseClass} executed` };
|
|
280
|
+
}
|
|
281
|
+
return { ...node, className: baseClass }; // Rétablir la classe de base si non exécuté
|
|
282
|
+
})
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
// 3. Mettre à jour les arêtes pour les animer si elles connectent deux nœuds exécutés.
|
|
286
|
+
setEdges((eds) =>
|
|
287
|
+
eds.map((edge) => {
|
|
288
|
+
const isExecuted = allExecutedNodeIds.has(edge.source) && allExecutedNodeIds.has(edge.target);
|
|
289
|
+
return {
|
|
290
|
+
...edge,
|
|
291
|
+
animated: isExecuted,
|
|
292
|
+
className: isExecuted ? 'executed' : ''
|
|
293
|
+
};
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
}, [selectedRun, setNodes, setEdges, mainWorkflowData]);
|
|
298
|
+
|
|
223
299
|
const onConnect = useCallback(
|
|
224
300
|
(params) => setEdges((eds) => addEdge(params, eds)),
|
|
225
301
|
[setEdges],
|
|
@@ -264,6 +340,11 @@ const WorkflowEditor = ({ workflowId }) => {
|
|
|
264
340
|
{/* Panneau latéral pour l'édition des propriétés */}
|
|
265
341
|
{selectedNode && (
|
|
266
342
|
<div className="properties-panel" style={{ width: `${panelWidth}px`, padding: '10px', borderLeft: '1px solid #ccc' }}>
|
|
343
|
+
<select onChange={(e) => setSelectedRun(workflowRuns.find(r => r._id === e.target.value))} value={selectedRun?._id || ''}>
|
|
344
|
+
<option value="">{t('select_a_run', 'Select a run to debug')}</option>
|
|
345
|
+
{workflowRuns.map(run => <option key={run._id} value={run._id}>{new Date(run.startedAt).toLocaleString()} - {run.status}</option>)}
|
|
346
|
+
</select>
|
|
347
|
+
<button onClick={() => refetchRuns()}>{t('refresh', 'Refresh')}</button>
|
|
267
348
|
<div
|
|
268
349
|
className="resizer"
|
|
269
350
|
onMouseDown={handleMouseDown}
|
|
@@ -271,6 +352,26 @@ const WorkflowEditor = ({ workflowId }) => {
|
|
|
271
352
|
<h3><Trans i18nKey="properties">Propriétés</Trans></h3>
|
|
272
353
|
<p><strong>ID:</strong> {selectedNode.id}</p>
|
|
273
354
|
|
|
355
|
+
{/* --- NOUVELLE SECTION POUR L'HISTORIQUE --- */}
|
|
356
|
+
{selectedRun && selectedRun.history && selectedRun.history.find(h => h.stepId === selectedNode.id) && (
|
|
357
|
+
<div className="mt-2 p-2 border rounded bg-gray-50">
|
|
358
|
+
<strong><Trans i18nKey="run_history">Run History</Trans> ({selectedRun.status})</strong>
|
|
359
|
+
{selectedRun.history.filter(h => h.stepId === selectedNode.id).map((historyEntry, index) => (
|
|
360
|
+
<div key={index} className="mt-1 text-sm">
|
|
361
|
+
<p><strong><Trans i18nKey="executed_at">Executed at:</Trans></strong> {new Date(historyEntry.executedAt).toLocaleTimeString()}</p>
|
|
362
|
+
<p><strong><Trans i18nKey="status">Status:</Trans></strong> {historyEntry.status}</p>
|
|
363
|
+
{historyEntry.actions?.length > 0 && (
|
|
364
|
+
<ul className="pl-4 list-disc">
|
|
365
|
+
{historyEntry.actions.map((actionHist, aIndex) => (
|
|
366
|
+
<li key={aIndex}>{actionHist.actionName}: {actionHist.status} ({actionHist.result})</li>
|
|
367
|
+
))}
|
|
368
|
+
</ul>
|
|
369
|
+
)}
|
|
370
|
+
</div>
|
|
371
|
+
))}
|
|
372
|
+
</div>
|
|
373
|
+
)}
|
|
374
|
+
|
|
274
375
|
{/* Affiche les conditions pour un workflowStep */}
|
|
275
376
|
{selectedNode.data.conditions && (
|
|
276
377
|
<div className="mt-2">
|
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
|
|
2
2
|
.workflow-step-node {
|
|
3
|
-
background-color: #
|
|
4
|
-
border-color: #
|
|
3
|
+
background-color: #f3f4f6; /* Gris clair par défaut */
|
|
4
|
+
border-color: #d1d5db;
|
|
5
5
|
border-width: 2px;
|
|
6
6
|
font-weight: bold;
|
|
7
|
+
transition: background-color 0.3s ease, border-color 0.3s ease;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
.workflow-action-node {
|
|
10
|
-
background-color: #
|
|
11
|
-
border-color: #
|
|
11
|
+
background-color: #f9fafb; /* Gris très clair par défaut */
|
|
12
|
+
border-color: #e5e7eb;
|
|
12
13
|
border-width: 1px;
|
|
13
14
|
border-style: dashed;
|
|
14
15
|
width: auto;
|
|
15
16
|
min-width: 150px;
|
|
17
|
+
transition: background-color 0.3s ease, border-color 0.3s ease;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* --- NOUVEAU : Styles pour les éléments exécutés --- */
|
|
21
|
+
|
|
22
|
+
/* Style pour les nœuds (étapes et actions) qui ont été exécutés */
|
|
23
|
+
.react-flow__node.executed {
|
|
24
|
+
background-color: #dcfce7; /* Vert clair */
|
|
25
|
+
border-color: #4ade80; /* Vert plus prononcé */
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Style pour les arêtes qui font partie du chemin d'exécution */
|
|
29
|
+
.react-flow__edge.executed .react-flow__edge-path {
|
|
30
|
+
stroke: #2563eb; /* Bleu vif */
|
|
31
|
+
stroke-width: 2.5;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Style pour l'animation sur les arêtes exécutées */
|
|
35
|
+
.react-flow__edge.executed.animated .react-flow__edge-path {
|
|
36
|
+
animation-duration: 1s;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.react-flow__edge-textbg {
|
|
40
|
+
fill: #f9fafb;
|
|
16
41
|
}
|
package/package.json
CHANGED
|
@@ -1,142 +1,145 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "data-primals-engine",
|
|
3
|
-
"version": "1.6.
|
|
4
|
-
"description": "data-primals-engine is a package responsible from handling large amount of data using MongoDB in a practical and performant way. It can also get workflow models working (for automation), and fully supports internationalisation. It also has integrated AI assistant.",
|
|
5
|
-
"main": "src/engine.js",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"preinstall": "npx force-resolutions",
|
|
9
|
-
"dev": "concurrently \"npm:client\" \"npm:devserver\"",
|
|
10
|
-
"prod": "npm run build-server && npm run server",
|
|
11
|
-
"client": "cd client && npm run dev",
|
|
12
|
-
"build-server": "vite build client --config client/vite.config.js --outDir dist",
|
|
13
|
-
"build-client": "cd client && npm run build",
|
|
14
|
-
"server": "cross-env NODE_ENV=production node server.js",
|
|
15
|
-
"devserver": "npm run build-server && cross-env NODE_ENV=development PORT=7633 node server.js",
|
|
16
|
-
"lint": "eslint .",
|
|
17
|
-
"format": "prettier --write .",
|
|
18
|
-
"clean": "rm -rf node_modules package-lock.json",
|
|
19
|
-
"test": "cross-env MONGO_DB_URL=\"mongodb://localhost:27017\" PORT=7635 vitest --no-file-parallelism --no-watch",
|
|
20
|
-
"audit": "npm audit --audit-level=high",
|
|
21
|
-
"migrate:create": "node src/migrate.js create",
|
|
22
|
-
"migrate:up": "node src/migrate.js up",
|
|
23
|
-
"migrate:down": "node src/migrate.js down",
|
|
24
|
-
"migrate:revert": "node src/migrate.js revert",
|
|
25
|
-
"migrate:status": "node src/migrate.js status"
|
|
26
|
-
},
|
|
27
|
-
"optionalDependencies": {
|
|
28
|
-
"@rollup/rollup-linux-x64-gnu": "4.6.1"
|
|
29
|
-
},
|
|
30
|
-
"resolutions": {
|
|
31
|
-
"on-headers": "1.1.0",
|
|
32
|
-
"brace-expansion": "2.0.2",
|
|
33
|
-
"prismjs": "1.30.0",
|
|
34
|
-
"xml2js": ">=0.5.0",
|
|
35
|
-
"tar-fs": ">=3.1.1",
|
|
36
|
-
"vite": ">=7.0.8"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
"./client": "./client
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"express-
|
|
77
|
-
"express-
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
"
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"@langchain/
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
"@
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"eslint": "^9.32.0",
|
|
124
|
-
"
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
"
|
|
128
|
-
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "data-primals-engine",
|
|
3
|
+
"version": "1.6.3",
|
|
4
|
+
"description": "data-primals-engine is a package responsible from handling large amount of data using MongoDB in a practical and performant way. It can also get workflow models working (for automation), and fully supports internationalisation. It also has integrated AI assistant.",
|
|
5
|
+
"main": "src/engine.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"preinstall": "npx force-resolutions",
|
|
9
|
+
"dev": "concurrently \"npm:client\" \"npm:devserver\"",
|
|
10
|
+
"prod": "npm run build-server && npm run server",
|
|
11
|
+
"client": "cd client && npm run dev",
|
|
12
|
+
"build-server": "vite build client --config client/vite.config.js --outDir dist",
|
|
13
|
+
"build-client": "cd client && npm run build",
|
|
14
|
+
"server": "cross-env NODE_ENV=production node server.js",
|
|
15
|
+
"devserver": "npm run build-server && cross-env NODE_ENV=development PORT=7633 node server.js",
|
|
16
|
+
"lint": "eslint .",
|
|
17
|
+
"format": "prettier --write .",
|
|
18
|
+
"clean": "rm -rf node_modules package-lock.json",
|
|
19
|
+
"test": "cross-env MONGO_DB_URL=\"mongodb://localhost:27017\" PORT=7635 vitest --no-file-parallelism --no-watch",
|
|
20
|
+
"audit": "npm audit --audit-level=high",
|
|
21
|
+
"migrate:create": "node src/migrate.js create",
|
|
22
|
+
"migrate:up": "node src/migrate.js up",
|
|
23
|
+
"migrate:down": "node src/migrate.js down",
|
|
24
|
+
"migrate:revert": "node src/migrate.js revert",
|
|
25
|
+
"migrate:status": "node src/migrate.js status"
|
|
26
|
+
},
|
|
27
|
+
"optionalDependencies": {
|
|
28
|
+
"@rollup/rollup-linux-x64-gnu": "4.6.1"
|
|
29
|
+
},
|
|
30
|
+
"resolutions": {
|
|
31
|
+
"on-headers": "1.1.0",
|
|
32
|
+
"brace-expansion": "2.0.2",
|
|
33
|
+
"prismjs": "1.30.0",
|
|
34
|
+
"xml2js": ">=0.5.0",
|
|
35
|
+
"tar-fs": ">=3.1.1",
|
|
36
|
+
"vite": ">=7.0.8",
|
|
37
|
+
"node-forge": ">=1.3.2",
|
|
38
|
+
"js-yaml": ">=4.1.1"
|
|
39
|
+
},
|
|
40
|
+
"overrides": {
|
|
41
|
+
"react-syntax-highlighter": {
|
|
42
|
+
"prismjs": "1.30.0"
|
|
43
|
+
},
|
|
44
|
+
"react-code-blocks": {
|
|
45
|
+
"prismjs": "1.30.0"
|
|
46
|
+
},
|
|
47
|
+
"refractor": {
|
|
48
|
+
"prismjs": "1.30.0"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "https://github.com/anonympins/data-primals-engine.git"
|
|
54
|
+
},
|
|
55
|
+
"exports": {
|
|
56
|
+
".": "./src/index.js",
|
|
57
|
+
"./client-only": "./src/client.js",
|
|
58
|
+
"./modules/*.js": "./src/modules/*.js",
|
|
59
|
+
"./modules/*": "./src/modules/*/index.js",
|
|
60
|
+
"./client": "./client/index.js",
|
|
61
|
+
"./*": "./src/*.js"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@langchain/core": "^0.3.79",
|
|
65
|
+
"archiver": "^7.0.1",
|
|
66
|
+
"aws-sdk": "^2.1692.0",
|
|
67
|
+
"bcrypt": "^6.0.0",
|
|
68
|
+
"body-parser": "^2.2.1",
|
|
69
|
+
"chalk": "^5.4.1",
|
|
70
|
+
"check-disk-space": "^3.4.0",
|
|
71
|
+
"compression": "^1.8.1",
|
|
72
|
+
"cookie-parser": "^1.4.7",
|
|
73
|
+
"cronstrue": "^3.2.0",
|
|
74
|
+
"csv-parse": "^6.1.0",
|
|
75
|
+
"date-fns": "^4.1.0",
|
|
76
|
+
"express-csrf-double-submit-cookie": "^2.0.0",
|
|
77
|
+
"express-formidable": "^1.2.0",
|
|
78
|
+
"express-mongo-sanitize": "^2.2.0",
|
|
79
|
+
"express-rate-limit": "^8.0.1",
|
|
80
|
+
"express-session": "^1.18.2",
|
|
81
|
+
"handlebars": "^4.7.8",
|
|
82
|
+
"i18next-browser-languagedetector": "^8.2.0",
|
|
83
|
+
"isolated-vm": "^5.0.4",
|
|
84
|
+
"juice": "^11.0.3",
|
|
85
|
+
"mathjs": "^15.1.0",
|
|
86
|
+
"mongodb": "^6.18.0",
|
|
87
|
+
"node-cache": "^5.1.2",
|
|
88
|
+
"node-schedule": "^2.1.1",
|
|
89
|
+
"nodemailer": "^7.0.10",
|
|
90
|
+
"openai": "^6.9.1",
|
|
91
|
+
"passport": "^0.7.0",
|
|
92
|
+
"passport-saml-encrypted": "^0.1.13",
|
|
93
|
+
"process": "^0.11.10",
|
|
94
|
+
"prop-types": "^15.8.1",
|
|
95
|
+
"randomcolor": "^0.6.2",
|
|
96
|
+
"react-markdown": "^10.1.0",
|
|
97
|
+
"read-excel-file": "^6.0.1",
|
|
98
|
+
"request-ip": "^3.3.0",
|
|
99
|
+
"safe-regex": "^2.1.1",
|
|
100
|
+
"sanitize-html": "^2.17.0",
|
|
101
|
+
"sirv": "^3.0.2",
|
|
102
|
+
"stripe": "^20.0.0",
|
|
103
|
+
"swagger-ui-express": "^5.0.1",
|
|
104
|
+
"tar": "^7.5.2",
|
|
105
|
+
"tinycolor2": "^1.6.0",
|
|
106
|
+
"uniqid": "^5.4.0",
|
|
107
|
+
"vitest": "^3.2.4",
|
|
108
|
+
"yaml": "^2.8.1"
|
|
109
|
+
},
|
|
110
|
+
"peerDependencies": {
|
|
111
|
+
"express": "^5.1.0",
|
|
112
|
+
"passport-azure-ad": "^4.3.5",
|
|
113
|
+
"passport-google-oauth20": "^2.0.0",
|
|
114
|
+
"react": "18.3.1",
|
|
115
|
+
"react-i18next": "^16.3.4",
|
|
116
|
+
"react-query": "^3.39.3",
|
|
117
|
+
"@langchain/anthropic": "^0.3.33",
|
|
118
|
+
"@langchain/deepseek": "^0.1.0",
|
|
119
|
+
"@langchain/google-genai": "^0.2.18",
|
|
120
|
+
"@langchain/openai": "^0.6.16"
|
|
121
|
+
},
|
|
122
|
+
"devDependencies": {
|
|
123
|
+
"@eslint/js": "^9.32.0",
|
|
124
|
+
"concurrently": "^9.2.0",
|
|
125
|
+
"cross-env": "^10.0.0",
|
|
126
|
+
"eslint": "^9.32.0",
|
|
127
|
+
"globals": "^16.3.0"
|
|
128
|
+
},
|
|
129
|
+
"subPackages": [
|
|
130
|
+
"client"
|
|
131
|
+
],
|
|
132
|
+
"keywords": [
|
|
133
|
+
"data-driven engine",
|
|
134
|
+
"headless CMS",
|
|
135
|
+
"backend",
|
|
136
|
+
"automation",
|
|
137
|
+
"AWS S3",
|
|
138
|
+
"MongoDB"
|
|
139
|
+
],
|
|
140
|
+
"author": "anonympins",
|
|
141
|
+
"license": "MIT",
|
|
142
|
+
"engines": {
|
|
143
|
+
"node": ">=20.0.0"
|
|
144
|
+
}
|
|
145
|
+
}
|
package/src/client.js
ADDED