@rest-vir/run-service 0.19.1 → 0.20.0
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/dist/handle-request/handle-cors.js +1 -1
- package/dist/handle-request/handle-endpoint.js +2 -1
- package/dist/handle-request/handle-request-method.js +1 -1
- package/dist/handle-request/handle-search-params.js +1 -1
- package/dist/handle-request/handle-web-socket.js +1 -0
- package/dist/handle-request/pre-handler.js +14 -13
- package/dist/start-service/attach-service.d.ts +14 -6
- package/package.json +8 -8
|
@@ -34,7 +34,7 @@ export async function handleCors({ route, request, }) {
|
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
|
-
route.service.logger.error(new RestVirHandlerError(route, `CORS rejected for origin '${origin}'
|
|
37
|
+
route.service.logger.error(new RestVirHandlerError(route, `CORS rejected for origin '${origin}'.`, HttpStatus.Forbidden));
|
|
38
38
|
/** The CORS requirements for this request have not been met. */
|
|
39
39
|
return {
|
|
40
40
|
statusCode: HttpStatus.Forbidden,
|
|
@@ -11,6 +11,7 @@ import { assertValidShape } from 'object-shape-tester';
|
|
|
11
11
|
*/
|
|
12
12
|
export async function handleEndpointRequest({ endpoint, request, response, attachId, server, }) {
|
|
13
13
|
try {
|
|
14
|
+
// by this point in the request lifecycle, we know that these properties have been set.
|
|
14
15
|
const restVirContext = request.restVirContext?.[attachId];
|
|
15
16
|
assert.isDefined(restVirContext, 'restVirContext is not defined');
|
|
16
17
|
const context = restVirContext.context;
|
|
@@ -36,7 +37,7 @@ export async function handleEndpointRequest({ endpoint, request, response, attac
|
|
|
36
37
|
throw new RestVirHandlerError(endpoint, 'Missing response status code.');
|
|
37
38
|
}
|
|
38
39
|
if (isErrorHttpStatus(endpointResult.statusCode)) {
|
|
39
|
-
endpoint.service.logger.error(new RestVirHandlerError(endpoint, `Endpoint implementation returned error status: ${endpointResult.statusCode}
|
|
40
|
+
endpoint.service.logger.error(new RestVirHandlerError(endpoint, `Endpoint implementation returned error status: ${endpointResult.statusCode}`, endpointResult.statusCode));
|
|
40
41
|
return {
|
|
41
42
|
statusCode: endpointResult.statusCode,
|
|
42
43
|
body: endpointResult.responseErrorMessage,
|
|
@@ -22,7 +22,7 @@ export function handleRequestMethod({ route, request, }) {
|
|
|
22
22
|
[HttpMethod.Get]: true,
|
|
23
23
|
};
|
|
24
24
|
if (!requestMethod || !allowedMethods[requestMethod]) {
|
|
25
|
-
route.service.logger.error(new RestVirHandlerError(route, `Method '${requestMethod}' rejected: '${request.originalUrl}'
|
|
25
|
+
route.service.logger.error(new RestVirHandlerError(route, `Method '${requestMethod}' rejected: '${request.originalUrl}'`, HttpStatus.MethodNotAllowed));
|
|
26
26
|
return {
|
|
27
27
|
statusCode: HttpStatus.MethodNotAllowed,
|
|
28
28
|
};
|
|
@@ -20,7 +20,7 @@ export function handleSearchParams({ request, route, }) {
|
|
|
20
20
|
})
|
|
21
21
|
: undefined;
|
|
22
22
|
if (validationError) {
|
|
23
|
-
route.service.logger.error(new RestVirHandlerError(route, `Search params failed for ${stringify(searchParams)}: ${validationError.message}
|
|
23
|
+
route.service.logger.error(new RestVirHandlerError(route, `Search params failed for ${stringify(searchParams)}: ${validationError.message}`, HttpStatus.BadRequest));
|
|
24
24
|
return {
|
|
25
25
|
body: 'Invalid search params.',
|
|
26
26
|
statusCode: HttpStatus.BadRequest,
|
|
@@ -11,6 +11,7 @@ import { assertValidShape } from 'object-shape-tester';
|
|
|
11
11
|
* @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
|
|
12
12
|
*/
|
|
13
13
|
export async function handleWebSocketRequest({ attachId, request, implementedWebSocket, webSocket: wsWebSocket, server, }) {
|
|
14
|
+
// by this point in the request lifecycle, we know that these properties have been set.
|
|
14
15
|
const restVirContext = request.restVirContext?.[attachId];
|
|
15
16
|
assert.isDefined(restVirContext, 'restVirContext is not defined');
|
|
16
17
|
const webSocket = overwriteWebSocketMethods(implementedWebSocket, wsWebSocket, WebSocketLocation.OnHost);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assertWrap } from '@augment-vir/assert';
|
|
2
|
-
import { ensureErrorAndPrependMessage, extractErrorMessage, HttpStatus, stringify, wrapInTry, } from '@augment-vir/common';
|
|
2
|
+
import { ensureErrorAndPrependMessage, extractErrorMessage, getOrSet, HttpStatus, stringify, wrapInTry, } from '@augment-vir/common';
|
|
3
3
|
import { isFormDataShape, matchUrlToService, restVirServiceNameHeader, } from '@rest-vir/define-service';
|
|
4
4
|
import { HttpMethod, RestVirHandlerError, } from '@rest-vir/implement-service';
|
|
5
5
|
import { assertValidShape, isValidShape } from 'object-shape-tester';
|
|
@@ -15,6 +15,12 @@ import { handleSearchParams } from './handle-search-params.js';
|
|
|
15
15
|
* @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
|
|
16
16
|
*/
|
|
17
17
|
export async function preHandler({ request, response, service, server, attachId, }) {
|
|
18
|
+
if (!request.restVirContext) {
|
|
19
|
+
request.restVirContext = {};
|
|
20
|
+
}
|
|
21
|
+
const attachedRestVirContext = getOrSet(request.restVirContext, attachId, () => {
|
|
22
|
+
return {};
|
|
23
|
+
});
|
|
18
24
|
response.header(restVirServiceNameHeader, service.serviceName);
|
|
19
25
|
const pathMatch = matchUrlToService(service, request.originalUrl);
|
|
20
26
|
if (!pathMatch) {
|
|
@@ -40,12 +46,13 @@ export async function preHandler({ request, response, service, server, attachId,
|
|
|
40
46
|
}))
|
|
41
47
|
: undefined;
|
|
42
48
|
if (protocolShapeError) {
|
|
43
|
-
service.logger.error(new RestVirHandlerError(route, extractErrorMessage(ensureErrorAndPrependMessage(protocolShapeError, `WebSocket protocols rejected (${stringify(protocols)}):`))));
|
|
49
|
+
service.logger.error(new RestVirHandlerError(route, extractErrorMessage(ensureErrorAndPrependMessage(protocolShapeError, `WebSocket protocols rejected (${stringify(protocols)}):`)), HttpStatus.BadRequest));
|
|
44
50
|
return {
|
|
45
51
|
statusCode: HttpStatus.BadRequest,
|
|
46
52
|
body: 'Invalid protocol.',
|
|
47
53
|
};
|
|
48
54
|
}
|
|
55
|
+
attachedRestVirContext.protocols = protocols;
|
|
49
56
|
const subHandlerResponse = handleHandlerOutputWithoutSending(await handleCors({
|
|
50
57
|
request,
|
|
51
58
|
route,
|
|
@@ -59,16 +66,18 @@ export async function preHandler({ request, response, service, server, attachId,
|
|
|
59
66
|
}
|
|
60
67
|
const requestData = wrapInTry(() => extractRequestData(request.body, request.headers, route));
|
|
61
68
|
if (requestData instanceof Error) {
|
|
62
|
-
service.logger.error(new RestVirHandlerError(route, `Rejected request body from '${request.originalUrl}': ${stringify(requestData)}
|
|
69
|
+
service.logger.error(new RestVirHandlerError(route, `Rejected request body from '${request.originalUrl}': ${stringify(requestData)}`, HttpStatus.BadRequest));
|
|
63
70
|
return {
|
|
64
71
|
statusCode: HttpStatus.BadRequest,
|
|
65
72
|
body: 'Invalid body.',
|
|
66
73
|
};
|
|
67
74
|
}
|
|
75
|
+
attachedRestVirContext.requestData = requestData;
|
|
68
76
|
const searchParams = handleSearchParams({ request, route });
|
|
69
77
|
if (!('data' in searchParams)) {
|
|
70
78
|
return handleHandlerOutputWithoutSending(searchParams, response);
|
|
71
79
|
}
|
|
80
|
+
attachedRestVirContext.searchParams = searchParams.data;
|
|
72
81
|
const contextParams = {
|
|
73
82
|
pathParams: request.params,
|
|
74
83
|
method: assertWrap.isEnumValue(request.method.toUpperCase(), HttpMethod),
|
|
@@ -84,23 +93,15 @@ export async function preHandler({ request, response, service, server, attachId,
|
|
|
84
93
|
};
|
|
85
94
|
try {
|
|
86
95
|
const contextOutput = await service.createContext?.(contextParams);
|
|
87
|
-
if (!request.restVirContext) {
|
|
88
|
-
request.restVirContext = {};
|
|
89
|
-
}
|
|
90
|
-
request.restVirContext[attachId] = {
|
|
91
|
-
context: contextOutput?.reject ? undefined : contextOutput?.context,
|
|
92
|
-
requestData,
|
|
93
|
-
protocols,
|
|
94
|
-
searchParams: searchParams.data,
|
|
95
|
-
};
|
|
96
96
|
if (contextOutput?.reject) {
|
|
97
|
-
service.logger.error(new RestVirHandlerError(route, `Context creation rejected: '${request.originalUrl}'
|
|
97
|
+
service.logger.error(new RestVirHandlerError(route, `Context creation rejected: '${request.originalUrl}'`, contextOutput.reject.statusCode));
|
|
98
98
|
return handleHandlerOutputWithoutSending({
|
|
99
99
|
body: contextOutput.reject.responseErrorMessage,
|
|
100
100
|
statusCode: contextOutput.reject.statusCode,
|
|
101
101
|
headers: contextOutput.reject.headers,
|
|
102
102
|
}, response);
|
|
103
103
|
}
|
|
104
|
+
attachedRestVirContext.context = contextOutput?.context;
|
|
104
105
|
return undefined;
|
|
105
106
|
}
|
|
106
107
|
catch (error) {
|
|
@@ -3,15 +3,23 @@ import { type BaseSearchParams, type MinimalService } from '@rest-vir/define-ser
|
|
|
3
3
|
import { type GenericServiceImplementation, type RunningServerInfo } from '@rest-vir/implement-service';
|
|
4
4
|
import { type FastifyInstance } from 'fastify';
|
|
5
5
|
import { type HandleRouteOptions } from '../handle-request/endpoint-handler.js';
|
|
6
|
+
/**
|
|
7
|
+
* Context attached to each fastify request object.
|
|
8
|
+
*
|
|
9
|
+
* @category Internal
|
|
10
|
+
* @category Package : @rest-vir/run-service
|
|
11
|
+
* @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
|
|
12
|
+
*/
|
|
13
|
+
export type RestVirRequestContext = {
|
|
14
|
+
context: unknown;
|
|
15
|
+
requestData: unknown;
|
|
16
|
+
protocols: string[];
|
|
17
|
+
searchParams: BaseSearchParams;
|
|
18
|
+
};
|
|
6
19
|
declare module 'fastify' {
|
|
7
20
|
interface FastifyRequest {
|
|
8
21
|
restVirContext: {
|
|
9
|
-
[AttachId in string]:
|
|
10
|
-
context: unknown;
|
|
11
|
-
requestData: unknown;
|
|
12
|
-
protocols: string[];
|
|
13
|
-
searchParams: BaseSearchParams;
|
|
14
|
-
};
|
|
22
|
+
[AttachId in string]: Partial<RestVirRequestContext>;
|
|
15
23
|
} | undefined;
|
|
16
24
|
}
|
|
17
25
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rest-vir/run-service",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Run a service defined by @rest-vir/define-service and implemented by @rest-vir/implement-service.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rest",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
"test:update": "npm test update"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@augment-vir/assert": "^31.
|
|
43
|
-
"@augment-vir/common": "^31.
|
|
44
|
-
"@augment-vir/node": "^31.
|
|
42
|
+
"@augment-vir/assert": "^31.20.0",
|
|
43
|
+
"@augment-vir/common": "^31.20.0",
|
|
44
|
+
"@augment-vir/node": "^31.20.0",
|
|
45
45
|
"@fastify/websocket": "^11.0.2",
|
|
46
|
-
"@rest-vir/define-service": "^0.
|
|
47
|
-
"@rest-vir/implement-service": "^0.
|
|
46
|
+
"@rest-vir/define-service": "^0.20.0",
|
|
47
|
+
"@rest-vir/implement-service": "^0.20.0",
|
|
48
48
|
"cluster-vir": "^0.1.0",
|
|
49
49
|
"date-vir": "^7.3.1",
|
|
50
50
|
"fastify": "^5.3.3",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
"url-vir": "^2.1.3"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@augment-vir/test": "^31.
|
|
57
|
+
"@augment-vir/test": "^31.20.0",
|
|
58
58
|
"@fastify/multipart": "^9.0.3",
|
|
59
59
|
"@types/connect": "^3.4.38",
|
|
60
|
-
"@types/node": "^22.15.
|
|
60
|
+
"@types/node": "^22.15.21",
|
|
61
61
|
"@types/ws": "^8.18.1",
|
|
62
62
|
"c8": "^10.1.3",
|
|
63
63
|
"istanbul-smart-text-reporter": "^1.1.5",
|