@senzops/apm-node 1.1.11 → 1.1.14
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.global.js +1 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/core/client.ts +23 -3
- package/src/core/types.ts +10 -0
- package/src/instrumentation/bullmq.ts +181 -31
- package/src/instrumentation/cron.ts +190 -27
- package/src/instrumentation/hook.ts +240 -17
|
@@ -1,45 +1,195 @@
|
|
|
1
1
|
import type { SenzorClient } from '../core/client';
|
|
2
2
|
import { hookRequire } from './hook';
|
|
3
|
+
import { Context } from '../core/context';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
const PATCHED =
|
|
6
|
+
Symbol.for(
|
|
7
|
+
'senzor.bullmq.patched'
|
|
8
|
+
);
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
function patchWorker(
|
|
11
|
+
target: any,
|
|
12
|
+
client: SenzorClient,
|
|
13
|
+
debug: boolean
|
|
14
|
+
) {
|
|
9
15
|
|
|
10
|
-
|
|
16
|
+
if (
|
|
17
|
+
!target?.Worker?.prototype
|
|
18
|
+
) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
11
21
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
22
|
+
const proto =
|
|
23
|
+
target.Worker.prototype;
|
|
24
|
+
|
|
25
|
+
const original =
|
|
26
|
+
proto.processJob;
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
typeof original !==
|
|
30
|
+
'function' ||
|
|
31
|
+
original[PATCHED]
|
|
32
|
+
) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
proto.processJob =
|
|
37
|
+
async function (
|
|
38
|
+
job: any
|
|
39
|
+
) {
|
|
40
|
+
|
|
41
|
+
const queueDelay =
|
|
42
|
+
job.timestamp
|
|
43
|
+
? Date.now() -
|
|
44
|
+
job.timestamp
|
|
45
|
+
: 0;
|
|
46
|
+
|
|
47
|
+
const currentAttempt =
|
|
48
|
+
(job.attemptsMade || 0)
|
|
49
|
+
+ 1;
|
|
50
|
+
|
|
51
|
+
const maxAttempts =
|
|
52
|
+
job.opts?.attempts
|
|
53
|
+
?? 1;
|
|
54
|
+
|
|
55
|
+
const isFinal =
|
|
56
|
+
currentAttempt >=
|
|
57
|
+
maxAttempts;
|
|
58
|
+
|
|
59
|
+
const taskName =
|
|
60
|
+
job.name ===
|
|
61
|
+
'__default__'
|
|
62
|
+
? job.queueName
|
|
63
|
+
: `${job.queueName}:${job.name}`;
|
|
64
|
+
|
|
65
|
+
return client.startTask(
|
|
66
|
+
|
|
67
|
+
taskName,
|
|
68
|
+
|
|
69
|
+
'queue',
|
|
70
|
+
|
|
71
|
+
{
|
|
72
|
+
queueDelay,
|
|
73
|
+
attempts:
|
|
74
|
+
currentAttempt,
|
|
75
|
+
isDeadLetter: false,
|
|
76
|
+
metadata: {
|
|
77
|
+
jobId: job.id,
|
|
78
|
+
queueName:
|
|
79
|
+
job.queueName,
|
|
80
|
+
maxAttempts
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
async () => {
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
|
|
88
|
+
const result =
|
|
89
|
+
await original.call(
|
|
90
|
+
this,
|
|
91
|
+
job
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
client.endTask(
|
|
95
|
+
'success'
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return result;
|
|
99
|
+
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
16
102
|
|
|
17
|
-
return client.startTask(
|
|
18
|
-
taskName,
|
|
19
|
-
'queue',
|
|
20
|
-
{ queueDelay, attempts, metadata: { jobId: job.id, queueName: job.queueName } },
|
|
21
|
-
async () => {
|
|
22
103
|
try {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
104
|
+
|
|
105
|
+
const ctx =
|
|
106
|
+
Context.current();
|
|
107
|
+
|
|
108
|
+
if (
|
|
109
|
+
ctx &&
|
|
110
|
+
ctx.contextType === 'task' &&
|
|
111
|
+
isFinal
|
|
112
|
+
) {
|
|
113
|
+
|
|
114
|
+
ctx.data
|
|
115
|
+
.isDeadLetter =
|
|
116
|
+
true;
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
|
|
30
120
|
}
|
|
121
|
+
catch { }
|
|
122
|
+
|
|
123
|
+
client.captureError(
|
|
124
|
+
error,
|
|
125
|
+
{
|
|
126
|
+
queueName:
|
|
127
|
+
job.queueName,
|
|
128
|
+
jobId: job.id,
|
|
129
|
+
isDeadLetter:
|
|
130
|
+
isFinal
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
client.endTask(
|
|
135
|
+
'failed'
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
throw error;
|
|
139
|
+
|
|
31
140
|
}
|
|
32
|
-
);
|
|
33
|
-
};
|
|
34
141
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
);
|
|
38
145
|
|
|
39
|
-
|
|
146
|
+
};
|
|
40
147
|
|
|
41
|
-
|
|
42
|
-
|
|
148
|
+
Object.defineProperty(
|
|
149
|
+
proto.processJob,
|
|
150
|
+
PATCHED,
|
|
151
|
+
{
|
|
152
|
+
value: true
|
|
43
153
|
}
|
|
44
|
-
|
|
45
|
-
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
if (debug) {
|
|
157
|
+
|
|
158
|
+
console.log(
|
|
159
|
+
'[Senzor] BullMQ instrumented'
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export const instrumentBullMQ =
|
|
167
|
+
(
|
|
168
|
+
client: SenzorClient,
|
|
169
|
+
debug: boolean
|
|
170
|
+
) => {
|
|
171
|
+
|
|
172
|
+
hookRequire(
|
|
173
|
+
'bullmq',
|
|
174
|
+
(exports: any) => {
|
|
175
|
+
|
|
176
|
+
patchWorker(
|
|
177
|
+
exports,
|
|
178
|
+
client,
|
|
179
|
+
debug
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
if (exports?.default) {
|
|
183
|
+
|
|
184
|
+
patchWorker(
|
|
185
|
+
exports.default,
|
|
186
|
+
client,
|
|
187
|
+
debug
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
};
|
|
@@ -1,41 +1,204 @@
|
|
|
1
1
|
import type { SenzorClient } from '../core/client';
|
|
2
2
|
import { hookRequire } from './hook';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const PATCHED =
|
|
5
|
+
Symbol.for('senzor.cron.patched');
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (!target || typeof target.schedule !== 'function' || target.__senzorPatched) return;
|
|
7
|
+
type CronHandler =
|
|
8
|
+
(...args: unknown[]) => unknown;
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
type CronSchedule =
|
|
11
|
+
(
|
|
12
|
+
expression: string,
|
|
13
|
+
handler: CronHandler,
|
|
14
|
+
options?: unknown
|
|
15
|
+
) => unknown;
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const taskName = optsObj?.name || `cron: ${expression}`;
|
|
17
|
+
function normalizeOptions(
|
|
18
|
+
options: unknown
|
|
19
|
+
): Record<string, unknown> {
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
if (
|
|
22
|
+
typeof options === 'object' &&
|
|
23
|
+
options !== null
|
|
24
|
+
) {
|
|
25
|
+
return options as Record<
|
|
26
|
+
string,
|
|
27
|
+
unknown
|
|
28
|
+
>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// backward compatibility with:
|
|
32
|
+
// cron.schedule(expr, fn, "UTC")
|
|
33
|
+
if (options) {
|
|
34
|
+
return { timezone: options };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {};
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function patchTarget(
|
|
42
|
+
target: Record<string, unknown>,
|
|
43
|
+
client: SenzorClient,
|
|
44
|
+
debug: boolean
|
|
45
|
+
): void {
|
|
46
|
+
|
|
47
|
+
const schedule =
|
|
48
|
+
target.schedule as
|
|
49
|
+
CronSchedule | undefined;
|
|
50
|
+
|
|
51
|
+
if (
|
|
52
|
+
typeof schedule !== 'function' ||
|
|
53
|
+
(schedule as any)[PATCHED]
|
|
54
|
+
) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const original =
|
|
59
|
+
schedule;
|
|
60
|
+
|
|
61
|
+
const wrapped: CronSchedule =
|
|
62
|
+
function (
|
|
63
|
+
this: unknown,
|
|
64
|
+
expression,
|
|
65
|
+
handler,
|
|
66
|
+
options
|
|
67
|
+
) {
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
typeof handler !==
|
|
71
|
+
'function'
|
|
72
|
+
) {
|
|
73
|
+
|
|
74
|
+
return original.call(
|
|
75
|
+
this,
|
|
76
|
+
expression,
|
|
77
|
+
handler,
|
|
78
|
+
options
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
|
|
85
|
+
const opts =
|
|
86
|
+
normalizeOptions(
|
|
87
|
+
options
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const taskName =
|
|
91
|
+
(opts as any)?.name ??
|
|
92
|
+
`cron: ${expression}`;
|
|
93
|
+
|
|
94
|
+
const wrappedHandler =
|
|
95
|
+
client.wrapTask(
|
|
96
|
+
taskName,
|
|
97
|
+
'cron',
|
|
98
|
+
{
|
|
99
|
+
expression,
|
|
100
|
+
metadata: opts
|
|
101
|
+
},
|
|
102
|
+
handler
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return original.call(
|
|
106
|
+
this,
|
|
107
|
+
expression,
|
|
108
|
+
wrappedHandler,
|
|
109
|
+
options
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
|
|
115
|
+
if (debug) {
|
|
116
|
+
|
|
117
|
+
console.error(
|
|
118
|
+
'[Senzor] cron wrap failed',
|
|
119
|
+
err
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return original.call(
|
|
125
|
+
this,
|
|
126
|
+
expression,
|
|
127
|
+
handler,
|
|
128
|
+
options
|
|
23
129
|
);
|
|
24
130
|
|
|
25
|
-
|
|
26
|
-
};
|
|
131
|
+
}
|
|
27
132
|
|
|
28
|
-
// Safely mark as patched to prevent infinite loops
|
|
29
|
-
Object.defineProperty(target, '__senzorPatched', { value: true, enumerable: false, writable: true });
|
|
30
|
-
if (debug) console.log('[Senzor] Node-Cron successfully instrumented');
|
|
31
133
|
};
|
|
32
134
|
|
|
33
|
-
|
|
34
|
-
|
|
135
|
+
Object.defineProperty(
|
|
136
|
+
wrapped,
|
|
137
|
+
PATCHED,
|
|
138
|
+
{
|
|
139
|
+
value: true,
|
|
140
|
+
enumerable: false
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// Some ESM namespace exports are frozen
|
|
145
|
+
try {
|
|
146
|
+
|
|
147
|
+
target.schedule =
|
|
148
|
+
wrapped;
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
|
|
153
|
+
if (debug) {
|
|
154
|
+
|
|
155
|
+
console.warn(
|
|
156
|
+
'[Senzor] unable to patch cron schedule (readonly export)'
|
|
157
|
+
);
|
|
35
158
|
|
|
36
|
-
// Apply patch to default (for import cron from 'node-cron')
|
|
37
|
-
if (cronExports.default) {
|
|
38
|
-
patchSchedule(cronExports.default);
|
|
39
159
|
}
|
|
40
|
-
|
|
41
|
-
}
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (debug) {
|
|
164
|
+
|
|
165
|
+
console.log(
|
|
166
|
+
'[Senzor] node-cron instrumented'
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export const instrumentNodeCron =
|
|
174
|
+
(
|
|
175
|
+
client: SenzorClient,
|
|
176
|
+
debug: boolean
|
|
177
|
+
): void => {
|
|
178
|
+
|
|
179
|
+
hookRequire(
|
|
180
|
+
'node-cron',
|
|
181
|
+
(exports: any) => {
|
|
182
|
+
|
|
183
|
+
if (!exports) return;
|
|
184
|
+
|
|
185
|
+
patchTarget(
|
|
186
|
+
exports,
|
|
187
|
+
client,
|
|
188
|
+
debug
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
if (exports.default) {
|
|
192
|
+
|
|
193
|
+
patchTarget(
|
|
194
|
+
exports.default,
|
|
195
|
+
client,
|
|
196
|
+
debug
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
};
|
|
@@ -1,24 +1,247 @@
|
|
|
1
1
|
import Module from 'module';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const SENZOR_PATCHED =
|
|
4
|
+
Symbol.for('senzor.require.patched');
|
|
5
|
+
|
|
6
|
+
const SENZOR_HOOKS =
|
|
7
|
+
Symbol.for('senzor.require.hooks');
|
|
8
|
+
|
|
9
|
+
type HookFn =
|
|
10
|
+
(exports: unknown) => void;
|
|
11
|
+
|
|
12
|
+
type HookMap =
|
|
13
|
+
Map<string, HookFn[]>;
|
|
14
|
+
|
|
15
|
+
function getHookRegistry(): HookMap {
|
|
16
|
+
|
|
17
|
+
const mod =
|
|
18
|
+
Module as unknown as Record<
|
|
19
|
+
symbol,
|
|
20
|
+
HookMap
|
|
21
|
+
>;
|
|
22
|
+
|
|
23
|
+
if (!mod[SENZOR_HOOKS]) {
|
|
24
|
+
|
|
25
|
+
Object.defineProperty(
|
|
26
|
+
mod,
|
|
27
|
+
SENZOR_HOOKS,
|
|
28
|
+
{
|
|
29
|
+
value: new Map(),
|
|
30
|
+
enumerable: false
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return mod[SENZOR_HOOKS];
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function runHooks(
|
|
41
|
+
moduleName: string,
|
|
42
|
+
exports: unknown
|
|
43
|
+
) {
|
|
44
|
+
|
|
45
|
+
const registry =
|
|
46
|
+
(Module as unknown as Record<
|
|
47
|
+
symbol,
|
|
48
|
+
HookMap
|
|
49
|
+
>)[SENZOR_HOOKS];
|
|
50
|
+
|
|
51
|
+
if (!registry) return;
|
|
52
|
+
|
|
53
|
+
const hooks =
|
|
54
|
+
registry.get(moduleName);
|
|
55
|
+
|
|
56
|
+
if (!hooks?.length) return;
|
|
57
|
+
|
|
58
|
+
for (const hook of hooks) {
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
hook(exports);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
|
|
65
|
+
console.error(
|
|
66
|
+
`[Senzor] instrumentation failed for ${moduleName}`,
|
|
67
|
+
err
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function patchLoaderOnce() {
|
|
77
|
+
|
|
78
|
+
const mod =
|
|
79
|
+
Module as unknown as any;
|
|
80
|
+
|
|
81
|
+
if (mod[SENZOR_PATCHED]) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const previousLoad =
|
|
86
|
+
mod._load;
|
|
87
|
+
|
|
88
|
+
mod._load =
|
|
89
|
+
function patchedLoad(
|
|
90
|
+
request: string,
|
|
91
|
+
parent: unknown,
|
|
92
|
+
isMain: boolean
|
|
93
|
+
) {
|
|
94
|
+
|
|
95
|
+
const exports =
|
|
96
|
+
previousLoad.apply(
|
|
97
|
+
this,
|
|
98
|
+
arguments
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
runHooks(
|
|
102
|
+
request,
|
|
103
|
+
exports
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return exports;
|
|
107
|
+
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
Object.defineProperty(
|
|
111
|
+
mod,
|
|
112
|
+
SENZOR_PATCHED,
|
|
113
|
+
{
|
|
114
|
+
value: true,
|
|
115
|
+
enumerable: false
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function patchCached(
|
|
122
|
+
moduleName: string,
|
|
123
|
+
hook: HookFn
|
|
124
|
+
) {
|
|
125
|
+
|
|
5
126
|
try {
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
127
|
+
|
|
128
|
+
const resolved =
|
|
129
|
+
require.resolve(
|
|
130
|
+
moduleName
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const cached =
|
|
134
|
+
require.cache?.[
|
|
135
|
+
resolved
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
if (cached?.exports) {
|
|
139
|
+
|
|
140
|
+
hook(
|
|
141
|
+
cached.exports
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
catch { }
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function tryRequire(
|
|
152
|
+
moduleName: string,
|
|
153
|
+
hook: HookFn
|
|
154
|
+
) {
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
|
|
158
|
+
const mod =
|
|
159
|
+
require(moduleName);
|
|
160
|
+
|
|
161
|
+
if (mod) {
|
|
162
|
+
hook(mod);
|
|
10
163
|
}
|
|
11
|
-
|
|
12
|
-
// Silently ignore if module is not installed
|
|
164
|
+
|
|
13
165
|
}
|
|
166
|
+
catch { }
|
|
167
|
+
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function retryPatch(
|
|
171
|
+
moduleName: string,
|
|
172
|
+
hook: HookFn
|
|
173
|
+
) {
|
|
174
|
+
|
|
175
|
+
let attempts = 0;
|
|
176
|
+
|
|
177
|
+
const max = 5;
|
|
178
|
+
|
|
179
|
+
const timer =
|
|
180
|
+
setInterval(() => {
|
|
181
|
+
|
|
182
|
+
attempts++;
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
|
|
186
|
+
const mod =
|
|
187
|
+
require(moduleName);
|
|
188
|
+
|
|
189
|
+
if (mod) {
|
|
190
|
+
|
|
191
|
+
hook(mod);
|
|
192
|
+
|
|
193
|
+
clearInterval(timer);
|
|
194
|
+
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
}
|
|
198
|
+
catch { }
|
|
199
|
+
|
|
200
|
+
if (attempts >= max) {
|
|
201
|
+
clearInterval(timer);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
}, 200);
|
|
205
|
+
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export const hookRequire =
|
|
209
|
+
(
|
|
210
|
+
moduleName: string,
|
|
211
|
+
onRequire: HookFn
|
|
212
|
+
) => {
|
|
213
|
+
|
|
214
|
+
const registry =
|
|
215
|
+
getHookRegistry();
|
|
216
|
+
|
|
217
|
+
if (!registry.has(moduleName)) {
|
|
218
|
+
|
|
219
|
+
registry.set(
|
|
220
|
+
moduleName,
|
|
221
|
+
[]
|
|
222
|
+
);
|
|
14
223
|
|
|
15
|
-
// 2. Intercept future requires
|
|
16
|
-
const originalLoad = (Module as any)._load;
|
|
17
|
-
(Module as any)._load = function (request: string, parent: any, isMain: boolean) {
|
|
18
|
-
const exports = originalLoad.apply(this, arguments);
|
|
19
|
-
if (request === moduleName && exports) {
|
|
20
|
-
onRequire(exports);
|
|
21
224
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
225
|
+
|
|
226
|
+
registry
|
|
227
|
+
.get(moduleName)!
|
|
228
|
+
.push(onRequire);
|
|
229
|
+
|
|
230
|
+
patchLoaderOnce();
|
|
231
|
+
|
|
232
|
+
patchCached(
|
|
233
|
+
moduleName,
|
|
234
|
+
onRequire
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
tryRequire(
|
|
238
|
+
moduleName,
|
|
239
|
+
onRequire
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
retryPatch(
|
|
243
|
+
moduleName,
|
|
244
|
+
onRequire
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
};
|