@rapidrest/core 1.15.0 → 3.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.
- package/dist/lib/AlertUtils.js +53 -37
- package/dist/lib/AlertUtils.js.map +1 -1
- package/dist/lib/ApiError.js +8 -1
- package/dist/lib/ApiError.js.map +1 -1
- package/dist/lib/CacheUtils.js +23 -0
- package/dist/lib/CacheUtils.js.map +1 -0
- package/dist/lib/ClassLoader.js +48 -55
- package/dist/lib/ClassLoader.js.map +1 -1
- package/dist/lib/FileUtils.js +120 -45
- package/dist/lib/FileUtils.js.map +1 -1
- package/dist/lib/JWTUtils.js +200 -165
- package/dist/lib/JWTUtils.js.map +1 -1
- package/dist/lib/Logger.js +32 -3
- package/dist/lib/Logger.js.map +1 -1
- package/dist/lib/MemoryStore.js +11 -10
- package/dist/lib/MemoryStore.js.map +1 -1
- package/dist/lib/MessagingUtils.js +69 -40
- package/dist/lib/MessagingUtils.js.map +1 -1
- package/dist/lib/NotificationsUtils.js +26 -8
- package/dist/lib/NotificationsUtils.js.map +1 -1
- package/dist/lib/OASUtils.js +55 -24
- package/dist/lib/OASUtils.js.map +1 -1
- package/dist/lib/ObjectFactory.js +144 -67
- package/dist/lib/ObjectFactory.js.map +1 -1
- package/dist/lib/ObjectUtils.js +18 -5
- package/dist/lib/ObjectUtils.js.map +1 -1
- package/dist/lib/RedisStore.js +129 -0
- package/dist/lib/RedisStore.js.map +1 -0
- package/dist/lib/SimpleStore.js +5 -0
- package/dist/lib/SimpleStore.js.map +1 -0
- package/dist/lib/StringUtils.js +55 -28
- package/dist/lib/StringUtils.js.map +1 -1
- package/dist/lib/TelemetryUtils.js +30 -4
- package/dist/lib/TelemetryUtils.js.map +1 -1
- package/dist/lib/UserUtils.js +4 -5
- package/dist/lib/UserUtils.js.map +1 -1
- package/dist/lib/ValidationUtils.js +10 -3
- package/dist/lib/ValidationUtils.js.map +1 -1
- package/dist/lib/index.js +1 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/threads/ThreadPool.js +131 -55
- package/dist/lib/threads/ThreadPool.js.map +1 -1
- package/dist/types/AlertUtils.d.ts +4 -0
- package/dist/types/CacheUtils.d.ts +14 -0
- package/dist/types/ClassLoader.d.ts +10 -0
- package/dist/types/FileUtils.d.ts +20 -7
- package/dist/types/JWTUtils.d.ts +69 -24
- package/dist/types/MemoryStore.d.ts +6 -10
- package/dist/types/MessagingUtils.d.ts +5 -1
- package/dist/types/NotificationsUtils.d.ts +22 -0
- package/dist/types/ObjectFactory.d.ts +25 -1
- package/dist/types/ObjectUtils.d.ts +4 -0
- package/dist/types/RedisStore.d.ts +26 -0
- package/dist/types/SimpleStore.d.ts +33 -0
- package/dist/types/StringUtils.d.ts +8 -0
- package/dist/types/TelemetryUtils.d.ts +10 -0
- package/dist/types/ValidationUtils.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/threads/ThreadPool.d.ts +30 -1
- package/package.json +3 -1
package/dist/lib/StringUtils.js
CHANGED
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
* @author Jean-Philippe Steinmetz
|
|
8
8
|
*/
|
|
9
9
|
export class StringUtils {
|
|
10
|
+
/**
|
|
11
|
+
* Escapes all regular expression metacharacters in `str` so it can be safely embedded in a `RegExp` pattern
|
|
12
|
+
* and matched as a literal string.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} str The string to escape.
|
|
15
|
+
* @returns {string} The escaped string.
|
|
16
|
+
*/
|
|
17
|
+
static escapeRegExp(str) {
|
|
18
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19
|
+
}
|
|
10
20
|
/**
|
|
11
21
|
* Returns a list of all parameters contained within the string. A parameter is a bracket delimited substring
|
|
12
22
|
* (e.g. /my/{key}/with/{id}).
|
|
@@ -42,36 +52,38 @@ export class StringUtils {
|
|
|
42
52
|
* @param {object} variables A map of key=>value pairs to search for and replace.
|
|
43
53
|
*/
|
|
44
54
|
static findAndReplace(contents, variables) {
|
|
45
|
-
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
const keys = Object.keys(variables);
|
|
56
|
+
// Keys with a null/undefined value are substituted as an empty string so that "{{key}}" placeholders aren't
|
|
57
|
+
// left in the final string. Resolved into a local copy rather than writing back onto `variables` itself,
|
|
58
|
+
// since this is a read-only formatting call from the caller's perspective - mutating their object would
|
|
59
|
+
// silently overwrite any null/undefined sentinel they relied on after this call returns.
|
|
60
|
+
const values = {};
|
|
61
|
+
for (const key of keys) {
|
|
62
|
+
const value = variables[key];
|
|
63
|
+
values[key] = value === null || value === undefined ? "" : value;
|
|
53
64
|
}
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
// A single combined regex - built once, O(k) - matching any `{{key}}` for any known key, rather than one
|
|
66
|
+
// regex per key checked in a nested O(k²) loop. Each key is escaped since it may contain regex
|
|
67
|
+
// metacharacters (e.g. from external input), which could otherwise be used for regex injection or
|
|
68
|
+
// catastrophic backtracking (ReDoS). Delimiting each alternative with the literal `{{`/`}}` means the
|
|
69
|
+
// matched key text is always recovered exactly, regardless of alternative order or shared prefixes
|
|
70
|
+
// between keys (backtracking still finds the alternative that makes the overall `\{\{...\}\}` match).
|
|
71
|
+
const combined = new RegExp("\\{\\{(" + keys.map((k) => StringUtils.escapeRegExp(k)).join("|") + ")\\}\\}", "g");
|
|
72
|
+
// A function replacer is used (rather than passing the value directly) so a value containing
|
|
73
|
+
// `$`-sequences (`$&`, `$$`, `$1`, ...) is inserted literally instead of being interpreted by
|
|
74
|
+
// `String.replace` as a special pattern.
|
|
75
|
+
const resolve = (key) => values[key].toString();
|
|
76
|
+
// Resolve one level of nested variable references within each value (e.g. a value of "{{adjective}} Dog"
|
|
77
|
+
// has "{{adjective}}" substituted), then use the resolved values for the final pass over `contents`.
|
|
78
|
+
const resolved = new Map();
|
|
79
|
+
for (const key of keys) {
|
|
80
|
+
let value = resolve(key);
|
|
81
|
+
if (value.includes("{{")) {
|
|
82
|
+
value = value.replace(combined, (_full, matchedKey) => resolve(matchedKey));
|
|
72
83
|
}
|
|
84
|
+
resolved.set(key, value);
|
|
73
85
|
}
|
|
74
|
-
return
|
|
86
|
+
return contents.replace(combined, (_full, matchedKey) => resolved.get(matchedKey) ?? _full);
|
|
75
87
|
}
|
|
76
88
|
/**
|
|
77
89
|
* Replaces all instances of the match regex pattern with the contents of the inner regular expression pattern for
|
|
@@ -94,7 +106,22 @@ export class StringUtils {
|
|
|
94
106
|
: match.global
|
|
95
107
|
? match
|
|
96
108
|
: new RegExp(match.source, match.flags + "g");
|
|
97
|
-
|
|
109
|
+
// Whether `global` has at least one capturing group, counted without executing it against `str` (a
|
|
110
|
+
// regex appended with an empty `|` alternative always matches the empty string, so `.exec("")`'s result
|
|
111
|
+
// array length - 1 gives the group count regardless of whether the original pattern would ever match).
|
|
112
|
+
// A plain `string` `match` compiles to a group-less regex, so this is always `false` in that case.
|
|
113
|
+
const hasCaptureGroup = new RegExp(global.source + "|").exec("").length > 1;
|
|
114
|
+
// A function replacer is used, receiving the full match plus every captured group in order. Without
|
|
115
|
+
// checking `hasCaptureGroup` first, a pattern with no capturing group would still receive a value in
|
|
116
|
+
// the "capture" position per String.prototype.replace's callback signature - but that value is the
|
|
117
|
+
// match's numeric *offset*, not `undefined`, silently corrupting the output (e.g. replaceAll("hello
|
|
118
|
+
// world", "o", "_") would embed "4"/"7" from the offsets instead of doing a plain substring
|
|
119
|
+
// replacement). With no capture group there's no "inner" text distinct from the match to preserve, so
|
|
120
|
+
// the whole match is simply replaced by `prefix` - i.e. ordinary search-and-replace semantics.
|
|
121
|
+
return str.replace(global, (...args) => {
|
|
122
|
+
const capture = hasCaptureGroup ? args[1] : "";
|
|
123
|
+
return prefix + capture;
|
|
124
|
+
});
|
|
98
125
|
}
|
|
99
126
|
/**
|
|
100
127
|
* Converts the first character in the given string to be lowercase (e.g. myVariable).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StringUtils.js","sourceRoot":"","sources":["../../src/StringUtils.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kDAAkD;AAClD,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,OAAO,WAAW;IACpB;;;;;;OAMG;IACI,MAAM,CAAC,aAAa,CAAC,GAAW;QACnC,IAAI,OAAO,GAAkB,IAAI,KAAK,EAAE,CAAC;QAEzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,IAAI,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBACf,IAAI,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBAClC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;oBACb,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;oBAC5C,CAAC,GAAG,GAAG,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACJ,MAAM;gBACV,CAAC;YACL,CAAC;iBAAM,CAAC;gBACJ,MAAM;YACV,CAAC;QACL,CAAC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,cAAc,CAAC,QAAgB,EAAE,SAAc;QACzD,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"StringUtils.js","sourceRoot":"","sources":["../../src/StringUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,12 +21,20 @@ export class Event {
|
|
|
21
21
|
this.origin = serviceName ? `${serviceName}:${config.get("version")}` : "unknown";
|
|
22
22
|
this.type = data.type;
|
|
23
23
|
this.userId = userId;
|
|
24
|
-
// Copy all fields in data to this object
|
|
25
24
|
const tmp = data;
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const protectedFields = new Set([
|
|
26
|
+
"environment",
|
|
27
|
+
"origin",
|
|
28
|
+
"uid",
|
|
29
|
+
"userId",
|
|
30
|
+
"__proto__",
|
|
31
|
+
"constructor",
|
|
32
|
+
"prototype",
|
|
33
|
+
]);
|
|
34
|
+
for (const key of Object.keys(tmp)) {
|
|
35
|
+
// We intentionally exclude only these fields from copying here. All others, including timestamp
|
|
28
36
|
// the caller can override in order to provide more accurate information about the event.
|
|
29
|
-
if (key
|
|
37
|
+
if (!protectedFields.has(key)) {
|
|
30
38
|
this[key] = tmp[key];
|
|
31
39
|
}
|
|
32
40
|
}
|
|
@@ -142,6 +150,24 @@ export class EventUtils {
|
|
|
142
150
|
EventUtils.listeners.set(type, callbacks);
|
|
143
151
|
}
|
|
144
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Unregisters a `callback` previously registered via `on()` for the given event `type`. Since `EventUtils` is
|
|
155
|
+
* a long-lived process-wide singleton, any listener registered dynamically (rather than once at startup) must
|
|
156
|
+
* eventually be removed via this method or its closure - and anything it captures - is retained for the life
|
|
157
|
+
* of the process.
|
|
158
|
+
*
|
|
159
|
+
* @param type The type of event the callback was registered for.
|
|
160
|
+
* @param callback The exact function reference passed to `on()`.
|
|
161
|
+
*/
|
|
162
|
+
static off(type, callback) {
|
|
163
|
+
const callbacks = EventUtils.listeners.get(type);
|
|
164
|
+
if (callbacks) {
|
|
165
|
+
const idx = callbacks.indexOf(callback);
|
|
166
|
+
if (idx >= 0) {
|
|
167
|
+
callbacks.splice(idx, 1);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
145
171
|
}
|
|
146
172
|
EventUtils.initialized = false;
|
|
147
173
|
EventUtils.listeners = new Map();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TelemetryUtils.js","sourceRoot":"","sources":["../../src/TelemetryUtils.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kDAAkD;AAClD,+EAA+E;AAC/E,OAAO,KAAwB,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAYzC;;;;GAIG;AACH,MAAM,OAAO,KAAK;IA+Bd,YAAY,MAAW,EAAE,MAAc,EAAE,IAAc;QAfvD;;WAEG;QACa,cAAS,GAAS,IAAI,IAAI,EAAE,CAAC;QAazC,IAAI,CAAC,GAAG,GAAG,MAAM,EAAE,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;QACxE,MAAM,WAAW,GAAW,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,
|
|
1
|
+
{"version":3,"file":"TelemetryUtils.js","sourceRoot":"","sources":["../../src/TelemetryUtils.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kDAAkD;AAClD,+EAA+E;AAC/E,OAAO,KAAwB,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAYzC;;;;GAIG;AACH,MAAM,OAAO,KAAK;IA+Bd,YAAY,MAAW,EAAE,MAAc,EAAE,IAAc;QAfvD;;WAEG;QACa,cAAS,GAAS,IAAI,IAAI,EAAE,CAAC;QAazC,IAAI,CAAC,GAAG,GAAG,MAAM,EAAE,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;QACxE,MAAM,WAAW,GAAW,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,MAAM,GAAG,GAAQ,IAAW,CAAC;QAC7B,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;YAC5B,aAAa;YACb,QAAQ;YACR,KAAK;YACL,QAAQ;YACR,WAAW;YACX,aAAa;YACb,WAAW;SACd,CAAC,CAAC;QACH,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACjC,gGAAgG;YAChG,yFAAyF;YACzF,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC3B,IAAY,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,CAAC;QACL,CAAC;IACL,CAAC;CACJ;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,UAAU;IAQnB;;;;;;OAMG;IACI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAW,EAAE,MAAW,EAAE,QAAgB;QAC/D,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC;QAC3B,UAAU,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;QACjC,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC;QAC3B,UAAU,CAAC,KAAK,GAAG,QAAQ,CAAC;QAE5B,qCAAqC;QACrC,MAAM,OAAO,GAAQ,MAAM,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9E,UAAU,CAAC,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;QAExC,UAAU,CAAC,WAAW,GAAG,IAAI,CAAC;IAClC,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAmB,EAAE,IAAa;QACzD,IAAI,CAAC;YACD,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;YAC5F,CAAC;YAED,IAAI,IAAI,EAAE,CAAC;gBACP,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YACpB,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAC5D,CAAC;YAED,0DAA0D;YAC1D,MAAM,KAAK,GAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAEvG,gCAAgC;YAChC,MAAM,OAAO,GAAW,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;YACxE,IAAI,OAAO,EAAE,CAAC;gBACV,MAAM,GAAG,GAAW,OAAO,GAAG,SAAS,CAAC;gBACxC,MAAM,QAAQ,GAAkB,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE;oBACzD,OAAO,EAAE;wBACL,aAAa,EAAE,MAAM,GAAG,UAAU,CAAC,KAAK;qBAC3C;iBACJ,CAAC,CAAC;YACP,CAAC;iBAAM,CAAC;gBACJ,UAAU,CAAC,MAAM,EAAE,KAAK,CACpB,wFAAwF,CAC3F,CAAC;YACN,CAAC;YAED,kCAAkC;YAClC,MAAM,SAAS,GAA2B,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7E,IAAI,SAAS,EAAE,CAAC;gBACZ,KAAK,IAAI,IAAI,IAAI,SAAS,EAAE,CAAC;oBACzB,IAAI,CAAC,KAAK,CAAC,CAAC;gBAChB,CAAC;YACL,CAAC;QACL,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAChB,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;gBACrB,OAAO,CAAC,IAAI,CAAC,0CAA0C,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1E,CAAC;iBAAM,CAAC;gBACJ,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACpF,CAAC;QACL,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,EAAE,CAAC,IAAY,EAAE,QAAkB;QAC7C,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;QAC5F,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,SAAS,GAA2B,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzE,sGAAsG;QACtG,yDAAyD;QACzD,sBAAsB;QACtB,IAAI,SAAS,EAAE,CAAC;YACZ,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,QAAkB;QAC9C,MAAM,SAAS,GAA2B,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzE,IAAI,SAAS,EAAE,CAAC;YACZ,MAAM,GAAG,GAAW,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAChD,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;gBACX,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAC7B,CAAC;QACL,CAAC;IACL,CAAC;;AA3Hc,sBAAW,GAAY,KAAK,CAAC;AAE7B,oBAAS,GAA4B,IAAI,GAAG,EAAE,CAAC"}
|
package/dist/lib/UserUtils.js
CHANGED
|
@@ -34,12 +34,10 @@ export class UserUtils {
|
|
|
34
34
|
* @param organizationUids The list of universally unique identifiers to search for.
|
|
35
35
|
*/
|
|
36
36
|
static hasOrganizations(user, organizationUids) {
|
|
37
|
-
if (user &&
|
|
37
|
+
if (user && Array.isArray(organizationUids)) {
|
|
38
38
|
for (const organizationUid of organizationUids) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
39
|
+
if (UserUtils.hasOrganization(user, organizationUid)) {
|
|
40
|
+
return true;
|
|
43
41
|
}
|
|
44
42
|
}
|
|
45
43
|
}
|
|
@@ -59,6 +57,7 @@ export class UserUtils {
|
|
|
59
57
|
const parts = externalId.split(":");
|
|
60
58
|
if (parts.length === 2 && parts[0] === type) {
|
|
61
59
|
result = parts[1];
|
|
60
|
+
break;
|
|
62
61
|
}
|
|
63
62
|
}
|
|
64
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserUtils.js","sourceRoot":"","sources":["../../src/UserUtils.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kDAAkD;AAClD,+EAA+E;AAE/E;;;;;;;;;;GAUG;AACH,MAAM,OAAO,SAAS;IAClB;;;;OAIG;IACI,MAAM,CAAC,eAAe,CAAC,IAAS,EAAE,eAAuB;QAC5D,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC1B,IAAI,GAAG,KAAK,eAAe,EAAE,CAAC;oBAC1B,OAAO,IAAI,CAAC;gBAChB,CAAC;YACL,CAAC;QACL,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,gBAAgB,CAAC,IAAS,EAAE,gBAA2B;QACjE,IAAI,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"UserUtils.js","sourceRoot":"","sources":["../../src/UserUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,10 +43,10 @@ export class ValidationUtils {
|
|
|
43
43
|
return val;
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* Validates that the provided array is not empty.
|
|
46
|
+
* Validates that the provided array is not empty (nor `null`/`undefined`).
|
|
47
47
|
*/
|
|
48
48
|
static checkEmpty(val) {
|
|
49
|
-
if (val
|
|
49
|
+
if (!val || val.length === 0) {
|
|
50
50
|
throw new Error("Value cannot be empty.");
|
|
51
51
|
}
|
|
52
52
|
return val;
|
|
@@ -129,7 +129,14 @@ export class ValidationUtils {
|
|
|
129
129
|
* Validates that the provided value is an entity `version` number (e.g. `value > 0`).
|
|
130
130
|
*/
|
|
131
131
|
static checkVersion(val) {
|
|
132
|
-
|
|
132
|
+
// `Number()` coerces several "empty" inputs - `null`, `""`/whitespace-only strings, `[]` - to `0`
|
|
133
|
+
// rather than `NaN`, which would otherwise let missing/malformed input silently through as if it were
|
|
134
|
+
// a legitimate version `0` instead of being rejected below. `undefined` needs no such guard since
|
|
135
|
+
// `Number(undefined)` already evaluates to `NaN`.
|
|
136
|
+
const isEmpty = val === null ||
|
|
137
|
+
(typeof val === "string" && val.trim() === "") ||
|
|
138
|
+
(Array.isArray(val) && val.length === 0);
|
|
139
|
+
const num = isEmpty ? NaN : Number(val);
|
|
133
140
|
if (isNaN(num)) {
|
|
134
141
|
throw new Error("Value is not a valid version number.");
|
|
135
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ValidationUtils.js","sourceRoot":"","sources":["../../src/ValidationUtils.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kDAAkD;AAClD,+EAA+E;AAC/E,OAAO,SAAS,MAAM,WAAW,CAAC;AAOlC;;GAEG;AACH,MAAM,OAAO,eAAe;IACxB;;;;;;;OAOG;IACI,MAAM,CAAC,KAAK,CAAC,GAAQ,EAAE,IAAiB;QAC3C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,SAAS,CAAC,GAAW;QAC/B,8FAA8F;QAC9F,8FAA8F;QAC9F,2FAA2F;QAC3F,oDAAoD;QACpD,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,UAAU,CAAC,GAAW;QAChC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,UAAU,CAAC,GAAe;QACpC,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"ValidationUtils.js","sourceRoot":"","sources":["../../src/ValidationUtils.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kDAAkD;AAClD,+EAA+E;AAC/E,OAAO,SAAS,MAAM,WAAW,CAAC;AAOlC;;GAEG;AACH,MAAM,OAAO,eAAe;IACxB;;;;;;;OAOG;IACI,MAAM,CAAC,KAAK,CAAC,GAAQ,EAAE,IAAiB;QAC3C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,SAAS,CAAC,GAAW;QAC/B,8FAA8F;QAC9F,8FAA8F;QAC9F,2FAA2F;QAC3F,oDAAoD;QACpD,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,UAAU,CAAC,GAAW;QAChC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,UAAU,CAAC,GAAe;QACpC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,OAAO,CAAC,GAAW;QAC7B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,SAAS,CAAC,GAAW;QAC/B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,SAAS,CAAC,GAAW;QAC/B,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,SAAS,CAAC,GAAQ;QAC5B,yGAAyG;QACzG,wDAAwD;QACxD,IAAI,OAAO,GAAG,KAAK,SAAS,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,UAAU,CAAC,GAAW;QAChC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,WAAW,CAAC,GAAW;QACjC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,QAAQ,CAAC,GAAW;QAC9B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,SAAS,CAAC,GAAW;QAC/B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,YAAY,CAAC,GAAQ;QAC/B,kGAAkG;QAClG,sGAAsG;QACtG,kGAAkG;QAClG,kDAAkD;QAClD,MAAM,OAAO,GACT,GAAG,KAAK,IAAI;YACZ,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;YAC9C,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAW,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC5B,CAAC;CACJ"}
|
package/dist/lib/index.js
CHANGED
package/dist/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC"}
|
|
@@ -67,6 +67,10 @@ export class ThreadPool {
|
|
|
67
67
|
constructor(max = 0, logger) {
|
|
68
68
|
/** The maximum number of threads allowed. */
|
|
69
69
|
this.maxThreads = os.cpus().length;
|
|
70
|
+
/** Tracks workers whose "exit" event has already fired, so a dead worker left in `workers` (e.g. exited
|
|
71
|
+
* without `restartOnExit`) is never sent a message via `postMessage()`, which throws synchronously once a
|
|
72
|
+
* worker has exited. */
|
|
73
|
+
this.exitedWorkers = new WeakSet();
|
|
70
74
|
// The `os.cpus().length` fallback can never actually be selected: `this.maxThreads`'s field initializer
|
|
71
75
|
// already evaluates to that same (always-truthy on a real OS) value before the constructor body runs, so
|
|
72
76
|
// it's only falsy when `os.cpus().length` itself is falsy too. Kept as defense in depth.
|
|
@@ -78,7 +82,28 @@ export class ThreadPool {
|
|
|
78
82
|
this.shutdown = false;
|
|
79
83
|
this.workers = new Array();
|
|
80
84
|
}
|
|
81
|
-
|
|
85
|
+
/**
|
|
86
|
+
* @param onRestart Invoked with the replacement `Worker` whenever `restartOnExit` recreates the worker for
|
|
87
|
+
* `idx`. Lets `start()` re-attach its readiness-tracking listeners to the replacement - without this, a
|
|
88
|
+
* worker that crashes and is restarted before ever reporting ready would leave `start()`'s returned promise
|
|
89
|
+
* hanging forever, since nothing would be listening for the *replacement's* readiness signal.
|
|
90
|
+
*/
|
|
91
|
+
/**
|
|
92
|
+
* Invokes every callback registered for `type` via `on()`, passing `idx` and optional `data`. Centralizes
|
|
93
|
+
* the "look up listeners, no-op if none registered" dispatch idiom shared by every worker event handler in
|
|
94
|
+
* `createWorker()`/`stop()` below, so a future change to how listeners are invoked - or a new message type
|
|
95
|
+
* that needs routing to a given event - only has to be made in one place instead of risking a hand-copied
|
|
96
|
+
* site being missed (as happened with WorkerMessageType.ERROR previously falling through to "message").
|
|
97
|
+
*/
|
|
98
|
+
dispatch(type, idx, data) {
|
|
99
|
+
const listeners = this.callbacks.get(type);
|
|
100
|
+
if (listeners) {
|
|
101
|
+
for (const callback of listeners) {
|
|
102
|
+
callback(idx, data);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
createWorker(idx, options, onRestart) {
|
|
82
107
|
if (!options.entry || !!options.worker) {
|
|
83
108
|
options.entry = path.join(_dirname, "ThreadWorkerEntry.js");
|
|
84
109
|
}
|
|
@@ -88,31 +113,48 @@ export class ThreadPool {
|
|
|
88
113
|
};
|
|
89
114
|
this.logger?.debug(`Creating thread worker: ${JSON.stringify(options)}`);
|
|
90
115
|
const worker = new Worker(options.entry, workerOptions);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
116
|
+
// Dispatches registered "online" callbacks for entry-mode pools, which have no other way to signal
|
|
117
|
+
// readiness at the application level. Guarded to worker-mode's exclusion (`!options.worker`) so a
|
|
118
|
+
// worker-mode pool - which reports readiness via the WorkerMessageType.ONLINE message handled below -
|
|
119
|
+
// doesn't fire "online" callbacks twice for the same worker.
|
|
120
|
+
worker.on("online", () => {
|
|
121
|
+
if (options && !options.worker) {
|
|
122
|
+
this.dispatch("online", idx);
|
|
97
123
|
}
|
|
98
124
|
});
|
|
125
|
+
worker.on("error", (error) => {
|
|
126
|
+
this.dispatch("error", idx, error);
|
|
127
|
+
});
|
|
99
128
|
worker.on("exit", async (code) => {
|
|
129
|
+
// Mark this worker instance as exited regardless of shutdown/restart state so send()/sendAll()/
|
|
130
|
+
// sendTo() never call postMessage() on it - postMessage() throws synchronously once a worker has
|
|
131
|
+
// exited, and a restarted worker gets a brand new Worker instance anyway so marking the old one here
|
|
132
|
+
// is harmless.
|
|
133
|
+
this.exitedWorkers.add(worker);
|
|
100
134
|
// While stop() is in progress it fires "exit" callbacks itself, using the authoritative exit code
|
|
101
135
|
// returned by terminate() - which is what triggers this very event. Firing them again here would
|
|
102
136
|
// invoke every registered "exit" callback twice per worker for a single stop() call.
|
|
103
137
|
if (!this.shutdown) {
|
|
104
|
-
|
|
105
|
-
if (listeners) {
|
|
106
|
-
for (const callback of listeners) {
|
|
107
|
-
callback(idx, code);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
138
|
+
this.dispatch("exit", idx, code);
|
|
110
139
|
}
|
|
111
140
|
// Restart worker thread
|
|
112
141
|
if (options?.restartOnExit && !this.shutdown) {
|
|
113
142
|
worker.removeAllListeners();
|
|
114
|
-
|
|
115
|
-
|
|
143
|
+
// createWorker() calls `new Worker(...)`, which can throw synchronously (e.g. non-cloneable
|
|
144
|
+
// workerData, thread-limit/OOM errors) - especially likely in a crash-loop scenario, which is
|
|
145
|
+
// exactly when restartOnExit is most active. This listener is itself async, and Node does not
|
|
146
|
+
// attach a rejection handler to an EventEmitter listener's returned promise, so an uncaught throw
|
|
147
|
+
// here would become an unhandled rejection capable of crashing the whole host process. Routing
|
|
148
|
+
// the failure to "error" listeners instead keeps it recoverable, consistent with how every other
|
|
149
|
+
// worker failure in this file is reported.
|
|
150
|
+
try {
|
|
151
|
+
const newWorker = this.createWorker(idx, options, onRestart);
|
|
152
|
+
this.workers[idx] = newWorker;
|
|
153
|
+
onRestart?.(newWorker);
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
this.dispatch("error", idx, error);
|
|
157
|
+
}
|
|
116
158
|
}
|
|
117
159
|
});
|
|
118
160
|
worker.on("message", (msg) => {
|
|
@@ -121,24 +163,17 @@ export class ThreadPool {
|
|
|
121
163
|
this.logger?.log(msg.data);
|
|
122
164
|
break;
|
|
123
165
|
case WorkerMessageType.ONLINE:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
166
|
+
this.dispatch("online", idx);
|
|
167
|
+
break;
|
|
168
|
+
case WorkerMessageType.ERROR:
|
|
169
|
+
// A post-startup runtime error reported by the worker (see ThreadWorkerEntry.js's message
|
|
170
|
+
// handler). Must route to "error" listeners like the native worker.on("error", ...) case
|
|
171
|
+
// above, not fall through to "message" - otherwise anything monitoring failures only via
|
|
172
|
+
// pool.on("error", ...) never learns the worker failed.
|
|
173
|
+
this.dispatch("error", idx, msg.data);
|
|
132
174
|
break;
|
|
133
175
|
default:
|
|
134
|
-
|
|
135
|
-
const listeners = this.callbacks.get("message");
|
|
136
|
-
if (listeners) {
|
|
137
|
-
for (const callback of listeners) {
|
|
138
|
-
callback(idx, msg);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
176
|
+
this.dispatch("message", idx, msg);
|
|
142
177
|
break;
|
|
143
178
|
}
|
|
144
179
|
});
|
|
@@ -162,10 +197,12 @@ export class ThreadPool {
|
|
|
162
197
|
return new Promise((resolve, reject) => {
|
|
163
198
|
let numReady = 0;
|
|
164
199
|
let settled = false;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
200
|
+
// Copied rather than mutated in place - `options` may be the caller's own object (reused across
|
|
201
|
+
// multiple start() calls, or even frozen), and it shouldn't gain an `allowTs` property - or, via
|
|
202
|
+
// createWorker() below, an `entry` property - that the caller never set themselves. Everything past
|
|
203
|
+
// this point operates on `resolvedOptions`, never the original `options` parameter.
|
|
204
|
+
const resolvedOptions = { ...options };
|
|
205
|
+
resolvedOptions.allowTs = "allowTs" in resolvedOptions ? resolvedOptions.allowTs : true;
|
|
169
206
|
const target = Math.min(num, this.maxThreads);
|
|
170
207
|
if (target <= 0) {
|
|
171
208
|
// Nothing to create; resolve immediately instead of hanging forever waiting for readiness signals
|
|
@@ -188,6 +225,7 @@ export class ThreadPool {
|
|
|
188
225
|
return;
|
|
189
226
|
}
|
|
190
227
|
settled = true;
|
|
228
|
+
clearTimeout(timeoutHandle);
|
|
191
229
|
this.shutdown = true;
|
|
192
230
|
for (const worker of this.workers) {
|
|
193
231
|
void worker.terminate();
|
|
@@ -195,31 +233,45 @@ export class ThreadPool {
|
|
|
195
233
|
this.workers.length = 0;
|
|
196
234
|
reject(error);
|
|
197
235
|
};
|
|
198
|
-
|
|
199
|
-
|
|
236
|
+
// Guard against a worker that never reports readiness and never errors either.
|
|
237
|
+
const timeoutMs = resolvedOptions.startupTimeoutMs ?? ThreadPool.START_TIMEOUT_MS;
|
|
238
|
+
const timeoutHandle = setTimeout(() => {
|
|
239
|
+
failStartup(new Error(`Timed out waiting for worker threads to start after ${timeoutMs}ms.`));
|
|
240
|
+
}, timeoutMs);
|
|
241
|
+
timeoutHandle.unref?.();
|
|
242
|
+
const succeed = () => {
|
|
243
|
+
settled = true;
|
|
244
|
+
clearTimeout(timeoutHandle);
|
|
245
|
+
resolve();
|
|
246
|
+
};
|
|
247
|
+
// Attaches the readiness-tracking listeners used to resolve/reject this start() call to `w`. Defined
|
|
248
|
+
// once per slot and re-invoked (via createWorker's `onRestart` hook below) on any replacement worker
|
|
249
|
+
// created by `restartOnExit` before this promise settles, so a worker that crashes and restarts
|
|
250
|
+
// during startup - before ever reporting ready - still lets start() resolve once the *replacement*
|
|
251
|
+
// becomes ready, instead of hanging forever with no listener tracking it.
|
|
252
|
+
const attachReadyListeners = (w) => {
|
|
200
253
|
let ready = false;
|
|
201
|
-
|
|
254
|
+
w.on("online", () => {
|
|
202
255
|
if (settled) {
|
|
203
256
|
return;
|
|
204
257
|
}
|
|
205
|
-
if (
|
|
258
|
+
if (!resolvedOptions.worker) {
|
|
206
259
|
ready = true;
|
|
207
260
|
numReady++;
|
|
208
261
|
}
|
|
209
262
|
// When all workers have finished being created resolve
|
|
210
263
|
if (numReady >= target) {
|
|
211
|
-
|
|
212
|
-
resolve();
|
|
264
|
+
succeed();
|
|
213
265
|
}
|
|
214
266
|
});
|
|
215
267
|
// If a worker fails to start before it ever reaches readiness, reject instead of leaving the
|
|
216
268
|
// returned promise hanging forever.
|
|
217
|
-
|
|
269
|
+
w.on("error", (error) => {
|
|
218
270
|
if (!ready) {
|
|
219
271
|
failStartup(error);
|
|
220
272
|
}
|
|
221
273
|
});
|
|
222
|
-
|
|
274
|
+
w.on("message", (msg) => {
|
|
223
275
|
if (settled) {
|
|
224
276
|
return;
|
|
225
277
|
}
|
|
@@ -234,10 +286,17 @@ export class ThreadPool {
|
|
|
234
286
|
}
|
|
235
287
|
// When all workers have finished being created resolve
|
|
236
288
|
if (numReady >= target) {
|
|
237
|
-
|
|
238
|
-
resolve();
|
|
289
|
+
succeed();
|
|
239
290
|
}
|
|
240
291
|
});
|
|
292
|
+
};
|
|
293
|
+
for (let i = 0; i < target; i++) {
|
|
294
|
+
const worker = this.createWorker(i, resolvedOptions, (newWorker) => {
|
|
295
|
+
if (!settled) {
|
|
296
|
+
attachReadyListeners(newWorker);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
attachReadyListeners(worker);
|
|
241
300
|
this.workers[i] = worker;
|
|
242
301
|
}
|
|
243
302
|
this.logger?.debug(`Created ${this.workers.length} worker(s)`);
|
|
@@ -257,11 +316,19 @@ export class ThreadPool {
|
|
|
257
316
|
// ThreadWorker.stop() to actually finish) before being force-terminated, so in-flight cleanup work
|
|
258
317
|
// (flushing writes, closing connections, etc.) isn't cut off by an arbitrary fixed delay.
|
|
259
318
|
await Promise.all(this.workers.map(async (worker, idx) => {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
exitCode =
|
|
319
|
+
let exitCode;
|
|
320
|
+
if (this.exitedWorkers.has(worker)) {
|
|
321
|
+
// Already exited (e.g. crashed with no restartOnExit, before stop() was ever called) - there's
|
|
322
|
+
// nothing to wait for or terminate.
|
|
323
|
+
exitCode = 0;
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
const exitedOnOwn = new Promise((resolve) => worker.once("exit", resolve));
|
|
327
|
+
const timedOut = sleep(ThreadPool.STOP_GRACE_PERIOD_MS).then(() => undefined);
|
|
328
|
+
exitCode = await Promise.race([exitedOnOwn, timedOut]);
|
|
329
|
+
if (exitCode === undefined) {
|
|
330
|
+
exitCode = await worker.terminate();
|
|
331
|
+
}
|
|
265
332
|
}
|
|
266
333
|
if (listeners) {
|
|
267
334
|
for (const callback of listeners) {
|
|
@@ -299,7 +366,9 @@ export class ThreadPool {
|
|
|
299
366
|
let idx = startIdx;
|
|
300
367
|
do {
|
|
301
368
|
const worker = this.workers[idx];
|
|
302
|
-
|
|
369
|
+
// Skip a worker that has already exited (e.g. crashed with no restartOnExit) rather than trying the
|
|
370
|
+
// next one - postMessage() throws synchronously on an exited worker.
|
|
371
|
+
if (worker && !this.exitedWorkers.has(worker)) {
|
|
303
372
|
worker.postMessage(msg);
|
|
304
373
|
this.lastThread = idx;
|
|
305
374
|
return;
|
|
@@ -309,12 +378,16 @@ export class ThreadPool {
|
|
|
309
378
|
throw new Error("No available workers in the pool.");
|
|
310
379
|
}
|
|
311
380
|
/**
|
|
312
|
-
* Sends the provided message to all worker threads in the pool.
|
|
381
|
+
* Sends the provided message to all worker threads in the pool. Workers that have already exited (e.g.
|
|
382
|
+
* crashed with no `restartOnExit`) are silently skipped rather than throwing, so one dead worker doesn't
|
|
383
|
+
* prevent delivery to every worker after it in the array.
|
|
313
384
|
* @param msg The message to send to all workers.
|
|
314
385
|
*/
|
|
315
386
|
sendAll(msg) {
|
|
316
387
|
for (const worker of this.workers) {
|
|
317
|
-
|
|
388
|
+
if (!this.exitedWorkers.has(worker)) {
|
|
389
|
+
worker.postMessage(msg);
|
|
390
|
+
}
|
|
318
391
|
}
|
|
319
392
|
}
|
|
320
393
|
/**
|
|
@@ -323,13 +396,16 @@ export class ThreadPool {
|
|
|
323
396
|
* @param msg The message to send the next available worker thread.
|
|
324
397
|
*/
|
|
325
398
|
sendTo(id, msg) {
|
|
326
|
-
|
|
327
|
-
|
|
399
|
+
const worker = this.workers[id];
|
|
400
|
+
if (worker && !this.exitedWorkers.has(worker)) {
|
|
401
|
+
worker.postMessage(msg);
|
|
328
402
|
}
|
|
329
403
|
}
|
|
330
404
|
}
|
|
331
405
|
/** The maximum amount of time, in milliseconds, `stop()` waits for a worker to exit on its own before force-terminating it. */
|
|
332
406
|
ThreadPool.STOP_GRACE_PERIOD_MS = 5000;
|
|
407
|
+
/** The default maximum amount of time, in milliseconds, `start()` waits for all workers to report readiness before rejecting. Overridable per-call via `WorkerOptions.startupTimeoutMs`. */
|
|
408
|
+
ThreadPool.START_TIMEOUT_MS = 30000;
|
|
333
409
|
__decorate([
|
|
334
410
|
Logger,
|
|
335
411
|
__metadata("design:type", Object)
|