1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | import {
|
18 | OmniHandler,
|
19 | StandardHandler,
|
20 | BuiltinFrameworks,
|
21 | builtin,
|
22 | } from './framework';
|
23 | import * as common from './common';
|
24 |
|
25 |
|
26 | export type AppHandler = OmniHandler & BaseApp;
|
27 |
|
28 |
|
29 | export interface AppOptions {
|
30 |
|
31 | debug?: boolean;
|
32 | }
|
33 |
|
34 |
|
35 | export interface ServiceBaseApp {
|
36 |
|
37 | handler: StandardHandler;
|
38 | }
|
39 |
|
40 |
|
41 | export interface Plugin<TService, TPlugin> {
|
42 |
|
43 | <TApp>(app: AppHandler & TService & TApp):
|
44 | | (AppHandler & TService & TApp & TPlugin)
|
45 | | void;
|
46 | }
|
47 |
|
48 |
|
49 | export interface BaseApp extends ServiceBaseApp {
|
50 |
|
51 | frameworks: BuiltinFrameworks;
|
52 |
|
53 |
|
54 | use<TService, TPlugin>(plugin: Plugin<TService, TPlugin>): this & TPlugin;
|
55 |
|
56 |
|
57 | debug: boolean;
|
58 | }
|
59 |
|
60 |
|
61 | const create = (options?: AppOptions): BaseApp => ({
|
62 | frameworks: Object.assign({}, builtin),
|
63 | handler: () => Promise.reject(new Error('StandardHandler not set')),
|
64 | use(plugin) {
|
65 | return plugin(this) || this;
|
66 | },
|
67 | debug: !!(options && options.debug),
|
68 | });
|
69 |
|
70 |
|
71 | export const attach = <TService>(
|
72 | service: TService,
|
73 | options?: AppOptions
|
74 | ): AppHandler & TService => {
|
75 | let app: (BaseApp & TService) | (AppHandler & TService) = Object.assign(
|
76 | create(options),
|
77 | service
|
78 | );
|
79 |
|
80 | const omni: OmniHandler = (...args: any[]) => {
|
81 | for (const framework of common.values(app.frameworks)) {
|
82 | if (framework.check(...args)) {
|
83 | return framework.handle(app.handler)(...args);
|
84 | }
|
85 | }
|
86 | return app.handler(args[0], args[1]);
|
87 | };
|
88 | app = Object.assign(omni, app);
|
89 | const handler: typeof app.handler = app.handler.bind(app);
|
90 | const standard: StandardHandler = async (body, headers, metadata) => {
|
91 | const log = app.debug ? common.info : common.debug;
|
92 | log('Request', common.stringify(body));
|
93 | log('Headers', common.stringify(headers));
|
94 | const response = await handler(body, headers, metadata);
|
95 | if (!response.headers) {
|
96 | response.headers = {};
|
97 | }
|
98 | response.headers['content-type'] = 'application/json;charset=utf-8';
|
99 | log('Response', common.stringify(response));
|
100 | return response;
|
101 | };
|
102 | app.handler = standard;
|
103 | return app as AppHandler & TService;
|
104 | };
|