@forklaunch/core 0.1.0 → 0.1.2
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/.prettierignore +2 -0
- package/.prettierrc +6 -0
- package/dist/cache/index.d.ts +3 -0
- package/dist/cache/index.js +20 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/interfaces/ttlCache.interface.d.ts +1 -1
- package/dist/cache/redisTtlCache.d.ts +3 -2
- package/dist/cache/redisTtlCache.js +2 -2
- package/dist/cache/redisTtlCache.js.map +1 -1
- package/dist/cache/types/{ttlCacheRecord.js → ttlCacheRecord.types.js} +1 -1
- package/dist/cache/types/ttlCacheRecord.types.js.map +1 -0
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/index.js +18 -0
- package/dist/controllers/index.js.map +1 -0
- package/dist/database/index.d.ts +1 -0
- package/dist/database/index.js +18 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/mikro/models/entities/base.entity.js +1 -1
- package/dist/entityMapper/index.d.ts +2 -0
- package/dist/entityMapper/index.js +19 -0
- package/dist/entityMapper/index.js.map +1 -0
- package/dist/entityMapper/interfaces/entityMapper.interface.d.ts +3 -3
- package/dist/entityMapper/models/baseEntityMapper.model.d.ts +23 -23
- package/dist/entityMapper/models/baseEntityMapper.model.js +17 -17
- package/dist/entityMapper/models/baseEntityMapper.model.js.map +1 -1
- package/dist/entityMapper/models/requestEntityMapper.model.d.ts +17 -23
- package/dist/entityMapper/models/requestEntityMapper.model.js +13 -19
- package/dist/entityMapper/models/requestEntityMapper.model.js.map +1 -1
- package/dist/entityMapper/models/responseEntityMapper.model.d.ts +15 -16
- package/dist/entityMapper/models/responseEntityMapper.model.js +8 -8
- package/dist/entityMapper/models/responseEntityMapper.model.js.map +1 -1
- package/dist/entityMapper/types/entityMapper.types.d.ts +3 -22
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +19 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/middlewares/index.d.ts +2 -0
- package/dist/http/middlewares/index.js +19 -0
- package/dist/http/middlewares/index.js.map +1 -0
- package/dist/http/middlewares/request.middleware.d.ts +11 -11
- package/dist/http/middlewares/request.middleware.js +32 -31
- package/dist/http/middlewares/request.middleware.js.map +1 -1
- package/dist/http/middlewares/response.middleware.d.ts +3 -2
- package/dist/http/middlewares/response.middleware.js +9 -6
- package/dist/http/middlewares/response.middleware.js.map +1 -1
- package/dist/http/types/api.types.d.ts +16 -13
- package/dist/http/types/index.d.ts +2 -0
- package/dist/http/types/index.js +19 -0
- package/dist/http/types/index.js.map +1 -0
- package/dist/http/types/primitive.types.d.ts +14 -13
- package/dist/index.d.ts +6 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +18 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/interfaces/baseService.d.ts +1 -1
- package/dist/tests/{dto.test.js → entityMapper.test.js} +10 -32
- package/dist/tests/entityMapper.test.js.map +1 -0
- package/dist/tests/http.middleware.test.d.ts +1 -0
- package/dist/tests/http.middleware.test.js +79 -0
- package/dist/tests/http.middleware.test.js.map +1 -0
- package/dist/tests/redisTtlCache.test.js +32 -15
- package/dist/tests/redisTtlCache.test.js.map +1 -1
- package/entityMapper/index.ts +2 -0
- package/entityMapper/interfaces/entityMapper.interface.ts +11 -11
- package/entityMapper/models/baseEntityMapper.model.ts +90 -73
- package/entityMapper/models/requestEntityMapper.model.ts +96 -76
- package/entityMapper/models/responseEntityMapper.model.ts +83 -62
- package/entityMapper/types/entityMapper.types.ts +6 -23
- package/http/index.ts +2 -0
- package/http/middlewares/index.ts +2 -0
- package/http/middlewares/request.middleware.ts +118 -62
- package/http/middlewares/response.middleware.ts +56 -30
- package/http/types/api.types.ts +43 -25
- package/http/types/index.ts +2 -0
- package/http/types/primitive.types.ts +65 -44
- package/index.ts +6 -5
- package/jest.config.ts +2 -2
- package/package.json +13 -4
- package/tests/entityMapper.test.ts +219 -0
- package/tests/http.middleware.test.ts +99 -0
- package/tests/redisTtlCache.test.ts +49 -29
- package/dist/cache/types/ttlCacheRecord.js.map +0 -1
- package/dist/tests/dto.test.js.map +0 -1
- package/tests/dto.test.ts +0 -235
- /package/dist/cache/types/{ttlCacheRecord.d.ts → ttlCacheRecord.types.d.ts} +0 -0
- /package/dist/tests/{dto.test.d.ts → entityMapper.test.d.ts} +0 -0
@@ -1,15 +1,26 @@
|
|
1
|
-
import { SchemaValidator } from
|
2
|
-
import * as jose from
|
3
|
-
import { v4 } from
|
4
|
-
import {
|
5
|
-
|
1
|
+
import { AnySchemaValidator, SchemaValidator } from '@forklaunch/validator';
|
2
|
+
import * as jose from 'jose';
|
3
|
+
import { v4 } from 'uuid';
|
4
|
+
import {
|
5
|
+
ForklaunchNextFunction,
|
6
|
+
ForklaunchRequest,
|
7
|
+
ForklaunchResponse
|
8
|
+
} from '../types/api.types';
|
9
|
+
import {
|
10
|
+
AuthMethod,
|
11
|
+
HttpContractDetails,
|
12
|
+
PathParamHttpContractDetails,
|
13
|
+
StringOnlyObject
|
14
|
+
} from '../types/primitive.types';
|
6
15
|
|
7
16
|
export function createRequestContext<
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
17
|
+
SV extends AnySchemaValidator,
|
18
|
+
Request extends ForklaunchRequest<SV>,
|
19
|
+
Response extends ForklaunchResponse,
|
20
|
+
NextFunction extends ForklaunchNextFunction
|
21
|
+
>(schemaValidator: SV) {
|
22
|
+
return (req: Request, res: Response, next?: NextFunction) => {
|
23
|
+
req.schemaValidator = schemaValidator as SchemaValidator;
|
13
24
|
|
14
25
|
let correlationId = v4();
|
15
26
|
|
@@ -21,29 +32,34 @@ export function createRequestContext<
|
|
21
32
|
|
22
33
|
req.context = {
|
23
34
|
correlationId: correlationId
|
24
|
-
}
|
35
|
+
};
|
25
36
|
|
26
37
|
if (next) {
|
27
38
|
next();
|
28
39
|
}
|
29
|
-
}
|
40
|
+
};
|
30
41
|
}
|
31
42
|
|
32
43
|
export function enrichRequestDetails<
|
33
|
-
SV extends
|
34
|
-
Request extends ForklaunchRequest<
|
35
|
-
Response extends ForklaunchResponse
|
44
|
+
SV extends AnySchemaValidator,
|
45
|
+
Request extends ForklaunchRequest<SV>,
|
46
|
+
Response extends ForklaunchResponse,
|
47
|
+
NextFunction extends ForklaunchNextFunction
|
36
48
|
>(contractDetails: PathParamHttpContractDetails<SV> | HttpContractDetails<SV>) {
|
37
|
-
return (req: Request, _res: Response, next?:
|
49
|
+
return (req: Request, _res: Response, next?: NextFunction) => {
|
38
50
|
req.contractDetails = contractDetails;
|
39
51
|
|
40
52
|
if (next) {
|
41
53
|
next();
|
42
54
|
}
|
43
|
-
}
|
55
|
+
};
|
44
56
|
}
|
45
57
|
|
46
|
-
export function preHandlerParse<SV extends
|
58
|
+
export function preHandlerParse<SV extends AnySchemaValidator>(
|
59
|
+
schemaValidator: SchemaValidator,
|
60
|
+
object: unknown,
|
61
|
+
schemaInput?: StringOnlyObject<SV>
|
62
|
+
) {
|
47
63
|
if (!schemaInput) {
|
48
64
|
return;
|
49
65
|
}
|
@@ -55,33 +71,42 @@ export function preHandlerParse<SV extends SchemaValidator>(schemaValidator: SV,
|
|
55
71
|
}
|
56
72
|
|
57
73
|
export function parseRequestParams<
|
58
|
-
|
59
|
-
|
74
|
+
SV extends AnySchemaValidator,
|
75
|
+
Request extends ForklaunchRequest<SV>,
|
76
|
+
Response extends ForklaunchResponse,
|
60
77
|
NextFunction extends ForklaunchNextFunction
|
61
78
|
>(req: Request, res: Response, next?: NextFunction) {
|
62
79
|
const params = req.contractDetails.params;
|
63
80
|
if (preHandlerParse(req.schemaValidator, req.params, params) === 400) {
|
64
|
-
res.status(400).send(
|
81
|
+
res.status(400).send('Invalid request parameters.');
|
65
82
|
if (next) {
|
66
|
-
next(new Error(
|
83
|
+
next(new Error('Invalid request parameters.'));
|
67
84
|
}
|
68
|
-
}
|
85
|
+
}
|
69
86
|
if (next) {
|
70
87
|
next();
|
71
88
|
}
|
72
89
|
}
|
73
90
|
|
74
91
|
export function parseRequestBody<
|
75
|
-
|
76
|
-
|
92
|
+
SV extends AnySchemaValidator,
|
93
|
+
Request extends ForklaunchRequest<SV>,
|
94
|
+
Response extends ForklaunchResponse,
|
77
95
|
NextFunction extends ForklaunchNextFunction
|
78
96
|
>(req: Request, res: Response, next?: NextFunction) {
|
79
97
|
if (req.headers['content-type'] === 'application/json') {
|
80
|
-
const body = (req.schemaValidator,
|
81
|
-
|
82
|
-
|
98
|
+
const body = (req.schemaValidator,
|
99
|
+
req.contractDetails as HttpContractDetails<SV>).body;
|
100
|
+
if (
|
101
|
+
preHandlerParse(
|
102
|
+
req.schemaValidator,
|
103
|
+
req.body,
|
104
|
+
body as StringOnlyObject<SV>
|
105
|
+
) === 400
|
106
|
+
) {
|
107
|
+
res.status(400).send('Invalid request body.');
|
83
108
|
if (next) {
|
84
|
-
next(new Error(
|
109
|
+
next(new Error('Invalid request body.'));
|
85
110
|
}
|
86
111
|
}
|
87
112
|
}
|
@@ -91,15 +116,16 @@ export function parseRequestBody<
|
|
91
116
|
}
|
92
117
|
|
93
118
|
export function parseRequestHeaders<
|
94
|
-
|
95
|
-
|
119
|
+
SV extends AnySchemaValidator,
|
120
|
+
Request extends ForklaunchRequest<SV>,
|
121
|
+
Response extends ForklaunchResponse,
|
96
122
|
NextFunction extends ForklaunchNextFunction
|
97
|
-
>
|
123
|
+
>(req: Request, res: Response, next?: NextFunction) {
|
98
124
|
const headers = req.contractDetails.requestHeaders;
|
99
125
|
if (preHandlerParse(req.schemaValidator, req.headers, headers) === 400) {
|
100
|
-
res.status(400).send(
|
126
|
+
res.status(400).send('Invalid request headers.');
|
101
127
|
if (next) {
|
102
|
-
next(new Error(
|
128
|
+
next(new Error('Invalid request headers.'));
|
103
129
|
}
|
104
130
|
}
|
105
131
|
if (next) {
|
@@ -108,15 +134,16 @@ export function parseRequestHeaders<
|
|
108
134
|
}
|
109
135
|
|
110
136
|
export function parseRequestQuery<
|
111
|
-
|
112
|
-
|
137
|
+
SV extends AnySchemaValidator,
|
138
|
+
Request extends ForklaunchRequest<SV>,
|
139
|
+
Response extends ForklaunchResponse,
|
113
140
|
NextFunction extends ForklaunchNextFunction
|
114
141
|
>(req: Request, res: Response, next?: NextFunction) {
|
115
142
|
const query = req.contractDetails.query;
|
116
|
-
if (preHandlerParse(req.query, query) === 400) {
|
117
|
-
res.status(400).send(
|
143
|
+
if (preHandlerParse(req.schemaValidator, req.query, query) === 400) {
|
144
|
+
res.status(400).send('Invalid request query.');
|
118
145
|
if (next) {
|
119
|
-
next(new Error(
|
146
|
+
next(new Error('Invalid request query.'));
|
120
147
|
}
|
121
148
|
}
|
122
149
|
if (next) {
|
@@ -124,43 +151,61 @@ export function parseRequestQuery<
|
|
124
151
|
}
|
125
152
|
}
|
126
153
|
|
127
|
-
async function checkAuthorizationToken(
|
154
|
+
async function checkAuthorizationToken(
|
155
|
+
authorizationMethod?: AuthMethod,
|
156
|
+
authorizationString?: string
|
157
|
+
): Promise<[401 | 403, string] | string | undefined> {
|
128
158
|
if (!authorizationString) {
|
129
|
-
return [401,
|
159
|
+
return [401, 'No Authorization token provided.'];
|
130
160
|
}
|
131
161
|
switch (authorizationMethod) {
|
132
162
|
case 'jwt': {
|
133
163
|
if (!authorizationString.startsWith('Bearer ')) {
|
134
|
-
return [401,
|
164
|
+
return [401, 'Invalid Authorization token format.'];
|
135
165
|
}
|
136
166
|
try {
|
137
|
-
const decodedJwt = await jose.jwtVerify(
|
167
|
+
const decodedJwt = await jose.jwtVerify(
|
168
|
+
authorizationString.split(' ')[1],
|
169
|
+
new TextEncoder().encode(
|
170
|
+
process.env.JWT_SECRET || 'your-256-bit-secret'
|
171
|
+
)
|
172
|
+
);
|
138
173
|
return decodedJwt.payload.iss;
|
139
|
-
} catch(error) {
|
174
|
+
} catch (error) {
|
140
175
|
console.error(error);
|
141
|
-
return [403,
|
176
|
+
return [403, 'Invalid Authorization token.'];
|
142
177
|
}
|
143
178
|
}
|
144
179
|
default:
|
145
|
-
return [401,
|
180
|
+
return [401, 'Invalid Authorization method.'];
|
146
181
|
}
|
147
182
|
}
|
148
183
|
|
149
|
-
function mapRoles(
|
184
|
+
function mapRoles(
|
185
|
+
authorizationType?: AuthMethod,
|
186
|
+
authorizationToken?: string
|
187
|
+
): string[] {
|
150
188
|
return [];
|
151
189
|
}
|
152
|
-
function mapPermissions(
|
190
|
+
function mapPermissions(
|
191
|
+
authorizationType?: AuthMethod,
|
192
|
+
authorizationToken?: string
|
193
|
+
): string[] {
|
153
194
|
return [];
|
154
195
|
}
|
155
196
|
|
156
197
|
export async function parseRequestAuth<
|
157
|
-
|
158
|
-
|
198
|
+
SV extends AnySchemaValidator,
|
199
|
+
Request extends ForklaunchRequest<SV>,
|
200
|
+
Response extends ForklaunchResponse,
|
159
201
|
NextFunction extends ForklaunchNextFunction
|
160
202
|
>(req: Request, res: Response, next?: NextFunction) {
|
161
203
|
const auth = req.contractDetails.auth;
|
162
204
|
if (auth) {
|
163
|
-
const errorAndMessage = await checkAuthorizationToken(
|
205
|
+
const errorAndMessage = await checkAuthorizationToken(
|
206
|
+
auth.method,
|
207
|
+
req.headers.authorization
|
208
|
+
);
|
164
209
|
if (Array.isArray(errorAndMessage)) {
|
165
210
|
res.status(errorAndMessage[0]).send(errorAndMessage[1]);
|
166
211
|
if (next) {
|
@@ -169,33 +214,44 @@ export async function parseRequestAuth<
|
|
169
214
|
}
|
170
215
|
|
171
216
|
// TODO: Implement role and permission checking
|
172
|
-
const permissionSlugs
|
217
|
+
const permissionSlugs = mapPermissions(
|
218
|
+
auth.method,
|
219
|
+
req.headers.authorization
|
220
|
+
);
|
173
221
|
const roles = mapRoles(auth.method, req.headers.authorization);
|
174
222
|
|
175
|
-
const permissionErrorMessage =
|
176
|
-
|
223
|
+
const permissionErrorMessage =
|
224
|
+
'User does not have sufficient permissions to perform action.';
|
225
|
+
const roleErrorMessage =
|
226
|
+
'User does not have correct role to perform action.';
|
177
227
|
|
178
228
|
// this is wrong, we need to check if any of the user's permissions are in the allowed permissions, while checking that any of the permissions is not in the forbidden slugs
|
179
229
|
// currently this is checking if any of the user's permissions are NOT in the allowed permissions
|
180
|
-
permissionSlugs.forEach(permissionSlug => {
|
181
|
-
if (
|
230
|
+
permissionSlugs.forEach((permissionSlug) => {
|
231
|
+
if (
|
232
|
+
!req.contractDetails.auth?.allowedSlugs?.has(permissionSlug) ||
|
233
|
+
req.contractDetails.auth?.forbiddenSlugs?.has(permissionSlug)
|
234
|
+
) {
|
182
235
|
res.status(403).send(permissionErrorMessage);
|
183
236
|
if (next) {
|
184
237
|
next(new Error(permissionErrorMessage));
|
185
238
|
}
|
186
|
-
}
|
239
|
+
}
|
187
240
|
});
|
188
|
-
roles.forEach(role => {
|
189
|
-
if (
|
241
|
+
roles.forEach((role) => {
|
242
|
+
if (
|
243
|
+
!req.contractDetails.auth?.allowedRoles?.has(role) ||
|
244
|
+
req.contractDetails.auth?.forbiddenRoles?.has(role)
|
245
|
+
) {
|
190
246
|
res.status(403).send(roleErrorMessage);
|
191
247
|
if (next) {
|
192
248
|
next(new Error(roleErrorMessage));
|
193
249
|
}
|
194
|
-
}
|
250
|
+
}
|
195
251
|
});
|
196
252
|
}
|
197
|
-
|
253
|
+
|
198
254
|
// if (next) {
|
199
255
|
// next();
|
200
256
|
// }
|
201
|
-
}
|
257
|
+
}
|
@@ -1,37 +1,63 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
|
1
|
+
import { AnySchemaValidator } from '@forklaunch/validator';
|
2
|
+
import {
|
3
|
+
ForklaunchNextFunction,
|
4
|
+
ForklaunchRequest,
|
5
|
+
ForklaunchResponse
|
6
|
+
} from '../types/api.types';
|
7
|
+
import { HttpContractDetails } from '../types/primitive.types';
|
4
8
|
|
5
|
-
function checkAnyValidation<SV extends
|
6
|
-
|
9
|
+
function checkAnyValidation<SV extends AnySchemaValidator>(
|
10
|
+
contractDetails: HttpContractDetails<SV>
|
11
|
+
) {
|
12
|
+
return (
|
13
|
+
contractDetails.body ||
|
14
|
+
contractDetails.params ||
|
15
|
+
contractDetails.requestHeaders ||
|
16
|
+
contractDetails.query
|
17
|
+
);
|
7
18
|
}
|
8
19
|
|
9
20
|
export function parseResponse<
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
(req.contractDetails.auth && (res.statusCode === 401 || res.statusCode === 403))
|
22
|
-
) {
|
23
|
-
return;
|
24
|
-
}
|
25
|
-
if (!req.contractDetails.responses.hasOwnProperty(res.statusCode)) {
|
26
|
-
if (next) {
|
27
|
-
next(new Error(`Response code ${res.statusCode} not defined in contract.`));
|
28
|
-
};
|
29
|
-
}
|
30
|
-
|
31
|
-
const schema = req.schemaValidator.schemify(req.contractDetails.responses[res.statusCode]);
|
32
|
-
req.schemaValidator.validate(schema, res.bodyData);
|
21
|
+
SV extends AnySchemaValidator,
|
22
|
+
Request extends ForklaunchRequest<SV>,
|
23
|
+
Response extends ForklaunchResponse,
|
24
|
+
NextFunction extends ForklaunchNextFunction
|
25
|
+
>(req: Request, res: Response, next?: NextFunction) {
|
26
|
+
if (req.contractDetails.responseHeaders) {
|
27
|
+
const schema = req.schemaValidator.schemify(
|
28
|
+
req.contractDetails.responseHeaders
|
29
|
+
);
|
30
|
+
req.schemaValidator.validate(schema, res.getHeaders());
|
31
|
+
}
|
33
32
|
|
33
|
+
if (
|
34
|
+
res.statusCode === 500 ||
|
35
|
+
(checkAnyValidation(req.contractDetails) && res.statusCode === 400) ||
|
36
|
+
(req.contractDetails.auth &&
|
37
|
+
(res.statusCode === 401 || res.statusCode === 403))
|
38
|
+
) {
|
39
|
+
req.schemaValidator.validate(req.schemaValidator.string, res.bodyData);
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
if (
|
43
|
+
Object.prototype.hasOwnProperty.call(
|
44
|
+
!req.contractDetails.responses,
|
45
|
+
res.statusCode
|
46
|
+
)
|
47
|
+
) {
|
34
48
|
if (next) {
|
35
|
-
|
49
|
+
next(
|
50
|
+
new Error(`Response code ${res.statusCode} not defined in contract.`)
|
51
|
+
);
|
36
52
|
}
|
37
|
-
}
|
53
|
+
}
|
54
|
+
|
55
|
+
const schema = req.schemaValidator.schemify(
|
56
|
+
req.contractDetails.responses[res.statusCode]
|
57
|
+
);
|
58
|
+
req.schemaValidator.validate(schema, res.bodyData);
|
59
|
+
|
60
|
+
if (next) {
|
61
|
+
next();
|
62
|
+
}
|
63
|
+
}
|
package/http/types/api.types.ts
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
-
import { Prettify } from
|
2
|
-
import {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
import {
|
7
|
-
import {
|
1
|
+
import { Prettify } from '@forklaunch/common';
|
2
|
+
import {
|
3
|
+
AnySchemaValidator,
|
4
|
+
Schema
|
5
|
+
} from '@forklaunch/validator';
|
6
|
+
import { IdiomaticSchema, SchemaValidator } from '@forklaunch/validator/types';
|
7
|
+
import { IncomingHttpHeaders, OutgoingHttpHeader } from 'http';
|
8
|
+
import { ParsedQs } from 'qs';
|
9
|
+
import {
|
10
|
+
HttpContractDetails,
|
11
|
+
ParamsDictionary,
|
12
|
+
PathParamHttpContractDetails
|
13
|
+
} from './primitive.types';
|
8
14
|
|
9
15
|
export interface RequestContext {
|
10
16
|
correlationId: string;
|
@@ -12,15 +18,15 @@ export interface RequestContext {
|
|
12
18
|
}
|
13
19
|
|
14
20
|
export interface ForklaunchRequest<
|
15
|
-
SV extends
|
21
|
+
SV extends AnySchemaValidator,
|
16
22
|
P = ParamsDictionary,
|
17
|
-
ReqBody =
|
23
|
+
ReqBody = unknown,
|
18
24
|
ReqQuery = ParsedQs,
|
19
|
-
Headers = IncomingHttpHeaders
|
25
|
+
Headers = IncomingHttpHeaders
|
20
26
|
> {
|
21
27
|
context: Prettify<RequestContext>;
|
22
28
|
contractDetails: HttpContractDetails<SV> | PathParamHttpContractDetails<SV>;
|
23
|
-
schemaValidator:
|
29
|
+
schemaValidator: SchemaValidator;
|
24
30
|
|
25
31
|
params: P;
|
26
32
|
headers: Headers;
|
@@ -29,37 +35,49 @@ export interface ForklaunchRequest<
|
|
29
35
|
}
|
30
36
|
|
31
37
|
export interface ForklaunchResponse<
|
32
|
-
ResBody =
|
33
|
-
|
38
|
+
ResBody = {
|
39
|
+
400: unknown;
|
40
|
+
401: unknown;
|
41
|
+
403: unknown;
|
42
|
+
500: unknown;
|
43
|
+
},
|
44
|
+
StatusCode = number
|
34
45
|
> {
|
35
46
|
bodyData: unknown;
|
36
47
|
statusCode: StatusCode;
|
37
48
|
corked: boolean;
|
38
|
-
|
49
|
+
|
39
50
|
getHeaders: () => OutgoingHttpHeader;
|
40
51
|
setHeader: (key: string, value: string) => void;
|
41
52
|
status: {
|
42
53
|
<U extends keyof ResBody>(code: U): ForklaunchResponse<ResBody[U], U>;
|
43
|
-
<U extends keyof ResBody>(
|
54
|
+
<U extends keyof ResBody>(
|
55
|
+
code: U,
|
56
|
+
message?: string
|
57
|
+
): ForklaunchResponse<ResBody[U], U>;
|
44
58
|
<U extends 500>(code: U): ForklaunchResponse<string, U>;
|
45
59
|
<U extends 500>(code: U, message?: string): ForklaunchResponse<string, U>;
|
46
|
-
}
|
60
|
+
};
|
47
61
|
send: {
|
48
62
|
<T>(body?: ResBody, close_connection?: boolean): T;
|
49
63
|
<T>(body?: ResBody): T;
|
50
|
-
}
|
64
|
+
};
|
51
65
|
json: {
|
52
66
|
(body?: ResBody): boolean;
|
53
67
|
<T>(body?: ResBody): T;
|
54
|
-
}
|
68
|
+
};
|
55
69
|
jsonp: {
|
56
70
|
(body?: ResBody): boolean;
|
57
71
|
<T>(body?: ResBody): T;
|
58
|
-
}
|
72
|
+
};
|
59
73
|
}
|
60
|
-
export type MapSchema<
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
74
|
+
export type MapSchema<
|
75
|
+
SV extends AnySchemaValidator,
|
76
|
+
T extends IdiomaticSchema<SV> | SV['_ValidSchemaObject']
|
77
|
+
> =
|
78
|
+
Schema<T, SV> extends infer U
|
79
|
+
? { [key: string]: unknown } extends U
|
80
|
+
? never
|
81
|
+
: U
|
82
|
+
: never;
|
83
|
+
export type ForklaunchNextFunction = (err?: unknown) => void;
|
@@ -1,55 +1,76 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import { UnboxedObjectSchema } from "@forklaunch/validator/types";
|
1
|
+
import { AnySchemaValidator } from '@forklaunch/validator';
|
2
|
+
import { UnboxedObjectSchema } from '@forklaunch/validator/types';
|
4
3
|
|
5
|
-
export type ParamsDictionary = { [key: string]: string
|
4
|
+
export type ParamsDictionary = { [key: string]: string };
|
6
5
|
|
7
|
-
export type StringOnlyObject<SV extends
|
8
|
-
|
6
|
+
export type StringOnlyObject<SV extends AnySchemaValidator> = Omit<
|
7
|
+
UnboxedObjectSchema<SV>,
|
8
|
+
number | symbol
|
9
|
+
>;
|
10
|
+
export type NumberOnlyObject<SV extends AnySchemaValidator> = Omit<
|
11
|
+
UnboxedObjectSchema<SV>,
|
12
|
+
string | symbol
|
13
|
+
>;
|
9
14
|
|
10
|
-
export type BodyObject<SV extends
|
11
|
-
|
12
|
-
export type
|
13
|
-
|
14
|
-
export type
|
15
|
+
export type BodyObject<SV extends AnySchemaValidator> = StringOnlyObject<SV> &
|
16
|
+
unknown;
|
17
|
+
export type ParamsObject<SV extends AnySchemaValidator> = StringOnlyObject<SV> &
|
18
|
+
unknown;
|
19
|
+
export type QueryObject<SV extends AnySchemaValidator> = StringOnlyObject<SV> &
|
20
|
+
unknown;
|
21
|
+
export type HeadersObject<SV extends AnySchemaValidator> =
|
22
|
+
StringOnlyObject<SV> & unknown;
|
23
|
+
export type ResponsesObject<SV extends AnySchemaValidator> = {
|
24
|
+
[key: number]:
|
25
|
+
| SV['_ValidSchemaObject']
|
26
|
+
| UnboxedObjectSchema<SV>
|
27
|
+
| string
|
28
|
+
| SV['string'];
|
29
|
+
} & unknown;
|
15
30
|
|
16
|
-
export type Body<SV extends
|
17
|
-
|
18
|
-
|
31
|
+
export type Body<SV extends AnySchemaValidator> =
|
32
|
+
| BodyObject<SV>
|
33
|
+
| SV['_ValidSchemaObject']
|
34
|
+
| SV['_SchemaCatchall'];
|
19
35
|
|
20
36
|
export type AuthMethod = 'jwt' | 'session';
|
21
37
|
export interface PathParamHttpContractDetails<
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
> {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
SV extends AnySchemaValidator,
|
39
|
+
ParamSchemas extends ParamsObject<SV> = ParamsObject<SV>,
|
40
|
+
ResponseSchemas extends ResponsesObject<SV> = ResponsesObject<SV>,
|
41
|
+
QuerySchemas extends QueryObject<SV> = QueryObject<SV>
|
42
|
+
> {
|
43
|
+
name: string;
|
44
|
+
summary: string;
|
45
|
+
responses: ResponseSchemas;
|
46
|
+
requestHeaders?: HeadersObject<SV>;
|
47
|
+
responseHeaders?: HeadersObject<SV>;
|
48
|
+
params?: ParamSchemas;
|
49
|
+
query?: QuerySchemas;
|
50
|
+
auth?: {
|
51
|
+
method: AuthMethod;
|
52
|
+
allowedSlugs?: Set<string>;
|
53
|
+
forbiddenSlugs?: Set<string>;
|
54
|
+
allowedRoles?: Set<string>;
|
55
|
+
forbiddenRoles?: Set<string>;
|
56
|
+
};
|
41
57
|
}
|
42
58
|
|
43
59
|
export interface HttpContractDetails<
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
> extends PathParamHttpContractDetails<
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
60
|
+
SV extends AnySchemaValidator,
|
61
|
+
ParamSchemas extends ParamsObject<SV> = ParamsObject<SV>,
|
62
|
+
ResponseSchemas extends ResponsesObject<SV> = ResponsesObject<SV>,
|
63
|
+
BodySchema extends Body<SV> = Body<SV>,
|
64
|
+
QuerySchemas extends QueryObject<SV> = QueryObject<SV>
|
65
|
+
> extends PathParamHttpContractDetails<
|
66
|
+
SV,
|
67
|
+
ParamSchemas,
|
68
|
+
ResponseSchemas,
|
69
|
+
QuerySchemas
|
70
|
+
> {
|
71
|
+
body?: BodySchema;
|
72
|
+
contentType?:
|
73
|
+
| 'application/json'
|
74
|
+
| 'multipart/form-data'
|
75
|
+
| 'application/x-www-form-urlencoded';
|
55
76
|
}
|
package/index.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
export * from './cache';
|
2
|
+
export * from './controllers';
|
3
|
+
export * from './database';
|
4
|
+
export * from './entityMapper';
|
5
|
+
export * from './http';
|
6
|
+
export * from './services';
|
package/jest.config.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import type {Config} from 'jest';
|
1
|
+
import type { Config } from 'jest';
|
2
2
|
|
3
3
|
const config: Config = {
|
4
4
|
verbose: true,
|
@@ -7,4 +7,4 @@ const config: Config = {
|
|
7
7
|
testPathIgnorePatterns: ['dist/', 'node_modules/']
|
8
8
|
};
|
9
9
|
|
10
|
-
export default config;
|
10
|
+
export default config;
|