nestworker 2.0.4 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -22
- package/dist/core/worker.service.d.ts +3 -2
- package/dist/core/worker.service.js +3 -1
- package/dist/core/worker.service.js.map +1 -1
- package/dist/di/di-serializer.d.ts +9 -8
- package/dist/di/di-serializer.js +29 -37
- package/dist/di/di-serializer.js.map +1 -1
- package/dist/di/worker-container.d.ts +32 -30
- package/dist/di/worker-container.js +130 -70
- package/dist/di/worker-container.js.map +1 -1
- package/dist/example/image.service.d.ts +4 -0
- package/dist/example/image.service.js +16 -1
- package/dist/example/image.service.js.map +1 -1
- package/dist/example/main.js +2 -1
- package/dist/example/main.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -252,42 +252,43 @@ Returns a `Promise<T>` that resolves with the method's return value.
|
|
|
252
252
|
|
|
253
253
|
## How DI in Workers Works
|
|
254
254
|
|
|
255
|
-
Worker threads run in an isolated V8 context — they share no heap with the main thread. Passing live NestJS services across the boundary is
|
|
255
|
+
Worker threads run in an isolated V8 context — they share no heap with the main thread. Passing live NestJS services across the boundary is not possible directly.
|
|
256
256
|
|
|
257
|
-
|
|
257
|
+
nestworker solves it in three steps:
|
|
258
258
|
|
|
259
|
-
**1. Main thread —
|
|
259
|
+
**1. Main thread — locate compiled files**
|
|
260
260
|
|
|
261
|
-
`
|
|
261
|
+
`serializeForWorker()` walks `require.cache` to find the compiled `.js` file path for each dep constructor. It also snapshots each dep's own properties via `structuredClone` to capture runtime state (e.g. loaded config values).
|
|
262
262
|
|
|
263
|
-
**2. Worker thread — `
|
|
263
|
+
**2. Worker thread — `vm.runInContext()`**
|
|
264
264
|
|
|
265
|
-
|
|
265
|
+
Each compiled `.js` file is executed inside a `vm` context with a custom `require()` that stubs NestJS decorator packages (`@nestjs/common`, `@nestjs/core`, etc.) so that decorator calls at file-eval time are silent no-ops. All other imports resolve normally through Node's module system — including Node built-ins and third-party packages.
|
|
266
|
+
|
|
267
|
+
Each dep is reconstructed as `Object.create(DepClass.prototype)` + `Object.assign(snapshot)`, restoring both prototype methods and runtime state. The dep is then assigned to the service instance by property key.
|
|
266
268
|
|
|
267
269
|
**3. Result**
|
|
268
270
|
|
|
269
|
-
`this.configService.get('KEY')` inside a worker task works exactly as on the main thread
|
|
271
|
+
`this.configService.get('KEY')` inside a worker task works exactly as on the main thread.
|
|
270
272
|
|
|
271
273
|
```
|
|
272
|
-
MAIN THREAD
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
→
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
→
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
this.configService.get() ✓
|
|
274
|
+
MAIN THREAD WORKER THREAD
|
|
275
|
+
───────────────────────────────────── ──────────────────────────────────────
|
|
276
|
+
serializeForWorker()
|
|
277
|
+
ConfigService → filePath + snapshot → vm.runInContext(config.service.js)
|
|
278
|
+
Object.create(ConfigService.prototype)
|
|
279
|
+
Object.assign(inst, snapshot)
|
|
280
|
+
ImageService → filePath → vm.runInContext(image.service.js)
|
|
281
|
+
Object.create(ImageService.prototype)
|
|
282
|
+
inst.configService = configInst
|
|
283
|
+
this.configService.get() ✓
|
|
283
284
|
```
|
|
284
285
|
|
|
285
|
-
### What deps can be
|
|
286
|
+
### What deps can be used
|
|
286
287
|
|
|
287
|
-
✅ Services holding plain config data (`
|
|
288
|
-
✅ Services whose methods only read from their own properties
|
|
288
|
+
✅ Services holding plain config data (`object`, `Map`, arrays, primitives)
|
|
289
|
+
✅ Services whose methods only read from their own snapshotted properties
|
|
289
290
|
❌ Services that hold DB connections, HTTP clients, or open streams
|
|
290
|
-
❌ Services with `Socket`, `Stream`, or non-cloneable properties
|
|
291
|
+
❌ Services with `Socket`, `Stream`, or other non-cloneable properties
|
|
291
292
|
|
|
292
293
|
---
|
|
293
294
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OnModuleDestroy } from '@nestjs/common';
|
|
1
|
+
import { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
|
2
2
|
import { WorkerDiscoveryService } from '../discovery/discovery.service';
|
|
3
3
|
import type { TaskPriority, WorkerModuleOptions } from './worker.interfaces';
|
|
4
4
|
/**
|
|
@@ -35,12 +35,13 @@ import type { TaskPriority, WorkerModuleOptions } from './worker.interfaces';
|
|
|
35
35
|
* );
|
|
36
36
|
* ```
|
|
37
37
|
*/
|
|
38
|
-
export declare class WorkerService implements OnModuleDestroy {
|
|
38
|
+
export declare class WorkerService implements OnModuleInit, OnModuleDestroy {
|
|
39
39
|
private readonly discovery;
|
|
40
40
|
private readonly options;
|
|
41
41
|
private pool;
|
|
42
42
|
private readonly taskOptions;
|
|
43
43
|
constructor(discovery: WorkerDiscoveryService, options: WorkerModuleOptions);
|
|
44
|
+
onModuleInit(): void;
|
|
44
45
|
private initPool;
|
|
45
46
|
/**
|
|
46
47
|
* Executes a worker task.
|
|
@@ -60,6 +60,9 @@ let WorkerService = class WorkerService {
|
|
|
60
60
|
this.discovery = discovery;
|
|
61
61
|
this.options = options;
|
|
62
62
|
}
|
|
63
|
+
onModuleInit() {
|
|
64
|
+
this.initPool();
|
|
65
|
+
}
|
|
63
66
|
initPool() {
|
|
64
67
|
if (this.pool)
|
|
65
68
|
return;
|
|
@@ -102,7 +105,6 @@ let WorkerService = class WorkerService {
|
|
|
102
105
|
* ```
|
|
103
106
|
*/
|
|
104
107
|
run(serviceName, methodName, args = [], overrides = {}) {
|
|
105
|
-
this.initPool();
|
|
106
108
|
const key = `${serviceName}.${methodName}`;
|
|
107
109
|
const defaults = this.taskOptions.get(key) ??
|
|
108
110
|
{ priority: 'NORMAL' };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.service.js","sourceRoot":"","sources":["../../src/core/worker.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"worker.service.js","sourceRoot":"","sources":["../../src/core/worker.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAmF;AACnF,+CAAyC;AACzC,sEAAsE;AACtE,uDAAuD;AAGvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAa;IAWL;IAEA;IAZX,IAAI,GAAsB,IAAI,CAAC;IACtB,WAAW,GAAG,IAAI,GAAG,EAMnC,CAAC;IAEJ,YACmB,SAAiC,EAEjC,OAA4B;QAF5B,cAAS,GAAT,SAAS,CAAwB;QAEjC,YAAO,GAAP,OAAO,CAAqB;IAE/C,CAAC;IAED,YAAY;QACV,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAEO,QAAQ;QACd,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO;QAEtB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAEpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,WAAW,CAAC,GAAG,CAClB,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,EAAE,EACxC,EAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAC,CACjD,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,IAAA,kCAAkB,EAAC,KAAK,CAAC,CAAC;QAE7C,IAAI,CAAC,IAAI,GAAG,IAAI,wBAAU,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,GAAG,CACD,WAAmB,EACnB,UAAkB,EAClB,OAAkB,EAAE,EACpB,YAA2D,EAAE;QAE7D,MAAM,GAAG,GAAG,GAAG,WAAW,IAAI,UAAU,EAAE,CAAC;QAE3C,MAAM,QAAQ,GACZ,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YACzB,EAAC,QAAQ,EAAE,QAAwB,EAAC,CAAC;QAEvC,OAAO,IAAI,CAAC,IAAK,CAAC,OAAO,CAAI;YAC3B,WAAW;YACX,UAAU;YACV,IAAI;YACJ,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;YACjD,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO;SAC/C,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAC7B,CAAC;CACF,CAAA;AAnGY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;IAaR,WAAA,IAAA,eAAM,EAAC,gBAAgB,CAAC,CAAA;qCADG,0CAAsB;GAXzC,aAAa,CAmGzB"}
|
|
@@ -4,15 +4,16 @@ import type { SerializedService } from './worker-container';
|
|
|
4
4
|
* serializeForWorker – converts the live NestJS service graph into a
|
|
5
5
|
* structured-clone-safe SerializedService[] payload for workerData.
|
|
6
6
|
*
|
|
7
|
-
* KEY DESIGN DECISION:
|
|
7
|
+
* KEY DESIGN DECISION: file paths instead of class source strings.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* The previous approach extracted class source via Class.toString() and
|
|
10
|
+
* eval()'d it inside the worker. This broke on any import that TS compiled
|
|
11
|
+
* to a file-scoped alias (crypto_1, node_os_1, …) because those aliases
|
|
12
|
+
* don't exist inside a bare new Function() scope.
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* no
|
|
14
|
+
* The new approach sends the absolute path to each compiled .js file.
|
|
15
|
+
* WorkerContainer runs each file in a vm context with a custom require()
|
|
16
|
+
* that stubs NestJS packages (so decorator calls at file-eval time are
|
|
17
|
+
* silent no-ops) while letting all other imports resolve normally.
|
|
17
18
|
*/
|
|
18
19
|
export declare function serializeForWorker(tasks: DiscoveredTask[]): SerializedService[];
|
package/dist/di/di-serializer.js
CHANGED
|
@@ -6,16 +6,17 @@ const worker_task_decorator_1 = require("../decorators/worker-task.decorator");
|
|
|
6
6
|
* serializeForWorker – converts the live NestJS service graph into a
|
|
7
7
|
* structured-clone-safe SerializedService[] payload for workerData.
|
|
8
8
|
*
|
|
9
|
-
* KEY DESIGN DECISION:
|
|
9
|
+
* KEY DESIGN DECISION: file paths instead of class source strings.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* The previous approach extracted class source via Class.toString() and
|
|
12
|
+
* eval()'d it inside the worker. This broke on any import that TS compiled
|
|
13
|
+
* to a file-scoped alias (crypto_1, node_os_1, …) because those aliases
|
|
14
|
+
* don't exist inside a bare new Function() scope.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* no
|
|
16
|
+
* The new approach sends the absolute path to each compiled .js file.
|
|
17
|
+
* WorkerContainer runs each file in a vm context with a custom require()
|
|
18
|
+
* that stubs NestJS packages (so decorator calls at file-eval time are
|
|
19
|
+
* silent no-ops) while letting all other imports resolve normally.
|
|
19
20
|
*/
|
|
20
21
|
function serializeForWorker(tasks) {
|
|
21
22
|
const byService = new Map();
|
|
@@ -38,14 +39,14 @@ function serializeForWorker(tasks) {
|
|
|
38
39
|
const propertyKey = findDepPropertyKey(instance, depInstance) ?? camelCase(DepType.name);
|
|
39
40
|
return {
|
|
40
41
|
name: DepType.name,
|
|
41
|
-
|
|
42
|
+
filePath: findFilePath(DepType),
|
|
42
43
|
snapshot: snapshotInstance(depInstance),
|
|
43
44
|
propertyKey,
|
|
44
45
|
};
|
|
45
46
|
});
|
|
46
47
|
result.push({
|
|
47
48
|
name: serviceName,
|
|
48
|
-
|
|
49
|
+
filePath: findFilePath(metatype),
|
|
49
50
|
methods,
|
|
50
51
|
deps: serializedDeps,
|
|
51
52
|
});
|
|
@@ -53,38 +54,28 @@ function serializeForWorker(tasks) {
|
|
|
53
54
|
return result;
|
|
54
55
|
}
|
|
55
56
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* returns the full class body including all methods — but WITHOUT the
|
|
60
|
-
* import statements or decorator calls at the top of the file.
|
|
61
|
-
*
|
|
62
|
-
* Example output:
|
|
63
|
-
* "class ConfigService {
|
|
64
|
-
* constructor() { this.config = { MULTIPLIER: '3' }; }
|
|
65
|
-
* get(k) { return this.config[k]; }
|
|
66
|
-
* getNumber(k) { return Number(this.config[k]); }
|
|
67
|
-
* }"
|
|
68
|
-
*
|
|
69
|
-
* This is eval()-safe and has no NestJS dependencies.
|
|
57
|
+
* Locate the compiled .js file for this constructor by scanning require.cache.
|
|
58
|
+
* NestJS loads all providers via require() so every user-defined class will
|
|
59
|
+
* be present in the cache at the time serializeForWorker() is called.
|
|
70
60
|
*/
|
|
71
|
-
function
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
`so classes are emitted as native class declarations, not functions.`);
|
|
61
|
+
function findFilePath(ctor) {
|
|
62
|
+
for (const [filePath, mod] of Object.entries(require.cache)) {
|
|
63
|
+
if (!mod?.exports)
|
|
64
|
+
continue;
|
|
65
|
+
for (const val of Object.values(mod.exports)) {
|
|
66
|
+
if (val === ctor)
|
|
67
|
+
return filePath;
|
|
68
|
+
}
|
|
80
69
|
}
|
|
81
|
-
|
|
70
|
+
throw new Error(`nestworker: could not find compiled file for "${ctor.name}" in require.cache. ` +
|
|
71
|
+
`Ensure the class is exported from its module file and the project is ` +
|
|
72
|
+
`compiled (not running via ts-node) before starting.`);
|
|
82
73
|
}
|
|
83
74
|
function findDepPropertyKey(serviceInstance, depInstance) {
|
|
84
75
|
if (!serviceInstance || typeof serviceInstance !== 'object')
|
|
85
76
|
return undefined;
|
|
86
|
-
for (const
|
|
87
|
-
if (
|
|
77
|
+
for (const key of Object.getOwnPropertyNames(serviceInstance)) {
|
|
78
|
+
if (serviceInstance[key] === depInstance)
|
|
88
79
|
return key;
|
|
89
80
|
}
|
|
90
81
|
return undefined;
|
|
@@ -93,7 +84,8 @@ function snapshotInstance(instance) {
|
|
|
93
84
|
if (!instance || typeof instance !== 'object')
|
|
94
85
|
return {};
|
|
95
86
|
const out = {};
|
|
96
|
-
for (const
|
|
87
|
+
for (const k of Object.getOwnPropertyNames(instance)) {
|
|
88
|
+
const v = instance[k];
|
|
97
89
|
if (typeof v === 'function' || typeof v === 'symbol')
|
|
98
90
|
continue;
|
|
99
91
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"di-serializer.js","sourceRoot":"","sources":["../../src/di/di-serializer.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"di-serializer.js","sourceRoot":"","sources":["../../src/di/di-serializer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,33 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WorkerContainer – minimal DI container for worker threads.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Compiled NestJS files import @nestjs/common at the top — requiring them
|
|
6
|
-
* inside a worker triggers the full NestJS bootstrap chain which throws.
|
|
4
|
+
* APPROACH: vm.runInNewContext() with a shared module cache.
|
|
7
5
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* Each compiled .js file is executed inside a vm context that has:
|
|
7
|
+
* - A custom require() that blocks NestJS bootstrap imports (returning
|
|
8
|
+
* transparent Proxy stubs so decorator calls at file-eval time are no-ops)
|
|
9
|
+
* - Full access to Node built-ins and third-party packages
|
|
10
|
+
* - Correct __filename / __dirname so relative requires resolve properly
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* → Promise.resolve().then(() => __importStar(require('node:os')))
|
|
18
|
-
*
|
|
19
|
-
* These helpers are defined as `(this && this.__importStar)` at the top of
|
|
20
|
-
* each compiled file — `this` being the module. Inside new Function(),
|
|
21
|
-
* `this` is the global object so all helpers resolve to undefined, causing:
|
|
22
|
-
* Fatal: Error: __importStar is not defined
|
|
23
|
-
*
|
|
24
|
-
* We define the helpers here (Node 16+ always has Object.create, no ternary
|
|
25
|
-
* needed) and inject them alongside require as explicit parameters so both
|
|
26
|
-
* `await import()` and `require()` work correctly inside task methods.
|
|
12
|
+
* This avoids every problem of the new Function() approach:
|
|
13
|
+
* - No alias injection (crypto_1, node_os_1, …)
|
|
14
|
+
* - No TS helper injection (__importStar, __importDefault, …)
|
|
15
|
+
* - No class-body-only extraction — the full compiled file runs as-is
|
|
16
|
+
* - Dynamic import() and require() both work natively
|
|
27
17
|
*/
|
|
28
18
|
export interface SerializedDep {
|
|
29
19
|
name: string;
|
|
30
|
-
|
|
20
|
+
/** Absolute path to the compiled .js file that exports this class */
|
|
21
|
+
filePath: string;
|
|
31
22
|
snapshot: Record<string, unknown>;
|
|
32
23
|
propertyKey: string;
|
|
33
24
|
}
|
|
@@ -38,21 +29,32 @@ export interface SerializedMethod {
|
|
|
38
29
|
}
|
|
39
30
|
export interface SerializedService {
|
|
40
31
|
name: string;
|
|
41
|
-
|
|
32
|
+
/** Absolute path to the compiled .js file that exports this class */
|
|
33
|
+
filePath: string;
|
|
42
34
|
methods: SerializedMethod[];
|
|
43
35
|
deps: SerializedDep[];
|
|
44
36
|
}
|
|
45
37
|
export declare class WorkerContainer {
|
|
46
38
|
private readonly instances;
|
|
39
|
+
/**
|
|
40
|
+
* Module export cache — keyed by absolute file path.
|
|
41
|
+
* Avoids re-executing the same file multiple times when several services
|
|
42
|
+
* live in the same compiled output (monorepo barrel files, etc.).
|
|
43
|
+
*/
|
|
44
|
+
private readonly fileCache;
|
|
47
45
|
load(services: SerializedService[]): void;
|
|
48
46
|
get<T>(name: string): T;
|
|
49
|
-
private
|
|
47
|
+
private reconstructFromFile;
|
|
48
|
+
/**
|
|
49
|
+
* Load a named export from a compiled .js file by running it in a vm
|
|
50
|
+
* context. The context's require() stubs NestJS packages so decorators
|
|
51
|
+
* at file-eval time are silent no-ops, while all other imports resolve
|
|
52
|
+
* normally through the real Node module system.
|
|
53
|
+
*/
|
|
54
|
+
private loadClass;
|
|
50
55
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* require + all four TypeScript CJS helpers are injected as explicit
|
|
54
|
-
* parameters so that compiled dynamic imports (`await import(...)`) and
|
|
55
|
-
* inline require() calls inside task methods work correctly.
|
|
56
|
+
* Execute a compiled .js file in an isolated vm context and return its
|
|
57
|
+
* module.exports. Results are cached by file path.
|
|
56
58
|
*/
|
|
57
|
-
private
|
|
59
|
+
private runFile;
|
|
58
60
|
}
|
|
@@ -2,77 +2,92 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* WorkerContainer – minimal DI container for worker threads.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* Compiled NestJS files import @nestjs/common at the top — requiring them
|
|
7
|
-
* inside a worker triggers the full NestJS bootstrap chain which throws.
|
|
5
|
+
* APPROACH: vm.runInNewContext() with a shared module cache.
|
|
8
6
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* Each compiled .js file is executed inside a vm context that has:
|
|
8
|
+
* - A custom require() that blocks NestJS bootstrap imports (returning
|
|
9
|
+
* transparent Proxy stubs so decorator calls at file-eval time are no-ops)
|
|
10
|
+
* - Full access to Node built-ins and third-party packages
|
|
11
|
+
* - Correct __filename / __dirname so relative requires resolve properly
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* This avoids every problem of the new Function() approach:
|
|
14
|
+
* - No alias injection (crypto_1, node_os_1, …)
|
|
15
|
+
* - No TS helper injection (__importStar, __importDefault, …)
|
|
16
|
+
* - No class-body-only extraction — the full compiled file runs as-is
|
|
17
|
+
* - Dynamic import() and require() both work natively
|
|
18
|
+
*/
|
|
19
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.WorkerContainer = void 0;
|
|
24
|
+
const node_vm_1 = __importDefault(require("node:vm"));
|
|
25
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
26
|
+
const node_module_1 = __importDefault(require("node:module"));
|
|
27
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
28
|
+
/**
|
|
29
|
+
* NestJS packages that must never be required inside a worker.
|
|
30
|
+
* Requiring them triggers the full NestJS bootstrap chain which crashes
|
|
31
|
+
* in an isolated vm context. We stub them with a transparent Proxy so
|
|
32
|
+
* decorator calls (@Injectable, @Controller, etc.) at file-eval time
|
|
33
|
+
* become silent no-ops.
|
|
34
|
+
*/
|
|
35
|
+
const NESTJS_STUB_PACKAGES = new Set([
|
|
36
|
+
'@nestjs/common',
|
|
37
|
+
'@nestjs/core',
|
|
38
|
+
'@nestjs/microservices',
|
|
39
|
+
'@nestjs/platform-express',
|
|
40
|
+
'@nestjs/platform-fastify',
|
|
41
|
+
'reflect-metadata',
|
|
42
|
+
]);
|
|
43
|
+
/**
|
|
44
|
+
* A Proxy that silently absorbs NestJS decorator calls at file-eval time.
|
|
16
45
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
46
|
+
* The apply trap passes through its first argument when it is a function —
|
|
47
|
+
* this preserves the class through decorator factory patterns emitted by TS:
|
|
19
48
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* `this` is the global object so all helpers resolve to undefined, causing:
|
|
23
|
-
* Fatal: Error: __importStar is not defined
|
|
49
|
+
* MyClass = Injectable()(MyClass) ?? MyClass
|
|
50
|
+
* └─ NOOP_STUB() ──┘└─ apply(MyClass) → MyClass ─┘
|
|
24
51
|
*
|
|
25
|
-
*
|
|
26
|
-
* needed) and inject them alongside require as explicit parameters so both
|
|
27
|
-
* `await import()` and `require()` work correctly inside task methods.
|
|
52
|
+
* Without this, NOOP_STUB would replace the class, breaking all exports.
|
|
28
53
|
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
o[k2] = m[k];
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
function __setModuleDefault(o, v) {
|
|
45
|
-
Object.defineProperty(o, 'default', { enumerable: true, value: v });
|
|
46
|
-
}
|
|
47
|
-
function __importStar(mod) {
|
|
48
|
-
if (mod && mod.__esModule)
|
|
49
|
-
return mod;
|
|
50
|
-
const result = {};
|
|
51
|
-
if (mod != null) {
|
|
52
|
-
for (const k of Object.getOwnPropertyNames(mod)) {
|
|
53
|
-
if (k !== 'default')
|
|
54
|
-
__createBinding(result, mod, k);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
__setModuleDefault(result, mod);
|
|
58
|
-
return result;
|
|
59
|
-
}
|
|
60
|
-
function __importDefault(mod) {
|
|
61
|
-
return mod && mod.__esModule ? mod : { default: mod };
|
|
62
|
-
}
|
|
54
|
+
const NOOP_STUB = new Proxy(
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
56
|
+
function () { }, {
|
|
57
|
+
get: (_t, _k) => NOOP_STUB,
|
|
58
|
+
apply: (_t, _this, args) => {
|
|
59
|
+
// If called with a class/function as the first arg (decorator pattern),
|
|
60
|
+
// return it unchanged so the assignment keeps the real class.
|
|
61
|
+
const first = args[0];
|
|
62
|
+
return typeof first === 'function' ? first : NOOP_STUB;
|
|
63
|
+
},
|
|
64
|
+
construct: () => Object.create(null),
|
|
65
|
+
});
|
|
63
66
|
// ── WorkerContainer ───────────────────────────────────────────────────────
|
|
64
67
|
class WorkerContainer {
|
|
65
68
|
instances = new Map();
|
|
69
|
+
/**
|
|
70
|
+
* Module export cache — keyed by absolute file path.
|
|
71
|
+
* Avoids re-executing the same file multiple times when several services
|
|
72
|
+
* live in the same compiled output (monorepo barrel files, etc.).
|
|
73
|
+
*/
|
|
74
|
+
fileCache = new Map();
|
|
66
75
|
load(services) {
|
|
67
76
|
for (const svc of services) {
|
|
68
|
-
|
|
77
|
+
// Reconstruct each dep from its compiled file + snapshot
|
|
78
|
+
const depsByKey = new Map();
|
|
69
79
|
for (const dep of svc.deps) {
|
|
70
|
-
const inst = this.
|
|
80
|
+
const inst = this.reconstructFromFile(dep.filePath, dep.name, dep.snapshot);
|
|
71
81
|
this.instances.set(dep.name, inst);
|
|
72
|
-
|
|
82
|
+
depsByKey.set(dep.propertyKey, inst);
|
|
83
|
+
}
|
|
84
|
+
// Allocate the service without calling its constructor — deps are
|
|
85
|
+
// assigned by property key so constructor slot order never matters.
|
|
86
|
+
const ServiceClass = this.loadClass(svc.filePath, svc.name);
|
|
87
|
+
const serviceInstance = Object.create(ServiceClass.prototype);
|
|
88
|
+
for (const [key, inst] of depsByKey) {
|
|
89
|
+
serviceInstance[key] = inst;
|
|
73
90
|
}
|
|
74
|
-
const ServiceClass = this.evalClass(svc.classSource, svc.name);
|
|
75
|
-
const serviceInstance = new ServiceClass(...depInstances);
|
|
76
91
|
this.instances.set(svc.name, serviceInstance);
|
|
77
92
|
}
|
|
78
93
|
}
|
|
@@ -82,29 +97,74 @@ class WorkerContainer {
|
|
|
82
97
|
throw new Error(`WorkerContainer: "${name}" not found`);
|
|
83
98
|
return inst;
|
|
84
99
|
}
|
|
85
|
-
|
|
86
|
-
const DepClass = this.
|
|
100
|
+
reconstructFromFile(filePath, className, snapshot) {
|
|
101
|
+
const DepClass = this.loadClass(filePath, className);
|
|
87
102
|
const instance = Object.create(DepClass.prototype);
|
|
88
103
|
Object.assign(instance, snapshot);
|
|
89
104
|
return instance;
|
|
90
105
|
}
|
|
91
106
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* inline require() calls inside task methods work correctly.
|
|
107
|
+
* Load a named export from a compiled .js file by running it in a vm
|
|
108
|
+
* context. The context's require() stubs NestJS packages so decorators
|
|
109
|
+
* at file-eval time are silent no-ops, while all other imports resolve
|
|
110
|
+
* normally through the real Node module system.
|
|
97
111
|
*/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
102
|
-
const cls = factory(require, __importStar, __importDefault, __createBinding, __setModuleDefault);
|
|
112
|
+
loadClass(filePath, className) {
|
|
113
|
+
const exports = this.runFile(filePath);
|
|
114
|
+
const cls = exports[className];
|
|
103
115
|
if (typeof cls !== 'function') {
|
|
104
|
-
throw new Error(`WorkerContainer:
|
|
116
|
+
throw new Error(`WorkerContainer: "${className}" not found in "${filePath}". ` +
|
|
117
|
+
`Available exports: ${Object.keys(exports).join(', ')}`);
|
|
105
118
|
}
|
|
106
119
|
return cls;
|
|
107
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Execute a compiled .js file in an isolated vm context and return its
|
|
123
|
+
* module.exports. Results are cached by file path.
|
|
124
|
+
*/
|
|
125
|
+
runFile(filePath) {
|
|
126
|
+
const cached = this.fileCache.get(filePath);
|
|
127
|
+
if (cached)
|
|
128
|
+
return cached;
|
|
129
|
+
const source = node_fs_1.default.readFileSync(filePath, 'utf8');
|
|
130
|
+
const mod = { exports: {} };
|
|
131
|
+
const customRequire = node_module_1.default.createRequire(filePath);
|
|
132
|
+
const sandboxRequire = (id) => {
|
|
133
|
+
if (NESTJS_STUB_PACKAGES.has(id))
|
|
134
|
+
return NOOP_STUB;
|
|
135
|
+
return customRequire(id);
|
|
136
|
+
};
|
|
137
|
+
const context = node_vm_1.default.createContext({
|
|
138
|
+
require: sandboxRequire,
|
|
139
|
+
module: mod,
|
|
140
|
+
exports: mod.exports,
|
|
141
|
+
__filename: filePath,
|
|
142
|
+
__dirname: node_path_1.default.dirname(filePath),
|
|
143
|
+
// Standard globals the compiled output may reference
|
|
144
|
+
console,
|
|
145
|
+
process,
|
|
146
|
+
Buffer,
|
|
147
|
+
URL,
|
|
148
|
+
URLSearchParams,
|
|
149
|
+
fetch,
|
|
150
|
+
setTimeout,
|
|
151
|
+
clearTimeout,
|
|
152
|
+
setInterval,
|
|
153
|
+
clearInterval,
|
|
154
|
+
setImmediate,
|
|
155
|
+
clearImmediate,
|
|
156
|
+
Promise,
|
|
157
|
+
// Make the context's global === the context itself so that
|
|
158
|
+
// `(this && this.__importStar)` patterns resolve to the context global
|
|
159
|
+
// rather than to undefined (as they would in new Function()).
|
|
160
|
+
global: undefined, // set below after createContext
|
|
161
|
+
});
|
|
162
|
+
// Wire global → context so self-referential global patterns work
|
|
163
|
+
context.global = context;
|
|
164
|
+
node_vm_1.default.runInContext(source, context, { filename: filePath });
|
|
165
|
+
this.fileCache.set(filePath, mod.exports);
|
|
166
|
+
return mod.exports;
|
|
167
|
+
}
|
|
108
168
|
}
|
|
109
169
|
exports.WorkerContainer = WorkerContainer;
|
|
110
170
|
//# sourceMappingURL=worker-container.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-container.js","sourceRoot":"","sources":["../../src/di/worker-container.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"worker-container.js","sourceRoot":"","sources":["../../src/di/worker-container.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,11 +41,15 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
41
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
42
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
43
|
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
44
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
48
|
exports.ImageService = void 0;
|
|
46
49
|
const common_1 = require("@nestjs/common");
|
|
47
50
|
const worker_task_decorator_1 = require("../decorators/worker-task.decorator");
|
|
48
51
|
const config_service_1 = require("./config.service");
|
|
52
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
49
53
|
let ImageService = class ImageService {
|
|
50
54
|
configService;
|
|
51
55
|
constructor(configService) {
|
|
@@ -74,10 +78,15 @@ let ImageService = class ImageService {
|
|
|
74
78
|
const os = require('node:os');
|
|
75
79
|
return `Require os size ${os.cpus().length}`;
|
|
76
80
|
}
|
|
81
|
+
async outlineModule() {
|
|
82
|
+
const p = await promises_1.default.readFile('./package.json', 'utf-8');
|
|
83
|
+
const f = (await fetch('https://api.github.com')).status;
|
|
84
|
+
return { p: p.length, f };
|
|
85
|
+
}
|
|
77
86
|
};
|
|
78
87
|
exports.ImageService = ImageService;
|
|
79
88
|
__decorate([
|
|
80
|
-
(0, worker_task_decorator_1.WorkerTask)(),
|
|
89
|
+
(0, worker_task_decorator_1.WorkerTask)({ priority: 'HIGH' }),
|
|
81
90
|
__metadata("design:type", Function),
|
|
82
91
|
__metadata("design:paramtypes", [Number]),
|
|
83
92
|
__metadata("design:returntype", Number)
|
|
@@ -100,6 +109,12 @@ __decorate([
|
|
|
100
109
|
__metadata("design:paramtypes", []),
|
|
101
110
|
__metadata("design:returntype", Promise)
|
|
102
111
|
], ImageService.prototype, "moduleRequire", null);
|
|
112
|
+
__decorate([
|
|
113
|
+
(0, worker_task_decorator_1.WorkerTask)(),
|
|
114
|
+
__metadata("design:type", Function),
|
|
115
|
+
__metadata("design:paramtypes", []),
|
|
116
|
+
__metadata("design:returntype", Promise)
|
|
117
|
+
], ImageService.prototype, "outlineModule", null);
|
|
103
118
|
exports.ImageService = ImageService = __decorate([
|
|
104
119
|
(0, common_1.Injectable)(),
|
|
105
120
|
(0, worker_task_decorator_1.WorkerClass)({ deps: [config_service_1.ConfigService] }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.service.js","sourceRoot":"","sources":["../../src/example/image.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"image.service.js","sourceRoot":"","sources":["../../src/example/image.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA4C;AAC5C,+EAA8E;AAC9E,qDAAiD;AACjD,2DAA6B;AAItB,IAAM,YAAY,GAAlB,MAAM,YAAY;IACM;IAA7B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IACzD,CAAC;IAGD,WAAW,CAAC,KAAa;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC9D,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE;YAAE,KAAK,IAAI,CAAC,GAAG,KAAK,GAAG,UAAU,CAAC;QACrE,OAAO,KAAK,CAAC;IACf,CAAC;IAGD,iBAAiB,CAAC,KAAa,EAAE,MAAc;QAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC9D,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC,EAAE;YAAE,IAAI,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1E,OAAO,SAAS,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,KAAK,IAAI,MAAM,OAAO,CAAC;IAC9D,CAAC;IAGK,AAAN,KAAK,CAAC,YAAY;QAChB,MAAM,EAAE,GAAG,wDAAa,SAAS,GAAC,CAAC;QACnC,OAAO,kBAAkB,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;IAC9C,CAAC;IAGK,AAAN,KAAK,CAAC,aAAa;QACjB,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QAC9B,OAAO,mBAAmB,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;IAC/C,CAAC;IAGK,AAAN,KAAK,CAAC,aAAa;QACjB,MAAM,CAAC,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC,MAAM,CAAC;QACzD,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;IAC5B,CAAC;CACF,CAAA;AAvCY,oCAAY;AAKvB;IADC,IAAA,kCAAU,EAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;;;;+CAOhC;AAGD;IADC,IAAA,kCAAU,GAAE;;;;qDAMZ;AAGK;IADL,IAAA,kCAAU,GAAE;;;;gDAIZ;AAGK;IADL,IAAA,kCAAU,GAAE;;;;iDAIZ;AAGK;IADL,IAAA,kCAAU,GAAE;;;;iDAKZ;uBAtCU,YAAY;IAFxB,IAAA,mBAAU,GAAE;IACZ,IAAA,mCAAW,EAAC,EAAE,IAAI,EAAE,CAAC,8BAAa,CAAC,EAAE,CAAC;qCAEO,8BAAa;GAD9C,YAAY,CAuCxB"}
|
package/dist/example/main.js
CHANGED
|
@@ -17,7 +17,7 @@ let AppModule = class AppModule {
|
|
|
17
17
|
};
|
|
18
18
|
AppModule = __decorate([
|
|
19
19
|
(0, common_1.Module)({
|
|
20
|
-
imports: [worker_module_1.WorkerModule.forRoot({ poolSize:
|
|
20
|
+
imports: [worker_module_1.WorkerModule.forRoot({ poolSize: 8 })],
|
|
21
21
|
providers: [config_service_1.ConfigService, image_service_1.ImageService],
|
|
22
22
|
})
|
|
23
23
|
], AppModule);
|
|
@@ -47,6 +47,7 @@ async function bootstrap() {
|
|
|
47
47
|
workerService.run('ImageService', 'generateThumbnail', [640, 480], { priority: 'HIGH' }),
|
|
48
48
|
workerService.run('ImageService', 'moduleImport'),
|
|
49
49
|
workerService.run('ImageService', 'moduleRequire'),
|
|
50
|
+
workerService.run('ImageService', 'outlineModule'),
|
|
50
51
|
]);
|
|
51
52
|
console.timeEnd('concurrent');
|
|
52
53
|
console.log(' results:', results);
|
package/dist/example/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/example/main.ts"],"names":[],"mappings":";;;;;;;;AAAA,4BAA0B;AAC1B,uCAAyC;AACzC,2CAAsC;AACtC,yDAAmD;AACnD,2DAAqD;AACrD,qDAA+C;AAC/C,mDAA6C;AAM7C,IAAM,SAAS,GAAf,MAAM,SAAS;CACd,CAAA;AADK,SAAS;IAJd,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC,OAAO,CAAC,EAAC,QAAQ,EAAE,CAAC,EAAC,CAAC,CAAC;QAC9C,SAAS,EAAE,CAAC,8BAAa,EAAE,4BAAY,CAAC;KACzC,CAAC;GACI,SAAS,CACd;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,wBAAwB,CAAC,SAAS,EAAE;QAChE,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,8BAAa,CAAC,CAAC;IAE7C,6EAA6E;IAC7E,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,CACrC,cAAc,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,CACnC,CAAC;IACF,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAElC,6EAA6E;IAC7E,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;IAC9D,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,GAAG,CACnC,cAAc,EAAE,mBAAmB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAC,QAAQ,EAAE,KAAK,EAAC,CACrE,CAAC;IACF,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAEhC,8EAA8E;IAC9E,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;IACrE,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;QACvC,aAAa,CAAC,GAAG,CAAS,cAAc,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,EAAC,QAAQ,EAAE,KAAK,EAAC,CAAC;QAChF,aAAa,CAAC,GAAG,CAAS,cAAc,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,EAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAC,CAAC;QAC9F,aAAa,CAAC,GAAG,CAAS,cAAc,EAAE,mBAAmB,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAC,QAAQ,EAAE,MAAM,EAAC,CAAC;QAC9F,aAAa,CAAC,GAAG,CAAS,cAAc,EAAE,cAAc,CAAC;QACzD,aAAa,CAAC,GAAG,CAAS,cAAc,EAAE,eAAe,CAAC;KAC3D,CAAC,CAAC;IACH,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAEnC,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/example/main.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED