@cldmv/slothlet 2.6.3 → 2.7.1
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/AGENT-USAGE.md +536 -0
- package/API-RULES-CONDITIONS.md +367 -0
- package/API-RULES.md +777 -0
- package/README.md +502 -1
- package/dist/lib/helpers/als-eventemitter.mjs +137 -0
- package/dist/lib/helpers/hooks.mjs +389 -0
- package/dist/lib/modes/slothlet_lazy.mjs +25 -19
- package/dist/lib/runtime/runtime-asynclocalstorage.mjs +97 -16
- package/dist/lib/runtime/runtime-livebindings.mjs +127 -5
- package/dist/slothlet.mjs +69 -2
- package/package.json +6 -3
- package/types/dist/lib/helpers/als-eventemitter.d.mts +33 -0
- package/types/dist/lib/helpers/als-eventemitter.d.mts.map +1 -1
- package/types/dist/lib/helpers/hooks.d.mts +342 -0
- package/types/dist/lib/helpers/hooks.d.mts.map +1 -0
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime-livebindings.d.mts +4 -3
- package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
- package/types/dist/slothlet.d.mts.map +1 -1
|
@@ -256,7 +256,73 @@ export function runWithCtx(ctx, fn, thisArg, args) {
|
|
|
256
256
|
|
|
257
257
|
try {
|
|
258
258
|
|
|
259
|
-
|
|
259
|
+
if (!ctx.hookManager?.enabled || !fn.__slothletPath) {
|
|
260
|
+
return Reflect.apply(fn, thisArg, args);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
const path = fn.__slothletPath;
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
|
|
268
|
+
const beforeResult = ctx.hookManager.executeBeforeHooks(path, args);
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
if (beforeResult.cancelled) {
|
|
272
|
+
ctx.hookManager.executeAlwaysHooks(path, beforeResult.value, []);
|
|
273
|
+
return beforeResult.value;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
const actualArgs = beforeResult.args;
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
const result = Reflect.apply(fn, thisArg, actualArgs);
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
284
|
+
return result.then(
|
|
285
|
+
(resolvedResult) => {
|
|
286
|
+
|
|
287
|
+
const finalResult = ctx.hookManager.executeAfterHooks(path, resolvedResult);
|
|
288
|
+
ctx.hookManager.executeAlwaysHooks(path, finalResult, []);
|
|
289
|
+
return finalResult;
|
|
290
|
+
},
|
|
291
|
+
(error) => {
|
|
292
|
+
|
|
293
|
+
if (!ctx.hookManager.reportedErrors.has(error)) {
|
|
294
|
+
ctx.hookManager.reportedErrors.add(error);
|
|
295
|
+
ctx.hookManager.executeErrorHooks(path, error, { type: "function" });
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
ctx.hookManager.executeAlwaysHooks(path, undefined, [error]);
|
|
299
|
+
|
|
300
|
+
if (!ctx.hookManager.suppressErrors) {
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
const finalResult = ctx.hookManager.executeAfterHooks(path, result);
|
|
310
|
+
ctx.hookManager.executeAlwaysHooks(path, finalResult, []);
|
|
311
|
+
return finalResult;
|
|
312
|
+
} catch (error) {
|
|
313
|
+
|
|
314
|
+
if (!ctx.hookManager.reportedErrors.has(error)) {
|
|
315
|
+
ctx.hookManager.reportedErrors.add(error);
|
|
316
|
+
ctx.hookManager.executeErrorHooks(path, error, { type: "function" });
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
ctx.hookManager.executeAlwaysHooks(path, undefined, [error]);
|
|
320
|
+
|
|
321
|
+
if (!ctx.hookManager.suppressErrors) {
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
324
|
+
return undefined;
|
|
325
|
+
}
|
|
260
326
|
} finally {
|
|
261
327
|
|
|
262
328
|
setActiveInstance(previousActiveInstance);
|
|
@@ -264,11 +330,67 @@ export function runWithCtx(ctx, fn, thisArg, args) {
|
|
|
264
330
|
}
|
|
265
331
|
|
|
266
332
|
|
|
267
|
-
export function makeWrapper(
|
|
268
|
-
|
|
269
|
-
|
|
333
|
+
export function makeWrapper(ctx) {
|
|
334
|
+
const cache = new WeakMap();
|
|
335
|
+
|
|
336
|
+
return function wrapperFunction(obj, currentPath = "") {
|
|
337
|
+
if (obj == null || (typeof obj !== "object" && typeof obj !== "function")) {
|
|
338
|
+
return obj;
|
|
339
|
+
}
|
|
340
|
+
|
|
270
341
|
|
|
271
|
-
|
|
342
|
+
if (cache.has(obj)) {
|
|
343
|
+
return cache.get(obj);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const proxied = new Proxy(obj, {
|
|
347
|
+
apply(target, thisArg, args) {
|
|
348
|
+
|
|
349
|
+
return runWithCtx(ctx, target, thisArg, args);
|
|
350
|
+
},
|
|
351
|
+
get(target, prop, receiver) {
|
|
352
|
+
const value = Reflect.get(target, prop, receiver);
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
const newPath = currentPath ? `${currentPath}.${String(prop)}` : String(prop);
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
const isInternalProperty = currentPath === "" && ["hooks", "__ctx", "shutdown", "_impl"].includes(String(prop));
|
|
359
|
+
const isInternalPath =
|
|
360
|
+
newPath === "hooks" ||
|
|
361
|
+
newPath.startsWith("hooks.") ||
|
|
362
|
+
newPath === "__ctx" ||
|
|
363
|
+
newPath.startsWith("__ctx.") ||
|
|
364
|
+
newPath === "shutdown" ||
|
|
365
|
+
newPath.startsWith("shutdown.") ||
|
|
366
|
+
newPath === "_impl" ||
|
|
367
|
+
newPath.startsWith("_impl.");
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
if (typeof value === "function" && !value.__slothletPath && !isInternalProperty && !isInternalPath) {
|
|
371
|
+
try {
|
|
372
|
+
Object.defineProperty(value, "__slothletPath", {
|
|
373
|
+
value: newPath,
|
|
374
|
+
writable: false,
|
|
375
|
+
enumerable: false,
|
|
376
|
+
configurable: true
|
|
377
|
+
});
|
|
378
|
+
} catch {
|
|
379
|
+
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
if ((typeof value === "function" || (value && typeof value === "object")) && !isInternalPath) {
|
|
385
|
+
return wrapperFunction(value, newPath);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return value;
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
cache.set(obj, proxied);
|
|
393
|
+
return proxied;
|
|
272
394
|
};
|
|
273
395
|
}
|
|
274
396
|
|
package/dist/slothlet.mjs
CHANGED
|
@@ -31,6 +31,8 @@ import {
|
|
|
31
31
|
buildCategoryDecisions
|
|
32
32
|
} from "@cldmv/slothlet/helpers/api_builder";
|
|
33
33
|
import { updateInstanceData, cleanupInstance } from "./lib/helpers/instance-manager.mjs";
|
|
34
|
+
import { disableAlsForEventEmitters, cleanupAllSlothletListeners } from "./lib/helpers/als-eventemitter.mjs";
|
|
35
|
+
import { HookManager } from "./lib/helpers/hooks.mjs";
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
|
|
@@ -222,11 +224,34 @@ const slothletObject = {
|
|
|
222
224
|
if (executionEngine === "singleton") {
|
|
223
225
|
|
|
224
226
|
|
|
225
|
-
const { context = null, reference = null, sanitize = null, engine, mode, ...loadConfig } = options;
|
|
227
|
+
const { context = null, reference = null, sanitize = null, hooks = false, engine, mode, ...loadConfig } = options;
|
|
226
228
|
this.context = context;
|
|
227
229
|
this.reference = reference;
|
|
228
230
|
|
|
229
231
|
|
|
232
|
+
let hooksEnabled = false;
|
|
233
|
+
let hooksPattern = null;
|
|
234
|
+
let hooksSuppressErrors = false;
|
|
235
|
+
|
|
236
|
+
if (hooks === true || hooks === false) {
|
|
237
|
+
|
|
238
|
+
hooksEnabled = hooks;
|
|
239
|
+
hooksPattern = hooks ? "**" : null;
|
|
240
|
+
} else if (typeof hooks === "string") {
|
|
241
|
+
|
|
242
|
+
hooksEnabled = true;
|
|
243
|
+
hooksPattern = hooks;
|
|
244
|
+
} else if (hooks && typeof hooks === "object") {
|
|
245
|
+
|
|
246
|
+
hooksEnabled = hooks.enabled !== false;
|
|
247
|
+
hooksPattern = hooks.pattern || "**";
|
|
248
|
+
hooksSuppressErrors = hooks.suppressErrors || false;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
this.hookManager = new HookManager(hooksEnabled, hooksPattern, { suppressErrors: hooksSuppressErrors });
|
|
253
|
+
|
|
254
|
+
|
|
230
255
|
if (sanitize !== null) {
|
|
231
256
|
this.config.sanitize = sanitize;
|
|
232
257
|
}
|
|
@@ -253,6 +278,8 @@ const slothletObject = {
|
|
|
253
278
|
await this.load(loadConfig, { context, reference });
|
|
254
279
|
|
|
255
280
|
|
|
281
|
+
|
|
282
|
+
|
|
256
283
|
|
|
257
284
|
return this.boundapi;
|
|
258
285
|
} else {
|
|
@@ -310,6 +337,27 @@ const slothletObject = {
|
|
|
310
337
|
} else {
|
|
311
338
|
this.api = await this.modes.eager.create.call(this, apiDir, this.config.apiDepth || Infinity, 0);
|
|
312
339
|
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
if (this.hookManager) {
|
|
343
|
+
const hooksApi = {
|
|
344
|
+
on: (name, type, handler, options) => this.hookManager.on(name, type, handler, options),
|
|
345
|
+
off: (idOrPattern) => this.hookManager.off(idOrPattern),
|
|
346
|
+
enable: (pattern) => this.hookManager.enable(pattern),
|
|
347
|
+
disable: () => this.hookManager.disable(),
|
|
348
|
+
clear: (type) => this.hookManager.clear(type),
|
|
349
|
+
list: (type) => this.hookManager.list(type)
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
Object.defineProperty(this.api, "hooks", {
|
|
354
|
+
value: hooksApi,
|
|
355
|
+
writable: false,
|
|
356
|
+
enumerable: true,
|
|
357
|
+
configurable: true
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
313
361
|
if (this.config.debug) console.log(this.api);
|
|
314
362
|
|
|
315
363
|
|
|
@@ -899,7 +947,8 @@ const slothletObject = {
|
|
|
899
947
|
this.safeDefine(this.boundapi, "__ctx", {
|
|
900
948
|
self: this.boundapi,
|
|
901
949
|
context: this.context,
|
|
902
|
-
reference: this.reference
|
|
950
|
+
reference: this.reference,
|
|
951
|
+
hookManager: this.hookManager
|
|
903
952
|
});
|
|
904
953
|
},
|
|
905
954
|
|
|
@@ -1104,12 +1153,30 @@ const slothletObject = {
|
|
|
1104
1153
|
this._boundAPIShutdown = null;
|
|
1105
1154
|
|
|
1106
1155
|
|
|
1156
|
+
if (this.hookManager) {
|
|
1157
|
+
this.hookManager.cleanup();
|
|
1158
|
+
this.hookManager = null;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
|
|
1107
1162
|
|
|
1108
1163
|
|
|
1109
1164
|
if (this.instanceId) {
|
|
1110
1165
|
await cleanupInstance(this.instanceId);
|
|
1111
1166
|
}
|
|
1112
1167
|
|
|
1168
|
+
|
|
1169
|
+
|
|
1170
|
+
try {
|
|
1171
|
+
|
|
1172
|
+
cleanupAllSlothletListeners();
|
|
1173
|
+
|
|
1174
|
+
disableAlsForEventEmitters();
|
|
1175
|
+
} catch (cleanupError) {
|
|
1176
|
+
|
|
1177
|
+
console.warn("[slothlet] Warning: EventEmitter cleanup failed:", cleanupError.message);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1113
1180
|
if (apiError || internalError) throw apiError || internalError;
|
|
1114
1181
|
}
|
|
1115
1182
|
} finally {
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cldmv/slothlet",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.1",
|
|
4
4
|
"moduleVersions": {
|
|
5
|
-
"lazy": "1.3.
|
|
6
|
-
"eager": "1.3.
|
|
5
|
+
"lazy": "1.3.1",
|
|
6
|
+
"eager": "1.3.1"
|
|
7
7
|
},
|
|
8
8
|
"description": "Slothlet: Modular API Loader for Node.js. Lazy mode dynamically loads API modules and submodules only when accessed, supporting both lazy and eager loading.",
|
|
9
9
|
"main": "./index.cjs",
|
|
@@ -188,6 +188,9 @@
|
|
|
188
188
|
"index.cjs",
|
|
189
189
|
"README.md",
|
|
190
190
|
"LICENSE",
|
|
191
|
+
"API-RULES.md",
|
|
192
|
+
"API-RULES-CONDITIONS.md",
|
|
193
|
+
"AGENT-USAGE.md",
|
|
191
194
|
"types/dist/",
|
|
192
195
|
"types/index.d.mts",
|
|
193
196
|
"types/index.d.mts.map",
|
|
@@ -19,5 +19,38 @@
|
|
|
19
19
|
* enableAlsForEventEmitters(als);
|
|
20
20
|
*/
|
|
21
21
|
export function enableAlsForEventEmitters(als?: AsyncLocalStorage<any>): void;
|
|
22
|
+
/**
|
|
23
|
+
* Disable AsyncLocalStorage context propagation for EventEmitter instances.
|
|
24
|
+
*
|
|
25
|
+
* @function disableAlsForEventEmitters
|
|
26
|
+
* @package
|
|
27
|
+
*
|
|
28
|
+
* @description
|
|
29
|
+
* Restores original EventEmitter methods, removing the AsyncLocalStorage
|
|
30
|
+
* context propagation. This should be called during cleanup to prevent
|
|
31
|
+
* hanging AsyncResource instances that can keep the event loop alive.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Disable ALS patching during shutdown
|
|
35
|
+
* disableAlsForEventEmitters();
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* Clean up ALL listeners that went through slothlet's EventEmitter patching.
|
|
39
|
+
*
|
|
40
|
+
* @function cleanupAllSlothletListeners
|
|
41
|
+
* @package
|
|
42
|
+
*
|
|
43
|
+
* @description
|
|
44
|
+
* Removes all event listeners that were registered through slothlet's patched
|
|
45
|
+
* EventEmitter methods. This includes listeners from third-party libraries
|
|
46
|
+
* that got wrapped with AsyncResource instances. This nuclear cleanup option
|
|
47
|
+
* should be called during shutdown to prevent hanging listeners.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // Clean up all patched listeners during shutdown
|
|
51
|
+
* cleanupAllSlothletListeners();
|
|
52
|
+
*/
|
|
53
|
+
export function cleanupAllSlothletListeners(): void;
|
|
54
|
+
export function disableAlsForEventEmitters(): void;
|
|
22
55
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
23
56
|
//# sourceMappingURL=als-eventemitter.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"als-eventemitter.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/als-eventemitter.mjs"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"als-eventemitter.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/als-eventemitter.mjs"],"names":[],"mappings":"AAkDA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,8EAiNC;AAED;;;;;;;;;;;;;;GAcG;AACH;;;;;;;;;;;;;;;GAeG;AACH,oDAyBC;AAED,mDAmCC;kCApViC,kBAAkB"}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class HookManager
|
|
3
|
+
* @internal
|
|
4
|
+
* @private
|
|
5
|
+
*
|
|
6
|
+
* @description
|
|
7
|
+
* Manages registration, pattern matching, and execution of hooks for slothlet API calls.
|
|
8
|
+
* Hooks are executed in priority order (higher priority first), then registration order.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // Create hook manager
|
|
12
|
+
* const manager = new HookManager();
|
|
13
|
+
* manager.on("logger", "before", (ctx) => { console.log(ctx.path); });
|
|
14
|
+
*/
|
|
15
|
+
export class HookManager {
|
|
16
|
+
/**
|
|
17
|
+
* @constructor
|
|
18
|
+
* @param {boolean} [enabled=true] - Initial enabled state
|
|
19
|
+
* @param {string} [defaultPattern="**"] - Default pattern for filtering
|
|
20
|
+
* @param {object} [options={}] - Additional options
|
|
21
|
+
* @param {boolean} [options.suppressErrors=false] - If true, errors are logged but not thrown (except for before/after hooks)
|
|
22
|
+
*/
|
|
23
|
+
constructor(enabled?: boolean, defaultPattern?: string, options?: {
|
|
24
|
+
suppressErrors?: boolean;
|
|
25
|
+
});
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
defaultPattern: string;
|
|
28
|
+
suppressErrors: boolean;
|
|
29
|
+
hooks: Map<any, any>;
|
|
30
|
+
registrationOrder: number;
|
|
31
|
+
reportedErrors: WeakSet<object>;
|
|
32
|
+
/**
|
|
33
|
+
* @function on
|
|
34
|
+
* @public
|
|
35
|
+
* @param {string} name - Hook name/ID for debugging and removal
|
|
36
|
+
* @param {string} type - Hook type: "before", "after", "always", or "error"
|
|
37
|
+
* @param {Function} handler - Hook handler function with type-specific signature:
|
|
38
|
+
* - before: ({ path, args }) => modified args array or value to short-circuit
|
|
39
|
+
* - after: ({ path, result }) => transformed result
|
|
40
|
+
* - always: ({ path, result, hasError, errors }) => void (read-only)
|
|
41
|
+
* - error: ({ path, error, errorType, source }) => void (observer)
|
|
42
|
+
* @param {object} [options] - Registration options
|
|
43
|
+
* @param {number} [options.priority=100] - Execution priority (higher = earlier)
|
|
44
|
+
* @param {string} [options.pattern] - Glob pattern for path filtering
|
|
45
|
+
* @returns {string} Hook name/ID for later removal
|
|
46
|
+
*
|
|
47
|
+
* @description
|
|
48
|
+
* Register a hook with optional priority and pattern filtering.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* // Register hook with priority
|
|
52
|
+
* manager.on("validator", "before", handler, { priority: 200 });
|
|
53
|
+
*/
|
|
54
|
+
public on(name: string, type: string, handler: Function, options?: {
|
|
55
|
+
priority?: number;
|
|
56
|
+
pattern?: string;
|
|
57
|
+
}): string;
|
|
58
|
+
/**
|
|
59
|
+
* Clean up all hooks and resources
|
|
60
|
+
* @public
|
|
61
|
+
* @description
|
|
62
|
+
* Clears all registered hooks and resets internal state.
|
|
63
|
+
* Should be called during shutdown to prevent memory leaks.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* // Clean up during shutdown
|
|
67
|
+
* manager.cleanup();
|
|
68
|
+
*/
|
|
69
|
+
public cleanup(): void;
|
|
70
|
+
/**
|
|
71
|
+
* @function off
|
|
72
|
+
* @public
|
|
73
|
+
* @param {string} nameOrPattern - Hook name or glob pattern to remove
|
|
74
|
+
* @returns {boolean} True if one or more hooks were removed
|
|
75
|
+
*
|
|
76
|
+
* @description
|
|
77
|
+
* Remove registered hook(s) by exact name or pattern matching.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* // Remove hook by exact name
|
|
81
|
+
* manager.off("validator");
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* // Remove all hooks matching pattern
|
|
85
|
+
* manager.off("math.*");
|
|
86
|
+
*/
|
|
87
|
+
public off(nameOrPattern: string): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* @function clear
|
|
90
|
+
* @public
|
|
91
|
+
* @param {string} [type] - Optional hook type to clear ("before", "after", "always", "error")
|
|
92
|
+
* @returns {void}
|
|
93
|
+
*
|
|
94
|
+
* @description
|
|
95
|
+
* Remove registered hooks. If type is provided, only hooks of that type are removed.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* // Clear all hooks
|
|
99
|
+
* manager.clear();
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* // Clear only before hooks
|
|
103
|
+
* manager.clear("before");
|
|
104
|
+
*/
|
|
105
|
+
public clear(type?: string): void;
|
|
106
|
+
/**
|
|
107
|
+
* @function list
|
|
108
|
+
* @public
|
|
109
|
+
* @param {string} [type] - Optional hook type to filter by ("before", "after", "always", "error")
|
|
110
|
+
* @returns {Array<object>} Array of hook metadata
|
|
111
|
+
*
|
|
112
|
+
* @description
|
|
113
|
+
* List registered hooks with their metadata. When type is provided, only hooks
|
|
114
|
+
* matching that type are returned.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* // List all hooks
|
|
118
|
+
* const hooks = manager.list();
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* // List only before hooks
|
|
122
|
+
* const beforeHooks = manager.list("before");
|
|
123
|
+
*/
|
|
124
|
+
public list(type?: string): Array<object>;
|
|
125
|
+
/**
|
|
126
|
+
* @function enable
|
|
127
|
+
* @public
|
|
128
|
+
* @param {string} [pattern] - Optional new default pattern
|
|
129
|
+
* @returns {void}
|
|
130
|
+
*
|
|
131
|
+
* @description
|
|
132
|
+
* Enable hook execution, optionally updating default pattern.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Enable with new pattern
|
|
136
|
+
* manager.enable("database.*");
|
|
137
|
+
*/
|
|
138
|
+
public enable(pattern?: string): void;
|
|
139
|
+
/**
|
|
140
|
+
* @function disable
|
|
141
|
+
* @public
|
|
142
|
+
* @returns {void}
|
|
143
|
+
*
|
|
144
|
+
* @description
|
|
145
|
+
* Disable hook execution (fast-path bypass).
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* // Disable hooks
|
|
149
|
+
* manager.disable();
|
|
150
|
+
*/
|
|
151
|
+
public disable(): void;
|
|
152
|
+
/**
|
|
153
|
+
* @function executeBeforeHooks
|
|
154
|
+
* @internal
|
|
155
|
+
* @private
|
|
156
|
+
* @param {string} path - Function path (e.g., "database.users.create")
|
|
157
|
+
* @param {Array} args - Function arguments
|
|
158
|
+
* @returns {{cancelled: boolean, value?: any, args: Array}} Execution result
|
|
159
|
+
*
|
|
160
|
+
* @description
|
|
161
|
+
* Execute before hooks in priority order. Returns object indicating if execution
|
|
162
|
+
* should be cancelled (short-circuited) and potentially modified arguments.
|
|
163
|
+
*
|
|
164
|
+
* Hook return semantics:
|
|
165
|
+
* - undefined: continue to next hook/function
|
|
166
|
+
* - Array: modified arguments for next hook/function
|
|
167
|
+
* - Other value: short-circuit and return this value
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* // Execute before hooks
|
|
171
|
+
* const result = manager.executeBeforeHooks("database.users.create", [data]);
|
|
172
|
+
* if (result.cancelled) return result.value;
|
|
173
|
+
*/
|
|
174
|
+
private executeBeforeHooks;
|
|
175
|
+
/**
|
|
176
|
+
* @function executeAfterHooks
|
|
177
|
+
* @internal
|
|
178
|
+
* @private
|
|
179
|
+
* @param {string} path - Function path
|
|
180
|
+
* @param {any} initialResult - Initial result from function
|
|
181
|
+
* @returns {any} Transformed result
|
|
182
|
+
*
|
|
183
|
+
* @description
|
|
184
|
+
* Execute after hooks in priority order, chaining results through each hook.
|
|
185
|
+
* Each hook receives the previous hook's return value (or initial result).
|
|
186
|
+
* After hooks only run if the function actually executed (not short-circuited).
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* // Execute after hooks with chaining
|
|
190
|
+
* const finalResult = manager.executeAfterHooks("database.users.create", result);
|
|
191
|
+
*/
|
|
192
|
+
private executeAfterHooks;
|
|
193
|
+
/**
|
|
194
|
+
* @function executeAlwaysHooks
|
|
195
|
+
* @internal
|
|
196
|
+
* @private
|
|
197
|
+
* @param {string} path - Function path
|
|
198
|
+
* @param {any} result - Final result (from function or short-circuit)
|
|
199
|
+
* @param {Array<Error>} [errors=[]] - Array of errors that occurred during execution
|
|
200
|
+
* @returns {void}
|
|
201
|
+
*
|
|
202
|
+
* @description
|
|
203
|
+
* Execute always hooks (like finally blocks). These hooks always run regardless
|
|
204
|
+
* of whether execution was short-circuited, completed normally, or threw errors.
|
|
205
|
+
* Always hooks receive full execution context including both errors and results,
|
|
206
|
+
* allowing a single hook to handle all logging scenarios.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* // Execute always hooks with success result
|
|
210
|
+
* manager.executeAlwaysHooks("database.users.create", result, []);
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* // Execute always hooks with error context
|
|
214
|
+
* manager.executeAlwaysHooks("database.users.create", undefined, [error]);
|
|
215
|
+
*/
|
|
216
|
+
private executeAlwaysHooks;
|
|
217
|
+
/**
|
|
218
|
+
* @function executeErrorHooks
|
|
219
|
+
* @internal
|
|
220
|
+
* @private
|
|
221
|
+
* @param {string} path - Function path
|
|
222
|
+
* @param {Error} error - Error that was thrown
|
|
223
|
+
* @param {Object} [source] - Source information about where error originated
|
|
224
|
+
* @param {string} source.type - Source type: 'before', 'function', 'after', 'always'
|
|
225
|
+
* @param {string} [source.hookId] - Hook ID if error came from a hook
|
|
226
|
+
* @param {string} [source.hookTag] - Hook tag if error came from a hook
|
|
227
|
+
* @returns {void}
|
|
228
|
+
*
|
|
229
|
+
* @description
|
|
230
|
+
* Execute error hooks (observers only, errors bubble naturally).
|
|
231
|
+
* Provides detailed context about where the error originated.
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* // Execute error hooks with source info
|
|
235
|
+
* manager.executeErrorHooks("database.users.create", error, {
|
|
236
|
+
* type: 'before',
|
|
237
|
+
* hookId: 'hook-123',
|
|
238
|
+
* hookTag: 'validation'
|
|
239
|
+
* });
|
|
240
|
+
*/
|
|
241
|
+
private executeErrorHooks;
|
|
242
|
+
/**
|
|
243
|
+
* @function _getMatchingHooks
|
|
244
|
+
* @internal
|
|
245
|
+
* @private
|
|
246
|
+
* @param {string} type - Hook type to match
|
|
247
|
+
* @param {string} path - Function path to test against patterns
|
|
248
|
+
* @returns {Array<object>} Sorted array of matching hooks
|
|
249
|
+
*
|
|
250
|
+
* @description
|
|
251
|
+
* Get hooks matching type and path, sorted by priority (DESC) then order (ASC).
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* // Get matching hooks
|
|
255
|
+
* const hooks = manager._getMatchingHooks("before", "database.users.create");
|
|
256
|
+
*/
|
|
257
|
+
private _getMatchingHooks;
|
|
258
|
+
/**
|
|
259
|
+
* @function _compilePattern
|
|
260
|
+
* @internal
|
|
261
|
+
* @private
|
|
262
|
+
* @param {string} pattern - Glob pattern string
|
|
263
|
+
* @returns {RegExp|null} Compiled RegExp or null for negation patterns
|
|
264
|
+
*
|
|
265
|
+
* @description
|
|
266
|
+
* Compile glob pattern to RegExp with support for:
|
|
267
|
+
* - `*`: single-level wildcard
|
|
268
|
+
* - `**`: multi-level wildcard
|
|
269
|
+
* - `{users,posts}`: brace expansion (max 10 nesting levels)
|
|
270
|
+
* - `!internal.*`: negation patterns
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* // Compile pattern
|
|
274
|
+
* const regex = manager._compilePattern("database.*.create");
|
|
275
|
+
*/
|
|
276
|
+
private _compilePattern;
|
|
277
|
+
/**
|
|
278
|
+
* @function _expandBraces
|
|
279
|
+
* @internal
|
|
280
|
+
* @private
|
|
281
|
+
* @param {string} pattern - Pattern with potential braces
|
|
282
|
+
* @param {number} [depth=0] - Current nesting depth
|
|
283
|
+
* @returns {Array<string>} Expanded pattern alternatives
|
|
284
|
+
*
|
|
285
|
+
* @description
|
|
286
|
+
* Expand brace patterns like `{users,posts}` to multiple alternatives.
|
|
287
|
+
* Limits nesting to MAX_BRACE_NESTING to prevent performance issues.
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* // Expand braces
|
|
291
|
+
* const patterns = manager._expandBraces("{users,posts}.create");
|
|
292
|
+
* // Returns: ["users.create", "posts.create"]
|
|
293
|
+
*/
|
|
294
|
+
private _expandBraces;
|
|
295
|
+
/**
|
|
296
|
+
* @function _splitAlternatives
|
|
297
|
+
* @internal
|
|
298
|
+
* @private
|
|
299
|
+
* @param {string} str - String to split on commas
|
|
300
|
+
* @returns {Array<string>} Split alternatives
|
|
301
|
+
*
|
|
302
|
+
* @description
|
|
303
|
+
* Split brace content on commas, respecting nested braces.
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* // Split alternatives
|
|
307
|
+
* const alts = manager._splitAlternatives("users,posts,{admin,guest}");
|
|
308
|
+
*/
|
|
309
|
+
private _splitAlternatives;
|
|
310
|
+
/**
|
|
311
|
+
* @function _patternToRegex
|
|
312
|
+
* @internal
|
|
313
|
+
* @private
|
|
314
|
+
* @param {string} pattern - Pattern without braces
|
|
315
|
+
* @returns {string} Regex pattern string
|
|
316
|
+
*
|
|
317
|
+
* @description
|
|
318
|
+
* Convert glob pattern to regex pattern string.
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* // Convert pattern
|
|
322
|
+
* const regex = manager._patternToRegex("database.*.create");
|
|
323
|
+
*/
|
|
324
|
+
private _patternToRegex;
|
|
325
|
+
/**
|
|
326
|
+
* @function _matchPattern
|
|
327
|
+
* @internal
|
|
328
|
+
* @private
|
|
329
|
+
* @param {RegExp|object} compiledPattern - Compiled pattern or negation object
|
|
330
|
+
* @param {string} path - Path to test
|
|
331
|
+
* @returns {boolean} True if path matches pattern
|
|
332
|
+
*
|
|
333
|
+
* @description
|
|
334
|
+
* Test if path matches compiled pattern, handling negation.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* // Match pattern
|
|
338
|
+
* const matches = manager._matchPattern(compiledPattern, "database.users.create");
|
|
339
|
+
*/
|
|
340
|
+
private _matchPattern;
|
|
341
|
+
}
|
|
342
|
+
//# sourceMappingURL=hooks.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/hooks.mjs"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;GAaG;AACH;IACC;;;;;;OAMG;IACH,sBALW,OAAO,mBACP,MAAM,YAEd;QAA0B,cAAc,GAAhC,OAAO;KACjB,EAQA;IANA,iBAAsB;IACtB,uBAAoC;IACpC,wBAAqD;IACrD,qBAAsB;IACtB,0BAA0B;IAC1B,gCAAmC;IAGpC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,gBAnBW,MAAM,QACN,MAAM,+BAOd;QAAyB,QAAQ,GAAzB,MAAM;QACW,OAAO,GAAxB,MAAM;KACd,GAAU,MAAM,CA0BlB;IAED;;;;;;;;;;OAUG;IACH,uBAKC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,0BAdW,MAAM,GACJ,OAAO,CA6BnB;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,oBAdW,MAAM,GACJ,IAAI,CA0BhB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,mBAfW,MAAM,GACJ,KAAK,CAAC,MAAM,CAAC,CA4BzB;IAED;;;;;;;;;;;;OAYG;IACH,wBAVW,MAAM,GACJ,IAAI,CAchB;IAED;;;;;;;;;;;OAWG;IACH,kBATa,IAAI,CAWhB;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,2BAkCC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,0BAwBC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,2BAqBC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,0BAyBC;IAED;;;;;;;;;;;;;;OAcG;IACH,0BAkBC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,wBAmBC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,sBA4CC;IAED;;;;;;;;;;;;;OAaG;IACH,2BAuBC;IAED;;;;;;;;;;;;;OAaG;IACH,wBAiBC;IAED;;;;;;;;;;;;;;OAcG;IACH,sBAOC;CACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-asynclocalstorage.d.mts","sourceRoot":"","sources":["../../../../dist/lib/runtime/runtime-asynclocalstorage.mjs"],"names":[],"mappings":"AAuCA;;;;;GAKG;AACH,wBAHU,qBAAqB,CAGkB;AAsB1C,gCAdI,MAAM,yBAEN,GAAG,gBAED,GAAG,
|
|
1
|
+
{"version":3,"file":"runtime-asynclocalstorage.d.mts","sourceRoot":"","sources":["../../../../dist/lib/runtime/runtime-asynclocalstorage.mjs"],"names":[],"mappings":"AAuCA;;;;;GAKG;AACH,wBAHU,qBAAqB,CAGkB;AAsB1C,gCAdI,MAAM,yBAEN,GAAG,gBAED,GAAG,CAoGf;AAiBM,0BAZM,MAAM,GAAC,IAAI,CAY0B;AAkN3C,iCAjBI,MAAM,YAiJhB;AAuSD;;;;;;;;;;;;;GAaG;AACH,mBATU,WAAS,MAAM,CAS6B;AAEtD;;;;;;;;;;;;;GAaG;AACH,sBATU,MAAM,CAS4C;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBATU,MAAM,CASgD;;kCApzB9B,kBAAkB"}
|