@deepkit/http 1.0.1-alpha.70 → 1.0.1-alpha.73

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 (121) hide show
  1. package/dist/cjs/src/decorator.d.ts +8 -6
  2. package/dist/cjs/src/decorator.js +49 -12
  3. package/dist/cjs/src/decorator.js.map +1 -1
  4. package/dist/cjs/src/filter.d.ts +3 -3
  5. package/dist/cjs/src/filter.js +3 -3
  6. package/dist/cjs/src/filter.js.map +1 -1
  7. package/dist/cjs/src/http.d.ts +49 -11
  8. package/dist/cjs/src/http.js +124 -38
  9. package/dist/cjs/src/http.js.map +1 -1
  10. package/dist/cjs/src/kernel.d.ts +3 -3
  11. package/dist/cjs/src/kernel.js +1 -1
  12. package/dist/cjs/src/kernel.js.map +1 -1
  13. package/dist/cjs/src/model.d.ts +11 -3
  14. package/dist/cjs/src/model.js +58 -26
  15. package/dist/cjs/src/model.js.map +1 -1
  16. package/dist/cjs/src/module.js +5 -3
  17. package/dist/cjs/src/module.js.map +1 -1
  18. package/dist/cjs/src/router.d.ts +84 -11
  19. package/dist/cjs/src/router.js +280 -94
  20. package/dist/cjs/src/router.js.map +1 -1
  21. package/dist/cjs/src/static-serving.js +15 -8
  22. package/dist/cjs/src/static-serving.js.map +1 -1
  23. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  24. package/dist/esm/src/decorator.d.ts +8 -6
  25. package/dist/esm/src/decorator.js +47 -11
  26. package/dist/esm/src/decorator.js.map +1 -1
  27. package/dist/esm/src/filter.d.ts +3 -3
  28. package/dist/esm/src/filter.js +4 -4
  29. package/dist/esm/src/filter.js.map +1 -1
  30. package/dist/esm/src/http.d.ts +49 -11
  31. package/dist/esm/src/http.js +111 -38
  32. package/dist/esm/src/http.js.map +1 -1
  33. package/dist/esm/src/kernel.d.ts +3 -3
  34. package/dist/esm/src/kernel.js +2 -2
  35. package/dist/esm/src/kernel.js.map +1 -1
  36. package/dist/esm/src/model.d.ts +11 -3
  37. package/dist/esm/src/model.js +47 -15
  38. package/dist/esm/src/model.js.map +1 -1
  39. package/dist/esm/src/module.js +6 -4
  40. package/dist/esm/src/module.js.map +1 -1
  41. package/dist/esm/src/router.d.ts +84 -11
  42. package/dist/esm/src/router.js +278 -94
  43. package/dist/esm/src/router.js.map +1 -1
  44. package/dist/esm/src/static-serving.js +16 -9
  45. package/dist/esm/src/static-serving.js.map +1 -1
  46. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  47. package/package.json +17 -14
  48. package/src/decorator.ts +9 -6
  49. package/src/filter.ts +4 -4
  50. package/src/http.ts +83 -15
  51. package/src/kernel.ts +2 -2
  52. package/src/model.ts +35 -6
  53. package/src/module.ts +5 -3
  54. package/src/router.ts +286 -73
  55. package/src/static-serving.ts +6 -3
  56. package/coverage/clover.xml +0 -1086
  57. package/coverage/coverage-final.json +0 -12
  58. package/coverage/lcov-report/base.css +0 -224
  59. package/coverage/lcov-report/block-navigation.js +0 -79
  60. package/coverage/lcov-report/favicon.png +0 -0
  61. package/coverage/lcov-report/index.html +0 -126
  62. package/coverage/lcov-report/prettify.css +0 -1
  63. package/coverage/lcov-report/prettify.js +0 -2
  64. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  65. package/coverage/lcov-report/sorter.js +0 -170
  66. package/coverage/lcov-report/src/controllers.ts.html +0 -113
  67. package/coverage/lcov-report/src/decorator.ts.html +0 -1280
  68. package/coverage/lcov-report/src/filter.ts.html +0 -734
  69. package/coverage/lcov-report/src/http.ts.html +0 -2192
  70. package/coverage/lcov-report/src/index.html +0 -246
  71. package/coverage/lcov-report/src/kernel.ts.html +0 -260
  72. package/coverage/lcov-report/src/middleware.ts.html +0 -428
  73. package/coverage/lcov-report/src/model.ts.html +0 -937
  74. package/coverage/lcov-report/src/module.config.ts.html +0 -89
  75. package/coverage/lcov-report/src/module.ts.html +0 -245
  76. package/coverage/lcov-report/src/router.ts.html +0 -2318
  77. package/coverage/lcov-report/tests/index.html +0 -111
  78. package/coverage/lcov-report/tests/utils.ts.html +0 -176
  79. package/coverage/lcov.info +0 -2225
  80. package/dist/cjs/tests/filter.spec.d.ts +0 -1
  81. package/dist/cjs/tests/filter.spec.js +0 -251
  82. package/dist/cjs/tests/filter.spec.js.map +0 -1
  83. package/dist/cjs/tests/middleware.spec.d.ts +0 -1
  84. package/dist/cjs/tests/middleware.spec.js +0 -471
  85. package/dist/cjs/tests/middleware.spec.js.map +0 -1
  86. package/dist/cjs/tests/model.spec.d.ts +0 -1
  87. package/dist/cjs/tests/model.spec.js +0 -23
  88. package/dist/cjs/tests/model.spec.js.map +0 -1
  89. package/dist/cjs/tests/module.spec.d.ts +0 -1
  90. package/dist/cjs/tests/module.spec.js +0 -46
  91. package/dist/cjs/tests/module.spec.js.map +0 -1
  92. package/dist/cjs/tests/router.spec.d.ts +0 -1
  93. package/dist/cjs/tests/router.spec.js +0 -987
  94. package/dist/cjs/tests/router.spec.js.map +0 -1
  95. package/dist/cjs/tests/utils.d.ts +0 -8
  96. package/dist/cjs/tests/utils.js +0 -30
  97. package/dist/cjs/tests/utils.js.map +0 -1
  98. package/dist/esm/tests/filter.spec.d.ts +0 -1
  99. package/dist/esm/tests/filter.spec.js +0 -249
  100. package/dist/esm/tests/filter.spec.js.map +0 -1
  101. package/dist/esm/tests/middleware.spec.d.ts +0 -1
  102. package/dist/esm/tests/middleware.spec.js +0 -469
  103. package/dist/esm/tests/middleware.spec.js.map +0 -1
  104. package/dist/esm/tests/model.spec.d.ts +0 -1
  105. package/dist/esm/tests/model.spec.js +0 -21
  106. package/dist/esm/tests/model.spec.js.map +0 -1
  107. package/dist/esm/tests/module.spec.d.ts +0 -1
  108. package/dist/esm/tests/module.spec.js +0 -44
  109. package/dist/esm/tests/module.spec.js.map +0 -1
  110. package/dist/esm/tests/router.spec.d.ts +0 -1
  111. package/dist/esm/tests/router.spec.js +0 -985
  112. package/dist/esm/tests/router.spec.js.map +0 -1
  113. package/dist/esm/tests/utils.d.ts +0 -8
  114. package/dist/esm/tests/utils.js +0 -26
  115. package/dist/esm/tests/utils.js.map +0 -1
  116. package/tests/filter.spec.ts +0 -181
  117. package/tests/middleware.spec.ts +0 -440
  118. package/tests/model.spec.ts +0 -26
  119. package/tests/module.spec.ts +0 -32
  120. package/tests/router.spec.ts +0 -781
  121. package/tests/utils.ts +0 -32
package/src/http.ts CHANGED
@@ -14,11 +14,12 @@ import { eventDispatcher } from '@deepkit/event';
14
14
  import { HttpRequest, HttpResponse } from './model';
15
15
  import { InjectorContext } from '@deepkit/injector';
16
16
  import { LoggerInterface } from '@deepkit/logger';
17
- import { RouteConfig, RouteParameterResolverForInjector, Router } from './router';
17
+ import { HttpRouter, RouteConfig, RouteParameterResolverForInjector } from './router';
18
18
  import { createWorkflow, WorkflowEvent } from '@deepkit/workflow';
19
19
  import type { ElementStruct, render } from '@deepkit/template';
20
20
  import { FrameCategory, Stopwatch } from '@deepkit/stopwatch';
21
21
  import { getSerializeFunction, hasTypeInformation, ReflectionKind, resolveReceiveType, SerializationError, serialize, serializer, ValidationError } from '@deepkit/type';
22
+ import stream from 'stream';
22
23
 
23
24
  export function isElementStruct(v: any): v is ElementStruct {
24
25
  return 'object' === typeof v && v.hasOwnProperty('render') && v.hasOwnProperty('attributes') && !v.slice;
@@ -73,24 +74,51 @@ export function createHttpError<T extends number>(code: T, defaultMessage: strin
73
74
  } as any;
74
75
  }
75
76
 
76
- export class HttpNotFoundError extends createHttpError(404, 'Not found') {
77
+ export class HttpBadRequestError extends createHttpError(400, 'Bad request') {
77
78
  }
78
79
 
79
- export class HttpBadRequestError extends createHttpError(400, 'Bad request') {
80
+ export class HttpUnauthorizedError extends createHttpError(401, 'Unauthorized') {
80
81
  }
81
82
 
82
83
  export class HttpAccessDeniedError extends createHttpError(403, 'Access denied') {
83
84
  }
84
85
 
86
+ export class HttpNotFoundError extends createHttpError(404, 'Not found') {
87
+ }
88
+
89
+ export class HttpMethodNotAllowedError extends createHttpError(405, 'Method not allowed') {
90
+ }
91
+
92
+ export class HttpNotAcceptableError extends createHttpError(406, 'Not acceptable') {
93
+ }
94
+
95
+ export class HttpTimeoutError extends createHttpError(408, 'Request timeout') {
96
+ }
97
+
98
+ export class HttpConflictError extends createHttpError(409, 'Conflict') {
99
+ }
100
+
101
+ export class HttpGoneError extends createHttpError(410, 'Gone') {
102
+ }
103
+
104
+ export class HttpTooManyRequestsError extends createHttpError(429, 'Too many requests') {
105
+ }
106
+
107
+ export class HttpInternalServerError extends createHttpError(500, 'Internal server error') {
108
+ }
109
+
110
+ export class HttpNotImplementedError extends createHttpError(501, 'Not implemented') {
111
+ }
112
+
85
113
  export class HttpWorkflowEvent {
86
- stopped = false;
114
+ propagationStopped = false;
87
115
 
88
116
  stopPropagation() {
89
- this.stopped = true;
117
+ this.propagationStopped = true;
90
118
  }
91
119
 
92
- isStopped() {
93
- return this.stopped;
120
+ isPropagationStopped() {
121
+ return this.propagationStopped;
94
122
  }
95
123
 
96
124
  public nextState?: any;
@@ -309,6 +337,10 @@ export class BaseResponse {
309
337
  return this;
310
338
  }
311
339
 
340
+ /**
341
+ * Per default a JSONResponse is serialized using the return type specified at the route.
342
+ * This disables that behaviour so that JSON.stringify is run on the result directly.
343
+ */
312
344
  disableAutoSerializing() {
313
345
  this.autoSerializing = false;
314
346
  return this;
@@ -330,6 +362,13 @@ export class BaseResponse {
330
362
  }
331
363
  }
332
364
 
365
+ export class Response extends BaseResponse {
366
+ constructor(public content: string | Uint8Array, contentType: string, statusCode?: number) {
367
+ super(statusCode);
368
+ this.contentType(contentType);
369
+ }
370
+ }
371
+
333
372
  export class HtmlResponse extends BaseResponse {
334
373
  constructor(public html: string, statusCode?: number) {
335
374
  super(statusCode);
@@ -342,7 +381,7 @@ export class JSONResponse extends BaseResponse {
342
381
  }
343
382
  }
344
383
 
345
- export type SupportedHttpResult = undefined | null | number | string | JSONResponse | HtmlResponse | HttpResponse | ServerResponse | Redirect | Uint8Array | Error;
384
+ export type SupportedHttpResult = undefined | null | number | string | Response | JSONResponse | HtmlResponse | HttpResponse | ServerResponse | stream.Readable | Redirect | Uint8Array | Error;
346
385
 
347
386
  export interface HttpResultFormatterContext {
348
387
  request: HttpRequest;
@@ -354,7 +393,7 @@ export class HttpResultFormatter {
354
393
  protected jsonContentType: string = 'application/json; charset=utf-8';
355
394
  protected htmlContentType: string = 'text/html; charset=utf-8';
356
395
 
357
- constructor(protected router: Router) {
396
+ constructor(protected router: HttpRouter) {
358
397
  }
359
398
 
360
399
  protected setContentTypeIfNotSetAlready(response: HttpResponse, contentType: string): void {
@@ -396,6 +435,11 @@ export class HttpResultFormatter {
396
435
  context.response.end(result.html);
397
436
  }
398
437
 
438
+ handleGenericResponse(result: Response, context: HttpResultFormatterContext): void {
439
+ context.response.writeHead(result._statusCode || 200, result._headers);
440
+ context.response.end(result.content);
441
+ }
442
+
399
443
  handleJSONResponse(result: JSONResponse, context: HttpResultFormatterContext): void {
400
444
  this.setContentTypeIfNotSetAlready(context.response, this.jsonContentType);
401
445
  context.response.writeHead(result._statusCode || 200, result._headers);
@@ -410,6 +454,10 @@ export class HttpResultFormatter {
410
454
  context.response.end(JSON.stringify(serialize(instance, route ? route.serializationOptions : undefined, serializerToUse, undefined, resolveReceiveType(classType))));
411
455
  }
412
456
 
457
+ handleStream(stream: stream.Readable, context: HttpResultFormatterContext): void {
458
+ stream.pipe(context.response);
459
+ }
460
+
413
461
  handleBinary(result: Uint8Array, context: HttpResultFormatterContext): void {
414
462
  context.response.end(result);
415
463
  }
@@ -428,10 +476,14 @@ export class HttpResultFormatter {
428
476
  this.handleResponse(context);
429
477
  } else if (result instanceof HtmlResponse) {
430
478
  this.handleHtmlResponse(result, context);
479
+ } else if (result instanceof stream.Readable) {
480
+ this.handleStream(result, context);
431
481
  } else if (result instanceof Uint8Array) {
432
482
  this.handleBinary(result, context);
433
483
  } else if (result instanceof JSONResponse) {
434
484
  this.handleJSONResponse(result, context);
485
+ } else if (result instanceof Response) {
486
+ this.handleGenericResponse(result, context);
435
487
  } else {
436
488
  if (isClassInstance(result)) {
437
489
  const classType = getClassTypeFromInstance(result);
@@ -448,7 +500,7 @@ export class HttpResultFormatter {
448
500
 
449
501
  export class HttpListener {
450
502
  constructor(
451
- protected router: Router,
503
+ protected router: HttpRouter,
452
504
  protected logger: LoggerInterface,
453
505
  protected resultFormatter: HttpResultFormatter,
454
506
  protected stopwatch?: Stopwatch,
@@ -584,18 +636,34 @@ export class HttpListener {
584
636
  if (event.sent) return;
585
637
  if (event.hasNext()) return;
586
638
 
587
- const controllerInstance = event.injectorContext.get(event.route.action.controller, event.route.action.module);
588
639
 
589
640
  const start = Date.now();
590
- const frame = this.stopwatch ? this.stopwatch.start(getClassName(event.route.action.controller) + '.' + event.route.action.methodName, FrameCategory.httpController) : undefined;
641
+ const stopWatchLabel = event.route.action.type === 'controller'
642
+ ? getClassName(event.route.action.controller) + '.' + event.route.action.methodName
643
+ : event.route.action.fn.name;
644
+
645
+ const frame = this.stopwatch ? this.stopwatch.start(stopWatchLabel, FrameCategory.httpController) : undefined;
591
646
  try {
592
- const method = controllerInstance[event.route.action.methodName];
593
- let result = await method.apply(controllerInstance, event.parameters);
647
+ let result: any;
648
+ if (event.route.action.type === 'controller') {
649
+ const controllerInstance = event.injectorContext.get(event.route.action.controller, event.route.action.module);
650
+ const method = controllerInstance[event.route.action.methodName];
651
+ result = await method.apply(controllerInstance, event.parameters);
652
+ } else {
653
+ result = await event.route.action.fn(...event.parameters);
654
+ }
594
655
 
595
656
  if (isElementStruct(result)) {
596
657
  const html = await getTemplateRender()(event.injectorContext.getRootInjector(), result, this.stopwatch ? this.stopwatch : undefined);
597
658
  result = new HtmlResponse(html, 200).header('Content-Type', 'text/html; charset=utf-8');
598
659
  }
660
+ if (result instanceof stream.Readable) {
661
+ const stream = result as stream.Readable;
662
+ await new Promise((resolve, reject) => {
663
+ stream.once('readable', resolve)
664
+ stream.once('error', reject)
665
+ })
666
+ }
599
667
  const responseEvent = new HttpResponseEvent(event.injectorContext, event.request, event.response, result, event.route);
600
668
  responseEvent.controllerActionTime = Date.now() - start;
601
669
  event.next('response', responseEvent);
@@ -671,7 +739,7 @@ export class HttpListener {
671
739
  if (event.response.headersSent) return;
672
740
  if (event.result === undefined || event.result === null) return;
673
741
 
674
- if (event.result instanceof HtmlResponse || event.result instanceof ServerResponse || event.result instanceof Redirect) {
742
+ if (event.result instanceof HtmlResponse || event.result instanceof ServerResponse || event.result instanceof Redirect || event.result instanceof stream.Readable) {
675
743
  // don't do anything
676
744
  } else if (event.result instanceof JSONResponse) {
677
745
  const schema = (event.result._statusCode && event.route.getSchemaForResponse(event.result._statusCode)) || event.route.returnType;
package/src/kernel.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { InjectorContext } from '@deepkit/injector';
2
- import { Router } from './router';
2
+ import { HttpRouter } from './router';
3
3
  import { EventDispatcher } from '@deepkit/event';
4
4
  import { LoggerInterface } from '@deepkit/logger';
5
5
  import { HttpRequest, HttpResponse, MemoryHttpResponse, RequestBuilder } from './model';
@@ -9,7 +9,7 @@ import { unlink } from 'fs';
9
9
 
10
10
  export class HttpKernel {
11
11
  constructor(
12
- protected router: Router,
12
+ protected router: HttpRouter,
13
13
  protected eventDispatcher: EventDispatcher,
14
14
  protected injectorContext: InjectorContext,
15
15
  protected logger: LoggerInterface,
package/src/model.ts CHANGED
@@ -8,11 +8,12 @@
8
8
  * You should have received a copy of the MIT License along with this program.
9
9
  */
10
10
 
11
- import { IncomingMessage, ServerResponse } from 'http';
11
+ import { IncomingMessage, OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from 'http';
12
12
  import { UploadedFile } from './router';
13
13
  import * as querystring from 'querystring';
14
14
  import { Writable } from 'stream';
15
15
  import { metaAnnotation, ReflectionKind, Type, ValidationErrorItem } from '@deepkit/type';
16
+ import { isArray } from '@deepkit/core';
16
17
 
17
18
  export class HttpResponse extends ServerResponse {
18
19
  status(code: number) {
@@ -77,13 +78,14 @@ export type HttpQueries<T, Options extends { name?: string } = {}> = T & { __met
77
78
  * }
78
79
  * ```
79
80
  */
80
- export type HttpRegExp<T, Pattern extends string> = T & { __meta?: ['httpRegExp', Pattern] };
81
+ export type HttpRegExp<T, Pattern extends string | RegExp> = T & { __meta?: ['httpRegExp', Pattern] };
81
82
 
82
- export function getRegExp(type: Type): string | undefined {
83
+ export function getRegExp(type: Type): string | RegExp | undefined {
83
84
  const options = metaAnnotation.getForName(type, 'httpRegExp');
84
85
  if (!options || !options[0]) return;
85
- if (options[0].kind !== ReflectionKind.literal || 'string' !== typeof options[0].literal) return;
86
- return options[0].literal;
86
+ if (options[0].kind === ReflectionKind.literal && 'string' === typeof options[0].literal) return options[0].literal;
87
+ if (options[0].kind === ReflectionKind.literal && options[0].literal instanceof RegExp) return options[0].literal;
88
+ return;
87
89
  }
88
90
 
89
91
  export class RequestBuilder {
@@ -235,6 +237,34 @@ export class HttpRequest extends IncomingMessage {
235
237
 
236
238
  export class MemoryHttpResponse extends HttpResponse {
237
239
  public body: Buffer = Buffer.alloc(0);
240
+ public headers: {[name: string]: number | string | string[] | undefined} = Object.create(null);
241
+
242
+ setHeader(name: string, value: number | string | ReadonlyArray<string>): this {
243
+ this.headers[name] = value as any;
244
+ super.setHeader(name, value);
245
+ return this;
246
+ }
247
+
248
+ removeHeader(name: string) {
249
+ delete this.headers[name];
250
+ super.removeHeader(name);
251
+ }
252
+
253
+ getHeader(name: string) {
254
+ return this.headers[name];
255
+ }
256
+
257
+ getHeaders(): OutgoingHttpHeaders {
258
+ return this.headers;
259
+ }
260
+
261
+ writeHead(statusCode: number, headersOrReasonPhrase?: string | OutgoingHttpHeaders | OutgoingHttpHeader[], headers?: OutgoingHttpHeaders | OutgoingHttpHeader[]): this {
262
+ headers = typeof headersOrReasonPhrase === 'string' ? headers : headersOrReasonPhrase;
263
+ if (headers && !isArray(headers)) this.headers = headers;
264
+
265
+ if (typeof headersOrReasonPhrase === 'string') return super.writeHead(statusCode, headersOrReasonPhrase, headers);
266
+ return super.writeHead(statusCode, headers);
267
+ }
238
268
 
239
269
  get json(): any {
240
270
  const json = this.bodyString;
@@ -287,6 +317,5 @@ export class MemoryHttpResponse extends HttpResponse {
287
317
  this.body = Buffer.concat([this.body, chunk]);
288
318
  }
289
319
  return super.end(chunk, encoding, callback);
290
- // if (callback) callback();
291
320
  }
292
321
  }
package/src/module.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { HttpListener, HttpResultFormatter, httpWorkflow } from './http';
2
2
  import { HttpConfig } from './module.config';
3
3
  import { AppModule, createModule } from '@deepkit/app';
4
- import { Router } from './router';
4
+ import { HttpRouter, HttpRouterRegistry } from './router';
5
5
  import { HttpKernel } from './kernel';
6
6
  import { HttpRouterFilterResolver } from './filter';
7
7
  import { HttpControllers } from './controllers';
@@ -14,9 +14,10 @@ import { httpClass } from './decorator';
14
14
  export class HttpModule extends createModule({
15
15
  config: HttpConfig,
16
16
  providers: [
17
- Router,
17
+ HttpRouter,
18
18
  HttpKernel,
19
19
  HttpResultFormatter,
20
+ HttpRouterRegistry,
20
21
  HttpRouterFilterResolver,
21
22
  { provide: HttpResponse, scope: 'http' },
22
23
  { provide: HttpRequest, scope: 'http' },
@@ -29,7 +30,8 @@ export class HttpModule extends createModule({
29
30
  httpWorkflow
30
31
  ],
31
32
  exports: [
32
- Router,
33
+ HttpRouter,
34
+ HttpRouterRegistry,
33
35
  HttpKernel,
34
36
  HttpResultFormatter,
35
37
  HttpRouterFilterResolver,