total5 0.0.1-9 → 0.0.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.
Files changed (59) hide show
  1. package/api.js +18 -10
  2. package/bin/flow5 +142 -0
  3. package/bin/total5 +166 -905
  4. package/builders.js +90 -35
  5. package/changelog.txt +3 -1
  6. package/cluster.js +1 -1
  7. package/cms.js +185 -51
  8. package/controller.js +233 -70
  9. package/cron.js +1 -1
  10. package/debug.js +12 -5
  11. package/edit.js +26 -33
  12. package/filestorage.js +38 -17
  13. package/flow-flowstream.js +199 -68
  14. package/flow.js +16 -10
  15. package/flowstream.js +4 -3
  16. package/global.js +84 -1
  17. package/htmlparser.js +41 -29
  18. package/http.js +3 -1
  19. package/image.js +4 -0
  20. package/images.js +1 -1
  21. package/index.js +246 -117
  22. package/jsonschema.js +21 -17
  23. package/macros.js +222 -0
  24. package/mail.js +11 -27
  25. package/markdown.js +21 -11
  26. package/minificators.js +1 -1
  27. package/nosql-querybuilder.js +4 -0
  28. package/nosql.js +8 -0
  29. package/openclient.js +1 -1
  30. package/package.json +4 -3
  31. package/pause.html +1 -1
  32. package/release.js +1 -1
  33. package/routing.js +118 -35
  34. package/sourcemap.js +6 -3
  35. package/test.js +9 -2
  36. package/tms.js +11 -14
  37. package/uibuilder.js +59 -23
  38. package/utils.js +147 -102
  39. package/viewengine.js +19 -8
  40. package/websocket.js +10 -6
  41. package/503.html +0 -65
  42. package/CONTRIBUTING.md +0 -55
  43. package/helpers/index.js +0 -32
  44. package/templates.json +0 -74
  45. package/tests/bundles/index.js +0 -25
  46. package/tests/cron.js +0 -0
  47. package/tests/htmlparser.js +0 -0
  48. package/tests/minifactors.js +0 -17
  49. package/tests/nosql.js +0 -18
  50. package/tests/proxy/index.js +0 -21
  51. package/tests/routing/index.js +0 -27
  52. package/tests/schemas.js +0 -17
  53. package/tests/server/index.js +0 -24
  54. package/tests/staticfiles/index.js +0 -24
  55. package/tests/utils.js +0 -17
  56. package/tmsclient.js +0 -125
  57. package/todo.txt +0 -11
  58. package/tools/beta.sh +0 -6
  59. package/tools/release.sh +0 -6
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // Total.js core
1
+ // Total.js framework
2
2
  // The MIT License
3
3
  // Copyright 2012-2023 (c) Peter Širka <petersirka@gmail.com>
4
4
 
@@ -20,7 +20,7 @@ Object.freeze(EMPTYOBJECT);
20
20
  Object.freeze(EMPTYARRAY);
21
21
 
22
22
  // Globals
23
- global.F = {};
23
+ global.F = global.Total = {};
24
24
  global.DEBUG = true;
25
25
  global.CONF = {};
26
26
  global.REPO = {};
@@ -38,6 +38,7 @@ global.DEF = {};
38
38
  F.clusterid = '';
39
39
  F.is5 = F.version = 5000;
40
40
  F.isBundle = false;
41
+ F.isLoaded = false;
41
42
  F.version_header = '5';
42
43
  F.version_node = process.version + '';
43
44
  F.EMPTYOBJECT = EMPTYOBJECT;
@@ -57,6 +58,8 @@ global.DEF = {};
57
58
  F.filestorages = {};
58
59
  F.jsonschemas = {};
59
60
  F.querybuilders = {};
61
+ F.openclients = {};
62
+ F.nodemodules = {};
60
63
  F.workers = {};
61
64
  F.config = CONF;
62
65
  F.def = DEF;
@@ -182,6 +185,7 @@ global.DEF = {};
182
185
  response: {
183
186
  ddos: 0,
184
187
  html: 0,
188
+ xml: 0,
185
189
  json: 0,
186
190
  websocket: 0,
187
191
  timeout: 0,
@@ -221,6 +225,9 @@ global.DEF = {};
221
225
  F.path.private = path => path ? F.path.$join(F.temporary.directories.private, path) : F.temporary.directories.private;
222
226
  F.path.databases = path => path ? F.path.$join(F.temporary.directories.databases, path) : F.temporary.directories.databases;
223
227
  F.path.plugins = path => path ? F.path.$join(F.temporary.directories.plugins, path) : F.temporary.directories.plugins;
228
+ F.path.templates = path => path ? F.path.$join(F.temporary.directories.templates, path) : F.temporary.directories.templates;
229
+ F.path.flowstreams = path => path ? F.path.$join(F.temporary.directories.flowstreams, path) : F.temporary.directories.flowstreams;
230
+ F.path.modules = path => path ? F.path.$join(F.temporary.directories.modules, path) : F.temporary.directories.modules;
224
231
  F.path.directory = (type, path) => path ? F.path.$join(F.temporary.directories[type], path) : F.temporary.directories[type];
225
232
  F.path.tmp = F.path.temp = path => path ? F.path.$join(F.temporary.directories.tmp, path) : F.temporary.directories.tmp;
226
233
  F.path.exists = (path, callback) => callback ? (F.Fs.lstat(path, (err, stats) => callback(err ? false : true, stats ? stats.size : 0, stats ? stats.isFile() : false))) : new Promise(resolve => F.path.exists(path, resolve));
@@ -338,15 +345,19 @@ function unlink(arr, callback) {
338
345
  // New internal configuration
339
346
  CONF.$root = '';
340
347
  CONF.$cors = ''; // hostnames separated by comma
348
+ CONF.$api = '/api/'; // a default API endpoint
341
349
  CONF.$sourcemap = true;
342
350
  CONF.$httpreqlimit = 0; // request limit per ip
343
351
  CONF.$httpcompress = true;
344
352
  CONF.$httpetag = '';
345
- CONF.$httpmaxsize = 256; // 256 kB
353
+ CONF.$httpmaxsize = 256; // kB
346
354
  CONF.$httprangebuffer = 5120; // 5 MB
347
355
  CONF.$httptimeout = 5; // 5 seconds
348
- CONF.$httpfiles = { flac: true, jpg: true, jpeg: true, png: true, gif: true, ico: true, wasm: true, js: true, mjs: true, css: true, txt: true, xml: true, woff: true, woff2: true, otf: true, ttf: true, eot: true, svg: true, zip: true, rar: true, pdf: true, docx: true, xlsx: true, doc: true, xls: true, html: true, htm: true, appcache: true, manifest: true, map: true, ogv: true, ogg: true, mp4: true, mp3: true, webp: true, webm: true, swf: true, package: true, json: true, ui: true, md: true, m4v: true, jsx: true, heif: true, heic: true, ics: true, ts: true, m3u8: true, wav: true, xsd: true, xsl: true, xslt: true };
356
+ CONF.$httpfiles = { flac: true, jpg: true, jpeg: true, png: true, gif: true, ico: true, wasm: true, js: true, mjs: true, css: true, txt: true, xml: true, woff: true, woff2: true, otf: true, ttf: true, eot: true, svg: true, zip: true, rar: true, pdf: true, docx: true, xlsx: true, doc: true, xls: true, html: true, htm: true, appcache: true, manifest: true, map: true, ogv: true, ogg: true, mp4: true, mp3: true, webp: true, webm: true, swf: true, package: true, json: true, ui: true, md: true, m4v: true, jsx: true, heif: true, heic: true, ics: true, ts: true, m3u8: true, wav: true, xsd: true, xsl: true, xslt: true, ipynb: true, ijsnb: true };
349
357
  CONF.$httpchecktypes = true; // for multipart data only
358
+ CONF.$httpmaxage = 60; // in seconds
359
+ CONF.$httpmaxkeys = 33;
360
+ CONF.$httpmaxkey = 25;
350
361
  CONF.$blacklist = '';
351
362
  CONF.$xpoweredby = 'Total.js';
352
363
  CONF.$maxopenfiles = 100;
@@ -369,15 +380,14 @@ function unlink(arr, callback) {
369
380
  CONF.$imagememory = 0; // disabled because e.g. GM v1.3.32 throws some error about the memory
370
381
  CONF.$stats = true;
371
382
 
372
- CONF.$nodemodules = require.resolve('./index');
373
- CONF.$nodemodules = CONF.$nodemodules.substring(0, CONF.$nodemodules.length - (8 + 7));
374
383
  CONF.$npmcache = '/var/www/.npm';
375
384
  CONF.$python = 'python3';
376
- CONF.$wsmaxsize = 256; // 256 kB
385
+ CONF.$wsmaxsize = 256; // kB
377
386
  CONF.$wscompress = true;
378
387
  CONF.$wsencodedecode = false;
379
388
  CONF.$wsmaxlatency = 2000;
380
389
  CONF.$proxytimeout = 5; // 5 seconds
390
+ // CONF.$proxyrequest = '';
381
391
  CONF.$cookiesamesite = 'Lax';
382
392
  CONF.$cookiesecure = false;
383
393
  CONF.$csrfexpiration = '30 minutes';
@@ -386,9 +396,10 @@ function unlink(arr, callback) {
386
396
  CONF.$tapiurl = 'eu';
387
397
  CONF.$tapimail = false;
388
398
  CONF.$tapilogger = false;
399
+ CONF.$imprint = true;
389
400
 
390
401
  CONF.$tms = false;
391
- CONF.$tmsmaxsize = 256;
402
+ CONF.$tmsmaxsize = 256; // kB
392
403
  CONF.$tmsurl = '/$tms/';
393
404
  CONF.$tmsclearblocked = 60; // in minutes
394
405
 
@@ -449,7 +460,7 @@ function unlink(arr, callback) {
449
460
  } else
450
461
  msg.to(email);
451
462
 
452
- msg.from(F.config.mail_from);
463
+ msg.from(F.config.mail_from || F.config.smtp.from || F.config.smtp.user);
453
464
  callback && msg.callback(callback);
454
465
 
455
466
  if (reply)
@@ -480,7 +491,10 @@ function unlink(arr, callback) {
480
491
 
481
492
  NOW = new Date();
482
493
 
483
- if (!name && err.name)
494
+ if (err instanceof F.TBuilders.ErrorBuilder) {
495
+ if (!name)
496
+ name = err[0].name;
497
+ } else if (!name && err.name)
484
498
  name = err.name;
485
499
 
486
500
  err = err.toString();
@@ -560,10 +574,12 @@ F.loadconfig = function(value) {
560
574
 
561
575
  break;
562
576
  case '$cryptoiv':
563
- cfg[key] = val ? Buffer.from(val, 'hex') : null;
577
+ cfg[key] = val ? Buffer.from(val, (/[A-Z=\/+]/).test(val) ? 'base64' : 'hex') : null;
564
578
  break;
565
- case 'mail_from':
566
579
  case '$root':
580
+ cfg[key] = val ? F.TUtils.normalize(val) : '';
581
+ break;
582
+ case 'mail_from':
567
583
  break;
568
584
  case '$port':
569
585
  cfg[key] = +val;
@@ -596,6 +612,7 @@ F.loadconfig = function(value) {
596
612
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = F.config.$insecure ? '0' : '1';
597
613
  F.logger(F.config.$logger == true);
598
614
  F.dir();
615
+ F.emit('$cors');
599
616
  F.emit('$tms');
600
617
  F.emit('$reconfigure');
601
618
  };
@@ -710,6 +727,9 @@ F.auth = function(fn) {
710
727
 
711
728
  F.load = async function(types, callback) {
712
729
 
730
+ if (!types)
731
+ types = '';
732
+
713
733
  var beg = Date.now();
714
734
 
715
735
  F.dir();
@@ -735,10 +755,11 @@ F.load = async function(types, callback) {
735
755
  return arr;
736
756
  };
737
757
 
738
- if (!types.length || types.includes('stats')) {
758
+ if (types.length && !types.includes('stats')) {
739
759
  F.config.$stats = false;
740
760
  F.config.$sourcemap = false;
741
- }
761
+ } else
762
+ F.config.$sourcemap = DEBUG;
742
763
 
743
764
  if (!types.length || types.includes('env')) {
744
765
  let env = await read(F.path.root('.env'));
@@ -770,7 +791,7 @@ F.load = async function(types, callback) {
770
791
  }
771
792
  }
772
793
 
773
- let loader = ['modules', 'controllers', 'actions', 'schemas', 'models', 'definitions', 'sources', 'middleware'];
794
+ let loader = ['modules', 'actions', 'schemas', 'models', 'definitions', 'controllers', 'middleware', 'sources'];
774
795
  var files = [];
775
796
  var tmp;
776
797
 
@@ -859,7 +880,7 @@ F.load = async function(types, callback) {
859
880
  F.loadservices();
860
881
  F.stats.compilation = Date.now() - beg;
861
882
  F.stats.compiled = files.length;
862
- F.isloaded = true;
883
+ F.isLoaded = true;
863
884
  DEBUG && F.TSourceMap.refresh();
864
885
  callback && callback();
865
886
 
@@ -868,9 +889,42 @@ F.load = async function(types, callback) {
868
889
  };
869
890
 
870
891
  F.require = function(name) {
892
+
871
893
  if (name.startsWith('node:'))
872
894
  return require(name);
873
- return NODE_MODULES[name] ? require('node:' + name) : require(F.Path.join(F.directory, name));
895
+
896
+ if (NODE_MODULES[name])
897
+ return require('node:' + name);
898
+
899
+ let mod = null;
900
+
901
+ try {
902
+ mod = require(name);
903
+ } catch (e) {
904
+ mod = require(F.Path.join(F.config.$nodemodules, name));
905
+ }
906
+
907
+ if (!mod)
908
+ throw new Error('NPM module "' + name + '" not found');
909
+
910
+ return mod;
911
+ };
912
+
913
+ F.runscript = function(filename) {
914
+ F.Fs.readFile(filename || PATH.root('debug.js'), function(err, data) {
915
+ if (data) {
916
+ var scr = data.toString('utf8').trim();
917
+ var fn;
918
+ if (data) {
919
+ try {
920
+ fn = new Function('require', scr);
921
+ } catch (e) {
922
+ console.error(e);
923
+ }
924
+ fn && fn(require);
925
+ }
926
+ }
927
+ });
874
928
  };
875
929
 
876
930
  F.import = function(url, callback) {
@@ -977,7 +1031,7 @@ F.npminstall = function(name, callback) {
977
1031
  if (!callback)
978
1032
  return new Promise((resolve, reject) => F.npminstall(name, err => err ? reject(err) : resolve()));
979
1033
 
980
- var path = F.config.$node_modules;
1034
+ var path = F.config.$nodemodules;
981
1035
  F.path.mkdir(path, true);
982
1036
 
983
1037
  var index = name.lastIndexOf('@');
@@ -1033,7 +1087,13 @@ F.shell = function(cmd, callback, cwd) {
1033
1087
 
1034
1088
  F.console = function() {
1035
1089
 
1090
+ if (!F.config.$imprint)
1091
+ return;
1092
+
1036
1093
  var memory = process.memoryUsage();
1094
+ var nodemodules = require.resolve('./index');
1095
+
1096
+ nodemodules = nodemodules.substring(0, nodemodules.length - (8 + 7));
1037
1097
 
1038
1098
  print('====================================================');
1039
1099
  print('PID : ' + process.pid);
@@ -1054,10 +1114,10 @@ F.console = function() {
1054
1114
  print('====================================================');
1055
1115
  F.config.$root && print('Root : ' + F.config.$root);
1056
1116
  print('Directory : ' + process.cwd());
1057
- print('node_modules : ' + F.config.$nodemodules);
1117
+ print('node_modules : ' + nodemodules);
1058
1118
  print('====================================================\n');
1059
1119
 
1060
- if (!F.isWorker) {
1120
+ if (!F.isWorker && F.server) {
1061
1121
 
1062
1122
  var hostname = F.unixsocket ? ('Socket: ' + F.unixsocket) : '{2}://{0}:{1}/'.format(F.config.$ip, F.config.$port, F.isHTTPS ? 'https' : 'http');
1063
1123
 
@@ -1082,7 +1142,7 @@ F.console = function() {
1082
1142
 
1083
1143
  F.loadservices = function() {
1084
1144
 
1085
- F.internal.interval && clearInterval(F.internal.timeouts);
1145
+ F.internal.interval && clearInterval(F.internal.interval);
1086
1146
 
1087
1147
  // This timer solving timeouts
1088
1148
  F.internal.interval = setInterval(function() {
@@ -1093,6 +1153,9 @@ F.loadservices = function() {
1093
1153
  for (let key in F.flowstreams)
1094
1154
  F.flowstreams[key].service(F.internal.ticks);
1095
1155
 
1156
+ if (F.internal.ticks == 6 || F.internal.ticks == 12)
1157
+ F.TWebSocket.ping();
1158
+
1096
1159
  // 1 minute
1097
1160
  if (F.internal.ticks == 12) {
1098
1161
  F.internal.ticks = 0;
@@ -1101,9 +1164,6 @@ F.loadservices = function() {
1101
1164
  F.$events.service && F.emit('service', F.internal.counter);
1102
1165
  }
1103
1166
 
1104
- if (F.internal.ticks == 6 || F.internal.ticks == 12)
1105
- F.TWebSocket.ping();
1106
-
1107
1167
  F.TFlow.ping();
1108
1168
 
1109
1169
  if (!F.temporary.pending.length) {
@@ -1116,7 +1176,7 @@ F.loadservices = function() {
1116
1176
  while (true) {
1117
1177
  let ctrl = F.temporary.pending[index];
1118
1178
  if (ctrl) {
1119
- if (ctrl.destroyed) {
1179
+ if (ctrl.destroyed || ctrl.res.headersSent || ctrl.res.writableEnded) {
1120
1180
  F.temporary.pending.splice(index, 1);
1121
1181
  } else if (ctrl.timeout <= 0) {
1122
1182
 
@@ -1155,6 +1215,11 @@ F.http = function(opt) {
1155
1215
  // config, env, modules, controllers, actions, schemas, models, definitions, sources, middleware, resources, plugins, stats
1156
1216
  // none - loads only web server
1157
1217
 
1218
+ if (F.isLoaded) {
1219
+ F.httpload(opt);
1220
+ return;
1221
+ }
1222
+
1158
1223
  if (opt.config) {
1159
1224
  let cfg = [];
1160
1225
  for (let key in opt.config)
@@ -1162,81 +1227,90 @@ F.http = function(opt) {
1162
1227
  F.loadconfig(cfg);
1163
1228
  }
1164
1229
 
1165
- F.load(opt.load || opt.type || '', function() {
1230
+ F.load(opt.load || opt.type || '', () => F.httpload(opt));
1231
+ };
1166
1232
 
1167
- F.server = F.Http.createServer(F.THttp.listen);
1168
- F.server.on('upgrade', F.TWebSocket.listen);
1233
+ F.httpload = function(opt) {
1169
1234
 
1170
- var unixsocket = opt.unixsocket || F.config.$unixsocket;
1235
+ if (F.server) {
1236
+ F.server.close(function() {
1237
+ F.server = null;
1238
+ F.httpload(opt);
1239
+ });
1240
+ return;
1241
+ }
1171
1242
 
1172
- if (unixsocket) {
1243
+ F.server = F.Http.createServer(F.THttp.listen);
1244
+ F.server.on('upgrade', F.TWebSocket.listen);
1173
1245
 
1174
- try {
1175
- F.Fs.unlinkSync(unixsocket);
1176
- } catch (e) {}
1246
+ var unixsocket = opt.unixsocket || F.config.$unixsocket;
1247
+ if (unixsocket) {
1177
1248
 
1178
- if (F.isWindows && unixsocket.indexOf(SOCKETWINDOWS) === -1)
1179
- unixsocket = F.Path.join(SOCKETWINDOWS, unixsocket);
1249
+ try {
1250
+ F.Fs.unlinkSync(unixsocket);
1251
+ } catch (e) {}
1180
1252
 
1181
- F.unixsocket = unixsocket;
1253
+ if (F.isWindows && unixsocket.indexOf(SOCKETWINDOWS) === -1)
1254
+ unixsocket = F.Path.join(SOCKETWINDOWS, unixsocket);
1182
1255
 
1183
- var listen = function(count) {
1184
- F.server.listen(unixsocket, function() {
1256
+ F.config.$unixsocket = F.unixsocket = unixsocket;
1185
1257
 
1186
- // Check if the socket exists
1187
- if (F.isWindows)
1188
- return;
1258
+ var listen = function(count) {
1259
+ F.server.listen(unixsocket, function() {
1189
1260
 
1190
- F.Fs.lstat(unixsocket, function(err) {
1261
+ // Check if the socket exists
1262
+ if (F.isWindows)
1263
+ return;
1191
1264
 
1192
- if (count > 9)
1193
- throw new Error('HTTP server can not listen the path "{0}"'.format(unixsocket));
1265
+ F.Fs.lstat(unixsocket, function(err) {
1194
1266
 
1195
- if (err)
1196
- setTimeout(listen, 500, count + 1);
1197
- else if (opt.unixsocket777)
1198
- F.Fs.chmodSync(unixsocket, 0o777);
1199
- });
1267
+ if (count > 9)
1268
+ throw new Error('HTTP server can not listen the path "{0}"'.format(unixsocket));
1200
1269
 
1270
+ if (err)
1271
+ setTimeout(listen, 500, count + 1);
1272
+ else if (opt.unixsocket777)
1273
+ F.Fs.chmodSync(unixsocket, 0o777);
1201
1274
  });
1202
- };
1203
1275
 
1204
- listen(1);
1276
+ });
1277
+ };
1278
+
1279
+ listen(1);
1205
1280
 
1206
- } else {
1281
+ } else {
1207
1282
 
1208
- if (opt.port)
1209
- F.config.$port = opt.port;
1210
-
1211
- if (F.config.$port === 'auto') {
1212
- let port = process.env.PORT;
1213
- if (!port) {
1214
- for (let arg of process.argv) {
1215
- if ((/^\d{3,5}$/).test(arg)) {
1216
- port = arg;
1217
- break;
1218
- }
1283
+ if (opt.port)
1284
+ F.config.$port = opt.port;
1285
+
1286
+ if (F.config.$port === 'auto') {
1287
+ let port = process.env.PORT;
1288
+ if (!port) {
1289
+ for (let arg of process.argv) {
1290
+ if ((/^\d{3,5}$/).test(arg)) {
1291
+ port = arg;
1292
+ break;
1219
1293
  }
1220
1294
  }
1221
- if (port)
1222
- port = +port;
1223
- if (isNaN(port))
1224
- port = 8000;
1225
- F.config.$port = port;
1226
1295
  }
1296
+ if (port)
1297
+ port = +port;
1298
+ if (isNaN(port))
1299
+ port = 8000;
1300
+ F.config.$port = port;
1301
+ }
1227
1302
 
1228
- if (opt.ip)
1229
- F.config.$ip = opt.ip;
1303
+ if (opt.ip)
1304
+ F.config.$ip = opt.ip;
1230
1305
 
1231
- F.server.listen(F.config.$port, F.config.$ip);
1232
- }
1306
+ F.server.listen(F.config.$port, F.config.$ip);
1307
+ }
1233
1308
 
1234
- F.config.$performance && F.server.on('connection', httptuningperformance);
1309
+ F.config.$performance && F.server.on('connection', httptuningperformance);
1235
1310
 
1236
- if (!process.connected && F.console)
1237
- F.console();
1311
+ if (!process.connected && F.console)
1312
+ F.console();
1238
1313
 
1239
- });
1240
1314
  };
1241
1315
 
1242
1316
  F.logger = function(enable) {
@@ -1305,8 +1379,12 @@ F.logger = function(enable) {
1305
1379
  };
1306
1380
  };
1307
1381
 
1382
+ F.componentator = function(name, components, removeprev = true, attrs = '') {
1308
1383
 
1309
- F.componentator = function(name, components, removeprev = true) {
1384
+ if (typeof(removeprev) === 'string') {
1385
+ attrs = removeprev;
1386
+ removeprev = true;
1387
+ }
1310
1388
 
1311
1389
  var meta = {};
1312
1390
 
@@ -1315,7 +1393,7 @@ F.componentator = function(name, components, removeprev = true) {
1315
1393
 
1316
1394
  F.$events.componentator && F.emit('componentator', meta);
1317
1395
 
1318
- var url = 'https://componentator.com/download.js?id=' + meta.components;
1396
+ var url = 'https://componentator.com/download.js?id=' + meta.components + (attrs ? ('&' + attrs) : '');
1319
1397
  var nameid = meta.name.slug();
1320
1398
  var relative = 'ui-' + (removeprev ? (nameid + '-') : '') + url.makeid() + '.min.js';
1321
1399
  var filename = F.path.public(relative);
@@ -1344,13 +1422,13 @@ F.componentator = function(name, components, removeprev = true) {
1344
1422
 
1345
1423
  };
1346
1424
 
1347
- F.error = function(err, name, uri) {
1425
+ F.error = function(err, name, url) {
1348
1426
 
1349
1427
  if (!arguments.length)
1350
1428
  return F.errorcallback;
1351
1429
 
1352
1430
  if (err)
1353
- F.def.onError(err, name, uri);
1431
+ F.def.onError(err, name, url);
1354
1432
  };
1355
1433
 
1356
1434
  F.errorcallback = function(err) {
@@ -1410,6 +1488,7 @@ F.merge = function(url) {
1410
1488
  if (F.temporary.merged[key]) {
1411
1489
  if (F.temporary.notfound[url]) {
1412
1490
  ctrl.fallback(404);
1491
+ next();
1413
1492
  return;
1414
1493
  }
1415
1494
  } else {
@@ -1520,8 +1599,12 @@ F.middleware = function(name, fn, assign) {
1520
1599
  }
1521
1600
  }
1522
1601
  } else {
1602
+
1523
1603
  if (a === 'websocket' || a === 'file' || a === 'route')
1524
1604
  a += 's';
1605
+ else if (a === 'dynamic')
1606
+ a = 'routes';
1607
+
1525
1608
  let routes = F.routes[a];
1526
1609
  if (routes) {
1527
1610
  for (let route of routes) {
@@ -1654,15 +1737,6 @@ F.service = function(count) {
1654
1737
  }
1655
1738
  }
1656
1739
 
1657
- // Exec crons
1658
- for (let cron of F.crons) {
1659
- if (cron.check(NOW))
1660
- cron.exec(NOW);
1661
- }
1662
-
1663
- if (count % 10 === 0 && global.gc)
1664
- setTimeout(cleargc, 1000);
1665
-
1666
1740
  F.temporary.service.publish = F.stats.performance.publish;
1667
1741
  F.temporary.service.subscribe = F.stats.performance.subscribe;
1668
1742
  F.temporary.service.call = F.stats.performance.call;
@@ -1695,6 +1769,16 @@ F.service = function(count) {
1695
1769
 
1696
1770
  F.usage && F.usage();
1697
1771
  F.temporary.service.usage = 0;
1772
+
1773
+ if (count % 10 === 0 && global.gc)
1774
+ setTimeout(cleargc, 1000);
1775
+
1776
+ // Exec crons
1777
+ for (let cron of F.crons) {
1778
+ if (cron.check(NOW))
1779
+ cron.exec(NOW);
1780
+ }
1781
+
1698
1782
  };
1699
1783
 
1700
1784
  function cleargc() {
@@ -1716,8 +1800,7 @@ F.clear = function(init = true, callback) {
1716
1800
  dir = dir.replaceAll('/', '\\');
1717
1801
 
1718
1802
  if (init) {
1719
-
1720
- if (!F.config.$cleartemp) {
1803
+ if (F.config.$cleartemp) {
1721
1804
  // clears only JS and CSS files
1722
1805
  F.TUtils.ls(dir, function(files) {
1723
1806
  F.path.unlink(files, callback);
@@ -1839,7 +1922,7 @@ F.newjsonschema = function(name, obj) {
1839
1922
  F.newtransform = function(name, action, id) {
1840
1923
  if (action == null) {
1841
1924
  let items = F.transformations[name];
1842
- let index = items.findIndex('id', id);
1925
+ let index = items.TfindIndex('id', id);
1843
1926
  if (index !== -1) {
1844
1927
  items.splice(index, 1);
1845
1928
  if (!items.length)
@@ -1849,19 +1932,30 @@ F.newtransform = function(name, action, id) {
1849
1932
  let obj = {};
1850
1933
  obj.id = id;
1851
1934
  obj.action = action;
1852
-
1935
+ obj.remove = function() {
1936
+ let arr = F.transformations[name];
1937
+ if (arr) {
1938
+ let index = arr.indexOf(obj);
1939
+ if (index !== -1) {
1940
+ arr.splice(index, 1);
1941
+ if (!arr.length)
1942
+ delete F.transformations[name];
1943
+ }
1944
+ }
1945
+ };
1853
1946
  if (F.transformations[name])
1854
1947
  F.transformations[name].push(obj);
1855
1948
  else
1856
1949
  F.transformations[name] = [obj];
1950
+ return obj;
1857
1951
  }
1858
1952
  };
1859
1953
 
1860
1954
  function transform(items, opt, index) {
1861
1955
  var t = items[index];
1862
1956
  if (t) {
1957
+ opt.next = () => transform(items, opt, index + 1);
1863
1958
  t.action(opt, opt.value);
1864
- t.next = () => transform(items, opt, index + 1);
1865
1959
  } else
1866
1960
  opt.$callback(opt.error.items.length ? opt.error : null, opt.value);
1867
1961
  }
@@ -1905,11 +1999,12 @@ F.audit = function(name, $, message, type) {
1905
1999
  if ($.controller) {
1906
2000
  if ($.controller.sessionid)
1907
2001
  data.sessionid = $.controller.sessionid;
1908
- data.ua = $.ua;
1909
- data.ip = $.ip;
1910
- data.url = $.url;
1911
2002
  }
1912
2003
 
2004
+ data.ua = $.ua;
2005
+ data.ip = $.ip;
2006
+ data.url = $.url;
2007
+
1913
2008
  if (type)
1914
2009
  data.type = type || 'info';
1915
2010
 
@@ -2130,7 +2225,7 @@ F.restore = function(filename, target, callback, filter) {
2130
2225
  parser.next();
2131
2226
  });
2132
2227
 
2133
- CLEANUP(stream, function() {
2228
+ F.cleanup(stream, function() {
2134
2229
  end = true;
2135
2230
  parser.end();
2136
2231
  });
@@ -2302,16 +2397,13 @@ F.restart = function() {
2302
2397
  process.send && process.send('total:restart');
2303
2398
  };
2304
2399
 
2305
- F.exit = function(signal) {
2400
+ F.exit = function(signal = 15) {
2306
2401
 
2307
2402
  if (F.isexited)
2308
2403
  return;
2309
2404
 
2310
2405
  F.isexited = true;
2311
2406
 
2312
- if (!signal)
2313
- signal = 'SIGTERM';
2314
-
2315
2407
  for (let m in F.workers) {
2316
2408
  let worker = F.workers[m];
2317
2409
  try {
@@ -2329,8 +2421,8 @@ F.exit = function(signal) {
2329
2421
  } catch (e) {}
2330
2422
  }
2331
2423
 
2332
- F.internal.timeouts && clearInterval(F.internal.timeouts);
2333
- F.internal.timeouts = null;
2424
+ F.internal.interval && clearInterval(F.internal.interval);
2425
+ F.internal.interval = null;
2334
2426
 
2335
2427
  if (F.server) {
2336
2428
  F.server.setTimeout(1);
@@ -2413,10 +2505,10 @@ F.dir = function(val) {
2413
2505
  if (val)
2414
2506
  F.directory = val;
2415
2507
 
2416
- var dirs = ['public', 'tmp', 'logs', 'databases', 'controllers', 'resources', 'plugins', 'views', 'definitions', 'schemas', 'models', 'flowstreams', 'bundles', 'actions', 'extensions', 'source', 'services', 'updates', 'templates'];
2508
+ var dirs = ['public', 'tmp', 'logs', 'databases', 'controllers', 'resources', 'plugins', 'modules', 'views', 'definitions', 'schemas', 'models', 'flowstreams', 'bundles', 'actions', 'extensions', 'source', 'services', 'updates', 'templates', 'private'];
2417
2509
 
2418
2510
  for (let dir of dirs) {
2419
- var cfg = F.config['$dir' + dir];
2511
+ let cfg = F.config['$dir' + dir];
2420
2512
  F.temporary.directories[dir] = cfg || F.Path.join(F.directory, dir);
2421
2513
  }
2422
2514
 
@@ -2456,7 +2548,7 @@ F.mail = function(email, subject, name, model, language, callback) {
2456
2548
  // Localization
2457
2549
  if (typeof(language) === 'string') {
2458
2550
  if (subject.includes('@('))
2459
- subject = TRANSLATE(language, subject);
2551
+ subject = F.translate(language, subject);
2460
2552
  }
2461
2553
 
2462
2554
  let body = F.view(name, model, view => view.language = language || '');
@@ -2474,9 +2566,9 @@ F.htmlmail = function(email, subject, body, language, callback) {
2474
2566
  // Localization
2475
2567
  if (typeof(language) === 'string') {
2476
2568
  if (subject.includes('@('))
2477
- subject = TRANSLATE(language, subject);
2569
+ subject = F.translate(language, subject);
2478
2570
  if (body.includes('@('))
2479
- body = TRANSLATE(language, body);
2571
+ body = F.translate(language, body);
2480
2572
  }
2481
2573
 
2482
2574
  body = body.indexOf('<body>') === -1 ? ('<!DOCTYPE html><html><head><title>' + subject + '</title><meta charset="utf-8" /></head><body style="padding:0;margin:0;font-family:Arial;font-size:14px;font-weight:normal">' + body + '</body></html>') : body;
@@ -2487,6 +2579,17 @@ F.readfile = function(path, type = null) {
2487
2579
  return new Promise(resolve => F.Fs.readFile(path, type, (err, response) => err ? resolve(null) : resolve(response)));
2488
2580
  };
2489
2581
 
2582
+ F.datauri = function(path) {
2583
+ return new Promise(resolve => F.Fs.readFile(path, 'base64', function(err, response) {
2584
+ if (err) {
2585
+ resolve(null);
2586
+ } else {
2587
+ var ext = F.TUtils.getExtension(path);
2588
+ resolve('data:' + F.TUtils.getContentType(ext) + ';base64,' + response);
2589
+ }
2590
+ }));
2591
+ };
2592
+
2490
2593
  F.loadstats = function() {
2491
2594
 
2492
2595
  var main = {};
@@ -2604,9 +2707,9 @@ process.on('message', function(msg, h) {
2604
2707
 
2605
2708
  let key;
2606
2709
 
2607
- if (msg === 'total:debug')
2608
- F.TUtils.wait(() => F.isloaded, F.console, 10000, 500);
2609
- else if (msg === 'total:ping')
2710
+ if (msg === 'total:debug') {
2711
+ F.TUtils.wait(() => F.isLoaded, F.console, 10000, 500);
2712
+ } else if (msg === 'total:ping')
2610
2713
  setImmediate(ping);
2611
2714
  else if (msg === 'total:update') {
2612
2715
  key = '$update';
@@ -2658,11 +2761,16 @@ process.on('message', function(msg, h) {
2658
2761
  F.TCluster = require('./cluster');
2659
2762
 
2660
2763
  // Settings
2661
- F.directory = F.TUtils.$normalize(require.main ? F.Path.dirname(require.main.filename) : process.cwd());
2764
+ // F.directory = F.TUtils.$normalize(require.main ? F.Path.dirname(require.main.filename) : process.cwd());
2765
+ F.directory = F.TUtils.$normalize(process.cwd());
2766
+
2662
2767
  F.is = F.Os.platform().substring(0, 3).toLowerCase() === 'win';
2663
2768
  F.isWorker = process.env.PASSENGER_APP_ENV ? false : F.Cluster.isWorker;
2664
2769
  F.syshash = (__dirname + '-' + F.Os.hostname() + '-' + F.Os.platform() + '-' + F.Os.arch() + '-' + F.Os.release() + '-' + F.Os.tmpdir() + JSON.stringify(process.versions)).md5();
2665
2770
  F.isLE = F.Os.endianness ? F.Os.endianness() === 'LE' : true;
2771
+ F.isWindows = F.Os.platform().substring(0, 3).toLowerCase() === 'win';
2772
+
2773
+ F.config.$total5 = F.Path.dirname(require.resolve('./index'));
2666
2774
 
2667
2775
  F.cache = require('./cache');
2668
2776
  F.TImages = require('./images');
@@ -2673,16 +2781,17 @@ process.on('message', function(msg, h) {
2673
2781
 
2674
2782
  F.on2 = F.on;
2675
2783
  F.on = function(name, fn) {
2676
- if (name === 'ready' && F.isloaded)
2784
+ if (name === 'ready' && F.isLoaded)
2677
2785
  fn();
2678
2786
  else
2679
2787
  F.on2(name, fn);
2680
2788
  };
2681
2789
 
2682
2790
  // Configuration
2683
- CONF.secret_uid = F.syshash.substring(10);
2684
- CONF.$httpexpire = NOW.add('y', 1).toUTCString(); // must be refreshed every hour
2685
- CONF.$cryptoiv = Buffer.from(F.syshash).slice(0, 16);
2791
+ F.config.secret_uid = F.syshash.substring(10);
2792
+ F.config.$httpexpire = NOW.add('y', 1).toUTCString(); // must be refreshed every hour
2793
+ F.config.$cryptoiv = Buffer.from(F.syshash).slice(0, 16);
2794
+ F.config.$nodemodules = F.Path.join(F.directory, 'node_modules');
2686
2795
 
2687
2796
  // Methods
2688
2797
  F.route = F.TRouting.route;
@@ -2719,4 +2828,24 @@ require('./markdown');
2719
2828
  // Init directories
2720
2829
  F.dir();
2721
2830
 
2831
+ // Init CORS
2832
+ F.on('$cors', function() {
2833
+
2834
+ var arr = (F.config.$cors || '').toLowerCase().split(',').trim();
2835
+ var wildcard = [];
2836
+ var strict = [];
2837
+
2838
+ for (let i = 0; i < arr.length; i++) {
2839
+ let val = arr[i];
2840
+ if (val !== '*') {
2841
+ if (val[0] === '*' && val.length > 1)
2842
+ wildcard.push(val.substring(1));
2843
+ else
2844
+ strict.push(val);
2845
+ }
2846
+ }
2847
+
2848
+ F.temporary.cors = F.config.$cors === '*' ? null : { wildcard: wildcard, strict: strict };
2849
+ });
2850
+
2722
2851
  module.exports = F;