@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 +25 -0
- package/README.md +32 -0
- package/dist/decorators/service.decorator.d.ts +17 -0
- package/dist/decorators/service.decorator.js +53 -0
- package/dist/decorators/service.decorator.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/legacy-juggler-bridge.d.ts +18 -0
- package/dist/legacy-juggler-bridge.js +28 -0
- package/dist/legacy-juggler-bridge.js.map +1 -0
- package/dist/mixins/index.d.ts +1 -0
- package/dist/mixins/index.js +9 -0
- package/dist/mixins/index.js.map +1 -0
- package/dist/mixins/service.mixin.d.ts +245 -0
- package/dist/mixins/service.mixin.js +182 -0
- package/dist/mixins/service.mixin.js.map +1 -0
- package/package.json +52 -0
- package/src/decorators/service.decorator.ts +72 -0
- package/src/index.ts +15 -0
- package/src/legacy-juggler-bridge.ts +34 -0
- package/src/mixins/index.ts +6 -0
- package/src/mixins/service.mixin.ts +239 -0
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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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,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
|
+
}
|