@bluelibs/runner 2.2.4 → 3.1.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/README.md +1409 -935
- package/dist/common.types.d.ts +20 -0
- package/dist/common.types.js +4 -0
- package/dist/common.types.js.map +1 -0
- package/dist/context.d.ts +34 -0
- package/dist/context.js +58 -0
- package/dist/context.js.map +1 -0
- package/dist/define.d.ts +24 -5
- package/dist/define.js +89 -20
- package/dist/define.js.map +1 -1
- package/dist/defs.d.ts +109 -73
- package/dist/defs.js +12 -2
- package/dist/defs.js.map +1 -1
- package/dist/errors.d.ts +5 -5
- package/dist/errors.js +6 -5
- package/dist/errors.js.map +1 -1
- package/dist/event.types.d.ts +18 -0
- package/dist/event.types.js +4 -0
- package/dist/event.types.js.map +1 -0
- package/dist/examples/registrator-example.d.ts +122 -0
- package/dist/examples/registrator-example.js +147 -0
- package/dist/examples/registrator-example.js.map +1 -0
- package/dist/globals/globalEvents.d.ts +41 -0
- package/dist/globals/globalEvents.js +94 -0
- package/dist/globals/globalEvents.js.map +1 -0
- package/dist/globals/globalMiddleware.d.ts +23 -0
- package/dist/globals/globalMiddleware.js +15 -0
- package/dist/globals/globalMiddleware.js.map +1 -0
- package/dist/globals/globalResources.d.ts +27 -0
- package/dist/globals/globalResources.js +47 -0
- package/dist/globals/globalResources.js.map +1 -0
- package/dist/globals/middleware/cache.middleware.d.ts +34 -0
- package/dist/globals/middleware/cache.middleware.js +85 -0
- package/dist/globals/middleware/cache.middleware.js.map +1 -0
- package/dist/globals/middleware/requireContext.middleware.d.ts +6 -0
- package/dist/globals/middleware/requireContext.middleware.js +25 -0
- package/dist/globals/middleware/requireContext.middleware.js.map +1 -0
- package/dist/globals/middleware/retry.middleware.d.ts +20 -0
- package/dist/globals/middleware/retry.middleware.js +34 -0
- package/dist/globals/middleware/retry.middleware.js.map +1 -0
- package/dist/globals/resources/queue.resource.d.ts +7 -0
- package/dist/globals/resources/queue.resource.js +31 -0
- package/dist/globals/resources/queue.resource.js.map +1 -0
- package/dist/index.d.ts +54 -18
- package/dist/index.js +14 -9
- package/dist/index.js.map +1 -1
- package/dist/middleware.types.d.ts +40 -0
- package/dist/middleware.types.js +4 -0
- package/dist/middleware.types.js.map +1 -0
- package/dist/models/DependencyProcessor.d.ts +6 -5
- package/dist/models/DependencyProcessor.js +13 -15
- package/dist/models/DependencyProcessor.js.map +1 -1
- package/dist/models/EventManager.d.ts +9 -4
- package/dist/models/EventManager.js +44 -2
- package/dist/models/EventManager.js.map +1 -1
- package/dist/models/Logger.d.ts +30 -13
- package/dist/models/Logger.js +132 -54
- package/dist/models/Logger.js.map +1 -1
- package/dist/models/OverrideManager.d.ts +13 -0
- package/dist/models/OverrideManager.js +70 -0
- package/dist/models/OverrideManager.js.map +1 -0
- package/dist/models/Queue.d.ts +25 -0
- package/dist/models/Queue.js +54 -0
- package/dist/models/Queue.js.map +1 -0
- package/dist/models/ResourceInitializer.d.ts +5 -2
- package/dist/models/ResourceInitializer.js +22 -14
- package/dist/models/ResourceInitializer.js.map +1 -1
- package/dist/models/Semaphore.d.ts +61 -0
- package/dist/models/Semaphore.js +166 -0
- package/dist/models/Semaphore.js.map +1 -0
- package/dist/models/Store.d.ts +18 -73
- package/dist/models/Store.js +71 -269
- package/dist/models/Store.js.map +1 -1
- package/dist/models/StoreConstants.d.ts +11 -0
- package/dist/models/StoreConstants.js +18 -0
- package/dist/models/StoreConstants.js.map +1 -0
- package/dist/models/StoreRegistry.d.ts +25 -0
- package/dist/models/StoreRegistry.js +171 -0
- package/dist/models/StoreRegistry.js.map +1 -0
- package/dist/models/StoreTypes.d.ts +21 -0
- package/dist/models/StoreTypes.js +3 -0
- package/dist/models/StoreTypes.js.map +1 -0
- package/dist/models/StoreValidator.d.ts +10 -0
- package/dist/models/StoreValidator.js +41 -0
- package/dist/models/StoreValidator.js.map +1 -0
- package/dist/models/TaskRunner.d.ts +1 -1
- package/dist/models/TaskRunner.js +39 -24
- package/dist/models/TaskRunner.js.map +1 -1
- package/dist/models/VarStore.d.ts +17 -0
- package/dist/models/VarStore.js +60 -0
- package/dist/models/VarStore.js.map +1 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.js +3 -0
- package/dist/models/index.js.map +1 -1
- package/dist/resource.types.d.ts +31 -0
- package/dist/resource.types.js +3 -0
- package/dist/resource.types.js.map +1 -0
- package/dist/run.d.ts +4 -1
- package/dist/run.js +6 -3
- package/dist/run.js.map +1 -1
- package/dist/symbols.d.ts +24 -0
- package/dist/symbols.js +29 -0
- package/dist/symbols.js.map +1 -0
- package/dist/task.types.d.ts +55 -0
- package/dist/task.types.js +23 -0
- package/dist/task.types.js.map +1 -0
- package/dist/tools/getCallerFile.d.ts +9 -1
- package/dist/tools/getCallerFile.js +41 -0
- package/dist/tools/getCallerFile.js.map +1 -1
- package/dist/tools/registratorId.d.ts +4 -0
- package/dist/tools/registratorId.js +40 -0
- package/dist/tools/registratorId.js.map +1 -0
- package/dist/tools/simpleHash.d.ts +9 -0
- package/dist/tools/simpleHash.js +34 -0
- package/dist/tools/simpleHash.js.map +1 -0
- package/dist/types/base-interfaces.d.ts +18 -0
- package/dist/types/base-interfaces.js +6 -0
- package/dist/types/base-interfaces.js.map +1 -0
- package/dist/types/base.d.ts +13 -0
- package/dist/types/base.js +3 -0
- package/dist/types/base.js.map +1 -0
- package/dist/types/dependencies.d.ts +22 -0
- package/dist/types/dependencies.js +3 -0
- package/dist/types/dependencies.js.map +1 -0
- package/dist/types/dependency-core.d.ts +14 -0
- package/dist/types/dependency-core.js +5 -0
- package/dist/types/dependency-core.js.map +1 -0
- package/dist/types/events.d.ts +52 -0
- package/dist/types/events.js +6 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/hooks.d.ts +16 -0
- package/dist/types/hooks.js +5 -0
- package/dist/types/hooks.js.map +1 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.js +27 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/meta.d.ts +13 -0
- package/dist/types/meta.js +5 -0
- package/dist/types/meta.js.map +1 -0
- package/dist/types/middleware.d.ts +38 -0
- package/dist/types/middleware.js +6 -0
- package/dist/types/middleware.js.map +1 -0
- package/dist/types/registerable.d.ts +10 -0
- package/dist/types/registerable.js +5 -0
- package/dist/types/registerable.js.map +1 -0
- package/dist/types/resources.d.ts +44 -0
- package/dist/types/resources.js +5 -0
- package/dist/types/resources.js.map +1 -0
- package/dist/types/symbols.d.ts +24 -0
- package/dist/types/symbols.js +30 -0
- package/dist/types/symbols.js.map +1 -0
- package/dist/types/tasks.d.ts +41 -0
- package/dist/types/tasks.js +5 -0
- package/dist/types/tasks.js.map +1 -0
- package/dist/types/utilities.d.ts +7 -0
- package/dist/types/utilities.js +5 -0
- package/dist/types/utilities.js.map +1 -0
- package/package.json +10 -6
- package/src/__tests__/benchmark/benchmark.test.ts +1 -1
- package/src/__tests__/context.test.ts +91 -0
- package/src/__tests__/errors.test.ts +8 -5
- package/src/__tests__/globalEvents.test.ts +1 -1
- package/src/__tests__/globals/cache.middleware.test.ts +772 -0
- package/src/__tests__/globals/queue.resource.test.ts +141 -0
- package/src/__tests__/globals/requireContext.middleware.test.ts +98 -0
- package/src/__tests__/globals/retry.middleware.test.ts +157 -0
- package/src/__tests__/index.helper.test.ts +55 -0
- package/src/__tests__/models/EventManager.test.ts +157 -11
- package/src/__tests__/models/Logger.test.ts +291 -34
- package/src/__tests__/models/Queue.test.ts +189 -0
- package/src/__tests__/models/ResourceInitializer.test.ts +8 -6
- package/src/__tests__/models/Semaphore.test.ts +713 -0
- package/src/__tests__/models/Store.test.ts +40 -0
- package/src/__tests__/models/TaskRunner.test.ts +86 -5
- package/src/__tests__/run.anonymous.test.ts +679 -0
- package/src/__tests__/run.middleware.test.ts +312 -12
- package/src/__tests__/run.overrides.test.ts +13 -10
- package/src/__tests__/run.test.ts +364 -13
- package/src/__tests__/setOutput.test.ts +244 -0
- package/src/__tests__/tools/getCallerFile.test.ts +124 -9
- package/src/__tests__/typesafety.test.ts +71 -41
- package/src/context.ts +86 -0
- package/src/define.ts +129 -34
- package/src/defs.ts +156 -119
- package/src/errors.ts +15 -10
- package/src/{globalEvents.ts → globals/globalEvents.ts} +13 -12
- package/src/globals/globalMiddleware.ts +14 -0
- package/src/{globalResources.ts → globals/globalResources.ts} +14 -10
- package/src/globals/middleware/cache.middleware.ts +115 -0
- package/src/globals/middleware/requireContext.middleware.ts +36 -0
- package/src/globals/middleware/retry.middleware.ts +56 -0
- package/src/globals/resources/queue.resource.ts +34 -0
- package/src/index.ts +9 -5
- package/src/models/DependencyProcessor.ts +42 -49
- package/src/models/EventManager.ts +64 -13
- package/src/models/Logger.ts +181 -64
- package/src/models/OverrideManager.ts +84 -0
- package/src/models/Queue.ts +66 -0
- package/src/models/ResourceInitializer.ts +40 -20
- package/src/models/Semaphore.ts +208 -0
- package/src/models/Store.ts +94 -342
- package/src/models/StoreConstants.ts +17 -0
- package/src/models/StoreRegistry.ts +228 -0
- package/src/models/StoreTypes.ts +46 -0
- package/src/models/StoreValidator.ts +43 -0
- package/src/models/TaskRunner.ts +54 -41
- package/src/models/index.ts +3 -0
- package/src/run.ts +7 -4
- package/src/tools/getCallerFile.ts +54 -2
- package/src/__tests__/index.ts +0 -15
- package/src/examples/express-mongo/index.ts +0 -1
package/src/models/Logger.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { globalEvents } from "../globalEvents";
|
|
1
|
+
import { globalEvents } from "../globals/globalEvents";
|
|
2
2
|
import { EventManager } from "./EventManager";
|
|
3
3
|
|
|
4
4
|
export type LogLevels =
|
|
@@ -9,17 +9,32 @@ export type LogLevels =
|
|
|
9
9
|
| "error"
|
|
10
10
|
| "critical";
|
|
11
11
|
|
|
12
|
+
export interface LogInfo {
|
|
13
|
+
source?: string | symbol;
|
|
14
|
+
error?: Error;
|
|
15
|
+
data?: Record<string, any>;
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}
|
|
18
|
+
|
|
12
19
|
export interface ILog {
|
|
13
20
|
level: string;
|
|
14
21
|
source?: string;
|
|
15
|
-
|
|
22
|
+
message: any;
|
|
16
23
|
timestamp: Date;
|
|
24
|
+
error?: {
|
|
25
|
+
name: string;
|
|
26
|
+
message: string;
|
|
27
|
+
stack?: string;
|
|
28
|
+
};
|
|
29
|
+
data?: Record<string, any>;
|
|
30
|
+
context?: Record<string, any>;
|
|
17
31
|
}
|
|
18
32
|
|
|
19
33
|
export class Logger {
|
|
20
34
|
printThreshold: LogLevels | null = null;
|
|
35
|
+
private boundContext: Record<string, any> = {};
|
|
21
36
|
|
|
22
|
-
public
|
|
37
|
+
public static Severity = {
|
|
23
38
|
trace: 0,
|
|
24
39
|
debug: 1,
|
|
25
40
|
info: 2,
|
|
@@ -28,32 +43,71 @@ export class Logger {
|
|
|
28
43
|
critical: 5,
|
|
29
44
|
};
|
|
30
45
|
|
|
31
|
-
constructor(
|
|
46
|
+
constructor(
|
|
47
|
+
protected eventManager: EventManager,
|
|
48
|
+
boundContext: Record<string, any> = {}
|
|
49
|
+
) {
|
|
50
|
+
this.boundContext = { ...boundContext };
|
|
51
|
+
}
|
|
32
52
|
|
|
33
53
|
/**
|
|
34
|
-
*
|
|
35
|
-
|
|
54
|
+
* Creates a new logger instance with additional bound context
|
|
55
|
+
*/
|
|
56
|
+
public with(context: Record<string, any>): Logger {
|
|
57
|
+
return new Logger(this.eventManager, {
|
|
58
|
+
...this.boundContext,
|
|
59
|
+
...context,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private extractErrorInfo(error: Error): {
|
|
64
|
+
name: string;
|
|
65
|
+
message: string;
|
|
66
|
+
stack?: string;
|
|
67
|
+
} {
|
|
68
|
+
return {
|
|
69
|
+
name: error.name,
|
|
70
|
+
message: error.message,
|
|
71
|
+
stack: error.stack,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Core logging method with structured LogInfo
|
|
36
77
|
*/
|
|
37
|
-
public
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
source?: string
|
|
41
|
-
): Promise<void> {
|
|
78
|
+
public log(level: LogLevels, message: any, logInfo: LogInfo = {}): void {
|
|
79
|
+
const { source, error, data, ...context } = logInfo;
|
|
80
|
+
|
|
42
81
|
const log: ILog = {
|
|
43
82
|
level,
|
|
44
|
-
|
|
45
|
-
source: source,
|
|
83
|
+
message,
|
|
84
|
+
source: source || this.boundContext.source,
|
|
46
85
|
timestamp: new Date(),
|
|
86
|
+
error: error ? this.extractErrorInfo(error) : undefined,
|
|
87
|
+
data: data || undefined,
|
|
88
|
+
context: { ...this.boundContext, ...context },
|
|
47
89
|
};
|
|
48
90
|
|
|
49
91
|
if (
|
|
50
92
|
this.printThreshold &&
|
|
51
|
-
|
|
93
|
+
Logger.Severity[level] >= Logger.Severity[this.printThreshold]
|
|
52
94
|
) {
|
|
53
95
|
this.print(log);
|
|
54
96
|
}
|
|
55
97
|
|
|
56
|
-
|
|
98
|
+
if (this.eventManager.hasListeners(globalEvents.log)) {
|
|
99
|
+
setImmediate(() => {
|
|
100
|
+
this.eventManager
|
|
101
|
+
.emit(
|
|
102
|
+
globalEvents.log,
|
|
103
|
+
log,
|
|
104
|
+
source || this.boundContext.source || "unknown"
|
|
105
|
+
)
|
|
106
|
+
.catch((err) => {
|
|
107
|
+
console.error("Logger event emission failed:", err);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
57
111
|
}
|
|
58
112
|
|
|
59
113
|
/**
|
|
@@ -65,73 +119,136 @@ export class Logger {
|
|
|
65
119
|
}
|
|
66
120
|
|
|
67
121
|
public print(log: ILog) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
122
|
+
const { level, source, message, timestamp, error, data, context } = log;
|
|
123
|
+
|
|
124
|
+
// Color codes for different log levels
|
|
125
|
+
const colors = {
|
|
126
|
+
trace: "\x1b[90m", // bright black/gray
|
|
127
|
+
debug: "\x1b[36m", // cyan
|
|
128
|
+
info: "\x1b[32m", // green
|
|
129
|
+
warn: "\x1b[33m", // yellow
|
|
130
|
+
error: "\x1b[31m", // red
|
|
131
|
+
critical: "\x1b[35m", // magenta
|
|
132
|
+
reset: "\x1b[0m", // reset
|
|
133
|
+
bold: "\x1b[1m", // bold
|
|
134
|
+
dim: "\x1b[2m", // dim
|
|
135
|
+
blue: "\x1b[34m", // blue
|
|
136
|
+
red: "\x1b[31m", // red
|
|
137
|
+
cyan: "\x1b[36m", // cyan
|
|
138
|
+
};
|
|
73
139
|
|
|
74
|
-
|
|
75
|
-
|
|
140
|
+
const levelColor = colors[level as keyof typeof colors] || colors.info;
|
|
141
|
+
|
|
142
|
+
// Format timestamp
|
|
143
|
+
const time = timestamp.toLocaleTimeString("en-US", {
|
|
144
|
+
hour12: false,
|
|
145
|
+
hour: "2-digit",
|
|
146
|
+
minute: "2-digit",
|
|
147
|
+
second: "2-digit",
|
|
148
|
+
});
|
|
149
|
+
const ms = timestamp.getMilliseconds().toString().padStart(3, "0");
|
|
150
|
+
const formattedTime = `${colors.dim}${time}.${ms}${colors.reset}`;
|
|
151
|
+
|
|
152
|
+
// Format level with color and padding
|
|
153
|
+
const levelStr = `${levelColor}${colors.bold}${level
|
|
154
|
+
.toUpperCase()
|
|
155
|
+
.padEnd(8)}${colors.reset}`;
|
|
156
|
+
|
|
157
|
+
// Format source
|
|
158
|
+
const sourceStr = source ? `${colors.blue}[${source}]${colors.reset} ` : "";
|
|
159
|
+
|
|
160
|
+
// Format the main message
|
|
161
|
+
let messageStr: string;
|
|
162
|
+
if (typeof message === "object") {
|
|
163
|
+
messageStr = JSON.stringify(message, null, 2);
|
|
164
|
+
} else {
|
|
165
|
+
messageStr = String(message);
|
|
166
|
+
}
|
|
76
167
|
|
|
77
|
-
//
|
|
78
|
-
const
|
|
168
|
+
// Build the main log line
|
|
169
|
+
const mainLine = `${formattedTime} ${levelStr} ${sourceStr}${messageStr}`;
|
|
170
|
+
|
|
171
|
+
// Start building output lines
|
|
172
|
+
const lines = [mainLine];
|
|
173
|
+
|
|
174
|
+
// Add error information if present
|
|
175
|
+
if (error) {
|
|
176
|
+
lines.push(
|
|
177
|
+
`${colors.dim}├─ ${colors.red}Error: ${error.name}${colors.reset}`
|
|
178
|
+
);
|
|
179
|
+
lines.push(
|
|
180
|
+
`${colors.dim}├─ ${colors.red}${error.message}${colors.reset}`
|
|
181
|
+
);
|
|
182
|
+
if (error.stack) {
|
|
183
|
+
const stackLines = error.stack.split("\n").slice(1, 4); // Show first 3 stack frames
|
|
184
|
+
stackLines.forEach((line, index) => {
|
|
185
|
+
const prefix = index === stackLines.length - 1 ? "└─" : "├─";
|
|
186
|
+
lines.push(
|
|
187
|
+
`${colors.dim}${prefix} ${colors.red}${line.trim()}${colors.reset}`
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
79
192
|
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
dataStr =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
193
|
+
// Add structured data if present
|
|
194
|
+
if (data && Object.keys(data).length > 0) {
|
|
195
|
+
lines.push(`${colors.dim}├─ ${colors.cyan}Data:${colors.reset}`);
|
|
196
|
+
const dataStr = JSON.stringify(data, null, 2);
|
|
197
|
+
const dataLines = dataStr.split("\n");
|
|
198
|
+
dataLines.forEach((line, index) => {
|
|
199
|
+
const prefix = index === dataLines.length - 1 ? "└─" : "├─";
|
|
200
|
+
lines.push(
|
|
201
|
+
`${colors.dim}${prefix} ${colors.cyan}${line}${colors.reset}`
|
|
202
|
+
);
|
|
203
|
+
});
|
|
88
204
|
}
|
|
89
205
|
|
|
90
|
-
//
|
|
91
|
-
const
|
|
206
|
+
// Add context if present (excluding common context we already show)
|
|
207
|
+
const filteredContext = context ? { ...context } : {};
|
|
208
|
+
delete filteredContext.source; // Already shown in source
|
|
209
|
+
|
|
210
|
+
if (filteredContext && Object.keys(filteredContext).length > 0) {
|
|
211
|
+
lines.push(`${colors.dim}└─ ${colors.blue}Context:${colors.reset}`);
|
|
212
|
+
const contextStr = JSON.stringify(filteredContext, null, 2);
|
|
213
|
+
const contextLines = contextStr.split("\n");
|
|
214
|
+
contextLines.forEach((line, index) => {
|
|
215
|
+
const prefix = index === contextLines.length - 1 ? " " : " ";
|
|
216
|
+
lines.push(
|
|
217
|
+
`${colors.dim}${prefix} ${colors.blue}${line}${colors.reset}`
|
|
218
|
+
);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
92
221
|
|
|
93
|
-
//
|
|
94
|
-
console.log(
|
|
95
|
-
}
|
|
222
|
+
// Output all lines
|
|
223
|
+
lines.forEach((line) => console.log(line));
|
|
96
224
|
|
|
97
|
-
|
|
98
|
-
|
|
225
|
+
// Add a subtle separator for multi-line logs
|
|
226
|
+
if (lines.length > 1) {
|
|
227
|
+
console.log(`${colors.dim}${colors.reset}`);
|
|
228
|
+
}
|
|
99
229
|
}
|
|
100
230
|
|
|
101
|
-
public
|
|
102
|
-
|
|
231
|
+
public info(message: any, logInfo: LogInfo = {}) {
|
|
232
|
+
this.log("info", message, logInfo);
|
|
103
233
|
}
|
|
104
234
|
|
|
105
|
-
public
|
|
106
|
-
|
|
235
|
+
public error(message: any, logInfo: LogInfo = {}) {
|
|
236
|
+
this.log("error", message, logInfo);
|
|
107
237
|
}
|
|
108
238
|
|
|
109
|
-
public
|
|
110
|
-
|
|
239
|
+
public warn(message: any, logInfo: LogInfo = {}) {
|
|
240
|
+
this.log("warn", message, logInfo);
|
|
111
241
|
}
|
|
112
242
|
|
|
113
|
-
public
|
|
114
|
-
|
|
243
|
+
public debug(message: any, logInfo: LogInfo = {}) {
|
|
244
|
+
this.log("debug", message, logInfo);
|
|
115
245
|
}
|
|
116
246
|
|
|
117
|
-
public
|
|
118
|
-
|
|
247
|
+
public trace(message: any, logInfo: LogInfo = {}) {
|
|
248
|
+
this.log("trace", message, logInfo);
|
|
119
249
|
}
|
|
120
250
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return JSON.stringify(
|
|
124
|
-
obj,
|
|
125
|
-
(key, value) => {
|
|
126
|
-
if (typeof value === "object" && value !== null) {
|
|
127
|
-
if (seen.has(value)) {
|
|
128
|
-
return "[Circular]";
|
|
129
|
-
}
|
|
130
|
-
seen.add(value);
|
|
131
|
-
}
|
|
132
|
-
return value;
|
|
133
|
-
},
|
|
134
|
-
indent
|
|
135
|
-
);
|
|
251
|
+
public critical(message: any, logInfo: LogInfo = {}) {
|
|
252
|
+
this.log("critical", message, logInfo);
|
|
136
253
|
}
|
|
137
254
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IResource,
|
|
3
|
+
IMiddleware,
|
|
4
|
+
ITask,
|
|
5
|
+
IResourceWithConfig,
|
|
6
|
+
RegisterableItems,
|
|
7
|
+
} from "../defs";
|
|
8
|
+
import * as utils from "../define";
|
|
9
|
+
import { Errors } from "../errors";
|
|
10
|
+
import {
|
|
11
|
+
TaskStoreElementType,
|
|
12
|
+
MiddlewareStoreElementType,
|
|
13
|
+
ResourceStoreElementType,
|
|
14
|
+
} from "./StoreTypes";
|
|
15
|
+
import { StoreRegistry } from "./StoreRegistry";
|
|
16
|
+
|
|
17
|
+
export class OverrideManager {
|
|
18
|
+
public overrides: Map<
|
|
19
|
+
string | symbol,
|
|
20
|
+
IResource | IMiddleware | ITask | IResourceWithConfig
|
|
21
|
+
> = new Map();
|
|
22
|
+
|
|
23
|
+
public overrideRequests: Set<{
|
|
24
|
+
source: string | symbol;
|
|
25
|
+
override: RegisterableItems;
|
|
26
|
+
}> = new Set();
|
|
27
|
+
|
|
28
|
+
constructor(private readonly registry: StoreRegistry) {}
|
|
29
|
+
|
|
30
|
+
storeOverridesDeeply<C>(element: IResource<C, any, any>) {
|
|
31
|
+
element.overrides.forEach((override) => {
|
|
32
|
+
if (utils.isResource(override)) {
|
|
33
|
+
this.storeOverridesDeeply(override);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let id: string | symbol;
|
|
37
|
+
if (utils.isResourceWithConfig(override)) {
|
|
38
|
+
this.storeOverridesDeeply(override.resource);
|
|
39
|
+
id = override.resource.id;
|
|
40
|
+
} else {
|
|
41
|
+
id = override.id;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.overrideRequests.add({ source: element.id, override });
|
|
45
|
+
this.overrides.set(id, override);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
processOverrides() {
|
|
50
|
+
// If we are trying to use override on something that wasn't previously registered, we throw an error.
|
|
51
|
+
for (const override of this.overrides.values()) {
|
|
52
|
+
let hasAnyItem = false;
|
|
53
|
+
if (utils.isTask(override)) {
|
|
54
|
+
hasAnyItem = this.registry.tasks.has(override.id);
|
|
55
|
+
} else if (utils.isResource(override)) {
|
|
56
|
+
hasAnyItem = this.registry.resources.has(override.id);
|
|
57
|
+
} else if (utils.isMiddleware(override)) {
|
|
58
|
+
hasAnyItem = this.registry.middlewares.has(override.id);
|
|
59
|
+
} else if (utils.isResourceWithConfig(override)) {
|
|
60
|
+
hasAnyItem = this.registry.resources.has(override.resource.id);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!hasAnyItem) {
|
|
64
|
+
const id = utils.isResourceWithConfig(override)
|
|
65
|
+
? override.resource.id
|
|
66
|
+
: override.id;
|
|
67
|
+
|
|
68
|
+
throw Errors.dependencyNotFound(id);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const override of this.overrides.values()) {
|
|
73
|
+
if (utils.isTask(override)) {
|
|
74
|
+
this.registry.storeTask(override, false);
|
|
75
|
+
} else if (utils.isResource(override)) {
|
|
76
|
+
this.registry.storeResource(override, false);
|
|
77
|
+
} else if (utils.isMiddleware(override)) {
|
|
78
|
+
this.registry.storeMiddleware(override, false);
|
|
79
|
+
} else if (utils.isResourceWithConfig(override)) {
|
|
80
|
+
this.registry.storeResourceWithConfig(override, false);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cooperative task queue.
|
|
5
|
+
* • Tasks run one‑after‑another (FIFO ordering).
|
|
6
|
+
* • Dead‑lock detection prevents nesting.
|
|
7
|
+
* • dispose() drains or cancels outstanding tasks, then rejects new ones.
|
|
8
|
+
*/
|
|
9
|
+
export class Queue {
|
|
10
|
+
private tail: Promise<unknown> = Promise.resolve();
|
|
11
|
+
private disposed = false;
|
|
12
|
+
private abortController = new AbortController();
|
|
13
|
+
|
|
14
|
+
// true while inside a queued task → helps detect "queue in queue"
|
|
15
|
+
private readonly executionContext = new AsyncLocalStorage<boolean>();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Schedule an asynchronous task.
|
|
19
|
+
* @param task – receives an AbortSignal so it can cancel early if desired.
|
|
20
|
+
*/
|
|
21
|
+
public run<T>(task: (signal: AbortSignal) => Promise<T>): Promise<T> {
|
|
22
|
+
// 1. refuse new work if we've disposed
|
|
23
|
+
if (this.disposed) {
|
|
24
|
+
return Promise.reject(new Error("Queue has been disposed"));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 2. detect dead‑locks (a queued task adding another queued task)
|
|
28
|
+
if (this.executionContext.getStore()) {
|
|
29
|
+
return Promise.reject(
|
|
30
|
+
new Error(
|
|
31
|
+
"Dead‑lock detected: a queued task attempted to queue another task"
|
|
32
|
+
)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const { signal } = this.abortController;
|
|
37
|
+
|
|
38
|
+
// 3. chain task after the current tail
|
|
39
|
+
const result = this.tail.then(() =>
|
|
40
|
+
this.executionContext.run(true, () => task(signal))
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// 4. preserve the chain even if the task rejects (swallow internally)
|
|
44
|
+
this.tail = result.catch(() => {});
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Disposes the queue.
|
|
51
|
+
* @param options.cancel – if true, broadcasts AbortSignal to running task.
|
|
52
|
+
* default: false (waits for tasks to finish).
|
|
53
|
+
*/
|
|
54
|
+
public async dispose(options: { cancel?: boolean } = {}): Promise<void> {
|
|
55
|
+
if (this.disposed) return;
|
|
56
|
+
|
|
57
|
+
this.disposed = true;
|
|
58
|
+
|
|
59
|
+
if (options.cancel) {
|
|
60
|
+
this.abortController.abort(); // notify cooperative tasks
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// wait for everything already chained to settle
|
|
64
|
+
await this.tail.catch(() => {});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -5,8 +5,9 @@ import {
|
|
|
5
5
|
IResource,
|
|
6
6
|
} from "../defs";
|
|
7
7
|
import { EventManager } from "./EventManager";
|
|
8
|
-
import { globalEvents } from "../globalEvents";
|
|
9
|
-
import {
|
|
8
|
+
import { globalEvents } from "../globals/globalEvents";
|
|
9
|
+
import { Store } from "./Store";
|
|
10
|
+
import { MiddlewareStoreElementType } from "./StoreTypes";
|
|
10
11
|
import { Logger } from "./Logger";
|
|
11
12
|
|
|
12
13
|
export class ResourceInitializer {
|
|
@@ -23,12 +24,14 @@ export class ResourceInitializer {
|
|
|
23
24
|
public async initializeResource<
|
|
24
25
|
TConfig = null,
|
|
25
26
|
TValue = any,
|
|
26
|
-
TDeps extends DependencyMapType = {}
|
|
27
|
+
TDeps extends DependencyMapType = {},
|
|
28
|
+
TContext = any
|
|
27
29
|
>(
|
|
28
30
|
resource: IResource<TConfig, TValue, TDeps>,
|
|
29
31
|
config: TConfig,
|
|
30
32
|
dependencies: DependencyValuesType<TDeps>
|
|
31
|
-
): Promise<TValue
|
|
33
|
+
): Promise<{ value: TValue; context: TContext }> {
|
|
34
|
+
const context = resource.context?.();
|
|
32
35
|
await this.eventManager.emit(
|
|
33
36
|
globalEvents.resources.beforeInit,
|
|
34
37
|
{
|
|
@@ -44,15 +47,22 @@ export class ResourceInitializer {
|
|
|
44
47
|
resource.id
|
|
45
48
|
);
|
|
46
49
|
|
|
47
|
-
let error, value;
|
|
50
|
+
let error: any, value: TValue | undefined;
|
|
48
51
|
try {
|
|
49
|
-
|
|
52
|
+
if (resource.init) {
|
|
53
|
+
value = await this.initWithMiddleware(
|
|
54
|
+
resource,
|
|
55
|
+
config,
|
|
56
|
+
dependencies,
|
|
57
|
+
context
|
|
58
|
+
);
|
|
59
|
+
}
|
|
50
60
|
|
|
51
61
|
await this.eventManager.emit(
|
|
52
62
|
resource.events.afterInit,
|
|
53
63
|
{
|
|
54
64
|
config,
|
|
55
|
-
value,
|
|
65
|
+
value: value as TValue,
|
|
56
66
|
},
|
|
57
67
|
resource.id
|
|
58
68
|
);
|
|
@@ -61,14 +71,16 @@ export class ResourceInitializer {
|
|
|
61
71
|
{
|
|
62
72
|
config,
|
|
63
73
|
resource,
|
|
64
|
-
value,
|
|
74
|
+
value: value as TValue,
|
|
65
75
|
},
|
|
66
76
|
resource.id
|
|
67
77
|
);
|
|
68
78
|
|
|
69
|
-
this.logger.debug(`Resource ${resource.id} initialized`,
|
|
79
|
+
this.logger.debug(`Resource ${resource.id.toString()} initialized`, {
|
|
80
|
+
source: resource.id,
|
|
81
|
+
});
|
|
70
82
|
|
|
71
|
-
return value;
|
|
83
|
+
return { value: value as TValue, context };
|
|
72
84
|
} catch (e) {
|
|
73
85
|
error = e;
|
|
74
86
|
let isSuppressed = false;
|
|
@@ -80,7 +92,7 @@ export class ResourceInitializer {
|
|
|
80
92
|
await this.eventManager.emit(
|
|
81
93
|
resource.events.onError,
|
|
82
94
|
{
|
|
83
|
-
error,
|
|
95
|
+
error: error as Error,
|
|
84
96
|
suppress,
|
|
85
97
|
},
|
|
86
98
|
resource.id
|
|
@@ -88,7 +100,7 @@ export class ResourceInitializer {
|
|
|
88
100
|
await this.eventManager.emit(
|
|
89
101
|
globalEvents.resources.onError,
|
|
90
102
|
{
|
|
91
|
-
error,
|
|
103
|
+
error: error as Error,
|
|
92
104
|
resource,
|
|
93
105
|
suppress,
|
|
94
106
|
},
|
|
@@ -96,23 +108,28 @@ export class ResourceInitializer {
|
|
|
96
108
|
);
|
|
97
109
|
|
|
98
110
|
if (!isSuppressed) throw e;
|
|
111
|
+
|
|
112
|
+
return { value: undefined as TValue, context: {} as TContext };
|
|
99
113
|
}
|
|
100
114
|
}
|
|
101
115
|
|
|
102
|
-
public async initWithMiddleware<C, V, D extends DependencyMapType>(
|
|
103
|
-
resource: IResource<C, V>,
|
|
116
|
+
public async initWithMiddleware<C, V, D extends DependencyMapType, TContext>(
|
|
117
|
+
resource: IResource<C, V, D, TContext>,
|
|
104
118
|
config: C,
|
|
105
|
-
dependencies: D
|
|
119
|
+
dependencies: DependencyValuesType<D>,
|
|
120
|
+
context: TContext
|
|
106
121
|
) {
|
|
107
122
|
let next = async (config: C): Promise<V | undefined> => {
|
|
108
123
|
if (resource.init) {
|
|
109
|
-
return resource.init.call(null, config, dependencies);
|
|
124
|
+
return resource.init.call(null, config, dependencies, context);
|
|
110
125
|
}
|
|
111
126
|
};
|
|
112
127
|
|
|
113
128
|
const existingMiddlewares = resource.middleware;
|
|
114
129
|
const createdMiddlewares = [
|
|
115
|
-
...this.store.
|
|
130
|
+
...this.store.getEverywhereMiddlewareForResources(
|
|
131
|
+
existingMiddlewares.map((x) => x.id)
|
|
132
|
+
),
|
|
116
133
|
...existingMiddlewares,
|
|
117
134
|
];
|
|
118
135
|
|
|
@@ -126,11 +143,14 @@ export class ResourceInitializer {
|
|
|
126
143
|
next = async (config: C) => {
|
|
127
144
|
return storeMiddleware.middleware.run(
|
|
128
145
|
{
|
|
129
|
-
|
|
130
|
-
|
|
146
|
+
resource: {
|
|
147
|
+
definition: resource,
|
|
148
|
+
config,
|
|
149
|
+
},
|
|
131
150
|
next: nextFunction,
|
|
132
151
|
},
|
|
133
|
-
storeMiddleware.computedDependencies
|
|
152
|
+
storeMiddleware.computedDependencies,
|
|
153
|
+
middleware.config
|
|
134
154
|
);
|
|
135
155
|
};
|
|
136
156
|
}
|