@bluelibs/runner 4.5.0-alpha → 4.5.0-alpha.2
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/index.cjs +4265 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +1734 -0
- package/dist/index.d.ts +1696 -45
- package/dist/index.mjs +4233 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +11 -14
- package/dist/context.d.ts +0 -29
- package/dist/context.js +0 -52
- package/dist/context.js.map +0 -1
- package/dist/define.d.ts +0 -9
- package/dist/define.js +0 -32
- package/dist/define.js.map +0 -1
- package/dist/definers/defineEvent.d.ts +0 -2
- package/dist/definers/defineEvent.js +0 -23
- package/dist/definers/defineEvent.js.map +0 -1
- package/dist/definers/defineHook.d.ts +0 -6
- package/dist/definers/defineHook.js +0 -24
- package/dist/definers/defineHook.js.map +0 -1
- package/dist/definers/defineOverride.d.ts +0 -14
- package/dist/definers/defineOverride.js +0 -13
- package/dist/definers/defineOverride.js.map +0 -1
- package/dist/definers/defineResource.d.ts +0 -2
- package/dist/definers/defineResource.js +0 -69
- package/dist/definers/defineResource.js.map +0 -1
- package/dist/definers/defineResourceMiddleware.d.ts +0 -2
- package/dist/definers/defineResourceMiddleware.js +0 -42
- package/dist/definers/defineResourceMiddleware.js.map +0 -1
- package/dist/definers/defineTag.d.ts +0 -12
- package/dist/definers/defineTag.js +0 -107
- package/dist/definers/defineTag.js.map +0 -1
- package/dist/definers/defineTask.d.ts +0 -15
- package/dist/definers/defineTask.js +0 -42
- package/dist/definers/defineTask.js.map +0 -1
- package/dist/definers/defineTaskMiddleware.d.ts +0 -2
- package/dist/definers/defineTaskMiddleware.js +0 -42
- package/dist/definers/defineTaskMiddleware.js.map +0 -1
- package/dist/definers/tools.d.ts +0 -45
- package/dist/definers/tools.js +0 -75
- package/dist/definers/tools.js.map +0 -1
- package/dist/defs.d.ts +0 -29
- package/dist/defs.js +0 -45
- package/dist/defs.js.map +0 -1
- package/dist/errors.d.ts +0 -96
- package/dist/errors.js +0 -178
- package/dist/errors.js.map +0 -1
- package/dist/globals/globalEvents.d.ts +0 -17
- package/dist/globals/globalEvents.js +0 -33
- package/dist/globals/globalEvents.js.map +0 -1
- package/dist/globals/globalMiddleware.d.ts +0 -31
- package/dist/globals/globalMiddleware.js +0 -25
- package/dist/globals/globalMiddleware.js.map +0 -1
- package/dist/globals/globalResources.d.ts +0 -30
- package/dist/globals/globalResources.js +0 -55
- package/dist/globals/globalResources.js.map +0 -1
- package/dist/globals/globalTags.d.ts +0 -9
- package/dist/globals/globalTags.js +0 -23
- package/dist/globals/globalTags.js.map +0 -1
- package/dist/globals/middleware/cache.middleware.d.ts +0 -27
- package/dist/globals/middleware/cache.middleware.js +0 -73
- package/dist/globals/middleware/cache.middleware.js.map +0 -1
- package/dist/globals/middleware/requireContext.middleware.d.ts +0 -6
- package/dist/globals/middleware/requireContext.middleware.js +0 -16
- package/dist/globals/middleware/requireContext.middleware.js.map +0 -1
- package/dist/globals/middleware/retry.middleware.d.ts +0 -21
- package/dist/globals/middleware/retry.middleware.js +0 -61
- package/dist/globals/middleware/retry.middleware.js.map +0 -1
- package/dist/globals/middleware/timeout.middleware.d.ts +0 -9
- package/dist/globals/middleware/timeout.middleware.js +0 -61
- package/dist/globals/middleware/timeout.middleware.js.map +0 -1
- package/dist/globals/resources/debug/debug.resource.d.ts +0 -7
- package/dist/globals/resources/debug/debug.resource.js +0 -29
- package/dist/globals/resources/debug/debug.resource.js.map +0 -1
- package/dist/globals/resources/debug/debug.tag.d.ts +0 -2
- package/dist/globals/resources/debug/debug.tag.js +0 -12
- package/dist/globals/resources/debug/debug.tag.js.map +0 -1
- package/dist/globals/resources/debug/debugConfig.resource.d.ts +0 -22
- package/dist/globals/resources/debug/debugConfig.resource.js +0 -20
- package/dist/globals/resources/debug/debugConfig.resource.js.map +0 -1
- package/dist/globals/resources/debug/executionTracker.middleware.d.ts +0 -50
- package/dist/globals/resources/debug/executionTracker.middleware.js +0 -78
- package/dist/globals/resources/debug/executionTracker.middleware.js.map +0 -1
- package/dist/globals/resources/debug/globalEvent.hook.d.ts +0 -27
- package/dist/globals/resources/debug/globalEvent.hook.js +0 -38
- package/dist/globals/resources/debug/globalEvent.hook.js.map +0 -1
- package/dist/globals/resources/debug/hook.hook.d.ts +0 -30
- package/dist/globals/resources/debug/hook.hook.js +0 -48
- package/dist/globals/resources/debug/hook.hook.js.map +0 -1
- package/dist/globals/resources/debug/index.d.ts +0 -6
- package/dist/globals/resources/debug/index.js +0 -23
- package/dist/globals/resources/debug/index.js.map +0 -1
- package/dist/globals/resources/debug/middleware.hook.d.ts +0 -30
- package/dist/globals/resources/debug/middleware.hook.js +0 -75
- package/dist/globals/resources/debug/middleware.hook.js.map +0 -1
- package/dist/globals/resources/debug/types.d.ts +0 -25
- package/dist/globals/resources/debug/types.js +0 -65
- package/dist/globals/resources/debug/types.js.map +0 -1
- package/dist/globals/resources/debug/utils.d.ts +0 -2
- package/dist/globals/resources/debug/utils.js +0 -13
- package/dist/globals/resources/debug/utils.js.map +0 -1
- package/dist/globals/resources/queue.resource.d.ts +0 -10
- package/dist/globals/resources/queue.resource.js +0 -31
- package/dist/globals/resources/queue.resource.js.map +0 -1
- package/dist/globals/types.d.ts +0 -1
- package/dist/globals/types.js +0 -18
- package/dist/globals/types.js.map +0 -1
- package/dist/index.js +0 -48
- package/dist/index.js.map +0 -1
- package/dist/models/DependencyProcessor.d.ts +0 -48
- package/dist/models/DependencyProcessor.js +0 -276
- package/dist/models/DependencyProcessor.js.map +0 -1
- package/dist/models/EventManager.d.ts +0 -153
- package/dist/models/EventManager.js +0 -421
- package/dist/models/EventManager.js.map +0 -1
- package/dist/models/LogPrinter.d.ts +0 -55
- package/dist/models/LogPrinter.js +0 -202
- package/dist/models/LogPrinter.js.map +0 -1
- package/dist/models/Logger.d.ts +0 -85
- package/dist/models/Logger.js +0 -194
- package/dist/models/Logger.js.map +0 -1
- package/dist/models/MiddlewareManager.d.ts +0 -86
- package/dist/models/MiddlewareManager.js +0 -391
- package/dist/models/MiddlewareManager.js.map +0 -1
- package/dist/models/OverrideManager.d.ts +0 -13
- package/dist/models/OverrideManager.js +0 -84
- package/dist/models/OverrideManager.js.map +0 -1
- package/dist/models/Queue.d.ts +0 -25
- package/dist/models/Queue.js +0 -56
- package/dist/models/Queue.js.map +0 -1
- package/dist/models/ResourceInitializer.d.ts +0 -20
- package/dist/models/ResourceInitializer.js +0 -34
- package/dist/models/ResourceInitializer.js.map +0 -1
- package/dist/models/RunResult.d.ts +0 -35
- package/dist/models/RunResult.js +0 -62
- package/dist/models/RunResult.js.map +0 -1
- package/dist/models/Semaphore.d.ts +0 -61
- package/dist/models/Semaphore.js +0 -164
- package/dist/models/Semaphore.js.map +0 -1
- package/dist/models/Store.d.ts +0 -56
- package/dist/models/Store.js +0 -209
- package/dist/models/Store.js.map +0 -1
- package/dist/models/StoreRegistry.d.ts +0 -43
- package/dist/models/StoreRegistry.js +0 -375
- package/dist/models/StoreRegistry.js.map +0 -1
- package/dist/models/StoreValidator.d.ts +0 -8
- package/dist/models/StoreValidator.js +0 -73
- package/dist/models/StoreValidator.js.map +0 -1
- package/dist/models/TaskRunner.d.ts +0 -27
- package/dist/models/TaskRunner.js +0 -53
- package/dist/models/TaskRunner.js.map +0 -1
- package/dist/models/UnhandledError.d.ts +0 -11
- package/dist/models/UnhandledError.js +0 -32
- package/dist/models/UnhandledError.js.map +0 -1
- package/dist/models/index.d.ts +0 -11
- package/dist/models/index.js +0 -28
- package/dist/models/index.js.map +0 -1
- package/dist/models/utils/findCircularDependencies.d.ts +0 -16
- package/dist/models/utils/findCircularDependencies.js +0 -45
- package/dist/models/utils/findCircularDependencies.js.map +0 -1
- package/dist/models/utils/safeStringify.d.ts +0 -3
- package/dist/models/utils/safeStringify.js +0 -45
- package/dist/models/utils/safeStringify.js.map +0 -1
- package/dist/platform/browser.d.ts +0 -15
- package/dist/platform/browser.js +0 -98
- package/dist/platform/browser.js.map +0 -1
- package/dist/platform/index.d.ts +0 -8
- package/dist/platform/index.js +0 -47
- package/dist/platform/index.js.map +0 -1
- package/dist/platform/node.d.ts +0 -11
- package/dist/platform/node.js +0 -45
- package/dist/platform/node.js.map +0 -1
- package/dist/platform/types.d.ts +0 -28
- package/dist/platform/types.js +0 -19
- package/dist/platform/types.js.map +0 -1
- package/dist/platform/universal.d.ts +0 -16
- package/dist/platform/universal.js +0 -57
- package/dist/platform/universal.js.map +0 -1
- package/dist/processHooks.d.ts +0 -2
- package/dist/processHooks.js +0 -79
- package/dist/processHooks.js.map +0 -1
- package/dist/run.d.ts +0 -14
- package/dist/run.js +0 -126
- package/dist/run.js.map +0 -1
- package/dist/testing.d.ts +0 -25
- package/dist/testing.js +0 -42
- package/dist/testing.js.map +0 -1
- package/dist/tools/getCallerFile.d.ts +0 -1
- package/dist/tools/getCallerFile.js +0 -30
- package/dist/tools/getCallerFile.js.map +0 -1
- package/dist/types/contracts.d.ts +0 -55
- package/dist/types/contracts.js +0 -4
- package/dist/types/contracts.js.map +0 -1
- package/dist/types/event.d.ts +0 -74
- package/dist/types/event.js +0 -17
- package/dist/types/event.js.map +0 -1
- package/dist/types/hook.d.ts +0 -23
- package/dist/types/hook.js +0 -4
- package/dist/types/hook.js.map +0 -1
- package/dist/types/meta.d.ts +0 -18
- package/dist/types/meta.js +0 -7
- package/dist/types/meta.js.map +0 -1
- package/dist/types/resource.d.ts +0 -84
- package/dist/types/resource.js +0 -4
- package/dist/types/resource.js.map +0 -1
- package/dist/types/resourceMiddleware.d.ts +0 -47
- package/dist/types/resourceMiddleware.js +0 -4
- package/dist/types/resourceMiddleware.js.map +0 -1
- package/dist/types/runner.d.ts +0 -55
- package/dist/types/runner.js +0 -3
- package/dist/types/runner.js.map +0 -1
- package/dist/types/storeTypes.d.ts +0 -40
- package/dist/types/storeTypes.js +0 -3
- package/dist/types/storeTypes.js.map +0 -1
- package/dist/types/symbols.d.ts +0 -30
- package/dist/types/symbols.js +0 -40
- package/dist/types/symbols.js.map +0 -1
- package/dist/types/tag.d.ts +0 -46
- package/dist/types/tag.js +0 -4
- package/dist/types/tag.js.map +0 -1
- package/dist/types/task.d.ts +0 -44
- package/dist/types/task.js +0 -4
- package/dist/types/task.js.map +0 -1
- package/dist/types/taskMiddleware.d.ts +0 -48
- package/dist/types/taskMiddleware.js +0 -4
- package/dist/types/taskMiddleware.js.map +0 -1
- package/dist/types/utilities.d.ts +0 -110
- package/dist/types/utilities.js +0 -19
- package/dist/types/utilities.js.map +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,4265 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var lruCache = require('lru-cache');
|
|
4
|
+
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __typeError = (msg) => {
|
|
7
|
+
throw TypeError(msg);
|
|
8
|
+
};
|
|
9
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
10
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
11
|
+
}) : x)(function(x) {
|
|
12
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
14
|
+
});
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
19
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
20
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
21
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
22
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
23
|
+
|
|
24
|
+
// src/defs.ts
|
|
25
|
+
var defs_exports = {};
|
|
26
|
+
__export(defs_exports, {
|
|
27
|
+
isOneOf: () => isOneOf,
|
|
28
|
+
onAnyOf: () => onAnyOf,
|
|
29
|
+
symbolDispose: () => symbolDispose,
|
|
30
|
+
symbolEvent: () => symbolEvent,
|
|
31
|
+
symbolFilePath: () => symbolFilePath,
|
|
32
|
+
symbolHook: () => symbolHook,
|
|
33
|
+
symbolIndexResource: () => symbolIndexResource,
|
|
34
|
+
symbolMiddleware: () => symbolMiddleware,
|
|
35
|
+
symbolMiddlewareConfigured: () => symbolMiddlewareConfigured,
|
|
36
|
+
symbolOptionalDependency: () => symbolOptionalDependency,
|
|
37
|
+
symbolResource: () => symbolResource,
|
|
38
|
+
symbolResourceMiddleware: () => symbolResourceMiddleware,
|
|
39
|
+
symbolResourceWithConfig: () => symbolResourceWithConfig,
|
|
40
|
+
symbolStore: () => symbolStore,
|
|
41
|
+
symbolTag: () => symbolTag,
|
|
42
|
+
symbolTagConfigured: () => symbolTagConfigured,
|
|
43
|
+
symbolTask: () => symbolTask,
|
|
44
|
+
symbolTaskMiddleware: () => symbolTaskMiddleware
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// src/types/symbols.ts
|
|
48
|
+
var symbolTask = Symbol("runner.task");
|
|
49
|
+
var symbolResource = Symbol("runner.resource");
|
|
50
|
+
var symbolResourceWithConfig = Symbol(
|
|
51
|
+
"runner.resourceWithConfig"
|
|
52
|
+
);
|
|
53
|
+
var symbolEvent = Symbol("runner.event");
|
|
54
|
+
var symbolMiddleware = Symbol("runner.middleware");
|
|
55
|
+
var symbolTaskMiddleware = Symbol(
|
|
56
|
+
"runner.taskMiddleware"
|
|
57
|
+
);
|
|
58
|
+
var symbolResourceMiddleware = Symbol(
|
|
59
|
+
"runner.resourceMiddleware"
|
|
60
|
+
);
|
|
61
|
+
var symbolMiddlewareConfigured = Symbol(
|
|
62
|
+
"runner.middlewareConfigured"
|
|
63
|
+
);
|
|
64
|
+
var symbolHook = Symbol("runner.hook");
|
|
65
|
+
var symbolTag = Symbol("runner.tag");
|
|
66
|
+
var symbolTagConfigured = Symbol(
|
|
67
|
+
"runner.tagConfigured"
|
|
68
|
+
);
|
|
69
|
+
var symbolOptionalDependency = Symbol(
|
|
70
|
+
"runner.optionalDependency"
|
|
71
|
+
);
|
|
72
|
+
var symbolFilePath = Symbol("runner.filePath");
|
|
73
|
+
var symbolDispose = Symbol("runner.dispose");
|
|
74
|
+
var symbolStore = Symbol("runner.store");
|
|
75
|
+
var symbolIndexResource = Symbol(
|
|
76
|
+
"runner.indexResource"
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// src/types/event.ts
|
|
80
|
+
function onAnyOf(...defs) {
|
|
81
|
+
return defs;
|
|
82
|
+
}
|
|
83
|
+
function isOneOf(emission, defs) {
|
|
84
|
+
return defs.some((d) => d.id === emission.id);
|
|
85
|
+
}
|
|
86
|
+
var cacheFactoryTask = defineTask({
|
|
87
|
+
id: "globals.tasks.cacheFactory",
|
|
88
|
+
run: async (options) => {
|
|
89
|
+
return new lruCache.LRUCache(options);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
var cacheResource = defineResource({
|
|
93
|
+
id: "globals.resources.cache",
|
|
94
|
+
register: [cacheFactoryTask],
|
|
95
|
+
dependencies: {
|
|
96
|
+
cacheFactoryTask
|
|
97
|
+
},
|
|
98
|
+
init: async (config, { cacheFactoryTask: cacheFactoryTask2 }) => {
|
|
99
|
+
return {
|
|
100
|
+
map: /* @__PURE__ */ new Map(),
|
|
101
|
+
cacheFactoryTask: cacheFactoryTask2,
|
|
102
|
+
defaultOptions: {
|
|
103
|
+
ttl: 10 * 1e3,
|
|
104
|
+
max: 100,
|
|
105
|
+
// Maximum number of items in cache
|
|
106
|
+
ttlAutopurge: true,
|
|
107
|
+
// Automatically purge expired items
|
|
108
|
+
...config.defaultOptions
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
dispose: async (cache) => {
|
|
113
|
+
for (const cacheInstance of cache.map.values()) {
|
|
114
|
+
await cacheInstance.clear();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
var defaultKeyBuilder = (taskId, input) => `${taskId}-${JSON.stringify(input)}`;
|
|
119
|
+
var cacheMiddleware = defineTaskMiddleware({
|
|
120
|
+
id: "globals.middleware.cache",
|
|
121
|
+
dependencies: { cache: cacheResource },
|
|
122
|
+
async run({ task, next }, deps, config) {
|
|
123
|
+
const { cache } = deps;
|
|
124
|
+
config = {
|
|
125
|
+
keyBuilder: defaultKeyBuilder,
|
|
126
|
+
ttl: 10 * 1e3,
|
|
127
|
+
max: 100,
|
|
128
|
+
// Maximum number of items in cache
|
|
129
|
+
ttlAutopurge: true,
|
|
130
|
+
// Automatically purge expired items
|
|
131
|
+
...config
|
|
132
|
+
};
|
|
133
|
+
const taskId = task.definition.id;
|
|
134
|
+
let cacheHolderForTask = cache.map.get(taskId);
|
|
135
|
+
if (!cacheHolderForTask) {
|
|
136
|
+
const { keyBuilder, ...lruOptions } = config;
|
|
137
|
+
const cacheOptions = {
|
|
138
|
+
...cache.defaultOptions,
|
|
139
|
+
...lruOptions
|
|
140
|
+
};
|
|
141
|
+
cacheHolderForTask = await cache.cacheFactoryTask(cacheOptions);
|
|
142
|
+
cache.map.set(taskId, cacheHolderForTask);
|
|
143
|
+
}
|
|
144
|
+
const key = config.keyBuilder(taskId, task.input);
|
|
145
|
+
const cachedValue = await cacheHolderForTask.get(key);
|
|
146
|
+
if (cachedValue) {
|
|
147
|
+
return cachedValue;
|
|
148
|
+
}
|
|
149
|
+
const result = await next(task.input);
|
|
150
|
+
await cacheHolderForTask.set(key, result);
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// src/tools/getCallerFile.ts
|
|
156
|
+
function getCallerFile() {
|
|
157
|
+
const originalFunc = Error.prepareStackTrace;
|
|
158
|
+
try {
|
|
159
|
+
const err = new Error();
|
|
160
|
+
let callerfile;
|
|
161
|
+
let currentfile;
|
|
162
|
+
Error.prepareStackTrace = (err2, stack2) => stack2;
|
|
163
|
+
const stack = err.stack;
|
|
164
|
+
stack.shift();
|
|
165
|
+
currentfile = stack.shift()?.getFileName?.();
|
|
166
|
+
callerfile = stack.shift()?.getFileName?.();
|
|
167
|
+
return callerfile;
|
|
168
|
+
} finally {
|
|
169
|
+
Error.prepareStackTrace = originalFunc;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/definers/defineTask.ts
|
|
174
|
+
function defineTask(taskConfig) {
|
|
175
|
+
const filePath = getCallerFile();
|
|
176
|
+
const id2 = taskConfig.id;
|
|
177
|
+
return {
|
|
178
|
+
[symbolTask]: true,
|
|
179
|
+
[symbolFilePath]: filePath,
|
|
180
|
+
id: id2,
|
|
181
|
+
dependencies: taskConfig.dependencies || {},
|
|
182
|
+
middleware: taskConfig.middleware || [],
|
|
183
|
+
run: taskConfig.run,
|
|
184
|
+
inputSchema: taskConfig.inputSchema,
|
|
185
|
+
resultSchema: taskConfig.resultSchema,
|
|
186
|
+
meta: taskConfig.meta || {},
|
|
187
|
+
tags: taskConfig.tags || [],
|
|
188
|
+
// autorun,
|
|
189
|
+
optional() {
|
|
190
|
+
return {
|
|
191
|
+
inner: this,
|
|
192
|
+
[symbolOptionalDependency]: true
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/definers/defineHook.ts
|
|
199
|
+
function defineHook(hookDef) {
|
|
200
|
+
const filePath = getCallerFile();
|
|
201
|
+
return {
|
|
202
|
+
[symbolHook]: true,
|
|
203
|
+
[symbolFilePath]: filePath,
|
|
204
|
+
id: hookDef.id,
|
|
205
|
+
dependencies: hookDef.dependencies || {},
|
|
206
|
+
on: hookDef.on,
|
|
207
|
+
order: hookDef.order,
|
|
208
|
+
run: hookDef.run,
|
|
209
|
+
meta: hookDef.meta || {},
|
|
210
|
+
tags: hookDef.tags || []
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/errors.ts
|
|
215
|
+
var errors_exports = {};
|
|
216
|
+
__export(errors_exports, {
|
|
217
|
+
CircularDependenciesError: () => CircularDependenciesError,
|
|
218
|
+
ContextError: () => ContextError,
|
|
219
|
+
DependencyNotFoundError: () => DependencyNotFoundError,
|
|
220
|
+
DuplicateRegistrationError: () => DuplicateRegistrationError,
|
|
221
|
+
EventCycleError: () => EventCycleError,
|
|
222
|
+
EventEmissionCycleError: () => EventEmissionCycleError,
|
|
223
|
+
EventNotFoundError: () => EventNotFoundError,
|
|
224
|
+
LockedError: () => LockedError,
|
|
225
|
+
MiddlewareNotRegisteredError: () => MiddlewareNotRegisteredError,
|
|
226
|
+
PlatformUnsupportedFunction: () => PlatformUnsupportedFunction,
|
|
227
|
+
ResourceNotFoundError: () => ResourceNotFoundError,
|
|
228
|
+
RuntimeError: () => RuntimeError,
|
|
229
|
+
StoreAlreadyInitializedError: () => StoreAlreadyInitializedError,
|
|
230
|
+
TagNotFoundError: () => TagNotFoundError,
|
|
231
|
+
UnknownItemTypeError: () => UnknownItemTypeError,
|
|
232
|
+
ValidationError: () => ValidationError
|
|
233
|
+
});
|
|
234
|
+
var RuntimeError = class extends Error {
|
|
235
|
+
constructor(message) {
|
|
236
|
+
super(message);
|
|
237
|
+
this.name = "RuntimeError";
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
var DuplicateRegistrationError = class extends RuntimeError {
|
|
241
|
+
constructor(type, id2) {
|
|
242
|
+
super(
|
|
243
|
+
`${type} "${id2.toString()}" already registered. You might have used the same 'id' in two different components or you may have registered the same element twice.`
|
|
244
|
+
);
|
|
245
|
+
this.name = "DuplicateRegistrationError";
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
var DependencyNotFoundError = class extends RuntimeError {
|
|
249
|
+
constructor(key) {
|
|
250
|
+
super(
|
|
251
|
+
`Dependency ${key.toString()} not found. Did you forget to register it through a resource?`
|
|
252
|
+
);
|
|
253
|
+
this.name = "DependencyNotFoundError";
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
var UnknownItemTypeError = class extends RuntimeError {
|
|
257
|
+
constructor(item) {
|
|
258
|
+
super(
|
|
259
|
+
`Unknown item type: ${item}. Please ensure you are not using different versions of '@bluelibs/runner'`
|
|
260
|
+
);
|
|
261
|
+
this.name = "UnknownItemTypeError";
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
var ContextError = class extends Error {
|
|
265
|
+
constructor(message) {
|
|
266
|
+
super(message);
|
|
267
|
+
this.name = "ContextError";
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
var CircularDependenciesError = class extends RuntimeError {
|
|
271
|
+
constructor(cycles) {
|
|
272
|
+
const cycleDetails = cycles.map((cycle) => ` \u2022 ${cycle}`).join("\n");
|
|
273
|
+
const hasMiddleware = cycles.some((cycle) => cycle.includes("middleware"));
|
|
274
|
+
let guidance = "\n\nTo resolve circular dependencies:";
|
|
275
|
+
guidance += "\n \u2022 Consider refactoring to reduce coupling between components";
|
|
276
|
+
guidance += "\n \u2022 Extract shared dependencies into separate resources";
|
|
277
|
+
if (hasMiddleware) {
|
|
278
|
+
guidance += "\n \u2022 For middleware: you can filter out tasks/resources using everywhere(fn)";
|
|
279
|
+
guidance += "\n \u2022 Consider using events for communication instead of direct dependencies";
|
|
280
|
+
}
|
|
281
|
+
super(`Circular dependencies detected:
|
|
282
|
+
${cycleDetails}${guidance}`);
|
|
283
|
+
this.name = "CircularDependenciesError";
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
var EventNotFoundError = class extends RuntimeError {
|
|
287
|
+
constructor(id2) {
|
|
288
|
+
super(`Event "${id2.toString()}" not found. Did you forget to register it?`);
|
|
289
|
+
this.name = "EventNotFoundError";
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
var ResourceNotFoundError = class extends RuntimeError {
|
|
293
|
+
constructor(id2) {
|
|
294
|
+
super(
|
|
295
|
+
`Resource "${id2.toString()}" not found. Did you forget to register it or are you using the correct id?`
|
|
296
|
+
);
|
|
297
|
+
this.name = "ResourceNotFoundError";
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
var MiddlewareNotRegisteredError = class extends RuntimeError {
|
|
301
|
+
constructor(type, source, middlewareId) {
|
|
302
|
+
super(
|
|
303
|
+
`Middleware inside ${type} "${source}" depends on "${middlewareId}" but it's not registered. Did you forget to register it?`
|
|
304
|
+
);
|
|
305
|
+
this.name = `MiddlewareNotRegisteredError: ${type} ${source} ${middlewareId}`;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
var TagNotFoundError = class extends RuntimeError {
|
|
309
|
+
constructor(id2) {
|
|
310
|
+
super(
|
|
311
|
+
`Tag "${id2}" not registered. Did you forget to register it inside a resource?`
|
|
312
|
+
);
|
|
313
|
+
this.name = "TagNotRegisteredError";
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
var LockedError = class extends RuntimeError {
|
|
317
|
+
constructor(what) {
|
|
318
|
+
super(`Cannot modify the ${what.toString()} when it is locked.`);
|
|
319
|
+
this.name = "LockedError";
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
var StoreAlreadyInitializedError = class extends RuntimeError {
|
|
323
|
+
constructor() {
|
|
324
|
+
super("Store already initialized. Cannot reinitialize.");
|
|
325
|
+
this.name = "StoreAlreadyInitializedError";
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
var ValidationError = class extends RuntimeError {
|
|
329
|
+
constructor(type, id2, originalError) {
|
|
330
|
+
const errorMessage = originalError instanceof Error ? originalError.message : String(originalError);
|
|
331
|
+
super(`${type} validation failed for ${id2.toString()}: ${errorMessage}`);
|
|
332
|
+
this.name = "ValidationError";
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
var EventCycleError = class extends RuntimeError {
|
|
336
|
+
constructor(path) {
|
|
337
|
+
const chain = path.map((p) => `${p.id}\u2190${p.source}`).join(" -> ");
|
|
338
|
+
super(
|
|
339
|
+
`Event emission cycle detected:
|
|
340
|
+
${chain}
|
|
341
|
+
|
|
342
|
+
Break the cycle by changing hook logic (avoid mutual emits) or gate with conditions/tags.`
|
|
343
|
+
);
|
|
344
|
+
this.name = "EventCycleError";
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
var EventEmissionCycleError = class extends RuntimeError {
|
|
348
|
+
constructor(cycles) {
|
|
349
|
+
const list = cycles.map((c) => ` \u2022 ${c}`).join("\n");
|
|
350
|
+
super(
|
|
351
|
+
`Event emission cycles detected between hooks and events:
|
|
352
|
+
${list}
|
|
353
|
+
|
|
354
|
+
This was detected at compile time (dry-run). Break the cycle by avoiding mutual emits between hooks or scoping hooks using tags.`
|
|
355
|
+
);
|
|
356
|
+
this.name = "EventEmissionCycleError";
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
var PlatformUnsupportedFunction = class extends RuntimeError {
|
|
360
|
+
constructor(functionName) {
|
|
361
|
+
super(
|
|
362
|
+
`Platform function not supported in this environment: ${functionName}`
|
|
363
|
+
);
|
|
364
|
+
this.name = "PlatformUnsupportedFunction";
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// src/definers/defineResource.ts
|
|
369
|
+
function defineResource(constConfig) {
|
|
370
|
+
const filePath = constConfig[symbolFilePath] || getCallerFile();
|
|
371
|
+
const isIndexResource = constConfig[symbolIndexResource] || false;
|
|
372
|
+
const id2 = constConfig.id;
|
|
373
|
+
return {
|
|
374
|
+
[symbolResource]: true,
|
|
375
|
+
[symbolFilePath]: filePath,
|
|
376
|
+
[symbolIndexResource]: isIndexResource,
|
|
377
|
+
id: id2,
|
|
378
|
+
dependencies: constConfig.dependencies,
|
|
379
|
+
dispose: constConfig.dispose,
|
|
380
|
+
register: constConfig.register || [],
|
|
381
|
+
overrides: constConfig.overrides || [],
|
|
382
|
+
init: constConfig.init,
|
|
383
|
+
context: constConfig.context,
|
|
384
|
+
configSchema: constConfig.configSchema,
|
|
385
|
+
resultSchema: constConfig.resultSchema,
|
|
386
|
+
tags: constConfig.tags || [],
|
|
387
|
+
with: function(config) {
|
|
388
|
+
if (constConfig.configSchema) {
|
|
389
|
+
try {
|
|
390
|
+
config = constConfig.configSchema.parse(config);
|
|
391
|
+
} catch (error) {
|
|
392
|
+
throw new ValidationError(
|
|
393
|
+
"Resource config",
|
|
394
|
+
id2,
|
|
395
|
+
error instanceof Error ? error : new Error(String(error))
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
[symbolResourceWithConfig]: true,
|
|
401
|
+
id: this.id,
|
|
402
|
+
resource: this,
|
|
403
|
+
config
|
|
404
|
+
};
|
|
405
|
+
},
|
|
406
|
+
meta: constConfig.meta || {},
|
|
407
|
+
middleware: constConfig.middleware || [],
|
|
408
|
+
optional() {
|
|
409
|
+
return {
|
|
410
|
+
inner: this,
|
|
411
|
+
[symbolOptionalDependency]: true
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/definers/defineEvent.ts
|
|
418
|
+
function defineEvent(config) {
|
|
419
|
+
const callerFilePath = getCallerFile();
|
|
420
|
+
const eventConfig = config;
|
|
421
|
+
return {
|
|
422
|
+
...eventConfig,
|
|
423
|
+
id: eventConfig.id,
|
|
424
|
+
[symbolFilePath]: callerFilePath,
|
|
425
|
+
[symbolEvent]: true,
|
|
426
|
+
// This is a workaround
|
|
427
|
+
tags: eventConfig.tags || [],
|
|
428
|
+
optional() {
|
|
429
|
+
return {
|
|
430
|
+
inner: this,
|
|
431
|
+
[symbolOptionalDependency]: true
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/definers/defineTaskMiddleware.ts
|
|
438
|
+
function defineTaskMiddleware(middlewareDef) {
|
|
439
|
+
const filePath = getCallerFile();
|
|
440
|
+
const base = {
|
|
441
|
+
[symbolFilePath]: filePath,
|
|
442
|
+
[symbolTaskMiddleware]: true,
|
|
443
|
+
config: {},
|
|
444
|
+
configSchema: middlewareDef.configSchema,
|
|
445
|
+
...middlewareDef,
|
|
446
|
+
dependencies: middlewareDef.dependencies || {}
|
|
447
|
+
};
|
|
448
|
+
const wrap = (obj) => {
|
|
449
|
+
return {
|
|
450
|
+
...obj,
|
|
451
|
+
with: (config) => {
|
|
452
|
+
if (obj.configSchema) {
|
|
453
|
+
try {
|
|
454
|
+
config = obj.configSchema.parse(config);
|
|
455
|
+
} catch (error) {
|
|
456
|
+
throw new ValidationError(
|
|
457
|
+
"Middleware config",
|
|
458
|
+
obj.id,
|
|
459
|
+
error instanceof Error ? error : new Error(String(error))
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return wrap({
|
|
464
|
+
...obj,
|
|
465
|
+
[symbolMiddlewareConfigured]: true,
|
|
466
|
+
config: {
|
|
467
|
+
...obj.config,
|
|
468
|
+
...config
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
};
|
|
474
|
+
return wrap(base);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// src/definers/defineResourceMiddleware.ts
|
|
478
|
+
function defineResourceMiddleware(middlewareDef) {
|
|
479
|
+
const filePath = getCallerFile();
|
|
480
|
+
const base = {
|
|
481
|
+
[symbolFilePath]: filePath,
|
|
482
|
+
[symbolResourceMiddleware]: true,
|
|
483
|
+
config: {},
|
|
484
|
+
configSchema: middlewareDef.configSchema,
|
|
485
|
+
...middlewareDef,
|
|
486
|
+
dependencies: middlewareDef.dependencies || {}
|
|
487
|
+
};
|
|
488
|
+
const wrap = (obj) => {
|
|
489
|
+
return {
|
|
490
|
+
...obj,
|
|
491
|
+
with: (config) => {
|
|
492
|
+
if (obj.configSchema) {
|
|
493
|
+
try {
|
|
494
|
+
config = obj.configSchema.parse(config);
|
|
495
|
+
} catch (error) {
|
|
496
|
+
throw new ValidationError(
|
|
497
|
+
"Middleware config",
|
|
498
|
+
obj.id,
|
|
499
|
+
error
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return wrap({
|
|
504
|
+
...obj,
|
|
505
|
+
[symbolMiddlewareConfigured]: true,
|
|
506
|
+
config: {
|
|
507
|
+
...obj.config,
|
|
508
|
+
...config
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
};
|
|
514
|
+
return wrap(base);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// src/definers/defineOverride.ts
|
|
518
|
+
function defineOverride(base, patch) {
|
|
519
|
+
const { id: _ignored, ...rest } = patch;
|
|
520
|
+
return {
|
|
521
|
+
...base,
|
|
522
|
+
...rest,
|
|
523
|
+
id: base.id
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// src/definers/defineTag.ts
|
|
528
|
+
function defineTag(definition) {
|
|
529
|
+
const id2 = definition.id;
|
|
530
|
+
const filePath = getCallerFile();
|
|
531
|
+
const foundation = {
|
|
532
|
+
id: id2,
|
|
533
|
+
meta: definition.meta,
|
|
534
|
+
config: definition.config,
|
|
535
|
+
configSchema: definition.configSchema
|
|
536
|
+
};
|
|
537
|
+
return {
|
|
538
|
+
...foundation,
|
|
539
|
+
[symbolTag]: true,
|
|
540
|
+
[symbolFilePath]: filePath,
|
|
541
|
+
/**
|
|
542
|
+
* Specify custom config for this tag which extends the default one if exists
|
|
543
|
+
* @param tagConfig
|
|
544
|
+
* @returns
|
|
545
|
+
*/
|
|
546
|
+
with(tagConfig) {
|
|
547
|
+
if (definition.configSchema) {
|
|
548
|
+
try {
|
|
549
|
+
tagConfig = definition.configSchema.parse(tagConfig);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
throw new ValidationError("Tag config", this.id, error);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
let config;
|
|
555
|
+
if (typeof tagConfig === "object") {
|
|
556
|
+
if (typeof foundation.config === "object") {
|
|
557
|
+
config = {
|
|
558
|
+
...foundation.config,
|
|
559
|
+
...tagConfig
|
|
560
|
+
};
|
|
561
|
+
} else {
|
|
562
|
+
config = tagConfig;
|
|
563
|
+
}
|
|
564
|
+
} else {
|
|
565
|
+
config = tagConfig;
|
|
566
|
+
}
|
|
567
|
+
return {
|
|
568
|
+
...foundation,
|
|
569
|
+
[symbolTagConfigured]: true,
|
|
570
|
+
config
|
|
571
|
+
};
|
|
572
|
+
},
|
|
573
|
+
/**
|
|
574
|
+
* Checks if the tag exists in a taggable or a list of tags.
|
|
575
|
+
* @param target
|
|
576
|
+
* @returns
|
|
577
|
+
*/
|
|
578
|
+
exists(target) {
|
|
579
|
+
let currentTags = [];
|
|
580
|
+
if (Array.isArray(target)) {
|
|
581
|
+
currentTags = target;
|
|
582
|
+
} else {
|
|
583
|
+
currentTags = target.tags;
|
|
584
|
+
}
|
|
585
|
+
for (const candidate of currentTags) {
|
|
586
|
+
if (candidate.id === id2) {
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return false;
|
|
591
|
+
},
|
|
592
|
+
/**
|
|
593
|
+
* Function which serves 2 purposes, verifying if the task exists, and retrieving its config
|
|
594
|
+
* @param target
|
|
595
|
+
* @returns
|
|
596
|
+
*/
|
|
597
|
+
extract(target) {
|
|
598
|
+
let currentTags = [];
|
|
599
|
+
if (Array.isArray(target)) {
|
|
600
|
+
currentTags = target;
|
|
601
|
+
} else {
|
|
602
|
+
currentTags = target.tags || [];
|
|
603
|
+
}
|
|
604
|
+
for (const candidate of currentTags) {
|
|
605
|
+
if (candidate.id === id2) {
|
|
606
|
+
return candidate.config;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// src/definers/tools.ts
|
|
615
|
+
function isTask(definition) {
|
|
616
|
+
return definition && definition[symbolTask];
|
|
617
|
+
}
|
|
618
|
+
function isResource(definition) {
|
|
619
|
+
return definition && definition[symbolResource];
|
|
620
|
+
}
|
|
621
|
+
function isResourceWithConfig(definition) {
|
|
622
|
+
return definition && definition[symbolResourceWithConfig];
|
|
623
|
+
}
|
|
624
|
+
function isEvent(definition) {
|
|
625
|
+
return definition && definition[symbolEvent];
|
|
626
|
+
}
|
|
627
|
+
function isHook(definition) {
|
|
628
|
+
return definition && definition[symbolHook];
|
|
629
|
+
}
|
|
630
|
+
function isTaskMiddleware(definition) {
|
|
631
|
+
return definition && definition[symbolTaskMiddleware];
|
|
632
|
+
}
|
|
633
|
+
function isResourceMiddleware(definition) {
|
|
634
|
+
return definition && definition[symbolResourceMiddleware];
|
|
635
|
+
}
|
|
636
|
+
function isTag(definition) {
|
|
637
|
+
return definition && definition[symbolTag];
|
|
638
|
+
}
|
|
639
|
+
function isOptional(definition) {
|
|
640
|
+
return definition && definition[symbolOptionalDependency];
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// src/platform/index.ts
|
|
644
|
+
function detectEnvironment() {
|
|
645
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
646
|
+
return "browser";
|
|
647
|
+
}
|
|
648
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
649
|
+
return "node";
|
|
650
|
+
}
|
|
651
|
+
return "universal";
|
|
652
|
+
}
|
|
653
|
+
async function loadModule(path) {
|
|
654
|
+
try {
|
|
655
|
+
return await import(path);
|
|
656
|
+
} catch (e) {
|
|
657
|
+
return __require(path);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
var PlatformAdapter = class {
|
|
661
|
+
constructor(env) {
|
|
662
|
+
this.isInitialized = false;
|
|
663
|
+
this.nodeALSClass = null;
|
|
664
|
+
// timers
|
|
665
|
+
this.setTimeout = globalThis.setTimeout;
|
|
666
|
+
this.clearTimeout = globalThis.clearTimeout;
|
|
667
|
+
this.env = env ?? detectEnvironment();
|
|
668
|
+
}
|
|
669
|
+
async init() {
|
|
670
|
+
if (this.env === "node") {
|
|
671
|
+
this.nodeALSClass = (await loadModule("node:async_hooks")).AsyncLocalStorage;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
onUncaughtException(handler) {
|
|
675
|
+
switch (this.env) {
|
|
676
|
+
case "node": {
|
|
677
|
+
process.on("uncaughtException", handler);
|
|
678
|
+
return () => process.off("uncaughtException", handler);
|
|
679
|
+
}
|
|
680
|
+
case "browser": {
|
|
681
|
+
const target = globalThis.window ?? globalThis;
|
|
682
|
+
const h = (e) => handler(e?.error ?? e);
|
|
683
|
+
target.addEventListener?.("error", h);
|
|
684
|
+
return () => target.removeEventListener?.("error", h);
|
|
685
|
+
}
|
|
686
|
+
default: {
|
|
687
|
+
const tgt = globalThis;
|
|
688
|
+
if (tgt.addEventListener) {
|
|
689
|
+
const h = (e) => handler(e?.error ?? e);
|
|
690
|
+
tgt.addEventListener("error", h);
|
|
691
|
+
return () => tgt.removeEventListener("error", h);
|
|
692
|
+
}
|
|
693
|
+
return () => {
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
onUnhandledRejection(handler) {
|
|
699
|
+
switch (this.env) {
|
|
700
|
+
case "node": {
|
|
701
|
+
const h = (reason) => handler(reason);
|
|
702
|
+
process.on("unhandledRejection", h);
|
|
703
|
+
return () => process.off("unhandledRejection", h);
|
|
704
|
+
}
|
|
705
|
+
case "browser": {
|
|
706
|
+
const target = globalThis.window ?? globalThis;
|
|
707
|
+
const wrap = (e) => handler(e.reason);
|
|
708
|
+
target.addEventListener?.("unhandledrejection", wrap);
|
|
709
|
+
return () => target.removeEventListener?.("unhandledrejection", wrap);
|
|
710
|
+
}
|
|
711
|
+
default: {
|
|
712
|
+
const tgt = globalThis;
|
|
713
|
+
if (tgt.addEventListener) {
|
|
714
|
+
const wrap = (e) => handler(e.reason ?? e);
|
|
715
|
+
tgt.addEventListener("unhandledrejection", wrap);
|
|
716
|
+
return () => tgt.removeEventListener("unhandledrejection", wrap);
|
|
717
|
+
}
|
|
718
|
+
return () => {
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
onShutdownSignal(handler) {
|
|
724
|
+
switch (this.env) {
|
|
725
|
+
case "node": {
|
|
726
|
+
process.on("SIGINT", handler);
|
|
727
|
+
process.on("SIGTERM", handler);
|
|
728
|
+
return () => {
|
|
729
|
+
process.off("SIGINT", handler);
|
|
730
|
+
process.off("SIGTERM", handler);
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
case "browser": {
|
|
734
|
+
const win = window ?? globalThis.window ?? globalThis;
|
|
735
|
+
win.addEventListener?.("beforeunload", handler);
|
|
736
|
+
return () => {
|
|
737
|
+
win.removeEventListener?.("beforeunload", handler);
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
default: {
|
|
741
|
+
const tgt = globalThis;
|
|
742
|
+
const cleanup = [];
|
|
743
|
+
if (tgt.addEventListener) {
|
|
744
|
+
tgt.addEventListener("beforeunload", handler);
|
|
745
|
+
cleanup.push(
|
|
746
|
+
() => tgt.removeEventListener?.("beforeunload", handler)
|
|
747
|
+
);
|
|
748
|
+
const vis = () => {
|
|
749
|
+
const doc = globalThis.document;
|
|
750
|
+
if (doc && doc.visibilityState === "hidden") handler();
|
|
751
|
+
};
|
|
752
|
+
tgt.addEventListener("visibilitychange", vis);
|
|
753
|
+
cleanup.push(
|
|
754
|
+
() => tgt.removeEventListener?.("visibilitychange", vis)
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
if (typeof process !== "undefined" && process.on) {
|
|
758
|
+
process.on("SIGINT", handler);
|
|
759
|
+
process.on("SIGTERM", handler);
|
|
760
|
+
cleanup.push(() => {
|
|
761
|
+
process.off?.("SIGINT", handler);
|
|
762
|
+
process.off?.("SIGTERM", handler);
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
return () => cleanup.forEach((fn) => fn());
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
exit(code) {
|
|
770
|
+
switch (this.env) {
|
|
771
|
+
case "node":
|
|
772
|
+
process.exit(code);
|
|
773
|
+
return;
|
|
774
|
+
default:
|
|
775
|
+
throw new PlatformUnsupportedFunction("exit");
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
getEnv(key) {
|
|
779
|
+
switch (this.env) {
|
|
780
|
+
case "node":
|
|
781
|
+
return process.env[key];
|
|
782
|
+
default: {
|
|
783
|
+
const g = globalThis;
|
|
784
|
+
if (g.__ENV__ && typeof g.__ENV__ === "object") return g.__ENV__[key];
|
|
785
|
+
if (typeof process !== "undefined" && process.env)
|
|
786
|
+
return process.env[key];
|
|
787
|
+
if (g.env && typeof g.env === "object") return g.env[key];
|
|
788
|
+
return void 0;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
hasAsyncLocalStorage() {
|
|
793
|
+
switch (this.env) {
|
|
794
|
+
case "node":
|
|
795
|
+
return true;
|
|
796
|
+
// We'll try native, else polyfill
|
|
797
|
+
case "browser":
|
|
798
|
+
default:
|
|
799
|
+
return false;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
createAsyncLocalStorage() {
|
|
803
|
+
switch (this.env) {
|
|
804
|
+
case "node": {
|
|
805
|
+
let instance;
|
|
806
|
+
const get = () => {
|
|
807
|
+
if (!instance) {
|
|
808
|
+
if (!this.nodeALSClass) {
|
|
809
|
+
throw new PlatformUnsupportedFunction(
|
|
810
|
+
"createAsyncLocalStorage: Platform not initialized"
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
instance = new this.nodeALSClass();
|
|
814
|
+
}
|
|
815
|
+
return instance;
|
|
816
|
+
};
|
|
817
|
+
return {
|
|
818
|
+
getStore: () => get().getStore(),
|
|
819
|
+
run: (store2, callback) => get().run(store2, callback)
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
case "browser":
|
|
823
|
+
default:
|
|
824
|
+
return {
|
|
825
|
+
getStore: () => {
|
|
826
|
+
throw new PlatformUnsupportedFunction("createAsyncLocalStorage");
|
|
827
|
+
},
|
|
828
|
+
run: () => {
|
|
829
|
+
throw new PlatformUnsupportedFunction("createAsyncLocalStorage");
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
var platformInstance = null;
|
|
836
|
+
function getPlatform() {
|
|
837
|
+
if (!platformInstance) {
|
|
838
|
+
const env = detectEnvironment();
|
|
839
|
+
platformInstance = new PlatformAdapter(env);
|
|
840
|
+
}
|
|
841
|
+
return platformInstance;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// src/globals/middleware/requireContext.middleware.ts
|
|
845
|
+
var requireContextTaskMiddleware = defineTaskMiddleware({
|
|
846
|
+
id: "globals.middleware.requireContext",
|
|
847
|
+
async run({ task, next }, deps, config) {
|
|
848
|
+
if (!config.context) {
|
|
849
|
+
throw new Error(
|
|
850
|
+
"Context not available. Did you forget to pass 'context' to the middleware?"
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
config.context.use();
|
|
854
|
+
return next(task?.input);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
// src/context.ts
|
|
859
|
+
var platform = getPlatform();
|
|
860
|
+
var storage = platform.createAsyncLocalStorage();
|
|
861
|
+
function getCurrentStore() {
|
|
862
|
+
return storage.getStore();
|
|
863
|
+
}
|
|
864
|
+
function createContext(name = "runner.context") {
|
|
865
|
+
if (!platform.hasAsyncLocalStorage()) {
|
|
866
|
+
throw new PlatformUnsupportedFunction(
|
|
867
|
+
`createAsyncLocalStorage: Cannot create context ${name}: no async storage available in this environment`
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
const ctxId = Symbol(name);
|
|
871
|
+
const use = () => {
|
|
872
|
+
const store2 = getCurrentStore();
|
|
873
|
+
if (!store2 || !store2.has(ctxId)) {
|
|
874
|
+
throw new ContextError(
|
|
875
|
+
`Context not available for symbol ${ctxId.toString()}`
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
return store2.get(ctxId);
|
|
879
|
+
};
|
|
880
|
+
const provide = (value, fn) => {
|
|
881
|
+
const currentStore = getCurrentStore();
|
|
882
|
+
const map = currentStore ? new Map(currentStore) : /* @__PURE__ */ new Map();
|
|
883
|
+
map.set(ctxId, value);
|
|
884
|
+
return storage.run(map, fn);
|
|
885
|
+
};
|
|
886
|
+
const api = {
|
|
887
|
+
id: ctxId,
|
|
888
|
+
use,
|
|
889
|
+
provide,
|
|
890
|
+
require() {
|
|
891
|
+
return requireContextTaskMiddleware.with({ context: api });
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
return api;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// src/globals/resources/debug/debug.tag.ts
|
|
898
|
+
var debugTag = defineTag({
|
|
899
|
+
id: "globals.tags.debug",
|
|
900
|
+
meta: {
|
|
901
|
+
title: "Debug",
|
|
902
|
+
description: "Debug-specific tags. Used for filtering out noise when you're focusing on your application."
|
|
903
|
+
}
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
// src/globals/globalTags.ts
|
|
907
|
+
var globalTags = {
|
|
908
|
+
system: defineTag({
|
|
909
|
+
id: "globals.tags.system",
|
|
910
|
+
meta: {
|
|
911
|
+
title: "System",
|
|
912
|
+
description: "System-wide tags. Used for filtering out noise when you're focusing on your application."
|
|
913
|
+
}
|
|
914
|
+
}),
|
|
915
|
+
excludeFromGlobalHooks: defineTag({
|
|
916
|
+
id: "globals.tags.excludeFromGlobalHooks",
|
|
917
|
+
meta: {
|
|
918
|
+
title: "Exclude Event From Global Hooks",
|
|
919
|
+
description: "Marks events that should not be dispatched to global hooks (on: '*')."
|
|
920
|
+
}
|
|
921
|
+
}),
|
|
922
|
+
debug: debugTag
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
// src/globals/globalEvents.ts
|
|
926
|
+
var systemTag = globalTags.system;
|
|
927
|
+
var globalEvents = {
|
|
928
|
+
// Minimal core events retained if any (custom events can still be defined by users)
|
|
929
|
+
/**
|
|
930
|
+
* Emitted when the system is fully initialized and ready for work.
|
|
931
|
+
*/
|
|
932
|
+
ready: defineEvent({
|
|
933
|
+
id: "globals.events.ready",
|
|
934
|
+
meta: {
|
|
935
|
+
title: "System Ready",
|
|
936
|
+
description: "Emitted when the system has completed boot and is ready for listeners to start work.This runs right before returning value for run()."
|
|
937
|
+
}
|
|
938
|
+
}),
|
|
939
|
+
/**
|
|
940
|
+
* Central error boundary event for any thrown error across the runner.
|
|
941
|
+
*/
|
|
942
|
+
unhandledError: defineEvent({
|
|
943
|
+
id: "globals.events.unhandledError",
|
|
944
|
+
meta: {
|
|
945
|
+
title: "Unhandled Error",
|
|
946
|
+
description: "Central error boundary event for any thrown error across the runner."
|
|
947
|
+
},
|
|
948
|
+
tags: [systemTag, globalTags.excludeFromGlobalHooks]
|
|
949
|
+
})
|
|
950
|
+
};
|
|
951
|
+
var globalEventsArray = [globalEvents.ready];
|
|
952
|
+
|
|
953
|
+
// src/models/Queue.ts
|
|
954
|
+
var Queue = class {
|
|
955
|
+
constructor() {
|
|
956
|
+
this.tail = Promise.resolve();
|
|
957
|
+
this.disposed = false;
|
|
958
|
+
this.abortController = new AbortController();
|
|
959
|
+
// true while inside a queued task → helps detect "queue in queue"
|
|
960
|
+
this.executionContext = getPlatform().createAsyncLocalStorage();
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Schedule an asynchronous task.
|
|
964
|
+
* @param task – receives an AbortSignal so it can cancel early if desired.
|
|
965
|
+
*/
|
|
966
|
+
run(task) {
|
|
967
|
+
if (this.disposed) {
|
|
968
|
+
return Promise.reject(new Error("Queue has been disposed"));
|
|
969
|
+
}
|
|
970
|
+
if (this.executionContext.getStore()) {
|
|
971
|
+
return Promise.reject(
|
|
972
|
+
new Error(
|
|
973
|
+
"Dead\u2011lock detected: a queued task attempted to queue another task"
|
|
974
|
+
)
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
const { signal } = this.abortController;
|
|
978
|
+
const result = this.tail.then(
|
|
979
|
+
() => this.executionContext.run(true, () => task(signal))
|
|
980
|
+
);
|
|
981
|
+
this.tail = result.catch(() => {
|
|
982
|
+
});
|
|
983
|
+
return result;
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Disposes the queue.
|
|
987
|
+
* @param options.cancel – if true, broadcasts AbortSignal to running task.
|
|
988
|
+
* default: false (waits for tasks to finish).
|
|
989
|
+
*/
|
|
990
|
+
async dispose(options = {}) {
|
|
991
|
+
if (this.disposed) return;
|
|
992
|
+
this.disposed = true;
|
|
993
|
+
if (options.cancel) {
|
|
994
|
+
this.abortController.abort();
|
|
995
|
+
}
|
|
996
|
+
await this.tail.catch(() => {
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
|
|
1001
|
+
// src/globals/resources/queue.resource.ts
|
|
1002
|
+
var queueResource = defineResource({
|
|
1003
|
+
id: "globals.resources.queue",
|
|
1004
|
+
context: () => ({
|
|
1005
|
+
map: /* @__PURE__ */ new Map()
|
|
1006
|
+
}),
|
|
1007
|
+
init: async (_, deps, context) => {
|
|
1008
|
+
const map = context.map;
|
|
1009
|
+
return {
|
|
1010
|
+
map,
|
|
1011
|
+
run: (id2, task) => {
|
|
1012
|
+
if (!map.has(id2)) {
|
|
1013
|
+
map.set(id2, new Queue());
|
|
1014
|
+
}
|
|
1015
|
+
return map.get(id2).run(task);
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
},
|
|
1019
|
+
dispose: async (value, _, deps, context) => {
|
|
1020
|
+
context.map.forEach((queue) => queue.dispose());
|
|
1021
|
+
},
|
|
1022
|
+
meta: {
|
|
1023
|
+
title: "Queue Map",
|
|
1024
|
+
description: "A global map that can be used to store and retrieve queues. You can run exclusive tasks based on using an id. queue.run(id, task) will run the task in the queue with the given id. If the queue does not exist, it will be created."
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
// src/globals/globalResources.ts
|
|
1029
|
+
var systemTag2 = globalTags.system;
|
|
1030
|
+
var store = defineResource({
|
|
1031
|
+
id: "globals.resources.store",
|
|
1032
|
+
meta: {
|
|
1033
|
+
title: "Store",
|
|
1034
|
+
description: "A global store that can be used to store and retrieve tasks, resources, events and middleware"
|
|
1035
|
+
},
|
|
1036
|
+
tags: [systemTag2]
|
|
1037
|
+
});
|
|
1038
|
+
var globalResources = {
|
|
1039
|
+
store,
|
|
1040
|
+
middlewareManager: defineResource({
|
|
1041
|
+
id: "globals.resources.middlewareManager",
|
|
1042
|
+
meta: {
|
|
1043
|
+
title: "Middleware Manager",
|
|
1044
|
+
description: "Manages all middleware and middleware interceptors."
|
|
1045
|
+
},
|
|
1046
|
+
tags: [systemTag2]
|
|
1047
|
+
}),
|
|
1048
|
+
eventManager: defineResource({
|
|
1049
|
+
id: "globals.resources.eventManager",
|
|
1050
|
+
meta: {
|
|
1051
|
+
title: "Event Manager",
|
|
1052
|
+
description: "Manages all events and event listeners. This is meant to be used internally for most use-cases."
|
|
1053
|
+
},
|
|
1054
|
+
tags: [systemTag2]
|
|
1055
|
+
}),
|
|
1056
|
+
taskRunner: defineResource({
|
|
1057
|
+
id: "globals.resources.taskRunner",
|
|
1058
|
+
meta: {
|
|
1059
|
+
title: "Task Runner",
|
|
1060
|
+
description: "Manages the execution of tasks and task dependencies. This is meant to be used internally for most use-cases."
|
|
1061
|
+
},
|
|
1062
|
+
tags: [systemTag2]
|
|
1063
|
+
}),
|
|
1064
|
+
logger: defineResource({
|
|
1065
|
+
id: "globals.resources.logger",
|
|
1066
|
+
meta: {
|
|
1067
|
+
// We skip system tag for logger because it's part of the utility toolkit.
|
|
1068
|
+
title: "Logger",
|
|
1069
|
+
description: "Logs all events and errors. This is meant to be used internally for most use-cases. Emits a globals.log event for each log."
|
|
1070
|
+
},
|
|
1071
|
+
tags: [systemTag2]
|
|
1072
|
+
}),
|
|
1073
|
+
cache: cacheResource,
|
|
1074
|
+
queue: queueResource
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1077
|
+
// src/globals/middleware/retry.middleware.ts
|
|
1078
|
+
var retryTaskMiddleware = defineTaskMiddleware({
|
|
1079
|
+
id: "globals.middleware.retry.task",
|
|
1080
|
+
async run({ task, next }, deps, config) {
|
|
1081
|
+
const input = task?.input;
|
|
1082
|
+
let attempts = 0;
|
|
1083
|
+
const maxRetries = config.retries ?? 3;
|
|
1084
|
+
const shouldStop = config.stopRetryIf ?? (() => false);
|
|
1085
|
+
while (true) {
|
|
1086
|
+
try {
|
|
1087
|
+
return await next(input);
|
|
1088
|
+
} catch (error) {
|
|
1089
|
+
const err = error;
|
|
1090
|
+
if (shouldStop(err) || attempts >= maxRetries) {
|
|
1091
|
+
throw error;
|
|
1092
|
+
}
|
|
1093
|
+
const delay = config.delayStrategy ? config.delayStrategy(attempts, err) : 100 * Math.pow(2, attempts);
|
|
1094
|
+
if (delay > 0) {
|
|
1095
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1096
|
+
}
|
|
1097
|
+
attempts++;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
var retryResourceMiddleware = defineResourceMiddleware({
|
|
1103
|
+
id: "globals.middleware.retry.resource",
|
|
1104
|
+
async run({ resource, next }, deps, config) {
|
|
1105
|
+
const input = resource?.config;
|
|
1106
|
+
let attempts = 0;
|
|
1107
|
+
const maxRetries = config.retries ?? 3;
|
|
1108
|
+
const shouldStop = config.stopRetryIf ?? (() => false);
|
|
1109
|
+
while (true) {
|
|
1110
|
+
try {
|
|
1111
|
+
return await next(input);
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
const err = error;
|
|
1114
|
+
if (shouldStop(err) || attempts >= maxRetries) {
|
|
1115
|
+
throw error;
|
|
1116
|
+
}
|
|
1117
|
+
const delay = config.delayStrategy ? config.delayStrategy(attempts, err) : 100 * Math.pow(2, attempts);
|
|
1118
|
+
if (delay > 0) {
|
|
1119
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1120
|
+
}
|
|
1121
|
+
attempts++;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
// src/globals/middleware/timeout.middleware.ts
|
|
1128
|
+
var timeoutTaskMiddleware = defineTaskMiddleware({
|
|
1129
|
+
id: "globals.middleware.timeout.task",
|
|
1130
|
+
async run({ task, next }, _deps, config) {
|
|
1131
|
+
const input = task?.input;
|
|
1132
|
+
const ttl = Math.max(0, config.ttl);
|
|
1133
|
+
const message = `Operation timed out after ${ttl}ms`;
|
|
1134
|
+
if (ttl === 0) {
|
|
1135
|
+
const error = new Error(message);
|
|
1136
|
+
error.name = "TimeoutError";
|
|
1137
|
+
throw error;
|
|
1138
|
+
}
|
|
1139
|
+
const controller = new AbortController();
|
|
1140
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1141
|
+
const timeoutId = setTimeout(() => {
|
|
1142
|
+
controller.abort();
|
|
1143
|
+
const error = new Error(message);
|
|
1144
|
+
error.name = "TimeoutError";
|
|
1145
|
+
reject(error);
|
|
1146
|
+
}, ttl);
|
|
1147
|
+
controller.signal.addEventListener("abort", () => {
|
|
1148
|
+
clearTimeout(timeoutId);
|
|
1149
|
+
});
|
|
1150
|
+
});
|
|
1151
|
+
return Promise.race([next(input), timeoutPromise]);
|
|
1152
|
+
}
|
|
1153
|
+
});
|
|
1154
|
+
var timeoutResourceMiddleware = defineResourceMiddleware({
|
|
1155
|
+
id: "globals.middleware.timeout.resource",
|
|
1156
|
+
async run({ resource, next }, _deps, config) {
|
|
1157
|
+
const input = resource?.config;
|
|
1158
|
+
const ttl = Math.max(0, config.ttl);
|
|
1159
|
+
const message = `Operation timed out after ${ttl}ms`;
|
|
1160
|
+
if (ttl === 0) {
|
|
1161
|
+
const error = new Error(message);
|
|
1162
|
+
error.name = "TimeoutError";
|
|
1163
|
+
throw error;
|
|
1164
|
+
}
|
|
1165
|
+
const controller = new AbortController();
|
|
1166
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1167
|
+
const timeoutId = setTimeout(() => {
|
|
1168
|
+
controller.abort();
|
|
1169
|
+
const error = new Error(message);
|
|
1170
|
+
error.name = "TimeoutError";
|
|
1171
|
+
reject(error);
|
|
1172
|
+
}, ttl);
|
|
1173
|
+
controller.signal.addEventListener("abort", () => {
|
|
1174
|
+
clearTimeout(timeoutId);
|
|
1175
|
+
});
|
|
1176
|
+
});
|
|
1177
|
+
return Promise.race([next(input), timeoutPromise]);
|
|
1178
|
+
}
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
// src/globals/globalMiddleware.ts
|
|
1182
|
+
var globalMiddlewares = {
|
|
1183
|
+
requireContext: requireContextTaskMiddleware,
|
|
1184
|
+
task: {
|
|
1185
|
+
requireContext: requireContextTaskMiddleware,
|
|
1186
|
+
cache: cacheMiddleware,
|
|
1187
|
+
// common with resources
|
|
1188
|
+
retry: retryTaskMiddleware,
|
|
1189
|
+
timeout: timeoutTaskMiddleware
|
|
1190
|
+
},
|
|
1191
|
+
resource: {
|
|
1192
|
+
retry: retryResourceMiddleware,
|
|
1193
|
+
timeout: timeoutResourceMiddleware
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
// src/models/TaskRunner.ts
|
|
1198
|
+
var TaskRunner = class {
|
|
1199
|
+
constructor(store2, eventManager, logger) {
|
|
1200
|
+
this.store = store2;
|
|
1201
|
+
this.eventManager = eventManager;
|
|
1202
|
+
this.logger = logger;
|
|
1203
|
+
this.runnerStore = /* @__PURE__ */ new Map();
|
|
1204
|
+
this.middlewareManager = this.store.getMiddlewareManager();
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Begins the execution of an task. These are registered tasks and all sanity checks have been performed at this stage to ensure consistency of the object.
|
|
1208
|
+
* This function can throw only if any of the event listeners or run function throws
|
|
1209
|
+
* @param task the task to be run
|
|
1210
|
+
* @param input the input to be passed to the task
|
|
1211
|
+
*/
|
|
1212
|
+
async run(task, input) {
|
|
1213
|
+
let runner = this.runnerStore.get(task.id);
|
|
1214
|
+
if (!runner) {
|
|
1215
|
+
runner = this.createRunnerWithMiddleware(task);
|
|
1216
|
+
this.runnerStore.set(task.id, runner);
|
|
1217
|
+
}
|
|
1218
|
+
try {
|
|
1219
|
+
return await runner(input);
|
|
1220
|
+
} catch (error) {
|
|
1221
|
+
try {
|
|
1222
|
+
await this.store.onUnhandledError({
|
|
1223
|
+
error,
|
|
1224
|
+
kind: "task",
|
|
1225
|
+
source: task.id
|
|
1226
|
+
});
|
|
1227
|
+
} catch (_) {
|
|
1228
|
+
}
|
|
1229
|
+
throw error;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Creates the function with the chain of middleware.
|
|
1234
|
+
* @param task
|
|
1235
|
+
* @param input
|
|
1236
|
+
* @param taskDependencies
|
|
1237
|
+
* @returns
|
|
1238
|
+
*/
|
|
1239
|
+
createRunnerWithMiddleware(task) {
|
|
1240
|
+
return this.middlewareManager.composeTaskRunner(task);
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
// src/models/MiddlewareManager.ts
|
|
1245
|
+
var _isLocked;
|
|
1246
|
+
var MiddlewareManager = class {
|
|
1247
|
+
constructor(store2, eventManager, logger) {
|
|
1248
|
+
this.store = store2;
|
|
1249
|
+
this.eventManager = eventManager;
|
|
1250
|
+
this.logger = logger;
|
|
1251
|
+
// Interceptor storage
|
|
1252
|
+
this.taskMiddlewareInterceptors = [];
|
|
1253
|
+
this.resourceMiddlewareInterceptors = [];
|
|
1254
|
+
// Per-middleware interceptor storage
|
|
1255
|
+
this.perMiddlewareInterceptors = /* @__PURE__ */ new Map();
|
|
1256
|
+
this.perResourceMiddlewareInterceptors = /* @__PURE__ */ new Map();
|
|
1257
|
+
// Locking mechanism to prevent modifications after initialization
|
|
1258
|
+
__privateAdd(this, _isLocked, false);
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Gets the current lock status of the MiddlewareManager
|
|
1262
|
+
*/
|
|
1263
|
+
get isLocked() {
|
|
1264
|
+
return __privateGet(this, _isLocked);
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Locks the MiddlewareManager, preventing any further modifications to interceptors
|
|
1268
|
+
*/
|
|
1269
|
+
lock() {
|
|
1270
|
+
__privateSet(this, _isLocked, true);
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Throws an error if the MiddlewareManager is locked
|
|
1274
|
+
*/
|
|
1275
|
+
checkLock() {
|
|
1276
|
+
if (__privateGet(this, _isLocked)) {
|
|
1277
|
+
throw new LockedError("MiddlewareManager");
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Adds an interceptor for task or resource middleware execution
|
|
1282
|
+
* Interceptors are executed in the order they are added, with the ability to
|
|
1283
|
+
* modify, log, or prevent middleware execution
|
|
1284
|
+
*
|
|
1285
|
+
* @param kind - The type of middleware to intercept ("task" or "resource")
|
|
1286
|
+
* @param interceptor - The interceptor function to add
|
|
1287
|
+
*/
|
|
1288
|
+
intercept(kind, interceptor) {
|
|
1289
|
+
this.checkLock();
|
|
1290
|
+
if (kind === "task") {
|
|
1291
|
+
this.taskMiddlewareInterceptors.push(
|
|
1292
|
+
interceptor
|
|
1293
|
+
);
|
|
1294
|
+
} else {
|
|
1295
|
+
this.resourceMiddlewareInterceptors.push(
|
|
1296
|
+
interceptor
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Adds an interceptor for a specific middleware instance with better type safety
|
|
1302
|
+
* This method automatically determines the type and provides type-safe access
|
|
1303
|
+
*
|
|
1304
|
+
* @param middleware - The middleware instance to intercept
|
|
1305
|
+
* @param interceptor - The interceptor function with proper typing
|
|
1306
|
+
*/
|
|
1307
|
+
interceptMiddleware(middleware, interceptor) {
|
|
1308
|
+
this.checkLock();
|
|
1309
|
+
if (isTaskMiddleware(middleware)) {
|
|
1310
|
+
if (!this.perMiddlewareInterceptors.has(middleware.id)) {
|
|
1311
|
+
this.perMiddlewareInterceptors.set(middleware.id, []);
|
|
1312
|
+
}
|
|
1313
|
+
this.perMiddlewareInterceptors.get(middleware.id).push(interceptor);
|
|
1314
|
+
} else if (isResourceMiddleware(middleware)) {
|
|
1315
|
+
if (!this.perResourceMiddlewareInterceptors.has(middleware.id)) {
|
|
1316
|
+
this.perResourceMiddlewareInterceptors.set(middleware.id, []);
|
|
1317
|
+
}
|
|
1318
|
+
this.perResourceMiddlewareInterceptors.get(middleware.id).push(interceptor);
|
|
1319
|
+
} else {
|
|
1320
|
+
throw new Error("Unknown middleware type");
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Wrap a middleware with its specific interceptors in onion style
|
|
1325
|
+
*/
|
|
1326
|
+
wrapMiddlewareWithInterceptors(middleware, middlewareRunner, interceptors) {
|
|
1327
|
+
if (!interceptors.length) {
|
|
1328
|
+
return middlewareRunner;
|
|
1329
|
+
}
|
|
1330
|
+
const reversedInterceptors = [...interceptors].reverse();
|
|
1331
|
+
let wrapped = middlewareRunner;
|
|
1332
|
+
for (let i = reversedInterceptors.length - 1; i >= 0; i--) {
|
|
1333
|
+
const interceptor = reversedInterceptors[i];
|
|
1334
|
+
const nextFunction = wrapped;
|
|
1335
|
+
wrapped = async (input) => {
|
|
1336
|
+
const executionInput = {
|
|
1337
|
+
task: {
|
|
1338
|
+
definition: null,
|
|
1339
|
+
// Will be filled by middleware.run
|
|
1340
|
+
input
|
|
1341
|
+
},
|
|
1342
|
+
next: nextFunction
|
|
1343
|
+
};
|
|
1344
|
+
const wrappedNext = (i2) => {
|
|
1345
|
+
return nextFunction(i2.task.input);
|
|
1346
|
+
};
|
|
1347
|
+
return interceptor(wrappedNext, executionInput);
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
return wrapped;
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Wrap a resource middleware with its specific interceptors in onion style
|
|
1354
|
+
*/
|
|
1355
|
+
wrapResourceMiddlewareWithInterceptors(middleware, middlewareRunner, interceptors) {
|
|
1356
|
+
if (!interceptors.length) {
|
|
1357
|
+
return middlewareRunner;
|
|
1358
|
+
}
|
|
1359
|
+
const reversedInterceptors = [...interceptors].reverse();
|
|
1360
|
+
let wrapped = middlewareRunner;
|
|
1361
|
+
for (let i = reversedInterceptors.length - 1; i >= 0; i--) {
|
|
1362
|
+
const interceptor = reversedInterceptors[i];
|
|
1363
|
+
const nextFunction = wrapped;
|
|
1364
|
+
wrapped = async (config) => {
|
|
1365
|
+
const executionInput = {
|
|
1366
|
+
resource: {
|
|
1367
|
+
definition: null,
|
|
1368
|
+
// Will be filled by middleware.run
|
|
1369
|
+
config
|
|
1370
|
+
},
|
|
1371
|
+
next: nextFunction
|
|
1372
|
+
};
|
|
1373
|
+
const wrappedNext = (input) => {
|
|
1374
|
+
return nextFunction(input.resource.config);
|
|
1375
|
+
};
|
|
1376
|
+
return interceptor(wrappedNext, executionInput);
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
return wrapped;
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Compose a runner for a task with its local interceptors and applicable middlewares.
|
|
1383
|
+
* Returns a function that accepts the task input and resolves to the task output.
|
|
1384
|
+
*/
|
|
1385
|
+
composeTaskRunner(task) {
|
|
1386
|
+
const storeTask = this.store.tasks.get(task.id);
|
|
1387
|
+
let next = async (input) => {
|
|
1388
|
+
let rawInput = input;
|
|
1389
|
+
if (task.inputSchema) {
|
|
1390
|
+
try {
|
|
1391
|
+
rawInput = task.inputSchema.parse(rawInput);
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
throw new ValidationError(
|
|
1394
|
+
"Task input",
|
|
1395
|
+
task.id,
|
|
1396
|
+
error instanceof Error ? error : new Error(String(error))
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
const deps = storeTask.computedDependencies;
|
|
1401
|
+
const rawResult = await task.run.call(null, rawInput, deps);
|
|
1402
|
+
if (task.resultSchema) {
|
|
1403
|
+
try {
|
|
1404
|
+
return task.resultSchema.parse(rawResult);
|
|
1405
|
+
} catch (error) {
|
|
1406
|
+
throw new ValidationError("Task result", task.id, error);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
return rawResult;
|
|
1410
|
+
};
|
|
1411
|
+
if (storeTask.interceptors && storeTask.interceptors.length > 0) {
|
|
1412
|
+
for (let i = storeTask.interceptors.length - 1; i >= 0; i--) {
|
|
1413
|
+
const interceptor = storeTask.interceptors[i];
|
|
1414
|
+
const nextFunction = next;
|
|
1415
|
+
next = async (input) => interceptor(nextFunction, input);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
if (this.taskMiddlewareInterceptors.length > 0) {
|
|
1419
|
+
const reversedInterceptors = [
|
|
1420
|
+
...this.taskMiddlewareInterceptors
|
|
1421
|
+
].reverse();
|
|
1422
|
+
const createExecutionInput = (input, nextFunc) => ({
|
|
1423
|
+
task: {
|
|
1424
|
+
definition: task,
|
|
1425
|
+
input
|
|
1426
|
+
},
|
|
1427
|
+
next: nextFunc
|
|
1428
|
+
});
|
|
1429
|
+
let currentNext = next;
|
|
1430
|
+
for (let i = reversedInterceptors.length - 1; i >= 0; i--) {
|
|
1431
|
+
const interceptor = reversedInterceptors[i];
|
|
1432
|
+
const nextFunction = currentNext;
|
|
1433
|
+
currentNext = async (input) => {
|
|
1434
|
+
const executionInput = createExecutionInput(input, nextFunction);
|
|
1435
|
+
const wrappedNext = (i2) => {
|
|
1436
|
+
return nextFunction(i2.task.input);
|
|
1437
|
+
};
|
|
1438
|
+
return interceptor(wrappedNext, executionInput);
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
next = currentNext;
|
|
1442
|
+
}
|
|
1443
|
+
const createdMiddlewares = this.getApplicableTaskMiddlewares(task);
|
|
1444
|
+
if (createdMiddlewares.length === 0) {
|
|
1445
|
+
return next;
|
|
1446
|
+
}
|
|
1447
|
+
for (let i = createdMiddlewares.length - 1; i >= 0; i--) {
|
|
1448
|
+
const middleware = createdMiddlewares[i];
|
|
1449
|
+
const storeMiddleware = this.store.taskMiddlewares.get(middleware.id);
|
|
1450
|
+
const nextFunction = next;
|
|
1451
|
+
const baseMiddlewareRunner = async (input) => {
|
|
1452
|
+
return storeMiddleware.middleware.run(
|
|
1453
|
+
{
|
|
1454
|
+
task: {
|
|
1455
|
+
definition: task,
|
|
1456
|
+
input
|
|
1457
|
+
},
|
|
1458
|
+
next: nextFunction
|
|
1459
|
+
},
|
|
1460
|
+
storeMiddleware.computedDependencies,
|
|
1461
|
+
middleware.config
|
|
1462
|
+
);
|
|
1463
|
+
};
|
|
1464
|
+
const middlewareInterceptors = this.perMiddlewareInterceptors.get(middleware.id) || [];
|
|
1465
|
+
const wrappedMiddleware = this.wrapMiddlewareWithInterceptors(
|
|
1466
|
+
middleware,
|
|
1467
|
+
baseMiddlewareRunner,
|
|
1468
|
+
middlewareInterceptors
|
|
1469
|
+
);
|
|
1470
|
+
next = wrappedMiddleware;
|
|
1471
|
+
}
|
|
1472
|
+
return next;
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Run a resource init wrapped with its applicable middlewares.
|
|
1476
|
+
*/
|
|
1477
|
+
async runResourceInit(resource, config, dependencies, context) {
|
|
1478
|
+
let next = async (cfg) => {
|
|
1479
|
+
if (!resource.init) return void 0;
|
|
1480
|
+
const rawValue = await resource.init.call(
|
|
1481
|
+
null,
|
|
1482
|
+
cfg,
|
|
1483
|
+
dependencies,
|
|
1484
|
+
context
|
|
1485
|
+
);
|
|
1486
|
+
if (resource.resultSchema) {
|
|
1487
|
+
try {
|
|
1488
|
+
return resource.resultSchema.parse(rawValue);
|
|
1489
|
+
} catch (error) {
|
|
1490
|
+
throw new ValidationError(
|
|
1491
|
+
"Resource result",
|
|
1492
|
+
resource.id,
|
|
1493
|
+
error
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
return rawValue;
|
|
1498
|
+
};
|
|
1499
|
+
const createdMiddlewares = this.getApplicableResourceMiddlewares(resource);
|
|
1500
|
+
for (let i = createdMiddlewares.length - 1; i >= 0; i--) {
|
|
1501
|
+
const middleware = createdMiddlewares[i];
|
|
1502
|
+
const storeMiddleware = this.store.resourceMiddlewares.get(
|
|
1503
|
+
middleware.id
|
|
1504
|
+
);
|
|
1505
|
+
const nextFunction = next;
|
|
1506
|
+
const baseMiddlewareRunner = async (cfg) => {
|
|
1507
|
+
try {
|
|
1508
|
+
const result = await storeMiddleware.middleware.run(
|
|
1509
|
+
{
|
|
1510
|
+
resource: {
|
|
1511
|
+
definition: resource,
|
|
1512
|
+
config: cfg
|
|
1513
|
+
},
|
|
1514
|
+
next: nextFunction
|
|
1515
|
+
},
|
|
1516
|
+
storeMiddleware.computedDependencies,
|
|
1517
|
+
middleware.config
|
|
1518
|
+
);
|
|
1519
|
+
return result;
|
|
1520
|
+
} catch (error) {
|
|
1521
|
+
try {
|
|
1522
|
+
await this.store.onUnhandledError({
|
|
1523
|
+
error,
|
|
1524
|
+
kind: "resourceInit",
|
|
1525
|
+
source: resource.id
|
|
1526
|
+
});
|
|
1527
|
+
} catch (_) {
|
|
1528
|
+
}
|
|
1529
|
+
throw error;
|
|
1530
|
+
}
|
|
1531
|
+
};
|
|
1532
|
+
const middlewareInterceptors = this.perResourceMiddlewareInterceptors.get(middleware.id) || [];
|
|
1533
|
+
const wrappedMiddleware = this.wrapResourceMiddlewareWithInterceptors(
|
|
1534
|
+
middleware,
|
|
1535
|
+
baseMiddlewareRunner,
|
|
1536
|
+
middlewareInterceptors
|
|
1537
|
+
);
|
|
1538
|
+
next = wrappedMiddleware;
|
|
1539
|
+
}
|
|
1540
|
+
if (this.resourceMiddlewareInterceptors.length > 0) {
|
|
1541
|
+
const reversedInterceptors = [
|
|
1542
|
+
...this.resourceMiddlewareInterceptors
|
|
1543
|
+
].reverse();
|
|
1544
|
+
const createExecutionInput = (config2, nextFunc) => ({
|
|
1545
|
+
resource: {
|
|
1546
|
+
definition: resource,
|
|
1547
|
+
config: config2
|
|
1548
|
+
},
|
|
1549
|
+
next: nextFunc
|
|
1550
|
+
});
|
|
1551
|
+
let currentNext = next;
|
|
1552
|
+
for (let i = reversedInterceptors.length - 1; i >= 0; i--) {
|
|
1553
|
+
const interceptor = reversedInterceptors[i];
|
|
1554
|
+
const nextFunction = currentNext;
|
|
1555
|
+
currentNext = async (cfg) => {
|
|
1556
|
+
const executionInput = createExecutionInput(cfg, nextFunction);
|
|
1557
|
+
const wrappedNext = (input) => {
|
|
1558
|
+
return nextFunction(input.resource.config);
|
|
1559
|
+
};
|
|
1560
|
+
return interceptor(wrappedNext, executionInput);
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
next = currentNext;
|
|
1564
|
+
}
|
|
1565
|
+
return next(config);
|
|
1566
|
+
}
|
|
1567
|
+
getApplicableTaskMiddlewares(task) {
|
|
1568
|
+
const existingMiddlewares = task.middleware;
|
|
1569
|
+
const existingMiddlewareIds = existingMiddlewares.map((x) => x.id);
|
|
1570
|
+
const globalMiddlewares2 = this.getEverywhereMiddlewareForTasks(task).filter(
|
|
1571
|
+
(x) => !existingMiddlewareIds.includes(x.id)
|
|
1572
|
+
);
|
|
1573
|
+
return [...globalMiddlewares2, ...existingMiddlewares];
|
|
1574
|
+
}
|
|
1575
|
+
getApplicableResourceMiddlewares(resource) {
|
|
1576
|
+
const existingMiddlewares = resource.middleware;
|
|
1577
|
+
const existingMiddlewareIds = existingMiddlewares.map((x) => x.id);
|
|
1578
|
+
const globalMiddlewares2 = this.getEverywhereMiddlewareForResources(
|
|
1579
|
+
resource
|
|
1580
|
+
).filter((x) => !existingMiddlewareIds.includes(x.id));
|
|
1581
|
+
return [...globalMiddlewares2, ...existingMiddlewares];
|
|
1582
|
+
}
|
|
1583
|
+
/**
|
|
1584
|
+
* @param task
|
|
1585
|
+
* @returns
|
|
1586
|
+
*/
|
|
1587
|
+
getEverywhereMiddlewareForTasks(task) {
|
|
1588
|
+
return Array.from(this.store.taskMiddlewares.values()).filter((x) => Boolean(x.middleware.everywhere)).filter((x) => {
|
|
1589
|
+
if (typeof x.middleware.everywhere === "function") {
|
|
1590
|
+
return x.middleware.everywhere(task);
|
|
1591
|
+
}
|
|
1592
|
+
return true;
|
|
1593
|
+
}).map((x) => x.middleware);
|
|
1594
|
+
}
|
|
1595
|
+
/**
|
|
1596
|
+
* Returns all global middleware for resource, which do not depend on the target resource.
|
|
1597
|
+
*/
|
|
1598
|
+
getEverywhereMiddlewareForResources(target) {
|
|
1599
|
+
return Array.from(this.store.resourceMiddlewares.values()).filter((x) => Boolean(x.middleware.everywhere)).filter((x) => {
|
|
1600
|
+
if (typeof x.middleware.everywhere === "function") {
|
|
1601
|
+
return x.middleware.everywhere(target);
|
|
1602
|
+
}
|
|
1603
|
+
return true;
|
|
1604
|
+
}).map((x) => x.middleware);
|
|
1605
|
+
}
|
|
1606
|
+
};
|
|
1607
|
+
_isLocked = new WeakMap();
|
|
1608
|
+
|
|
1609
|
+
// src/models/ResourceInitializer.ts
|
|
1610
|
+
var ResourceInitializer = class {
|
|
1611
|
+
constructor(store2, eventManager, logger) {
|
|
1612
|
+
this.store = store2;
|
|
1613
|
+
this.eventManager = eventManager;
|
|
1614
|
+
this.logger = logger;
|
|
1615
|
+
this.middlewareManager = new MiddlewareManager(
|
|
1616
|
+
this.store,
|
|
1617
|
+
this.eventManager,
|
|
1618
|
+
this.logger
|
|
1619
|
+
);
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* Begins the execution of an task. These are registered tasks and all sanity checks have been performed at this stage to ensure consistency of the object.
|
|
1623
|
+
* This function can throw only if any of the event listeners or run function throws
|
|
1624
|
+
*/
|
|
1625
|
+
async initializeResource(resource, config, dependencies) {
|
|
1626
|
+
const context = resource.context?.();
|
|
1627
|
+
let value;
|
|
1628
|
+
if (!resource.init) {
|
|
1629
|
+
resource.init = (async () => void 0);
|
|
1630
|
+
}
|
|
1631
|
+
if (resource.init) {
|
|
1632
|
+
value = await this.initWithMiddleware(
|
|
1633
|
+
resource,
|
|
1634
|
+
config,
|
|
1635
|
+
dependencies,
|
|
1636
|
+
context
|
|
1637
|
+
);
|
|
1638
|
+
}
|
|
1639
|
+
return { value, context };
|
|
1640
|
+
}
|
|
1641
|
+
// Lifecycle emissions removed
|
|
1642
|
+
async initWithMiddleware(resource, config, dependencies, context) {
|
|
1643
|
+
return this.middlewareManager.runResourceInit(
|
|
1644
|
+
resource,
|
|
1645
|
+
config,
|
|
1646
|
+
dependencies,
|
|
1647
|
+
context
|
|
1648
|
+
);
|
|
1649
|
+
}
|
|
1650
|
+
};
|
|
1651
|
+
|
|
1652
|
+
// src/models/utils/safeStringify.ts
|
|
1653
|
+
function safeStringify(value, space, options) {
|
|
1654
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
1655
|
+
const holderDepth = /* @__PURE__ */ new WeakMap();
|
|
1656
|
+
const maxDepth = typeof options?.maxDepth === "number" ? options.maxDepth : Infinity;
|
|
1657
|
+
const replacer = function(_key, val) {
|
|
1658
|
+
if (typeof val === "function") {
|
|
1659
|
+
return "function()";
|
|
1660
|
+
}
|
|
1661
|
+
if (typeof val === "bigint") {
|
|
1662
|
+
return val.toString();
|
|
1663
|
+
}
|
|
1664
|
+
const holderObject = Object(this);
|
|
1665
|
+
const parentDepth = holderDepth.get(holderObject) || 0;
|
|
1666
|
+
const currentDepth = parentDepth + 1;
|
|
1667
|
+
if (typeof val === "object" && val !== null) {
|
|
1668
|
+
if (seen.has(val)) return "[Circular]";
|
|
1669
|
+
if (currentDepth > maxDepth) {
|
|
1670
|
+
return Array.isArray(val) ? "[Array]" : "[Object]";
|
|
1671
|
+
}
|
|
1672
|
+
seen.add(val);
|
|
1673
|
+
holderDepth.set(val, currentDepth);
|
|
1674
|
+
}
|
|
1675
|
+
return val;
|
|
1676
|
+
};
|
|
1677
|
+
try {
|
|
1678
|
+
return JSON.stringify(value, replacer, space);
|
|
1679
|
+
} catch {
|
|
1680
|
+
try {
|
|
1681
|
+
return String(value);
|
|
1682
|
+
} catch {
|
|
1683
|
+
return "[Unserializable]";
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
// src/models/LogPrinter.ts
|
|
1689
|
+
var ansiRegex = /[][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
|
1690
|
+
function stripAnsi(str) {
|
|
1691
|
+
return str.replace(ansiRegex, "");
|
|
1692
|
+
}
|
|
1693
|
+
var COLORS = {
|
|
1694
|
+
trace: "\x1B[90m",
|
|
1695
|
+
debug: "\x1B[36m",
|
|
1696
|
+
info: "\x1B[32m",
|
|
1697
|
+
warn: "\x1B[33m",
|
|
1698
|
+
error: "\x1B[31m",
|
|
1699
|
+
critical: "\x1B[35m",
|
|
1700
|
+
reset: "\x1B[0m",
|
|
1701
|
+
bold: "\x1B[1m",
|
|
1702
|
+
dim: "\x1B[2m",
|
|
1703
|
+
blue: "\x1B[34m",
|
|
1704
|
+
cyan: "\x1B[36m",
|
|
1705
|
+
gray: "\x1B[90m"
|
|
1706
|
+
};
|
|
1707
|
+
var ICONS = {
|
|
1708
|
+
trace: "\u25CB",
|
|
1709
|
+
debug: "\u25C6",
|
|
1710
|
+
info: "\u25CF",
|
|
1711
|
+
warn: "\u25B2",
|
|
1712
|
+
error: "\u2715",
|
|
1713
|
+
critical: "\u2588"
|
|
1714
|
+
};
|
|
1715
|
+
var _LogPrinter = class _LogPrinter {
|
|
1716
|
+
constructor(options) {
|
|
1717
|
+
this.strategy = options.strategy;
|
|
1718
|
+
if (options.strategy === "plain") {
|
|
1719
|
+
this.colors = _LogPrinter.NO_COLORS;
|
|
1720
|
+
} else {
|
|
1721
|
+
const base = options.useColors || options.colorTheme ? COLORS : _LogPrinter.NO_COLORS;
|
|
1722
|
+
this.colors = { ...base, ...options.colorTheme || {} };
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
print(log) {
|
|
1726
|
+
if (this.strategy === "json") {
|
|
1727
|
+
_LogPrinter.writers.log(safeStringify(this.normalizeForJson(log)));
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
if (this.strategy === "json_pretty") {
|
|
1731
|
+
_LogPrinter.writers.log(safeStringify(this.normalizeForJson(log), 2));
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
const { level, source, message, timestamp, error, data, context } = log;
|
|
1735
|
+
const timePart = this.formatTime(timestamp);
|
|
1736
|
+
const levelPart = this.formatLevel(level);
|
|
1737
|
+
const sourcePart = this.formatSource(source);
|
|
1738
|
+
const headerLine = [timePart, levelPart, sourcePart].filter(Boolean).join(" ");
|
|
1739
|
+
const messageString = this.formatMessage(message);
|
|
1740
|
+
const messageLines = messageString.split("\n");
|
|
1741
|
+
const output = [headerLine];
|
|
1742
|
+
const timePartLength = stripAnsi(timePart).length;
|
|
1743
|
+
const levelPartLength = stripAnsi(levelPart).length;
|
|
1744
|
+
const indentation = " ".repeat(timePartLength + 1 + levelPartLength + 1);
|
|
1745
|
+
if (message) {
|
|
1746
|
+
output.push(...messageLines.map((line) => `${indentation}${line}`));
|
|
1747
|
+
}
|
|
1748
|
+
const errorLines = this.formatError(error);
|
|
1749
|
+
const dataLines = this.formatData(data);
|
|
1750
|
+
const contextLines = this.formatContext(context);
|
|
1751
|
+
const detailsExist = errorLines.length > 0 || dataLines.length > 0 || contextLines.length > 0;
|
|
1752
|
+
if (detailsExist) {
|
|
1753
|
+
output.push("");
|
|
1754
|
+
}
|
|
1755
|
+
output.push(...errorLines, ...dataLines, ...contextLines);
|
|
1756
|
+
if (detailsExist) {
|
|
1757
|
+
output.push("");
|
|
1758
|
+
}
|
|
1759
|
+
const writer = this.pickWriter(level);
|
|
1760
|
+
output.forEach((line) => writer(line));
|
|
1761
|
+
writer("");
|
|
1762
|
+
}
|
|
1763
|
+
pickWriter(level) {
|
|
1764
|
+
const toError = level === "warn" || level === "error" || level === "critical";
|
|
1765
|
+
if (toError && typeof _LogPrinter.writers.error === "function") {
|
|
1766
|
+
return (msg) => _LogPrinter.writers.error(msg);
|
|
1767
|
+
}
|
|
1768
|
+
return (msg) => _LogPrinter.writers.log(msg);
|
|
1769
|
+
}
|
|
1770
|
+
formatTime(timestamp) {
|
|
1771
|
+
const time = timestamp.toISOString().slice(11, 19);
|
|
1772
|
+
const ms = timestamp.getMilliseconds().toString().padStart(3, "0");
|
|
1773
|
+
return `${this.colors.gray}${time}.${ms}${this.colors.reset}`;
|
|
1774
|
+
}
|
|
1775
|
+
formatLevel(level) {
|
|
1776
|
+
const color = this.colors[level] || this.colors.info;
|
|
1777
|
+
const icon = ICONS[level] || "\u25CF";
|
|
1778
|
+
const label = level.toUpperCase().padEnd(7);
|
|
1779
|
+
return `${color}${icon} ${this.colors.bold}${label}${this.colors.reset}`;
|
|
1780
|
+
}
|
|
1781
|
+
formatSource(source) {
|
|
1782
|
+
if (!source) return "";
|
|
1783
|
+
return `${this.colors.cyan}${source}${this.colors.reset}`;
|
|
1784
|
+
}
|
|
1785
|
+
formatMessage(message) {
|
|
1786
|
+
if (typeof message === "object" && message !== null) {
|
|
1787
|
+
return safeStringify(message, 2);
|
|
1788
|
+
}
|
|
1789
|
+
return String(message);
|
|
1790
|
+
}
|
|
1791
|
+
formatError(error, indentation = " ") {
|
|
1792
|
+
if (!error) return [];
|
|
1793
|
+
const lines = [];
|
|
1794
|
+
lines.push(
|
|
1795
|
+
`${indentation}${this.colors.gray}\u2570\u2500${this.colors.reset} ${this.colors.error}Error: ${error.name}: ${error.message}${this.colors.reset}`
|
|
1796
|
+
);
|
|
1797
|
+
if (error.stack) {
|
|
1798
|
+
const frames = error.stack.split("\n").slice(1);
|
|
1799
|
+
frames.forEach((frame) => {
|
|
1800
|
+
const cleaned = frame.trim().replace(/^at /, "");
|
|
1801
|
+
lines.push(
|
|
1802
|
+
`${indentation} ${this.colors.gray}\u21B3${this.colors.reset} ${this.colors.dim}${cleaned}${this.colors.reset}`
|
|
1803
|
+
);
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
return lines;
|
|
1807
|
+
}
|
|
1808
|
+
formatData(data, indentation = " ") {
|
|
1809
|
+
if (!data || Object.keys(data).length === 0) return [];
|
|
1810
|
+
const lines = [];
|
|
1811
|
+
const formatted = safeStringify(data, 2, { maxDepth: 3 }).split("\n");
|
|
1812
|
+
lines.push(
|
|
1813
|
+
`${indentation}${this.colors.gray}\u2570\u2500${this.colors.reset} ${this.colors.cyan}Data:${this.colors.reset}`
|
|
1814
|
+
);
|
|
1815
|
+
formatted.forEach((line) => {
|
|
1816
|
+
lines.push(`${indentation}${this.colors.dim}${line}${this.colors.reset}`);
|
|
1817
|
+
});
|
|
1818
|
+
return lines;
|
|
1819
|
+
}
|
|
1820
|
+
formatContext(context, indentation = " ") {
|
|
1821
|
+
if (!context) return [];
|
|
1822
|
+
const filtered = { ...context };
|
|
1823
|
+
delete filtered.source;
|
|
1824
|
+
if (Object.keys(filtered).length === 0) return [];
|
|
1825
|
+
const lines = [];
|
|
1826
|
+
const formatted = safeStringify(filtered, 2, { maxDepth: 3 }).split("\n");
|
|
1827
|
+
lines.push(
|
|
1828
|
+
`${indentation}${this.colors.gray}\u2570\u2500${this.colors.reset} ${this.colors.blue}Context:${this.colors.reset}`
|
|
1829
|
+
);
|
|
1830
|
+
formatted.forEach((line) => {
|
|
1831
|
+
lines.push(`${indentation}${this.colors.dim}${line}${this.colors.reset}`);
|
|
1832
|
+
});
|
|
1833
|
+
return lines;
|
|
1834
|
+
}
|
|
1835
|
+
normalizeForJson(log) {
|
|
1836
|
+
const normalized = { ...log };
|
|
1837
|
+
if (typeof log.message === "object") {
|
|
1838
|
+
const text = safeStringify(log.message);
|
|
1839
|
+
try {
|
|
1840
|
+
normalized.message = JSON.parse(text);
|
|
1841
|
+
} catch {
|
|
1842
|
+
normalized.message = text;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
return normalized;
|
|
1846
|
+
}
|
|
1847
|
+
static setWriters(writers) {
|
|
1848
|
+
_LogPrinter.writers = { ..._LogPrinter.writers, ...writers };
|
|
1849
|
+
}
|
|
1850
|
+
static resetWriters() {
|
|
1851
|
+
_LogPrinter.writers = {
|
|
1852
|
+
log: (msg) => console.log(msg),
|
|
1853
|
+
error: (msg) => console.error?.(msg)
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
};
|
|
1857
|
+
_LogPrinter.NO_COLORS = {
|
|
1858
|
+
trace: "",
|
|
1859
|
+
debug: "",
|
|
1860
|
+
info: "",
|
|
1861
|
+
warn: "",
|
|
1862
|
+
error: "",
|
|
1863
|
+
critical: "",
|
|
1864
|
+
reset: "",
|
|
1865
|
+
bold: "",
|
|
1866
|
+
dim: "",
|
|
1867
|
+
blue: "",
|
|
1868
|
+
cyan: "",
|
|
1869
|
+
gray: ""
|
|
1870
|
+
};
|
|
1871
|
+
_LogPrinter.writers = {
|
|
1872
|
+
// eslint-disable-next-line no-console
|
|
1873
|
+
log: (msg) => console.log(msg),
|
|
1874
|
+
// eslint-disable-next-line no-console
|
|
1875
|
+
error: (msg) => console.error?.(msg)
|
|
1876
|
+
};
|
|
1877
|
+
var LogPrinter = _LogPrinter;
|
|
1878
|
+
|
|
1879
|
+
// src/models/Logger.ts
|
|
1880
|
+
var _Logger = class _Logger {
|
|
1881
|
+
constructor(options, boundContext = {}, source, printer) {
|
|
1882
|
+
this.printThreshold = "info";
|
|
1883
|
+
this.printStrategy = "pretty";
|
|
1884
|
+
this.bufferLogs = false;
|
|
1885
|
+
this.buffer = [];
|
|
1886
|
+
this.boundContext = {};
|
|
1887
|
+
this.isLocked = false;
|
|
1888
|
+
this.useColors = true;
|
|
1889
|
+
// Observable why not?
|
|
1890
|
+
this.localListeners = [];
|
|
1891
|
+
this.boundContext = { ...boundContext };
|
|
1892
|
+
this.printThreshold = options.printThreshold;
|
|
1893
|
+
this.printStrategy = options.printStrategy;
|
|
1894
|
+
this.bufferLogs = options.bufferLogs;
|
|
1895
|
+
this.useColors = typeof options.useColors === "boolean" ? options.useColors : this.detectColorSupport();
|
|
1896
|
+
this.source = source;
|
|
1897
|
+
this.printer = printer ? printer : new LogPrinter({
|
|
1898
|
+
strategy: this.printStrategy,
|
|
1899
|
+
useColors: this.useColors
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
detectColorSupport() {
|
|
1903
|
+
const noColor = typeof process !== "undefined" && !!process.env.NO_COLOR;
|
|
1904
|
+
if (noColor) return false;
|
|
1905
|
+
const isTty = typeof process !== "undefined" && !!process.stdout && !!process.stdout.isTTY;
|
|
1906
|
+
return isTty;
|
|
1907
|
+
}
|
|
1908
|
+
/**
|
|
1909
|
+
* Creates a new logger instance with additional bound context
|
|
1910
|
+
*/
|
|
1911
|
+
with({
|
|
1912
|
+
source,
|
|
1913
|
+
additionalContext: context
|
|
1914
|
+
}) {
|
|
1915
|
+
const child = new _Logger(
|
|
1916
|
+
{
|
|
1917
|
+
printThreshold: this.printThreshold,
|
|
1918
|
+
printStrategy: this.printStrategy,
|
|
1919
|
+
bufferLogs: this.bufferLogs,
|
|
1920
|
+
useColors: this.useColors
|
|
1921
|
+
},
|
|
1922
|
+
{ ...this.boundContext, ...context },
|
|
1923
|
+
source,
|
|
1924
|
+
this.printer
|
|
1925
|
+
);
|
|
1926
|
+
child.rootLogger = this.rootLogger ?? this;
|
|
1927
|
+
return child;
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* Core logging method with structured LogInfo
|
|
1931
|
+
*/
|
|
1932
|
+
async log(level, message, logInfo = {}) {
|
|
1933
|
+
const { source, error, data, ...context } = logInfo;
|
|
1934
|
+
const log = {
|
|
1935
|
+
level,
|
|
1936
|
+
message,
|
|
1937
|
+
source: source || this.source,
|
|
1938
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1939
|
+
error: error ? this.extractErrorInfo(error) : void 0,
|
|
1940
|
+
data: data || void 0,
|
|
1941
|
+
context: { ...this.boundContext, ...context }
|
|
1942
|
+
};
|
|
1943
|
+
const root = this.rootLogger ?? this;
|
|
1944
|
+
if (root.bufferLogs) {
|
|
1945
|
+
root.buffer.push(log);
|
|
1946
|
+
return;
|
|
1947
|
+
}
|
|
1948
|
+
await root.triggerLogListeners(log);
|
|
1949
|
+
if (root.canPrint(level)) {
|
|
1950
|
+
root.printer.print(log);
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
extractErrorInfo(error) {
|
|
1954
|
+
if (error instanceof Error) {
|
|
1955
|
+
return {
|
|
1956
|
+
name: error.name,
|
|
1957
|
+
message: error.message,
|
|
1958
|
+
stack: error.stack
|
|
1959
|
+
};
|
|
1960
|
+
}
|
|
1961
|
+
return {
|
|
1962
|
+
name: "UnknownError",
|
|
1963
|
+
message: String(error)
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
async info(message, logInfo) {
|
|
1967
|
+
await this.log("info", message, logInfo);
|
|
1968
|
+
}
|
|
1969
|
+
async error(message, logInfo) {
|
|
1970
|
+
await this.log("error", message, logInfo);
|
|
1971
|
+
}
|
|
1972
|
+
async warn(message, logInfo) {
|
|
1973
|
+
await this.log("warn", message, logInfo);
|
|
1974
|
+
}
|
|
1975
|
+
async debug(message, logInfo) {
|
|
1976
|
+
await this.log("debug", message, logInfo);
|
|
1977
|
+
}
|
|
1978
|
+
async trace(message, logInfo) {
|
|
1979
|
+
await this.log("trace", message, logInfo);
|
|
1980
|
+
}
|
|
1981
|
+
async critical(message, logInfo) {
|
|
1982
|
+
await this.log("critical", message, logInfo);
|
|
1983
|
+
}
|
|
1984
|
+
/**
|
|
1985
|
+
* Direct print for tests and advanced scenarios. Delegates to LogPrinter.
|
|
1986
|
+
*/
|
|
1987
|
+
print(log) {
|
|
1988
|
+
this.printer.print(log);
|
|
1989
|
+
}
|
|
1990
|
+
/**
|
|
1991
|
+
* @param listener - A listener that will be triggered for every log.
|
|
1992
|
+
*/
|
|
1993
|
+
onLog(listener) {
|
|
1994
|
+
if (this.rootLogger && this.rootLogger !== this) {
|
|
1995
|
+
this.rootLogger.onLog(listener);
|
|
1996
|
+
} else {
|
|
1997
|
+
this.localListeners.push(listener);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
/**
|
|
2001
|
+
* Marks the logger as ready.
|
|
2002
|
+
* This is used to trigger the local listeners and print the buffered logs (if they exists)
|
|
2003
|
+
* @returns A promise that resolves when the logger is ready.
|
|
2004
|
+
*/
|
|
2005
|
+
async lock() {
|
|
2006
|
+
const root = this.rootLogger ?? this;
|
|
2007
|
+
if (root.isLocked) {
|
|
2008
|
+
return;
|
|
2009
|
+
}
|
|
2010
|
+
if (root.bufferLogs) {
|
|
2011
|
+
for (const log of root.buffer) {
|
|
2012
|
+
await root.triggerLogListeners(log);
|
|
2013
|
+
}
|
|
2014
|
+
for (const log of root.buffer) {
|
|
2015
|
+
if (root.canPrint(log.level)) {
|
|
2016
|
+
root.printer.print(log);
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
root.bufferLogs = false;
|
|
2021
|
+
root.buffer = [];
|
|
2022
|
+
root.isLocked = true;
|
|
2023
|
+
}
|
|
2024
|
+
canPrint(level) {
|
|
2025
|
+
if (this.printThreshold === null) {
|
|
2026
|
+
return false;
|
|
2027
|
+
}
|
|
2028
|
+
return this.printThreshold && _Logger.Severity[level] >= _Logger.Severity[this.printThreshold];
|
|
2029
|
+
}
|
|
2030
|
+
async triggerLogListeners(log) {
|
|
2031
|
+
if (this.rootLogger && this.rootLogger !== this) {
|
|
2032
|
+
await this.rootLogger.triggerLogListeners(log);
|
|
2033
|
+
}
|
|
2034
|
+
for (const listener of this.localListeners) {
|
|
2035
|
+
try {
|
|
2036
|
+
await listener(log);
|
|
2037
|
+
} catch (error) {
|
|
2038
|
+
this.print({
|
|
2039
|
+
level: "error",
|
|
2040
|
+
message: "Error in log listener",
|
|
2041
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2042
|
+
error: {
|
|
2043
|
+
name: "ListenerError",
|
|
2044
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2045
|
+
}
|
|
2046
|
+
});
|
|
2047
|
+
continue;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
};
|
|
2052
|
+
_Logger.Severity = {
|
|
2053
|
+
trace: 0,
|
|
2054
|
+
debug: 1,
|
|
2055
|
+
info: 2,
|
|
2056
|
+
warn: 3,
|
|
2057
|
+
error: 4,
|
|
2058
|
+
critical: 5
|
|
2059
|
+
};
|
|
2060
|
+
var Logger = _Logger;
|
|
2061
|
+
|
|
2062
|
+
// src/models/DependencyProcessor.ts
|
|
2063
|
+
var DependencyProcessor = class {
|
|
2064
|
+
constructor(store2, eventManager, taskRunner, logger) {
|
|
2065
|
+
this.store = store2;
|
|
2066
|
+
this.eventManager = eventManager;
|
|
2067
|
+
this.taskRunner = taskRunner;
|
|
2068
|
+
this.logger = logger.with({ source: "dependencyProcessor" });
|
|
2069
|
+
this.resourceInitializer = new ResourceInitializer(
|
|
2070
|
+
store2,
|
|
2071
|
+
eventManager,
|
|
2072
|
+
logger
|
|
2073
|
+
);
|
|
2074
|
+
}
|
|
2075
|
+
/**
|
|
2076
|
+
* This function is going to go through all the resources, tasks and middleware to compute their required dependencies.
|
|
2077
|
+
*/
|
|
2078
|
+
async computeAllDependencies() {
|
|
2079
|
+
for (const middleware of this.store.resourceMiddlewares.values()) {
|
|
2080
|
+
const computedDependencies = await this.extractDependencies(
|
|
2081
|
+
middleware.middleware.dependencies,
|
|
2082
|
+
middleware.middleware.id
|
|
2083
|
+
);
|
|
2084
|
+
middleware.computedDependencies = computedDependencies;
|
|
2085
|
+
middleware.isInitialized = true;
|
|
2086
|
+
}
|
|
2087
|
+
for (const middleware of this.store.taskMiddlewares.values()) {
|
|
2088
|
+
const computedDependencies = await this.extractDependencies(
|
|
2089
|
+
middleware.middleware.dependencies,
|
|
2090
|
+
middleware.middleware.id
|
|
2091
|
+
);
|
|
2092
|
+
middleware.computedDependencies = computedDependencies;
|
|
2093
|
+
middleware.isInitialized = true;
|
|
2094
|
+
}
|
|
2095
|
+
for (const resource of this.store.resources.values()) {
|
|
2096
|
+
await this.processResourceDependencies(resource);
|
|
2097
|
+
}
|
|
2098
|
+
for (const task of this.store.tasks.values()) {
|
|
2099
|
+
await this.computeTaskDependencies(task);
|
|
2100
|
+
}
|
|
2101
|
+
for (const hookStoreElement of this.store.hooks.values()) {
|
|
2102
|
+
const hook = hookStoreElement.hook;
|
|
2103
|
+
const deps = hook.dependencies;
|
|
2104
|
+
hookStoreElement.computedDependencies = await this.extractDependencies(
|
|
2105
|
+
deps,
|
|
2106
|
+
hook.id
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
await this.initializeUninitializedResources();
|
|
2110
|
+
}
|
|
2111
|
+
async computeTaskDependencies(task) {
|
|
2112
|
+
const deps = task.task.dependencies;
|
|
2113
|
+
task.computedDependencies = await this.extractDependencies(
|
|
2114
|
+
deps,
|
|
2115
|
+
task.task.id
|
|
2116
|
+
);
|
|
2117
|
+
task.isInitialized = true;
|
|
2118
|
+
}
|
|
2119
|
+
// Most likely these are resources that no-one has dependencies towards
|
|
2120
|
+
// We need to ensure they work too!
|
|
2121
|
+
async initializeUninitializedResources() {
|
|
2122
|
+
for (const resource of this.store.resources.values()) {
|
|
2123
|
+
if (resource.isInitialized === false && // The root is the last one to be initialized and is done in a separate process.
|
|
2124
|
+
resource.resource.id !== this.store.root.resource.id) {
|
|
2125
|
+
await this.processResourceDependencies(resource);
|
|
2126
|
+
const { value, context } = await this.resourceInitializer.initializeResource(
|
|
2127
|
+
resource.resource,
|
|
2128
|
+
resource.config,
|
|
2129
|
+
resource.computedDependencies
|
|
2130
|
+
);
|
|
2131
|
+
resource.context = context;
|
|
2132
|
+
resource.value = value;
|
|
2133
|
+
resource.isInitialized = true;
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2138
|
+
* Processes dependencies and hooks
|
|
2139
|
+
* @param resource
|
|
2140
|
+
*/
|
|
2141
|
+
async processResourceDependencies(resource) {
|
|
2142
|
+
const deps = resource.resource.dependencies || {};
|
|
2143
|
+
const extracted = await this.extractDependencies(
|
|
2144
|
+
deps,
|
|
2145
|
+
resource.resource.id
|
|
2146
|
+
);
|
|
2147
|
+
resource.computedDependencies = this.wrapResourceDependencies(
|
|
2148
|
+
deps,
|
|
2149
|
+
extracted
|
|
2150
|
+
);
|
|
2151
|
+
}
|
|
2152
|
+
wrapResourceDependencies(deps, extracted) {
|
|
2153
|
+
const wrapped = {};
|
|
2154
|
+
for (const key of Object.keys(deps)) {
|
|
2155
|
+
const original = deps[key];
|
|
2156
|
+
const value = extracted[key];
|
|
2157
|
+
if (isOptional(original)) {
|
|
2158
|
+
const inner = original.inner;
|
|
2159
|
+
if (isTask(inner)) {
|
|
2160
|
+
wrapped[key] = value ? this.makeTaskWithIntercept(inner) : void 0;
|
|
2161
|
+
} else {
|
|
2162
|
+
wrapped[key] = value;
|
|
2163
|
+
}
|
|
2164
|
+
continue;
|
|
2165
|
+
}
|
|
2166
|
+
if (isTask(original)) {
|
|
2167
|
+
wrapped[key] = this.makeTaskWithIntercept(original);
|
|
2168
|
+
} else {
|
|
2169
|
+
wrapped[key] = value;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
return wrapped;
|
|
2173
|
+
}
|
|
2174
|
+
makeTaskWithIntercept(original) {
|
|
2175
|
+
const taskId = original.id;
|
|
2176
|
+
const fn = (input) => {
|
|
2177
|
+
const storeTask = this.store.tasks.get(taskId);
|
|
2178
|
+
const effective = storeTask.task;
|
|
2179
|
+
return this.taskRunner.run(effective, input);
|
|
2180
|
+
};
|
|
2181
|
+
return Object.assign(fn, {
|
|
2182
|
+
intercept: (middleware) => {
|
|
2183
|
+
this.store.checkLock();
|
|
2184
|
+
const storeTask = this.store.tasks.get(taskId);
|
|
2185
|
+
if (!storeTask.interceptors) storeTask.interceptors = [];
|
|
2186
|
+
storeTask.interceptors.push(middleware);
|
|
2187
|
+
}
|
|
2188
|
+
});
|
|
2189
|
+
}
|
|
2190
|
+
async initializeRoot() {
|
|
2191
|
+
const rootResource = this.store.root;
|
|
2192
|
+
const { value, context } = await this.resourceInitializer.initializeResource(
|
|
2193
|
+
rootResource.resource,
|
|
2194
|
+
rootResource.config,
|
|
2195
|
+
// They are already computed
|
|
2196
|
+
rootResource.computedDependencies
|
|
2197
|
+
);
|
|
2198
|
+
rootResource.context = context;
|
|
2199
|
+
rootResource.value = value;
|
|
2200
|
+
rootResource.isInitialized = true;
|
|
2201
|
+
}
|
|
2202
|
+
/**
|
|
2203
|
+
* Processes all hooks, should run before emission of any event.
|
|
2204
|
+
*/
|
|
2205
|
+
attachListeners() {
|
|
2206
|
+
for (const hookStoreElement of this.store.hooks.values()) {
|
|
2207
|
+
const hook = hookStoreElement.hook;
|
|
2208
|
+
if (hook.on) {
|
|
2209
|
+
const eventDefinition = hook.on;
|
|
2210
|
+
const handler = async (receivedEvent) => {
|
|
2211
|
+
if (receivedEvent.source === hook.id) {
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2214
|
+
return this.eventManager.executeHookWithInterceptors(
|
|
2215
|
+
hook,
|
|
2216
|
+
receivedEvent,
|
|
2217
|
+
hookStoreElement.computedDependencies
|
|
2218
|
+
);
|
|
2219
|
+
};
|
|
2220
|
+
const order = hook.order ?? 0;
|
|
2221
|
+
if (eventDefinition === "*") {
|
|
2222
|
+
this.eventManager.addGlobalListener(handler, { order });
|
|
2223
|
+
} else if (Array.isArray(eventDefinition)) {
|
|
2224
|
+
for (const ed of eventDefinition) {
|
|
2225
|
+
if (this.store.events.get(ed.id) === void 0) {
|
|
2226
|
+
throw new EventNotFoundError(ed.id);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
this.eventManager.addListener(eventDefinition, handler, {
|
|
2230
|
+
order
|
|
2231
|
+
});
|
|
2232
|
+
} else {
|
|
2233
|
+
if (this.store.events.get(eventDefinition.id) === void 0) {
|
|
2234
|
+
throw new EventNotFoundError(eventDefinition.id);
|
|
2235
|
+
}
|
|
2236
|
+
this.eventManager.addListener(eventDefinition, handler, {
|
|
2237
|
+
order
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
async extractDependencies(map, source) {
|
|
2244
|
+
const object = {};
|
|
2245
|
+
for (const key in map) {
|
|
2246
|
+
try {
|
|
2247
|
+
object[key] = await this.extractDependency(map[key], source);
|
|
2248
|
+
if (object[key] instanceof Logger) {
|
|
2249
|
+
object[key] = object[key].with({ source });
|
|
2250
|
+
}
|
|
2251
|
+
} catch (e) {
|
|
2252
|
+
const errorMessage = String(e);
|
|
2253
|
+
this.logger.error(
|
|
2254
|
+
`Failed to extract dependency from source: ${source} -> ${key} with error: ${errorMessage}`
|
|
2255
|
+
);
|
|
2256
|
+
throw e;
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
this.logger.trace(`Finished computing dependencies for source: ${source}`);
|
|
2260
|
+
return object;
|
|
2261
|
+
}
|
|
2262
|
+
async extractDependency(object, source) {
|
|
2263
|
+
this.logger.trace(`Extracting dependency -> ${source} -> ${object?.id}`);
|
|
2264
|
+
if (isOptional(object)) {
|
|
2265
|
+
const inner = object.inner;
|
|
2266
|
+
if (isResource(inner)) {
|
|
2267
|
+
const exists = this.store.resources.get(inner.id) !== void 0;
|
|
2268
|
+
return exists ? this.extractResourceDependency(inner) : void 0;
|
|
2269
|
+
} else if (isTask(inner)) {
|
|
2270
|
+
const exists = this.store.tasks.get(inner.id) !== void 0;
|
|
2271
|
+
return exists ? this.extractTaskDependency(inner) : void 0;
|
|
2272
|
+
} else if (isEvent(inner)) {
|
|
2273
|
+
const exists = this.store.events.get(inner.id) !== void 0;
|
|
2274
|
+
return exists ? this.extractEventDependency(inner, source) : void 0;
|
|
2275
|
+
}
|
|
2276
|
+
throw new UnknownItemTypeError(inner);
|
|
2277
|
+
}
|
|
2278
|
+
if (isResource(object)) {
|
|
2279
|
+
return this.extractResourceDependency(object);
|
|
2280
|
+
} else if (isTask(object)) {
|
|
2281
|
+
return this.extractTaskDependency(object);
|
|
2282
|
+
} else if (isEvent(object)) {
|
|
2283
|
+
return this.extractEventDependency(object, source);
|
|
2284
|
+
} else {
|
|
2285
|
+
throw new UnknownItemTypeError(object);
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
/**
|
|
2289
|
+
* Converts the event into a running functions with real inputs
|
|
2290
|
+
* @param object
|
|
2291
|
+
* @returns
|
|
2292
|
+
*/
|
|
2293
|
+
extractEventDependency(object, source) {
|
|
2294
|
+
return async (input) => {
|
|
2295
|
+
return this.eventManager.emit(object, input, source);
|
|
2296
|
+
};
|
|
2297
|
+
}
|
|
2298
|
+
async extractTaskDependency(object) {
|
|
2299
|
+
const storeTask = this.store.tasks.get(object.id);
|
|
2300
|
+
if (storeTask === void 0) {
|
|
2301
|
+
throw new DependencyNotFoundError(`Task ${object.id}`);
|
|
2302
|
+
}
|
|
2303
|
+
if (!storeTask.isInitialized) {
|
|
2304
|
+
const dependencies = object.dependencies;
|
|
2305
|
+
storeTask.computedDependencies = await this.extractDependencies(
|
|
2306
|
+
dependencies,
|
|
2307
|
+
storeTask.task.id
|
|
2308
|
+
);
|
|
2309
|
+
storeTask.isInitialized = true;
|
|
2310
|
+
}
|
|
2311
|
+
return (input) => {
|
|
2312
|
+
return this.taskRunner.run(storeTask.task, input);
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
async extractResourceDependency(object) {
|
|
2316
|
+
const storeResource = this.store.resources.get(object.id);
|
|
2317
|
+
if (storeResource === void 0) {
|
|
2318
|
+
throw new DependencyNotFoundError(`Resource ${object.id}`);
|
|
2319
|
+
}
|
|
2320
|
+
const { resource, config } = storeResource;
|
|
2321
|
+
if (!storeResource.isInitialized) {
|
|
2322
|
+
if (resource.init) {
|
|
2323
|
+
const depMap = resource.dependencies || {};
|
|
2324
|
+
const raw = await this.extractDependencies(depMap, resource.id);
|
|
2325
|
+
const wrapped = this.wrapResourceDependencies(depMap, raw);
|
|
2326
|
+
const { value, context } = await this.resourceInitializer.initializeResource(
|
|
2327
|
+
resource,
|
|
2328
|
+
config,
|
|
2329
|
+
wrapped
|
|
2330
|
+
);
|
|
2331
|
+
storeResource.context = context;
|
|
2332
|
+
storeResource.value = value;
|
|
2333
|
+
}
|
|
2334
|
+
storeResource.isInitialized = true;
|
|
2335
|
+
}
|
|
2336
|
+
return storeResource.value;
|
|
2337
|
+
}
|
|
2338
|
+
};
|
|
2339
|
+
|
|
2340
|
+
// src/models/EventManager.ts
|
|
2341
|
+
var HandlerOptionsDefaults = { order: 0 };
|
|
2342
|
+
var _isLocked2;
|
|
2343
|
+
var EventManager = class {
|
|
2344
|
+
constructor(options) {
|
|
2345
|
+
// Core storage for event listeners
|
|
2346
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
2347
|
+
this.globalListeners = [];
|
|
2348
|
+
// Caching system for merged listeners to improve performance
|
|
2349
|
+
this.cachedMergedListeners = /* @__PURE__ */ new Map();
|
|
2350
|
+
this.globalListenersCacheValid = true;
|
|
2351
|
+
// Interceptors storage
|
|
2352
|
+
this.emissionInterceptors = [];
|
|
2353
|
+
this.hookInterceptors = [];
|
|
2354
|
+
// Locking mechanism to prevent modifications after initialization
|
|
2355
|
+
__privateAdd(this, _isLocked2, false);
|
|
2356
|
+
this.runtimeCycleDetection = options?.runtimeCycleDetection ?? true;
|
|
2357
|
+
if (getPlatform().hasAsyncLocalStorage() && this.runtimeCycleDetection) {
|
|
2358
|
+
this.emissionStack = getPlatform().createAsyncLocalStorage();
|
|
2359
|
+
this.currentHookIdContext = getPlatform().createAsyncLocalStorage();
|
|
2360
|
+
} else {
|
|
2361
|
+
this.runtimeCycleDetection = false;
|
|
2362
|
+
this.emissionStack = null;
|
|
2363
|
+
this.currentHookIdContext = null;
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
// ==================== PUBLIC API ====================
|
|
2367
|
+
/**
|
|
2368
|
+
* Gets the current lock status of the EventManager
|
|
2369
|
+
*/
|
|
2370
|
+
get isLocked() {
|
|
2371
|
+
return __privateGet(this, _isLocked2);
|
|
2372
|
+
}
|
|
2373
|
+
/**
|
|
2374
|
+
* Locks the EventManager, preventing any further modifications to listeners
|
|
2375
|
+
*/
|
|
2376
|
+
lock() {
|
|
2377
|
+
__privateSet(this, _isLocked2, true);
|
|
2378
|
+
}
|
|
2379
|
+
/**
|
|
2380
|
+
* Emits an event to all registered listeners for that event type.
|
|
2381
|
+
* Listeners are processed in order of priority and can stop event propagation.
|
|
2382
|
+
*
|
|
2383
|
+
* @param eventDefinition - The event definition to emit
|
|
2384
|
+
* @param data - The event payload data
|
|
2385
|
+
* @param source - The source identifier of the event emitter
|
|
2386
|
+
*/
|
|
2387
|
+
async emit(eventDefinition, data, source) {
|
|
2388
|
+
if (eventDefinition.payloadSchema) {
|
|
2389
|
+
try {
|
|
2390
|
+
data = eventDefinition.payloadSchema.parse(data);
|
|
2391
|
+
} catch (error) {
|
|
2392
|
+
throw new ValidationError(
|
|
2393
|
+
"Event payload",
|
|
2394
|
+
eventDefinition.id,
|
|
2395
|
+
error instanceof Error ? error : new Error(String(error))
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
const frame = { id: eventDefinition.id, source };
|
|
2400
|
+
const processEmission = async () => {
|
|
2401
|
+
const pseudoForExclude = {
|
|
2402
|
+
id: eventDefinition.id,
|
|
2403
|
+
data,
|
|
2404
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2405
|
+
source,
|
|
2406
|
+
meta: eventDefinition.meta || {},
|
|
2407
|
+
stopPropagation: () => {
|
|
2408
|
+
},
|
|
2409
|
+
isPropagationStopped: () => false,
|
|
2410
|
+
tags: eventDefinition.tags
|
|
2411
|
+
};
|
|
2412
|
+
const excludeFromGlobal = this.isExcludedFromGlobal(pseudoForExclude);
|
|
2413
|
+
const allListeners = excludeFromGlobal ? this.listeners.get(eventDefinition.id) || [] : this.getCachedMergedListeners(eventDefinition.id);
|
|
2414
|
+
let propagationStopped = false;
|
|
2415
|
+
const event = {
|
|
2416
|
+
id: eventDefinition.id,
|
|
2417
|
+
data,
|
|
2418
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2419
|
+
source,
|
|
2420
|
+
meta: eventDefinition.meta || {},
|
|
2421
|
+
stopPropagation: () => {
|
|
2422
|
+
propagationStopped = true;
|
|
2423
|
+
},
|
|
2424
|
+
isPropagationStopped: () => propagationStopped,
|
|
2425
|
+
tags: eventDefinition.tags
|
|
2426
|
+
};
|
|
2427
|
+
const baseEmit = async (eventToEmit) => {
|
|
2428
|
+
if (allListeners.length === 0) {
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
this.isExcludedFromGlobal(eventToEmit);
|
|
2432
|
+
for (const listener of allListeners) {
|
|
2433
|
+
if (propagationStopped) {
|
|
2434
|
+
break;
|
|
2435
|
+
}
|
|
2436
|
+
if (listener.id && listener.id === eventToEmit.source) {
|
|
2437
|
+
continue;
|
|
2438
|
+
}
|
|
2439
|
+
if (!listener.filter || listener.filter(eventToEmit)) {
|
|
2440
|
+
await listener.handler(eventToEmit);
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
};
|
|
2444
|
+
let emitWithInterceptors = baseEmit;
|
|
2445
|
+
const reversedInterceptors = [...this.emissionInterceptors].reverse();
|
|
2446
|
+
for (const interceptor of reversedInterceptors) {
|
|
2447
|
+
const nextFunction = emitWithInterceptors;
|
|
2448
|
+
emitWithInterceptors = async (eventToEmit) => interceptor(nextFunction, eventToEmit);
|
|
2449
|
+
}
|
|
2450
|
+
await emitWithInterceptors(event);
|
|
2451
|
+
};
|
|
2452
|
+
if (this.runtimeCycleDetection && this.emissionStack && this.currentHookIdContext) {
|
|
2453
|
+
const currentStack = this.emissionStack.getStore();
|
|
2454
|
+
if (currentStack) {
|
|
2455
|
+
const cycleStart = currentStack.findIndex(
|
|
2456
|
+
(f) => f.id === frame.id
|
|
2457
|
+
);
|
|
2458
|
+
if (cycleStart !== -1) {
|
|
2459
|
+
const top = currentStack[currentStack.length - 1];
|
|
2460
|
+
const currentHookId = this.currentHookIdContext.getStore();
|
|
2461
|
+
const safeReEmitBySameHook = top.id === frame.id && currentHookId && currentHookId === source;
|
|
2462
|
+
if (!safeReEmitBySameHook) {
|
|
2463
|
+
throw new EventCycleError([
|
|
2464
|
+
...currentStack.slice(cycleStart),
|
|
2465
|
+
frame
|
|
2466
|
+
]);
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
const nextStack = currentStack ? [...currentStack, frame] : [frame];
|
|
2471
|
+
await this.emissionStack.run(nextStack, processEmission);
|
|
2472
|
+
} else {
|
|
2473
|
+
await processEmission();
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
/**
|
|
2477
|
+
* Registers an event listener for specific event(s).
|
|
2478
|
+
* Listeners are ordered by priority and executed in ascending order.
|
|
2479
|
+
*
|
|
2480
|
+
* @param event - The event definition(s) to listen for
|
|
2481
|
+
* @param handler - The callback function to handle the event
|
|
2482
|
+
* @param options - Configuration options for the listener
|
|
2483
|
+
*/
|
|
2484
|
+
addListener(event, handler, options = HandlerOptionsDefaults) {
|
|
2485
|
+
this.checkLock();
|
|
2486
|
+
const newListener = {
|
|
2487
|
+
handler,
|
|
2488
|
+
order: options.order || 0,
|
|
2489
|
+
filter: options.filter,
|
|
2490
|
+
id: options.id,
|
|
2491
|
+
isGlobal: false
|
|
2492
|
+
};
|
|
2493
|
+
if (Array.isArray(event)) {
|
|
2494
|
+
event.forEach((id2) => this.addListener(id2, handler, options));
|
|
2495
|
+
} else {
|
|
2496
|
+
const eventId = event.id;
|
|
2497
|
+
const listeners = this.listeners.get(eventId);
|
|
2498
|
+
if (listeners) {
|
|
2499
|
+
this.insertListener(listeners, newListener);
|
|
2500
|
+
} else {
|
|
2501
|
+
this.listeners.set(eventId, [newListener]);
|
|
2502
|
+
}
|
|
2503
|
+
this.invalidateCache(eventId);
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
/**
|
|
2507
|
+
* Registers a global event listener that handles all events.
|
|
2508
|
+
* Global listeners are mixed with specific listeners and ordered by priority.
|
|
2509
|
+
*
|
|
2510
|
+
* @param handler - The callback function to handle events
|
|
2511
|
+
* @param options - Configuration options for the listener
|
|
2512
|
+
*/
|
|
2513
|
+
addGlobalListener(handler, options = HandlerOptionsDefaults) {
|
|
2514
|
+
this.checkLock();
|
|
2515
|
+
const newListener = {
|
|
2516
|
+
handler,
|
|
2517
|
+
order: options.order || 0,
|
|
2518
|
+
filter: options.filter,
|
|
2519
|
+
id: options.id,
|
|
2520
|
+
isGlobal: true
|
|
2521
|
+
};
|
|
2522
|
+
this.insertListener(this.globalListeners, newListener);
|
|
2523
|
+
this.invalidateCache();
|
|
2524
|
+
}
|
|
2525
|
+
/**
|
|
2526
|
+
* Checks if there are any listeners registered for the given event
|
|
2527
|
+
*
|
|
2528
|
+
* @param eventDefinition - The event definition to check
|
|
2529
|
+
* @returns true if listeners exist, false otherwise
|
|
2530
|
+
*/
|
|
2531
|
+
hasListeners(eventDefinition) {
|
|
2532
|
+
const eventListeners = this.listeners.get(eventDefinition.id) || [];
|
|
2533
|
+
if (eventListeners.length > 0) {
|
|
2534
|
+
return true;
|
|
2535
|
+
}
|
|
2536
|
+
if (this.globalListeners.length === 0) {
|
|
2537
|
+
return false;
|
|
2538
|
+
}
|
|
2539
|
+
const pseudoEmission = {
|
|
2540
|
+
id: eventDefinition.id,
|
|
2541
|
+
data: void 0,
|
|
2542
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2543
|
+
source: "",
|
|
2544
|
+
meta: eventDefinition.meta || {},
|
|
2545
|
+
stopPropagation: () => {
|
|
2546
|
+
},
|
|
2547
|
+
isPropagationStopped: () => false,
|
|
2548
|
+
tags: eventDefinition.tags
|
|
2549
|
+
};
|
|
2550
|
+
if (this.isExcludedFromGlobal(pseudoEmission)) {
|
|
2551
|
+
return false;
|
|
2552
|
+
}
|
|
2553
|
+
return true;
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Adds an interceptor for all event emissions
|
|
2557
|
+
* Interceptors are executed in the order they are added, with the ability to
|
|
2558
|
+
* modify, log, or prevent event emissions
|
|
2559
|
+
*
|
|
2560
|
+
* @param interceptor - The interceptor function to add
|
|
2561
|
+
*/
|
|
2562
|
+
intercept(interceptor) {
|
|
2563
|
+
this.checkLock();
|
|
2564
|
+
this.emissionInterceptors.push(interceptor);
|
|
2565
|
+
}
|
|
2566
|
+
/**
|
|
2567
|
+
* Adds an interceptor for hook execution
|
|
2568
|
+
* Interceptors are executed in the order they are added, with the ability to
|
|
2569
|
+
* modify, log, or prevent hook execution
|
|
2570
|
+
*
|
|
2571
|
+
* @param interceptor - The interceptor function to add
|
|
2572
|
+
*/
|
|
2573
|
+
interceptHook(interceptor) {
|
|
2574
|
+
this.checkLock();
|
|
2575
|
+
this.hookInterceptors.push(interceptor);
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* Executes a hook with all registered hook interceptors applied
|
|
2579
|
+
* This method should be used by TaskRunner when executing hooks
|
|
2580
|
+
*
|
|
2581
|
+
* @param hook - The hook to execute
|
|
2582
|
+
* @param event - The event that triggered the hook
|
|
2583
|
+
* @param computedDependencies - The computed dependencies for the hook
|
|
2584
|
+
* @returns Promise resolving to the hook execution result
|
|
2585
|
+
*/
|
|
2586
|
+
async executeHookWithInterceptors(hook, event, computedDependencies) {
|
|
2587
|
+
const baseExecute = async (hookToExecute, eventForHook) => {
|
|
2588
|
+
try {
|
|
2589
|
+
const result = await hookToExecute.run(
|
|
2590
|
+
eventForHook,
|
|
2591
|
+
computedDependencies
|
|
2592
|
+
);
|
|
2593
|
+
return result;
|
|
2594
|
+
} catch (err) {
|
|
2595
|
+
throw err;
|
|
2596
|
+
}
|
|
2597
|
+
};
|
|
2598
|
+
let executeWithInterceptors = baseExecute;
|
|
2599
|
+
const reversedInterceptors = [...this.hookInterceptors].reverse();
|
|
2600
|
+
for (const interceptor of reversedInterceptors) {
|
|
2601
|
+
const nextFunction = executeWithInterceptors;
|
|
2602
|
+
executeWithInterceptors = async (hookToExecute, eventForHook) => interceptor(nextFunction, hookToExecute, eventForHook);
|
|
2603
|
+
}
|
|
2604
|
+
if (this.runtimeCycleDetection) {
|
|
2605
|
+
return await this.currentHookIdContext?.run(
|
|
2606
|
+
hook.id,
|
|
2607
|
+
async () => await executeWithInterceptors(hook, event)
|
|
2608
|
+
);
|
|
2609
|
+
} else {
|
|
2610
|
+
return await executeWithInterceptors(hook, event);
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
// ==================== PRIVATE METHODS ====================
|
|
2614
|
+
/**
|
|
2615
|
+
* Throws an error if the EventManager is locked
|
|
2616
|
+
*/
|
|
2617
|
+
checkLock() {
|
|
2618
|
+
if (__privateGet(this, _isLocked2)) {
|
|
2619
|
+
throw new LockedError("EventManager");
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
/**
|
|
2623
|
+
* Merges two sorted arrays of listeners while maintaining order.
|
|
2624
|
+
* Used to combine event-specific listeners with global listeners.
|
|
2625
|
+
*
|
|
2626
|
+
* @param a - First array of listeners
|
|
2627
|
+
* @param b - Second array of listeners
|
|
2628
|
+
* @returns Merged and sorted array of listeners
|
|
2629
|
+
*/
|
|
2630
|
+
mergeSortedListeners(a, b) {
|
|
2631
|
+
const result = [];
|
|
2632
|
+
let i = 0, j = 0;
|
|
2633
|
+
while (i < a.length && j < b.length) {
|
|
2634
|
+
if (a[i].order <= b[j].order) {
|
|
2635
|
+
result.push(a[i++]);
|
|
2636
|
+
} else {
|
|
2637
|
+
result.push(b[j++]);
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
while (i < a.length) result.push(a[i++]);
|
|
2641
|
+
while (j < b.length) result.push(b[j++]);
|
|
2642
|
+
return result;
|
|
2643
|
+
}
|
|
2644
|
+
/**
|
|
2645
|
+
* Inserts a new listener into a sorted array using binary search.
|
|
2646
|
+
* Maintains order based on listener priority.
|
|
2647
|
+
*
|
|
2648
|
+
* @param listeners - Array to insert into
|
|
2649
|
+
* @param newListener - Listener to insert
|
|
2650
|
+
*/
|
|
2651
|
+
insertListener(listeners, newListener) {
|
|
2652
|
+
let low = 0;
|
|
2653
|
+
let high = listeners.length;
|
|
2654
|
+
while (low < high) {
|
|
2655
|
+
const mid = low + high >>> 1;
|
|
2656
|
+
if (listeners[mid].order < newListener.order) {
|
|
2657
|
+
low = mid + 1;
|
|
2658
|
+
} else {
|
|
2659
|
+
high = mid;
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
listeners.splice(low, 0, newListener);
|
|
2663
|
+
}
|
|
2664
|
+
/**
|
|
2665
|
+
* Returns true if the given emission carries the tag that marks
|
|
2666
|
+
* it as excluded from global ("*") listeners.
|
|
2667
|
+
*
|
|
2668
|
+
* @param event - The event emission to check
|
|
2669
|
+
* @returns true if event should exclude global listeners
|
|
2670
|
+
*/
|
|
2671
|
+
isExcludedFromGlobal(event) {
|
|
2672
|
+
return globalTags.excludeFromGlobalHooks.exists(event);
|
|
2673
|
+
}
|
|
2674
|
+
/**
|
|
2675
|
+
* Retrieves cached merged listeners for an event, or creates them if not cached.
|
|
2676
|
+
* Combines event-specific listeners with global listeners and sorts them by priority.
|
|
2677
|
+
*
|
|
2678
|
+
* @param eventId - The event ID to get listeners for
|
|
2679
|
+
* @returns Array of merged listeners sorted by priority
|
|
2680
|
+
*/
|
|
2681
|
+
getCachedMergedListeners(eventId) {
|
|
2682
|
+
if (!this.globalListenersCacheValid) {
|
|
2683
|
+
this.cachedMergedListeners.clear();
|
|
2684
|
+
this.globalListenersCacheValid = true;
|
|
2685
|
+
}
|
|
2686
|
+
let cached = this.cachedMergedListeners.get(eventId);
|
|
2687
|
+
if (!cached) {
|
|
2688
|
+
const eventListeners = this.listeners.get(eventId) || [];
|
|
2689
|
+
if (eventListeners.length === 0 && this.globalListeners.length === 0) {
|
|
2690
|
+
cached = [];
|
|
2691
|
+
} else if (eventListeners.length === 0) {
|
|
2692
|
+
cached = this.globalListeners;
|
|
2693
|
+
} else if (this.globalListeners.length === 0) {
|
|
2694
|
+
cached = eventListeners;
|
|
2695
|
+
} else {
|
|
2696
|
+
cached = this.mergeSortedListeners(
|
|
2697
|
+
eventListeners,
|
|
2698
|
+
this.globalListeners
|
|
2699
|
+
);
|
|
2700
|
+
}
|
|
2701
|
+
this.cachedMergedListeners.set(eventId, cached);
|
|
2702
|
+
}
|
|
2703
|
+
return cached;
|
|
2704
|
+
}
|
|
2705
|
+
/**
|
|
2706
|
+
* Invalidates the cached merged listeners.
|
|
2707
|
+
* If eventId is provided, only invalidates cache for that specific event.
|
|
2708
|
+
* Otherwise, invalidates the global cache.
|
|
2709
|
+
*
|
|
2710
|
+
* @param eventId - Optional specific event ID to invalidate
|
|
2711
|
+
*/
|
|
2712
|
+
invalidateCache(eventId) {
|
|
2713
|
+
if (eventId) {
|
|
2714
|
+
this.cachedMergedListeners.delete(eventId);
|
|
2715
|
+
} else {
|
|
2716
|
+
this.globalListenersCacheValid = false;
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
};
|
|
2720
|
+
_isLocked2 = new WeakMap();
|
|
2721
|
+
|
|
2722
|
+
// src/models/utils/findCircularDependencies.ts
|
|
2723
|
+
function findCircularDependencies(nodes) {
|
|
2724
|
+
const result = {
|
|
2725
|
+
cycles: [],
|
|
2726
|
+
missingDependencies: []
|
|
2727
|
+
};
|
|
2728
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2729
|
+
const stack = /* @__PURE__ */ new Set();
|
|
2730
|
+
const path = [];
|
|
2731
|
+
function dfs(node) {
|
|
2732
|
+
if (stack.has(node.id)) {
|
|
2733
|
+
const cycleStartIndex = path.indexOf(node.id);
|
|
2734
|
+
const cycle = path.slice(cycleStartIndex).concat(node.id).join(" -> ");
|
|
2735
|
+
result.cycles.push(cycle);
|
|
2736
|
+
return;
|
|
2737
|
+
}
|
|
2738
|
+
if (visited.has(node.id)) return;
|
|
2739
|
+
visited.add(node.id);
|
|
2740
|
+
stack.add(node.id);
|
|
2741
|
+
path.push(node.id);
|
|
2742
|
+
for (const [depKey, dependentNode] of Object.entries(node.dependencies)) {
|
|
2743
|
+
if (!dependentNode) {
|
|
2744
|
+
result.missingDependencies.push({
|
|
2745
|
+
nodeId: node.id,
|
|
2746
|
+
dependencyId: depKey
|
|
2747
|
+
});
|
|
2748
|
+
continue;
|
|
2749
|
+
}
|
|
2750
|
+
dfs(dependentNode);
|
|
2751
|
+
}
|
|
2752
|
+
stack.delete(node.id);
|
|
2753
|
+
path.pop();
|
|
2754
|
+
}
|
|
2755
|
+
for (const node of nodes) {
|
|
2756
|
+
if (!visited.has(node.id)) {
|
|
2757
|
+
dfs(node);
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
result.cycles = Array.from(new Set(result.cycles));
|
|
2761
|
+
return result;
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
// src/models/StoreValidator.ts
|
|
2765
|
+
var StoreValidator = class {
|
|
2766
|
+
constructor(registry) {
|
|
2767
|
+
this.registry = registry;
|
|
2768
|
+
}
|
|
2769
|
+
checkIfIDExists(id2) {
|
|
2770
|
+
if (this.registry.tasks.has(id2)) {
|
|
2771
|
+
throw new DuplicateRegistrationError("Task", id2);
|
|
2772
|
+
}
|
|
2773
|
+
if (this.registry.resources.has(id2)) {
|
|
2774
|
+
throw new DuplicateRegistrationError("Resource", id2);
|
|
2775
|
+
}
|
|
2776
|
+
if (this.registry.events.has(id2)) {
|
|
2777
|
+
throw new DuplicateRegistrationError("Event", id2);
|
|
2778
|
+
}
|
|
2779
|
+
if (this.registry.taskMiddlewares.has(id2)) {
|
|
2780
|
+
throw new DuplicateRegistrationError("Middleware", id2);
|
|
2781
|
+
}
|
|
2782
|
+
if (this.registry.resourceMiddlewares.has(id2)) {
|
|
2783
|
+
throw new DuplicateRegistrationError("Middleware", id2);
|
|
2784
|
+
}
|
|
2785
|
+
if (this.registry.tags.has(id2)) {
|
|
2786
|
+
throw new DuplicateRegistrationError("Tag", id2);
|
|
2787
|
+
}
|
|
2788
|
+
if (this.registry.hooks.has(id2)) {
|
|
2789
|
+
throw new DuplicateRegistrationError("Hook", id2);
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
runSanityChecks() {
|
|
2793
|
+
for (const task of this.registry.tasks.values()) {
|
|
2794
|
+
const middlewares = task.task.middleware;
|
|
2795
|
+
middlewares.forEach((middlewareAttachment) => {
|
|
2796
|
+
if (!this.registry.taskMiddlewares.has(middlewareAttachment.id)) {
|
|
2797
|
+
throw new MiddlewareNotRegisteredError(
|
|
2798
|
+
"task",
|
|
2799
|
+
task.task.id,
|
|
2800
|
+
middlewareAttachment.id
|
|
2801
|
+
);
|
|
2802
|
+
}
|
|
2803
|
+
});
|
|
2804
|
+
}
|
|
2805
|
+
for (const resource of this.registry.resources.values()) {
|
|
2806
|
+
const middlewares = resource.resource.middleware;
|
|
2807
|
+
middlewares.forEach((middlewareAttachment) => {
|
|
2808
|
+
if (!this.registry.resourceMiddlewares.has(middlewareAttachment.id)) {
|
|
2809
|
+
throw new MiddlewareNotRegisteredError(
|
|
2810
|
+
"resource",
|
|
2811
|
+
resource.resource.id,
|
|
2812
|
+
middlewareAttachment.id
|
|
2813
|
+
);
|
|
2814
|
+
}
|
|
2815
|
+
});
|
|
2816
|
+
}
|
|
2817
|
+
this.ensureAllTagsUsedAreRegistered();
|
|
2818
|
+
}
|
|
2819
|
+
ensureAllTagsUsedAreRegistered() {
|
|
2820
|
+
const taggables = [
|
|
2821
|
+
...Array.from(this.registry.tasks.values()).map((x) => x.task),
|
|
2822
|
+
...Array.from(this.registry.resources.values()).map((x) => x.resource),
|
|
2823
|
+
...Array.from(this.registry.events.values()).map((x) => x.event),
|
|
2824
|
+
...Array.from(this.registry.taskMiddlewares.values()).map(
|
|
2825
|
+
(x) => x.middleware
|
|
2826
|
+
),
|
|
2827
|
+
...Array.from(this.registry.resourceMiddlewares.values()).map(
|
|
2828
|
+
(x) => x.middleware
|
|
2829
|
+
),
|
|
2830
|
+
...Array.from(this.registry.hooks.values()).map((x) => x.hook)
|
|
2831
|
+
];
|
|
2832
|
+
for (const taggable of taggables) {
|
|
2833
|
+
const tags = taggable.tags;
|
|
2834
|
+
if (tags) {
|
|
2835
|
+
for (const tag of tags) {
|
|
2836
|
+
if (!this.registry.tags.has(tag.id)) {
|
|
2837
|
+
throw new TagNotFoundError(tag.id);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
}
|
|
2843
|
+
};
|
|
2844
|
+
|
|
2845
|
+
// src/models/StoreRegistry.ts
|
|
2846
|
+
var StoreRegistry = class {
|
|
2847
|
+
constructor(store2) {
|
|
2848
|
+
this.store = store2;
|
|
2849
|
+
this.tasks = /* @__PURE__ */ new Map();
|
|
2850
|
+
this.resources = /* @__PURE__ */ new Map();
|
|
2851
|
+
this.events = /* @__PURE__ */ new Map();
|
|
2852
|
+
this.taskMiddlewares = /* @__PURE__ */ new Map();
|
|
2853
|
+
this.resourceMiddlewares = /* @__PURE__ */ new Map();
|
|
2854
|
+
this.hooks = /* @__PURE__ */ new Map();
|
|
2855
|
+
this.tags = /* @__PURE__ */ new Map();
|
|
2856
|
+
this.validator = new StoreValidator(this);
|
|
2857
|
+
}
|
|
2858
|
+
getValidator() {
|
|
2859
|
+
return this.validator;
|
|
2860
|
+
}
|
|
2861
|
+
storeGenericItem(item) {
|
|
2862
|
+
if (isTask(item)) {
|
|
2863
|
+
this.storeTask(item);
|
|
2864
|
+
} else if (isHook && isHook(item)) {
|
|
2865
|
+
this.storeHook(item);
|
|
2866
|
+
} else if (isResource(item)) {
|
|
2867
|
+
this.storeResource(item);
|
|
2868
|
+
} else if (isEvent(item)) {
|
|
2869
|
+
this.storeEvent(item);
|
|
2870
|
+
} else if (isTaskMiddleware(item)) {
|
|
2871
|
+
this.storeTaskMiddleware(item);
|
|
2872
|
+
} else if (isResourceMiddleware(item)) {
|
|
2873
|
+
this.storeResourceMiddleware(item);
|
|
2874
|
+
} else if (isResourceWithConfig(item)) {
|
|
2875
|
+
this.storeResourceWithConfig(item);
|
|
2876
|
+
} else if (isTag(item)) {
|
|
2877
|
+
this.storeTag(item);
|
|
2878
|
+
} else {
|
|
2879
|
+
throw new UnknownItemTypeError(item);
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
storeTag(item) {
|
|
2883
|
+
this.validator.checkIfIDExists(item.id);
|
|
2884
|
+
this.tags.set(item.id, item);
|
|
2885
|
+
}
|
|
2886
|
+
storeHook(item, overrideMode = "normal") {
|
|
2887
|
+
overrideMode === "normal" && this.validator.checkIfIDExists(item.id);
|
|
2888
|
+
const hook = this.getFreshValue(item, this.hooks, "hook", overrideMode);
|
|
2889
|
+
this.hooks.set(hook.id, {
|
|
2890
|
+
hook,
|
|
2891
|
+
computedDependencies: {}
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2894
|
+
storeTaskMiddleware(item, storingMode = "normal") {
|
|
2895
|
+
storingMode === "normal" && this.validator.checkIfIDExists(item.id);
|
|
2896
|
+
const middleware = this.getFreshValue(
|
|
2897
|
+
item,
|
|
2898
|
+
this.taskMiddlewares,
|
|
2899
|
+
"middleware",
|
|
2900
|
+
storingMode
|
|
2901
|
+
);
|
|
2902
|
+
this.taskMiddlewares.set(item.id, {
|
|
2903
|
+
middleware,
|
|
2904
|
+
computedDependencies: {},
|
|
2905
|
+
isInitialized: false
|
|
2906
|
+
});
|
|
2907
|
+
}
|
|
2908
|
+
storeResourceMiddleware(item, overrideMode = "normal") {
|
|
2909
|
+
overrideMode === "normal" && this.validator.checkIfIDExists(item.id);
|
|
2910
|
+
const middleware = this.getFreshValue(
|
|
2911
|
+
item,
|
|
2912
|
+
this.resourceMiddlewares,
|
|
2913
|
+
"middleware",
|
|
2914
|
+
overrideMode
|
|
2915
|
+
);
|
|
2916
|
+
this.resourceMiddlewares.set(item.id, {
|
|
2917
|
+
middleware,
|
|
2918
|
+
computedDependencies: {},
|
|
2919
|
+
isInitialized: false
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
storeEvent(item) {
|
|
2923
|
+
this.validator.checkIfIDExists(item.id);
|
|
2924
|
+
this.events.set(item.id, { event: item });
|
|
2925
|
+
}
|
|
2926
|
+
storeResourceWithConfig(item, storingMode = "normal") {
|
|
2927
|
+
storingMode === "normal" && this.validator.checkIfIDExists(item.resource.id);
|
|
2928
|
+
const prepared = this.getFreshValue(
|
|
2929
|
+
item.resource,
|
|
2930
|
+
this.resources,
|
|
2931
|
+
"resource",
|
|
2932
|
+
storingMode,
|
|
2933
|
+
item.config
|
|
2934
|
+
);
|
|
2935
|
+
this.resources.set(prepared.id, {
|
|
2936
|
+
resource: prepared,
|
|
2937
|
+
config: item.config,
|
|
2938
|
+
value: void 0,
|
|
2939
|
+
isInitialized: false,
|
|
2940
|
+
context: {}
|
|
2941
|
+
});
|
|
2942
|
+
this.computeRegistrationDeeply(prepared, item.config);
|
|
2943
|
+
return prepared;
|
|
2944
|
+
}
|
|
2945
|
+
computeRegistrationDeeply(element, config) {
|
|
2946
|
+
const items = typeof element.register === "function" ? element.register(config) : element.register;
|
|
2947
|
+
element.register = items;
|
|
2948
|
+
for (const item of items) {
|
|
2949
|
+
this.storeGenericItem(item);
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
storeResource(item, overrideMode = "normal") {
|
|
2953
|
+
overrideMode === "normal" && this.validator.checkIfIDExists(item.id);
|
|
2954
|
+
const prepared = this.getFreshValue(
|
|
2955
|
+
item,
|
|
2956
|
+
this.resources,
|
|
2957
|
+
"resource",
|
|
2958
|
+
overrideMode
|
|
2959
|
+
);
|
|
2960
|
+
this.resources.set(prepared.id, {
|
|
2961
|
+
resource: prepared,
|
|
2962
|
+
config: {},
|
|
2963
|
+
value: void 0,
|
|
2964
|
+
isInitialized: false,
|
|
2965
|
+
context: prepared.context?.() || {}
|
|
2966
|
+
});
|
|
2967
|
+
this.computeRegistrationDeeply(prepared, {});
|
|
2968
|
+
return prepared;
|
|
2969
|
+
}
|
|
2970
|
+
storeTask(item, storingMode = "normal") {
|
|
2971
|
+
storingMode === "normal" && this.validator.checkIfIDExists(item.id);
|
|
2972
|
+
const task = this.getFreshValue(item, this.tasks, "task", storingMode);
|
|
2973
|
+
this.tasks.set(task.id, {
|
|
2974
|
+
task,
|
|
2975
|
+
computedDependencies: {},
|
|
2976
|
+
isInitialized: false
|
|
2977
|
+
});
|
|
2978
|
+
}
|
|
2979
|
+
// Feels like a dependencyProcessor task?
|
|
2980
|
+
getDependentNodes() {
|
|
2981
|
+
const depenedants = [];
|
|
2982
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
2983
|
+
this.setupBlankNodes(nodeMap, depenedants);
|
|
2984
|
+
for (const task of this.tasks.values()) {
|
|
2985
|
+
const node = nodeMap.get(task.task.id);
|
|
2986
|
+
if (task.task.dependencies) {
|
|
2987
|
+
for (const [depKey, depItem] of Object.entries(
|
|
2988
|
+
task.task.dependencies
|
|
2989
|
+
)) {
|
|
2990
|
+
const candidate = isOptional(depItem) ? depItem.inner : depItem;
|
|
2991
|
+
const depNode = nodeMap.get(candidate.id);
|
|
2992
|
+
if (depNode) {
|
|
2993
|
+
node.dependencies[depKey] = depNode;
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
const t = task.task;
|
|
2998
|
+
for (const middleware of t.middleware) {
|
|
2999
|
+
const middlewareNode = nodeMap.get(middleware.id);
|
|
3000
|
+
if (middlewareNode) {
|
|
3001
|
+
node.dependencies[middleware.id] = middlewareNode;
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
for (const storeTaskMiddleware of this.taskMiddlewares.values()) {
|
|
3006
|
+
const node = nodeMap.get(storeTaskMiddleware.middleware.id);
|
|
3007
|
+
const { middleware } = storeTaskMiddleware;
|
|
3008
|
+
if (middleware.dependencies) {
|
|
3009
|
+
for (const [depKey, depItem] of Object.entries(
|
|
3010
|
+
middleware.dependencies
|
|
3011
|
+
)) {
|
|
3012
|
+
const candidate = isOptional(depItem) ? depItem.inner : depItem;
|
|
3013
|
+
const depNode = nodeMap.get(candidate.id);
|
|
3014
|
+
if (depNode) {
|
|
3015
|
+
node.dependencies[depKey] = depNode;
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
if (middleware.everywhere) {
|
|
3020
|
+
const filter = typeof middleware.everywhere === "function" ? middleware.everywhere : () => true;
|
|
3021
|
+
for (const task of this.tasks.values()) {
|
|
3022
|
+
if (filter(task.task)) {
|
|
3023
|
+
const taskNode = nodeMap.get(task.task.id);
|
|
3024
|
+
taskNode.dependencies[`__middleware.${middleware.id}`] = node;
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
for (const storeResourceMiddleware of this.resourceMiddlewares.values()) {
|
|
3030
|
+
const node = nodeMap.get(storeResourceMiddleware.middleware.id);
|
|
3031
|
+
const { middleware } = storeResourceMiddleware;
|
|
3032
|
+
if (middleware.dependencies) {
|
|
3033
|
+
for (const [depKey, depItem] of Object.entries(
|
|
3034
|
+
middleware.dependencies
|
|
3035
|
+
)) {
|
|
3036
|
+
const candidate = isOptional(depItem) ? depItem.inner : depItem;
|
|
3037
|
+
const depNode = nodeMap.get(candidate.id);
|
|
3038
|
+
if (depNode) {
|
|
3039
|
+
node.dependencies[depKey] = depNode;
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
if (middleware.everywhere) {
|
|
3044
|
+
const filter = typeof middleware.everywhere === "function" ? middleware.everywhere : () => true;
|
|
3045
|
+
for (const resource of this.resources.values()) {
|
|
3046
|
+
if (filter(resource.resource)) {
|
|
3047
|
+
const resourceNode = nodeMap.get(resource.resource.id);
|
|
3048
|
+
resourceNode.dependencies[`__middleware.${middleware.id}`] = node;
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
for (const resource of this.resources.values()) {
|
|
3054
|
+
const node = nodeMap.get(resource.resource.id);
|
|
3055
|
+
if (resource.resource.dependencies) {
|
|
3056
|
+
for (const [depKey, depItem] of Object.entries(
|
|
3057
|
+
resource.resource.dependencies
|
|
3058
|
+
)) {
|
|
3059
|
+
const candidate = isOptional(depItem) ? depItem.inner : depItem;
|
|
3060
|
+
const depNode = nodeMap.get(candidate.id);
|
|
3061
|
+
if (depNode) {
|
|
3062
|
+
node.dependencies[depKey] = depNode;
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
for (const middleware of resource.resource.middleware) {
|
|
3067
|
+
const middlewareNode = nodeMap.get(middleware.id);
|
|
3068
|
+
if (middlewareNode) {
|
|
3069
|
+
node.dependencies[middleware.id] = middlewareNode;
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
for (const hook of this.hooks.values()) {
|
|
3074
|
+
const node = nodeMap.get(hook.hook.id);
|
|
3075
|
+
if (hook.hook.dependencies) {
|
|
3076
|
+
for (const [depKey, depItem] of Object.entries(
|
|
3077
|
+
hook.hook.dependencies
|
|
3078
|
+
)) {
|
|
3079
|
+
const candidate = isOptional(depItem) ? depItem.inner : depItem;
|
|
3080
|
+
const depNode = nodeMap.get(candidate.id);
|
|
3081
|
+
if (depNode) {
|
|
3082
|
+
node.dependencies[depKey] = depNode;
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
return depenedants;
|
|
3088
|
+
}
|
|
3089
|
+
/**
|
|
3090
|
+
* Builds a directed graph of event emissions based on hooks listening to events
|
|
3091
|
+
* and their dependencies on events (emission capability). Ignores wildcard hooks by default.
|
|
3092
|
+
*/
|
|
3093
|
+
buildEventEmissionGraph() {
|
|
3094
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
3095
|
+
for (const e of this.events.values()) {
|
|
3096
|
+
nodes.set(e.event.id, { id: e.event.id, dependencies: {} });
|
|
3097
|
+
}
|
|
3098
|
+
for (const h of this.hooks.values()) {
|
|
3099
|
+
const listened = [];
|
|
3100
|
+
const on = h.hook.on;
|
|
3101
|
+
if (on === "*") continue;
|
|
3102
|
+
if (Array.isArray(on)) listened.push(...on.map((e) => e.id));
|
|
3103
|
+
else listened.push(on.id);
|
|
3104
|
+
const depEvents = [];
|
|
3105
|
+
const deps = h.hook.dependencies;
|
|
3106
|
+
if (deps) {
|
|
3107
|
+
for (const value of Object.values(deps)) {
|
|
3108
|
+
const candidate = isOptional(value) ? value.inner : value;
|
|
3109
|
+
if (candidate && isEvent(candidate)) {
|
|
3110
|
+
depEvents.push(candidate.id);
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
for (const srcId of listened) {
|
|
3115
|
+
const srcNode = nodes.get(srcId);
|
|
3116
|
+
if (!srcNode) continue;
|
|
3117
|
+
for (const dstId of depEvents) {
|
|
3118
|
+
if (srcId === dstId) continue;
|
|
3119
|
+
const dstNode = nodes.get(dstId);
|
|
3120
|
+
if (dstNode) {
|
|
3121
|
+
srcNode.dependencies[dstId] = dstNode;
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
return Array.from(nodes.values());
|
|
3127
|
+
}
|
|
3128
|
+
setupBlankNodes(nodeMap, depenedants) {
|
|
3129
|
+
for (const task of this.tasks.values()) {
|
|
3130
|
+
const node = {
|
|
3131
|
+
id: task.task.id,
|
|
3132
|
+
dependencies: {}
|
|
3133
|
+
};
|
|
3134
|
+
nodeMap.set(task.task.id, node);
|
|
3135
|
+
depenedants.push(node);
|
|
3136
|
+
}
|
|
3137
|
+
for (const middleware of this.taskMiddlewares.values()) {
|
|
3138
|
+
const node = {
|
|
3139
|
+
id: middleware.middleware.id,
|
|
3140
|
+
dependencies: {}
|
|
3141
|
+
};
|
|
3142
|
+
nodeMap.set(middleware.middleware.id, node);
|
|
3143
|
+
depenedants.push(node);
|
|
3144
|
+
}
|
|
3145
|
+
for (const middleware of this.resourceMiddlewares.values()) {
|
|
3146
|
+
const node = {
|
|
3147
|
+
id: middleware.middleware.id,
|
|
3148
|
+
dependencies: {}
|
|
3149
|
+
};
|
|
3150
|
+
nodeMap.set(middleware.middleware.id, node);
|
|
3151
|
+
depenedants.push(node);
|
|
3152
|
+
}
|
|
3153
|
+
for (const resource of this.resources.values()) {
|
|
3154
|
+
const node = {
|
|
3155
|
+
id: resource.resource.id,
|
|
3156
|
+
dependencies: {}
|
|
3157
|
+
};
|
|
3158
|
+
nodeMap.set(resource.resource.id, node);
|
|
3159
|
+
depenedants.push(node);
|
|
3160
|
+
}
|
|
3161
|
+
for (const hook of this.hooks.values()) {
|
|
3162
|
+
const node = {
|
|
3163
|
+
id: hook.hook.id,
|
|
3164
|
+
dependencies: {}
|
|
3165
|
+
};
|
|
3166
|
+
nodeMap.set(hook.hook.id, node);
|
|
3167
|
+
depenedants.push(node);
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
getTasksWithTag(tag) {
|
|
3171
|
+
const tagId = typeof tag === "string" ? tag : tag.id;
|
|
3172
|
+
return Array.from(this.tasks.values()).filter((x) => {
|
|
3173
|
+
return x.task.tags.some((t) => t.id === tagId);
|
|
3174
|
+
}).map((x) => x.task);
|
|
3175
|
+
}
|
|
3176
|
+
getResourcesWithTag(tag) {
|
|
3177
|
+
const tagId = typeof tag === "string" ? tag : tag.id;
|
|
3178
|
+
return Array.from(this.resources.values()).filter((x) => {
|
|
3179
|
+
return x.resource.tags.some((t) => t.id === tagId);
|
|
3180
|
+
}).map((x) => x.resource);
|
|
3181
|
+
}
|
|
3182
|
+
/**
|
|
3183
|
+
* Used to fetch the value cloned, and if we're dealing with an override, we need to extend the previous value.
|
|
3184
|
+
*/
|
|
3185
|
+
getFreshValue(item, collection, key, overrideMode, config) {
|
|
3186
|
+
let currentItem;
|
|
3187
|
+
if (overrideMode === "override") {
|
|
3188
|
+
const existing = collection.get(item.id)[key];
|
|
3189
|
+
currentItem = { ...existing, ...item };
|
|
3190
|
+
} else {
|
|
3191
|
+
currentItem = { ...item };
|
|
3192
|
+
}
|
|
3193
|
+
currentItem.dependencies = typeof currentItem.dependencies === "function" ? currentItem.dependencies(config || currentItem.config) : currentItem.dependencies;
|
|
3194
|
+
return currentItem;
|
|
3195
|
+
}
|
|
3196
|
+
};
|
|
3197
|
+
|
|
3198
|
+
// src/models/OverrideManager.ts
|
|
3199
|
+
var OverrideManager = class {
|
|
3200
|
+
constructor(registry) {
|
|
3201
|
+
this.registry = registry;
|
|
3202
|
+
this.overrides = /* @__PURE__ */ new Map();
|
|
3203
|
+
this.overrideRequests = /* @__PURE__ */ new Set();
|
|
3204
|
+
}
|
|
3205
|
+
storeOverridesDeeply(element) {
|
|
3206
|
+
element.overrides.forEach((override) => {
|
|
3207
|
+
if (!override) {
|
|
3208
|
+
return;
|
|
3209
|
+
}
|
|
3210
|
+
if (isResource(override)) {
|
|
3211
|
+
this.storeOverridesDeeply(override);
|
|
3212
|
+
}
|
|
3213
|
+
let id2;
|
|
3214
|
+
if (isResourceWithConfig(override)) {
|
|
3215
|
+
this.storeOverridesDeeply(override.resource);
|
|
3216
|
+
id2 = override.resource.id;
|
|
3217
|
+
} else {
|
|
3218
|
+
id2 = override.id;
|
|
3219
|
+
}
|
|
3220
|
+
this.overrideRequests.add({ source: element.id, override });
|
|
3221
|
+
this.overrides.set(id2, override);
|
|
3222
|
+
});
|
|
3223
|
+
}
|
|
3224
|
+
processOverrides() {
|
|
3225
|
+
for (const override of this.overrides.values()) {
|
|
3226
|
+
let hasAnyItem = false;
|
|
3227
|
+
if (isTask(override)) {
|
|
3228
|
+
hasAnyItem = this.registry.tasks.has(override.id);
|
|
3229
|
+
} else if (isResource(override)) {
|
|
3230
|
+
hasAnyItem = this.registry.resources.has(override.id);
|
|
3231
|
+
} else if (isTaskMiddleware(override)) {
|
|
3232
|
+
hasAnyItem = this.registry.taskMiddlewares.has(override.id);
|
|
3233
|
+
} else if (isResourceMiddleware(override)) {
|
|
3234
|
+
hasAnyItem = this.registry.resourceMiddlewares.has(override.id);
|
|
3235
|
+
} else if (isResourceWithConfig(override)) {
|
|
3236
|
+
hasAnyItem = this.registry.resources.has(override.resource.id);
|
|
3237
|
+
} else if (isHook(override)) {
|
|
3238
|
+
hasAnyItem = this.registry.hooks.has(override.id);
|
|
3239
|
+
}
|
|
3240
|
+
if (!hasAnyItem) {
|
|
3241
|
+
const id2 = isResourceWithConfig(override) ? override.resource.id : override.id;
|
|
3242
|
+
throw new DependencyNotFoundError(id2);
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
for (const override of this.overrides.values()) {
|
|
3246
|
+
if (isTask(override)) {
|
|
3247
|
+
this.registry.storeTask(override, "override");
|
|
3248
|
+
} else if (isResource(override)) {
|
|
3249
|
+
this.registry.storeResource(override, "override");
|
|
3250
|
+
} else if (isTaskMiddleware(override)) {
|
|
3251
|
+
this.registry.storeTaskMiddleware(override, "override");
|
|
3252
|
+
} else if (isResourceMiddleware(override)) {
|
|
3253
|
+
this.registry.storeResourceMiddleware(override, "override");
|
|
3254
|
+
} else if (isResourceWithConfig(override)) {
|
|
3255
|
+
this.registry.storeResourceWithConfig(override, "override");
|
|
3256
|
+
} else if (isHook(override)) {
|
|
3257
|
+
this.registry.storeHook(override, "override");
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
};
|
|
3262
|
+
|
|
3263
|
+
// src/models/Store.ts
|
|
3264
|
+
var _isLocked3, _isInitialized;
|
|
3265
|
+
var Store = class {
|
|
3266
|
+
constructor(eventManager, logger, onUnhandledError) {
|
|
3267
|
+
this.eventManager = eventManager;
|
|
3268
|
+
this.logger = logger;
|
|
3269
|
+
this.onUnhandledError = onUnhandledError;
|
|
3270
|
+
__privateAdd(this, _isLocked3, false);
|
|
3271
|
+
__privateAdd(this, _isInitialized, false);
|
|
3272
|
+
this.registry = new StoreRegistry(this);
|
|
3273
|
+
this.validator = this.registry.getValidator();
|
|
3274
|
+
this.overrideManager = new OverrideManager(this.registry);
|
|
3275
|
+
this.middlewareManager = new MiddlewareManager(this, eventManager, logger);
|
|
3276
|
+
}
|
|
3277
|
+
// Delegate properties to registry
|
|
3278
|
+
get tasks() {
|
|
3279
|
+
return this.registry.tasks;
|
|
3280
|
+
}
|
|
3281
|
+
get hooks() {
|
|
3282
|
+
return this.registry.hooks;
|
|
3283
|
+
}
|
|
3284
|
+
get resources() {
|
|
3285
|
+
return this.registry.resources;
|
|
3286
|
+
}
|
|
3287
|
+
get events() {
|
|
3288
|
+
return this.registry.events;
|
|
3289
|
+
}
|
|
3290
|
+
get taskMiddlewares() {
|
|
3291
|
+
return this.registry.taskMiddlewares;
|
|
3292
|
+
}
|
|
3293
|
+
get resourceMiddlewares() {
|
|
3294
|
+
return this.registry.resourceMiddlewares;
|
|
3295
|
+
}
|
|
3296
|
+
get tags() {
|
|
3297
|
+
return this.registry.tags;
|
|
3298
|
+
}
|
|
3299
|
+
get overrides() {
|
|
3300
|
+
return this.overrideManager.overrides;
|
|
3301
|
+
}
|
|
3302
|
+
get overrideRequests() {
|
|
3303
|
+
return this.overrideManager.overrideRequests;
|
|
3304
|
+
}
|
|
3305
|
+
// Expose the shared MiddlewareManager instance so other components (like TaskRunner)
|
|
3306
|
+
// can compose runners using the same interceptor configuration.
|
|
3307
|
+
getMiddlewareManager() {
|
|
3308
|
+
return this.middlewareManager;
|
|
3309
|
+
}
|
|
3310
|
+
get isLocked() {
|
|
3311
|
+
return __privateGet(this, _isLocked3);
|
|
3312
|
+
}
|
|
3313
|
+
lock() {
|
|
3314
|
+
__privateSet(this, _isLocked3, true);
|
|
3315
|
+
}
|
|
3316
|
+
checkLock() {
|
|
3317
|
+
if (__privateGet(this, _isLocked3)) {
|
|
3318
|
+
throw new Error("Cannot modify the Store when it is locked.");
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
registerGlobalComponents() {
|
|
3322
|
+
const builtInResourcesMap = /* @__PURE__ */ new Map();
|
|
3323
|
+
builtInResourcesMap.set(globalResources.store, this);
|
|
3324
|
+
builtInResourcesMap.set(globalResources.eventManager, this.eventManager);
|
|
3325
|
+
builtInResourcesMap.set(globalResources.logger, this.logger);
|
|
3326
|
+
builtInResourcesMap.set(globalResources.taskRunner, this.taskRunner);
|
|
3327
|
+
builtInResourcesMap.set(
|
|
3328
|
+
globalResources.middlewareManager,
|
|
3329
|
+
this.middlewareManager
|
|
3330
|
+
);
|
|
3331
|
+
this.registry.storeGenericItem(globalResources.queue);
|
|
3332
|
+
for (const [resource, value] of builtInResourcesMap.entries()) {
|
|
3333
|
+
this.registry.storeGenericItem(resource);
|
|
3334
|
+
const entry = this.resources.get(resource.id);
|
|
3335
|
+
if (entry) {
|
|
3336
|
+
entry.value = value;
|
|
3337
|
+
entry.isInitialized = true;
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
Object.values(globalTags).forEach((tag) => {
|
|
3341
|
+
this.registry.storeTag(tag);
|
|
3342
|
+
});
|
|
3343
|
+
globalEventsArray.forEach((event) => {
|
|
3344
|
+
this.registry.storeEvent(event);
|
|
3345
|
+
});
|
|
3346
|
+
const builtInTaskMiddlewares = [
|
|
3347
|
+
requireContextTaskMiddleware,
|
|
3348
|
+
retryTaskMiddleware,
|
|
3349
|
+
timeoutTaskMiddleware
|
|
3350
|
+
];
|
|
3351
|
+
builtInTaskMiddlewares.forEach((middleware) => {
|
|
3352
|
+
this.registry.taskMiddlewares.set(middleware.id, {
|
|
3353
|
+
middleware,
|
|
3354
|
+
computedDependencies: {},
|
|
3355
|
+
isInitialized: false
|
|
3356
|
+
});
|
|
3357
|
+
});
|
|
3358
|
+
const builtInResourceMiddlewares = [
|
|
3359
|
+
retryResourceMiddleware,
|
|
3360
|
+
timeoutResourceMiddleware
|
|
3361
|
+
];
|
|
3362
|
+
builtInResourceMiddlewares.forEach((middleware) => {
|
|
3363
|
+
this.registry.resourceMiddlewares.set(middleware.id, {
|
|
3364
|
+
middleware,
|
|
3365
|
+
computedDependencies: {},
|
|
3366
|
+
isInitialized: false
|
|
3367
|
+
});
|
|
3368
|
+
});
|
|
3369
|
+
}
|
|
3370
|
+
setTaskRunner(taskRunner) {
|
|
3371
|
+
this.taskRunner = taskRunner;
|
|
3372
|
+
}
|
|
3373
|
+
setupRootResource(root, config) {
|
|
3374
|
+
root.dependencies = typeof root.dependencies === "function" ? root.dependencies(config) : root.dependencies;
|
|
3375
|
+
this.root = {
|
|
3376
|
+
resource: root,
|
|
3377
|
+
computedDependencies: {},
|
|
3378
|
+
config,
|
|
3379
|
+
value: void 0,
|
|
3380
|
+
isInitialized: false,
|
|
3381
|
+
context: {}
|
|
3382
|
+
};
|
|
3383
|
+
this.registry.computeRegistrationDeeply(root, config);
|
|
3384
|
+
this.registry.resources.set(root.id, this.root);
|
|
3385
|
+
}
|
|
3386
|
+
validateDependencyGraph() {
|
|
3387
|
+
const dependentNodes = this.registry.getDependentNodes();
|
|
3388
|
+
const circularDependencies = findCircularDependencies(dependentNodes);
|
|
3389
|
+
if (circularDependencies.cycles.length > 0) {
|
|
3390
|
+
throw new CircularDependenciesError(circularDependencies.cycles);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
validateEventEmissionGraph() {
|
|
3394
|
+
const eventNodes = this.registry.buildEventEmissionGraph();
|
|
3395
|
+
const circular = findCircularDependencies(eventNodes);
|
|
3396
|
+
if (circular.cycles.length > 0) {
|
|
3397
|
+
throw new EventEmissionCycleError(circular.cycles);
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
initializeStore(root, config) {
|
|
3401
|
+
if (__privateGet(this, _isInitialized)) {
|
|
3402
|
+
throw new StoreAlreadyInitializedError();
|
|
3403
|
+
}
|
|
3404
|
+
this.registerGlobalComponents();
|
|
3405
|
+
this.setupRootResource(root, config);
|
|
3406
|
+
this.validator.runSanityChecks();
|
|
3407
|
+
for (const resource of this.resources.values()) {
|
|
3408
|
+
this.overrideManager.storeOverridesDeeply(resource.resource);
|
|
3409
|
+
}
|
|
3410
|
+
__privateSet(this, _isInitialized, true);
|
|
3411
|
+
}
|
|
3412
|
+
async dispose() {
|
|
3413
|
+
for (const resource of this.resources.values()) {
|
|
3414
|
+
if (resource.isInitialized && resource.resource.dispose) {
|
|
3415
|
+
await resource.resource.dispose(
|
|
3416
|
+
resource.value,
|
|
3417
|
+
resource.config,
|
|
3418
|
+
resource.computedDependencies,
|
|
3419
|
+
resource.context
|
|
3420
|
+
);
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
processOverrides() {
|
|
3425
|
+
this.overrideManager.processOverrides();
|
|
3426
|
+
}
|
|
3427
|
+
storeGenericItem(item) {
|
|
3428
|
+
return this.registry.storeGenericItem(item);
|
|
3429
|
+
}
|
|
3430
|
+
/**
|
|
3431
|
+
* Returns all tasks with the given tag.
|
|
3432
|
+
* @param tag - The tag to filter by.
|
|
3433
|
+
* @returns The tasks with the given tag.
|
|
3434
|
+
*/
|
|
3435
|
+
getTasksWithTag(tag) {
|
|
3436
|
+
return this.registry.getTasksWithTag(tag);
|
|
3437
|
+
}
|
|
3438
|
+
getResourcesWithTag(tag) {
|
|
3439
|
+
return this.registry.getResourcesWithTag(tag);
|
|
3440
|
+
}
|
|
3441
|
+
};
|
|
3442
|
+
_isLocked3 = new WeakMap();
|
|
3443
|
+
_isInitialized = new WeakMap();
|
|
3444
|
+
|
|
3445
|
+
// src/globals/resources/debug/types.ts
|
|
3446
|
+
var allFalse = Object.freeze({
|
|
3447
|
+
logResourceBeforeRun: false,
|
|
3448
|
+
logResourceAfterRun: false,
|
|
3449
|
+
logMiddlewareBeforeRun: false,
|
|
3450
|
+
logMiddlewareAfterRun: false,
|
|
3451
|
+
logTaskBeforeRun: false,
|
|
3452
|
+
logTaskAfterRun: false,
|
|
3453
|
+
logTaskInput: false,
|
|
3454
|
+
logTaskOutput: false,
|
|
3455
|
+
logResourceConfig: false,
|
|
3456
|
+
logResourceValue: false,
|
|
3457
|
+
logHookTriggered: false,
|
|
3458
|
+
logHookCompleted: false,
|
|
3459
|
+
logEventEmissionOnRun: false,
|
|
3460
|
+
logEventEmissionInput: false
|
|
3461
|
+
});
|
|
3462
|
+
var levelNormal = Object.freeze({
|
|
3463
|
+
...allFalse,
|
|
3464
|
+
logTaskAfterRun: true,
|
|
3465
|
+
logTaskBeforeRun: true,
|
|
3466
|
+
logResourceBeforeRun: true,
|
|
3467
|
+
logResourceAfterRun: true,
|
|
3468
|
+
logMiddlewareBeforeRun: true,
|
|
3469
|
+
logMiddlewareAfterRun: true,
|
|
3470
|
+
logHookTriggered: true,
|
|
3471
|
+
logHookCompleted: true,
|
|
3472
|
+
logEventEmissionOnRun: true
|
|
3473
|
+
});
|
|
3474
|
+
Object.freeze(levelNormal);
|
|
3475
|
+
var levelVerbose = Object.freeze({
|
|
3476
|
+
...levelNormal,
|
|
3477
|
+
logTaskInput: true,
|
|
3478
|
+
logTaskOutput: true,
|
|
3479
|
+
logResourceConfig: true,
|
|
3480
|
+
logResourceValue: true,
|
|
3481
|
+
logHookTriggered: true,
|
|
3482
|
+
logHookCompleted: true
|
|
3483
|
+
});
|
|
3484
|
+
Object.freeze(levelVerbose);
|
|
3485
|
+
function formatConfig(config) {
|
|
3486
|
+
if (config === "normal") {
|
|
3487
|
+
return { ...levelNormal };
|
|
3488
|
+
}
|
|
3489
|
+
if (config === "verbose") {
|
|
3490
|
+
return { ...levelVerbose };
|
|
3491
|
+
}
|
|
3492
|
+
return { ...allFalse, ...config };
|
|
3493
|
+
}
|
|
3494
|
+
var getConfig = (config, taggable) => {
|
|
3495
|
+
if (!taggable) {
|
|
3496
|
+
return formatConfig(config);
|
|
3497
|
+
}
|
|
3498
|
+
const debugTagConfig = debugTag.extract(taggable);
|
|
3499
|
+
if (debugTagConfig) {
|
|
3500
|
+
const debugTagConfigFormatted = formatConfig(debugTagConfig);
|
|
3501
|
+
return { ...formatConfig(config), ...debugTagConfigFormatted };
|
|
3502
|
+
}
|
|
3503
|
+
return formatConfig(config);
|
|
3504
|
+
};
|
|
3505
|
+
|
|
3506
|
+
// src/globals/resources/debug/debugConfig.resource.ts
|
|
3507
|
+
var debugConfig = defineResource({
|
|
3508
|
+
id: "globals.debug.resources.config",
|
|
3509
|
+
meta: {
|
|
3510
|
+
title: "Debug Config",
|
|
3511
|
+
description: "Debug config. This is used to debug the system."
|
|
3512
|
+
},
|
|
3513
|
+
tags: [globalTags.system],
|
|
3514
|
+
init: async (config) => {
|
|
3515
|
+
const myConfig = { ...getConfig(config) };
|
|
3516
|
+
Object.freeze(myConfig);
|
|
3517
|
+
return myConfig;
|
|
3518
|
+
}
|
|
3519
|
+
});
|
|
3520
|
+
|
|
3521
|
+
// src/globals/resources/debug/utils.ts
|
|
3522
|
+
var hasSystemTag = (definition) => {
|
|
3523
|
+
const maybeTags = definition.tags;
|
|
3524
|
+
if (!Array.isArray(maybeTags)) {
|
|
3525
|
+
return false;
|
|
3526
|
+
}
|
|
3527
|
+
return globalTags.system.exists(definition);
|
|
3528
|
+
};
|
|
3529
|
+
|
|
3530
|
+
// src/globals/resources/debug/globalEvent.hook.ts
|
|
3531
|
+
var globalEventListener = defineHook({
|
|
3532
|
+
id: "globals.debug.hooks.onAnyEvent",
|
|
3533
|
+
on: "*",
|
|
3534
|
+
dependencies: {
|
|
3535
|
+
logger: globalResources.logger,
|
|
3536
|
+
debugConfig
|
|
3537
|
+
},
|
|
3538
|
+
run: async (event, { logger, debugConfig: debugConfig2 }) => {
|
|
3539
|
+
if (hasSystemTag(event)) {
|
|
3540
|
+
return;
|
|
3541
|
+
}
|
|
3542
|
+
debugConfig2 = getConfig(debugConfig2, event);
|
|
3543
|
+
if (debugConfig2.logEventEmissionOnRun) {
|
|
3544
|
+
const message = `Event ${String(event.id)} emitted`;
|
|
3545
|
+
await logger.info(message, {
|
|
3546
|
+
source: "globals.debug.hooks.onAnyEvent",
|
|
3547
|
+
data: debugConfig2.logEventEmissionInput ? { data: event.data } : void 0
|
|
3548
|
+
});
|
|
3549
|
+
}
|
|
3550
|
+
},
|
|
3551
|
+
meta: {
|
|
3552
|
+
title: "Non-system Event Logger",
|
|
3553
|
+
description: "Logs all non-system events."
|
|
3554
|
+
},
|
|
3555
|
+
tags: [globalTags.system]
|
|
3556
|
+
});
|
|
3557
|
+
|
|
3558
|
+
// src/globals/resources/debug/executionTracker.middleware.ts
|
|
3559
|
+
var tasksTrackerMiddleware = defineTaskMiddleware({
|
|
3560
|
+
id: "globals.debug.middleware.task.executionTracker",
|
|
3561
|
+
everywhere: (task) => !globalTags.system.exists(task),
|
|
3562
|
+
dependencies: {
|
|
3563
|
+
logger: globalResources.logger,
|
|
3564
|
+
debugConfig,
|
|
3565
|
+
store: globalResources.store
|
|
3566
|
+
},
|
|
3567
|
+
run: async ({ task, next }, { logger, debugConfig: debugConfig2, store: store2 }) => {
|
|
3568
|
+
const start = Date.now();
|
|
3569
|
+
logger = logger.with({
|
|
3570
|
+
source: tasksTrackerMiddleware.id
|
|
3571
|
+
});
|
|
3572
|
+
debugConfig2 = getConfig(debugConfig2, task?.definition);
|
|
3573
|
+
const taskStartMessage = `Task ${task.definition.id} is running...`;
|
|
3574
|
+
const shouldShowData = debugConfig2.logTaskInput && task.input;
|
|
3575
|
+
await logger.info(taskStartMessage, {
|
|
3576
|
+
data: shouldShowData ? { input: task.input } : void 0
|
|
3577
|
+
});
|
|
3578
|
+
const result = await next(task.input);
|
|
3579
|
+
const duration = Date.now() - start;
|
|
3580
|
+
const taskCompleteMessage = `Task ${task.definition.id} completed in ${duration}ms`;
|
|
3581
|
+
const shouldShowResult = debugConfig2.logTaskOutput && result;
|
|
3582
|
+
await logger.info(taskCompleteMessage, {
|
|
3583
|
+
data: shouldShowResult ? { result } : void 0
|
|
3584
|
+
});
|
|
3585
|
+
return result;
|
|
3586
|
+
},
|
|
3587
|
+
meta: {
|
|
3588
|
+
title: "Execution Tracker",
|
|
3589
|
+
description: "Tracks the execution of tasks and resources."
|
|
3590
|
+
},
|
|
3591
|
+
tags: [globalTags.system]
|
|
3592
|
+
});
|
|
3593
|
+
var resourcesTrackerMiddleware = defineResourceMiddleware({
|
|
3594
|
+
id: "globals.debug.middleware.resource.executionTracker",
|
|
3595
|
+
dependencies: {
|
|
3596
|
+
logger: globalResources.logger,
|
|
3597
|
+
debugConfig,
|
|
3598
|
+
store: globalResources.store
|
|
3599
|
+
},
|
|
3600
|
+
everywhere: (resource) => !globalTags.system.exists(resource),
|
|
3601
|
+
run: async ({ resource, next }, { logger, debugConfig: debugConfig2, store: store2 }) => {
|
|
3602
|
+
const start = Date.now();
|
|
3603
|
+
logger = logger.with({
|
|
3604
|
+
source: resourcesTrackerMiddleware.id
|
|
3605
|
+
});
|
|
3606
|
+
debugConfig2 = getConfig(debugConfig2, resource?.definition);
|
|
3607
|
+
const resourceStartMessage = `Resource ${resource.definition.id} is initializing...`;
|
|
3608
|
+
const isConfigEmpty = Object.keys(resource.config || {}).length === 0;
|
|
3609
|
+
const shouldShowConfig = debugConfig2.logResourceConfig && !isConfigEmpty;
|
|
3610
|
+
await logger.info(resourceStartMessage, {
|
|
3611
|
+
data: shouldShowConfig ? { config: resource.config } : void 0
|
|
3612
|
+
});
|
|
3613
|
+
const result = await next(resource.config);
|
|
3614
|
+
const duration = Date.now() - start;
|
|
3615
|
+
const resourceCompleteMessage = `Resource ${String(
|
|
3616
|
+
resource.definition.id
|
|
3617
|
+
)} initialized in ${duration}ms`;
|
|
3618
|
+
const shouldShowResult = debugConfig2.logResourceValue && result !== void 0;
|
|
3619
|
+
await logger.info(resourceCompleteMessage, {
|
|
3620
|
+
data: shouldShowResult ? { result } : void 0
|
|
3621
|
+
});
|
|
3622
|
+
return result;
|
|
3623
|
+
},
|
|
3624
|
+
meta: {
|
|
3625
|
+
title: "Execution Tracker",
|
|
3626
|
+
description: "Tracks the execution of tasks and resources."
|
|
3627
|
+
},
|
|
3628
|
+
tags: [globalTags.system]
|
|
3629
|
+
});
|
|
3630
|
+
|
|
3631
|
+
// src/globals/resources/debug/middleware.hook.ts
|
|
3632
|
+
var id = "globals.debug.resources.middlewareInterceptor";
|
|
3633
|
+
var middlewareInterceptorResource = defineResource({
|
|
3634
|
+
id,
|
|
3635
|
+
meta: {
|
|
3636
|
+
title: "Middleware Interceptor",
|
|
3637
|
+
description: "Intercepts task and resource middleware, skipping system-tagged entities."
|
|
3638
|
+
},
|
|
3639
|
+
tags: [globalTags.system],
|
|
3640
|
+
dependencies: {
|
|
3641
|
+
logger: globalResources.logger,
|
|
3642
|
+
debugConfig,
|
|
3643
|
+
middlewareManager: globalResources.middlewareManager
|
|
3644
|
+
},
|
|
3645
|
+
init: async (event, deps) => {
|
|
3646
|
+
const { logger, debugConfig: debugConfig2, middlewareManager } = deps;
|
|
3647
|
+
middlewareManager.intercept(
|
|
3648
|
+
"task",
|
|
3649
|
+
async (next, input) => {
|
|
3650
|
+
const taskDef = input.task.definition;
|
|
3651
|
+
if (!hasSystemTag(taskDef)) {
|
|
3652
|
+
const cfg = getConfig(debugConfig2, event);
|
|
3653
|
+
if (cfg.logMiddlewareBeforeRun) {
|
|
3654
|
+
const msg = `Middleware triggered for task ${String(taskDef.id)}`;
|
|
3655
|
+
await logger.info(msg, {
|
|
3656
|
+
source: id
|
|
3657
|
+
});
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
const result = await next(input);
|
|
3661
|
+
if (!hasSystemTag(taskDef)) {
|
|
3662
|
+
const cfg = getConfig(debugConfig2, event);
|
|
3663
|
+
if (cfg.logMiddlewareAfterRun) {
|
|
3664
|
+
const msg = `Middleware completed for task ${String(taskDef.id)}`;
|
|
3665
|
+
await logger.info(msg, {
|
|
3666
|
+
source: id
|
|
3667
|
+
});
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
return result;
|
|
3671
|
+
}
|
|
3672
|
+
);
|
|
3673
|
+
middlewareManager.intercept(
|
|
3674
|
+
"resource",
|
|
3675
|
+
async (next, input) => {
|
|
3676
|
+
const resourceDef = input.resource.definition;
|
|
3677
|
+
if (!hasSystemTag(resourceDef)) {
|
|
3678
|
+
const cfg = getConfig(debugConfig2, event);
|
|
3679
|
+
if (cfg.logMiddlewareBeforeRun) {
|
|
3680
|
+
const msg = `Middleware triggered for resource ${String(
|
|
3681
|
+
resourceDef.id
|
|
3682
|
+
)}`;
|
|
3683
|
+
await logger.info(msg, {
|
|
3684
|
+
source: id
|
|
3685
|
+
});
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
const result = await next(input);
|
|
3689
|
+
if (!hasSystemTag(resourceDef)) {
|
|
3690
|
+
const cfg = getConfig(debugConfig2, event);
|
|
3691
|
+
if (cfg.logMiddlewareAfterRun) {
|
|
3692
|
+
const msg = `Middleware completed for resource ${String(
|
|
3693
|
+
resourceDef.id
|
|
3694
|
+
)}`;
|
|
3695
|
+
await logger.info(msg, {
|
|
3696
|
+
source: id
|
|
3697
|
+
});
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
return result;
|
|
3701
|
+
}
|
|
3702
|
+
);
|
|
3703
|
+
}
|
|
3704
|
+
});
|
|
3705
|
+
|
|
3706
|
+
// src/globals/resources/debug/hook.hook.ts
|
|
3707
|
+
var hookInterceptorResource = defineResource({
|
|
3708
|
+
id: "globals.debug.resources.hookInterceptor",
|
|
3709
|
+
meta: {
|
|
3710
|
+
title: "Hook Interceptor",
|
|
3711
|
+
description: "Intercepts hooks for debug logging, skipping system-tagged hooks."
|
|
3712
|
+
},
|
|
3713
|
+
tags: [globalTags.system],
|
|
3714
|
+
dependencies: {
|
|
3715
|
+
logger: globalResources.logger,
|
|
3716
|
+
debugConfig,
|
|
3717
|
+
eventManager: globalResources.eventManager
|
|
3718
|
+
},
|
|
3719
|
+
init: async (event, deps) => {
|
|
3720
|
+
deps.eventManager.interceptHook(async (next, hook, event2) => {
|
|
3721
|
+
const { logger, debugConfig: debugConfig2 } = deps;
|
|
3722
|
+
if (hasSystemTag(hook)) {
|
|
3723
|
+
return await next(hook, event2);
|
|
3724
|
+
}
|
|
3725
|
+
const resolved = getConfig(debugConfig2, event2);
|
|
3726
|
+
if (resolved.logHookTriggered) {
|
|
3727
|
+
const hookId = hook.id;
|
|
3728
|
+
let logString = `Hook triggered for ${String(hookId)}`;
|
|
3729
|
+
await logger.info(logString, {
|
|
3730
|
+
source: "globals.debug.resources.hookInterceptor"
|
|
3731
|
+
});
|
|
3732
|
+
}
|
|
3733
|
+
await next(hook, event2);
|
|
3734
|
+
if (resolved.logHookCompleted) {
|
|
3735
|
+
const hookId = hook.id;
|
|
3736
|
+
let logString = `Hook completed for ${String(hookId)}`;
|
|
3737
|
+
await logger.info(logString, {
|
|
3738
|
+
source: "globals.debug.resources.hookInterceptor"
|
|
3739
|
+
});
|
|
3740
|
+
}
|
|
3741
|
+
});
|
|
3742
|
+
}
|
|
3743
|
+
});
|
|
3744
|
+
|
|
3745
|
+
// src/globals/resources/debug/debug.resource.ts
|
|
3746
|
+
var debugResource = defineResource({
|
|
3747
|
+
id: "globals.resources.debug",
|
|
3748
|
+
register: (config) => {
|
|
3749
|
+
return [
|
|
3750
|
+
debugConfig.with(config),
|
|
3751
|
+
globalEventListener,
|
|
3752
|
+
middlewareInterceptorResource,
|
|
3753
|
+
hookInterceptorResource,
|
|
3754
|
+
tasksTrackerMiddleware,
|
|
3755
|
+
resourcesTrackerMiddleware
|
|
3756
|
+
];
|
|
3757
|
+
},
|
|
3758
|
+
meta: {
|
|
3759
|
+
title: "Debug",
|
|
3760
|
+
description: "Debug resource. This is used to debug the system."
|
|
3761
|
+
},
|
|
3762
|
+
tags: [globalTags.system]
|
|
3763
|
+
});
|
|
3764
|
+
|
|
3765
|
+
// src/processHooks.ts
|
|
3766
|
+
var platform2 = getPlatform();
|
|
3767
|
+
var activeErrorHandlers = /* @__PURE__ */ new Set();
|
|
3768
|
+
var processSafetyNetsInstalled = false;
|
|
3769
|
+
function installGlobalProcessSafetyNetsOnce() {
|
|
3770
|
+
if (processSafetyNetsInstalled) return;
|
|
3771
|
+
processSafetyNetsInstalled = true;
|
|
3772
|
+
const onUncaughtException = async (err) => {
|
|
3773
|
+
for (const handler of activeErrorHandlers) {
|
|
3774
|
+
try {
|
|
3775
|
+
await handler(err, "uncaughtException");
|
|
3776
|
+
} catch (_) {
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
};
|
|
3780
|
+
const onUnhandledRejection = async (reason) => {
|
|
3781
|
+
for (const handler of activeErrorHandlers) {
|
|
3782
|
+
try {
|
|
3783
|
+
await handler(reason, "unhandledRejection");
|
|
3784
|
+
} catch (_) {
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
};
|
|
3788
|
+
platform2.onUncaughtException(onUncaughtException);
|
|
3789
|
+
platform2.onUnhandledRejection(onUnhandledRejection);
|
|
3790
|
+
}
|
|
3791
|
+
function registerProcessLevelSafetyNets(handler) {
|
|
3792
|
+
installGlobalProcessSafetyNetsOnce();
|
|
3793
|
+
activeErrorHandlers.add(handler);
|
|
3794
|
+
return () => {
|
|
3795
|
+
activeErrorHandlers.delete(handler);
|
|
3796
|
+
};
|
|
3797
|
+
}
|
|
3798
|
+
var activeDisposers = /* @__PURE__ */ new Set();
|
|
3799
|
+
var shutdownHooksInstalled = false;
|
|
3800
|
+
function installGlobalShutdownHooksOnce() {
|
|
3801
|
+
if (shutdownHooksInstalled) return;
|
|
3802
|
+
shutdownHooksInstalled = true;
|
|
3803
|
+
const handler = async () => {
|
|
3804
|
+
try {
|
|
3805
|
+
const disposers = Array.from(activeDisposers);
|
|
3806
|
+
for (const d of disposers) {
|
|
3807
|
+
try {
|
|
3808
|
+
await d();
|
|
3809
|
+
} catch {
|
|
3810
|
+
}
|
|
3811
|
+
activeDisposers.delete(d);
|
|
3812
|
+
}
|
|
3813
|
+
} finally {
|
|
3814
|
+
try {
|
|
3815
|
+
platform2.exit(0);
|
|
3816
|
+
} catch (e) {
|
|
3817
|
+
if (!(e instanceof PlatformUnsupportedFunction)) {
|
|
3818
|
+
throw e;
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
};
|
|
3823
|
+
platform2.onShutdownSignal(handler);
|
|
3824
|
+
}
|
|
3825
|
+
function registerShutdownHook(disposeOnce) {
|
|
3826
|
+
installGlobalShutdownHooksOnce();
|
|
3827
|
+
activeDisposers.add(disposeOnce);
|
|
3828
|
+
return () => {
|
|
3829
|
+
activeDisposers.delete(disposeOnce);
|
|
3830
|
+
};
|
|
3831
|
+
}
|
|
3832
|
+
|
|
3833
|
+
// src/models/UnhandledError.ts
|
|
3834
|
+
function createDefaultUnhandledError(logger) {
|
|
3835
|
+
return async ({ error, kind, source }) => {
|
|
3836
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
3837
|
+
await logger.error(`${normalizedError.toString()}`, {
|
|
3838
|
+
source,
|
|
3839
|
+
error: normalizedError,
|
|
3840
|
+
data: {
|
|
3841
|
+
kind
|
|
3842
|
+
}
|
|
3843
|
+
});
|
|
3844
|
+
};
|
|
3845
|
+
}
|
|
3846
|
+
function bindProcessErrorHandler(handler) {
|
|
3847
|
+
return async (error, source) => {
|
|
3848
|
+
try {
|
|
3849
|
+
await handler({ error, kind: "process", source });
|
|
3850
|
+
} catch {
|
|
3851
|
+
}
|
|
3852
|
+
};
|
|
3853
|
+
}
|
|
3854
|
+
async function safeReportUnhandledError(handler, info) {
|
|
3855
|
+
try {
|
|
3856
|
+
await handler(info);
|
|
3857
|
+
} catch {
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3860
|
+
|
|
3861
|
+
// src/models/RunResult.ts
|
|
3862
|
+
var RunResult = class {
|
|
3863
|
+
constructor(value, logger, store2, eventManager, taskRunner, disposeFn) {
|
|
3864
|
+
this.value = value;
|
|
3865
|
+
this.logger = logger;
|
|
3866
|
+
this.store = store2;
|
|
3867
|
+
this.eventManager = eventManager;
|
|
3868
|
+
this.taskRunner = taskRunner;
|
|
3869
|
+
this.disposeFn = disposeFn;
|
|
3870
|
+
/**
|
|
3871
|
+
* Run a task within the context of the run result.
|
|
3872
|
+
* @param task - The task to run.
|
|
3873
|
+
* @param args - The arguments to pass to the task.
|
|
3874
|
+
* @returns The result of the task.
|
|
3875
|
+
*/
|
|
3876
|
+
this.runTask = (task, ...args) => {
|
|
3877
|
+
if (typeof task === "string") {
|
|
3878
|
+
const taskId = task;
|
|
3879
|
+
if (!this.store.tasks.has(taskId)) {
|
|
3880
|
+
throw new RuntimeError(`Task "${taskId}" not found.`);
|
|
3881
|
+
}
|
|
3882
|
+
task = this.store.tasks.get(taskId).task;
|
|
3883
|
+
}
|
|
3884
|
+
return this.taskRunner.run(task, ...args);
|
|
3885
|
+
};
|
|
3886
|
+
/**
|
|
3887
|
+
* Emit an event within the context of the run result.
|
|
3888
|
+
* @param event - The event to emit.
|
|
3889
|
+
* @param payload - The payload to emit.
|
|
3890
|
+
*/
|
|
3891
|
+
this.emitEvent = (event, payload) => {
|
|
3892
|
+
if (typeof event === "string") {
|
|
3893
|
+
const eventId = event;
|
|
3894
|
+
if (!this.store.events.has(eventId)) {
|
|
3895
|
+
throw new RuntimeError(`Event "${eventId}" not found.`);
|
|
3896
|
+
}
|
|
3897
|
+
event = this.store.events.get(eventId).event;
|
|
3898
|
+
}
|
|
3899
|
+
return this.eventManager.emit(event, payload, "outside");
|
|
3900
|
+
};
|
|
3901
|
+
/**
|
|
3902
|
+
* Get the value of a resource from the run result.
|
|
3903
|
+
* @param resource - The resource to get the value of.
|
|
3904
|
+
* @returns The value of the resource.
|
|
3905
|
+
*/
|
|
3906
|
+
this.getResourceValue = (resource) => {
|
|
3907
|
+
const resourceId = typeof resource === "string" ? resource : resource.id;
|
|
3908
|
+
if (!this.store.resources.has(resourceId)) {
|
|
3909
|
+
throw new ResourceNotFoundError(resourceId);
|
|
3910
|
+
}
|
|
3911
|
+
return this.store.resources.get(resourceId).value;
|
|
3912
|
+
};
|
|
3913
|
+
this.dispose = () => {
|
|
3914
|
+
return this.disposeFn();
|
|
3915
|
+
};
|
|
3916
|
+
}
|
|
3917
|
+
};
|
|
3918
|
+
|
|
3919
|
+
// src/run.ts
|
|
3920
|
+
var platform3 = getPlatform();
|
|
3921
|
+
async function run(resourceOrResourceWithConfig, options) {
|
|
3922
|
+
await getPlatform().init();
|
|
3923
|
+
const {
|
|
3924
|
+
debug = void 0,
|
|
3925
|
+
logs = {},
|
|
3926
|
+
errorBoundary = true,
|
|
3927
|
+
shutdownHooks = true,
|
|
3928
|
+
dryRun = false,
|
|
3929
|
+
onUnhandledError: onUnhandledErrorOpt,
|
|
3930
|
+
runtimeCycleDetection = true
|
|
3931
|
+
} = options || {};
|
|
3932
|
+
const {
|
|
3933
|
+
printThreshold = platform3.getEnv("NODE_ENV") === "test" ? null : "info",
|
|
3934
|
+
printStrategy = "pretty",
|
|
3935
|
+
bufferLogs = false
|
|
3936
|
+
} = logs;
|
|
3937
|
+
const eventManager = new EventManager({
|
|
3938
|
+
runtimeCycleDetection
|
|
3939
|
+
});
|
|
3940
|
+
let { resource, config } = extractResourceAndConfig(
|
|
3941
|
+
resourceOrResourceWithConfig
|
|
3942
|
+
);
|
|
3943
|
+
const logger = new Logger({
|
|
3944
|
+
printThreshold,
|
|
3945
|
+
printStrategy,
|
|
3946
|
+
bufferLogs
|
|
3947
|
+
});
|
|
3948
|
+
const onUnhandledError = onUnhandledErrorOpt || createDefaultUnhandledError(logger);
|
|
3949
|
+
const store2 = new Store(eventManager, logger, onUnhandledError);
|
|
3950
|
+
const taskRunner = new TaskRunner(store2, eventManager, logger);
|
|
3951
|
+
store2.setTaskRunner(taskRunner);
|
|
3952
|
+
let unhookProcessSafetyNets;
|
|
3953
|
+
if (errorBoundary) {
|
|
3954
|
+
unhookProcessSafetyNets = registerProcessLevelSafetyNets(
|
|
3955
|
+
bindProcessErrorHandler(onUnhandledError)
|
|
3956
|
+
);
|
|
3957
|
+
}
|
|
3958
|
+
const processor = new DependencyProcessor(
|
|
3959
|
+
store2,
|
|
3960
|
+
eventManager,
|
|
3961
|
+
taskRunner,
|
|
3962
|
+
logger
|
|
3963
|
+
);
|
|
3964
|
+
let unhookShutdown;
|
|
3965
|
+
const disposeAll = async () => {
|
|
3966
|
+
try {
|
|
3967
|
+
if (unhookProcessSafetyNets) {
|
|
3968
|
+
unhookProcessSafetyNets();
|
|
3969
|
+
unhookProcessSafetyNets = void 0;
|
|
3970
|
+
}
|
|
3971
|
+
if (unhookShutdown) {
|
|
3972
|
+
unhookShutdown();
|
|
3973
|
+
unhookShutdown = void 0;
|
|
3974
|
+
}
|
|
3975
|
+
} finally {
|
|
3976
|
+
await store2.dispose();
|
|
3977
|
+
}
|
|
3978
|
+
};
|
|
3979
|
+
try {
|
|
3980
|
+
if (debug) {
|
|
3981
|
+
store2.storeGenericItem(debugResource.with(debug));
|
|
3982
|
+
}
|
|
3983
|
+
store2.initializeStore(resource, config);
|
|
3984
|
+
await store2.processOverrides();
|
|
3985
|
+
store2.validateDependencyGraph();
|
|
3986
|
+
store2.validateEventEmissionGraph();
|
|
3987
|
+
const boundedLogger = logger.with({ source: "run" });
|
|
3988
|
+
if (dryRun) {
|
|
3989
|
+
await boundedLogger.debug("Dry run mode. Skipping initialization...");
|
|
3990
|
+
return new RunResult(
|
|
3991
|
+
store2.root.value,
|
|
3992
|
+
logger,
|
|
3993
|
+
store2,
|
|
3994
|
+
eventManager,
|
|
3995
|
+
taskRunner,
|
|
3996
|
+
disposeAll
|
|
3997
|
+
);
|
|
3998
|
+
}
|
|
3999
|
+
await boundedLogger.debug("Events stored. Attaching listeners...");
|
|
4000
|
+
await processor.attachListeners();
|
|
4001
|
+
await boundedLogger.debug("Listeners attached. Computing dependencies...");
|
|
4002
|
+
await processor.computeAllDependencies();
|
|
4003
|
+
await boundedLogger.debug(
|
|
4004
|
+
"Dependencies computed. Proceeding with initialization..."
|
|
4005
|
+
);
|
|
4006
|
+
await processor.initializeRoot();
|
|
4007
|
+
store2.lock();
|
|
4008
|
+
eventManager.lock();
|
|
4009
|
+
await logger.lock();
|
|
4010
|
+
await eventManager.emit(
|
|
4011
|
+
globalEvents.ready,
|
|
4012
|
+
{
|
|
4013
|
+
root: store2.root.resource
|
|
4014
|
+
},
|
|
4015
|
+
"system"
|
|
4016
|
+
);
|
|
4017
|
+
await boundedLogger.info("Runner online. Awaiting tasks and events.");
|
|
4018
|
+
if (shutdownHooks) {
|
|
4019
|
+
unhookShutdown = registerShutdownHook(() => store2.dispose());
|
|
4020
|
+
}
|
|
4021
|
+
return new RunResult(
|
|
4022
|
+
store2.root.value,
|
|
4023
|
+
logger,
|
|
4024
|
+
store2,
|
|
4025
|
+
eventManager,
|
|
4026
|
+
taskRunner,
|
|
4027
|
+
disposeAll
|
|
4028
|
+
);
|
|
4029
|
+
} catch (err) {
|
|
4030
|
+
await disposeAll();
|
|
4031
|
+
throw err;
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
4034
|
+
function extractResourceAndConfig(resourceOrResourceWithConfig) {
|
|
4035
|
+
let resource;
|
|
4036
|
+
let config;
|
|
4037
|
+
if (isResourceWithConfig(resourceOrResourceWithConfig)) {
|
|
4038
|
+
resource = resourceOrResourceWithConfig.resource;
|
|
4039
|
+
config = resourceOrResourceWithConfig.config;
|
|
4040
|
+
} else {
|
|
4041
|
+
resource = resourceOrResourceWithConfig;
|
|
4042
|
+
config = void 0;
|
|
4043
|
+
}
|
|
4044
|
+
return { resource, config };
|
|
4045
|
+
}
|
|
4046
|
+
|
|
4047
|
+
// src/testing.ts
|
|
4048
|
+
var testResourceCounter = 0;
|
|
4049
|
+
function createTestResource(root, options) {
|
|
4050
|
+
return defineResource({
|
|
4051
|
+
id: `testing.${root.id}.${++testResourceCounter}`,
|
|
4052
|
+
register: [root],
|
|
4053
|
+
overrides: options?.overrides || [],
|
|
4054
|
+
dependencies: {
|
|
4055
|
+
taskRunner: globalResources.taskRunner,
|
|
4056
|
+
store: globalResources.store,
|
|
4057
|
+
logger: globalResources.logger,
|
|
4058
|
+
eventManager: globalResources.eventManager
|
|
4059
|
+
},
|
|
4060
|
+
async init(_, deps) {
|
|
4061
|
+
return buildTestFacade(deps);
|
|
4062
|
+
}
|
|
4063
|
+
});
|
|
4064
|
+
}
|
|
4065
|
+
function buildTestFacade(deps) {
|
|
4066
|
+
return {
|
|
4067
|
+
// Run a task within the fully initialized ecosystem
|
|
4068
|
+
runTask: (task, ...args) => deps.taskRunner.run(task, ...args),
|
|
4069
|
+
// Access a resource value by id (string or symbol)
|
|
4070
|
+
getResource: (id2) => deps.store.resources.get(id2)?.value,
|
|
4071
|
+
// Expose internals when needed in tests (not recommended for app usage)
|
|
4072
|
+
taskRunner: deps.taskRunner,
|
|
4073
|
+
store: deps.store,
|
|
4074
|
+
logger: deps.logger,
|
|
4075
|
+
eventManager: deps.eventManager
|
|
4076
|
+
};
|
|
4077
|
+
}
|
|
4078
|
+
|
|
4079
|
+
// src/models/Semaphore.ts
|
|
4080
|
+
var Semaphore = class {
|
|
4081
|
+
constructor(maxPermits) {
|
|
4082
|
+
this.waitingQueue = [];
|
|
4083
|
+
this.disposed = false;
|
|
4084
|
+
if (maxPermits <= 0) {
|
|
4085
|
+
throw new Error("maxPermits must be greater than 0");
|
|
4086
|
+
}
|
|
4087
|
+
this.permits = maxPermits;
|
|
4088
|
+
this.maxPermits = maxPermits;
|
|
4089
|
+
}
|
|
4090
|
+
/**
|
|
4091
|
+
* Acquire a permit. If no permits are available, waits until one becomes available.
|
|
4092
|
+
*/
|
|
4093
|
+
async acquire(options) {
|
|
4094
|
+
if (this.disposed) {
|
|
4095
|
+
throw new Error("Semaphore has been disposed");
|
|
4096
|
+
}
|
|
4097
|
+
if (options?.signal?.aborted) {
|
|
4098
|
+
throw new Error("Operation was aborted");
|
|
4099
|
+
}
|
|
4100
|
+
if (this.permits > 0) {
|
|
4101
|
+
this.permits--;
|
|
4102
|
+
return;
|
|
4103
|
+
}
|
|
4104
|
+
return new Promise((resolve, reject) => {
|
|
4105
|
+
const operation = { resolve, reject };
|
|
4106
|
+
if (options?.timeout && options.timeout > 0) {
|
|
4107
|
+
operation.timeout = setTimeout(() => {
|
|
4108
|
+
this.removeFromQueue(operation);
|
|
4109
|
+
reject(
|
|
4110
|
+
new Error(`Semaphore acquire timeout after ${options.timeout}ms`)
|
|
4111
|
+
);
|
|
4112
|
+
}, options.timeout);
|
|
4113
|
+
}
|
|
4114
|
+
if (options?.signal) {
|
|
4115
|
+
const abortHandler = () => {
|
|
4116
|
+
this.removeFromQueue(operation);
|
|
4117
|
+
reject(new Error("Operation was aborted"));
|
|
4118
|
+
};
|
|
4119
|
+
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
4120
|
+
const originalResolve = operation.resolve;
|
|
4121
|
+
const originalReject = operation.reject;
|
|
4122
|
+
operation.resolve = () => {
|
|
4123
|
+
options.signal.removeEventListener("abort", abortHandler);
|
|
4124
|
+
originalResolve();
|
|
4125
|
+
};
|
|
4126
|
+
operation.reject = (error) => {
|
|
4127
|
+
options.signal.removeEventListener("abort", abortHandler);
|
|
4128
|
+
originalReject(error);
|
|
4129
|
+
};
|
|
4130
|
+
}
|
|
4131
|
+
this.waitingQueue.push(operation);
|
|
4132
|
+
});
|
|
4133
|
+
}
|
|
4134
|
+
/**
|
|
4135
|
+
* Release a permit, allowing waiting operations to proceed.
|
|
4136
|
+
*/
|
|
4137
|
+
release() {
|
|
4138
|
+
if (this.disposed) {
|
|
4139
|
+
return;
|
|
4140
|
+
}
|
|
4141
|
+
if (this.waitingQueue.length > 0) {
|
|
4142
|
+
const nextOperation = this.waitingQueue.shift();
|
|
4143
|
+
if (nextOperation.timeout) {
|
|
4144
|
+
clearTimeout(nextOperation.timeout);
|
|
4145
|
+
}
|
|
4146
|
+
nextOperation.resolve();
|
|
4147
|
+
} else {
|
|
4148
|
+
this.permits = Math.min(this.permits + 1, this.maxPermits);
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
removeFromQueue(operation) {
|
|
4152
|
+
const index = this.waitingQueue.indexOf(operation);
|
|
4153
|
+
if (index !== -1) {
|
|
4154
|
+
this.waitingQueue.splice(index, 1);
|
|
4155
|
+
if (operation.timeout) {
|
|
4156
|
+
clearTimeout(operation.timeout);
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
/**
|
|
4161
|
+
* Execute a function with a permit, automatically releasing it afterwards.
|
|
4162
|
+
*/
|
|
4163
|
+
async withPermit(fn, options) {
|
|
4164
|
+
await this.acquire(options);
|
|
4165
|
+
try {
|
|
4166
|
+
return await fn();
|
|
4167
|
+
} finally {
|
|
4168
|
+
this.release();
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
/**
|
|
4172
|
+
* Dispose the semaphore, rejecting all waiting operations and preventing new ones.
|
|
4173
|
+
*/
|
|
4174
|
+
dispose() {
|
|
4175
|
+
if (this.disposed) {
|
|
4176
|
+
return;
|
|
4177
|
+
}
|
|
4178
|
+
this.disposed = true;
|
|
4179
|
+
while (this.waitingQueue.length > 0) {
|
|
4180
|
+
const operation = this.waitingQueue.shift();
|
|
4181
|
+
if (operation.timeout) {
|
|
4182
|
+
clearTimeout(operation.timeout);
|
|
4183
|
+
}
|
|
4184
|
+
operation.reject(new Error("Semaphore has been disposed"));
|
|
4185
|
+
}
|
|
4186
|
+
}
|
|
4187
|
+
/**
|
|
4188
|
+
* Get current number of available permits (for debugging)
|
|
4189
|
+
*/
|
|
4190
|
+
getAvailablePermits() {
|
|
4191
|
+
return this.permits;
|
|
4192
|
+
}
|
|
4193
|
+
/**
|
|
4194
|
+
* Get current number of waiting operations (for debugging)
|
|
4195
|
+
*/
|
|
4196
|
+
getWaitingCount() {
|
|
4197
|
+
return this.waitingQueue.length;
|
|
4198
|
+
}
|
|
4199
|
+
/**
|
|
4200
|
+
* Get maximum number of permits
|
|
4201
|
+
*/
|
|
4202
|
+
getMaxPermits() {
|
|
4203
|
+
return this.maxPermits;
|
|
4204
|
+
}
|
|
4205
|
+
/**
|
|
4206
|
+
* Check if the semaphore has been disposed
|
|
4207
|
+
*/
|
|
4208
|
+
isDisposed() {
|
|
4209
|
+
return this.disposed;
|
|
4210
|
+
}
|
|
4211
|
+
/**
|
|
4212
|
+
* Get metrics about the current state of the semaphore
|
|
4213
|
+
*/
|
|
4214
|
+
getMetrics() {
|
|
4215
|
+
return {
|
|
4216
|
+
availablePermits: this.permits,
|
|
4217
|
+
waitingCount: this.waitingQueue.length,
|
|
4218
|
+
maxPermits: this.maxPermits,
|
|
4219
|
+
utilization: (this.maxPermits - this.permits) / this.maxPermits,
|
|
4220
|
+
disposed: this.disposed
|
|
4221
|
+
};
|
|
4222
|
+
}
|
|
4223
|
+
};
|
|
4224
|
+
|
|
4225
|
+
// src/index.ts
|
|
4226
|
+
var globals = {
|
|
4227
|
+
events: globalEvents,
|
|
4228
|
+
resources: globalResources,
|
|
4229
|
+
middleware: globalMiddlewares,
|
|
4230
|
+
tags: globalTags
|
|
4231
|
+
};
|
|
4232
|
+
|
|
4233
|
+
exports.DependencyProcessor = DependencyProcessor;
|
|
4234
|
+
exports.Errors = errors_exports;
|
|
4235
|
+
exports.EventManager = EventManager;
|
|
4236
|
+
exports.Logger = Logger;
|
|
4237
|
+
exports.MiddlewareManager = MiddlewareManager;
|
|
4238
|
+
exports.Queue = Queue;
|
|
4239
|
+
exports.ResourceInitializer = ResourceInitializer;
|
|
4240
|
+
exports.RunResult = RunResult;
|
|
4241
|
+
exports.Semaphore = Semaphore;
|
|
4242
|
+
exports.Store = Store;
|
|
4243
|
+
exports.TaskRunner = TaskRunner;
|
|
4244
|
+
exports.allFalse = allFalse;
|
|
4245
|
+
exports.bindProcessErrorHandler = bindProcessErrorHandler;
|
|
4246
|
+
exports.createContext = createContext;
|
|
4247
|
+
exports.createDefaultUnhandledError = createDefaultUnhandledError;
|
|
4248
|
+
exports.createTestResource = createTestResource;
|
|
4249
|
+
exports.definitions = defs_exports;
|
|
4250
|
+
exports.event = defineEvent;
|
|
4251
|
+
exports.getConfig = getConfig;
|
|
4252
|
+
exports.globals = globals;
|
|
4253
|
+
exports.hook = defineHook;
|
|
4254
|
+
exports.levelNormal = levelNormal;
|
|
4255
|
+
exports.levelVerbose = levelVerbose;
|
|
4256
|
+
exports.override = defineOverride;
|
|
4257
|
+
exports.resource = defineResource;
|
|
4258
|
+
exports.resourceMiddleware = defineResourceMiddleware;
|
|
4259
|
+
exports.run = run;
|
|
4260
|
+
exports.safeReportUnhandledError = safeReportUnhandledError;
|
|
4261
|
+
exports.tag = defineTag;
|
|
4262
|
+
exports.task = defineTask;
|
|
4263
|
+
exports.taskMiddleware = defineTaskMiddleware;
|
|
4264
|
+
//# sourceMappingURL=index.cjs.map
|
|
4265
|
+
//# sourceMappingURL=index.cjs.map
|