@rapidrest/core 1.15.0 → 2.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 (53) hide show
  1. package/dist/lib/AlertUtils.js +53 -37
  2. package/dist/lib/AlertUtils.js.map +1 -1
  3. package/dist/lib/ApiError.js +8 -1
  4. package/dist/lib/ApiError.js.map +1 -1
  5. package/dist/lib/CacheUtils.js +23 -0
  6. package/dist/lib/CacheUtils.js.map +1 -0
  7. package/dist/lib/ClassLoader.js +48 -55
  8. package/dist/lib/ClassLoader.js.map +1 -1
  9. package/dist/lib/FileUtils.js +120 -45
  10. package/dist/lib/FileUtils.js.map +1 -1
  11. package/dist/lib/JWTUtils.js +200 -165
  12. package/dist/lib/JWTUtils.js.map +1 -1
  13. package/dist/lib/Logger.js +32 -3
  14. package/dist/lib/Logger.js.map +1 -1
  15. package/dist/lib/MemoryStore.js +8 -6
  16. package/dist/lib/MemoryStore.js.map +1 -1
  17. package/dist/lib/MessagingUtils.js +69 -40
  18. package/dist/lib/MessagingUtils.js.map +1 -1
  19. package/dist/lib/NotificationsUtils.js +26 -8
  20. package/dist/lib/NotificationsUtils.js.map +1 -1
  21. package/dist/lib/OASUtils.js +55 -24
  22. package/dist/lib/OASUtils.js.map +1 -1
  23. package/dist/lib/ObjectFactory.js +144 -67
  24. package/dist/lib/ObjectFactory.js.map +1 -1
  25. package/dist/lib/ObjectUtils.js +18 -5
  26. package/dist/lib/ObjectUtils.js.map +1 -1
  27. package/dist/lib/StringUtils.js +55 -28
  28. package/dist/lib/StringUtils.js.map +1 -1
  29. package/dist/lib/TelemetryUtils.js +30 -4
  30. package/dist/lib/TelemetryUtils.js.map +1 -1
  31. package/dist/lib/UserUtils.js +4 -5
  32. package/dist/lib/UserUtils.js.map +1 -1
  33. package/dist/lib/ValidationUtils.js +10 -3
  34. package/dist/lib/ValidationUtils.js.map +1 -1
  35. package/dist/lib/index.js +1 -0
  36. package/dist/lib/index.js.map +1 -1
  37. package/dist/lib/threads/ThreadPool.js +131 -55
  38. package/dist/lib/threads/ThreadPool.js.map +1 -1
  39. package/dist/types/AlertUtils.d.ts +4 -0
  40. package/dist/types/CacheUtils.d.ts +14 -0
  41. package/dist/types/ClassLoader.d.ts +10 -0
  42. package/dist/types/FileUtils.d.ts +20 -7
  43. package/dist/types/JWTUtils.d.ts +69 -24
  44. package/dist/types/MessagingUtils.d.ts +5 -1
  45. package/dist/types/NotificationsUtils.d.ts +22 -0
  46. package/dist/types/ObjectFactory.d.ts +25 -1
  47. package/dist/types/ObjectUtils.d.ts +4 -0
  48. package/dist/types/StringUtils.d.ts +8 -0
  49. package/dist/types/TelemetryUtils.d.ts +10 -0
  50. package/dist/types/ValidationUtils.d.ts +1 -1
  51. package/dist/types/index.d.ts +1 -0
  52. package/dist/types/threads/ThreadPool.d.ts +30 -1
  53. package/package.json +1 -1
@@ -122,30 +122,48 @@ export interface JWTUtilsConfig {
122
122
  * @author Jean-Philippe Steinmetz <rapidrests@gmail.com>
123
123
  */
124
124
  export declare class JWTUtils {
125
- private static _parsedKeyCache;
126
- /**
127
- * Throws if `config.secret` looks like an asymmetric (RSA/EC) key but `config.options.algorithms` was not
128
- * explicitly restricted. Signing/verifying with an asymmetric key while leaving `algorithms` unset opens the
129
- * door to algorithm-confusion attacks (e.g. an attacker forging an HS256 token using the public key as the
130
- * HMAC secret). HMAC secrets (plain strings/buffers that aren't PEM-encoded) are unaffected.
125
+ /** HMAC algorithm names that must never be permitted alongside a non-HMAC secret (see `assertSafeAlgorithm`). */
126
+ private static readonly HMAC_ALGORITHMS;
127
+ /** Maximum size, in bytes, a compressed profile is allowed to decompress to (see `finalizePayload`). Guards
128
+ * against a decompression bomb - a small compressed payload expanding to consume excessive memory. */
129
+ private static readonly MAX_DECOMPRESSED_PROFILE_BYTES;
130
+ /**
131
+ * Returns `true` if `secret` is a form that is only ever usable as a genuine HMAC secret - a plain
132
+ * string/Buffer that isn't PEM-encoded, or a `KeyObject` of type `"secret"`. Anything else (a PEM
133
+ * string/Buffer, an asymmetric `KeyObject`, a `{ key, passphrase }` wrapper, a `GetPublicKeyOrSecret`
134
+ * callback, a JWK-shaped object, etc.) is *not* considered safe, since it may resolve to a non-secret
135
+ * (public) value that an attacker could use to forge an HS256/384/512 token.
136
+ */
137
+ private static isKnownSafeHmacSecret;
138
+ /**
139
+ * Throws unless `config.secret` is a known-safe plain HMAC secret. Any other secret shape is treated
140
+ * conservatively as potentially asymmetric (fail closed, rather than only matching a fixed allowlist of
141
+ * asymmetric shapes seen so far) and requires `config.options.algorithms` to be explicitly set to a list
142
+ * that does not itself include an HMAC algorithm. Without this, signing/verifying with e.g. an RSA key
143
+ * while leaving `algorithms` unset - or restricting it to `["RS256", "HS256"]` - opens the door to
144
+ * algorithm-confusion attacks: an attacker holding only the public half of the key pair can forge a token
145
+ * by signing it with HS256 using that public value as the HMAC secret.
131
146
  *
132
147
  * @param config The JWT configuration to validate.
133
148
  */
134
149
  private static assertSafeAlgorithm;
135
150
  /**
136
- * Generates a new JWT token for the given config and user object. The user object must be a valid RapidREST
137
- * user.
138
- *
139
- * @param config The JWT configuration to use when generating the token.
140
- * @param user The user to encode into the token's payload.
151
+ * Returns the key length, in bytes, required by `algorithm` (e.g. 32 for `aes-256-cbc`, 24 for
152
+ * `aes-192-cbc`), so the scrypt-derived key `deriveKey`/`deriveKeySync` produce always matches whatever
153
+ * cipher `passwordOptions.algorithm` actually names, instead of a length hard-coded for one specific
154
+ * algorithm. Throws a clear error for an algorithm Node's `crypto` module doesn't recognize, rather than
155
+ * letting `createCipheriv`/`createDecipheriv` fail later with an opaque "Invalid key length".
156
+ */
157
+ private static resolveKeyLength;
158
+ /**
159
+ * Derives a symmetric encryption key from `password`/`salt` for use with `algorithm`.
141
160
  */
142
161
  private static deriveKey;
143
162
  /**
144
- * Generates a new JWT token for the given config and user object. The user object must be a valid RapidREST
145
- * user.
146
- *
147
- * @param config The JWT configuration to use when generating the token.
148
- * @param user The user to encode into the token's payload.
163
+ * Synchronous counterpart to `deriveKey()`. **Blocks the event loop** for the duration of the scrypt
164
+ * derivation (deliberately CPU-expensive, typically tens of milliseconds) - `createTokenSync`/
165
+ * `decodeTokenSync` should therefore be avoided on a request-handling path when password-based payload
166
+ * encryption is configured; prefer `createToken`/`decodeToken` there.
149
167
  */
150
168
  private static deriveKeySync;
151
169
  /**
@@ -159,13 +177,13 @@ export declare class JWTUtils {
159
177
  */
160
178
  private static hybridEncrypt;
161
179
  /**
162
- * Returns `true` if `algorithm` is an AEAD cipher (GCM/CCM/OCB/ChaCha20-Poly1305), which produces an
163
- * authentication tag that must be captured on encryption and supplied back on decryption via
164
- * `getAuthTag()`/`setAuthTag()`.
165
- *
166
- * @param algorithm The cipher algorithm name (e.g. `aes-256-gcm`).
180
+ * Returns the base64-encoded authentication tag for `cipher` if it's an AEAD cipher, otherwise `""`. Rather
181
+ * than pattern-matching the algorithm name (which only recognizes a fixed list of known AEAD naming
182
+ * conventions), this asks the cipher itself via `getAuthTag()`, which throws for any non-AEAD cipher - so
183
+ * any AEAD cipher/alias supported by the current Node/OpenSSL build is handled correctly, including ones
184
+ * not known when this was last updated.
167
185
  */
168
- private static isAEADCipher;
186
+ private static getAuthTagIfAEAD;
169
187
  /**
170
188
  * Decrypts data produced by `hybridEncrypt`.
171
189
  *
@@ -173,8 +191,34 @@ export declare class JWTUtils {
173
191
  * @param encoded The encrypted data, as produced by `hybridEncrypt`.
174
192
  */
175
193
  private static hybridDecrypt;
194
+ /**
195
+ * Builds the signable payload shared by `createToken`/`createTokenSync`: validates `config`/`user`, spreads
196
+ * `data`, compresses the profile if requested, and - for public-key encryption only, which has no async
197
+ * dependency - encrypts it. Password-based encryption is left for the caller to finish via
198
+ * `finishPasswordEncryption()`, since deriving the key is the one step that differs between the sync and
199
+ * async entry points.
200
+ */
201
+ private static preparePayload;
202
+ /** Finishes password-based payload encryption once `key` has been derived (sync or async). */
203
+ private static finishPasswordEncryption;
176
204
  static createToken(config: JWTUtilsConfig, user: JWTUser, data?: any): Promise<string>;
205
+ /**
206
+ * Synchronous counterpart to `createToken()`. **Blocks the event loop** while deriving the encryption key
207
+ * when password-based payload encryption is configured (see `deriveKeySync`) - prefer `createToken()` on a
208
+ * request-handling path in that case.
209
+ */
177
210
  static createTokenSync(config: JWTUtilsConfig, user: JWTUser, data?: any): string;
211
+ /**
212
+ * Verifies `token` and prepares its payload for `decodeToken`/`decodeTokenSync`: validates the signature/
213
+ * shape, and - for private-key decryption only, which has no async dependency - decrypts it in place.
214
+ * Password-based decryption is left for the caller to finish via `finishPasswordDecryption()`, since
215
+ * deriving the key is the one step that differs between the sync and async entry points.
216
+ */
217
+ private static preDecode;
218
+ /** Finishes password-based payload decryption once `key` has been derived (sync or async). */
219
+ private static finishPasswordDecryption;
220
+ /** Decompresses (if applicable) and parses the final payload profile shared by both decode entry points. */
221
+ private static finalizePayload;
178
222
  /**
179
223
  * Decodes the given JWT authentication token using the provided configuration. If the token is not valid an
180
224
  * error is thrown with the reason. Returns the encoded user object payload upon success.
@@ -185,8 +229,9 @@ export declare class JWTUtils {
185
229
  */
186
230
  static decodeToken(config: JWTUtilsConfig, token: string): Promise<JWTPayload>;
187
231
  /**
188
- * Decodes the given JWT authentication token using the provided configuration. If the token is not valid an
189
- * error is thrown with the reason. Returns the encoded user object payload upon success.
232
+ * Synchronous counterpart to `decodeToken()`. **Blocks the event loop** while deriving the decryption key
233
+ * when password-based payload encryption is configured (see `deriveKeySync`) - prefer `decodeToken()` on a
234
+ * request-handling path in that case.
190
235
  *
191
236
  * @param config The JWT configuration to use when validating the token.
192
237
  * @param token The JWT token to validate.
@@ -57,6 +57,10 @@ export declare class MessagingUtils {
57
57
  private _transporter;
58
58
  /** Cache of compiled Handlebars delegates keyed by "<templateName>:<field>". */
59
59
  private _compiledTemplates;
60
+ /** Source string each `_compiledTemplates` entry was compiled from, keyed the same way. Lets `loadTemplate()`
61
+ * detect when an existing field's value has changed (e.g. a live config reload editing a template's subject/
62
+ * text/html) and recompile, instead of only ever compiling a field once and rendering stale content forever. */
63
+ private _compiledTemplateSources;
60
64
  /** Names of templates already compiled into `_compiledTemplates` for this instance. See `loadTemplate()`. */
61
65
  private _loadedTemplates;
62
66
  init(): Promise<void>;
@@ -64,7 +68,7 @@ export declare class MessagingUtils {
64
68
  * Loads the template with the given name and returns its contents as a string.
65
69
  * @param name The name of the template to load.
66
70
  */
67
- loadTemplate(name: string): Template;
71
+ loadTemplate(name: string): Promise<Template>;
68
72
  /**
69
73
  * Sends an email using the given template name and variables.
70
74
  * @param templateName The name of the email template to send.
@@ -4,6 +4,20 @@
4
4
  * @author Jean-Philippe Steinmetz
5
5
  */
6
6
  export declare class NotificationUtils {
7
+ /**
8
+ * The redis channel `broadcastMessage()` publishes to. Namespaced (rather than a bare `"allusers"`) so it
9
+ * can never collide with a per-recipient channel `sendMessage()` derives from a caller-supplied uid - a
10
+ * client-facing "send a message to this uid" feature that passes its recipient straight through to
11
+ * `sendMessage()` must not be able to choose a uid that lands on the broadcast channel and reach every
12
+ * subscriber instead of the intended one recipient.
13
+ */
14
+ static readonly BROADCAST_CHANNEL = "broadcast:allusers";
15
+ /**
16
+ * Prefix applied to every per-recipient channel in `sendMessage()`. Combined with `BROADCAST_CHANNEL`'s own
17
+ * distinct `"broadcast:"` prefix, this guarantees the two channel namespaces can never overlap regardless of
18
+ * what uid value a caller supplies.
19
+ */
20
+ static readonly USER_CHANNEL_PREFIX = "user:";
7
21
  /** The redis client to use for broadcasting messages. */
8
22
  private redis;
9
23
  /** The logging utility to use. */
@@ -23,6 +37,9 @@ export declare class NotificationUtils {
23
37
  /**
24
38
  * Broadcasts a given message to all users.
25
39
  *
40
+ * Subscribers must listen on `NotificationUtils.BROADCAST_CHANNEL` (rather than a bare `"allusers"`) to
41
+ * receive these messages.
42
+ *
26
43
  * @param {any} type The type of message being sent.
27
44
  * @param {string} action The action performed on the data (if applicable).
28
45
  * @param {string} data The contents of the message to send.
@@ -31,6 +48,11 @@ export declare class NotificationUtils {
31
48
  /**
32
49
  * Sends a given message to the room or user with the specified uid(s).
33
50
  *
51
+ * Each recipient's channel is `NotificationUtils.USER_CHANNEL_PREFIX + uid` (rather than the bare uid), so
52
+ * that no caller-supplied uid can collide with `NotificationUtils.BROADCAST_CHANNEL` or any other reserved
53
+ * channel and be delivered to unintended subscribers. Subscribers must listen on that prefixed channel name
54
+ * to receive messages sent to their uid.
55
+ *
34
56
  * @param {string} uids The universally unique identifier of the room or user to send the message to.
35
57
  * @param {string} type The type of message being sent.
36
58
  * @param {string} action The action performed on the data (if applicable).
@@ -22,7 +22,10 @@ export declare class ObjectFactory {
22
22
  readonly classes: Map<string, any>;
23
23
  /** The global application configuration object. */
24
24
  protected config: any;
25
- /** A map for the unique name to the intance of a particular class type. */
25
+ /** A map for the unique name to the intance of a particular class type.
26
+ *
27
+ * Note that this map is unbounded and only shrinks via an explicit `destroy()` call.
28
+ */
26
29
  readonly instances: Map<string, any>;
27
30
  /** The application logging utility. */
28
31
  protected logger: any;
@@ -30,6 +33,12 @@ export declare class ObjectFactory {
30
33
  private readonly _metadataCache;
31
34
  /** Secondary index: className → first registered instance key, for O(1) getInstance() fallback. */
32
35
  private readonly _firstByClass;
36
+ /** Tracks in-flight `initialize()` promises, keyed by registry name, for instances currently completing
37
+ * async initialization. `newInstance()` registers an instance in `instances` before its (possibly async)
38
+ * initialization completes, so a concurrent `newInstance()` call for the same name would otherwise find the
39
+ * entry via the instances-map fast path and receive the not-yet-initialized instance synchronously instead
40
+ * of waiting. Consulting this map lets that caller await the same in-flight initialization instead. */
41
+ private readonly _pendingInit;
33
42
  constructor(config?: any, logger?: any);
34
43
  /** Walks the prototype chain once for `obj` and caches the discovered decorator metadata on the constructor. */
35
44
  private _getOrBuildMetadata;
@@ -37,6 +46,11 @@ export declare class ObjectFactory {
37
46
  * Destroys the specified objects. If `undefined` is passed in, all objects managed by the factory are destroyed.
38
47
  */
39
48
  destroy(objs?: any | any[]): Promise<void>;
49
+ /** Removes `name` from `instances`. If it was the secondary index's "first" entry for its class, promotes
50
+ * another surviving instance of the same class if one exists, otherwise drops the entry so `getInstance()`
51
+ * correctly reports no instance is available. Shared by `destroy()` and `newInstance()`'s failed-initialization
52
+ * cleanup. */
53
+ private _removeInstance;
40
54
  /**
41
55
  * Deletes all instantiated objects.
42
56
  */
@@ -57,6 +71,16 @@ export declare class ObjectFactory {
57
71
  * @returns The list of functions that implements the `@Init` decorator if found, otherwise undefined.
58
72
  */
59
73
  getInitMethods(obj: any): Function[];
74
+ /**
75
+ * Derives the class name/fqn used to index `instances`/`classes` from a class type, fully qualified name
76
+ * string, or (defensively) a live instance. Shared by `getInstance`, `newInstance` and `register` so the
77
+ * three can never disagree about which string identifies a given class - a custom `.fqn` (e.g. one assigned
78
+ * by `ClassLoader`) always takes precedence over the bare `.name`, honored consistently everywhere a class
79
+ * identity is resolved.
80
+ *
81
+ * @param typeOrInstance The class type, fqn string, or instance to derive the name from.
82
+ */
83
+ private static classNameOf;
60
84
  /**
61
85
  * Returns the object instance with the given unique name. Unique names take the form `<ClassName>:<InstanceName>`.
62
86
  * It is possible to only specifiy the `<ClassName>`, doing so will automatically look for the `<ClassName>:default`
@@ -6,6 +6,10 @@ import { JWTUser } from "./JWTUtils.js";
6
6
  * @author Jean-Philippe Steinmetz
7
7
  */
8
8
  export declare class ObjectUtils {
9
+ /** Maximum object nesting depth `deleteScopedProps`/`validate` will recurse into with `recurse: true`. Guards
10
+ * against stack exhaustion from a pathologically deep (but otherwise valid, e.g. attacker-controlled JSON)
11
+ * object graph - cycle detection alone doesn't bound depth for a non-cyclic but very deep structure. */
12
+ private static readonly MAX_RECURSE_DEPTH;
9
13
  /**
10
14
  * Deletes all properties from the given object(s) that the specified user does not have scope to read.
11
15
  *
@@ -4,6 +4,14 @@
4
4
  * @author Jean-Philippe Steinmetz
5
5
  */
6
6
  export declare class StringUtils {
7
+ /**
8
+ * Escapes all regular expression metacharacters in `str` so it can be safely embedded in a `RegExp` pattern
9
+ * and matched as a literal string.
10
+ *
11
+ * @param {string} str The string to escape.
12
+ * @returns {string} The escaped string.
13
+ */
14
+ static escapeRegExp(str: string): string;
7
15
  /**
8
16
  * Returns a list of all parameters contained within the string. A parameter is a bracket delimited substring
9
17
  * (e.g. /my/{key}/with/{id}).
@@ -89,4 +89,14 @@ export declare class EventUtils {
89
89
  * @param callback The function to call when an event is recorded.
90
90
  */
91
91
  static on(type: string, callback: Function): void;
92
+ /**
93
+ * Unregisters a `callback` previously registered via `on()` for the given event `type`. Since `EventUtils` is
94
+ * a long-lived process-wide singleton, any listener registered dynamically (rather than once at startup) must
95
+ * eventually be removed via this method or its closure - and anything it captures - is retained for the life
96
+ * of the process.
97
+ *
98
+ * @param type The type of event the callback was registered for.
99
+ * @param callback The exact function reference passed to `on()`.
100
+ */
101
+ static off(type: string, callback: Function): void;
92
102
  }
@@ -24,7 +24,7 @@ export declare class ValidationUtils {
24
24
  */
25
25
  static checkEmail(val: string): string;
26
26
  /**
27
- * Validates that the provided array is not empty.
27
+ * Validates that the provided array is not empty (nor `null`/`undefined`).
28
28
  */
29
29
  static checkEmpty(val: Array<any>): Array<any>;
30
30
  /**
@@ -1,5 +1,6 @@
1
1
  export * from "./ApiError.js";
2
2
  export * from "./AlertUtils.js";
3
+ export * from "./CacheUtils.js";
3
4
  export * from "./ClassLoader.js";
4
5
  export * from "./decorators/index.js";
5
6
  export * from "./FileUtils.js";
@@ -20,6 +20,13 @@ export interface WorkerOptions {
20
20
  allowTs?: boolean;
21
21
  /** The path to the worker file. This must be set when using `ThreadWorkerEntry` as the default entry file. */
22
22
  worker?: string;
23
+ /**
24
+ * The maximum amount of time, in milliseconds, to wait for all worker threads to report readiness before
25
+ * `start()` rejects. Default is `ThreadPool.START_TIMEOUT_MS`. Guards against a worker whose entry script
26
+ * hangs during its own setup and never posts online/emits an error, which would otherwise leave the
27
+ * returned promise hanging forever with no way to detect or recover.
28
+ */
29
+ startupTimeoutMs?: number;
23
30
  }
24
31
  /**
25
32
  * The `ThreadPool` class provides an interface for managing a pool of execution threads that can be used for parallel
@@ -51,6 +58,8 @@ export interface WorkerOptions {
51
58
  export declare class ThreadPool {
52
59
  /** The maximum amount of time, in milliseconds, `stop()` waits for a worker to exit on its own before force-terminating it. */
53
60
  private static readonly STOP_GRACE_PERIOD_MS;
61
+ /** The default maximum amount of time, in milliseconds, `start()` waits for all workers to report readiness before rejecting. Overridable per-call via `WorkerOptions.startupTimeoutMs`. */
62
+ private static readonly START_TIMEOUT_MS;
54
63
  /** The map of event types to a list of callback functions. */
55
64
  private callbacks;
56
65
  /** The index of the last worker that was assigned work. */
@@ -63,6 +72,10 @@ export declare class ThreadPool {
63
72
  readonly workers: Array<Worker>;
64
73
  /** Used to indicate that the pool is shutting down. */
65
74
  private shutdown;
75
+ /** Tracks workers whose "exit" event has already fired, so a dead worker left in `workers` (e.g. exited
76
+ * without `restartOnExit`) is never sent a message via `postMessage()`, which throws synchronously once a
77
+ * worker has exited. */
78
+ private exitedWorkers;
66
79
  /**
67
80
  * The maximum number of threads that can be created by the pool.
68
81
  */
@@ -78,6 +91,20 @@ export declare class ThreadPool {
78
91
  * @param logger The Winston logger instance to forward all worker thread logs to.
79
92
  */
80
93
  constructor(max?: number, logger?: any);
94
+ /**
95
+ * @param onRestart Invoked with the replacement `Worker` whenever `restartOnExit` recreates the worker for
96
+ * `idx`. Lets `start()` re-attach its readiness-tracking listeners to the replacement - without this, a
97
+ * worker that crashes and is restarted before ever reporting ready would leave `start()`'s returned promise
98
+ * hanging forever, since nothing would be listening for the *replacement's* readiness signal.
99
+ */
100
+ /**
101
+ * Invokes every callback registered for `type` via `on()`, passing `idx` and optional `data`. Centralizes
102
+ * the "look up listeners, no-op if none registered" dispatch idiom shared by every worker event handler in
103
+ * `createWorker()`/`stop()` below, so a future change to how listeners are invoked - or a new message type
104
+ * that needs routing to a given event - only has to be made in one place instead of risking a hand-copied
105
+ * site being missed (as happened with WorkerMessageType.ERROR previously falling through to "message").
106
+ */
107
+ private dispatch;
81
108
  private createWorker;
82
109
  /**
83
110
  * Initializes the thread pool with the initial worker threads and begins execution.
@@ -104,7 +131,9 @@ export declare class ThreadPool {
104
131
  */
105
132
  send(msg: any): void;
106
133
  /**
107
- * Sends the provided message to all worker threads in the pool.
134
+ * Sends the provided message to all worker threads in the pool. Workers that have already exited (e.g.
135
+ * crashed with no `restartOnExit`) are silently skipped rather than throwing, so one dead worker doesn't
136
+ * prevent delivery to every worker after it in the array.
108
137
  * @param msg The message to send to all workers.
109
138
  */
110
139
  sendAll(msg: any): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rapidrest/core",
3
- "version": "1.15.0",
3
+ "version": "2.0.0",
4
4
  "description": "A collection of common utilities and core functionality for rapidly building RESTful applications.",
5
5
  "repository": "https://github.com/rapidrest/core.git",
6
6
  "author": "RapidREST <rapidrests@gmail.com>",