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,251 @@
1
+ import { EventEmitter } from "events";
2
+ import { api, config } from "../index";
3
+ import { log, ActionheroLogLevel } from "../modules/log";
4
+ import { ActionProcessor } from "./actionProcessor";
5
+ import { Connection } from "./connection";
6
+
7
+ interface ServerConfig {
8
+ [key: string]: any;
9
+ }
10
+
11
+ /**
12
+ * Create a new Actionhero Server. The required properties of an server. These can be defined statically (this.name) or as methods which return a value.
13
+ */
14
+ export abstract class Server extends EventEmitter {
15
+ /**The name & type of the server. */
16
+ type: string;
17
+ /**What connection verbs can connections of this type use? */
18
+ verbs?: Array<string>;
19
+ /**Shorthand for `api.config[this.type]` */
20
+ config?: ServerConfig;
21
+ options?: {
22
+ [key: string]: any;
23
+ };
24
+ /** attributes of the server */
25
+ attributes: {
26
+ [key: string]: any;
27
+ };
28
+ /**Can connections of this server use the chat system? */
29
+ canChat: boolean;
30
+ /**Should we log every new connection? */
31
+ logConnections: boolean;
32
+ /**Should we log when a connection disconnects/exits? */
33
+ logExits: boolean;
34
+ /**Should every new connection of this server type receive the welcome message */
35
+ sendWelcomeMessage: boolean;
36
+ /**Methods described by the server to apply to each connection (like connection.setHeader for web connections) */
37
+ connectionCustomMethods: {
38
+ [key: string]: Function;
39
+ };
40
+ /**A place to store the actually server object you create */
41
+ server?: any;
42
+
43
+ constructor() {
44
+ super();
45
+
46
+ this.options = {};
47
+ this.attributes = {};
48
+ this.config = {}; // will be applied by the initializer
49
+ this.connectionCustomMethods = {};
50
+
51
+ this.canChat = this.canChat ?? true;
52
+ this.logExits = this.logExits ?? true;
53
+ this.sendWelcomeMessage = this.sendWelcomeMessage ?? true;
54
+ this.logConnections = this.logConnections ?? true;
55
+ this.verbs = this.verbs ?? [];
56
+ }
57
+
58
+ /**
59
+ * Event called when a formal new connection is created for this server type. This is a response to calling Actionhero.Server#buildConnection
60
+ *
61
+ * @event Actionhero.Server#connection
62
+ */
63
+
64
+ /**
65
+ * Event called when a an action is complete for a connection created by this server. You may want to send a response to the client as a response to this event.
66
+ *
67
+ * @event Actionhero.Server#actionComplete
68
+ * @property {object} data - The same data from the Action. Includes the connection, response, etc.
69
+ */
70
+
71
+ /**
72
+ * Method run as part of the `initialize` lifecycle of your server. Usually configures the server.
73
+ */
74
+ abstract initialize(): Promise<void>;
75
+
76
+ /**
77
+ * Method run as part of the `start` lifecycle of your server. Usually boots the server (listens on port, etc).
78
+ */
79
+ abstract start(): Promise<void>;
80
+
81
+ /**
82
+ * Method run as part of the `stop` lifecycle of your server. Usually configures the server (disconnects from port, etc).
83
+ */
84
+ abstract stop(): Promise<void>;
85
+
86
+ /**
87
+ * Must be defined explaining how to send a message to an individual connection.
88
+ */
89
+ abstract sendMessage(
90
+ connection: Connection,
91
+ message: string | object | Array<any>,
92
+ messageId?: string,
93
+ ): Promise<void>;
94
+
95
+ /**
96
+ * Must be defined explaining how to send a file to an individual connection. Might be a noop for some connection types.
97
+ */
98
+ abstract sendFile(
99
+ connection: Connection,
100
+ error: NodeJS.ErrnoException,
101
+ fileStream: any,
102
+ mime: string,
103
+ length: number,
104
+ lastModified: Date,
105
+ ): Promise<void>;
106
+
107
+ /**An optional message to send to clients when they disconnect */
108
+ async goodbye?(connection: Connection): Promise<void>;
109
+
110
+ validate() {
111
+ if (!this.type) {
112
+ throw new Error("type is required for this server");
113
+ }
114
+
115
+ (
116
+ [
117
+ "start",
118
+ "stop",
119
+ "sendFile", // connection, error, fileStream, mime, length, lastModified
120
+ "sendMessage", // connection, message
121
+ "goodbye",
122
+ ] as const
123
+ ).forEach((method) => {
124
+ if (!this[method] || typeof this[method] !== "function") {
125
+ throw new Error(
126
+ `${method} is a required method for the server \`${this.type}\``,
127
+ );
128
+ }
129
+ });
130
+ }
131
+
132
+ /**
133
+ * * Build a the Actionhero.Connection from the raw parts provided by the server.
134
+ * ```js
135
+ *this.buildConnection({
136
+ * rawConnection: {
137
+ * req: req,
138
+ * res: res,
139
+ * params: {},
140
+ * method: method,
141
+ * cookies: cookies,
142
+ * responseHeaders: responseHeaders,
143
+ * responseHttpCode: responseHttpCode,
144
+ * parsedURL: parsedURL
145
+ * },
146
+ * id: fingerprint + '-' + uuid.v4(),
147
+ * fingerprint: fingerprint,
148
+ * remoteAddress: remoteIP,
149
+ * remotePort: remotePort
150
+ *})
151
+ * ```
152
+ */
153
+ async buildConnection(data: { [key: string]: any }) {
154
+ const details = {
155
+ type: this.type,
156
+ id: data.id,
157
+ remotePort: data.remotePort,
158
+ remoteIP: data.remoteAddress,
159
+ rawConnection: data.rawConnection,
160
+ messageId: data.messageId,
161
+ canChat: this.attributes.canChat ?? null,
162
+ fingerprint: data.fingerprint ?? null,
163
+ };
164
+
165
+ const connection = await Connection.createAsync(details);
166
+
167
+ connection.sendMessage = async (message) => {
168
+ this.sendMessage(connection, message);
169
+ };
170
+
171
+ connection.sendFile = async (path) => {
172
+ connection.params.file = path;
173
+ this.processFile(connection);
174
+ };
175
+
176
+ this.emit("connection", connection);
177
+
178
+ if (this.attributes.logConnections === true) {
179
+ this.log("new connection", "info", { to: connection.remoteIP });
180
+ }
181
+
182
+ if (this.attributes.sendWelcomeMessage === true) {
183
+ connection.sendMessage({
184
+ welcome: config.general.welcomeMessage,
185
+ context: "api",
186
+ });
187
+ }
188
+
189
+ if (typeof this.attributes.sendWelcomeMessage === "number") {
190
+ setTimeout(() => {
191
+ try {
192
+ connection.sendMessage({
193
+ welcome: config.general.welcomeMessage,
194
+ context: "api",
195
+ });
196
+ } catch (e) {
197
+ this.log(e, "error");
198
+ }
199
+ }, this.attributes.sendWelcomeMessage);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * When a connection has called an Action command, and all properties are set. Connection should have `params.action` set at least.
205
+ * on(event: 'actionComplete', cb: (data: object) => void): this;
206
+ */
207
+ async processAction(connection: Connection) {
208
+ const actionProcessor = new ActionProcessor(connection);
209
+ const data = await actionProcessor.processAction();
210
+ this.emit("actionComplete", data);
211
+ }
212
+
213
+ /**
214
+ * When a connection has called an File command, and all properties are set. Connection should have `params.file` set at least. Will eventually call Actionhero.Server#sendFile.
215
+ */
216
+ async processFile(connection: Connection) {
217
+ const results = await api.staticFile.get(connection);
218
+
219
+ this.sendFile(
220
+ results.connection,
221
+ results.error,
222
+ results.fileStream,
223
+ results.mime,
224
+ results.length,
225
+ results.lastModified,
226
+ );
227
+ }
228
+
229
+ /**
230
+ * Enumerate the connections for this server type on this server.
231
+ */
232
+ connections(): Array<Connection> {
233
+ const connections = [];
234
+
235
+ for (const i in api.connections.connections) {
236
+ const connection = api.connections.connections[i];
237
+ if (connection.type === this.type) {
238
+ connections.push(connection);
239
+ }
240
+ }
241
+
242
+ return connections;
243
+ }
244
+
245
+ /**
246
+ * Log a message from this server type. A wrapper around log() with a server prefix.
247
+ */
248
+ log(message: string, severity?: ActionheroLogLevel, data?: any) {
249
+ log(`[server: ${this.type}] ${message}`, severity, data);
250
+ }
251
+ }
@@ -0,0 +1,87 @@
1
+ import { Inputs } from "./inputs";
2
+ import { Plugin, Worker } from "node-resque";
3
+
4
+ /**
5
+ * Create a new Actionhero Task. The required properties of an task. These can be defined statically (this.name) or as methods which return a value.
6
+ * ```js
7
+ * import { Task, api, log } from "actionhero"
8
+ *
9
+ * export default class SayHello extends Task {
10
+ * constructor () {
11
+ * super()
12
+ * this.name = 'sayHello'
13
+ * this.description = 'I say Hello every minute'
14
+ * this.frequency = (60 * 1000)
15
+ * }
16
+ * async run (data, worker) {
17
+ * log('Hello!')
18
+ * }
19
+ * }
20
+ * ```
21
+ */
22
+ export abstract class Task {
23
+ /**The name of the Task */
24
+ name: string;
25
+ /**The description of the Task (default this.name) */
26
+ description: string;
27
+ /**The default queue to run this Task on (default: 'default') */
28
+ queue: string;
29
+ /**How often to run this Task, in ms. 0 is non-recurring. (default: 0) */
30
+ frequency?: number;
31
+ /**The inputs of the Task (default: {}) */
32
+ inputs?: Inputs;
33
+ /**The Middleware specific to this Task (default: []). Middleware is described by the string names of the middleware */
34
+ middleware?: Array<string>;
35
+ /**Plugins from node-resque to use on this task (default: []). Plugins like `QueueLock can be applied` */
36
+ plugins?: Array<
37
+ string | (new (args: ConstructorParameters<typeof Plugin>) => Plugin)
38
+ >;
39
+ /**Options for the node-resque plugins. */
40
+ pluginOptions?: { [key: string]: any };
41
+ /**Re-enqueuing a periodic task in the case of an exception. (default: false) */
42
+ reEnqueuePeriodicTaskIfException?: boolean;
43
+
44
+ constructor() {
45
+ this.description = this.description ?? this.name;
46
+ this.frequency = this.frequency ?? 0;
47
+ this.queue = this.queue ?? "default";
48
+ this.middleware = this.middleware ?? [];
49
+ this.plugins = this.plugins ?? [];
50
+ this.pluginOptions = this.pluginOptions ?? {};
51
+ this.reEnqueuePeriodicTaskIfException =
52
+ this.reEnqueuePeriodicTaskIfException ?? true;
53
+ }
54
+
55
+ /**
56
+ * The main "do something" method for this task. It can be `async`. Anything returned from this method will be logged.
57
+ * If error is thrown in this method, it will be logged & caught. Using middleware, you can decide to re-run the task on failure.
58
+ * `this` is a Task instance itself now.
59
+ *
60
+ * Inputs:
61
+ * * data: The data about this instance of the task, specifically params.
62
+ * * worker: Instance of a node-resque worker. You can inspect `worker.job` and set `worker.result` explicitly if your Task does not return a value.
63
+ */
64
+ abstract run(data: TaskInputs, worker: Worker): Promise<any>;
65
+
66
+ validate?() {
67
+ if (!this.name) {
68
+ throw new Error("name is required for this task");
69
+ }
70
+ if (!this.description) {
71
+ throw new Error(`description is required for the task \`${this.name}\``);
72
+ }
73
+ if (!this.queue) {
74
+ throw new Error(`queue is required for the task \`${this.name}\``);
75
+ }
76
+ if (this.frequency === null || this.frequency === undefined) {
77
+ throw new Error(`frequency is required for the task \`${this.name}\``);
78
+ }
79
+ if (!this.run || typeof this.run !== "function") {
80
+ throw new Error(`task \`${this.name}\` has no run method`);
81
+ }
82
+ }
83
+ }
84
+
85
+ export interface TaskInputs {
86
+ [key: string]: any;
87
+ }
@@ -0,0 +1,107 @@
1
+ import * as path from "path";
2
+ import * as fs from "fs";
3
+ import { PackageJson } from "type-fest";
4
+ import { ActionheroLogLevel } from "..";
5
+
6
+ const namespace = "general";
7
+
8
+ declare module ".." {
9
+ export interface ActionheroConfigInterface {
10
+ [namespace]: ReturnType<(typeof DEFAULT)[typeof namespace]>;
11
+ }
12
+ }
13
+
14
+ export const DEFAULT = {
15
+ [namespace]: () => {
16
+ const packageJSON: PackageJson = JSON.parse(
17
+ fs
18
+ .readFileSync(path.join(__dirname, "..", "..", "package.json"))
19
+ .toString(),
20
+ );
21
+
22
+ return {
23
+ apiVersion: packageJSON.version,
24
+ serverName: packageJSON.name,
25
+ // you can manually set the server id (not recommended)
26
+ id: undefined as string,
27
+ welcomeMessage: `Welcome to the ${packageJSON.name} api`,
28
+ // A unique token to your application that servers will use to authenticate to each other
29
+ serverToken: "change-me",
30
+ // the redis prefix for Actionhero cache objects
31
+ cachePrefix: "actionhero:cache:",
32
+ // the redis prefix for Actionhero cache/lock objects
33
+ lockPrefix: "actionhero:lock:",
34
+ // how long will a lock last before it expires (ms)?
35
+ lockDuration: 1000 * 10, // 10 seconds
36
+ // How many pending actions can a single connection be working on
37
+ simultaneousActions: 5,
38
+ // allow connections to be created without remoteIp and remotePort (they will be set to 0)
39
+ enforceConnectionProperties: true,
40
+ // disables the whitelisting of client params
41
+ disableParamScrubbing: false,
42
+ // enable action response to logger
43
+ enableResponseLogging: false,
44
+ // params you would like hidden from any logs. Can be an array of strings or a method that returns an array of strings.
45
+ filteredParams: [] as string[] | (() => string[]),
46
+ // responses you would like hidden from any logs. Can be an array of strings or a method that returns an array of strings.
47
+ filteredResponse: [] as string[] | (() => string[]),
48
+ // values that signify missing params
49
+ missingParamChecks: [null, "", undefined],
50
+ // The default filetype to server when a user requests a directory
51
+ directoryFileType: "index.html",
52
+ // What log-level should we use for file requests?
53
+ fileRequestLogLevel: "info" as ActionheroLogLevel,
54
+ // The default priority level given to middleware of all types (action, connection, say, and task)
55
+ defaultMiddlewarePriority: 100,
56
+ // Which channel to use on redis pub/sub for RPC communication
57
+ channel: "actionhero",
58
+ // How long to wait for an RPC call before considering it a failure
59
+ rpcTimeout: 5000,
60
+ // should CLI methods and help include internal Actionhero CLI methods?
61
+ cliIncludeInternal: true,
62
+ // configuration for your actionhero project structure
63
+ paths: {
64
+ action: [path.join(__dirname, "..", "actions")],
65
+ task: [path.join(__dirname, "..", "tasks")],
66
+ server: [path.join(__dirname, "..", "servers")],
67
+ cli: [path.join(__dirname, "..", "bin")],
68
+ initializer: [path.join(__dirname, "..", "initializers")],
69
+ public: [path.join(process.cwd(), "public")],
70
+ pid: [path.join(process.cwd(), "pids")],
71
+ log: [path.join(process.cwd(), "log")],
72
+ plugin: [path.join(process.cwd(), "node_modules")],
73
+ test: [path.join(process.cwd(), "__tests__")],
74
+ // for the src and dist paths, assume we are running in compiled mode from `dist`
75
+ src: path.join(process.cwd(), "src"),
76
+ dist: path.join(process.cwd(), "dist"),
77
+ },
78
+
79
+ // hash containing chat rooms you wish to be created at server boot
80
+ startingChatRooms: {
81
+ // format is {roomName: {authKey, authValue}}
82
+ // 'secureRoom': {authorized: true},
83
+ } as Record<string, Record<string, any>>,
84
+ };
85
+ },
86
+ };
87
+
88
+ export const test = {
89
+ [namespace]: () => {
90
+ return {
91
+ serverToken: `serverToken-${process.env.JEST_WORKER_ID || 0}`,
92
+ startingChatRooms: {
93
+ defaultRoom: {},
94
+ otherRoom: {},
95
+ },
96
+ rpcTimeout: 3000,
97
+ };
98
+ },
99
+ };
100
+
101
+ export const production = {
102
+ [namespace]: () => {
103
+ return {
104
+ fileRequestLogLevel: "debug",
105
+ };
106
+ },
107
+ };
@@ -0,0 +1,162 @@
1
+ import { ActionProcessor, Connection } from "..";
2
+
3
+ const namespace = "errors";
4
+
5
+ declare module ".." {
6
+ export interface ActionheroConfigInterface {
7
+ [namespace]: ReturnType<(typeof DEFAULT)[typeof namespace]>;
8
+ }
9
+ }
10
+
11
+ export const DEFAULT = {
12
+ [namespace]: () => {
13
+ return {
14
+ _toExpand: false,
15
+
16
+ // Should error types of "unknownAction" be included to the Exception handlers?
17
+ reportUnknownActions: false,
18
+
19
+ // ///////////////
20
+ // SERIALIZERS //
21
+ // ///////////////
22
+
23
+ serializers: {
24
+ servers: {
25
+ web: (error: NodeJS.ErrnoException) => {
26
+ if (error.message) {
27
+ return String(error.message);
28
+ } else {
29
+ return error;
30
+ }
31
+ },
32
+ websocket: (error: NodeJS.ErrnoException) => {
33
+ if (error.message) {
34
+ return String(error.message);
35
+ } else {
36
+ return error;
37
+ }
38
+ },
39
+ specHelper: (error: NodeJS.ErrnoException) => {
40
+ if (error.message) {
41
+ return "Error: " + String(error.message);
42
+ } else {
43
+ return error;
44
+ }
45
+ },
46
+ },
47
+ // See ActionProcessor#applyDefaultErrorLogLineFormat to see an example of how to customize
48
+ actionProcessor:
49
+ null as ActionProcessor<any>["applyDefaultErrorLogLineFormat"],
50
+ },
51
+
52
+ // ///////////
53
+ // ACTIONS //
54
+ // ///////////
55
+
56
+ // When a params for an action is invalid
57
+ invalidParams: (
58
+ data: ActionProcessor<any>,
59
+ validationErrors: Array<string | Error>,
60
+ ) => {
61
+ if (validationErrors.length >= 0) return validationErrors[0];
62
+ return "validation error";
63
+ },
64
+
65
+ // When a required param for an action is not provided
66
+ missingParams: (data: ActionProcessor<any>, missingParams: string[]) => {
67
+ return `${missingParams[0]} is a required parameter for this action`;
68
+ },
69
+
70
+ // user requested an unknown action
71
+ unknownAction: (data: ActionProcessor<any>) => {
72
+ return `unknown action or invalid apiVersion`;
73
+ },
74
+
75
+ // action not useable by this client/server type
76
+ unsupportedServerType: (data: ActionProcessor<any>) => {
77
+ return `this action does not support the ${data.connection.type} connection type`;
78
+ },
79
+
80
+ // action failed because server is mid-shutdown
81
+ serverShuttingDown: (data: ActionProcessor<any>) => {
82
+ return `the server is shutting down`;
83
+ },
84
+
85
+ // action failed because this client already has too many pending actions
86
+ // limit defined in api.config.general.simultaneousActions
87
+ tooManyPendingActions: (data: ActionProcessor<any>) => {
88
+ return `you have too many pending requests`;
89
+ },
90
+
91
+ // Decorate your response based on Error here.
92
+ // Any action that throws an Error will pass through this method before returning
93
+ // an error to the client. Response can be edited here, status codes changed, etc.
94
+ async genericError(
95
+ data: ActionProcessor<any>,
96
+ error: NodeJS.ErrnoException,
97
+ ) {
98
+ return error;
99
+ },
100
+
101
+ // ///////////////
102
+ // FILE SERVER //
103
+ // ///////////////
104
+
105
+ // The body message to accompany 404 (file not found) errors regarding flat files
106
+ // You may want to load in the content of 404.html or similar
107
+ fileNotFound: (connection: Connection) => {
108
+ return `that file is not found`;
109
+ },
110
+
111
+ // user didn't request a file
112
+ fileNotProvided: (connection: Connection) => {
113
+ return `file is a required param to send a file`;
114
+ },
115
+
116
+ // something went wrong trying to read the file
117
+ fileReadError: (connection: Connection, error: NodeJS.ErrnoException) => {
118
+ return `error reading file: ${error?.message ?? error}`;
119
+ },
120
+
121
+ // ///////////////
122
+ // CONNECTIONS //
123
+ // ///////////////
124
+
125
+ verbNotFound: (connection: Connection, verb: string) => {
126
+ return `verb not found or not allowed (${verb})`;
127
+ },
128
+
129
+ verbNotAllowed: (connection: Connection, verb: string) => {
130
+ return `verb not found or not allowed (${verb})`;
131
+ },
132
+
133
+ connectionRoomAndMessage: (connection: Connection) => {
134
+ return `both room and message are required`;
135
+ },
136
+
137
+ connectionNotInRoom: (connection: Connection, room: string) => {
138
+ return `connection not in this room (${room})`;
139
+ },
140
+
141
+ connectionAlreadyInRoom: (connection: Connection, room: string) => {
142
+ return `connection already in this room (${room})`;
143
+ },
144
+
145
+ connectionRoomHasBeenDeleted: (room: string) => {
146
+ return "this room has been deleted";
147
+ },
148
+
149
+ connectionRoomNotExist: (room: string) => {
150
+ return "room does not exist";
151
+ },
152
+
153
+ connectionRoomExists: (room: string) => {
154
+ return "room exists";
155
+ },
156
+
157
+ connectionRoomRequired: () => {
158
+ return "a room is required";
159
+ },
160
+ };
161
+ },
162
+ };