@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.
- package/LICENSE-CC0 +121 -0
- package/LICENSE-MIT +21 -0
- package/README.md +23 -0
- package/dist/handle-request/endpoint-handler.d.ts +76 -0
- package/dist/handle-request/endpoint-handler.js +29 -0
- package/dist/handle-request/handle-cors.d.ts +37 -0
- package/dist/handle-request/handle-cors.js +141 -0
- package/dist/handle-request/handle-endpoint.d.ts +13 -0
- package/dist/handle-request/handle-endpoint.js +62 -0
- package/dist/handle-request/handle-request-method.d.ts +26 -0
- package/dist/handle-request/handle-request-method.js +33 -0
- package/dist/handle-request/handle-route.d.ts +15 -0
- package/dist/handle-request/handle-route.js +65 -0
- package/dist/handle-request/handle-search-params.d.ts +33 -0
- package/dist/handle-request/handle-search-params.js +32 -0
- package/dist/handle-request/handle-web-socket.d.ts +15 -0
- package/dist/handle-request/handle-web-socket.js +65 -0
- package/dist/handle-request/pre-handler.d.ts +18 -0
- package/dist/handle-request/pre-handler.js +123 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +17 -0
- package/dist/start-service/attach-service.d.ts +45 -0
- package/dist/start-service/attach-service.js +124 -0
- package/dist/start-service/start-service-options.d.ts +83 -0
- package/dist/start-service/start-service-options.js +73 -0
- package/dist/start-service/start-service.d.ts +63 -0
- package/dist/start-service/start-service.js +85 -0
- package/dist/util/debug.d.ts +11 -0
- package/dist/util/debug.js +16 -0
- package/dist/util/headers.d.ts +11 -0
- package/dist/util/headers.js +19 -0
- 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
|
+
}
|