adapt-authoring-core 2.5.0 → 3.0.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.
- package/.github/workflows/releases.yml +9 -24
- package/conf/config.schema.json +16 -0
- package/conf/deprecated-lang.json +4 -0
- package/conf/deprecated-logger.json +7 -0
- package/docs/configure-environment.md +78 -0
- package/docs/developer-workflow.md +649 -0
- package/docs/error-handling.md +49 -0
- package/docs/plugins/configuration.js +75 -0
- package/docs/plugins/configuration.md +14 -0
- package/docs/plugins/errors.js +22 -0
- package/docs/plugins/errorsref.md +9 -0
- package/errors/errors.json +87 -0
- package/errors/node-core.json +39 -0
- package/index.js +5 -0
- package/lib/AbstractModule.js +3 -13
- package/lib/AdaptError.js +57 -0
- package/lib/App.js +66 -51
- package/lib/Config.js +226 -0
- package/lib/DataCache.js +6 -0
- package/lib/DependencyLoader.js +46 -103
- package/lib/Errors.js +50 -0
- package/lib/Hook.js +2 -3
- package/lib/Lang.js +126 -0
- package/lib/Logger.js +149 -0
- package/lib/utils/getArgs.js +4 -6
- package/migrations/3.0.0-conf-migrate-lang-config.js +7 -0
- package/migrations/3.0.0-conf-migrate-logger-config.js +9 -0
- package/package.json +8 -25
- package/tests/AbstractModule.spec.js +4 -54
- package/tests/AdaptError.spec.js +62 -0
- package/tests/Config.spec.js +122 -0
- package/tests/DataCache.spec.js +84 -1
- package/tests/DependencyLoader.spec.js +61 -146
- package/tests/Errors.spec.js +91 -0
- package/tests/Lang.spec.js +116 -0
- package/tests/Logger.spec.js +187 -0
- package/tests/utils-getArgs.spec.js +2 -8
- package/tests/App.spec.js +0 -160
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
|
|
4
|
+
export default class Configuration {
|
|
5
|
+
async run () {
|
|
6
|
+
const schemas = this.loadSchemas()
|
|
7
|
+
this.contents = Object.keys(schemas).sort()
|
|
8
|
+
this.manualFile = 'configuration.md'
|
|
9
|
+
this.replace = {
|
|
10
|
+
CODE_EXAMPLE: this.generateCodeExample(schemas),
|
|
11
|
+
LIST: this.generateList(schemas)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
loadSchemas () {
|
|
16
|
+
const schemas = {}
|
|
17
|
+
Object.values(this.app.dependencies).forEach(c => {
|
|
18
|
+
const confDir = path.join(c.rootDir, 'conf')
|
|
19
|
+
try {
|
|
20
|
+
schemas[c.name] = JSON.parse(fs.readFileSync(path.join(confDir, 'config.schema.json')))
|
|
21
|
+
} catch (e) {}
|
|
22
|
+
})
|
|
23
|
+
return schemas
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
generateCodeExample (schemas) {
|
|
27
|
+
let output = '```javascript\nexport default {\n'
|
|
28
|
+
this.contents.forEach((name) => {
|
|
29
|
+
const schema = schemas[name]
|
|
30
|
+
output += ` '${name}': {\n`
|
|
31
|
+
Object.entries(schema.properties).forEach(([attr, config]) => {
|
|
32
|
+
const required = schema.required && schema.required.includes(attr)
|
|
33
|
+
if (config.description) output += ` // ${config.description}\n`
|
|
34
|
+
output += ` ${attr}: ${this.defaultToMd(config)}, // ${config.type}, ${required ? 'required' : 'optional'}\n`
|
|
35
|
+
})
|
|
36
|
+
output += ' },\n'
|
|
37
|
+
})
|
|
38
|
+
output += '};\n```'
|
|
39
|
+
return output
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
generateList (schemas) {
|
|
43
|
+
let output = ''
|
|
44
|
+
|
|
45
|
+
this.contents.forEach(dep => {
|
|
46
|
+
const schema = schemas[dep]
|
|
47
|
+
output += `<h3 id="${dep}" class="dep">${dep}</h3>\n\n`
|
|
48
|
+
output += '<div class="options">\n'
|
|
49
|
+
Object.entries(schema.properties).forEach(([attr, config]) => {
|
|
50
|
+
const required = schema.required && schema.required.includes(attr)
|
|
51
|
+
output += '<div class="attribute">\n'
|
|
52
|
+
output += `<div class="title"><span class="main">${attr}</span> (${config.type || ''}, ${required ? 'required' : 'optional'})</div>\n`
|
|
53
|
+
output += '<div class="inner">\n'
|
|
54
|
+
output += `<div class="description">${config.description}</div>\n`
|
|
55
|
+
if (!required) {
|
|
56
|
+
output += `<div class="default"><span class="label">Default</span>: <pre class="no-bg">${this.defaultToMd(config)}</pre></div>\n`
|
|
57
|
+
}
|
|
58
|
+
output += '</div>\n'
|
|
59
|
+
output += '</div>\n'
|
|
60
|
+
})
|
|
61
|
+
output += '</div>'
|
|
62
|
+
output += '\n\n'
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
return output
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns a string formatted nicely for markdown
|
|
70
|
+
*/
|
|
71
|
+
defaultToMd (config) {
|
|
72
|
+
const s = JSON.stringify(config.default, null, 2)
|
|
73
|
+
return s?.length < 75 ? s : s?.replaceAll('\n', '\n ')
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Configuration reference
|
|
2
|
+
This page lists all configuration options supported by the [core bundle](coremodules) of Adapt authoring modules. For details on how to set up your configuration, including using environment variables, see [Configuring your environment](configure-environment).
|
|
3
|
+
|
|
4
|
+
{{{TABLE_OF_CONTENTS}}}
|
|
5
|
+
|
|
6
|
+
## Quick reference
|
|
7
|
+
See below for an overview of all available configuration options.
|
|
8
|
+
|
|
9
|
+
{{{CODE_EXAMPLE}}}
|
|
10
|
+
|
|
11
|
+
## Complete reference
|
|
12
|
+
See below for a full list of available configuration options.
|
|
13
|
+
|
|
14
|
+
{{{LIST}}}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export default class Errors {
|
|
2
|
+
async run () {
|
|
3
|
+
this.manualFile = 'errorsref.md'
|
|
4
|
+
this.contents = Object.keys(this.app.errors)
|
|
5
|
+
this.replace = { ERRORS: this.generateMd() }
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
generateMd () {
|
|
9
|
+
return Object.keys(this.app.errors).reduce((md, k) => {
|
|
10
|
+
const e = this.app.errors[k]
|
|
11
|
+
return `${md}\n| \`${e.code}\` | ${e.meta.description} | ${e.statusCode} | <ul>${this.dataToMd(e.meta.data)}</ul> |`
|
|
12
|
+
}, '| Error code | Description | HTTP status code | Supplemental data |\n| - | - | :-: | - |')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
dataToMd (data) {
|
|
16
|
+
if (!data) return ''
|
|
17
|
+
return Object.entries(data).reduce((acc, [k, v]) => {
|
|
18
|
+
const nested = typeof v === 'object' ? this.dataToMd(v) : v
|
|
19
|
+
return `${acc}<li>\`${k}\`: ${nested}</li>`
|
|
20
|
+
}, '')
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Errors Reference
|
|
2
|
+
|
|
3
|
+
This page documents all errors which are likely to be thrown in the system, along with the appropriate HTTP status code and any supplemental data which is stored with the error.
|
|
4
|
+
|
|
5
|
+
Supplemental data can be used at the point that errors are translated to provide more context to a specific error. All data stored with an error can be assumed to be a primitive type for easy printing.
|
|
6
|
+
|
|
7
|
+
{{{TABLE_OF_CONTENTS}}}
|
|
8
|
+
|
|
9
|
+
{{{ERRORS}}}
|
package/errors/errors.json
CHANGED
|
@@ -1,4 +1,84 @@
|
|
|
1
1
|
{
|
|
2
|
+
"FILE_SYNTAX_ERROR": {
|
|
3
|
+
"data": {
|
|
4
|
+
"path": "Path to the invalid file",
|
|
5
|
+
"message": "The error message"
|
|
6
|
+
},
|
|
7
|
+
"description": "File contains a syntax error",
|
|
8
|
+
"statusCode": 500
|
|
9
|
+
},
|
|
10
|
+
"DEP_ALREADY_LOADED": {
|
|
11
|
+
"data": { "module": "The module name" },
|
|
12
|
+
"description": "Module has already been loaded",
|
|
13
|
+
"statusCode": 500
|
|
14
|
+
},
|
|
15
|
+
"DEP_FAILED": {
|
|
16
|
+
"data": { "module": "The module name" },
|
|
17
|
+
"description": "Required dependency failed to load",
|
|
18
|
+
"statusCode": 500,
|
|
19
|
+
"isFatal": true
|
|
20
|
+
},
|
|
21
|
+
"DEP_INVALID_EXPORT": {
|
|
22
|
+
"data": { "module": "The module name" },
|
|
23
|
+
"description": "Module must export a class as its default export",
|
|
24
|
+
"statusCode": 500
|
|
25
|
+
},
|
|
26
|
+
"DEP_MISSING": {
|
|
27
|
+
"data": { "module": "The module name" },
|
|
28
|
+
"description": "Required module is not installed",
|
|
29
|
+
"statusCode": 500,
|
|
30
|
+
"isFatal": true
|
|
31
|
+
},
|
|
32
|
+
"DEP_NO_ONREADY": {
|
|
33
|
+
"data": { "module": "The module name" },
|
|
34
|
+
"description": "Module must define an onReady function",
|
|
35
|
+
"statusCode": 500
|
|
36
|
+
},
|
|
37
|
+
"DEP_TIMEOUT": {
|
|
38
|
+
"data": { "module": "The module name", "timeout": "The timeout in ms" },
|
|
39
|
+
"description": "Module load exceeded timeout",
|
|
40
|
+
"statusCode": 500
|
|
41
|
+
},
|
|
42
|
+
"FUNC_DISABLED": {
|
|
43
|
+
"data": {
|
|
44
|
+
"name": "The name of the function"
|
|
45
|
+
},
|
|
46
|
+
"description": "Function has been disabled",
|
|
47
|
+
"statusCode": 500
|
|
48
|
+
},
|
|
49
|
+
"FUNC_NOT_OVERRIDDEN": {
|
|
50
|
+
"data": {
|
|
51
|
+
"name": "The name of the function"
|
|
52
|
+
},
|
|
53
|
+
"description": "Function must be overridden in child class",
|
|
54
|
+
"statusCode": 500
|
|
55
|
+
},
|
|
56
|
+
"INVALID_PARAMS": {
|
|
57
|
+
"data": {
|
|
58
|
+
"params": "The invalid params"
|
|
59
|
+
},
|
|
60
|
+
"description": "Invalid parameters have been provided",
|
|
61
|
+
"statusCode": 400
|
|
62
|
+
},
|
|
63
|
+
"LOAD_ERROR": {
|
|
64
|
+
"description": "Config failed to load",
|
|
65
|
+
"statusCode": 500
|
|
66
|
+
},
|
|
67
|
+
"NOT_FOUND": {
|
|
68
|
+
"data": {
|
|
69
|
+
"id": "An identifier for the missing item",
|
|
70
|
+
"type": "Type of the missing item"
|
|
71
|
+
},
|
|
72
|
+
"description": "Requested item could not be found",
|
|
73
|
+
"statusCode": 404
|
|
74
|
+
},
|
|
75
|
+
"SERVER_ERROR": {
|
|
76
|
+
"description": "Generic server error",
|
|
77
|
+
"statusCode": 500,
|
|
78
|
+
"data": {
|
|
79
|
+
"error": "The original error"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
2
82
|
"SPAWN": {
|
|
3
83
|
"data": {
|
|
4
84
|
"cmd": "The command",
|
|
@@ -7,5 +87,12 @@
|
|
|
7
87
|
},
|
|
8
88
|
"description": "Error occurred spawning command",
|
|
9
89
|
"statusCode": 500
|
|
90
|
+
},
|
|
91
|
+
"UNKNOWN_LANG": {
|
|
92
|
+
"data": {
|
|
93
|
+
"lang": "language"
|
|
94
|
+
},
|
|
95
|
+
"description": "unknown language",
|
|
96
|
+
"statusCode": 400
|
|
10
97
|
}
|
|
11
98
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"EACCES": {
|
|
3
|
+
"description": "An attempt was made to access a file in a way forbidden by its file access permissions",
|
|
4
|
+
"statusCode": 500
|
|
5
|
+
},
|
|
6
|
+
"EADDRINUSE": {
|
|
7
|
+
"description": "An attempt to bind a server to a local address failed due to another server on the local system already occupying that address",
|
|
8
|
+
"statusCode": 500
|
|
9
|
+
},
|
|
10
|
+
"ECONNREFUSED": {
|
|
11
|
+
"description": "No connection could be made because the target machine actively refused it",
|
|
12
|
+
"statusCode": 500
|
|
13
|
+
},
|
|
14
|
+
"EEXIST": {
|
|
15
|
+
"description": "An existing file was the target of an operation that required that the target not exist",
|
|
16
|
+
"statusCode": 500,
|
|
17
|
+
"data": {
|
|
18
|
+
"path": "Path to target file or directory"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"ENOENT": {
|
|
22
|
+
"description": "No entity (file or directory) could be found by the given path",
|
|
23
|
+
"statusCode": 500,
|
|
24
|
+
"data": {
|
|
25
|
+
"path": "Path to target file or directory"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"ENOTEMPTY": {
|
|
29
|
+
"description": "A directory with entries was the target of an operation that requires an empty directory",
|
|
30
|
+
"statusCode": 500,
|
|
31
|
+
"data": {
|
|
32
|
+
"path": "Path to target file or directory"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"MODULE_NOT_FOUND": {
|
|
36
|
+
"description": "A module file could not be resolved while attempting a require() or import operation",
|
|
37
|
+
"statusCode": 500
|
|
38
|
+
}
|
|
39
|
+
}
|
package/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export { default as AbstractModule } from './lib/AbstractModule.js'
|
|
2
|
+
export { default as AdaptError } from './lib/AdaptError.js'
|
|
2
3
|
export { default as App } from './lib/App.js'
|
|
4
|
+
export { default as Config } from './lib/Config.js'
|
|
3
5
|
export { default as DataCache } from './lib/DataCache.js'
|
|
4
6
|
export { default as DependencyLoader } from './lib/DependencyLoader.js'
|
|
7
|
+
export { default as Errors } from './lib/Errors.js'
|
|
5
8
|
export { default as Hook } from './lib/Hook.js'
|
|
9
|
+
export { default as Lang } from './lib/Lang.js'
|
|
10
|
+
export { default as Logger } from './lib/Logger.js'
|
|
6
11
|
export { metadataFileName, packageFileName, isObject, getArgs, spawn, readJson, writeJson, toBoolean, ensureDir, escapeRegExp, stringifyValues, loadDependencyFiles } from './lib/Utils.js'
|
package/lib/AbstractModule.js
CHANGED
|
@@ -105,26 +105,16 @@ class AbstractModule {
|
|
|
105
105
|
* @return {*}
|
|
106
106
|
*/
|
|
107
107
|
getConfig (key) {
|
|
108
|
-
|
|
109
|
-
return this.app.config.get(`${this.name}.${key}`)
|
|
110
|
-
} catch (e) {
|
|
111
|
-
return undefined
|
|
112
|
-
}
|
|
108
|
+
return this.app.config?.get(`${this.name}.${key}`)
|
|
113
109
|
}
|
|
114
110
|
|
|
115
111
|
/**
|
|
116
|
-
* Log a message using the Logger
|
|
112
|
+
* Log a message using the Logger
|
|
117
113
|
* @param {String} level Log level of message
|
|
118
114
|
* @param {...*} rest Arguments to log
|
|
119
115
|
*/
|
|
120
116
|
log (level, ...rest) {
|
|
121
|
-
|
|
122
|
-
if (!this.app.logger || (instance && instance.name !== this.app.logger.name)) return false
|
|
123
|
-
this.app.dependencyloader.moduleLoadedHook.untap(_log)
|
|
124
|
-
this.app.logger.log(level, this.name.replace(/^adapt-authoring-/, ''), ...rest)
|
|
125
|
-
return true
|
|
126
|
-
}
|
|
127
|
-
if (!_log()) this.app.dependencyloader.moduleLoadedHook.tap(_log)
|
|
117
|
+
this.app.logger?.log(level, this.name.replace(/^adapt-authoring-/, ''), ...rest)
|
|
128
118
|
}
|
|
129
119
|
}
|
|
130
120
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A generic error class for use in Adapt applications
|
|
3
|
+
* @memberof core
|
|
4
|
+
*/
|
|
5
|
+
class AdaptError extends Error {
|
|
6
|
+
/**
|
|
7
|
+
* @constructor
|
|
8
|
+
* @param {string} code The human-readable error code
|
|
9
|
+
* @param {number} statusCode The HTTP status code
|
|
10
|
+
* @param {object} metadata Metadata describing the error
|
|
11
|
+
*/
|
|
12
|
+
constructor (code, statusCode = 500, metadata = {}) {
|
|
13
|
+
super(code)
|
|
14
|
+
/**
|
|
15
|
+
* The error code
|
|
16
|
+
* @type {String}
|
|
17
|
+
*/
|
|
18
|
+
this.code = code
|
|
19
|
+
/**
|
|
20
|
+
* The HTTP status code
|
|
21
|
+
* @type {String}
|
|
22
|
+
*/
|
|
23
|
+
this.statusCode = statusCode
|
|
24
|
+
/**
|
|
25
|
+
* Whether this error should halt the application
|
|
26
|
+
* @type {Boolean}
|
|
27
|
+
*/
|
|
28
|
+
this.isFatal = metadata.isFatal ?? false
|
|
29
|
+
/**
|
|
30
|
+
* Metadata describing the error
|
|
31
|
+
* @type {Object}
|
|
32
|
+
*/
|
|
33
|
+
this.meta = metadata
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Chainable function to allow setting of data for use in user-friendly error messages later on.
|
|
38
|
+
* @param {object} data
|
|
39
|
+
* @returns {AdaptError}
|
|
40
|
+
* @example
|
|
41
|
+
* // note calling this function will also return
|
|
42
|
+
* // the error itself to allow for easy error throwing
|
|
43
|
+
* throw this.app.errors.MY_ERROR
|
|
44
|
+
* .setData({ hello: 'world' })
|
|
45
|
+
*/
|
|
46
|
+
setData (data) {
|
|
47
|
+
this.data = data
|
|
48
|
+
return this
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @override */
|
|
52
|
+
toString () {
|
|
53
|
+
return `${this.constructor.name}: ${this.code} ${this.data ? JSON.stringify(this.data) : ''}`
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default AdaptError
|
package/lib/App.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import AbstractModule from './AbstractModule.js'
|
|
2
|
+
import Config from './Config.js'
|
|
2
3
|
import DependencyLoader from './DependencyLoader.js'
|
|
4
|
+
import Errors from './Errors.js'
|
|
5
|
+
import Lang from './Lang.js'
|
|
6
|
+
import Logger from './Logger.js'
|
|
3
7
|
import fs from 'fs'
|
|
4
8
|
import path from 'path'
|
|
9
|
+
import { runMigrations } from 'adapt-authoring-migrations'
|
|
5
10
|
import { metadataFileName, packageFileName, getArgs } from './Utils.js'
|
|
6
11
|
|
|
7
12
|
let instance
|
|
@@ -26,54 +31,85 @@ class App extends AbstractModule {
|
|
|
26
31
|
|
|
27
32
|
/** @override */
|
|
28
33
|
constructor () {
|
|
34
|
+
process.env.NODE_ENV ??= 'production'
|
|
29
35
|
const rootDir = process.env.ROOT_DIR ?? process.cwd()
|
|
30
36
|
const adaptJson = JSON.parse(fs.readFileSync(path.join(rootDir, metadataFileName)))
|
|
31
37
|
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, packageFileName)))
|
|
32
38
|
super(null, { ...packageJson, ...adaptJson, name: 'adapt-authoring-core', rootDir })
|
|
33
|
-
this.git = this.getGitInfo()
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
/** @override */
|
|
37
42
|
async init () {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
43
|
+
try {
|
|
44
|
+
/**
|
|
45
|
+
* Instance of App instance (required by all AbstractModules)
|
|
46
|
+
* @type {App}
|
|
47
|
+
*/
|
|
48
|
+
this.app = this
|
|
49
|
+
/**
|
|
50
|
+
* Reference to the passed arguments (parsed for easy reference)
|
|
51
|
+
* @type {Object}
|
|
52
|
+
*/
|
|
53
|
+
this.args = getArgs()
|
|
54
|
+
/**
|
|
55
|
+
* Reference to the Config instance
|
|
56
|
+
* @type {Config}
|
|
57
|
+
*/
|
|
58
|
+
this.config = undefined
|
|
59
|
+
/**
|
|
60
|
+
* Reference to the error registry
|
|
61
|
+
* @type {Errors}
|
|
62
|
+
*/
|
|
63
|
+
this.errors = undefined
|
|
64
|
+
/**
|
|
65
|
+
* Reference to the Lang instance
|
|
66
|
+
* @type {Lang}
|
|
67
|
+
*/
|
|
68
|
+
this.lang = undefined
|
|
69
|
+
/**
|
|
70
|
+
* Reference to the Logger instance
|
|
71
|
+
* @type {Logger}
|
|
72
|
+
*/
|
|
73
|
+
this.logger = new Logger()
|
|
74
|
+
/**
|
|
75
|
+
* Reference to the DependencyLoader instance
|
|
76
|
+
* @type {DependencyLoader}
|
|
77
|
+
*/
|
|
78
|
+
this.dependencyloader = new DependencyLoader(this)
|
|
79
|
+
/**
|
|
80
|
+
* Git metadata for the application (branch and commit hash)
|
|
81
|
+
* @type {Object}
|
|
82
|
+
*/
|
|
83
|
+
this.git = this.getGitInfo()
|
|
53
84
|
|
|
54
|
-
|
|
85
|
+
await this.dependencyloader.loadConfigs()
|
|
55
86
|
|
|
56
|
-
|
|
57
|
-
|
|
87
|
+
const options = {
|
|
88
|
+
dependencies: this.dependencies,
|
|
89
|
+
configFilePath: path.join(this.rootDir, 'conf', `${process.env.NODE_ENV}.config.js`),
|
|
90
|
+
rootDir: this.rootDir,
|
|
91
|
+
log: (...args) => this.logger.log(...args)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await runMigrations({ ...options, dryRun: this.args['dry-run'] === true })
|
|
95
|
+
|
|
96
|
+
this.config = await new Config({ ...options, appName: this.name }).load()
|
|
97
|
+
this.logger = new Logger({ levels: this.getConfig('logLevels'), showTimestamp: this.getConfig('showLogTimestamp') })
|
|
98
|
+
this.errors = new Errors(options)
|
|
99
|
+
this.lang = new Lang({ ...options, defaultLang: this.getConfig('defaultLang') })
|
|
100
|
+
|
|
101
|
+
await this.dependencyloader.loadModules()
|
|
58
102
|
|
|
59
|
-
let startError
|
|
60
|
-
try {
|
|
61
|
-
await this.start()
|
|
62
103
|
this.log('verbose', 'GIT', 'INFO', this.git)
|
|
63
104
|
this.log('verbose', 'DIR', 'rootDir', this.rootDir)
|
|
64
105
|
this.log('verbose', 'DIR', 'dataDir', this.getConfig('dataDir'))
|
|
65
106
|
this.log('verbose', 'DIR', 'tempDir', this.getConfig('tempDir'))
|
|
66
|
-
} catch (
|
|
67
|
-
|
|
107
|
+
} catch (cause) {
|
|
108
|
+
await this.setReady(new Error('Failed to start App', { cause }))
|
|
109
|
+
process.exit(1)
|
|
68
110
|
}
|
|
69
111
|
const failedMods = this.dependencyloader.failedModules
|
|
70
112
|
if (failedMods.length) this.log('warn', `${failedMods.length} module${failedMods.length === 1 ? '' : 's'} failed to load: ${failedMods}. See above for details`)
|
|
71
|
-
if (startError) {
|
|
72
|
-
process.exitCode = 1
|
|
73
|
-
const e = new Error('Failed to start App')
|
|
74
|
-
e.cause = startError
|
|
75
|
-
throw e
|
|
76
|
-
}
|
|
77
113
|
}
|
|
78
114
|
|
|
79
115
|
/**
|
|
@@ -101,21 +137,6 @@ class App extends AbstractModule {
|
|
|
101
137
|
}
|
|
102
138
|
}
|
|
103
139
|
|
|
104
|
-
/**
|
|
105
|
-
* Starts the app
|
|
106
|
-
* @return {Promise} Resolves when the app has started
|
|
107
|
-
*/
|
|
108
|
-
async start () {
|
|
109
|
-
if (this._isReady) throw new Error('warn', 'cannot start app, already started')
|
|
110
|
-
if (this._isStarting) throw new Error('warn', 'cannot start app, already initialising')
|
|
111
|
-
|
|
112
|
-
this._isStarting = true
|
|
113
|
-
|
|
114
|
-
await this.dependencyloader.load()
|
|
115
|
-
|
|
116
|
-
this._isStarting = false
|
|
117
|
-
}
|
|
118
|
-
|
|
119
140
|
/**
|
|
120
141
|
* Enables waiting for other modules to load
|
|
121
142
|
* @param {...String} modNames Names of modules to wait for
|
|
@@ -125,12 +146,6 @@ class App extends AbstractModule {
|
|
|
125
146
|
const results = await Promise.all(modNames.map(m => this.dependencyloader.waitForModule(m)))
|
|
126
147
|
return results.length > 1 ? results : results[0]
|
|
127
148
|
}
|
|
128
|
-
|
|
129
|
-
/** @override */
|
|
130
|
-
setReady (error) {
|
|
131
|
-
this._isStarting = false
|
|
132
|
-
super.setReady(error)
|
|
133
|
-
}
|
|
134
149
|
}
|
|
135
150
|
|
|
136
151
|
export default App
|