@rest-vir/run-service 0.0.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.
Files changed (32) hide show
  1. package/LICENSE-CC0 +121 -0
  2. package/LICENSE-MIT +21 -0
  3. package/README.md +23 -0
  4. package/dist/handle-request/endpoint-handler.d.ts +76 -0
  5. package/dist/handle-request/endpoint-handler.js +29 -0
  6. package/dist/handle-request/handle-cors.d.ts +37 -0
  7. package/dist/handle-request/handle-cors.js +141 -0
  8. package/dist/handle-request/handle-endpoint.d.ts +13 -0
  9. package/dist/handle-request/handle-endpoint.js +62 -0
  10. package/dist/handle-request/handle-request-method.d.ts +26 -0
  11. package/dist/handle-request/handle-request-method.js +33 -0
  12. package/dist/handle-request/handle-route.d.ts +15 -0
  13. package/dist/handle-request/handle-route.js +65 -0
  14. package/dist/handle-request/handle-search-params.d.ts +33 -0
  15. package/dist/handle-request/handle-search-params.js +32 -0
  16. package/dist/handle-request/handle-web-socket.d.ts +15 -0
  17. package/dist/handle-request/handle-web-socket.js +65 -0
  18. package/dist/handle-request/pre-handler.d.ts +18 -0
  19. package/dist/handle-request/pre-handler.js +123 -0
  20. package/dist/index.d.ts +18 -0
  21. package/dist/index.js +17 -0
  22. package/dist/start-service/attach-service.d.ts +45 -0
  23. package/dist/start-service/attach-service.js +124 -0
  24. package/dist/start-service/start-service-options.d.ts +83 -0
  25. package/dist/start-service/start-service-options.js +73 -0
  26. package/dist/start-service/start-service.d.ts +63 -0
  27. package/dist/start-service/start-service.js +85 -0
  28. package/dist/util/debug.d.ts +11 -0
  29. package/dist/util/debug.js +16 -0
  30. package/dist/util/headers.d.ts +11 -0
  31. package/dist/util/headers.js +19 -0
  32. package/package.json +72 -0
@@ -0,0 +1,63 @@
1
+ import { type SelectFrom } from '@augment-vir/common';
2
+ import { GenericServiceImplementation } from '@rest-vir/implement-service';
3
+ import { ClusterManager, type WorkerRunner } from 'cluster-vir';
4
+ import { type FastifyInstance } from 'fastify';
5
+ import { StartServiceUserOptions } from './start-service-options.js';
6
+ /**
7
+ * Output of {@link startService}.
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 StartServiceOutput = {
14
+ /**
15
+ * The port that the server actually started on. This depends on the options given to
16
+ * {@link startService}.
17
+ */
18
+ port: number;
19
+ /**
20
+ * The host that the server was attached to. (This is simply passed directly from the user
21
+ * options, merged with the default.)
22
+ */
23
+ host: string;
24
+ /**
25
+ * The instantiated and running [`fastify`](https://www.npmjs.com/package/fastify) instance.
26
+ * This is populated when the server is run on only a single thread (when `options.workerCount`
27
+ * is 1).
28
+ */
29
+ server?: FastifyInstance;
30
+ /**
31
+ * The `ClusterManager` for all the spawned server workers. This is populated when the server is
32
+ * run with a multiple threads (when `options.workerCount` > 1). It will only be populated for
33
+ * the primary thread.
34
+ */
35
+ cluster?: ClusterManager;
36
+ /**
37
+ * The `WorkerRunner` for the current worker. This is populated when the server is run with a
38
+ * multiple threads (when `options.workerCount` > 1). It will only be populated for non-primary
39
+ * threads.
40
+ */
41
+ worker?: WorkerRunner;
42
+ /** A function that will kill the service even if it's using multiple workers. */
43
+ kill: () => void;
44
+ };
45
+ /**
46
+ * Starts the given {@link ServiceImplementation} inside of a backend [Fastify
47
+ * server](https://www.npmjs.com/package/fastify).
48
+ *
49
+ * To attach the service endpoint handlers to an existing Fastify server, use {@link attachService}.
50
+ *
51
+ * @category Run Service
52
+ * @category Package : @rest-vir/run-service
53
+ * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
54
+ */
55
+ export declare function startService(service: Readonly<SelectFrom<GenericServiceImplementation, {
56
+ webSockets: true;
57
+ endpoints: true;
58
+ serviceName: true;
59
+ createContext: true;
60
+ serviceOrigin: true;
61
+ requiredClientOrigin: true;
62
+ logger: true;
63
+ }>>, userOptions: Readonly<StartServiceUserOptions>): Promise<StartServiceOutput>;
@@ -0,0 +1,85 @@
1
+ import { check } from '@augment-vir/assert';
2
+ import { ClusterManager, runInCluster } from 'cluster-vir';
3
+ import fastify from 'fastify';
4
+ import { getPortPromise } from 'portfinder';
5
+ import { attachService } from './attach-service.js';
6
+ import { finalizeOptions, } from './start-service-options.js';
7
+ /**
8
+ * Starts the given {@link ServiceImplementation} inside of a backend [Fastify
9
+ * server](https://www.npmjs.com/package/fastify).
10
+ *
11
+ * To attach the service endpoint handlers to an existing Fastify server, use {@link attachService}.
12
+ *
13
+ * @category Run Service
14
+ * @category Package : @rest-vir/run-service
15
+ * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
16
+ */
17
+ export async function startService(service, userOptions) {
18
+ const options = finalizeOptions(userOptions);
19
+ const port = options.lockPort || check.isFalse(options.port)
20
+ ? options.port
21
+ : await getPortPromise({
22
+ port: options.port,
23
+ });
24
+ options.port = port;
25
+ if (options.workerCount === 1 || !check.isNumber(port)) {
26
+ /** Only run a single server. */
27
+ const result = await startServer(service, options);
28
+ if (options.port) {
29
+ service.logger.info(`${service.serviceName} started on http://localhost:${options.port}`);
30
+ }
31
+ return result;
32
+ }
33
+ else {
34
+ /** Run in a cluster. */
35
+ const manager = runInCluster(async () => {
36
+ const { kill } = await startServer(service, options);
37
+ return () => {
38
+ kill();
39
+ };
40
+ }, {
41
+ startWorkersImmediately: false,
42
+ respawnWorkers: !options.preventWorkerRespawn,
43
+ workerCount: options.workerCount,
44
+ });
45
+ if (check.instanceOf(manager, ClusterManager)) {
46
+ await manager.startWorkers();
47
+ if (options.port) {
48
+ service.logger.info(`${service.serviceName} started on http://localhost:${options.port}`);
49
+ }
50
+ return {
51
+ host: options.host,
52
+ port: port,
53
+ cluster: manager,
54
+ kill() {
55
+ manager.destroy();
56
+ },
57
+ };
58
+ }
59
+ else {
60
+ return {
61
+ host: options.host,
62
+ port: port,
63
+ worker: manager,
64
+ kill() {
65
+ manager.destroy();
66
+ },
67
+ };
68
+ }
69
+ }
70
+ }
71
+ async function startServer(service, { host, port }) {
72
+ const server = fastify();
73
+ await attachService(server, service, {
74
+ throwErrorsForExternalHandling: false,
75
+ });
76
+ await server.listen({ port, host });
77
+ return {
78
+ host,
79
+ port,
80
+ server,
81
+ kill() {
82
+ server.server.close();
83
+ },
84
+ };
85
+ }
@@ -0,0 +1,11 @@
1
+ import { type GenericServiceImplementation } from '@rest-vir/implement-service';
2
+ /**
3
+ * When debug is set to `true`, this overwrites the service's logger to {@link defaultServiceLogger}.
4
+ *
5
+ * WARNING: this mutates the input `service` object.
6
+ *
7
+ * @category Internal
8
+ * @category Package : @rest-vir/run-service
9
+ * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
10
+ */
11
+ export declare function applyDebugLogger(debug: undefined | boolean, service: Pick<GenericServiceImplementation, 'logger'>): void;
@@ -0,0 +1,16 @@
1
+ import { defaultServiceLogger } from '@rest-vir/implement-service';
2
+ /**
3
+ * When debug is set to `true`, this overwrites the service's logger to {@link defaultServiceLogger}.
4
+ *
5
+ * WARNING: this mutates the input `service` object.
6
+ *
7
+ * @category Internal
8
+ * @category Package : @rest-vir/run-service
9
+ * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
10
+ */
11
+ export function applyDebugLogger(debug, service) {
12
+ if (!debug) {
13
+ return;
14
+ }
15
+ service.logger = defaultServiceLogger;
16
+ }
@@ -0,0 +1,11 @@
1
+ import { type ServerResponse } from '@rest-vir/implement-service';
2
+ import { type OutgoingHttpHeaders } from 'node:http';
3
+ /**
4
+ * Easily apply an object of headers to a Response object. Setting a header to `undefined` removes
5
+ * it.
6
+ *
7
+ * @category Internal
8
+ * @category Package : @rest-vir/run-service
9
+ * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
10
+ */
11
+ export declare function setResponseHeaders(response: Readonly<Pick<ServerResponse, 'removeHeader' | 'header'>>, headers: Readonly<OutgoingHttpHeaders>): void;
@@ -0,0 +1,19 @@
1
+ import { getObjectTypedEntries } from '@augment-vir/common';
2
+ /**
3
+ * Easily apply an object of headers to a Response object. Setting a header to `undefined` removes
4
+ * it.
5
+ *
6
+ * @category Internal
7
+ * @category Package : @rest-vir/run-service
8
+ * @package [`@rest-vir/run-service`](https://www.npmjs.com/package/@rest-vir/run-service)
9
+ */
10
+ export function setResponseHeaders(response, headers) {
11
+ getObjectTypedEntries(headers).forEach(([name, value,]) => {
12
+ if (value == undefined) {
13
+ response.removeHeader(String(name));
14
+ }
15
+ else {
16
+ response.header(String(name), value);
17
+ }
18
+ });
19
+ }
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@rest-vir/run-service",
3
+ "version": "0.0.2",
4
+ "description": "Run a service defined by @rest-vir/define-service and implemented by @rest-vir/implement-service.",
5
+ "keywords": [
6
+ "rest",
7
+ "api",
8
+ "express",
9
+ "service",
10
+ "backend",
11
+ "server",
12
+ "websocket",
13
+ "vir"
14
+ ],
15
+ "homepage": "https://github.com/electrovir/rest-vir",
16
+ "bugs": {
17
+ "url": "https://github.com/electrovir/rest-vir/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/electrovir/rest-vir.git"
22
+ },
23
+ "license": "(MIT or CC0 1.0)",
24
+ "author": {
25
+ "name": "electrovir",
26
+ "url": "https://github.com/electrovir"
27
+ },
28
+ "type": "module",
29
+ "main": "dist/index.js",
30
+ "module": "dist/index.js",
31
+ "types": "dist/index.d.ts",
32
+ "scripts": {
33
+ "compile": "virmator compile",
34
+ "docs": "md-code README.md",
35
+ "start": "tsx src/index.ts",
36
+ "test": "virmator test node",
37
+ "test:coverage": "npm run test coverage",
38
+ "test:docs": "npm run docs check",
39
+ "test:update": "npm test update"
40
+ },
41
+ "dependencies": {
42
+ "@augment-vir/assert": "^31.9.1",
43
+ "@augment-vir/common": "^31.9.1",
44
+ "@augment-vir/node": "^31.9.1",
45
+ "@fastify/websocket": "^11.0.2",
46
+ "@rest-vir/define-service": "^0.0.2",
47
+ "@rest-vir/implement-service": "^0.0.2",
48
+ "cluster-vir": "^0.1.0",
49
+ "date-vir": "^7.2.0",
50
+ "fastify": "^5.2.1",
51
+ "light-my-request": "^6.6.0",
52
+ "object-shape-tester": "^5.1.1",
53
+ "portfinder": "^1.0.32",
54
+ "type-fest": "^4.35.0",
55
+ "url-vir": "^2.1.1"
56
+ },
57
+ "devDependencies": {
58
+ "@augment-vir/test": "^31.9.1",
59
+ "@types/connect": "^3.4.38",
60
+ "@types/node": "^22.13.4",
61
+ "@types/ws": "^8.5.14",
62
+ "c8": "^10.1.3",
63
+ "istanbul-smart-text-reporter": "^1.1.5",
64
+ "markdown-code-example-inserter": "^3.0.3"
65
+ },
66
+ "engines": {
67
+ "node": ">=22"
68
+ },
69
+ "publishConfig": {
70
+ "access": "public"
71
+ }
72
+ }