@idlebox/node 1.4.11 → 1.4.13

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 (45) hide show
  1. package/lib/asyncLoad.d.ts +1 -0
  2. package/lib/asyncLoad.d.ts.map +1 -1
  3. package/lib/asyncLoad.js +3 -2
  4. package/lib/asyncLoad.js.map +1 -1
  5. package/lib/autoindex.d.ts +73 -76
  6. package/lib/autoindex.d.ts.map +1 -1
  7. package/lib/autoindex.js +65 -68
  8. package/lib/autoindex.js.map +1 -1
  9. package/lib/child_process/respawn.d.ts +2 -0
  10. package/lib/child_process/respawn.d.ts.map +1 -1
  11. package/lib/child_process/respawn.js +2 -0
  12. package/lib/child_process/respawn.js.map +1 -1
  13. package/lib/fs/exists.js +1 -1
  14. package/lib/fs/exists.js.map +1 -1
  15. package/lib/lifecycle/register.d.ts +11 -1
  16. package/lib/lifecycle/register.d.ts.map +1 -1
  17. package/lib/lifecycle/register.js +152 -51
  18. package/lib/lifecycle/register.js.map +1 -1
  19. package/lib/lifecycle/workingDirectory.d.ts +11 -0
  20. package/lib/lifecycle/workingDirectory.d.ts.map +1 -0
  21. package/lib/lifecycle/workingDirectory.js +40 -0
  22. package/lib/lifecycle/workingDirectory.js.map +1 -0
  23. package/lib/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +10 -11
  25. package/src/asyncLoad.ts +3 -2
  26. package/src/autoindex.ts +109 -115
  27. package/src/child_process/respawn.ts +2 -0
  28. package/src/fs/exists.ts +1 -1
  29. package/src/lifecycle/register.ts +152 -53
  30. package/src/lifecycle/workingDirectory.ts +45 -0
  31. package/lib/autoindex.generated.d.ts +0 -80
  32. package/lib/autoindex.generated.d.ts.map +0 -1
  33. package/lib/autoindex.generated.js +0 -132
  34. package/lib/autoindex.generated.js.map +0 -1
  35. package/lib/error/linux.d.ts +0 -125
  36. package/lib/error/linux.d.ts.map +0 -1
  37. package/lib/error/linux.js +0 -126
  38. package/lib/error/linux.js.map +0 -1
  39. package/lib/error/types.d.ts +0 -24
  40. package/lib/error/types.d.ts.map +0 -1
  41. package/lib/error/types.js +0 -25
  42. package/lib/error/types.js.map +0 -1
  43. package/src/autoindex.generated.ts +0 -159
  44. package/src/error/linux.ts +0 -124
  45. package/src/error/types.ts +0 -39
package/src/autoindex.ts CHANGED
@@ -3,151 +3,145 @@
3
3
  /* eslint-disable */
4
4
 
5
5
  /* asyncLoad.ts */
6
- // Identifiers
7
- export type { AsyncMainFunction } from './asyncLoad.js';
8
- export { executeMainFunction } from './asyncLoad.js';
6
+ // Identifiers
7
+ export type { AsyncMainFunction } from "./asyncLoad.js";
8
+ export { executeMainFunction } from "./asyncLoad.js";
9
9
  /* preload.ts */
10
- // Identifiers
10
+ // Identifiers
11
11
  /* child_process/error.ts */
12
- // Identifiers
13
- export { checkChildProcessResult } from './child_process/error.js';
12
+ // Identifiers
13
+ export { checkChildProcessResult } from "./child_process/error.js";
14
14
  /* child_process/execa.ts */
15
- // Identifiers
16
- export type { ICommand } from './child_process/execa.js';
17
- export { spawnWithoutOutputSync } from './child_process/execa.js';
18
- export { spawnWithoutOutput } from './child_process/execa.js';
19
- export { spawnGetOutputSync } from './child_process/execa.js';
20
- export { spawnGetOutput } from './child_process/execa.js';
21
- export { spawnGetEverything } from './child_process/execa.js';
15
+ // Identifiers
16
+ export type { ICommand } from "./child_process/execa.js";
17
+ export { spawnWithoutOutputSync } from "./child_process/execa.js";
18
+ export { spawnWithoutOutput } from "./child_process/execa.js";
19
+ export { spawnGetOutputSync } from "./child_process/execa.js";
20
+ export { spawnGetOutput } from "./child_process/execa.js";
21
+ export { spawnGetEverything } from "./child_process/execa.js";
22
22
  /* cli-io/output.ts */
23
- // Identifiers
24
- export { printLine } from './cli-io/output.js';
23
+ // Identifiers
24
+ export { printLine } from "./cli-io/output.js";
25
25
  /* child_process/lateError.ts */
26
- // Identifiers
27
- export type { ISpawnOptions } from './child_process/lateError.js';
28
- export type { ExecaReturnValue } from './child_process/lateError.js';
29
- export { execLazyError } from './child_process/lateError.js';
30
- /* error/linux.ts */
31
- // Identifiers
32
- export { LinuxError } from './error/linux.js';
33
- /* error/types.ts */
34
- // Identifiers
35
- export type { OpenSSLException } from './error/types.js';
36
- export { isModuleResolutionError } from './error/types.js';
37
- export { isNotExistsError } from './error/types.js';
38
- export { isExistsError } from './error/types.js';
39
- export { isTypeError } from './error/types.js';
40
- export { isFileTypeError } from './error/types.js';
41
- export { isNodeError } from './error/types.js';
42
- // References
43
- export * from '@idlebox/node-error-codes';
26
+ // Identifiers
27
+ export type { ISpawnOptions } from "./child_process/lateError.js";
28
+ export type { ExecaReturnValue } from "./child_process/lateError.js";
29
+ export { execLazyError } from "./child_process/lateError.js";
44
30
  /* fs/exists.ts */
45
- // Identifiers
46
- export { existsSync } from './fs/exists.js';
47
- export { exists } from './fs/exists.js';
48
- export { readFileIfExists } from './fs/exists.js';
31
+ // Identifiers
32
+ export { existsSync } from "./fs/exists.js";
33
+ export { exists } from "./fs/exists.js";
34
+ export { readFileIfExists } from "./fs/exists.js";
49
35
  /* environment/getEnvironment.ts */
50
- // Identifiers
51
- export type { IEnvironmentResult } from './environment/getEnvironment.js';
52
- export { getEnvironment } from './environment/getEnvironment.js';
53
- export { deleteEnvironment } from './environment/getEnvironment.js';
54
- export { cleanupEnvironment } from './environment/getEnvironment.js';
36
+ // Identifiers
37
+ export type { IEnvironmentResult } from "./environment/getEnvironment.js";
38
+ export { getEnvironment } from "./environment/getEnvironment.js";
39
+ export { deleteEnvironment } from "./environment/getEnvironment.js";
40
+ export { cleanupEnvironment } from "./environment/getEnvironment.js";
55
41
  /* environment/pathEnvironment.ts */
56
- // Identifiers
57
- export { PATH_SEPARATOR } from './environment/pathEnvironment.js';
58
- export { PathEnvironment } from './environment/pathEnvironment.js';
42
+ // Identifiers
43
+ export { PATH_SEPARATOR } from "./environment/pathEnvironment.js";
44
+ export { PathEnvironment } from "./environment/pathEnvironment.js";
59
45
  /* environment/findBinary.ts */
60
- // Identifiers
61
- export { findBinary } from './environment/findBinary.js';
46
+ // Identifiers
47
+ export { findBinary } from "./environment/findBinary.js";
62
48
  /* child_process/respawn.ts */
63
- // Identifiers
64
- export { spawnRecreateEventHandlers } from './child_process/respawn.js';
65
- export { trySpawnInScope } from './child_process/respawn.js';
66
- export { respawnInScope } from './child_process/respawn.js';
49
+ // Identifiers
50
+ export { spawnRecreateEventHandlers } from "./child_process/respawn.js";
51
+ export { trySpawnInScope } from "./child_process/respawn.js";
52
+ export { respawnInScope } from "./child_process/respawn.js";
67
53
  /* crypto/md5.ts */
68
- // Identifiers
69
- export { md5 } from './crypto/md5.js';
54
+ // Identifiers
55
+ export { md5 } from "./crypto/md5.js";
70
56
  /* crypto/sha256.ts */
71
- // Identifiers
72
- export { sha256 } from './crypto/sha256.js';
57
+ // Identifiers
58
+ export { sha256 } from "./crypto/sha256.js";
73
59
  /* environment/npmConfig.ts */
74
- // Identifiers
75
- export { getNpmConfigValue } from './environment/npmConfig.js';
60
+ // Identifiers
61
+ export { getNpmConfigValue } from "./environment/npmConfig.js";
76
62
  /* events/dumpEventEmitter.ts */
77
- // Identifiers
78
- export { dumpEventEmitterEmit } from './events/dumpEventEmitter.js';
63
+ // Identifiers
64
+ export { dumpEventEmitterEmit } from "./events/dumpEventEmitter.js";
79
65
  /* fs/commandExists.ts */
80
- // Identifiers
81
- export { commandInPath } from './fs/commandExists.js';
82
- export { commandInPathSync } from './fs/commandExists.js';
66
+ // Identifiers
67
+ export { commandInPath } from "./fs/commandExists.js";
68
+ export { commandInPathSync } from "./fs/commandExists.js";
83
69
  /* fs/emptyDir.ts */
84
- // Identifiers
85
- export { emptyDir } from './fs/emptyDir.js';
70
+ // Identifiers
71
+ export { emptyDir } from "./fs/emptyDir.js";
86
72
  /* fs/ensureDir.ts */
87
- // Identifiers
88
- export { ensureDirExists } from './fs/ensureDir.js';
89
- export { ensureParentExists } from './fs/ensureDir.js';
73
+ // Identifiers
74
+ export { ensureDirExists } from "./fs/ensureDir.js";
75
+ export { ensureParentExists } from "./fs/ensureDir.js";
90
76
  /* fs/tempFolder.ts */
91
- // Identifiers
92
- export { createTempFolder } from './fs/tempFolder.js';
77
+ // Identifiers
78
+ export { createTempFolder } from "./fs/tempFolder.js";
93
79
  /* fs/weiteChanged.ts */
94
- // Identifiers
95
- export { writeFileIfChangeSync } from './fs/weiteChanged.js';
96
- export { writeFileIfChange } from './fs/weiteChanged.js';
80
+ // Identifiers
81
+ export { writeFileIfChangeSync } from "./fs/weiteChanged.js";
82
+ export { writeFileIfChange } from "./fs/weiteChanged.js";
97
83
  /* lifecycle/register.ts */
98
- // Identifiers
99
- export { shutdown } from './lifecycle/register.js';
100
- export { registerNodejsExitHandler } from './lifecycle/register.js';
101
- export { die } from './lifecycle/register.js';
84
+ // Identifiers
85
+ export { setExitCodeIfNot } from "./lifecycle/register.js";
86
+ export { shutdown } from "./lifecycle/register.js";
87
+ export { registerNodejsGlobalTypedErrorHandlerWithInheritance } from "./lifecycle/register.js";
88
+ export { registerNodejsGlobalTypedErrorHandler } from "./lifecycle/register.js";
89
+ export { registerNodejsExitHandler } from "./lifecycle/register.js";
90
+ export { die } from "./lifecycle/register.js";
91
+ /* lifecycle/workingDirectory.ts */
92
+ // Identifiers
93
+ export { workingDirectory } from "./lifecycle/workingDirectory.js";
102
94
  /* log/terminal.ts */
103
- // Identifiers
104
- export { WrappedTerminalConsole } from './log/terminal.js';
95
+ // Identifiers
96
+ export { WrappedTerminalConsole } from "./log/terminal.js";
105
97
  /* path-resolve/findUp.ts */
106
- // Identifiers
107
- export type { IFindOptions } from './path-resolve/findUp.js';
108
- export { findUpUntil } from './path-resolve/findUp.js';
109
- export { findUpUntilSync } from './path-resolve/findUp.js';
98
+ // Identifiers
99
+ export type { IFindOptions } from "./path-resolve/findUp.js";
100
+ export { findUpUntil } from "./path-resolve/findUp.js";
101
+ export { findUp } from "./path-resolve/findUp.js";
102
+ export { findUpUntilSync } from "./path-resolve/findUp.js";
103
+ export { findUpSync } from "./path-resolve/findUp.js";
110
104
  /* path-resolve/findPackageRoot.ts */
111
- // Identifiers
112
- export { findPackageRoot } from './path-resolve/findPackageRoot.js';
105
+ // Identifiers
106
+ export { findPackageRoot } from "./path-resolve/findPackageRoot.js";
113
107
  /* path-resolve/getAllUp.ts */
114
- // Identifiers
115
- export { getAllPathUpToRoot } from './path-resolve/getAllUp.js';
108
+ // Identifiers
109
+ export { getAllPathUpToRoot } from "./path-resolve/getAllUp.js";
116
110
  /* path-resolve/lrelative.ts */
117
- // Identifiers
118
- export { lrelative } from './path-resolve/lrelative.js';
111
+ // Identifiers
112
+ export { lrelative } from "./path-resolve/lrelative.js";
119
113
  /* path-resolve/nodeResolvePathArray.ts */
120
- // Identifiers
121
- export { nodeResolvePathArray } from './path-resolve/nodeResolvePathArray.js';
114
+ // Identifiers
115
+ export { nodeResolvePathArray } from "./path-resolve/nodeResolvePathArray.js";
122
116
  /* path-resolve/resolvePath.ts */
123
- // Identifiers
124
- export type { ResolvePathFunction } from './path-resolve/resolvePath.js';
125
- export type { JoinPathFunction } from './path-resolve/resolvePath.js';
126
- export { resolvePath } from './path-resolve/resolvePath.js';
127
- export type { NormalizePathFunction } from './path-resolve/resolvePath.js';
128
- export { normalizePath } from './path-resolve/resolvePath.js';
129
- export { osTempDir } from './path-resolve/resolvePath.js';
130
- export { relativePath } from './path-resolve/resolvePath.js';
117
+ // Identifiers
118
+ export type { ResolvePathFunction } from "./path-resolve/resolvePath.js";
119
+ export type { JoinPathFunction } from "./path-resolve/resolvePath.js";
120
+ export { resolvePath } from "./path-resolve/resolvePath.js";
121
+ export type { NormalizePathFunction } from "./path-resolve/resolvePath.js";
122
+ export { normalizePath } from "./path-resolve/resolvePath.js";
123
+ export { osTempDir } from "./path-resolve/resolvePath.js";
124
+ export { relativePath } from "./path-resolve/resolvePath.js";
131
125
  /* stream/blackHoleStream.ts */
132
- // Identifiers
133
- export { BlackHoleStream } from './stream/blackHoleStream.js';
126
+ // Identifiers
127
+ export { BlackHoleStream } from "./stream/blackHoleStream.js";
134
128
  /* stream/streamPromise.ts */
135
- // Identifiers
136
- export { streamPromise } from './stream/streamPromise.js';
137
- export { streamHasEnd } from './stream/streamPromise.js';
129
+ // Identifiers
130
+ export { streamPromise } from "./stream/streamPromise.js";
131
+ export { streamHasEnd } from "./stream/streamPromise.js";
138
132
  /* stream/collectingStream.ts */
139
- // Identifiers
140
- export { streamToBuffer } from './stream/collectingStream.js';
141
- export { RawCollectingStream } from './stream/collectingStream.js';
142
- export { CollectingStream } from './stream/collectingStream.js';
133
+ // Identifiers
134
+ export { streamToBuffer } from "./stream/collectingStream.js";
135
+ export { RawCollectingStream } from "./stream/collectingStream.js";
136
+ export { CollectingStream } from "./stream/collectingStream.js";
143
137
  /* stream/disposableStream.ts */
144
- // Identifiers
145
- export { disposableStream } from './stream/disposableStream.js';
138
+ // Identifiers
139
+ export { disposableStream } from "./stream/disposableStream.js";
146
140
  /* stream/drainStream.ts */
147
- // Identifiers
148
- export { drainStream } from './stream/drainStream.js';
141
+ // Identifiers
142
+ export { drainStream } from "./stream/drainStream.js";
149
143
  /* stream/loggerStream.ts */
150
- // Identifiers
151
- export type { LogFunction } from './stream/loggerStream.js';
152
- export { LoggerStream } from './stream/loggerStream.js';
153
- export { HexDumpLoggerStream } from './stream/loggerStream.js';
144
+ // Identifiers
145
+ export type { LogFunction } from "./stream/loggerStream.js";
146
+ export { LoggerStream } from "./stream/loggerStream.js";
147
+ export { HexDumpLoggerStream } from "./stream/loggerStream.js";
@@ -9,6 +9,7 @@ if (platform() === 'linux' && process.getuid?.() !== 0) {
9
9
  unshareArgs.push('--map-root-user');
10
10
  }
11
11
 
12
+ /** @deprecated */
12
13
  export function spawnRecreateEventHandlers() {
13
14
  process.on('SIGINT', () => shutdown_quit('SIGINT', 130));
14
15
  process.on('SIGTERM', () => shutdown_quit('SIGTERM', 143));
@@ -26,6 +27,7 @@ function shutdown_quit(signal: string, code: number) {
26
27
  /**
27
28
  * Spawn a command, replace current node process
28
29
  * If can't do that (eg. on Windows), spawn as normal, but quit self after it quit.
30
+ * @deprecated
29
31
  */
30
32
  export function trySpawnInScope(cmds: string[]): never {
31
33
  if (process.env.NEVER_UNSHARE || !process.execve || insideScope() || !supportScope()) {
package/src/fs/exists.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ObjectEncodingOptions } from 'node:fs';
2
2
  import { access, readFile } from 'node:fs/promises';
3
- import { isNotExistsError } from '../error/types.js';
3
+ import { isNotExistsError } from '@idlebox/errors';
4
4
  export { existsSync } from 'node:fs';
5
5
 
6
6
  export async function exists(path: string) {
@@ -1,13 +1,15 @@
1
1
  /** biome-ignore-all lint/suspicious/noDebugger: debug file */
2
2
 
3
- import { AppExit, ensureDisposeGlobal, ensureGlobalObject, prettyPrintError } from '@idlebox/common';
4
- import { createRequire, syncBuiltinESMExports } from 'node:module';
3
+ import { ensureDisposeGlobal, ensureGlobalObject, functionName, isProductionMode, prettyPrintError, type MyCallback } from '@idlebox/common';
4
+ import { ErrorWithCode, Exit, ExitCode, InterruptError, UncaughtException, UnhandledRejection } from '@idlebox/errors';
5
+ import assert from 'node:assert';
6
+ import { syncBuiltinESMExports } from 'node:module';
5
7
  import { basename } from 'node:path';
6
8
  import process from 'node:process';
9
+ import { inspect } from 'node:util';
7
10
 
8
- const originalExit = process.exit;
11
+ const originalExit: (code?: number) => never = process.exit;
9
12
  const prefix = process.stderr.isTTY ? '' : `<${title()} ${process.pid}> `;
10
- const hasInspect = process.argv.some((arg) => arg.startsWith('--inspect=') || arg.startsWith('--inspect-brk=') || arg === '--inspect' || arg === '--inspect-brk');
11
13
 
12
14
  function title() {
13
15
  if (process.title && process.title !== 'node') {
@@ -16,87 +18,181 @@ function title() {
16
18
  return basename(process.argv[1] || '') || 'node';
17
19
  }
18
20
 
19
- class Exit extends AppExit {
20
- constructor(code: number) {
21
- super(`process exit with code ${code}`, code);
21
+ function getCurrentCode() {
22
+ return typeof process.exitCode === 'string' ? parseInt(process.exitCode) : process.exitCode || 0;
23
+ }
24
+
25
+ export function setExitCodeIfNot(exitCode: number) {
26
+ if (exitCode || typeof process.exitCode !== 'number') {
27
+ process.exitCode = exitCode;
28
+ globalThis.process.exitCode = exitCode;
22
29
  }
23
30
  }
24
31
 
25
- const shuttingDown = false;
32
+ let shuttingDown = 0;
26
33
  export function shutdown(exitCode: number): never {
27
- if (hasInspect) debugger;
34
+ _shutdown(exitCode);
35
+ throw new Exit(getCurrentCode());
36
+ }
37
+ function _shutdown(exitCode: number) {
38
+ setExitCodeIfNot(exitCode);
39
+
40
+ if (!shuttingDown) {
41
+ shuttingDown = 1;
42
+ ensureDisposeGlobal().finally(() => {
43
+ originalExit(getCurrentCode());
44
+ });
45
+ } else {
46
+ shuttingDown++;
47
+ }
48
+ }
28
49
 
29
- if (exitCode) {
30
- process.exitCode = exitCode;
50
+ const typed_error_handlers = new WeakMap<ErrorConstructor, MyCallback<[Error]>>();
51
+ const inherit_error_handlers = new Map<ErrorConstructor, MyCallback<[Error]>>();
52
+
53
+ type ErrorConstructor = new (...args: any[]) => Error;
54
+
55
+ export function registerNodejsGlobalTypedErrorHandlerWithInheritance(ErrorCls: ErrorConstructor, fn: MyCallback<[Error]>) {
56
+ if (typed_error_handlers.has(ErrorCls)) {
57
+ throw new ErrorCls(`conflict register of error type ${ErrorCls.name}`);
58
+ }
59
+ assert.notEqual(ErrorCls, Error, 'cannot register basic Error type');
60
+ inherit_error_handlers.set(ErrorCls, fn);
61
+ }
62
+ export function registerNodejsGlobalTypedErrorHandler(ErrorCls: ErrorConstructor, fn: MyCallback<[Error]>) {
63
+ if (typed_error_handlers.has(ErrorCls)) {
64
+ throw new ErrorCls(`conflict register of error type ${ErrorCls.name}`);
65
+ }
66
+ assert.notEqual(ErrorCls, Error, 'cannot register basic Error type');
67
+ typed_error_handlers.set(ErrorCls, fn);
68
+ }
69
+
70
+ function uniqueErrorHandler(e: unknown, logger: IDebugOutput) {
71
+ if (!isProductionMode) logger.verbose?.(`uniqueErrorHandler:`);
72
+ if (!(e instanceof Error)) {
73
+ prettyPrintError(`${prefix}catch unexpect object`, new Error(`error object is ${typeof e} ${e ? (e as any).constructor?.name : 'unknown'}`));
74
+ throw originalExit(ExitCode.PROGRAM);
31
75
  }
32
- const code = typeof process.exitCode === 'string' ? parseInt(process.exitCode) : process.exitCode || 0;
33
76
 
34
- if (shuttingDown) {
35
- throw new Exit(code);
77
+ if (e instanceof Exit) {
78
+ if (!isProductionMode) logger.verbose?.(` - skip exit object`);
79
+ if (!shuttingDown) {
80
+ _shutdown(e.code);
81
+ }
82
+ throw e;
36
83
  }
37
84
 
38
- ensureDisposeGlobal().finally(() => {
39
- originalExit(process.exitCode);
40
- });
85
+ try {
86
+ const catcher = typed_error_handlers.get(e.constructor as ErrorConstructor);
87
+ if (catcher) {
88
+ if (!isProductionMode) logger.verbose?.(` - call catcher ${functionName(catcher)}`);
89
+ catcher(e);
90
+ return;
91
+ }
92
+ for (const [Cls, fn] of inherit_error_handlers) {
93
+ if (!isProductionMode) logger.verbose?.(` - call inherited catcher ${functionName(fn)}`);
94
+ if (e instanceof Cls) {
95
+ fn(e);
96
+ return;
97
+ }
98
+ }
99
+ } catch (ee: any) {
100
+ prettyPrintError(`${prefix}error while handle error`, {
101
+ message: ee.message,
102
+ stack: ee.stack,
103
+ cause: e,
104
+ });
105
+ return;
106
+ }
107
+
108
+ if (e instanceof InterruptError) {
109
+ if (!isProductionMode) logger.verbose?.(` - shuttingDown = ${shuttingDown}`);
110
+ if (shuttingDown > 5) {
111
+ logger.output(`${prefix}Exiting immediately.`);
112
+ originalExit(ExitCode.INTERRUPT);
113
+ }
41
114
 
42
- throw new Exit(code);
115
+ shutdown(ExitCode.INTERRUPT);
116
+ }
117
+ if (e instanceof UnhandledRejection) {
118
+ if (!isProductionMode) logger.verbose?.(` - UnhandledRejection`);
119
+ if (e.cause instanceof Error) {
120
+ prettyPrintError(`${prefix}Unhandled Rejection`, e.cause);
121
+ } else {
122
+ logger.output(`${prefix}Unhandled Rejection / error type unknown: ${inspect(e.cause)}`);
123
+ }
124
+ return;
125
+ }
126
+ if (e instanceof UncaughtException) {
127
+ if (!isProductionMode) logger.verbose?.(` - UncaughtException`);
128
+ prettyPrintError(`${prefix}Uncaught Exception`, e.cause);
129
+ return;
130
+ }
131
+
132
+ if (!isProductionMode) logger.verbose?.(` - common error`);
133
+ prettyPrintError(`${prefix}unhandled global exception`, e);
134
+ shutdown(ExitCode.PROGRAM);
135
+ }
136
+
137
+ interface IDebugOutput {
138
+ output(message: string): void;
139
+ verbose?(message: string): void;
43
140
  }
44
141
 
45
142
  /**
46
143
  * 注册nodejs退出处理器
47
144
  */
48
- export function registerNodejsExitHandler() {
49
- ensureGlobalObject('exithandler/register', _real_register);
145
+ export function registerNodejsExitHandler(logger: IDebugOutput = { output: console.error }) {
146
+ ensureGlobalObject('exithandler/register', () => _real_register(logger));
50
147
  }
51
- function _real_register() {
148
+ function _real_register(logger: IDebugOutput) {
149
+ logger.verbose?.(`register nodejs exit handler: production=${isProductionMode}`);
52
150
  process.on('SIGINT', () => {
53
- console.error(`\n${prefix}Received SIGINT. Exiting gracefully...`);
54
-
55
- if (shuttingDown) {
56
- console.error(`Exiting immediately.`);
57
- originalExit(1);
58
- }
59
-
60
- shutdown(0);
151
+ logger.output(`\n${prefix}Received SIGINT. Exiting gracefully...`);
152
+ uniqueErrorHandler(new InterruptError('SIGINT'), logger);
61
153
  });
62
154
 
63
155
  process.on('SIGTERM', () => {
64
- console.error(`${prefix}Received SIGTERM. Exiting gracefully...`);
65
- shutdown(0);
156
+ logger.output(`${prefix}Received SIGTERM. Exiting gracefully...`);
157
+ uniqueErrorHandler(new InterruptError('SIGTERM'), logger);
66
158
  });
67
159
 
68
160
  process.on('beforeExit', (code) => {
69
- console.error(`${prefix}Process beforeExit with code: ${code}`);
70
- shutdown(code);
161
+ // empty handler prevent real exit
162
+ if (!isProductionMode) logger.verbose?.(`process: beforeExit: ${code}`);
163
+ if (process.exitCode === undefined || process.exitCode === '') {
164
+ code = ExitCode.EXECUTION;
165
+ logger.output(`${prefix}beforeExit called, but process.exitCode has not been set, switch to ${code}`);
166
+ }
167
+ _shutdown(code);
71
168
  });
72
169
 
73
- process.on('unhandledRejection', (reason, _promise) => {
74
- if (hasInspect) debugger;
170
+ function finalThrow(e: UnhandledRejection | UncaughtException) {
171
+ try {
172
+ uniqueErrorHandler(e, logger);
75
173
 
76
- if (reason instanceof Error) {
77
- if (reason instanceof AppExit) {
174
+ if (e.cause instanceof ErrorWithCode) {
175
+ if (!isProductionMode) logger.verbose?.(`finalThrow: got code: ${e.cause.code}`);
176
+ _shutdown(e.cause.code);
177
+ } else {
178
+ if (!isProductionMode) logger.verbose?.(`finalThrow: not got code: ${e.cause} `);
179
+ _shutdown(ExitCode.PROGRAM);
180
+ }
181
+ } catch (e: any) {
182
+ if (e instanceof Exit) {
78
183
  return;
79
184
  }
80
- prettyPrintError(`${prefix}Unhandled Rejection`, reason);
81
- } else {
82
- console.error(`${prefix}Unhandled Rejection / error type unknown:`, reason);
185
+ prettyPrintError('Exception while handling error', e);
186
+ _shutdown(ExitCode.PROGRAM);
83
187
  }
84
- shutdown(1);
85
- });
188
+ }
86
189
 
87
- const processMdl = createRequire(import.meta.url)('node:process');
88
- processMdl.exit = shutdown;
89
- syncBuiltinESMExports();
190
+ process.on('unhandledRejection', (reason, promise) => {
191
+ finalThrow(new UnhandledRejection(reason, promise));
192
+ });
90
193
 
91
194
  function uncaughtException(error: Error): void {
92
- if (error instanceof AppExit) {
93
- return;
94
- }
95
-
96
- if (hasInspect) debugger;
97
-
98
- prettyPrintError(`${prefix}Uncaught Exception`, error);
99
- shutdown(1);
195
+ finalThrow(new UncaughtException(error));
100
196
  }
101
197
 
102
198
  if (process.hasUncaughtExceptionCaptureCallback()) {
@@ -105,6 +201,9 @@ function _real_register() {
105
201
  }
106
202
  process.setUncaughtExceptionCaptureCallback(uncaughtException);
107
203
 
204
+ process.exit = shutdown;
205
+ syncBuiltinESMExports();
206
+
108
207
  return true;
109
208
  }
110
209
 
@@ -0,0 +1,45 @@
1
+ import { noop, vscEscapeValue } from '@idlebox/common';
2
+ import { syncBuiltinESMExports } from 'node:module';
3
+ import process from 'node:process';
4
+
5
+ const originalChdir = process.chdir;
6
+ const originalCwd = process.cwd;
7
+
8
+ let currentEnvironmentChdir = originalChdir;
9
+ const currentEnvironmentCwd = originalCwd;
10
+ let patch = noop;
11
+
12
+ const wd = {
13
+ cwd() {
14
+ return currentEnvironmentCwd();
15
+ },
16
+ chdir(dir: string) {
17
+ currentEnvironmentChdir(dir);
18
+ },
19
+ patchGlobal() {
20
+ patch();
21
+ wd.cwd = currentEnvironmentCwd;
22
+ wd.chdir = currentEnvironmentChdir;
23
+ wd.patchGlobal = noop;
24
+ },
25
+ escapeVscodeCwd,
26
+ isVscodeShellIntegration: process.env.VSCODE_SHELL_INTEGRATION || process.env.VSCODE_SHELL_INTEGRATION_SHELL_SCRIPT,
27
+ };
28
+
29
+ export const workingDirectory: Readonly<typeof wd> = wd;
30
+
31
+ function escapeVscodeCwd(path: string) {
32
+ return `\x1B]633;P;Cwd=${vscEscapeValue(path)}\x07`;
33
+ }
34
+
35
+ if (wd.isVscodeShellIntegration) {
36
+ currentEnvironmentChdir = (newRoot: string) => {
37
+ process.stderr.write(escapeVscodeCwd(newRoot));
38
+ originalChdir(newRoot);
39
+ };
40
+ patch = () => {
41
+ process.chdir = currentEnvironmentChdir;
42
+ globalThis.process.chdir = currentEnvironmentChdir;
43
+ syncBuiltinESMExports();
44
+ };
45
+ }