@noxfly/noxus 1.1.10 → 2.0.0

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.
@@ -0,0 +1,485 @@
1
+ /**
2
+ * @copyright 2025 NoxFly
3
+ * @license MIT
4
+ * @author NoxFly
5
+ */
6
+ var __defProp = Object.defineProperty;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
10
+
11
+ // src/request.ts
12
+ import "reflect-metadata";
13
+
14
+ // src/DI/app-injector.ts
15
+ import "reflect-metadata";
16
+
17
+ // src/exceptions.ts
18
+ var _ResponseException = class _ResponseException extends Error {
19
+ constructor(statusOrMessage, message) {
20
+ let statusCode;
21
+ if (typeof statusOrMessage === "number") {
22
+ statusCode = statusOrMessage;
23
+ } else if (typeof statusOrMessage === "string") {
24
+ message = statusOrMessage;
25
+ }
26
+ super(message ?? "");
27
+ __publicField(this, "status", 0);
28
+ if (statusCode !== void 0) {
29
+ this.status = statusCode;
30
+ }
31
+ this.name = this.constructor.name.replace(/([A-Z])/g, " $1");
32
+ }
33
+ };
34
+ __name(_ResponseException, "ResponseException");
35
+ var ResponseException = _ResponseException;
36
+ var _InternalServerException = class _InternalServerException extends ResponseException {
37
+ constructor() {
38
+ super(...arguments);
39
+ __publicField(this, "status", 500);
40
+ }
41
+ };
42
+ __name(_InternalServerException, "InternalServerException");
43
+ var InternalServerException = _InternalServerException;
44
+
45
+ // src/DI/app-injector.ts
46
+ var _AppInjector = class _AppInjector {
47
+ constructor(name = null) {
48
+ __publicField(this, "name");
49
+ __publicField(this, "bindings", /* @__PURE__ */ new Map());
50
+ __publicField(this, "singletons", /* @__PURE__ */ new Map());
51
+ __publicField(this, "scoped", /* @__PURE__ */ new Map());
52
+ this.name = name;
53
+ }
54
+ /**
55
+ * Typically used to create a dependency injection scope
56
+ * at the "scope" level (i.e., per-request lifetime).
57
+ *
58
+ * SHOULD NOT BE USED by anything else than the framework itself.
59
+ */
60
+ createScope() {
61
+ const scope = new _AppInjector();
62
+ scope.bindings = this.bindings;
63
+ scope.singletons = this.singletons;
64
+ return scope;
65
+ }
66
+ /**
67
+ * Called when resolving a dependency,
68
+ * i.e., retrieving the instance of a given class.
69
+ */
70
+ resolve(target) {
71
+ const binding = this.bindings.get(target);
72
+ if (!binding) throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${target.name}.
73
+ Did you forget to use @Injectable() decorator ?`);
74
+ switch (binding.lifetime) {
75
+ case "transient":
76
+ return this.instantiate(binding.implementation);
77
+ case "scope": {
78
+ if (this.scoped.has(target)) {
79
+ return this.scoped.get(target);
80
+ }
81
+ const instance = this.instantiate(binding.implementation);
82
+ this.scoped.set(target, instance);
83
+ return instance;
84
+ }
85
+ case "singleton": {
86
+ if (binding.instance === void 0 && this.name === "root") {
87
+ binding.instance = this.instantiate(binding.implementation);
88
+ this.singletons.set(target, binding.instance);
89
+ }
90
+ return binding.instance;
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ *
96
+ */
97
+ instantiate(target) {
98
+ const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
99
+ const params = paramTypes.map((p) => this.resolve(p));
100
+ return new target(...params);
101
+ }
102
+ };
103
+ __name(_AppInjector, "AppInjector");
104
+ var AppInjector = _AppInjector;
105
+ var RootInjector = new AppInjector("root");
106
+
107
+ // src/request.ts
108
+ var _Request = class _Request {
109
+ constructor(event, senderId, id, method, path, body) {
110
+ __publicField(this, "event");
111
+ __publicField(this, "senderId");
112
+ __publicField(this, "id");
113
+ __publicField(this, "method");
114
+ __publicField(this, "path");
115
+ __publicField(this, "body");
116
+ __publicField(this, "context", RootInjector.createScope());
117
+ __publicField(this, "params", {});
118
+ this.event = event;
119
+ this.senderId = senderId;
120
+ this.id = id;
121
+ this.method = method;
122
+ this.path = path;
123
+ this.body = body;
124
+ this.path = path.replace(/^\/|\/$/g, "");
125
+ }
126
+ };
127
+ __name(_Request, "Request");
128
+ var Request = _Request;
129
+ var RENDERER_EVENT_TYPE = "noxus:event";
130
+ function createRendererEventMessage(event, payload) {
131
+ return {
132
+ type: RENDERER_EVENT_TYPE,
133
+ event,
134
+ payload
135
+ };
136
+ }
137
+ __name(createRendererEventMessage, "createRendererEventMessage");
138
+ function isRendererEventMessage(value) {
139
+ if (value === null || typeof value !== "object") {
140
+ return false;
141
+ }
142
+ const possibleMessage = value;
143
+ return possibleMessage.type === RENDERER_EVENT_TYPE && typeof possibleMessage.event === "string";
144
+ }
145
+ __name(isRendererEventMessage, "isRendererEventMessage");
146
+
147
+ // src/renderer-events.ts
148
+ var _RendererEventRegistry = class _RendererEventRegistry {
149
+ constructor() {
150
+ __publicField(this, "listeners", /* @__PURE__ */ new Map());
151
+ }
152
+ /**
153
+ *
154
+ */
155
+ subscribe(eventName, handler) {
156
+ const normalizedEventName = eventName.trim();
157
+ if (normalizedEventName.length === 0) {
158
+ throw new Error("Renderer event name must be a non-empty string.");
159
+ }
160
+ const handlers = this.listeners.get(normalizedEventName) ?? /* @__PURE__ */ new Set();
161
+ handlers.add(handler);
162
+ this.listeners.set(normalizedEventName, handlers);
163
+ return {
164
+ unsubscribe: /* @__PURE__ */ __name(() => this.unsubscribe(normalizedEventName, handler), "unsubscribe")
165
+ };
166
+ }
167
+ /**
168
+ *
169
+ */
170
+ unsubscribe(eventName, handler) {
171
+ const handlers = this.listeners.get(eventName);
172
+ if (!handlers) {
173
+ return;
174
+ }
175
+ handlers.delete(handler);
176
+ if (handlers.size === 0) {
177
+ this.listeners.delete(eventName);
178
+ }
179
+ }
180
+ /**
181
+ *
182
+ */
183
+ clear(eventName) {
184
+ if (eventName) {
185
+ this.listeners.delete(eventName);
186
+ return;
187
+ }
188
+ this.listeners.clear();
189
+ }
190
+ /**
191
+ *
192
+ */
193
+ dispatch(message) {
194
+ const handlers = this.listeners.get(message.event);
195
+ if (!handlers || handlers.size === 0) {
196
+ return;
197
+ }
198
+ handlers.forEach((handler) => {
199
+ try {
200
+ handler(message.payload);
201
+ } catch (error) {
202
+ console.error(`[Noxus] Renderer event handler for "${message.event}" threw an error.`, error);
203
+ }
204
+ });
205
+ }
206
+ /**
207
+ *
208
+ */
209
+ tryDispatchFromMessageEvent(event) {
210
+ if (!isRendererEventMessage(event.data)) {
211
+ return false;
212
+ }
213
+ this.dispatch(event.data);
214
+ return true;
215
+ }
216
+ /**
217
+ *
218
+ */
219
+ hasHandlers(eventName) {
220
+ const handlers = this.listeners.get(eventName);
221
+ return !!handlers && handlers.size > 0;
222
+ }
223
+ };
224
+ __name(_RendererEventRegistry, "RendererEventRegistry");
225
+ var RendererEventRegistry = _RendererEventRegistry;
226
+
227
+ // src/renderer-client.ts
228
+ var DEFAULT_INIT_EVENT = "init-port";
229
+ var DEFAULT_BRIDGE_NAMES = [
230
+ "noxus",
231
+ "ipcRenderer"
232
+ ];
233
+ function defaultRequestId() {
234
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
235
+ return crypto.randomUUID();
236
+ }
237
+ return `${Date.now().toString(16)}-${Math.floor(Math.random() * 1e8).toString(16)}`;
238
+ }
239
+ __name(defaultRequestId, "defaultRequestId");
240
+ function normalizeBridgeNames(preferred) {
241
+ const names = [];
242
+ const add = /* @__PURE__ */ __name((name) => {
243
+ if (!name) return;
244
+ if (!names.includes(name)) {
245
+ names.push(name);
246
+ }
247
+ }, "add");
248
+ if (Array.isArray(preferred)) {
249
+ for (const name of preferred) {
250
+ add(name);
251
+ }
252
+ } else {
253
+ add(preferred);
254
+ }
255
+ for (const fallback of DEFAULT_BRIDGE_NAMES) {
256
+ add(fallback);
257
+ }
258
+ return names;
259
+ }
260
+ __name(normalizeBridgeNames, "normalizeBridgeNames");
261
+ function resolveBridgeFromWindow(windowRef, preferred) {
262
+ const names = normalizeBridgeNames(preferred);
263
+ const globalRef = windowRef;
264
+ if (!globalRef) {
265
+ return null;
266
+ }
267
+ for (const name of names) {
268
+ const candidate = globalRef[name];
269
+ if (candidate && typeof candidate.requestPort === "function") {
270
+ return candidate;
271
+ }
272
+ }
273
+ return null;
274
+ }
275
+ __name(resolveBridgeFromWindow, "resolveBridgeFromWindow");
276
+ var _NoxRendererClient = class _NoxRendererClient {
277
+ constructor(options = {}) {
278
+ __publicField(this, "events", new RendererEventRegistry());
279
+ __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
280
+ __publicField(this, "requestPort");
281
+ __publicField(this, "socketPort");
282
+ __publicField(this, "senderId");
283
+ __publicField(this, "bridge");
284
+ __publicField(this, "initMessageType");
285
+ __publicField(this, "windowRef");
286
+ __publicField(this, "generateRequestId");
287
+ __publicField(this, "isReady", false);
288
+ __publicField(this, "setupPromise");
289
+ __publicField(this, "setupResolve");
290
+ __publicField(this, "setupReject");
291
+ __publicField(this, "onWindowMessage", /* @__PURE__ */ __name((event) => {
292
+ if (event.data?.type !== this.initMessageType) {
293
+ return;
294
+ }
295
+ if (!Array.isArray(event.ports) || event.ports.length < 2) {
296
+ const error = new Error("[Noxus] Renderer expected two MessagePorts (request + socket).");
297
+ console.error(error);
298
+ this.setupReject?.(error);
299
+ this.resetSetupState();
300
+ return;
301
+ }
302
+ this.windowRef.removeEventListener("message", this.onWindowMessage);
303
+ this.requestPort = event.ports[0];
304
+ this.socketPort = event.ports[1];
305
+ this.senderId = event.data.senderId;
306
+ if (this.requestPort === void 0 || this.socketPort === void 0) {
307
+ const error = new Error("[Noxus] Renderer failed to receive valid MessagePorts.");
308
+ console.error(error);
309
+ this.setupReject?.(error);
310
+ this.resetSetupState();
311
+ return;
312
+ }
313
+ this.attachRequestPort(this.requestPort);
314
+ this.attachSocketPort(this.socketPort);
315
+ this.isReady = true;
316
+ this.setupResolve?.();
317
+ this.resetSetupState(true);
318
+ }, "onWindowMessage"));
319
+ __publicField(this, "onSocketMessage", /* @__PURE__ */ __name((event) => {
320
+ if (this.events.tryDispatchFromMessageEvent(event)) {
321
+ return;
322
+ }
323
+ console.warn("[Noxus] Received a socket message that is not a renderer event payload.", event.data);
324
+ }, "onSocketMessage"));
325
+ __publicField(this, "onRequestMessage", /* @__PURE__ */ __name((event) => {
326
+ if (this.events.tryDispatchFromMessageEvent(event)) {
327
+ return;
328
+ }
329
+ const response = event.data;
330
+ if (!response || typeof response.requestId !== "string") {
331
+ console.error("[Noxus] Renderer received an invalid response payload.", response);
332
+ return;
333
+ }
334
+ const pending = this.pendingRequests.get(response.requestId);
335
+ if (!pending) {
336
+ console.error(`[Noxus] No pending handler found for request ${response.requestId}.`);
337
+ return;
338
+ }
339
+ this.pendingRequests.delete(response.requestId);
340
+ this.onRequestCompleted(pending, response);
341
+ if (response.status >= 400) {
342
+ pending.reject(response);
343
+ return;
344
+ }
345
+ pending.resolve(response.body);
346
+ }, "onRequestMessage"));
347
+ this.windowRef = options.windowRef ?? window;
348
+ const resolvedBridge = options.bridge ?? resolveBridgeFromWindow(this.windowRef, options.bridgeName);
349
+ this.bridge = resolvedBridge ?? null;
350
+ this.initMessageType = options.initMessageType ?? DEFAULT_INIT_EVENT;
351
+ this.generateRequestId = options.generateRequestId ?? defaultRequestId;
352
+ }
353
+ async setup() {
354
+ if (this.isReady) {
355
+ return Promise.resolve();
356
+ }
357
+ if (this.setupPromise) {
358
+ return this.setupPromise;
359
+ }
360
+ if (!this.bridge || typeof this.bridge.requestPort !== "function") {
361
+ throw new Error("[Noxus] Renderer bridge is missing requestPort().");
362
+ }
363
+ this.setupPromise = new Promise((resolve, reject) => {
364
+ this.setupResolve = resolve;
365
+ this.setupReject = reject;
366
+ });
367
+ this.windowRef.addEventListener("message", this.onWindowMessage);
368
+ this.bridge.requestPort();
369
+ return this.setupPromise;
370
+ }
371
+ dispose() {
372
+ this.windowRef.removeEventListener("message", this.onWindowMessage);
373
+ this.requestPort?.close();
374
+ this.socketPort?.close();
375
+ this.requestPort = void 0;
376
+ this.socketPort = void 0;
377
+ this.senderId = void 0;
378
+ this.isReady = false;
379
+ this.pendingRequests.clear();
380
+ }
381
+ async request(request) {
382
+ const senderId = this.senderId;
383
+ const requestId = this.generateRequestId();
384
+ if (senderId === void 0) {
385
+ return Promise.reject(this.createErrorResponse(requestId, "MessagePort is not available"));
386
+ }
387
+ const readinessError = this.validateReady(requestId);
388
+ if (readinessError) {
389
+ return Promise.reject(readinessError);
390
+ }
391
+ const message = {
392
+ requestId,
393
+ senderId,
394
+ ...request
395
+ };
396
+ return new Promise((resolve, reject) => {
397
+ const pending = {
398
+ resolve,
399
+ reject: /* @__PURE__ */ __name((response) => reject(response), "reject"),
400
+ request: message,
401
+ submittedAt: Date.now()
402
+ };
403
+ this.pendingRequests.set(message.requestId, pending);
404
+ this.requestPort.postMessage(message);
405
+ });
406
+ }
407
+ async batch(requests) {
408
+ return this.request({
409
+ method: "BATCH",
410
+ path: "",
411
+ body: {
412
+ requests
413
+ }
414
+ });
415
+ }
416
+ getSenderId() {
417
+ return this.senderId;
418
+ }
419
+ onRequestCompleted(pending, response) {
420
+ if (typeof console.groupCollapsed === "function") {
421
+ console.groupCollapsed(`${response.status} ${pending.request.method} /${pending.request.path}`);
422
+ }
423
+ if (response.error) {
424
+ console.error("error message:", response.error);
425
+ }
426
+ if (response.body !== void 0) {
427
+ console.info("response:", response.body);
428
+ }
429
+ console.info("request:", pending.request);
430
+ console.info(`Request duration: ${Date.now() - pending.submittedAt} ms`);
431
+ if (typeof console.groupCollapsed === "function") {
432
+ console.groupEnd();
433
+ }
434
+ }
435
+ attachRequestPort(port) {
436
+ port.onmessage = this.onRequestMessage;
437
+ port.start();
438
+ }
439
+ attachSocketPort(port) {
440
+ port.onmessage = this.onSocketMessage;
441
+ port.start();
442
+ }
443
+ validateReady(requestId) {
444
+ if (!this.isElectronEnvironment()) {
445
+ return this.createErrorResponse(requestId, "Not running in Electron environment");
446
+ }
447
+ if (!this.requestPort) {
448
+ return this.createErrorResponse(requestId, "MessagePort is not available");
449
+ }
450
+ return void 0;
451
+ }
452
+ createErrorResponse(requestId, message) {
453
+ return {
454
+ status: 500,
455
+ requestId,
456
+ error: message
457
+ };
458
+ }
459
+ resetSetupState(success = false) {
460
+ if (!success) {
461
+ this.setupPromise = void 0;
462
+ }
463
+ this.setupResolve = void 0;
464
+ this.setupReject = void 0;
465
+ }
466
+ isElectronEnvironment() {
467
+ return typeof window !== "undefined" && /Electron/.test(window.navigator.userAgent);
468
+ }
469
+ };
470
+ __name(_NoxRendererClient, "NoxRendererClient");
471
+ var NoxRendererClient = _NoxRendererClient;
472
+ export {
473
+ NoxRendererClient,
474
+ RENDERER_EVENT_TYPE,
475
+ RendererEventRegistry,
476
+ Request,
477
+ createRendererEventMessage,
478
+ isRendererEventMessage
479
+ };
480
+ /**
481
+ * @copyright 2025 NoxFly
482
+ * @license MIT
483
+ * @author NoxFly
484
+ */
485
+ //# sourceMappingURL=renderer.mjs.map
package/package.json CHANGED
@@ -1,50 +1,75 @@
1
1
  {
2
- "name": "@noxfly/noxus",
3
- "version": "1.1.10",
4
- "main": "dist/noxus.js",
5
- "types": "dist/noxus.d.ts",
6
- "scripts": {
7
- "build": "tsup",
8
- "prepublishOnly": "npm run build",
9
- "prepush": "npm run build",
10
- "postbuild": "node scripts/postbuild.js"
11
- },
12
- "keywords": [
13
- "noxus",
14
- "nox",
15
- "nodejs",
16
- "typescript",
17
- "framework",
18
- "web framework",
19
- "electron"
20
- ],
21
- "author": "NoxFly",
22
- "license": "MIT",
23
- "description": "Simulate lightweight HTTP-like requests between renderer and main process in Electron applications with MessagePort, with structured and modular design.",
24
- "homepage": "https://github.com/NoxFly/noxus",
25
- "repository": {
26
- "type": "git",
27
- "url": "https://github.com/NoxFly/noxus.git"
28
- },
29
- "engines": {
30
- "node": ">= 20"
31
- },
32
- "devDependencies": {
33
- "@stylistic/eslint-plugin": "^5.1.0",
34
- "@swc/core": "^1.12.14",
35
- "@typescript-eslint/eslint-plugin": "^8.36.0",
36
- "@typescript-eslint/parser": "^8.36.0",
37
- "electron": "^37.2.1",
38
- "eslint": "^9.31.0",
39
- "eslint-plugin-import": "^2.32.0",
40
- "eslint-plugin-jsdoc": "^51.3.4",
41
- "eslint-plugin-prefer-arrow": "^1.2.3",
42
- "tsc-alias": "^1.8.16",
43
- "tsup": "^8.5.0",
44
- "typescript": "^5.8.3",
45
- "typescript-eslint": "^8.36.0"
46
- },
47
- "peerDependencies": {
48
- "reflect-metadata": "^0.2.2"
49
- }
2
+ "name": "@noxfly/noxus",
3
+ "version": "2.0.0",
4
+ "main": "dist/main.js",
5
+ "module": "dist/main.mjs",
6
+ "types": "dist/main.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "browser": {
10
+ "types": "./dist/renderer.d.ts",
11
+ "import": "./dist/renderer.mjs",
12
+ "require": "./dist/renderer.js"
13
+ },
14
+ "default": {
15
+ "types": "./dist/main.d.ts",
16
+ "import": "./dist/main.mjs",
17
+ "require": "./dist/main.js"
18
+ }
19
+ },
20
+ "./renderer": {
21
+ "types": "./dist/renderer.d.ts",
22
+ "import": "./dist/renderer.mjs",
23
+ "require": "./dist/renderer.js"
24
+ },
25
+ "./main": {
26
+ "types": "./dist/main.d.ts",
27
+ "import": "./dist/main.mjs",
28
+ "require": "./dist/main.js"
29
+ }
30
+ },
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "prepublishOnly": "npm run build",
34
+ "prepush": "npm run build",
35
+ "postbuild": "node scripts/postbuild.js"
36
+ },
37
+ "keywords": [
38
+ "noxus",
39
+ "nox",
40
+ "nodejs",
41
+ "typescript",
42
+ "framework",
43
+ "web framework",
44
+ "electron"
45
+ ],
46
+ "author": "NoxFly",
47
+ "license": "MIT",
48
+ "description": "Simulate lightweight HTTP-like requests between renderer and main process in Electron applications with MessagePort, with structured and modular design.",
49
+ "homepage": "https://github.com/NoxFly/noxus",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/NoxFly/noxus.git"
53
+ },
54
+ "engines": {
55
+ "node": ">= 20"
56
+ },
57
+ "devDependencies": {
58
+ "@stylistic/eslint-plugin": "^5.1.0",
59
+ "@swc/core": "^1.12.14",
60
+ "@typescript-eslint/eslint-plugin": "^8.36.0",
61
+ "@typescript-eslint/parser": "^8.36.0",
62
+ "electron": "^37.2.1",
63
+ "eslint": "^9.31.0",
64
+ "eslint-plugin-import": "^2.32.0",
65
+ "eslint-plugin-jsdoc": "^51.3.4",
66
+ "eslint-plugin-prefer-arrow": "^1.2.3",
67
+ "tsc-alias": "^1.8.16",
68
+ "tsup": "^8.5.0",
69
+ "typescript": "^5.8.3",
70
+ "typescript-eslint": "^8.36.0"
71
+ },
72
+ "peerDependencies": {
73
+ "reflect-metadata": "^0.2.2"
74
+ }
50
75
  }
@@ -1,10 +1,11 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
 
4
- const frameworkName = 'noxus';
4
+ function uniqueDocBlocks(filepath) {
5
+ if(!fs.existsSync(filepath)) {
6
+ return;
7
+ }
5
8
 
6
- function removeDuplicateCopyrights(filename) {
7
- const filepath = path.join(__dirname, '../dist/' + filename);
8
9
  const content = fs.readFileSync(filepath, 'utf8');
9
10
 
10
11
  const reg = /\/\*\*[\t ]*\n(?: \*.*\n)*? \* *@copyright.*\n(?: \*.*\n)*? \*\/\n?/gm;
@@ -21,6 +22,10 @@ function removeDuplicateCopyrights(filename) {
21
22
  fs.writeFileSync(filepath, deduped);
22
23
  }
23
24
 
25
+ const distDir = path.join(__dirname, '../dist');
24
26
 
25
- removeDuplicateCopyrights(`${frameworkName}.d.mts`);
26
- removeDuplicateCopyrights(`${frameworkName}.d.ts`);
27
+ for(const filename of fs.readdirSync(distDir)) {
28
+ if(filename.endsWith('.d.ts') || filename.endsWith('.d.mts')) {
29
+ uniqueDocBlocks(path.join(distDir, filename));
30
+ }
31
+ }
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { getControllerMetadata } from "src/decorators/controller.decorator";
8
- import { getInjectableMetadata } from "src/decorators/injectable.decorator";
8
+ import { getInjectableMetadata } from "src/decorators/injectable.metadata";
9
9
  import { getRouteMetadata } from "src/decorators/method.decorator";
10
10
  import { getModuleMetadata } from "src/decorators/module.decorator";
11
11
  import { Lifetime, RootInjector } from "src/DI/app-injector";