@bluelibs/runner 2.2.3 → 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/README.md +1315 -942
- 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 +22 -3
- package/dist/define.js +52 -8
- package/dist/define.js.map +1 -1
- package/dist/defs.d.ts +52 -31
- package/dist/defs.js +10 -2
- package/dist/defs.js.map +1 -1
- package/dist/errors.js +1 -1
- 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 +45 -9
- 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 +2 -1
- package/dist/models/DependencyProcessor.js +11 -13
- package/dist/models/DependencyProcessor.js.map +1 -1
- package/dist/models/EventManager.d.ts +5 -0
- package/dist/models/EventManager.js +44 -2
- package/dist/models/EventManager.js.map +1 -1
- package/dist/models/Logger.d.ts +30 -12
- package/dist/models/Logger.js +130 -42
- 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 +20 -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 +17 -72
- 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.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/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 +144 -0
- 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.middleware.test.ts +166 -12
- package/src/__tests__/run.overrides.test.ts +13 -10
- package/src/__tests__/run.test.ts +363 -12
- package/src/__tests__/setOutput.test.ts +244 -0
- package/src/__tests__/tools/getCallerFile.test.ts +9 -9
- package/src/__tests__/typesafety.test.ts +54 -39
- package/src/context.ts +86 -0
- package/src/define.ts +84 -14
- package/src/defs.ts +91 -41
- package/src/errors.ts +3 -1
- 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 +36 -40
- package/src/models/EventManager.ts +45 -5
- package/src/models/Logger.ts +170 -48
- package/src/models/OverrideManager.ts +84 -0
- package/src/models/Queue.ts +66 -0
- package/src/models/ResourceInitializer.ts +38 -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 +217 -0
- package/src/models/StoreTypes.ts +46 -0
- package/src/models/StoreValidator.ts +38 -0
- package/src/models/TaskRunner.ts +53 -40
- package/src/models/index.ts +3 -0
- package/src/run.ts +7 -4
- 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;
|
|
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
|
-
* @param message
|
|
54
|
+
* Creates a new logger instance with additional bound context
|
|
36
55
|
*/
|
|
37
|
-
public
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
|
77
|
+
*/
|
|
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,56 +119,124 @@ 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.toUpperCase().padEnd(8)}${colors.reset}`;
|
|
154
|
+
|
|
155
|
+
// Format source
|
|
156
|
+
const sourceStr = source ? `${colors.blue}[${source}]${colors.reset} ` : '';
|
|
157
|
+
|
|
158
|
+
// Format the main message
|
|
159
|
+
let messageStr: string;
|
|
160
|
+
if (typeof message === 'object') {
|
|
161
|
+
messageStr = JSON.stringify(message, null, 2);
|
|
162
|
+
} else {
|
|
163
|
+
messageStr = String(message);
|
|
164
|
+
}
|
|
76
165
|
|
|
77
|
-
//
|
|
78
|
-
const
|
|
166
|
+
// Build the main log line
|
|
167
|
+
const mainLine = `${formattedTime} ${levelStr} ${sourceStr}${messageStr}`;
|
|
168
|
+
|
|
169
|
+
// Start building output lines
|
|
170
|
+
const lines = [mainLine];
|
|
171
|
+
|
|
172
|
+
// Add error information if present
|
|
173
|
+
if (error) {
|
|
174
|
+
lines.push(`${colors.dim}├─ ${colors.red}Error: ${error.name}${colors.reset}`);
|
|
175
|
+
lines.push(`${colors.dim}├─ ${colors.red}${error.message}${colors.reset}`);
|
|
176
|
+
if (error.stack) {
|
|
177
|
+
const stackLines = error.stack.split('\n').slice(1, 4); // Show first 3 stack frames
|
|
178
|
+
stackLines.forEach((line, index) => {
|
|
179
|
+
const prefix = index === stackLines.length - 1 ? '└─' : '├─';
|
|
180
|
+
lines.push(`${colors.dim}${prefix} ${colors.red}${line.trim()}${colors.reset}`);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
79
184
|
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
dataStr =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
185
|
+
// Add structured data if present
|
|
186
|
+
if (data && Object.keys(data).length > 0) {
|
|
187
|
+
lines.push(`${colors.dim}├─ ${colors.cyan}Data:${colors.reset}`);
|
|
188
|
+
const dataStr = JSON.stringify(data, null, 2);
|
|
189
|
+
const dataLines = dataStr.split('\n');
|
|
190
|
+
dataLines.forEach((line, index) => {
|
|
191
|
+
const prefix = index === dataLines.length - 1 ? '└─' : '├─';
|
|
192
|
+
lines.push(`${colors.dim}${prefix} ${colors.cyan}${line}${colors.reset}`);
|
|
193
|
+
});
|
|
88
194
|
}
|
|
89
195
|
|
|
90
|
-
//
|
|
91
|
-
const
|
|
196
|
+
// Add context if present (excluding common context we already show)
|
|
197
|
+
const filteredContext = context ? { ...context } : {};
|
|
198
|
+
delete filteredContext.source; // Already shown in source
|
|
199
|
+
|
|
200
|
+
if (filteredContext && Object.keys(filteredContext).length > 0) {
|
|
201
|
+
lines.push(`${colors.dim}└─ ${colors.blue}Context:${colors.reset}`);
|
|
202
|
+
const contextStr = JSON.stringify(filteredContext, null, 2);
|
|
203
|
+
const contextLines = contextStr.split('\n');
|
|
204
|
+
contextLines.forEach((line, index) => {
|
|
205
|
+
const prefix = index === contextLines.length - 1 ? ' ' : ' ';
|
|
206
|
+
lines.push(`${colors.dim}${prefix} ${colors.blue}${line}${colors.reset}`);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
92
209
|
|
|
93
|
-
//
|
|
94
|
-
console.log(
|
|
210
|
+
// Output all lines
|
|
211
|
+
lines.forEach(line => console.log(line));
|
|
212
|
+
|
|
213
|
+
// Add a subtle separator for multi-line logs
|
|
214
|
+
if (lines.length > 1) {
|
|
215
|
+
console.log(`${colors.dim}${colors.reset}`);
|
|
216
|
+
}
|
|
95
217
|
}
|
|
96
218
|
|
|
97
|
-
public
|
|
98
|
-
|
|
219
|
+
public info(message: any, logInfo: LogInfo = {}) {
|
|
220
|
+
this.log("info", message, logInfo);
|
|
99
221
|
}
|
|
100
222
|
|
|
101
|
-
public
|
|
102
|
-
|
|
223
|
+
public error(message: any, logInfo: LogInfo = {}) {
|
|
224
|
+
this.log("error", message, logInfo);
|
|
103
225
|
}
|
|
104
226
|
|
|
105
|
-
public
|
|
106
|
-
|
|
227
|
+
public warn(message: any, logInfo: LogInfo = {}) {
|
|
228
|
+
this.log("warn", message, logInfo);
|
|
107
229
|
}
|
|
108
230
|
|
|
109
|
-
public
|
|
110
|
-
|
|
231
|
+
public debug(message: any, logInfo: LogInfo = {}) {
|
|
232
|
+
this.log("debug", message, logInfo);
|
|
111
233
|
}
|
|
112
234
|
|
|
113
|
-
public
|
|
114
|
-
|
|
235
|
+
public trace(message: any, logInfo: LogInfo = {}) {
|
|
236
|
+
this.log("trace", message, logInfo);
|
|
115
237
|
}
|
|
116
238
|
|
|
117
|
-
public
|
|
118
|
-
|
|
239
|
+
public critical(message: any, logInfo: LogInfo = {}) {
|
|
240
|
+
this.log("critical", message, logInfo);
|
|
119
241
|
}
|
|
120
242
|
}
|
|
@@ -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,
|
|
20
|
+
IResource | IMiddleware | ITask | IResourceWithConfig
|
|
21
|
+
> = new Map();
|
|
22
|
+
|
|
23
|
+
public overrideRequests: Set<{
|
|
24
|
+
source: string;
|
|
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;
|
|
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,14 @@ 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`, resource.id);
|
|
79
|
+
this.logger.debug(`Resource ${resource.id} initialized`, { source: resource.id });
|
|
70
80
|
|
|
71
|
-
return value;
|
|
81
|
+
return { value: value as TValue, context };
|
|
72
82
|
} catch (e) {
|
|
73
83
|
error = e;
|
|
74
84
|
let isSuppressed = false;
|
|
@@ -80,7 +90,7 @@ export class ResourceInitializer {
|
|
|
80
90
|
await this.eventManager.emit(
|
|
81
91
|
resource.events.onError,
|
|
82
92
|
{
|
|
83
|
-
error,
|
|
93
|
+
error: error as Error,
|
|
84
94
|
suppress,
|
|
85
95
|
},
|
|
86
96
|
resource.id
|
|
@@ -88,7 +98,7 @@ export class ResourceInitializer {
|
|
|
88
98
|
await this.eventManager.emit(
|
|
89
99
|
globalEvents.resources.onError,
|
|
90
100
|
{
|
|
91
|
-
error,
|
|
101
|
+
error: error as Error,
|
|
92
102
|
resource,
|
|
93
103
|
suppress,
|
|
94
104
|
},
|
|
@@ -96,23 +106,28 @@ export class ResourceInitializer {
|
|
|
96
106
|
);
|
|
97
107
|
|
|
98
108
|
if (!isSuppressed) throw e;
|
|
109
|
+
|
|
110
|
+
return { value: undefined as TValue, context: {} as TContext };
|
|
99
111
|
}
|
|
100
112
|
}
|
|
101
113
|
|
|
102
|
-
public async initWithMiddleware<C, V, D extends DependencyMapType>(
|
|
103
|
-
resource: IResource<C, V>,
|
|
114
|
+
public async initWithMiddleware<C, V, D extends DependencyMapType, TContext>(
|
|
115
|
+
resource: IResource<C, V, D, TContext>,
|
|
104
116
|
config: C,
|
|
105
|
-
dependencies: D
|
|
117
|
+
dependencies: DependencyValuesType<D>,
|
|
118
|
+
context: TContext
|
|
106
119
|
) {
|
|
107
120
|
let next = async (config: C): Promise<V | undefined> => {
|
|
108
121
|
if (resource.init) {
|
|
109
|
-
return resource.init.call(null, config, dependencies);
|
|
122
|
+
return resource.init.call(null, config, dependencies, context);
|
|
110
123
|
}
|
|
111
124
|
};
|
|
112
125
|
|
|
113
126
|
const existingMiddlewares = resource.middleware;
|
|
114
127
|
const createdMiddlewares = [
|
|
115
|
-
...this.store.
|
|
128
|
+
...this.store.getEverywhereMiddlewareForResources(
|
|
129
|
+
existingMiddlewares.map((x) => x.id)
|
|
130
|
+
),
|
|
116
131
|
...existingMiddlewares,
|
|
117
132
|
];
|
|
118
133
|
|
|
@@ -126,11 +141,14 @@ export class ResourceInitializer {
|
|
|
126
141
|
next = async (config: C) => {
|
|
127
142
|
return storeMiddleware.middleware.run(
|
|
128
143
|
{
|
|
129
|
-
|
|
130
|
-
|
|
144
|
+
resource: {
|
|
145
|
+
definition: resource,
|
|
146
|
+
config,
|
|
147
|
+
},
|
|
131
148
|
next: nextFunction,
|
|
132
149
|
},
|
|
133
|
-
storeMiddleware.computedDependencies
|
|
150
|
+
storeMiddleware.computedDependencies,
|
|
151
|
+
middleware.config
|
|
134
152
|
);
|
|
135
153
|
};
|
|
136
154
|
}
|