data-primals-engine 1.2.3 → 1.2.5
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/CONTRIBUTING.md +91 -0
- package/README.md +50 -22
- package/client/src/App.jsx +0 -5
- package/client/src/App.scss +6 -0
- package/client/src/ConditionBuilder.scss +34 -1
- package/client/src/ConditionBuilder2.jsx +179 -53
- package/client/src/ContentView.jsx +0 -3
- package/client/src/CronBuilder.jsx +0 -1
- package/client/src/CronPartBuilder.jsx +0 -2
- package/client/src/DashboardView.jsx +0 -5
- package/client/src/DataEditor.jsx +8 -10
- package/client/src/DataImporter.jsx +469 -0
- package/client/src/DataLayout.jsx +0 -1
- package/client/src/DataTable.jsx +2 -368
- package/client/src/DataTable.scss +18 -1
- package/client/src/Field.jsx +85 -48
- package/client/src/FlexBuilder.jsx +1 -1
- package/client/src/ModelCreator.jsx +29 -25
- package/client/src/ModelCreator.scss +13 -0
- package/client/src/ModelCreatorField.jsx +1 -5
- package/client/src/RTE.jsx +1 -6
- package/client/src/RTETrans.jsx +0 -2
- package/client/src/RelationField.jsx +1 -1
- package/client/src/RelationValue.jsx +1 -2
- package/client/src/TourSpotlight.jsx +0 -2
- package/client/src/filter.js +87 -0
- package/client/src/hooks/data.js +1 -3
- package/client/src/hooks/useTutorials.jsx +0 -1
- package/client/src/translations.js +60 -26
- package/package.json +4 -3
- package/server.js +2 -2
- package/src/data.js +8 -0
- package/src/email.js +2 -2
- package/src/engine.js +59 -20
- package/src/index.js +1 -1
- package/src/middlewares/middleware-mongodb.js +0 -1
- package/src/modules/assistant.js +1 -3
- package/src/modules/bucket.js +3 -4
- package/src/modules/data/data.core.js +17 -0
- package/src/modules/{data.js → data/data.js} +4595 -5991
- package/src/modules/data/data.routes.js +1637 -0
- package/src/modules/data/index.js +1 -0
- package/src/modules/file.js +1 -1
- package/src/modules/mongodb.js +0 -1
- package/src/modules/user.js +1 -1
- package/src/modules/workflow.js +38 -38
- package/src/packs.js +4 -1
- package/test/data.backup.integration.test.js +4 -5
- package/test/data.integration.test.js +2 -6
- package/test/events.test.js +1 -1
- package/test/file.test.js +1 -4
- package/test/import_export.integration.test.js +22 -15
- package/test/model.integration.test.js +8 -10
- package/test/user.test.js +2 -2
- package/test/vm.test.js +1 -1
- package/test/workflow.integration.test.js +17 -14
- package/test/workflow.robustness.test.js +15 -10
- package/src/modules/test +0 -147
package/server.js
CHANGED
|
@@ -8,7 +8,7 @@ import {Config, Engine, BenchmarkTool, GameObject, Logger} from "./src/index.js"
|
|
|
8
8
|
import sirv from "sirv";
|
|
9
9
|
import express from "express";
|
|
10
10
|
|
|
11
|
-
Config.Set("modules", ["
|
|
11
|
+
Config.Set("modules", ["data", "mongodb", "file", "bucket", "workflow","user", "assistant", "swagger"])
|
|
12
12
|
Config.Set("middlewares", []);
|
|
13
13
|
|
|
14
14
|
const bench = GameObject.Create("Benchmark");
|
|
@@ -30,7 +30,7 @@ if (process.argv.length === 3) {
|
|
|
30
30
|
const port = process.env.PORT || 7633;
|
|
31
31
|
engine.start(port, async (r) => {
|
|
32
32
|
const logger = engine.getComponent(Logger);
|
|
33
|
-
console.log("Server started on port" + port);
|
|
33
|
+
console.log("Server started on port " + port);
|
|
34
34
|
timer.stop();
|
|
35
35
|
|
|
36
36
|
});
|
package/src/data.js
CHANGED
|
@@ -405,6 +405,14 @@ export function conditionToApiSearchFilter(condition) {
|
|
|
405
405
|
|
|
406
406
|
|
|
407
407
|
export const getFieldValueHash = (model, data) => {
|
|
408
|
+
// Prioritize composite unique constraints if they exist
|
|
409
|
+
const uniqueConstraints = model.constraints?.filter(c => c.type === 'unique') || [];
|
|
410
|
+
|
|
411
|
+
if (uniqueConstraints.length > 0) {
|
|
412
|
+
// Combine keys from all unique constraints to create a truly unique hash.
|
|
413
|
+
const constraintKeys = [...new Set(uniqueConstraints.flatMap(c => c.keys))];
|
|
414
|
+
return getObjectHash(data, constraintKeys, 'constraint');
|
|
415
|
+
}
|
|
408
416
|
const uniqueFields = model.fields.filter(f => f.unique).map(m => m.name);
|
|
409
417
|
const fs = model.fields.map(m => m.name);
|
|
410
418
|
const fields = ['_model', '_user', ...(uniqueFields.length ? uniqueFields : fs)];
|
package/src/email.js
CHANGED
|
@@ -75,9 +75,9 @@ export const sendEmail = async (email = "", data, smtpConfig = null, lang, tpl =
|
|
|
75
75
|
|
|
76
76
|
try {
|
|
77
77
|
await Promise.all(sendPromises);
|
|
78
|
-
console.log(`Email(s)
|
|
78
|
+
console.log(`Email(s) sent successfully to : ${emails.join(', ')}`);
|
|
79
79
|
} catch (error) {
|
|
80
|
-
console.error("
|
|
80
|
+
console.error("Error when sending to one ore more emails :", error);
|
|
81
81
|
// Vous pouvez relancer l'erreur si vous voulez que l'appelant la gère
|
|
82
82
|
throw error;
|
|
83
83
|
}
|
package/src/engine.js
CHANGED
|
@@ -13,13 +13,15 @@ import {
|
|
|
13
13
|
import http from "http";
|
|
14
14
|
import cookieParser from "cookie-parser";
|
|
15
15
|
import requestIp from 'request-ip';
|
|
16
|
-
import {createModel, deleteModels, getModels, installAllPacks, validateModelStructure} from "./modules/data.js";
|
|
16
|
+
import {createModel, deleteModels, getModels, installAllPacks, validateModelStructure} from "./modules/data/data.js";
|
|
17
17
|
import {defaultModels} from "./defaultModels.js";
|
|
18
18
|
import {DefaultUserProvider} from "./providers.js";
|
|
19
19
|
import formidableMiddleware from 'express-formidable';
|
|
20
20
|
import sirv from "sirv";
|
|
21
21
|
import * as tls from "node:tls";
|
|
22
22
|
import {Event} from "./events.js";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
import {isPathRelativeTo, isValidPath} from "./core.js";
|
|
23
25
|
|
|
24
26
|
// Constants
|
|
25
27
|
const isProduction = process.env.NODE_ENV === 'production'
|
|
@@ -49,23 +51,35 @@ const isTlsActive = !(!process.env.TLS || ["0", "false"].includes(process.env.TL
|
|
|
49
51
|
const clientOptions = {
|
|
50
52
|
maxPoolSize: databasePoolSize
|
|
51
53
|
};
|
|
52
|
-
|
|
54
|
+
|
|
55
|
+
// We add TLS options if enabled
|
|
53
56
|
if (isTlsActive) {
|
|
54
57
|
clientOptions.tls = true;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
|
|
59
|
+
// is mTLS ? (client certificate required instead of password)
|
|
60
|
+
if (process.env.CERT) {
|
|
61
|
+
clientOptions.secureContext = tls.createSecureContext({
|
|
62
|
+
ca: fs.readFileSync(process.env.CA_CERT),
|
|
63
|
+
cert: fs.readFileSync(process.env.CERT),
|
|
64
|
+
key: fs.readFileSync(process.env.CERT_KEY)
|
|
65
|
+
});
|
|
66
|
+
}else {
|
|
67
|
+
// Path to the authority certificate
|
|
68
|
+
if (process.env.CA_CERT) {
|
|
69
|
+
clientOptions.tlsCAFile = process.env.CA_CERT;
|
|
70
|
+
}
|
|
71
|
+
// Path to the certificate key
|
|
72
|
+
if (process.env.CERT_KEY) {
|
|
73
|
+
clientOptions.tlsCertificateKeyFile = process.env.CERT_KEY;
|
|
74
|
+
}
|
|
62
75
|
}
|
|
63
|
-
// Options pour le développement (à utiliser avec prudence)
|
|
64
76
|
if (tlsAllowInvalidCertificates) {
|
|
65
77
|
clientOptions.tlsAllowInvalidCertificates = true;
|
|
78
|
+
console.warn("🚨 [SECURITY WARNING] tlsAllowInvalidCertificates is ON. Server certificate will not be validated.");
|
|
66
79
|
}
|
|
67
80
|
if (tlsAllowInvalidHostnames) {
|
|
68
81
|
clientOptions.tlsAllowInvalidHostnames = true;
|
|
82
|
+
console.warn("🚨 [SECURITY WARNING] tlsAllowInvalidHostnames is ON. Server hostname will not be validated.");
|
|
69
83
|
}
|
|
70
84
|
}
|
|
71
85
|
|
|
@@ -143,18 +157,44 @@ export const Engine = {
|
|
|
143
157
|
}
|
|
144
158
|
};
|
|
145
159
|
|
|
146
|
-
await Promise.all(Config.Get('modules', []).map(async
|
|
160
|
+
await Promise.all(Config.Get('modules', []).map(async moduleIdentifier => {
|
|
147
161
|
try {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
162
|
+
let moduleDir;
|
|
163
|
+
const moduleName = path.basename(moduleIdentifier);
|
|
164
|
+
|
|
165
|
+
const directPath = path.resolve(moduleIdentifier);
|
|
166
|
+
let isDir = fs.existsSync(directPath) && fs.statSync(directPath).isDirectory();
|
|
167
|
+
if (isDir) {
|
|
168
|
+
moduleDir = directPath;
|
|
169
|
+
if (!fs.existsSync(moduleDir) || !fs.statSync(moduleDir).isDirectory()) {
|
|
170
|
+
logger.warn(`Le dossier du module est introuvable pour l'identifiant : '${moduleIdentifier}'. Chemin cherché : '${moduleDir}'.`);
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
moduleDir = path.resolve('./src/modules', moduleIdentifier);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
let moduleEntryPoint;
|
|
178
|
+
const jsPath = moduleDir+'.js';
|
|
179
|
+
const indexJsPath = path.join(moduleDir, 'index.js');
|
|
180
|
+
const moduleJsPath = path.join(moduleDir, `${moduleName}.js`);
|
|
181
|
+
|
|
182
|
+
if (fs.existsSync(jsPath)) {
|
|
183
|
+
moduleEntryPoint = 'file://'+jsPath;
|
|
184
|
+
} else if (fs.existsSync(indexJsPath)) {
|
|
185
|
+
moduleEntryPoint = 'file://'+indexJsPath;
|
|
186
|
+
} else if (fs.existsSync(moduleJsPath)) {
|
|
187
|
+
moduleEntryPoint = 'file://'+moduleJsPath;
|
|
152
188
|
}
|
|
153
|
-
|
|
154
|
-
|
|
189
|
+
|
|
190
|
+
return await importModule(moduleEntryPoint);
|
|
191
|
+
} catch (e) {
|
|
192
|
+
logger.error(`Échec du chargement du module '${moduleIdentifier}':`, e.stack);
|
|
193
|
+
return null;
|
|
155
194
|
}
|
|
156
|
-
})).then(async
|
|
157
|
-
|
|
195
|
+
})).then(async results => {
|
|
196
|
+
// On filtre les modules qui n'ont pas pu être chargés
|
|
197
|
+
engine._modules = results.filter(Boolean);
|
|
158
198
|
return Promise.resolve();
|
|
159
199
|
});
|
|
160
200
|
|
|
@@ -239,4 +279,3 @@ export const Engine = {
|
|
|
239
279
|
return engine;
|
|
240
280
|
}
|
|
241
281
|
}
|
|
242
|
-
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,6 @@ export { UserProvider } from './providers.js';
|
|
|
10
10
|
|
|
11
11
|
// --- Database & Data Modules ---
|
|
12
12
|
export { datasCollection, filesCollection, modelsCollection, packsCollection } from './modules/mongodb.js';
|
|
13
|
-
export { searchData, insertData, editData, exportData, importData, scheduleAlerts, cancelAlerts, validateModelStructure, installPack, jobDumpUserData, loadFromDump, dumpUserData, validateRestoreRequest, patchData, deleteData, createModel, editModel, deleteModels, getModel, getModels } from './modules/data.js';
|
|
13
|
+
export { searchData, insertData, editData, exportData, importData, scheduleAlerts, cancelAlerts, validateModelStructure, installPack, jobDumpUserData, loadFromDump, dumpUserData, validateRestoreRequest, patchData, deleteData, createModel, editModel, deleteModels, getModel, getModels } from './modules/data/index.js';
|
|
14
14
|
|
|
15
15
|
|
package/src/modules/assistant.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
// server/src/modules/assistant.js
|
|
2
|
-
|
|
3
1
|
import { getCollectionForUser, modelsCollection } from "./mongodb.js";
|
|
4
2
|
import { Logger } from "../gameObject.js";
|
|
5
3
|
import { ChatOpenAI } from "@langchain/openai";
|
|
6
4
|
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
|
7
5
|
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
8
|
-
import {searchData, patchData, deleteData, insertData} from "./data.js";
|
|
6
|
+
import {searchData, patchData, deleteData, insertData} from "./data/index.js";
|
|
9
7
|
import { getDataAsString } from "../data.js";
|
|
10
8
|
import i18n from "../../src/i18n.js";
|
|
11
9
|
import {generateLimiter} from "./user.js";
|
package/src/modules/bucket.js
CHANGED
|
@@ -3,7 +3,7 @@ import AWS from "aws-sdk";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import {decryptValue, encryptValue} from "../data.js";
|
|
6
|
-
import {loadFromDump, validateRestoreRequest} from "./data.js";
|
|
6
|
+
import {loadFromDump, validateRestoreRequest} from "./data/index.js";
|
|
7
7
|
import {Logger} from "../gameObject.js";
|
|
8
8
|
import {middlewareAuthenticator, userInitiator} from "./user.js";
|
|
9
9
|
import {awsDefaultConfig, maxBytesPerSecondThrottleData} from "../constants.js";
|
|
@@ -117,7 +117,6 @@ export async function getUserS3Config(user) {
|
|
|
117
117
|
bucketName: userConfig.bucketName || defaultConfig.bucketName
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
|
-
console.log({defaultConfig})
|
|
121
120
|
return defaultConfig;
|
|
122
121
|
}
|
|
123
122
|
const getS3Client = (s3Config) => {
|
|
@@ -212,9 +211,9 @@ export const deleteFromS3 = async (s3Config, remoteFilename) => {
|
|
|
212
211
|
|
|
213
212
|
try {
|
|
214
213
|
await s3.deleteObject(params).promise();
|
|
215
|
-
console.log(`
|
|
214
|
+
console.log(`File successfully removed from S3 : ${bucketPath}`);
|
|
216
215
|
} catch (err) {
|
|
217
|
-
console.error("
|
|
216
|
+
console.error("Error when deleting S3 file :", err);
|
|
218
217
|
throw err;
|
|
219
218
|
}
|
|
220
219
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import NodeCache from "node-cache";
|
|
2
|
+
|
|
3
|
+
export const modelsCache = new NodeCache( { stdTTL: 100, checkperiod: 120 } );
|
|
4
|
+
|
|
5
|
+
export const mongoDBWhitelist = [
|
|
6
|
+
"$$NOW", "$in", "$eq", "$gt", "$gte", "$in", "$lt", "$lte", "$ne", "$nin", "$type", "$size",
|
|
7
|
+
"$and", "$not", "$nor", "$or", "$regexMatch", "$find", "$elemMatch", "$filter", "$toString", "$toObjectId",
|
|
8
|
+
"$concat",
|
|
9
|
+
'$add', '$subtract', '$multiply', '$divide', '$mod', '$pow', "$sqrt",
|
|
10
|
+
"$rand",
|
|
11
|
+
"$abs", '$sin', '$cos', '$tan', '$asin', '$acos', '$atan',
|
|
12
|
+
"$toDate", "$toBool", "$toString", "$toInt", "$toDouble",
|
|
13
|
+
"$dateDiff", "$dateSubtract", "$dateAdd", "$dateToString",
|
|
14
|
+
'$year', '$month', '$week', '$dayOfMonth', '$dayOfWeek', '$dayOfYear', '$hour', '$minute', '$second', '$millisecond'
|
|
15
|
+
];
|
|
16
|
+
export let importJobs = {};
|
|
17
|
+
|