@loopback/core 1.10.7 → 1.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,48 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.12.2](https://github.com/strongloop/loopback-next/compare/@loopback/core@1.12.1...@loopback/core@1.12.2) (2020-01-27)
7
+
8
+ **Note:** Version bump only for package @loopback/core
9
+
10
+
11
+
12
+
13
+
14
+ ## [1.12.1](https://github.com/strongloop/loopback-next/compare/@loopback/core@1.12.0...@loopback/core@1.12.1) (2020-01-07)
15
+
16
+ **Note:** Version bump only for package @loopback/core
17
+
18
+
19
+
20
+
21
+
22
+ # [1.12.0](https://github.com/strongloop/loopback-next/compare/@loopback/core@1.11.0...@loopback/core@1.12.0) (2019-12-09)
23
+
24
+
25
+ ### Features
26
+
27
+ * **core:** allow application to trap shutdown signals ([2130634](https://github.com/strongloop/loopback-next/commit/213063424c2690aa7ef3f4494d8fc2a7e593b883))
28
+ * **core:** emit stateChanged events for application state transitions ([5257a8f](https://github.com/strongloop/loopback-next/commit/5257a8f68525921028b98a340c75758725d256b9))
29
+ * **core:** enable start/stop/boot to be idempotent ([b614a78](https://github.com/strongloop/loopback-next/commit/b614a7825be1dc1875556388443f72385525fa29))
30
+ * **core:** improve application states for start/stop ([01dac15](https://github.com/strongloop/loopback-next/commit/01dac151260e6c743cc77863f6495a85d19d338c))
31
+ * **core:** simplify state management by checking in process states ([874d2b3](https://github.com/strongloop/loopback-next/commit/874d2b385dd8c1dbf3d3980118898c6b99f145aa))
32
+
33
+
34
+
35
+
36
+
37
+ # [1.11.0](https://github.com/strongloop/loopback-next/compare/@loopback/core@1.10.7...@loopback/core@1.11.0) (2019-11-25)
38
+
39
+
40
+ ### Features
41
+
42
+ * **core:** add [@service](https://github.com/service) decorator to inject a service by class/interface ([1d80904](https://github.com/strongloop/loopback-next/commit/1d80904b670724b00cb6a2965b8472f44d23eed0))
43
+
44
+
45
+
46
+
47
+
6
48
  ## [1.10.7](https://github.com/strongloop/loopback-next/compare/@loopback/core@1.10.6...@loopback/core@1.10.7) (2019-11-12)
7
49
 
8
50
  **Note:** Version bump only for package @loopback/core
@@ -1,7 +1,9 @@
1
+ /// <reference types="node" />
1
2
  import { Binding, Constructor, Context, Provider } from '@loopback/context';
2
3
  import { Component } from './component';
3
4
  import { LifeCycleObserver } from './lifecycle';
4
5
  import { Server } from './server';
6
+ import { ServiceOptions } from './service';
5
7
  /**
6
8
  * Application is the container for various types of artifacts, such as
7
9
  * components, servers, controllers, repositories, datasources, connectors,
@@ -9,6 +11,34 @@ import { Server } from './server';
9
11
  */
10
12
  export declare class Application extends Context implements LifeCycleObserver {
11
13
  readonly options: ApplicationConfig;
14
+ /**
15
+ * A flag to indicate that the application is being shut down
16
+ */
17
+ private _isShuttingDown;
18
+ /**
19
+ * State of the application
20
+ */
21
+ private _state;
22
+ /**
23
+ * Get the state of the application. The initial state is `created` and it can
24
+ * transition as follows by `start` and `stop`:
25
+ *
26
+ * 1. start
27
+ * - !started -> starting -> started
28
+ * - started -> started (no-op)
29
+ * 2. stop
30
+ * - started -> stopping -> stopped
31
+ * - !started -> stopped (no-op)
32
+ *
33
+ * Two types of states are expected:
34
+ * - stable, such as `started` and `stopped`
35
+ * - in process, such as `booting` and `starting`
36
+ *
37
+ * Operations such as `start` and `stop` can only be called at a stable state.
38
+ * The logic should immediately set the state to a new one indicating work in
39
+ * process, such as `starting` and `stopping`.
40
+ */
41
+ get state(): string;
12
42
  /**
13
43
  * Create an application with the given parent context
14
44
  * @param parent - Parent context
@@ -91,11 +121,37 @@ export declare class Application extends Context implements LifeCycleObserver {
91
121
  */
92
122
  getServer<T extends Server>(target: Constructor<T> | string): Promise<T>;
93
123
  /**
94
- * Start the application, and all of its registered observers.
124
+ * Assert there is no other operation is in progress, i.e., the state is not
125
+ * `*ing`, such as `starting` or `stopping`.
126
+ *
127
+ * @param op - The operation name, such as 'boot', 'start', or 'stop'
128
+ */
129
+ protected assertNotInProcess(op: string): void;
130
+ /**
131
+ * Assert current state of the application to be one of the expected values
132
+ * @param op - The operation name, such as 'boot', 'start', or 'stop'
133
+ * @param states - Valid states
134
+ */
135
+ protected assertInStates(op: string, ...states: string[]): void;
136
+ /**
137
+ * Transition the application to a new state and emit an event
138
+ * @param state - The new state
139
+ */
140
+ protected setState(state: string): void;
141
+ protected awaitState(state: string): Promise<void>;
142
+ /**
143
+ * Start the application, and all of its registered observers. The application
144
+ * state is checked to ensure the integrity of `start`.
145
+ *
146
+ * If the application is already started, no operation is performed.
95
147
  */
96
148
  start(): Promise<void>;
97
149
  /**
98
- * Stop the application instance and all of its registered observers.
150
+ * Stop the application instance and all of its registered observers. The
151
+ * application state is checked to ensure the integrity of `stop`.
152
+ *
153
+ * If the application is already stopped or not started, no operation is
154
+ * performed.
99
155
  */
100
156
  stop(): Promise<void>;
101
157
  private getLifeCycleObserverRegistry;
@@ -177,12 +233,36 @@ export declare class Application extends Context implements LifeCycleObserver {
177
233
  * }
178
234
  * ```
179
235
  */
180
- service<S>(cls: Constructor<S> | Constructor<Provider<S>>, name?: string): Binding<S>;
236
+ service<S>(cls: Constructor<S> | Constructor<Provider<S>>, name?: string | ServiceOptions): Binding<S>;
237
+ /**
238
+ * Set up signals that are captured to shutdown the application
239
+ * @param signals - An array of signals to be trapped
240
+ * @param gracePeriod - A grace period in ms before forced exit
241
+ */
242
+ protected setupShutdown(signals: NodeJS.Signals[], gracePeriod?: number): void;
181
243
  }
244
+ /**
245
+ * Options to set up application shutdown
246
+ */
247
+ export declare type ShutdownOptions = {
248
+ /**
249
+ * An array of signals to be trapped for graceful shutdown
250
+ */
251
+ signals?: NodeJS.Signals[];
252
+ /**
253
+ * Period in milliseconds to wait for the grace shutdown to finish before
254
+ * exiting the process
255
+ */
256
+ gracePeriod?: number;
257
+ };
182
258
  /**
183
259
  * Configuration for application
184
260
  */
185
261
  export interface ApplicationConfig {
262
+ /**
263
+ * Configuration for signals that shut down the application
264
+ */
265
+ shutdown?: ShutdownOptions;
186
266
  /**
187
267
  * Other properties
188
268
  */
@@ -3,14 +3,20 @@
3
3
  // Node module: @loopback/core
4
4
  // This file is licensed under the MIT License.
5
5
  // License text available at https://opensource.org/licenses/MIT
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
6
9
  Object.defineProperty(exports, "__esModule", { value: true });
7
10
  const context_1 = require("@loopback/context");
8
- const debugFactory = require("debug");
11
+ const assert_1 = __importDefault(require("assert"));
12
+ const p_event_1 = __importDefault(require("p-event"));
13
+ const debug_1 = __importDefault(require("debug"));
9
14
  const component_1 = require("./component");
10
15
  const keys_1 = require("./keys");
11
16
  const lifecycle_1 = require("./lifecycle");
12
17
  const lifecycle_registry_1 = require("./lifecycle-registry");
13
- const debug = debugFactory('loopback:core:application');
18
+ const service_1 = require("./service");
19
+ const debug = debug_1.default('loopback:core:application');
14
20
  /**
15
21
  * Application is the container for various types of artifacts, such as
16
22
  * components, servers, controllers, repositories, datasources, connectors,
@@ -18,10 +24,19 @@ const debug = debugFactory('loopback:core:application');
18
24
  */
19
25
  class Application extends context_1.Context {
20
26
  constructor(configOrParent, parent) {
27
+ var _a, _b;
21
28
  super(configOrParent instanceof context_1.Context ? configOrParent : parent, 'application');
29
+ /**
30
+ * A flag to indicate that the application is being shut down
31
+ */
32
+ this._isShuttingDown = false;
33
+ /**
34
+ * State of the application
35
+ */
36
+ this._state = 'created';
22
37
  if (configOrParent instanceof context_1.Context)
23
38
  configOrParent = {};
24
- this.options = configOrParent || {};
39
+ this.options = (configOrParent !== null && configOrParent !== void 0 ? configOrParent : {});
25
40
  // Bind the life cycle observer registry
26
41
  this.bind(keys_1.CoreBindings.LIFE_CYCLE_OBSERVER_REGISTRY)
27
42
  .toClass(lifecycle_registry_1.LifeCycleObserverRegistry)
@@ -30,6 +45,30 @@ class Application extends context_1.Context {
30
45
  this.bind(keys_1.CoreBindings.APPLICATION_INSTANCE).to(this);
31
46
  // Make options available to other modules as well.
32
47
  this.bind(keys_1.CoreBindings.APPLICATION_CONFIG).to(this.options);
48
+ const shutdownConfig = (_a = this.options.shutdown, (_a !== null && _a !== void 0 ? _a : {}));
49
+ this.setupShutdown((_b = shutdownConfig.signals, (_b !== null && _b !== void 0 ? _b : ['SIGTERM'])), shutdownConfig.gracePeriod);
50
+ }
51
+ /**
52
+ * Get the state of the application. The initial state is `created` and it can
53
+ * transition as follows by `start` and `stop`:
54
+ *
55
+ * 1. start
56
+ * - !started -> starting -> started
57
+ * - started -> started (no-op)
58
+ * 2. stop
59
+ * - started -> stopping -> stopped
60
+ * - !started -> stopped (no-op)
61
+ *
62
+ * Two types of states are expected:
63
+ * - stable, such as `started` and `stopped`
64
+ * - in process, such as `booting` and `starting`
65
+ *
66
+ * Operations such as `start` and `stop` can only be called at a stable state.
67
+ * The logic should immediately set the state to a new one indicating work in
68
+ * process, such as `starting` and `stopping`.
69
+ */
70
+ get state() {
71
+ return this._state;
33
72
  }
34
73
  /**
35
74
  * Register a controller class with this application.
@@ -49,7 +88,7 @@ class Application extends context_1.Context {
49
88
  * ```
50
89
  */
51
90
  controller(controllerCtor, name) {
52
- debug('Adding controller %s', name || controllerCtor.name);
91
+ debug('Adding controller %s', (name !== null && name !== void 0 ? name : controllerCtor.name));
53
92
  const binding = context_1.createBindingFromClass(controllerCtor, {
54
93
  name,
55
94
  namespace: keys_1.CoreBindings.CONTROLLERS,
@@ -78,7 +117,7 @@ class Application extends context_1.Context {
78
117
  *
79
118
  */
80
119
  server(ctor, name) {
81
- debug('Adding server %s', name || ctor.name);
120
+ debug('Adding server %s', (name !== null && name !== void 0 ? name : ctor.name));
82
121
  const binding = context_1.createBindingFromClass(ctor, {
83
122
  name,
84
123
  namespace: keys_1.CoreBindings.SERVERS,
@@ -135,18 +174,73 @@ class Application extends context_1.Context {
135
174
  return this.get(key);
136
175
  }
137
176
  /**
138
- * Start the application, and all of its registered observers.
177
+ * Assert there is no other operation is in progress, i.e., the state is not
178
+ * `*ing`, such as `starting` or `stopping`.
179
+ *
180
+ * @param op - The operation name, such as 'boot', 'start', or 'stop'
181
+ */
182
+ assertNotInProcess(op) {
183
+ assert_1.default(!this._state.endsWith('ing'), `Cannot ${op} the application as it is ${this._state}.`);
184
+ }
185
+ /**
186
+ * Assert current state of the application to be one of the expected values
187
+ * @param op - The operation name, such as 'boot', 'start', or 'stop'
188
+ * @param states - Valid states
189
+ */
190
+ assertInStates(op, ...states) {
191
+ assert_1.default(states.includes(this._state), `Cannot ${op} the application as it is ${this._state}. Valid states are ${states}.`);
192
+ }
193
+ /**
194
+ * Transition the application to a new state and emit an event
195
+ * @param state - The new state
196
+ */
197
+ setState(state) {
198
+ const oldState = this._state;
199
+ this._state = state;
200
+ if (oldState !== state) {
201
+ this.emit('stateChanged', { from: oldState, to: this._state });
202
+ this.emit(state);
203
+ }
204
+ }
205
+ async awaitState(state) {
206
+ await p_event_1.default(this, state);
207
+ }
208
+ /**
209
+ * Start the application, and all of its registered observers. The application
210
+ * state is checked to ensure the integrity of `start`.
211
+ *
212
+ * If the application is already started, no operation is performed.
139
213
  */
140
214
  async start() {
215
+ if (this._state === 'starting')
216
+ return this.awaitState('started');
217
+ this.assertNotInProcess('start');
218
+ // No-op if it's started
219
+ if (this._state === 'started')
220
+ return;
221
+ this.setState('starting');
141
222
  const registry = await this.getLifeCycleObserverRegistry();
142
223
  await registry.start();
224
+ this.setState('started');
143
225
  }
144
226
  /**
145
- * Stop the application instance and all of its registered observers.
227
+ * Stop the application instance and all of its registered observers. The
228
+ * application state is checked to ensure the integrity of `stop`.
229
+ *
230
+ * If the application is already stopped or not started, no operation is
231
+ * performed.
146
232
  */
147
233
  async stop() {
234
+ if (this._state === 'stopping')
235
+ return this.awaitState('stopped');
236
+ this.assertNotInProcess('stop');
237
+ // No-op if it's created or stopped
238
+ if (this._state !== 'started')
239
+ return;
240
+ this.setState('stopping');
148
241
  const registry = await this.getLifeCycleObserverRegistry();
149
242
  await registry.stop();
243
+ this.setState('stopped');
150
244
  }
151
245
  async getLifeCycleObserverRegistry() {
152
246
  return this.get(keys_1.CoreBindings.LIFE_CYCLE_OBSERVER_REGISTRY);
@@ -174,7 +268,7 @@ class Application extends context_1.Context {
174
268
  * ```
175
269
  */
176
270
  component(componentCtor, name) {
177
- debug('Adding component: %s', name || componentCtor.name);
271
+ debug('Adding component: %s', (name !== null && name !== void 0 ? name : componentCtor.name));
178
272
  const binding = context_1.createBindingFromClass(componentCtor, {
179
273
  name,
180
274
  namespace: keys_1.CoreBindings.COMPONENTS,
@@ -205,7 +299,7 @@ class Application extends context_1.Context {
205
299
  * @param name - Optional name for the life cycle observer
206
300
  */
207
301
  lifeCycleObserver(ctor, name) {
208
- debug('Adding life cycle observer %s', name || ctor.name);
302
+ debug('Adding life cycle observer %s', (name !== null && name !== void 0 ? name : ctor.name));
209
303
  const binding = context_1.createBindingFromClass(ctor, {
210
304
  name,
211
305
  namespace: keys_1.CoreBindings.LIFE_CYCLE_OBSERVERS,
@@ -258,24 +352,43 @@ class Application extends context_1.Context {
258
352
  * ```
259
353
  */
260
354
  service(cls, name) {
261
- if (!name && context_1.isProviderClass(cls)) {
262
- // Trim `Provider` from the default service name
263
- // This is needed to keep backward compatibility
264
- const templateFn = context_1.bindingTemplateFor(cls);
265
- const template = context_1.Binding.bind('template').apply(templateFn);
266
- if (template.tagMap[context_1.ContextTags.PROVIDER] &&
267
- !template.tagMap[context_1.ContextTags.NAME]) {
268
- // The class is a provider and no `name` tag is found
269
- name = cls.name.replace(/Provider$/, '');
270
- }
271
- }
272
- const binding = context_1.createBindingFromClass(cls, {
273
- name,
274
- type: 'service',
275
- });
355
+ const options = typeof name === 'string' ? { name } : name;
356
+ const binding = service_1.createServiceBinding(cls, options);
276
357
  this.add(binding);
277
358
  return binding;
278
359
  }
360
+ /**
361
+ * Set up signals that are captured to shutdown the application
362
+ * @param signals - An array of signals to be trapped
363
+ * @param gracePeriod - A grace period in ms before forced exit
364
+ */
365
+ setupShutdown(signals, gracePeriod) {
366
+ const cleanup = async (signal) => {
367
+ const kill = () => {
368
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
369
+ signals.forEach(sig => process.removeListener(sig, cleanup));
370
+ process.kill(process.pid, signal);
371
+ };
372
+ debug('Signal %s received for process %d', signal, process.pid);
373
+ if (!this._isShuttingDown) {
374
+ this._isShuttingDown = true;
375
+ let timer;
376
+ if (typeof gracePeriod === 'number' && !isNaN(gracePeriod)) {
377
+ timer = setTimeout(kill, gracePeriod);
378
+ }
379
+ try {
380
+ await this.stop();
381
+ }
382
+ finally {
383
+ if (timer != null)
384
+ clearTimeout(timer);
385
+ kill();
386
+ }
387
+ }
388
+ };
389
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
390
+ signals.forEach(sig => process.on(sig, cleanup));
391
+ }
279
392
  }
280
393
  exports.Application = Application;
281
394
  //# sourceMappingURL=application.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"application.js","sourceRoot":"","sources":["../src/application.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"application.js","sourceRoot":"","sources":["../src/application.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;;;;AAEhE,+CAO2B;AAC3B,oDAA4B;AAC5B,sDAA6B;AAC7B,kDAAiC;AACjC,2CAAsD;AACtD,iCAA8C;AAC9C,2CAIqB;AACrB,6DAA+D;AAE/D,uCAA+D;AAC/D,MAAM,KAAK,GAAG,eAAY,CAAC,2BAA2B,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAa,WAAY,SAAQ,iBAAO;IAgDtC,YAAY,cAA4C,EAAE,MAAgB;;QACxE,KAAK,CACH,cAAc,YAAY,iBAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,EAC3D,aAAa,CACd,CAAC;QAjDJ;;WAEG;QACK,oBAAe,GAAG,KAAK,CAAC;QAEhC;;WAEG;QACK,WAAM,GAAG,SAAS,CAAC;QA2CzB,IAAI,cAAc,YAAY,iBAAO;YAAE,cAAc,GAAG,EAAE,CAAC;QAC3D,IAAI,CAAC,OAAO,IAAG,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,EAAE,CAAA,CAAC;QAEpC,wCAAwC;QACxC,IAAI,CAAC,IAAI,CAAC,mBAAY,CAAC,4BAA4B,CAAC;aACjD,OAAO,CAAC,8CAAyB,CAAC;aAClC,OAAO,CAAC,sBAAY,CAAC,SAAS,CAAC,CAAC;QACnC,2EAA2E;QAC3E,IAAI,CAAC,IAAI,CAAC,mBAAY,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACtD,mDAAmD;QACnD,IAAI,CAAC,IAAI,CAAC,mBAAY,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE5D,MAAM,cAAc,SAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,uCAAI,EAAE,EAAA,CAAC;QACnD,IAAI,CAAC,aAAa,OAChB,cAAc,CAAC,OAAO,uCAAI,CAAC,SAAS,CAAC,IACrC,cAAc,CAAC,WAAW,CAC3B,CAAC;IACJ,CAAC;IA1DD;;;;;;;;;;;;;;;;;;OAkBG;IACH,IAAW,KAAK;QACd,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAuCD;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAAC,cAA+B,EAAE,IAAa;QACvD,KAAK,CAAC,sBAAsB,GAAE,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,cAAc,CAAC,IAAI,EAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,gCAAsB,CAAC,cAAc,EAAE;YACrD,IAAI;YACJ,SAAS,EAAE,mBAAY,CAAC,WAAW;YACnC,IAAI,EAAE,eAAQ,CAAC,UAAU;YACzB,YAAY,EAAE,sBAAY,CAAC,SAAS;SACrC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACI,MAAM,CACX,IAAoB,EACpB,IAAa;QAEb,KAAK,CAAC,kBAAkB,GAAE,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,IAAI,CAAC,IAAI,EAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,gCAAsB,CAAC,IAAI,EAAE;YAC3C,IAAI;YACJ,SAAS,EAAE,mBAAY,CAAC,OAAO;YAC/B,IAAI,EAAE,eAAQ,CAAC,MAAM;YACrB,YAAY,EAAE,sBAAY,CAAC,SAAS;SACrC,CAAC,CAAC,KAAK,CAAC,+BAAmB,CAAC,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACI,OAAO,CAAmB,KAAuB;QACtD,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,SAAS,CACpB,MAA+B;QAE/B,IAAI,GAAW,CAAC;QAChB,4CAA4C;QAC5C,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YAC9B,GAAG,GAAG,GAAG,mBAAY,CAAC,OAAO,IAAI,MAAM,EAAE,CAAC;SAC3C;aAAM;YACL,MAAM,IAAI,GAAG,MAAwB,CAAC;YACtC,GAAG,GAAG,GAAG,mBAAY,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;SAC9C;QACD,OAAO,IAAI,CAAC,GAAG,CAAI,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED;;;;;OAKG;IACO,kBAAkB,CAAC,EAAU;QACrC,gBAAM,CACJ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAC5B,UAAU,EAAE,6BAA6B,IAAI,CAAC,MAAM,GAAG,CACxD,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACO,cAAc,CAAC,EAAU,EAAE,GAAG,MAAgB;QACtD,gBAAM,CACJ,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAC5B,UAAU,EAAE,6BAA6B,IAAI,CAAC,MAAM,sBAAsB,MAAM,GAAG,CACpF,CAAC;IACJ,CAAC;IAED;;;OAGG;IACO,QAAQ,CAAC,KAAa;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,QAAQ,KAAK,KAAK,EAAE;YACtB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,EAAC,CAAC,CAAC;YAC7D,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SAClB;IACH,CAAC;IAES,KAAK,CAAC,UAAU,CAAC,KAAa;QACtC,MAAM,iBAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,KAAK;QAChB,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAClE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACjC,wBAAwB;QACxB,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO;QACtC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,4BAA4B,EAAE,CAAC;QAC3D,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,IAAI;QACf,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAClE,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAChC,mCAAmC;QACnC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO;QACtC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,4BAA4B,EAAE,CAAC;QAC3D,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,4BAA4B;QACxC,OAAO,IAAI,CAAC,GAAG,CAAC,mBAAY,CAAC,4BAA4B,CAAC,CAAC;IAC7D,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACI,SAAS,CAAC,aAAqC,EAAE,IAAa;QACnE,KAAK,CAAC,sBAAsB,GAAE,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,aAAa,CAAC,IAAI,EAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,gCAAsB,CAAC,aAAa,EAAE;YACpD,IAAI;YACJ,SAAS,EAAE,mBAAY,CAAC,UAAU;YAClC,IAAI,EAAE,eAAQ,CAAC,SAAS;YACxB,YAAY,EAAE,sBAAY,CAAC,SAAS;SACrC,CAAC,CAAC;QACH,IAAI,oCAAwB,CAAC,aAAa,CAAC,EAAE;YAC3C,OAAO,CAAC,KAAK,CAAC,+BAAmB,CAAC,CAAC;SACpC;QACD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,wDAAwD;QACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAY,OAAO,CAAC,GAAG,CAAC,CAAC;QACtD,0BAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACI,WAAW,CAAC,QAA6B;QAC9C,IAAI,CAAC,IAAI,CAAC,mBAAY,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC5D,CAAC;IAED;;;;OAIG;IACI,iBAAiB,CACtB,IAAoB,EACpB,IAAa;QAEb,KAAK,CAAC,+BAA+B,GAAE,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,IAAI,CAAC,IAAI,EAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,gCAAsB,CAAC,IAAI,EAAE;YAC3C,IAAI;YACJ,SAAS,EAAE,mBAAY,CAAC,oBAAoB;YAC5C,IAAI,EAAE,eAAQ,CAAC,mBAAmB;YAClC,YAAY,EAAE,sBAAY,CAAC,SAAS;SACrC,CAAC,CAAC,KAAK,CAAC,+BAAmB,CAAC,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;IACI,OAAO,CACZ,GAA8C,EAC9C,IAA8B;QAE9B,MAAM,OAAO,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAC,IAAI,EAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACzD,MAAM,OAAO,GAAG,8BAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACO,aAAa,CAAC,OAAyB,EAAE,WAAoB;QACrE,MAAM,OAAO,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;YACvC,MAAM,IAAI,GAAG,GAAG,EAAE;gBAChB,kEAAkE;gBAClE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC7D,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACpC,CAAC,CAAC;YACF,KAAK,CAAC,mCAAmC,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YAChE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;gBACzB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;gBAC5B,IAAI,KAAK,CAAC;gBACV,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;oBAC1D,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;iBACvC;gBACD,IAAI;oBACF,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;iBACnB;wBAAS;oBACR,IAAI,KAAK,IAAI,IAAI;wBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;oBACvC,IAAI,EAAE,CAAC;iBACR;aACF;QACH,CAAC,CAAC;QACF,kEAAkE;QAClE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,CAAC;CACF;AAjaD,kCAiaC"}
@@ -47,7 +47,7 @@ export declare function extensions(extensionPointName?: string): (target: Object
47
47
  * extension point
48
48
  * @param extensionPointName - Name of the extension point
49
49
  */
50
- export declare function extensionFilter(extensionPointName: string): import("@loopback/context").BindingFilter<unknown>;
50
+ export declare function extensionFilter(extensionPointName: string): import("@loopback/context").BindingTagFilter;
51
51
  /**
52
52
  * A factory function to create binding template for extensions of the given
53
53
  * extension point
@@ -53,9 +53,7 @@ exports.extensionPoint = extensionPoint;
53
53
  */
54
54
  function extensions(extensionPointName) {
55
55
  return context_1.inject('', { decorator: '@extensions' }, (ctx, injection, session) => {
56
- extensionPointName =
57
- extensionPointName ||
58
- inferExtensionPointName(injection.target, session.currentBinding);
56
+ extensionPointName = (extensionPointName !== null && extensionPointName !== void 0 ? extensionPointName : inferExtensionPointName(injection.target, session.currentBinding));
59
57
  const bindingFilter = extensionFilter(extensionPointName);
60
58
  return context_1.createViewGetter(ctx, bindingFilter, injection.metadata.bindingComparator, session);
61
59
  });
@@ -1 +1 @@
1
- {"version":3,"file":"extension-point.js","sourceRoot":"","sources":["../src/extension-point.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;AAEhE,+CAa2B;AAC3B,iCAAgC;AAEhC;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,cAAc,CAAC,IAAY,EAAE,GAAG,KAAoB;IAClE,OAAO,cAAI,CAAC,EAAC,IAAI,EAAE,EAAC,CAAC,eAAQ,CAAC,eAAe,CAAC,EAAE,IAAI,EAAC,EAAC,EAAE,GAAG,KAAK,CAAC,CAAC;AACpE,CAAC;AAFD,wCAEC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,SAAgB,UAAU,CAAC,kBAA2B;IACpD,OAAO,gBAAM,CAAC,EAAE,EAAE,EAAC,SAAS,EAAE,aAAa,EAAC,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;QACxE,kBAAkB;YAChB,kBAAkB;gBAClB,uBAAuB,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QAEpE,MAAM,aAAa,GAAG,eAAe,CAAC,kBAAkB,CAAC,CAAC;QAC1D,OAAO,0BAAgB,CACrB,GAAG,EACH,aAAa,EACb,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EACpC,OAAO,CACR,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAdD,gCAcC;AAED;;;;GAIG;AACH,SAAS,uBAAuB,CAC9B,eAAuB,EACvB,cAA2C;IAE3C,IAAI,cAAc,EAAE;QAClB,MAAM,IAAI,GACR,cAAc,CAAC,MAAM,CAAC,eAAQ,CAAC,eAAe,CAAC;YAC/C,cAAc,CAAC,MAAM,CAAC,qBAAW,CAAC,IAAI,CAAC,CAAC;QAE1C,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;KACvB;IAED,IAAI,MAAgB,CAAC;IACrB,IAAI,OAAO,eAAe,KAAK,UAAU,EAAE;QACzC,wBAAwB;QACxB,MAAM,GAAG,eAAe,CAAC;KAC1B;SAAM;QACL,6BAA6B;QAC7B,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC;KACtC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAAC,kBAA0B;IACxD,OAAO,qBAAW,CAAC;QACjB,CAAC,eAAQ,CAAC,aAAa,CAAC,EAAE,kBAAkB;KAC7C,CAAC,CAAC;AACL,CAAC;AAJD,0CAIC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,kBAA0B;IACrD,OAAO,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAC,CAAC,eAAQ,CAAC,aAAa,CAAC,EAAE,kBAAkB,EAAC,CAAC,CAAC;AAChF,CAAC;AAFD,oCAEC;AAED;;;;;;GAMG;AACH,SAAgB,YAAY,CAC1B,OAAgB,EAChB,kBAA0B,EAC1B,cAAoC,EACpC,OAAiC;IAEjC,MAAM,OAAO,GAAG,gCAAsB,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,KAAK,CACnE,YAAY,CAAC,kBAAkB,CAAC,CACjC,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,OAAO,CAAC;AACjB,CAAC;AAXD,oCAWC"}
1
+ {"version":3,"file":"extension-point.js","sourceRoot":"","sources":["../src/extension-point.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;AAEhE,+CAa2B;AAC3B,iCAAgC;AAEhC;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,cAAc,CAAC,IAAY,EAAE,GAAG,KAAoB;IAClE,OAAO,cAAI,CAAC,EAAC,IAAI,EAAE,EAAC,CAAC,eAAQ,CAAC,eAAe,CAAC,EAAE,IAAI,EAAC,EAAC,EAAE,GAAG,KAAK,CAAC,CAAC;AACpE,CAAC;AAFD,wCAEC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,SAAgB,UAAU,CAAC,kBAA2B;IACpD,OAAO,gBAAM,CAAC,EAAE,EAAE,EAAC,SAAS,EAAE,aAAa,EAAC,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;QACxE,kBAAkB,IAChB,kBAAkB,aAAlB,kBAAkB,cAAlB,kBAAkB,GAClB,uBAAuB,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA,CAAC;QAEpE,MAAM,aAAa,GAAG,eAAe,CAAC,kBAAkB,CAAC,CAAC;QAC1D,OAAO,0BAAgB,CACrB,GAAG,EACH,aAAa,EACb,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EACpC,OAAO,CACR,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAdD,gCAcC;AAED;;;;GAIG;AACH,SAAS,uBAAuB,CAC9B,eAAuB,EACvB,cAA2C;IAE3C,IAAI,cAAc,EAAE;QAClB,MAAM,IAAI,GACR,cAAc,CAAC,MAAM,CAAC,eAAQ,CAAC,eAAe,CAAC;YAC/C,cAAc,CAAC,MAAM,CAAC,qBAAW,CAAC,IAAI,CAAC,CAAC;QAE1C,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;KACvB;IAED,IAAI,MAAgB,CAAC;IACrB,IAAI,OAAO,eAAe,KAAK,UAAU,EAAE;QACzC,wBAAwB;QACxB,MAAM,GAAG,eAAe,CAAC;KAC1B;SAAM;QACL,6BAA6B;QAC7B,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC;KACtC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAAC,kBAA0B;IACxD,OAAO,qBAAW,CAAC;QACjB,CAAC,eAAQ,CAAC,aAAa,CAAC,EAAE,kBAAkB;KAC7C,CAAC,CAAC;AACL,CAAC;AAJD,0CAIC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,kBAA0B;IACrD,OAAO,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAC,CAAC,eAAQ,CAAC,aAAa,CAAC,EAAE,kBAAkB,EAAC,CAAC,CAAC;AAChF,CAAC;AAFD,oCAEC;AAED;;;;;;GAMG;AACH,SAAgB,YAAY,CAC1B,OAAgB,EAChB,kBAA0B,EAC1B,cAAoC,EACpC,OAAiC;IAEjC,MAAM,OAAO,GAAG,gCAAsB,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,KAAK,CACnE,YAAY,CAAC,kBAAkB,CAAC,CACjC,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,OAAO,CAAC;AACjB,CAAC;AAXD,oCAWC"}
package/dist/index.d.ts CHANGED
@@ -6,3 +6,4 @@ export * from './keys';
6
6
  export * from './lifecycle';
7
7
  export * from './lifecycle-registry';
8
8
  export * from './server';
9
+ export * from './service';
package/dist/index.js CHANGED
@@ -16,4 +16,5 @@ __export(require("./extension-point"));
16
16
  __export(require("./keys"));
17
17
  __export(require("./lifecycle"));
18
18
  __export(require("./lifecycle-registry"));
19
+ __export(require("./service"));
19
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;;;;AAEhE,qDAAqD;AACrD,uCAAkC;AAElC,cAAc;AACd,mCAA8B;AAC9B,iCAA4B;AAC5B,uCAAkC;AAClC,4BAAuB;AACvB,iCAA4B;AAC5B,0CAAqC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;;;;AAEhE,qDAAqD;AACrD,uCAAkC;AAElC,cAAc;AACd,mCAA8B;AAC9B,iCAA4B;AAC5B,uCAAkC;AAClC,4BAAuB;AACvB,iCAA4B;AAC5B,0CAAqC;AAErC,+BAA0B"}
package/dist/keys.d.ts CHANGED
@@ -73,6 +73,10 @@ export declare namespace CoreTags {
73
73
  * Binding tag for services
74
74
  */
75
75
  const SERVICE = "service";
76
+ /**
77
+ * Binding tag for the service interface
78
+ */
79
+ const SERVICE_INTERFACE = "serviceInterface";
76
80
  /**
77
81
  * Binding tag for life cycle observers
78
82
  */
package/dist/keys.js CHANGED
@@ -83,6 +83,10 @@ var CoreTags;
83
83
  * Binding tag for services
84
84
  */
85
85
  CoreTags.SERVICE = 'service';
86
+ /**
87
+ * Binding tag for the service interface
88
+ */
89
+ CoreTags.SERVICE_INTERFACE = 'serviceInterface';
86
90
  /**
87
91
  * Binding tag for life cycle observers
88
92
  */
package/dist/keys.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;AAEhE,+CAA6C;AAY7C;;GAEG;AACH,IAAiB,YAAY,CAgF5B;AAhFD,WAAiB,YAAY;IAC3B,cAAc;IACd;;OAEG;IACU,iCAAoB,GAAG,oBAAU,CAAC,MAAM,CACnD,sBAAsB,CACvB,CAAC;IAEF;;OAEG;IACU,+BAAkB,GAAG,oBAAU,CAAC,MAAM,CACjD,oBAAoB,CACrB,CAAC;IAEF;;OAEG;IACU,iCAAoB,GAAG,oBAAU,CAAC,MAAM,CACnD,sBAAsB,CACvB,CAAC;IAEF,SAAS;IACT;;OAEG;IACU,oBAAO,GAAG,SAAS,CAAC;IAEjC,YAAY;IACZ;;OAEG;IACU,uBAAU,GAAG,YAAY,CAAC;IAEvC,aAAa;IACA,wBAAW,GAAG,aAAa,CAAC;IAEzC;;;OAGG;IACU,6BAAgB,GAAG,oBAAU,CAAC,MAAM,CAC/C,yBAAyB,CAC1B,CAAC;IAEF;;;OAGG;IACU,mCAAsB,GAAG,oBAAU,CAAC,MAAM,CACrD,8BAA8B,CAC/B,CAAC;IAEF;;;OAGG;IACU,mCAAsB,GAAG,wBAAwB,CAAC;IAE/D;;;OAGG;IACU,+BAAkB,GAAG,oBAAU,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAE7D,iCAAoB,GAAG,oBAAoB,CAAC;IACzD;;OAEG;IACU,yCAA4B,GAAG,oBAAU,CAAC,MAAM,CAE3D,4BAA4B,CAAC,CAAC;IAEhC;;OAEG;IACU,wCAA2B,GAAG,oBAAU,CAAC,MAAM,CAE1D,2BAA2B,CAAC,CAAC;AACjC,CAAC,EAhFgB,YAAY,GAAZ,oBAAY,KAAZ,oBAAY,QAgF5B;AAED,IAAiB,QAAQ,CAyCxB;AAzCD,WAAiB,QAAQ;IACvB;;OAEG;IACU,kBAAS,GAAG,WAAW,CAAC;IAErC;;OAEG;IACU,eAAM,GAAG,QAAQ,CAAC;IAE/B;;OAEG;IACU,mBAAU,GAAG,YAAY,CAAC;IAEvC;;OAEG;IACU,gBAAO,GAAG,SAAS,CAAC;IAEjC;;OAEG;IACU,4BAAmB,GAAG,mBAAmB,CAAC;IAEvD;;OAEG;IACU,kCAAyB,GAAG,wBAAwB,CAAC;IAElE;;;OAGG;IACU,sBAAa,GAAG,cAAc,CAAC;IAE5C;;OAEG;IACU,wBAAe,GAAG,gBAAgB,CAAC;AAClD,CAAC,EAzCgB,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAyCxB"}
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8BAA8B;AAC9B,+CAA+C;AAC/C,gEAAgE;;AAEhE,+CAA6C;AAY7C;;GAEG;AACH,IAAiB,YAAY,CAgF5B;AAhFD,WAAiB,YAAY;IAC3B,cAAc;IACd;;OAEG;IACU,iCAAoB,GAAG,oBAAU,CAAC,MAAM,CACnD,sBAAsB,CACvB,CAAC;IAEF;;OAEG;IACU,+BAAkB,GAAG,oBAAU,CAAC,MAAM,CACjD,oBAAoB,CACrB,CAAC;IAEF;;OAEG;IACU,iCAAoB,GAAG,oBAAU,CAAC,MAAM,CACnD,sBAAsB,CACvB,CAAC;IAEF,SAAS;IACT;;OAEG;IACU,oBAAO,GAAG,SAAS,CAAC;IAEjC,YAAY;IACZ;;OAEG;IACU,uBAAU,GAAG,YAAY,CAAC;IAEvC,aAAa;IACA,wBAAW,GAAG,aAAa,CAAC;IAEzC;;;OAGG;IACU,6BAAgB,GAAG,oBAAU,CAAC,MAAM,CAC/C,yBAAyB,CAC1B,CAAC;IAEF;;;OAGG;IACU,mCAAsB,GAAG,oBAAU,CAAC,MAAM,CACrD,8BAA8B,CAC/B,CAAC;IAEF;;;OAGG;IACU,mCAAsB,GAAG,wBAAwB,CAAC;IAE/D;;;OAGG;IACU,+BAAkB,GAAG,oBAAU,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAE7D,iCAAoB,GAAG,oBAAoB,CAAC;IACzD;;OAEG;IACU,yCAA4B,GAAG,oBAAU,CAAC,MAAM,CAE3D,4BAA4B,CAAC,CAAC;IAEhC;;OAEG;IACU,wCAA2B,GAAG,oBAAU,CAAC,MAAM,CAE1D,2BAA2B,CAAC,CAAC;AACjC,CAAC,EAhFgB,YAAY,GAAZ,oBAAY,KAAZ,oBAAY,QAgF5B;AAED,IAAiB,QAAQ,CA6CxB;AA7CD,WAAiB,QAAQ;IACvB;;OAEG;IACU,kBAAS,GAAG,WAAW,CAAC;IAErC;;OAEG;IACU,eAAM,GAAG,QAAQ,CAAC;IAE/B;;OAEG;IACU,mBAAU,GAAG,YAAY,CAAC;IAEvC;;OAEG;IACU,gBAAO,GAAG,SAAS,CAAC;IACjC;;OAEG;IACU,0BAAiB,GAAG,kBAAkB,CAAC;IAEpD;;OAEG;IACU,4BAAmB,GAAG,mBAAmB,CAAC;IAEvD;;OAEG;IACU,kCAAyB,GAAG,wBAAwB,CAAC;IAElE;;;OAGG;IACU,sBAAa,GAAG,cAAc,CAAC;IAE5C;;OAEG;IACU,wBAAe,GAAG,gBAAgB,CAAC;AAClD,CAAC,EA7CgB,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QA6CxB"}
@@ -0,0 +1,63 @@
1
+ import { Binding, BindingFilter, BindingTemplate, Constructor, InjectionMetadata, Provider } from '@loopback/context';
2
+ /**
3
+ * Representing an interface for services. In TypeScript, the `interface` does
4
+ * not have reflections at runtime. We use a string, a symbol or a Function as
5
+ * the type for the service interface.
6
+ */
7
+ export declare type ServiceInterface = string | symbol | Function;
8
+ /**
9
+ * Options to register a service binding
10
+ */
11
+ export declare type ServiceOptions = {
12
+ name?: string;
13
+ interface?: ServiceInterface;
14
+ };
15
+ /**
16
+ * `@service` injects a service instance that matches the class or interface.
17
+ *
18
+ * @param serviceInterface - Interface for the service. It can be in one of the
19
+ * following forms:
20
+ *
21
+ * - A class, such as MyService
22
+ * - A string that identifies the interface, such as `'MyService'`
23
+ * - A symbol that identifies the interface, such as `Symbol('MyService')`
24
+ *
25
+ * If not provided, the value is inferred from the design:type of the parameter
26
+ * or property
27
+ *
28
+ * @example
29
+ * ```ts
30
+ *
31
+ * const ctx = new Context();
32
+ * ctx.bind('my-service').toClass(MyService);
33
+ * ctx.bind('logger').toClass(Logger);
34
+ *
35
+ * export class MyController {
36
+ * constructor(@service(MyService) private myService: MyService) {}
37
+ *
38
+ * @service()
39
+ * private logger: Logger;
40
+ * }
41
+ *
42
+ * ctx.bind('my-controller').toClass(MyController);
43
+ * await myController = ctx.get<MyController>('my-controller');
44
+ * ```
45
+ */
46
+ export declare function service(serviceInterface?: ServiceInterface, metadata?: InjectionMetadata): (target: Object, member: string | undefined, methodDescriptorOrParameterIndex?: number | TypedPropertyDescriptor<any> | undefined) => void;
47
+ /**
48
+ * Create a binding filter by service class
49
+ * @param serviceInterface - Service class matching the one used by `binding.toClass()`
50
+ * @param options - Options to control if subclasses should be skipped for matching
51
+ */
52
+ export declare function filterByServiceInterface(serviceInterface: ServiceInterface): BindingFilter;
53
+ /**
54
+ * Create a service binding from a class or provider
55
+ * @param cls - Service class or provider
56
+ * @param options - Service options
57
+ */
58
+ export declare function createServiceBinding<S>(cls: Constructor<S> | Constructor<Provider<S>>, options?: ServiceOptions): Binding<S>;
59
+ /**
60
+ * Create a binding template for a service interface
61
+ * @param serviceInterface - Service interface
62
+ */
63
+ export declare function asService(serviceInterface: ServiceInterface): BindingTemplate;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 2019. All Rights Reserved.
3
+ // Node module: @loopback/core
4
+ // This file is licensed under the MIT License.
5
+ // License text available at https://opensource.org/licenses/MIT
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const context_1 = require("@loopback/context");
8
+ const keys_1 = require("./keys");
9
+ /**
10
+ * `@service` injects a service instance that matches the class or interface.
11
+ *
12
+ * @param serviceInterface - Interface for the service. It can be in one of the
13
+ * following forms:
14
+ *
15
+ * - A class, such as MyService
16
+ * - A string that identifies the interface, such as `'MyService'`
17
+ * - A symbol that identifies the interface, such as `Symbol('MyService')`
18
+ *
19
+ * If not provided, the value is inferred from the design:type of the parameter
20
+ * or property
21
+ *
22
+ * @example
23
+ * ```ts
24
+ *
25
+ * const ctx = new Context();
26
+ * ctx.bind('my-service').toClass(MyService);
27
+ * ctx.bind('logger').toClass(Logger);
28
+ *
29
+ * export class MyController {
30
+ * constructor(@service(MyService) private myService: MyService) {}
31
+ *
32
+ * @service()
33
+ * private logger: Logger;
34
+ * }
35
+ *
36
+ * ctx.bind('my-controller').toClass(MyController);
37
+ * await myController = ctx.get<MyController>('my-controller');
38
+ * ```
39
+ */
40
+ function service(serviceInterface, metadata) {
41
+ return context_1.inject('', Object.assign({ decorator: '@service' }, metadata), (ctx, injection, session) => {
42
+ let serviceType = serviceInterface;
43
+ if (!serviceType) {
44
+ if (typeof injection.methodDescriptorOrParameterIndex === 'number') {
45
+ serviceType = context_1.MetadataInspector.getDesignTypeForMethod(injection.target, injection.member).parameterTypes[injection.methodDescriptorOrParameterIndex];
46
+ }
47
+ else {
48
+ serviceType = context_1.MetadataInspector.getDesignTypeForProperty(injection.target, injection.member);
49
+ }
50
+ }
51
+ if (serviceType === Object || serviceType === Array) {
52
+ throw new Error('Service class cannot be inferred from design type. Use @service(ServiceClass).');
53
+ }
54
+ const view = new context_1.ContextView(ctx, filterByServiceInterface(serviceType));
55
+ const result = view.resolve(session);
56
+ const serviceTypeName = typeof serviceType === 'string'
57
+ ? serviceType
58
+ : typeof serviceType === 'symbol'
59
+ ? serviceType.toString()
60
+ : serviceType.name;
61
+ return context_1.transformValueOrPromise(result, values => {
62
+ var _a;
63
+ if (values.length === 1)
64
+ return values[0];
65
+ if (values.length >= 1) {
66
+ throw new Error(`More than one bindings found for ${serviceTypeName}`);
67
+ }
68
+ else {
69
+ if ((_a = metadata) === null || _a === void 0 ? void 0 : _a.optional) {
70
+ return undefined;
71
+ }
72
+ throw new Error(`No binding found for ${serviceTypeName}. Make sure a service ` +
73
+ `binding is created in context ${ctx.name} with serviceInterface (${serviceTypeName}).`);
74
+ }
75
+ });
76
+ });
77
+ }
78
+ exports.service = service;
79
+ /**
80
+ * Create a binding filter by service class
81
+ * @param serviceInterface - Service class matching the one used by `binding.toClass()`
82
+ * @param options - Options to control if subclasses should be skipped for matching
83
+ */
84
+ function filterByServiceInterface(serviceInterface) {
85
+ return binding => binding.valueConstructor === serviceInterface ||
86
+ binding.tagMap[keys_1.CoreTags.SERVICE_INTERFACE] === serviceInterface;
87
+ }
88
+ exports.filterByServiceInterface = filterByServiceInterface;
89
+ /**
90
+ * Create a service binding from a class or provider
91
+ * @param cls - Service class or provider
92
+ * @param options - Service options
93
+ */
94
+ function createServiceBinding(cls, options = {}) {
95
+ var _a;
96
+ let name = options.name;
97
+ if (!name && context_1.isProviderClass(cls)) {
98
+ // Trim `Provider` from the default service name
99
+ // This is needed to keep backward compatibility
100
+ const templateFn = context_1.bindingTemplateFor(cls);
101
+ const template = context_1.Binding.bind('template').apply(templateFn);
102
+ if (template.tagMap[context_1.ContextTags.PROVIDER] &&
103
+ !template.tagMap[context_1.ContextTags.NAME]) {
104
+ // The class is a provider and no `name` tag is found
105
+ name = cls.name.replace(/Provider$/, '');
106
+ }
107
+ }
108
+ const binding = context_1.createBindingFromClass(cls, {
109
+ name,
110
+ type: keys_1.CoreTags.SERVICE,
111
+ }).apply(asService((_a = options.interface, (_a !== null && _a !== void 0 ? _a : cls))));
112
+ return binding;
113
+ }
114
+ exports.createServiceBinding = createServiceBinding;
115
+ /**
116
+ * Create a binding template for a service interface
117
+ * @param serviceInterface - Service interface
118
+ */
119
+ function asService(serviceInterface) {
120
+ return function serviceTemplate(binding) {
121
+ binding.tag({
122
+ [context_1.ContextTags.TYPE]: keys_1.CoreTags.SERVICE,
123
+ [keys_1.CoreTags.SERVICE_INTERFACE]: serviceInterface,
124
+ });
125
+ };
126
+ }
127
+ exports.asService = asService;
128
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loopback/core",
3
- "version": "1.10.7",
3
+ "version": "1.12.2",
4
4
  "description": "LoopBack 4 core",
5
5
  "engines": {
6
6
  "node": ">=8.9"
@@ -19,15 +19,16 @@
19
19
  "copyright.owner": "IBM Corp.",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@loopback/context": "^1.23.5",
23
- "debug": "^4.1.1"
22
+ "@loopback/context": "^2.0.0",
23
+ "debug": "^4.1.1",
24
+ "p-event": "^4.1.0"
24
25
  },
25
26
  "devDependencies": {
26
- "@loopback/build": "^2.0.16",
27
- "@loopback/eslint-config": "^4.1.4",
28
- "@loopback/testlab": "^1.9.4",
27
+ "@loopback/build": "^3.1.0",
28
+ "@loopback/eslint-config": "^5.0.2",
29
+ "@loopback/testlab": "^1.10.2",
29
30
  "@types/debug": "^4.1.5",
30
- "@types/node": "^10.17.5"
31
+ "@types/node": "^10.17.13"
31
32
  },
32
33
  "files": [
33
34
  "README.md",
@@ -42,5 +43,5 @@
42
43
  "url": "https://github.com/strongloop/loopback-next.git",
43
44
  "directory": "packages/core"
44
45
  },
45
- "gitHead": "7f0ae6ec124c19357c3016cd11f9bc9c739dffcb"
46
+ "gitHead": "d08f135a0d1040edc61497739a8d86a866e4e29a"
46
47
  }
@@ -6,15 +6,14 @@
6
6
  import {
7
7
  Binding,
8
8
  BindingScope,
9
- bindingTemplateFor,
10
9
  Constructor,
11
10
  Context,
12
- ContextTags,
13
11
  createBindingFromClass,
14
- isProviderClass,
15
12
  Provider,
16
13
  } from '@loopback/context';
17
- import * as debugFactory from 'debug';
14
+ import assert from 'assert';
15
+ import pEvent from 'p-event';
16
+ import debugFactory from 'debug';
18
17
  import {Component, mountComponent} from './component';
19
18
  import {CoreBindings, CoreTags} from './keys';
20
19
  import {
@@ -24,6 +23,7 @@ import {
24
23
  } from './lifecycle';
25
24
  import {LifeCycleObserverRegistry} from './lifecycle-registry';
26
25
  import {Server} from './server';
26
+ import {createServiceBinding, ServiceOptions} from './service';
27
27
  const debug = debugFactory('loopback:core:application');
28
28
 
29
29
  /**
@@ -34,6 +34,39 @@ const debug = debugFactory('loopback:core:application');
34
34
  export class Application extends Context implements LifeCycleObserver {
35
35
  public readonly options: ApplicationConfig;
36
36
 
37
+ /**
38
+ * A flag to indicate that the application is being shut down
39
+ */
40
+ private _isShuttingDown = false;
41
+
42
+ /**
43
+ * State of the application
44
+ */
45
+ private _state = 'created';
46
+
47
+ /**
48
+ * Get the state of the application. The initial state is `created` and it can
49
+ * transition as follows by `start` and `stop`:
50
+ *
51
+ * 1. start
52
+ * - !started -> starting -> started
53
+ * - started -> started (no-op)
54
+ * 2. stop
55
+ * - started -> stopping -> stopped
56
+ * - !started -> stopped (no-op)
57
+ *
58
+ * Two types of states are expected:
59
+ * - stable, such as `started` and `stopped`
60
+ * - in process, such as `booting` and `starting`
61
+ *
62
+ * Operations such as `start` and `stop` can only be called at a stable state.
63
+ * The logic should immediately set the state to a new one indicating work in
64
+ * process, such as `starting` and `stopping`.
65
+ */
66
+ public get state() {
67
+ return this._state;
68
+ }
69
+
37
70
  /**
38
71
  * Create an application with the given parent context
39
72
  * @param parent - Parent context
@@ -53,7 +86,7 @@ export class Application extends Context implements LifeCycleObserver {
53
86
  );
54
87
 
55
88
  if (configOrParent instanceof Context) configOrParent = {};
56
- this.options = configOrParent || {};
89
+ this.options = configOrParent ?? {};
57
90
 
58
91
  // Bind the life cycle observer registry
59
92
  this.bind(CoreBindings.LIFE_CYCLE_OBSERVER_REGISTRY)
@@ -63,6 +96,12 @@ export class Application extends Context implements LifeCycleObserver {
63
96
  this.bind(CoreBindings.APPLICATION_INSTANCE).to(this);
64
97
  // Make options available to other modules as well.
65
98
  this.bind(CoreBindings.APPLICATION_CONFIG).to(this.options);
99
+
100
+ const shutdownConfig = this.options.shutdown ?? {};
101
+ this.setupShutdown(
102
+ shutdownConfig.signals ?? ['SIGTERM'],
103
+ shutdownConfig.gracePeriod,
104
+ );
66
105
  }
67
106
 
68
107
  /**
@@ -83,7 +122,7 @@ export class Application extends Context implements LifeCycleObserver {
83
122
  * ```
84
123
  */
85
124
  controller(controllerCtor: ControllerClass, name?: string): Binding {
86
- debug('Adding controller %s', name || controllerCtor.name);
125
+ debug('Adding controller %s', name ?? controllerCtor.name);
87
126
  const binding = createBindingFromClass(controllerCtor, {
88
127
  name,
89
128
  namespace: CoreBindings.CONTROLLERS,
@@ -116,7 +155,7 @@ export class Application extends Context implements LifeCycleObserver {
116
155
  ctor: Constructor<T>,
117
156
  name?: string,
118
157
  ): Binding<T> {
119
- debug('Adding server %s', name || ctor.name);
158
+ debug('Adding server %s', name ?? ctor.name);
120
159
  const binding = createBindingFromClass(ctor, {
121
160
  name,
122
161
  namespace: CoreBindings.SERVERS,
@@ -177,19 +216,80 @@ export class Application extends Context implements LifeCycleObserver {
177
216
  }
178
217
 
179
218
  /**
180
- * Start the application, and all of its registered observers.
219
+ * Assert there is no other operation is in progress, i.e., the state is not
220
+ * `*ing`, such as `starting` or `stopping`.
221
+ *
222
+ * @param op - The operation name, such as 'boot', 'start', or 'stop'
223
+ */
224
+ protected assertNotInProcess(op: string) {
225
+ assert(
226
+ !this._state.endsWith('ing'),
227
+ `Cannot ${op} the application as it is ${this._state}.`,
228
+ );
229
+ }
230
+
231
+ /**
232
+ * Assert current state of the application to be one of the expected values
233
+ * @param op - The operation name, such as 'boot', 'start', or 'stop'
234
+ * @param states - Valid states
235
+ */
236
+ protected assertInStates(op: string, ...states: string[]) {
237
+ assert(
238
+ states.includes(this._state),
239
+ `Cannot ${op} the application as it is ${this._state}. Valid states are ${states}.`,
240
+ );
241
+ }
242
+
243
+ /**
244
+ * Transition the application to a new state and emit an event
245
+ * @param state - The new state
246
+ */
247
+ protected setState(state: string) {
248
+ const oldState = this._state;
249
+ this._state = state;
250
+ if (oldState !== state) {
251
+ this.emit('stateChanged', {from: oldState, to: this._state});
252
+ this.emit(state);
253
+ }
254
+ }
255
+
256
+ protected async awaitState(state: string) {
257
+ await pEvent(this, state);
258
+ }
259
+
260
+ /**
261
+ * Start the application, and all of its registered observers. The application
262
+ * state is checked to ensure the integrity of `start`.
263
+ *
264
+ * If the application is already started, no operation is performed.
181
265
  */
182
266
  public async start(): Promise<void> {
267
+ if (this._state === 'starting') return this.awaitState('started');
268
+ this.assertNotInProcess('start');
269
+ // No-op if it's started
270
+ if (this._state === 'started') return;
271
+ this.setState('starting');
183
272
  const registry = await this.getLifeCycleObserverRegistry();
184
273
  await registry.start();
274
+ this.setState('started');
185
275
  }
186
276
 
187
277
  /**
188
- * Stop the application instance and all of its registered observers.
278
+ * Stop the application instance and all of its registered observers. The
279
+ * application state is checked to ensure the integrity of `stop`.
280
+ *
281
+ * If the application is already stopped or not started, no operation is
282
+ * performed.
189
283
  */
190
284
  public async stop(): Promise<void> {
285
+ if (this._state === 'stopping') return this.awaitState('stopped');
286
+ this.assertNotInProcess('stop');
287
+ // No-op if it's created or stopped
288
+ if (this._state !== 'started') return;
289
+ this.setState('stopping');
191
290
  const registry = await this.getLifeCycleObserverRegistry();
192
291
  await registry.stop();
292
+ this.setState('stopped');
193
293
  }
194
294
 
195
295
  private async getLifeCycleObserverRegistry() {
@@ -219,7 +319,7 @@ export class Application extends Context implements LifeCycleObserver {
219
319
  * ```
220
320
  */
221
321
  public component(componentCtor: Constructor<Component>, name?: string) {
222
- debug('Adding component: %s', name || componentCtor.name);
322
+ debug('Adding component: %s', name ?? componentCtor.name);
223
323
  const binding = createBindingFromClass(componentCtor, {
224
324
  name,
225
325
  namespace: CoreBindings.COMPONENTS,
@@ -255,7 +355,7 @@ export class Application extends Context implements LifeCycleObserver {
255
355
  ctor: Constructor<T>,
256
356
  name?: string,
257
357
  ): Binding<T> {
258
- debug('Adding life cycle observer %s', name || ctor.name);
358
+ debug('Adding life cycle observer %s', name ?? ctor.name);
259
359
  const binding = createBindingFromClass(ctor, {
260
360
  name,
261
361
  namespace: CoreBindings.LIFE_CYCLE_OBSERVERS,
@@ -310,34 +410,70 @@ export class Application extends Context implements LifeCycleObserver {
310
410
  */
311
411
  public service<S>(
312
412
  cls: Constructor<S> | Constructor<Provider<S>>,
313
- name?: string,
413
+ name?: string | ServiceOptions,
314
414
  ): Binding<S> {
315
- if (!name && isProviderClass(cls)) {
316
- // Trim `Provider` from the default service name
317
- // This is needed to keep backward compatibility
318
- const templateFn = bindingTemplateFor(cls);
319
- const template = Binding.bind<S>('template').apply(templateFn);
320
- if (
321
- template.tagMap[ContextTags.PROVIDER] &&
322
- !template.tagMap[ContextTags.NAME]
323
- ) {
324
- // The class is a provider and no `name` tag is found
325
- name = cls.name.replace(/Provider$/, '');
326
- }
327
- }
328
- const binding = createBindingFromClass(cls, {
329
- name,
330
- type: 'service',
331
- });
415
+ const options = typeof name === 'string' ? {name} : name;
416
+ const binding = createServiceBinding(cls, options);
332
417
  this.add(binding);
333
418
  return binding;
334
419
  }
420
+
421
+ /**
422
+ * Set up signals that are captured to shutdown the application
423
+ * @param signals - An array of signals to be trapped
424
+ * @param gracePeriod - A grace period in ms before forced exit
425
+ */
426
+ protected setupShutdown(signals: NodeJS.Signals[], gracePeriod?: number) {
427
+ const cleanup = async (signal: string) => {
428
+ const kill = () => {
429
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
430
+ signals.forEach(sig => process.removeListener(sig, cleanup));
431
+ process.kill(process.pid, signal);
432
+ };
433
+ debug('Signal %s received for process %d', signal, process.pid);
434
+ if (!this._isShuttingDown) {
435
+ this._isShuttingDown = true;
436
+ let timer;
437
+ if (typeof gracePeriod === 'number' && !isNaN(gracePeriod)) {
438
+ timer = setTimeout(kill, gracePeriod);
439
+ }
440
+ try {
441
+ await this.stop();
442
+ } finally {
443
+ if (timer != null) clearTimeout(timer);
444
+ kill();
445
+ }
446
+ }
447
+ };
448
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
449
+ signals.forEach(sig => process.on(sig, cleanup));
450
+ }
335
451
  }
336
452
 
453
+ /**
454
+ * Options to set up application shutdown
455
+ */
456
+ export type ShutdownOptions = {
457
+ /**
458
+ * An array of signals to be trapped for graceful shutdown
459
+ */
460
+ signals?: NodeJS.Signals[];
461
+ /**
462
+ * Period in milliseconds to wait for the grace shutdown to finish before
463
+ * exiting the process
464
+ */
465
+ gracePeriod?: number;
466
+ };
467
+
337
468
  /**
338
469
  * Configuration for application
339
470
  */
340
471
  export interface ApplicationConfig {
472
+ /**
473
+ * Configuration for signals that shut down the application
474
+ */
475
+ shutdown?: ShutdownOptions;
476
+
341
477
  /**
342
478
  * Other properties
343
479
  */
@@ -67,7 +67,7 @@ export function extensionPoint(name: string, ...specs: BindingSpec[]) {
67
67
  export function extensions(extensionPointName?: string) {
68
68
  return inject('', {decorator: '@extensions'}, (ctx, injection, session) => {
69
69
  extensionPointName =
70
- extensionPointName ||
70
+ extensionPointName ??
71
71
  inferExtensionPointName(injection.target, session.currentBinding);
72
72
 
73
73
  const bindingFilter = extensionFilter(extensionPointName);
package/src/index.ts CHANGED
@@ -14,3 +14,4 @@ export * from './keys';
14
14
  export * from './lifecycle';
15
15
  export * from './lifecycle-registry';
16
16
  export * from './server';
17
+ export * from './service';
package/src/keys.ts CHANGED
@@ -120,6 +120,10 @@ export namespace CoreTags {
120
120
  * Binding tag for services
121
121
  */
122
122
  export const SERVICE = 'service';
123
+ /**
124
+ * Binding tag for the service interface
125
+ */
126
+ export const SERVICE_INTERFACE = 'serviceInterface';
123
127
 
124
128
  /**
125
129
  * Binding tag for life cycle observers
package/src/service.ts ADDED
@@ -0,0 +1,180 @@
1
+ // Copyright IBM Corp. 2019. All Rights Reserved.
2
+ // Node module: @loopback/core
3
+ // This file is licensed under the MIT License.
4
+ // License text available at https://opensource.org/licenses/MIT
5
+
6
+ import {
7
+ Binding,
8
+ BindingFilter,
9
+ BindingTemplate,
10
+ bindingTemplateFor,
11
+ Constructor,
12
+ ContextTags,
13
+ ContextView,
14
+ createBindingFromClass,
15
+ inject,
16
+ InjectionMetadata,
17
+ isProviderClass,
18
+ MetadataInspector,
19
+ Provider,
20
+ transformValueOrPromise,
21
+ } from '@loopback/context';
22
+ import {CoreTags} from './keys';
23
+
24
+ /**
25
+ * Representing an interface for services. In TypeScript, the `interface` does
26
+ * not have reflections at runtime. We use a string, a symbol or a Function as
27
+ * the type for the service interface.
28
+ */
29
+ export type ServiceInterface = string | symbol | Function;
30
+
31
+ /**
32
+ * Options to register a service binding
33
+ */
34
+ export type ServiceOptions = {
35
+ name?: string;
36
+ interface?: ServiceInterface;
37
+ };
38
+
39
+ /**
40
+ * `@service` injects a service instance that matches the class or interface.
41
+ *
42
+ * @param serviceInterface - Interface for the service. It can be in one of the
43
+ * following forms:
44
+ *
45
+ * - A class, such as MyService
46
+ * - A string that identifies the interface, such as `'MyService'`
47
+ * - A symbol that identifies the interface, such as `Symbol('MyService')`
48
+ *
49
+ * If not provided, the value is inferred from the design:type of the parameter
50
+ * or property
51
+ *
52
+ * @example
53
+ * ```ts
54
+ *
55
+ * const ctx = new Context();
56
+ * ctx.bind('my-service').toClass(MyService);
57
+ * ctx.bind('logger').toClass(Logger);
58
+ *
59
+ * export class MyController {
60
+ * constructor(@service(MyService) private myService: MyService) {}
61
+ *
62
+ * @service()
63
+ * private logger: Logger;
64
+ * }
65
+ *
66
+ * ctx.bind('my-controller').toClass(MyController);
67
+ * await myController = ctx.get<MyController>('my-controller');
68
+ * ```
69
+ */
70
+ export function service(
71
+ serviceInterface?: ServiceInterface,
72
+ metadata?: InjectionMetadata,
73
+ ) {
74
+ return inject(
75
+ '',
76
+ {decorator: '@service', ...metadata},
77
+ (ctx, injection, session) => {
78
+ let serviceType = serviceInterface;
79
+ if (!serviceType) {
80
+ if (typeof injection.methodDescriptorOrParameterIndex === 'number') {
81
+ serviceType = MetadataInspector.getDesignTypeForMethod(
82
+ injection.target,
83
+ injection.member!,
84
+ ).parameterTypes[injection.methodDescriptorOrParameterIndex];
85
+ } else {
86
+ serviceType = MetadataInspector.getDesignTypeForProperty(
87
+ injection.target,
88
+ injection.member!,
89
+ );
90
+ }
91
+ }
92
+ if (serviceType === Object || serviceType === Array) {
93
+ throw new Error(
94
+ 'Service class cannot be inferred from design type. Use @service(ServiceClass).',
95
+ );
96
+ }
97
+ const view = new ContextView(ctx, filterByServiceInterface(serviceType));
98
+ const result = view.resolve(session);
99
+
100
+ const serviceTypeName =
101
+ typeof serviceType === 'string'
102
+ ? serviceType
103
+ : typeof serviceType === 'symbol'
104
+ ? serviceType.toString()
105
+ : serviceType.name;
106
+ return transformValueOrPromise(result, values => {
107
+ if (values.length === 1) return values[0];
108
+ if (values.length >= 1) {
109
+ throw new Error(
110
+ `More than one bindings found for ${serviceTypeName}`,
111
+ );
112
+ } else {
113
+ if (metadata?.optional) {
114
+ return undefined;
115
+ }
116
+ throw new Error(
117
+ `No binding found for ${serviceTypeName}. Make sure a service ` +
118
+ `binding is created in context ${ctx.name} with serviceInterface (${serviceTypeName}).`,
119
+ );
120
+ }
121
+ });
122
+ },
123
+ );
124
+ }
125
+
126
+ /**
127
+ * Create a binding filter by service class
128
+ * @param serviceInterface - Service class matching the one used by `binding.toClass()`
129
+ * @param options - Options to control if subclasses should be skipped for matching
130
+ */
131
+ export function filterByServiceInterface(
132
+ serviceInterface: ServiceInterface,
133
+ ): BindingFilter {
134
+ return binding =>
135
+ binding.valueConstructor === serviceInterface ||
136
+ binding.tagMap[CoreTags.SERVICE_INTERFACE] === serviceInterface;
137
+ }
138
+
139
+ /**
140
+ * Create a service binding from a class or provider
141
+ * @param cls - Service class or provider
142
+ * @param options - Service options
143
+ */
144
+ export function createServiceBinding<S>(
145
+ cls: Constructor<S> | Constructor<Provider<S>>,
146
+ options: ServiceOptions = {},
147
+ ): Binding<S> {
148
+ let name = options.name;
149
+ if (!name && isProviderClass(cls)) {
150
+ // Trim `Provider` from the default service name
151
+ // This is needed to keep backward compatibility
152
+ const templateFn = bindingTemplateFor(cls);
153
+ const template = Binding.bind<S>('template').apply(templateFn);
154
+ if (
155
+ template.tagMap[ContextTags.PROVIDER] &&
156
+ !template.tagMap[ContextTags.NAME]
157
+ ) {
158
+ // The class is a provider and no `name` tag is found
159
+ name = cls.name.replace(/Provider$/, '');
160
+ }
161
+ }
162
+ const binding = createBindingFromClass(cls, {
163
+ name,
164
+ type: CoreTags.SERVICE,
165
+ }).apply(asService(options.interface ?? cls));
166
+ return binding;
167
+ }
168
+
169
+ /**
170
+ * Create a binding template for a service interface
171
+ * @param serviceInterface - Service interface
172
+ */
173
+ export function asService(serviceInterface: ServiceInterface): BindingTemplate {
174
+ return function serviceTemplate(binding: Binding) {
175
+ binding.tag({
176
+ [ContextTags.TYPE]: CoreTags.SERVICE,
177
+ [CoreTags.SERVICE_INTERFACE]: serviceInterface,
178
+ });
179
+ };
180
+ }