@deepkit/http 1.0.1-alpha.71 → 1.0.1-alpha.72

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 +129 -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 +102 -24
  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 +5 -3
  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 +88 -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,12 @@ 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
+ console.log('generic response', result.content);
441
+ context.response.end(result.content);
442
+ }
443
+
399
444
  handleJSONResponse(result: JSONResponse, context: HttpResultFormatterContext): void {
400
445
  this.setContentTypeIfNotSetAlready(context.response, this.jsonContentType);
401
446
  context.response.writeHead(result._statusCode || 200, result._headers);
@@ -410,6 +455,10 @@ export class HttpResultFormatter {
410
455
  context.response.end(JSON.stringify(serialize(instance, route ? route.serializationOptions : undefined, serializerToUse, undefined, resolveReceiveType(classType))));
411
456
  }
412
457
 
458
+ handleStream(stream: stream.Readable, context: HttpResultFormatterContext): void {
459
+ stream.pipe(context.response);
460
+ }
461
+
413
462
  handleBinary(result: Uint8Array, context: HttpResultFormatterContext): void {
414
463
  context.response.end(result);
415
464
  }
@@ -428,10 +477,14 @@ export class HttpResultFormatter {
428
477
  this.handleResponse(context);
429
478
  } else if (result instanceof HtmlResponse) {
430
479
  this.handleHtmlResponse(result, context);
480
+ } else if (result instanceof stream.Readable) {
481
+ this.handleStream(result, context);
431
482
  } else if (result instanceof Uint8Array) {
432
483
  this.handleBinary(result, context);
433
484
  } else if (result instanceof JSONResponse) {
434
485
  this.handleJSONResponse(result, context);
486
+ } else if (result instanceof Response) {
487
+ this.handleGenericResponse(result, context);
435
488
  } else {
436
489
  if (isClassInstance(result)) {
437
490
  const classType = getClassTypeFromInstance(result);
@@ -448,7 +501,7 @@ export class HttpResultFormatter {
448
501
 
449
502
  export class HttpListener {
450
503
  constructor(
451
- protected router: Router,
504
+ protected router: HttpRouter,
452
505
  protected logger: LoggerInterface,
453
506
  protected resultFormatter: HttpResultFormatter,
454
507
  protected stopwatch?: Stopwatch,
@@ -584,18 +637,34 @@ export class HttpListener {
584
637
  if (event.sent) return;
585
638
  if (event.hasNext()) return;
586
639
 
587
- const controllerInstance = event.injectorContext.get(event.route.action.controller, event.route.action.module);
588
640
 
589
641
  const start = Date.now();
590
- const frame = this.stopwatch ? this.stopwatch.start(getClassName(event.route.action.controller) + '.' + event.route.action.methodName, FrameCategory.httpController) : undefined;
642
+ const stopWatchLabel = event.route.action.type === 'controller'
643
+ ? getClassName(event.route.action.controller) + '.' + event.route.action.methodName
644
+ : event.route.action.fn.name;
645
+
646
+ const frame = this.stopwatch ? this.stopwatch.start(stopWatchLabel, FrameCategory.httpController) : undefined;
591
647
  try {
592
- const method = controllerInstance[event.route.action.methodName];
593
- let result = await method.apply(controllerInstance, event.parameters);
648
+ let result: any;
649
+ if (event.route.action.type === 'controller') {
650
+ const controllerInstance = event.injectorContext.get(event.route.action.controller, event.route.action.module);
651
+ const method = controllerInstance[event.route.action.methodName];
652
+ result = await method.apply(controllerInstance, event.parameters);
653
+ } else {
654
+ result = await event.route.action.fn(...event.parameters);
655
+ }
594
656
 
595
657
  if (isElementStruct(result)) {
596
658
  const html = await getTemplateRender()(event.injectorContext.getRootInjector(), result, this.stopwatch ? this.stopwatch : undefined);
597
659
  result = new HtmlResponse(html, 200).header('Content-Type', 'text/html; charset=utf-8');
598
660
  }
661
+ if (result instanceof stream.Readable) {
662
+ const stream = result as stream.Readable;
663
+ await new Promise((resolve, reject) => {
664
+ stream.once('readable', resolve)
665
+ stream.once('error', reject)
666
+ })
667
+ }
599
668
  const responseEvent = new HttpResponseEvent(event.injectorContext, event.request, event.response, result, event.route);
600
669
  responseEvent.controllerActionTime = Date.now() - start;
601
670
  event.next('response', responseEvent);
@@ -671,7 +740,7 @@ export class HttpListener {
671
740
  if (event.response.headersSent) return;
672
741
  if (event.result === undefined || event.result === null) return;
673
742
 
674
- if (event.result instanceof HtmlResponse || event.result instanceof ServerResponse || event.result instanceof Redirect) {
743
+ if (event.result instanceof HtmlResponse || event.result instanceof ServerResponse || event.result instanceof Redirect || event.result instanceof stream.Readable) {
675
744
  // don't do anything
676
745
  } else if (event.result instanceof JSONResponse) {
677
746
  const schema = (event.result._statusCode && event.route.getSchemaForResponse(event.result._statusCode)) || event.route.returnType;
@@ -700,5 +769,9 @@ export class HttpListener {
700
769
  if (event.response.headersSent) return;
701
770
 
702
771
  this.resultFormatter.handle(event.result, event);
772
+ await new Promise((resolve, reject) => {
773
+ event.response.once('finish', resolve);
774
+ event.response.once('error', reject);
775
+ });
703
776
  }
704
777
  }
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,