0z2i6v3u5t 1.0.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.
Files changed (211) hide show
  1. package/.devcontainer/devcontainer.json +4 -0
  2. package/.devcontainer/setup.sh +11 -0
  3. package/.dockerignore +2 -0
  4. package/.github/CONTRIBUTING.md +52 -0
  5. package/.github/FUNDING.yml +3 -0
  6. package/.github/ISSUE_TEMPLATE/bug_report.yml +59 -0
  7. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  8. package/.github/ISSUE_TEMPLATE/feature_request.yml +43 -0
  9. package/.github/dependabot.yml +17 -0
  10. package/.github/workflows/codeql.yml +76 -0
  11. package/.github/workflows/publish_docs.yml +25 -0
  12. package/.github/workflows/test.yml +78 -0
  13. package/.nvmrc +1 -0
  14. package/.prettierignore +1 -0
  15. package/.prettierrc +1 -0
  16. package/.vscode/launch.json +42 -0
  17. package/CODE_OF_CONDUCT.md +76 -0
  18. package/Dockerfile +17 -0
  19. package/LICENSE +21 -0
  20. package/README.md +3 -0
  21. package/SECURITY.md +5 -0
  22. package/__tests__/actions/cacheTest.ts +58 -0
  23. package/__tests__/actions/randomNumber.ts +26 -0
  24. package/__tests__/actions/recursiveAction.ts +16 -0
  25. package/__tests__/actions/sleepTest.ts +24 -0
  26. package/__tests__/actions/status.ts +17 -0
  27. package/__tests__/actions/swagger.ts +76 -0
  28. package/__tests__/actions/validationTest.ts +63 -0
  29. package/__tests__/cli/cli.ts +126 -0
  30. package/__tests__/core/api.ts +632 -0
  31. package/__tests__/core/cache.ts +400 -0
  32. package/__tests__/core/chatRoom.ts +589 -0
  33. package/__tests__/core/cli.ts +349 -0
  34. package/__tests__/core/cluster.ts +132 -0
  35. package/__tests__/core/config.ts +78 -0
  36. package/__tests__/core/errors.ts +112 -0
  37. package/__tests__/core/log.ts +23 -0
  38. package/__tests__/core/middleware.ts +427 -0
  39. package/__tests__/core/plugins/partialPlugin.ts +94 -0
  40. package/__tests__/core/plugins/withPlugin.ts +88 -0
  41. package/__tests__/core/plugins/withoutPlugin.ts +81 -0
  42. package/__tests__/core/process.ts +42 -0
  43. package/__tests__/core/specHelper.ts +330 -0
  44. package/__tests__/core/staticFile/compression.ts +99 -0
  45. package/__tests__/core/staticFile/staticFile.ts +180 -0
  46. package/__tests__/core/tasks/customQueueFunction.ts +67 -0
  47. package/__tests__/core/tasks/fullWorkerFlow.ts +199 -0
  48. package/__tests__/core/tasks/tasks.ts +605 -0
  49. package/__tests__/integration/browser.ts +133 -0
  50. package/__tests__/integration/ioredis-mock.ts +194 -0
  51. package/__tests__/integration/sendBuffer.ts +97 -0
  52. package/__tests__/integration/sendFile.ts +24 -0
  53. package/__tests__/integration/sharedFingerprint.ts +82 -0
  54. package/__tests__/integration/taskFlow.ts +110 -0
  55. package/__tests__/jest.ts +5 -0
  56. package/__tests__/modules/action.ts +103 -0
  57. package/__tests__/modules/config.ts +19 -0
  58. package/__tests__/modules/utils/ensureNoTsHeaderOrSpecFiles.ts +24 -0
  59. package/__tests__/servers/web/allowedRequestHosts.ts +88 -0
  60. package/__tests__/servers/web/enableMultiples.ts +83 -0
  61. package/__tests__/servers/web/fileUpload.ts +79 -0
  62. package/__tests__/servers/web/jsonp.ts +57 -0
  63. package/__tests__/servers/web/nonMultiples.ts +83 -0
  64. package/__tests__/servers/web/rawBody.ts +208 -0
  65. package/__tests__/servers/web/returnErrorCodes.ts +55 -0
  66. package/__tests__/servers/web/routes/deepRoutes.ts +96 -0
  67. package/__tests__/servers/web/routes/routes.ts +579 -0
  68. package/__tests__/servers/web/routes/veryDeepRoutes.ts +92 -0
  69. package/__tests__/servers/web/web.ts +1031 -0
  70. package/__tests__/servers/websocket.ts +795 -0
  71. package/__tests__/tasks/runAction.ts +37 -0
  72. package/__tests__/template.ts.example +20 -0
  73. package/__tests__/testCliCommands/hello.ts +44 -0
  74. package/__tests__/testPlugin/public/plugin.html +1 -0
  75. package/__tests__/testPlugin/src/actions/pluginAction.ts +14 -0
  76. package/__tests__/testPlugin/src/bin/hello.ts +22 -0
  77. package/__tests__/testPlugin/src/initializers/pluginInitializer.ts +17 -0
  78. package/__tests__/testPlugin/src/tasks/pluginTask.ts +15 -0
  79. package/__tests__/testPlugin/tsconfig.json +10 -0
  80. package/__tests__/utils/utils.ts +492 -0
  81. package/app.json +23 -0
  82. package/bin/deploy-docs +39 -0
  83. package/client/ActionheroWebsocketClient.js +277 -0
  84. package/docker-compose.yml +73 -0
  85. package/package.json +24 -0
  86. package/public/chat.html +194 -0
  87. package/public/css/cosmo.css +12 -0
  88. package/public/favicon.ico +0 -0
  89. package/public/index.html +115 -0
  90. package/public/javascript/.gitkeep +0 -0
  91. package/public/linkedSession.html +80 -0
  92. package/public/logo/actionhero-small.png +0 -0
  93. package/public/logo/actionhero.png +0 -0
  94. package/public/pixel.gif +0 -0
  95. package/public/simple.html +2 -0
  96. package/public/swagger.html +32 -0
  97. package/public/websocketLoadTest.html +322 -0
  98. package/src/actions/cacheTest.ts +58 -0
  99. package/src/actions/createChatRoom.ts +20 -0
  100. package/src/actions/randomNumber.ts +17 -0
  101. package/src/actions/recursiveAction.ts +13 -0
  102. package/src/actions/sendFile.ts +12 -0
  103. package/src/actions/sleepTest.ts +40 -0
  104. package/src/actions/status.ts +73 -0
  105. package/src/actions/swagger.ts +155 -0
  106. package/src/actions/validationTest.ts +36 -0
  107. package/src/bin/actionhero.ts +225 -0
  108. package/src/bin/methods/actions/list.ts +30 -0
  109. package/src/bin/methods/console.ts +26 -0
  110. package/src/bin/methods/generate/action.ts +58 -0
  111. package/src/bin/methods/generate/cli.ts +51 -0
  112. package/src/bin/methods/generate/initializer.ts +54 -0
  113. package/src/bin/methods/generate/plugin.ts +57 -0
  114. package/src/bin/methods/generate/server.ts +38 -0
  115. package/src/bin/methods/generate/task.ts +68 -0
  116. package/src/bin/methods/generate.ts +176 -0
  117. package/src/bin/methods/task/enqueue.ts +35 -0
  118. package/src/classes/action.ts +98 -0
  119. package/src/classes/actionProcessor.ts +463 -0
  120. package/src/classes/api.ts +51 -0
  121. package/src/classes/cli.ts +67 -0
  122. package/src/classes/config.ts +15 -0
  123. package/src/classes/connection.ts +321 -0
  124. package/src/classes/exceptionReporter.ts +9 -0
  125. package/src/classes/initializer.ts +59 -0
  126. package/src/classes/initializers.ts +5 -0
  127. package/src/classes/input.ts +9 -0
  128. package/src/classes/inputs.ts +34 -0
  129. package/src/classes/process/actionheroVersion.ts +15 -0
  130. package/src/classes/process/env.ts +16 -0
  131. package/src/classes/process/id.ts +34 -0
  132. package/src/classes/process/pid.ts +32 -0
  133. package/src/classes/process/projectRoot.ts +16 -0
  134. package/src/classes/process/typescript.ts +47 -0
  135. package/src/classes/process.ts +479 -0
  136. package/src/classes/server.ts +251 -0
  137. package/src/classes/task.ts +87 -0
  138. package/src/config/api.ts +107 -0
  139. package/src/config/errors.ts +162 -0
  140. package/src/config/logger.ts +113 -0
  141. package/src/config/plugins.ts +37 -0
  142. package/src/config/redis.ts +78 -0
  143. package/src/config/routes.ts +44 -0
  144. package/src/config/tasks.ts +84 -0
  145. package/src/config/web.ts +136 -0
  146. package/src/config/websocket.ts +62 -0
  147. package/src/index.ts +46 -0
  148. package/src/initializers/actions.ts +125 -0
  149. package/src/initializers/chatRoom.ts +214 -0
  150. package/src/initializers/connections.ts +124 -0
  151. package/src/initializers/exceptions.ts +155 -0
  152. package/src/initializers/params.ts +52 -0
  153. package/src/initializers/redis.ts +191 -0
  154. package/src/initializers/resque.ts +248 -0
  155. package/src/initializers/routes.ts +229 -0
  156. package/src/initializers/servers.ts +134 -0
  157. package/src/initializers/specHelper.ts +195 -0
  158. package/src/initializers/staticFile.ts +253 -0
  159. package/src/initializers/tasks.ts +188 -0
  160. package/src/modules/action.ts +89 -0
  161. package/src/modules/cache.ts +326 -0
  162. package/src/modules/chatRoom.ts +321 -0
  163. package/src/modules/config.ts +246 -0
  164. package/src/modules/log.ts +62 -0
  165. package/src/modules/redis.ts +93 -0
  166. package/src/modules/route.ts +59 -0
  167. package/src/modules/specHelper.ts +182 -0
  168. package/src/modules/task.ts +527 -0
  169. package/src/modules/utils/argv.ts +3 -0
  170. package/src/modules/utils/arrayStartingMatch.ts +21 -0
  171. package/src/modules/utils/arrayUnique.ts +15 -0
  172. package/src/modules/utils/collapseObjectToArray.ts +33 -0
  173. package/src/modules/utils/deepCopy.ts +3 -0
  174. package/src/modules/utils/ensureNoTsHeaderOrSpecFiles.ts +19 -0
  175. package/src/modules/utils/eventLoopDelay.ts +34 -0
  176. package/src/modules/utils/fileUtils.ts +119 -0
  177. package/src/modules/utils/filterObjectForLogging.ts +51 -0
  178. package/src/modules/utils/filterResponseForLogging.ts +53 -0
  179. package/src/modules/utils/getExternalIPAddress.ts +17 -0
  180. package/src/modules/utils/hashMerge.ts +63 -0
  181. package/src/modules/utils/isPlainObject.ts +45 -0
  182. package/src/modules/utils/isRunning.ts +7 -0
  183. package/src/modules/utils/parseCookies.ts +20 -0
  184. package/src/modules/utils/parseHeadersForClientAddress.ts +53 -0
  185. package/src/modules/utils/parseIPv6URI.ts +24 -0
  186. package/src/modules/utils/replaceDistWithSrc.ts +9 -0
  187. package/src/modules/utils/safeGlob.ts +6 -0
  188. package/src/modules/utils/sleep.ts +8 -0
  189. package/src/modules/utils/sortGlobalMiddleware.ts +17 -0
  190. package/src/modules/utils/sourceRelativeLinkPath.ts +29 -0
  191. package/src/modules/utils.ts +66 -0
  192. package/src/server.ts +20 -0
  193. package/src/servers/web.ts +894 -0
  194. package/src/servers/websocket.ts +304 -0
  195. package/src/tasks/runAction.ts +29 -0
  196. package/tea.yaml +9 -0
  197. package/templates/README.md.template +17 -0
  198. package/templates/action.ts.template +15 -0
  199. package/templates/boot.js.template +9 -0
  200. package/templates/cli.ts.template +15 -0
  201. package/templates/gitignore.template +23 -0
  202. package/templates/initializer.ts.template +17 -0
  203. package/templates/package-plugin.json.template +12 -0
  204. package/templates/package.json.template +45 -0
  205. package/templates/projectMap.txt +39 -0
  206. package/templates/projectServer.ts.template +20 -0
  207. package/templates/server.ts.template +37 -0
  208. package/templates/task.ts.template +16 -0
  209. package/templates/test/action.ts.template +13 -0
  210. package/templates/test/task.ts.template +20 -0
  211. package/tsconfig.json +11 -0
@@ -0,0 +1,479 @@
1
+ import * as path from "path";
2
+ import * as fs from "fs";
3
+ import { config } from "..";
4
+ import { log } from "../modules/log";
5
+ import { Initializer } from "./initializer";
6
+ import { Initializers } from "./initializers";
7
+ import { utils } from "../modules/utils";
8
+ import { id } from "./process/id";
9
+ import { env } from "./process/env";
10
+ import { writePidFile, clearPidFile } from "./process/pid";
11
+ import { api } from "../index";
12
+ import { rebuildConfig } from "../modules/config";
13
+ import { safeGlobSync } from "../modules/utils/safeGlob";
14
+
15
+ export const fatalErrorCode = "FATAL_ACTIONHERO_ERROR";
16
+
17
+ export class Process {
18
+ running: boolean;
19
+ initialized: boolean;
20
+ started: boolean;
21
+ stopped: boolean;
22
+ stopReasons?: string[];
23
+ shuttingDown: boolean;
24
+ bootTime: number;
25
+ initializers: Initializers;
26
+ startCount: number;
27
+ loadInitializers: Initializer["initialize"][];
28
+ startInitializers: Initializer["start"][];
29
+ stopInitializers: Initializer["stop"][];
30
+
31
+ constructor() {
32
+ this.initialized = false;
33
+ this.started = false;
34
+ this.stopped = false;
35
+ this.initializers = {};
36
+ this.loadInitializers = [];
37
+ this.startInitializers = [];
38
+ this.stopInitializers = [];
39
+ this.stopReasons = [];
40
+ this.startCount = 0;
41
+
42
+ api.process = this;
43
+
44
+ api.commands.initialize = this.initialize;
45
+ api.commands.start = this.start;
46
+ api.commands.stop = this.stop;
47
+ api.commands.restart = this.restart;
48
+ }
49
+
50
+ async initialize() {
51
+ const loadInitializerRankings: {
52
+ [rank: number]: Initializer["initialize"][];
53
+ } = {};
54
+ const startInitializerRankings: {
55
+ [rank: number]: Initializer["start"][];
56
+ } = {};
57
+ const stopInitializerRankings: {
58
+ [rank: number]: Initializer["stop"][];
59
+ } = {};
60
+
61
+ let initializerFiles: Array<string> = [];
62
+
63
+ // load initializers from core
64
+ initializerFiles = initializerFiles.concat(
65
+ safeGlobSync(
66
+ path.join(__dirname, "..", "initializers", "**", "**/*(*.js|*.ts)"),
67
+ ),
68
+ );
69
+
70
+ // load initializers from project
71
+ config.general.paths.initializer.forEach((startPath: string) => {
72
+ initializerFiles = initializerFiles.concat(
73
+ safeGlobSync(path.join(startPath, "**", "**/*(*.js|*.ts)")),
74
+ );
75
+ });
76
+
77
+ // load initializers from plugins
78
+ for (const plugin of Object.values(config.plugins)) {
79
+ const pluginPath: string = path.normalize(plugin.path);
80
+ if (!fs.existsSync(pluginPath)) {
81
+ throw new Error(`plugin path does not exist: ${pluginPath}`);
82
+ }
83
+
84
+ if (plugin.initializers !== false) {
85
+ // old style at the root of the project
86
+ initializerFiles = initializerFiles.concat(
87
+ safeGlobSync(path.join(pluginPath, "initializers", "**", "*.js")),
88
+ );
89
+
90
+ // new TS dist files
91
+ initializerFiles = initializerFiles.concat(
92
+ safeGlobSync(
93
+ path.join(pluginPath, "dist", "initializers", "**", "*.js"),
94
+ ),
95
+ );
96
+ }
97
+ }
98
+
99
+ initializerFiles = utils.arrayUnique(initializerFiles);
100
+ initializerFiles = utils.ensureNoTsHeaderOrSpecFiles(initializerFiles);
101
+
102
+ for (const i in initializerFiles) {
103
+ const f = initializerFiles[i];
104
+ const file = path.normalize(f);
105
+ if (require.cache[require.resolve(file)]) {
106
+ delete require.cache[require.resolve(file)];
107
+ }
108
+
109
+ let exportedClasses = await import(file);
110
+
111
+ // allow for old-js style single default exports
112
+ if (typeof exportedClasses === "function") {
113
+ exportedClasses = { default: exportedClasses };
114
+ }
115
+
116
+ if (Object.keys(exportedClasses).length === 0) {
117
+ this.fatalError(
118
+ new Error(`no exported initializers found in ${file}`),
119
+ file,
120
+ );
121
+ }
122
+
123
+ for (const exportKey in exportedClasses) {
124
+ let initializer: Initializer;
125
+ let InitializerClass = exportedClasses[exportKey];
126
+ try {
127
+ initializer = new InitializerClass();
128
+
129
+ // check if initializer already exists (exclude utils and config)
130
+ if (this.initializers[initializer.name]) {
131
+ const warningMessage = `an existing initializer with the same name \`${initializer.name}\` will be overridden by the file ${file}`;
132
+ log(warningMessage, "warning");
133
+ } else {
134
+ initializer.validate();
135
+ this.initializers[initializer.name] = initializer;
136
+ }
137
+ } catch (error) {
138
+ this.fatalError(error, file);
139
+ }
140
+
141
+ function decorateInitError(
142
+ error: NodeJS.ErrnoException & Record<string, any>,
143
+ type: string,
144
+ ) {
145
+ error["data"] = error["data"] ?? {};
146
+ error["data"].name = initializer.name;
147
+ error["data"].file = file;
148
+ error["data"].type = type;
149
+ }
150
+
151
+ const initializeFunction = async () => {
152
+ if (typeof initializer.initialize === "function") {
153
+ log(`Loading initializer: ${initializer.name}`, "debug", file);
154
+
155
+ try {
156
+ await initializer.initialize();
157
+ log(`Loaded initializer: ${initializer.name}`, "debug", file);
158
+ } catch (error) {
159
+ decorateInitError(error, "initialize");
160
+ throw error;
161
+ }
162
+ }
163
+ };
164
+
165
+ const startFunction = async () => {
166
+ if (typeof initializer.start === "function") {
167
+ log(`Starting initializer: ${initializer.name}`, "debug", file);
168
+
169
+ try {
170
+ await initializer.start();
171
+ log(`Started initializer: ${initializer.name}`, "debug", file);
172
+ } catch (error) {
173
+ decorateInitError(error, "start");
174
+ throw error;
175
+ }
176
+ }
177
+ };
178
+
179
+ const stopFunction = async () => {
180
+ if (typeof initializer.stop === "function") {
181
+ log(`Stopping initializer: ${initializer.name}`, "debug", file);
182
+
183
+ try {
184
+ await initializer.stop();
185
+ log(`Stopped initializer: ${initializer.name}`, "debug", file);
186
+ } catch (error) {
187
+ decorateInitError(error, "stop");
188
+ throw error;
189
+ }
190
+ }
191
+ };
192
+
193
+ if (!loadInitializerRankings[initializer.loadPriority]) {
194
+ loadInitializerRankings[initializer.loadPriority] = [];
195
+ }
196
+ if (!startInitializerRankings[initializer.startPriority]) {
197
+ startInitializerRankings[initializer.startPriority] = [];
198
+ }
199
+ if (!stopInitializerRankings[initializer.stopPriority]) {
200
+ stopInitializerRankings[initializer.stopPriority] = [];
201
+ }
202
+
203
+ if (initializer.loadPriority > 0) {
204
+ loadInitializerRankings[initializer.loadPriority].push(
205
+ initializeFunction,
206
+ );
207
+ }
208
+ if (initializer.startPriority > 0) {
209
+ startInitializerRankings[initializer.startPriority].push(
210
+ startFunction,
211
+ );
212
+ }
213
+ if (initializer.stopPriority > 0) {
214
+ stopInitializerRankings[initializer.stopPriority].push(stopFunction);
215
+ }
216
+ }
217
+ }
218
+
219
+ // flatten all the ordered initializer methods
220
+ this.loadInitializers = this.flattenOrderedInitializer(
221
+ loadInitializerRankings,
222
+ );
223
+ this.startInitializers = this.flattenOrderedInitializer(
224
+ startInitializerRankings,
225
+ );
226
+ this.stopInitializers = this.flattenOrderedInitializer(
227
+ stopInitializerRankings,
228
+ );
229
+
230
+ try {
231
+ for (const loader of this.loadInitializers) await loader();
232
+ } catch (error) {
233
+ return this.fatalError(error, "initialize");
234
+ }
235
+
236
+ this.initialized = true;
237
+ }
238
+
239
+ /**
240
+ * Start the Actionhero Process
241
+ */
242
+ async start() {
243
+ if (!this.initialized) await this.initialize();
244
+ const serverName = config.general.serverName;
245
+
246
+ writePidFile();
247
+ this.running = true;
248
+ api.running = true;
249
+ log(`environment: ${env}`, "notice");
250
+ log(`*** Starting ${serverName} ***`, "info");
251
+
252
+ this.startInitializers.push(async () => {
253
+ this.bootTime = new Date().getTime();
254
+ if (this.startCount === 0) {
255
+ log(`server ID: ${id}`, "notice");
256
+ log(`*** ${serverName} Started ***`, "notice");
257
+ this.startCount++;
258
+ } else {
259
+ log(`*** ${serverName} Restarted ***`, "notice");
260
+ }
261
+ });
262
+
263
+ try {
264
+ for (const starter of this.startInitializers) await starter();
265
+ } catch (error) {
266
+ return this.fatalError(error, "start");
267
+ }
268
+
269
+ this.started = true;
270
+ }
271
+
272
+ /**
273
+ * Stop the Actionhero Process
274
+ */
275
+ async stop(stopReasons: string | string[] = []) {
276
+ const serverName = config.general.serverName;
277
+
278
+ if (this.running) {
279
+ this.shuttingDown = true;
280
+ this.running = false;
281
+ this.initialized = false;
282
+ this.started = false;
283
+ this.stopReasons = Array.isArray(stopReasons)
284
+ ? stopReasons
285
+ : [stopReasons];
286
+
287
+ log("stopping process...", "notice");
288
+ if (this.stopReasons?.length > 0) {
289
+ log(`stop reasons: ${this.stopReasons.join(", ")}`, "debug");
290
+ }
291
+
292
+ await utils.sleep(100);
293
+
294
+ this.stopInitializers.push(async () => {
295
+ clearPidFile();
296
+ log(`*** ${serverName} Stopped ***`, "notice");
297
+ delete this.shuttingDown;
298
+ // reset initializers to prevent duplicate check on restart
299
+ this.initializers = {};
300
+ api.running = false;
301
+ await utils.sleep(100);
302
+ });
303
+
304
+ try {
305
+ for (const stopper of this.stopInitializers) await stopper();
306
+ } catch (error) {
307
+ return this.fatalError(error, "stop");
308
+ }
309
+
310
+ this.stopped = true;
311
+ } else if (this.shuttingDown === true) {
312
+ // double sigterm; ignore it
313
+ } else {
314
+ const message = `Cannot shut down ${serverName}, not running`;
315
+ log(message, "crit");
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Restart the Actionhero Process
321
+ */
322
+ async restart() {
323
+ if (this.running === true) {
324
+ await this.stop();
325
+ rebuildConfig();
326
+ await this.start();
327
+ } else {
328
+ await this.start();
329
+ }
330
+ }
331
+
332
+ /**
333
+ * Register listeners for process signals and uncaught exceptions & rejections.
334
+ * Try to gracefully shut down when signaled to do so
335
+ */
336
+ registerProcessSignals(stopCallback = (exitCode?: number) => {}) {
337
+ const timeout = process.env.ACTIONHERO_SHUTDOWN_TIMEOUT
338
+ ? parseInt(process.env.ACTIONHERO_SHUTDOWN_TIMEOUT)
339
+ : 1000 * 30;
340
+
341
+ function awaitHardStop() {
342
+ return setTimeout(() => {
343
+ console.error(
344
+ `Process did not terminate within ${timeout}ms. Stopping now!`,
345
+ );
346
+ process.nextTick(process.exit(1));
347
+ }, timeout);
348
+ }
349
+
350
+ // handle errors & rejections
351
+ process.once("uncaughtException", async (error: NodeJS.ErrnoException) => {
352
+ if (error.code !== fatalErrorCode) {
353
+ if (api.exceptionHandlers) {
354
+ api.exceptionHandlers.report(
355
+ error,
356
+ "uncaught",
357
+ "Exception",
358
+ {},
359
+ "emerg",
360
+ );
361
+ } else {
362
+ console.error(error);
363
+ }
364
+ }
365
+
366
+ if (this.shuttingDown !== true) {
367
+ let timer = awaitHardStop();
368
+ if (this.running) await this.stop();
369
+ clearTimeout(timer);
370
+ stopCallback(1);
371
+ }
372
+ });
373
+
374
+ process.once(
375
+ "unhandledRejection",
376
+ async (rejection: NodeJS.ErrnoException) => {
377
+ if (rejection.code !== fatalErrorCode) {
378
+ if (api.exceptionHandlers) {
379
+ api.exceptionHandlers.report(
380
+ rejection,
381
+ "uncaught",
382
+ "Rejection",
383
+ {},
384
+ "emerg",
385
+ );
386
+ } else {
387
+ console.error(rejection);
388
+ }
389
+ }
390
+
391
+ if (!this.shuttingDown) {
392
+ let timer = awaitHardStop();
393
+ if (this.running) await this.stop();
394
+ clearTimeout(timer);
395
+ stopCallback(1);
396
+ }
397
+ },
398
+ );
399
+
400
+ // handle signals
401
+ process.on("SIGINT", async () => {
402
+ log(`[ SIGNAL ] - SIGINT`, "notice");
403
+ let timer = awaitHardStop();
404
+ if (this.running) await this.stop();
405
+ if (!this.shuttingDown) {
406
+ clearTimeout(timer);
407
+ stopCallback(0);
408
+ }
409
+ });
410
+
411
+ process.on("SIGTERM", async () => {
412
+ log(`[ SIGNAL ] - SIGTERM`, "notice");
413
+ let timer = awaitHardStop();
414
+ if (this.running) await this.stop();
415
+ if (!this.shuttingDown) {
416
+ clearTimeout(timer);
417
+ stopCallback(0);
418
+ }
419
+ });
420
+
421
+ process.on("SIGUSR2", async () => {
422
+ log(`[ SIGNAL ] - SIGUSR2`, "notice");
423
+ let timer = awaitHardStop();
424
+ await this.restart();
425
+ clearTimeout(timer);
426
+ });
427
+ }
428
+
429
+ // HELPERS
430
+ async fatalError(
431
+ errors: NodeJS.ErrnoException | NodeJS.ErrnoException[] = [],
432
+ type: string,
433
+ ) {
434
+ if (!(errors instanceof Array)) errors = [errors];
435
+
436
+ if (errors) {
437
+ const showStack = process.env.ACTIONHERO_FATAL_ERROR_STACK_DISPLAY
438
+ ? process.env.ACTIONHERO_FATAL_ERROR_STACK_DISPLAY === "true"
439
+ : true;
440
+
441
+ errors.forEach((error) => {
442
+ if (!showStack) delete error.stack;
443
+ if (api.exceptionHandlers) {
444
+ api.exceptionHandlers.report(error, "initializer", type);
445
+ } else {
446
+ console.error(error);
447
+ }
448
+ });
449
+
450
+ if (this.running) {
451
+ await this.stop(errors.map((e) => e.message ?? e.toString())); // stop and set the stopReasons
452
+ }
453
+ await utils.sleep(100); // allow time for console.log to print
454
+
455
+ if (!errors[0].code) errors[0].code = fatalErrorCode;
456
+ throw errors[0];
457
+ }
458
+ }
459
+
460
+ flattenOrderedInitializer<T>(collection: { [rank: number]: T[] }) {
461
+ const output: T[] = [];
462
+ const keys = [];
463
+
464
+ for (const key in collection) keys.push(parseInt(key, 10));
465
+ keys.sort(sortNumber);
466
+
467
+ keys.forEach((key) => {
468
+ collection[key].forEach((d) => {
469
+ output.push(d);
470
+ });
471
+ });
472
+
473
+ return output;
474
+ }
475
+ }
476
+
477
+ function sortNumber(a: number, b: number) {
478
+ return a - b;
479
+ }