@travetto/runtime 7.1.2 → 7.1.4
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/README.md +3 -3
- package/package.json +3 -3
- package/src/context.ts +9 -5
- package/src/exec.ts +7 -19
- package/src/shutdown.ts +14 -19
package/README.md
CHANGED
|
@@ -51,8 +51,6 @@ class $Runtime {
|
|
|
51
51
|
get monoRoot(): boolean;
|
|
52
52
|
/** Main source path */
|
|
53
53
|
get mainSourcePath(): string;
|
|
54
|
-
/** Get trv entrypoint */
|
|
55
|
-
get trvEntryPoint(): string;
|
|
56
54
|
/** Produce a workspace relative path */
|
|
57
55
|
workspaceRelative(...parts: string[]): string;
|
|
58
56
|
/** Strip off the workspace path from a file */
|
|
@@ -69,6 +67,8 @@ class $Runtime {
|
|
|
69
67
|
getImport(handle: Function): string;
|
|
70
68
|
/** Import from a given path */
|
|
71
69
|
async importFrom<T = unknown>(location?: string): Promise<T>;
|
|
70
|
+
/** Get an install command for a given npm module */
|
|
71
|
+
getInstallCommand(pkg: string, production = false): string;
|
|
72
72
|
}
|
|
73
73
|
```
|
|
74
74
|
|
|
@@ -323,7 +323,7 @@ export class TimeUtil {
|
|
|
323
323
|
```
|
|
324
324
|
|
|
325
325
|
## Process Execution
|
|
326
|
-
[ExecUtil](https://github.com/travetto/travetto/tree/main/module/runtime/src/exec.ts#
|
|
326
|
+
[ExecUtil](https://github.com/travetto/travetto/tree/main/module/runtime/src/exec.ts#L41) exposes `getResult` as a means to wrap [child_process](https://nodejs.org/api/child_process.html)'s process object. This wrapper allows for a promise-based resolution of the subprocess with the ability to capture the stderr/stdout.
|
|
327
327
|
|
|
328
328
|
A simple example would be:
|
|
329
329
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/runtime",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Runtime for travetto applications.",
|
|
6
6
|
"keywords": [
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"directory": "module/runtime"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@travetto/manifest": "^7.1.
|
|
29
|
+
"@travetto/manifest": "^7.1.3",
|
|
30
30
|
"@types/debug": "^4.1.12",
|
|
31
31
|
"debug": "^4.4.3"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@travetto/transformer": "^7.1.
|
|
34
|
+
"@travetto/transformer": "^7.1.3"
|
|
35
35
|
},
|
|
36
36
|
"peerDependenciesMeta": {
|
|
37
37
|
"@travetto/transformer": {
|
package/src/context.ts
CHANGED
|
@@ -68,11 +68,6 @@ class $Runtime {
|
|
|
68
68
|
return this.#idx.mainModule.sourcePath;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
/** Get trv entrypoint */
|
|
72
|
-
get trvEntryPoint(): string {
|
|
73
|
-
return this.workspaceRelative('node_modules', '.bin', 'trv');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
71
|
/** Produce a workspace relative path */
|
|
77
72
|
workspaceRelative(...parts: string[]): string {
|
|
78
73
|
return path.resolve(this.workspace.path, ...parts);
|
|
@@ -141,6 +136,15 @@ class $Runtime {
|
|
|
141
136
|
const imported = await import(location);
|
|
142
137
|
return imported;
|
|
143
138
|
}
|
|
139
|
+
|
|
140
|
+
/** Get an install command for a given npm module */
|
|
141
|
+
getInstallCommand(pkg: string, production = false): string {
|
|
142
|
+
switch (this.workspace.manager) {
|
|
143
|
+
case 'npm': return `npm install ${production ? '' : '--save-dev '}${pkg}`;
|
|
144
|
+
case 'yarn': return `yarn add ${production ? '' : '--dev '}${pkg}`;
|
|
145
|
+
case 'pnpm': return `pnpm add ${production ? '' : '--dev '}${pkg}`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
144
148
|
}
|
|
145
149
|
|
|
146
150
|
export const Runtime = new $Runtime(RuntimeIndex, Env.TRV_RESOURCE_OVERRIDES.object);
|
package/src/exec.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { type ChildProcess } from 'node:child_process';
|
|
1
|
+
import { type ChildProcess, spawn, type SpawnOptions } from 'node:child_process';
|
|
2
2
|
import type { Readable } from 'node:stream';
|
|
3
3
|
import { createInterface } from 'node:readline/promises';
|
|
4
4
|
|
|
5
5
|
import { castTo } from './types.ts';
|
|
6
|
+
import { RuntimeIndex } from './manifest-index.ts';
|
|
6
7
|
|
|
7
8
|
const ResultSymbol = Symbol();
|
|
8
9
|
|
|
@@ -39,24 +40,6 @@ type ExecutionBaseResult = Omit<ExecutionResult, 'stdout' | 'stderr'>;
|
|
|
39
40
|
*/
|
|
40
41
|
export class ExecUtil {
|
|
41
42
|
|
|
42
|
-
/**
|
|
43
|
-
* Defer control to subprocess execution, mainly used for nested execution
|
|
44
|
-
*/
|
|
45
|
-
static async deferToSubprocess(child: ChildProcess): Promise<ExecutionResult> {
|
|
46
|
-
const messageToChild = (value: unknown): void => { child.send(value!); };
|
|
47
|
-
const messageToParent = (value: unknown): void => { process.send?.(value); };
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
process.on('message', messageToChild);
|
|
51
|
-
child.on('message', messageToParent);
|
|
52
|
-
const result = await this.getResult(child, { catch: true });
|
|
53
|
-
process.exitCode = child.exitCode;
|
|
54
|
-
return result;
|
|
55
|
-
} finally {
|
|
56
|
-
process.off('message', messageToChild);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
43
|
/**
|
|
61
44
|
* Take a child process, and some additional options, and produce a promise that
|
|
62
45
|
* represents the entire execution. On successful completion the promise will resolve, and
|
|
@@ -128,4 +111,9 @@ export class ExecUtil {
|
|
|
128
111
|
await handler(item);
|
|
129
112
|
}
|
|
130
113
|
}
|
|
114
|
+
|
|
115
|
+
/** Spawn a package command */
|
|
116
|
+
static spawnPackageCommand(cmd: string, args: string[], config: SpawnOptions = {}): ChildProcess {
|
|
117
|
+
return spawn(process.argv0, [RuntimeIndex.resolvePackageCommand(cmd), ...args], config);
|
|
118
|
+
}
|
|
131
119
|
}
|
package/src/shutdown.ts
CHANGED
|
@@ -11,8 +11,7 @@ const REASON_TO_CODE = new Map<ShutdownReason, number>(MAPPING);
|
|
|
11
11
|
const CODE_TO_REASON = new Map<number, ShutdownReason>(MAPPING.map(([k, v]) => [v, k]));
|
|
12
12
|
|
|
13
13
|
type Handler = (event: Event) => unknown;
|
|
14
|
-
type
|
|
15
|
-
type ShutdownEvent = { signal?: ShutdownSignal, reason?: ShutdownReason | number, exit?: boolean };
|
|
14
|
+
type ShutdownEvent = { reason?: ShutdownReason, mode?: 'exit' | 'interrupt' };
|
|
16
15
|
|
|
17
16
|
const isShutdownEvent = (event: unknown): event is ShutdownEvent =>
|
|
18
17
|
typeof event === 'object' && event !== null && 'type' in event && event.type === 'shutdown';
|
|
@@ -36,11 +35,12 @@ export class ShutdownManager {
|
|
|
36
35
|
static {
|
|
37
36
|
this.#controller.signal.addEventListener = (_: 'abort', listener: Handler): void => { this.#registered.add(listener); };
|
|
38
37
|
this.#controller.signal.removeEventListener = (_: 'abort', listener: Handler): void => { this.#registered.delete(listener); };
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
try {
|
|
39
|
+
process
|
|
40
|
+
.on('message', event => { isShutdownEvent(event) && this.shutdown(event); })
|
|
41
|
+
.on('SIGINT', () => this.shutdown({ mode: 'interrupt' }))
|
|
42
|
+
.on('SIGTERM', () => this.shutdown());
|
|
43
|
+
} catch { }
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
static get signal(): AbortSignal {
|
|
@@ -66,29 +66,24 @@ export class ShutdownManager {
|
|
|
66
66
|
/**
|
|
67
67
|
* Shutdown the application gracefully
|
|
68
68
|
*/
|
|
69
|
-
static async shutdown(
|
|
70
|
-
if ((
|
|
69
|
+
static async shutdown({ reason = 'quit', mode = undefined }: ShutdownEvent = {}): Promise<void> {
|
|
70
|
+
if ((mode === 'interrupt' && this.#shouldIgnoreInterrupt) || this.#controller.signal.aborted) {
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
process // Allow shutdown if anything is still listening
|
|
75
75
|
.removeAllListeners('message')
|
|
76
76
|
.removeAllListeners('SIGINT')
|
|
77
|
-
.removeAllListeners('SIGTERM')
|
|
78
|
-
.removeAllListeners('SIGUSR2');
|
|
77
|
+
.removeAllListeners('SIGTERM');
|
|
79
78
|
|
|
80
|
-
if (
|
|
79
|
+
if (mode === 'interrupt' && process.stdout.isTTY) {
|
|
81
80
|
process.stdout.write('\n');
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
const { reason } = event;
|
|
86
|
-
process.exitCode = (typeof reason === 'string' ? REASON_TO_CODE.get(reason) : reason);
|
|
87
|
-
}
|
|
83
|
+
process.exitCode ??= REASON_TO_CODE.get(reason);
|
|
88
84
|
|
|
89
85
|
const timeout = TimeUtil.fromValue(Env.TRV_SHUTDOWN_WAIT.value) ?? 2000;
|
|
90
|
-
const context = {
|
|
91
|
-
|
|
86
|
+
const context = { reason, mode, pid: process.pid, timeout, pending: this.#registered.size };
|
|
92
87
|
this.#controller.abort('Shutdown started');
|
|
93
88
|
console.debug('Shutdown started', context);
|
|
94
89
|
|
|
@@ -103,7 +98,7 @@ export class ShutdownManager {
|
|
|
103
98
|
console.warn('Shutdown timed out', context);
|
|
104
99
|
}
|
|
105
100
|
|
|
106
|
-
if (
|
|
101
|
+
if (mode === 'exit') {
|
|
107
102
|
process.exit();
|
|
108
103
|
}
|
|
109
104
|
}
|