data-primals-engine 1.0.11 → 1.1.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/client/README.md +8 -0
- package/client/index.html +31 -0
- package/client/index.js +25 -0
- package/client/package-lock.json +11664 -0
- package/client/package.json +70 -0
- package/client/public/demo/26899917-d1ba-4df4-bb33-48d09a8778da.jpg +0 -0
- package/client/public/demo/4b9894c7-12cd-466d-8fd3-a2757b09ec96.jpg +0 -0
- package/client/public/demo/7ed369ac-a1a2-4b45-b0cd-4fd5bcf5a75a.jpg +0 -0
- package/client/public/doc/API.postman_collection.json +214 -0
- package/client/public/github.svg +1 -0
- package/client/public/profilCompany.jpg +0 -0
- package/client/public/profilDeveloper.jpg +0 -0
- package/client/public/profilEngineer.jpg +0 -0
- package/client/public/profilPersonal.jpg +0 -0
- package/client/public/profils .psd +0 -0
- package/client/public/react.svg +9 -0
- package/client/src/APIInfo.jsx +328 -0
- package/client/src/AddWidgetTypeModal.jsx +44 -0
- package/client/src/AddWidgetTypeModal.scss +87 -0
- package/client/src/App.css +42 -0
- package/client/src/App.jsx +586 -0
- package/client/src/App.scss +1466 -0
- package/client/src/AssistantChat.jsx +280 -0
- package/client/src/AssistantChat.scss +229 -0
- package/client/src/Button.jsx +12 -0
- package/client/src/Button.scss +197 -0
- package/client/src/CalculationBuilder.jsx +338 -0
- package/client/src/CalculationStepRow.jsx +199 -0
- package/client/src/CalendarConfigModal.jsx +49 -0
- package/client/src/ChartConfigModal.jsx +402 -0
- package/client/src/ConditionBuilder.jsx +622 -0
- package/client/src/ConditionBuilder.scss +672 -0
- package/client/src/ConditionBuilder2.jsx +757 -0
- package/client/src/ContentView.jsx +274 -0
- package/client/src/CronBuilder.jsx +126 -0
- package/client/src/CronBuilder.scss +128 -0
- package/client/src/CronPartBuilder.jsx +150 -0
- package/client/src/Dashboard.jsx +210 -0
- package/client/src/Dashboard.scss +445 -0
- package/client/src/DashboardChart.jsx +362 -0
- package/client/src/DashboardFlexViewItem.jsx +129 -0
- package/client/src/DashboardView.jsx +554 -0
- package/client/src/DataChart.jsx +349 -0
- package/client/src/DataEditor.jsx +556 -0
- package/client/src/DataLayout.jsx +709 -0
- package/client/src/DataTable.jsx +996 -0
- package/client/src/DataTable.scss +73 -0
- package/client/src/Dialog.jsx +90 -0
- package/client/src/Dialog.scss +117 -0
- package/client/src/DisplayFlexNodeRenderer.jsx +115 -0
- package/client/src/DocumentationPageLayout.jsx +93 -0
- package/client/src/DocumentationPageLayout.scss +262 -0
- package/client/src/Draggable.jsx +222 -0
- package/client/src/Draggable.scss +49 -0
- package/client/src/ExportDialog.jsx +172 -0
- package/client/src/Field.jsx +1558 -0
- package/client/src/FlexBuilder.jsx +269 -0
- package/client/src/FlexBuilder.scss +226 -0
- package/client/src/FlexBuilderControls.jsx +170 -0
- package/client/src/FlexBuilderModal.jsx +75 -0
- package/client/src/FlexBuilderModal.scss +109 -0
- package/client/src/FlexBuilderPreview.jsx +48 -0
- package/client/src/FlexBuilderUtils.js +84 -0
- package/client/src/FlexDataRenderer.jsx +170 -0
- package/client/src/FlexDataRenderer.scss +80 -0
- package/client/src/FlexNode.jsx +290 -0
- package/client/src/FlexTreeUtils.js +129 -0
- package/client/src/HiddenableCell.jsx +46 -0
- package/client/src/HiddenableCell.scss +36 -0
- package/client/src/KPIDialog.jsx +39 -0
- package/client/src/KPIWidget.jsx +139 -0
- package/client/src/KanbanCard.jsx +92 -0
- package/client/src/KanbanColumn.jsx +29 -0
- package/client/src/KanbanConfigModal.jsx +115 -0
- package/client/src/KanbanView.jsx +113 -0
- package/client/src/KanbanView.scss +107 -0
- package/client/src/MessageRotator.jsx +77 -0
- package/client/src/MessageRotator.scss +14 -0
- package/client/src/ModelCreator.jsx +640 -0
- package/client/src/ModelCreator.scss +154 -0
- package/client/src/ModelCreatorField.jsx +810 -0
- package/client/src/ModelImporter.jsx +120 -0
- package/client/src/ModelList.jsx +205 -0
- package/client/src/Notification.jsx +137 -0
- package/client/src/Notification.scss +126 -0
- package/client/src/NotificationProvider.jsx +73 -0
- package/client/src/PackGallery.jsx +211 -0
- package/client/src/PackGallery.scss +156 -0
- package/client/src/Pagination.jsx +141 -0
- package/client/src/RTE.jsx +415 -0
- package/client/src/RTETrans.jsx +103 -0
- package/client/src/RelationField.jsx +247 -0
- package/client/src/RelationValue.jsx +230 -0
- package/client/src/RestoreConfirmationModal.jsx +183 -0
- package/client/src/RestoreDialog.jsx +134 -0
- package/client/src/RestoreDialog.scss +67 -0
- package/client/src/RichTextEditorModal.jsx +34 -0
- package/client/src/RichTextEditorModal.scss +54 -0
- package/client/src/TourSpotlight.jsx +234 -0
- package/client/src/TourSpotlight.scss +100 -0
- package/client/src/TutorialsMenu.jsx +83 -0
- package/client/src/TutorialsMenu.scss +217 -0
- package/client/src/TutorialsRewardModal.jsx +65 -0
- package/client/src/Utils.jsx +78 -0
- package/client/src/ViewSwitcher.jsx +54 -0
- package/client/src/ViewSwitcher.scss +74 -0
- package/client/src/Webpage.jsx +69 -0
- package/client/src/_variables.scss +21 -0
- package/client/src/assets/react.svg +1 -0
- package/client/src/constants.js +68 -0
- package/client/src/contexts/AuthContext.jsx +28 -0
- package/client/src/contexts/ModelContext.jsx +328 -0
- package/client/src/contexts/UIContext.jsx +52 -0
- package/client/src/core/data.js +35 -0
- package/client/src/entry-client.jsx +15 -0
- package/client/src/entry-server.jsx +13 -0
- package/client/src/filter.js +222 -0
- package/client/src/hooks/data.js +101 -0
- package/client/src/hooks/useDebounce.js +20 -0
- package/client/src/hooks/useDragAndDrop.js +59 -0
- package/client/src/hooks/useLocalStorage.js +100 -0
- package/client/src/hooks/useMount.js +42 -0
- package/client/src/hooks/useTutorials.jsx +227 -0
- package/client/src/hooks/useWindowSize.js +24 -0
- package/client/src/i18n.js +47 -0
- package/client/src/index.css +90 -0
- package/client/src/index.js +10 -0
- package/client/src/main.jsx +11 -0
- package/client/src/translations.js +15940 -0
- package/client/src/tutorials.js +112 -0
- package/client/vite.config.js +30 -0
- package/eslint.config.js +50 -0
- package/package.json +48 -27
- package/server.js +9 -0
- package/src/constants.js +12 -23
- package/src/core.js +9 -8
- package/src/data.js +81 -80
- package/src/defaultModels.js +114 -115
- package/src/email.js +8 -9
- package/src/engine.js +5 -5
- package/src/events.js +1 -2
- package/src/i18n.js +212 -211
- package/src/middlewares/middleware-mongodb.js +94 -93
- package/src/migrate.js +24 -24
- package/src/modules/assistant.js +55 -55
- package/src/modules/bucket.js +10 -9
- package/src/modules/data.js +387 -357
- package/src/modules/file.js +3 -6
- package/src/modules/mongodb.js +6 -7
- package/src/modules/user.js +24 -47
- package/src/modules/workflow.js +68 -67
- package/src/openai.jobs.js +2 -2
- package/src/packs.js +30 -31
- package/src/providers.js +101 -3
- package/src/setenv.js +1 -1
- package/src/user.js +0 -17
- package/src/workers/crypto-worker.js +21 -20
- package/src/workers/import-export-worker.js +18 -18
- package/test/data.backup.integration.test.js +7 -12
- package/test/data.integration.test.js +27 -25
- package/test/globalSetup.js +2 -2
- package/test/import_export.integration.test.js +6 -6
- package/test/model.integration.test.js +21 -22
- package/test/workflow.integration.test.js +2 -5
- package/test/workflow.robustness.test.js +6 -13
- package/vitest.config.js +2 -2
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Fichier : src/tutorials.js
|
|
2
|
+
|
|
3
|
+
export const tutorialsConfig = [
|
|
4
|
+
{
|
|
5
|
+
id: 'contact-management-basics',
|
|
6
|
+
name: 'Gestion des contacts : Les bases',
|
|
7
|
+
description: 'Apprenez les opérations fondamentales : créer et supprimer un contact.',
|
|
8
|
+
icon: 'FaUserPlus',
|
|
9
|
+
stages: [
|
|
10
|
+
{
|
|
11
|
+
stage: 1,
|
|
12
|
+
tourName: 'tour-create-contact', // Nom du tour guidé à lancer
|
|
13
|
+
name: 'Créez votre premier contact',
|
|
14
|
+
description: 'Ajoutez un nouveau contact avec le prénom "Richard".',
|
|
15
|
+
completionCondition: { model: 'contact', limit: 1, filter: { "firstName": "Richard" } }
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
stage: 2,
|
|
19
|
+
tourName: 'tour-delete-contact',
|
|
20
|
+
name: 'Effacez vos traces',
|
|
21
|
+
description: 'Maintenant, supprimez le contact "Richard" que vous venez de créer.',
|
|
22
|
+
// La condition pour valider une suppression est de vérifier que le nombre d'éléments correspondants est 0.
|
|
23
|
+
completionCondition: { model: 'contact', limit: 0, filter: { "firstName": "Richard" } }
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
rewards: {
|
|
27
|
+
xpBonus: 150,
|
|
28
|
+
achievement: 'CONTACT_MANAGER_NOVICE',
|
|
29
|
+
notification: { title: 'Gestionnaire de contacts', message: 'Vous maîtrisez les bases de la gestion de contacts !' }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'advanced-permissions',
|
|
34
|
+
name: 'Permissions & rôles',
|
|
35
|
+
description: 'Maîtrisez la gestion des droits du bout des doigts !',
|
|
36
|
+
icon: 'FaUserShield',
|
|
37
|
+
stages: [
|
|
38
|
+
{
|
|
39
|
+
stage: 1,
|
|
40
|
+
tourName: 'tour-set-permissions',
|
|
41
|
+
name: 'Gestion des droits utilisateurs',
|
|
42
|
+
description: 'Trouvez l\'utilisateur "userTuto" et donnez-lui le droit "visitor".',
|
|
43
|
+
completionCondition: {model: 'user', limit: 1, filter: {"username": "userTuto", "roles": { "$find": {"$eq":["$$this.name","visitor"]}}}}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
stage: 2,
|
|
47
|
+
tourName: 'tour-create-role',
|
|
48
|
+
name: 'Créer un nouveau rôle',
|
|
49
|
+
description: 'Créez un rôle personnalisé nommé "Modérateur".',
|
|
50
|
+
// Condition : un document dans le modèle 'role' avec le nom 'Modérateur' doit exister.
|
|
51
|
+
// (On suppose ici l'existence d'un modèle 'role' pour gérer les rôles).
|
|
52
|
+
completionCondition: { model: 'role', limit: 1, filter: { "name": "moderator" } }
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
stage: 3,
|
|
56
|
+
tourName: 'tour-assign-permission-to-role',
|
|
57
|
+
name: 'Ajouter une permission au rôle',
|
|
58
|
+
description: 'Modifiez le rôle "moderator" pour lui ajouter la permission "API_EDIT_DATA_content".',
|
|
59
|
+
// Condition : le rôle 'Modérateur' doit avoir une permission nommée 'delete_contact'.
|
|
60
|
+
// (On suppose que le modèle 'role' a un champ 'permissions' qui est un tableau de relations).
|
|
61
|
+
completionCondition: { model: 'role', limit: 1, filter: { "name": "moderator", "permissions": { "$find": { "$eq": ["$$this.name", "API_EDIT_DATA_content"] } } } }
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
stage: 4,
|
|
65
|
+
tourName: 'tour-assign-role-to-user',
|
|
66
|
+
name: 'Promouvoir un utilisateur',
|
|
67
|
+
description: 'Maintenant, assignez votre rôle "moderator" à l\'utilisateur "userTuto".',
|
|
68
|
+
// Condition : l'utilisateur 'userTuto' doit maintenant aussi avoir le rôle 'Modérateur'.
|
|
69
|
+
completionCondition: { model: 'user', limit: 1, filter: { "username": "userTuto", "roles": { "$find": { "$eq": ["$$this.name", "moderator"] } } } }
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
rewards: {
|
|
73
|
+
xpBonus: 500,
|
|
74
|
+
achievement: 'PERMISSION_ARCHITECT',
|
|
75
|
+
notification: { title: 'Architecte des Permissions', message: 'Vous savez maintenant comment finement gérer les accès !' }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'requests',
|
|
80
|
+
name: 'Suivi d\'Activité',
|
|
81
|
+
description: 'Découvrez les succès liés à l\'activité.',
|
|
82
|
+
icon: 'FaUserShield',
|
|
83
|
+
stages: [
|
|
84
|
+
{
|
|
85
|
+
stage: 1,
|
|
86
|
+
tourName: null, // Pas de tour guidé, l'action peut se faire n'importe où
|
|
87
|
+
name: 'Première requête',
|
|
88
|
+
description: 'Effectuez des actions pour générer 50 requêtes système pour débloquer votre premier succès d\'activité.',
|
|
89
|
+
completionCondition: {model: 'request', limit: 50, filter: {}}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
stage: 2,
|
|
93
|
+
tourName: null,
|
|
94
|
+
name: 'Activité soutenue',
|
|
95
|
+
description: 'Continuez votre activité et atteignez 250 requêtes pour le prochain palier.',
|
|
96
|
+
completionCondition: {model: 'request', limit: 250, filter: {}}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
stage: 3,
|
|
100
|
+
tourName: null,
|
|
101
|
+
name: 'Expert en requêtes',
|
|
102
|
+
description: 'Impressionnant ! Atteignez 1000 requêtes pour prouver votre maîtrise.',
|
|
103
|
+
completionCondition: {model: 'request', limit: 1000, filter: {}}
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
rewards: {
|
|
107
|
+
xpBonus: 1000,
|
|
108
|
+
achievement: 'REQUEST_MASTER',
|
|
109
|
+
notification: { title: 'Maître des Requêtes', message: 'Votre activité sur le réseau est remarquable !' }
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
|
+
|
|
4
|
+
// https://vite.dev/config/
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
base: "/",
|
|
8
|
+
build: {
|
|
9
|
+
outDir: "dist"
|
|
10
|
+
},
|
|
11
|
+
server : {
|
|
12
|
+
proxy: {
|
|
13
|
+
'/api': {
|
|
14
|
+
target: 'http://localhost:7633',
|
|
15
|
+
secure: false,
|
|
16
|
+
changeOrigin: true,
|
|
17
|
+
// Optionnel mais utile pour le débogage :
|
|
18
|
+
// Affiche les requêtes proxy dans la console de Vite.
|
|
19
|
+
configure: (proxy, options) => {
|
|
20
|
+
proxy.on('proxyReq', (proxyReq, req, res) => {
|
|
21
|
+
console.log(`[Vite Proxy] Forwarding request: ${req.method} ${req.url} -> ${options.target}${proxyReq.path}`);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
fs: {
|
|
28
|
+
allow: ["./src"]
|
|
29
|
+
}
|
|
30
|
+
})
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// eslint.config.js
|
|
2
|
+
import globals from "globals";
|
|
3
|
+
import js from "@eslint/js";
|
|
4
|
+
// eslint.config.js
|
|
5
|
+
import { defineConfig } from "eslint/config";
|
|
6
|
+
|
|
7
|
+
export default defineConfig([
|
|
8
|
+
{
|
|
9
|
+
// Fichiers sur lesquels appliquer cette configuration
|
|
10
|
+
files: ["**/*.js"],
|
|
11
|
+
|
|
12
|
+
// Ignore les répertoires qui ne doivent pas être analysés
|
|
13
|
+
ignores: [
|
|
14
|
+
"node_modules/",
|
|
15
|
+
"dist/",
|
|
16
|
+
"coverage/",
|
|
17
|
+
"test-backups/"
|
|
18
|
+
],
|
|
19
|
+
|
|
20
|
+
// Options liées au langage JavaScript
|
|
21
|
+
languageOptions: {
|
|
22
|
+
ecmaVersion: "latest", // Utilise la dernière version de JavaScript
|
|
23
|
+
sourceType: "module", // Votre projet utilise des modules ES
|
|
24
|
+
globals: {
|
|
25
|
+
...globals.node, // Globaux pour l'environnement Node.js
|
|
26
|
+
...globals.es2021, // Globaux pour ES2021
|
|
27
|
+
...globals.vitest // Globaux pour Vitest (describe, it, expect, etc.)
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// Utilise les règles recommandées par ESLint
|
|
32
|
+
...js.configs.recommended,
|
|
33
|
+
|
|
34
|
+
// Vos règles personnalisées (à ajuster selon vos préférences)
|
|
35
|
+
rules: {
|
|
36
|
+
// Erreurs potentielles
|
|
37
|
+
"no-console": "off", // Avertit sur l'utilisation de console.log, mais ne bloque pas
|
|
38
|
+
"no-unused-vars": ["warn", { "args": "none" }], // Avertit sur les variables non utilisées
|
|
39
|
+
|
|
40
|
+
// Meilleures pratiques
|
|
41
|
+
"eqeqeq": ["error", "always"], // Impose l'utilisation de === et !==
|
|
42
|
+
|
|
43
|
+
// Style du code
|
|
44
|
+
"indent": ["error", 4], // Impose une indentation de 4 espaces
|
|
45
|
+
"quotes": ["off"], // Impose l'utilisation de guillemets simples
|
|
46
|
+
"semi": ["off"], // Impose l'utilisation de points-virgules à la fin des instructions
|
|
47
|
+
"comma-dangle": ["error"] // Impose une virgule finale sur les objets et tableaux multilignes
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]);
|
package/package.json
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-primals-engine",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "data-primals-engine is the package responsible from handling large amount of data in a practical and performant way. It can handle large amount of data in a practical and performant way. It can also get workflow models working (for automation), and fully supports internationalisation.",
|
|
5
5
|
"main": "src/engine.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"test": "cross-env MONGO_DB_URL=\"mongodb://localhost:27017\" PORT=7635 vitest --no-file-parallelism",
|
|
9
8
|
"preinstall": "npx force-resolutions",
|
|
10
|
-
"
|
|
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",
|
|
11
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",
|
|
20
|
+
"audit": "npm audit --audit-level=high",
|
|
12
21
|
"migrate:create": "node src/migrate.js create",
|
|
13
22
|
"migrate:up": "node src/migrate.js up",
|
|
14
23
|
"migrate:down": "node src/migrate.js down",
|
|
15
24
|
"migrate:revert": "node src/migrate.js revert",
|
|
16
25
|
"migrate:status": "node src/migrate.js status"
|
|
17
26
|
},
|
|
27
|
+
"optionalDependencies": {
|
|
28
|
+
"@rollup/rollup-linux-x64-gnu": "4.6.1"
|
|
29
|
+
},
|
|
18
30
|
"resolutions": {
|
|
19
31
|
"tar-fs": "3.0.9",
|
|
20
32
|
"on-headers": "1.1.0",
|
|
@@ -27,41 +39,49 @@
|
|
|
27
39
|
"exports": {
|
|
28
40
|
".": "./src/index.js",
|
|
29
41
|
"./modules/*": "./src/modules/*.js",
|
|
42
|
+
"./client": "./client/index.js",
|
|
30
43
|
"./*": "./src/*.js"
|
|
31
44
|
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"react": ">=18.0.0",
|
|
47
|
+
"react-query": ">=3.0.0"
|
|
48
|
+
},
|
|
32
49
|
"dependencies": {
|
|
33
|
-
"@langchain/core": "^0.3.
|
|
34
|
-
"@langchain/google-genai": "^0.2.
|
|
35
|
-
"@langchain/openai": "^0.
|
|
50
|
+
"@langchain/core": "^0.3.66",
|
|
51
|
+
"@langchain/google-genai": "^0.2.16",
|
|
52
|
+
"@langchain/openai": "^0.6.3",
|
|
36
53
|
"archiver": "^7.0.1",
|
|
37
54
|
"aws-sdk": "^2.1692.0",
|
|
38
|
-
"bcrypt": "^
|
|
39
|
-
"body-parser": "^
|
|
55
|
+
"bcrypt": "^6.0.0",
|
|
56
|
+
"body-parser": "^2.2.0",
|
|
40
57
|
"chalk": "^5.4.1",
|
|
41
58
|
"check-disk-space": "^3.4.0",
|
|
42
|
-
"compression": "^1.8.
|
|
59
|
+
"compression": "^1.8.1",
|
|
43
60
|
"cookie-parser": "^1.4.7",
|
|
44
|
-
"cronstrue": "^3.
|
|
45
|
-
"csv-parse": "^
|
|
61
|
+
"cronstrue": "^3.2.0",
|
|
62
|
+
"csv-parse": "^6.1.0",
|
|
63
|
+
"data-primals-engine": "^1.0.11",
|
|
46
64
|
"date-fns": "^4.1.0",
|
|
47
|
-
"express": "^
|
|
48
|
-
"express-csrf-double-submit-cookie": "^
|
|
65
|
+
"express": "^5.1.0",
|
|
66
|
+
"express-csrf-double-submit-cookie": "^2.0.0",
|
|
49
67
|
"express-formidable": "^1.2.0",
|
|
50
68
|
"express-mongo-sanitize": "^2.2.0",
|
|
51
69
|
"express-rate-limit": "^8.0.1",
|
|
52
|
-
"express-session": "^1.18.
|
|
53
|
-
"i18next": "^
|
|
54
|
-
"i18next-browser-languagedetector": "^8.0
|
|
70
|
+
"express-session": "^1.18.2",
|
|
71
|
+
"i18next": "^25.3.2",
|
|
72
|
+
"i18next-browser-languagedetector": "^8.2.0",
|
|
55
73
|
"juice": "^11.0.1",
|
|
56
|
-
"mathjs": "^14.
|
|
57
|
-
"mongodb": "^6.
|
|
74
|
+
"mathjs": "^14.6.0",
|
|
75
|
+
"mongodb": "^6.18.0",
|
|
58
76
|
"node-cache": "^5.1.2",
|
|
59
77
|
"node-schedule": "^2.1.1",
|
|
60
|
-
"nodemailer": "^
|
|
61
|
-
"
|
|
78
|
+
"nodemailer": "^7.0.5",
|
|
79
|
+
"prop-types": "^15.8.1",
|
|
80
|
+
"openai": "^5.10.2",
|
|
81
|
+
"process": "^0.11.10",
|
|
62
82
|
"randomcolor": "^0.6.2",
|
|
63
83
|
"react-helmet": "^6.1.0",
|
|
64
|
-
"react-i18next": "^15.
|
|
84
|
+
"react-i18next": "^15.6.1",
|
|
65
85
|
"react-markdown": "^10.1.0",
|
|
66
86
|
"request-ip": "^3.3.0",
|
|
67
87
|
"sanitize-html": "^2.17.0",
|
|
@@ -69,16 +89,17 @@
|
|
|
69
89
|
"swagger-ui-express": "^5.0.1",
|
|
70
90
|
"tar": "^7.4.3",
|
|
71
91
|
"uniqid": "^5.4.0",
|
|
72
|
-
"vitest": "^3.2.
|
|
92
|
+
"vitest": "^3.2.4",
|
|
73
93
|
"yaml": "^2.8.0"
|
|
74
94
|
},
|
|
75
95
|
"devDependencies": {
|
|
76
|
-
"@eslint/js": "^9.
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
96
|
+
"@eslint/js": "^9.32.0",
|
|
97
|
+
"concurrently": "^9.2.0",
|
|
98
|
+
"cross-env": "^10.0.0",
|
|
99
|
+
"eslint": "^9.32.0",
|
|
100
|
+
"globals": "^16.3.0"
|
|
81
101
|
},
|
|
102
|
+
"subPackages": ["client"],
|
|
82
103
|
"keywords": [
|
|
83
104
|
"mongodb",
|
|
84
105
|
"data",
|
package/server.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
//set ES modules to be loaded by the script
|
|
6
6
|
import process from "node:process";
|
|
7
7
|
import {Config, Engine, BenchmarkTool, GameObject, Logger} from "./src/index.js";
|
|
8
|
+
import sirv from "sirv";
|
|
8
9
|
|
|
9
10
|
Config.Set("modules", ["mongodb", "data", "file", "bucket", "workflow","user", "assistant", "swagger"])
|
|
10
11
|
Config.Set("middlewares", []);
|
|
@@ -29,4 +30,12 @@ engine.start(port, async (r) => {
|
|
|
29
30
|
const logger = engine.getComponent(Logger);
|
|
30
31
|
console.log("Server started on port" + port);
|
|
31
32
|
timer.stop();
|
|
33
|
+
|
|
34
|
+
// 2. Use sirv to serve static files from 'client/dist'
|
|
35
|
+
// The 'single: true' option is key for SPAs. It will serve 'index.html'
|
|
36
|
+
// for any route that doesn't match a file, enabling client-side routing.
|
|
37
|
+
engine.use(sirv('client/dist', {
|
|
38
|
+
single: true,
|
|
39
|
+
dev: process.env.NODE_ENV === 'development'
|
|
40
|
+
}));
|
|
32
41
|
});
|
package/src/constants.js
CHANGED
|
@@ -14,12 +14,13 @@ export const availableLangs = [
|
|
|
14
14
|
"el",
|
|
15
15
|
"ru",
|
|
16
16
|
"cs",
|
|
17
|
-
"sv"
|
|
17
|
+
"sv"
|
|
18
18
|
];
|
|
19
19
|
|
|
20
|
+
|
|
20
21
|
export const awsDefaultConfig = {
|
|
21
22
|
bucketName : 'bucket-primals',
|
|
22
|
-
region: 'eu-north-1'
|
|
23
|
+
region: 'eu-north-1'
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export const emailDefaultConfig = {
|
|
@@ -70,21 +71,8 @@ export const maxExecutionsByStep = 5;
|
|
|
70
71
|
export const maxWorkflowSteps = 15;
|
|
71
72
|
|
|
72
73
|
export const maxPrivateFileSize = 20 * megabytes; // Taille max par fichier privé (20 Mo)
|
|
73
|
-
export const
|
|
74
|
-
|
|
75
|
-
export const maxTotalPrivateFilesSizePremium = 20000 * kilobytes * kilobytes; //
|
|
76
|
-
|
|
77
|
-
export const plans = {
|
|
78
|
-
free:{
|
|
79
|
-
maxModelsPerUser,
|
|
80
|
-
maxTotalDataPerUser,
|
|
81
|
-
maxDataPerModelPerUser,
|
|
82
|
-
requestLimitPerHour: 7200,
|
|
83
|
-
},
|
|
84
|
-
premium: {
|
|
85
|
-
requestLimitPerHour: 250000,
|
|
86
|
-
}
|
|
87
|
-
}
|
|
74
|
+
export const maxTotalPrivateFilesSize = 250 * megabytes;
|
|
75
|
+
|
|
88
76
|
//
|
|
89
77
|
export const optionsSanitizer = {
|
|
90
78
|
allowedTags: [
|
|
@@ -103,9 +91,9 @@ export const optionsSanitizer = {
|
|
|
103
91
|
code: ['class'],
|
|
104
92
|
img: [ 'src', "alt","width","height","style" ]
|
|
105
93
|
},
|
|
106
|
-
// Lots of these won't come up by default because we don't allow them
|
|
94
|
+
// Lots of these won't come up by default because we don't allow them
|
|
107
95
|
selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
|
|
108
|
-
// URL schemes we permit
|
|
96
|
+
// URL schemes we permit
|
|
109
97
|
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto', 'tel' ],
|
|
110
98
|
allowedSchemesByTag: {},
|
|
111
99
|
allowedSchemesAppliedToAttributes: [ 'href', 'src', 'cite' ],
|
|
@@ -123,14 +111,15 @@ metaModels['i18n'] = { load: ['translation','lang']};
|
|
|
123
111
|
metaModels['website'] = { load: ['webpage', 'content', 'taxonomy', 'contact', 'event', 'resource'], 'require': ['i18n'] };
|
|
124
112
|
metaModels['messaging'] = { load: ['alert','ticket', 'message', 'channel'], 'require': ['i18n'] };
|
|
125
113
|
metaModels['eshopping'] = { load: [
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
114
|
+
'order', 'currency', 'product', 'productVariant', 'discount', 'cart', 'cartItem',
|
|
115
|
+
'brand', 'return', 'review', 'stock', 'returnItem', 'userSubscription',
|
|
116
|
+
'warehouse', 'shipment', 'campaign', 'stockAlert', 'invoice'],
|
|
117
|
+
'require': ['i18n', 'users', 'messaging'] };
|
|
130
118
|
metaModels['workflow'] = { load: ['env', 'workflow', 'workflowRun', 'workflowAction', 'workflowStep', 'workflowTrigger']};
|
|
131
119
|
metaModels['erp'] = { load: [ 'accountingExercise', 'accountingLineItem', 'accountingEntry', 'employee', 'dashboard', 'kpi'] };
|
|
132
120
|
|
|
133
121
|
|
|
122
|
+
|
|
134
123
|
export const allowedFields = ['locked', 'hiddenable', 'anonymized', 'condition', 'color', 'index', 'type', 'required', 'hint', 'default', 'validate', 'unique', 'name', 'placeholder', 'asMain'];
|
|
135
124
|
|
|
136
125
|
|
package/src/core.js
CHANGED
|
@@ -136,7 +136,7 @@ export function shuffle(array) {
|
|
|
136
136
|
let currentIndex = array.length;
|
|
137
137
|
|
|
138
138
|
// While there remain elements to shuffle...
|
|
139
|
-
while (currentIndex
|
|
139
|
+
while (currentIndex !== 0) {
|
|
140
140
|
|
|
141
141
|
// Pick a remaining element...
|
|
142
142
|
let randomIndex = Math.floor(Math.random() * currentIndex);
|
|
@@ -164,15 +164,16 @@ export const setSeed = (s)=>{
|
|
|
164
164
|
seed = s;
|
|
165
165
|
}
|
|
166
166
|
function splitmix32(a) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
167
|
+
a |= 0;
|
|
168
|
+
a = a + 0x9e3779b9 | 0;
|
|
169
|
+
let t = a ^ a >>> 16;
|
|
170
|
+
t = Math.imul(t, 0x21f0aaad);
|
|
171
|
+
t = t ^ t >>> 15;
|
|
172
|
+
t = Math.imul(t, 0x735a2d97);
|
|
173
|
+
return ((t = t ^ t >>> 15) >>> 0) / 4294967296;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
|
|
176
177
|
export const getRand = () =>splitmix32(seed);
|
|
177
178
|
|
|
178
179
|
export const getRandom = (minInclusive,maxInclusive) => {
|
package/src/data.js
CHANGED
|
@@ -183,39 +183,40 @@ export function getDefaultForType(field) {
|
|
|
183
183
|
if(field.default)
|
|
184
184
|
return typeof(field.default) === 'function' ? field.default() : field.default;
|
|
185
185
|
switch (field.type) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
186
|
+
case 'string':
|
|
187
|
+
case 'string_t':
|
|
188
|
+
case 'richtext':
|
|
189
|
+
case 'password':
|
|
190
|
+
case 'email':
|
|
191
|
+
case 'phone':
|
|
192
|
+
case 'url':
|
|
193
|
+
return '';
|
|
194
|
+
case 'model':
|
|
195
|
+
return '';
|
|
196
|
+
case 'modelField':
|
|
197
|
+
return { model: '', field: '' };
|
|
198
|
+
case 'color':
|
|
199
|
+
return null;
|
|
200
|
+
case 'number':
|
|
201
|
+
return 0;
|
|
202
|
+
case 'date':
|
|
203
|
+
case 'datetime':
|
|
204
|
+
return null;
|
|
205
|
+
case 'boolean':
|
|
206
|
+
return false;
|
|
207
|
+
case 'file':
|
|
208
|
+
return null;
|
|
209
|
+
case 'array':
|
|
210
|
+
return [];
|
|
211
|
+
case 'enum':
|
|
212
|
+
return field.required && field.items && field.items.length > 0 ? field.items[0] : null;
|
|
213
|
+
case 'object':
|
|
214
|
+
return {};
|
|
215
|
+
case 'relation':
|
|
216
|
+
return field.multiple ? [] : null;
|
|
217
|
+
default:
|
|
218
|
+
|
|
219
|
+
return undefined;
|
|
219
220
|
}
|
|
220
221
|
}
|
|
221
222
|
|
|
@@ -319,54 +320,54 @@ function buildApiConditionPayloadRecursive(conditionNode) {
|
|
|
319
320
|
|
|
320
321
|
// --- Build the specific $expr based on the operator ---
|
|
321
322
|
switch (exprOperator) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
break;
|
|
343
|
-
case '$exists':
|
|
344
|
-
const shouldExist = typeof value === 'boolean' ? value : String(value).toLowerCase() === 'true';
|
|
345
|
-
// Using $ne/$eq with $type is a common way to check existence in $expr
|
|
346
|
-
exprPayload = {
|
|
347
|
-
[shouldExist ? '$ne' : '$eq']: [ { $type: fieldPathForExpr }, "undefined" ]
|
|
348
|
-
};
|
|
349
|
-
// Note: For top-level, { field: { $exists: true/false } } is standard.
|
|
350
|
-
break;
|
|
351
|
-
default:
|
|
352
|
-
// Standard binary operators ($eq, $ne, $gt, $gte, $lt, $lte)
|
|
353
|
-
let processedValue = value;
|
|
354
|
-
// Basic type guessing for common string values
|
|
355
|
-
if (operator === '$eq' || operator === '$ne') {
|
|
356
|
-
if (value === 'true') processedValue = true;
|
|
357
|
-
else if (value === 'false') processedValue = false;
|
|
358
|
-
else if (value === 'null') processedValue = null;
|
|
359
|
-
// Avoid automatic number conversion for eq/ne unless explicitly needed
|
|
360
|
-
} else if (['$gt', '$gte', '$lt', '$lte'].includes(operator)) {
|
|
361
|
-
// Attempt number conversion for comparison operators
|
|
362
|
-
const num = Number(value);
|
|
363
|
-
if (!isNaN(num) && String(value).trim() !== '') {
|
|
364
|
-
processedValue = num;
|
|
365
|
-
}
|
|
366
|
-
// TODO: Consider adding date conversion if field type is known
|
|
323
|
+
case '$nin':
|
|
324
|
+
const ninValueArray = Array.isArray(value) ? value : String(value).split(',').map(s => s.trim()).filter(Boolean);
|
|
325
|
+
// Note: $nin at the top level is often better handled *outside* $expr
|
|
326
|
+
// but for consistency with $find, we keep it inside $expr here.
|
|
327
|
+
// If segmentsForNesting.length === 0, a standard query { field: { $nin: [...] } } might be more efficient.
|
|
328
|
+
exprPayload = { '$not': { '$in': [fieldPathForExpr, ninValueArray] } };
|
|
329
|
+
break;
|
|
330
|
+
case '$in':
|
|
331
|
+
const inValueArray = Array.isArray(value) ? value : String(value).split(',').map(s => s.trim()).filter(Boolean);
|
|
332
|
+
// Similar note as $nin regarding top-level efficiency.
|
|
333
|
+
exprPayload = { '$in': [fieldPathForExpr, inValueArray] };
|
|
334
|
+
break;
|
|
335
|
+
case '$regexMatch':
|
|
336
|
+
exprPayload = {
|
|
337
|
+
'$regexMatch': {
|
|
338
|
+
input: fieldPathForExpr,
|
|
339
|
+
regex: String(value),
|
|
340
|
+
options: 'i'
|
|
367
341
|
}
|
|
368
|
-
|
|
369
|
-
|
|
342
|
+
};
|
|
343
|
+
break;
|
|
344
|
+
case '$exists':
|
|
345
|
+
const shouldExist = typeof value === 'boolean' ? value : String(value).toLowerCase() === 'true';
|
|
346
|
+
// Using $ne/$eq with $type is a common way to check existence in $expr
|
|
347
|
+
exprPayload = {
|
|
348
|
+
[shouldExist ? '$ne' : '$eq']: [ { $type: fieldPathForExpr }, "undefined" ]
|
|
349
|
+
};
|
|
350
|
+
// Note: For top-level, { field: { $exists: true/false } } is standard.
|
|
351
|
+
break;
|
|
352
|
+
default:
|
|
353
|
+
// Standard binary operators ($eq, $ne, $gt, $gte, $lt, $lte)
|
|
354
|
+
let processedValue = value;
|
|
355
|
+
// Basic type guessing for common string values
|
|
356
|
+
if (operator === '$eq' || operator === '$ne') {
|
|
357
|
+
if (value === 'true') processedValue = true;
|
|
358
|
+
else if (value === 'false') processedValue = false;
|
|
359
|
+
else if (value === 'null') processedValue = null;
|
|
360
|
+
// Avoid automatic number conversion for eq/ne unless explicitly needed
|
|
361
|
+
} else if (['$gt', '$gte', '$lt', '$lte'].includes(operator)) {
|
|
362
|
+
// Attempt number conversion for comparison operators
|
|
363
|
+
const num = Number(value);
|
|
364
|
+
if (!isNaN(num) && String(value).trim() !== '') {
|
|
365
|
+
processedValue = num;
|
|
366
|
+
}
|
|
367
|
+
// TODO: Consider adding date conversion if field type is known
|
|
368
|
+
}
|
|
369
|
+
exprPayload = { [exprOperator]: [fieldPathForExpr, processedValue] };
|
|
370
|
+
break;
|
|
370
371
|
}
|
|
371
372
|
|
|
372
373
|
// The final payload for the innermost level is the $expr object
|