alchemymvc 1.2.8 → 1.3.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.
@@ -7,7 +7,7 @@ var publicDirs = alchemy.shared('public.directories', new Deck()),
7
7
  imageDirs = alchemy.shared('images.directories', new Deck()),
8
8
  rootDirs = alchemy.shared('root.directories', new Deck()),
9
9
  fontDirs = alchemy.shared('font.directories', new Deck()),
10
- assetMap = alchemy.shared('files.assetMap'),
10
+ asset_cache= alchemy.getCache('files.assets'),
11
11
  fileCache = alchemy.shared('files.fileCache'),
12
12
  minifyMap = alchemy.shared('files.minifyMap'),
13
13
  Nodent = alchemy.use('nodent-compiler'),
@@ -128,7 +128,7 @@ function getMiddlePaths(paths, ext, new_ext) {
128
128
  *
129
129
  * @author Jelle De Loecker <jelle@develry.be>
130
130
  * @since 0.2.0
131
- * @version 1.2.7
131
+ * @version 1.3.0
132
132
  */
133
133
  Alchemy.setMethod(function styleMiddleware(req, res, nextMiddleware) {
134
134
 
@@ -145,10 +145,10 @@ Alchemy.setMethod(function styleMiddleware(req, res, nextMiddleware) {
145
145
  path = url.path;
146
146
 
147
147
  // If this file has already been found & compiled, serve it to the user
148
- if (assetMap[path]) {
149
- return req.conduit.serveFile(assetMap[path].path, {onError: function onError() {
148
+ if (asset_cache.has(path)) {
149
+ return req.conduit.serveFile(asset_cache.get(path).path, {onError: function onError() {
150
150
  // Unset asset
151
- assetMap[path] = null;
151
+ asset_cache.remove(path);
152
152
  alchemy.styleMiddleware(req, res, nextMiddleware);
153
153
  }});
154
154
  }
@@ -246,17 +246,20 @@ Alchemy.setMethod(function styleMiddleware(req, res, nextMiddleware) {
246
246
  return nextMiddleware();
247
247
  }
248
248
 
249
- return req.conduit.serveFile(compiled.path, {onError: function onError(err) {
250
- if (fileCache[compiled.path]) {
251
- fileCache[compiled.path] = null;
249
+ return req.conduit.serveFile(compiled.path, {
250
+ mimetype: 'text/css',
251
+ onError: function onError(err) {
252
+ if (fileCache[compiled.path]) {
253
+ fileCache[compiled.path] = null;
252
254
 
253
- if (o_stats && fileCache[o_stats.path]) {
254
- fileCache[o_stats.path] = null;
255
- }
255
+ if (o_stats && fileCache[o_stats.path]) {
256
+ fileCache[o_stats.path] = null;
257
+ }
256
258
 
257
- alchemy.styleMiddleware(req, res, nextMiddleware);
259
+ alchemy.styleMiddleware(req, res, nextMiddleware);
260
+ }
258
261
  }
259
- }});
262
+ });
260
263
  });
261
264
  });
262
265
 
@@ -266,7 +269,7 @@ Alchemy.setMethod(function styleMiddleware(req, res, nextMiddleware) {
266
269
  *
267
270
  * @author Jelle De Loecker <jelle@elevenways.be>
268
271
  * @since 1.1.0
269
- * @version 1.1.0
272
+ * @version 1.3.0
270
273
  */
271
274
  Alchemy.setMethod(function sourcemapMiddleware(req, res, nextMiddleware) {
272
275
 
@@ -297,7 +300,9 @@ Alchemy.setMethod(function sourcemapMiddleware(req, res, nextMiddleware) {
297
300
  return nextMiddleware();
298
301
  }
299
302
 
300
- req.conduit.serveFile(stats.path);
303
+ req.conduit.serveFile(stats.path, {
304
+ mimetype: 'application/json',
305
+ });
301
306
  });
302
307
  });
303
308
 
@@ -503,7 +508,7 @@ Alchemy.setMethod(function minifyScript(path, options, callback) {
503
508
  *
504
509
  * @author Jelle De Loecker <jelle@develry.be>
505
510
  * @since 0.2.0
506
- * @version 1.0.4
511
+ * @version 1.3.0
507
512
  */
508
513
  Alchemy.setMethod(function scriptMiddleware(req, res, nextMiddleware) {
509
514
 
@@ -517,15 +522,15 @@ Alchemy.setMethod(function scriptMiddleware(req, res, nextMiddleware) {
517
522
  return next();
518
523
  }
519
524
 
520
- if (assetMap[req.url]) {
521
- source = assetMap[req.url];
525
+ if (asset_cache.has(req.url)) {
526
+ source = asset_cache.get(req.url);
522
527
  return next();
523
528
  }
524
529
 
525
530
  alchemy.findAssetPath(req.middlePath, scriptDirs.getSorted(), function gotAssetPath(err, stats) {
526
531
 
527
532
  // @todo: error stuff, 404
528
- assetMap[req.url] = stats;
533
+ asset_cache.set(req.url, stats);
529
534
  source = stats;
530
535
 
531
536
  next();
@@ -566,22 +571,25 @@ Alchemy.setMethod(function scriptMiddleware(req, res, nextMiddleware) {
566
571
  return nextMiddleware();
567
572
  }
568
573
 
569
- req.conduit.serveFile(source.path, {onError: function onError() {
570
- // Unset asset
571
- if (fileCache[req.url]) {
572
- fileCache[req.url] = null;
573
- }
574
+ req.conduit.serveFile(source.path, {
575
+ mimetype: 'text/javascript',
576
+ onError: function onError() {
577
+ // Unset asset
578
+ if (fileCache[req.url]) {
579
+ fileCache[req.url] = null;
580
+ }
574
581
 
575
- if (assetMap[req.url]) {
576
- assetMap[req.url] = null;
577
- }
582
+ if (asset_cache.has(req.url)) {
583
+ asset_cache.remove(req.url);
584
+ }
578
585
 
579
- if (source && minifyMap[source.path]) {
580
- minifyMap[source.path] = null;
581
- }
586
+ if (source && minifyMap[source.path]) {
587
+ minifyMap[source.path] = null;
588
+ }
582
589
 
583
- alchemy.scriptMiddleware(req, res, nextMiddleware);
584
- }});
590
+ alchemy.scriptMiddleware(req, res, nextMiddleware);
591
+ }
592
+ });
585
593
  });
586
594
  });
587
595
 
@@ -622,15 +630,15 @@ Alchemy.setMethod(function assetInDirsMiddleware(req, res, directories, nextMidd
622
630
 
623
631
  Function.series(function getPath(next) {
624
632
 
625
- if (assetMap[req.url]) {
626
- source = assetMap[req.url];
633
+ if (asset_cache.has(req.url)) {
634
+ source = asset_cache.get(req.url);
627
635
  return next();
628
636
  }
629
637
 
630
638
  alchemy.findAssetPath(req.middlePath, directories, function gotAssetPath(err, stats) {
631
639
 
632
640
  // @todo: error stuff, 404
633
- assetMap[req.url] = stats;
641
+ asset_cache.set(req.url, stats);
634
642
  source = stats;
635
643
 
636
644
  next();
@@ -654,7 +662,7 @@ Alchemy.setMethod(function assetInDirsMiddleware(req, res, directories, nextMidd
654
662
  *
655
663
  * @author Jelle De Loecker <jelle@develry.be>
656
664
  * @since 0.2.0
657
- * @version 1.1.0
665
+ * @version 1.3.0
658
666
  */
659
667
  Alchemy.setMethod(function rootMiddleware(req, res, nextMiddleware) {
660
668
 
@@ -663,8 +671,8 @@ Alchemy.setMethod(function rootMiddleware(req, res, nextMiddleware) {
663
671
 
664
672
  Function.series(function getPath(next) {
665
673
 
666
- if (assetMap[req.url]) {
667
- source = assetMap[req.url];
674
+ if (asset_cache.has(req.url)) {
675
+ source = asset_cache.get(req.url);
668
676
  cached = true;
669
677
  return next();
670
678
  }
@@ -672,7 +680,10 @@ Alchemy.setMethod(function rootMiddleware(req, res, nextMiddleware) {
672
680
  alchemy.findAssetPath(req.middlePath, rootDirs.getSorted(), function gotAssetPath(err, stats) {
673
681
 
674
682
  // @todo: error stuff, 404
675
- assetMap[req.url] = stats;
683
+ if (stats?.path) {
684
+ asset_cache.set(req.url, stats);
685
+ }
686
+
676
687
  source = stats;
677
688
 
678
689
  next();
@@ -689,7 +700,7 @@ Alchemy.setMethod(function rootMiddleware(req, res, nextMiddleware) {
689
700
  onError: function onError() {
690
701
 
691
702
  if (cached) {
692
- assetMap[req.url] = null;
703
+ asset_cache.remove(req.url);
693
704
  alchemy.rootMiddleware(req, res, nextMiddleware);
694
705
  return;
695
706
  }
@@ -704,7 +715,7 @@ Alchemy.setMethod(function rootMiddleware(req, res, nextMiddleware) {
704
715
  *
705
716
  * @author Jelle De Loecker <jelle@develry.be>
706
717
  * @since 0.2.0
707
- * @version 1.1.4
718
+ * @version 1.3.0
708
719
  *
709
720
  * @param {String} image_path
710
721
  * @param {Function} callback
@@ -723,8 +734,8 @@ Alchemy.setMethod(function findImagePath(image_path, callback) {
723
734
 
724
735
  let id = 'image-' + image_path;
725
736
 
726
- if (alchemy.settings.cache && assetMap[id]) {
727
- pledge.resolve(assetMap[id].path);
737
+ if (alchemy.settings.cache && asset_cache.has(id)) {
738
+ pledge.resolve(asset_cache.get(id).path);
728
739
  } else {
729
740
 
730
741
  alchemy.findAssetPath(image_path, imageDirs.getSorted(), function gotImagePath(err, stats) {
@@ -732,7 +743,7 @@ Alchemy.setMethod(function findImagePath(image_path, callback) {
732
743
  if (err) {
733
744
  pledge.reject(err);
734
745
  } else {
735
- assetMap[id] = stats;
746
+ asset_cache.set(id, stats);
736
747
  pledge.resolve(stats.path);
737
748
  }
738
749
  });
@@ -869,7 +880,7 @@ Alchemy.setMethod(function findAssetPath(assetFile, directories, callback) {
869
880
  }, function lastly() {
870
881
 
871
882
  // Return an empty object when nothing was found,
872
- // so we'll cache that in the assetMap
883
+ // so we'll cache that in the asset_cache
873
884
  // Otherwise it'll keep checking for every request
874
885
  if (found == null) {
875
886
  found = {};
@@ -92,6 +92,9 @@ global.Alchemy = Function.inherits('Informer', 'Alchemy', function Alchemy() {
92
92
  // Also store the version of the app
93
93
  process.versions.alchemy_app = this.package.version;
94
94
 
95
+ // Distinct problems
96
+ this.distinct_problems = new Map();
97
+
95
98
  // Load the settings
96
99
  this.loadSettings();
97
100
 
@@ -1113,7 +1116,7 @@ Alchemy.setMethod(function isStream(obj) {
1113
1116
  *
1114
1117
  * @author Jelle De Loecker <jelle@develry.be>
1115
1118
  * @since 1.0.0
1116
- * @version 1.0.4
1119
+ * @version 1.3.0
1117
1120
  *
1118
1121
  * @param {String} name
1119
1122
  * @param {Number|Object} options
@@ -1144,12 +1147,11 @@ Alchemy.setMethod(function getCache(name, options) {
1144
1147
  }
1145
1148
 
1146
1149
  config = Object.assign({
1150
+ name,
1147
1151
  max_length : 5000,
1148
1152
  }, options);
1149
1153
 
1150
- // @TODO: Fixed in 0.6.1
1151
- instance = new Blast.Classes.Develry.Cache();
1152
- Object.assign(instance, config);
1154
+ instance = new Blast.Classes.Develry.Cache(config);
1153
1155
 
1154
1156
  this.caches[name] = instance;
1155
1157
 
@@ -1161,16 +1163,17 @@ Alchemy.setMethod(function getCache(name, options) {
1161
1163
  *
1162
1164
  * @author Jelle De Loecker <jelle@elevenways.be>
1163
1165
  * @since 1.1.3
1164
- * @version 1.1.3
1166
+ * @version 1.3.0
1165
1167
  *
1166
1168
  * @param {String} href The href or route name
1167
1169
  * @param {Object} parameters Route parameters
1170
+ * @param {Object} options
1168
1171
  *
1169
1172
  * @return {String}
1170
1173
  */
1171
- Alchemy.setMethod(function routeUrl(href, parameters) {
1174
+ Alchemy.setMethod(function routeUrl(href, parameters, options) {
1172
1175
 
1173
- let temp = Router.getUrl(href, parameters);
1176
+ let temp = Router.getUrl(href, parameters, options);
1174
1177
 
1175
1178
  if (temp && temp.href) {
1176
1179
  temp = String(temp);
@@ -1382,7 +1385,7 @@ Alchemy.setMethod(function addAppcacheEntry(entry) {
1382
1385
  *
1383
1386
  * @author Jelle De Loecker <jelle@develry.be>
1384
1387
  * @since 1.1.0
1385
- * @version 1.2.7
1388
+ * @version 1.3.0
1386
1389
  *
1387
1390
  * @param {IncomingMessage} req
1388
1391
  * @param {OutgoingMessage} res Optional
@@ -1410,7 +1413,7 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
1410
1413
 
1411
1414
  let form = new formidable.IncomingForm({
1412
1415
  multiples : true,
1413
- hashAlgorithm : 'md5',
1416
+ hashAlgorithm : alchemy.settings.file_hash_algorithm || 'sha1',
1414
1417
  });
1415
1418
 
1416
1419
  form.parse(req, function parsedMultipart(err, form_fields, form_files) {
@@ -48,6 +48,17 @@ DEFINE('Blast', __Protoblast);
48
48
  */
49
49
  DEFINE('Classes', Blast.Classes);
50
50
 
51
+ /**
52
+ * Available types
53
+ *
54
+ * @author Jelle De Loecker <jelle@elevenways.be>
55
+ * @since 1.3.0
56
+ * @version 1.3.0
57
+ *
58
+ * @type {Object}
59
+ */
60
+ DEFINE('Types', Blast.Types);
61
+
51
62
  /**
52
63
  * Path to the directory of the server.js file
53
64
  *
@@ -11,8 +11,9 @@ var mkdirp = alchemy.use('mkdirp'),
11
11
  timers = {},
12
12
  lpQueue = 0,
13
13
  moduledirs,
14
- spawnQueue,
15
- Magic;
14
+ spawnQueue;
15
+
16
+ const HAS_EXPOSED = Symbol('has_exposed');
16
17
 
17
18
  // Create a queue for functions opening files
18
19
  spawnQueue = Function.createQueue();
@@ -519,25 +520,22 @@ alchemy.ObjectId = mongo.ObjectID;
519
520
 
520
521
  /**
521
522
  * Get mimetype info of a file
523
+ *
524
+ * @deprecated Use Classes.Alchemy.Inode.File.getMimetype(path)
522
525
  *
523
526
  * @author Jelle De Loecker <jelle@develry.be>
524
527
  * @since 0.2.0
525
- * @version 0.4.0
528
+ * @version 1.3.0
526
529
  *
527
- * @param {String} filePath A path to the file
530
+ * @param {String} filepath A path to the file
528
531
  * @param {Function} callback
532
+ *
533
+ * @return {Pledge<String>}
529
534
  */
530
- Alchemy.setMethod(function getMimetype(filePath, callback) {
531
-
532
- var magic,
533
- mmm = alchemy.use('mmmagic');
534
-
535
- if (!mmm) {
536
- return callback(new Error('The mmmagic module is not available'));
537
- }
538
-
539
- magic = new mmm.Magic(mmm.MAGIC_MIME_TYPE);
540
- magic.detectFile(filePath, callback);
535
+ Alchemy.setMethod(function getMimetype(filepath, callback) {
536
+ const pledge = Classes.Alchemy.Inode.File.getMimetype(filepath);
537
+ pledge.done(callback);
538
+ return pledge;
541
539
  });
542
540
 
543
541
  /**
@@ -687,9 +685,9 @@ Alchemy.setMethod(function getMedhash(file_path, options) {
687
685
  /**
688
686
  * Hash the given file_path using the given hash
689
687
  *
690
- * @author Jelle De Loecker <jelle@develry.be>
688
+ * @author Jelle De Loecker <jelle@elevenways.be>
691
689
  * @since 1.0.7
692
- * @version 1.0.7
690
+ * @version 1.3.0
693
691
  *
694
692
  * @param {String} file_path
695
693
  * @param {Object} options
@@ -698,7 +696,7 @@ Alchemy.setMethod(function hashFile(file_path, options) {
698
696
 
699
697
  var stream_options = {},
700
698
  digest_type,
701
- type;
699
+ hash_algorithm;
702
700
 
703
701
  if (!options) {
704
702
  options = {};
@@ -710,10 +708,10 @@ Alchemy.setMethod(function hashFile(file_path, options) {
710
708
  };
711
709
  }
712
710
 
713
- type = options.type || 'sha1';
711
+ hash_algorithm = options.algorithm || options.type || alchemy.settings.file_hash_algorithm || 'sha1';
714
712
  digest_type = options.digest_type || 'hex';
715
713
 
716
- let checksum = crypto.createHash(type),
714
+ let checksum = crypto.createHash(hash_algorithm),
717
715
  pledge = new Pledge(),
718
716
  stream;
719
717
 
@@ -781,7 +779,7 @@ Alchemy.setMethod(function statPath(path, options) {
781
779
  *
782
780
  * @author Jelle De Loecker <jelle@develry.be>
783
781
  * @since 0.0.1
784
- * @version 1.0.7
782
+ * @version 1.3.0
785
783
  *
786
784
  * @param {String} filePath A path to the file
787
785
  * @param {Object} options
@@ -802,7 +800,7 @@ Alchemy.setMethod(function getFileInfo(filePath, options, callback) {
802
800
 
803
801
  // Use sha1 as hashing default
804
802
  if (typeof options.hash == 'undefined' || options.hash === true) {
805
- options.hash = 'sha1';
803
+ options.hash = alchemy.settings.file_hash_algorithm || 'sha1';
806
804
  }
807
805
 
808
806
  // Get basic file information
@@ -1011,42 +1009,45 @@ Alchemy.setMethod(function request(url, options, callback) {
1011
1009
  });
1012
1010
 
1013
1011
  /**
1014
- * Download a url to a temporary location
1012
+ * Download a file
1015
1013
  *
1016
- * @author Jelle De Loecker <jelle@develry.be>
1017
- * @since 0.1.0
1018
- * @version 1.2.6
1014
+ * @author Jelle De Loecker <jelle@elevenways.be>
1015
+ * @since 1.3.0
1016
+ * @version 1.3.0
1019
1017
  *
1020
- * @param {String} url The url
1021
- * @param {Object} options
1022
- * @param {Function} callback Callback
1018
+ * @param {String} url
1019
+ *
1020
+ * @return {Pledge<File>}
1023
1021
  */
1024
- Alchemy.setMethod(function downloadFile(url, options, callback) {
1022
+ Alchemy.setMethod(function download(url, options) {
1025
1023
 
1026
- var filepath,
1027
- options,
1028
- name,
1029
- file,
1030
- res;
1031
-
1032
- if (typeof options === 'function') {
1033
- callback = options;
1034
- options = {};
1035
- } else if (!options && typeof options !== 'object') {
1036
- options = {};
1037
- }
1038
-
1039
- if (typeof callback !== 'function') {
1040
- callback = Function.thrower;
1041
- }
1024
+ const pledge = new Pledge();
1042
1025
 
1043
1026
  // Get the file
1044
- Blast.fetch({url, get_stream: true}, function gotStream(err, res, output) {
1027
+ Blast.fetch({url, get_stream: true}, async function gotStream(err, res, output) {
1045
1028
 
1046
1029
  if (err) {
1047
- return callback(err);
1030
+ return pledge.reject(err);
1031
+ }
1032
+
1033
+ if (res.statusCode == 404) {
1034
+ err = new Error('Path "' + url + '" does not exist');
1035
+ err.number = 404;
1036
+ return pledge.reject(err);
1037
+ }
1038
+
1039
+ if (options?.type && res.headers['content-type']) {
1040
+ if (res.headers['content-type'].indexOf(options.type) < 0) {
1041
+
1042
+ err = new Error('Received unexpected filetype');
1043
+ err.number = 500;
1044
+
1045
+ return pledge.reject(err);
1046
+ }
1048
1047
  }
1049
1048
 
1049
+ let name;
1050
+
1050
1051
  if (res.headers['content-disposition']) {
1051
1052
  let disposition = res.headers['content-disposition'],
1052
1053
  pieces = disposition.split(';'),
@@ -1075,44 +1076,60 @@ Alchemy.setMethod(function downloadFile(url, options, callback) {
1075
1076
  }
1076
1077
  }
1077
1078
 
1078
- // Construct a temporary file path
1079
- filepath = '/tmp/alchemy_' + Crypto.pseudoHex(8) + '_' + name;
1080
-
1081
- // Open the temp file
1082
- file = fs.createWriteStream(filepath);
1083
-
1084
- if (res.statusCode == 404) {
1085
- err = new Error('Path "' + url + '" does not exist');
1086
- err.number = 404;
1087
-
1088
- return callback(err);
1079
+ if (name.indexOf('/') > -1) {
1080
+ name = name.replaceAll('/', '-');
1089
1081
  }
1090
1082
 
1091
- if (options.type && res.headers['content-type']) {
1092
- if (res.headers['content-type'].indexOf(options.type) < 0) {
1093
-
1094
- err = new Error('Received unexpected filetype');
1095
- err.number = 500;
1096
-
1097
- return callback(err);
1098
- }
1099
- }
1083
+ let temp_dir = await Blast.createTempDir({prefix: 'aldl'}),
1084
+ full_path = libpath.resolve(temp_dir, name);
1085
+
1086
+ let write_stream = fs.createWriteStream(full_path);
1100
1087
 
1101
1088
  if (output) {
1102
1089
  // Pipe the response stream into the file
1103
- output.pipe(file);
1090
+ output.pipe(write_stream);
1104
1091
  } else {
1105
- file.end('');
1092
+ write_stream.end('');
1106
1093
  }
1107
1094
 
1108
- // @todo: maybe implement content-type for downloaded file, too?
1109
- // Because webservers can lie about filetypes
1095
+ // Wait for it to finish writing to the temp file
1096
+ write_stream.on('finish', async function writeFinished() {
1110
1097
 
1111
- // Close the file when finished and callback
1112
- file.on('finish', function writeFinished() {
1113
- callback(null, filepath, name);
1098
+ try {
1099
+ let file = await Classes.Alchemy.Inode.Inode.from(full_path);
1100
+ pledge.resolve(file);
1101
+ } catch (err) {
1102
+ pledge.reject(err);
1103
+ }
1114
1104
  });
1115
1105
  });
1106
+
1107
+ return pledge;
1108
+ });
1109
+
1110
+ /**
1111
+ * Download a url to a temporary location
1112
+ *
1113
+ * @author Jelle De Loecker <jelle@elevenways.be>
1114
+ * @since 0.1.0
1115
+ * @version 1.3.0
1116
+ *
1117
+ * @deprecated Use `download` instead
1118
+ *
1119
+ * @param {String} url The url
1120
+ * @param {Object} options
1121
+ * @param {Function} callback Callback
1122
+ */
1123
+ Alchemy.setMethod(function downloadFile(url, options, callback) {
1124
+
1125
+ if (typeof options == 'function') {
1126
+ callback = options;
1127
+ options = null;
1128
+ }
1129
+
1130
+ let pledge = this.download(url, options);
1131
+ pledge.done(callback);
1132
+ return pledge;
1116
1133
  });
1117
1134
 
1118
1135
  /**
@@ -1345,14 +1362,7 @@ Alchemy.setMethod(function exposeDefaultStaticVariables() {
1345
1362
  // Expose the model configuration
1346
1363
  hawkejs.exposeStatic('model_info', model_info);
1347
1364
 
1348
- // Expose router options
1349
- hawkejs.exposeStatic('router_options', Router.getOptions());
1350
-
1351
- // Expose basic HTTP routes
1352
- hawkejs.exposeStatic('routes', Router.getRoutes());
1353
-
1354
- // Expose socket routes
1355
- hawkejs.exposeStatic('socket_routes', Router.getSocketRoutes());
1365
+ this.exposeRouteData();
1356
1366
 
1357
1367
  // Expose breadcrumb info
1358
1368
  hawkejs.exposeStatic('breadcrumb_info', Router.getBreadcrumbInfo());
@@ -1379,6 +1389,47 @@ Alchemy.setMethod(function exposeDefaultStaticVariables() {
1379
1389
 
1380
1390
  // Emit as a global event so plugins can also expose their data
1381
1391
  this.emit('generate_static_variables', hawkejs);
1392
+
1393
+ this[HAS_EXPOSED] = true;
1394
+ });
1395
+
1396
+ /**
1397
+ * Regenerate exposed route data
1398
+ *
1399
+ * @author Jelle De Loecker <jelle@elevenways.be>
1400
+ * @since 1.3.0
1401
+ * @version 1.3.0
1402
+ */
1403
+ Alchemy.setMethod(function exposeRouteData() {
1404
+
1405
+ const hawkejs = alchemy.hawkejs;
1406
+
1407
+ // Expose router options
1408
+ hawkejs.exposeStatic('router_options', Router.getOptions());
1409
+
1410
+ // Expose basic HTTP routes
1411
+ hawkejs.exposeStatic('routes', Router.getRoutes());
1412
+
1413
+ // Expose socket routes
1414
+ hawkejs.exposeStatic('socket_routes', Router.getSocketRoutes());
1415
+ });
1416
+
1417
+
1418
+ /**
1419
+ * Flush the exposed route data
1420
+ * (Will only regenerate if default static variables haven't been generated yet)
1421
+ *
1422
+ * @author Jelle De Loecker <jelle@elevenways.be>
1423
+ * @since 1.3.0
1424
+ * @version 1.3.0
1425
+ */
1426
+ Alchemy.setMethod(function checkExposedRouteData() {
1427
+
1428
+ if (!this[HAS_EXPOSED]) {
1429
+ return;
1430
+ }
1431
+
1432
+ this.exposeRouteData();
1382
1433
  });
1383
1434
 
1384
1435
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemymvc",
3
3
  "description": "MVC framework for Node.js",
4
- "version": "1.2.8",
4
+ "version": "1.3.0",
5
5
  "author": "Jelle De Loecker <jelle@elevenways.be>",
6
6
  "keywords": [
7
7
  "alchemy",
@@ -22,7 +22,7 @@
22
22
  "chokidar" : "~3.5.3",
23
23
  "formidable" : "~2.0.1",
24
24
  "graceful-fs" : "~4.2.9",
25
- "hawkejs" : "~2.2.18",
25
+ "hawkejs" : "~2.2.23",
26
26
  "jsondiffpatch" : "~0.4.1",
27
27
  "mime" : "~3.0.0",
28
28
  "minimist" : "~1.2.5",
@@ -31,7 +31,7 @@
31
31
  "mongodb" : "~3.6.6",
32
32
  "ncp" : "~2.0.0",
33
33
  "postcss" : "~8.4.6",
34
- "protoblast" : "~0.7.24",
34
+ "protoblast" : "~0.7.27",
35
35
  "semver" : "~7.3.5",
36
36
  "socket.io" : "~2.4.0",
37
37
  "@11ways/socket.io-stream" : "~0.9.2",
@@ -56,9 +56,9 @@
56
56
  "codecov" : "~3.8.1",
57
57
  "istanbul-lib-instrument" : "~4.0.3",
58
58
  "mocha" : "~8.3.2",
59
- "mongo-unit" : "~2.0.1",
59
+ "mongo-unit" : "~3.2.0",
60
60
  "nyc" : "^15.1.0",
61
- "puppeteer" : "~9.0.0",
61
+ "puppeteer" : "~19.0.0",
62
62
  "source-map" : "~0.7.3"
63
63
  },
64
64
  "scripts": {