@travetto/cli 7.0.7 → 7.1.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.
package/README.md CHANGED
@@ -472,14 +472,14 @@ import type { WebHttpServer } from '../src/types.ts';
472
472
  /**
473
473
  * Run a web server
474
474
  */
475
- @CliCommand({ runTarget: true, with: { debugIpc: 'optional', restartOnChange: true, module: true, env: true } })
475
+ @CliCommand({ runTarget: true, with: { debugIpc: 'optional', restartOnChange: true, module: true, profiles: true } })
476
476
  export class WebHttpCommand implements CliCommandShape {
477
477
 
478
478
  /** Port to run on */
479
479
  port?: number;
480
480
 
481
481
  /** Kill conflicting port owner */
482
- killConflict?: boolean = Runtime.envType === 'development';
482
+ killConflict?: boolean = Runtime.localDevelopment;
483
483
 
484
484
  preMain(): void {
485
485
  if (this.port) {
@@ -506,7 +506,7 @@ export class WebHttpCommand implements CliCommandShape {
506
506
  }
507
507
  ```
508
508
 
509
- As noted in the example above, `fields` is specified in this execution, with support for `module`, and `env`. These env flag is directly tied to the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime/src/context.ts#L12) `name` defined in the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime#readme "Runtime for travetto applications.") module.
509
+ As noted in the example above, `fields` is specified in this execution, with support for `module`, and `env`. These env flag is directly tied to the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime/src/context.ts#L13) `name` defined in the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime#readme "Runtime for travetto applications.") module.
510
510
 
511
511
  The `module` field is slightly more complex, but is geared towards supporting commands within a monorepo context. This flag ensures that a module is specified if running from the root of the monorepo, and that the module provided is real, and can run the desired command. When running from an explicit module folder in the monorepo, the module flag is ignored.
512
512
 
package/bin/trv.js CHANGED
@@ -2,4 +2,4 @@
2
2
  // @ts-check
3
3
  import '@travetto/compiler/bin/hook.js';
4
4
  const { invoke } = await import('@travetto/compiler/support/invoke.ts');
5
- invoke('exec', ['@travetto/cli/support/entry.trv.js', ...process.argv.slice(2)]);
5
+ await invoke('exec', ['@travetto/cli/support/entry.trv.js', ...process.argv.slice(2)]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/cli",
3
- "version": "7.0.7",
3
+ "version": "7.1.0",
4
4
  "type": "module",
5
5
  "description": "CLI infrastructure for Travetto framework",
6
6
  "keywords": [
@@ -29,8 +29,8 @@
29
29
  "directory": "module/cli"
30
30
  },
31
31
  "dependencies": {
32
- "@travetto/schema": "^7.0.6",
33
- "@travetto/terminal": "^7.0.5"
32
+ "@travetto/schema": "^7.1.0",
33
+ "@travetto/terminal": "^7.1.0"
34
34
  },
35
35
  "travetto": {
36
36
  "displayName": "Command Line Interface",
package/src/error.ts CHANGED
@@ -23,8 +23,8 @@ export class CliUnknownCommandError extends Error {
23
23
  #getMissingCommandHelp(cmd: string): string | undefined {
24
24
  const matchedConfig = COMMAND_PACKAGE.find(([regex]) => regex.test(cmd));
25
25
  if (matchedConfig) {
26
- const [, pkg, prod] = matchedConfig;
27
- const install = PackageUtil.getInstallCommand(Runtime, `@travetto/${pkg}`, prod);
26
+ const [, pkg, production] = matchedConfig;
27
+ const install = PackageUtil.getInstallCommand(Runtime, `@travetto/${pkg}`, production);
28
28
  return cliTpl`
29
29
  ${{ title: 'Missing Package' }}\n${'-'.repeat(20)}\nTo use ${{ input: cmd }} please run:\n
30
30
  ${{ identifier: install }}
package/src/execute.ts CHANGED
@@ -75,7 +75,7 @@ export class ExecutionManager {
75
75
  } catch (error) {
76
76
  await this.#onError(error);
77
77
  } finally {
78
- await ShutdownManager.gracefulShutdown('@travetto/cli:execute');
78
+ await ShutdownManager.shutdown();
79
79
  }
80
80
  }
81
81
  }
@@ -7,14 +7,14 @@ import { CliModuleUtil } from '../module.ts';
7
7
  import { CliParseUtil } from '../parse.ts';
8
8
  import { CliUtil } from '../util.ts';
9
9
 
10
- type Cmd = CliCommandShape & { env?: string };
10
+ type Cmd = CliCommandShape & { profiles?: string[] };
11
11
 
12
12
  type CliCommandConfigOptions = {
13
13
  runTarget?: boolean;
14
14
  runtimeModule?: 'current' | 'command';
15
15
  with?: {
16
16
  /** Application environment */
17
- env?: boolean;
17
+ profiles?: boolean;
18
18
  /** Module to run for */
19
19
  module?: boolean;
20
20
  /** Should debug invocation trigger via ipc */
@@ -32,15 +32,15 @@ type WithHandler<K extends keyof WithConfig> = (config?: WithConfig[K]) => ({
32
32
  } | undefined);
33
33
 
34
34
  const FIELD_CONFIG: { [K in keyof WithConfig]: WithHandler<K> } = {
35
- env: (config) => {
35
+ profiles: (config) => {
36
36
  if (!config) { return; }
37
37
  return {
38
- name: 'env',
39
- run: cmd => Env.TRV_ENV.set(cmd.env || Runtime.env),
38
+ name: 'profiles',
39
+ run: cmd => cmd.profiles && Env.TRV_PROFILES.set([...cmd.profiles, ...(Env.TRV_PROFILES.list ?? [])]),
40
40
  field: {
41
41
  type: String,
42
- aliases: ['-e', CliParseUtil.toEnvField(Env.TRV_ENV.key)],
43
- description: 'Application environment',
42
+ aliases: ['--profile', '--profiles', CliParseUtil.toEnvField(Env.TRV_PROFILES.key)],
43
+ description: 'Application profiles',
44
44
  required: { active: false },
45
45
  },
46
46
  };
@@ -62,7 +62,7 @@ const FIELD_CONFIG: { [K in keyof WithConfig]: WithHandler<K> } = {
62
62
  if (!config) { return; }
63
63
  return {
64
64
  name: 'debugIpc',
65
- run: cmd => CliUtil.runWithDebugIpc(cmd).then((executed) => executed && process.exit(0)),
65
+ run: cmd => CliUtil.runWithDebugIpc(cmd),
66
66
  field: {
67
67
  type: Boolean,
68
68
  aliases: ['-di', CliParseUtil.toEnvField(Env.TRV_DEBUG_IPC.key)],
@@ -79,9 +79,9 @@ const FIELD_CONFIG: { [K in keyof WithConfig]: WithHandler<K> } = {
79
79
  run: cmd => CliUtil.runWithRestartOnChange(cmd),
80
80
  field: {
81
81
  type: Boolean,
82
- aliases: ['-rc', CliParseUtil.toEnvField(Env.TRV_RESTART_ON_CHANGE.key)],
82
+ aliases: ['-rc'],
83
83
  description: 'Should the invocation automatically restart on source changes',
84
- default: config !== 'optional' && Runtime.envType === 'development',
84
+ default: config !== 'optional' && Runtime.localDevelopment,
85
85
  required: { active: false },
86
86
  },
87
87
  };
@@ -41,7 +41,7 @@ export class CliCommandRegistryIndex implements RegistryIndex {
41
41
  if (!this.#fileMapping) {
42
42
  const all = new Map<string, string>();
43
43
  for (const entry of RuntimeIndex.find({
44
- module: module => !Runtime.production || module.prod,
44
+ module: module => !Runtime.production || module.production,
45
45
  folder: folder => folder === 'support',
46
46
  file: file => file.role === 'std' && CLI_FILE_REGEX.test(file.sourceFile)
47
47
  })) {
package/src/trv.d.ts CHANGED
@@ -8,9 +8,9 @@ declare module '@travetto/runtime' {
8
8
  */
9
9
  TRV_CLI_IPC: string;
10
10
  /**
11
- * Overrides behavior for allowing restart on changes
11
+ * Signals to the child they are the restart target
12
12
  */
13
- TRV_RESTART_ON_CHANGE: boolean;
13
+ TRV_RESTART_TARGET: boolean;
14
14
  /**
15
15
  * Overrides behavior for triggering debug session via IPC
16
16
  */
package/src/types.ts CHANGED
@@ -80,9 +80,9 @@ export interface CliCommandShape<T extends unknown[] = unknown[]> {
80
80
  */
81
81
  export type CliCommandShapeFields = {
82
82
  /**
83
- * Environment to run in
83
+ * Profiles to run the application under
84
84
  */
85
- env?: string;
85
+ profiles?: string[];
86
86
  /**
87
87
  * Should the cli invocation trigger a debug session, via IPC
88
88
  */
package/src/util.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { spawn, type ChildProcess } from 'node:child_process';
2
2
 
3
- import { Env, ExecUtil, Runtime, ShutdownManager, Util, WatchUtil } from '@travetto/runtime';
3
+ import { AppError, Env, ExecUtil, Runtime, ShutdownManager, Util, WatchUtil } from '@travetto/runtime';
4
4
 
5
5
  import type { CliCommandShape, CliCommandShapeFields } from './types.ts';
6
6
 
@@ -28,53 +28,57 @@ export class CliUtil {
28
28
  /**
29
29
  * Run a command as restartable, linking into self
30
30
  */
31
- static async runWithRestartOnChange<T extends CliCommandShapeFields>(cmd: T): Promise<boolean> {
32
- if (cmd.restartOnChange !== true) {
33
- WatchUtil.listenForRestartSignal();
34
- return false;
31
+ static async runWithRestartOnChange<T extends CliCommandShapeFields>(cmd: T): Promise<void> {
32
+ if (Env.TRV_RESTART_TARGET.isTrue) {
33
+ Env.TRV_RESTART_TARGET.clear();
34
+ WatchUtil.listenForSignals();
35
+ return;
36
+ } else if (cmd.restartOnChange !== true) {
37
+ return; // Not restarting, run normal
35
38
  }
36
39
 
37
- let subProcess: ChildProcess | undefined;
38
- void WatchUtil.watchCompilerEvents('file', () => WatchUtil.triggerRestartSignal(subProcess));
40
+ ShutdownManager.disableInterrupt();
39
41
 
40
- const env = { ...process.env, ...Env.TRV_RESTART_ON_CHANGE.export(false) };
42
+ let child: ChildProcess | undefined;
43
+ void WatchUtil.watchCompilerEvents('file', () => child && WatchUtil.triggerSignal(child, 'WATCH_RESTART'));
44
+ process.on('SIGINT', () => child && WatchUtil.triggerSignal(child, 'WATCH_SHUTDOWN'));
41
45
 
42
- const log = (msg: string, extra?: Record<string, unknown>): void => {
43
- console.error(`[cli-restart] ${msg}`, { pid: process.pid, ...extra });
44
- };
46
+ const env = { ...process.env, ...Env.TRV_RESTART_TARGET.export(true) };
45
47
 
46
48
  await WatchUtil.runWithRetry(
47
49
  async () => {
48
- const { code } = await ExecUtil.deferToSubprocess(
49
- subProcess = spawn(process.argv0, process.argv.slice(1), { env, stdio: [0, 1, 2, 'ipc'] }),
50
- );
50
+ child = spawn(process.argv0, process.argv.slice(1), { env, stdio: ['pipe', 1, 2, 'ipc'] });
51
+ const { code } = await ExecUtil.deferToSubprocess(child);
51
52
  return WatchUtil.exitCodeToResult(code);
52
53
  },
53
54
  {
54
55
  maxRetries: 5,
55
56
  onRetry: async (state, config) => {
56
57
  const duration = WatchUtil.computeRestartDelay(state, config);
57
- log('Restarting subprocess due to change...', { waiting: duration, iteration: state.iteration, errorIterations: state.errorIterations || undefined });
58
+ console.error(
59
+ '[cli-restart] Restarting subprocess due to change...',
60
+ { waiting: duration, iteration: state.iteration, errorIterations: state.errorIterations || undefined }
61
+ );
58
62
  await Util.nonBlockingTimeout(duration);
59
63
  },
60
- });
64
+ }
65
+ );
61
66
 
62
- await ShutdownManager.gracefulShutdown('cli-restart');
63
- process.exit();
67
+ await ShutdownManager.shutdown();
64
68
  }
65
69
 
66
70
  /**
67
71
  * Dispatch IPC payload
68
72
  */
69
- static async runWithDebugIpc<T extends CliCommandShapeFields & CliCommandShape>(cmd: T): Promise<boolean> {
73
+ static async runWithDebugIpc<T extends CliCommandShapeFields & CliCommandShape>(cmd: T): Promise<void> {
70
74
  if (cmd.debugIpc !== true || !Env.TRV_CLI_IPC.isSet) {
71
- return false;
75
+ return; // Not debugging, run normal
72
76
  }
73
77
 
74
78
  const info = await fetch(Env.TRV_CLI_IPC.value!).catch(() => ({ ok: false }));
75
79
 
76
- if (!info.ok) { // Server not running
77
- return false;
80
+ if (!info.ok) {
81
+ return; // Server not running, run normal
78
82
  }
79
83
 
80
84
  const env: Record<string, string> = {};
@@ -91,7 +95,10 @@ export class CliUtil {
91
95
 
92
96
  Object.entries(process.env).forEach(([key, value]) => validEnv(key) && (env[key] = value!));
93
97
  const sent = await fetch(Env.TRV_CLI_IPC.value!, { method: 'POST', body: JSON.stringify(request) });
94
- return sent.ok;
98
+
99
+ if (!sent.ok) {
100
+ throw new AppError(`IPC Request failed: ${sent.status} ${await sent.text()}`);
101
+ }
95
102
  }
96
103
 
97
104
  /**