Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

knifecycle

Package Overview
Dependencies
Maintainers
1
Versions
101
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

knifecycle - npm Package Compare versions

Comparing version 1.0.5 to 1.1.0

dist/instance.js

31

dist/index.js

@@ -25,2 +25,3 @@ 'use strict';

var SHUTDOWN = '$shutdown';
var INJECT = '$inject';
var FATAL_ERROR = '$fatalError';

@@ -31,2 +32,3 @@ var E_UNMATCHED_DEPENDENCY = 'E_UNMATCHED_DEPENDENCY';

var E_BAD_SERVICE_PROMISE = 'E_BAD_SERVICE_PROMISE';
var E_BAD_INJECTION = 'E_BAD_INJECTION';

@@ -245,3 +247,6 @@ // Constants that should use Symbol whenever possible

value: function run(dependenciesNames) {
var _this2 = this;
var siloContext = {
name: 'silo-' + Date.now(),
servicesDescriptors: new Map(),

@@ -298,3 +303,10 @@ servicesSequence: [],

return this._initializeDependencies(siloContext, 'silo', dependenciesNames).then(function (servicesHash) {
// Create a provider for the special inject service
siloContext.servicesDescriptors.set(INJECT, {
servicePromise: Promise.resolve(function (dependenciesNames) {
return _this2._initializeDependencies(siloContext, siloContext.name, dependenciesNames, true);
})
});
return this._initializeDependencies(siloContext, siloContext.name, dependenciesNames).then(function (servicesHash) {
debug('Handling fatal errors:', siloContext.errorsPromises);

@@ -309,2 +321,3 @@ Promise.all(siloContext.errorsPromises).catch(siloContext.throwFatalError);

* @param {Object} siloContext Current execution silo context
* @param {Boolean} injectOnly Flag indicating if existing services only should be used
* @param {String} serviceName Service name.

@@ -317,3 +330,3 @@ * @param {String} serviceProvider Service provider.

key: '_getServiceDescriptor',
value: function _getServiceDescriptor(siloContext, serviceName) {
value: function _getServiceDescriptor(siloContext, injectOnly, serviceName) {
var serviceDescriptor = siloContext.servicesDescriptors.get(serviceName);

@@ -325,2 +338,9 @@

// The inject service is intended to be used as a workaround for unavoidable
// circular dependencies. It wouldn't make sense to instanciate new services
// at this level so throwing an error
if (injectOnly) {
return Promise.reject(new _yerror2.default(E_BAD_INJECTION, serviceName));
}
return this._initializeServiceDescriptor(siloContext, serviceName);

@@ -385,2 +405,3 @@ }

* @param {String} servicesNames Dependencies names.
* @param {Boolean} injectOnly Flag indicating if existing services only should be used
* @return {Promise} Service dependencies hash promise.

@@ -392,7 +413,9 @@ */

value: function _initializeDependencies(siloContext, serviceName, servicesNames) {
var _this2 = this;
var _this3 = this;
var injectOnly = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
debug('Initializing dependencies:', serviceName, servicesNames);
return Promise.resolve().then(function () {
return Promise.all(servicesNames.map(_this2._getServiceDescriptor.bind(_this2, siloContext))).then(function (servicesDescriptors) {
return Promise.all(servicesNames.map(_this3._getServiceDescriptor.bind(_this3, siloContext, injectOnly))).then(function (servicesDescriptors) {
debug('Initialized dependencies descriptors:', serviceName, servicesNames);

@@ -399,0 +422,0 @@ siloContext.servicesSequence.push(servicesNames);

@@ -294,2 +294,54 @@ 'use strict';

describe('inject', function () {
it('should work with no dependencies', function (done) {
$.constant('ENV', ENV);
$.constant('time', time);
$.provider('hash', $.depends(['ENV'], hashProvider));
$.run(['time', 'hash', '$inject']).then(function (dependencies) {
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'hash', '$inject']);
return dependencies.$inject([]).then(function (injectDependencies) {
_assert2.default.deepEqual(Object.keys(injectDependencies), []);
_assert2.default.deepEqual(injectDependencies, {});
done();
});
}).catch(done);
});
it('should work with same dependencies then the running silo', function (done) {
$.constant('ENV', ENV);
$.constant('time', time);
$.provider('hash', $.depends(['ENV'], hashProvider));
$.run(['time', 'hash', '$inject']).then(function (dependencies) {
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'hash', '$inject']);
return dependencies.$inject(['time', 'hash']).then(function (injectDependencies) {
_assert2.default.deepEqual(Object.keys(injectDependencies), ['time', 'hash']);
_assert2.default.deepEqual(injectDependencies, {
hash: { ENV: ENV },
time: time
});
done();
});
}).catch(done);
});
it('should fail with non instanciated dependencies', function (done) {
$.constant('ENV', ENV);
$.constant('time', time);
$.provider('hash', $.depends(['ENV'], hashProvider));
$.run(['time', '$inject']).then(function (dependencies) {
_assert2.default.deepEqual(Object.keys(dependencies), ['time', '$inject']);
return dependencies.$inject(['time', 'hash']).catch(function (err) {
_assert2.default.equal(err.code, 'E_BAD_INJECTION');
done();
});
}).catch(done);
});
});
describe('shutdown', function () {

@@ -296,0 +348,0 @@

2

package.json
{
"name": "knifecycle",
"version": "1.0.5",
"version": "1.1.0",
"description": "Manage your NodeJS processes's lifecycle.",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -20,45 +20,35 @@ # knifecycle

Unfortunately, applications often rely on **global states** where the JavaScript
module system show its limits. This is where `knifecycle` enters the game.
module system shows its limits. This is where `knifecycle` enters the game.
It is largely inspired from the Angular service system except is should not
provide code but access to global stuffs (time, filesystem, dbs). It also
have an important additional feature to shutdown processes which is less
useful for front-end applications and doesn't exists in Angular.
It is largely inspired by the Angular service system except it should not
provide code but access to global states (time, filesystem, db). It also
have an important additional feature to shutdown processes which is really
useful for back-end servers and doesn't exists in Angular.
## Features
- services management: start services taking their dependencies in count and
shut them down the same way to gracefully exit.
shut them down the same way for graceful exits.
- easy end to end testing: just replace your services per your own mocks and
stubs.
stubs while ensuring your application integrity between testing and production.
- isolation: isolate processing in a clean manner, per concerns.
- functional programming ready: encapsulate global states allowing the rest of
your application to be purely functional.
- no circular dependencies for services: while circular dependencies is not a
- no circular dependencies for services: while circular dependencies are not a
problem within purely functional libraries (require allows it), it may be
harmful for your services, knifecycle impeach that.
harmful for your services, knifecycle impeach that while providing an `$inject`
service à la Angular to allow accessing existing services references.
## Usage
First we create a Knifecycle instance:
Using Knifecycle is all about declaring the services our application need. Some
of them are simple constants:
```js
// services/knifecycle.js
// For this sample application, we know we won't need several lifecycle
// instances so we will use the module singleton instead of injecting the
// lifecycle instance everywhere.
import Knifecycle from 'knifecycle';
const $ = Knifecycle.getInstance();
export default $;
```
Then we create the services our application need. Some of them are simple
constants:
```js
// services/core.js
// Core services that are often needed. The constant decorator allows you to
// declare values or simple functions managing global states
import { constant } from './knifecycle';
import Winston from 'winston';
// Notice we are directly using the instance module that prepare the Knifecycle
// instance for us
import { constant } from 'knifecycle/instance';
// Add the process environment as a simple constant

@@ -84,6 +74,7 @@ constant('ENV', process.env);

logger.
```js
// services/logger.js
// A log service that depends on the process environment
import { depends, service } from './knifecycle';
import { depends, service } from 'knifecycle/instance';
import Logger from 'logger';

@@ -112,3 +103,3 @@

// services/db.js
import { depends, provider } from './knifecycle';
import { depends, provider } from 'knifecycle/instance';
import MongoClient from 'mongodb';

@@ -143,6 +134,6 @@

Adding an express server
Adding an Express server
```js
// services/server.js
import { depends, constant, provider, service } from './knifecycle';
import { depends, constant, provider, service } from 'knifecycle/instance';
import express from 'express';

@@ -209,3 +200,3 @@

import { run } from './services/knifecycle';
import { run } from 'knifecycle/instance';
import * from './services/core';

@@ -227,3 +218,3 @@ import * from './services/log';

// The shutdown service will disable silos progressively and then the services
// they rely on to finaly resolve the returned promise when done
// they rely on to finally resolve the returned promise once done
.then($shutdown)

@@ -251,13 +242,14 @@ .then(() => {

Use this lib for real world applications. I plan to use it with the
[Trip Story](https://github.com/nfroidure/TripStory) toy project first and use
it at work then. Maybe for front-end stuffs too.
This library is already used by the microservices i am working on at 7Digital
but I plan to use it with the
[Trip Story](https://github.com/nfroidure/TripStory) toy project in order to
illustrate its usage on an open-source project. I think i will also use it for
front-end projects too.
The scope of this library won't change. However the plan is:
- improve performances
- allow to declare singleton services
- use next JavaScript feature that ships to Node if it make sense:
depends, constant, service, provider may become decorators;
WeakMap may be used to share singleton services between runs
- track bugs
- [allow to declare singleton services](https://github.com/nfroidure/knifecycle/issues/3)
- evolve with Node. You will never have to transpile this library to use it with Node.
- `depends`, `constant`, `service`, `provider` may become decorators;
- track bugs ;)

@@ -264,0 +256,0 @@ I'll also share most of my own services/providers and their stubs/mocks in order

@@ -7,2 +7,3 @@ import YError from 'yerror';

const SHUTDOWN = '$shutdown';
const INJECT = '$inject';
const FATAL_ERROR = '$fatalError';

@@ -13,2 +14,3 @@ const E_UNMATCHED_DEPENDENCY = 'E_UNMATCHED_DEPENDENCY';

const E_BAD_SERVICE_PROMISE = 'E_BAD_SERVICE_PROMISE';
const E_BAD_INJECTION = 'E_BAD_INJECTION';

@@ -217,2 +219,3 @@ // Constants that should use Symbol whenever possible

const siloContext = {
name: 'silo-' + Date.now(),
servicesDescriptors: new Map(),

@@ -274,3 +277,10 @@ servicesSequence: [],

return this._initializeDependencies(siloContext, 'silo', dependenciesNames)
// Create a provider for the special inject service
siloContext.servicesDescriptors.set(INJECT, {
servicePromise: Promise.resolve(dependenciesNames =>
this._initializeDependencies(siloContext, siloContext.name, dependenciesNames, true)
),
});
return this._initializeDependencies(siloContext, siloContext.name, dependenciesNames)
.then((servicesHash) => {

@@ -286,2 +296,3 @@ debug('Handling fatal errors:', siloContext.errorsPromises);

* @param {Object} siloContext Current execution silo context
* @param {Boolean} injectOnly Flag indicating if existing services only should be used
* @param {String} serviceName Service name.

@@ -291,3 +302,3 @@ * @param {String} serviceProvider Service provider.

*/
_getServiceDescriptor(siloContext, serviceName) {
_getServiceDescriptor(siloContext, injectOnly, serviceName) {
const serviceDescriptor = siloContext.servicesDescriptors.get(serviceName);

@@ -299,2 +310,9 @@

// The inject service is intended to be used as a workaround for unavoidable
// circular dependencies. It wouldn't make sense to instanciate new services
// at this level so throwing an error
if(injectOnly) {
return Promise.reject(new YError(E_BAD_INJECTION, serviceName));
}
return this._initializeServiceDescriptor(siloContext, serviceName);

@@ -367,5 +385,6 @@ }

* @param {String} servicesNames Dependencies names.
* @param {Boolean} injectOnly Flag indicating if existing services only should be used
* @return {Promise} Service dependencies hash promise.
*/
_initializeDependencies(siloContext, serviceName, servicesNames) {
_initializeDependencies(siloContext, serviceName, servicesNames, injectOnly = false) {
debug('Initializing dependencies:', serviceName, servicesNames);

@@ -375,3 +394,3 @@ return Promise.resolve()

() => Promise.all(
servicesNames.map(this._getServiceDescriptor.bind(this, siloContext))
servicesNames.map(this._getServiceDescriptor.bind(this, siloContext, injectOnly))
)

@@ -378,0 +397,0 @@ .then((servicesDescriptors) => {

@@ -309,2 +309,67 @@ import assert from 'assert';

describe('inject', () => {
it('should work with no dependencies', (done) => {
$.constant('ENV', ENV);
$.constant('time', time);
$.provider('hash', $.depends(['ENV'], hashProvider));
$.run(['time', 'hash', '$inject'])
.then((dependencies) => {
assert.deepEqual(Object.keys(dependencies), ['time', 'hash', '$inject']);
return dependencies.$inject([])
.then((injectDependencies) => {
assert.deepEqual(Object.keys(injectDependencies), []);
assert.deepEqual(injectDependencies, {});
done();
});
})
.catch(done);
});
it('should work with same dependencies then the running silo', (done) => {
$.constant('ENV', ENV);
$.constant('time', time);
$.provider('hash', $.depends(['ENV'], hashProvider));
$.run(['time', 'hash', '$inject'])
.then((dependencies) => {
assert.deepEqual(Object.keys(dependencies), ['time', 'hash', '$inject']);
return dependencies.$inject(['time', 'hash'])
.then((injectDependencies) => {
assert.deepEqual(Object.keys(injectDependencies), ['time', 'hash']);
assert.deepEqual(injectDependencies, {
hash: { ENV },
time,
});
done();
});
})
.catch(done);
});
it('should fail with non instanciated dependencies', (done) => {
$.constant('ENV', ENV);
$.constant('time', time);
$.provider('hash', $.depends(['ENV'], hashProvider));
$.run(['time', '$inject'])
.then((dependencies) => {
assert.deepEqual(Object.keys(dependencies), ['time', '$inject']);
return dependencies.$inject(['time', 'hash'])
.catch((err) => {
assert.equal(err.code, 'E_BAD_INJECTION');
done();
});
})
.catch(done);
});
});
describe('shutdown', () => {

@@ -311,0 +376,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc