@clairejs/server 3.16.19 → 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.
- package/README.md +5 -0
- package/dist/common/ControllerMetadata.d.ts +2 -2
- package/dist/common/request/endpoint-metadata.d.ts +12 -0
- package/dist/http/auth/AbstractHttpAuthorizer.d.ts +2 -2
- package/dist/http/common/HttpRequest.d.ts +1 -1
- package/dist/http/common/HttpRequest.js +7 -8
- package/dist/http/controller/AbstractHttpController.d.ts +2 -2
- package/dist/http/controller/AbstractHttpController.js +2 -2
- package/dist/http/controller/AbstractHttpMiddleware.d.ts +1 -1
- package/dist/http/controller/AbstractHttpRequestHandler.d.ts +8 -8
- package/dist/http/controller/AbstractHttpRequestHandler.js +14 -22
- package/dist/http/controller/CrudHttpController.d.ts +6 -6
- package/dist/http/controller/CrudHttpController.js +42 -84
- package/dist/http/controller/DefaultHttpRequestHandler.d.ts +2 -2
- package/dist/http/controller/DefaultHttpRequestHandler.js +9 -11
- package/dist/http/decorators.d.ts +5 -9
- package/dist/http/decorators.js +10 -22
- package/dist/http/repository/ICrudRepository.d.ts +3 -3
- package/dist/http/utils.d.ts +1 -3
- package/dist/http/utils.js +3 -20
- package/dist/index.d.ts +1 -6
- package/dist/index.js +1 -6
- package/dist/services/AbstractFileService.d.ts +2 -0
- package/dist/services/implementations/LocalFileService.d.ts +2 -0
- package/dist/services/implementations/LocalFileService.js +9 -0
- package/dist/services/implementations/S3FileService.d.ts +3 -1
- package/dist/services/implementations/S3FileService.js +22 -5
- package/dist/socket/AbstractServerSocketManager.d.ts +2 -2
- package/dist/socket/AbstractServerSocketManager.js +20 -70
- package/dist/socket/AbstractSocketController.d.ts +0 -1
- package/dist/socket/AbstractSocketController.js +0 -1
- package/dist/system/ClaireServer.d.ts +2 -3
- package/dist/system/ClaireServer.js +2 -10
- package/dist/system/ServerGlobalStore.d.ts +2 -2
- package/package.json +5 -5
- package/dist/common/request/EndpointMetadata.d.ts +0 -40
- package/dist/common/request/HttpEndpoint.d.ts +0 -7
- package/dist/common/request/HttpEndpoint.js +0 -1
- package/dist/common/request/MountedEndpointInfo.d.ts +0 -6
- package/dist/common/request/MountedEndpointInfo.js +0 -1
- package/dist/http/security/AbstractAccessCondition.d.ts +0 -7
- package/dist/http/security/AbstractAccessCondition.js +0 -2
- package/dist/http/security/access-conditions/FilterModelFieldAccessCondition.d.ts +0 -4
- package/dist/http/security/access-conditions/FilterModelFieldAccessCondition.js +0 -30
- package/dist/http/security/access-conditions/MaximumQueryLimit.d.ts +0 -8
- package/dist/http/security/access-conditions/MaximumQueryLimit.js +0 -31
- /package/dist/common/request/{EndpointMetadata.js → endpoint-metadata.js} +0 -0
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ObjectMetadata } from "@clairejs/core";
|
|
2
|
-
import { EndpointMetadata } from "./request/
|
|
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 {
|
|
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:
|
|
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/
|
|
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?.
|
|
50
|
-
this.params.data = validateData(this.params.data, this.endpointMetadata.
|
|
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?.
|
|
57
|
-
this.query.data = validateData(this.jsonParsing(this.query.data, this.endpointMetadata.
|
|
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.
|
|
65
|
-
|
|
66
|
-
this.endpointMetadata
|
|
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/
|
|
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.
|
|
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,
|
|
19
|
+
.map((f) => ({ ...f, apiGroup: controllerMetadata.permissionGroup }));
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EndpointMetadata } from "../../common/request/
|
|
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 {
|
|
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
|
|
15
|
-
getMountedEndpointInfo(): Promise<
|
|
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
|
-
|
|
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
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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.
|
|
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: ${
|
|
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,
|
|
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/
|
|
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 {
|
|
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 {
|
|
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.
|
|
52
|
-
endpointMetadata.
|
|
53
|
-
endpointMetadata.name =
|
|
54
|
-
endpointMetadata.
|
|
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.
|
|
53
|
+
endpointMetadata.bodyDto = getCreateManyBodyValidator(this.modelMetadata);
|
|
57
54
|
//-- response dto ------------------------------------
|
|
58
|
-
endpointMetadata.
|
|
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.
|
|
70
|
-
endpointMetadata.
|
|
71
|
-
endpointMetadata.
|
|
72
|
-
endpointMetadata.
|
|
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.
|
|
70
|
+
endpointMetadata.queryDto = getGetManyQueryValidator(this.modelMetadata);
|
|
75
71
|
//-- response dto ------------------------------------
|
|
76
|
-
endpointMetadata.
|
|
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.
|
|
91
|
-
endpointMetadata.
|
|
92
|
-
endpointMetadata.
|
|
93
|
-
endpointMetadata.
|
|
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.
|
|
86
|
+
endpointMetadata.queryDto = getUpdateManyQueryValidator(this.modelMetadata);
|
|
96
87
|
//-- body dto ------------------------------------
|
|
97
|
-
endpointMetadata.
|
|
88
|
+
endpointMetadata.bodyDto = getUpdateManyBodyValidator(this.modelMetadata);
|
|
98
89
|
//-- response dto ------------------------------------
|
|
99
|
-
endpointMetadata.
|
|
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.
|
|
116
|
-
endpointMetadata.
|
|
117
|
-
endpointMetadata.
|
|
118
|
-
endpointMetadata.
|
|
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.
|
|
101
|
+
endpointMetadata.queryDto = getUpdateRecordsQueryValidator();
|
|
121
102
|
//-- body dto ------------------------------------
|
|
122
|
-
endpointMetadata.
|
|
103
|
+
endpointMetadata.bodyDto = getUpdateRecordsBodyValidator(this.modelMetadata);
|
|
123
104
|
//-- response dto ------------------------------------
|
|
124
|
-
endpointMetadata.
|
|
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.
|
|
142
|
-
endpointMetadata.
|
|
143
|
-
endpointMetadata.
|
|
144
|
-
endpointMetadata.
|
|
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.
|
|
147
|
-
endpointMetadata.
|
|
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.
|
|
188
|
-
(e.name === endpoint.name && (!e.
|
|
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", [
|
|
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", [
|
|
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", [
|
|
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", [
|
|
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", [
|
|
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:
|
|
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.
|
|
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.
|
|
48
|
+
const response = await endpoint.controller[endpoint.handlerFunctionName](...params);
|
|
49
49
|
//-- validate response value against response dto
|
|
50
|
-
if (endpoint.
|
|
51
|
-
response.value = stripData(response.value, endpoint.
|
|
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.
|
|
65
|
-
match(info.
|
|
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
|
|
86
|
+
}, info);
|
|
87
87
|
const authInfo = await this.principalResolver.resolvePrincipal(request);
|
|
88
88
|
request.setAuthInfo(authInfo);
|
|
89
|
-
|
|
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
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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;
|
package/dist/http/decorators.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
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.
|
|
8
|
+
endpointMetadata.method = config.method;
|
|
9
9
|
//-- default to "/" if empty string is provided
|
|
10
|
-
endpointMetadata.
|
|
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.
|
|
21
|
+
endpointMetadata.responseDto = { id: "", primitiveType: DataType.STRING, fields: [] };
|
|
22
22
|
}
|
|
23
23
|
else if (responseClass === Number) {
|
|
24
|
-
endpointMetadata.
|
|
24
|
+
endpointMetadata.responseDto = { id: "", primitiveType: DataType.NUMBER, fields: [] };
|
|
25
25
|
}
|
|
26
26
|
else if (responseClass === Boolean) {
|
|
27
|
-
endpointMetadata.
|
|
27
|
+
endpointMetadata.responseDto = { id: "", primitiveType: DataType.BOOLEAN, fields: [] };
|
|
28
28
|
}
|
|
29
29
|
else {
|
|
30
|
-
endpointMetadata.
|
|
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.
|
|
38
|
+
endpointMetadata.bodyDto = getObjectMetadata(paramClasses[paramIndex]);
|
|
51
39
|
break;
|
|
52
40
|
case "params":
|
|
53
|
-
endpointMetadata.
|
|
41
|
+
endpointMetadata.paramDto = getObjectMetadata(paramClasses[paramIndex]);
|
|
54
42
|
break;
|
|
55
43
|
case "queries":
|
|
56
|
-
endpointMetadata.
|
|
44
|
+
endpointMetadata.queryDto = getObjectMetadata(paramClasses[paramIndex]);
|
|
57
45
|
break;
|
|
58
46
|
default:
|
|
59
47
|
break;
|