@nmshd/typescript-rest 3.0.5

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/.ci/runChecks.sh +7 -0
  2. package/.eslintrc.js +226 -0
  3. package/.github/dependabot.yml +27 -0
  4. package/.github/workflows/publish.yml +33 -0
  5. package/.github/workflows/test.yml +31 -0
  6. package/.prettierrc +27 -0
  7. package/.vscode/settings.json +31 -0
  8. package/LICENSE +22 -0
  9. package/README.md +128 -0
  10. package/dist/decorators/methods.d.ts +165 -0
  11. package/dist/decorators/methods.js +263 -0
  12. package/dist/decorators/methods.js.map +1 -0
  13. package/dist/decorators/parameters.d.ts +295 -0
  14. package/dist/decorators/parameters.js +423 -0
  15. package/dist/decorators/parameters.js.map +1 -0
  16. package/dist/decorators/services.d.ts +199 -0
  17. package/dist/decorators/services.js +367 -0
  18. package/dist/decorators/services.js.map +1 -0
  19. package/dist/server/config.d.ts +4 -0
  20. package/dist/server/config.js +43 -0
  21. package/dist/server/config.js.map +1 -0
  22. package/dist/server/model/errors.d.ts +111 -0
  23. package/dist/server/model/errors.js +178 -0
  24. package/dist/server/model/errors.js.map +1 -0
  25. package/dist/server/model/metadata.d.ts +91 -0
  26. package/dist/server/model/metadata.js +80 -0
  27. package/dist/server/model/metadata.js.map +1 -0
  28. package/dist/server/model/return-types.d.ts +86 -0
  29. package/dist/server/model/return-types.js +110 -0
  30. package/dist/server/model/return-types.js.map +1 -0
  31. package/dist/server/model/server-types.d.ts +118 -0
  32. package/dist/server/model/server-types.js +47 -0
  33. package/dist/server/model/server-types.js.map +1 -0
  34. package/dist/server/parameter-processor.d.ts +13 -0
  35. package/dist/server/parameter-processor.js +84 -0
  36. package/dist/server/parameter-processor.js.map +1 -0
  37. package/dist/server/server-container.d.ts +55 -0
  38. package/dist/server/server-container.js +432 -0
  39. package/dist/server/server-container.js.map +1 -0
  40. package/dist/server/server.d.ts +136 -0
  41. package/dist/server/server.js +278 -0
  42. package/dist/server/server.js.map +1 -0
  43. package/dist/server/service-invoker.d.ts +28 -0
  44. package/dist/server/service-invoker.js +270 -0
  45. package/dist/server/service-invoker.js.map +1 -0
  46. package/dist/typescript-rest.d.ts +9 -0
  47. package/dist/typescript-rest.js +31 -0
  48. package/dist/typescript-rest.js.map +1 -0
  49. package/package.json +113 -0
  50. package/src/decorators/methods.ts +279 -0
  51. package/src/decorators/parameters.ts +442 -0
  52. package/src/decorators/services.ts +390 -0
  53. package/src/server/config.ts +40 -0
  54. package/src/server/model/errors.ts +178 -0
  55. package/src/server/model/metadata.ts +118 -0
  56. package/src/server/model/return-types.ts +109 -0
  57. package/src/server/model/server-types.ts +130 -0
  58. package/src/server/parameter-processor.ts +105 -0
  59. package/src/server/server-container.ts +504 -0
  60. package/src/server/server.ts +340 -0
  61. package/src/server/service-invoker.ts +266 -0
  62. package/src/typescript-rest.ts +16 -0
@@ -0,0 +1,340 @@
1
+ 'use strict';
2
+
3
+ import * as debug from 'debug';
4
+ import * as express from 'express';
5
+ import * as fs from 'fs-extra';
6
+ import * as _ from 'lodash';
7
+ import 'multer';
8
+ import * as path from 'path';
9
+ import * as YAML from 'yamljs';
10
+ import { FileLimits, HttpMethod, ParameterConverter, ServiceAuthenticator, ServiceFactory } from './model/server-types';
11
+ import { ServerContainer } from './server-container';
12
+
13
+ const serverDebugger = debug('typescript-rest:server:build');
14
+
15
+ /**
16
+ * The Http server main class.
17
+ */
18
+ export class Server {
19
+ /**
20
+ * Create the routes for all classes decorated with our decorators
21
+ */
22
+ public static buildServices(router: express.Router, ...types: Array<any>) {
23
+ if (!Server.locked) {
24
+ serverDebugger('Creating typescript-rest services handlers');
25
+ const serverContainer = ServerContainer.get();
26
+ serverContainer.router = router;
27
+ serverContainer.buildServices(types);
28
+ }
29
+ }
30
+
31
+ /**
32
+ * An alias for Server.loadServices()
33
+ */
34
+ public static loadControllers(router: express.Router, patterns: string | Array<string>, baseDir?: string) {
35
+ Server.loadServices(router, patterns, baseDir);
36
+ }
37
+
38
+ /**
39
+ * Load all services from the files that matches the patterns provided
40
+ */
41
+ public static loadServices(router: express.Router, patterns: string | Array<string>, baseDir?: string) {
42
+ if (!Server.locked) {
43
+ serverDebugger('Loading typescript-rest services %j. BaseDir: %s', patterns, baseDir);
44
+ const importedTypes: Array<Function> = [];
45
+ const requireGlob = require('require-glob');
46
+ baseDir = baseDir || process.cwd();
47
+ const loadedModules: Array<any> = requireGlob.sync(patterns, {
48
+ cwd: baseDir
49
+ });
50
+
51
+ _.values(loadedModules).forEach((serviceModule) => {
52
+ _.values(serviceModule)
53
+ .filter((service: Function) => typeof service === 'function')
54
+ .forEach((service: Function) => {
55
+ importedTypes.push(service);
56
+ });
57
+ });
58
+
59
+ try {
60
+ Server.buildServices(router, ...importedTypes);
61
+ } catch (e) {
62
+ serverDebugger('Error loading services for pattern: %j. Error: %o', patterns, e);
63
+ serverDebugger('ImportedTypes: %o', importedTypes);
64
+ throw new TypeError(
65
+ `Error loading services for pattern: ${JSON.stringify(patterns)}. Error: ${e.message}`
66
+ );
67
+ }
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Makes the server immutable. Any configuration change request to the Server
73
+ * is ignored when immutable is true
74
+ * @param value true to make immutable
75
+ */
76
+ public static immutable(value: boolean) {
77
+ Server.locked = value;
78
+ }
79
+
80
+ /**
81
+ * Return true if the server is immutable. Any configuration change request to the Server
82
+ * is ignored when immutable is true
83
+ */
84
+ public static isImmutable() {
85
+ return Server.locked;
86
+ }
87
+
88
+ /**
89
+ * Retrieve the express router that serves the rest endpoints
90
+ */
91
+ public static server() {
92
+ return ServerContainer.get().router;
93
+ }
94
+
95
+ /**
96
+ * Return all paths accepted by the Server
97
+ */
98
+ public static getPaths(): Array<string> {
99
+ const result = new Array<string>();
100
+ ServerContainer.get()
101
+ .getPaths()
102
+ .forEach((value) => {
103
+ result.push(value);
104
+ });
105
+
106
+ return result;
107
+ }
108
+
109
+ /**
110
+ * Register a custom serviceFactory. It will be used to instantiate the service Objects
111
+ * If You plan to use a custom serviceFactory, You must ensure to call this method before any typescript-rest service declaration.
112
+ */
113
+ public static registerServiceFactory(serviceFactory: ServiceFactory | string) {
114
+ if (!Server.locked) {
115
+ let factory: ServiceFactory;
116
+ if (typeof serviceFactory === 'string') {
117
+ const mod = require(serviceFactory);
118
+ factory = mod.default ? mod.default : mod;
119
+ } else {
120
+ factory = serviceFactory;
121
+ }
122
+
123
+ serverDebugger('Registering a new serviceFactory');
124
+ ServerContainer.get().serviceFactory = factory;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Register a service authenticator. It will be used to authenticate users before the service method
130
+ * invocations occurs.
131
+ */
132
+ public static registerAuthenticator(authenticator: ServiceAuthenticator, name: string = 'default') {
133
+ if (!Server.locked) {
134
+ serverDebugger('Registering a new authenticator with name %s', name);
135
+ ServerContainer.get().authenticator.set(name, authenticator);
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Return the set oh HTTP verbs configured for the given path
141
+ * @param servicePath The path to search HTTP verbs
142
+ */
143
+ public static getHttpMethods(servicePath: string): Array<HttpMethod> {
144
+ const result = new Array<HttpMethod>();
145
+ ServerContainer.get()
146
+ .getHttpMethods(servicePath)
147
+ .forEach((value) => {
148
+ result.push(value);
149
+ });
150
+
151
+ return result;
152
+ }
153
+
154
+ /**
155
+ * A string used for signing cookies. This is optional and if not specified,
156
+ * will not parse signed cookies.
157
+ * @param secret the secret used to sign
158
+ */
159
+ public static setCookiesSecret(secret: string) {
160
+ if (!Server.locked) {
161
+ serverDebugger('Setting a new secret for cookies: %s', secret);
162
+ ServerContainer.get().cookiesSecret = secret;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Specifies a function that will be used to decode a cookie's value.
168
+ * This function can be used to decode a previously-encoded cookie value
169
+ * into a JavaScript string.
170
+ * The default function is the global decodeURIComponent, which will decode
171
+ * any URL-encoded sequences into their byte representations.
172
+ *
173
+ * NOTE: if an error is thrown from this function, the original, non-decoded
174
+ * cookie value will be returned as the cookie's value.
175
+ * @param decoder The decoder function
176
+ */
177
+ public static setCookiesDecoder(decoder: (val: string) => string) {
178
+ if (!Server.locked) {
179
+ serverDebugger('Setting a new secret decoder');
180
+ ServerContainer.get().cookiesDecoder = decoder;
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Set where to store the uploaded files
186
+ * @param dest Destination folder
187
+ */
188
+ public static setFileDest(dest: string) {
189
+ if (!Server.locked) {
190
+ serverDebugger('Setting a new destination for files: %s', dest);
191
+ ServerContainer.get().fileDest = dest;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Set a Function to control which files are accepted to upload
197
+ * @param filter The filter function
198
+ */
199
+ public static setFileFilter(
200
+ filter: (
201
+ req: Express.Request,
202
+ file: Express.Multer.File,
203
+ callback: (error: Error, acceptFile: boolean) => void
204
+ ) => void
205
+ ) {
206
+ if (!Server.locked) {
207
+ serverDebugger('Setting a new filter for files');
208
+ ServerContainer.get().fileFilter = filter;
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Set the limits of uploaded data
214
+ * @param limit The data limit
215
+ */
216
+ public static setFileLimits(limit: FileLimits) {
217
+ if (!Server.locked) {
218
+ serverDebugger('Setting a new fileLimits: %j', limit);
219
+ ServerContainer.get().fileLimits = limit;
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Adds a converter for param values to have an ability to intercept the type that actually will be passed to service
225
+ * @param converter The converter
226
+ * @param type The target type that needs to be converted
227
+ */
228
+ public static addParameterConverter(converter: ParameterConverter, type: Function): void {
229
+ if (!Server.locked) {
230
+ serverDebugger('Adding a new parameter converter');
231
+ ServerContainer.get().paramConverters.set(type, converter);
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Remove the converter associated with the given type.
237
+ * @param type The target type that needs to be converted
238
+ */
239
+ public static removeParameterConverter(type: Function): void {
240
+ if (!Server.locked) {
241
+ serverDebugger('Removing a parameter converter');
242
+ ServerContainer.get().paramConverters.delete(type);
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Makes the server ignore next middlewares for all endpoints.
248
+ * It has the same effect than add @IgnoreNextMiddlewares to all
249
+ * services.
250
+ * @param value - true to ignore next middlewares.
251
+ */
252
+ public static ignoreNextMiddlewares(value: boolean) {
253
+ if (!Server.locked) {
254
+ serverDebugger('Ignoring next middlewares: %b', value);
255
+ ServerContainer.get().ignoreNextMiddlewares = value;
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Creates and endpoint to publish the swagger documentation.
261
+ * @param router Express router
262
+ * @param options Options for swagger endpoint
263
+ */
264
+ public static swagger(router: express.Router, options?: SwaggerOptions) {
265
+ if (!Server.locked) {
266
+ const swaggerUi = require('swagger-ui-express');
267
+ options = Server.getOptions(options);
268
+ serverDebugger('Configuring open api documentation endpoints for options: %j', options);
269
+
270
+ const swaggerDocument: any = Server.loadSwaggerDocument(options);
271
+
272
+ if (options.host) {
273
+ swaggerDocument.host = options.host;
274
+ }
275
+ if (options.schemes) {
276
+ swaggerDocument.schemes = options.schemes;
277
+ }
278
+
279
+ router.get(path.posix.join('/', options.endpoint, 'json'), (req, res) => {
280
+ res.send(swaggerDocument);
281
+ });
282
+ router.get(path.posix.join('/', options.endpoint, 'yaml'), (req, res) => {
283
+ res.set('Content-Type', 'text/vnd.yaml');
284
+ res.send(YAML.stringify(swaggerDocument, 1000));
285
+ });
286
+ router.use(
287
+ path.posix.join('/', options.endpoint),
288
+ swaggerUi.serve,
289
+ swaggerUi.setup(swaggerDocument, options.swaggerUiOptions)
290
+ );
291
+ }
292
+ }
293
+
294
+ private static locked = false;
295
+
296
+ private static loadSwaggerDocument(options: SwaggerOptions) {
297
+ let swaggerDocument: any;
298
+ if (_.endsWith(options.filePath, '.yml') || _.endsWith(options.filePath, '.yaml')) {
299
+ swaggerDocument = YAML.load(options.filePath);
300
+ } else {
301
+ swaggerDocument = fs.readJSONSync(options.filePath);
302
+ }
303
+ serverDebugger('Loaded swagger configurations: %j', swaggerDocument);
304
+ return swaggerDocument;
305
+ }
306
+
307
+ private static getOptions(options: SwaggerOptions) {
308
+ options = _.defaults(options, {
309
+ endpoint: 'api-docs',
310
+ filePath: './swagger.json'
311
+ });
312
+ if (_.startsWith(options.filePath, '.')) {
313
+ options.filePath = path.join(process.cwd(), options.filePath);
314
+ }
315
+ return options;
316
+ }
317
+ }
318
+
319
+ export interface SwaggerOptions {
320
+ /**
321
+ * The path to a swagger file (json or yaml)
322
+ */
323
+ filePath?: string;
324
+ /**
325
+ * Where to publish the docs
326
+ */
327
+ endpoint?: string;
328
+ /**
329
+ * The hostname of the service
330
+ */
331
+ host?: string;
332
+ /**
333
+ * The schemes used by the server
334
+ */
335
+ schemes?: Array<string>;
336
+ /**
337
+ * Options to send to swagger-ui
338
+ */
339
+ swaggerUiOptions?: object;
340
+ }
@@ -0,0 +1,266 @@
1
+ 'use strict';
2
+
3
+ import * as debug from 'debug';
4
+ import * as express from 'express';
5
+ import * as _ from 'lodash';
6
+ import { Errors } from '../typescript-rest';
7
+ import { ServiceClass, ServiceMethod, ServiceProperty } from './model/metadata';
8
+ import { DownloadBinaryData, DownloadResource, NoResponse } from './model/return-types';
9
+ import { HttpMethod, ReferencedResource, ServiceContext, ServiceProcessor } from './model/server-types';
10
+ import { ParameterProcessor } from './parameter-processor';
11
+ import { ServerContainer } from './server-container';
12
+
13
+ export class ServiceInvoker {
14
+ private serviceClass: ServiceClass;
15
+ private serviceMethod: ServiceMethod;
16
+ private preProcessors: Array<ServiceProcessor>;
17
+ private postProcessors: Array<ServiceProcessor>;
18
+ private debugger = debug('typescript-rest:service-invoker:runtime');
19
+
20
+ constructor(serviceClass: ServiceClass, serviceMethod: ServiceMethod) {
21
+ this.serviceClass = serviceClass;
22
+ this.serviceMethod = serviceMethod;
23
+ this.preProcessors = _.union(serviceMethod.preProcessors, serviceClass.preProcessors);
24
+ this.postProcessors = _.union(serviceMethod.postProcessors, serviceClass.postProcessors);
25
+ }
26
+
27
+ public async callService(context: ServiceContext) {
28
+ try {
29
+ await this.callTargetEndPoint(context);
30
+ if (this.mustCallNext()) {
31
+ context.next();
32
+ } else if (this.debugger.enabled) {
33
+ this.debugger('Ignoring next middlewares');
34
+ }
35
+ } catch (err) {
36
+ context.next(err);
37
+ }
38
+ }
39
+
40
+ private mustCallNext() {
41
+ return (
42
+ !ServerContainer.get().ignoreNextMiddlewares &&
43
+ !this.serviceMethod.ignoreNextMiddlewares &&
44
+ !this.serviceClass.ignoreNextMiddlewares
45
+ );
46
+ }
47
+
48
+ private async runPreProcessors(context: ServiceContext): Promise<void> {
49
+ this.debugger('Running preprocessors');
50
+ for (const processor of this.preProcessors) {
51
+ await Promise.resolve(processor(context.request, context.response));
52
+ }
53
+ }
54
+
55
+ private async runPostProcessors(context: ServiceContext): Promise<void> {
56
+ this.debugger('Running postprocessors');
57
+ for (const processor of this.postProcessors) {
58
+ await Promise.resolve(processor(context.request, context.response));
59
+ }
60
+ }
61
+
62
+ private async callTargetEndPoint(context: ServiceContext) {
63
+ this.debugger('Calling targetEndpoint %s', this.serviceMethod.resolvedPath);
64
+ this.checkAcceptance(context);
65
+ if (this.preProcessors.length) {
66
+ await this.runPreProcessors(context);
67
+ }
68
+ const serviceObject = this.createService(context);
69
+ const args = this.buildArgumentsList(context);
70
+ const toCall = this.getMethodToCall();
71
+ if (this.debugger.enabled) {
72
+ this.debugger('Invoking service method <%s> with params: %j', this.serviceMethod.name, args);
73
+ }
74
+ const result = await toCall.apply(serviceObject, args);
75
+ if (this.postProcessors.length) {
76
+ await this.runPostProcessors(context);
77
+ }
78
+ this.processResponseHeaders(context);
79
+ await this.sendValue(result, context);
80
+ }
81
+
82
+ private getMethodToCall() {
83
+ return (
84
+ this.serviceClass.targetClass.prototype[this.serviceMethod.name] ||
85
+ this.serviceClass.targetClass[this.serviceMethod.name]
86
+ );
87
+ }
88
+
89
+ private checkAcceptance(context: ServiceContext): void {
90
+ this.debugger('Verifying accept headers');
91
+ this.identifyAcceptedLanguage(context);
92
+ this.identifyAcceptedType(context);
93
+
94
+ if (!context.accept) {
95
+ throw new Errors.NotAcceptableError('Accept');
96
+ }
97
+ if (!context.language) {
98
+ throw new Errors.NotAcceptableError('Accept-Language');
99
+ }
100
+ }
101
+
102
+ private identifyAcceptedLanguage(context: ServiceContext) {
103
+ if (this.serviceMethod.resolvedLanguages) {
104
+ const lang: any = context.request.acceptsLanguages(this.serviceMethod.resolvedLanguages);
105
+ if (lang) {
106
+ context.language = lang as string;
107
+ }
108
+ } else {
109
+ const languages: Array<string> = context.request.acceptsLanguages();
110
+ if (languages && languages.length > 0) {
111
+ context.language = languages[0];
112
+ }
113
+ }
114
+ this.debugger('Identified the preferable language accepted by server: %s', context.language);
115
+ }
116
+
117
+ private identifyAcceptedType(context: ServiceContext) {
118
+ if (this.serviceMethod.resolvedAccepts) {
119
+ context.accept = context.request.accepts(this.serviceMethod.resolvedAccepts) as string;
120
+ } else {
121
+ const accepts: Array<string> = context.request.accepts();
122
+ if (accepts && accepts.length > 0) {
123
+ context.accept = accepts[0];
124
+ }
125
+ }
126
+ this.debugger('Identified the preferable media type accepted by server: %s', context.accept);
127
+ }
128
+
129
+ private createService(context: ServiceContext) {
130
+ const serviceObject = ServerContainer.get().serviceFactory.create(this.serviceClass.targetClass, context);
131
+ this.debugger('Creating service object');
132
+ if (this.serviceClass.hasProperties()) {
133
+ this.serviceClass.properties.forEach((property, key) => {
134
+ this.debugger('Setting service property %s', key);
135
+ serviceObject[key] = this.processParameter(context, property);
136
+ });
137
+ }
138
+ return serviceObject;
139
+ }
140
+
141
+ private buildArgumentsList(context: ServiceContext) {
142
+ const result: Array<any> = new Array<any>();
143
+
144
+ this.serviceMethod.parameters.forEach((param) => {
145
+ this.debugger('Processing service parameter [%s]', param.name || 'body');
146
+ result.push(
147
+ this.processParameter(context, {
148
+ name: param.name,
149
+ propertyType: param.type,
150
+ type: param.paramType
151
+ })
152
+ );
153
+ });
154
+
155
+ return result;
156
+ }
157
+
158
+ private processParameter(context: ServiceContext, property: ServiceProperty) {
159
+ return ParameterProcessor.get().processParameter(context, property);
160
+ }
161
+
162
+ private processResponseHeaders(context: ServiceContext) {
163
+ if (this.serviceMethod.resolvedLanguages) {
164
+ if (this.serviceMethod.httpMethod === HttpMethod.GET) {
165
+ this.debugger('Adding response header vary: Accept-Language');
166
+ context.response.vary('Accept-Language');
167
+ }
168
+ this.debugger('Adding response header Content-Language: %s', context.language);
169
+ context.response.set('Content-Language', context.language);
170
+ }
171
+ if (this.serviceMethod.resolvedAccepts) {
172
+ if (this.serviceMethod.httpMethod === HttpMethod.GET) {
173
+ this.debugger('Adding response header vary: Accept');
174
+ context.response.vary('Accept');
175
+ }
176
+ }
177
+ }
178
+
179
+ private async sendValue(value: any, context: ServiceContext) {
180
+ if (value !== NoResponse) {
181
+ this.debugger('Sending response value: %o', value);
182
+ switch (typeof value) {
183
+ case 'number':
184
+ context.response.send(value.toString());
185
+ break;
186
+ case 'string':
187
+ context.response.send(value);
188
+ break;
189
+ case 'boolean':
190
+ context.response.send(value.toString());
191
+ break;
192
+ case 'undefined':
193
+ if (!context.response.headersSent) {
194
+ context.response.sendStatus(204);
195
+ }
196
+ break;
197
+ default:
198
+ if (value === null) {
199
+ context.response.send(value);
200
+ } else {
201
+ await this.sendComplexValue(context, value);
202
+ }
203
+ }
204
+ } else {
205
+ this.debugger('Do not send any response value');
206
+ }
207
+ }
208
+
209
+ private async sendComplexValue(context: ServiceContext, value: any) {
210
+ if (value.filePath && value instanceof DownloadResource) {
211
+ await this.downloadResToPromise(context.response, value);
212
+ } else if (value instanceof DownloadBinaryData) {
213
+ this.sendFile(context, value);
214
+ } else if (value.location && value instanceof ReferencedResource) {
215
+ await this.sendReferencedResource(context, value);
216
+ } else if (value.then && value.catch) {
217
+ const val = await value;
218
+ await this.sendValue(val, context);
219
+ } else {
220
+ this.debugger('Sending a json value: %j', value);
221
+ context.response.json(value);
222
+ }
223
+ }
224
+
225
+ private async sendReferencedResource(context: ServiceContext, value: ReferencedResource<any>) {
226
+ this.debugger('Setting the header Location: %s', value.location);
227
+ this.debugger('Sendinf status code: %d', value.statusCode);
228
+ context.response.set('Location', value.location);
229
+ if (value.body) {
230
+ context.response.status(value.statusCode);
231
+ await this.sendValue(value.body, context);
232
+ } else {
233
+ context.response.sendStatus(value.statusCode);
234
+ }
235
+ }
236
+
237
+ private sendFile(context: ServiceContext, value: DownloadBinaryData) {
238
+ this.debugger('Sending file as response');
239
+ if (value.fileName) {
240
+ context.response.writeHead(200, {
241
+ 'Content-Length': value.content.length,
242
+ 'Content-Type': value.mimeType,
243
+ 'Content-disposition': 'attachment;filename=' + value.fileName
244
+ });
245
+ } else {
246
+ context.response.writeHead(200, {
247
+ 'Content-Length': value.content.length,
248
+ 'Content-Type': value.mimeType
249
+ });
250
+ }
251
+ context.response.end(value.content);
252
+ }
253
+
254
+ private downloadResToPromise(res: express.Response, value: DownloadResource) {
255
+ this.debugger('Sending a resource to download. Path: %s', value.filePath);
256
+ return new Promise((resolve, reject) => {
257
+ res.download(value.filePath, value.fileName || value.filePath, (err) => {
258
+ if (err) {
259
+ reject(err);
260
+ } else {
261
+ resolve(undefined);
262
+ }
263
+ });
264
+ });
265
+ }
266
+ }
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ import { ServerConfig } from './server/config';
4
+ import * as Errors from './server/model/errors';
5
+ import * as Return from './server/model/return-types';
6
+
7
+ export * from './decorators/methods';
8
+ export * from './decorators/parameters';
9
+ export * from './decorators/services';
10
+ export * from './server/model/server-types';
11
+ export * from './server/server';
12
+
13
+ export { DefaultServiceFactory } from './server/server-container';
14
+ export { Errors, Return };
15
+
16
+ ServerConfig.configure();