New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@loopback/core

Package Overview
Dependencies
Maintainers
7
Versions
204
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@loopback/core - npm Package Compare versions

Comparing version 1.11.0 to 1.12.0

15

CHANGELOG.md

@@ -6,2 +6,17 @@ # Change Log

# [1.12.0](https://github.com/strongloop/loopback-next/compare/@loopback/core@1.11.0...@loopback/core@1.12.0) (2019-12-09)
### Features
* **core:** allow application to trap shutdown signals ([2130634](https://github.com/strongloop/loopback-next/commit/213063424c2690aa7ef3f4494d8fc2a7e593b883))
* **core:** emit stateChanged events for application state transitions ([5257a8f](https://github.com/strongloop/loopback-next/commit/5257a8f68525921028b98a340c75758725d256b9))
* **core:** enable start/stop/boot to be idempotent ([b614a78](https://github.com/strongloop/loopback-next/commit/b614a7825be1dc1875556388443f72385525fa29))
* **core:** improve application states for start/stop ([01dac15](https://github.com/strongloop/loopback-next/commit/01dac151260e6c743cc77863f6495a85d19d338c))
* **core:** simplify state management by checking in process states ([874d2b3](https://github.com/strongloop/loopback-next/commit/874d2b385dd8c1dbf3d3980118898c6b99f145aa))
# [1.11.0](https://github.com/strongloop/loopback-next/compare/@loopback/core@1.10.7...@loopback/core@1.11.0) (2019-11-25)

@@ -8,0 +23,0 @@

83

dist/application.d.ts

@@ -0,1 +1,2 @@

/// <reference types="node" />
import { Binding, Constructor, Context, Provider } from '@loopback/context';

@@ -14,2 +15,30 @@ import { Component } from './component';

/**
* A flag to indicate that the application is being shut down
*/
private _isShuttingDown;
/**
* State of the application
*/
private _state;
/**
* Get the state of the application. The initial state is `created` and it can
* transition as follows by `start` and `stop`:
*
* 1. start
* - !started -> starting -> started
* - started -> started (no-op)
* 2. stop
* - started -> stopping -> stopped
* - !started -> stopped (no-op)
*
* Two types of states are expected:
* - stable, such as `started` and `stopped`
* - in process, such as `booting` and `starting`
*
* Operations such as `start` and `stop` can only be called at a stable state.
* The logic should immediately set the state to a new one indicating work in
* process, such as `starting` and `stopping`.
*/
get state(): string;
/**
* Create an application with the given parent context

@@ -96,7 +125,33 @@ * @param parent - Parent context

/**
* Start the application, and all of its registered observers.
* Assert there is no other operation is in progress, i.e., the state is not
* `*ing`, such as `starting` or `stopping`.
*
* @param op - The operation name, such as 'boot', 'start', or 'stop'
*/
protected assertNotInProcess(op: string): void;
/**
* Assert current state of the application to be one of the expected values
* @param op - The operation name, such as 'boot', 'start', or 'stop'
* @param states - Valid states
*/
protected assertInStates(op: string, ...states: string[]): void;
/**
* Transition the application to a new state and emit an event
* @param state - The new state
*/
protected setState(state: string): void;
protected awaitState(state: string): Promise<void>;
/**
* Start the application, and all of its registered observers. The application
* state is checked to ensure the integrity of `start`.
*
* If the application is already started, no operation is performed.
*/
start(): Promise<void>;
/**
* Stop the application instance and all of its registered observers.
* Stop the application instance and all of its registered observers. The
* application state is checked to ensure the integrity of `stop`.
*
* If the application is already stopped or not started, no operation is
* performed.
*/

@@ -184,4 +239,24 @@ stop(): Promise<void>;

service<S>(cls: Constructor<S> | Constructor<Provider<S>>, name?: string | ServiceOptions): Binding<S>;
/**
* Set up signals that are captured to shutdown the application
* @param signals - An array of signals to be trapped
* @param gracePeriod - A grace period in ms before forced exit
*/
protected setupShutdown(signals: NodeJS.Signals[], gracePeriod?: number): void;
}
/**
* Options to set up application shutdown
*/
export declare type ShutdownOptions = {
/**
* An array of signals to be trapped for graceful shutdown
*/
signals?: NodeJS.Signals[];
/**
* Period in milliseconds to wait for the grace shutdown to finish before
* exiting the process
*/
gracePeriod?: number;
};
/**
* Configuration for application

@@ -191,2 +266,6 @@ */

/**
* Configuration for signals that shut down the application
*/
shutdown?: ShutdownOptions;
/**
* Other properties

@@ -193,0 +272,0 @@ */

@@ -6,5 +6,10 @@ "use strict";

// License text available at https://opensource.org/licenses/MIT
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const context_1 = require("@loopback/context");
const debugFactory = require("debug");
const assert_1 = __importDefault(require("assert"));
const p_event_1 = __importDefault(require("p-event"));
const debug_1 = __importDefault(require("debug"));
const component_1 = require("./component");

@@ -15,3 +20,3 @@ const keys_1 = require("./keys");

const service_1 = require("./service");
const debug = debugFactory('loopback:core:application');
const debug = debug_1.default('loopback:core:application');
/**

@@ -24,6 +29,15 @@ * Application is the container for various types of artifacts, such as

constructor(configOrParent, parent) {
var _a, _b;
super(configOrParent instanceof context_1.Context ? configOrParent : parent, 'application');
/**
* A flag to indicate that the application is being shut down
*/
this._isShuttingDown = false;
/**
* State of the application
*/
this._state = 'created';
if (configOrParent instanceof context_1.Context)
configOrParent = {};
this.options = configOrParent || {};
this.options = (configOrParent !== null && configOrParent !== void 0 ? configOrParent : {});
// Bind the life cycle observer registry

@@ -37,4 +51,28 @@ this.bind(keys_1.CoreBindings.LIFE_CYCLE_OBSERVER_REGISTRY)

this.bind(keys_1.CoreBindings.APPLICATION_CONFIG).to(this.options);
const shutdownConfig = (_a = this.options.shutdown, (_a !== null && _a !== void 0 ? _a : {}));
this.setupShutdown((_b = shutdownConfig.signals, (_b !== null && _b !== void 0 ? _b : ['SIGTERM'])), shutdownConfig.gracePeriod);
}
/**
* Get the state of the application. The initial state is `created` and it can
* transition as follows by `start` and `stop`:
*
* 1. start
* - !started -> starting -> started
* - started -> started (no-op)
* 2. stop
* - started -> stopping -> stopped
* - !started -> stopped (no-op)
*
* Two types of states are expected:
* - stable, such as `started` and `stopped`
* - in process, such as `booting` and `starting`
*
* Operations such as `start` and `stop` can only be called at a stable state.
* The logic should immediately set the state to a new one indicating work in
* process, such as `starting` and `stopping`.
*/
get state() {
return this._state;
}
/**
* Register a controller class with this application.

@@ -57,3 +95,3 @@ *

controller(controllerCtor, name) {
debug('Adding controller %s', name || controllerCtor.name);
debug('Adding controller %s', (name !== null && name !== void 0 ? name : controllerCtor.name));
const binding = context_1.createBindingFromClass(controllerCtor, {

@@ -87,3 +125,3 @@ name,

server(ctor, name) {
debug('Adding server %s', name || ctor.name);
debug('Adding server %s', (name !== null && name !== void 0 ? name : ctor.name));
const binding = context_1.createBindingFromClass(ctor, {

@@ -145,14 +183,69 @@ name,

/**
* Start the application, and all of its registered observers.
* Assert there is no other operation is in progress, i.e., the state is not
* `*ing`, such as `starting` or `stopping`.
*
* @param op - The operation name, such as 'boot', 'start', or 'stop'
*/
assertNotInProcess(op) {
assert_1.default(!this._state.endsWith('ing'), `Cannot ${op} the application as it is ${this._state}.`);
}
/**
* Assert current state of the application to be one of the expected values
* @param op - The operation name, such as 'boot', 'start', or 'stop'
* @param states - Valid states
*/
assertInStates(op, ...states) {
assert_1.default(states.includes(this._state), `Cannot ${op} the application as it is ${this._state}. Valid states are ${states}.`);
}
/**
* Transition the application to a new state and emit an event
* @param state - The new state
*/
setState(state) {
const oldState = this._state;
this._state = state;
if (oldState !== state) {
this.emit('stateChanged', { from: oldState, to: this._state });
this.emit(state);
}
}
async awaitState(state) {
await p_event_1.default(this, state);
}
/**
* Start the application, and all of its registered observers. The application
* state is checked to ensure the integrity of `start`.
*
* If the application is already started, no operation is performed.
*/
async start() {
if (this._state === 'starting')
return this.awaitState('started');
this.assertNotInProcess('start');
// No-op if it's started
if (this._state === 'started')
return;
this.setState('starting');
const registry = await this.getLifeCycleObserverRegistry();
await registry.start();
this.setState('started');
}
/**
* Stop the application instance and all of its registered observers.
* Stop the application instance and all of its registered observers. The
* application state is checked to ensure the integrity of `stop`.
*
* If the application is already stopped or not started, no operation is
* performed.
*/
async stop() {
if (this._state === 'stopping')
return this.awaitState('stopped');
this.assertNotInProcess('stop');
// No-op if it's created or stopped
if (this._state !== 'started')
return;
this.setState('stopping');
const registry = await this.getLifeCycleObserverRegistry();
await registry.stop();
this.setState('stopped');
}

@@ -185,3 +278,3 @@ async getLifeCycleObserverRegistry() {

component(componentCtor, name) {
debug('Adding component: %s', name || componentCtor.name);
debug('Adding component: %s', (name !== null && name !== void 0 ? name : componentCtor.name));
const binding = context_1.createBindingFromClass(componentCtor, {

@@ -217,3 +310,3 @@ name,

lifeCycleObserver(ctor, name) {
debug('Adding life cycle observer %s', name || ctor.name);
debug('Adding life cycle observer %s', (name !== null && name !== void 0 ? name : ctor.name));
const binding = context_1.createBindingFromClass(ctor, {

@@ -276,4 +369,36 @@ name,

}
/**
* Set up signals that are captured to shutdown the application
* @param signals - An array of signals to be trapped
* @param gracePeriod - A grace period in ms before forced exit
*/
setupShutdown(signals, gracePeriod) {
const cleanup = async (signal) => {
const kill = () => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
signals.forEach(sig => process.removeListener(sig, cleanup));
process.kill(process.pid, signal);
};
debug('Signal %s received for process %d', signal, process.pid);
if (!this._isShuttingDown) {
this._isShuttingDown = true;
let timer;
if (typeof gracePeriod === 'number' && !isNaN(gracePeriod)) {
timer = setTimeout(kill, gracePeriod);
}
try {
await this.stop();
}
finally {
if (timer != null)
clearTimeout(timer);
kill();
}
}
};
// eslint-disable-next-line @typescript-eslint/no-misused-promises
signals.forEach(sig => process.on(sig, cleanup));
}
}
exports.Application = Application;
//# sourceMappingURL=application.js.map

4

dist/extension-point.js

@@ -56,5 +56,3 @@ "use strict";

return context_1.inject('', { decorator: '@extensions' }, (ctx, injection, session) => {
extensionPointName =
extensionPointName ||
inferExtensionPointName(injection.target, session.currentBinding);
extensionPointName = (extensionPointName !== null && extensionPointName !== void 0 ? extensionPointName : inferExtensionPointName(injection.target, session.currentBinding));
const bindingFilter = extensionFilter(extensionPointName);

@@ -61,0 +59,0 @@ return context_1.createViewGetter(ctx, bindingFilter, injection.metadata.bindingComparator, session);

@@ -62,2 +62,3 @@ "use strict";

return context_1.transformValueOrPromise(result, values => {
var _a;
if (values.length === 1)

@@ -69,3 +70,3 @@ return values[0];

else {
if (metadata && metadata.optional) {
if ((_a = metadata) === null || _a === void 0 ? void 0 : _a.optional) {
return undefined;

@@ -96,2 +97,3 @@ }

function createServiceBinding(cls, options = {}) {
var _a;
let name = options.name;

@@ -112,3 +114,3 @@ if (!name && context_1.isProviderClass(cls)) {

type: keys_1.CoreTags.SERVICE,
}).apply(asService(options.interface || cls));
}).apply(asService((_a = options.interface, (_a !== null && _a !== void 0 ? _a : cls))));
return binding;

@@ -115,0 +117,0 @@ }

{
"name": "@loopback/core",
"version": "1.11.0",
"version": "1.12.0",
"description": "LoopBack 4 core",

@@ -22,11 +22,12 @@ "engines": {

"dependencies": {
"@loopback/context": "^1.24.0",
"debug": "^4.1.1"
"@loopback/context": "^1.25.0",
"debug": "^4.1.1",
"p-event": "^4.1.0"
},
"devDependencies": {
"@loopback/build": "^2.1.0",
"@loopback/eslint-config": "^4.1.5",
"@loopback/testlab": "^1.9.5",
"@loopback/build": "^3.0.0",
"@loopback/eslint-config": "^5.0.0",
"@loopback/testlab": "^1.10.0",
"@types/debug": "^4.1.5",
"@types/node": "^10.17.5"
"@types/node": "^10.17.6"
},

@@ -46,3 +47,3 @@ "files": [

},
"gitHead": "c111543a6139c5a2999930c593aabbbdf10a838e"
"gitHead": "89eb61bacaed75e6eb61ae6840cea266cb888659"
}

@@ -14,3 +14,5 @@ // Copyright IBM Corp. 2017,2018. All Rights Reserved.

} from '@loopback/context';
import * as debugFactory from 'debug';
import assert from 'assert';
import pEvent from 'p-event';
import debugFactory from 'debug';
import {Component, mountComponent} from './component';

@@ -37,2 +39,35 @@ import {CoreBindings, CoreTags} from './keys';

/**
* A flag to indicate that the application is being shut down
*/
private _isShuttingDown = false;
/**
* State of the application
*/
private _state = 'created';
/**
* Get the state of the application. The initial state is `created` and it can
* transition as follows by `start` and `stop`:
*
* 1. start
* - !started -> starting -> started
* - started -> started (no-op)
* 2. stop
* - started -> stopping -> stopped
* - !started -> stopped (no-op)
*
* Two types of states are expected:
* - stable, such as `started` and `stopped`
* - in process, such as `booting` and `starting`
*
* Operations such as `start` and `stop` can only be called at a stable state.
* The logic should immediately set the state to a new one indicating work in
* process, such as `starting` and `stopping`.
*/
public get state() {
return this._state;
}
/**
* Create an application with the given parent context

@@ -56,3 +91,3 @@ * @param parent - Parent context

if (configOrParent instanceof Context) configOrParent = {};
this.options = configOrParent || {};
this.options = configOrParent ?? {};

@@ -67,2 +102,8 @@ // Bind the life cycle observer registry

this.bind(CoreBindings.APPLICATION_CONFIG).to(this.options);
const shutdownConfig = this.options.shutdown ?? {};
this.setupShutdown(
shutdownConfig.signals ?? ['SIGTERM'],
shutdownConfig.gracePeriod,
);
}

@@ -88,3 +129,3 @@

controller(controllerCtor: ControllerClass, name?: string): Binding {
debug('Adding controller %s', name || controllerCtor.name);
debug('Adding controller %s', name ?? controllerCtor.name);
const binding = createBindingFromClass(controllerCtor, {

@@ -122,3 +163,3 @@ name,

): Binding<T> {
debug('Adding server %s', name || ctor.name);
debug('Adding server %s', name ?? ctor.name);
const binding = createBindingFromClass(ctor, {

@@ -184,15 +225,76 @@ name,

/**
* Start the application, and all of its registered observers.
* Assert there is no other operation is in progress, i.e., the state is not
* `*ing`, such as `starting` or `stopping`.
*
* @param op - The operation name, such as 'boot', 'start', or 'stop'
*/
protected assertNotInProcess(op: string) {
assert(
!this._state.endsWith('ing'),
`Cannot ${op} the application as it is ${this._state}.`,
);
}
/**
* Assert current state of the application to be one of the expected values
* @param op - The operation name, such as 'boot', 'start', or 'stop'
* @param states - Valid states
*/
protected assertInStates(op: string, ...states: string[]) {
assert(
states.includes(this._state),
`Cannot ${op} the application as it is ${this._state}. Valid states are ${states}.`,
);
}
/**
* Transition the application to a new state and emit an event
* @param state - The new state
*/
protected setState(state: string) {
const oldState = this._state;
this._state = state;
if (oldState !== state) {
this.emit('stateChanged', {from: oldState, to: this._state});
this.emit(state);
}
}
protected async awaitState(state: string) {
await pEvent(this, state);
}
/**
* Start the application, and all of its registered observers. The application
* state is checked to ensure the integrity of `start`.
*
* If the application is already started, no operation is performed.
*/
public async start(): Promise<void> {
if (this._state === 'starting') return this.awaitState('started');
this.assertNotInProcess('start');
// No-op if it's started
if (this._state === 'started') return;
this.setState('starting');
const registry = await this.getLifeCycleObserverRegistry();
await registry.start();
this.setState('started');
}
/**
* Stop the application instance and all of its registered observers.
* Stop the application instance and all of its registered observers. The
* application state is checked to ensure the integrity of `stop`.
*
* If the application is already stopped or not started, no operation is
* performed.
*/
public async stop(): Promise<void> {
if (this._state === 'stopping') return this.awaitState('stopped');
this.assertNotInProcess('stop');
// No-op if it's created or stopped
if (this._state !== 'started') return;
this.setState('stopping');
const registry = await this.getLifeCycleObserverRegistry();
await registry.stop();
this.setState('stopped');
}

@@ -227,3 +329,3 @@

public component(componentCtor: Constructor<Component>, name?: string) {
debug('Adding component: %s', name || componentCtor.name);
debug('Adding component: %s', name ?? componentCtor.name);
const binding = createBindingFromClass(componentCtor, {

@@ -264,3 +366,3 @@ name,

): Binding<T> {
debug('Adding life cycle observer %s', name || ctor.name);
debug('Adding life cycle observer %s', name ?? ctor.name);
const binding = createBindingFromClass(ctor, {

@@ -327,5 +429,51 @@ name,

}
/**
* Set up signals that are captured to shutdown the application
* @param signals - An array of signals to be trapped
* @param gracePeriod - A grace period in ms before forced exit
*/
protected setupShutdown(signals: NodeJS.Signals[], gracePeriod?: number) {
const cleanup = async (signal: string) => {
const kill = () => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
signals.forEach(sig => process.removeListener(sig, cleanup));
process.kill(process.pid, signal);
};
debug('Signal %s received for process %d', signal, process.pid);
if (!this._isShuttingDown) {
this._isShuttingDown = true;
let timer;
if (typeof gracePeriod === 'number' && !isNaN(gracePeriod)) {
timer = setTimeout(kill, gracePeriod);
}
try {
await this.stop();
} finally {
if (timer != null) clearTimeout(timer);
kill();
}
}
};
// eslint-disable-next-line @typescript-eslint/no-misused-promises
signals.forEach(sig => process.on(sig, cleanup));
}
}
/**
* Options to set up application shutdown
*/
export type ShutdownOptions = {
/**
* An array of signals to be trapped for graceful shutdown
*/
signals?: NodeJS.Signals[];
/**
* Period in milliseconds to wait for the grace shutdown to finish before
* exiting the process
*/
gracePeriod?: number;
};
/**
* Configuration for application

@@ -335,2 +483,7 @@ */

/**
* Configuration for signals that shut down the application
*/
shutdown?: ShutdownOptions;
/**
* Other properties

@@ -337,0 +490,0 @@ */

@@ -70,3 +70,3 @@ // Copyright IBM Corp. 2019. All Rights Reserved.

extensionPointName =
extensionPointName ||
extensionPointName ??
inferExtensionPointName(injection.target, session.currentBinding);

@@ -73,0 +73,0 @@

@@ -113,3 +113,3 @@ // Copyright IBM Corp. 2019. All Rights Reserved.

} else {
if (metadata && metadata.optional) {
if (metadata?.optional) {
return undefined;

@@ -166,3 +166,3 @@ }

type: CoreTags.SERVICE,
}).apply(asService(options.interface || cls));
}).apply(asService(options.interface ?? cls));
return binding;

@@ -169,0 +169,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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