alchemymvc 1.3.16 → 1.3.18
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/datasource/mongo_datasource.js +51 -29
- package/lib/app/element/time_ago.js +19 -36
- package/lib/app/helper/alchemy_helper.js +2 -2
- package/lib/app/helper/cron.js +1502 -0
- package/lib/app/helper_model/document.js +1 -0
- package/lib/app/model/alchemy_task_history_model.js +109 -0
- package/lib/app/model/alchemy_task_model.js +141 -18
- package/lib/bootstrap.js +3 -0
- package/lib/class/conduit.js +103 -33
- package/lib/class/model.js +24 -0
- package/lib/class/schema_client.js +8 -11
- package/lib/class/session.js +14 -3
- package/lib/class/task.js +297 -145
- package/lib/class/task_service.js +933 -0
- package/lib/core/base.js +23 -1
- package/lib/core/middleware.js +2 -2
- package/lib/init/alchemy.js +210 -28
- package/lib/init/requirements.js +0 -7
- package/package.json +2 -2
package/lib/core/base.js
CHANGED
|
@@ -35,7 +35,7 @@ __Protoblast.getGroup = function getGroup(name) {
|
|
|
35
35
|
*
|
|
36
36
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
37
37
|
* @since 0.3.0
|
|
38
|
-
* @version 1.
|
|
38
|
+
* @version 1.3.17
|
|
39
39
|
*/
|
|
40
40
|
Base.constitute(function setBasicBehaviour() {
|
|
41
41
|
|
|
@@ -134,6 +134,28 @@ Base.constitute(function setBasicBehaviour() {
|
|
|
134
134
|
this.setStatic('title', this.createClassTitle(name), false);
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
// And also set the type path
|
|
138
|
+
if (!this.hasOwnProperty('type_path')) {
|
|
139
|
+
let namespace = this.namespace;
|
|
140
|
+
let parent_namespace = this.super?.namespace;
|
|
141
|
+
let type_path = this.type_name;
|
|
142
|
+
|
|
143
|
+
// Add extra identifier info if this child comes from another namespace
|
|
144
|
+
if (namespace && namespace != parent_namespace) {
|
|
145
|
+
if (parent_namespace && namespace.startsWith(parent_namespace)) {
|
|
146
|
+
namespace = namespace.after(parent_namespace);
|
|
147
|
+
|
|
148
|
+
if (namespace[0] == '.') {
|
|
149
|
+
namespace = namespace.slice(1);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
type_path = Blast.Bound.String.underscore(Blast.Bound.String.slug(namespace)) + '.' + type_path;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.setStatic('type_path', type_path, false);
|
|
157
|
+
}
|
|
158
|
+
|
|
137
159
|
// Add this class to the shared group
|
|
138
160
|
shared_group[this.type_name] = this;
|
|
139
161
|
});
|
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.3.
|
|
314
|
+
* @version 1.3.17
|
|
315
315
|
*
|
|
316
316
|
* @param {String} path
|
|
317
317
|
* @param {Object} options
|
|
@@ -418,7 +418,7 @@ Alchemy.setMethod(function minifyScript(path, options, callback) {
|
|
|
418
418
|
}
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
-
if (should_minify) {
|
|
421
|
+
if (should_minify && typeof Terser?.minify == 'function') {
|
|
422
422
|
|
|
423
423
|
// Force Blast.isNode & Blast.isBrowser to be replaced later
|
|
424
424
|
data = data.replaceAll('Blast.isNode', '__BLAST_IS_NODE');
|
package/lib/init/alchemy.js
CHANGED
|
@@ -135,7 +135,11 @@ global.Alchemy = Function.inherits('Informer', 'Alchemy', function Alchemy() {
|
|
|
135
135
|
this.startJaneway();
|
|
136
136
|
}
|
|
137
137
|
} catch (err) {
|
|
138
|
-
|
|
138
|
+
if (typeof log != 'undefined') {
|
|
139
|
+
log.warn('Failed to start Janeway:', err);
|
|
140
|
+
} else {
|
|
141
|
+
console.warn('Failed to start Janeway:', err);
|
|
142
|
+
}
|
|
139
143
|
}
|
|
140
144
|
});
|
|
141
145
|
|
|
@@ -334,7 +338,7 @@ Alchemy.setMethod(function isTooBusyForRequests() {
|
|
|
334
338
|
*
|
|
335
339
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
336
340
|
* @since 1.3.1
|
|
337
|
-
* @version 1.3.
|
|
341
|
+
* @version 1.3.18
|
|
338
342
|
*
|
|
339
343
|
* @return {Boolean}
|
|
340
344
|
*/
|
|
@@ -344,11 +348,11 @@ Alchemy.setMethod(function isTooBusyForAjax() {
|
|
|
344
348
|
return false;
|
|
345
349
|
}
|
|
346
350
|
|
|
347
|
-
let
|
|
348
|
-
|
|
349
|
-
let max_event_loop_lag = alchemy.settings.max_event_loop_lag || alchemy.settings.toobusy;
|
|
351
|
+
let max_event_loop_lag = alchemy.settings.max_event_loop_lag ?? alchemy.settings.toobusy;
|
|
350
352
|
|
|
351
353
|
if (max_event_loop_lag) {
|
|
354
|
+
let lag = this.lagInMs();
|
|
355
|
+
|
|
352
356
|
if (lag > (max_event_loop_lag * 3)) {
|
|
353
357
|
return true;
|
|
354
358
|
}
|
|
@@ -357,6 +361,83 @@ Alchemy.setMethod(function isTooBusyForAjax() {
|
|
|
357
361
|
return false;
|
|
358
362
|
});
|
|
359
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Set the maximum event loop lag before the server is considered overloaded
|
|
366
|
+
*
|
|
367
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
368
|
+
* @since 1.3.18
|
|
369
|
+
* @version 1.3.18
|
|
370
|
+
*
|
|
371
|
+
* @param {Number} max_lag
|
|
372
|
+
*/
|
|
373
|
+
Alchemy.setMethod(function setMaxEventLoopLag(max_lag) {
|
|
374
|
+
|
|
375
|
+
if (typeof max_lag != 'number' || !isFinite(max_lag)) {
|
|
376
|
+
max_lag = null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (max_lag == null) {
|
|
380
|
+
max_lag = 70;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
this.settings.max_event_loop_lag = max_lag;
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Called after the server has started
|
|
388
|
+
*
|
|
389
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
390
|
+
* @since 1.3.17
|
|
391
|
+
* @version 1.3.17
|
|
392
|
+
*/
|
|
393
|
+
Alchemy.setMethod(function afterStart() {
|
|
394
|
+
this.startTaskService();
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
let task_service_has_started = false;
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Start the task service
|
|
401
|
+
*
|
|
402
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
403
|
+
* @since 1.3.17
|
|
404
|
+
* @version 1.3.17
|
|
405
|
+
*/
|
|
406
|
+
Alchemy.setMethod(function startTaskService() {
|
|
407
|
+
|
|
408
|
+
if (task_service_has_started) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
task_service_has_started = true;
|
|
413
|
+
|
|
414
|
+
this.task_service = new Classes.Alchemy.Task.TaskService();
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Is the given PID running?
|
|
419
|
+
*
|
|
420
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
421
|
+
* @since 1.3.17
|
|
422
|
+
* @version 1.3.17
|
|
423
|
+
*
|
|
424
|
+
* @param {Number} pid
|
|
425
|
+
*
|
|
426
|
+
* @return {Boolean}
|
|
427
|
+
*/
|
|
428
|
+
Alchemy.setMethod(function isProcessRunning(pid) {
|
|
429
|
+
|
|
430
|
+
if (!pid) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
try {
|
|
435
|
+
return process.kill(pid, 0);
|
|
436
|
+
} catch (e) {
|
|
437
|
+
return e.code === 'EPERM'
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
360
441
|
/**
|
|
361
442
|
* Start janeway
|
|
362
443
|
*
|
|
@@ -441,6 +522,13 @@ Alchemy.setMethod(function startJaneway(options) {
|
|
|
441
522
|
return session_menu.remove();
|
|
442
523
|
}
|
|
443
524
|
|
|
525
|
+
session_menu.addItem({
|
|
526
|
+
title : 'Current active browser sessions:',
|
|
527
|
+
weight : Infinity,
|
|
528
|
+
}, () => {
|
|
529
|
+
console.log('All sessions:', alchemy.sessions);
|
|
530
|
+
});
|
|
531
|
+
|
|
444
532
|
this.Janeway.session_menu = session_menu;
|
|
445
533
|
}
|
|
446
534
|
|
|
@@ -522,7 +610,7 @@ Alchemy.setMethod(function printLog(level, args, options) {
|
|
|
522
610
|
*
|
|
523
611
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
524
612
|
* @since 0.4.0
|
|
525
|
-
* @version 1.3.
|
|
613
|
+
* @version 1.3.18
|
|
526
614
|
*/
|
|
527
615
|
Alchemy.setMethod(function loadSettings() {
|
|
528
616
|
|
|
@@ -660,8 +748,10 @@ Alchemy.setMethod(function loadSettings() {
|
|
|
660
748
|
settings.url = this.argv.url;
|
|
661
749
|
}
|
|
662
750
|
|
|
663
|
-
|
|
664
|
-
|
|
751
|
+
this.setUrl(settings.url);
|
|
752
|
+
|
|
753
|
+
if (settings.cookie_domain) {
|
|
754
|
+
this.setCookieDomain(settings.cookie_domain);
|
|
665
755
|
}
|
|
666
756
|
|
|
667
757
|
if (this.argv.preload) {
|
|
@@ -714,10 +804,76 @@ Alchemy.setMethod(function loadSettings() {
|
|
|
714
804
|
this.doPreload();
|
|
715
805
|
}
|
|
716
806
|
|
|
807
|
+
this.setMaxEventLoopLag(settings.max_event_loop_lag);
|
|
808
|
+
|
|
717
809
|
// Set the debug value
|
|
718
810
|
global.DEBUG = settings.debug;
|
|
719
811
|
});
|
|
720
812
|
|
|
813
|
+
/**
|
|
814
|
+
* Set the main url
|
|
815
|
+
*
|
|
816
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
817
|
+
* @since 1.3.18
|
|
818
|
+
* @version 1.3.18
|
|
819
|
+
*
|
|
820
|
+
* @param {RURL|String} value
|
|
821
|
+
*/
|
|
822
|
+
Alchemy.setMethod(function setUrl(value) {
|
|
823
|
+
|
|
824
|
+
if (value) {
|
|
825
|
+
value = ''+value;
|
|
826
|
+
|
|
827
|
+
if (value.indexOf('{') > -1) {
|
|
828
|
+
value = value.assign(this.settings);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
this.settings.url = value;
|
|
833
|
+
|
|
834
|
+
if (this.settings.cookie_domain === true || this.settings.cookie_domain == null) {
|
|
835
|
+
this.setCookieDomain(value);
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Set the cookie domain
|
|
841
|
+
*
|
|
842
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
843
|
+
* @since 1.3.18
|
|
844
|
+
* @version 1.3.18
|
|
845
|
+
*
|
|
846
|
+
* @param {RURL|String} value
|
|
847
|
+
*/
|
|
848
|
+
Alchemy.setMethod(function setCookieDomain(value) {
|
|
849
|
+
|
|
850
|
+
if (value === false) {
|
|
851
|
+
this.settings.cookie_domain = false;
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (!value) {
|
|
856
|
+
value = this.settings.url;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
if (!value) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
value = ''+value;
|
|
864
|
+
|
|
865
|
+
if (value.indexOf('{') > -1) {
|
|
866
|
+
value = value.assign(this.settings);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (value.indexOf('/') > -1) {
|
|
870
|
+
let url = RURL.parse(value);
|
|
871
|
+
value = url.hostname;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
this.settings.cookie_domain = value;
|
|
875
|
+
});
|
|
876
|
+
|
|
721
877
|
/**
|
|
722
878
|
* Set status
|
|
723
879
|
*
|
|
@@ -1051,7 +1207,7 @@ Alchemy.setMethod(function searchModule(startPath, moduleName, recurse) {
|
|
|
1051
1207
|
*
|
|
1052
1208
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1053
1209
|
* @since 0.0.1
|
|
1054
|
-
* @version 1.3.
|
|
1210
|
+
* @version 1.3.17
|
|
1055
1211
|
*
|
|
1056
1212
|
* @param {String} moduleName
|
|
1057
1213
|
* @param {Object} options
|
|
@@ -1183,10 +1339,22 @@ Alchemy.setMethod(function findModule(moduleName, options) {
|
|
|
1183
1339
|
// Make sure this does not support CJS.
|
|
1184
1340
|
// Some packages have the `module` type, but do have CJS exports too
|
|
1185
1341
|
if (!supports_cjs) {
|
|
1186
|
-
let exports = package_json.exports?.['.'];
|
|
1187
1342
|
|
|
1188
|
-
if (
|
|
1343
|
+
if (package_json.module && package_json.main) {
|
|
1189
1344
|
supports_cjs = true;
|
|
1345
|
+
} else {
|
|
1346
|
+
|
|
1347
|
+
let exports = package_json.exports?.['.'];
|
|
1348
|
+
|
|
1349
|
+
if (Array.isArray(exports)) {
|
|
1350
|
+
for (let entry of exports) {
|
|
1351
|
+
if (entry && typeof entry == 'object' && entry.require) {
|
|
1352
|
+
supports_cjs = true;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
} else if (exports?.require) {
|
|
1356
|
+
supports_cjs = true;
|
|
1357
|
+
}
|
|
1190
1358
|
}
|
|
1191
1359
|
}
|
|
1192
1360
|
|
|
@@ -1573,7 +1741,7 @@ Alchemy.setMethod(function addAppcacheEntry(entry) {
|
|
|
1573
1741
|
*
|
|
1574
1742
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1575
1743
|
* @since 1.1.0
|
|
1576
|
-
* @version 1.3.
|
|
1744
|
+
* @version 1.3.18
|
|
1577
1745
|
*
|
|
1578
1746
|
* @param {IncomingMessage} req
|
|
1579
1747
|
* @param {OutgoingMessage} res Optional
|
|
@@ -1596,8 +1764,10 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
|
|
|
1596
1764
|
return callback(null, req.body);
|
|
1597
1765
|
}
|
|
1598
1766
|
|
|
1767
|
+
let content_type = req.headers['content-type'];
|
|
1768
|
+
|
|
1599
1769
|
// Multipart data is handled by "formidable"
|
|
1600
|
-
if (
|
|
1770
|
+
if (content_type && content_type.startsWith('multipart/form-data')) {
|
|
1601
1771
|
|
|
1602
1772
|
let form = new formidable.IncomingForm({
|
|
1603
1773
|
multiples : true,
|
|
@@ -1651,7 +1821,7 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
|
|
|
1651
1821
|
}
|
|
1652
1822
|
|
|
1653
1823
|
// Regular form-encoded data
|
|
1654
|
-
if (
|
|
1824
|
+
if (content_type && content_type.indexOf('form-urlencoded') > -1) {
|
|
1655
1825
|
|
|
1656
1826
|
urlFormBody(req, res, function parsedBody(err) {
|
|
1657
1827
|
|
|
@@ -1682,25 +1852,36 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
|
|
|
1682
1852
|
// Any other encoded data (like JSON)
|
|
1683
1853
|
anyBody(req, function parsedBody(err, body) {
|
|
1684
1854
|
|
|
1685
|
-
|
|
1686
|
-
|
|
1855
|
+
function handleResponse(err, body) {
|
|
1856
|
+
if (err && req.conduit && req.conduit.aborted) {
|
|
1857
|
+
return callback(null);
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
// You can't send files using a regular post
|
|
1861
|
+
req.files = {};
|
|
1862
|
+
|
|
1863
|
+
if (err) {
|
|
1864
|
+
log.error('Error parsing body data', {err: err});
|
|
1865
|
+
req.body = {};
|
|
1866
|
+
} else {
|
|
1867
|
+
req.body = body;
|
|
1868
|
+
|
|
1869
|
+
if (conduit) {
|
|
1870
|
+
conduit.setRequestBody(body);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
callback(null, req.body);
|
|
1687
1875
|
}
|
|
1688
1876
|
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
log.error('Error parsing body data', {err: err});
|
|
1694
|
-
req.body = {};
|
|
1695
|
-
} else {
|
|
1696
|
-
req.body = body;
|
|
1697
|
-
|
|
1698
|
-
if (conduit) {
|
|
1699
|
-
conduit.setRequestBody(body);
|
|
1877
|
+
if (err?.type == 'invalid.content.type') {
|
|
1878
|
+
if (!content_type || content_type.startsWith('text/')) {
|
|
1879
|
+
textBody(req, handleResponse);
|
|
1880
|
+
return;
|
|
1700
1881
|
}
|
|
1701
1882
|
}
|
|
1702
1883
|
|
|
1703
|
-
|
|
1884
|
+
handleResponse(err, body);
|
|
1704
1885
|
});
|
|
1705
1886
|
});
|
|
1706
1887
|
|
|
@@ -2180,6 +2361,7 @@ log.todo = function todo(...args) {
|
|
|
2180
2361
|
|
|
2181
2362
|
const anyBody = alchemy.use('body/any'),
|
|
2182
2363
|
formBody = alchemy.use('body/form'),
|
|
2364
|
+
textBody = alchemy.use('body'),
|
|
2183
2365
|
formidable = alchemy.use('formidable'),
|
|
2184
2366
|
bodyParser = alchemy.use('body-parser'),
|
|
2185
2367
|
urlFormBody = bodyParser.urlencoded({extended: true});
|
package/lib/init/requirements.js
CHANGED
|
@@ -57,13 +57,6 @@ 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
|
-
|
|
62
|
-
// If the config is a number, use that as the lag threshold
|
|
63
|
-
if (typeof max_event_loop_lag === 'number') {
|
|
64
|
-
alchemy.toobusy.maxLag(max_event_loop_lag);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
60
|
/**
|
|
68
61
|
* Load Sputnik, the stage-based launcher
|
|
69
62
|
*/
|
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.18",
|
|
5
5
|
"author": "Jelle De Loecker <jelle@elevenways.be>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"alchemy",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"index.js"
|
|
46
46
|
],
|
|
47
47
|
"optionalDependencies": {
|
|
48
|
-
"janeway" : "~0.4.
|
|
48
|
+
"janeway" : "~0.4.2",
|
|
49
49
|
"less" : "~4.2.0",
|
|
50
50
|
"sass" : "~1.68.0",
|
|
51
51
|
"sass-embedded" : "~1.67.0",
|