alchemymvc 1.3.21 → 1.4.0-alpha.1

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.
Files changed (155) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +3 -3
  3. package/lib/app/behaviour/publishable_behaviour.js +5 -5
  4. package/lib/app/behaviour/revision_behaviour.js +10 -10
  5. package/lib/app/behaviour/sluggable_behaviour.js +14 -14
  6. package/lib/app/conduit/electron_conduit.js +9 -9
  7. package/lib/app/conduit/http_conduit.js +13 -13
  8. package/lib/app/conduit/loopback_conduit.js +15 -15
  9. package/lib/app/conduit/socket_conduit.js +43 -43
  10. package/lib/app/config/routes.js +26 -0
  11. package/lib/app/controller/00-default_app_controller.js +21 -0
  12. package/lib/app/controller/alchemy_info_controller.js +12 -12
  13. package/lib/app/datasource/mongo_datasource.js +16 -16
  14. package/lib/app/element/00-default_app_element.js +19 -0
  15. package/lib/app/element/time_ago.js +5 -5
  16. package/lib/app/helper/00-default_app_helper.js +11 -0
  17. package/lib/app/helper/alchemy_helper.js +22 -22
  18. package/lib/app/helper/backed_map.js +1 -1
  19. package/lib/app/helper/breadcrumb.js +10 -10
  20. package/lib/app/helper/client_collection.js +3 -3
  21. package/lib/app/helper/cron.js +29 -29
  22. package/lib/app/helper/enum_values.js +6 -6
  23. package/lib/app/helper/pagination_helper.js +36 -36
  24. package/lib/app/helper/router_helper.js +35 -35
  25. package/lib/app/helper/socket_helper.js +57 -57
  26. package/lib/app/helper/syncable.js +84 -59
  27. package/lib/app/helper_component/paginate_component.js +9 -9
  28. package/lib/app/helper_controller/component.js +1 -1
  29. package/lib/app/helper_controller/conduit.js +31 -31
  30. package/lib/app/helper_controller/controller.js +54 -39
  31. package/lib/app/helper_datasource/00-nosql_datasource.js +624 -70
  32. package/lib/app/helper_datasource/05-fallback_datasource.js +10 -10
  33. package/lib/app/helper_datasource/idb_datasource.js +6 -6
  34. package/lib/app/helper_datasource/indexed_db.js +22 -22
  35. package/lib/app/helper_datasource/remote_datasource.js +5 -5
  36. package/lib/app/helper_error/http_error.js +4 -4
  37. package/lib/app/helper_error/model_error.js +2 -2
  38. package/lib/app/helper_error/validation_error.js +12 -12
  39. package/lib/app/helper_field/00-objectid_field.js +7 -7
  40. package/lib/app/helper_field/05-string_field.js +16 -12
  41. package/lib/app/helper_field/06-text_field.js +2 -4
  42. package/lib/app/helper_field/10-number_field.js +9 -12
  43. package/lib/app/helper_field/11-date_field.js +15 -15
  44. package/lib/app/helper_field/15-local_temporal_field.js +10 -10
  45. package/lib/app/helper_field/20-decimal_field.js +8 -9
  46. package/lib/app/helper_field/belongsto_field.js +1 -1
  47. package/lib/app/helper_field/big_int_field.js +8 -8
  48. package/lib/app/helper_field/boolean_field.js +9 -11
  49. package/lib/app/helper_field/datetime_field.js +3 -3
  50. package/lib/app/helper_field/enum_field.js +13 -8
  51. package/lib/app/helper_field/fixed_decimal_field.js +6 -7
  52. package/lib/app/helper_field/geopoint_field.js +9 -10
  53. package/lib/app/helper_field/habtm_field.js +3 -3
  54. package/lib/app/helper_field/hasoneparent_field.js +1 -1
  55. package/lib/app/helper_field/html_field.js +2 -4
  56. package/lib/app/helper_field/integer_field.js +8 -11
  57. package/lib/app/helper_field/local_date_field.js +5 -5
  58. package/lib/app/helper_field/local_date_time_field.js +5 -5
  59. package/lib/app/helper_field/local_time_field.js +5 -5
  60. package/lib/app/helper_field/mixed_field.js +5 -5
  61. package/lib/app/helper_field/object_field.js +8 -8
  62. package/lib/app/helper_field/password_field.js +3 -3
  63. package/lib/app/helper_field/regexp_field.js +7 -9
  64. package/lib/app/helper_field/schema_field.js +91 -88
  65. package/lib/app/helper_field/settings_field.js +92 -0
  66. package/lib/app/helper_field/time_field.js +6 -6
  67. package/lib/app/helper_field/url_field.js +2 -4
  68. package/lib/app/helper_model/00-base_criteria.js +662 -0
  69. package/lib/app/helper_model/05-criteria_expressions.js +605 -0
  70. package/lib/app/helper_model/10-model_criteria.js +1182 -0
  71. package/lib/app/helper_model/data_provider.js +2 -2
  72. package/lib/app/helper_model/document.js +103 -92
  73. package/lib/app/helper_model/document_list.js +14 -14
  74. package/lib/app/helper_model/field_config.js +11 -11
  75. package/lib/app/helper_model/field_set.js +17 -17
  76. package/lib/app/helper_model/model.js +203 -124
  77. package/lib/app/helper_model/remote_data_provider.js +2 -2
  78. package/lib/app/helper_validator/00_validator.js +16 -16
  79. package/lib/app/helper_validator/not_empty_validator.js +9 -9
  80. package/lib/app/model/00-default_app_model.js +18 -0
  81. package/lib/app/model/05-system_model.js +27 -0
  82. package/lib/app/model/{alchemy_migration_model.js → system_migration_model.js} +4 -4
  83. package/lib/app/model/system_setting_model.js +154 -0
  84. package/lib/app/model/{alchemy_task_history_model.js → system_task_history_model.js} +7 -7
  85. package/lib/app/model/{alchemy_task_model.js → system_task_model.js} +11 -11
  86. package/lib/bootstrap.js +22 -312
  87. package/lib/class/accumulator.js +5 -5
  88. package/lib/class/behaviour.js +5 -5
  89. package/lib/class/component.js +3 -3
  90. package/lib/class/conduit.js +203 -163
  91. package/lib/class/controller.js +42 -42
  92. package/lib/class/datasource.js +74 -79
  93. package/lib/class/document.js +74 -95
  94. package/lib/class/document_list.js +5 -5
  95. package/lib/class/element.js +17 -17
  96. package/lib/class/error.js +3 -3
  97. package/lib/class/field.js +169 -91
  98. package/lib/class/field_value.js +6 -6
  99. package/lib/class/helper.js +3 -3
  100. package/lib/class/inode.js +17 -17
  101. package/lib/class/inode_dir.js +12 -12
  102. package/lib/class/inode_file.js +50 -25
  103. package/lib/class/inode_list.js +4 -4
  104. package/lib/class/migration.js +4 -4
  105. package/lib/class/model.js +182 -168
  106. package/lib/class/path_definition.js +22 -22
  107. package/lib/class/path_evaluator.js +5 -5
  108. package/lib/class/path_param_definition.js +7 -7
  109. package/lib/class/plugin.js +312 -0
  110. package/lib/class/postponement.js +29 -29
  111. package/lib/class/reciprocal.js +8 -8
  112. package/lib/class/route.js +33 -33
  113. package/lib/class/router.js +73 -73
  114. package/lib/class/schema.js +21 -21
  115. package/lib/class/schema_client.js +73 -67
  116. package/lib/class/session.js +63 -29
  117. package/lib/class/session_scene.js +4 -4
  118. package/lib/class/sitemap.js +16 -16
  119. package/lib/class/task.js +39 -39
  120. package/lib/class/task_service.js +43 -47
  121. package/lib/{init → core}/alchemy.js +413 -374
  122. package/lib/{init/functions.js → core/alchemy_functions.js} +171 -108
  123. package/lib/core/alchemy_load_functions.js +715 -0
  124. package/lib/core/base.js +50 -62
  125. package/lib/core/client_alchemy.js +144 -152
  126. package/lib/core/client_base.js +39 -52
  127. package/lib/core/discovery.js +16 -18
  128. package/lib/core/middleware.js +54 -43
  129. package/lib/core/{routing.js → prefix.js} +14 -16
  130. package/lib/core/setting.js +1684 -0
  131. package/lib/core/stage.js +758 -0
  132. package/lib/scripts/create_constants.js +119 -0
  133. package/lib/{init/languages.js → scripts/create_languages.js} +5 -5
  134. package/lib/scripts/create_settings.js +449 -0
  135. package/lib/scripts/create_shared_constants.js +95 -0
  136. package/lib/scripts/create_stages.js +55 -0
  137. package/lib/scripts/init_alchemy.js +51 -0
  138. package/lib/{init/requirements.js → scripts/preload_modules.js} +15 -2
  139. package/lib/scripts/setup_devwatch.js +238 -0
  140. package/lib/stages/00-load_core.js +342 -0
  141. package/lib/stages/05-load_app.js +57 -0
  142. package/lib/stages/10-datasource.js +61 -0
  143. package/lib/stages/15-tasks.js +27 -0
  144. package/lib/stages/20-settings.js +68 -0
  145. package/lib/stages/50-routes.js +218 -0
  146. package/lib/stages/90-server.js +347 -0
  147. package/package.json +5 -7
  148. package/lib/app/helper_model/criteria.js +0 -2294
  149. package/lib/app/helper_model/db_query.js +0 -1488
  150. package/lib/app/routes.js +0 -11
  151. package/lib/core/socket.js +0 -171
  152. package/lib/init/constants.js +0 -158
  153. package/lib/init/devwatch.js +0 -238
  154. package/lib/init/load_functions.js +0 -973
  155. package/lib/stages.js +0 -513
@@ -1,6 +1,4 @@
1
- 'use strict';
2
-
3
- var shared_objects = {},
1
+ let shared_objects = {},
4
2
  plugModules = null,
5
3
  usedModules = {},
6
4
  useErrors = {},
@@ -17,20 +15,20 @@ var shared_objects = {},
17
15
  *
18
16
  * @constructor
19
17
  *
20
- * @author Jelle De Loecker <jelle@elevenways.be>
18
+ * @author Jelle De Loecker <jelle@elevenways.be>
21
19
  * @since 0.0.1
22
20
  * @version 1.3.21
23
21
  */
24
- global.Alchemy = Function.inherits('Informer', 'Alchemy', function Alchemy() {
25
-
26
- var that = this,
27
- package_json;
22
+ global.Alchemy = Function.inherits('Alchemy.Base', function Alchemy() {
28
23
 
29
24
  // Only allow a single instance of the Alchemy class
30
25
  if (global.alchemy) {
31
26
  return global.alchemy;
32
27
  }
33
28
 
29
+ let that = this,
30
+ package_json;
31
+
34
32
  // Timestamp when alchemy started
35
33
  this.start_time = Date.now();
36
34
 
@@ -144,16 +142,22 @@ global.Alchemy = Function.inherits('Informer', 'Alchemy', function Alchemy() {
144
142
  console.warn('Failed to start Janeway:', err);
145
143
  }
146
144
  }
145
+
146
+ this.any_body = this.use('body/any');
147
+ this.text_body = this.use('body');
148
+ this.formidable = this.use('formidable');
149
+ this.body_parser = this.use('body-parser');
150
+ this.url_form_body = this.body_parser.urlencoded({extended: true});
147
151
  });
148
152
 
149
153
  /**
150
154
  * See if running janeway is allowed
151
155
  *
152
- * @author Jelle De Loecker <jelle@develry.be>
156
+ * @author Jelle De Loecker <jelle@elevenways.be>
153
157
  * @since 0.5.0
154
158
  * @version 0.5.0
155
159
  *
156
- * @type {Boolean}
160
+ * @type {boolean}
157
161
  */
158
162
  Alchemy.prepareProperty(function allow_janeway() {
159
163
 
@@ -163,7 +167,7 @@ Alchemy.prepareProperty(function allow_janeway() {
163
167
  }
164
168
 
165
169
  // You can also disable janeway in the settings
166
- if (this.settings.janeway === false) {
170
+ if (this.settings.debugging.enable_janeway === false) {
167
171
  return false;
168
172
  }
169
173
 
@@ -177,16 +181,16 @@ Alchemy.prepareProperty(function allow_janeway() {
177
181
  /**
178
182
  * Expirable object where sessions are stored
179
183
  *
180
- * @author Jelle De Loecker <jelle@develry.be>
184
+ * @author Jelle De Loecker <jelle@elevenways.be>
181
185
  * @since 0.5.0
182
186
  * @version 1.0.4
183
187
  *
184
- * @type {Develry.Cache}
188
+ * @type {Develry.Cache}
185
189
  */
186
190
  Alchemy.prepareProperty(function sessions() {
187
191
 
188
192
  var cache = this.getCache('sessions', {
189
- max_idle : alchemy.settings.session_length,
193
+ max_idle : this.settings.sessions.duration,
190
194
  max_length : Infinity
191
195
  });
192
196
 
@@ -202,11 +206,11 @@ Alchemy.prepareProperty(function sessions() {
202
206
  * Expirable object where sessions are temporarily stored
203
207
  * based on the browser fingerprints
204
208
  *
205
- * @author Jelle De Loecker <jelle@develry.be>
209
+ * @author Jelle De Loecker <jelle@elevenways.be>
206
210
  * @since 1.1.0
207
211
  * @version 1.1.0
208
212
  *
209
- * @type {Develry.Cache}
213
+ * @type {Develry.Cache}
210
214
  */
211
215
  Alchemy.prepareProperty(function fingerprints() {
212
216
 
@@ -221,27 +225,40 @@ Alchemy.prepareProperty(function fingerprints() {
221
225
  /**
222
226
  * Get or set the environment
223
227
  *
224
- * @author Jelle De Loecker <jelle@develry.be>
228
+ * @author Jelle De Loecker <jelle@elevenways.be>
225
229
  * @since 0.4.0
226
230
  * @version 0.4.0
227
231
  *
228
- * @type {String}
232
+ * @type {string}
229
233
  */
230
234
  Alchemy.setProperty(function environment() {
231
- return alchemy.settings.environment;
235
+ return this.settings.environment;
232
236
  }, function set_environment(value) {
233
- alchemy.settings.environment = String(value);
234
- return alchemy.settings.environment;
237
+ this.setSetting('environment', String(value));
238
+ return this.settings.environment;
239
+ });
240
+
241
+ /**
242
+ * Add a getter for the total amount of http requests
243
+ *
244
+ * @author Jelle De Loecker <jelle@elevenways.be>
245
+ * @since 1.3.1
246
+ * @version 1.3.1
247
+ *
248
+ * @type {number}
249
+ */
250
+ Alchemy.setProperty(function http_request_counter() {
251
+ return 0;
235
252
  });
236
253
 
237
254
  /**
238
255
  * Get the current lag in ms
239
256
  *
240
- * @author Jelle De Loecker <jelle@elevenways.be>
257
+ * @author Jelle De Loecker <jelle@elevenways.be>
241
258
  * @since 1.3.1
242
259
  * @version 1.3.1
243
260
  *
244
- * @return {Number}
261
+ * @return {number}
245
262
  */
246
263
  Alchemy.setMethod(function lagInMs() {
247
264
  return this.toobusy.lag();
@@ -250,11 +267,11 @@ Alchemy.setMethod(function lagInMs() {
250
267
  /**
251
268
  * Get the system load as percentage points
252
269
  *
253
- * @author Jelle De Loecker <jelle@elevenways.be>
270
+ * @author Jelle De Loecker <jelle@elevenways.be>
254
271
  * @since 1.3.1
255
272
  * @version 1.3.1
256
273
  *
257
- * @return {Number}
274
+ * @return {number}
258
275
  */
259
276
  Alchemy.setMethod(function systemLoad() {
260
277
 
@@ -269,7 +286,7 @@ Alchemy.setMethod(function systemLoad() {
269
286
  * Register an extra toobusy check method.
270
287
  * These will be checked after event loop lag & system load are deemed OK.
271
288
  *
272
- * @author Jelle De Loecker <jelle@elevenways.be>
289
+ * @author Jelle De Loecker <jelle@elevenways.be>
273
290
  * @since 1.3.2
274
291
  * @version 1.3.2
275
292
  */
@@ -280,11 +297,11 @@ Alchemy.setMethod(function addToobusyCheck(fnc) {
280
297
  /**
281
298
  * Is the server currently too busy, overloaded in some way?
282
299
  *
283
- * @author Jelle De Loecker <jelle@elevenways.be>
300
+ * @author Jelle De Loecker <jelle@elevenways.be>
284
301
  * @since 1.3.1
285
302
  * @version 1.3.2
286
303
  *
287
- * @return {Boolean}
304
+ * @return {boolean}
288
305
  */
289
306
  Alchemy.setMethod(function isTooBusy() {
290
307
 
@@ -293,9 +310,11 @@ Alchemy.setMethod(function isTooBusy() {
293
310
  return true;
294
311
  }
295
312
 
296
- if (this.settings.max_system_load > 0) {
313
+ const max_system_load = this.settings.performance.max_system_load;
314
+
315
+ if (max_system_load > 0) {
297
316
  // Then check the load average
298
- if (this.systemLoad() > this.settings.max_system_load) {
317
+ if (this.systemLoad() > max_system_load) {
299
318
  return true;
300
319
  }
301
320
  }
@@ -308,7 +327,7 @@ Alchemy.setMethod(function isTooBusy() {
308
327
  return true;
309
328
  }
310
329
  } catch (err) {
311
- alchemy.distinctProblem('error-extra-toobusy-check', 'Extra toobusy check failed', {error: err});
330
+ this.distinctProblem('error-extra-toobusy-check', 'Extra toobusy check failed', {error: err});
312
331
  }
313
332
  }
314
333
  }
@@ -319,11 +338,11 @@ Alchemy.setMethod(function isTooBusy() {
319
338
  /**
320
339
  * Is the server too busy for requests?
321
340
  *
322
- * @author Jelle De Loecker <jelle@elevenways.be>
341
+ * @author Jelle De Loecker <jelle@elevenways.be>
323
342
  * @since 1.3.1
324
343
  * @version 1.3.1
325
344
  *
326
- * @return {Boolean}
345
+ * @return {boolean}
327
346
  */
328
347
  Alchemy.setMethod(function isTooBusyForRequests() {
329
348
 
@@ -339,11 +358,11 @@ Alchemy.setMethod(function isTooBusyForRequests() {
339
358
  /**
340
359
  * Is the server too busy for AJAX too?
341
360
  *
342
- * @author Jelle De Loecker <jelle@elevenways.be>
361
+ * @author Jelle De Loecker <jelle@elevenways.be>
343
362
  * @since 1.3.1
344
363
  * @version 1.3.18
345
364
  *
346
- * @return {Boolean}
365
+ * @return {boolean}
347
366
  */
348
367
  Alchemy.setMethod(function isTooBusyForAjax() {
349
368
 
@@ -351,7 +370,7 @@ Alchemy.setMethod(function isTooBusyForAjax() {
351
370
  return false;
352
371
  }
353
372
 
354
- let max_event_loop_lag = alchemy.settings.max_event_loop_lag ?? alchemy.settings.toobusy;
373
+ let max_event_loop_lag = this.settings.performance.max_event_loop_lag ?? this.settings.performance.toobusy;
355
374
 
356
375
  if (max_event_loop_lag) {
357
376
  let lag = this.lagInMs();
@@ -367,11 +386,11 @@ Alchemy.setMethod(function isTooBusyForAjax() {
367
386
  /**
368
387
  * Set the maximum event loop lag before the server is considered overloaded
369
388
  *
370
- * @author Jelle De Loecker <jelle@elevenways.be>
389
+ * @author Jelle De Loecker <jelle@elevenways.be>
371
390
  * @since 1.3.18
372
391
  * @version 1.3.18
373
392
  *
374
- * @param {Number} max_lag
393
+ * @param {number} max_lag
375
394
  */
376
395
  Alchemy.setMethod(function setMaxEventLoopLag(max_lag) {
377
396
 
@@ -383,50 +402,30 @@ Alchemy.setMethod(function setMaxEventLoopLag(max_lag) {
383
402
  max_lag = 70;
384
403
  }
385
404
 
386
- this.settings.max_event_loop_lag = max_lag;
405
+ this.setSetting('performance.max_event_loop_lag', max_lag);
387
406
  });
388
407
 
389
408
  /**
390
409
  * Called after the server has started
391
410
  *
392
- * @author Jelle De Loecker <jelle@elevenways.be>
411
+ * @author Jelle De Loecker <jelle@elevenways.be>
393
412
  * @since 1.3.17
394
- * @version 1.3.17
413
+ * @version 1.4.0
395
414
  */
396
415
  Alchemy.setMethod(function afterStart() {
397
- this.startTaskService();
398
- });
399
-
400
- let task_service_has_started = false;
401
-
402
- /**
403
- * Start the task service
404
- *
405
- * @author Jelle De Loecker <jelle@elevenways.be>
406
- * @since 1.3.17
407
- * @version 1.3.17
408
- */
409
- Alchemy.setMethod(function startTaskService() {
410
-
411
- if (task_service_has_started) {
412
- return;
413
- }
414
-
415
- task_service_has_started = true;
416
-
417
- this.task_service = new Classes.Alchemy.Task.TaskService();
416
+
418
417
  });
419
418
 
420
419
  /**
421
420
  * Is the given PID running?
422
421
  *
423
- * @author Jelle De Loecker <jelle@elevenways.be>
422
+ * @author Jelle De Loecker <jelle@elevenways.be>
424
423
  * @since 1.3.17
425
424
  * @version 1.3.17
426
425
  *
427
- * @param {Number} pid
426
+ * @param {number} pid
428
427
  *
429
- * @return {Boolean}
428
+ * @return {boolean}
430
429
  */
431
430
  Alchemy.setMethod(function isProcessRunning(pid) {
432
431
 
@@ -444,9 +443,9 @@ Alchemy.setMethod(function isProcessRunning(pid) {
444
443
  /**
445
444
  * Start janeway
446
445
  *
447
- * @author Jelle De Loecker <jelle@develry.be>
446
+ * @author Jelle De Loecker <jelle@elevenways.be>
448
447
  * @since 0.5.0
449
- * @version 1.3.1
448
+ * @version 1.4.0
450
449
  *
451
450
  * @param {Object} options
452
451
  */
@@ -506,67 +505,27 @@ Alchemy.setMethod(function startJaneway(options) {
506
505
 
507
506
  this.Janeway.started = true;
508
507
  this.Janeway.start(options);
509
-
510
- if (this.settings.title) {
511
- let title = this.settings.title;
512
-
513
- if (this.settings.titleized) {
514
- title = 'Alchemy: ' + title;
515
- }
516
-
517
- this.Janeway.setTitle(title);
518
- }
519
-
520
- if (this.settings.session_menu) {
521
-
522
- let session_menu = this.Janeway.addIndicator('⌨ ');
523
-
524
- if (!session_menu.addItem) {
525
- return session_menu.remove();
526
- }
527
-
528
- session_menu.addItem({
529
- title : 'Current active browser sessions:',
530
- weight : Infinity,
531
- }, () => {
532
- console.log('All sessions:', alchemy.sessions);
533
- });
534
-
535
- this.Janeway.session_menu = session_menu;
536
- }
537
-
538
- if (this.settings.lag_menu) {
539
- let lag_menu = this.Janeway.addIndicator('0 ms');
540
-
541
- setInterval(() => {
542
- lag_menu.setIcon(this.lagInMs() + ' ms');
543
- this.Janeway.redraw();
544
- }, 900).unref();
545
-
546
- this.Janeway.lag_menu = lag_menu;
547
- }
548
-
549
508
  });
550
509
 
551
510
  /**
552
511
  * Log messages of level 5 (info)
553
512
  *
554
- * @author Jelle De Loecker <jelle@develry.be>
513
+ * @author Jelle De Loecker <jelle@elevenways.be>
555
514
  * @since 0.0.1
556
515
  * @version 0.4.0
557
516
  */
558
517
  Alchemy.setMethod(function log(...args) {
559
- return alchemy.printLog(5, args, {level: 3});
518
+ return this.printLog(5, args, {level: 3});
560
519
  });
561
520
 
562
521
  /**
563
522
  * Actually print a log message
564
523
  *
565
- * @author Jelle De Loecker <jelle@develry.be>
524
+ * @author Jelle De Loecker <jelle@elevenways.be>
566
525
  * @since 0.4.0
567
526
  * @version 1.1.0
568
527
  *
569
- * @param {Number} level
528
+ * @param {number} level
570
529
  * @param {Array} args
571
530
  * @param {Object} options
572
531
  */
@@ -575,7 +534,7 @@ Alchemy.setMethod(function printLog(level, args, options) {
575
534
  var type,
576
535
  line;
577
536
 
578
- if (this.settings.silent) {
537
+ if (this.settings.debugging.silent) {
579
538
  return;
580
539
  }
581
540
 
@@ -609,49 +568,112 @@ Alchemy.setMethod(function printLog(level, args, options) {
609
568
  });
610
569
 
611
570
  /**
612
- * Load the settings
571
+ * Set a setting value (without triggering actions)
572
+ *
573
+ * @author Jelle De Loecker <jelle@elevenways.be>
574
+ * @since 1.4.0
575
+ * @version 1.4.0
576
+ *
577
+ * @param {string} path The path of the setting (without system prefix)
578
+ * @param {Mixed} value
579
+ */
580
+ Alchemy.setMethod(function setSetting(path, value) {
581
+ this.system_settings.setPathSilently(path, value);
582
+
583
+ if (this.started) {
584
+ this.settings = this.system_settings.toObject();
585
+ }
586
+ });
587
+
588
+ /**
589
+ * Get a setting value
590
+ *
591
+ * @author Jelle De Loecker <jelle@elevenways.be>
592
+ * @since 1.4.0
593
+ * @version 1.4.0
594
+ *
595
+ * @param {string} path The path of the setting (without system prefix)
596
+ */
597
+ Alchemy.setMethod(function getSetting(path) {
598
+
599
+ let value = this.getSettingValueInstance(path);
600
+
601
+ if (value) {
602
+ return value.get();
603
+ }
604
+ });
605
+
606
+ /**
607
+ * Get a setting value instance
608
+ *
609
+ * @author Jelle De Loecker <jelle@elevenways.be>
610
+ * @since 1.4.0
611
+ * @version 1.4.0
612
+ *
613
+ * @param {string} path The path of the setting (without system prefix)
614
+ */
615
+ Alchemy.setMethod(function getSettingValueInstance(path) {
616
+ return this.system_settings.getPath(path);
617
+ });
618
+
619
+ /**
620
+ * Execute the action linked to a setting
621
+ *
622
+ * @author Jelle De Loecker <jelle@elevenways.be>
623
+ * @since 1.4.0
624
+ * @version 1.4.0
625
+ *
626
+ * @param {string} path The path of the setting (without system prefix)
627
+ */
628
+ Alchemy.setMethod(function executeSetting(path) {
629
+
630
+ let value = this.getSettingValueInstance(path);
631
+
632
+ if (value) {
633
+ return value.executeAction();
634
+ }
635
+ });
636
+
637
+ /**
638
+ * Load the initial hard-coded settings
613
639
  *
614
- * @author Jelle De Loecker <jelle@develry.be>
640
+ * @author Jelle De Loecker <jelle@elevenways.be>
615
641
  * @since 0.4.0
616
- * @version 1.3.18
642
+ * @version 1.4.0
617
643
  */
618
644
  Alchemy.setMethod(function loadSettings() {
619
645
 
620
- var default_path,
621
- port_error,
622
- local_path,
623
- env_config,
624
- env_path,
625
- settings,
626
- local,
627
- env;
628
-
629
646
  if (this.settings) {
630
647
  return;
631
648
  }
632
649
 
633
- // Create the settings object
634
- this.settings = settings = {};
650
+ // Create the settings scope
651
+ const system = Classes.Alchemy.Setting.SYSTEM.generateValue();
652
+
653
+ this.system_settings = system;
654
+ let settings = this.settings = system.toProxyObject();
635
655
 
636
656
  // Generate the path to the default settings file
637
- default_path = libpath.resolve(PATH_ROOT, 'app', 'config', 'default');
657
+ let default_path = libpath.resolve(PATH_ROOT, 'app', 'config', 'default');
638
658
 
639
659
  // Get default settings
640
660
  try {
641
- Object.assign(settings, require(default_path));
661
+ let value = require(default_path);
662
+ system.setDefaultValue(value);
642
663
  } catch (err) {
643
- settings.no_default_file = default_path;
664
+ this.setSetting('no_default_file', default_path);
644
665
  }
645
666
 
646
667
  // Generate the path to the local settings file
647
- local_path = libpath.resolve(PATH_ROOT, 'app', 'config', 'local');
668
+ let local_path = libpath.resolve(PATH_ROOT, 'app', 'config', 'local'),
669
+ local;
648
670
 
649
671
  // Get the local settings
650
672
  try {
651
673
  local = require(local_path);
652
674
  } catch(err) {
653
675
  local = {};
654
- settings.no_local_file = local_path;
676
+ this.setSetting('no_local_file', local_path);
655
677
  }
656
678
 
657
679
  // Default to the 'dev' environment
@@ -664,7 +686,7 @@ Alchemy.setMethod(function loadSettings() {
664
686
  }
665
687
  }
666
688
 
667
- env = this.argv.env || this.argv.environment;
689
+ let env = this.argv.env || this.argv.environment;
668
690
 
669
691
  if (env) {
670
692
  local.environment = env;
@@ -672,30 +694,30 @@ Alchemy.setMethod(function loadSettings() {
672
694
  }
673
695
 
674
696
  // Generate the path to the environment settings file
675
- env_path = libpath.resolve(PATH_APP, 'config', local.environment, 'config');
697
+ let env_path = libpath.resolve(PATH_APP, 'config', local.environment, 'config');
676
698
 
677
699
  // Get the config
678
700
  try {
679
- env_config = require(env_path);
701
+ let value = require(env_path);
702
+ system.setValueSilently(value);
680
703
  } catch(err) {
681
- env_config = {};
682
- settings.no_env_file = env_path;
704
+ this.setSetting('no_env_file', env_path);
683
705
  }
684
706
 
685
- // Merge all the settings in order: default - environment - local
686
- Object.merge(settings, env_config, local);
707
+ // And now overlay the final local settings
708
+ system.setValueSilently(local);
687
709
 
688
710
  if (!settings.name) {
689
- settings.name = this.package.name;
711
+ this.setSetting('name', this.package.name);
690
712
  }
691
713
 
692
- if (settings.title == null) {
714
+ if (this.getSetting('frontend.title') == null) {
693
715
  if (this.package.title) {
694
716
  // Allow users to set the title in their package file
695
- settings.title = this.package.title;
717
+ this.setSetting('frontend.title', this.package.title);
696
718
  } else if (settings.name) {
697
- settings.title = settings.name.replace(/-/g, ' ').titleize();
698
- settings.titleized = true;
719
+ let title = settings.name.replace(/-/g, ' ').titleize();
720
+ this.setSetting('frontend.title', title);
699
721
  }
700
722
  }
701
723
 
@@ -704,41 +726,44 @@ Alchemy.setMethod(function loadSettings() {
704
726
 
705
727
  if (port) {
706
728
  this.printLog(this.INFO, ['Using port setting from argument:', port]);
707
- settings.port = port;
729
+ this.setSetting('network.port', port);
708
730
  } else {
709
- this.argv.socket = this.argv.port;
710
- this.argv.port = null;
731
+ this.setSetting('network.socket', this.argv.port);
732
+ this.setSetting('network.port', null);
711
733
  }
712
734
  }
713
735
 
714
736
  if (this.argv.socket) {
715
- settings.port = false;
716
- settings.socket = this.argv.socket;
737
+ this.setSetting('network.port', false);
738
+ this.setSetting('network.socket', this.argv.socket);
717
739
 
718
740
  let stat;
719
741
 
720
742
  try {
721
- stat = fs.statSync(settings.socket);
743
+ stat = fs.statSync(this.argv.socket);
722
744
  } catch (err) {
723
745
  // Ignore if it doesn't exist yet
724
746
  }
725
747
 
726
748
  if (stat && stat.isDirectory()) {
727
- settings.socket = libpath.resolve(settings.socket, settings.name + '.alchemy.sock');
749
+ let socket = libpath.resolve(this.argv.socket, settings.name + '.alchemy.sock');
750
+ this.setSetting('network.socket', socket);
728
751
  }
729
752
 
730
- this.printLog(this.INFO, ['Using socket setting from argument:', settings.socket]);
753
+ this.printLog(this.INFO, ['Using socket setting from argument:', settings.network.socket]);
731
754
  }
732
755
 
733
- if (!settings.port && settings.port !== false) {
734
- settings.port = 3000;
756
+ if (!settings.network.port && settings.network.port !== false) {
757
+ this.setSetting('network.port', 3000);
735
758
  }
736
759
 
737
- if (settings.port > 49151) {
760
+ let port = this.getSetting('network.port');
761
+
762
+ if (port > 49151) {
738
763
  port_error = 'Could not use port number ' + String(port).bold.red + ' because ';
739
764
 
740
765
  // Make sure the port is valid
741
- if (settings.port > 65535) {
766
+ if (port > 65535) {
742
767
  this.printLog(this.FATAL, [port_error + 'there is no port higher than 65535. Please use ports below 49151.']);
743
768
  } else {
744
769
  this.printLog(this.FATAL, [port_error + 'it\'s an ephemeral port. Please use ports below 49151.']);
@@ -748,27 +773,23 @@ Alchemy.setMethod(function loadSettings() {
748
773
  }
749
774
 
750
775
  if (this.argv.url) {
751
- settings.url = this.argv.url;
776
+ this.setUrl(this.argv.url);
777
+ } else {
778
+ this.setUrl(settings.network.main_url);
752
779
  }
753
780
 
754
- this.setUrl(settings.url);
755
-
756
- if (settings.cookie_domain) {
757
- this.setCookieDomain(settings.cookie_domain);
781
+ if (settings.frontend.cookies.domain) {
782
+ this.setCookieDomain(settings.frontend.cookies.domain);
758
783
  }
759
784
 
760
785
  if (this.argv.preload) {
761
786
  settings.preload = this.argv.preload;
762
787
 
763
- if (Array.isArray(settings.preload)) {
788
+ if (Array.isArray(settings.performance.preload)) {
764
789
  settings.preload = settings.preload.last();
765
790
  }
766
791
  }
767
792
 
768
- if (settings.preload == 'false') {
769
- settings.preload = false;
770
- }
771
-
772
793
  let key,
773
794
  val;
774
795
 
@@ -781,46 +802,39 @@ Alchemy.setMethod(function loadSettings() {
781
802
  val = this.argv[key];
782
803
  key = key.after('override-');
783
804
 
784
- if (!settings[key] || typeof settings[key] != 'object') {
785
- settings[key] = val;
786
- } else {
787
- Object.merge(settings[key], val);
788
- }
789
- }
805
+ this.setSetting(key, val);
790
806
 
791
- if (settings.debug) {
807
+ // if (!settings[key] || typeof settings[key] != 'object') {
808
+ // settings[key] = val;
809
+ // } else {
810
+ // Object.merge(settings[key], val);
811
+ // }
812
+ }
792
813
 
793
- if (settings.source_map === 'false') {
794
- settings.source_map = false;
814
+ if (settings.debugging.debug) {
815
+ if (settings.debugging.create_source_map == null) {
816
+ this.setSetting('debugging.create_source_map', true);
795
817
  }
796
-
797
- if (settings.source_map == null || settings.source_map) {
798
- settings.source_map = true;
799
- } else {
800
- settings.source_map = false;
801
- }
802
- } else {
803
- settings.source_map = false;
804
818
  }
805
819
 
806
- if (settings.preload) {
820
+ if (settings.performance.preload) {
807
821
  this.doPreload();
808
822
  }
809
823
 
810
- this.setMaxEventLoopLag(settings.max_event_loop_lag);
824
+ this.setMaxEventLoopLag(settings.performance.max_event_loop_lag);
811
825
 
812
826
  // Set the debug value
813
- global.DEBUG = settings.debug;
827
+ global.DEBUG = settings.debugging.debug;
814
828
  });
815
829
 
816
830
  /**
817
831
  * Set the main url
818
832
  *
819
- * @author Jelle De Loecker <jelle@elevenways.be>
833
+ * @author Jelle De Loecker <jelle@elevenways.be>
820
834
  * @since 1.3.18
821
835
  * @version 1.3.18
822
836
  *
823
- * @param {RURL|String} value
837
+ * @param {RURL|string} value
824
838
  */
825
839
  Alchemy.setMethod(function setUrl(value) {
826
840
 
@@ -832,9 +846,9 @@ Alchemy.setMethod(function setUrl(value) {
832
846
  }
833
847
  }
834
848
 
835
- this.settings.url = value;
849
+ this.setSetting('network.main_url', value);
836
850
 
837
- if (this.settings.cookie_domain === true || this.settings.cookie_domain == null) {
851
+ if (this.settings.frontend.cookies.domain === true || this.settings.frontend.cookies.domain == null) {
838
852
  this.setCookieDomain(value);
839
853
  }
840
854
  });
@@ -842,21 +856,21 @@ Alchemy.setMethod(function setUrl(value) {
842
856
  /**
843
857
  * Set the cookie domain
844
858
  *
845
- * @author Jelle De Loecker <jelle@elevenways.be>
859
+ * @author Jelle De Loecker <jelle@elevenways.be>
846
860
  * @since 1.3.18
847
861
  * @version 1.3.18
848
862
  *
849
- * @param {RURL|String} value
863
+ * @param {RURL|string} value
850
864
  */
851
865
  Alchemy.setMethod(function setCookieDomain(value) {
852
866
 
853
867
  if (value === false) {
854
- this.settings.cookie_domain = false;
868
+ this.setSetting('frontend.cookies.domain', false);
855
869
  return;
856
870
  }
857
871
 
858
872
  if (!value) {
859
- value = this.settings.url;
873
+ value = this.settings.network.main_url;
860
874
  }
861
875
 
862
876
  if (!value) {
@@ -874,13 +888,13 @@ Alchemy.setMethod(function setCookieDomain(value) {
874
888
  value = url.hostname;
875
889
  }
876
890
 
877
- this.settings.cookie_domain = value;
891
+ this.setSetting('frontend.cookies.domain', value);
878
892
  });
879
893
 
880
894
  /**
881
895
  * Set status
882
896
  *
883
- * @author Jelle De Loecker <jelle@develry.be>
897
+ * @author Jelle De Loecker <jelle@elevenways.be>
884
898
  * @since 0.4.1
885
899
  * @version 0.4.1
886
900
  */
@@ -891,9 +905,9 @@ Alchemy.setMethod(function setStatus(name, value) {
891
905
  /**
892
906
  * Execute the function when alchemy is ready
893
907
  *
894
- * @author Jelle De Loecker <jelle@develry.be>
908
+ * @author Jelle De Loecker <jelle@elevenways.be>
895
909
  * @since 0.0.1
896
- * @version 1.1.2
910
+ * @version 1.4.0
897
911
  *
898
912
  * @param {Function} callback The function to execute
899
913
  *
@@ -901,20 +915,17 @@ Alchemy.setMethod(function setStatus(name, value) {
901
915
  */
902
916
  Alchemy.setMethod(function ready(callback) {
903
917
 
904
- var that = this,
905
- pledge = new Pledge();
918
+ let pledge = new Pledge();
906
919
 
907
920
  pledge.done(callback);
908
921
 
909
- if (!this.sputnik) {
910
- Blast.loaded(function hasLoaded() {
911
- pledge.resolve(that.ready());
912
- });
913
- } else {
914
- this.sputnik.after(['start_server', 'datasources', 'listening'], function afterReady() {
915
- pledge.resolve();
916
- });
917
- }
922
+ STAGES.afterStages([
923
+ 'server.start',
924
+ 'datasource',
925
+ 'server.listening',
926
+ ], function hasLoaded() {
927
+ pledge.resolve();
928
+ });
918
929
 
919
930
  return pledge;
920
931
  });
@@ -922,9 +933,9 @@ Alchemy.setMethod(function ready(callback) {
922
933
  /**
923
934
  * Preload the client-side stuff
924
935
  *
925
- * @author Jelle De Loecker <jelle@elevenways.be>
936
+ * @author Jelle De Loecker <jelle@elevenways.be>
926
937
  * @since 1.1.2
927
- * @version 1.3.3
938
+ * @version 1.3.22
928
939
  */
929
940
  Alchemy.setMethod(async function doPreload() {
930
941
 
@@ -932,10 +943,10 @@ Alchemy.setMethod(async function doPreload() {
932
943
 
933
944
  let url;
934
945
 
935
- if (this.settings.url) {
936
- url = this.settings.url;
937
- } else if (this.settings.port) {
938
- url = 'http://localhost:' + this.settings.port;
946
+ if (this.settings.network.main_url) {
947
+ url = this.settings.network.main_url;
948
+ } else if (this.settings.network.port) {
949
+ url = 'http://localhost:' + this.settings.network.port;
939
950
  }
940
951
 
941
952
  if (url) {
@@ -951,8 +962,9 @@ Alchemy.setMethod(async function doPreload() {
951
962
 
952
963
  Blast.getClientPath({
953
964
  modify_prototypes : true,
954
- create_source_map : alchemy.settings.source_map,
955
- enable_coverage : !!global.__coverage__
965
+ create_source_map : this.settings.debugging.create_source_map,
966
+ enable_coverage : !!global.__coverage__,
967
+ debug : this.settings.debugging.debug,
956
968
  });
957
969
  }
958
970
  });
@@ -961,11 +973,11 @@ Alchemy.setMethod(async function doPreload() {
961
973
  * Resolve the provided arguments to a useable path string.
962
974
  * Only used strings, discards objects.
963
975
  *
964
- * @author Jelle De Loecker <jelle@develry.be>
976
+ * @author Jelle De Loecker <jelle@elevenways.be>
965
977
  * @since 0.0.1
966
978
  * @version 0.4.0
967
979
  *
968
- * @param {String} path_to_dirs The path containing the dirs to load
980
+ * @param {string} path_to_dirs The path containing the dirs to load
969
981
  */
970
982
  Alchemy.setMethod(function pathResolve(...path_to_dirs) {
971
983
 
@@ -994,16 +1006,16 @@ Alchemy.setMethod(function pathResolve(...path_to_dirs) {
994
1006
  /**
995
1007
  * A wrapper function for requiring modules
996
1008
  *
997
- * @author Jelle De Loecker <jelle@develry.be>
1009
+ * @author Jelle De Loecker <jelle@elevenways.be>
998
1010
  * @since 0.0.1
999
1011
  * @version 1.0.0
1000
1012
  *
1001
- * @param {String} module_name The name/path of the module to load
1002
- * @param {String} register_as Cache the module under this name
1003
- * @param {Object} options Extra options
1004
- * @param {Boolean} options.force Force a new requirement and do not cache
1013
+ * @param {string} module_name The name/path of the module to load
1014
+ * @param {string} register_as Cache the module under this name
1015
+ * @param {Object} options Extra options
1016
+ * @param {boolean} options.force Force a new requirement and do not cache
1005
1017
  *
1006
- * @return {Object} The required module
1018
+ * @return {Object} The required module
1007
1019
  */
1008
1020
  Alchemy.setMethod(function use(module_name, register_as, options) {
1009
1021
 
@@ -1087,15 +1099,15 @@ Alchemy.setMethod(function use(module_name, register_as, options) {
1087
1099
  /**
1088
1100
  * Look for a module by traversing the filesystem
1089
1101
  *
1090
- * @author Jelle De Loecker <jelle@develry.be>
1102
+ * @author Jelle De Loecker <jelle@elevenways.be>
1091
1103
  * @since 0.0.1
1092
- * @version 0.4.0
1104
+ * @version 1.4.0
1093
1105
  *
1094
- * @param {String} startPath The path to originate the search from
1095
- * @param {String} moduleName
1096
- * @param {Number} recurse
1106
+ * @param {string} startPath The path to originate the search from
1107
+ * @param {string} moduleName
1108
+ * @param {number} recurse
1097
1109
  *
1098
- * @return {String}
1110
+ * @return {string}
1099
1111
  */
1100
1112
  Alchemy.setMethod(function searchModule(startPath, moduleName, recurse) {
1101
1113
 
@@ -1108,54 +1120,41 @@ Alchemy.setMethod(function searchModule(startPath, moduleName, recurse) {
1108
1120
  key,
1109
1121
  i;
1110
1122
 
1111
- // Don't do this search if it hasn't been enabled
1112
- // The new npm flat structure makes this an expensive thing to do
1113
- if (!this.settings.search_for_modules) {
1123
+ // Set recurse to 3, so this is the first and last call
1124
+ recurse = 3;
1114
1125
 
1115
- // Set recurse to 3, so this is the first and last call
1116
- recurse = 3;
1126
+ // Only add 2 folder to look through,
1127
+ // the alchemymvc node_modules folder
1128
+ // and the base node_modules folder
1129
+ moduledirs = ['..', libpath.resolve(startPath, 'node_modules', 'alchemymvc')];
1117
1130
 
1118
- // Only add 2 folder to look through,
1119
- // the alchemymvc node_modules folder
1120
- // and the base node_modules folder
1121
- moduledirs = ['..', libpath.resolve(startPath, 'node_modules', 'alchemymvc')];
1131
+ // Add plugin folders
1132
+ if (!plugModules) {
1133
+ path = libpath.resolve(PATH_ROOT, 'node_modules');
1122
1134
 
1123
- // Add plugin folders
1124
- if (!plugModules) {
1125
- path = libpath.resolve(PATH_ROOT, 'node_modules');
1135
+ if (fs.existsSync(path)) {
1126
1136
 
1127
- if (fs.existsSync(path)) {
1137
+ // Get all the entries in the main modules folder
1138
+ entries = fs.readdirSync(libpath.resolve(PATH_ROOT, 'node_modules'));
1128
1139
 
1129
- // Get all the entries in the main modules folder
1130
- entries = fs.readdirSync(libpath.resolve(PATH_ROOT, 'node_modules'));
1140
+ // Initiate the plugin modules variables
1141
+ plugModules = [];
1131
1142
 
1132
- // Initiate the plugin modules variables
1133
- plugModules = [];
1134
1143
 
1144
+ for (i = 0; i < entries.length; i++) {
1145
+ temp = entries[i];
1135
1146
 
1136
- for (i = 0; i < entries.length; i++) {
1137
- temp = entries[i];
1138
-
1139
- if (temp.startsWith('alchemy-')) {
1140
- plugModules.push(libpath.resolve(PATH_ROOT, 'node_modules', temp));
1141
- }
1147
+ if (temp.startsWith('alchemy-')) {
1148
+ plugModules.push(libpath.resolve(PATH_ROOT, 'node_modules', temp));
1142
1149
  }
1143
- } else {
1144
- plugModules = [];
1145
1150
  }
1151
+ } else {
1152
+ plugModules = [];
1146
1153
  }
1147
-
1148
- for (i = 0; i < plugModules.length; i++) {
1149
- moduledirs.push(plugModules[i]);
1150
- }
1151
-
1152
- } else if (!searchModule.have_warned) {
1153
- searchModule.have_warned = true;
1154
- log.warn('The "search_for_modules" config has been enabled!');
1155
1154
  }
1156
1155
 
1157
- if (!recurse) {
1158
- recurse = 1;
1156
+ for (i = 0; i < plugModules.length; i++) {
1157
+ moduledirs.push(plugModules[i]);
1159
1158
  }
1160
1159
 
1161
1160
  nmPath = libpath.resolve(startPath, 'node_modules');
@@ -1208,11 +1207,11 @@ Alchemy.setMethod(function searchModule(startPath, moduleName, recurse) {
1208
1207
  /**
1209
1208
  * Find a module in our customized file structure
1210
1209
  *
1211
- * @author Jelle De Loecker <jelle@develry.be>
1210
+ * @author Jelle De Loecker <jelle@elevenways.be>
1212
1211
  * @since 0.0.1
1213
1212
  * @version 1.3.17
1214
1213
  *
1215
- * @param {String} moduleName
1214
+ * @param {string} moduleName
1216
1215
  * @param {Object} options
1217
1216
  *
1218
1217
  * @return {Object}
@@ -1362,7 +1361,7 @@ Alchemy.setMethod(function findModule(moduleName, options) {
1362
1361
  }
1363
1362
 
1364
1363
  if (!supports_cjs) {
1365
- module = doImport(module_path)
1364
+ module = import(module_path)
1366
1365
  } else {
1367
1366
  module = require(module_path);
1368
1367
  }
@@ -1398,14 +1397,14 @@ Alchemy.setMethod(function findModule(moduleName, options) {
1398
1397
  /**
1399
1398
  * Create a shared object
1400
1399
  *
1401
- * @author Jelle De Loecker <jelle@develry.be>
1400
+ * @author Jelle De Loecker <jelle@elevenways.be>
1402
1401
  * @since 0.0.1
1403
1402
  * @version 0.4.0
1404
1403
  *
1405
- * @param {String} name The name of the object to get
1406
- * @param {String} type The type to create (array or object)
1404
+ * @param {string} name The name of the object to get
1405
+ * @param {string} type The type to create (array or object)
1407
1406
  *
1408
- * @return {Object|Array}
1407
+ * @return {Object|Array}
1409
1408
  */
1410
1409
  Alchemy.setMethod(function shared(name, type, value) {
1411
1410
 
@@ -1430,11 +1429,11 @@ Alchemy.setMethod(function shared(name, type, value) {
1430
1429
  * Get an object id,
1431
1430
  * return undefined if no valid data was given (instead of throwing an error)
1432
1431
  *
1433
- * @author Jelle De Loecker <jelle@develry.be>
1432
+ * @author Jelle De Loecker <jelle@elevenways.be>
1434
1433
  * @since 0.0.1
1435
1434
  * @version 1.3.16
1436
1435
  *
1437
- * @param {String|ObjectId} obj
1436
+ * @param {string|ObjectId} obj
1438
1437
  *
1439
1438
  * @return {ObjectId|undefined}
1440
1439
  */
@@ -1443,7 +1442,7 @@ Alchemy.setMethod(function castObjectId(obj) {
1443
1442
  let type = typeof obj;
1444
1443
 
1445
1444
  if (type === 'string' && obj.isObjectId()) {
1446
- return alchemy.ObjectId(obj);
1445
+ return this.ObjectId(obj);
1447
1446
  }
1448
1447
 
1449
1448
  if (obj && type === 'object') {
@@ -1460,11 +1459,11 @@ Alchemy.setMethod(function castObjectId(obj) {
1460
1459
  /**
1461
1460
  * See if the given object is a stream
1462
1461
  *
1463
- * @author Jelle De Loecker <jelle@develry.be>
1462
+ * @author Jelle De Loecker <jelle@elevenways.be>
1464
1463
  * @since 0.2.0
1465
1464
  * @version 1.0.5
1466
1465
  *
1467
- * @return {Boolean}
1466
+ * @return {boolean}
1468
1467
  */
1469
1468
  Alchemy.setMethod(function isStream(obj) {
1470
1469
  return obj && (typeof obj._read == 'function' || typeof obj._write == 'function') && typeof obj.on === 'function';
@@ -1473,12 +1472,12 @@ Alchemy.setMethod(function isStream(obj) {
1473
1472
  /**
1474
1473
  * Get or create a new cache instance
1475
1474
  *
1476
- * @author Jelle De Loecker <jelle@develry.be>
1475
+ * @author Jelle De Loecker <jelle@elevenways.be>
1477
1476
  * @since 1.0.0
1478
1477
  * @version 1.3.0
1479
1478
  *
1480
- * @param {String} name
1481
- * @param {Number|Object} options
1479
+ * @param {string} name
1480
+ * @param {number|Object} options
1482
1481
  *
1483
1482
  * @return {Develry.Cache}
1484
1483
  */
@@ -1520,15 +1519,15 @@ Alchemy.setMethod(function getCache(name, options) {
1520
1519
  /**
1521
1520
  * Get a route
1522
1521
  *
1523
- * @author Jelle De Loecker <jelle@elevenways.be>
1524
- * @since 1.1.3
1525
- * @version 1.3.0
1522
+ * @author Jelle De Loecker <jelle@elevenways.be>
1523
+ * @since 1.1.3
1524
+ * @version 1.3.0
1526
1525
  *
1527
- * @param {String} href The href or route name
1528
- * @param {Object} parameters Route parameters
1529
- * @param {Object} options
1526
+ * @param {string} href The href or route name
1527
+ * @param {Object} parameters Route parameters
1528
+ * @param {Object} options
1530
1529
  *
1531
- * @return {String}
1530
+ * @return {string}
1532
1531
  */
1533
1532
  Alchemy.setMethod(function routeUrl(href, parameters, options) {
1534
1533
 
@@ -1548,7 +1547,7 @@ Alchemy.setMethod(function routeUrl(href, parameters, options) {
1548
1547
  /**
1549
1548
  * Get paths that should be cached by the client
1550
1549
  *
1551
- * @author Jelle De Loecker <jelle@develry.be>
1550
+ * @author Jelle De Loecker <jelle@elevenways.be>
1552
1551
  * @since 1.0.7
1553
1552
  * @version 1.0.7
1554
1553
  *
@@ -1660,7 +1659,7 @@ Alchemy.decorateMethod(Blast.Decorators.memoize(), function getAppcachePaths() {
1660
1659
  /**
1661
1660
  * Get the appcache manifest text
1662
1661
  *
1663
- * @author Jelle De Loecker <jelle@develry.be>
1662
+ * @author Jelle De Loecker <jelle@elevenways.be>
1664
1663
  * @since 1.0.7
1665
1664
  * @version 1.0.7
1666
1665
  *
@@ -1712,11 +1711,11 @@ Alchemy.decorateMethod(Blast.Decorators.memoize(), function getAppcacheManifest(
1712
1711
  /**
1713
1712
  * Add an appcache entry
1714
1713
  *
1715
- * @author Jelle De Loecker <jelle@develry.be>
1714
+ * @author Jelle De Loecker <jelle@elevenways.be>
1716
1715
  * @since 1.0.7
1717
1716
  * @version 1.0.7
1718
1717
  *
1719
- * @param {String|Object}
1718
+ * @param {string|Object}
1720
1719
  */
1721
1720
  Alchemy.setMethod(function addAppcacheEntry(entry) {
1722
1721
 
@@ -1742,7 +1741,7 @@ Alchemy.setMethod(function addAppcacheEntry(entry) {
1742
1741
  /**
1743
1742
  * Get the body of an IncomingMessage
1744
1743
  *
1745
- * @author Jelle De Loecker <jelle@develry.be>
1744
+ * @author Jelle De Loecker <jelle@elevenways.be>
1746
1745
  * @since 1.1.0
1747
1746
  * @version 1.3.18
1748
1747
  *
@@ -1767,14 +1766,16 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
1767
1766
  return callback(null, req.body);
1768
1767
  }
1769
1768
 
1769
+ const that = this;
1770
+
1770
1771
  let content_type = req.headers['content-type'];
1771
1772
 
1772
1773
  // Multipart data is handled by "formidable"
1773
1774
  if (content_type && content_type.startsWith('multipart/form-data')) {
1774
1775
 
1775
- let form = new formidable.IncomingForm({
1776
+ let form = new this.formidable.IncomingForm({
1776
1777
  multiples : true,
1777
- hashAlgorithm : alchemy.settings.file_hash_algorithm || 'sha1',
1778
+ hashAlgorithm : this.settings.data_management.file_hash_algorithm || 'sha1',
1778
1779
  });
1779
1780
 
1780
1781
  form.parse(req, function parsedMultipart(err, form_fields, form_files) {
@@ -1826,7 +1827,7 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
1826
1827
  // Regular form-encoded data
1827
1828
  if (content_type && content_type.indexOf('form-urlencoded') > -1) {
1828
1829
 
1829
- urlFormBody(req, res, function parsedBody(err) {
1830
+ this.url_form_body(req, res, function parsedBody(err) {
1830
1831
 
1831
1832
  if (err && req.conduit && req.conduit.aborted) {
1832
1833
  return callback(null);
@@ -1853,7 +1854,7 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
1853
1854
  }
1854
1855
 
1855
1856
  // Any other encoded data (like JSON)
1856
- anyBody(req, function parsedBody(err, body) {
1857
+ this.any_body(req, function parsedBody(err, body) {
1857
1858
 
1858
1859
  function handleResponse(err, body) {
1859
1860
  if (err && req.conduit && req.conduit.aborted) {
@@ -1879,7 +1880,7 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
1879
1880
 
1880
1881
  if (err?.type == 'invalid.content.type') {
1881
1882
  if (!content_type || content_type.startsWith('text/')) {
1882
- textBody(req, handleResponse);
1883
+ that.text_body(req, handleResponse);
1883
1884
  return;
1884
1885
  }
1885
1886
  }
@@ -1891,7 +1892,7 @@ Alchemy.setMethod(function parseRequestBody(req, res, callback) {
1891
1892
  /**
1892
1893
  * Undo formidable's new array handling
1893
1894
  *
1894
- * @author Jelle De Loecker <jelle@elevenways.be>
1895
+ * @author Jelle De Loecker <jelle@elevenways.be>
1895
1896
  * @since 1.3.16
1896
1897
  * @version 1.3.16
1897
1898
  *
@@ -1927,7 +1928,7 @@ function undoFormidableArray(data) {
1927
1928
  /**
1928
1929
  * Export all data
1929
1930
  *
1930
- * @author Jelle De Loecker <jelle@develry.be>
1931
+ * @author Jelle De Loecker <jelle@elevenways.be>
1931
1932
  * @since 1.0.5
1932
1933
  * @version 1.0.5
1933
1934
  *
@@ -1945,7 +1946,7 @@ Alchemy.setMethod(function createExportStream(options) {
1945
1946
  /**
1946
1947
  * Export all data to stream
1947
1948
  *
1948
- * @author Jelle De Loecker <jelle@develry.be>
1949
+ * @author Jelle De Loecker <jelle@elevenways.be>
1949
1950
  * @since 1.0.5
1950
1951
  * @version 1.0.5
1951
1952
  *
@@ -1956,7 +1957,7 @@ Alchemy.setMethod(function createExportStream(options) {
1956
1957
  */
1957
1958
  Alchemy.setMethod(function exportToStream(output, options) {
1958
1959
 
1959
- if (!alchemy.isStream(output)) {
1960
+ if (!this.isStream(output)) {
1960
1961
  if (!options) {
1961
1962
  options = output;
1962
1963
  output = null;
@@ -1998,7 +1999,7 @@ Alchemy.setMethod(function exportToStream(output, options) {
1998
1999
  /**
1999
2000
  * Import from a stream
2000
2001
  *
2001
- * @author Jelle De Loecker <jelle@develry.be>
2002
+ * @author Jelle De Loecker <jelle@elevenways.be>
2002
2003
  * @since 1.0.5
2003
2004
  * @version 1.0.5
2004
2005
  *
@@ -2009,7 +2010,7 @@ Alchemy.setMethod(function exportToStream(output, options) {
2009
2010
  */
2010
2011
  Alchemy.setMethod(function importFromStream(input, options) {
2011
2012
 
2012
- if (!alchemy.isStream(input)) {
2013
+ if (!this.isStream(input)) {
2013
2014
  if (!options) {
2014
2015
  options = input;
2015
2016
  input = null;
@@ -2180,7 +2181,7 @@ Alchemy.setMethod(function importFromStream(input, options) {
2180
2181
  /**
2181
2182
  * Create a new schema
2182
2183
  *
2183
- * @author Jelle De Loecker <jelle@elevenways.be>
2184
+ * @author Jelle De Loecker <jelle@elevenways.be>
2184
2185
  * @since 1.2.1
2185
2186
  * @version 1.2.1
2186
2187
  *
@@ -2194,14 +2195,14 @@ Alchemy.setMethod(function createSchema(parent) {
2194
2195
  /**
2195
2196
  * Get a client-side model
2196
2197
  *
2197
- * @author Jelle De Loecker <jelle@elevenways.be>
2198
+ * @author Jelle De Loecker <jelle@elevenways.be>
2198
2199
  * @since 1.2.4
2199
2200
  * @version 1.2.4
2200
2201
  *
2201
- * @param {String} name
2202
- * @param {Object} options
2202
+ * @param {string} name
2203
+ * @param {Object} options
2203
2204
  *
2204
- * @return {Model}
2205
+ * @return {Model}
2205
2206
  */
2206
2207
  Alchemy.setMethod(function getClientModel(name, init, options) {
2207
2208
  return Classes.Alchemy.Client.Base.prototype.getModel.call(this, name, init, options);
@@ -2212,12 +2213,12 @@ let error_handler_count = 0;
2212
2213
  /**
2213
2214
  * Register an error handler
2214
2215
  *
2215
- * @author Jelle De Loecker <jelle@elevenways.be>
2216
+ * @author Jelle De Loecker <jelle@elevenways.be>
2216
2217
  * @since 1.3.11
2217
2218
  * @version 1.3.11
2218
2219
  *
2219
- * @param {Function} callback
2220
- * @param {Number} weight
2220
+ * @param {Function} callback
2221
+ * @param {number} weight
2221
2222
  */
2222
2223
  Alchemy.setMethod(function registerErrorHandler(callback, weight) {
2223
2224
 
@@ -2245,12 +2246,12 @@ Alchemy.setMethod(function registerErrorHandler(callback, weight) {
2245
2246
  /**
2246
2247
  * Process the given error
2247
2248
  *
2248
- * @author Jelle De Loecker <jelle@elevenways.be>
2249
+ * @author Jelle De Loecker <jelle@elevenways.be>
2249
2250
  * @since 1.3.11
2250
2251
  * @version 1.3.11
2251
2252
  *
2252
- * @param {Error} error
2253
- * @param {Object} info
2253
+ * @param {Error} error
2254
+ * @param {Object} info
2254
2255
  */
2255
2256
  Alchemy.setMethod(async function registerError(error, info = {}) {
2256
2257
 
@@ -2283,88 +2284,126 @@ Alchemy.setMethod(async function registerError(error, info = {}) {
2283
2284
  return handle_count;
2284
2285
  });
2285
2286
 
2287
+ let starting;
2288
+
2286
2289
  /**
2287
- * Initialize the error handler (if it's enabled)
2290
+ * Only start the server after this function has been called
2288
2291
  *
2289
- * @author Jelle De Loecker <jelle@elevenways.be>
2290
- * @since 1.3.11
2291
- * @version 1.3.11
2292
+ * @author Jelle De Loecker <jelle@elevenways.be>
2293
+ * @since 0.0.1
2294
+ * @version 1.1.5
2295
+ *
2296
+ * @param {Function} callback The optional callback after alchemy is ready
2297
+ *
2298
+ * @return {Pledge}
2292
2299
  */
2293
- function initializeErrorHandler() {
2300
+ Alchemy.setMethod(function start(options, callback) {
2301
+
2302
+ if (typeof options == 'function') {
2303
+ callback = options;
2304
+ options = {};
2305
+ }
2306
+
2307
+ if (!options) {
2308
+ options = {};
2309
+ }
2294
2310
 
2295
- const config = this.settings.errors ?? {};
2311
+ // If silent is true, don't output anything
2312
+ if (options.silent == true) {
2313
+ this.setSetting('debugging.silent', true);
2314
+ }
2296
2315
 
2297
- if (config.handle_uncaught) {
2298
- this.registerErrorHandler((error, info) => {
2316
+ if (starting) {
2317
+ return this.ready(callback);
2318
+ }
2299
2319
 
2300
- let message;
2320
+ if (Object.size(Blast.loaded_versions) > 1) {
2321
+ log.warn(Object.size(Blast.loaded_versions), 'versions of Protoblast have been loaded, this can cause problems!');
2322
+ }
2301
2323
 
2302
- if (info?.promise) {
2303
- message = 'Unhandled promise rejection';
2304
- } else {
2305
- message = 'Uncaught exception';
2306
- }
2324
+ if (options.client_mode) {
2325
+ this.setSetting('client_mode', true);
2326
+ } else {
2327
+ if (alchemy.settings.no_default_file) {
2328
+ log.warn('Could not find default settings file at "' + alchemy.settings.no_default_file + '.js"');
2329
+ }
2307
2330
 
2308
- alchemy.printLog('error', [message, String(error), error], {err: error, level: -2});
2309
- }, 1);
2331
+ if (alchemy.settings.no_local_file) {
2332
+ log.warn('Could not find local settings file');
2333
+ }
2334
+
2335
+ if (alchemy.settings.no_env_file) {
2336
+ log.warn('Could not find environment settings file at "' + alchemy.settings.no_env_file + '.js"');
2337
+ }
2310
2338
  }
2311
- }
2312
2339
 
2313
- /**
2314
- * The alchemy global, where everything will be stored
2315
- *
2316
- * @author Jelle De Loecker <jelle@develry.be>
2317
- * @since 0.0.1
2318
- * @version 0.4.0
2319
- *
2320
- * @type {Alchemy}
2321
- */
2322
- DEFINE('alchemy', new Alchemy());
2340
+ // Indicate the server is starting
2341
+ starting = true;
2342
+
2343
+ // Start the stages
2344
+ STAGES.launch([
2345
+ 'load_app',
2346
+ 'datasource',
2347
+ 'tasks',
2348
+ 'settings',
2349
+ 'routes',
2350
+ 'server',
2351
+ ]);
2352
+
2353
+ // Make sure Blast has executed everything that's still waiting
2354
+ Blast.doLoaded();
2355
+
2356
+ // Call the `afterStart` method
2357
+ this.ready(() => this.afterStart());
2358
+
2359
+ // Schedule the callback
2360
+ return this.ready(callback);
2361
+ });
2323
2362
 
2324
2363
  /**
2325
- * Define the log function
2364
+ * Stop the server
2326
2365
  *
2327
- * @author Jelle De Loecker <jelle@develry.be>
2328
- * @since 0.0.1
2329
- * @version 0.4.0
2366
+ * @author Jelle De Loecker <jelle@elevenways.be>
2367
+ * @since 1.0.3
2368
+ * @version 1.0.3
2330
2369
  *
2331
- * @type {Function}
2370
+ * @param {Function} callback The optional callback after alchemy has stopped
2332
2371
  */
2333
- DEFINE('log', alchemy.log);
2372
+ Alchemy.setMethod(function stop(callback) {
2334
2373
 
2335
- for (let key in alchemy.Janeway.LEVELS) {
2336
- let name = key.toLowerCase();
2337
- let val = alchemy.Janeway.LEVELS[key];
2374
+ this.server.close(function closed() {
2338
2375
 
2339
- log[name] = function(...args) {
2340
- return alchemy.printLog(val, args, {level: 2});
2341
- };
2342
- }
2376
+ if (callback) {
2377
+ callback();
2378
+ }
2343
2379
 
2344
- log.warn = log.warning;
2380
+ });
2381
+
2382
+ });
2345
2383
 
2346
2384
  /**
2347
- * Define the todo log function
2348
- *
2349
- * @author Jelle De Loecker <jelle@develry.be>
2350
- * @since 0.2.0
2351
- * @version 0.4.0
2385
+ * Initialize the error handler (if it's enabled)
2352
2386
  *
2353
- * @type {Function}
2387
+ * @author Jelle De Loecker <jelle@elevenways.be>
2388
+ * @since 1.3.11
2389
+ * @version 1.4.0
2354
2390
  */
2355
- log.todo = function todo(...args) {
2391
+ function initializeErrorHandler() {
2356
2392
 
2357
- var options = {
2358
- gutter: alchemy.Janeway.esc(91) + '\u2620 Todo:' + alchemy.Janeway.esc(39),
2359
- level: 2
2360
- };
2393
+ if (!this.settings.errors.handle_uncaught) {
2394
+ return;
2395
+ }
2396
+
2397
+ this.registerErrorHandler((error, info) => {
2398
+
2399
+ let message;
2361
2400
 
2362
- return alchemy.printLog(alchemy.TODO, args, options);
2363
- };
2401
+ if (info?.promise) {
2402
+ message = 'Unhandled promise rejection';
2403
+ } else {
2404
+ message = 'Uncaught exception';
2405
+ }
2364
2406
 
2365
- const anyBody = alchemy.use('body/any'),
2366
- formBody = alchemy.use('body/form'),
2367
- textBody = alchemy.use('body'),
2368
- formidable = alchemy.use('formidable'),
2369
- bodyParser = alchemy.use('body-parser'),
2370
- urlFormBody = bodyParser.urlencoded({extended: true});
2407
+ this.printLog('error', [message, String(error), error], {err: error, level: -2});
2408
+ }, 1);
2409
+ }