@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
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 CLDMV/Shinrai
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
const MAX_BRACE_NESTING = 10;
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
export class HookManager {
|
|
25
|
+
|
|
26
|
+
constructor(enabled = true, defaultPattern = "**", options = {}) {
|
|
27
|
+
this.enabled = enabled;
|
|
28
|
+
this.defaultPattern = defaultPattern;
|
|
29
|
+
this.suppressErrors = options.suppressErrors || false;
|
|
30
|
+
this.hooks = new Map();
|
|
31
|
+
this.registrationOrder = 0;
|
|
32
|
+
this.reportedErrors = new WeakSet();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
on(name, type, handler, options = {}) {
|
|
37
|
+
const priority = options.priority ?? 100;
|
|
38
|
+
const pattern = options.pattern || this.defaultPattern;
|
|
39
|
+
const compiledPattern = this._compilePattern(pattern);
|
|
40
|
+
const order = this.registrationOrder++;
|
|
41
|
+
|
|
42
|
+
this.hooks.set(name, {
|
|
43
|
+
tag: name,
|
|
44
|
+
type,
|
|
45
|
+
handler,
|
|
46
|
+
priority,
|
|
47
|
+
pattern,
|
|
48
|
+
compiledPattern,
|
|
49
|
+
order
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return name;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
cleanup() {
|
|
57
|
+
this.hooks.clear();
|
|
58
|
+
this.reportedErrors = new WeakSet();
|
|
59
|
+
this.registrationOrder = 0;
|
|
60
|
+
this.enabled = false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
off(nameOrPattern) {
|
|
65
|
+
|
|
66
|
+
if (this.hooks.has(nameOrPattern)) {
|
|
67
|
+
return this.hooks.delete(nameOrPattern);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
const compiled = this._compilePattern(nameOrPattern);
|
|
72
|
+
let removed = false;
|
|
73
|
+
for (const key of [...this.hooks.keys()]) {
|
|
74
|
+
if (this._matchPattern(compiled, key)) {
|
|
75
|
+
this.hooks.delete(key);
|
|
76
|
+
removed = true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return removed;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
clear(type) {
|
|
84
|
+
if (type === undefined) {
|
|
85
|
+
this.hooks.clear();
|
|
86
|
+
this.registrationOrder = 0;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
for (const [name, hook] of this.hooks) {
|
|
92
|
+
if (hook.type === type) {
|
|
93
|
+
this.hooks.delete(name);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
list(type) {
|
|
100
|
+
const result = [];
|
|
101
|
+
for (const [name, hook] of this.hooks) {
|
|
102
|
+
if (type === undefined || hook.type === type) {
|
|
103
|
+
result.push({
|
|
104
|
+
name,
|
|
105
|
+
type: hook.type,
|
|
106
|
+
priority: hook.priority,
|
|
107
|
+
pattern: hook.pattern,
|
|
108
|
+
order: hook.order
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
enable(pattern) {
|
|
117
|
+
this.enabled = true;
|
|
118
|
+
if (pattern !== undefined) {
|
|
119
|
+
this.defaultPattern = pattern;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
disable() {
|
|
125
|
+
this.enabled = false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
executeBeforeHooks(path, args) {
|
|
130
|
+
const hooks = this._getMatchingHooks("before", path);
|
|
131
|
+
let currentArgs = args;
|
|
132
|
+
|
|
133
|
+
for (const hook of hooks) {
|
|
134
|
+
try {
|
|
135
|
+
const result = hook.handler({ path, args: currentArgs });
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if (result === undefined) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if (Array.isArray(result)) {
|
|
144
|
+
currentArgs = result;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
return { cancelled: true, value: result, args: currentArgs };
|
|
150
|
+
} catch (error) {
|
|
151
|
+
|
|
152
|
+
this.reportedErrors.add(error);
|
|
153
|
+
this.executeErrorHooks(path, error, {
|
|
154
|
+
type: "before",
|
|
155
|
+
hookId: hook.id,
|
|
156
|
+
hookTag: hook.tag
|
|
157
|
+
});
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { cancelled: false, args: currentArgs };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
executeAfterHooks(path, initialResult) {
|
|
167
|
+
const hooks = this._getMatchingHooks("after", path);
|
|
168
|
+
let currentResult = initialResult;
|
|
169
|
+
|
|
170
|
+
for (const hook of hooks) {
|
|
171
|
+
try {
|
|
172
|
+
const transformed = hook.handler({ path, result: currentResult });
|
|
173
|
+
|
|
174
|
+
if (transformed !== undefined) {
|
|
175
|
+
currentResult = transformed;
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
|
|
179
|
+
this.reportedErrors.add(error);
|
|
180
|
+
this.executeErrorHooks(path, error, {
|
|
181
|
+
type: "after",
|
|
182
|
+
hookId: hook.id,
|
|
183
|
+
hookTag: hook.tag
|
|
184
|
+
});
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return currentResult;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
executeAlwaysHooks(path, result, errors = []) {
|
|
194
|
+
const hooks = this._getMatchingHooks("always", path);
|
|
195
|
+
|
|
196
|
+
for (const hook of hooks) {
|
|
197
|
+
try {
|
|
198
|
+
hook.handler({
|
|
199
|
+
path,
|
|
200
|
+
result,
|
|
201
|
+
hasError: errors.length > 0,
|
|
202
|
+
errors
|
|
203
|
+
});
|
|
204
|
+
} catch (error) {
|
|
205
|
+
|
|
206
|
+
this.executeErrorHooks(path, error, {
|
|
207
|
+
type: "always",
|
|
208
|
+
hookId: hook.id,
|
|
209
|
+
hookTag: hook.tag
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
executeErrorHooks(path, error, source = { type: "unknown" }) {
|
|
218
|
+
const hooks = this._getMatchingHooks("error", path);
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
const errorContext = {
|
|
222
|
+
path,
|
|
223
|
+
error,
|
|
224
|
+
errorType: error.constructor ? error.constructor.name : "Error",
|
|
225
|
+
source: {
|
|
226
|
+
type: source.type || "unknown",
|
|
227
|
+
hookId: source.hookId,
|
|
228
|
+
hookTag: source.hookTag,
|
|
229
|
+
timestamp: Date.now(),
|
|
230
|
+
stack: error.stack
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
for (const hook of hooks) {
|
|
235
|
+
try {
|
|
236
|
+
hook.handler(errorContext);
|
|
237
|
+
} catch (hookError) {
|
|
238
|
+
|
|
239
|
+
console.error(`Error in error hook for ${path}:`, hookError);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
_getMatchingHooks(type, path) {
|
|
246
|
+
const matching = [];
|
|
247
|
+
|
|
248
|
+
for (const [hookId, hook] of this.hooks.entries()) {
|
|
249
|
+
if (hook.type !== type) continue;
|
|
250
|
+
if (!this._matchPattern(hook.compiledPattern, path)) continue;
|
|
251
|
+
matching.push({ ...hook, id: hookId });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
matching.sort((a, b) => {
|
|
256
|
+
if (a.priority !== b.priority) {
|
|
257
|
+
return b.priority - a.priority;
|
|
258
|
+
}
|
|
259
|
+
return a.order - b.order;
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
return matching;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
_compilePattern(pattern) {
|
|
267
|
+
|
|
268
|
+
if (pattern.startsWith("!")) {
|
|
269
|
+
return {
|
|
270
|
+
negation: true,
|
|
271
|
+
regex: this._compilePattern(pattern.slice(1))
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
const expanded = this._expandBraces(pattern);
|
|
277
|
+
if (expanded.length > 1) {
|
|
278
|
+
|
|
279
|
+
const regexes = expanded.map((p) => this._patternToRegex(p));
|
|
280
|
+
return new RegExp(`^(?:${regexes.join("|")})$`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
return new RegExp(`^${this._patternToRegex(expanded[0])}$`);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
_expandBraces(pattern, depth = 0) {
|
|
289
|
+
if (depth > MAX_BRACE_NESTING) {
|
|
290
|
+
throw new Error(`Brace expansion exceeds maximum nesting depth of ${MAX_BRACE_NESTING}`);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const braceStart = pattern.indexOf("{");
|
|
294
|
+
if (braceStart === -1) {
|
|
295
|
+
return [pattern];
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
let braceEnd = -1;
|
|
300
|
+
let nestLevel = 0;
|
|
301
|
+
for (let i = braceStart; i < pattern.length; i++) {
|
|
302
|
+
if (pattern[i] === "{") nestLevel++;
|
|
303
|
+
if (pattern[i] === "}") {
|
|
304
|
+
nestLevel--;
|
|
305
|
+
if (nestLevel === 0) {
|
|
306
|
+
braceEnd = i;
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (braceEnd === -1) {
|
|
313
|
+
|
|
314
|
+
return [pattern];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const before = pattern.slice(0, braceStart);
|
|
318
|
+
const inside = pattern.slice(braceStart + 1, braceEnd);
|
|
319
|
+
const after = pattern.slice(braceEnd + 1);
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
const alternatives = this._splitAlternatives(inside);
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
const results = [];
|
|
326
|
+
for (const alt of alternatives) {
|
|
327
|
+
const expanded = this._expandBraces(before + alt + after, depth + 1);
|
|
328
|
+
results.push(...expanded);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return results;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
_splitAlternatives(str) {
|
|
336
|
+
const alternatives = [];
|
|
337
|
+
let current = "";
|
|
338
|
+
let nestLevel = 0;
|
|
339
|
+
|
|
340
|
+
for (let i = 0; i < str.length; i++) {
|
|
341
|
+
const char = str[i];
|
|
342
|
+
if (char === "{") nestLevel++;
|
|
343
|
+
if (char === "}") nestLevel--;
|
|
344
|
+
|
|
345
|
+
if (char === "," && nestLevel === 0) {
|
|
346
|
+
alternatives.push(current);
|
|
347
|
+
current = "";
|
|
348
|
+
} else {
|
|
349
|
+
current += char;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (current) {
|
|
354
|
+
alternatives.push(current);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return alternatives;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
_patternToRegex(pattern) {
|
|
362
|
+
|
|
363
|
+
let regex = pattern.replace(/[+?^${}()|[\]\\]/g, "\\$&");
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
regex = regex.replace(/\./g, "\\.");
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
regex = regex.replace(/\*\*/g, "___DOUBLESTAR___");
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
regex = regex.replace(/\*/g, "([^\\.]+)");
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
regex = regex.replace(/___DOUBLESTAR___/g, ".*?");
|
|
376
|
+
|
|
377
|
+
return regex;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
_matchPattern(compiledPattern, path) {
|
|
382
|
+
if (compiledPattern.negation) {
|
|
383
|
+
|
|
384
|
+
return !this._matchPattern(compiledPattern.regex, path);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return compiledPattern.test(path);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
@@ -341,6 +341,10 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
|
|
|
341
341
|
if (prop === "_materialize") return _materialize;
|
|
342
342
|
if (prop === "then") return undefined;
|
|
343
343
|
|
|
344
|
+
if (prop === "__slothletPath") {
|
|
345
|
+
return pathParts.length > 0 ? pathParts.join(".") : undefined;
|
|
346
|
+
}
|
|
347
|
+
|
|
344
348
|
if (materialized) {
|
|
345
349
|
if (materialized && (typeof materialized === "object" || typeof materialized === "function")) return materialized[prop];
|
|
346
350
|
return undefined;
|
|
@@ -348,10 +352,12 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
|
|
|
348
352
|
|
|
349
353
|
if (!inFlight) inFlight = _materialize();
|
|
350
354
|
|
|
355
|
+
const apiPath = pathParts.length > 0 ? `${pathParts.join(".")}.${String(prop)}` : String(prop);
|
|
356
|
+
|
|
351
357
|
|
|
352
358
|
|
|
353
359
|
|
|
354
|
-
|
|
360
|
+
const propertyProxy = new Proxy(
|
|
355
361
|
|
|
356
362
|
function lazy_propertyAccessor(...args) {
|
|
357
363
|
return inFlight.then(
|
|
@@ -360,12 +366,7 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
|
|
|
360
366
|
const value = resolved ? resolved[prop] : undefined;
|
|
361
367
|
if (typeof value === "function") {
|
|
362
368
|
|
|
363
|
-
|
|
364
|
-
if (ctx) {
|
|
365
|
-
return runWithCtx(ctx, value, this, args);
|
|
366
|
-
} else {
|
|
367
|
-
return value.apply(this, args);
|
|
368
|
-
}
|
|
369
|
+
return value.apply(this, args);
|
|
369
370
|
}
|
|
370
371
|
return value;
|
|
371
372
|
}
|
|
@@ -377,6 +378,10 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
|
|
|
377
378
|
if (subProp === "name") return `lazy_${prop}`;
|
|
378
379
|
if (subProp === "length") return 0;
|
|
379
380
|
|
|
381
|
+
if (subProp === "__slothletPath") {
|
|
382
|
+
return pathParts.length > 0 ? `${pathParts.join(".")}.${String(prop)}` : String(prop);
|
|
383
|
+
}
|
|
384
|
+
|
|
380
385
|
return new Proxy(
|
|
381
386
|
function lazy_deepPropertyAccessor() {},
|
|
382
387
|
{
|
|
@@ -390,12 +395,8 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
|
|
|
390
395
|
const value = materialized[prop];
|
|
391
396
|
const subValue = value ? value[subProp] : undefined;
|
|
392
397
|
if (subValue && typeof subValue[nextProp] === "function") {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
return runWithCtx(ctx, subValue[nextProp], thisArg, args);
|
|
396
|
-
} else {
|
|
397
|
-
return subValue[nextProp].apply(thisArg, args);
|
|
398
|
-
}
|
|
398
|
+
|
|
399
|
+
return subValue[nextProp].apply(thisArg, args);
|
|
399
400
|
}
|
|
400
401
|
return subValue ? subValue[nextProp] : undefined;
|
|
401
402
|
}
|
|
@@ -423,12 +424,7 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
|
|
|
423
424
|
const value = materialized[prop];
|
|
424
425
|
if (value && typeof value[subProp] === "function") {
|
|
425
426
|
|
|
426
|
-
|
|
427
|
-
if (ctx) {
|
|
428
|
-
return runWithCtx(ctx, value[subProp], thisArg, args);
|
|
429
|
-
} else {
|
|
430
|
-
return value[subProp].apply(thisArg, args);
|
|
431
|
-
}
|
|
427
|
+
return value[subProp].apply(thisArg, args);
|
|
432
428
|
}
|
|
433
429
|
return value ? value[subProp] : undefined;
|
|
434
430
|
}
|
|
@@ -457,6 +453,16 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
|
|
|
457
453
|
}
|
|
458
454
|
}
|
|
459
455
|
);
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
Object.defineProperty(propertyProxy, "__slothletPath", {
|
|
459
|
+
value: apiPath,
|
|
460
|
+
writable: false,
|
|
461
|
+
enumerable: false,
|
|
462
|
+
configurable: true
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
return propertyProxy;
|
|
460
466
|
},
|
|
461
467
|
has(_t, prop) {
|
|
462
468
|
if (materialized && (typeof materialized === "object" || typeof materialized === "function")) return prop in materialized;
|
|
@@ -33,10 +33,81 @@ enableAlsForEventEmitters(als);
|
|
|
33
33
|
|
|
34
34
|
export const runWithCtx = (ctx, fn, thisArg, args) => {
|
|
35
35
|
|
|
36
|
+
if (!ctx.hookManager?.enabled || !fn.__slothletPath) {
|
|
37
|
+
const runtime_runInALS = () => {
|
|
38
|
+
const result = Reflect.apply(fn, thisArg, args);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
return als.run(ctx, runtime_runInALS);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
const path = fn.__slothletPath;
|
|
46
|
+
|
|
47
|
+
|
|
36
48
|
const runtime_runInALS = () => {
|
|
37
|
-
|
|
38
|
-
|
|
49
|
+
try {
|
|
50
|
+
|
|
51
|
+
const beforeResult = ctx.hookManager.executeBeforeHooks(path, args);
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if (beforeResult.cancelled) {
|
|
55
|
+
ctx.hookManager.executeAlwaysHooks(path, beforeResult.value, []);
|
|
56
|
+
return beforeResult.value;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
const actualArgs = beforeResult.args;
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
const result = Reflect.apply(fn, thisArg, actualArgs);
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
67
|
+
return result.then(
|
|
68
|
+
(resolvedResult) => {
|
|
69
|
+
|
|
70
|
+
const finalResult = ctx.hookManager.executeAfterHooks(path, resolvedResult);
|
|
71
|
+
ctx.hookManager.executeAlwaysHooks(path, finalResult, []);
|
|
72
|
+
return finalResult;
|
|
73
|
+
},
|
|
74
|
+
(error) => {
|
|
75
|
+
|
|
76
|
+
if (!ctx.hookManager.reportedErrors.has(error)) {
|
|
77
|
+
ctx.hookManager.reportedErrors.add(error);
|
|
78
|
+
ctx.hookManager.executeErrorHooks(path, error, { type: "function" });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
ctx.hookManager.executeAlwaysHooks(path, undefined, [error]);
|
|
82
|
+
|
|
83
|
+
if (!ctx.hookManager.suppressErrors) {
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
const finalResult = ctx.hookManager.executeAfterHooks(path, result);
|
|
93
|
+
ctx.hookManager.executeAlwaysHooks(path, finalResult, []);
|
|
94
|
+
return finalResult;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
|
|
97
|
+
if (!ctx.hookManager.reportedErrors.has(error)) {
|
|
98
|
+
ctx.hookManager.reportedErrors.add(error);
|
|
99
|
+
ctx.hookManager.executeErrorHooks(path, error, { type: "function" });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
ctx.hookManager.executeAlwaysHooks(path, undefined, [error]);
|
|
103
|
+
|
|
104
|
+
if (!ctx.hookManager.suppressErrors) {
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
39
109
|
};
|
|
110
|
+
|
|
40
111
|
return als.run(ctx, runtime_runInALS);
|
|
41
112
|
};
|
|
42
113
|
|
|
@@ -157,7 +228,7 @@ export const makeWrapper = (ctx) => {
|
|
|
157
228
|
const cache = new WeakMap();
|
|
158
229
|
const instanceCache = new WeakMap();
|
|
159
230
|
const promiseMethodCache = new WeakMap();
|
|
160
|
-
const wrap = (val) => {
|
|
231
|
+
const wrap = (val, currentPath = "") => {
|
|
161
232
|
if (val == null || (typeof val !== "object" && typeof val !== "function")) return val;
|
|
162
233
|
if (cache.has(val)) return cache.get(val);
|
|
163
234
|
|
|
@@ -170,17 +241,6 @@ export const makeWrapper = (ctx) => {
|
|
|
170
241
|
|
|
171
242
|
const proxied = new Proxy(val, {
|
|
172
243
|
apply(target, thisArg, args) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
244
|
const result = runWithCtx(ctx, target, thisArg, args);
|
|
185
245
|
|
|
186
246
|
|
|
@@ -205,6 +265,27 @@ export const makeWrapper = (ctx) => {
|
|
|
205
265
|
const value = Reflect.get(target, prop, receiver);
|
|
206
266
|
|
|
207
267
|
|
|
268
|
+
const newPath = currentPath ? `${currentPath}.${String(prop)}` : String(prop);
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
const isInternalProperty = currentPath === "" && ["hooks", "__ctx", "shutdown", "_impl"].includes(String(prop));
|
|
272
|
+
const isInternalPath = newPath.startsWith("hooks.") || newPath.startsWith("__ctx.") || newPath.startsWith("shutdown.");
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
if (typeof value === "function" && !value.__slothletPath && !isInternalProperty && !isInternalPath) {
|
|
276
|
+
try {
|
|
277
|
+
Object.defineProperty(value, "__slothletPath", {
|
|
278
|
+
value: newPath,
|
|
279
|
+
writable: false,
|
|
280
|
+
enumerable: false,
|
|
281
|
+
configurable: true
|
|
282
|
+
});
|
|
283
|
+
} catch {
|
|
284
|
+
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
|
|
208
289
|
|
|
209
290
|
const isPromiseMethod = typeof value === "function" && PROMISE_METHODS.has(prop);
|
|
210
291
|
const isNativePromise = util.types.isPromise(target);
|
|
@@ -236,14 +317,14 @@ export const makeWrapper = (ctx) => {
|
|
|
236
317
|
|
|
237
318
|
const result = Reflect.apply(value, target, wrappedArgs);
|
|
238
319
|
|
|
239
|
-
return wrap(result);
|
|
320
|
+
return wrap(result, newPath);
|
|
240
321
|
};
|
|
241
322
|
|
|
242
323
|
targetMethodCache.set(prop, wrappedMethod);
|
|
243
324
|
return wrappedMethod;
|
|
244
325
|
}
|
|
245
326
|
|
|
246
|
-
return wrap(value);
|
|
327
|
+
return wrap(value, newPath);
|
|
247
328
|
},
|
|
248
329
|
set(target, prop, value, receiver) {
|
|
249
330
|
|