@idlebox/node 1.4.28 → 1.4.29

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.
@@ -1,242 +0,0 @@
1
- /** biome-ignore-all lint/suspicious/noDebugger: debug file */
2
-
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';
7
- import { basename } from 'node:path';
8
- import process from 'node:process';
9
- import { inspect } from 'node:util';
10
-
11
- const shutdown_immediate: (code?: number) => never = process.exit;
12
- const prefix = process.stderr.isTTY ? '' : `<${title()} ${process.pid}> `;
13
-
14
- function title() {
15
- if (process.title && process.title !== 'node') {
16
- return process.title;
17
- }
18
- return basename(process.argv[1] || '') || 'node';
19
- }
20
-
21
- function getCurrentCode() {
22
- return typeof process.exitCode === 'string' ? parseInt(process.exitCode, 10) : 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;
29
- }
30
- }
31
-
32
- let shuttingDown = 0;
33
- export function shutdown(exitCode: number): never {
34
- _shutdown_graceful(exitCode);
35
- throw new Exit(getCurrentCode());
36
- }
37
- export function isShuttingDown() {
38
- return shuttingDown > 0;
39
- }
40
- function _shutdown_graceful(exitCode: number) {
41
- setExitCodeIfNot(exitCode);
42
-
43
- if (!shuttingDown) {
44
- shuttingDown = 1;
45
- ensureDisposeGlobal().finally(() => {
46
- shutdown_immediate(getCurrentCode());
47
- });
48
- } else {
49
- shuttingDown++;
50
- }
51
- }
52
-
53
- const typed_error_handlers = new WeakMap<ErrorConstructor, MyCallback<[Error]>>();
54
- const inherit_error_handlers = new Map<ErrorConstructor, MyCallback<[Error]>>();
55
-
56
- type ErrorConstructor = new (...args: any[]) => Error;
57
-
58
- export function registerNodejsGlobalTypedErrorHandlerWithInheritance(ErrorCls: ErrorConstructor, fn: MyCallback<[Error]>) {
59
- if (typed_error_handlers.has(ErrorCls)) {
60
- throw new ErrorCls(`conflict register of error type ${ErrorCls.name}`);
61
- }
62
- assert.notEqual(ErrorCls, Error, 'cannot register basic Error type');
63
- inherit_error_handlers.set(ErrorCls, fn);
64
- }
65
- export function registerNodejsGlobalTypedErrorHandler(ErrorCls: ErrorConstructor, fn: MyCallback<[Error]>) {
66
- if (typed_error_handlers.has(ErrorCls)) {
67
- throw new ErrorCls(`conflict register of error type ${ErrorCls.name}`);
68
- }
69
- assert.notEqual(ErrorCls, Error, 'cannot register basic Error type');
70
- typed_error_handlers.set(ErrorCls, fn);
71
- }
72
-
73
- function _root_cause(e: Error) {
74
- if (e.cause instanceof Error) {
75
- return _root_cause(e.cause);
76
- }
77
- return e;
78
- }
79
-
80
- function uniqueErrorHandler(currentError: unknown, logger: IDebugOutput) {
81
- if (!isProductionMode) logger.verbose?.(`uniqueErrorHandler:`);
82
- if (!(currentError instanceof Error)) {
83
- prettyPrintError(
84
- `${prefix}catch unexpect object`,
85
- new Error(`error object is ${typeof currentError} ${currentError ? (currentError as any).constructor?.name : 'unknown'}`),
86
- );
87
- throw shutdown_immediate(ExitCode.PROGRAM);
88
- }
89
-
90
- const rootCause = _root_cause(currentError);
91
- if (rootCause instanceof Exit) {
92
- if (!isProductionMode) logger.verbose?.(` - skip exit object`);
93
- if (!shuttingDown) _shutdown_graceful(rootCause.code);
94
- throw rootCause;
95
- }
96
-
97
- try {
98
- const catcher = typed_error_handlers.get(rootCause.constructor as ErrorConstructor);
99
- if (catcher) {
100
- if (!isProductionMode) logger.verbose?.(` - call catcher ${functionName(catcher)}`);
101
- catcher(rootCause);
102
- return;
103
- }
104
- for (const [Cls, fn] of inherit_error_handlers) {
105
- if (!isProductionMode) logger.verbose?.(` - call inherited catcher ${functionName(fn)}`);
106
- if (rootCause instanceof Cls) {
107
- fn(rootCause);
108
- return;
109
- }
110
- }
111
- } catch (ee: any) {
112
- if (ee instanceof Exit) return;
113
- prettyPrintError(`${prefix}error while handle error`, {
114
- message: ee.message,
115
- stack: ee.stack,
116
- cause: rootCause,
117
- });
118
- return;
119
- }
120
-
121
- if (rootCause instanceof InterruptError) {
122
- if (!isProductionMode) logger.verbose?.(` - shuttingDown = ${shuttingDown}`);
123
-
124
- const signal = rootCause.signal;
125
- if (signal === 'SIGINT') {
126
- process.stderr.write(shuttingDown === 0 ? '\n' : '\r');
127
- }
128
- if (shuttingDown > 4) {
129
- logger.output(`${prefix}Received ${signal} more than 5 times. Exiting immediately.`);
130
- shutdown_immediate(ExitCode.INTERRUPT);
131
- } else if (shuttingDown > 0) {
132
- logger.output(`${prefix}Received ${signal} ${shuttingDown + 1} times.`);
133
- } else {
134
- logger.output(`${prefix}Received ${signal}. Exiting gracefully...`);
135
- }
136
- shutdown(ExitCode.INTERRUPT);
137
- }
138
- if (currentError instanceof UnhandledRejection) {
139
- if (!isProductionMode) logger.verbose?.(` - UnhandledRejection`);
140
- if (rootCause !== currentError) {
141
- prettyPrintError(`${prefix}Unhandled Rejection`, currentError.cause);
142
- } else {
143
- logger.output(`${prefix}Unhandled Rejection / error type unknown: ${inspect(currentError.cause)}`);
144
- }
145
- return;
146
- }
147
- if (currentError instanceof UncaughtException) {
148
- if (!isProductionMode) logger.verbose?.(` - UncaughtException`);
149
- if (rootCause !== currentError) {
150
- prettyPrintError(`${prefix}Unhandled Exception`, currentError.cause);
151
- } else {
152
- logger.output(`${prefix}Unhandled Exception / error type unknown: ${inspect(currentError.cause)}`);
153
- }
154
- return;
155
- }
156
-
157
- if (!isProductionMode) logger.verbose?.(` - common error`);
158
- prettyPrintError(`${prefix}unhandled global exception`, currentError);
159
- shutdown(ExitCode.PROGRAM);
160
- }
161
-
162
- interface IDebugOutput {
163
- output(message: string): void;
164
- verbose?(message: string): void;
165
- }
166
-
167
- /**
168
- * 注册nodejs退出处理器
169
- */
170
- export function registerNodejsExitHandler(logger: IDebugOutput = { output: console.error }) {
171
- ensureGlobalObject('exithandler/register', () => _real_register(logger));
172
- }
173
- function _real_register(logger: IDebugOutput) {
174
- logger.verbose?.(`register nodejs exit handler: production=${isProductionMode}`);
175
-
176
- process.on('SIGINT', () => signal_handler('SIGINT'));
177
- process.on('SIGTERM', () => signal_handler('SIGTERM'));
178
-
179
- function signal_handler(signal: 'SIGINT' | 'SIGTERM') {
180
- setImmediate(() => {
181
- uniqueErrorHandler(new InterruptError(signal, { boundary: signal_handler }), logger);
182
- });
183
- }
184
-
185
- process.on('beforeExit', (code) => {
186
- // empty handler prevent real exit
187
- if (!isProductionMode) logger.verbose?.(`process: beforeExit: ${code}`);
188
- if (process.exitCode === undefined || process.exitCode === '') {
189
- code = ExitCode.EXECUTION;
190
- logger.output(`${prefix}beforeExit called, but process.exitCode has not been set, switch to ${code}`);
191
- }
192
- _shutdown_graceful(code);
193
- });
194
-
195
- function finalThrow(e: UnhandledRejection | UncaughtException) {
196
- try {
197
- uniqueErrorHandler(e, logger);
198
-
199
- if (e.cause instanceof ErrorWithCode) {
200
- if (!isProductionMode) logger.verbose?.(`finalThrow: got code: ${e.cause.code}`);
201
- _shutdown_graceful(e.cause.code);
202
- } else {
203
- if (!isProductionMode) logger.verbose?.(`finalThrow: not got code: ${e.cause} `);
204
- _shutdown_graceful(ExitCode.PROGRAM);
205
- }
206
- } catch (ee: any) {
207
- if (ee instanceof Exit) {
208
- return;
209
- }
210
- prettyPrintError('Exception while handling error', ee);
211
- shutdown_immediate(ExitCode.PROGRAM);
212
- }
213
- }
214
-
215
- process.on('unhandledRejection', (reason, promise) => {
216
- finalThrow(new UnhandledRejection(reason, promise));
217
- });
218
-
219
- function uncaughtException(error: Error): void {
220
- finalThrow(new UncaughtException(error));
221
- }
222
-
223
- if (process.hasUncaughtExceptionCaptureCallback()) {
224
- process.on('uncaughtException', uncaughtException);
225
- throw new Error(`${prefix} [uncaught exception capture] callback already registered by other module`);
226
- }
227
- process.setUncaughtExceptionCaptureCallback(uncaughtException);
228
-
229
- process.exit = shutdown;
230
- syncBuiltinESMExports();
231
-
232
- return true;
233
- }
234
-
235
- /**
236
- * @deprecated 仅用于测试
237
- */
238
- export function die(message: string): never {
239
- debugger;
240
- console.error(`${prefix}DIE!`, message);
241
- shutdown(1);
242
- }