@rest-vir/run-service 0.18.0 → 0.19.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.
@@ -42,6 +42,7 @@ export declare function attachService(server: Readonly<FastifyInstance>, service
42
42
  serviceOrigin: true;
43
43
  requiredClientOrigin: true;
44
44
  logger: true;
45
+ postHook: true;
45
46
  }>>, options?: Readonly<HandleRouteOptions>): Promise<void>;
46
47
  /**
47
48
  * Merge the running Fastify server's port with the given service's origin port (if it has a port).
@@ -1,10 +1,12 @@
1
- import { check } from '@augment-vir/assert';
2
- import { ensureError, extractErrorMessage, getEnumValues, getObjectTypedKeys, HttpMethod, HttpStatus, randomString, } from '@augment-vir/common';
1
+ import { assertWrap, check } from '@augment-vir/assert';
2
+ import { ensureError, extractErrorMessage, getEnumValues, getObjectTypedKeys, HttpMethod, HttpStatus, isErrorHttpStatus, randomString, } from '@augment-vir/common';
3
3
  import fastifyWs from '@fastify/websocket';
4
+ import { matchUrlToService, } from '@rest-vir/define-service';
4
5
  import { RestVirHandlerError, } from '@rest-vir/implement-service';
5
6
  import { buildUrl, parseUrl } from 'url-vir';
6
7
  import { handleRoute } from '../handle-request/handle-route.js';
7
8
  import { preHandler } from '../handle-request/pre-handler.js';
9
+ import { setResponseHeaders } from '../util/headers.js';
8
10
  const endpointFastifyMethods = getEnumValues(HttpMethod).filter((value) => {
9
11
  return (
10
12
  /** Fastify doesn't support the CONNECT method. */
@@ -66,6 +68,79 @@ export async function attachService(server, service, options = {}) {
66
68
  }
67
69
  }
68
70
  });
71
+ const postHook = service.postHook;
72
+ if (postHook) {
73
+ server.addHook('onSend', async (request, response, body) => {
74
+ /* node:coverage ignore next 4 */
75
+ const restVirContext = request.restVirContext?.[attachId];
76
+ if (!restVirContext) {
77
+ return undefined;
78
+ }
79
+ const context = restVirContext.context;
80
+ const requestData = restVirContext.requestData;
81
+ const searchParams = restVirContext.searchParams;
82
+ const pathMatch = matchUrlToService(service, request.originalUrl);
83
+ /* node:coverage ignore next 10 */
84
+ if (!pathMatch) {
85
+ return undefined;
86
+ }
87
+ const endpointDefinition = pathMatch.endpointPath
88
+ ? service.endpoints[pathMatch.endpointPath]
89
+ : undefined;
90
+ const webSocketDefinition = request.ws && pathMatch.webSocketPath
91
+ ? service.webSockets[pathMatch.webSocketPath]
92
+ : undefined;
93
+ const postHookParams = {
94
+ context,
95
+ method: assertWrap.isEnumValue(request.method.toUpperCase(), HttpMethod),
96
+ request,
97
+ requestData,
98
+ requestHeaders: request.headers,
99
+ response,
100
+ service,
101
+ endpointDefinition: endpointDefinition,
102
+ webSocketDefinition: webSocketDefinition,
103
+ server: extractRunningServerInfo(service, server),
104
+ searchParams,
105
+ originalResponseData: body,
106
+ originalStatus: response.statusCode,
107
+ };
108
+ const result = await postHook(postHookParams);
109
+ if (result) {
110
+ if (result.headers) {
111
+ setResponseHeaders(response, result.headers);
112
+ }
113
+ if (result.dataType) {
114
+ setResponseHeaders(response, {
115
+ 'content-type': result.dataType,
116
+ });
117
+ }
118
+ if (result.statusCode) {
119
+ response.status(result.statusCode);
120
+ }
121
+ if (isErrorHttpStatus(result.statusCode ?? response.statusCode) &&
122
+ 'responseErrorMessage' in result) {
123
+ if (result.responseErrorMessage == undefined) {
124
+ /** Clear the body. */
125
+ return null;
126
+ }
127
+ else {
128
+ return result.responseErrorMessage;
129
+ }
130
+ }
131
+ else if ('responseData' in result) {
132
+ if (result.responseData == undefined) {
133
+ /** Clear the body. */
134
+ return null;
135
+ }
136
+ else {
137
+ return result.responseData;
138
+ }
139
+ }
140
+ }
141
+ return undefined;
142
+ });
143
+ }
69
144
  const allPaths = new Set([
70
145
  ...getObjectTypedKeys(service.webSockets),
71
146
  ...getObjectTypedKeys(service.endpoints),
@@ -69,4 +69,5 @@ export declare function startService(service: Readonly<SelectFrom<GenericService
69
69
  serviceOrigin: true;
70
70
  requiredClientOrigin: true;
71
71
  logger: true;
72
+ postHook: true;
72
73
  }>>, userOptions?: Readonly<StartServiceUserOptions>, fastifyPlugins?: Readonly<FastifyPlugins>): Promise<StartServiceOutput>;
@@ -284,6 +284,7 @@ export declare function testService<const Service extends Readonly<SelectFrom<Ge
284
284
  serviceOrigin: true;
285
285
  requiredClientOrigin: true;
286
286
  logger: true;
287
+ postHook: true;
287
288
  }>>>(service: Readonly<Service>, testServiceOptions?: Readonly<Omit<PartialWithUndefined<StartServiceUserOptions>, 'workerCount' | 'preventWorkerRespawn' | ''>>): Promise<{
288
289
  /** Kill the server being tested. This should always be called after your tests are finished. */
289
290
  kill(this: void): Promise<void>;
@@ -313,6 +314,7 @@ export declare function testExistingServer<const Service extends Readonly<Select
313
314
  serviceOrigin: true;
314
315
  requiredClientOrigin: true;
315
316
  logger: true;
317
+ postHook: true;
316
318
  }>>>(server: Readonly<FastifyInstance>, service: Readonly<Service>, options?: Readonly<HandleRouteOptions & Omit<PartialWithUndefined<StartServiceOptions>, 'workerCount' | 'preventWorkerRespawn'>>): Promise<{
317
319
  /** Send a request to the service. */
318
320
  fetchEndpoint: FetchTestService<Service>;
@@ -353,6 +355,7 @@ export declare function describeService<const Service extends Readonly<SelectFro
353
355
  serviceOrigin: true;
354
356
  requiredClientOrigin: true;
355
357
  logger: true;
358
+ postHook: true;
356
359
  }>>>({ service, options, }: {
357
360
  /** The service to startup and send requests to. */
358
361
  service: Readonly<Service>;
@@ -182,7 +182,7 @@ export async function testExistingServer(server, service, options = {}) {
182
182
  const webSocketUrl = buildWebSocketUrl(overwrittenOriginWebSocket, ...args);
183
183
  assertValidWebSocketProtocols(protocols);
184
184
  const webSocket = webSocketOrigin == undefined
185
- ? (await server.injectWS(parseUrl(webSocketUrl).pathname, protocols.length
185
+ ? (await server.injectWS(parseUrl(webSocketUrl).fullPath, protocols.length
186
186
  ? {
187
187
  headers: {
188
188
  'sec-websocket-protocol': protocols.join(', '),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rest-vir/run-service",
3
- "version": "0.18.0",
3
+ "version": "0.19.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,25 +39,25 @@
39
39
  "test:update": "npm test update"
40
40
  },
41
41
  "dependencies": {
42
- "@augment-vir/assert": "^31.16.0",
43
- "@augment-vir/common": "^31.16.0",
44
- "@augment-vir/node": "^31.16.0",
42
+ "@augment-vir/assert": "^31.19.1",
43
+ "@augment-vir/common": "^31.19.1",
44
+ "@augment-vir/node": "^31.19.1",
45
45
  "@fastify/websocket": "^11.0.2",
46
- "@rest-vir/define-service": "^0.18.0",
47
- "@rest-vir/implement-service": "^0.18.0",
46
+ "@rest-vir/define-service": "^0.19.0",
47
+ "@rest-vir/implement-service": "^0.19.0",
48
48
  "cluster-vir": "^0.1.0",
49
49
  "date-vir": "^7.3.1",
50
- "fastify": "^5.3.2",
50
+ "fastify": "^5.3.3",
51
51
  "light-my-request": "^6.6.0",
52
52
  "portfinder": "^1.0.37",
53
- "type-fest": "^4.40.1",
53
+ "type-fest": "^4.41.0",
54
54
  "url-vir": "^2.1.3"
55
55
  },
56
56
  "devDependencies": {
57
- "@augment-vir/test": "^31.16.0",
57
+ "@augment-vir/test": "^31.19.1",
58
58
  "@fastify/multipart": "^9.0.3",
59
59
  "@types/connect": "^3.4.38",
60
- "@types/node": "^22.15.3",
60
+ "@types/node": "^22.15.18",
61
61
  "@types/ws": "^8.18.1",
62
62
  "c8": "^10.1.3",
63
63
  "istanbul-smart-text-reporter": "^1.1.5",