alchemymvc 1.3.1 → 1.3.3-alpha

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.
@@ -1503,7 +1503,7 @@ Select.setMethod(function addAssociation(name) {
1503
1503
  this.requireFieldForQuery(info.options.localKey);
1504
1504
  }
1505
1505
  } catch (err) {
1506
- console.warn('Failed to find "' + name + '" association for ' + this.criteria.model.modelName);
1506
+ console.warn('Failed to find "' + name + '" association for ' + this.criteria.model.model_name);
1507
1507
  }
1508
1508
 
1509
1509
  return this.associations[name];
@@ -218,6 +218,10 @@ Validator.setMethod(async function validateDocument(root, context, schema) {
218
218
 
219
219
  fields_with_value = field.getDocumentValues(root);
220
220
 
221
+ if (!fields_with_value?.length) {
222
+ continue;
223
+ }
224
+
221
225
  violation = await this.validateFieldValue(fields_with_value);
222
226
 
223
227
  if (violation) {
@@ -645,31 +645,26 @@ Document.setMethod(['populate', 'addAssociatedData'], function addAssociatedData
645
645
  /**
646
646
  * Get the display field value
647
647
  *
648
- * @author Jelle De Loecker <jelle@develry.be>
648
+ * @author Jelle De Loecker <jelle@elevenways.be>
649
649
  * @since 0.3.0
650
- * @version 1.3.0
650
+ * @version 1.3.3
651
651
  *
652
652
  * @param {Object} options
653
653
  *
654
- * @return {String}
654
+ * @return {String|undefined}
655
655
  */
656
- Document.setMethod(function getDisplayFieldValue(options) {
657
-
658
- var display_field,
659
- result,
660
- i;
661
-
662
- if (!options) {
663
- options = {};
664
- }
656
+ Document.setMethod(function getDisplayFieldValue(options = {}) {
665
657
 
666
- display_field = Array.cast(this.$model.display_field);
658
+ let display_field = Array.cast(this.$model.display_field);
667
659
 
668
660
  // If there are fields we prefer, check those first
669
661
  if (options.prefer) {
670
662
  display_field = Array.cast(options.prefer).concat(display_field);
671
663
  }
672
664
 
665
+ let result,
666
+ i;
667
+
673
668
  for (i = 0; i < display_field.length; i++) {
674
669
  result = this[display_field[i]];
675
670
 
@@ -682,8 +677,14 @@ Document.setMethod(function getDisplayFieldValue(options) {
682
677
  }
683
678
  }
684
679
 
680
+ let fallback_property = options.fallback ?? '_id';
681
+
682
+ if (!fallback_property) {
683
+ return;
684
+ }
685
+
685
686
  // If nothing was found, return the _id value
686
- return String(this._id);
687
+ return String(this[fallback_property]);
687
688
  });
688
689
 
689
690
  /**
@@ -7,7 +7,7 @@ let queue_check_id,
7
7
  *
8
8
  * @author Jelle De Loecker <jelle@elevenways.be>
9
9
  * @since 1.3.1
10
- * @version 1.3.1
10
+ * @version 1.3.2
11
11
  *
12
12
  * @param {Conduit} conduit The original conduit
13
13
  */
@@ -43,6 +43,9 @@ const Postponement = Function.inherits('Alchemy.Base', 'Alchemy.Conduit', functi
43
43
  // When did this postponement end?
44
44
  this.ended = null;
45
45
 
46
+ // Has this postponement expired?
47
+ this.expired = false;
48
+
46
49
  // Has this postponement been released yet?
47
50
  this.released = false;
48
51
 
@@ -127,13 +130,15 @@ Postponement.setProperty(function time_unchecked() {
127
130
  *
128
131
  * @author Jelle De Loecker <jelle@elevenways.be>
129
132
  * @since 1.3.1
130
- * @version 1.3.1
133
+ * @version 1.3.2
131
134
  *
132
135
  * @return {Number}
133
136
  */
134
137
  Postponement.setProperty(function has_been_abandoned() {
135
138
 
136
- if (this.time_unchecked > 30 * 1000) {
139
+ // Postponements that haven't been checked in 3 minutes
140
+ // are considered abandoned
141
+ if (this.time_unchecked > 180_000) {
137
142
  return true;
138
143
  }
139
144
 
@@ -236,7 +241,7 @@ Postponement.setStatic(function checkQueue() {
236
241
  *
237
242
  * @author Jelle De Loecker <jelle@elevenways.be>
238
243
  * @since 1.3.1
239
- * @version 1.3.1
244
+ * @version 1.3.2
240
245
  *
241
246
  * @param {Conduit} conduit The new conduit
242
247
  */
@@ -253,7 +258,19 @@ Postponement.setMethod(function handleRequest(conduit) {
253
258
  location : null,
254
259
  };
255
260
 
256
- if (this.attemptUnlock()) {
261
+ if (this.released) {
262
+ data.allowed = true;
263
+ data.location = this.url;
264
+ } else if (this.expired) {
265
+ // If the request has expired, send them to the original url again
266
+ data.allowed = true;
267
+ data.location = this.original_path;
268
+ } else if (this.attemptUnlock()) {
269
+ data.allowed = true;
270
+ data.location = this.url;
271
+ } else if (data.position == null) {
272
+ // Something else has gone wrong?
273
+ // Send them to the url anyway
257
274
  data.allowed = true;
258
275
  data.location = this.url;
259
276
  }
@@ -276,7 +293,7 @@ Postponement.setMethod(function handleRequest(conduit) {
276
293
  *
277
294
  * @author Jelle De Loecker <jelle@elevenways.be>
278
295
  * @since 1.3.1
279
- * @version 1.3.1
296
+ * @version 1.3.2
280
297
  *
281
298
  * @return {Boolean} True if the request is being resumed
282
299
  */
@@ -286,6 +303,8 @@ Postponement.setMethod(function attemptUnlock() {
286
303
  return true;
287
304
  }
288
305
 
306
+ this.last_check = Date.now();
307
+
289
308
  Postponement.scheduleQueueCheck();
290
309
 
291
310
  if (this.position_in_queue > 5) {
@@ -431,6 +450,7 @@ Postponement.setMethod(function remove(expired) {
431
450
  */
432
451
  Postponement.setMethod(function expire() {
433
452
  this.remove(true);
453
+ this.expired = true;
434
454
  });
435
455
 
436
456
  /**
@@ -281,7 +281,12 @@ Sitemap.setTypedMethod([Types.Alchemy.Route, Types.Object, Types.Alchemy.Criteri
281
281
  *
282
282
  * @author Jelle De Loecker <jelle@elevenways.be>
283
283
  * @since 1.3.0
284
- * @version 1.3.0
284
+ * @version 1.3.3
285
+ *
286
+ * @param {Route} route The route of which to add something to the map
287
+ * @param {Object} config Sitemap configuration for this route
288
+ * @param {Object} parameters The parameter object to use for generating the url
289
+ * @param {String} forced_prefix The optional prefix to use
285
290
  *
286
291
  * @return {Promise}
287
292
  */
@@ -290,6 +295,7 @@ Sitemap.setMethod(function addRouteWithParameters(route, config, parameters, for
290
295
  if (!parameters) {
291
296
  parameters = {};
292
297
  } else {
298
+ // Make an overlay object
293
299
  parameters = Object.create(parameters);
294
300
  }
295
301
 
@@ -319,7 +325,7 @@ Sitemap.setMethod(function addRouteWithParameters(route, config, parameters, for
319
325
  let route_config = Object.assign({}, config);
320
326
 
321
327
  if (parameters && parameters.getDisplayFieldValue) {
322
- route_config.title = parameters.getDisplayFieldValue({prefix});
328
+ route_config.title = parameters.getDisplayFieldValue({prefix, fallback: false});
323
329
  }
324
330
 
325
331
  if (!route_config.title) {
@@ -333,7 +339,9 @@ Sitemap.setMethod(function addRouteWithParameters(route, config, parameters, for
333
339
  }
334
340
 
335
341
  if (!route_config.title) {
336
- route_config.title = route.name;
342
+ // Skip this if no title was found.
343
+ // It's better to show nothing
344
+ continue;
337
345
  }
338
346
 
339
347
  this.addUrl(config.category, url, route_config, prefix);
@@ -294,7 +294,7 @@ ClientBase.setMethod(function getModel(name, init, options) {
294
294
  *
295
295
  * @author Jelle De Loecker <jelle@elevenways.be>
296
296
  * @since 1.1.1
297
- * @version 1.3.0
297
+ * @version 1.3.2
298
298
  *
299
299
  * @param {String} name The name of the event to emit
300
300
  * @param {Array} args The parameters to pass to the event
@@ -330,7 +330,12 @@ ClientBase.setMethod(function issueEvent(name, args, next) {
330
330
 
331
331
  if (err) {
332
332
  pledge.reject(err);
333
- return next(err);
333
+
334
+ if (next) {
335
+ next(err);
336
+ }
337
+
338
+ return;
334
339
  }
335
340
 
336
341
  if (result !== false) {
@@ -311,7 +311,7 @@ Alchemy.setMethod(function sourcemapMiddleware(req, res, nextMiddleware) {
311
311
  *
312
312
  * @author Jelle De Loecker <jelle@develry.be>
313
313
  * @since 0.2.0
314
- * @version 1.2.7
314
+ * @version 1.3.3
315
315
  *
316
316
  * @param {String} path
317
317
  * @param {Object} options
@@ -434,7 +434,7 @@ Alchemy.setMethod(function minifyScript(path, options, callback) {
434
434
  }
435
435
  };
436
436
 
437
- if (alchemy.settings.debug && alchemy.settings.source_map !== false) {
437
+ if (alchemy.settings.debug && alchemy.settings.source_map) {
438
438
  minify_options.sourceMap = {
439
439
  url: 'inline'
440
440
  };
@@ -90,6 +90,9 @@ global.Alchemy = Function.inherits('Informer', 'Alchemy', function Alchemy() {
90
90
  // All caches
91
91
  this.caches = {};
92
92
 
93
+ // Extra toobusy checks
94
+ this.extra_toobusy_checks = [];
95
+
93
96
  // Also store the version in the process versions object
94
97
  process.versions.alchemy = this.version;
95
98
 
@@ -249,24 +252,55 @@ Alchemy.setMethod(function systemLoad() {
249
252
  return percentage;
250
253
  });
251
254
 
255
+ /**
256
+ * Register an extra toobusy check method.
257
+ * These will be checked after event loop lag & system load are deemed OK.
258
+ *
259
+ * @author Jelle De Loecker <jelle@elevenways.be>
260
+ * @since 1.3.2
261
+ * @version 1.3.2
262
+ */
263
+ Alchemy.setMethod(function addToobusyCheck(fnc) {
264
+ this.extra_toobusy_checks.push(fnc);
265
+ });
266
+
252
267
  /**
253
268
  * Is the server currently too busy, overloaded in some way?
254
269
  *
255
270
  * @author Jelle De Loecker <jelle@elevenways.be>
256
271
  * @since 1.3.1
257
- * @version 1.3.1
272
+ * @version 1.3.2
258
273
  *
259
274
  * @return {Boolean}
260
275
  */
261
276
  Alchemy.setMethod(function isTooBusy() {
262
277
 
263
- // First check if it's too busy because of lag
278
+ // First check if it's too busy because of event loop lag
264
279
  if (this.toobusy()) {
265
280
  return true;
266
281
  }
267
282
 
268
- // Then check the load average
269
- return this.systemLoad() > 90;
283
+ if (this.settings.max_system_load > 0) {
284
+ // Then check the load average
285
+ if (this.systemLoad() > this.settings.max_system_load) {
286
+ return true;
287
+ }
288
+ }
289
+
290
+ if (this.extra_toobusy_checks.length > 0) {
291
+
292
+ for (let fnc of this.extra_toobusy_checks) {
293
+ try {
294
+ if (fnc()) {
295
+ return true;
296
+ }
297
+ } catch (err) {
298
+ alchemy.distinctProblem('error-extra-toobusy-check', 'Extra toobusy check failed', {error: err});
299
+ }
300
+ }
301
+ }
302
+
303
+ return false;
270
304
  });
271
305
 
272
306
  /**
@@ -294,7 +328,7 @@ Alchemy.setMethod(function isTooBusyForRequests() {
294
328
  *
295
329
  * @author Jelle De Loecker <jelle@elevenways.be>
296
330
  * @since 1.3.1
297
- * @version 1.3.1
331
+ * @version 1.3.2
298
332
  *
299
333
  * @return {Boolean}
300
334
  */
@@ -306,8 +340,12 @@ Alchemy.setMethod(function isTooBusyForAjax() {
306
340
 
307
341
  let lag = this.lagInMs();
308
342
 
309
- if (lag > (alchemy.settings.toobusy * 3)) {
310
- return true;
343
+ let max_event_loop_lag = alchemy.settings.max_event_loop_lag || alchemy.settings.toobusy;
344
+
345
+ if (max_event_loop_lag) {
346
+ if (lag > (max_event_loop_lag * 3)) {
347
+ return true;
348
+ }
311
349
  }
312
350
 
313
351
  return false;
@@ -478,7 +516,7 @@ Alchemy.setMethod(function printLog(level, args, options) {
478
516
  *
479
517
  * @author Jelle De Loecker <jelle@develry.be>
480
518
  * @since 0.4.0
481
- * @version 1.1.6
519
+ * @version 1.3.3
482
520
  */
483
521
  Alchemy.setMethod(function loadSettings() {
484
522
 
@@ -651,6 +689,21 @@ Alchemy.setMethod(function loadSettings() {
651
689
  }
652
690
  }
653
691
 
692
+ if (settings.debug) {
693
+
694
+ if (settings.source_map === 'false') {
695
+ settings.source_map = false;
696
+ }
697
+
698
+ if (settings.source_map == null || settings.source_map) {
699
+ settings.source_map = true;
700
+ } else {
701
+ settings.source_map = false;
702
+ }
703
+ } else {
704
+ settings.source_map = false;
705
+ }
706
+
654
707
  if (settings.preload) {
655
708
  this.doPreload();
656
709
  }
@@ -706,7 +759,7 @@ Alchemy.setMethod(function ready(callback) {
706
759
  *
707
760
  * @author Jelle De Loecker <jelle@elevenways.be>
708
761
  * @since 1.1.2
709
- * @version 1.1.2
762
+ * @version 1.3.3
710
763
  */
711
764
  Alchemy.setMethod(async function doPreload() {
712
765
 
@@ -733,7 +786,7 @@ Alchemy.setMethod(async function doPreload() {
733
786
 
734
787
  Blast.getClientPath({
735
788
  modify_prototypes : true,
736
- create_source_map : alchemy.settings.debug,
789
+ create_source_map : alchemy.settings.source_map,
737
790
  enable_coverage : !!global.__coverage__
738
791
  });
739
792
  }
@@ -57,9 +57,11 @@ alchemy.hawkejs = Classes.Hawkejs.Hawkejs.getInstance();
57
57
  */
58
58
  alchemy.toobusy = alchemy.use('toobusy-js', 'toobusy');
59
59
 
60
+ let max_event_loop_lag = alchemy.settings.max_event_loop_lag || alchemy.settings.toobusy;
61
+
60
62
  // If the config is a number, use that as the lag threshold
61
- if (typeof alchemy.settings.toobusy === 'number') {
62
- alchemy.toobusy.maxLag(alchemy.settings.toobusy);
63
+ if (typeof max_event_loop_lag === 'number') {
64
+ alchemy.toobusy.maxLag(max_event_loop_lag);
63
65
  }
64
66
 
65
67
  /**
package/lib/stages.js CHANGED
@@ -183,9 +183,9 @@ alchemy.sputnik.add(function define_debug() {
183
183
  * The "hawkejsSetup" stage:
184
184
  * Initialize Hawkejs
185
185
  *
186
- * @author Jelle De Loecker <jelle@develry.be>
186
+ * @author Jelle De Loecker <jelle@elevenways.be>
187
187
  * @since 0.0.1
188
- * @version 1.1.0
188
+ * @version 1.3.3
189
189
  */
190
190
  alchemy.sputnik.add(function hawkejs_setup() {
191
191
 
@@ -201,7 +201,7 @@ alchemy.sputnik.add(function hawkejs_setup() {
201
201
  Blast.getClientPath({
202
202
  modify_prototypes : true,
203
203
  ua : req.conduit.headers.useragent,
204
- create_source_map : alchemy.settings.debug,
204
+ create_source_map : alchemy.settings.source_map,
205
205
  enable_coverage : !!global.__coverage__
206
206
  }).done(gotClientFile);
207
207
 
@@ -243,7 +243,7 @@ alchemy.sputnik.add(function hawkejs_setup() {
243
243
  refresh : true,
244
244
  modify_prototypes : true,
245
245
  ua : req.conduit.headers.useragent,
246
- create_source_map : alchemy.settings.debug,
246
+ create_source_map : alchemy.settings.source_map,
247
247
  }).done(gotClientFile);
248
248
  }
249
249
  });
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.3.1",
4
+ "version": "1.3.3-alpha",
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.3.1",
25
+ "hawkejs" : "~2.3.3",
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.8.0",
34
+ "protoblast" : "~0.8.3",
35
35
  "semver" : "~7.3.5",
36
36
  "socket.io" : "~2.4.0",
37
37
  "@11ways/socket.io-stream" : "~0.9.2",