@rest-vir/run-service 0.6.0 → 0.8.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,6 +1,6 @@
1
1
  import { assertWrap } from '@augment-vir/assert';
2
2
  import { ensureErrorAndPrependMessage, extractErrorMessage, HttpStatus, stringify, wrapInTry, } from '@augment-vir/common';
3
- import { matchUrlToService, restVirServiceNameHeader, } from '@rest-vir/define-service';
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';
6
6
  import { handleHandlerResult } from './endpoint-handler.js';
@@ -55,7 +55,7 @@ export async function preHandler(request, response, service, attachId) {
55
55
  }), response).responseSent) {
56
56
  return;
57
57
  }
58
- const requestData = wrapInTry(() => extractRequestData(request.body, route));
58
+ const requestData = wrapInTry(() => extractRequestData(request.body, request.headers, route));
59
59
  if (requestData instanceof Error) {
60
60
  service.logger.error(new RestVirHandlerError(route, `Rejected request body from '${request.originalUrl}': ${stringify(requestData)}`));
61
61
  response.statusCode = HttpStatus.BadRequest;
@@ -102,7 +102,7 @@ export async function preHandler(request, response, service, attachId) {
102
102
  throw ensureErrorAndPrependMessage(error, 'Failed to generate request context.');
103
103
  }
104
104
  }
105
- function extractRequestData(body, route) {
105
+ function extractRequestData(body, headers, route) {
106
106
  const dataShape = 'requestDataShape' in route ? route.requestDataShape : undefined;
107
107
  if (!dataShape) {
108
108
  if (body) {
@@ -112,7 +112,10 @@ function extractRequestData(body, route) {
112
112
  return undefined;
113
113
  }
114
114
  }
115
- if (!isValidShape(body, dataShape, {
115
+ if (isFormDataShape(dataShape.shape) && headers['content-type'] === 'multipart/form-data') {
116
+ return body;
117
+ }
118
+ else if (!isValidShape(body, dataShape, {
116
119
  /** Allow extra keys for forwards / backwards compatibility. */
117
120
  allowExtraKeys: true,
118
121
  })) {
@@ -1,7 +1,7 @@
1
1
  import { type SelectFrom } from '@augment-vir/common';
2
2
  import { GenericServiceImplementation } from '@rest-vir/implement-service';
3
3
  import { ClusterManager, type WorkerRunner } from 'cluster-vir';
4
- import { type FastifyInstance } from 'fastify';
4
+ import { type FastifyInstance, type FastifyPluginCallback } from 'fastify';
5
5
  import { StartServiceUserOptions } from './start-service-options.js';
6
6
  /**
7
7
  * Output of {@link startService}.
@@ -42,6 +42,15 @@ export type StartServiceOutput = {
42
42
  /** A function that will kill the service even if it's using multiple workers. */
43
43
  kill: () => void;
44
44
  };
45
+ /**
46
+ * A list of plugins and their options that will be registered on the internal fastify instance
47
+ * created by {@link startService}.
48
+ *
49
+ * @category Internal
50
+ * @category Package : @rest-vir/run-service
51
+ * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
52
+ */
53
+ export type FastifyPlugins = [plugin: FastifyPluginCallback, options?: any][];
45
54
  /**
46
55
  * Starts the given {@link ServiceImplementation} inside of a backend [Fastify
47
56
  * server](https://www.npmjs.com/package/fastify).
@@ -60,4 +69,4 @@ export declare function startService(service: Readonly<SelectFrom<GenericService
60
69
  serviceOrigin: true;
61
70
  requiredClientOrigin: true;
62
71
  logger: true;
63
- }>>, userOptions?: Readonly<StartServiceUserOptions>): Promise<StartServiceOutput>;
72
+ }>>, userOptions?: Readonly<StartServiceUserOptions>, fastifyPlugins?: Readonly<FastifyPlugins>): Promise<StartServiceOutput>;
@@ -1,4 +1,5 @@
1
1
  import { check } from '@augment-vir/assert';
2
+ import { awaitedForEach } from '@augment-vir/common';
2
3
  import { ClusterManager, runInCluster } from 'cluster-vir';
3
4
  import fastify from 'fastify';
4
5
  import { getPortPromise } from 'portfinder';
@@ -14,7 +15,7 @@ import { finalizeOptions, } from './start-service-options.js';
14
15
  * @category Package : @rest-vir/run-service
15
16
  * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
16
17
  */
17
- export async function startService(service, userOptions = {}) {
18
+ export async function startService(service, userOptions = {}, fastifyPlugins = []) {
18
19
  const options = finalizeOptions(service.serviceOrigin, userOptions);
19
20
  const port = options.lockPort || check.isFalse(options.port)
20
21
  ? options.port
@@ -24,7 +25,7 @@ export async function startService(service, userOptions = {}) {
24
25
  options.port = port;
25
26
  if (options.workerCount === 1 || !check.isNumber(port)) {
26
27
  /** Only run a single server. */
27
- const result = await startServer(service, options);
28
+ const result = await startServer(service, options, fastifyPlugins);
28
29
  if (options.port) {
29
30
  service.logger.info(`${service.serviceName} started on http://localhost:${options.port}`);
30
31
  }
@@ -33,7 +34,7 @@ export async function startService(service, userOptions = {}) {
33
34
  else {
34
35
  /** Run in a cluster. */
35
36
  const manager = runInCluster(async () => {
36
- const { kill } = await startServer(service, options);
37
+ const { kill } = await startServer(service, options, fastifyPlugins);
37
38
  return () => {
38
39
  kill();
39
40
  };
@@ -68,8 +69,11 @@ export async function startService(service, userOptions = {}) {
68
69
  }
69
70
  }
70
71
  }
71
- async function startServer(service, { host, port }) {
72
+ async function startServer(service, { host, port }, fastifyPlugins) {
72
73
  const server = fastify();
74
+ await awaitedForEach(fastifyPlugins, async ([plugin, options,]) => {
75
+ await server.register(plugin, options);
76
+ });
73
77
  await attachService(server, service, {
74
78
  throwErrorsForExternalHandling: false,
75
79
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rest-vir/run-service",
3
- "version": "0.6.0",
3
+ "version": "0.8.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",
@@ -43,8 +43,8 @@
43
43
  "@augment-vir/common": "^31.9.4",
44
44
  "@augment-vir/node": "^31.9.4",
45
45
  "@fastify/websocket": "^11.0.2",
46
- "@rest-vir/define-service": "^0.6.0",
47
- "@rest-vir/implement-service": "^0.6.0",
46
+ "@rest-vir/define-service": "^0.8.0",
47
+ "@rest-vir/implement-service": "^0.8.0",
48
48
  "cluster-vir": "^0.1.0",
49
49
  "date-vir": "^7.2.1",
50
50
  "fastify": "^5.2.1",
@@ -55,6 +55,7 @@
55
55
  },
56
56
  "devDependencies": {
57
57
  "@augment-vir/test": "^31.9.4",
58
+ "@fastify/multipart": "^9.0.3",
58
59
  "@types/connect": "^3.4.38",
59
60
  "@types/node": "^22.13.9",
60
61
  "@types/ws": "^8.18.0",