data-primals-engine 1.0.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/LICENSE.md +7 -0
- package/README.md +169 -0
- package/package.json +72 -0
- package/server.js +85 -0
- package/src/config.js +16 -0
- package/src/constants.js +210 -0
- package/src/core.js +340 -0
- package/src/data.js +495 -0
- package/src/defaultModels.js +1287 -0
- package/src/email.js +349 -0
- package/src/engine.js +168 -0
- package/src/events.js +81 -0
- package/src/gameObject.js +189 -0
- package/src/i18n.js +16855 -0
- package/src/index.js +15 -0
- package/src/middlewares/middleware-mongodb.js +131 -0
- package/src/middlewares/throttle.js +33 -0
- package/src/middlewares/timeout.js +47 -0
- package/src/migrate.js +216 -0
- package/src/migrations/20240522143000-content.js +20 -0
- package/src/modules/assistant.js +296 -0
- package/src/modules/bucket.js +233 -0
- package/src/modules/data.js +5692 -0
- package/src/modules/file.js +192 -0
- package/src/modules/mongodb.js +67 -0
- package/src/modules/swagger.js +18 -0
- package/src/modules/user.js +226 -0
- package/src/modules/workflow.js +1296 -0
- package/src/openai.jobs.js +145 -0
- package/src/packs.js +3799 -0
- package/src/providers.js +61 -0
- package/src/tutorials.js +112 -0
- package/src/user.js +17 -0
- package/src/workers/crypto-worker.js +77 -0
- package/src/workers/import-export-worker.js +36 -0
package/src/core.js
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
|
|
5
|
+
export const sleep = (ms = 1000) =>
|
|
6
|
+
new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
|
|
8
|
+
export function escapeRegex(string) {
|
|
9
|
+
return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const isDate = dt => String(new Date(dt)) !== 'Invalid Date'
|
|
13
|
+
|
|
14
|
+
export function debounce(callback, delay=300){
|
|
15
|
+
var timer;
|
|
16
|
+
return function(){
|
|
17
|
+
var args = arguments;
|
|
18
|
+
var context = this;
|
|
19
|
+
clearTimeout(timer);
|
|
20
|
+
timer = setTimeout(function(){
|
|
21
|
+
callback.apply(context, args);
|
|
22
|
+
}, delay)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function uuidv4() {
|
|
27
|
+
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
|
|
28
|
+
(+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function cssProps(cssString) {
|
|
33
|
+
if (!cssString) return {};
|
|
34
|
+
|
|
35
|
+
const style = {};
|
|
36
|
+
const declarations = cssString.split(';');
|
|
37
|
+
|
|
38
|
+
declarations.forEach(declaration => {
|
|
39
|
+
const trimmed = declaration.trim();
|
|
40
|
+
if (!trimmed) return;
|
|
41
|
+
|
|
42
|
+
const colonIndex = trimmed.indexOf(':');
|
|
43
|
+
if (colonIndex === -1) return;
|
|
44
|
+
|
|
45
|
+
let property = trimmed.slice(0, colonIndex).trim();
|
|
46
|
+
const value = trimmed.slice(colonIndex + 1).trim();
|
|
47
|
+
|
|
48
|
+
// Convert kebab-case to camelCase
|
|
49
|
+
if (property.includes('-')) {
|
|
50
|
+
property = property.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
style[property] = value;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return style;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
export function removeDir(dirPath) {
|
|
61
|
+
const dirContents = fs.readdirSync(dirPath); // List dir content
|
|
62
|
+
|
|
63
|
+
for (const fileOrDirPath of dirContents) {
|
|
64
|
+
try {
|
|
65
|
+
// Get Full path
|
|
66
|
+
const fullPath = path.join(dirPath, fileOrDirPath);
|
|
67
|
+
const stat = fs.statSync(fullPath);
|
|
68
|
+
if (stat.isDirectory()) {
|
|
69
|
+
// It's a sub directory
|
|
70
|
+
if (fs.readdirSync(fullPath).length) removeDir(fullPath);
|
|
71
|
+
// If the dir is not empty then remove it's contents too(recursively)
|
|
72
|
+
fs.rmdirSync(fullPath);
|
|
73
|
+
} else fs.unlinkSync(fullPath); // It's a file
|
|
74
|
+
} catch (ex) {
|
|
75
|
+
console.error(ex.message);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const wordWrap = (str, max, br = '\n') => str.replace(
|
|
82
|
+
new RegExp(`(?![^\\n]{1,${max}}$)([^\\n]{1,${max}})\\s`, 'g'), `$1${br}`
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
export const getObjectHash = (obj, uniqueFields = null, key = "") => {
|
|
86
|
+
let str = "";
|
|
87
|
+
const keysToProcess = Object.keys(obj).sort(); // Trier les clés pour la cohérence
|
|
88
|
+
|
|
89
|
+
keysToProcess.forEach(k1 => {
|
|
90
|
+
const v = obj[k1];
|
|
91
|
+
if (v !== undefined) { // Ignorer les clés avec des valeurs undefined
|
|
92
|
+
// Simplification de la logique: on inclut soit les champs uniques, soit tous les champs.
|
|
93
|
+
// La sérialisation est la même dans les deux cas pour un champ donné.
|
|
94
|
+
if (uniqueFields === null || uniqueFields.length === 0 || uniqueFields.includes(k1)) {
|
|
95
|
+
try {
|
|
96
|
+
// Utiliser JSON.stringify avec un replacer pour gérer plus de types si nécessaire,
|
|
97
|
+
// ou simplement stringify directement. Attention aux types non sérialisables.
|
|
98
|
+
str += k1 + ':' + JSON.stringify(v) + ';'; // Inclure clé + valeur sérialisée
|
|
99
|
+
} catch (e) {
|
|
100
|
+
// Gérer les erreurs de sérialisation (ex: objets circulaires)
|
|
101
|
+
console.warn(`Could not stringify value for key ${k1} in getObjectHash`, e);
|
|
102
|
+
str += k1 + ':[unserializable];';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const buffer = str + key; // Ajouter la clé optionnelle à la fin
|
|
109
|
+
|
|
110
|
+
// Utiliser cyrb53 pour le hachage final
|
|
111
|
+
return cyrb53(buffer);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export function isPathRelativeTo(dir, parent) {
|
|
115
|
+
const relative = path.relative(parent, dir);
|
|
116
|
+
return relative && !relative.startsWith('..') && !path.isAbsolute(relative);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Ensures the value is a valid GUID
|
|
121
|
+
* @param value string value
|
|
122
|
+
*/
|
|
123
|
+
export function isGUID(value) {
|
|
124
|
+
return typeof(value) === 'string' && value.match(/^[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}$/);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function isPlainObject(obj) {
|
|
128
|
+
return typeof obj === 'object' && obj !== null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function escapeRegExp(string) {
|
|
132
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function shuffle(array) {
|
|
136
|
+
let currentIndex = array.length;
|
|
137
|
+
|
|
138
|
+
// While there remain elements to shuffle...
|
|
139
|
+
while (currentIndex != 0) {
|
|
140
|
+
|
|
141
|
+
// Pick a remaining element...
|
|
142
|
+
let randomIndex = Math.floor(Math.random() * currentIndex);
|
|
143
|
+
currentIndex--;
|
|
144
|
+
|
|
145
|
+
// And swap it with the current element.
|
|
146
|
+
[array[currentIndex], array[randomIndex]] = [
|
|
147
|
+
array[randomIndex], array[currentIndex]];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function sfc32(a, b, c, d) {
|
|
152
|
+
a |= 0; b |= 0; c |= 0; d |= 0;
|
|
153
|
+
let t = (a + b | 0) + d | 0;
|
|
154
|
+
d = d + 1 | 0;
|
|
155
|
+
a = b ^ b >>> 9;
|
|
156
|
+
b = c + (c << 3) | 0;
|
|
157
|
+
c = (c << 21 | c >>> 11);
|
|
158
|
+
c = c + t | 0;
|
|
159
|
+
return (t >>> 0) / 4294967296;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let seed = 0;
|
|
163
|
+
export const setSeed = (s)=>{
|
|
164
|
+
seed = s;
|
|
165
|
+
}
|
|
166
|
+
function splitmix32(a) {
|
|
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
|
+
}
|
|
175
|
+
|
|
176
|
+
export const getRand = () =>splitmix32(seed);
|
|
177
|
+
|
|
178
|
+
export const getRandom = (minInclusive,maxInclusive) => {
|
|
179
|
+
return Math.floor(Math.random() * (maxInclusive - minInclusive + 1) + minInclusive);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export function randomDate(start, end) {
|
|
183
|
+
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
|
|
184
|
+
}
|
|
185
|
+
export function isLightColor(color) {
|
|
186
|
+
if( !color )
|
|
187
|
+
return true;
|
|
188
|
+
const hex = color.replace('#', '');
|
|
189
|
+
const c_r = parseInt(hex.substr(0, 2), 16);
|
|
190
|
+
const c_g = parseInt(hex.substr(2, 2), 16);
|
|
191
|
+
const c_b = parseInt(hex.substr(4, 2), 16);
|
|
192
|
+
const brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000;
|
|
193
|
+
return brightness > 155;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Mettez cette fonction au début du fichier DataEditor.jsx ou dans un fichier utilitaire importé
|
|
197
|
+
export const tryParseJson = (jsonString) => {
|
|
198
|
+
if (!jsonString || typeof jsonString !== 'string') {
|
|
199
|
+
return null; // Retourne null si la chaîne est vide, null, ou pas une chaîne
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
// Tenter de parser la chaîne JSON
|
|
203
|
+
const parsed = JSON.parse(jsonString);
|
|
204
|
+
// S'assurer que c'est un objet ou null (pas un simple nombre, string, etc.)
|
|
205
|
+
return (typeof parsed === 'object' || parsed === null) ? parsed : null;
|
|
206
|
+
} catch (e) {
|
|
207
|
+
console.error("Failed to parse condition JSON:", e, jsonString);
|
|
208
|
+
return null; // Retourne null en cas d'erreur de parsing
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
export function isIsoDate(str) {
|
|
213
|
+
if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) return false;
|
|
214
|
+
const d = new Date(str);
|
|
215
|
+
return !isNaN(d.getTime()) && d.toISOString()===str; // valid date
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
Math.seed = function(s) {
|
|
220
|
+
return function() {
|
|
221
|
+
s = Math.sin(s) * 10000; return s - Math.floor(s);
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const cyrb53 = (str, seed = 0) => {
|
|
226
|
+
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
|
227
|
+
for(let i = 0, ch; i < str.length; i++) {
|
|
228
|
+
ch = str.charCodeAt(i);
|
|
229
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
230
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
231
|
+
}
|
|
232
|
+
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
|
|
233
|
+
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
234
|
+
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
|
|
235
|
+
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
236
|
+
|
|
237
|
+
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
String.prototype.hashCode = function() {
|
|
241
|
+
return cyrb53(this);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function random(min, max) {
|
|
245
|
+
min = Math.ceil(min);
|
|
246
|
+
max = Math.floor(max);
|
|
247
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
let triggers = {};
|
|
252
|
+
export const event_trigger = (name, ...params) => {
|
|
253
|
+
//console.log('Triggering raw event "' + name + '"');
|
|
254
|
+
let ret = false;
|
|
255
|
+
if (Array.isArray(triggers[name])) {
|
|
256
|
+
triggers[name].forEach((t) => {
|
|
257
|
+
const res = t.callback(...params);
|
|
258
|
+
if (Array.isArray(res)) {
|
|
259
|
+
if (!Array.isArray(ret)) ret = [];
|
|
260
|
+
ret = ret.concat(res);
|
|
261
|
+
} else if (typeof res === "string") {
|
|
262
|
+
if (typeof ret !== "string") ret = "";
|
|
263
|
+
ret += res;
|
|
264
|
+
} else if (typeof res === "number") {
|
|
265
|
+
if (typeof ret !== "number") ret = 0;
|
|
266
|
+
ret += res;
|
|
267
|
+
} else if (typeof res === "boolean") {
|
|
268
|
+
if (typeof ret !== "boolean") ret = true;
|
|
269
|
+
ret = res && ret;
|
|
270
|
+
} else {
|
|
271
|
+
ret = res || ret;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return ret;
|
|
276
|
+
};
|
|
277
|
+
export const event_on = (name, callback) => {
|
|
278
|
+
if (!Array.isArray(triggers[name])) {
|
|
279
|
+
triggers[name] = [];
|
|
280
|
+
}
|
|
281
|
+
triggers[name].push({ callback });
|
|
282
|
+
};
|
|
283
|
+
export const event_off = (name, callback) => {
|
|
284
|
+
if (callback && triggers[name]) {
|
|
285
|
+
triggers[name] = triggers[name].filter((f) => f.callback !== callback);
|
|
286
|
+
} else {
|
|
287
|
+
triggers[name] = undefined;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
export function slugify(str) {
|
|
293
|
+
str = str.replace(/^\s+|\s+$/g, ''); // trim leading/trailing white space
|
|
294
|
+
str = str.toLowerCase(); // convert string to lowercase
|
|
295
|
+
str = str.replace(/[^a-z0-9 -]/g, '') // remove any non-alphanumeric characters
|
|
296
|
+
.replace(/\s+/g, '-') // replace spaces with hyphens
|
|
297
|
+
.replace(/-+/g, '-'); // remove consecutive hyphens
|
|
298
|
+
return str;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// resource : https://stackoverflow.com/questions/190852/how-can-i-get-file-extensions-with-javascript
|
|
302
|
+
export function getFileExtension(fname) {
|
|
303
|
+
return fname.slice((fname.lastIndexOf(".") - 1 >>> 0) + 2);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export function object_equals( x, y ) {
|
|
307
|
+
if ( x === y ) return true;
|
|
308
|
+
// if both x and y are null or undefined and exactly the same
|
|
309
|
+
|
|
310
|
+
if ( ! ( x instanceof Object ) || ! ( y instanceof Object ) ) return false;
|
|
311
|
+
// if they are not strictly equal, they both need to be Objects
|
|
312
|
+
|
|
313
|
+
if ( x.constructor !== y.constructor ) return false;
|
|
314
|
+
// they must have the exact same prototype chain, the closest we can do is
|
|
315
|
+
// test there constructor.
|
|
316
|
+
|
|
317
|
+
for ( var p in x ) {
|
|
318
|
+
if ( ! x.hasOwnProperty( p ) ) continue;
|
|
319
|
+
// other properties were tested using x.constructor === y.constructor
|
|
320
|
+
|
|
321
|
+
if ( ! y.hasOwnProperty( p ) ) return false;
|
|
322
|
+
// allows to compare x[ p ] and y[ p ] when set to undefined
|
|
323
|
+
|
|
324
|
+
if ( x[ p ] === y[ p ] ) continue;
|
|
325
|
+
// if they have the same strict value or identity then they are equal
|
|
326
|
+
|
|
327
|
+
if ( typeof( x[ p ] ) !== "object" ) return false;
|
|
328
|
+
// Numbers, Strings, Functions, Booleans must be strictly equal
|
|
329
|
+
|
|
330
|
+
if ( ! object_equals( x[ p ], y[ p ] ) ) return false;
|
|
331
|
+
// Objects and Arrays must be tested recursively
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
for ( p in y )
|
|
335
|
+
if ( y.hasOwnProperty( p ) && ! x.hasOwnProperty( p ) )
|
|
336
|
+
return false;
|
|
337
|
+
// allows x[ p ] to be set to undefined
|
|
338
|
+
|
|
339
|
+
return true;
|
|
340
|
+
}
|