@loopback/example-greeting-app 3.0.1

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.
Files changed (62) hide show
  1. package/.prettierignore +2 -0
  2. package/.prettierrc +7 -0
  3. package/.vscode/settings.json +19 -0
  4. package/.vscode/tasks.json +29 -0
  5. package/CHANGELOG.md +552 -0
  6. package/LICENSE +25 -0
  7. package/README.md +61 -0
  8. package/dist/__tests__/integration/greeting-service.integration.d.ts +1 -0
  9. package/dist/__tests__/integration/greeting-service.integration.js +68 -0
  10. package/dist/__tests__/integration/greeting-service.integration.js.map +1 -0
  11. package/dist/application.d.ts +98 -0
  12. package/dist/application.js +29 -0
  13. package/dist/application.js.map +1 -0
  14. package/dist/caching-service.d.ts +64 -0
  15. package/dist/caching-service.js +133 -0
  16. package/dist/caching-service.js.map +1 -0
  17. package/dist/controllers/greeting.controller.d.ts +10 -0
  18. package/dist/controllers/greeting.controller.js +59 -0
  19. package/dist/controllers/greeting.controller.js.map +1 -0
  20. package/dist/controllers/index.d.ts +1 -0
  21. package/dist/controllers/index.js +9 -0
  22. package/dist/controllers/index.js.map +1 -0
  23. package/dist/index.d.ts +4 -0
  24. package/dist/index.js +37 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/interceptors/caching.interceptor.d.ts +7 -0
  27. package/dist/interceptors/caching.interceptor.js +49 -0
  28. package/dist/interceptors/caching.interceptor.js.map +1 -0
  29. package/dist/interceptors/index.d.ts +1 -0
  30. package/dist/interceptors/index.js +9 -0
  31. package/dist/interceptors/index.js.map +1 -0
  32. package/dist/keys.d.ts +6 -0
  33. package/dist/keys.js +13 -0
  34. package/dist/keys.js.map +1 -0
  35. package/dist/observers/cache.observer.d.ts +19 -0
  36. package/dist/observers/cache.observer.js +39 -0
  37. package/dist/observers/cache.observer.js.map +1 -0
  38. package/dist/observers/index.d.ts +1 -0
  39. package/dist/observers/index.js +9 -0
  40. package/dist/observers/index.js.map +1 -0
  41. package/dist/openapi-spec.d.ts +1 -0
  42. package/dist/openapi-spec.js +28 -0
  43. package/dist/openapi-spec.js.map +1 -0
  44. package/dist/types.d.ts +8 -0
  45. package/dist/types.js +7 -0
  46. package/dist/types.js.map +1 -0
  47. package/greeting-app.png +0 -0
  48. package/package.json +69 -0
  49. package/src/__tests__/integration/greeting-service.integration.ts +79 -0
  50. package/src/application.ts +27 -0
  51. package/src/caching-service.ts +146 -0
  52. package/src/controllers/greeting.controller.ts +50 -0
  53. package/src/controllers/index.ts +6 -0
  54. package/src/index.ts +33 -0
  55. package/src/interceptors/caching.interceptor.ts +55 -0
  56. package/src/interceptors/index.ts +6 -0
  57. package/src/keys.ts +14 -0
  58. package/src/observers/cache.observer.ts +34 -0
  59. package/src/observers/index.ts +6 -0
  60. package/src/openapi-spec.ts +28 -0
  61. package/src/types.ts +13 -0
  62. package/tsconfig.json +30 -0
package/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) IBM Corp. 2019.
2
+ Node module: @loopback/example-greeting-app
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,61 @@
1
+ # @loopback/example-greeting-app
2
+
3
+ This application is built on top of
4
+ [`@loopback/example-greeter-extension`](https://github.com/loopbackio/loopback-next/tree/master/examples/greeter-extension).
5
+
6
+ ## Compose the application
7
+
8
+ 1. Add REST API
9
+
10
+ - GreetingController - providing endpoints over `GreetingService`
11
+
12
+ 2. Add caching
13
+
14
+ - CachingService - implementing cache operations, such as set,get, delete,
15
+ and sweep
16
+ - CachingInterceptor - intercepting http requests to apply caching
17
+ - CacheObserver - watching and sweeping cache in the background
18
+
19
+ ![greeting-app](./greeting-app.png)
20
+
21
+ ## Contributions
22
+
23
+ - [Guidelines](https://github.com/loopbackio/loopback-next/blob/master/docs/CONTRIBUTING.md)
24
+ - [Join the team](https://github.com/loopbackio/loopback-next/issues/110)
25
+
26
+ ## Try out
27
+
28
+ Run `npm start`:
29
+
30
+ The service is running at http://127.0.0.1:3000/greet/world.
31
+
32
+ Open your browser to try the REST APIs. You can replace `world` with other
33
+ names.
34
+
35
+ The following `curl` command sets `Accept-Language` header to `zh` to receive
36
+ the greeting in Chinese.
37
+
38
+ ```sh
39
+ curl -H 'Accept-Language: zh' http://127.0.0.1:3000/greet/Ray
40
+ ```
41
+
42
+ ```json
43
+ {
44
+ "timestamp": "2019-05-29T22:48:03.040Z",
45
+ "language": "zh",
46
+ "greeting": "Ray,你好!"
47
+ }
48
+ ```
49
+
50
+ ## Tests
51
+
52
+ Run `npm test` from the root folder.
53
+
54
+ ## Contributors
55
+
56
+ See
57
+ [all contributors](https://github.com/loopbackio/loopback-next/graphs/contributors).
58
+
59
+ ## License
60
+
61
+ MIT
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 2019,2020. All Rights Reserved.
3
+ // Node module: @loopback/example-greeting-app
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 testlab_1 = require("@loopback/testlab");
8
+ const util_1 = require("util");
9
+ const __1 = require("../..");
10
+ const keys_1 = require("../../keys");
11
+ describe('GreetingApplication', () => {
12
+ let app;
13
+ let client;
14
+ before(givenRunningApplicationWithCustomConfiguration);
15
+ after(() => app.stop());
16
+ before(() => {
17
+ client = testlab_1.createRestAppClient(app);
18
+ });
19
+ it('gets a greeting in English', async function () {
20
+ const response = await client
21
+ .get('/greet/Raymond')
22
+ .set('Accept-Language', 'en')
23
+ .expect(200);
24
+ testlab_1.expect(response.body).to.containEql({
25
+ language: 'en',
26
+ greeting: 'Hello, Raymond!',
27
+ });
28
+ });
29
+ it('gets a greeting in Chinese', async function () {
30
+ const response = await client
31
+ .get('/greet/Raymond')
32
+ .set('Accept-Language', 'zh')
33
+ .expect(200);
34
+ testlab_1.expect(response.body).to.containEql({
35
+ language: 'zh',
36
+ greeting: 'Raymond,你好!',
37
+ });
38
+ });
39
+ it('gets a greeting from cache', async function () {
40
+ app.configure(keys_1.CACHING_SERVICE).to({ ttl: 100 });
41
+ let response = await client
42
+ .get('/greet/Raymond')
43
+ .set('Accept-Language', 'en')
44
+ .expect(200);
45
+ const msg1 = response.body;
46
+ // Now the result should be cached
47
+ response = await client
48
+ .get('/greet/Raymond')
49
+ .set('Accept-Language', 'en')
50
+ .expect(200);
51
+ testlab_1.expect(response.body).to.eql(msg1);
52
+ // Cache should be expired now
53
+ await util_1.promisify(setTimeout)(200);
54
+ response = await client
55
+ .get('/greet/Raymond')
56
+ .set('Accept-Language', 'en')
57
+ .expect(200);
58
+ testlab_1.expect(response.body.timestamp).to.not.eql(msg1.timestamp);
59
+ });
60
+ async function givenRunningApplicationWithCustomConfiguration() {
61
+ app = new __1.GreetingApplication({
62
+ rest: testlab_1.givenHttpServerConfig(),
63
+ });
64
+ // Start Application
65
+ await app.main();
66
+ }
67
+ });
68
+ //# sourceMappingURL=greeting-service.integration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"greeting-service.integration.js","sourceRoot":"","sources":["../../../src/__tests__/integration/greeting-service.integration.ts"],"names":[],"mappings":";AAAA,sDAAsD;AACtD,8CAA8C;AAC9C,+CAA+C;AAC/C,gEAAgE;;AAEhE,+CAK2B;AAC3B,+BAA+B;AAC/B,6BAA0C;AAC1C,qCAA2C;AAE3C,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,IAAI,GAAwB,CAAC;IAC7B,IAAI,MAAc,CAAC;IAEnB,MAAM,CAAC,8CAA8C,CAAC,CAAC;IACvD,KAAK,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAExB,MAAM,CAAC,GAAG,EAAE;QACV,MAAM,GAAG,6BAAmB,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK;QACpC,MAAM,QAAQ,GAAG,MAAM,MAAM;aAC1B,GAAG,CAAC,gBAAgB,CAAC;aACrB,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC;aAC5B,MAAM,CAAC,GAAG,CAAC,CAAC;QACf,gBAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC;YAClC,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,iBAAiB;SAC5B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK;QACpC,MAAM,QAAQ,GAAG,MAAM,MAAM;aAC1B,GAAG,CAAC,gBAAgB,CAAC;aACrB,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC;aAC5B,MAAM,CAAC,GAAG,CAAC,CAAC;QACf,gBAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC;YAClC,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,aAAa;SACxB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK;QACpC,GAAG,CAAC,SAAS,CAAC,sBAAe,CAAC,CAAC,EAAE,CAAC,EAAC,GAAG,EAAE,GAAG,EAAC,CAAC,CAAC;QAC9C,IAAI,QAAQ,GAAG,MAAM,MAAM;aACxB,GAAG,CAAC,gBAAgB,CAAC;aACrB,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC;aAC5B,MAAM,CAAC,GAAG,CAAC,CAAC;QACf,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,kCAAkC;QAClC,QAAQ,GAAG,MAAM,MAAM;aACpB,GAAG,CAAC,gBAAgB,CAAC;aACrB,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC;aAC5B,MAAM,CAAC,GAAG,CAAC,CAAC;QACf,gBAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,8BAA8B;QAC9B,MAAM,gBAAS,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC;QACjC,QAAQ,GAAG,MAAM,MAAM;aACpB,GAAG,CAAC,gBAAgB,CAAC;aACrB,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC;aAC5B,MAAM,CAAC,GAAG,CAAC,CAAC;QACf,gBAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,KAAK,UAAU,8CAA8C;QAC3D,GAAG,GAAG,IAAI,uBAAmB,CAAC;YAC5B,IAAI,EAAE,+BAAqB,EAAE;SAC9B,CAAC,CAAC;QAEH,oBAAoB;QACpB,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,98 @@
1
+ import { ApplicationConfig } from '@loopback/core';
2
+ import { RestApplication } from '@loopback/rest';
3
+ declare const GreetingApplication_base: (new (...args: any[]) => {
4
+ projectRoot: string;
5
+ bootOptions?: import("@loopback/boot").BootOptions | undefined;
6
+ booted: boolean;
7
+ start(): Promise<void>;
8
+ boot(): Promise<void>;
9
+ booters(...booterCls: import("@loopback/core").Constructor<import("@loopback/boot").Booter>[]): import("@loopback/boot").Binding<any>[];
10
+ applicationBooter(subApp: import("@loopback/core").Application & import("@loopback/boot").Bootable, filter?: import("@loopback/core").BindingFilter | undefined): import("@loopback/boot").Binding<import("@loopback/boot").Booter>;
11
+ component<C extends import("@loopback/core").Component = import("@loopback/core").Component>(componentCtor: import("@loopback/core").Constructor<C>, nameOrOptions?: string | import("@loopback/core").BindingFromClassOptions | undefined): import("@loopback/boot").Binding<C>;
12
+ mountComponentBooters(componentInstanceOrClass: import("@loopback/core").Constructor<unknown> | import("@loopback/boot").InstanceWithBooters): void;
13
+ readonly options: ApplicationConfig;
14
+ readonly state: string;
15
+ controller: <T_1>(controllerCtor: import("@loopback/core").ControllerClass<T_1>, nameOrOptions?: string | import("@loopback/core").BindingFromClassOptions | undefined) => import("@loopback/boot").Binding<T_1>;
16
+ server: <T_2 extends import("@loopback/core").Server>(ctor: import("@loopback/core").Constructor<T_2>, nameOrOptions?: string | import("@loopback/core").BindingFromClassOptions | undefined) => import("@loopback/boot").Binding<T_2>;
17
+ servers: <T_3 extends import("@loopback/core").Server>(ctors: import("@loopback/core").Constructor<T_3>[]) => import("@loopback/boot").Binding<any>[];
18
+ getServer: <T_4 extends import("@loopback/core").Server>(target: string | import("@loopback/core").Constructor<T_4>) => Promise<T_4>;
19
+ init: () => Promise<void>;
20
+ onInit: (fn: () => import("@loopback/core").ValueOrPromise<void>) => import("@loopback/boot").Binding<import("@loopback/core").LifeCycleObserver>;
21
+ onStart: (fn: () => import("@loopback/core").ValueOrPromise<void>) => import("@loopback/boot").Binding<import("@loopback/core").LifeCycleObserver>;
22
+ stop: () => Promise<void>;
23
+ onStop: (fn: () => import("@loopback/core").ValueOrPromise<void>) => import("@loopback/boot").Binding<import("@loopback/core").LifeCycleObserver>;
24
+ setMetadata: (metadata: import("@loopback/core").ApplicationMetadata) => void;
25
+ lifeCycleObserver: <T_5 extends import("@loopback/core").LifeCycleObserver>(ctor: import("@loopback/core").Constructor<T_5>, nameOrOptions?: string | import("@loopback/core").BindingFromClassOptions | undefined) => import("@loopback/boot").Binding<T_5>;
26
+ service: <S>(cls: import("@loopback/core").ServiceOrProviderClass<S>, nameOrOptions?: string | import("@loopback/core").ServiceOptions | undefined) => import("@loopback/boot").Binding<S>;
27
+ interceptor: (interceptor: import("@loopback/core").Interceptor | import("@loopback/core").Constructor<import("@loopback/core").Provider<import("@loopback/core").Interceptor>>, nameOrOptions?: string | import("@loopback/core").InterceptorBindingOptions | undefined) => import("@loopback/boot").Binding<import("@loopback/core").Interceptor>;
28
+ readonly name: string;
29
+ readonly subscriptionManager: import("@loopback/core").ContextSubscriptionManager;
30
+ scope: import("@loopback/core").BindingScope;
31
+ readonly parent: import("@loopback/core").Context | undefined;
32
+ emitEvent: <T_6 extends import("@loopback/core").ContextEvent>(type: string, event: T_6) => void;
33
+ emitError: (err: unknown) => void;
34
+ bind: <ValueType = any>(key: import("@loopback/core").BindingAddress<ValueType>) => import("@loopback/boot").Binding<ValueType>;
35
+ add: (binding: import("@loopback/boot").Binding<unknown>) => import("@loopback/core").Application;
36
+ configure: <ConfigValueType = any>(key?: import("@loopback/core").BindingAddress<unknown> | undefined) => import("@loopback/boot").Binding<ConfigValueType>;
37
+ getConfigAsValueOrPromise: <ConfigValueType_1>(key: import("@loopback/core").BindingAddress<unknown>, propertyPath?: string | undefined, resolutionOptions?: import("@loopback/core").ResolutionOptions | undefined) => import("@loopback/core").ValueOrPromise<ConfigValueType_1 | undefined>;
38
+ getConfig: <ConfigValueType_2>(key: import("@loopback/core").BindingAddress<unknown>, propertyPath?: string | undefined, resolutionOptions?: import("@loopback/core").ResolutionOptions | undefined) => Promise<ConfigValueType_2 | undefined>;
39
+ getConfigSync: <ConfigValueType_3>(key: import("@loopback/core").BindingAddress<unknown>, propertyPath?: string | undefined, resolutionOptions?: import("@loopback/core").ResolutionOptions | undefined) => ConfigValueType_3 | undefined;
40
+ unbind: (key: import("@loopback/core").BindingAddress<unknown>) => boolean;
41
+ subscribe: (observer: import("@loopback/core").ContextEventObserver) => import("@loopback/core").Subscription;
42
+ unsubscribe: (observer: import("@loopback/core").ContextEventObserver) => boolean;
43
+ close: () => void;
44
+ isSubscribed: (observer: import("@loopback/core").ContextObserver) => boolean;
45
+ createView: <T_7 = unknown>(filter: import("@loopback/core").BindingFilter, comparator?: import("@loopback/core").BindingComparator | undefined) => import("@loopback/core").ContextView<T_7>;
46
+ contains: (key: import("@loopback/core").BindingAddress<unknown>) => boolean;
47
+ isBound: (key: import("@loopback/core").BindingAddress<unknown>) => boolean;
48
+ getOwnerContext: (keyOrBinding: import("@loopback/core").BindingAddress<unknown> | Readonly<import("@loopback/boot").Binding<unknown>>) => import("@loopback/core").Context | undefined;
49
+ getScopedContext: (scope: import("@loopback/core").BindingScope.APPLICATION | import("@loopback/core").BindingScope.SERVER | import("@loopback/core").BindingScope.REQUEST) => import("@loopback/core").Context | undefined;
50
+ getResolutionContext: (binding: Readonly<import("@loopback/boot").Binding<unknown>>) => import("@loopback/core").Context | undefined;
51
+ isVisibleTo: (ctx: import("@loopback/core").Context) => boolean;
52
+ find: <ValueType_1 = any>(pattern?: string | RegExp | import("@loopback/core").BindingFilter | undefined) => Readonly<import("@loopback/boot").Binding<ValueType_1>>[];
53
+ findByTag: <ValueType_2 = any>(tagFilter: RegExp | import("@loopback/core").BindingTag) => Readonly<import("@loopback/boot").Binding<ValueType_2>>[];
54
+ get: {
55
+ <ValueType_3>(keyWithPath: import("@loopback/core").BindingAddress<ValueType_3>, session?: import("@loopback/core").ResolutionSession | undefined): Promise<ValueType_3>;
56
+ <ValueType_4>(keyWithPath: import("@loopback/core").BindingAddress<ValueType_4>, options: import("@loopback/core").ResolutionOptions): Promise<ValueType_4 | undefined>;
57
+ };
58
+ getSync: {
59
+ <ValueType_5>(keyWithPath: import("@loopback/core").BindingAddress<ValueType_5>, session?: import("@loopback/core").ResolutionSession | undefined): ValueType_5;
60
+ <ValueType_6>(keyWithPath: import("@loopback/core").BindingAddress<ValueType_6>, options?: import("@loopback/core").ResolutionOptions | undefined): ValueType_6 | undefined;
61
+ };
62
+ getBinding: {
63
+ <ValueType_7 = any>(key: import("@loopback/core").BindingAddress<ValueType_7>): import("@loopback/boot").Binding<ValueType_7>;
64
+ <ValueType_8>(key: import("@loopback/core").BindingAddress<ValueType_8>, options?: {
65
+ optional?: boolean | undefined;
66
+ } | undefined): import("@loopback/boot").Binding<ValueType_8> | undefined;
67
+ };
68
+ findOrCreateBinding: <T_8>(key: import("@loopback/core").BindingAddress<T_8>, policy?: import("@loopback/core").BindingCreationPolicy | undefined) => import("@loopback/boot").Binding<T_8>;
69
+ getValueOrPromise: <ValueType_9>(keyWithPath: import("@loopback/core").BindingAddress<ValueType_9>, optionsOrSession?: import("@loopback/core").ResolutionOptionsOrSession | undefined) => import("@loopback/core").ValueOrPromise<ValueType_9 | undefined>;
70
+ toJSON: () => import("@loopback/core").JSONObject;
71
+ inspect: (options?: import("@loopback/core").ContextInspectOptions | undefined) => import("@loopback/core").JSONObject;
72
+ on: {
73
+ (eventName: "bind" | "unbind", listener: import("@loopback/core").ContextEventListener): import("@loopback/core").Application;
74
+ (event: string | symbol, listener: (...args: any[]) => void): import("@loopback/core").Application;
75
+ };
76
+ once: {
77
+ (eventName: "bind" | "unbind", listener: import("@loopback/core").ContextEventListener): import("@loopback/core").Application;
78
+ (event: string | symbol, listener: (...args: any[]) => void): import("@loopback/core").Application;
79
+ };
80
+ addListener: (event: string | symbol, listener: (...args: any[]) => void) => import("@loopback/core").Application;
81
+ removeListener: (event: string | symbol, listener: (...args: any[]) => void) => import("@loopback/core").Application;
82
+ off: (event: string | symbol, listener: (...args: any[]) => void) => import("@loopback/core").Application;
83
+ removeAllListeners: (event?: string | symbol | undefined) => import("@loopback/core").Application;
84
+ setMaxListeners: (n: number) => import("@loopback/core").Application;
85
+ getMaxListeners: () => number;
86
+ listeners: (event: string | symbol) => Function[];
87
+ rawListeners: (event: string | symbol) => Function[];
88
+ emit: (event: string | symbol, ...args: any[]) => boolean;
89
+ listenerCount: (type: string | symbol) => number;
90
+ prependListener: (event: string | symbol, listener: (...args: any[]) => void) => import("@loopback/core").Application;
91
+ prependOnceListener: (event: string | symbol, listener: (...args: any[]) => void) => import("@loopback/core").Application;
92
+ eventNames: () => (string | symbol)[];
93
+ }) & typeof RestApplication;
94
+ export declare class GreetingApplication extends GreetingApplication_base {
95
+ constructor(config?: ApplicationConfig);
96
+ main(): Promise<void>;
97
+ }
98
+ export {};
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 2019. All Rights Reserved.
3
+ // Node module: @loopback/example-greeting-app
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.GreetingApplication = void 0;
8
+ const boot_1 = require("@loopback/boot");
9
+ const core_1 = require("@loopback/core");
10
+ const example_greeter_extension_1 = require("@loopback/example-greeter-extension");
11
+ const rest_1 = require("@loopback/rest");
12
+ const caching_service_1 = require("./caching-service");
13
+ const interceptors_1 = require("./interceptors");
14
+ const keys_1 = require("./keys");
15
+ class GreetingApplication extends boot_1.BootMixin(rest_1.RestApplication) {
16
+ constructor(config = {}) {
17
+ super(config);
18
+ this.projectRoot = __dirname;
19
+ this.add(core_1.createBindingFromClass(caching_service_1.CachingService, { key: keys_1.CACHING_SERVICE }));
20
+ this.add(core_1.createBindingFromClass(interceptors_1.CachingInterceptor));
21
+ this.component(example_greeter_extension_1.GreetingComponent);
22
+ }
23
+ async main() {
24
+ await this.boot();
25
+ await this.start();
26
+ }
27
+ }
28
+ exports.GreetingApplication = GreetingApplication;
29
+ //# sourceMappingURL=application.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"application.js","sourceRoot":"","sources":["../src/application.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,8CAA8C;AAC9C,+CAA+C;AAC/C,gEAAgE;;;AAEhE,yCAAyC;AACzC,yCAAyE;AACzE,mFAAsE;AACtE,yCAA+C;AAC/C,uDAAiD;AACjD,iDAAkD;AAClD,iCAAuC;AAEvC,MAAa,mBAAoB,SAAQ,gBAAS,CAAC,sBAAe,CAAC;IACjE,YAAY,SAA4B,EAAE;QACxC,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,6BAAsB,CAAC,gCAAc,EAAE,EAAC,GAAG,EAAE,sBAAe,EAAC,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,GAAG,CAAC,6BAAsB,CAAC,iCAAkB,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,SAAS,CAAC,6CAAiB,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAbD,kDAaC"}
@@ -0,0 +1,64 @@
1
+ import { ContextView } from '@loopback/core';
2
+ import { Message } from './types';
3
+ /**
4
+ * Configuration for CachingService
5
+ */
6
+ export interface CachingServiceOptions {
7
+ ttl: number;
8
+ }
9
+ /**
10
+ * Message caching service
11
+ */
12
+ export declare class CachingService {
13
+ private optionsView;
14
+ private timer;
15
+ private store;
16
+ constructor(optionsView: ContextView<CachingServiceOptions>);
17
+ /**
18
+ * Store a message in the cache
19
+ * @param key - Key for caching
20
+ * @param message - Message
21
+ */
22
+ set(key: string, message: Message): Promise<void>;
23
+ /**
24
+ * Load a message from the cache by key
25
+ * @param key - Key for caching
26
+ */
27
+ get(key: string): Promise<Message | undefined>;
28
+ /**
29
+ * Delete a message from the cache by key
30
+ * @param key - Key for caching
31
+ */
32
+ delete(key: string): Promise<boolean>;
33
+ /**
34
+ * Clear the cache
35
+ */
36
+ clear(): Promise<void>;
37
+ /**
38
+ * Check if the cached item is expired by key
39
+ * @param key - Key for caching
40
+ * @param now - The current date
41
+ */
42
+ isExpired(key: string, now?: Date): Promise<boolean>;
43
+ /**
44
+ * Get the TTL setting
45
+ */
46
+ getTTL(): Promise<number>;
47
+ /**
48
+ * Remove expired items from the cache
49
+ */
50
+ sweep(): Promise<void>;
51
+ /**
52
+ * This method will be invoked when the application starts
53
+ */
54
+ start(): Promise<void>;
55
+ /**
56
+ * This method will be invoked when the application stops
57
+ */
58
+ stop(): Promise<void>;
59
+ /**
60
+ * This method may be used to restart the service (and may be triggered by a
61
+ * 'refresh' event)
62
+ */
63
+ restart(): Promise<void>;
64
+ }
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ // Copyright IBM Corp. 2019. All Rights Reserved.
3
+ // Node module: @loopback/example-greeting-app
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.CachingService = void 0;
8
+ const tslib_1 = require("tslib");
9
+ const core_1 = require("@loopback/core");
10
+ const debug_1 = tslib_1.__importDefault(require("debug"));
11
+ const debug = debug_1.default('greeter-extension');
12
+ /**
13
+ * Message caching service
14
+ */
15
+ let CachingService = class CachingService {
16
+ constructor(optionsView) {
17
+ this.optionsView = optionsView;
18
+ this.store = new Map();
19
+ // Use a view so that we can listen on `refresh` events, which are emitted
20
+ // when the configuration binding is updated in the context.
21
+ optionsView.on('refresh', () => {
22
+ debug('Restarting the service as configuration changes...');
23
+ this.restart().catch(err => {
24
+ console.error('Cannot restart the caching service.', err);
25
+ process.exit(1);
26
+ });
27
+ });
28
+ }
29
+ // We intentionally mark all operations `async` to reflect the commonly used
30
+ // caching infrastructure even though our in-memory implementation is based
31
+ // on a `Map` that provides synchronous APIs.
32
+ /**
33
+ * Store a message in the cache
34
+ * @param key - Key for caching
35
+ * @param message - Message
36
+ */
37
+ async set(key, message) {
38
+ this.store.set(key, message);
39
+ }
40
+ /**
41
+ * Load a message from the cache by key
42
+ * @param key - Key for caching
43
+ */
44
+ async get(key) {
45
+ const expired = await this.isExpired(key);
46
+ debug('Getting cache for %s', key, expired);
47
+ return expired ? undefined : this.store.get(key);
48
+ }
49
+ /**
50
+ * Delete a message from the cache by key
51
+ * @param key - Key for caching
52
+ */
53
+ async delete(key) {
54
+ return this.store.delete(key);
55
+ }
56
+ /**
57
+ * Clear the cache
58
+ */
59
+ async clear() {
60
+ this.store.clear();
61
+ }
62
+ /**
63
+ * Check if the cached item is expired by key
64
+ * @param key - Key for caching
65
+ * @param now - The current date
66
+ */
67
+ async isExpired(key, now = new Date()) {
68
+ const ttl = await this.getTTL();
69
+ const msg = this.store.get(key);
70
+ if (!msg)
71
+ return true;
72
+ return now.getTime() - msg.timestamp.getTime() > ttl;
73
+ }
74
+ /**
75
+ * Get the TTL setting
76
+ */
77
+ async getTTL() {
78
+ var _a;
79
+ const options = await this.optionsView.singleValue();
80
+ debug('Caching options: %j', options);
81
+ return (_a = options === null || options === void 0 ? void 0 : options.ttl) !== null && _a !== void 0 ? _a : 5000;
82
+ }
83
+ /**
84
+ * Remove expired items from the cache
85
+ */
86
+ async sweep() {
87
+ debug('Sweeping cache...');
88
+ for (const key of this.store.keys()) {
89
+ if (await this.isExpired(key)) {
90
+ debug('Cache for %s is swept.', key);
91
+ await this.delete(key);
92
+ }
93
+ }
94
+ }
95
+ /**
96
+ * This method will be invoked when the application starts
97
+ */
98
+ async start() {
99
+ debug('Starting caching service');
100
+ await this.clear();
101
+ const ttl = await this.getTTL();
102
+ debug('TTL: %d', ttl);
103
+ this.timer = setInterval(() => {
104
+ this.sweep().catch(console.warn);
105
+ }, ttl);
106
+ }
107
+ /**
108
+ * This method will be invoked when the application stops
109
+ */
110
+ async stop() {
111
+ debug('Stopping caching service');
112
+ /* istanbul ignore if */
113
+ if (this.timer) {
114
+ clearInterval(this.timer);
115
+ }
116
+ await this.clear();
117
+ }
118
+ /**
119
+ * This method may be used to restart the service (and may be triggered by a
120
+ * 'refresh' event)
121
+ */
122
+ async restart() {
123
+ await this.stop();
124
+ await this.start();
125
+ }
126
+ };
127
+ CachingService = tslib_1.__decorate([
128
+ core_1.injectable({ scope: core_1.BindingScope.SINGLETON }),
129
+ tslib_1.__param(0, core_1.config.view()),
130
+ tslib_1.__metadata("design:paramtypes", [core_1.ContextView])
131
+ ], CachingService);
132
+ exports.CachingService = CachingService;
133
+ //# sourceMappingURL=caching-service.js.map