@rest-vir/run-service 0.11.4 → 0.12.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.
@@ -1,4 +1,4 @@
1
- import { ImplementedEndpoint } from '@rest-vir/implement-service';
1
+ import { ImplementedEndpoint, type RunningServerInfo } from '@rest-vir/implement-service';
2
2
  import { EndpointHandlerParams, type HandledOutput } from './endpoint-handler.js';
3
3
  /**
4
4
  * Handles an endpoint's implementation execution.
@@ -7,7 +7,8 @@ import { EndpointHandlerParams, type HandledOutput } from './endpoint-handler.js
7
7
  * @category Package : @rest-vir/run-service
8
8
  * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
9
9
  */
10
- export declare function handleEndpointRequest(this: void, { endpoint, request, response, attachId, }: Readonly<Omit<EndpointHandlerParams, 'route'> & {
10
+ export declare function handleEndpointRequest(this: void, { endpoint, request, response, attachId, server, }: Readonly<Omit<EndpointHandlerParams, 'route'> & {
11
11
  attachId: string;
12
12
  endpoint: Readonly<ImplementedEndpoint>;
13
+ server: Readonly<RunningServerInfo>;
13
14
  }>): Promise<HandledOutput>;
@@ -9,7 +9,7 @@ import { assertValidShape } from 'object-shape-tester';
9
9
  * @category Package : @rest-vir/run-service
10
10
  * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
11
11
  */
12
- export async function handleEndpointRequest({ endpoint, request, response, attachId, }) {
12
+ export async function handleEndpointRequest({ endpoint, request, response, attachId, server, }) {
13
13
  try {
14
14
  const restVirContext = request.restVirContext?.[attachId];
15
15
  assert.isDefined(restVirContext, 'restVirContext is not defined');
@@ -28,6 +28,7 @@ export async function handleEndpointRequest({ endpoint, request, response, attac
28
28
  log: endpoint.service.logger,
29
29
  context,
30
30
  searchParams,
31
+ server,
31
32
  };
32
33
  const endpointResult = (await endpoint.implementation(endpointParams));
33
34
  if (isErrorHttpStatus(endpointResult.statusCode)) {
@@ -1,4 +1,4 @@
1
- import { ImplementedEndpoint, ServerRequest, ServerResponse, type ImplementedWebSocket } from '@rest-vir/implement-service';
1
+ import { ImplementedEndpoint, ImplementedWebSocket, RunningServerInfo, ServerRequest, ServerResponse } from '@rest-vir/implement-service';
2
2
  import { type WebSocket as WsWebSocket } from 'ws';
3
3
  import { HandleRouteOptions } from './endpoint-handler.js';
4
4
  /**
@@ -12,4 +12,4 @@ export declare function handleRoute(
12
12
  /** Endpoint requests won't have a `WebSocket`. */
13
13
  webSocket: WsWebSocket | undefined, request: ServerRequest,
14
14
  /** `WebSocket` requests won't have a response. */
15
- response: ServerResponse | undefined, route: Readonly<ImplementedEndpoint | ImplementedWebSocket>, attachId: string, options?: Readonly<Pick<HandleRouteOptions, 'throwErrorsForExternalHandling'>>): Promise<void>;
15
+ response: ServerResponse | undefined, route: Readonly<ImplementedEndpoint | ImplementedWebSocket>, attachId: string, server: Readonly<RunningServerInfo>, options?: Readonly<Pick<HandleRouteOptions, 'throwErrorsForExternalHandling'>>): Promise<void>;
@@ -16,7 +16,7 @@ export async function handleRoute(
16
16
  /** Endpoint requests won't have a `WebSocket`. */
17
17
  webSocket, request,
18
18
  /** `WebSocket` requests won't have a response. */
19
- response, route, attachId, options = {}) {
19
+ response, route, attachId, server, options = {}) {
20
20
  try {
21
21
  const workerPid = cluster.isPrimary ? '' : process.pid;
22
22
  const webSocketMarker = route.isWebSocket ? '(ws)' : '';
@@ -34,6 +34,7 @@ response, route, attachId, options = {}) {
34
34
  response,
35
35
  endpoint: route,
36
36
  attachId,
37
+ server,
37
38
  });
38
39
  const sentResponse = handleHandlerResult(result, response);
39
40
  if (sentResponse) {
@@ -47,6 +48,7 @@ response, route, attachId, options = {}) {
47
48
  implementedWebSocket: route,
48
49
  webSocket,
49
50
  attachId,
51
+ server,
50
52
  });
51
53
  }
52
54
  /* node:coverage ignore next: this can't actually be triggered but it should be covered as a potential future edge case. */
@@ -1,4 +1,4 @@
1
- import { ImplementedWebSocket, ServerRequest } from '@rest-vir/implement-service';
1
+ import { ImplementedWebSocket, ServerRequest, type RunningServerInfo } from '@rest-vir/implement-service';
2
2
  import { type WebSocket as WsWebSocket } from 'ws';
3
3
  /**
4
4
  * Handles a WebSocket request.
@@ -7,9 +7,10 @@ import { type WebSocket as WsWebSocket } from 'ws';
7
7
  * @category Package : @rest-vir/run-service
8
8
  * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
9
9
  */
10
- export declare function handleWebSocketRequest(this: void, { attachId, request, implementedWebSocket, webSocket: wsWebSocket, }: Readonly<{
10
+ export declare function handleWebSocketRequest(this: void, { attachId, request, implementedWebSocket, webSocket: wsWebSocket, server, }: Readonly<{
11
11
  request: ServerRequest;
12
12
  attachId: string;
13
13
  implementedWebSocket: Readonly<ImplementedWebSocket>;
14
14
  webSocket: WsWebSocket;
15
+ server: Readonly<RunningServerInfo>;
15
16
  }>): Promise<void>;
@@ -10,7 +10,7 @@ import { assertValidShape } from 'object-shape-tester';
10
10
  * @category Package : @rest-vir/run-service
11
11
  * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
12
12
  */
13
- export async function handleWebSocketRequest({ attachId, request, implementedWebSocket, webSocket: wsWebSocket, }) {
13
+ export async function handleWebSocketRequest({ attachId, request, implementedWebSocket, webSocket: wsWebSocket, server, }) {
14
14
  const restVirContext = request.restVirContext?.[attachId];
15
15
  assert.isDefined(restVirContext, 'restVirContext is not defined');
16
16
  const webSocket = overwriteWebSocketMethods(implementedWebSocket, wsWebSocket, WebSocketLocation.OnHost);
@@ -24,6 +24,7 @@ export async function handleWebSocketRequest({ attachId, request, implementedWeb
24
24
  webSocket,
25
25
  protocols: restVirContext.protocols,
26
26
  searchParams: restVirContext.searchParams,
27
+ server,
27
28
  };
28
29
  if (implementedWebSocket.implementation.close) {
29
30
  webSocket.on('close', async () => {
@@ -1,5 +1,5 @@
1
1
  import { type SelectFrom } from '@augment-vir/common';
2
- import { GenericServiceImplementation, ServerRequest, ServerResponse } from '@rest-vir/implement-service';
2
+ import { GenericServiceImplementation, RunningServerInfo, ServerRequest, ServerResponse } from '@rest-vir/implement-service';
3
3
  import { type FastifyReply } from 'fastify';
4
4
  /**
5
5
  * Handles a request before it gets to the actual route handlers.
@@ -16,4 +16,4 @@ export declare function preHandler(request: ServerRequest, response: ServerRespo
16
16
  serviceOrigin: true;
17
17
  requiredClientOrigin: true;
18
18
  logger: true;
19
- }>>, attachId: string): Promise<FastifyReply | undefined>;
19
+ }>>, server: Readonly<RunningServerInfo>, attachId: string): Promise<FastifyReply | undefined>;
@@ -14,7 +14,7 @@ import { handleSearchParams } from './handle-search-params.js';
14
14
  * @category Package : @rest-vir/run-service
15
15
  * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
16
16
  */
17
- export async function preHandler(request, response, service, attachId) {
17
+ export async function preHandler(request, response, service, server, attachId) {
18
18
  response.header(restVirServiceNameHeader, service.serviceName);
19
19
  const pathMatch = matchUrlToService(service, request.originalUrl);
20
20
  if (!pathMatch) {
@@ -72,6 +72,7 @@ export async function preHandler(request, response, service, attachId) {
72
72
  service,
73
73
  endpointDefinition: endpointDefinition,
74
74
  webSocketDefinition: webSocketDefinition,
75
+ server,
75
76
  };
76
77
  const searchParams = handleSearchParams({ request, route });
77
78
  if (!('data' in searchParams)) {
@@ -1,6 +1,6 @@
1
1
  import { SelectFrom } from '@augment-vir/common';
2
- import type { BaseSearchParams } from '@rest-vir/define-service';
3
- import { GenericServiceImplementation } from '@rest-vir/implement-service';
2
+ import type { BaseSearchParams, MinimalService } from '@rest-vir/define-service';
3
+ import { GenericServiceImplementation, type RunningServerInfo } from '@rest-vir/implement-service';
4
4
  import { type FastifyInstance } from 'fastify';
5
5
  import { HandleRouteOptions } from '../handle-request/endpoint-handler.js';
6
6
  declare module 'fastify' {
@@ -43,3 +43,13 @@ export declare function attachService(server: Readonly<FastifyInstance>, service
43
43
  requiredClientOrigin: true;
44
44
  logger: true;
45
45
  }>>, options?: Readonly<HandleRouteOptions>): Promise<void>;
46
+ /**
47
+ * Merge the running Fastify server's port with the given service's origin port (if it has a port).
48
+ *
49
+ * @category Internal
50
+ */
51
+ export declare function extractRunningServerInfo(service: Readonly<Pick<MinimalService, 'serviceOrigin'>>, fastify: Readonly<SelectFrom<FastifyInstance, {
52
+ server: {
53
+ address: true;
54
+ };
55
+ }>>): RunningServerInfo;
@@ -1,6 +1,8 @@
1
+ import { check } from '@augment-vir/assert';
1
2
  import { ensureError, extractErrorMessage, getEnumValues, getObjectTypedKeys, HttpMethod, HttpStatus, randomString, } from '@augment-vir/common';
2
3
  import fastifyWs from '@fastify/websocket';
3
4
  import { RestVirHandlerError, } from '@rest-vir/implement-service';
5
+ import { buildUrl, parseUrl } from 'url-vir';
4
6
  import { handleRoute } from '../handle-request/handle-route.js';
5
7
  import { preHandler } from '../handle-request/pre-handler.js';
6
8
  const endpointFastifyMethods = getEnumValues(HttpMethod).filter((value) => {
@@ -51,7 +53,7 @@ export async function attachService(server, service, options = {}) {
51
53
  }
52
54
  server.addHook('preValidation', async (request, response) => {
53
55
  try {
54
- return await preHandler(request, response, service, attachId);
56
+ return await preHandler(request, response, service, extractRunningServerInfo(service, server), attachId);
55
57
  }
56
58
  catch (error) {
57
59
  service.logger.error(ensureError(error));
@@ -76,17 +78,17 @@ export async function attachService(server, service, options = {}) {
76
78
  method: endpointFastifyMethods,
77
79
  url: path,
78
80
  handler(request, response) {
79
- return handleRoute(undefined, request, response, endpoint, attachId, options);
81
+ return handleRoute(undefined, request, response, endpoint, attachId, extractRunningServerInfo(service, server), options);
80
82
  },
81
83
  });
82
84
  server.route({
83
85
  method: HttpMethod.Get,
84
86
  url: path,
85
87
  handler(request, response) {
86
- return handleRoute(undefined, request, response, endpoint, attachId, options);
88
+ return handleRoute(undefined, request, response, endpoint, attachId, extractRunningServerInfo(service, server), options);
87
89
  },
88
90
  wsHandler(webSocket, request) {
89
- return handleRoute(webSocket, request, undefined, webSocketDefinition, attachId, options);
91
+ return handleRoute(webSocket, request, undefined, webSocketDefinition, attachId, extractRunningServerInfo(service, server), options);
90
92
  },
91
93
  });
92
94
  }
@@ -98,7 +100,7 @@ export async function attachService(server, service, options = {}) {
98
100
  ],
99
101
  url: path,
100
102
  handler(request, response) {
101
- return handleRoute(undefined, request, response, endpoint, attachId, options);
103
+ return handleRoute(undefined, request, response, endpoint, attachId, extractRunningServerInfo(service, server), options);
102
104
  },
103
105
  });
104
106
  }
@@ -110,7 +112,7 @@ export async function attachService(server, service, options = {}) {
110
112
  return response.status(HttpStatus.NotFound).send();
111
113
  },
112
114
  wsHandler(webSocket, request) {
113
- return handleRoute(webSocket, request, undefined, webSocketDefinition, attachId, options);
115
+ return handleRoute(webSocket, request, undefined, webSocketDefinition, attachId, extractRunningServerInfo(service, server), options);
114
116
  },
115
117
  });
116
118
  }
@@ -122,3 +124,25 @@ export async function attachService(server, service, options = {}) {
122
124
  throw error;
123
125
  }
124
126
  }
127
+ /**
128
+ * Merge the running Fastify server's port with the given service's origin port (if it has a port).
129
+ *
130
+ * @category Internal
131
+ */
132
+ export function extractRunningServerInfo(service, fastify) {
133
+ const address = fastify.server.address();
134
+ const { port: originalPort } = parseUrl(service.serviceOrigin);
135
+ if (!originalPort || check.isString(address) || !address) {
136
+ return {
137
+ serviceOrigin: service.serviceOrigin,
138
+ };
139
+ }
140
+ else {
141
+ const { origin } = buildUrl(service.serviceOrigin, {
142
+ port: address.port,
143
+ });
144
+ return {
145
+ serviceOrigin: origin,
146
+ };
147
+ }
148
+ }
@@ -22,7 +22,9 @@ export declare const startServiceOptionsShape: import("object-shape-tester").Sha
22
22
  * If this property is set to `false`, no port will be listened to (so you can manually do that
23
23
  * later if you wish).
24
24
  *
25
- * @default 3000
25
+ * @default
26
+ * // the service definition's port or
27
+ * 3000
26
28
  */
27
29
  port: number;
28
30
  /**
@@ -25,7 +25,9 @@ export const startServiceOptionsShape = defineShape({
25
25
  * If this property is set to `false`, no port will be listened to (so you can manually do that
26
26
  * later if you wish).
27
27
  *
28
- * @default 3000
28
+ * @default
29
+ * // the service definition's port or
30
+ * 3000
29
31
  */
30
32
  port: 3000,
31
33
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rest-vir/run-service",
3
- "version": "0.11.4",
3
+ "version": "0.12.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.10.2",
43
- "@augment-vir/common": "^31.10.2",
44
- "@augment-vir/node": "^31.10.2",
42
+ "@augment-vir/assert": "^31.11.0",
43
+ "@augment-vir/common": "^31.11.0",
44
+ "@augment-vir/node": "^31.11.0",
45
45
  "@fastify/websocket": "^11.0.2",
46
- "@rest-vir/define-service": "^0.11.4",
47
- "@rest-vir/implement-service": "^0.11.4",
46
+ "@rest-vir/define-service": "^0.12.0",
47
+ "@rest-vir/implement-service": "^0.12.0",
48
48
  "cluster-vir": "^0.1.0",
49
49
  "date-vir": "^7.3.1",
50
- "fastify": "^5.2.2",
50
+ "fastify": "^5.3.0",
51
51
  "light-my-request": "^6.6.0",
52
- "portfinder": "^1.0.35",
53
- "type-fest": "^4.39.1",
52
+ "portfinder": "^1.0.36",
53
+ "type-fest": "^4.40.0",
54
54
  "url-vir": "^2.1.3"
55
55
  },
56
56
  "devDependencies": {
57
- "@augment-vir/test": "^31.10.2",
57
+ "@augment-vir/test": "^31.11.0",
58
58
  "@fastify/multipart": "^9.0.3",
59
59
  "@types/connect": "^3.4.38",
60
- "@types/node": "^22.14.0",
60
+ "@types/node": "^22.14.1",
61
61
  "@types/ws": "^8.18.1",
62
62
  "c8": "^10.1.3",
63
63
  "istanbul-smart-text-reporter": "^1.1.5",