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.
- package/lib/app/helper_model/criteria.js +1 -1
- package/lib/app/helper_validator/00_validator.js +4 -0
- package/lib/class/document.js +15 -14
- package/lib/class/postponement.js +26 -6
- package/lib/class/sitemap.js +11 -3
- package/lib/core/client_base.js +7 -2
- package/lib/core/middleware.js +2 -2
- package/lib/init/alchemy.js +63 -10
- package/lib/init/requirements.js +4 -2
- package/lib/stages.js +4 -4
- package/package.json +3 -3
|
@@ -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.
|
|
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) {
|
package/lib/class/document.js
CHANGED
|
@@ -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
|
|
648
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
649
649
|
* @since 0.3.0
|
|
650
|
-
* @version 1.3.
|
|
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
|
|
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.
|
|
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.
|
|
133
|
+
* @version 1.3.2
|
|
131
134
|
*
|
|
132
135
|
* @return {Number}
|
|
133
136
|
*/
|
|
134
137
|
Postponement.setProperty(function has_been_abandoned() {
|
|
135
138
|
|
|
136
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
/**
|
package/lib/class/sitemap.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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);
|
package/lib/core/client_base.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
333
|
+
|
|
334
|
+
if (next) {
|
|
335
|
+
next(err);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return;
|
|
334
339
|
}
|
|
335
340
|
|
|
336
341
|
if (result !== false) {
|
package/lib/core/middleware.js
CHANGED
|
@@ -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.
|
|
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
|
|
437
|
+
if (alchemy.settings.debug && alchemy.settings.source_map) {
|
|
438
438
|
minify_options.sourceMap = {
|
|
439
439
|
url: 'inline'
|
|
440
440
|
};
|
package/lib/init/alchemy.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
269
|
-
|
|
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.
|
|
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
|
-
|
|
310
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
789
|
+
create_source_map : alchemy.settings.source_map,
|
|
737
790
|
enable_coverage : !!global.__coverage__
|
|
738
791
|
});
|
|
739
792
|
}
|
package/lib/init/requirements.js
CHANGED
|
@@ -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
|
|
62
|
-
alchemy.toobusy.maxLag(
|
|
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@
|
|
186
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
187
187
|
* @since 0.0.1
|
|
188
|
-
* @version 1.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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",
|