From 6b4471ed2a39272ab3caa557c3471510d2766d01 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 27 Nov 2018 17:12:12 +0100 Subject: [PATCH 01/35] =?UTF-8?q?feat(atlas):=20add=20typings=20for=20the?= =?UTF-8?q?=20whole=20@atlas.js/atlas=20package=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This still needs work, but the basic API surface is typed now! 💪 --- packages/action/src/index.d.ts | 4 + packages/atlas/src/atlas.mjs | 6 +- packages/atlas/src/index.d.ts | 277 ++++++++++++++++++++++++++++++++ packages/hook/src/index.d.ts | 4 + packages/service/src/index.d.ts | 4 + 5 files changed, 292 insertions(+), 3 deletions(-) create mode 100644 packages/action/src/index.d.ts create mode 100644 packages/atlas/src/index.d.ts create mode 100644 packages/hook/src/index.d.ts create mode 100644 packages/service/src/index.d.ts diff --git a/packages/action/src/index.d.ts b/packages/action/src/index.d.ts new file mode 100644 index 0000000..a8fb2e5 --- /dev/null +++ b/packages/action/src/index.d.ts @@ -0,0 +1,4 @@ +// @TODO(typings): write the types +declare module '@atlas.js/action' { + export default class Action { } +} diff --git a/packages/atlas/src/atlas.mjs b/packages/atlas/src/atlas.mjs index 94c39b1..6eb710f 100644 --- a/packages/atlas/src/atlas.mjs +++ b/packages/atlas/src/atlas.mjs @@ -315,7 +315,7 @@ class Atlas { } /** - * Register a service into this atlas at given alias + * Register a service into this instance of Atlas with the given alias * * @param {String} alias The alias for the service - it will be used for exposing * the service's API on the atlas.services object and for @@ -337,7 +337,7 @@ class Atlas { } /** - * Register a hook into this atlas using given alias + * Register a hook into this instance of Atlas with the given alias * * @param {String} alias The alias for the hook - it will be used for passing * configuration data to it @@ -358,7 +358,7 @@ class Atlas { } /** - * Register an action into this atlas at given alias + * Register an action into this instance of Atlas with the given alias * * @param {String} alias The alias for the action - it will be used for exposing * the action's API on the atlas.actions object and for diff --git a/packages/atlas/src/index.d.ts b/packages/atlas/src/index.d.ts new file mode 100644 index 0000000..c5934a1 --- /dev/null +++ b/packages/atlas/src/index.d.ts @@ -0,0 +1,277 @@ +declare module '@atlas.js/atlas' { + import * as errors from '@atlas.js/errors' + import Ajv from 'ajv' + import Pino from 'pino' + + // @TODO: Move this into @atlas.js/component + declare class Component { + static internal: boolean + static config: object + static requires: Array + + atlas: Atlas + log: Pino.Logger + config: object + dispatch(): Component + component(alias: string): any + } + + interface ComponentConstructor { + new (): Component + } + + + interface Config { + atlas?: { + /** Default configuration options for Atlas' pino logger */ + log?: Pino.LoggerOptions + /** Default configuration options for Atlas' component configuration validator */ + validator?: Ajv.Options & { + /** Keywords to enable from the `ajv-keywords` package */ + keywords?: Array + } + } + /** + * Configuration options for services. + * + * The key must be the alias used when adding the service to Atlas, and the value will be + * provided to the component as its configuration. + */ + services: { [key: string]: any } + /** + * Configuration options for actions. + * + * The key must be the alias used when adding the action to Atlas, and the value will be + * provided to the component as its configuration. + */ + actions: { [key: string]: any } + /** + * Configuration options for hooks. + * + * The key must be the alias used when adding the hook to Atlas, and the value will be + * provided to the component as its configuration. + */ + hooks: { [key: string]: any } + } + + interface Options { + /** Environment to run Atlas in. Default: value of `process.env.NODE_ENV` */ + env: string + /** Absolute path to folder structure where Atlas can expect its components to be defined */ + root: string + /** + * Configuration options for Atlas and all components + * + * If string is provided, it will be used as path relative to `root` and required. The resulting + * object will be used as the configuration object. If an object is provided, it will be used + * as-is. + */ + config: Config | string + } + + interface InitOptions extends Options { + /** Path to a module from which service components should be loaded. Default: `services` */ + services?: string + /** Path to a module from which action components should be loaded. Default: `actions` */ + actions?: string + /** Path to a module from which hook components should be loaded. Default: `hooks` */ + hooks?: string + /** + * Path to a module from which component configuration should be loaded (or the configuration + * itself). Default: `config` + */ + config?: Options["config"] + } + + interface BootstrapOptions extends Options { + /** + * All services to be added to Atlas. The key is the alias for the component and the value is + * the Component class itself (ie. `new Component()` will be called on the value). + */ + services: { [key: string]: ComponentConstructor } + /** + * All actions to be added to Atlas. The key is the alias for the component and the value is + * the Component class itself (ie. `new Component()` will be called on the value). + */ + actions: { [key: string]: ComponentConstructor } + /** + * All hooks to be added to Atlas. The key is the alias for the component and the value is + * the Component class itself (ie. `new Component()` will be called on the value). + */ + hooks: { [key: string]: ComponentConstructor } + } + + interface ComponentOptions { + /** + * If this component requires other components, you must specify their aliases you chose for + * them here. The key is the component name which is used by this component, and the value + * is the alias you chose for that compoennt in this instance of Atlas. + */ + aliases: { + [name: string]: string + } + } + + + /** + * The main point of interaction with Atlas. + */ + export class Atlas { + /** + * Default values for configuration options which Atlas accepts. + */ + static readonly defaults: Config['atlas'] + + /** Current execution environment (usually mirrors `process.env.NODE_ENV` unless overriden) */ + readonly env: string + + /** + * The root folder where all other paths should be relative to + * + * It is recommended that you set this to the project's root directory. + */ + readonly root: string + + /** Is this instance in a prepared state? */ + readonly prepared: boolean + + /** Is this instance in a started state? */ + readonly started: boolean + + /** Atlas configuration, as passed in to the constructor */ + readonly config: Config + + /** All services added to this instance */ + readonly services: object + + /** All actions added to this instance */ + readonly actions: object + + /** An instance of Ajv used to validate component configuration */ + validator: Ajv.Ajv + + /** Logger used throughout Atlas and its components */ + log: Pino.Logger + + /** + * Initialise Atlas instance from the module paths provided in the `options` object + * + * Use this method to quickly configure Atlas instance by simply telling it where your + * components live on the filesystem, and Atlas will load them from the given module locations + * and add them to the Atlas instance. + * + * This is the preferred way of initialising an Atlas instance. + */ + static init(options: InitOptions): Atlas + + /** + * Bootstrap the given Atlas instance with the provided modules + * + * Use this method to quickly set up the given Atlas instance to use the provided components. + * This is useful if you need to have multiple entry points to your program and some entrypoints + * should only use some components available. This is especially useful when implementing worker + * processes where you only need a subset of all available components. This method, while more + * verbose as Atlas.init(), still frees you from manually adding all the components by hand + * while providing greater flexibility as to which components will be used. + */ + static bootstrap(atlas: Atlas, options: BootstrapOptions): Atlas + + /** + * Create a new Atlas instance + * + * Generally you should not need to create an Atlas instance via its constructor and use either + * the `Atlas.init()` or `Atlas.bootstrap()` options which are more easy to use. Using the + * constructor is more verbose but provides greatest level of control over the initialisation. + * + * You will have to manually register each component to the instance. + */ + constructor(options: Options) + + /** + * Require a module by path, relative to the project root + */ + require( + /** Location of the module to load, relative to `atlas.root` (unless `absolute = true`) */ + location: string, + /** Options which affect how the module will be loaded */ + options: { + /** If true, do not throw if the module does not exist */ + optional: boolean, + /** + * If true, prefer the ES modules' `default` export over named or CommonJS exports + */ + normalise: boolean, + /** + * If true, will try to load the module without resolving the specified location to the + * project root (it will load the module using standard Node's mechanism). + */ + absolute: boolean + }): any + + /** + * Register a service into this instance of Atlas with the given alias + */ + service( + /** Alias to associate with this component */ + alias: string, + /** The component class. It will be constructed using `new Component()` during startup. */ + Component: ComponentConstructor, + /** Options for the component */ + options: ComponentOptions + ): this + + /** + * Register a hook into this instance of Atlas with the given alias + */ + hook( + /** Alias to associate with this component */ + alias: string, + /** The component class. It will be constructed using `new Component()` during startup. */ + Component: ComponentConstructor, + /** Options for the component */ + options: ComponentOptions + ): this + + /** + * Register an action into this instance of Atlas with the given alias + */ + action( + /** Alias to associate with this component */ + alias: string, + /** The component class. It will be constructed using `new Component()` during startup. */ + Component: ComponentConstructor, + /** Options for the component */ + options: ComponentOptions + ): this + + /** + * Prepare all services and hooks for use + * + * Generally you should use `atlas.start()` instead to get your instance up and running. + * However, sometimes it is necessary to get all the services into a "get-ready" state before + * they start connecting to remote resources or doing any intensive I/O operations. + */ + prepare(): Promise + + /** + * Start alll services + * + * This puts all components into a fully functional state, with all connections established (if + * any) and ready for use once this function resolves. + */ + start(): Promise + + /** + * Stop all services, unregister all actions and hooks and unpublish any APIs exposed by them + * + * This puts the whole application into a state as it was before `atlas.prepare()` and/or + * `atlas.start()` was called. + */ + stop(): Promise + } + + export { default as Action } from '@atlas.js/action' + export { default as Service } from '@atlas.js/service' + export { default as Hook } from '@atlas.js/hook' + export { errors } +} diff --git a/packages/hook/src/index.d.ts b/packages/hook/src/index.d.ts new file mode 100644 index 0000000..c5b26f0 --- /dev/null +++ b/packages/hook/src/index.d.ts @@ -0,0 +1,4 @@ +// @TODO(typings): write the types +declare module '@atlas.js/hook' { + export default class Hook { } +} diff --git a/packages/service/src/index.d.ts b/packages/service/src/index.d.ts new file mode 100644 index 0000000..e68a397 --- /dev/null +++ b/packages/service/src/index.d.ts @@ -0,0 +1,4 @@ +// @TODO(typings): write the types +declare module '@atlas.js/service' { + export default class Service { } +} From 1ce7545e18df8a18b0e84a313a6108e4c0f3b9df Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Thu, 29 Nov 2018 12:32:03 +0100 Subject: [PATCH 02/35] feat(component): add typings for @atlas.js/component --- packages/atlas/src/index.d.ts | 22 +++------- packages/atlas/src/private/dispatch.mjs | 2 +- packages/component/package.json | 1 + packages/component/src/index.d.ts | 56 +++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 packages/component/src/index.d.ts diff --git a/packages/atlas/src/index.d.ts b/packages/atlas/src/index.d.ts index c5934a1..827bc32 100644 --- a/packages/atlas/src/index.d.ts +++ b/packages/atlas/src/index.d.ts @@ -1,26 +1,13 @@ declare module '@atlas.js/atlas' { import * as errors from '@atlas.js/errors' + import Component from '@atlas.js/component' import Ajv from 'ajv' import Pino from 'pino' - // @TODO: Move this into @atlas.js/component - declare class Component { - static internal: boolean - static config: object - static requires: Array - - atlas: Atlas - log: Pino.Logger - config: object - dispatch(): Component - component(alias: string): any - } - interface ComponentConstructor { new (): Component } - interface Config { atlas?: { /** Default configuration options for Atlas' pino logger */ @@ -116,7 +103,7 @@ declare module '@atlas.js/atlas' { /** * The main point of interaction with Atlas. */ - export class Atlas { + declare class Atlas { /** * Default values for configuration options which Atlas accepts. */ @@ -270,8 +257,11 @@ declare module '@atlas.js/atlas' { stop(): Promise } + export { + Atlas, + errors, + } export { default as Action } from '@atlas.js/action' export { default as Service } from '@atlas.js/service' export { default as Hook } from '@atlas.js/hook' - export { errors } } diff --git a/packages/atlas/src/private/dispatch.mjs b/packages/atlas/src/private/dispatch.mjs index 5629645..6f8872f 100644 --- a/packages/atlas/src/private/dispatch.mjs +++ b/packages/atlas/src/private/dispatch.mjs @@ -1,7 +1,7 @@ /** * Dispatch an event to hooks * - * This function takes variable number of events to be dispatched to hooks + * Dispatch an event to all hooks listening on this component * * @private * @param {String} event The event's name diff --git a/packages/component/package.json b/packages/component/package.json index 1277e15..ea98884 100644 --- a/packages/component/package.json +++ b/packages/component/package.json @@ -5,6 +5,7 @@ "author": "Robert Rossmann ", "bugs": "https://github.com/strvcom/atlas.js/issues", "contributors": [], + "dependencies": {}, "engines": { "node": ">=8.3.0", "npm": "^5.3.0" diff --git a/packages/component/src/index.d.ts b/packages/component/src/index.d.ts new file mode 100644 index 0000000..f440849 --- /dev/null +++ b/packages/component/src/index.d.ts @@ -0,0 +1,56 @@ +declare module '@atlas.js/component' { + import Pino from 'pino' + + type ComponentName = string + + export default class Component { + /** + * By default, a component is marked as "public", ie. accessible on the Atlas instance. With + * this set to `true` you will only be able to access this component only via inter-component + * resolution mechanism (`this.component(name)`). + * + * This is useful to hide various low-level or "glue" components from the public API surface. + */ + static internal: boolean + + /** + * Default configuration for this component + * + * @deprecated Use the `config` static property (JSON schema) to describe your configuration + */ + static defaults: object + + /** JSON Schema describing this component's configuration values */ + static config: object + + /** Array of component aliases which this component consumes/requires */ + static requires: Array + + /** + * A child log created specifically for this component to easily distinguish log entries coming + * from this component + */ + log: Pino.Logger + // @TODO: Refactor to show the real Atlas instance + /** The Atlas instance which is currently managing this component */ + atlas: object + /** Runtime configuration values as received from the user, with defaults applied */ + config: object + + /** + * Get the instance of a component + * + * @param componentName The name of the component to retrieve, as defined in this + * component's `static requires` array. + */ + component(componentName: ComponentName): any + + /** + * Dispatch an event to all hooks listening on this component + * + * @param event The event to dispatch (an arbitrary string) + * @param subject The thing to send to the hooks along with this event as an argument + */ + dispatch(event: string, subject: any): Promise + } +} From a86365224e637cb0f81788dded61a571d239fa37 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Thu, 29 Nov 2018 12:35:36 +0100 Subject: [PATCH 03/35] feat(action): expand typings --- packages/action/src/index.d.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/action/src/index.d.ts b/packages/action/src/index.d.ts index a8fb2e5..f6107c1 100644 --- a/packages/action/src/index.d.ts +++ b/packages/action/src/index.d.ts @@ -1,4 +1,7 @@ -// @TODO(typings): write the types declare module '@atlas.js/action' { - export default class Action { } + import Component from '@atlas.js/component' + + export default class Action extends Component { + static type = 'action' + } } From 1e92767ecd152bf4555b708102e2667f8128affe Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Thu, 29 Nov 2018 12:35:44 +0100 Subject: [PATCH 04/35] feat(hook): expand typings --- packages/hook/src/index.d.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/hook/src/index.d.ts b/packages/hook/src/index.d.ts index c5b26f0..d43bca6 100644 --- a/packages/hook/src/index.d.ts +++ b/packages/hook/src/index.d.ts @@ -1,4 +1,7 @@ -// @TODO(typings): write the types declare module '@atlas.js/hook' { - export default class Hook { } + import Component from '@atlas.js/component' + + export default class Hook extends Component { + static type = 'hook' + } } From 0717430ba6af906e6a68e4717c1eb703526ac6c3 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Thu, 29 Nov 2018 12:35:50 +0100 Subject: [PATCH 05/35] feat(service): expand typings --- packages/service/src/index.d.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/service/src/index.d.ts b/packages/service/src/index.d.ts index e68a397..3016b10 100644 --- a/packages/service/src/index.d.ts +++ b/packages/service/src/index.d.ts @@ -1,4 +1,7 @@ -// @TODO(typings): write the types declare module '@atlas.js/service' { - export default class Service { } + import Component from '@atlas.js/component' + + export default class Service extends Component { + static type = 'service' + } } From b456579c2843f4700ef9b8d4e66a0a49b4530c6f Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Thu, 29 Nov 2018 16:22:10 +0100 Subject: [PATCH 06/35] chore: improve some internal type hints when working on Atlas source This also demonstrates the idea behind type-hinting the component instances users receive when using `this.component(alias)` from within their components. --- packages/firebase/src/service.mjs | 12 ++++++++++++ packages/koa/src/context.mjs | 2 ++ packages/koa/src/middleware.mjs | 14 ++++++++++++-- packages/koa/src/server.mjs | 18 ++++++++++++++---- packages/koa/src/websocket.mjs | 7 ++++++- packages/mongoose/src/service.mjs | 17 +++++++++++++++++ 6 files changed, 63 insertions(+), 7 deletions(-) diff --git a/packages/firebase/src/service.mjs b/packages/firebase/src/service.mjs index 4136407..a2224b3 100644 --- a/packages/firebase/src/service.mjs +++ b/packages/firebase/src/service.mjs @@ -2,6 +2,7 @@ import Service from '@atlas.js/service' import * as Admin from 'firebase-admin' class Firebase extends Service { + /** Firebase configuration schema */ static config = { type: 'object', additionalProperties: false, @@ -18,6 +19,11 @@ class Firebase extends Service { }, } + /** + * Start the service + * + * @return {Promise} + */ prepare() { const config = this.config // Either load the credentials from the file (if it's a string) or just pass it as is (object?) @@ -31,6 +37,12 @@ class Firebase extends Service { }, config.name) } + /** + * Stop the service + * + * @param {Admin.app.App} firebase The firebase instance + * @return {Promise} + */ async stop(firebase) { await firebase.delete() } diff --git a/packages/koa/src/context.mjs b/packages/koa/src/context.mjs index 4599cc4..315e8c8 100644 --- a/packages/koa/src/context.mjs +++ b/packages/koa/src/context.mjs @@ -2,6 +2,7 @@ import Hook from '@atlas.js/hook' import { FrameworkError } from '@atlas.js/errors' class ContextHook extends Hook { + /** ContextHook configuration schema */ static config = { type: 'object', additionalProperties: false, @@ -20,6 +21,7 @@ class ContextHook extends Hook { ] afterPrepare() { + /** @type {import("koa")} */ const koa = this.component('service:koa') // Prefer default export or a standard CommonJS module const context = this.atlas.require(this.config.module, { normalise: true }) diff --git a/packages/koa/src/middleware.mjs b/packages/koa/src/middleware.mjs index 5b8ba77..bf73066 100644 --- a/packages/koa/src/middleware.mjs +++ b/packages/koa/src/middleware.mjs @@ -1,8 +1,18 @@ +/** + * @typedef {import("koa")} Koa + */ + +/** + * @typedef {Object} Handlers + * @property {function} name The handler function associated with a name through the object + * key + */ + /** * Register the given middleware functions into the given Koa-compatible instance * - * @param {Object} instance Koa-compatible instance. Must implement `.use()`. - * @param {Object} handlers Object where keys are the middlewares' names and the + * @param {Koa} instance Koa-compatible instance. Must implement `.use()`. + * @param {Handlers} handlers Object where keys are the middlewares' names and the * values are the actual middleware functions. * @param {Object} config={} Configuration for individual middlewares. The keys should * match the middleware names. diff --git a/packages/koa/src/server.mjs b/packages/koa/src/server.mjs index ce42daa..fb8a100 100644 --- a/packages/koa/src/server.mjs +++ b/packages/koa/src/server.mjs @@ -77,9 +77,7 @@ class KoaService extends Service { } - prepare(options) { - super.prepare(options) - + prepare() { // Prepare Koa instance const koa = new Koa() koa.env = this.atlas.env @@ -101,6 +99,12 @@ class KoaService extends Service { return koa } + /** + * Start the service + * + * @param {Koa} koa The koa instance + * @return {Promise} + */ async start(koa) { const server = http.createServer(koa.callback()) koa.server = server @@ -123,12 +127,18 @@ class KoaService extends Service { server.once('error', fail) // Listen already! - koa.server.listen(this.config.listen.port, this.config.listen.hostname) + server.listen(this.config.listen.port, this.config.listen.hostname) }) this.log.info({ addrinfo: server.address() }, 'listening') } + /** + * Stop the service + * + * @param {Koa} koa The koa instance + * @return {Promise} + */ async stop(koa) { if (!koa || !koa.server) { throw new FrameworkError('Cannot stop a non-running server') diff --git a/packages/koa/src/websocket.mjs b/packages/koa/src/websocket.mjs index cd169df..6479ec6 100644 --- a/packages/koa/src/websocket.mjs +++ b/packages/koa/src/websocket.mjs @@ -46,6 +46,7 @@ class WebsocketHook extends Hook { } afterPrepare() { + /** @type {import("koa")} */ const koa = this.component('service:koa') const config = this.config @@ -59,6 +60,7 @@ class WebsocketHook extends Hook { } afterStart() { + /** @type {import("koa")} */ const koa = this.component('service:koa') koa.ws.listen({ @@ -70,10 +72,13 @@ class WebsocketHook extends Hook { } async beforeStop() { + /** @type {import("koa")} */ + const koa = this.component('service:koa') + this.log.info('websocket:close') await new Promise((resolve, reject) => - this.component('service:koa').ws.server.close(err => + koa.ws.server.close(err => err ? reject(err) : resolve())) } } diff --git a/packages/mongoose/src/service.mjs b/packages/mongoose/src/service.mjs index 877173e..13d94a4 100644 --- a/packages/mongoose/src/service.mjs +++ b/packages/mongoose/src/service.mjs @@ -29,6 +29,11 @@ class Mongoose extends Service { options: {}, } + /** + * Prepare the service + * + * @return {Promise} + */ prepare() { const instance = new mongoose.Mongoose() // Add a trace logger to allow users to monitor Mongoose activity @@ -37,6 +42,12 @@ class Mongoose extends Service { return Promise.resolve(instance) } + /** + * Start the service + * + * @param {mongoose.Mongoose} instance The instance being started + * @return {Promise} + */ async start(instance) { for (const name of instance.modelNames()) { // Allow models to use the Atlas instance @@ -47,6 +58,12 @@ class Mongoose extends Service { await instance.connect(this.config.uri, this.config.options) } + /** + * Stop the service + * + * @param {mongoose.Mongoose} instance The instance being started + * @return {Promise} + */ async stop(instance) { await instance.disconnect() } From d3ea062cda9355d7ad5ad72d429d4a1da35cc3ec Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Mon, 3 Dec 2018 11:23:25 +0100 Subject: [PATCH 07/35] chore: fix some docblocks --- packages/atlas/src/atlas.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/atlas/src/atlas.mjs b/packages/atlas/src/atlas.mjs index 6eb710f..385fb15 100644 --- a/packages/atlas/src/atlas.mjs +++ b/packages/atlas/src/atlas.mjs @@ -107,7 +107,7 @@ class Atlas { * providing greater flexibility as to which components will be used. * * @param {Atlas} atlas The Atlas instance to bootstrap - * @param {Object} modules={} All the modules which should be added to Atlas + * @param {Object} modules? All the modules which should be added to Atlas * @param {Object} modules.actions Actions to add * @param {Object} modules.hooks Hooks to add * @param {Object} modules.services Services to add @@ -290,7 +290,7 @@ class Atlas { * Require a module by path, relative to the project root * * @param {String} location The module's location, relative to root - * @param {Object} options={} Options + * @param {Object} options? Options * @param {Boolean} options.optional If true, will not throw if the module does not exist * @param {Boolean} options.normalise If true, it will prefer the ES modules' default export * over named exports or the CommonJS exports From 330c2809b93d320dd6592d2e99e8d404c99663bf Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Mon, 3 Dec 2018 11:51:42 +0100 Subject: [PATCH 08/35] fix(component): use real Atlas declaration --- packages/component/src/index.d.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/component/src/index.d.ts b/packages/component/src/index.d.ts index f440849..ac519a0 100644 --- a/packages/component/src/index.d.ts +++ b/packages/component/src/index.d.ts @@ -1,5 +1,6 @@ declare module '@atlas.js/component' { import Pino from 'pino' + import { Atlas } from '@atlas.js/atlas' type ComponentName = string @@ -31,9 +32,10 @@ declare module '@atlas.js/component' { * from this component */ log: Pino.Logger - // @TODO: Refactor to show the real Atlas instance + /** The Atlas instance which is currently managing this component */ - atlas: object + atlas: Atlas + /** Runtime configuration values as received from the user, with defaults applied */ config: object From ab0a0af8462127cf01beb8ade51415ba459d9b33 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Mon, 3 Dec 2018 15:28:25 +0100 Subject: [PATCH 09/35] =?UTF-8?q?feat:=20expand=20JSDocs=20for=20all=20bas?= =?UTF-8?q?e=20component=20classes=20=F0=9F=92=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/action/src/index.d.ts | 22 ++++++++++++-- packages/action/src/index.mjs | 17 +++++++++++ packages/component/src/index.d.ts | 10 ++++++- packages/hook/src/index.d.ts | 30 +++++++++++++++++-- packages/hook/src/index.mjs | 18 +++++++++++ packages/service/src/index.d.ts | 50 +++++++++++++++++++++++++++++-- packages/service/src/index.mjs | 8 ++++- 7 files changed, 147 insertions(+), 8 deletions(-) diff --git a/packages/action/src/index.d.ts b/packages/action/src/index.d.ts index f6107c1..702f180 100644 --- a/packages/action/src/index.d.ts +++ b/packages/action/src/index.d.ts @@ -1,7 +1,25 @@ declare module '@atlas.js/action' { import Component from '@atlas.js/component' - export default class Action extends Component { - static type = 'action' + /** + * Use this class to implement custom high-level "actions" or "operations" in your code + * + * An action could be thought of as a controller of sorts in the MVC architecture. The general + * idea of actions is that each class represents a group of releated operations which yield a + * specific end result. They should be callable from anywhere and should not be tied to a + * particular interface (ie. an HTTP server or a REPL session) - in other words, the idea is to + * make them as reusable as possible. + * + * Actions can be completely standalone or they might call other, lower-level actions or interact + * with services to manipulate external resources. Generally actions are called from some kind of + * externally available entry point, like an HTTP interface, a REPL session, a custom socket etc. + * + * Actions are intended to encapsulate "business-specific" or re-usable code/behaviour. + * + * @abstract + */ + export default abstract class Action extends Component { + /** @private */ + static type: 'action' } } diff --git a/packages/action/src/index.mjs b/packages/action/src/index.mjs index 6afd0f9..5b6074d 100644 --- a/packages/action/src/index.mjs +++ b/packages/action/src/index.mjs @@ -1,5 +1,22 @@ import Component from '@atlas.js/component' +/** + * Use this class to implement custom high-level "actions" or "operations" in your code + * + * An action could be thought of as a controller of sorts in the MVC architecture. The general + * idea of actions is that each class represents a group of releated operations which yield a + * specific end result. They should be callable from anywhere and should not be tied to a + * particular interface (ie. an HTTP server or a REPL session) - in other words, the idea is to + * make them as reusable as possible. + * + * Actions can be completely standalone or they might call other, lower-level actions or interact + * with services to manipulate external resources. Generally actions are called from some kind of + * externally available entry point, like an HTTP interface, a REPL session, a custom socket etc. + * + * Actions are intended to encapsulate "business-specific" or re-usable code/behaviour. + * + * @abstract + */ class Action extends Component { static type = 'action' } diff --git a/packages/component/src/index.d.ts b/packages/component/src/index.d.ts index ac519a0..0cda419 100644 --- a/packages/component/src/index.d.ts +++ b/packages/component/src/index.d.ts @@ -4,7 +4,15 @@ declare module '@atlas.js/component' { type ComponentName = string - export default class Component { + /** + * A base class implementing common behaviour for Service, Action and Hook subclasses + * + * You should not use this class directly and instead use either `Service`, `Action` or `Hook` + * subclasses. + * + * @abstract + */ + export default abstract class Component { /** * By default, a component is marked as "public", ie. accessible on the Atlas instance. With * this set to `true` you will only be able to access this component only via inter-component diff --git a/packages/hook/src/index.d.ts b/packages/hook/src/index.d.ts index d43bca6..c6bb021 100644 --- a/packages/hook/src/index.d.ts +++ b/packages/hook/src/index.d.ts @@ -1,7 +1,33 @@ declare module '@atlas.js/hook' { import Component from '@atlas.js/component' - export default class Hook extends Component { - static type = 'hook' + /** + * Use this class to implement the "observer" pattern within Atlas + * + * A hook is capable of receiving "events" emitted from other components as method invocations. + * If a hook observes a component "service:database", and that component emits a "didCreateRecord" + * event with the record on input, you can declare a method on your hook like this and Atlas will + * call it when the observing component emits that event: + * + * ```js + * class MyHook extends Hook { + * async didCreaterecord(record) { + * // process the record somehow + * } + * } + * ``` + * + * @abstract + */ + export default abstract class Hook extends Component { + /** @private */ + static type: 'hook' + + /** + * The name of the component this hook wants to receive events from + * + * If `atlas` is specified, this hook will receive events from the Atlas instance itself. + */ + static observes: string } } diff --git a/packages/hook/src/index.mjs b/packages/hook/src/index.mjs index 639b900..f759192 100644 --- a/packages/hook/src/index.mjs +++ b/packages/hook/src/index.mjs @@ -1,5 +1,23 @@ import Component from '@atlas.js/component' +/** + * Use this class to implement the "observer" pattern within Atlas + * + * A hook is capable of receiving "events" emitted from other components as method invocations. + * If a hook observes a component "service:database", and that component emits a "didCreateRecord" + * event with the record on input, you can declare a method on your hook like this and Atlas will + * call it when the observing component emits that event: + * + * ```js + * class MyHook extends Hook { + * async didCreaterecord(record) { + * // process the record somehow + * } + * } + * ``` + * + * @abstract + */ class Hook extends Component { static type = 'hook' static observes = null diff --git a/packages/service/src/index.d.ts b/packages/service/src/index.d.ts index 3016b10..46e584d 100644 --- a/packages/service/src/index.d.ts +++ b/packages/service/src/index.d.ts @@ -1,7 +1,53 @@ declare module '@atlas.js/service' { import Component from '@atlas.js/component' - export default class Service extends Component { - static type = 'service' + type ServiceApi = Object | Function | Array + + /** + * Base service class which all Atlas services should subclass + * + * This class provides basic functionality to integrate a Service into Atlas. Atlas expects all + * Services to have a certain interface, therefore when you want to create your own service, you + * should subclass this base Service class. + * + * @abstract + */ + export default abstract class Service extends Component { + /** @private */ + static type: 'service' + + /** + * Prepare the service instance your consumers will use in their projects + * + * You must implement this method in a subclass. + * You should not attempt to make any connections or other I/O unless absolutely necessary for + * preparing the service for work. This method should only be used to expose the data structures + * your consumers will have access to. Atlas uses this method to allow component inspection in a + * REPL or to provide some auto-complete suggestions when using the CLI. + * + * @abstract + * @return {Promise} The API your users will be interacting with. It can be + * anything, really, but usually it will be some kind of + * connection object or similar. + */ + abstract prepare(): Promise + + /** + * Start the service or put the service into a fully functional and ready state + * + * @abstract + * @param ServiceApi The API your users will be interacting with. You should provide this + * API as the return value of the `.prepare()` method. + */ + abstract start(ServiceApi): Promise + + /** + * Stop the service by terminating any pending connections and finishing all pending work + * + * @abstract + * @param ServiceApi The API your users have interacted with. You created this API as the + * return value of the `.prepare()` method. + */ + abstract stop(ServiceApi): Promise } } diff --git a/packages/service/src/index.mjs b/packages/service/src/index.mjs index 61fee28..7ab1f94 100644 --- a/packages/service/src/index.mjs +++ b/packages/service/src/index.mjs @@ -1,7 +1,13 @@ import Component from '@atlas.js/component' /** - * Base service class all other services should inherit from + * Base service class which all Atlas services should subclass + * + * This class provides basic functionality to integrate a Service into Atlas. Atlas expects all + * Services to have a certain interface, therefore when you want to create your own service, you + * should subclass this base Service class. + * + * @abstract */ class Service extends Component { static type = 'service' From 401458c5675b7ae2b68205a5ae02f6f971dd4e6e Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Mon, 3 Dec 2018 15:47:35 +0100 Subject: [PATCH 10/35] chore(koa): more type fixes for @atlas.js/koa --- packages/koa/package-lock.json | 149 ++++++++++++++++++++++++++++++++ packages/koa/package.json | 4 +- packages/koa/src/middleware.mjs | 2 +- 3 files changed, 153 insertions(+), 2 deletions(-) diff --git a/packages/koa/package-lock.json b/packages/koa/package-lock.json index 6d93756..022cf20 100644 --- a/packages/koa/package-lock.json +++ b/packages/koa/package-lock.json @@ -4,6 +4,155 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/accepts": { + "version": "1.3.5", + "resolved": "http://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/body-parser": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz", + "integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", + "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cookies": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.1.tgz", + "integrity": "sha512-ku6IvbucEyuC6i4zAVK/KnuzWNXdbFd1HkXlNLg/zhWDGTtQT5VhumiPruB/BHW34PWVFwyfwGftDQHfWNxu3Q==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/express": "*", + "@types/keygrip": "*", + "@types/node": "*" + } + }, + "@types/events": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", + "dev": true + }, + "@types/express": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.16.0.tgz", + "integrity": "sha512-TtPEYumsmSTtTetAPXlJVf3kEqb6wZK0bZojpJQrnD/djV4q1oB6QQ8aKvKqwNPACoe02GNiy5zDzcYivR5Z2w==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz", + "integrity": "sha512-lTeoCu5NxJU4OD9moCgm0ESZzweAx0YqsAcab6OB0EB3+As1OaHtKnaGJvcngQxYsi9UNv0abn4/DRavrRxt4w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/node": "*", + "@types/range-parser": "*" + } + }, + "@types/http-assert": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.3.0.tgz", + "integrity": "sha512-RObYTpPMo0IY+ZksPtKHsXlYFRxsYIvUqd68e89Y7otDrXsjBy1VgMd53kxVV0JMsNlkCASjllFOlLlhxEv0iw==", + "dev": true + }, + "@types/keygrip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.1.tgz", + "integrity": "sha1-/1QEYtL7TQqIRBzq8n0oewHD2Hg=", + "dev": true + }, + "@types/koa": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.0.47.tgz", + "integrity": "sha512-llhCaHNWKFDMx1GCrqwgsWgUO+C4Da0SccbgevHIYOKVxwegEjFzl0WaMWHk3wWx0P0AdqHR+gQYZ2ZAb0ez0Q==", + "dev": true, + "requires": { + "@types/accepts": "*", + "@types/cookies": "*", + "@types/http-assert": "*", + "@types/keygrip": "*", + "@types/koa-compose": "*", + "@types/node": "*" + } + }, + "@types/koa-compose": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.2.tgz", + "integrity": "sha1-3BBuAAu/kqOskA91bfRzRIh+6Ec=", + "dev": true + }, + "@types/koa-websocket": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/koa-websocket/-/koa-websocket-5.0.3.tgz", + "integrity": "sha512-VgDEoySsNJTi+g0niUaUlnzYGJTeJmNoAxX+2cUGsHrVg19wczEN76TkQY+KGGh8r8vOSyky3qNqMXv1ncBdoA==", + "dev": true, + "requires": { + "@types/koa": "*", + "@types/koa-compose": "*", + "@types/ws": "*" + } + }, + "@types/mime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", + "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==", + "dev": true + }, + "@types/node": { + "version": "10.12.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.11.tgz", + "integrity": "sha512-3iIOhNiPGTdcUNVCv9e5G7GotfvJJe2pc9w2UgDXlUwnxSZ3RgcUocIU+xYm+rTU54jIKih998QE4dMOyMN1NQ==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.2.tgz", + "integrity": "sha512-HtKGu+qG1NPvYe1z7ezLsyIaXYyi8SoAVqWDZgDQ8dLrsZvSzUNCwZyfX33uhWxL/SU0ZDQZ3nwZ0nimt507Kw==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, + "@types/ws": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.1.tgz", + "integrity": "sha512-EzH8k1gyZ4xih/MaZTXwT2xOkPiIMSrhQ9b8wrlX88L0T02eYsddatQlwVFlEPyEqV0ChpdpNnE51QPH6NVT4Q==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/node": "*" + } + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", diff --git a/packages/koa/package.json b/packages/koa/package.json index 8b4484c..cfdf1f3 100644 --- a/packages/koa/package.json +++ b/packages/koa/package.json @@ -13,7 +13,9 @@ "koa-websocket": "^5.0.1" }, "devDependencies": { - "@atlas.js/atlas": "^2.1.0" + "@atlas.js/atlas": "^2.1.0", + "@types/koa": "^2.0.47", + "@types/koa-websocket": "^5.0.3" }, "engines": { "node": ">=8.3.0", diff --git a/packages/koa/src/middleware.mjs b/packages/koa/src/middleware.mjs index bf73066..b0ef0a0 100644 --- a/packages/koa/src/middleware.mjs +++ b/packages/koa/src/middleware.mjs @@ -14,7 +14,7 @@ * @param {Koa} instance Koa-compatible instance. Must implement `.use()`. * @param {Handlers} handlers Object where keys are the middlewares' names and the * values are the actual middleware functions. - * @param {Object} config={} Configuration for individual middlewares. The keys should + * @param {Object=} config Configuration for individual middlewares. The keys should * match the middleware names. * @return {void} */ From 403394caa84aee7594694e684f2f98d0e66d4ac8 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Mon, 3 Dec 2018 15:53:34 +0100 Subject: [PATCH 11/35] feat(mongoose): export the whole mongoose package Useful when doing custom stuff and you need access to mongoose internals. Also great for type hinting to some extent. --- packages/mongoose/package-lock.json | 35 +++++++++++++++++++++++++++++ packages/mongoose/package.json | 3 ++- packages/mongoose/src/index.mjs | 9 ++++---- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/packages/mongoose/package-lock.json b/packages/mongoose/package-lock.json index 5b2fbfa..f20c58e 100644 --- a/packages/mongoose/package-lock.json +++ b/packages/mongoose/package-lock.json @@ -4,6 +4,41 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/bson": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-1.0.11.tgz", + "integrity": "sha512-j+UcCWI+FsbI5/FQP/Kj2CXyplWAz39ktHFkXk84h7dNblKRSoNJs95PZFRd96NQGqsPEPgeclqnznWZr14ZDA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/mongodb": { + "version": "3.1.15", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.1.15.tgz", + "integrity": "sha512-JSvtmrdrh88WH0Lo8Hq7sB1FkEChkrt6+fAZdFhEsRXcUetnrdU7wd2yar40tPg5wfRI2t31yduQgPiMUvgEEA==", + "dev": true, + "requires": { + "@types/bson": "*", + "@types/node": "*" + } + }, + "@types/mongoose": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.3.2.tgz", + "integrity": "sha512-BodywHKMSpitNsfktZiWfdYT+irLYHeLuknYk59zGTNpm8uoNZ1pLCH+dWMC3k2SlgiP7qL8ij+OlCRXDWkSrQ==", + "dev": true, + "requires": { + "@types/mongodb": "*", + "@types/node": "*" + } + }, + "@types/node": { + "version": "10.12.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.11.tgz", + "integrity": "sha512-3iIOhNiPGTdcUNVCv9e5G7GotfvJJe2pc9w2UgDXlUwnxSZ3RgcUocIU+xYm+rTU54jIKih998QE4dMOyMN1NQ==", + "dev": true + }, "async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", diff --git a/packages/mongoose/package.json b/packages/mongoose/package.json index ff747b8..19ce1e9 100644 --- a/packages/mongoose/package.json +++ b/packages/mongoose/package.json @@ -12,7 +12,8 @@ "mongoose": "^5.0.0" }, "devDependencies": { - "@atlas.js/atlas": "^2.1.0" + "@atlas.js/atlas": "^2.1.0", + "@types/mongoose": "^5.0.0" }, "engines": { "node": ">=8.3.0", diff --git a/packages/mongoose/src/index.mjs b/packages/mongoose/src/index.mjs index 37f35db..555c92f 100644 --- a/packages/mongoose/src/index.mjs +++ b/packages/mongoose/src/index.mjs @@ -1,13 +1,14 @@ -import { - Schema, - SchemaTypes, -} from 'mongoose' +import mongoose from 'mongoose' import Service from './service' import ModelsHook from './models' +const Schema = mongoose.Schema +const SchemaTypes = mongoose.SchemaTypes + export { Service, ModelsHook, Schema, SchemaTypes, + mongoose, } From 84d9543739e1f2959838d6067fe2ef54ea190bec Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Mon, 3 Dec 2018 16:07:55 +0100 Subject: [PATCH 12/35] feat(nodemailer): export the whole nodemailer package --- packages/nodemailer/package-lock.json | 22 ++++++++++++++++++++++ packages/nodemailer/package.json | 3 ++- packages/nodemailer/src/index.mjs | 2 ++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/nodemailer/package-lock.json b/packages/nodemailer/package-lock.json index 895dfe6..ccc9579 100644 --- a/packages/nodemailer/package-lock.json +++ b/packages/nodemailer/package-lock.json @@ -4,6 +4,28 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/events": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", + "dev": true + }, + "@types/node": { + "version": "10.12.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.11.tgz", + "integrity": "sha512-3iIOhNiPGTdcUNVCv9e5G7GotfvJJe2pc9w2UgDXlUwnxSZ3RgcUocIU+xYm+rTU54jIKih998QE4dMOyMN1NQ==", + "dev": true + }, + "@types/nodemailer": { + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-4.6.5.tgz", + "integrity": "sha512-cbs2HFLj33TBqzcCqTrs+6/mgTX3xl0odbApv3vTdF2+JERLxh5rDZCasXhvy+YqaiUNBr2I1RjNCdbKGs1Bnw==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/node": "*" + } + }, "nodemailer": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.7.0.tgz", diff --git a/packages/nodemailer/package.json b/packages/nodemailer/package.json index 35ba699..df9236a 100644 --- a/packages/nodemailer/package.json +++ b/packages/nodemailer/package.json @@ -10,7 +10,8 @@ "nodemailer": "^4.0.1" }, "devDependencies": { - "@atlas.js/atlas": "^2.1.0" + "@atlas.js/atlas": "^2.1.0", + "@types/nodemailer": "^4.0.1" }, "engines": { "node": ">=8.3.0", diff --git a/packages/nodemailer/src/index.mjs b/packages/nodemailer/src/index.mjs index 7d9a61c..22ea9b8 100644 --- a/packages/nodemailer/src/index.mjs +++ b/packages/nodemailer/src/index.mjs @@ -1,5 +1,7 @@ +import nodemailer from 'nodemailer' import Service from './service' export { Service, + nodemailer, } From 8edb617b32cc90951f59852f3196234340372527 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 10:23:49 +0100 Subject: [PATCH 13/35] feat(atlas): export the Config interface --- packages/atlas/src/index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/atlas/src/index.d.ts b/packages/atlas/src/index.d.ts index 827bc32..63666fa 100644 --- a/packages/atlas/src/index.d.ts +++ b/packages/atlas/src/index.d.ts @@ -259,6 +259,7 @@ declare module '@atlas.js/atlas' { export { Atlas, + Config, errors, } export { default as Action } from '@atlas.js/action' From 510df7c26704b2b7142acfe9ec3d1a887d6978bb Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 11:42:35 +0100 Subject: [PATCH 14/35] fix(service): fix types for method inputs, export ServiceApi declaration --- packages/service/src/index.d.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/service/src/index.d.ts b/packages/service/src/index.d.ts index 46e584d..7b7d401 100644 --- a/packages/service/src/index.d.ts +++ b/packages/service/src/index.d.ts @@ -12,7 +12,7 @@ declare module '@atlas.js/service' { * * @abstract */ - export default abstract class Service extends Component { + abstract class Service extends Component { /** @private */ static type: 'service' @@ -39,7 +39,7 @@ declare module '@atlas.js/service' { * @param ServiceApi The API your users will be interacting with. You should provide this * API as the return value of the `.prepare()` method. */ - abstract start(ServiceApi): Promise + abstract start(service: ServiceApi): Promise /** * Stop the service by terminating any pending connections and finishing all pending work @@ -48,6 +48,11 @@ declare module '@atlas.js/service' { * @param ServiceApi The API your users have interacted with. You created this API as the * return value of the `.prepare()` method. */ - abstract stop(ServiceApi): Promise + abstract stop(service: ServiceApi): Promise + } + + export default Service + export { + ServiceApi, } } From 85e6e2b2740b78394183403e96b2ffedde10cd79 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 12:06:43 +0100 Subject: [PATCH 15/35] chore: add {js,ts}config.json --- .gitignore | 1 - jsconfig.json | 18 ++++++++++++++++++ tsconfig.json | 22 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 jsconfig.json create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index e7a5575..01e49cb 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,3 @@ nbproject *.sublime-* *.atom-* .tern-* -jsconfig.json diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..900a292 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "charset": "utf8", + "module": "commonjs", + "moduleResolution": "node", + "target": "esnext", + "noEmit": true, + "checkJs": false, + "noImplicitAny": true + }, + "exclude": [ + "node_modules", + "**/node_modules/*" + ], + "typeAcquisition": { + "enable": true + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1dac3fe --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "charset": "utf8", + "module": "commonjs", + "moduleResolution": "node", + "target": "esnext", + "noEmit": true, + "noImplicitAny": true, + "skipLibCheck": false, + "noUnusedParameters": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "strictNullChecks": true + }, + "exclude": [ + "node_modules", + "**/node_modules/*" + ], + "typeAcquisition": { + "enable": true + } +} From e8f265405350b5e3cba3d51f0b296c30843a234d Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 12:13:38 +0100 Subject: [PATCH 16/35] feat(aws): add typings --- packages/aws/src/index.d.ts | 49 +++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 packages/aws/src/index.d.ts diff --git a/packages/aws/src/index.d.ts b/packages/aws/src/index.d.ts new file mode 100644 index 0000000..f976c6a --- /dev/null +++ b/packages/aws/src/index.d.ts @@ -0,0 +1,49 @@ +declare module '@atlas.js/aws' { + import * as AWS from 'aws-sdk' + import { GlobalConfigInstance } from 'aws-sdk/lib/config' + import * as AWSClients from 'aws-sdk/clients/all' + import AtlasService from '@atlas.js/service' + import { ServiceApi } from '@atlas.js/service' + + type ServiceName = string + type ServiceConfig = object + type AWSServiceApi = { + [key: string]: object + } + + interface Config { + /** Global configuration options which will be applied into every service */ + globals: GlobalConfigInstance + + /** + * Configuration options which will be applied only to specific services + * + * ⚠️ Note that only services for which a configuration object has been defined will be made + * available, so make sure you declare at least an empty object here if you want to use that + * service. + */ + services?: { + [key: string]: GlobalConfigInstance + } + } + + class Service extends AtlasService { + config: GlobalConfigInstance + + /** + * Prepare an AWS client instance + * + * ⚠️ Note that the client will only include services for which a key in the configuration has + * been defined. + */ + prepare(): Promise + start(service: AWSServiceApi): Promise + stop(service: AWSServiceApi): Promise + } + + export { + Service, + Config, + AWS, + } +} From 1ee849ad7ba106cf4298d39844f5db7f5a221cff Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 12:21:36 +0100 Subject: [PATCH 17/35] fix(atlas): fix type definition issues --- packages/atlas/src/index.d.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/atlas/src/index.d.ts b/packages/atlas/src/index.d.ts index 63666fa..096931e 100644 --- a/packages/atlas/src/index.d.ts +++ b/packages/atlas/src/index.d.ts @@ -1,8 +1,8 @@ declare module '@atlas.js/atlas' { import * as errors from '@atlas.js/errors' import Component from '@atlas.js/component' - import Ajv from 'ajv' - import Pino from 'pino' + import * as Ajv from 'ajv' + import * as Pino from 'pino' interface ComponentConstructor { new (): Component @@ -51,9 +51,9 @@ declare module '@atlas.js/atlas' { * * If string is provided, it will be used as path relative to `root` and required. The resulting * object will be used as the configuration object. If an object is provided, it will be used - * as-is. + * as-is. Default: `'config'` */ - config: Config | string + config?: Config | string } interface InitOptions extends Options { @@ -103,7 +103,7 @@ declare module '@atlas.js/atlas' { /** * The main point of interaction with Atlas. */ - declare class Atlas { + class Atlas { /** * Default values for configuration options which Atlas accepts. */ From 3ba35721dc4fd7035c0f07d793d53ce87083ec8e Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 12:47:30 +0100 Subject: [PATCH 18/35] feat(braintree): add typings --- packages/braintree/src/index.d.ts | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 packages/braintree/src/index.d.ts diff --git a/packages/braintree/src/index.d.ts b/packages/braintree/src/index.d.ts new file mode 100644 index 0000000..69475af --- /dev/null +++ b/packages/braintree/src/index.d.ts @@ -0,0 +1,40 @@ +declare module '@atlas.js/braintree' { + import AtlasService from '@atlas.js/service' + import { ServiceApi } from '@atlas.js/service' + + // @TODO: Braintree does not have typings. Watch for any changes to that situation. 👀 + type Braintree = object + + interface Config { + /** + * Environment to connect to + * + * Available values: + * + * ```js + * import { Braintree } from '@atlas.js/braintree' + * + * Braintree.Environment.{choose one} + * ``` + */ + environment: object + + merchantId: string + publicKey: string + privateKey: string + } + + class Service extends AtlasService { + config: Config + + prepare(): Promise + start(service: ServiceApi): Promise + stop(service: ServiceApi): Promise + } + + export { + Service, + Config, + Braintree, + } +} From 363ab9297916ca126067e4dcf69b6b3216e9b141 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 12:52:38 +0100 Subject: [PATCH 19/35] fix(atlas): add missing @types/pino to deps --- packages/atlas/package-lock.json | 19 +++++++++++++++++++ packages/atlas/package.json | 1 + 2 files changed, 20 insertions(+) diff --git a/packages/atlas/package-lock.json b/packages/atlas/package-lock.json index d31172f..7914501 100644 --- a/packages/atlas/package-lock.json +++ b/packages/atlas/package-lock.json @@ -4,6 +4,25 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/events": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==" + }, + "@types/node": { + "version": "10.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.12.tgz", + "integrity": "sha512-Pr+6JRiKkfsFvmU/LK68oBRCQeEg36TyAbPhc2xpez24OOZZCuoIhWGTd39VZy6nGafSbxzGouFPTFD/rR1A0A==" + }, + "@types/pino": { + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@types/pino/-/pino-4.16.1.tgz", + "integrity": "sha512-uYEhZ3jsuiYFsPcR34fbxVlrqzqphc+QQ3fU4rWR6PXH8ka2TKvPBjtkNqj8oBHouVGf4GCRfyPb7FG2TEtPZA==", + "requires": { + "@types/events": "*", + "@types/node": "*" + } + }, "ajv": { "version": "6.5.5", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", diff --git a/packages/atlas/package.json b/packages/atlas/package.json index f133035..fb327ac 100644 --- a/packages/atlas/package.json +++ b/packages/atlas/package.json @@ -10,6 +10,7 @@ "@atlas.js/errors": "^0.2.1", "@atlas.js/hook": "^2.0.1", "@atlas.js/service": "^1.1.1", + "@types/pino": "^4.7.0", "ajv": "^6.5.0", "ajv-keywords": "^3.2.0", "lodash": "^4.17.4", From 98ffb350fe50ab0384e4b4f094fd781b582358c1 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 12:53:04 +0100 Subject: [PATCH 20/35] fix(component): add missing @types/pino to deps --- packages/component/package-lock.json | 27 +++++++++++++++++++++++++++ packages/component/package.json | 4 +++- packages/component/src/index.d.ts | 2 +- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 packages/component/package-lock.json diff --git a/packages/component/package-lock.json b/packages/component/package-lock.json new file mode 100644 index 0000000..ebb3bf0 --- /dev/null +++ b/packages/component/package-lock.json @@ -0,0 +1,27 @@ +{ + "name": "@atlas.js/component", + "version": "2.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/events": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==" + }, + "@types/node": { + "version": "10.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.12.tgz", + "integrity": "sha512-Pr+6JRiKkfsFvmU/LK68oBRCQeEg36TyAbPhc2xpez24OOZZCuoIhWGTd39VZy6nGafSbxzGouFPTFD/rR1A0A==" + }, + "@types/pino": { + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@types/pino/-/pino-4.16.1.tgz", + "integrity": "sha512-uYEhZ3jsuiYFsPcR34fbxVlrqzqphc+QQ3fU4rWR6PXH8ka2TKvPBjtkNqj8oBHouVGf4GCRfyPb7FG2TEtPZA==", + "requires": { + "@types/events": "*", + "@types/node": "*" + } + } + } +} diff --git a/packages/component/package.json b/packages/component/package.json index ea98884..3007aec 100644 --- a/packages/component/package.json +++ b/packages/component/package.json @@ -5,7 +5,9 @@ "author": "Robert Rossmann ", "bugs": "https://github.com/strvcom/atlas.js/issues", "contributors": [], - "dependencies": {}, + "dependencies": { + "@types/pino": "^4.7.0" + }, "engines": { "node": ">=8.3.0", "npm": "^5.3.0" diff --git a/packages/component/src/index.d.ts b/packages/component/src/index.d.ts index 0cda419..b202622 100644 --- a/packages/component/src/index.d.ts +++ b/packages/component/src/index.d.ts @@ -1,5 +1,5 @@ declare module '@atlas.js/component' { - import Pino from 'pino' + import * as Pino from 'pino' import { Atlas } from '@atlas.js/atlas' type ComponentName = string From a0ddbfe6575a205bab5030f5507d0a2d43ce35ca Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 12:54:24 +0100 Subject: [PATCH 21/35] fix(errors): fix type declarations --- packages/errors/src/index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/errors/src/index.d.ts b/packages/errors/src/index.d.ts index ee1bac7..6304640 100644 --- a/packages/errors/src/index.d.ts +++ b/packages/errors/src/index.d.ts @@ -1,12 +1,12 @@ declare module '@atlas.js/errors' { - import ajv from 'ajv' + import * as Ajv from 'ajv' export class FrameworkError extends Error { } export class ValidationError extends FrameworkError { - constructor(errors: Array) + constructor(errors: Array) /** Errors returned by Ajv */ - errors: Array + errors: Array } } From 3a60ce715accee8335ef8e3800fc5464a5749cb2 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 13:36:42 +0100 Subject: [PATCH 22/35] fix(firebase): allow additional configuration properties --- packages/firebase/src/service.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/firebase/src/service.mjs b/packages/firebase/src/service.mjs index a2224b3..7b52c62 100644 --- a/packages/firebase/src/service.mjs +++ b/packages/firebase/src/service.mjs @@ -5,7 +5,6 @@ class Firebase extends Service { /** Firebase configuration schema */ static config = { type: 'object', - additionalProperties: false, default: {}, properties: { name: { type: 'string' }, From d113ecdc04a360eee89221cf2d0f38dfe13f9357 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 14:01:57 +0100 Subject: [PATCH 23/35] feat(firebase): add typings --- packages/firebase/src/index.d.ts | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 packages/firebase/src/index.d.ts diff --git a/packages/firebase/src/index.d.ts b/packages/firebase/src/index.d.ts new file mode 100644 index 0000000..114f140 --- /dev/null +++ b/packages/firebase/src/index.d.ts @@ -0,0 +1,33 @@ +declare module '@atlas.js/firebase' { + import * as firebase from 'firebase-admin' + import AtlasService from '@atlas.js/service' + + interface Config extends firebase.AppOptions { + /** + * Define the Firebase App's name + * Default: `'default'` + */ + name?: string + /** + * Provide the credentials for Firebase + * This can optionally be a `string`, in which case the string will be treated as a module + * location relative to Atlas' root and the actual credentials will be `require()` from that + * module. + */ + credential: firebase.credential.Credential + } + + class Service extends AtlasService { + config: Config + + prepare(): Promise + start(service: firebase.app.App): Promise + stop(service: firebase.app.App): Promise + } + + export { + Service, + Config, + firebase, + } +} From 849e62d6f76b89d59450be41db5be017494a43f5 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Tue, 4 Dec 2018 19:13:39 +0100 Subject: [PATCH 24/35] feat(koa): add typings --- packages/koa/package-lock.json | 38 +++++++--------- packages/koa/package.json | 2 + packages/koa/src/context.d.ts | 28 ++++++++++++ packages/koa/src/index.d.ts | 13 ++++++ packages/koa/src/server.d.ts | 80 +++++++++++++++++++++++++++++++++ packages/koa/src/server.mjs | 1 + packages/koa/src/websocket.d.ts | 45 +++++++++++++++++++ 7 files changed, 185 insertions(+), 22 deletions(-) create mode 100644 packages/koa/src/context.d.ts create mode 100644 packages/koa/src/index.d.ts create mode 100644 packages/koa/src/server.d.ts create mode 100644 packages/koa/src/websocket.d.ts diff --git a/packages/koa/package-lock.json b/packages/koa/package-lock.json index 022cf20..6f963b4 100644 --- a/packages/koa/package-lock.json +++ b/packages/koa/package-lock.json @@ -8,7 +8,6 @@ "version": "1.3.5", "resolved": "http://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", - "dev": true, "requires": { "@types/node": "*" } @@ -17,7 +16,6 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz", "integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==", - "dev": true, "requires": { "@types/connect": "*", "@types/node": "*" @@ -27,7 +25,6 @@ "version": "3.4.32", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", - "dev": true, "requires": { "@types/node": "*" } @@ -36,7 +33,6 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.1.tgz", "integrity": "sha512-ku6IvbucEyuC6i4zAVK/KnuzWNXdbFd1HkXlNLg/zhWDGTtQT5VhumiPruB/BHW34PWVFwyfwGftDQHfWNxu3Q==", - "dev": true, "requires": { "@types/connect": "*", "@types/express": "*", @@ -47,14 +43,12 @@ "@types/events": { "version": "1.2.0", "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", - "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", - "dev": true + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==" }, "@types/express": { "version": "4.16.0", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.16.0.tgz", "integrity": "sha512-TtPEYumsmSTtTetAPXlJVf3kEqb6wZK0bZojpJQrnD/djV4q1oB6QQ8aKvKqwNPACoe02GNiy5zDzcYivR5Z2w==", - "dev": true, "requires": { "@types/body-parser": "*", "@types/express-serve-static-core": "*", @@ -65,7 +59,6 @@ "version": "4.16.0", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz", "integrity": "sha512-lTeoCu5NxJU4OD9moCgm0ESZzweAx0YqsAcab6OB0EB3+As1OaHtKnaGJvcngQxYsi9UNv0abn4/DRavrRxt4w==", - "dev": true, "requires": { "@types/events": "*", "@types/node": "*", @@ -75,20 +68,17 @@ "@types/http-assert": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.3.0.tgz", - "integrity": "sha512-RObYTpPMo0IY+ZksPtKHsXlYFRxsYIvUqd68e89Y7otDrXsjBy1VgMd53kxVV0JMsNlkCASjllFOlLlhxEv0iw==", - "dev": true + "integrity": "sha512-RObYTpPMo0IY+ZksPtKHsXlYFRxsYIvUqd68e89Y7otDrXsjBy1VgMd53kxVV0JMsNlkCASjllFOlLlhxEv0iw==" }, "@types/keygrip": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.1.tgz", - "integrity": "sha1-/1QEYtL7TQqIRBzq8n0oewHD2Hg=", - "dev": true + "integrity": "sha1-/1QEYtL7TQqIRBzq8n0oewHD2Hg=" }, "@types/koa": { "version": "2.0.47", "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.0.47.tgz", "integrity": "sha512-llhCaHNWKFDMx1GCrqwgsWgUO+C4Da0SccbgevHIYOKVxwegEjFzl0WaMWHk3wWx0P0AdqHR+gQYZ2ZAb0ez0Q==", - "dev": true, "requires": { "@types/accepts": "*", "@types/cookies": "*", @@ -101,8 +91,7 @@ "@types/koa-compose": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.2.tgz", - "integrity": "sha1-3BBuAAu/kqOskA91bfRzRIh+6Ec=", - "dev": true + "integrity": "sha1-3BBuAAu/kqOskA91bfRzRIh+6Ec=" }, "@types/koa-websocket": { "version": "5.0.3", @@ -118,26 +107,31 @@ "@types/mime": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", - "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==", - "dev": true + "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==" }, "@types/node": { "version": "10.12.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.11.tgz", - "integrity": "sha512-3iIOhNiPGTdcUNVCv9e5G7GotfvJJe2pc9w2UgDXlUwnxSZ3RgcUocIU+xYm+rTU54jIKih998QE4dMOyMN1NQ==", - "dev": true + "integrity": "sha512-3iIOhNiPGTdcUNVCv9e5G7GotfvJJe2pc9w2UgDXlUwnxSZ3RgcUocIU+xYm+rTU54jIKih998QE4dMOyMN1NQ==" + }, + "@types/pino": { + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@types/pino/-/pino-4.16.1.tgz", + "integrity": "sha512-uYEhZ3jsuiYFsPcR34fbxVlrqzqphc+QQ3fU4rWR6PXH8ka2TKvPBjtkNqj8oBHouVGf4GCRfyPb7FG2TEtPZA==", + "requires": { + "@types/events": "*", + "@types/node": "*" + } }, "@types/range-parser": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.2.tgz", - "integrity": "sha512-HtKGu+qG1NPvYe1z7ezLsyIaXYyi8SoAVqWDZgDQ8dLrsZvSzUNCwZyfX33uhWxL/SU0ZDQZ3nwZ0nimt507Kw==", - "dev": true + "integrity": "sha512-HtKGu+qG1NPvYe1z7ezLsyIaXYyi8SoAVqWDZgDQ8dLrsZvSzUNCwZyfX33uhWxL/SU0ZDQZ3nwZ0nimt507Kw==" }, "@types/serve-static": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==", - "dev": true, "requires": { "@types/express-serve-static-core": "*", "@types/mime": "*" diff --git a/packages/koa/package.json b/packages/koa/package.json index cfdf1f3..e3c296f 100644 --- a/packages/koa/package.json +++ b/packages/koa/package.json @@ -9,6 +9,8 @@ "@atlas.js/errors": "^0.2.1", "@atlas.js/hook": "^2.0.1", "@atlas.js/service": "^1.1.1", + "@types/pino": "^4.7.0", + "@types/koa": "^2.0.0", "koa": "^2.3.0", "koa-websocket": "^5.0.1" }, diff --git a/packages/koa/src/context.d.ts b/packages/koa/src/context.d.ts new file mode 100644 index 0000000..50bfe27 --- /dev/null +++ b/packages/koa/src/context.d.ts @@ -0,0 +1,28 @@ +import AtlasHook from '@atlas.js/hook' + +/** + * This hook allows you to extend the default `Koa.Context` object with custom properties + * + * You specify a module from which to load an object and that object's enumerable properties will + * be copied over onto `Koa.Context`. This means that all those properties will be available from + * within route handlers on the `ctx` function argument. + */ +declare class ContextHook extends AtlasHook { + config: ContextHook.Config + + afterPrepare(): void +} + +declare namespace ContextHook { + /** Configuration options for the ContextHook hook */ + interface Config { + /** + * Location of the module, relative to `atlas.root`, from which to load the properties to extend + * the base Koa.Context with + * Default: `koa-context` + */ + module: string + } +} + +export = ContextHook diff --git a/packages/koa/src/index.d.ts b/packages/koa/src/index.d.ts new file mode 100644 index 0000000..e42f320 --- /dev/null +++ b/packages/koa/src/index.d.ts @@ -0,0 +1,13 @@ +import * as Server from './server' +import * as ContextHook from './context' +import * as WebsocketHook from './websocket' +import * as Koa from 'koa' + +declare module '@atlas.js/koa' { + export { + Server, + ContextHook, + WebsocketHook, + Koa, + } +} diff --git a/packages/koa/src/server.d.ts b/packages/koa/src/server.d.ts new file mode 100644 index 0000000..8370cde --- /dev/null +++ b/packages/koa/src/server.d.ts @@ -0,0 +1,80 @@ +import * as Koa from 'koa' +import * as Pino from 'pino' +import { Atlas } from '@atlas.js/atlas' +import AtlasService from '@atlas.js/service' + +type MiddlewareConfig = object + +/** + * The Server service which manages a Koa instance + * + * Use this service to start a Koa server as part of Atlas. + */ +declare class Server extends AtlasService { + config: Server.Config + + prepare(): Promise + start(service: Koa): Promise + stop(service: Koa): Promise +} + +declare namespace Server { + /** + * A Koa Context, enhanced with some extra properties to make it easy to interact with Atlas from + * within a route handler + */ + interface Context extends Koa.Context { + atlas: Atlas + log: Pino.Logger + } + + /** Configuration schema for the Server service */ + interface Config { + /** Configuration for the middleware loader */ + middleware: { + /** + * The middleware loader will load the middleware to register with this Koa instance at this + * module location, relative to `atlas.root`. + * Default: `'middleware'` + */ + module: string + /** + * Configuration options for the individual middleware. The key should match the name of the + * middleware under which it was exported from the module you specified in the `module` + * configuration. The value will be passed directly to the middleware function. + */ + config: { + [key: string]: MiddlewareConfig + } + } + + // @TODO(semver-major): change this to match `net.ListenOptions`. + /** Configuration options specifying where to listen for incoming requests */ + listen: { + /** + * Port to listen on + * Default: `3000` + */ + port: number + /** + * Hostname to listen on + * Default: `127.0.0.1` + */ + hostname: string + } + + /** Configuration options applied to the `http.Server` instance using `Object.assign()` */ + server: { + maxHeadersCount: number; + timeout: number; + keepAliveTimeout: number; + } + + /** Settings applied to the `Koa` instance directly using `Object.assign()` */ + koa: { + proxy: boolean + } + } +} + +export = Server diff --git a/packages/koa/src/server.mjs b/packages/koa/src/server.mjs index fb8a100..ca8ce0a 100644 --- a/packages/koa/src/server.mjs +++ b/packages/koa/src/server.mjs @@ -25,6 +25,7 @@ class KoaService extends Service { }, }, + // @TODO(semver-major): change this to an object matching the http.Server.listen({}) pattern listen: { type: 'object', additionalProperties: false, diff --git a/packages/koa/src/websocket.d.ts b/packages/koa/src/websocket.d.ts new file mode 100644 index 0000000..ee82525 --- /dev/null +++ b/packages/koa/src/websocket.d.ts @@ -0,0 +1,45 @@ +import AtlasHook from '@atlas.js/hook' +import * as ws from 'ws' + + +type MiddlewareConfig = object + +/** + * Attach a websocket interface to a regular Koa server + * + * This allows you to upgrade your regular Koa server with websocker capabilities. + */ +declare class WebsocketHook extends AtlasHook { + config: WebsocketHook.Config + + afterPrepare(): void + afterStart(): void + beforeStop(): Promise +} + +declare namespace WebsocketHook { + interface Config { + /** Configuration for the websocket's middleware loader */ + middleware: { + /** + * The middleware loader will load the middleware for the websocket interface at this module + * location, relative to `atlas.root`. + * Default: `'websocket/middleware'` + */ + module: string + /** + * Configuration options for the individual middleware. The key should match the name of the + * middleware under which it was exported from the module you specified in the `module` + * configuration. The value will be passed directly to the middleware function. + */ + config: { + [key: string]: MiddlewareConfig + } + } + + /** Configuration options for the `ws.listen()` method */ + listen: ws.ServerOptions + } +} + +export = WebsocketHook From b8f2feb3711727a00794cd49495ea6a75d4cee2a Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 11:37:30 +0100 Subject: [PATCH 25/35] chore(mongoose): drop no longer-used defaults --- packages/mongoose/src/service.mjs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/mongoose/src/service.mjs b/packages/mongoose/src/service.mjs index 13d94a4..d16a49d 100644 --- a/packages/mongoose/src/service.mjs +++ b/packages/mongoose/src/service.mjs @@ -24,11 +24,6 @@ class Mongoose extends Service { }, } - static defaults = { - uri: 'mongodb://127.0.0.1:27017', - options: {}, - } - /** * Prepare the service * From 930d4af6e06b23c5b3cee36ec4ce2999ef4783aa Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 13:03:51 +0100 Subject: [PATCH 26/35] feat(mongoose): add typings --- packages/mongoose/src/index.d.ts | 14 +++++++++++++ packages/mongoose/src/models.d.ts | 27 +++++++++++++++++++++++++ packages/mongoose/src/service.d.ts | 32 ++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 packages/mongoose/src/index.d.ts create mode 100644 packages/mongoose/src/models.d.ts create mode 100644 packages/mongoose/src/service.d.ts diff --git a/packages/mongoose/src/index.d.ts b/packages/mongoose/src/index.d.ts new file mode 100644 index 0000000..b35e019 --- /dev/null +++ b/packages/mongoose/src/index.d.ts @@ -0,0 +1,14 @@ +import Service from './service' +import ModelsHook from './models' +import * as mongoose from 'mongoose' +import { Schema, SchemaTypes } from 'mongoose' + +declare module '@atlas.js/mongoose' { + export { + Service, + ModelsHook, + Schema, + SchemaTypes, + mongoose, + } +} diff --git a/packages/mongoose/src/models.d.ts b/packages/mongoose/src/models.d.ts new file mode 100644 index 0000000..0bbc296 --- /dev/null +++ b/packages/mongoose/src/models.d.ts @@ -0,0 +1,27 @@ +import AtlasHook from '@atlas.js/hook' + +/** + * This hook allows you to load your Mongoose schemas from a particular module location and add them + * to the Mongoose service as models. + * + * The models exported at the specified location will then be accessible via + * `atlas.services.mongoose.model('name')`. + */ +declare class ModelsHook extends AtlasHook { + config: ModelsHook.Config + + afterPrepare(): void +} + +declare namespace ModelsHook { + /** Configuration schema available to this hook */ + interface Config { + /** + * The module location, relative to `atlas.root`, from which to load the Mongoose models + * Default: `'models'` + */ + module: string + } +} + +export = ModelsHook diff --git a/packages/mongoose/src/service.d.ts b/packages/mongoose/src/service.d.ts new file mode 100644 index 0000000..6002c01 --- /dev/null +++ b/packages/mongoose/src/service.d.ts @@ -0,0 +1,32 @@ +import AtlasService from '@atlas.js/service' +import { Mongoose, ConnectionOptions } from 'mongoose' + +/** + * Connect to a MongoDB server using the mongoose ODM + * + * This service allows you to connect to a MongoDB server and use the mongoose object document + * model that comes with it from within Atlas. + */ +declare class Service extends AtlasService { + /** Service runtime configuration values, with defaults applied */ + config: Service.Config + + prepare(): Promise + start(service: Mongoose): Promise + stop(service: Mongoose): Promise +} + +declare namespace Service { + /** Configuration schema available to this service */ + interface Config { + /** + * MongoDB URI to connect to + * Default: `mongodb://127.0.0.1:27017` + */ + uri: string + /** Additional connection options */ + options: ConnectionOptions + } +} + +export = Service From 4d6e6dc5a447f93ebbd031d7308b0f1ddbbcbc99 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 13:09:00 +0100 Subject: [PATCH 27/35] feat(koa): add typings --- packages/koa/src/context.d.ts | 2 +- packages/koa/src/server.d.ts | 2 +- packages/koa/src/websocket.d.ts | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/koa/src/context.d.ts b/packages/koa/src/context.d.ts index 50bfe27..01a2eab 100644 --- a/packages/koa/src/context.d.ts +++ b/packages/koa/src/context.d.ts @@ -14,7 +14,7 @@ declare class ContextHook extends AtlasHook { } declare namespace ContextHook { - /** Configuration options for the ContextHook hook */ + /** Configuration schema available to this hook */ interface Config { /** * Location of the module, relative to `atlas.root`, from which to load the properties to extend diff --git a/packages/koa/src/server.d.ts b/packages/koa/src/server.d.ts index 8370cde..bee5cd8 100644 --- a/packages/koa/src/server.d.ts +++ b/packages/koa/src/server.d.ts @@ -28,7 +28,7 @@ declare namespace Server { log: Pino.Logger } - /** Configuration schema for the Server service */ + /** Configuration schema available to this service */ interface Config { /** Configuration for the middleware loader */ middleware: { diff --git a/packages/koa/src/websocket.d.ts b/packages/koa/src/websocket.d.ts index ee82525..6d16d60 100644 --- a/packages/koa/src/websocket.d.ts +++ b/packages/koa/src/websocket.d.ts @@ -18,6 +18,7 @@ declare class WebsocketHook extends AtlasHook { } declare namespace WebsocketHook { + /** Configuration schema available to this hook */ interface Config { /** Configuration for the websocket's middleware loader */ middleware: { From 6c2095b744faae5e51f260cd4499b9da03bf5954 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 13:09:07 +0100 Subject: [PATCH 28/35] feat(firebase): add typings --- packages/firebase/src/index.d.ts | 43 +++++++++++++++++++------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/packages/firebase/src/index.d.ts b/packages/firebase/src/index.d.ts index 114f140..0b44b6a 100644 --- a/packages/firebase/src/index.d.ts +++ b/packages/firebase/src/index.d.ts @@ -2,32 +2,41 @@ declare module '@atlas.js/firebase' { import * as firebase from 'firebase-admin' import AtlasService from '@atlas.js/service' - interface Config extends firebase.AppOptions { - /** - * Define the Firebase App's name - * Default: `'default'` - */ - name?: string - /** - * Provide the credentials for Firebase - * This can optionally be a `string`, in which case the string will be treated as a module - * location relative to Atlas' root and the actual credentials will be `require()` from that - * module. - */ - credential: firebase.credential.Credential - } - + /** + * Start a Firebase instance from within Atlas + * + * This service allows you to configure a Firebase app and use all available Firebase services, + * like the realtime database, Firestore etc. + */ class Service extends AtlasService { - config: Config + /** Service runtime configuration values */ + config: Service.Config prepare(): Promise start(service: firebase.app.App): Promise stop(service: firebase.app.App): Promise } + namespace Service { + /** Configuration schema available to this service */ + interface Config extends firebase.AppOptions { + /** + * Define the Firebase App's name + * Default: `'default'` + */ + name?: string + /** + * Provide the credentials for Firebase + * This can optionally be a `string`, in which case the string will be treated as a module + * location relative to Atlas' root and the actual credentials will be `require()` from that + * module. + */ + credential: firebase.credential.Credential + } + } + export { Service, - Config, firebase, } } From d1d5755a5930de26217ca23dfa8a0d78744dfed5 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 13:09:16 +0100 Subject: [PATCH 29/35] feat(braintree): add typings --- packages/braintree/src/index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/braintree/src/index.d.ts b/packages/braintree/src/index.d.ts index 69475af..6bec2a5 100644 --- a/packages/braintree/src/index.d.ts +++ b/packages/braintree/src/index.d.ts @@ -5,6 +5,7 @@ declare module '@atlas.js/braintree' { // @TODO: Braintree does not have typings. Watch for any changes to that situation. 👀 type Braintree = object + /** Configuration schema available to this service */ interface Config { /** * Environment to connect to From 60240295666b2d2a08ab8491c04041b7be279b4a Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 13:09:23 +0100 Subject: [PATCH 30/35] feat(aws): add typings --- packages/aws/src/index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/aws/src/index.d.ts b/packages/aws/src/index.d.ts index f976c6a..26327cf 100644 --- a/packages/aws/src/index.d.ts +++ b/packages/aws/src/index.d.ts @@ -11,6 +11,7 @@ declare module '@atlas.js/aws' { [key: string]: object } + /** Configuration schema available to this service */ interface Config { /** Global configuration options which will be applied into every service */ globals: GlobalConfigInstance From ea088d182590e3f20e361bd6f592f8ac741a1ada Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 13:10:30 +0100 Subject: [PATCH 31/35] feat(errors): add typings --- packages/errors/src/index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/errors/src/index.d.ts b/packages/errors/src/index.d.ts index 6304640..b6fef19 100644 --- a/packages/errors/src/index.d.ts +++ b/packages/errors/src/index.d.ts @@ -1,12 +1,12 @@ declare module '@atlas.js/errors' { - import * as Ajv from 'ajv' + import { ErrorObject } from 'ajv' export class FrameworkError extends Error { } export class ValidationError extends FrameworkError { - constructor(errors: Array) + constructor(errors: Array) /** Errors returned by Ajv */ - errors: Array + errors: Array } } From 630aa63f1be0703389bd477c2b82cb45ae1efc3b Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 13:12:48 +0100 Subject: [PATCH 32/35] feat(braintree): add typings --- packages/braintree/src/index.d.ts | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/braintree/src/index.d.ts b/packages/braintree/src/index.d.ts index 6bec2a5..9e25c4d 100644 --- a/packages/braintree/src/index.d.ts +++ b/packages/braintree/src/index.d.ts @@ -5,37 +5,37 @@ declare module '@atlas.js/braintree' { // @TODO: Braintree does not have typings. Watch for any changes to that situation. 👀 type Braintree = object - /** Configuration schema available to this service */ - interface Config { - /** - * Environment to connect to - * - * Available values: - * - * ```js - * import { Braintree } from '@atlas.js/braintree' - * - * Braintree.Environment.{choose one} - * ``` - */ - environment: object - - merchantId: string - publicKey: string - privateKey: string - } - class Service extends AtlasService { - config: Config + /** Runtime configuration values */ + config: Service.Config prepare(): Promise start(service: ServiceApi): Promise stop(service: ServiceApi): Promise } + namespace Service { + /** Configuration schema available to this service */ + interface Config { + /** + * Environment to connect to + * + * Available values: + * + * ```js + * import { Braintree } from '@atlas.js/braintree' + * Braintree.Environment.{choose one} + * ``` + */ + environment: object + merchantId: string + publicKey: string + privateKey: string + } + } + export { Service, - Config, Braintree, } } From 418d36577ba6e81ec19fb9df03196eb82144e43b Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 13:24:23 +0100 Subject: [PATCH 33/35] feat(aws): add typings --- packages/aws/src/index.d.ts | 50 +++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/packages/aws/src/index.d.ts b/packages/aws/src/index.d.ts index 26327cf..e1511c1 100644 --- a/packages/aws/src/index.d.ts +++ b/packages/aws/src/index.d.ts @@ -3,33 +3,21 @@ declare module '@atlas.js/aws' { import { GlobalConfigInstance } from 'aws-sdk/lib/config' import * as AWSClients from 'aws-sdk/clients/all' import AtlasService from '@atlas.js/service' - import { ServiceApi } from '@atlas.js/service' - type ServiceName = string - type ServiceConfig = object type AWSServiceApi = { [key: string]: object } - /** Configuration schema available to this service */ - interface Config { - /** Global configuration options which will be applied into every service */ - globals: GlobalConfigInstance - - /** - * Configuration options which will be applied only to specific services - * - * ⚠️ Note that only services for which a configuration object has been defined will be made - * available, so make sure you declare at least an empty object here if you want to use that - * service. - */ - services?: { - [key: string]: GlobalConfigInstance - } - } - + /** + * Load and set up AWS services for use from within Atlas + * + * This class loads the AWS clients for which it will find a configuration object (even if it is + * empty). This is done to reduce memory footprint (the AWS SDK it huge!), so only specified + * clients will be loaded. + */ class Service extends AtlasService { - config: GlobalConfigInstance + /** Runtime configuration values */ + config: Service.Config /** * Prepare an AWS client instance @@ -42,9 +30,27 @@ declare module '@atlas.js/aws' { stop(service: AWSServiceApi): Promise } + namespace Service { + /** Configuration schema available to this service */ + interface Config { + /** Global configuration options which will be applied into every service */ + globals: GlobalConfigInstance + + /** + * Configuration options which will be applied only to specific services + * + * ⚠️ Note that only services for which a configuration object has been defined will be made + * available, so make sure you declare at least an empty object here if you want to use that + * service. + */ + services?: { + [key: string]: GlobalConfigInstance + } + } + } + export { Service, - Config, AWS, } } From 1e1cc178c6abd614efa2fca8fd3fea789f59cc57 Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 16:14:04 +0100 Subject: [PATCH 34/35] feat(atlas): add typings --- packages/atlas/src/atlas.d.ts | 271 ++++++++++++++++++++++++++++++++++ packages/atlas/src/index.d.ts | 268 +-------------------------------- 2 files changed, 279 insertions(+), 260 deletions(-) create mode 100644 packages/atlas/src/atlas.d.ts diff --git a/packages/atlas/src/atlas.d.ts b/packages/atlas/src/atlas.d.ts new file mode 100644 index 0000000..845cbf2 --- /dev/null +++ b/packages/atlas/src/atlas.d.ts @@ -0,0 +1,271 @@ +import * as Ajv from 'ajv' +import * as Pino from 'pino' +import Component from '@atlas.js/component' + +declare interface ComponentConstructor { + new (): Component +} + +/** Input options for `Atlas.init()` */ +declare interface InitOptions extends Options { + /** Path to a module from which service components should be loaded. Default: `services` */ + services?: string + /** Path to a module from which action components should be loaded. Default: `actions` */ + actions?: string + /** Path to a module from which hook components should be loaded. Default: `hooks` */ + hooks?: string + /** + * Path to a module from which component configuration should be loaded (or the configuration + * object itself). Default: `config` + */ + config?: Options["config"] +} + +/** Input options for `Atlas.bootstrap()` */ +declare interface BootstrapOptions extends Options { + /** + * All services to be added to Atlas. The key is the alias for the component and the value is + * the Component class itself (ie. `new Component()` will be called on the value). + */ + services: { [key: string]: ComponentConstructor } + /** + * All actions to be added to Atlas. The key is the alias for the component and the value is + * the Component class itself (ie. `new Component()` will be called on the value). + */ + actions: { [key: string]: ComponentConstructor } + /** + * All hooks to be added to Atlas. The key is the alias for the component and the value is + * the Component class itself (ie. `new Component()` will be called on the value). + */ + hooks: { [key: string]: ComponentConstructor } +} + +/** + * Input options for the second argument of `atlas.action()`, `atlas.service()`, `atlas.hook()` + */ +declare interface ComponentOptions { + /** + * If this component requires other components, you must specify their aliases you chose for + * them here. The key is the component name which is used by this component, and the value + * is the alias you chose for that compoennt in this instance of Atlas. + */ + aliases: { + [name: string]: string + } +} + +/** Input options for the second argument of `atlas.require()` */ +declare interface RequireOptions { + /** If true, do not throw if the module does not exist */ + optional: boolean, + /** If true, prefer the ES modules' `default` export over named or CommonJS exports */ + normalise: boolean, + /** + * If true, will try to load the module without resolving the specified location to the project + * root (it will load the module using standard Node's mechanism). + */ + absolute: boolean +} + +/** Input options for the `new Atlas()` constructor */ +declare interface Options { + /** Environment to run Atlas in. Default: value of `process.env.NODE_ENV` */ + env: string + /** Absolute path to folder structure where Atlas can expect its components to be defined */ + root: string + /** + * Configuration options for Atlas and all components + * + * If string is provided, it will be used as path relative to `root` and required. The resulting + * object will be used as the configuration object. If an object is provided, it will be used + * as-is. Default: `'config'` + */ + config?: Config | string +} + +/** + * Configuration object which Atlas accepts. Child values are either passed to Atlas directly or + * to individual components. The objects are delivered to components by checking the configuration + * keys against the component's associated alias. + */ +declare interface Config { + /** Configuration options for Atlas itself */ + atlas?: Atlas.Config + + /** + * Configuration options for services. + * + * The key must be the alias used when adding the service to Atlas, and the value will be + * provided to the component as its configuration. + */ + services: { [key: string]: any } + /** + * Configuration options for actions. + * + * The key must be the alias used when adding the action to Atlas, and the value will be + * provided to the component as its configuration. + */ + actions: { [key: string]: any } + /** + * Configuration options for hooks. + * + * The key must be the alias used when adding the hook to Atlas, and the value will be + * provided to the component as its configuration. + */ + hooks: { [key: string]: any } +} + + +/** + * The main point of interaction with Atlas. + */ +declare class Atlas { + /** + * Default values for configuration options which Atlas accepts. + */ + static readonly defaults: Atlas.Config + + /** Current execution environment (usually mirrors `process.env.NODE_ENV` unless overriden) */ + readonly env: string + + /** + * The root folder where all other paths should be relative to + * + * It is recommended that you set this to the project's root directory. + */ + readonly root: string + + /** Is this instance in a prepared state? */ + readonly prepared: boolean + + /** Is this instance in a started state? */ + readonly started: boolean + + /** Configuration for Atlas and all associated components, as passed in to the constructor */ + readonly config: Config + + /** All services added to this instance */ + readonly services: object + + /** All actions added to this instance */ + readonly actions: object + + /** An instance of Ajv used to validate component configuration */ + validator: Ajv.Ajv + + /** Logger used throughout Atlas and its components */ + log: Pino.Logger + + /** + * Initialise Atlas instance from the module paths provided in the `options` object + * + * Use this method to quickly configure Atlas instance by simply telling it where your + * components live on the filesystem, and Atlas will load them from the given module locations + * and add them to the Atlas instance. + * + * This is the preferred way of initialising an Atlas instance. + */ + static init(options: InitOptions): Atlas + + /** + * Bootstrap the given Atlas instance with the provided modules + * + * Use this method to quickly set up the given Atlas instance to use the provided components. + * This is useful if you need to have multiple entry points to your program and some entry + * points should only use some components available. This is especially useful when implementing + * worker processes where you only need a subset of all available components. This method, while + * more verbose as Atlas.init(), still frees you from manually adding all the components by hand + * while providing greater flexibility as to which components will be used. + */ + static bootstrap(atlas: Atlas, options: BootstrapOptions): Atlas + + /** + * Create a new Atlas instance + * + * Generally you should not need to create an Atlas instance via its constructor and use either + * the `Atlas.init()` or `Atlas.bootstrap()` options which are more easy to use. Using the + * constructor is more verbose but provides greatest level of control over the initialisation. + * + * You will have to manually register each component to the instance. + */ + constructor(options: Options) + + /** + * Require a module by path, relative to the project root + * + * @param {string} location Location of the module to load, relative to `atlas.root` + * (unless `{ absolute: true }`) + * @param {RequireOptions} options Options which affect how the module will be loaded + */ + require(location: string, options?: RequireOptions): any + + /** + * Register a service into this instance of Atlas with the given alias + * + * @param {string} alias Alias to associate with this component + * @param {ComponentConstructor} Component The component class. It will be constructed + * using `new Component()` during startup. + * @param {ComponentOptions} options Options for the component + */ + service(alias: string, Component: ComponentConstructor, options: ComponentOptions): this + + /** + * Register a hook into this instance of Atlas with the given alias + * + * @param {string} alias Alias to associate with this component + * @param {ComponentConstructor} Component The component class. It will be constructed + * using `new Component()` during startup. + * @param {ComponentOptions} options Options for the component + */ + hook(alias: string, Component: ComponentConstructor, options: ComponentOptions): this + + /** + * Register an action into this instance of Atlas with the given alias + * + * @param {string} alias Alias to associate with this component + * @param {ComponentConstructor} Component The component class. It will be constructed + * using `new Component()` during startup. + * @param {ComponentOptions} options Options for the component + */ + action(alias: string, Component: ComponentConstructor, options: ComponentOptions): this + + /** + * Prepare all services and hooks for use + * + * Generally you should use `atlas.start()` instead to get your instance up and running. + * However, sometimes it is necessary to get all the services into a "get-ready" state before + * they start connecting to remote resources or doing any intensive I/O operations. + */ + prepare(): Promise + + /** + * Start alll services + * + * This puts all components into a fully functional state, with all connections established (if + * any) and ready for use once this function resolves. + */ + start(): Promise + + /** + * Stop all services, unregister all actions and hooks and unpublish any APIs exposed by them + * + * This puts the whole application into a state as it was before `atlas.prepare()` and/or + * `atlas.start()` was called. + */ + stop(): Promise +} + +declare namespace Atlas { + /** Configuration options for Atlas */ + export interface Config { + /** Configuration options for Atlas' pino logger */ + log?: Pino.LoggerOptions + /** Configuration options for Atlas' component configuration validator */ + validator?: Ajv.Options & { + /** Keywords to enable from the `ajv-keywords` package */ + keywords?: Array + } + } +} + +export = Atlas diff --git a/packages/atlas/src/index.d.ts b/packages/atlas/src/index.d.ts index 096931e..18ada90 100644 --- a/packages/atlas/src/index.d.ts +++ b/packages/atlas/src/index.d.ts @@ -1,268 +1,16 @@ +import * as Atlas from './atlas' + declare module '@atlas.js/atlas' { + import Action from '@atlas.js/action' + import Service from '@atlas.js/service' + import Hook from '@atlas.js/hook' import * as errors from '@atlas.js/errors' - import Component from '@atlas.js/component' - import * as Ajv from 'ajv' - import * as Pino from 'pino' - - interface ComponentConstructor { - new (): Component - } - - interface Config { - atlas?: { - /** Default configuration options for Atlas' pino logger */ - log?: Pino.LoggerOptions - /** Default configuration options for Atlas' component configuration validator */ - validator?: Ajv.Options & { - /** Keywords to enable from the `ajv-keywords` package */ - keywords?: Array - } - } - /** - * Configuration options for services. - * - * The key must be the alias used when adding the service to Atlas, and the value will be - * provided to the component as its configuration. - */ - services: { [key: string]: any } - /** - * Configuration options for actions. - * - * The key must be the alias used when adding the action to Atlas, and the value will be - * provided to the component as its configuration. - */ - actions: { [key: string]: any } - /** - * Configuration options for hooks. - * - * The key must be the alias used when adding the hook to Atlas, and the value will be - * provided to the component as its configuration. - */ - hooks: { [key: string]: any } - } - - interface Options { - /** Environment to run Atlas in. Default: value of `process.env.NODE_ENV` */ - env: string - /** Absolute path to folder structure where Atlas can expect its components to be defined */ - root: string - /** - * Configuration options for Atlas and all components - * - * If string is provided, it will be used as path relative to `root` and required. The resulting - * object will be used as the configuration object. If an object is provided, it will be used - * as-is. Default: `'config'` - */ - config?: Config | string - } - - interface InitOptions extends Options { - /** Path to a module from which service components should be loaded. Default: `services` */ - services?: string - /** Path to a module from which action components should be loaded. Default: `actions` */ - actions?: string - /** Path to a module from which hook components should be loaded. Default: `hooks` */ - hooks?: string - /** - * Path to a module from which component configuration should be loaded (or the configuration - * itself). Default: `config` - */ - config?: Options["config"] - } - - interface BootstrapOptions extends Options { - /** - * All services to be added to Atlas. The key is the alias for the component and the value is - * the Component class itself (ie. `new Component()` will be called on the value). - */ - services: { [key: string]: ComponentConstructor } - /** - * All actions to be added to Atlas. The key is the alias for the component and the value is - * the Component class itself (ie. `new Component()` will be called on the value). - */ - actions: { [key: string]: ComponentConstructor } - /** - * All hooks to be added to Atlas. The key is the alias for the component and the value is - * the Component class itself (ie. `new Component()` will be called on the value). - */ - hooks: { [key: string]: ComponentConstructor } - } - - interface ComponentOptions { - /** - * If this component requires other components, you must specify their aliases you chose for - * them here. The key is the component name which is used by this component, and the value - * is the alias you chose for that compoennt in this instance of Atlas. - */ - aliases: { - [name: string]: string - } - } - - - /** - * The main point of interaction with Atlas. - */ - class Atlas { - /** - * Default values for configuration options which Atlas accepts. - */ - static readonly defaults: Config['atlas'] - - /** Current execution environment (usually mirrors `process.env.NODE_ENV` unless overriden) */ - readonly env: string - - /** - * The root folder where all other paths should be relative to - * - * It is recommended that you set this to the project's root directory. - */ - readonly root: string - - /** Is this instance in a prepared state? */ - readonly prepared: boolean - - /** Is this instance in a started state? */ - readonly started: boolean - - /** Atlas configuration, as passed in to the constructor */ - readonly config: Config - - /** All services added to this instance */ - readonly services: object - - /** All actions added to this instance */ - readonly actions: object - - /** An instance of Ajv used to validate component configuration */ - validator: Ajv.Ajv - - /** Logger used throughout Atlas and its components */ - log: Pino.Logger - - /** - * Initialise Atlas instance from the module paths provided in the `options` object - * - * Use this method to quickly configure Atlas instance by simply telling it where your - * components live on the filesystem, and Atlas will load them from the given module locations - * and add them to the Atlas instance. - * - * This is the preferred way of initialising an Atlas instance. - */ - static init(options: InitOptions): Atlas - - /** - * Bootstrap the given Atlas instance with the provided modules - * - * Use this method to quickly set up the given Atlas instance to use the provided components. - * This is useful if you need to have multiple entry points to your program and some entrypoints - * should only use some components available. This is especially useful when implementing worker - * processes where you only need a subset of all available components. This method, while more - * verbose as Atlas.init(), still frees you from manually adding all the components by hand - * while providing greater flexibility as to which components will be used. - */ - static bootstrap(atlas: Atlas, options: BootstrapOptions): Atlas - - /** - * Create a new Atlas instance - * - * Generally you should not need to create an Atlas instance via its constructor and use either - * the `Atlas.init()` or `Atlas.bootstrap()` options which are more easy to use. Using the - * constructor is more verbose but provides greatest level of control over the initialisation. - * - * You will have to manually register each component to the instance. - */ - constructor(options: Options) - - /** - * Require a module by path, relative to the project root - */ - require( - /** Location of the module to load, relative to `atlas.root` (unless `absolute = true`) */ - location: string, - /** Options which affect how the module will be loaded */ - options: { - /** If true, do not throw if the module does not exist */ - optional: boolean, - /** - * If true, prefer the ES modules' `default` export over named or CommonJS exports - */ - normalise: boolean, - /** - * If true, will try to load the module without resolving the specified location to the - * project root (it will load the module using standard Node's mechanism). - */ - absolute: boolean - }): any - - /** - * Register a service into this instance of Atlas with the given alias - */ - service( - /** Alias to associate with this component */ - alias: string, - /** The component class. It will be constructed using `new Component()` during startup. */ - Component: ComponentConstructor, - /** Options for the component */ - options: ComponentOptions - ): this - - /** - * Register a hook into this instance of Atlas with the given alias - */ - hook( - /** Alias to associate with this component */ - alias: string, - /** The component class. It will be constructed using `new Component()` during startup. */ - Component: ComponentConstructor, - /** Options for the component */ - options: ComponentOptions - ): this - - /** - * Register an action into this instance of Atlas with the given alias - */ - action( - /** Alias to associate with this component */ - alias: string, - /** The component class. It will be constructed using `new Component()` during startup. */ - Component: ComponentConstructor, - /** Options for the component */ - options: ComponentOptions - ): this - - /** - * Prepare all services and hooks for use - * - * Generally you should use `atlas.start()` instead to get your instance up and running. - * However, sometimes it is necessary to get all the services into a "get-ready" state before - * they start connecting to remote resources or doing any intensive I/O operations. - */ - prepare(): Promise - - /** - * Start alll services - * - * This puts all components into a fully functional state, with all connections established (if - * any) and ready for use once this function resolves. - */ - start(): Promise - - /** - * Stop all services, unregister all actions and hooks and unpublish any APIs exposed by them - * - * This puts the whole application into a state as it was before `atlas.prepare()` and/or - * `atlas.start()` was called. - */ - stop(): Promise - } export { Atlas, - Config, + Action, + Service, + Hook, errors, } - export { default as Action } from '@atlas.js/action' - export { default as Service } from '@atlas.js/service' - export { default as Hook } from '@atlas.js/hook' } From d18d95d1c39b07585880c72af6ba797484ba878a Mon Sep 17 00:00:00 2001 From: Robert Rossmann Date: Wed, 5 Dec 2018 16:44:42 +0100 Subject: [PATCH 35/35] feat(nodemailer): add typings --- packages/nodemailer/src/index.d.ts | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 packages/nodemailer/src/index.d.ts diff --git a/packages/nodemailer/src/index.d.ts b/packages/nodemailer/src/index.d.ts new file mode 100644 index 0000000..74573fc --- /dev/null +++ b/packages/nodemailer/src/index.d.ts @@ -0,0 +1,56 @@ +declare module '@atlas.js/nodemailer' { + import * as nodemailer from 'nodemailer' + import AtlasService from '@atlas.js/service' + + /** + * Send emails using nodemailer from within Atlas + */ + class Service extends AtlasService { + /** Service runtime configuration values */ + config: Service.Config + + prepare(): Promise + start(service: nodemailer.Transporter): Promise + stop(service: nodemailer.Transporter): Promise + } + + namespace Service { + /** Configuration schema available to this service */ + interface Config { + /** + * The transport to be used for sending emails + * + * Either provide the transport module itself or specify it as a string and it will be + * `require()`d. + */ + transport: Function | string + /** + * Transport-specific options + * + * Check the docs for the transporter you are going to use for available options. + */ + options: object + + plugins?: Array + } + + interface PluginConfiguration { + /** + * The plugin to be added to the transporter + * + * Either provide the plugin module itself or specify it as a string and it will be + * `require()`d. + */ + plugin: Function | string + /** Event to which this plugin should be attached */ + event: 'compile' | 'stream' + /** Plugin configuration options */ + options: object + } + } + + export { + Service, + nodemailer, + } +}