total5 0.0.1-2 → 0.0.1-21

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/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
 
@@ -8,7 +8,7 @@ const NODE_MODULES = { buffer: 1, child_process: 1, process: 1, fs: 1, events: 1
8
8
  const EMPTYOBJECT = {};
9
9
  const EMPTYARRAY = [];
10
10
 
11
- const REG_SKIPERRORS = /epipe|invalid\sdistance/i;
11
+ const REG_SKIPERRORS = /epipe|invalid\sdistance|err_ipc_channel_closed/i;
12
12
  const REG_HTTPHTTPS = /^(http|https):\/\//i;
13
13
  const SOCKETWINDOWS = '\\\\?\\pipe';
14
14
  const CLUSTER_STATS = { TYPE: 'stats' };
@@ -37,6 +37,7 @@ global.DEF = {};
37
37
  F.id = '';
38
38
  F.clusterid = '';
39
39
  F.is5 = F.version = 5000;
40
+ F.isBundle = false;
40
41
  F.version_header = '5';
41
42
  F.version_node = process.version + '';
42
43
  F.EMPTYOBJECT = EMPTYOBJECT;
@@ -214,14 +215,17 @@ global.DEF = {};
214
215
  };
215
216
 
216
217
  F.path = {};
217
-
218
218
  F.path.root = path => path ? F.path.$join(F.directory, path) : F.directory;
219
219
  F.path.logs = path => path ? F.path.$join(F.temporary.directories.logs, path) : F.temporary.directories.logs;
220
220
  F.path.public = path => path ? F.path.$join(F.temporary.directories.public, path) : F.temporary.directories.public;
221
221
  F.path.private = path => path ? F.path.$join(F.temporary.directories.private, path) : F.temporary.directories.private;
222
222
  F.path.databases = path => path ? F.path.$join(F.temporary.directories.databases, path) : F.temporary.directories.databases;
223
+ F.path.plugins = path => path ? F.path.$join(F.temporary.directories.plugins, path) : F.temporary.directories.plugins;
224
+ F.path.templates = path => path ? F.path.$join(F.temporary.directories.templates, path) : F.temporary.directories.templates;
225
+ F.path.flowstreams = path => path ? F.path.$join(F.temporary.directories.flowstreams, path) : F.temporary.directories.flowstreams;
223
226
  F.path.directory = (type, path) => path ? F.path.$join(F.temporary.directories[type], path) : F.temporary.directories[type];
224
227
  F.path.tmp = F.path.temp = path => path ? F.path.$join(F.temporary.directories.tmp, path) : F.temporary.directories.tmp;
228
+ 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));
225
229
 
226
230
  F.path.$join = function(directory, path) {
227
231
  var key = '$' + directory;
@@ -340,11 +344,12 @@ function unlink(arr, callback) {
340
344
  CONF.$httpreqlimit = 0; // request limit per ip
341
345
  CONF.$httpcompress = true;
342
346
  CONF.$httpetag = '';
343
- CONF.$httpmaxsize = 256; // 256 kB
347
+ CONF.$httpmaxsize = 256; // kB
344
348
  CONF.$httprangebuffer = 5120; // 5 MB
345
349
  CONF.$httptimeout = 5; // 5 seconds
346
- 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 };
350
+ 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 };
347
351
  CONF.$httpchecktypes = true; // for multipart data only
352
+ CONF.$httpmaxage = 60; // in seconds
348
353
  CONF.$blacklist = '';
349
354
  CONF.$xpoweredby = 'Total.js';
350
355
  CONF.$maxopenfiles = 100;
@@ -352,7 +357,7 @@ function unlink(arr, callback) {
352
357
  CONF.$minifycss = true;
353
358
  CONF.$minifyhtml = true;
354
359
  CONF.$localize = true;
355
- CONF.$port = 8000;
360
+ CONF.$port = 'auto';
356
361
  CONF.$ip = '0.0.0.0';
357
362
  CONF.$unixsocket = '';
358
363
  CONF.$timezone = 'utc';
@@ -367,11 +372,9 @@ function unlink(arr, callback) {
367
372
  CONF.$imagememory = 0; // disabled because e.g. GM v1.3.32 throws some error about the memory
368
373
  CONF.$stats = true;
369
374
 
370
- CONF.$nodemodules = require.resolve('./index');
371
- CONF.$nodemodules = CONF.$nodemodules.substring(0, CONF.$nodemodules.length - (8 + 7));
372
375
  CONF.$npmcache = '/var/www/.npm';
373
376
  CONF.$python = 'python3';
374
- CONF.$wsmaxsize = 256; // 256 kB
377
+ CONF.$wsmaxsize = 256; // kB
375
378
  CONF.$wscompress = true;
376
379
  CONF.$wsencodedecode = false;
377
380
  CONF.$wsmaxlatency = 2000;
@@ -386,7 +389,7 @@ function unlink(arr, callback) {
386
389
  CONF.$tapilogger = false;
387
390
 
388
391
  CONF.$tms = false;
389
- CONF.$tmsmaxsize = 256;
392
+ CONF.$tmsmaxsize = 256; // kB
390
393
  CONF.$tmsurl = '/$tms/';
391
394
  CONF.$tmsclearblocked = 60; // in minutes
392
395
 
@@ -478,7 +481,10 @@ function unlink(arr, callback) {
478
481
 
479
482
  NOW = new Date();
480
483
 
481
- if (!name && err.name)
484
+ if (err instanceof F.TBuilders.ErrorBuilder) {
485
+ if (!name)
486
+ name = err[0].name;
487
+ } else if (!name && err.name)
482
488
  name = err.name;
483
489
 
484
490
  err = err.toString();
@@ -489,7 +495,7 @@ function unlink(arr, callback) {
489
495
  if (F.errors.push(obj) > 10)
490
496
  F.errors.shift();
491
497
 
492
- EMIT('error', obj);
498
+ F.$events.error && F.emit('error', obj);
493
499
  F.stats.error++;
494
500
  };
495
501
 
@@ -591,9 +597,13 @@ F.loadconfig = function(value) {
591
597
  if (smtp)
592
598
  F.config.smtp = smtp;
593
599
 
600
+ if (!F.config.$nodemodules)
601
+ F.config.$nodemodules = PATH.root('node_modules');
602
+
594
603
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = F.config.$insecure ? '0' : '1';
595
604
  F.logger(F.config.$logger == true);
596
605
  F.dir();
606
+ F.emit('$cors');
597
607
  F.emit('$tms');
598
608
  F.emit('$reconfigure');
599
609
  };
@@ -610,10 +620,10 @@ F.loadresource = function(name, value) {
610
620
  if (response && (response instanceof Array || typeof(response) === 'object')) {
611
621
  if (response instanceof Array) {
612
622
  for (let item of response)
613
- LOADRESOURCE(item.id || item.key || item.code || item.language, item.value || item.name || item.text || item.body);
623
+ F.loadresource(item.id || item.key || item.code || item.language, item.value || item.name || item.text || item.body);
614
624
  } else {
615
625
  for (let key in response)
616
- LOADRESOURCE(key, response[key]);
626
+ F.loadresource(key, response[key]);
617
627
  }
618
628
  }
619
629
 
@@ -695,8 +705,15 @@ F.resource = function(language, key) {
695
705
  return language === 'default' ? '' : F.resource('default', key);
696
706
  };
697
707
 
708
+ F.localize = function(fn) {
709
+ F.def.onLocalize = fn;
710
+ };
711
+
698
712
  F.auth = function(fn) {
699
- F.def.onAuthorize = fn;
713
+ if (typeof(fn) === 'object')
714
+ F.TBuilders.builtinauth(fn);
715
+ else
716
+ F.def.onAuthorize = fn;
700
717
  };
701
718
 
702
719
  F.load = async function(types, callback) {
@@ -708,6 +725,8 @@ F.load = async function(types, callback) {
708
725
  await F.TBundles.extract();
709
726
  await F.clear(true);
710
727
 
728
+ process.send && process.send('total:ready');
729
+
711
730
  if (typeof(types) === 'string')
712
731
  types = types.split(',').trim();
713
732
 
@@ -730,21 +749,35 @@ F.load = async function(types, callback) {
730
749
  }
731
750
 
732
751
  if (!types.length || types.includes('env')) {
733
- var env = await read(F.path.root('.env'));
752
+ let env = await read(F.path.root('.env'));
734
753
  env && F.loadenv(env);
735
754
  }
736
755
 
737
756
  if (!types.length || types.includes('config')) {
738
- var config = await read(F.path.root('config'));
757
+ let config = await read(F.path.root('config'));
739
758
  config && F.loadconfig(config);
740
759
  }
741
760
 
742
761
  if (!types.length || types.includes('resources')) {
743
- var resources = await list(F.path.root('resources'), 'resource');
762
+ let resources = await list(F.path.root('resources'), 'resource');
744
763
  for (let resource of resources)
745
764
  F.loadresource(F.TUtils.getName(resource).replace(/\.resource$/i, ''), await read(resource));
746
765
  }
747
766
 
767
+ if (!types.length || types.includes('jsonschemas')) {
768
+ let jsonschemas = await list(F.path.root('jsonschemas'), 'json');
769
+ for (let jsonschema of jsonschemas) {
770
+ let json = await read(jsonschema);
771
+ json = json.parseJSON();
772
+ json && F.newjsonschema(F.TUtils.getName(jsonschema).replace(/\.json$/i, ''), json);
773
+ }
774
+ jsonschemas = await list(F.path.root('jsonschemas'), 'txt');
775
+ for (let jsonschema of jsonschemas) {
776
+ let txt = await read(jsonschema);
777
+ txt && F.newjsonschema(F.TUtils.getName(jsonschema).replace(/\.txt$/i, ''), txt);
778
+ }
779
+ }
780
+
748
781
  let loader = ['modules', 'controllers', 'actions', 'schemas', 'models', 'definitions', 'sources', 'middleware'];
749
782
  var files = [];
750
783
  var tmp;
@@ -836,7 +869,6 @@ F.load = async function(types, callback) {
836
869
  F.stats.compiled = files.length;
837
870
  F.isloaded = true;
838
871
  DEBUG && F.TSourceMap.refresh();
839
- process.send && process.send('total:ready');
840
872
  callback && callback();
841
873
 
842
874
  F.emit('ready');
@@ -846,7 +878,7 @@ F.load = async function(types, callback) {
846
878
  F.require = function(name) {
847
879
  if (name.startsWith('node:'))
848
880
  return require(name);
849
- return NODE_MODULES[name] ? require('node:' + name) : require(F.Path.join(F.directory, name));
881
+ return NODE_MODULES[name] ? require('node:' + name) : require(name); // TODO: check functionality without absolute path: require(F.Path.join(F.config.$nodemodules, name))
850
882
  };
851
883
 
852
884
  F.import = function(url, callback) {
@@ -953,7 +985,7 @@ F.npminstall = function(name, callback) {
953
985
  if (!callback)
954
986
  return new Promise((resolve, reject) => F.npminstall(name, err => err ? reject(err) : resolve()));
955
987
 
956
- var path = F.config.$node_modules;
988
+ var path = F.config.$nodemodules;
957
989
  F.path.mkdir(path, true);
958
990
 
959
991
  var index = name.lastIndexOf('@');
@@ -1010,6 +1042,9 @@ F.shell = function(cmd, callback, cwd) {
1010
1042
  F.console = function() {
1011
1043
 
1012
1044
  var memory = process.memoryUsage();
1045
+ var nodemodules = require.resolve('./index');
1046
+
1047
+ nodemodules = nodemodules.substring(0, CONF.$nodemodules.length - (8 + 7));
1013
1048
 
1014
1049
  print('====================================================');
1015
1050
  print('PID : ' + process.pid);
@@ -1030,10 +1065,10 @@ F.console = function() {
1030
1065
  print('====================================================');
1031
1066
  F.config.$root && print('Root : ' + F.config.$root);
1032
1067
  print('Directory : ' + process.cwd());
1033
- print('node_modules : ' + F.config.$nodemodules);
1068
+ print('node_modules : ' + nodemodules);
1034
1069
  print('====================================================\n');
1035
1070
 
1036
- if (!F.isWorker) {
1071
+ if (!F.isWorker && F.server) {
1037
1072
 
1038
1073
  var hostname = F.unixsocket ? ('Socket: ' + F.unixsocket) : '{2}://{0}:{1}/'.format(F.config.$ip, F.config.$port, F.isHTTPS ? 'https' : 'http');
1039
1074
 
@@ -1147,6 +1182,10 @@ F.http = function(opt) {
1147
1182
 
1148
1183
  if (unixsocket) {
1149
1184
 
1185
+ try {
1186
+ F.Fs.unlinkSync(unixsocket);
1187
+ } catch (e) {}
1188
+
1150
1189
  if (F.isWindows && unixsocket.indexOf(SOCKETWINDOWS) === -1)
1151
1190
  unixsocket = F.Path.join(SOCKETWINDOWS, unixsocket);
1152
1191
 
@@ -1180,6 +1219,23 @@ F.http = function(opt) {
1180
1219
  if (opt.port)
1181
1220
  F.config.$port = opt.port;
1182
1221
 
1222
+ if (F.config.$port === 'auto') {
1223
+ let port = process.env.PORT;
1224
+ if (!port) {
1225
+ for (let arg of process.argv) {
1226
+ if ((/^\d{3,5}$/).test(arg)) {
1227
+ port = arg;
1228
+ break;
1229
+ }
1230
+ }
1231
+ }
1232
+ if (port)
1233
+ port = +port;
1234
+ if (isNaN(port))
1235
+ port = 8000;
1236
+ F.config.$port = port;
1237
+ }
1238
+
1183
1239
  if (opt.ip)
1184
1240
  F.config.$ip = opt.ip;
1185
1241
 
@@ -1294,18 +1350,18 @@ F.componentator = function(name, components, removeprev = true) {
1294
1350
 
1295
1351
  F.Fs.lstat(filename, function(err) {
1296
1352
  if (err)
1297
- F.download(url, filename, F.error('COMPONENTATOR'));
1353
+ F.download(url, filename, err => err ? F.error(err, 'COMPONENTATOR') : null);
1298
1354
  });
1299
1355
 
1300
1356
  };
1301
1357
 
1302
- F.error = function(err, name, uri) {
1358
+ F.error = function(err, name, url) {
1303
1359
 
1304
1360
  if (!arguments.length)
1305
1361
  return F.errorcallback;
1306
1362
 
1307
1363
  if (err)
1308
- F.def.onError(err, name, uri);
1364
+ F.def.onError(err, name, url);
1309
1365
  };
1310
1366
 
1311
1367
  F.errorcallback = function(err) {
@@ -1475,8 +1531,12 @@ F.middleware = function(name, fn, assign) {
1475
1531
  }
1476
1532
  }
1477
1533
  } else {
1534
+
1478
1535
  if (a === 'websocket' || a === 'file' || a === 'route')
1479
1536
  a += 's';
1537
+ else if (a === 'dynamic')
1538
+ a = 'routes';
1539
+
1480
1540
  let routes = F.routes[a];
1481
1541
  if (routes) {
1482
1542
  for (let route of routes) {
@@ -1586,10 +1646,8 @@ F.service = function(count) {
1586
1646
  }
1587
1647
 
1588
1648
  // Update expires date
1589
- if (count % 60 === 0) {
1649
+ if (count % 60 === 0)
1590
1650
  F.config.$httpexpire = NOW.add('y', 1).toUTCString();
1591
- F.TImages.clear();
1592
- }
1593
1651
 
1594
1652
  if (count % F.config.$tmsclearblocked === 0)
1595
1653
  F.temporary.tmsblocked = {};
@@ -1796,7 +1854,7 @@ F.newjsonschema = function(name, obj) {
1796
1854
  F.newtransform = function(name, action, id) {
1797
1855
  if (action == null) {
1798
1856
  let items = F.transformations[name];
1799
- let index = items.findIndex('id', id);
1857
+ let index = items.TfindIndex('id', id);
1800
1858
  if (index !== -1) {
1801
1859
  items.splice(index, 1);
1802
1860
  if (!items.length)
@@ -2160,7 +2218,7 @@ F.backup = function(filename, files, callback, filter) {
2160
2218
  F.Fs.stat(file, function(err, stats) {
2161
2219
 
2162
2220
  if (err) {
2163
- F.error(err, 'BACKUP()', filename);
2221
+ F.error(err, 'F.backup()', filename);
2164
2222
  next();
2165
2223
  return;
2166
2224
  }
@@ -2246,7 +2304,7 @@ F.backup = function(filename, files, callback, filter) {
2246
2304
  counter++;
2247
2305
  setImmediate(next);
2248
2306
  }).on('error', function(err) {
2249
- F.error(err, 'F.backup', file);
2307
+ F.error(err, 'F.backup()', file);
2250
2308
  setImmediate(next);
2251
2309
  });
2252
2310
 
@@ -2255,16 +2313,17 @@ F.backup = function(filename, files, callback, filter) {
2255
2313
  });
2256
2314
  };
2257
2315
 
2258
- F.exit = function(signal) {
2316
+ F.restart = function() {
2317
+ process.send && process.send('total:restart');
2318
+ };
2319
+
2320
+ F.exit = function(signal = 15) {
2259
2321
 
2260
2322
  if (F.isexited)
2261
2323
  return;
2262
2324
 
2263
2325
  F.isexited = true;
2264
2326
 
2265
- if (!signal)
2266
- signal = 'SIGTERM';
2267
-
2268
2327
  for (let m in F.workers) {
2269
2328
  let worker = F.workers[m];
2270
2329
  try {
@@ -2272,7 +2331,7 @@ F.exit = function(signal) {
2272
2331
  } catch (e) {}
2273
2332
  }
2274
2333
 
2275
- let key = '$exit';
2334
+ let key = 'exit';
2276
2335
 
2277
2336
  F.$events[key] && F.emit(key, signal);
2278
2337
 
@@ -2366,7 +2425,7 @@ F.dir = function(val) {
2366
2425
  if (val)
2367
2426
  F.directory = val;
2368
2427
 
2369
- var dirs = ['public', 'tmp', 'logs', 'databases', 'controllers', 'resources', 'plugins', 'views', 'definitions', 'schemas', 'models', 'flowstreams', 'bundles', 'actions', 'extensions', 'source', 'services', 'updates', 'templates'];
2428
+ var dirs = ['public', 'tmp', 'logs', 'databases', 'controllers', 'resources', 'plugins', 'views', 'definitions', 'schemas', 'models', 'flowstreams', 'bundles', 'actions', 'extensions', 'source', 'services', 'updates', 'templates', 'private'];
2370
2429
 
2371
2430
  for (let dir of dirs) {
2372
2431
  var cfg = F.config['$dir' + dir];
@@ -2406,6 +2465,12 @@ F.mail = function(email, subject, name, model, language, callback) {
2406
2465
  callback = tmp;
2407
2466
  }
2408
2467
 
2468
+ // Localization
2469
+ if (typeof(language) === 'string') {
2470
+ if (subject.includes('@('))
2471
+ subject = TRANSLATE(language, subject);
2472
+ }
2473
+
2409
2474
  let body = F.view(name, model, view => view.language = language || '');
2410
2475
  return F.def.onMail(email, subject, body, callback);
2411
2476
  };
@@ -2418,17 +2483,22 @@ F.htmlmail = function(email, subject, body, language, callback) {
2418
2483
  callback = tmp;
2419
2484
  }
2420
2485
 
2421
- // Translation
2486
+ // Localization
2422
2487
  if (typeof(language) === 'string') {
2423
- subject = subject.indexOf('@(') === -1 ? TRANSLATE(language, subject) : TRANSLATOR(language, subject);
2424
- if (body.indexOf('@(') !== -1)
2425
- body = TRANSLATOR(language, body);
2488
+ if (subject.includes('@('))
2489
+ subject = TRANSLATE(language, subject);
2490
+ if (body.includes('@('))
2491
+ body = TRANSLATE(language, body);
2426
2492
  }
2427
2493
 
2428
- var 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;
2494
+ 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;
2429
2495
  return F.def.onMail(email, subject, body, callback);
2430
2496
  };
2431
2497
 
2498
+ F.readfile = function(path, type = null) {
2499
+ return new Promise(resolve => F.Fs.readFile(path, type, (err, response) => err ? resolve(null) : resolve(response)));
2500
+ };
2501
+
2432
2502
  F.loadstats = function() {
2433
2503
 
2434
2504
  var main = {};
@@ -2526,13 +2596,11 @@ process.on('unhandledRejection', function(e) {
2526
2596
  F.error(e.stack, '');
2527
2597
  });
2528
2598
 
2529
- // process.on('uncaughtException', function(e) {
2530
2599
  process.on('uncaughtException', function(e) {
2531
-
2532
2600
  var err = e + '';
2533
2601
  if (err.indexOf('listen EADDRINUSE') !== -1) {
2534
- process.send && process.send('total:eaddrinuse');
2535
2602
  console.log('\nThe IP address and the PORT is already in use.\nYou must change the PORT\'s number or IP address.\n');
2603
+ process.send && process.send('total:eaddrinuse');
2536
2604
  process.exit(1);
2537
2605
  return;
2538
2606
  } else if (F.config.$filtererrors && REG_SKIPERRORS.test(err))
@@ -2548,9 +2616,9 @@ process.on('message', function(msg, h) {
2548
2616
 
2549
2617
  let key;
2550
2618
 
2551
- if (msg === 'total:debug')
2619
+ if (msg === 'total:debug') {
2552
2620
  F.TUtils.wait(() => F.isloaded, F.console, 10000, 500);
2553
- else if (msg === 'total:ping')
2621
+ } else if (msg === 'total:ping')
2554
2622
  setImmediate(ping);
2555
2623
  else if (msg === 'total:update') {
2556
2624
  key = '$update';
@@ -2608,6 +2676,8 @@ process.on('message', function(msg, h) {
2608
2676
  F.syshash = (__dirname + '-' + F.Os.hostname() + '-' + F.Os.platform() + '-' + F.Os.arch() + '-' + F.Os.release() + '-' + F.Os.tmpdir() + JSON.stringify(process.versions)).md5();
2609
2677
  F.isLE = F.Os.endianness ? F.Os.endianness() === 'LE' : true;
2610
2678
 
2679
+ CONF.$total5 = F.Path.dirname(require.resolve('./index'));
2680
+
2611
2681
  F.cache = require('./cache');
2612
2682
  F.TImages = require('./images');
2613
2683
  F.path.fs = F.Fs;
@@ -2658,5 +2728,29 @@ process.connected && setTimeout(() => process.send('total:init'), 100);
2658
2728
 
2659
2729
  require('./global');
2660
2730
  require('./tangular');
2731
+ require('./markdown');
2732
+
2733
+ // Init directories
2734
+ F.dir();
2735
+
2736
+ // Init CORS
2737
+ F.on('$cors', function() {
2738
+
2739
+ var arr = (F.config.$cors || '').toLowerCase().split(',').trim();
2740
+ var wildcard = [];
2741
+ var strict = [];
2742
+
2743
+ for (let i = 0; i < arr.length; i++) {
2744
+ let val = arr[i];
2745
+ if (val !== '*') {
2746
+ if (val[0] === '*' && val.length > 1)
2747
+ wildcard.push(val.substring(1));
2748
+ else
2749
+ strict.push(val);
2750
+ }
2751
+ }
2752
+
2753
+ F.temporary.cors = F.config.$cors === '*' ? null : { wildcard: wildcard, strict: strict };
2754
+ });
2661
2755
 
2662
2756
  module.exports = F;
package/jsonschema.js CHANGED
@@ -18,7 +18,7 @@ function check_string(meta, error, value, errplus, path) {
18
18
  var type = typeof(value);
19
19
 
20
20
  if (type !== 'string')
21
- value = value ? (value + '') : null;
21
+ value = value ? (value + '') : meta.nullable ? null : '';
22
22
 
23
23
  if (errplus == null)
24
24
  errplus = '';
@@ -37,7 +37,7 @@ function check_string(meta, error, value, errplus, path) {
37
37
  }
38
38
 
39
39
  if (value == null)
40
- return;
40
+ return null;
41
41
 
42
42
  var len = value.length;
43
43
 
@@ -133,6 +133,14 @@ function check_string(meta, error, value, errplus, path) {
133
133
  return;
134
134
  }
135
135
  break;
136
+ case 'datauri':
137
+ value = value.trim();
138
+ if (value && !value.isBase64(true)) {
139
+ error.push2(errplus + meta.$$ID, path);
140
+ return;
141
+ }
142
+ value = value ? value.parseDataURI() : null;
143
+ break;
136
144
  case 'color':
137
145
  value = value.trim();
138
146
  if (value && !REG_COLOR.test(value)) {
@@ -299,7 +307,8 @@ function check_date(meta, error, value, errplus, path) {
299
307
  return value;
300
308
  }
301
309
 
302
- function read_def(ref, definitions) {
310
+ function readdef(ref, definitions) {
311
+
303
312
  if (ref[0] === '#') {
304
313
  var tmp = ref.substring(2).split('/');
305
314
  var def = definitions[tmp[0]];
@@ -312,7 +321,8 @@ function read_def(ref, definitions) {
312
321
  return obj;
313
322
  }
314
323
  }
315
- }
324
+ } else
325
+ return F.jsonschemas[ref];
316
326
  }
317
327
 
318
328
  function check_array(meta, error, value, stop, definitions, path) {
@@ -420,13 +430,14 @@ function check_array(meta, error, value, stop, definitions, path) {
420
430
  var val = value[i];
421
431
 
422
432
  if (meta.items.$ref) {
423
- var ref = read_def(meta.items.$ref, definitions);
433
+ var ref = typeof(meta.items.$ref) === 'object' ? meta.items.$ref :readdef(meta.items.$ref, definitions);
424
434
  if (ref) {
425
- var newerror = [];
426
- tmp = transform(ref, newerror, val);
427
- if (newerror.length) {
428
- for (var err of newerror)
429
- error.push2(ref.$$ID + '.' + err, path, i);
435
+ var newerror = new F.ErrorBuilder();
436
+ tmp = transform(ref, newerror, val, false, currentpath + '[' + i + ']');
437
+ if (newerror.items.length) {
438
+ for (var err of newerror.items) {
439
+ error.push2(err.name, err.path, i);
440
+ }
430
441
  } else if (tmp != null && (!meta.uniqueItems || response.indexOf(tmp) === -1))
431
442
  response.push(tmp);
432
443
  continue;
@@ -552,10 +563,8 @@ function check_object(meta, error, value, response, stop, definitions, path) {
552
563
  case 'boolean':
553
564
  case 'bool':
554
565
  tmp = check_boolean(prop, error, val, null, currentpath);
555
- if (tmp != null) {
556
- response[key] = tmp;
557
- count++;
558
- }
566
+ response[key] = tmp == true;
567
+ count++;
559
568
  break;
560
569
  case 'date':
561
570
  tmp = check_date(prop, error, val, null, currentpath);
@@ -564,16 +573,14 @@ function check_object(meta, error, value, response, stop, definitions, path) {
564
573
  break;
565
574
  case 'string':
566
575
  tmp = check_string(prop, error, val, null, currentpath);
567
- if (tmp != null) {
568
-
569
- if (!tmp && prop.subtype === 'uid')
570
- tmp = null;
571
-
572
- response[key] = tmp;
573
- count++;
574
- }
576
+ if (tmp == '' && prop.nullable)
577
+ tmp = null;
578
+ response[key] = tmp;
579
+ count++;
575
580
  break;
581
+
576
582
  case 'object':
583
+
577
584
  if (prop.properties) {
578
585
  tmp = check_object(prop, error, val, null, null, definitions, currentpath);
579
586
  if (tmp != null) {
@@ -584,13 +591,14 @@ function check_object(meta, error, value, response, stop, definitions, path) {
584
591
 
585
592
  // check ref
586
593
  if (prop.$ref) {
587
- var ref = read_def(prop.$ref, definitions);
594
+ var ref = typeof(prop.$ref) === 'object' ? prop.$ref : readdef(prop.$ref, definitions);
588
595
  if (ref) {
589
- var newerror = new ErrorBuilder();
590
- tmp = transform(ref, newerror, val);
596
+ var newerror = new F.ErrorBuilder();
597
+ tmp = transform(ref, newerror, val, false, currentpath);
591
598
  if (newerror.items.length) {
592
- for (var err of newerror.items)
593
- error.push(ref.$$ID + '.' + err, '@');
599
+ for (var err of newerror.items) {
600
+ error.push2(err.name, err.path);
601
+ }
594
602
  } else
595
603
  response[key] = tmp;
596
604
  continue;
package/mail.js CHANGED
@@ -225,10 +225,12 @@ Message.prototype.send2 = function(callback) {
225
225
  Mailer.send(F.config.smtp, self, callback);
226
226
  };
227
227
 
228
- Message.prototype.send = function(smtp, options, callback) {
229
- this.$callback2 = callback;
230
- Mailer.send(smtp, options, this);
231
- return this;
228
+ Message.prototype.send = function(smtp, options, callback, cache) {
229
+ var self = this;
230
+ self.$callback2 = callback;
231
+ options.server = smtp;
232
+ Mailer.send(options, self, callback, cache);
233
+ return self;
232
234
  };
233
235
 
234
236
  Mailer.tls = function(obj, opt) {
@@ -396,12 +398,12 @@ function writeattachmentbytes(chunk) {
396
398
  }
397
399
  }
398
400
 
399
- Mailer.try = function(smtp, options, callback) {
401
+ Mailer.try = function(options, callback) {
400
402
  var self = this;
401
403
  if (callback)
402
- return self.send(smtp, options, undefined, callback);
404
+ self.send(options, undefined, callback);
403
405
  else
404
- return new Promise((resolve, reject) => self.send(smtp, options, undefined, err => err ? reject(err) : resolve()));
406
+ return new Promise((resolve, reject) => self.send(options, undefined, err => err ? reject(err) : resolve()));
405
407
  };
406
408
 
407
409
  Mailer.send2 = function(messages, callback) {