Application
Application constructor.
Options is an object that should contain
a config
object holding the configuration
that will be used to configure all modules.
The application instance will extend itself
with the options
object, meaning that we
can override any functions available in the
Application prototype or add new functions
which will be available in the instance.
Extends EventEmitter
options
(Object)
loadConfig(options, asObject)
Convenience method to load configuration objects.
This uses the simple-config-loader package
to load, merge, and resolve all configuration files
found in options.dirname
.
For more information regarding the options that the configuration
loader takes, see here.
options
(Object
= {}
)
Default options
Name | Description |
---|---|
options.basepath String
|
Path to main module |
options.projectpath String
(default process.cwd() )
|
|
options.dirname String
(default 'config' )
|
Name of directory holding configuration files |
options.globOptions Object
|
Options object used to match and ignore files. |
options.getConfigFiles Function
|
Function to collect configuration files.
Uses
glob
under the hood.
|
options.getPackage Function
|
Function to retrieve package.json |
options.configsPath String
(default './' )
|
asObject
(Boolean
= true
)
Return an object
Object
:
Configuration object resulting from
merging all files in config directory.
chainEvents
hook
getLogger(name, config)
Get a Logger instance by name.
If no Logger instance exists with the
given name, a new one will be created.
All calls to getLogger
with
the same name will return the same instance.
Logger
:
Logger instance.
restoreNativeConsole()
Add a restore function to app.
This method is added to Application by
the muteConsole
.
void
:
environment
Default environment variable. This is used for instance to enable long stack traces using the longjohn module.
logger
This will hold the app child logger used by the applciation instance. The output will be identified with the app id.
getLogger(name)
Default implementation of a logger factory that is provided by the logger module. Needed to ensure we can run applications if we decide to not load the logger module.
name
(String)
Child logger indentifier
Logger
:
A child logger instance.
context.getLogger('my-module').info('hi');
autorun
Flag indicating wether to start the application as soon as all core modules are loaded.
autoinitialize
Initialize the applciation from the constructor call?
You can create an application
instance and delay the boot cycle
by initializeing the instance with
this value set to false
.
autoloadModulesCommands
If a module has a commands
name
Name of the application instance. Used by the REPL module to display the prompt or by the logger module to create a child logger asigned to the application context.
exitOnError
Critical errors handled by onErrorHandler
will process.exit
the application.
enableLongStackTrackes
Enable long stack traces using the longjohn module.
This module collects a lot of data and it's not resource friendly. It's always disabled in production irregardless of this property value.
sanitizeName
Function to sanitize module names.
It ensures the resulting name is a valid JavaScript variable name.
Normalized module name.
// returns 'dataManager'
context.sanitizeName('data-manager');
registerReadyEvent
Once a module is registered the
application instance will emit an event.
The event type is:
coremodules
List of modules that will be loaded on boot and are considered to be part of the application context's core.
If you want to override this provide full paths.
basepath
Base path used to resolve relative paths like the paths to the modules directory or other directories that need to be loaded by the application instance.
Defualts to current working directory of the Node.js process.
loaders
Default paths to load commands and modules. Relative to application path.
resolveTimeout
Time in seconds aftwer which we reject
a call to context.resolve
.
If we set it too low we might not give enough time to slower parts of the application to fail, for instance if the ORM module is taking a long time to connect we might abort the app without having the ORM throw an error, thus being hard to debug.
registerTimeout
Time in seconds aftwer which we reject
a call to context.register
.
config
registration
registration.data
can be either
an object or a function that returns
an object.
The object will be sent to the
core.io application registry.
init(options)
Initializes the instance by:
- Registering event listeners
- Configuring the application instance
- Setup long statck traces
- Show ASCII banner
- Mount modules
It will extend options
with
Application.DEFAULTS
, the resulting
object will extend the application
instance.
options
(Object)
Config object
void
:
register(instance, name)
Register a module with the application
context to be exposed as a property with
the name name
.
Due to the mount process and auto-wiring,
name
will often times refer to a npm
package name or a file name. Basically
anyting that can be require
d.
This function will:
-
Normalize
name
: ensure name is a valid JavaScript property name. -
If the module exports an
alias
property it's normalized value will be used instead ofname
. -
The function looks for a key in
context.config
with a key matchingname
. -
If the config object does not export an
moduleid
property it will create it assigningname
to it. -
If the module exports an
init
function it will be called with a reference to the application context and a configuration object. -
instance
is the value of callingrequire
on the module. -
I will
Promise.resolve
instance
, meaning that instance can be either a Promise or an object. -
Once
instance
is resolved, the function will assign a child logger to it. -
If it does not have an
moduleid
property it will assingname
. -
If instance extends EventEmitter it will register
handleModuleError
as an error listener. -
Emit an event with the instance as event. The event type will be:
.<context.registerReadyEvent>. e.g. "logger.registered"
void
:
Nothing
- Error: Will throw an Error if the module has an init property that is not a function.
provide(attr, extension)
This will add attr
to the application
context and ensure that it does not get
overwritten unnoticeably.
If we really want to overwrite the given attribute, we can still do so, but explicitly using Object.defineProperty
This will throw an error in strict mode, which is probably what you want.
attr
(String)
Attribute name
extension
(Mixed)
Funtion or value
this
:
- any: This will throw a TypeError if we are trying to overwrite a previously defined property.
isModuleRegistered(name)
onceRegistered(id, handler)
Register a callback to get notfied
once module
Once a module is registered the
application instance will fire an
event with type <moduleId>.registered
,
logger.registred
for the logger module.
We can't guarantee the other in which modules
are going to be loaded since it depends on
dependency chain resolution. It might be the
case that a module A depends on module B,
module A loads after module B. Using
onceRegistered
module A would still get
notified.
this
:
onErrorHandler(critical, message, err)
handleModuleError(moduleId, err)
Handled errors from registered modules.
During the registration process of a module
we add handleModuleError
as an event listener.
This will retrhow the error, unless the error
object has a handledByModule
property set
to true
.
We give the modules the chance to prevent main app to handle this event. For this to work, and since EventEmitter has no event bubbling we rely on clumsy JS facts:
- Event object is passed by reference.
- event handlers are executed in order they where attached.
So, if we want our module to handle an error before we do here, our module needs to attach it's error listener before returning the module to App core.
void
:
- Error: Will retrhow the error from here.
loadDirectory(dir, options)
Helper function to glob contents of
a directory. Returns a Promise that
resolves with the files. If the options
object contains a handler
function
then we return the value of calling this
function.
Promise
:
Will resolve with files
loadModules(dir, options)
loadCommands(dir, options)
loadModuleCommands(modulePathOrId)
resolve(id, ignoreUndefinedIds)
Resolve a dependency, this will return a Proimse that will be resolved once the module(s) is available.
If the module was already loaded the Promise will be resolve immediately. If not it will wait for the module to be registered.
If after context.resolveTimeout
milliseconds the
module has not been registered the promise will be
rejected.
If id
is undefined
this method will
throw an Error.
If we are trying to resolve a set of dependencies
that might or might not be there you can pass
ignoreUndefinedIds
as true to not generate an error.
This might be the case if we are loading optional
dependencies from a user configuration file
ignoreUndefinedIds
(Boolean
= false
)
Wether to ignore undefined ids.
Promise
:
run()
Application entry point. This will register
a hook listener for the run
hook, and
once the hook has finalized will call
registerApplication
.
void
:
registerApplication(register)
Register the application instance with the core.io registry service.
register
(any
= true
)
void
:
deregisterApplication()
Deregister the application instance from the core.io registry service.
void
:
command(eventType, handler, unique)
Register a command for the given event type.
Command handler functions get bound to the application context.
We can ensure that a given eventType
executes a single command by setting
unique
to true.
eventType
(String)
Event type
handler
(Function)
Command handler
unique
(Boolean
= false
)
Register a single command
for a given eventType
this
:
close(code, label)
nicename
Sanitized version of the given name. It will remove starting digits, and camel case it.
core/logger
config
afterSolver(config)
new Filter(config)
Logger()
Logger class providing extra functionality on top of winston.Logger.
init(app, config)
Logger moudle provides a wrapper around winston.
Look into pino: https://www.npmjs.com/package/pino
app
(Application)
Application context
config
(Object)
Configuration object for "logger"
Object
:
Winston instance
enforceColumnWidth(message, length)
new Message()
Message is the formatter for messages being written to the console transport.
See winston.transports.Console fore more information.
muteConsole(context, config)
Utility function to mute the native console.
It adds a restoreNativeConsole
method to
the Application instance context
.
context
(Application)
Application context
config
(Object)
Configuration object
core/dispatcher
init(context, config)
Adds Event management methods to Application
.
context
(Application)
Application context
config
(Object)
Configuration Object
createHook(emitter, config)
Creates a wrapper function that will make hooks. This function will wrap an event emitter instance with a hook function
A hook is like an event but with a Lifecycle.
A hook has four stages:
- pre
- post
- execution
- complete
You emit a hook the using the hook
method of your emitter.
You register listeners to each stage.
Function
:
createHook
Wraps a chain of events in a Promise.
chainEvents(emitter)
chainEvents
Wraps a chain of events in a Promise.
emit
Gioc
Gioc constructor.
config
(Object)
Optional config object.
configure(config)
map(beanId, context, config)
solve(beanId, options)
Solve for the provided beanId, it returns a value and solves all dependencies, etc.
The cycle to solve for a beanId is the result of runing the methods in order:
prepare
as a pre processbuild
to generate the contextwire
to solve dependenciespost
as a post process
(Object | undefined)
:
Solved value
for the given beanId.
prepare(beanId, target, config, options)
Pre process to consolidate the configuration object for a given beanId.
It will loop over all providers in order the order
they were added and call the provider with the
Gioc instance as scope.
The default provider is the extend
method.
beanId
(String)
String ID we are solving
for
target
(Object)
Resulting object.
config
(Object)
Conf object stored with the
beanId.
options
(Object)
Conf object passed in the
method call.
Gioc
:
build(beanId, options)
Retrieve the context value for the given beanId. If the context is a literal value, we just return it without any further steps. If the context is a function then we execute it with the scope and args provided in the config object.
beanId
(String)
String ID we are solving
for
options
(Object)
Conf object passed in the
method call.
(Primitive | Object)
:
Raw stored value for beanId.
wire(beanId, target, config)
Goes over the config
object's beanIds
and for any of its beanIds that has a related solver
it will apply the solver method to the
target.
Meant to be overridden with use.
Default solvers are the extend
method
for the beanId props
and solveDependencies
for the deps
beanId.
beanId
(String)
String ID we are solving
for
target
((Primitive | Object))
Solved value for the
provided beanId.
config
(Object)
Configuration object.
(Primitive | object)
:
Solved value.
inject(beanId, scope, options)
post(beanId, target, options)
mapped(beanId)
solveDependencies(beanId, scope, mappings)
error(beanId, message)
addSolver(beanId, solver)
addPost(processor)
extend(beanId, target, options, config)
Extend method. It has a common signature with other methods- taking a beanId as first argument- and ignoring it. Then just merging onto "target" from left to right.
Under the hood, is just doing a normal extend.
Object
:
Resulting object from
meging target to params.
logger
Stub method for logger. By default is mapped to console.
mute
names
(String)
A list of names to mute
this
:
`context.getLogger('core').mute('commands', 'modules');`
unmute
Un-mute previously mute'd logger instances.
names
(String)
A list of names of loggers
this
:
silence
Silence a given Logger instance.
Application/Logger
Application/Logger
setColorizer
colorizer
(Colorizer)
Message
:
Return instance
setColors
This takes a configuration object like Winston's colors object.
colors
(Object)
setTime
Message
:
setLabel
Message
:
setLevel
Message
:
setFrom
Message
:
setMessage
Set the message of this instance.
message
(String)
String to output
this
:
wrapper
filters: used to meddle with the content string, e.g.
logger.info('User id: 423423 pass: ahdaljwer')
=>
info: User id: 4...23 pass: ahd.....r
rewriters: used to format metadata:
logger.info('transaction ok', {__meta__: {creditCard: 123456789012345}})
info: transaction ok creditCard=123456****2345
logger
(core/Logger)
Logger instance
collectDirectory
Collect files in a directory.
void
:
require
Require module
Object
:
CareTaker
Manages a program life-cycle.
- raise
- check
- terminate
set timeout. If we do not get new content after this period of time, we consider the system wonked
TODO: Make CLI helper program
options
(Object)
Config object
startup()
Code to be executed on startup
void
:
check(data)
Check point for monitored service.
CareTaker expects this function to be called
in an interval of time lower than the specified
timeout
period.
In the case that the TTL is expired the instance
will execute the terminate
function.
data
(Object)
Object to be serialized
void
:
Serene
TODO: Move to it's own package. Require inside errors core module.
Serene, graceful and controlled shutdowns.
http://joseoncode.com/2014/07/21/graceful-shutdown-in-node-dot-js/
Process managers usually will send first a SIGTERM and wait 10* seconds, if the process is still running a SIGKILL gets sent.
upstart: SIGTERM - 5 secs - SIGKILL runit: SIGTERM - 10 secs - SIGKILL heroku: SIGTERM - 10 secs - SIGKILL docker: SIGTERM - 10 secs - SIGKILL supervisord: SIGTERM - 10 secs - SIGKILL
config
(Object)
Config object
core/repl
The repl module provides a REPL interface to your Application instance.
init(context, config)
This enables connecting to your application using a terminal.
Use poke-repl to create a TCP repl server, to which you can connect using a the poke-repl client.
The REPL serer supports a rudimentary firewall and authentication mechanism.
REPL header:
╔═════════════════════════════════════════════════════════════════════╗
║ poke-repl remote console √ ║
║ ║
║ All connections are monitored and recorded ║
║ Disconnect IMMEDIATELY if you are not an authorized user ║
╚═════════════════════════════════════════════════════════════════════╝
context
(Application)
Application context.
config
(Object)
Configuration object.
Name | Description |
---|---|
config.port Number
(default 8989 )
|
Port exposed by the REPL server. |
config.host String
(default 'localhost' )
|
Host of the REPL server. |
config.enabled Boolean
(default false )
|
Should the REPL be enabled. |
config.metadata Object
|
Object passed to render the REPL banner. This depends on what the banner you use expects. |
config.options Object
|
on
the application context changed, we should reload the connection.
There should be a repl command to reload/refresh the connection.
core/utils
Module holding different utilities.
CommandLike
Anything that can be executed.
Type: (Function | Class | Command)
getUid
Generate an unique identifier in the form or: "jce1t9gu-sg69zzohk7"
len
(Number
= 20
)
Output length
String
: