@clairejs/server 3.17.0 → 3.17.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 (42) hide show
  1. package/README.md +2 -1
  2. package/dist/common/ControllerMetadata.d.ts +2 -2
  3. package/dist/common/request/endpoint-metadata.d.ts +12 -0
  4. package/dist/http/auth/AbstractHttpAuthorizer.d.ts +2 -2
  5. package/dist/http/common/HttpRequest.d.ts +1 -1
  6. package/dist/http/common/HttpRequest.js +7 -8
  7. package/dist/http/controller/AbstractHttpController.d.ts +2 -2
  8. package/dist/http/controller/AbstractHttpController.js +2 -2
  9. package/dist/http/controller/AbstractHttpMiddleware.d.ts +1 -1
  10. package/dist/http/controller/AbstractHttpRequestHandler.d.ts +8 -8
  11. package/dist/http/controller/AbstractHttpRequestHandler.js +14 -22
  12. package/dist/http/controller/CrudHttpController.d.ts +6 -6
  13. package/dist/http/controller/CrudHttpController.js +42 -84
  14. package/dist/http/controller/DefaultHttpRequestHandler.d.ts +2 -2
  15. package/dist/http/controller/DefaultHttpRequestHandler.js +9 -11
  16. package/dist/http/decorators.d.ts +5 -9
  17. package/dist/http/decorators.js +10 -22
  18. package/dist/http/repository/ICrudRepository.d.ts +3 -3
  19. package/dist/http/utils.d.ts +1 -3
  20. package/dist/http/utils.js +3 -20
  21. package/dist/index.d.ts +1 -6
  22. package/dist/index.js +1 -6
  23. package/dist/socket/AbstractServerSocketManager.d.ts +2 -2
  24. package/dist/socket/AbstractServerSocketManager.js +20 -70
  25. package/dist/socket/AbstractSocketController.d.ts +0 -1
  26. package/dist/socket/AbstractSocketController.js +0 -1
  27. package/dist/system/ClaireServer.d.ts +2 -3
  28. package/dist/system/ClaireServer.js +2 -10
  29. package/dist/system/ServerGlobalStore.d.ts +2 -2
  30. package/package.json +5 -5
  31. package/dist/common/request/EndpointMetadata.d.ts +0 -40
  32. package/dist/common/request/HttpEndpoint.d.ts +0 -7
  33. package/dist/common/request/HttpEndpoint.js +0 -1
  34. package/dist/common/request/MountedEndpointInfo.d.ts +0 -6
  35. package/dist/common/request/MountedEndpointInfo.js +0 -1
  36. package/dist/http/security/AbstractAccessCondition.d.ts +0 -7
  37. package/dist/http/security/AbstractAccessCondition.js +0 -2
  38. package/dist/http/security/access-conditions/FilterModelFieldAccessCondition.d.ts +0 -4
  39. package/dist/http/security/access-conditions/FilterModelFieldAccessCondition.js +0 -30
  40. package/dist/http/security/access-conditions/MaximumQueryLimit.d.ts +0 -8
  41. package/dist/http/security/access-conditions/MaximumQueryLimit.js +0 -31
  42. /package/dist/common/request/{EndpointMetadata.js → endpoint-metadata.js} +0 -0
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  ## Change Log
2
2
 
3
- #### 3.17.0:
3
+ #### 3.17.1:
4
4
 
5
+ - refactor EndpointMetadata, remove MountedEndpointInfo
5
6
  - add putFile in AbstractFileService
6
7
 
7
8
  #### 3.16.19:
@@ -1,5 +1,5 @@
1
- import { ObjectMetadata } from "@clairejs/core";
2
- import { EndpointMetadata } from "./request/EndpointMetadata";
1
+ import { type ObjectMetadata } from "@clairejs/core";
2
+ import { type EndpointMetadata } from "./request/endpoint-metadata";
3
3
  export interface ControllerMetadata extends ObjectMetadata {
4
4
  fields: EndpointMetadata[];
5
5
  permissionGroup?: string;
@@ -0,0 +1,12 @@
1
+ import { type ApiInfo, type Constructor, type ObjectFieldMetadata } from "@clairejs/core";
2
+ import { type RequestDataSource } from "./types";
3
+ export interface EndpointMetadata extends ApiInfo, ObjectFieldMetadata {
4
+ controller: any;
5
+ handlerFunctionName: string;
6
+ params?: {
7
+ [index: number]: {
8
+ source?: RequestDataSource;
9
+ diClass?: Constructor<any>;
10
+ };
11
+ };
12
+ }
@@ -1,5 +1,5 @@
1
- import { MountedEndpointInfo } from "../../common/request/MountedEndpointInfo";
1
+ import { EndpointMetadata } from "../../common/request/endpoint-metadata";
2
2
  import { HttpRequest } from "../common/HttpRequest";
3
3
  export declare abstract class AbstractRequestAuthorizer {
4
- abstract authorize(req: HttpRequest, endpoint: MountedEndpointInfo): Promise<void>;
4
+ abstract authorize(req: HttpRequest, endpoint: EndpointMetadata): Promise<void>;
5
5
  }
@@ -1,5 +1,5 @@
1
1
  import { HttpMethod, SocketMethod } from "@clairejs/core";
2
- import { EndpointMetadata } from "../../common/request/EndpointMetadata";
2
+ import { EndpointMetadata } from "../../common/request/endpoint-metadata";
3
3
  import { IPrincipal } from "../../common/auth/IPrincipal";
4
4
  import { IServerSocket } from "../../socket/IServerSocket";
5
5
  export declare class HttpRequest {
@@ -46,25 +46,24 @@ export class HttpRequest {
46
46
  this.authInfo = authInfo;
47
47
  }
48
48
  getParams() {
49
- if (this.endpointMetadata?.paramsValidationDto && !this.params.validated) {
50
- this.params.data = validateData(this.params.data, this.endpointMetadata.paramsValidationDto);
49
+ if (this.endpointMetadata?.paramDto && !this.params.validated) {
50
+ this.params.data = validateData(this.params.data, this.endpointMetadata.paramDto);
51
51
  this.params.validated = true;
52
52
  }
53
53
  return this.params.data;
54
54
  }
55
55
  getQuery() {
56
- if (this.endpointMetadata?.queriesValidationDto && !this.query.validated) {
57
- this.query.data = validateData(this.jsonParsing(this.query.data, this.endpointMetadata.queriesValidationDto), this.endpointMetadata.queriesValidationDto);
56
+ if (this.endpointMetadata?.queryDto && !this.query.validated) {
57
+ this.query.data = validateData(this.jsonParsing(this.query.data, this.endpointMetadata.queryDto), this.endpointMetadata.queryDto);
58
58
  this.query.validated = true;
59
59
  }
60
60
  return this.query.data;
61
61
  }
62
62
  getBody() {
63
63
  if (this.endpointMetadata &&
64
- (this.endpointMetadata.httpMethod === HttpMethod.POST ||
65
- this.endpointMetadata.httpMethod === HttpMethod.PUT) &&
66
- this.endpointMetadata?.bodyValidationDto) {
67
- this.body.data = validateData(this.body.data, this.endpointMetadata.bodyValidationDto, false);
64
+ (this.endpointMetadata.method === HttpMethod.POST || this.endpointMetadata.method === HttpMethod.PUT) &&
65
+ this.endpointMetadata?.bodyDto) {
66
+ this.body.data = validateData(this.body.data, this.endpointMetadata.bodyDto, false);
68
67
  this.body.validated = true;
69
68
  }
70
69
  return this.body.data;
@@ -1,6 +1,6 @@
1
- import { ITransactionFactory } from "@clairejs/orm";
1
+ import { type ITransactionFactory } from "@clairejs/orm";
2
2
  import { AbstractController } from "../../common/AbstractController";
3
- import { EndpointMetadata } from "../../common/request/EndpointMetadata";
3
+ import { type EndpointMetadata } from "../../common/request/endpoint-metadata";
4
4
  export declare abstract class AbstractHttpController extends AbstractController {
5
5
  protected readonly databaseAdapter: ITransactionFactory;
6
6
  constructor(databaseAdapter: ITransactionFactory);
@@ -1,7 +1,7 @@
1
1
  import { getObjectMetadata } from "@clairejs/core";
2
2
  import { AbstractController } from "../../common/AbstractController";
3
3
  const isEndpoint = (metadata) => {
4
- return !!metadata.httpMethod || metadata.openAccess !== undefined || !!metadata.accessConditions;
4
+ return !!metadata.method || metadata.description !== undefined;
5
5
  };
6
6
  export class AbstractHttpController extends AbstractController {
7
7
  databaseAdapter;
@@ -16,6 +16,6 @@ export class AbstractHttpController extends AbstractController {
16
16
  }
17
17
  return controllerMetadata.fields
18
18
  .filter((f) => isEndpoint(f))
19
- .map((f) => ({ ...f, permissionGroup: controllerMetadata.permissionGroup }));
19
+ .map((f) => ({ ...f, apiGroup: controllerMetadata.permissionGroup }));
20
20
  }
21
21
  }
@@ -1,4 +1,4 @@
1
- import { EndpointMetadata } from "../../common/request/EndpointMetadata";
1
+ import { EndpointMetadata } from "../../common/request/endpoint-metadata";
2
2
  import { HttpRequest } from "../common/HttpRequest";
3
3
  import { HttpResponse } from "../common/HttpResponse";
4
4
  export declare abstract class AbstractHttpMiddleware {
@@ -1,18 +1,18 @@
1
1
  import { AbstractLogger } from "@clairejs/core";
2
- import { HttpData } from "../../common/request/HttpData";
3
- import { MountedEndpointInfo } from "../../common/request/MountedEndpointInfo";
4
- import { HttpResponse } from "../common/HttpResponse";
5
- import { ControllerMetadata } from "../../common/ControllerMetadata";
6
- import { CorsConfig } from "../security/cors";
7
- import { AbstractHttpMiddleware } from "./AbstractHttpMiddleware";
2
+ import { type HttpData } from "../../common/request/HttpData";
3
+ import { type EndpointMetadata } from "../../common/request/endpoint-metadata";
4
+ import { type HttpResponse } from "../common/HttpResponse";
5
+ import { type ControllerMetadata } from "../../common/ControllerMetadata";
6
+ import { type CorsConfig } from "../security/cors";
7
+ import { type AbstractHttpMiddleware } from "./AbstractHttpMiddleware";
8
8
  export declare abstract class AbstractHttpRequestHandler {
9
9
  readonly mountPoint: string;
10
10
  readonly logger: AbstractLogger;
11
11
  private mountedEndpointInfo?;
12
12
  corsConfig?: CorsConfig;
13
13
  constructor(mountPoint: string, logger: AbstractLogger);
14
- protected resolverMountPoint(controllerMetadata: ControllerMetadata, mappingUrls: string[]): string;
15
- getMountedEndpointInfo(): Promise<MountedEndpointInfo[]>;
14
+ protected resolveMountPoint(controllerMetadata: ControllerMetadata, mappingUrls: string[]): string;
15
+ getMountedEndpointInfo(): Promise<EndpointMetadata[]>;
16
16
  abstract getMiddleware(): Promise<AbstractHttpMiddleware[]>;
17
17
  abstract handle(httpData: HttpData): Promise<HttpResponse<any>>;
18
18
  }
@@ -1,5 +1,4 @@
1
- import { getObjectMetadata, getServiceProvider, SocketMethod } from "@clairejs/core";
2
- import { getEndpointId } from "../utils";
1
+ import { getObjectMetadata, getServiceProvider, HttpMethod, SocketMethod } from "@clairejs/core";
3
2
  import { AbstractHttpController } from "./AbstractHttpController";
4
3
  export class AbstractHttpRequestHandler {
5
4
  mountPoint;
@@ -10,7 +9,7 @@ export class AbstractHttpRequestHandler {
10
9
  this.mountPoint = mountPoint;
11
10
  this.logger = logger;
12
11
  }
13
- resolverMountPoint(controllerMetadata, mappingUrls) {
12
+ resolveMountPoint(controllerMetadata, mappingUrls) {
14
13
  if (!controllerMetadata) {
15
14
  return "";
16
15
  }
@@ -30,33 +29,26 @@ export class AbstractHttpRequestHandler {
30
29
  for (const controller of controllers) {
31
30
  const controllerMetadata = getObjectMetadata(controller.constructor);
32
31
  const allEndpointMetadata = controller.getEndpointMetadata();
33
- for (const endpointMetadata of allEndpointMetadata) {
34
- const endpoint = {
35
- mount: endpointMetadata.httpMethod === SocketMethod.MESSAGE
36
- ? endpointMetadata.url
37
- : this.resolverMountPoint(controllerMetadata, [
38
- this.mountPoint || "/",
39
- endpointMetadata.url,
40
- ]),
41
- httpMethod: endpointMetadata.httpMethod,
42
- controller: controller,
43
- handlerFunctionName: endpointMetadata.name,
32
+ result.push(...allEndpointMetadata.map((endpoint) => {
33
+ const mount = endpoint.method === SocketMethod.MESSAGE
34
+ ? endpoint.mount
35
+ : this.resolveMountPoint(controllerMetadata, [this.mountPoint || "/", endpoint.mount]);
36
+ return {
37
+ ...endpoint,
38
+ readOnly: endpoint.method === HttpMethod.GET,
39
+ mount,
40
+ id: `${endpoint.method}:${mount}`,
44
41
  };
45
- result.push({
46
- endpointMetadata,
47
- endpoint,
48
- });
49
- }
42
+ }));
50
43
  }
51
44
  //-- add to final to-be-mounted endpoints
52
45
  const mountedEndpointInfo = [];
53
46
  for (const endpointInfo of result) {
54
47
  //-- check overriden endpoints
55
- const overridingEndpoint = mountedEndpointInfo.find((info) => info.endpoint.mount === endpointInfo.endpoint.mount &&
56
- info.endpoint.httpMethod === endpointInfo.endpoint.httpMethod);
48
+ const overridingEndpoint = mountedEndpointInfo.find((info) => info.mount === endpointInfo.mount && info.method === endpointInfo.method);
57
49
  if (overridingEndpoint) {
58
50
  //-- if this endpoint has an other overriden endpoints then do not mount
59
- this.logger?.warn(`Implicit overriding endpoint: ${getEndpointId(overridingEndpoint.endpoint)} of ${overridingEndpoint.endpoint.controller?.constructor.name}:${overridingEndpoint.endpoint.handlerFunctionName}`, `Ignore ${getEndpointId(endpointInfo.endpoint)} of ${endpointInfo.endpoint.controller?.constructor.name}:${endpointInfo.endpoint.handlerFunctionName}`);
51
+ this.logger?.warn(`Implicit overriding endpoint: ${overridingEndpoint.method}:${overridingEndpoint.mount} of ${overridingEndpoint.controller?.constructor.name}:${overridingEndpoint.handlerFunctionName}`, `Ignore ${endpointInfo.method}:${endpointInfo.mount} of ${endpointInfo.controller?.constructor.name}:${endpointInfo.handlerFunctionName}`);
60
52
  }
61
53
  else {
62
54
  mountedEndpointInfo.push(endpointInfo);
@@ -1,10 +1,10 @@
1
- import { CreateManyResponseBody, GetManyResponseBody, UpdateManyResponse, Identifiable, Constructor, ModelMetadata } from "@clairejs/core";
2
- import { IQueryProvider, ITransactionFactory } from "@clairejs/orm";
3
- import { HttpRequest } from "../common/HttpRequest";
4
- import { HttpResponse } from "../common/HttpResponse";
5
- import { EndpointMetadata } from "../../common/request/EndpointMetadata";
1
+ import { type Constructor, type CreateManyResponseBody, type GetManyResponseBody, type Identifiable, type ModelMetadata, type UpdateManyResponse } from "@clairejs/core";
2
+ import { type IQueryProvider, type ITransactionFactory } from "@clairejs/orm";
3
+ import { type HttpRequest } from "../common/HttpRequest";
4
+ import { type HttpResponse } from "../common/HttpResponse";
5
+ import { type EndpointMetadata } from "../../common/request/endpoint-metadata";
6
6
  import { AbstractHttpController } from "./AbstractHttpController";
7
- import { ICrudRepository } from "../repository/ICrudRepository";
7
+ import { type ICrudRepository } from "../repository/ICrudRepository";
8
8
  export declare class CrudHttpController<T extends Identifiable> extends AbstractHttpController {
9
9
  protected readonly model: Constructor<T>;
10
10
  protected readonly crudRepository: ICrudRepository<T>;
@@ -10,15 +10,12 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
- import { getObjectMetadata, HttpMethod, getServiceProvider, leanData, getCreateManyBodyValidator, getCreateManyResponseValidator, getGetManyQueryValidator, getGetManyResponseValidator, getUpdateManyQueryValidator, getUpdateManyBodyValidator, getUpdateManyResponseValidator, uniqueReducer, omitData, getUpdateRecordsQueryValidator, getUpdateRecordsBodyValidator, } from "@clairejs/core";
13
+ import { deepMerge, getCreateManyBodyValidator, getCreateManyResponseValidator, getGetManyQueryValidator, getGetManyResponseValidator, getObjectMetadata, getServiceProvider, getUpdateManyBodyValidator, getUpdateManyQueryValidator, getUpdateManyResponseValidator, getUpdateRecordsBodyValidator, getUpdateRecordsQueryValidator, HttpMethod, omitData, } from "@clairejs/core";
14
14
  import { Transactional, PropagationMode } from "@clairejs/orm";
15
- import { HttpRequest } from "../common/HttpRequest";
16
15
  import { ResponseBuilder } from "../common/HttpResponse";
17
16
  import { AbstractPrincipalResolver } from "../../common/auth/AbstractPrincipalResolver";
18
- import { AccessCondition, ApiDescription, Raw } from "../decorators";
17
+ import { ApiDescription, Raw } from "../decorators";
19
18
  import { AbstractHttpController } from "./AbstractHttpController";
20
- import { MaximumQueryLimit } from "../security/access-conditions/MaximumQueryLimit";
21
- import { FilterModelFieldAccessCondition } from "../security/access-conditions/FilterModelFieldAccessCondition";
22
19
  export class CrudHttpController extends AbstractHttpController {
23
20
  model;
24
21
  crudRepository;
@@ -48,15 +45,14 @@ export class CrudHttpController extends AbstractHttpController {
48
45
  */
49
46
  createManyEndpoinMetadata() {
50
47
  const endpointMetadata = {};
51
- endpointMetadata.httpMethod = HttpMethod.POST;
52
- endpointMetadata.url = this.getMountedUrl();
53
- endpointMetadata.name = CrudHttpController.prototype.createMany.name;
54
- endpointMetadata.displayName = "createMany" + this.model.name;
48
+ endpointMetadata.method = HttpMethod.POST;
49
+ endpointMetadata.mount = this.getMountedUrl();
50
+ endpointMetadata.name = "createMany" + this.model.name;
51
+ endpointMetadata.handlerFunctionName = CrudHttpController.prototype.createMany.name;
55
52
  //-- body dto ------------------------------------
56
- endpointMetadata.bodyValidationDto = getCreateManyBodyValidator(this.modelMetadata);
53
+ endpointMetadata.bodyDto = getCreateManyBodyValidator(this.modelMetadata);
57
54
  //-- response dto ------------------------------------
58
- endpointMetadata.responseValidationDto = getCreateManyResponseValidator(this.modelMetadata);
59
- endpointMetadata.accessConditions = [];
55
+ endpointMetadata.responseDto = getCreateManyResponseValidator(this.modelMetadata);
60
56
  endpointMetadata.params = { 0: { source: "raw" } };
61
57
  return endpointMetadata;
62
58
  }
@@ -66,19 +62,14 @@ export class CrudHttpController extends AbstractHttpController {
66
62
  getManyEndpointMetadata() {
67
63
  //-- get all
68
64
  const endpointMetadata = {};
69
- endpointMetadata.httpMethod = HttpMethod.GET;
70
- endpointMetadata.url = this.getMountedUrl();
71
- endpointMetadata.name = CrudHttpController.prototype.getMany.name;
72
- endpointMetadata.displayName = "getAll" + this.model.name;
65
+ endpointMetadata.method = HttpMethod.GET;
66
+ endpointMetadata.mount = this.getMountedUrl();
67
+ endpointMetadata.handlerFunctionName = CrudHttpController.prototype.getMany.name;
68
+ endpointMetadata.name = "getAll" + this.model.name;
73
69
  //-- query dto
74
- endpointMetadata.queriesValidationDto = getGetManyQueryValidator(this.modelMetadata);
70
+ endpointMetadata.queryDto = getGetManyQueryValidator(this.modelMetadata);
75
71
  //-- response dto ------------------------------------
76
- endpointMetadata.responseValidationDto = getGetManyResponseValidator(this.modelMetadata);
77
- //-- access condition
78
- endpointMetadata.accessConditions = [
79
- FilterModelFieldAccessCondition(this.model, "model_projection", (request) => request.getQuery().projection),
80
- MaximumQueryLimit,
81
- ];
72
+ endpointMetadata.responseDto = getGetManyResponseValidator(this.modelMetadata);
82
73
  endpointMetadata.params = { 0: { source: "raw" } };
83
74
  return endpointMetadata;
84
75
  }
@@ -87,50 +78,31 @@ export class CrudHttpController extends AbstractHttpController {
87
78
  */
88
79
  updateManyEndpointMetadata() {
89
80
  const endpointMetadata = {};
90
- endpointMetadata.httpMethod = HttpMethod.PUT;
91
- endpointMetadata.url = this.getMountedUrl();
92
- endpointMetadata.name = CrudHttpController.prototype.updateMany.name;
93
- endpointMetadata.displayName = "update" + this.model.name;
81
+ endpointMetadata.method = HttpMethod.PUT;
82
+ endpointMetadata.mount = this.getMountedUrl();
83
+ endpointMetadata.handlerFunctionName = CrudHttpController.prototype.updateMany.name;
84
+ endpointMetadata.name = "update" + this.model.name;
94
85
  //-- queries dto ---------------------------------
95
- endpointMetadata.queriesValidationDto = getUpdateManyQueryValidator(this.modelMetadata);
86
+ endpointMetadata.queryDto = getUpdateManyQueryValidator(this.modelMetadata);
96
87
  //-- body dto ------------------------------------
97
- endpointMetadata.bodyValidationDto = getUpdateManyBodyValidator(this.modelMetadata);
88
+ endpointMetadata.bodyDto = getUpdateManyBodyValidator(this.modelMetadata);
98
89
  //-- response dto ------------------------------------
99
- endpointMetadata.responseValidationDto = getUpdateManyResponseValidator(this.modelMetadata);
100
- //-- access condition
101
- endpointMetadata.accessConditions = [
102
- FilterModelFieldAccessCondition(this.model, "restrict_update_fields", (request) => {
103
- const updateBody = request.getBody().update;
104
- if (!updateBody) {
105
- return [];
106
- }
107
- return Object.keys(leanData(updateBody));
108
- }),
109
- ];
90
+ endpointMetadata.responseDto = getUpdateManyResponseValidator(this.modelMetadata);
110
91
  endpointMetadata.params = { 0: { source: "raw" } };
111
92
  return endpointMetadata;
112
93
  }
113
94
  updateRecordsEndpointMetadata() {
114
95
  const endpointMetadata = {};
115
- endpointMetadata.httpMethod = HttpMethod.PUT;
116
- endpointMetadata.url = `${this.getMountedUrl()}/records`;
117
- endpointMetadata.name = CrudHttpController.prototype.updateRecords.name;
118
- endpointMetadata.displayName = "updateRecords" + this.model.name;
96
+ endpointMetadata.method = HttpMethod.PUT;
97
+ endpointMetadata.mount = `${this.getMountedUrl()}/records`;
98
+ endpointMetadata.handlerFunctionName = CrudHttpController.prototype.updateRecords.name;
99
+ endpointMetadata.name = "updateRecords" + this.model.name;
119
100
  //-- queries dto ---------------------------------
120
- endpointMetadata.queriesValidationDto = getUpdateRecordsQueryValidator();
101
+ endpointMetadata.queryDto = getUpdateRecordsQueryValidator();
121
102
  //-- body dto ------------------------------------
122
- endpointMetadata.bodyValidationDto = getUpdateRecordsBodyValidator(this.modelMetadata);
103
+ endpointMetadata.bodyDto = getUpdateRecordsBodyValidator(this.modelMetadata);
123
104
  //-- response dto ------------------------------------
124
- endpointMetadata.responseValidationDto = getUpdateManyResponseValidator(this.modelMetadata);
125
- //-- access condition
126
- endpointMetadata.accessConditions = [
127
- FilterModelFieldAccessCondition(this.model, "restrict_update_fields", (request) => {
128
- const updates = request.getBody();
129
- return updates.records
130
- .flatMap(({ id, ...update }) => Object.keys(leanData(update) || {}))
131
- .reduce(uniqueReducer, []);
132
- }),
133
- ];
105
+ endpointMetadata.responseDto = getUpdateManyResponseValidator(this.modelMetadata);
134
106
  return endpointMetadata;
135
107
  }
136
108
  /**
@@ -138,16 +110,14 @@ export class CrudHttpController extends AbstractHttpController {
138
110
  */
139
111
  deleteManyEndpoinMetadata() {
140
112
  const endpointMetadata = {};
141
- endpointMetadata.httpMethod = HttpMethod.DEL;
142
- endpointMetadata.url = this.getMountedUrl();
143
- endpointMetadata.name = CrudHttpController.prototype.deleteMany.name;
144
- endpointMetadata.displayName = "delete" + this.model.name;
113
+ endpointMetadata.method = HttpMethod.DEL;
114
+ endpointMetadata.mount = this.getMountedUrl();
115
+ endpointMetadata.handlerFunctionName = CrudHttpController.prototype.deleteMany.name;
116
+ endpointMetadata.name = "delete" + this.model.name;
145
117
  //-- queries ---------------------------------
146
- endpointMetadata.queriesValidationDto = getUpdateManyQueryValidator(this.modelMetadata);
147
- endpointMetadata.responseValidationDto = getUpdateManyResponseValidator(this.modelMetadata);
118
+ endpointMetadata.queryDto = getUpdateManyQueryValidator(this.modelMetadata);
119
+ endpointMetadata.responseDto = getUpdateManyResponseValidator(this.modelMetadata);
148
120
  endpointMetadata.params = { 0: { source: "raw" } };
149
- //-- access condition
150
- endpointMetadata.accessConditions = [];
151
121
  return endpointMetadata;
152
122
  }
153
123
  /**
@@ -184,17 +154,10 @@ export class CrudHttpController extends AbstractHttpController {
184
154
  }
185
155
  //-- merge with super
186
156
  for (const endpoint of crudEnpointMetadata) {
187
- const index = allEndpoints.findIndex((e) => (e.httpMethod === endpoint.httpMethod && e.url === endpoint.url) ||
188
- (e.name === endpoint.name && (!e.httpMethod || !e.url)));
157
+ const index = allEndpoints.findIndex((e) => (e.method === endpoint.method && e.mount === endpoint.mount) ||
158
+ (e.name === endpoint.name && (!e.method || !e.mount)));
189
159
  if (index >= 0) {
190
- allEndpoints[index] = {
191
- ...endpoint,
192
- ...allEndpoints[index],
193
- accessConditions: [
194
- ...(endpoint.accessConditions || []),
195
- ...(allEndpoints[index].accessConditions || []),
196
- ],
197
- };
160
+ deepMerge(allEndpoints[index], endpoint, true);
198
161
  }
199
162
  else {
200
163
  allEndpoints.push(endpoint);
@@ -260,44 +223,39 @@ export class CrudHttpController extends AbstractHttpController {
260
223
  __decorate([
261
224
  Transactional(PropagationMode.INHERIT_OR_CREATE),
262
225
  ApiDescription("Update records of this table."),
263
- AccessCondition([]),
264
226
  __param(0, Raw()),
265
227
  __metadata("design:type", Function),
266
- __metadata("design:paramtypes", [HttpRequest]),
228
+ __metadata("design:paramtypes", [Function]),
267
229
  __metadata("design:returntype", Promise)
268
230
  ], CrudHttpController.prototype, "updateRecords", null);
269
231
  __decorate([
270
232
  Transactional(PropagationMode.INHERIT_OR_CREATE),
271
233
  ApiDescription("Create records of this table."),
272
- AccessCondition([]),
273
234
  __param(0, Raw()),
274
235
  __metadata("design:type", Function),
275
- __metadata("design:paramtypes", [HttpRequest]),
236
+ __metadata("design:paramtypes", [Function]),
276
237
  __metadata("design:returntype", Promise)
277
238
  ], CrudHttpController.prototype, "createMany", null);
278
239
  __decorate([
279
- AccessCondition([]),
280
240
  ApiDescription("Get records of this table."),
281
241
  __param(0, Raw()),
282
242
  __metadata("design:type", Function),
283
- __metadata("design:paramtypes", [HttpRequest]),
243
+ __metadata("design:paramtypes", [Function]),
284
244
  __metadata("design:returntype", Promise)
285
245
  ], CrudHttpController.prototype, "getMany", null);
286
246
  __decorate([
287
247
  Transactional(PropagationMode.INHERIT_OR_CREATE),
288
248
  ApiDescription("Find and update records which match search condition."),
289
- AccessCondition([]),
290
249
  __param(0, Raw()),
291
250
  __metadata("design:type", Function),
292
- __metadata("design:paramtypes", [HttpRequest]),
251
+ __metadata("design:paramtypes", [Function]),
293
252
  __metadata("design:returntype", Promise)
294
253
  ], CrudHttpController.prototype, "updateMany", null);
295
254
  __decorate([
296
255
  Transactional(PropagationMode.INHERIT_OR_CREATE),
297
256
  ApiDescription("Find and remove records which match search condition."),
298
- AccessCondition([]),
299
257
  __param(0, Raw()),
300
258
  __metadata("design:type", Function),
301
- __metadata("design:paramtypes", [HttpRequest]),
259
+ __metadata("design:paramtypes", [Function]),
302
260
  __metadata("design:returntype", Promise)
303
261
  ], CrudHttpController.prototype, "deleteMany", null);
@@ -3,8 +3,8 @@ import { HttpResponse } from "../common/HttpResponse";
3
3
  import { AbstractPrincipalResolver } from "../../common/auth/AbstractPrincipalResolver";
4
4
  import { HttpRequest } from "../common/HttpRequest";
5
5
  import { AbstractRequestAuthorizer } from "../auth/AbstractHttpAuthorizer";
6
- import { MountedEndpointInfo } from "../../common/request/MountedEndpointInfo";
7
6
  import { HttpData } from "../../common/request/HttpData";
7
+ import { EndpointMetadata } from "../../common/request/endpoint-metadata";
8
8
  import { AbstractHttpMiddleware } from "./AbstractHttpMiddleware";
9
9
  import { AbstractHttpRequestHandler } from "./AbstractHttpRequestHandler";
10
10
  export declare class DefaultHttpRequestHandler extends AbstractHttpRequestHandler {
@@ -13,7 +13,7 @@ export declare class DefaultHttpRequestHandler extends AbstractHttpRequestHandle
13
13
  readonly principalResolver: AbstractPrincipalResolver;
14
14
  private _middleware;
15
15
  constructor(logger: AbstractLogger, authorizationProvider: AbstractRequestAuthorizer, principalResolver: AbstractPrincipalResolver);
16
- protected handleRequest(endpoint: MountedEndpointInfo, req: HttpRequest): Promise<HttpResponse<any>>;
16
+ protected handleRequest(endpoint: EndpointMetadata, req: HttpRequest): Promise<HttpResponse<any>>;
17
17
  exit(): void;
18
18
  private getResponse;
19
19
  handle(httpData: HttpData): Promise<HttpResponse<any>>;
@@ -31,7 +31,7 @@ let DefaultHttpRequestHandler = class DefaultHttpRequestHandler extends Abstract
31
31
  }
32
32
  async handleRequest(endpoint, req) {
33
33
  //-- supply correct order of params into handler
34
- const params = Object.values(endpoint.endpointMetadata.params || {}).map((p) => {
34
+ const params = Object.values(endpoint.params || {}).map((p) => {
35
35
  switch (p.source) {
36
36
  case "body":
37
37
  return req.getBody();
@@ -45,10 +45,10 @@ let DefaultHttpRequestHandler = class DefaultHttpRequestHandler extends Abstract
45
45
  return req;
46
46
  }
47
47
  });
48
- const response = await endpoint.endpoint.controller[endpoint.endpointMetadata.name](...params);
48
+ const response = await endpoint.controller[endpoint.handlerFunctionName](...params);
49
49
  //-- validate response value against response dto
50
- if (endpoint.endpointMetadata.responseValidationDto) {
51
- response.value = stripData(response.value, endpoint.endpointMetadata.responseValidationDto);
50
+ if (endpoint.responseDto) {
51
+ response.value = stripData(response.value, endpoint.responseDto);
52
52
  }
53
53
  return response;
54
54
  }
@@ -61,8 +61,8 @@ let DefaultHttpRequestHandler = class DefaultHttpRequestHandler extends Abstract
61
61
  let params = {};
62
62
  const mountedEndpointInfo = await this.getMountedEndpointInfo();
63
63
  const info = mountedEndpointInfo.find((info) => {
64
- const parsedParams = info.endpointMetadata.httpMethod === method &&
65
- match(info.endpointMetadata.url, { decode: decodeURIComponent })(result.pathname || "/");
64
+ const parsedParams = info.method === method &&
65
+ match(info.mount, { decode: decodeURIComponent })(result.pathname || "/");
66
66
  if (!parsedParams) {
67
67
  return false;
68
68
  }
@@ -83,15 +83,13 @@ let DefaultHttpRequestHandler = class DefaultHttpRequestHandler extends Abstract
83
83
  params: params.params,
84
84
  body: httpData.body,
85
85
  cookies: httpData.cookies,
86
- }, info.endpointMetadata);
86
+ }, info);
87
87
  const authInfo = await this.principalResolver.resolvePrincipal(request);
88
88
  request.setAuthInfo(authInfo);
89
- if (!info.endpointMetadata.openAccess) {
90
- await this.authorizationProvider.authorize(request, info);
91
- }
89
+ await this.authorizationProvider.authorize(request, info);
92
90
  const mws = await this.getMiddleware();
93
91
  for (const mw of mws) {
94
- const next = await mw.intercept(request, response, info.endpointMetadata);
92
+ const next = await mw.intercept(request, response, info);
95
93
  if (!next) {
96
94
  return response;
97
95
  }
@@ -1,9 +1,8 @@
1
- import { HttpMethod, Constructor, AbstractModel } from "@clairejs/core";
2
- import { AbstractHttpController } from "./controller/AbstractHttpController";
3
- import { AbstractAccessCondition } from "./security/AbstractAccessCondition";
4
- import { HttpResponse } from "./common/HttpResponse";
5
- import { UriMapperHandler } from "./file-upload/types";
6
- import { IPrincipal } from "../common/auth/IPrincipal";
1
+ import { type Constructor, AbstractModel, HttpMethod } from "@clairejs/core";
2
+ import { type UriMapperHandler } from "./file-upload/types";
3
+ import { type HttpResponse } from "./common/HttpResponse";
4
+ import { type IPrincipal } from "../common/auth/IPrincipal";
5
+ import { type AbstractHttpController } from "./controller/AbstractHttpController";
7
6
  type HttpFunctionMethod<T> = (...args: any[]) => Promise<HttpResponse<T>>;
8
7
  export declare const ApiDescription: (description: string) => (prototype: AbstractHttpController, propertyKey: string) => void;
9
8
  export declare const Endpoint: (config: {
@@ -16,9 +15,6 @@ export declare const Del: (url: string) => (prototype: AbstractHttpController, p
16
15
  export declare const Get: (url: string) => (prototype: AbstractHttpController, propertyKey: string, _descriptor: TypedPropertyDescriptor<HttpFunctionMethod<any>>) => void;
17
16
  export declare const Head: (url: string) => (prototype: AbstractHttpController, propertyKey: string, _descriptor: TypedPropertyDescriptor<HttpFunctionMethod<any>>) => void;
18
17
  export declare const ApiResponse: <T>(responseClass: Constructor<T>) => (prototype: AbstractHttpController, propertyKey: string, _descriptor: TypedPropertyDescriptor<HttpFunctionMethod<T>>) => void;
19
- export declare const OpenAccess: () => (prototype: AbstractHttpController, propertyKey: string) => void;
20
- export declare const TfaRequired: () => (prototype: AbstractHttpController, propertyKey: string) => void;
21
- export declare const AccessCondition: (conditions: Constructor<AbstractAccessCondition>[]) => (prototype: AbstractHttpController, propertyKey: string) => void;
22
18
  export declare const Body: () => (prototype: AbstractHttpController, propertyKey: string, paramIndex: number) => void;
23
19
  export declare const Params: () => (prototype: AbstractHttpController, propertyKey: string, paramIndex: number) => void;
24
20
  export declare const Queries: () => (prototype: AbstractHttpController, propertyKey: string, paramIndex: number) => void;
@@ -1,13 +1,13 @@
1
- import { initFieldMetadata, getObjectMetadata, HttpMethod, DataType, } from "@clairejs/core";
1
+ import { DataType, getObjectMetadata, HttpMethod, initFieldMetadata, } from "@clairejs/core";
2
2
  export const ApiDescription = (description) => (prototype, propertyKey) => {
3
3
  const endpointMetadata = initFieldMetadata(prototype, propertyKey);
4
4
  endpointMetadata.description = description;
5
5
  };
6
6
  export const Endpoint = (config) => (prototype, propertyKey) => {
7
7
  const endpointMetadata = initFieldMetadata(prototype, propertyKey);
8
- endpointMetadata.httpMethod = config.method;
8
+ endpointMetadata.method = config.method;
9
9
  //-- default to "/" if empty string is provided
10
- endpointMetadata.url = config.url || "/";
10
+ endpointMetadata.mount = config.url || "/";
11
11
  };
12
12
  const HttpMethodDecoratorFactory = (method) => (url) => (prototype, propertyKey, _descriptor) => Endpoint({ method, url })(prototype, propertyKey);
13
13
  export const Post = HttpMethodDecoratorFactory(HttpMethod.POST);
@@ -18,42 +18,30 @@ export const Head = HttpMethodDecoratorFactory(HttpMethod.HEAD);
18
18
  export const ApiResponse = (responseClass) => (prototype, propertyKey, _descriptor) => {
19
19
  const endpointMetadata = initFieldMetadata(prototype, propertyKey);
20
20
  if (responseClass === String) {
21
- endpointMetadata.responseValidationDto = { id: "", primitiveType: DataType.STRING, fields: [] };
21
+ endpointMetadata.responseDto = { id: "", primitiveType: DataType.STRING, fields: [] };
22
22
  }
23
23
  else if (responseClass === Number) {
24
- endpointMetadata.responseValidationDto = { id: "", primitiveType: DataType.NUMBER, fields: [] };
24
+ endpointMetadata.responseDto = { id: "", primitiveType: DataType.NUMBER, fields: [] };
25
25
  }
26
26
  else if (responseClass === Boolean) {
27
- endpointMetadata.responseValidationDto = { id: "", primitiveType: DataType.BOOLEAN, fields: [] };
27
+ endpointMetadata.responseDto = { id: "", primitiveType: DataType.BOOLEAN, fields: [] };
28
28
  }
29
29
  else {
30
- endpointMetadata.responseValidationDto = getObjectMetadata(responseClass);
30
+ endpointMetadata.responseDto = getObjectMetadata(responseClass);
31
31
  }
32
32
  };
33
- export const OpenAccess = () => (prototype, propertyKey) => {
34
- const endpointMetadata = initFieldMetadata(prototype, propertyKey);
35
- endpointMetadata.openAccess = true;
36
- };
37
- export const TfaRequired = () => (prototype, propertyKey) => {
38
- const endpointMetadata = initFieldMetadata(prototype, propertyKey);
39
- endpointMetadata.tfaRequired = true;
40
- };
41
- export const AccessCondition = (conditions) => (prototype, propertyKey) => {
42
- const endpointMetadata = initFieldMetadata(prototype, propertyKey);
43
- endpointMetadata.accessConditions = conditions;
44
- };
45
33
  const RequestDeco = (source) => (prototype, propertyKey, paramIndex) => {
46
34
  const endpointMetadata = initFieldMetadata(prototype, propertyKey);
47
35
  const paramClasses = Reflect.getMetadata("design:paramtypes", prototype, propertyKey) || [];
48
36
  switch (source) {
49
37
  case "body":
50
- endpointMetadata.bodyValidationDto = getObjectMetadata(paramClasses[paramIndex]);
38
+ endpointMetadata.bodyDto = getObjectMetadata(paramClasses[paramIndex]);
51
39
  break;
52
40
  case "params":
53
- endpointMetadata.paramsValidationDto = getObjectMetadata(paramClasses[paramIndex]);
41
+ endpointMetadata.paramDto = getObjectMetadata(paramClasses[paramIndex]);
54
42
  break;
55
43
  case "queries":
56
- endpointMetadata.queriesValidationDto = getObjectMetadata(paramClasses[paramIndex]);
44
+ endpointMetadata.queryDto = getObjectMetadata(paramClasses[paramIndex]);
57
45
  break;
58
46
  default:
59
47
  break;
@@ -1,6 +1,6 @@
1
- import { AbstractLogger, CreateManyRequestBody, CreateManyResponseBody, GetManyQueries, GetManyResponseBody, UpdateManyBody, UpdateManyQueries, UpdateManyResponse } from "@clairejs/core";
2
- import { IQueryProvider, ITransaction, QueryCondition } from "@clairejs/orm";
3
- import { IPrincipal } from "../../common/auth/IPrincipal";
1
+ import { type AbstractLogger, type CreateManyRequestBody, type CreateManyResponseBody, type GetManyQueries, type GetManyResponseBody, type UpdateManyBody, type UpdateManyQueries, type UpdateManyResponse } from "@clairejs/core";
2
+ import { type IQueryProvider, type ITransaction, type QueryCondition } from "@clairejs/orm";
3
+ import { type IPrincipal } from "../../common/auth/IPrincipal";
4
4
  export interface ICrudRepository<T> {
5
5
  createMany({ principal, body, tx, logger, }: {
6
6
  body: CreateManyRequestBody<T>;
@@ -1,4 +1,2 @@
1
- import { ApiInfoResponse } from "@clairejs/core";
2
- import { HttpEndpoint } from "../common/request/HttpEndpoint";
3
- export declare const getEndpointId: (endpoint: HttpEndpoint) => string;
1
+ import { type ApiInfoResponse } from "@clairejs/core";
4
2
  export declare const getApiInfo: () => Promise<ApiInfoResponse>;
@@ -1,9 +1,7 @@
1
- import { HttpMethod, getServiceProvider } from "@clairejs/core";
1
+ import { getServiceProvider, pickData, ApiInfo, getObjectMetadata } from "@clairejs/core";
2
2
  import { AbstractHttpRequestHandler } from "./controller/AbstractHttpRequestHandler";
3
3
  import { AbstractServerSocketManager } from "../socket/AbstractServerSocketManager";
4
- export const getEndpointId = (endpoint) => {
5
- return `${endpoint.httpMethod}:${endpoint.mount}`;
6
- };
4
+ const fields = (getObjectMetadata(ApiInfo)?.fields || []).map((f) => f.name);
7
5
  export const getApiInfo = async () => {
8
6
  const injector = getServiceProvider().getInjector();
9
7
  const httpHandler = injector.resolveOptional(AbstractHttpRequestHandler);
@@ -12,21 +10,6 @@ export const getApiInfo = async () => {
12
10
  const httpInfo = httpHandler ? await httpHandler.getMountedEndpointInfo() : [];
13
11
  const socketInfo = socketManager ? await socketManager.getMountedEndpointInfo() : [];
14
12
  return {
15
- permissions: [...httpInfo, ...socketInfo].map((endpointInfo) => ({
16
- id: getEndpointId(endpointInfo.endpoint),
17
- description: endpointInfo.endpointMetadata.description,
18
- name: endpointInfo.endpointMetadata.displayName || endpointInfo.endpointMetadata.name,
19
- openAccess: !!endpointInfo.endpointMetadata.openAccess,
20
- permissionGroup: endpointInfo.endpointMetadata.permissionGroup || "",
21
- accessConditions: endpointInfo.endpointMetadata.accessConditions?.map((ac) => injector.resolve(ac).getConditionMetadata()) || [],
22
- readOnly: endpointInfo.endpointMetadata.httpMethod === HttpMethod.GET,
23
- tfaRequired: !!endpointInfo.endpointMetadata.tfaRequired,
24
- method: endpointInfo.endpointMetadata.httpMethod,
25
- mount: endpointInfo.endpoint.mount || "",
26
- paramDto: endpointInfo.endpointMetadata.paramsValidationDto,
27
- queryDto: endpointInfo.endpointMetadata.queriesValidationDto,
28
- bodyDto: endpointInfo.endpointMetadata.bodyValidationDto,
29
- responseDto: endpointInfo.endpointMetadata.responseValidationDto,
30
- })),
13
+ apis: [...httpInfo, ...socketInfo].map((metadata) => pickData(metadata, fields)),
31
14
  };
32
15
  };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  export * from "./common/FileOperation";
2
2
  export * from "./common/auth/AbstractPrincipalResolver";
3
3
  export * from "./common/auth/IPrincipal";
4
- export * from "./common/request/MountedEndpointInfo";
5
- export * from "./common/request/HttpEndpoint";
6
- export * from "./common/request/EndpointMetadata";
4
+ export * from "./common/request/endpoint-metadata";
7
5
  export * from "./common/request/RequestOptions";
8
6
  export * from "./common/AbstractController";
9
7
  export * from "./common/ControllerMetadata";
@@ -17,9 +15,6 @@ export * from "./http/controller/CrudHttpController";
17
15
  export * from "./http/controller/AbstractHttpRequestHandler";
18
16
  export * from "./http/controller/AbstractHttpMiddleware";
19
17
  export * from "./http/security/cors";
20
- export * from "./http/security/AbstractAccessCondition";
21
- export * from "./http/security/access-conditions/FilterModelFieldAccessCondition";
22
- export * from "./http/security/access-conditions/MaximumQueryLimit";
23
18
  export * from "./http/auth/AbstractHttpAuthorizer";
24
19
  export * from "./http/repository/ModelRepository";
25
20
  export * from "./http/repository/DtoRepository";
package/dist/index.js CHANGED
@@ -2,9 +2,7 @@
2
2
  export * from "./common/FileOperation";
3
3
  export * from "./common/auth/AbstractPrincipalResolver";
4
4
  export * from "./common/auth/IPrincipal";
5
- export * from "./common/request/MountedEndpointInfo";
6
- export * from "./common/request/HttpEndpoint";
7
- export * from "./common/request/EndpointMetadata";
5
+ export * from "./common/request/endpoint-metadata";
8
6
  export * from "./common/request/RequestOptions";
9
7
  export * from "./common/AbstractController";
10
8
  export * from "./common/ControllerMetadata";
@@ -19,9 +17,6 @@ export * from "./http/controller/CrudHttpController";
19
17
  export * from "./http/controller/AbstractHttpRequestHandler";
20
18
  export * from "./http/controller/AbstractHttpMiddleware";
21
19
  export * from "./http/security/cors";
22
- export * from "./http/security/AbstractAccessCondition";
23
- export * from "./http/security/access-conditions/FilterModelFieldAccessCondition";
24
- export * from "./http/security/access-conditions/MaximumQueryLimit";
25
20
  export * from "./http/auth/AbstractHttpAuthorizer";
26
21
  export * from "./http/repository/ModelRepository";
27
22
  export * from "./http/repository/DtoRepository";
@@ -2,8 +2,8 @@ import { AbstractLogger, SocketMessage } from "@clairejs/core";
2
2
  import Redis from "ioredis";
3
3
  import { SocketData } from "../common/request/SocketData";
4
4
  import { IPrincipal } from "../common/auth/IPrincipal";
5
+ import { EndpointMetadata } from "../common/request/endpoint-metadata";
5
6
  import { AbstractPrincipalResolver } from "../common/auth/AbstractPrincipalResolver";
6
- import { MountedEndpointInfo } from "../common/request/MountedEndpointInfo";
7
7
  import { AbstractRequestAuthorizer } from "../http/auth/AbstractHttpAuthorizer";
8
8
  import { AbstractSocketConnectionHandler } from "./AbstractSocketConnectionHandler";
9
9
  import { AbstractServerSocket } from "./AbstractServerSocket";
@@ -42,5 +42,5 @@ export declare abstract class AbstractServerSocketManager {
42
42
  removeSocket(socketId: string, _physicRemove?: boolean): Promise<void>;
43
43
  abstract getById(socketId: string): Promise<AbstractServerSocket | undefined>;
44
44
  handle(socketData: SocketData): Promise<void>;
45
- getMountedEndpointInfo(): Promise<MountedEndpointInfo[]>;
45
+ getMountedEndpointInfo(): Promise<EndpointMetadata[]>;
46
46
  }
@@ -1,53 +1,10 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { AccessConditionValueType, DataType, Errors, getObjectMetadata, getServiceProvider, MessageType, Register, SocketMethod, } from "@clairejs/core";
8
- import { AbstractAccessCondition } from "../http/security/AbstractAccessCondition";
1
+ import { DataType, Errors, getServiceProvider, MessageType, SocketMethod, } from "@clairejs/core";
9
2
  import { HttpRequest } from "../http/common/HttpRequest";
10
3
  import { AbstractSocketConnectionHandler } from "./AbstractSocketConnectionHandler";
11
4
  import { AbstractSocketController } from "./AbstractSocketController";
12
5
  const SOCKET_ACTION_HEADER = "x-socket-action";
13
6
  const SOCKET_ACTION_READ = "read";
14
7
  const SOCKET_ACTION_WRITE = "write";
15
- let SocketReadCondition = class SocketReadCondition extends AbstractAccessCondition {
16
- async resolveConditionValue(request) {
17
- return request.headers[SOCKET_ACTION_HEADER] === SOCKET_ACTION_READ;
18
- }
19
- async validate(conditionValue) {
20
- return !!conditionValue;
21
- }
22
- getConditionMetadata() {
23
- return {
24
- name: "disable_write",
25
- description: "Disable send message to channel",
26
- valueType: AccessConditionValueType.BOOLEAN,
27
- };
28
- }
29
- };
30
- SocketReadCondition = __decorate([
31
- Register()
32
- ], SocketReadCondition);
33
- let SocketWriteCondition = class SocketWriteCondition extends AbstractAccessCondition {
34
- async resolveConditionValue(request) {
35
- return request.headers[SOCKET_ACTION_HEADER] === SOCKET_ACTION_WRITE;
36
- }
37
- async validate(conditionValue) {
38
- return !!conditionValue;
39
- }
40
- getConditionMetadata() {
41
- return {
42
- name: "disable_read",
43
- description: "Disable receive message from channel",
44
- valueType: AccessConditionValueType.BOOLEAN,
45
- };
46
- }
47
- };
48
- SocketWriteCondition = __decorate([
49
- Register()
50
- ], SocketWriteCondition);
51
8
  export class AbstractServerSocketManager {
52
9
  requireAuthentication;
53
10
  logger;
@@ -157,9 +114,9 @@ export class AbstractServerSocketManager {
157
114
  //-- notify all channels
158
115
  this.logger.debug("Notify channels");
159
116
  for (const channelInfo of socket.getChannelsInfo()) {
160
- const currentEndpoint = mountedEndpoints.find((e) => e.endpointMetadata.url === channelInfo.name);
117
+ const currentEndpoint = mountedEndpoints.find((e) => e.mount === channelInfo.name);
161
118
  if (currentEndpoint) {
162
- currentEndpoint.endpoint.controller.onChannelLeave(socket);
119
+ currentEndpoint.controller.onChannelLeave(socket);
163
120
  }
164
121
  }
165
122
  this.logger.debug("Calling disconnection handler");
@@ -206,7 +163,7 @@ export class AbstractServerSocketManager {
206
163
  let canSend = false;
207
164
  let canReceive = false;
208
165
  const mountedEndpoints = await this.getMountedEndpointInfo();
209
- const currentEndpoint = mountedEndpoints.find((e) => e.endpointMetadata.url === channel);
166
+ const currentEndpoint = mountedEndpoints.find((e) => e.mount === channel);
210
167
  if (!currentEndpoint) {
211
168
  continue;
212
169
  }
@@ -215,7 +172,7 @@ export class AbstractServerSocketManager {
215
172
  method: SocketMethod.MESSAGE,
216
173
  pathName: channel,
217
174
  headers: { [SOCKET_ACTION_HEADER]: SOCKET_ACTION_READ },
218
- }, currentEndpoint.endpointMetadata);
175
+ }, currentEndpoint);
219
176
  request.setAuthInfo(clientSocket.getAuthInfo());
220
177
  await this.requestAuthorizer.authorize(request, currentEndpoint);
221
178
  canReceive = true;
@@ -228,7 +185,7 @@ export class AbstractServerSocketManager {
228
185
  method: SocketMethod.MESSAGE,
229
186
  pathName: channel,
230
187
  headers: { [SOCKET_ACTION_HEADER]: SOCKET_ACTION_WRITE },
231
- }, currentEndpoint.endpointMetadata);
188
+ }, currentEndpoint);
232
189
  request.setAuthInfo(clientSocket.getAuthInfo());
233
190
  await this.requestAuthorizer.authorize(request, currentEndpoint);
234
191
  canSend = true;
@@ -258,7 +215,7 @@ export class AbstractServerSocketManager {
258
215
  type: MessageType.CHANNEL_JOIN,
259
216
  data: channelsInfo.map((c) => c.name),
260
217
  }),
261
- ...endpoints.map((endpoint) => endpoint.endpoint.controller.onChannelJoin(clientSocket)),
218
+ ...endpoints.map((endpoint) => endpoint.controller.onChannelJoin(clientSocket)),
262
219
  ]);
263
220
  }
264
221
  }
@@ -269,11 +226,11 @@ export class AbstractServerSocketManager {
269
226
  //-- remove channels from socket
270
227
  const mountedEndpoints = await this.getMountedEndpointInfo();
271
228
  Promise.all(channels.map((channel) => () => {
272
- const currentEndpoint = mountedEndpoints.find((e) => e.endpointMetadata.url === channel);
229
+ const currentEndpoint = mountedEndpoints.find((e) => e.mount === channel);
273
230
  if (!currentEndpoint) {
274
231
  return;
275
232
  }
276
- return currentEndpoint.endpoint.controller.onChannelLeave(clientSocket);
233
+ return currentEndpoint.controller.onChannelLeave(clientSocket);
277
234
  }));
278
235
  //-- remove socket from channels
279
236
  await this.removeSocketFromChannel(clientSocket.getId(), channels);
@@ -291,9 +248,9 @@ export class AbstractServerSocketManager {
291
248
  .find((info) => info.name === channel && info.clientToServerAllowed);
292
249
  if (allowed) {
293
250
  const mountedEndpoints = await this.getMountedEndpointInfo();
294
- const currentEndpoint = mountedEndpoints.find((e) => e.endpointMetadata.url === channel);
251
+ const currentEndpoint = mountedEndpoints.find((e) => e.mount === channel);
295
252
  if (currentEndpoint) {
296
- const result = await currentEndpoint.endpoint.controller.onMessage(clientSocket, data);
253
+ const result = await currentEndpoint.controller.onMessage(clientSocket, data);
297
254
  if (result !== false) {
298
255
  //-- broadcast
299
256
  this.logger.debug("broadcasting to channel", channel, data);
@@ -325,23 +282,16 @@ export class AbstractServerSocketManager {
325
282
  const socketController = injector.resolveMultiple(AbstractSocketController);
326
283
  await injector.initInstances();
327
284
  this.mountedEndpointInfo = socketController.map((controller) => {
328
- const controllerMetadata = getObjectMetadata(controller.constructor);
329
285
  return {
330
- endpoint: {
331
- httpMethod: SocketMethod.MESSAGE,
332
- mount: controller.getChannelName(),
333
- controller: controller,
334
- handlerFunctionName: controller.onMessage.name,
335
- },
336
- endpointMetadata: {
337
- httpMethod: SocketMethod.MESSAGE,
338
- description: "Send / Receive message to / from channel",
339
- permissionGroup: controllerMetadata.permissionGroup,
340
- dataType: DataType.OBJECT,
341
- url: controller.getChannelName(),
342
- name: controller.getChannelName(),
343
- accessConditions: [SocketReadCondition, SocketWriteCondition],
344
- },
286
+ id: `${SocketMethod.MESSAGE}:${controller.getChannelName()}`,
287
+ readOnly: false,
288
+ controller: socketController,
289
+ method: SocketMethod.MESSAGE,
290
+ mount: controller.getChannelName(),
291
+ handlerFunctionName: controller.onMessage.name,
292
+ description: "Send / Receive message to / from channel",
293
+ name: controller.getChannelName(),
294
+ dataType: DataType.OBJECT,
345
295
  };
346
296
  });
347
297
  }
@@ -7,7 +7,6 @@ export declare abstract class AbstractSocketController extends AbstractControlle
7
7
  /**
8
8
  * Handle the message sent to this channel
9
9
  * @param socket the socket sending message
10
- * @param data the data payload being sent
11
10
  * @returns return false to prevent message broadcast
12
11
  */
13
12
  onMessage(_socket: IServerSocket, _message: any): Promise<boolean | void>;
@@ -5,7 +5,6 @@ export class AbstractSocketController extends AbstractController {
5
5
  /**
6
6
  * Handle the message sent to this channel
7
7
  * @param socket the socket sending message
8
- * @param data the data payload being sent
9
8
  * @returns return false to prevent message broadcast
10
9
  */
11
10
  async onMessage(_socket, _message) { }
@@ -1,6 +1,6 @@
1
1
  import { AbstractLogger, ClaireApp } from "@clairejs/core";
2
- import { AbstractHttpRequestHandler } from "../http/controller/AbstractHttpRequestHandler";
3
- import { AbstractServerSocketManager } from "../socket/AbstractServerSocketManager";
2
+ import { type AbstractHttpRequestHandler } from "../http/controller/AbstractHttpRequestHandler";
3
+ import { type AbstractServerSocketManager } from "../socket/AbstractServerSocketManager";
4
4
  export declare class ClaireServer extends ClaireApp {
5
5
  protected readonly logger: AbstractLogger;
6
6
  protected readonly httpRequestHandler?: AbstractHttpRequestHandler | undefined;
@@ -8,6 +8,5 @@ export declare class ClaireServer extends ClaireApp {
8
8
  private booted;
9
9
  constructor(logger: AbstractLogger, httpRequestHandler?: AbstractHttpRequestHandler | undefined, socketManager?: AbstractServerSocketManager | undefined);
10
10
  init(): Promise<void>;
11
- exit(): void;
12
11
  private stop;
13
12
  }
@@ -9,9 +9,6 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  };
10
10
  import { AbstractLogger, ClaireApp, LogContext, getGlobalStore } from "@clairejs/core";
11
11
  import { ExitCode } from "../common/constants";
12
- import { AbstractHttpRequestHandler } from "../http/controller/AbstractHttpRequestHandler";
13
- import { AbstractServerSocketManager } from "../socket/AbstractServerSocketManager";
14
- import { getEndpointId } from "../http/utils";
15
12
  let ClaireServer = class ClaireServer extends ClaireApp {
16
13
  logger;
17
14
  httpRequestHandler;
@@ -38,7 +35,7 @@ let ClaireServer = class ClaireServer extends ClaireApp {
38
35
  }
39
36
  //-- save mounted endpoint info in server store to prevent circular dependency when resolving http request handler in controller
40
37
  for (const endpoint of mountedEndpointInfo) {
41
- this.logger.info(`Mounting: ${getEndpointId(endpoint.endpoint)}`);
38
+ this.logger.info(`Mounting: ${endpoint.method}:${endpoint.mount}`);
42
39
  }
43
40
  getGlobalStore().mountedEndpointInfo = mountedEndpointInfo;
44
41
  this.logger.debug("Claire server initing");
@@ -60,9 +57,6 @@ let ClaireServer = class ClaireServer extends ClaireApp {
60
57
  });
61
58
  this.booted = true;
62
59
  }
63
- exit() {
64
- super.exit();
65
- }
66
60
  stop(code) {
67
61
  this.logger.debug("Server is shutting down");
68
62
  this.exit();
@@ -71,8 +65,6 @@ let ClaireServer = class ClaireServer extends ClaireApp {
71
65
  };
72
66
  ClaireServer = __decorate([
73
67
  LogContext(),
74
- __metadata("design:paramtypes", [AbstractLogger,
75
- AbstractHttpRequestHandler,
76
- AbstractServerSocketManager])
68
+ __metadata("design:paramtypes", [AbstractLogger, Function, Function])
77
69
  ], ClaireServer);
78
70
  export { ClaireServer };
@@ -1,5 +1,5 @@
1
1
  import { CoreGlobalStore } from "@clairejs/core";
2
- import { MountedEndpointInfo } from "../common/request/MountedEndpointInfo";
2
+ import { EndpointMetadata } from "../common/request/endpoint-metadata";
3
3
  export interface ServerGlobalStore extends CoreGlobalStore {
4
- mountedEndpointInfo?: MountedEndpointInfo[];
4
+ mountedEndpointInfo?: EndpointMetadata[];
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clairejs/server",
3
- "version": "3.17.0",
3
+ "version": "3.17.1",
4
4
  "description": "Claire server NodeJs framework written in Typescript.",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
@@ -16,10 +16,12 @@
16
16
  "license": "ISC",
17
17
  "dependencies": {
18
18
  "aws-sdk": "^2.841.0",
19
+ "axios": "^0.21.4",
19
20
  "cookie-parser": "^1.4.6",
20
21
  "cors": "^2.8.5",
21
22
  "express": "^4.17.1",
22
23
  "express-fileupload": "^1.2.1",
24
+ "ioredis": "^5.2.0",
23
25
  "node-cron": "^3.0.1",
24
26
  "node-schedule": "^2.1.0",
25
27
  "parseurl": "^1.3.3",
@@ -28,12 +30,10 @@
28
30
  "randomstring": "^1.2.2",
29
31
  "redlock": "^5.0.0-beta.2",
30
32
  "reflect-metadata": "^0.1.13",
31
- "ws": "^7.5.5",
32
- "ioredis": "^5.2.0",
33
- "axios": "^0.21.4"
33
+ "ws": "^7.5.5"
34
34
  },
35
35
  "peerDependencies": {
36
- "@clairejs/core": "^3.6.1",
36
+ "@clairejs/core": "^3.7.1",
37
37
  "@clairejs/orm": "^3.11.0"
38
38
  },
39
39
  "devDependencies": {
@@ -1,40 +0,0 @@
1
- import { Constructor, DtoMetadata, HttpMethod, SocketMethod, ObjectFieldMetadata } from "@clairejs/core";
2
- import { RequestDataSource } from "./types";
3
- import { AbstractAccessCondition } from "../../http/security/AbstractAccessCondition";
4
- export interface EndpointMetadata extends ObjectFieldMetadata {
5
- /**
6
- * Basic HTTP information, name property is handler function name.
7
- */
8
- httpMethod: HttpMethod | SocketMethod;
9
- url: string;
10
- /**
11
- * User-friendly display name of endpoint.
12
- */
13
- displayName?: string;
14
- bodyValidationDto?: DtoMetadata;
15
- queriesValidationDto?: DtoMetadata;
16
- paramsValidationDto?: DtoMetadata;
17
- responseValidationDto?: DtoMetadata;
18
- params?: {
19
- [index: number]: {
20
- source?: RequestDataSource;
21
- diClass?: Constructor<any>;
22
- };
23
- };
24
- /**
25
- * This endpoint requires tfa
26
- */
27
- tfaRequired?: boolean;
28
- /**
29
- * Allow public access to this endpoint.
30
- */
31
- openAccess?: boolean;
32
- /**
33
- * Metadata of access condition to allow a conditional access to the endpoint.
34
- */
35
- accessConditions?: Constructor<AbstractAccessCondition>[];
36
- /**
37
- * Group of permission of this endpoint.
38
- */
39
- permissionGroup?: string;
40
- }
@@ -1,7 +0,0 @@
1
- import { HttpMethod, SocketMethod } from "@clairejs/core";
2
- export interface HttpEndpoint {
3
- mount?: string;
4
- httpMethod?: HttpMethod | SocketMethod;
5
- controller: any;
6
- handlerFunctionName: string;
7
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,6 +0,0 @@
1
- import { EndpointMetadata } from "./EndpointMetadata";
2
- import { HttpEndpoint } from "./HttpEndpoint";
3
- export interface MountedEndpointInfo {
4
- endpointMetadata: EndpointMetadata;
5
- endpoint: HttpEndpoint;
6
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,7 +0,0 @@
1
- import { AccessConditionMetadata } from "@clairejs/core";
2
- import { HttpRequest } from "../common/HttpRequest";
3
- export declare abstract class AbstractAccessCondition<T = any> {
4
- abstract resolveConditionValue(request: HttpRequest): Promise<T>;
5
- abstract validate(conditionValue: T, permittedConditionValue: any): Promise<boolean>;
6
- abstract getConditionMetadata(): AccessConditionMetadata;
7
- }
@@ -1,2 +0,0 @@
1
- export class AbstractAccessCondition {
2
- }
@@ -1,4 +0,0 @@
1
- import { Constructor } from "@clairejs/core";
2
- import { HttpRequest } from "../../common/HttpRequest";
3
- import { AbstractAccessCondition } from "../AbstractAccessCondition";
4
- export declare const FilterModelFieldAccessCondition: <T extends Constructor<any>>(model: T, name: string, requestedConditionValueResolver: (request: HttpRequest) => string[] | undefined) => Constructor<AbstractAccessCondition<string[] | undefined>>;
@@ -1,30 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { AccessConditionValueType, getObjectMetadata, Register, } from "@clairejs/core";
8
- import { AbstractAccessCondition } from "../AbstractAccessCondition";
9
- export const FilterModelFieldAccessCondition = (model, name, requestedConditionValueResolver) => {
10
- let _ = class _ extends AbstractAccessCondition {
11
- async resolveConditionValue(request) {
12
- return requestedConditionValueResolver(request);
13
- }
14
- getConditionMetadata() {
15
- return {
16
- name,
17
- valueType: AccessConditionValueType.CHOICES,
18
- valueConstraint: getObjectMetadata(model).fields.map((f) => f.name),
19
- };
20
- }
21
- async validate(requestedConditionValue, permittedConditionValue) {
22
- return (!!requestedConditionValue &&
23
- requestedConditionValue.every((value) => permittedConditionValue.includes(value)));
24
- }
25
- };
26
- _ = __decorate([
27
- Register()
28
- ], _);
29
- return _;
30
- };
@@ -1,8 +0,0 @@
1
- import { AccessConditionMetadata } from "@clairejs/core";
2
- import { HttpRequest } from "../../common/HttpRequest";
3
- import { AbstractAccessCondition } from "../AbstractAccessCondition";
4
- export declare class MaximumQueryLimit extends AbstractAccessCondition {
5
- resolveConditionValue(request: HttpRequest): Promise<any>;
6
- validate(conditionValue: number, permittedConditionValue: number): Promise<boolean>;
7
- getConditionMetadata(): AccessConditionMetadata;
8
- }
@@ -1,31 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { AccessConditionValueType, Register } from "@clairejs/core";
8
- import { AbstractAccessCondition } from "../AbstractAccessCondition";
9
- let MaximumQueryLimit = class MaximumQueryLimit extends AbstractAccessCondition {
10
- async resolveConditionValue(request) {
11
- let limit = request.getQuery().limit;
12
- if (limit) {
13
- limit = parseInt(limit);
14
- }
15
- return limit || 0;
16
- }
17
- async validate(conditionValue, permittedConditionValue) {
18
- return conditionValue > 0 && conditionValue <= permittedConditionValue;
19
- }
20
- getConditionMetadata() {
21
- return {
22
- name: "maximum_query_limit",
23
- valueType: AccessConditionValueType.NUMBER,
24
- valueConstraint: JSON.stringify({ min: 1 }),
25
- };
26
- }
27
- };
28
- MaximumQueryLimit = __decorate([
29
- Register()
30
- ], MaximumQueryLimit);
31
- export { MaximumQueryLimit };