@loopback/service-proxy 3.2.3

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/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) IBM Corp. 2018,2019.
2
+ Node module: @loopback/service-proxy
3
+ This project is licensed under the MIT License, full text below.
4
+
5
+ --------
6
+
7
+ MIT license
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in
17
+ all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # @loopback/service-proxy
2
+
3
+ This module provides a common set of interfaces for interacting with service
4
+ oriented backends such as REST APIs, SOAP Web Services, and gRPC microservices.
5
+
6
+ ## Installation
7
+
8
+ ```
9
+ $ npm install @loopback/service-proxy
10
+ ```
11
+
12
+ ## Basic use
13
+
14
+ See https://loopback.io/doc/en/lb4/Calling-other-APIs-and-web-services.html
15
+
16
+ ## Contributions
17
+
18
+ - [Guidelines](https://github.com/loopbackio/loopback-next/blob/master/docs/CONTRIBUTING.md)
19
+ - [Join the team](https://github.com/loopbackio/loopback-next/issues/110)
20
+
21
+ ## Tests
22
+
23
+ run 'npm test' from the root folder.
24
+
25
+ ## Contributors
26
+
27
+ See
28
+ [all contributors](https://github.com/loopbackio/loopback-next/graphs/contributors).
29
+
30
+ ## License
31
+
32
+ MIT
@@ -0,0 +1,17 @@
1
+ import { MetadataAccessor, InjectionMetadata } from '@loopback/core';
2
+ import { juggler } from '..';
3
+ /**
4
+ * Type definition for decorators returned by `@serviceProxy` decorator factory
5
+ */
6
+ export declare type ServiceProxyDecorator = PropertyDecorator | ParameterDecorator;
7
+ export declare const SERVICE_PROXY_KEY: MetadataAccessor<string, ServiceProxyDecorator>;
8
+ /**
9
+ * Metadata for a service proxy
10
+ */
11
+ export declare class ServiceProxyMetadata implements InjectionMetadata {
12
+ decorator: string;
13
+ dataSourceName?: string;
14
+ dataSource?: juggler.DataSource;
15
+ constructor(dataSource: string | juggler.DataSource);
16
+ }
17
+ export declare function serviceProxy(dataSource: string | juggler.DataSource): (target: object, key: string, parameterIndex?: number | undefined) => void;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
3
+ // Node module: @loopback/service-proxy
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
+ exports.serviceProxy = exports.ServiceProxyMetadata = exports.SERVICE_PROXY_KEY = void 0;
8
+ const core_1 = require("@loopback/core");
9
+ const __1 = require("..");
10
+ exports.SERVICE_PROXY_KEY = core_1.MetadataAccessor.create('service.proxy');
11
+ /**
12
+ * Metadata for a service proxy
13
+ */
14
+ class ServiceProxyMetadata {
15
+ constructor(dataSource) {
16
+ this.decorator = '@serviceProxy';
17
+ if (typeof dataSource === 'string') {
18
+ this.dataSourceName = dataSource;
19
+ }
20
+ else {
21
+ this.dataSource = dataSource;
22
+ }
23
+ }
24
+ }
25
+ exports.ServiceProxyMetadata = ServiceProxyMetadata;
26
+ function serviceProxy(dataSource) {
27
+ return function (target, key, parameterIndex) {
28
+ if (key || typeof parameterIndex === 'number') {
29
+ const meta = new ServiceProxyMetadata(dataSource);
30
+ core_1.inject('', meta, resolve)(target, key, parameterIndex);
31
+ }
32
+ else {
33
+ throw new Error('@serviceProxy can only be applied to properties or method parameters');
34
+ }
35
+ };
36
+ }
37
+ exports.serviceProxy = serviceProxy;
38
+ /**
39
+ * Resolve the @repository injection
40
+ * @param ctx - Context
41
+ * @param injection - Injection metadata
42
+ */
43
+ async function resolve(ctx, injection) {
44
+ const meta = injection.metadata;
45
+ if (meta.dataSource)
46
+ return __1.getService(meta.dataSource);
47
+ if (meta.dataSourceName) {
48
+ const ds = await ctx.get('datasources.' + meta.dataSourceName);
49
+ return __1.getService(ds);
50
+ }
51
+ throw new Error('@serviceProxy must provide a name or an instance of DataSource');
52
+ }
53
+ //# sourceMappingURL=service.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.decorator.js","sourceRoot":"","sources":["../../src/decorators/service.decorator.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,uCAAuC;AACvC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAMwB;AACxB,0BAAuC;AAO1B,QAAA,iBAAiB,GAAG,uBAAgB,CAAC,MAAM,CAGtD,eAAe,CAAC,CAAC;AAEnB;;GAEG;AACH,MAAa,oBAAoB;IAK/B,YAAY,UAAuC;QAJnD,cAAS,GAAG,eAAe,CAAC;QAK1B,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;YAClC,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC;SAClC;aAAM;YACL,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;SAC9B;IACH,CAAC;CACF;AAZD,oDAYC;AAED,SAAgB,YAAY,CAAC,UAAuC;IAClE,OAAO,UAAU,MAAc,EAAE,GAAW,EAAE,cAAuB;QACnE,IAAI,GAAG,IAAI,OAAO,cAAc,KAAK,QAAQ,EAAE;YAC7C,MAAM,IAAI,GAAG,IAAI,oBAAoB,CAAC,UAAU,CAAC,CAAC;YAClD,aAAM,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;SACxD;aAAM;YACL,MAAM,IAAI,KAAK,CACb,sEAAsE,CACvE,CAAC;SACH;IACH,CAAC,CAAC;AACJ,CAAC;AAXD,oCAWC;AAED;;;;GAIG;AACH,KAAK,UAAU,OAAO,CAAC,GAAY,EAAE,SAAoB;IACvD,MAAM,IAAI,GAAG,SAAS,CAAC,QAAgC,CAAC;IACxD,IAAI,IAAI,CAAC,UAAU;QAAE,OAAO,cAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxD,IAAI,IAAI,CAAC,cAAc,EAAE;QACvB,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,GAAG,CACtB,cAAc,GAAG,IAAI,CAAC,cAAc,CACrC,CAAC;QACF,OAAO,cAAU,CAAC,EAAE,CAAC,CAAC;KACvB;IACD,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * A common set of interfaces for interacting with service oriented backends
3
+ * such as REST APIs, SOAP Web Services, and gRPC microservices.
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+ export * from './decorators/service.decorator';
8
+ export * from './legacy-juggler-bridge';
9
+ export * from './mixins';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
3
+ // Node module: @loopback/service-proxy
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 tslib_1 = require("tslib");
8
+ /**
9
+ * A common set of interfaces for interacting with service oriented backends
10
+ * such as REST APIs, SOAP Web Services, and gRPC microservices.
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+ tslib_1.__exportStar(require("./decorators/service.decorator"), exports);
15
+ tslib_1.__exportStar(require("./legacy-juggler-bridge"), exports);
16
+ tslib_1.__exportStar(require("./mixins"), exports);
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,uCAAuC;AACvC,+CAA+C;AAC/C,gEAAgE;;;AAEhE;;;;;GAKG;AAEH,yEAA+C;AAC/C,kEAAwC;AACxC,mDAAyB"}
@@ -0,0 +1,18 @@
1
+ import legacy from 'loopback-datasource-juggler';
2
+ export declare namespace juggler {
3
+ export import DataSource = legacy.DataSource;
4
+ }
5
+ /**
6
+ * A generic service interface with any number of methods that return a promise
7
+ */
8
+ export interface GenericService {
9
+ [methodName: string]: (...args: any[]) => Promise<any>;
10
+ }
11
+ /**
12
+ * Get a service proxy from a LoopBack 3.x data source backed by
13
+ * service-oriented connectors such as `rest`, `soap`, and `grpc`.
14
+ *
15
+ * @param ds - A legacy data source
16
+ * @typeParam T - The generic type of service interface
17
+ */
18
+ export declare function getService<T = GenericService>(ds: legacy.DataSource): Promise<T>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 2018,2019. All Rights Reserved.
3
+ // Node module: @loopback/service-proxy
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
+ exports.getService = exports.juggler = void 0;
8
+ const tslib_1 = require("tslib");
9
+ const loopback_datasource_juggler_1 = tslib_1.__importDefault(require("loopback-datasource-juggler"));
10
+ var juggler;
11
+ (function (juggler) {
12
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
13
+ juggler.DataSource = loopback_datasource_juggler_1.default.DataSource;
14
+ })(juggler = exports.juggler || (exports.juggler = {}));
15
+ /**
16
+ * Get a service proxy from a LoopBack 3.x data source backed by
17
+ * service-oriented connectors such as `rest`, `soap`, and `grpc`.
18
+ *
19
+ * @param ds - A legacy data source
20
+ * @typeParam T - The generic type of service interface
21
+ */
22
+ async function getService(ds) {
23
+ await ds.connect();
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ return ds.DataAccessObject;
26
+ }
27
+ exports.getService = getService;
28
+ //# sourceMappingURL=legacy-juggler-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-juggler-bridge.js","sourceRoot":"","sources":["../src/legacy-juggler-bridge.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,uCAAuC;AACvC,+CAA+C;AAC/C,gEAAgE;;;;AAEhE,sGAAiD;AAEjD,IAAiB,OAAO,CAGvB;AAHD,WAAiB,OAAO;IACtB,6DAA6D;IAC/C,kBAAU,GAAG,qCAAM,CAAC,UAAU,CAAC;AAC/C,CAAC,EAHgB,OAAO,GAAP,eAAO,KAAP,eAAO,QAGvB;AAUD;;;;;;GAMG;AACI,KAAK,UAAU,UAAU,CAC9B,EAAqB;IAErB,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;IACnB,8DAA8D;IAC9D,OAAO,EAAE,CAAC,gBAAuB,CAAC;AACpC,CAAC;AAND,gCAMC"}
@@ -0,0 +1 @@
1
+ export * from './service.mixin';
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
3
+ // Node module: @loopback/service-proxy
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 tslib_1 = require("tslib");
8
+ tslib_1.__exportStar(require("./service.mixin"), exports);
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mixins/index.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,uCAAuC;AACvC,+CAA+C;AAC/C,gEAAgE;;;AAEhE,0DAAgC"}
@@ -0,0 +1,245 @@
1
+ import { Binding, BindingAddress, BindingFromClassOptions, Provider, Constructor } from '@loopback/core';
2
+ import { Application, MixinTarget, ServiceOptions, Component } from '@loopback/core';
3
+ import * as loopbackContext from '@loopback/core';
4
+ /**
5
+ * Interface for classes with `new` operator.
6
+ */
7
+ export interface Class<T> {
8
+ new (...args: any[]): T;
9
+ }
10
+ /**
11
+ * A mixin class for Application that creates a .serviceProvider()
12
+ * function to register a service automatically. Also overrides
13
+ * component function to allow it to register repositories automatically.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * class MyApplication extends ServiceMixin(Application) {}
18
+ * ```
19
+ *
20
+ * Please note: the members in the mixin function are documented in a dummy class
21
+ * called <a href="#ServiceMixinDoc">ServiceMixinDoc</a>
22
+ *
23
+ * @param superClass - Application class
24
+ * @returns A new class that extends the super class with service proxy related
25
+ * methods
26
+ *
27
+ * @typeParam T - Type of the application class as the target for the mixin
28
+ */
29
+ export declare function ServiceMixin<T extends MixinTarget<Application>>(superClass: T): {
30
+ new (...args: any[]): {
31
+ /**
32
+ * Add a service to this application.
33
+ *
34
+ * @deprecated Use app.service() instead
35
+ *
36
+ * @param provider - The service provider to register.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * export interface GeocoderService {
41
+ * geocode(address: string): Promise<GeoPoint[]>;
42
+ * }
43
+ *
44
+ * export class GeocoderServiceProvider implements Provider<GeocoderService> {
45
+ * constructor(
46
+ * @inject('services.geocoder')
47
+ * protected dataSource: juggler.DataSource = new GeocoderDataSource(),
48
+ * ) {}
49
+ *
50
+ * value(): Promise<GeocoderService> {
51
+ * return getService(this.dataSource);
52
+ * }
53
+ * }
54
+ *
55
+ * app.serviceProvider(GeocoderServiceProvider);
56
+ * ```
57
+ */
58
+ serviceProvider<S>(provider: Constructor<Provider<S>>, nameOrOptions?: string | ServiceOptions | undefined): Binding<S>;
59
+ /**
60
+ * Add a component to this application. Also mounts
61
+ * all the components services.
62
+ *
63
+ * @param component - The component to add.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ *
68
+ * export class ProductComponent {
69
+ * controllers = [ProductController];
70
+ * repositories = [ProductRepo, UserRepo];
71
+ * providers = {
72
+ * [AUTHENTICATION_STRATEGY]: AuthStrategy,
73
+ * [AUTHORIZATION_ROLE]: Role,
74
+ * };
75
+ * };
76
+ *
77
+ * app.component(ProductComponent);
78
+ * ```
79
+ */
80
+ component<C extends Component = Component>(componentCtor: Constructor<C>, nameOrOptions?: string | BindingFromClassOptions | undefined): Binding<C>;
81
+ /**
82
+ * Get an instance of a component and mount all it's
83
+ * services. This function is intended to be used internally
84
+ * by component()
85
+ *
86
+ * @param component - The component to mount services of
87
+ */
88
+ mountComponentServices<C_1 extends Component = Component>(component: Constructor<C_1>, componentBindingKey?: BindingAddress<C_1> | undefined): void;
89
+ readonly options: loopbackContext.ApplicationConfig;
90
+ readonly state: string;
91
+ controller: <T_1>(controllerCtor: loopbackContext.ControllerClass<T_1>, nameOrOptions?: string | BindingFromClassOptions | undefined) => Binding<T_1>;
92
+ server: <T_2 extends loopbackContext.Server>(ctor: Constructor<T_2>, nameOrOptions?: string | BindingFromClassOptions | undefined) => Binding<T_2>;
93
+ servers: <T_3 extends loopbackContext.Server>(ctors: Constructor<T_3>[]) => Binding<any>[];
94
+ getServer: <T_4 extends loopbackContext.Server>(target: string | Constructor<T_4>) => Promise<T_4>;
95
+ init: () => Promise<void>;
96
+ onInit: (fn: () => loopbackContext.ValueOrPromise<void>) => Binding<loopbackContext.LifeCycleObserver>;
97
+ start: () => Promise<void>;
98
+ onStart: (fn: () => loopbackContext.ValueOrPromise<void>) => Binding<loopbackContext.LifeCycleObserver>;
99
+ stop: () => Promise<void>;
100
+ onStop: (fn: () => loopbackContext.ValueOrPromise<void>) => Binding<loopbackContext.LifeCycleObserver>;
101
+ setMetadata: (metadata: loopbackContext.ApplicationMetadata) => void;
102
+ lifeCycleObserver: <T_5 extends loopbackContext.LifeCycleObserver>(ctor: Constructor<T_5>, nameOrOptions?: string | BindingFromClassOptions | undefined) => Binding<T_5>;
103
+ service: <S_1>(cls: loopbackContext.ServiceOrProviderClass<S_1>, nameOrOptions?: string | ServiceOptions | undefined) => Binding<S_1>;
104
+ interceptor: (interceptor: loopbackContext.Interceptor | Constructor<Provider<loopbackContext.Interceptor>>, nameOrOptions?: string | loopbackContext.InterceptorBindingOptions | undefined) => Binding<loopbackContext.Interceptor>;
105
+ readonly name: string;
106
+ readonly subscriptionManager: loopbackContext.ContextSubscriptionManager;
107
+ scope: loopbackContext.BindingScope;
108
+ readonly parent: loopbackContext.Context | undefined;
109
+ emitEvent: <T_6 extends loopbackContext.ContextEvent>(type: string, event: T_6) => void;
110
+ emitError: (err: unknown) => void;
111
+ bind: <ValueType = any>(key: BindingAddress<ValueType>) => Binding<ValueType>;
112
+ add: (binding: Binding<unknown>) => Application;
113
+ configure: <ConfigValueType = any>(key?: BindingAddress<unknown> | undefined) => Binding<ConfigValueType>;
114
+ getConfigAsValueOrPromise: <ConfigValueType_1>(key: BindingAddress<unknown>, propertyPath?: string | undefined, resolutionOptions?: loopbackContext.ResolutionOptions | undefined) => loopbackContext.ValueOrPromise<ConfigValueType_1 | undefined>;
115
+ getConfig: <ConfigValueType_2>(key: BindingAddress<unknown>, propertyPath?: string | undefined, resolutionOptions?: loopbackContext.ResolutionOptions | undefined) => Promise<ConfigValueType_2 | undefined>;
116
+ getConfigSync: <ConfigValueType_3>(key: BindingAddress<unknown>, propertyPath?: string | undefined, resolutionOptions?: loopbackContext.ResolutionOptions | undefined) => ConfigValueType_3 | undefined;
117
+ unbind: (key: BindingAddress<unknown>) => boolean;
118
+ subscribe: (observer: loopbackContext.ContextEventObserver) => loopbackContext.Subscription;
119
+ unsubscribe: (observer: loopbackContext.ContextEventObserver) => boolean;
120
+ close: () => void;
121
+ isSubscribed: (observer: loopbackContext.ContextObserver) => boolean;
122
+ createView: <T_7 = unknown>(filter: loopbackContext.BindingFilter, comparator?: loopbackContext.BindingComparator | undefined) => loopbackContext.ContextView<T_7>;
123
+ contains: (key: BindingAddress<unknown>) => boolean;
124
+ isBound: (key: BindingAddress<unknown>) => boolean;
125
+ getOwnerContext: (keyOrBinding: BindingAddress<unknown> | Readonly<Binding<unknown>>) => loopbackContext.Context | undefined;
126
+ getScopedContext: (scope: loopbackContext.BindingScope.APPLICATION | loopbackContext.BindingScope.SERVER | loopbackContext.BindingScope.REQUEST) => loopbackContext.Context | undefined;
127
+ getResolutionContext: (binding: Readonly<Binding<unknown>>) => loopbackContext.Context | undefined;
128
+ isVisibleTo: (ctx: loopbackContext.Context) => boolean;
129
+ find: <ValueType_1 = any>(pattern?: string | RegExp | loopbackContext.BindingFilter | undefined) => Readonly<Binding<ValueType_1>>[];
130
+ findByTag: <ValueType_2 = any>(tagFilter: RegExp | loopbackContext.BindingTag) => Readonly<Binding<ValueType_2>>[];
131
+ get: {
132
+ <ValueType_3>(keyWithPath: BindingAddress<ValueType_3>, session?: loopbackContext.ResolutionSession | undefined): Promise<ValueType_3>;
133
+ <ValueType_4>(keyWithPath: BindingAddress<ValueType_4>, options: loopbackContext.ResolutionOptions): Promise<ValueType_4 | undefined>;
134
+ };
135
+ getSync: {
136
+ <ValueType_5>(keyWithPath: BindingAddress<ValueType_5>, session?: loopbackContext.ResolutionSession | undefined): ValueType_5;
137
+ <ValueType_6>(keyWithPath: BindingAddress<ValueType_6>, options?: loopbackContext.ResolutionOptions | undefined): ValueType_6 | undefined;
138
+ };
139
+ getBinding: {
140
+ <ValueType_7 = any>(key: BindingAddress<ValueType_7>): Binding<ValueType_7>;
141
+ <ValueType_8>(key: BindingAddress<ValueType_8>, options?: {
142
+ optional?: boolean | undefined;
143
+ } | undefined): Binding<ValueType_8> | undefined;
144
+ };
145
+ findOrCreateBinding: <T_8>(key: BindingAddress<T_8>, policy?: loopbackContext.BindingCreationPolicy | undefined) => Binding<T_8>;
146
+ getValueOrPromise: <ValueType_9>(keyWithPath: BindingAddress<ValueType_9>, optionsOrSession?: loopbackContext.ResolutionOptionsOrSession | undefined) => loopbackContext.ValueOrPromise<ValueType_9 | undefined>;
147
+ toJSON: () => loopbackContext.JSONObject;
148
+ inspect: (options?: loopbackContext.ContextInspectOptions | undefined) => loopbackContext.JSONObject;
149
+ on: {
150
+ (eventName: "bind" | "unbind", listener: loopbackContext.ContextEventListener): Application;
151
+ (event: string | symbol, listener: (...args: any[]) => void): Application;
152
+ };
153
+ once: {
154
+ (eventName: "bind" | "unbind", listener: loopbackContext.ContextEventListener): Application;
155
+ (event: string | symbol, listener: (...args: any[]) => void): Application;
156
+ };
157
+ addListener: (event: string | symbol, listener: (...args: any[]) => void) => Application;
158
+ removeListener: (event: string | symbol, listener: (...args: any[]) => void) => Application;
159
+ off: (event: string | symbol, listener: (...args: any[]) => void) => Application;
160
+ removeAllListeners: (event?: string | symbol | undefined) => Application;
161
+ setMaxListeners: (n: number) => Application;
162
+ getMaxListeners: () => number;
163
+ listeners: (event: string | symbol) => Function[];
164
+ rawListeners: (event: string | symbol) => Function[];
165
+ emit: (event: string | symbol, ...args: any[]) => boolean;
166
+ listenerCount: (type: string | symbol) => number;
167
+ prependListener: (event: string | symbol, listener: (...args: any[]) => void) => Application;
168
+ prependOnceListener: (event: string | symbol, listener: (...args: any[]) => void) => Application;
169
+ eventNames: () => (string | symbol)[];
170
+ };
171
+ } & T;
172
+ /**
173
+ * Interface for an Application mixed in with ServiceMixin
174
+ */
175
+ export interface ApplicationWithServices extends Application {
176
+ serviceProvider<S>(provider: Constructor<Provider<S>>, name?: string): Binding<S>;
177
+ component(component: Constructor<{}>, name?: string): Binding;
178
+ mountComponentServices(component: Constructor<{}>): void;
179
+ }
180
+ /**
181
+ * A dummy class created to generate the tsdoc for the members in service
182
+ * mixin. Please don't use it.
183
+ *
184
+ * The members are implemented in function
185
+ * <a href="#ServiceMixin">ServiceMixin</a>
186
+ */
187
+ export declare class ServiceMixinDoc {
188
+ constructor(...args: any[]);
189
+ /**
190
+ * Add a service to this application.
191
+ *
192
+ * @param provider - The service provider to register.
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * export interface GeocoderService {
197
+ * geocode(address: string): Promise<GeoPoint[]>;
198
+ * }
199
+ *
200
+ * export class GeocoderServiceProvider implements Provider<GeocoderService> {
201
+ * constructor(
202
+ * @inject('datasources.geocoder')
203
+ * protected dataSource: juggler.DataSource = new GeocoderDataSource(),
204
+ * ) {}
205
+ *
206
+ * value(): Promise<GeocoderService> {
207
+ * return getService(this.dataSource);
208
+ * }
209
+ * }
210
+ *
211
+ * app.serviceProvider(GeocoderServiceProvider);
212
+ * ```
213
+ */
214
+ serviceProvider<S>(provider: Constructor<Provider<S>>): Binding<S>;
215
+ /**
216
+ * Add a component to this application. Also mounts
217
+ * all the components services.
218
+ *
219
+ * @param component - The component to add.
220
+ *
221
+ * @example
222
+ * ```ts
223
+ *
224
+ * export class ProductComponent {
225
+ * controllers = [ProductController];
226
+ * repositories = [ProductRepo, UserRepo];
227
+ * providers = {
228
+ * [AUTHENTICATION_STRATEGY]: AuthStrategy,
229
+ * [AUTHORIZATION_ROLE]: Role,
230
+ * };
231
+ * };
232
+ *
233
+ * app.component(ProductComponent);
234
+ * ```
235
+ */
236
+ component(component: Constructor<unknown>): Binding;
237
+ /**
238
+ * Get an instance of a component and mount all it's
239
+ * services. This function is intended to be used internally
240
+ * by component()
241
+ *
242
+ * @param component - The component to mount services of
243
+ */
244
+ mountComponentServices(component: Constructor<unknown>): void;
245
+ }
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
3
+ // Node module: @loopback/service-proxy
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
+ exports.ServiceMixinDoc = exports.ServiceMixin = void 0;
8
+ /**
9
+ * A mixin class for Application that creates a .serviceProvider()
10
+ * function to register a service automatically. Also overrides
11
+ * component function to allow it to register repositories automatically.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * class MyApplication extends ServiceMixin(Application) {}
16
+ * ```
17
+ *
18
+ * Please note: the members in the mixin function are documented in a dummy class
19
+ * called <a href="#ServiceMixinDoc">ServiceMixinDoc</a>
20
+ *
21
+ * @param superClass - Application class
22
+ * @returns A new class that extends the super class with service proxy related
23
+ * methods
24
+ *
25
+ * @typeParam T - Type of the application class as the target for the mixin
26
+ */
27
+ function ServiceMixin(superClass) {
28
+ return class extends superClass {
29
+ /**
30
+ * Add a service to this application.
31
+ *
32
+ * @deprecated Use app.service() instead
33
+ *
34
+ * @param provider - The service provider to register.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * export interface GeocoderService {
39
+ * geocode(address: string): Promise<GeoPoint[]>;
40
+ * }
41
+ *
42
+ * export class GeocoderServiceProvider implements Provider<GeocoderService> {
43
+ * constructor(
44
+ * @inject('services.geocoder')
45
+ * protected dataSource: juggler.DataSource = new GeocoderDataSource(),
46
+ * ) {}
47
+ *
48
+ * value(): Promise<GeocoderService> {
49
+ * return getService(this.dataSource);
50
+ * }
51
+ * }
52
+ *
53
+ * app.serviceProvider(GeocoderServiceProvider);
54
+ * ```
55
+ */
56
+ serviceProvider(provider, nameOrOptions) {
57
+ return this.service(provider, nameOrOptions);
58
+ }
59
+ /**
60
+ * Add a component to this application. Also mounts
61
+ * all the components services.
62
+ *
63
+ * @param component - The component to add.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ *
68
+ * export class ProductComponent {
69
+ * controllers = [ProductController];
70
+ * repositories = [ProductRepo, UserRepo];
71
+ * providers = {
72
+ * [AUTHENTICATION_STRATEGY]: AuthStrategy,
73
+ * [AUTHORIZATION_ROLE]: Role,
74
+ * };
75
+ * };
76
+ *
77
+ * app.component(ProductComponent);
78
+ * ```
79
+ */
80
+ // Unfortunately, TypeScript does not allow overriding methods inherited
81
+ // from mapped types. https://github.com/microsoft/TypeScript/issues/38496
82
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
83
+ // @ts-ignore
84
+ component(componentCtor, nameOrOptions) {
85
+ const binding = super.component(componentCtor, nameOrOptions);
86
+ this.mountComponentServices(componentCtor, binding.key);
87
+ return binding;
88
+ }
89
+ /**
90
+ * Get an instance of a component and mount all it's
91
+ * services. This function is intended to be used internally
92
+ * by component()
93
+ *
94
+ * @param component - The component to mount services of
95
+ */
96
+ mountComponentServices(component, componentBindingKey) {
97
+ const componentKey = componentBindingKey !== null && componentBindingKey !== void 0 ? componentBindingKey : `components.${component.name}`;
98
+ const compInstance = this.getSync(componentKey);
99
+ if (compInstance.serviceProviders) {
100
+ for (const provider of compInstance.serviceProviders) {
101
+ this.serviceProvider(provider);
102
+ }
103
+ }
104
+ }
105
+ };
106
+ }
107
+ exports.ServiceMixin = ServiceMixin;
108
+ /**
109
+ * A dummy class created to generate the tsdoc for the members in service
110
+ * mixin. Please don't use it.
111
+ *
112
+ * The members are implemented in function
113
+ * <a href="#ServiceMixin">ServiceMixin</a>
114
+ */
115
+ class ServiceMixinDoc {
116
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
117
+ constructor(...args) {
118
+ throw new Error('This is a dummy class created for apidoc! Please do not use it!');
119
+ }
120
+ /**
121
+ * Add a service to this application.
122
+ *
123
+ * @param provider - The service provider to register.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * export interface GeocoderService {
128
+ * geocode(address: string): Promise<GeoPoint[]>;
129
+ * }
130
+ *
131
+ * export class GeocoderServiceProvider implements Provider<GeocoderService> {
132
+ * constructor(
133
+ * @inject('datasources.geocoder')
134
+ * protected dataSource: juggler.DataSource = new GeocoderDataSource(),
135
+ * ) {}
136
+ *
137
+ * value(): Promise<GeocoderService> {
138
+ * return getService(this.dataSource);
139
+ * }
140
+ * }
141
+ *
142
+ * app.serviceProvider(GeocoderServiceProvider);
143
+ * ```
144
+ */
145
+ serviceProvider(provider) {
146
+ throw new Error();
147
+ }
148
+ /**
149
+ * Add a component to this application. Also mounts
150
+ * all the components services.
151
+ *
152
+ * @param component - The component to add.
153
+ *
154
+ * @example
155
+ * ```ts
156
+ *
157
+ * export class ProductComponent {
158
+ * controllers = [ProductController];
159
+ * repositories = [ProductRepo, UserRepo];
160
+ * providers = {
161
+ * [AUTHENTICATION_STRATEGY]: AuthStrategy,
162
+ * [AUTHORIZATION_ROLE]: Role,
163
+ * };
164
+ * };
165
+ *
166
+ * app.component(ProductComponent);
167
+ * ```
168
+ */
169
+ component(component) {
170
+ throw new Error();
171
+ }
172
+ /**
173
+ * Get an instance of a component and mount all it's
174
+ * services. This function is intended to be used internally
175
+ * by component()
176
+ *
177
+ * @param component - The component to mount services of
178
+ */
179
+ mountComponentServices(component) { }
180
+ }
181
+ exports.ServiceMixinDoc = ServiceMixinDoc;
182
+ //# sourceMappingURL=service.mixin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.mixin.js","sourceRoot":"","sources":["../../src/mixins/service.mixin.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,uCAAuC;AACvC,+CAA+C;AAC/C,gEAAgE;;;AA+BhE;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,YAAY,CAC1B,UAAa;IAEb,OAAO,KAAM,SAAQ,UAAU;QAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;WA0BG;QACH,eAAe,CACb,QAAkC,EAClC,aAAuC;YAEvC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAC/C,CAAC;QAED;;;;;;;;;;;;;;;;;;;;WAoBG;QACH,wEAAwE;QACxE,0EAA0E;QAC1E,6DAA6D;QAC7D,aAAa;QACb,SAAS,CACP,aAA6B,EAC7B,aAAgD;YAEhD,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;YAC9D,IAAI,CAAC,sBAAsB,CAAC,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YACxD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED;;;;;;WAMG;QACH,sBAAsB,CACpB,SAAyB,EACzB,mBAAuC;YAEvC,MAAM,YAAY,GAChB,mBAAmB,aAAnB,mBAAmB,cAAnB,mBAAmB,GAAI,cAAc,SAAS,CAAC,IAAI,EAAE,CAAC;YACxD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAY,YAAY,CAAC,CAAC;YAE3D,IAAI,YAAY,CAAC,gBAAgB,EAAE;gBACjC,KAAK,MAAM,QAAQ,IAAI,YAAY,CAAC,gBAAgB,EAAE;oBACpD,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;iBAChC;aACF;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AA9FD,oCA8FC;AAcD;;;;;;GAMG;AACH,MAAa,eAAe;IAC1B,8DAA8D;IAC9D,YAAY,GAAG,IAAW;QACxB,MAAM,IAAI,KAAK,CACb,iEAAiE,CAClE,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,eAAe,CAAI,QAAkC;QACnD,MAAM,IAAI,KAAK,EAAE,CAAC;IACpB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACI,SAAS,CAAC,SAA+B;QAC9C,MAAM,IAAI,KAAK,EAAE,CAAC;IACpB,CAAC;IAED;;;;;;OAMG;IACH,sBAAsB,CAAC,SAA+B,IAAG,CAAC;CAC3D;AAtED,0CAsEC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@loopback/service-proxy",
3
+ "description": "A common set of interfaces for interacting with service oriented backends such as REST APIs, SOAP Web Services, and gRPC microservices",
4
+ "version": "3.2.3",
5
+ "license": "MIT",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "author": "IBM Corp.",
9
+ "copyright.owner": "IBM Corp.",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/loopbackio/loopback-next.git",
13
+ "directory": "packages/service-proxy"
14
+ },
15
+ "engines": {
16
+ "node": "^10.16 || 12 || 14 || 16"
17
+ },
18
+ "scripts": {
19
+ "acceptance": "lb-mocha \"dist/__tests__/acceptance/**/*.js\"",
20
+ "build": "lb-tsc",
21
+ "clean": "lb-clean loopback-service-proxy*.tgz dist *.tsbuildinfo package",
22
+ "integration": "lb-mocha \"dist/__tests__/integration/**/*.js\"",
23
+ "pretest": "npm run build",
24
+ "test": "lb-mocha \"dist/__tests__/**/*.js\"",
25
+ "unit": "lb-mocha \"dist/__tests__/unit/**/*.js\"",
26
+ "verify": "npm pack && tar xf loopback-service-proxy*.tgz && tree package && npm run clean"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "files": [
32
+ "README.md",
33
+ "dist",
34
+ "src",
35
+ "!*/__tests__"
36
+ ],
37
+ "peerDependencies": {
38
+ "@loopback/core": "^2.17.0"
39
+ },
40
+ "dependencies": {
41
+ "loopback-datasource-juggler": "^4.26.0",
42
+ "tslib": "^2.3.1"
43
+ },
44
+ "devDependencies": {
45
+ "@loopback/build": "^7.0.1",
46
+ "@loopback/core": "^2.17.0",
47
+ "@loopback/eslint-config": "^11.0.1",
48
+ "@loopback/testlab": "^3.4.3",
49
+ "@types/node": "^10.17.60"
50
+ },
51
+ "gitHead": "1df36bb1ee2e513d9e197bd6010c4cfb296d50b8"
52
+ }
@@ -0,0 +1,72 @@
1
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
2
+ // Node module: @loopback/service-proxy
3
+ // This file is licensed under the MIT License.
4
+ // License text available at https://opensource.org/licenses/MIT
5
+
6
+ import {
7
+ MetadataAccessor,
8
+ inject,
9
+ Context,
10
+ Injection,
11
+ InjectionMetadata,
12
+ } from '@loopback/core';
13
+ import {getService, juggler} from '..';
14
+
15
+ /**
16
+ * Type definition for decorators returned by `@serviceProxy` decorator factory
17
+ */
18
+ export type ServiceProxyDecorator = PropertyDecorator | ParameterDecorator;
19
+
20
+ export const SERVICE_PROXY_KEY = MetadataAccessor.create<
21
+ string,
22
+ ServiceProxyDecorator
23
+ >('service.proxy');
24
+
25
+ /**
26
+ * Metadata for a service proxy
27
+ */
28
+ export class ServiceProxyMetadata implements InjectionMetadata {
29
+ decorator = '@serviceProxy';
30
+ dataSourceName?: string;
31
+ dataSource?: juggler.DataSource;
32
+
33
+ constructor(dataSource: string | juggler.DataSource) {
34
+ if (typeof dataSource === 'string') {
35
+ this.dataSourceName = dataSource;
36
+ } else {
37
+ this.dataSource = dataSource;
38
+ }
39
+ }
40
+ }
41
+
42
+ export function serviceProxy(dataSource: string | juggler.DataSource) {
43
+ return function (target: object, key: string, parameterIndex?: number) {
44
+ if (key || typeof parameterIndex === 'number') {
45
+ const meta = new ServiceProxyMetadata(dataSource);
46
+ inject('', meta, resolve)(target, key, parameterIndex);
47
+ } else {
48
+ throw new Error(
49
+ '@serviceProxy can only be applied to properties or method parameters',
50
+ );
51
+ }
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Resolve the @repository injection
57
+ * @param ctx - Context
58
+ * @param injection - Injection metadata
59
+ */
60
+ async function resolve(ctx: Context, injection: Injection) {
61
+ const meta = injection.metadata as ServiceProxyMetadata;
62
+ if (meta.dataSource) return getService(meta.dataSource);
63
+ if (meta.dataSourceName) {
64
+ const ds = await ctx.get<juggler.DataSource>(
65
+ 'datasources.' + meta.dataSourceName,
66
+ );
67
+ return getService(ds);
68
+ }
69
+ throw new Error(
70
+ '@serviceProxy must provide a name or an instance of DataSource',
71
+ );
72
+ }
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
2
+ // Node module: @loopback/service-proxy
3
+ // This file is licensed under the MIT License.
4
+ // License text available at https://opensource.org/licenses/MIT
5
+
6
+ /**
7
+ * A common set of interfaces for interacting with service oriented backends
8
+ * such as REST APIs, SOAP Web Services, and gRPC microservices.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+
13
+ export * from './decorators/service.decorator';
14
+ export * from './legacy-juggler-bridge';
15
+ export * from './mixins';
@@ -0,0 +1,34 @@
1
+ // Copyright IBM Corp. 2018,2019. All Rights Reserved.
2
+ // Node module: @loopback/service-proxy
3
+ // This file is licensed under the MIT License.
4
+ // License text available at https://opensource.org/licenses/MIT
5
+
6
+ import legacy from 'loopback-datasource-juggler';
7
+
8
+ export namespace juggler {
9
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
10
+ export import DataSource = legacy.DataSource;
11
+ }
12
+
13
+ /**
14
+ * A generic service interface with any number of methods that return a promise
15
+ */
16
+ export interface GenericService {
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ [methodName: string]: (...args: any[]) => Promise<any>;
19
+ }
20
+
21
+ /**
22
+ * Get a service proxy from a LoopBack 3.x data source backed by
23
+ * service-oriented connectors such as `rest`, `soap`, and `grpc`.
24
+ *
25
+ * @param ds - A legacy data source
26
+ * @typeParam T - The generic type of service interface
27
+ */
28
+ export async function getService<T = GenericService>(
29
+ ds: legacy.DataSource,
30
+ ): Promise<T> {
31
+ await ds.connect();
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ return ds.DataAccessObject as any;
34
+ }
@@ -0,0 +1,6 @@
1
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
2
+ // Node module: @loopback/service-proxy
3
+ // This file is licensed under the MIT License.
4
+ // License text available at https://opensource.org/licenses/MIT
5
+
6
+ export * from './service.mixin';
@@ -0,0 +1,239 @@
1
+ // Copyright IBM Corp. 2018,2020. All Rights Reserved.
2
+ // Node module: @loopback/service-proxy
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
+ BindingAddress,
9
+ BindingFromClassOptions,
10
+ Provider,
11
+ Constructor,
12
+ } from '@loopback/core';
13
+ import {
14
+ Application,
15
+ MixinTarget,
16
+ ServiceOptions,
17
+ Component,
18
+ } from '@loopback/core';
19
+
20
+ // FIXME(rfeng): Workaround for https://github.com/microsoft/rushstack/pull/1867
21
+ /* eslint-disable @typescript-eslint/no-unused-vars */
22
+ import * as loopbackContext from '@loopback/core';
23
+ import * as loopbackCore from '@loopback/core';
24
+ /* eslint-enable @typescript-eslint/no-unused-vars */
25
+
26
+ /**
27
+ * Interface for classes with `new` operator.
28
+ */
29
+ export interface Class<T> {
30
+ // new MyClass(...args) ==> T
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ new (...args: any[]): T;
33
+ }
34
+
35
+ /**
36
+ * A mixin class for Application that creates a .serviceProvider()
37
+ * function to register a service automatically. Also overrides
38
+ * component function to allow it to register repositories automatically.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * class MyApplication extends ServiceMixin(Application) {}
43
+ * ```
44
+ *
45
+ * Please note: the members in the mixin function are documented in a dummy class
46
+ * called <a href="#ServiceMixinDoc">ServiceMixinDoc</a>
47
+ *
48
+ * @param superClass - Application class
49
+ * @returns A new class that extends the super class with service proxy related
50
+ * methods
51
+ *
52
+ * @typeParam T - Type of the application class as the target for the mixin
53
+ */
54
+ export function ServiceMixin<T extends MixinTarget<Application>>(
55
+ superClass: T,
56
+ ) {
57
+ return class extends superClass {
58
+ /**
59
+ * Add a service to this application.
60
+ *
61
+ * @deprecated Use app.service() instead
62
+ *
63
+ * @param provider - The service provider to register.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * export interface GeocoderService {
68
+ * geocode(address: string): Promise<GeoPoint[]>;
69
+ * }
70
+ *
71
+ * export class GeocoderServiceProvider implements Provider<GeocoderService> {
72
+ * constructor(
73
+ * @inject('services.geocoder')
74
+ * protected dataSource: juggler.DataSource = new GeocoderDataSource(),
75
+ * ) {}
76
+ *
77
+ * value(): Promise<GeocoderService> {
78
+ * return getService(this.dataSource);
79
+ * }
80
+ * }
81
+ *
82
+ * app.serviceProvider(GeocoderServiceProvider);
83
+ * ```
84
+ */
85
+ serviceProvider<S>(
86
+ provider: Constructor<Provider<S>>,
87
+ nameOrOptions?: string | ServiceOptions,
88
+ ): Binding<S> {
89
+ return this.service(provider, nameOrOptions);
90
+ }
91
+
92
+ /**
93
+ * Add a component to this application. Also mounts
94
+ * all the components services.
95
+ *
96
+ * @param component - The component to add.
97
+ *
98
+ * @example
99
+ * ```ts
100
+ *
101
+ * export class ProductComponent {
102
+ * controllers = [ProductController];
103
+ * repositories = [ProductRepo, UserRepo];
104
+ * providers = {
105
+ * [AUTHENTICATION_STRATEGY]: AuthStrategy,
106
+ * [AUTHORIZATION_ROLE]: Role,
107
+ * };
108
+ * };
109
+ *
110
+ * app.component(ProductComponent);
111
+ * ```
112
+ */
113
+ // Unfortunately, TypeScript does not allow overriding methods inherited
114
+ // from mapped types. https://github.com/microsoft/TypeScript/issues/38496
115
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
116
+ // @ts-ignore
117
+ component<C extends Component = Component>(
118
+ componentCtor: Constructor<C>,
119
+ nameOrOptions?: string | BindingFromClassOptions,
120
+ ) {
121
+ const binding = super.component(componentCtor, nameOrOptions);
122
+ this.mountComponentServices(componentCtor, binding.key);
123
+ return binding;
124
+ }
125
+
126
+ /**
127
+ * Get an instance of a component and mount all it's
128
+ * services. This function is intended to be used internally
129
+ * by component()
130
+ *
131
+ * @param component - The component to mount services of
132
+ */
133
+ mountComponentServices<C extends Component = Component>(
134
+ component: Constructor<C>,
135
+ componentBindingKey?: BindingAddress<C>,
136
+ ) {
137
+ const componentKey =
138
+ componentBindingKey ?? `components.${component.name}`;
139
+ const compInstance = this.getSync<Component>(componentKey);
140
+
141
+ if (compInstance.serviceProviders) {
142
+ for (const provider of compInstance.serviceProviders) {
143
+ this.serviceProvider(provider);
144
+ }
145
+ }
146
+ }
147
+ };
148
+ }
149
+
150
+ /**
151
+ * Interface for an Application mixed in with ServiceMixin
152
+ */
153
+ export interface ApplicationWithServices extends Application {
154
+ serviceProvider<S>(
155
+ provider: Constructor<Provider<S>>,
156
+ name?: string,
157
+ ): Binding<S>;
158
+ component(component: Constructor<{}>, name?: string): Binding;
159
+ mountComponentServices(component: Constructor<{}>): void;
160
+ }
161
+
162
+ /**
163
+ * A dummy class created to generate the tsdoc for the members in service
164
+ * mixin. Please don't use it.
165
+ *
166
+ * The members are implemented in function
167
+ * <a href="#ServiceMixin">ServiceMixin</a>
168
+ */
169
+ export class ServiceMixinDoc {
170
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
171
+ constructor(...args: any[]) {
172
+ throw new Error(
173
+ 'This is a dummy class created for apidoc! Please do not use it!',
174
+ );
175
+ }
176
+
177
+ /**
178
+ * Add a service to this application.
179
+ *
180
+ * @param provider - The service provider to register.
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * export interface GeocoderService {
185
+ * geocode(address: string): Promise<GeoPoint[]>;
186
+ * }
187
+ *
188
+ * export class GeocoderServiceProvider implements Provider<GeocoderService> {
189
+ * constructor(
190
+ * @inject('datasources.geocoder')
191
+ * protected dataSource: juggler.DataSource = new GeocoderDataSource(),
192
+ * ) {}
193
+ *
194
+ * value(): Promise<GeocoderService> {
195
+ * return getService(this.dataSource);
196
+ * }
197
+ * }
198
+ *
199
+ * app.serviceProvider(GeocoderServiceProvider);
200
+ * ```
201
+ */
202
+ serviceProvider<S>(provider: Constructor<Provider<S>>): Binding<S> {
203
+ throw new Error();
204
+ }
205
+
206
+ /**
207
+ * Add a component to this application. Also mounts
208
+ * all the components services.
209
+ *
210
+ * @param component - The component to add.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ *
215
+ * export class ProductComponent {
216
+ * controllers = [ProductController];
217
+ * repositories = [ProductRepo, UserRepo];
218
+ * providers = {
219
+ * [AUTHENTICATION_STRATEGY]: AuthStrategy,
220
+ * [AUTHORIZATION_ROLE]: Role,
221
+ * };
222
+ * };
223
+ *
224
+ * app.component(ProductComponent);
225
+ * ```
226
+ */
227
+ public component(component: Constructor<unknown>): Binding {
228
+ throw new Error();
229
+ }
230
+
231
+ /**
232
+ * Get an instance of a component and mount all it's
233
+ * services. This function is intended to be used internally
234
+ * by component()
235
+ *
236
+ * @param component - The component to mount services of
237
+ */
238
+ mountComponentServices(component: Constructor<unknown>) {}
239
+ }