data-primals-engine 1.7.0 → 1.7.2
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 +160 -160
- package/client/package-lock.json +1080 -212
- package/client/package.json +12 -6
- package/client/src/AssistantChat.jsx +1 -3
- package/client/src/DataLayout.jsx +19 -20
- package/client/src/DataTable.jsx +2 -2
- package/client/src/DocumentationPageLayout.scss +1 -1
- package/client/src/ViewSwitcher.jsx +1 -1
- package/client/vite.config.js +31 -30
- package/package.json +39 -23
- package/src/ai.jobs.js +135 -0
- package/src/constants.js +561 -545
- package/src/core.js +487 -477
- package/src/data.js +2 -0
- package/src/email.js +0 -2
- package/src/engine.js +50 -42
- package/src/filter.js +348 -343
- package/src/modules/assistant/assistant.js +782 -763
- package/src/modules/assistant/constants.js +23 -16
- package/src/modules/assistant/providers.js +77 -37
- package/src/modules/bucket.js +4 -0
- package/src/modules/data/data.cluster.js +191 -0
- package/src/modules/data/data.core.js +11 -8
- package/src/modules/data/data.js +13 -4
- package/src/modules/data/data.operations.js +186 -106
- package/src/modules/data/data.relations.js +1 -0
- package/src/modules/data/data.replication.js +83 -0
- package/src/modules/data/data.routes.js +2183 -1879
- package/src/modules/mongodb.js +76 -73
- package/src/modules/user.js +7 -1
- package/src/modules/worker-script-runner.js +97 -0
- package/src/modules/workflow.js +1953 -1815
- package/src/packs.js +5701 -5697
- package/src/providers.js +298 -297
- package/test/assistant.test.js +207 -206
- package/test/data.integration.test.js +1425 -1416
- package/test/import_export.integration.test.js +210 -210
- package/test/workflow.actions.integration.test.js +487 -475
- package/test/workflow.integration.test.js +332 -329
package/src/modules/mongodb.js
CHANGED
|
@@ -1,73 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
import {Logger} from "../gameObject.js";
|
|
3
|
-
import {MongoDatabase} from "../engine.js";
|
|
4
|
-
import {ObjectId} from "mongodb";
|
|
5
|
-
import {isLocalUser} from "../data.js";
|
|
6
|
-
import {Event} from "../events.js";
|
|
7
|
-
import {Config} from "../config.js";
|
|
8
|
-
|
|
9
|
-
export let modelsCollection, datasCollection, filesCollection, packsCollection;
|
|
10
|
-
|
|
11
|
-
export {ObjectId};
|
|
12
|
-
|
|
13
|
-
let engine, logger, currentDb
|
|
14
|
-
|
|
15
|
-
let colls= [];
|
|
16
|
-
export async function onInit(defaultEngine) {
|
|
17
|
-
engine = defaultEngine;
|
|
18
|
-
logger = engine.getComponent(Logger);
|
|
19
|
-
|
|
20
|
-
currentDb = MongoDatabase();
|
|
21
|
-
modelsCollection = getCollection("models");
|
|
22
|
-
datasCollection = getCollection(Config.Get('dataCollection', 'datas'));
|
|
23
|
-
filesCollection = getCollection("files");
|
|
24
|
-
packsCollection = getCollection("packs");
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
export const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
1
|
+
|
|
2
|
+
import {Logger} from "../gameObject.js";
|
|
3
|
+
import {MongoDatabase} from "../engine.js";
|
|
4
|
+
import {ObjectId} from "mongodb";
|
|
5
|
+
import {isLocalUser} from "../data.js";
|
|
6
|
+
import {Event} from "../events.js";
|
|
7
|
+
import {Config} from "../config.js";
|
|
8
|
+
|
|
9
|
+
export let modelsCollection, datasCollection, filesCollection, packsCollection;
|
|
10
|
+
|
|
11
|
+
export {ObjectId};
|
|
12
|
+
|
|
13
|
+
let engine, logger, currentDb
|
|
14
|
+
|
|
15
|
+
let colls= [];
|
|
16
|
+
export async function onInit(defaultEngine) {
|
|
17
|
+
engine = defaultEngine;
|
|
18
|
+
logger = engine.getComponent(Logger);
|
|
19
|
+
|
|
20
|
+
currentDb = MongoDatabase();
|
|
21
|
+
modelsCollection = getCollection("models");
|
|
22
|
+
datasCollection = getCollection(Config.Get('dataCollection', 'datas'));
|
|
23
|
+
filesCollection = getCollection("files");
|
|
24
|
+
packsCollection = getCollection("packs");
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
colls = await (currentDb.listCollections()).toArray();
|
|
28
|
+
|
|
29
|
+
await Event.Trigger("OnDatabaseLoaded", "system", "calls", engine)
|
|
30
|
+
logger.info("MongoDB collections loaded.");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const getCollections= async (forceRefresh)=>{
|
|
34
|
+
if( !forceRefresh )
|
|
35
|
+
return colls;
|
|
36
|
+
colls = await currentDb.listCollections().toArray();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const createCollection = async (coll)=>{
|
|
40
|
+
const found =colls.find(f => f.name === coll);
|
|
41
|
+
if( found){
|
|
42
|
+
return getCollection(coll);
|
|
43
|
+
}
|
|
44
|
+
return await currentDb.createCollection(coll);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const isObjectId = (id) => {
|
|
48
|
+
return (typeof(id) === 'string' && id.match(/^[0-9a-fA-F]{24}$/));
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
export const getCollection = (str) => {
|
|
53
|
+
if (typeof str !== 'string') {
|
|
54
|
+
logger?.error(`[MongoDB] Tentative d'accès à une collection avec un type invalide: ${typeof str}`);
|
|
55
|
+
throw new Error("Le nom de la collection doit être une chaîne de caractères.");
|
|
56
|
+
}
|
|
57
|
+
return currentDb.collection(str);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const getDatabase = () => {
|
|
61
|
+
return currentDb;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// New function to determine the collection name for a user
|
|
65
|
+
export const getUserCollectionName = async (user) => {
|
|
66
|
+
const feat = await engine.userProvider.hasFeature(user, 'indexes');
|
|
67
|
+
const dataCollectionName = Config.Get('dataCollection', 'datas');
|
|
68
|
+
return feat ? (isLocalUser(user) ? `${dataCollectionName}_${user._user}` :`${dataCollectionName}_${user.username}` ) : dataCollectionName;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
// Modify existing functions to use the correct collection
|
|
73
|
+
export const getCollectionForUser = async (user) => {
|
|
74
|
+
const collectionName = await getUserCollectionName(user);
|
|
75
|
+
return getCollection(collectionName);
|
|
76
|
+
};
|
package/src/modules/user.js
CHANGED
|
@@ -358,8 +358,14 @@ export async function getSmtpConfig(user) {
|
|
|
358
358
|
acc[variable.name.replace('SMTP_', '').toLowerCase()] = variable.value;
|
|
359
359
|
return acc;
|
|
360
360
|
}, {});
|
|
361
|
+
|
|
361
362
|
if( !smtpConfig.port )
|
|
362
363
|
smtpConfig.port = cfg.port;
|
|
363
|
-
|
|
364
|
+
if( !smtpConfig.host )
|
|
365
|
+
smtpConfig.host = cfg.host;
|
|
366
|
+
if( !smtpConfig.user )
|
|
367
|
+
smtpConfig.user = cfg.user;
|
|
368
|
+
if( !smtpConfig.pass )
|
|
369
|
+
smtpConfig.pass = cfg.pass;
|
|
364
370
|
return smtpConfig;
|
|
365
371
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { parentPort } from 'worker_threads';
|
|
2
|
+
|
|
3
|
+
let callIdCounter = 0;
|
|
4
|
+
const pendingCalls = new Map();
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Appelle une fonction sur le thread principal et attend la réponse.
|
|
8
|
+
* @param {string} service - Le nom du service (ex: 'db').
|
|
9
|
+
* @param {string} method - Le nom de la méthode (ex: 'find').
|
|
10
|
+
* @param {...any} args - Les arguments de la méthode.
|
|
11
|
+
* @returns {Promise<any>}
|
|
12
|
+
*/
|
|
13
|
+
function callHost(service, method, ...args) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const callId = callIdCounter++;
|
|
16
|
+
pendingCalls.set(callId, { resolve, reject });
|
|
17
|
+
parentPort.postMessage({ type: 'call', callId, service, method, args });
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// API exposée au script de l'utilisateur
|
|
22
|
+
const db = {
|
|
23
|
+
create: (model, data) => callHost('db', 'create', model, data),
|
|
24
|
+
find: (model, filter, options) => callHost('db', 'find', model, filter, options),
|
|
25
|
+
findOne: (model, filter) => callHost('db', 'findOne', model, filter),
|
|
26
|
+
update: (model, filter, update) => callHost('db', 'update', model, filter, update),
|
|
27
|
+
delete: (model, filter) => callHost('db', 'delete', model, filter),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const workflow = {
|
|
31
|
+
run: (name, context) => callHost('workflow', 'run', name, context),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const logger = {
|
|
35
|
+
info: (...args) => callHost('log', 'info', ...args),
|
|
36
|
+
warn: (...args) => callHost('log', 'warn', ...args),
|
|
37
|
+
error: (...args) => callHost('log', 'error', ...args),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const env = {
|
|
41
|
+
get: (name) => callHost('env', 'get', name),
|
|
42
|
+
getAll: () => callHost('env', 'getAll'),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const http = {
|
|
46
|
+
request: (method, url, options) => callHost('http', 'request', method, url, options),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Exécute le code utilisateur dans un scope sécurisé.
|
|
51
|
+
* @param {string} code - Le code à exécuter.
|
|
52
|
+
* @param {object} context - Le contexte du workflow.
|
|
53
|
+
*/
|
|
54
|
+
async function runUserCode(code, context) {
|
|
55
|
+
// Crée une fonction asynchrone avec le code utilisateur.
|
|
56
|
+
// Les variables `db`, `logger`, `context`, etc., sont disponibles dans son scope.
|
|
57
|
+
const userFunction = new Function('db', 'workflow', 'logger', 'env', 'http', 'context', `return (async () => { ${code} })();`);
|
|
58
|
+
|
|
59
|
+
// Appelle la fonction avec l'API sandboxed.
|
|
60
|
+
return userFunction(db, workflow, logger, env, http, context);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Gestionnaire de messages unique pour le worker
|
|
64
|
+
parentPort.on('message', (msg) => {
|
|
65
|
+
// Message initial pour démarrer l'exécution
|
|
66
|
+
if (msg.code) {
|
|
67
|
+
// Le worker ne doit pas se terminer tant que le code n'est pas fini.
|
|
68
|
+
parentPort.ref();
|
|
69
|
+
runUserCode(msg.code, msg.context)
|
|
70
|
+
.then(result => {
|
|
71
|
+
parentPort.postMessage({ type: 'done', result });
|
|
72
|
+
})
|
|
73
|
+
.catch(e => {
|
|
74
|
+
parentPort.postMessage({ type: 'error', error: e.message });
|
|
75
|
+
})
|
|
76
|
+
.finally(() => {
|
|
77
|
+
// Une fois terminé, le worker peut se fermer.
|
|
78
|
+
parentPort.unref();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Message de réponse à un appel `callHost`
|
|
82
|
+
else if (msg.type === 'response') {
|
|
83
|
+
const { callId, result, error } = msg;
|
|
84
|
+
if (pendingCalls.has(callId)) {
|
|
85
|
+
const { resolve, reject } = pendingCalls.get(callId);
|
|
86
|
+
if (error) {
|
|
87
|
+
reject(new Error(error));
|
|
88
|
+
} else {
|
|
89
|
+
resolve(result);
|
|
90
|
+
}
|
|
91
|
+
pendingCalls.delete(callId);
|
|
92
|
+
}
|
|
93
|
+
} else if (msg.type === 'call') {
|
|
94
|
+
// Ce cas ne devrait pas arriver (le worker envoie 'call', il ne le reçoit pas),
|
|
95
|
+
// mais on le laisse pour la robustesse.
|
|
96
|
+
}
|
|
97
|
+
});
|