@zerooneit/expressive-tea 1.3.0-beta.6 → 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.
Files changed (78) hide show
  1. package/.swcrc +61 -0
  2. package/README.md +564 -174
  3. package/classes/Boot.d.ts +89 -2
  4. package/classes/Boot.js +149 -31
  5. package/classes/Engine.d.ts +58 -10
  6. package/classes/Engine.js +69 -9
  7. package/classes/EngineRegistry.d.ts +154 -0
  8. package/classes/EngineRegistry.js +247 -0
  9. package/classes/LoadBalancer.js +2 -5
  10. package/classes/ProxyRoute.js +5 -5
  11. package/classes/Settings.d.ts +31 -2
  12. package/classes/Settings.js +64 -11
  13. package/decorators/annotations.d.ts +1 -1
  14. package/decorators/annotations.js +17 -17
  15. package/decorators/env.d.ts +145 -0
  16. package/decorators/env.js +177 -0
  17. package/decorators/health.d.ts +115 -0
  18. package/decorators/health.js +124 -0
  19. package/decorators/module.d.ts +15 -16
  20. package/decorators/module.js +14 -24
  21. package/decorators/proxy.d.ts +26 -11
  22. package/decorators/proxy.js +35 -49
  23. package/decorators/router.d.ts +17 -16
  24. package/decorators/router.js +31 -53
  25. package/decorators/server.d.ts +7 -7
  26. package/decorators/server.js +48 -50
  27. package/engines/health/index.d.ts +120 -0
  28. package/engines/health/index.js +179 -0
  29. package/engines/http/index.d.ts +6 -10
  30. package/engines/http/index.js +18 -17
  31. package/engines/index.d.ts +32 -0
  32. package/engines/index.js +112 -0
  33. package/engines/socketio/index.d.ts +2 -4
  34. package/engines/socketio/index.js +14 -7
  35. package/engines/teacup/index.d.ts +12 -2
  36. package/engines/teacup/index.js +56 -10
  37. package/engines/teapot/index.d.ts +12 -2
  38. package/engines/teapot/index.js +58 -17
  39. package/engines/websocket/index.d.ts +1 -1
  40. package/engines/websocket/index.js +8 -3
  41. package/eslint.config.mjs +138 -0
  42. package/exceptions/RequestExceptions.d.ts +3 -3
  43. package/helpers/boot-helper.d.ts +4 -4
  44. package/helpers/boot-helper.js +27 -22
  45. package/helpers/decorators.js +7 -6
  46. package/helpers/promise-helper.d.ts +1 -1
  47. package/helpers/promise-helper.js +1 -2
  48. package/helpers/server.d.ts +31 -5
  49. package/helpers/server.js +98 -60
  50. package/helpers/teapot-helper.d.ts +2 -3
  51. package/helpers/teapot-helper.js +34 -8
  52. package/helpers/websocket-helper.d.ts +1 -3
  53. package/helpers/websocket-helper.js +3 -3
  54. package/interfaces/index.d.ts +1 -1
  55. package/inversify.config.d.ts +4 -4
  56. package/inversify.config.js +1 -1
  57. package/libs/utilities.d.ts +21910 -0
  58. package/libs/utilities.js +420 -0
  59. package/mixins/module.d.ts +45 -0
  60. package/mixins/module.js +71 -0
  61. package/mixins/proxy.d.ts +46 -0
  62. package/mixins/proxy.js +86 -0
  63. package/mixins/route.d.ts +48 -0
  64. package/mixins/route.js +96 -0
  65. package/package.json +85 -73
  66. package/services/DependencyInjection.d.ts +94 -8
  67. package/services/DependencyInjection.js +121 -3
  68. package/services/WebsocketService.d.ts +2 -4
  69. package/services/WebsocketService.js +5 -3
  70. package/types/core.d.ts +14 -0
  71. package/types/core.js +2 -0
  72. package/types/injection-types.d.ts +6 -0
  73. package/types/injection-types.js +10 -0
  74. package/types/inversify.d.ts +5 -0
  75. package/types/inversify.js +3 -0
  76. package/.eslintrc.js +0 -44
  77. package/tsconfig.linter.json +0 -24
  78. package/tslint-to-eslint-config.log +0 -12
@@ -1,16 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return */
4
5
  const chalk = require("chalk");
5
6
  const url_1 = require("url");
6
7
  const socket_io_client_1 = require("socket.io-client");
7
8
  const inversify_1 = require("inversify");
8
- const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
9
- const constants_1 = require("@expressive-tea/commons/constants");
9
+ const commons_1 = require("@expressive-tea/commons");
10
+ const commons_2 = require("@expressive-tea/commons");
10
11
  const teapot_helper_1 = require("../../helpers/teapot-helper");
11
- const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
12
+ const commons_3 = require("@expressive-tea/commons");
12
13
  const Engine_1 = require("../../classes/Engine");
13
14
  let TeacupEngine = class TeacupEngine extends Engine_1.default {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.isStopping = false;
18
+ }
14
19
  header() {
15
20
  console.log(chalk.white.bold('Teacup Engine is initializing...'));
16
21
  console.log(chalk `
@@ -25,6 +30,7 @@ let TeacupEngine = class TeacupEngine extends Engine_1.default {
25
30
  All Communication are encrypted to ensure intruder can not connected, however, please does not share any sensitive data like keys or passwords to avoid security issues.
26
31
  `);
27
32
  }
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
34
  handshaked(key, signature, isSecure, cb) {
29
35
  try {
30
36
  console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {yellow.bold Server Verification Started}`);
@@ -37,30 +43,33 @@ All Communication are encrypted to ensure intruder can not connected, however, p
37
43
  cb(Buffer.from(this.publicKey), this.clientSignature);
38
44
  }
39
45
  catch (e) {
40
- console.error(chalk `{cyan.bold [TEACUP]} - {red.bold TEAPOD} {magenta.bold ${this.client.id}}: Failed with next message: ${e.message}`);
46
+ const error = e;
47
+ console.error(chalk `{cyan.bold [TEACUP]} - {red.bold TEAPOD} {magenta.bold ${this.client.id}}: Failed with next message: ${error.message}`);
41
48
  this.client.disconnect();
42
49
  }
43
50
  }
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
52
  accepted(cb) {
45
53
  var _a;
46
54
  console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {green.bold Registered} - {blue.bold <${this.teacupSettings.serverUrl}>} <-> {white.bold ${this.teacupSettings.mountTo}}`);
47
55
  const encryptedMessage = teapot_helper_1.default.encrypt({
48
56
  mountTo: this.teacupSettings.mountTo,
49
57
  address: this.teacupSettings.address
50
- }, this.serverSignature.slice(0, 32));
58
+ }, this.serverSignature);
51
59
  cb(encryptedMessage);
52
60
  const onClose = () => {
53
61
  try {
54
62
  this.client.close();
55
63
  }
56
- catch (_) {
64
+ catch (_a) {
65
+ // Intentionally empty - ignore close errors
57
66
  }
58
67
  };
59
68
  this.server.on('close', onClose);
60
69
  (_a = this.serverSecure) === null || _a === void 0 ? void 0 : _a.on('close', onClose);
61
70
  }
62
71
  async start() {
63
- this.teacupSettings = Metadata_1.default.get(constants_1.ASSIGN_TEACUP_KEY, (0, object_helper_1.getClass)(this.context));
72
+ this.teacupSettings = commons_1.Metadata.get(commons_2.ASSIGN_TEACUP_KEY, (0, commons_3.getClass)(this.context));
64
73
  const scheme = new url_1.URL(this.teacupSettings.serverUrl);
65
74
  const { publicKey, privateKey } = teapot_helper_1.default.generateKeys(this.teacupSettings.clientKey);
66
75
  const protocol = teapot_helper_1.default.httpSchema(scheme.protocol);
@@ -80,11 +89,48 @@ All Communication are encrypted to ensure intruder can not connected, however, p
80
89
  this.client.on('error', console.log);
81
90
  this.client.connect();
82
91
  }
83
- static canRegister(ctx, settings) {
84
- return Metadata_1.default.get(constants_1.ASSIGN_TEACUP_KEY, (0, object_helper_1.getClass)(ctx), 'isTeacupActive');
92
+ static canRegister(ctx) {
93
+ return commons_1.Metadata.get(commons_2.ASSIGN_TEACUP_KEY, (0, commons_3.getClass)(ctx), 'isTeacupActive');
94
+ }
95
+ /**
96
+ * Graceful shutdown for TeacupEngine
97
+ *
98
+ * Disconnects the socket.io-client connection and prevents automatic reconnection.
99
+ * This method is idempotent and safe to call multiple times.
100
+ *
101
+ * @returns {Promise<void>} Promise that resolves when cleanup is complete
102
+ * @since 2.0.0
103
+ */
104
+ async stop() {
105
+ // Prevent multiple stop calls from racing
106
+ if (this.isStopping) {
107
+ return;
108
+ }
109
+ this.isStopping = true;
110
+ if (this.client) {
111
+ try {
112
+ // Disable reconnection before disconnecting to prevent automatic reconnect attempts
113
+ this.client.io.opts.reconnection = false;
114
+ // Remove all listeners to prevent any callbacks during shutdown
115
+ this.client.removeAllListeners();
116
+ // Disconnect the socket
117
+ if (this.client.connected) {
118
+ this.client.disconnect();
119
+ }
120
+ // Close the underlying manager to release all resources
121
+ this.client.close();
122
+ console.log('[TEACUP] - Socket connection closed gracefully');
123
+ }
124
+ catch (e) {
125
+ // Log but don't throw - we want shutdown to complete even if cleanup has issues
126
+ const error = e;
127
+ console.error(`[TEACUP] - Error during shutdown: ${error.message}`);
128
+ }
129
+ }
85
130
  }
86
131
  };
87
132
  TeacupEngine = tslib_1.__decorate([
88
- (0, inversify_1.injectable)()
133
+ (0, inversify_1.injectable)(),
134
+ (0, inversify_1.injectFromBase)({ extendConstructorArguments: true })
89
135
  ], TeacupEngine);
90
136
  exports.default = TeacupEngine;
@@ -1,6 +1,5 @@
1
1
  import ExpressiveTeaEngine from '../../classes/Engine';
2
2
  import Boot from '../../classes/Boot';
3
- import Settings from '../../classes/Settings';
4
3
  export default class TeapotEngine extends ExpressiveTeaEngine {
5
4
  private readonly clients;
6
5
  private readonly registeredRoute;
@@ -9,6 +8,7 @@ export default class TeapotEngine extends ExpressiveTeaEngine {
9
8
  private privateKey;
10
9
  private serverSignature;
11
10
  private socketServer;
11
+ private isStopped;
12
12
  private static header;
13
13
  private registerTeacup;
14
14
  private clientVerification;
@@ -18,5 +18,15 @@ export default class TeapotEngine extends ExpressiveTeaEngine {
18
18
  private disconnected;
19
19
  init(): Promise<void>;
20
20
  start(): Promise<void>;
21
- static canRegister(ctx?: Boot, settings?: Settings): boolean;
21
+ /**
22
+ * Graceful shutdown for the Teapot engine.
23
+ *
24
+ * Disconnects all connected Teacup clients, closes the Socket.IO namespace,
25
+ * and clears internal state. This method is idempotent and safe to call multiple times.
26
+ *
27
+ * @returns {Promise<void>} Promise that resolves when cleanup is complete
28
+ * @since 2.0.0
29
+ */
30
+ stop(): Promise<void>;
31
+ static canRegister(ctx?: Boot): boolean;
22
32
  }
@@ -4,18 +4,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const tslib_1 = require("tslib");
5
5
  const chalk = require("chalk");
6
6
  const inversify_1 = require("inversify");
7
- const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
8
- const constants_1 = require("@expressive-tea/commons/constants");
7
+ const commons_1 = require("@expressive-tea/commons");
8
+ const commons_2 = require("@expressive-tea/commons");
9
9
  const ProxyRoute_1 = require("../../classes/ProxyRoute");
10
10
  const Engine_1 = require("../../classes/Engine");
11
11
  const teapot_helper_1 = require("../../helpers/teapot-helper");
12
- const constants_2 = require("../constants/constants");
13
- const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
12
+ const constants_1 = require("../constants/constants");
13
+ const commons_3 = require("@expressive-tea/commons");
14
14
  let TeapotEngine = TeapotEngine_1 = class TeapotEngine extends Engine_1.default {
15
15
  constructor() {
16
16
  super(...arguments);
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
18
  this.clients = new Map();
18
19
  this.registeredRoute = new Map();
20
+ this.isStopped = false;
19
21
  }
20
22
  static header(teapotSettings) {
21
23
  console.log(chalk.white.bold('Teapot Engine is initializing...'));
@@ -42,8 +44,6 @@ All Communication are encrypted to ensure intruder can not connected, however, p
42
44
  }
43
45
  clientVerification(teacup, userPublicKey, userSignature) {
44
46
  console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {yellow.bold Client Verification Started}`);
45
- console.log('userKey', userPublicKey.toString('base64'));
46
- console.log('userSignature', userSignature.toString('base64'));
47
47
  try {
48
48
  if (!teapot_helper_1.default.verify(this.teapotSettings.clientKey, userPublicKey.toString('ascii'), userSignature)) {
49
49
  console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${teacup.id}}]: Failed to verify and will be disconnected...`);
@@ -57,31 +57,37 @@ All Communication are encrypted to ensure intruder can not connected, however, p
57
57
  console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {green.bold Client Verified}`);
58
58
  }
59
59
  catch (e) {
60
- console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${teacup.id}}]: Failed wiht next message: ${e.message}`);
60
+ const error = e;
61
+ console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${teacup.id}}]: Failed wiht next message: ${error.message}`);
61
62
  teacup.disconnect();
62
63
  }
63
64
  }
64
65
  registered(teacup, encryptedMessage) {
65
66
  try {
66
- const message = teapot_helper_1.default.decrypt(encryptedMessage, this.serverSignature.slice(0, 32));
67
+ const message = teapot_helper_1.default.decrypt(encryptedMessage, this.serverSignature);
67
68
  const isRegistered = this.registeredRoute.has(message.mountTo);
68
69
  const proxyRoute = isRegistered ? this.registeredRoute.get(message.mountTo) : new ProxyRoute_1.default(message.mountTo);
70
+ if (!proxyRoute) {
71
+ throw new Error('Failed to create or retrieve proxy route');
72
+ }
69
73
  proxyRoute.registerServer(message.address, teacup.id);
70
74
  if (!isRegistered) {
71
75
  this.registeredRoute.set(message.mountTo, proxyRoute);
72
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
73
76
  this.context.getApplication().use(message.mountTo, teapot_helper_1.default.proxyResponse.bind(this, proxyRoute));
74
77
  }
75
78
  console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}] {blue.bold <${message.address}>} <--> {white.bold ${message.mountTo}}`);
76
79
  }
77
80
  catch (e) {
78
- console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${e.message}`);
81
+ const error = e;
82
+ console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${error.message}`);
79
83
  }
80
84
  }
81
85
  removeFromRoutes(routes = [], id) {
82
86
  routes.forEach(route => {
83
87
  const proxyRoute = this.registeredRoute.get(route);
84
- proxyRoute.unregisterServer(id);
88
+ if (proxyRoute) {
89
+ proxyRoute.unregisterServer(id);
90
+ }
85
91
  });
86
92
  }
87
93
  findClientInRoutes(teacupId) {
@@ -100,27 +106,62 @@ All Communication are encrypted to ensure intruder can not connected, however, p
100
106
  console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: Got disconnected by ${reason}`);
101
107
  }
102
108
  catch (e) {
103
- console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${e.message}`);
109
+ const error = e;
110
+ console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${error.message}`);
104
111
  }
105
112
  }
106
113
  async init() {
107
- this.teapotSettings = Metadata_1.default.get(constants_1.ASSIGN_TEAPOT_KEY, this.context);
114
+ // Metadata is stored on the class by decorators, not on instances
115
+ this.teapotSettings = commons_1.Metadata.get(commons_2.ASSIGN_TEAPOT_KEY, (0, commons_3.getClass)(this.context));
108
116
  const { publicKey, privateKey } = teapot_helper_1.default.generateKeys(this.teapotSettings.serverKey);
109
117
  this.publicKey = publicKey;
110
118
  this.privateKey = privateKey;
111
119
  this.serverSignature = teapot_helper_1.default.sign(this.teapotSettings.clientKey, privateKey, this.teapotSettings.serverKey);
112
120
  }
113
121
  async start() {
114
- this.socketServer = Metadata_1.default.get(constants_2.SOCKET_IO_INSTANCE_KEY, this.context).of('/teapot');
122
+ // Socket.IO instance is stored on the Boot instance at runtime (not on the class)
123
+ this.socketServer = commons_1.Metadata.get(constants_1.SOCKET_IO_INSTANCE_KEY, this.context).of('/teapot');
115
124
  TeapotEngine_1.header(this.teapotSettings);
116
125
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
117
126
  this.socketServer.on('connection', this.registerTeacup.bind(this));
118
127
  }
119
- static canRegister(ctx, settings) {
120
- return Metadata_1.default.get(constants_1.ASSIGN_TEAPOT_KEY, (0, object_helper_1.getClass)(ctx), 'isTeapotActive');
128
+ /**
129
+ * Graceful shutdown for the Teapot engine.
130
+ *
131
+ * Disconnects all connected Teacup clients, closes the Socket.IO namespace,
132
+ * and clears internal state. This method is idempotent and safe to call multiple times.
133
+ *
134
+ * @returns {Promise<void>} Promise that resolves when cleanup is complete
135
+ * @since 2.0.0
136
+ */
137
+ async stop() {
138
+ // Idempotent: skip if already stopped or never started
139
+ if (this.isStopped || !this.socketServer) {
140
+ return;
141
+ }
142
+ this.isStopped = true;
143
+ console.log(chalk.cyan.bold('[TEAPOT]') + ' - Initiating graceful shutdown...');
144
+ // Disconnect all connected clients gracefully
145
+ const connectedSockets = await this.socketServer.fetchSockets();
146
+ for (const socket of connectedSockets) {
147
+ const routes = this.findClientInRoutes(socket.id);
148
+ this.removeFromRoutes(routes, socket.id);
149
+ socket.disconnect(true);
150
+ console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${socket.id}}]: {yellow.bold Disconnected for shutdown}`);
151
+ }
152
+ // Remove all listeners from the namespace
153
+ this.socketServer.removeAllListeners();
154
+ // Clear internal state
155
+ this.clients.clear();
156
+ this.registeredRoute.clear();
157
+ console.log(chalk.cyan.bold('[TEAPOT]') + ' - Graceful shutdown complete.');
158
+ }
159
+ static canRegister(ctx) {
160
+ return commons_1.Metadata.get(commons_2.ASSIGN_TEAPOT_KEY, (0, commons_3.getClass)(ctx), 'isTeapotActive');
121
161
  }
122
162
  };
123
163
  TeapotEngine = TeapotEngine_1 = tslib_1.__decorate([
124
- (0, inversify_1.injectable)()
164
+ (0, inversify_1.injectable)(),
165
+ (0, inversify_1.injectFromBase)({ extendConstructorArguments: true })
125
166
  ], TeapotEngine);
126
167
  exports.default = TeapotEngine;
@@ -4,6 +4,6 @@ import Settings from '../../classes/Settings';
4
4
  export default class WebsocketEngine extends ExpressiveTeaEngine {
5
5
  canStart: boolean;
6
6
  isDetached: boolean;
7
- init(): Promise<void>;
7
+ init(): void;
8
8
  static canRegister(ctx?: Boot, settings?: Settings): boolean;
9
9
  }
@@ -11,8 +11,10 @@ let WebsocketEngine = class WebsocketEngine extends Engine_1.default {
11
11
  this.canStart = false;
12
12
  this.isDetached = false;
13
13
  }
14
- async init() {
14
+ init() {
15
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
15
16
  this.canStart = this.settings.get('startWebsocket');
17
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
16
18
  this.isDetached = this.settings.get('detachWebsocket');
17
19
  if (this.canStart) {
18
20
  WebsocketService_1.default.init();
@@ -25,10 +27,13 @@ let WebsocketEngine = class WebsocketEngine extends Engine_1.default {
25
27
  }
26
28
  }
27
29
  static canRegister(ctx, settings) {
28
- return settings.get('startWebsocket');
30
+ var _a;
31
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
32
+ return (_a = settings === null || settings === void 0 ? void 0 : settings.get('startWebsocket')) !== null && _a !== void 0 ? _a : false;
29
33
  }
30
34
  };
31
35
  WebsocketEngine = tslib_1.__decorate([
32
- (0, inversify_1.injectable)()
36
+ (0, inversify_1.injectable)(),
37
+ (0, inversify_1.injectFromBase)({ extendConstructorArguments: true })
33
38
  ], WebsocketEngine);
34
39
  exports.default = WebsocketEngine;
@@ -0,0 +1,138 @@
1
+ // @ts-check
2
+ import eslint from '@eslint/js';
3
+ import tseslintPlugin from '@typescript-eslint/eslint-plugin';
4
+ import tsparser from '@typescript-eslint/parser';
5
+ import jsdoc from 'eslint-plugin-jsdoc';
6
+ import globals from 'globals';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { dirname } from 'node:path';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+
13
+ export default [
14
+ // Global ignores (applies to all configs)
15
+ {
16
+ ignores: [
17
+ 'benchmark/**',
18
+ '__test__/mock/*',
19
+ '__test__/**/helper/*',
20
+ 'node_modules/**',
21
+ 'coverage/**',
22
+ 'dist/**',
23
+ '**/*.js',
24
+ '**/*.d.ts',
25
+ '**/*.js.map',
26
+ '**/*.d.ts.map',
27
+ '!eslint.config.js',
28
+ '!jest.config.js',
29
+ '!gulpfile.js',
30
+ ],
31
+ },
32
+
33
+ // Base ESLint recommended rules
34
+ eslint.configs.recommended,
35
+
36
+ // Main configuration for TypeScript files
37
+ {
38
+ files: ['**/*.ts'],
39
+ languageOptions: {
40
+ parser: tsparser,
41
+ parserOptions: {
42
+ project: './tsconfig.linter.json',
43
+ tsconfigRootDir: __dirname,
44
+ },
45
+ globals: {
46
+ ...globals.browser,
47
+ ...globals.node,
48
+ ...globals.es2021,
49
+ },
50
+ },
51
+ plugins: {
52
+ '@typescript-eslint': tseslintPlugin,
53
+ jsdoc,
54
+ },
55
+ rules: {
56
+ // Apply TypeScript recommended rules
57
+ ...tseslintPlugin.configs.recommended.rules,
58
+
59
+ // Disable semicolon requirements
60
+ 'semi': 'off',
61
+ '@typescript-eslint/semi': 'off',
62
+
63
+ // Array type preferences
64
+ '@typescript-eslint/array-type': ['error', { default: 'array' }],
65
+
66
+ // Return await handling
67
+ '@typescript-eslint/return-await': 'off',
68
+
69
+ // Boolean expression strictness
70
+ '@typescript-eslint/strict-boolean-expressions': 'off',
71
+
72
+ // Function return type requirements
73
+ '@typescript-eslint/explicit-function-return-type': 'off',
74
+
75
+ // Allow classes with only static members
76
+ '@typescript-eslint/no-extraneous-class': 'off',
77
+
78
+ // Unsafe argument warnings
79
+ '@typescript-eslint/no-unsafe-argument': 'warn',
80
+ '@typescript-eslint/no-unsafe-assignment': 'warn',
81
+ '@typescript-eslint/no-unsafe-member-access': 'warn',
82
+ '@typescript-eslint/no-unsafe-call': 'warn',
83
+ '@typescript-eslint/no-unsafe-return': 'warn',
84
+
85
+ // Unused variables with ignore patterns
86
+ '@typescript-eslint/no-unused-vars': ['error', {
87
+ argsIgnorePattern: '^_',
88
+ varsIgnorePattern: '^_',
89
+ }],
90
+
91
+ // Allow explicit any where needed (warn instead of error)
92
+ '@typescript-eslint/no-explicit-any': 'warn',
93
+
94
+ // Allow non-null assertions (used in tests)
95
+ '@typescript-eslint/no-non-null-assertion': 'off',
96
+
97
+ // Allow require imports (used in some configs)
98
+ '@typescript-eslint/no-require-imports': 'off',
99
+
100
+ // General rules
101
+ 'no-duplicate-imports': 'off',
102
+ 'no-unused-vars': 'off', // Use TypeScript version instead
103
+ },
104
+ },
105
+
106
+ // Configuration for test files
107
+ {
108
+ files: ['__test__/**/*.ts', '**/*.spec.ts', '**/*.test.ts'],
109
+ languageOptions: {
110
+ globals: {
111
+ ...globals.jest,
112
+ },
113
+ },
114
+ rules: {
115
+ // Relax TypeScript strict rules for test files
116
+ '@typescript-eslint/no-unsafe-argument': 'off',
117
+ '@typescript-eslint/no-unsafe-assignment': 'off',
118
+ '@typescript-eslint/no-unsafe-member-access': 'off',
119
+ '@typescript-eslint/no-unsafe-call': 'off',
120
+ '@typescript-eslint/no-unsafe-return': 'off',
121
+ '@typescript-eslint/no-explicit-any': 'off',
122
+ },
123
+ },
124
+
125
+ // Configuration for JavaScript config files
126
+ {
127
+ files: ['*.js', '*.mjs', '*.cjs'],
128
+ languageOptions: {
129
+ globals: {
130
+ ...globals.node,
131
+ },
132
+ },
133
+ rules: {
134
+ '@typescript-eslint/no-require-imports': 'off',
135
+ },
136
+ },
137
+ ];
138
+
@@ -25,7 +25,7 @@
25
25
  export declare class GenericRequestException extends Error {
26
26
  statusCode: number;
27
27
  message: string;
28
- constructor(message: string | never, statusCode?: number);
28
+ constructor(message: string, statusCode?: number);
29
29
  }
30
30
  /**
31
31
  * Shortcut Exception for 400 HTTP Errors (Bad Request).
@@ -48,7 +48,7 @@ export declare class GenericRequestException extends Error {
48
48
  * }
49
49
  */
50
50
  export declare class BadRequestException extends GenericRequestException {
51
- constructor(message?: string | never);
51
+ constructor(message?: string);
52
52
  }
53
53
  /**
54
54
  * Shortcut Exception for 401 HTTP Errors (Unauthorized Request).
@@ -71,5 +71,5 @@ export declare class BadRequestException extends GenericRequestException {
71
71
  * }
72
72
  */
73
73
  export declare class UnauthorizedException extends GenericRequestException {
74
- constructor(message?: string | never);
74
+ constructor(message?: string);
75
75
  }
@@ -1,7 +1,7 @@
1
- import { BOOT_STAGES } from '@expressive-tea/commons/constants';
1
+ import { BOOT_STAGES } from '@expressive-tea/commons';
2
2
  import { type Express } from 'express';
3
3
  import type Boot from '../classes/Boot';
4
4
  export declare function resolveStage(stage: BOOT_STAGES, ctx: Boot, server: Express, ...extraArgs: unknown[]): Promise<void>;
5
- export declare function resolveDirectives(instance: typeof Boot | Boot, server: Express): Promise<void>;
6
- export declare function resolveStatic(instance: typeof Boot | Boot, server: Express): Promise<void>;
7
- export declare function resolveProxy(ProxyContainer: any, server: Express): Promise<void>;
5
+ export declare function resolveDirectives(instance: typeof Boot | Boot, server: Express): void;
6
+ export declare function resolveStatic(instance: typeof Boot | Boot, server: Express): void;
7
+ export declare function resolveProxy(ProxyContainer: any, server: Express): void;
@@ -1,16 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveProxy = exports.resolveStatic = exports.resolveDirectives = exports.resolveStage = void 0;
4
- const constants_1 = require("@expressive-tea/commons/constants");
3
+ exports.resolveStage = resolveStage;
4
+ exports.resolveDirectives = resolveDirectives;
5
+ exports.resolveStatic = resolveStatic;
6
+ exports.resolveProxy = resolveProxy;
7
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return */
8
+ const commons_1 = require("@expressive-tea/commons");
5
9
  const express = require("express");
6
- const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
7
- const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
10
+ const commons_2 = require("@expressive-tea/commons");
11
+ const commons_3 = require("@expressive-tea/commons");
8
12
  const BootLoaderExceptions_1 = require("../exceptions/BootLoaderExceptions");
13
+ const DependencyInjection_1 = require("../services/DependencyInjection");
9
14
  async function resolveStage(stage, ctx, server, ...extraArgs) {
10
15
  try {
11
16
  await bootloaderResolve(stage, server, ctx, ...extraArgs);
12
- if (stage === constants_1.BOOT_STAGES.APPLICATION) {
13
- await resolveModules(ctx, server);
17
+ if (stage === commons_1.BOOT_STAGES.APPLICATION) {
18
+ resolveModules(ctx, server);
14
19
  }
15
20
  }
16
21
  catch (e) {
@@ -19,18 +24,16 @@ async function resolveStage(stage, ctx, server, ...extraArgs) {
19
24
  }
20
25
  }
21
26
  }
22
- exports.resolveStage = resolveStage;
23
- async function resolveDirectives(instance, server) {
24
- const registeredDirectives = Metadata_1.default.get(constants_1.REGISTERED_DIRECTIVES_KEY, (0, object_helper_1.getClass)(instance)) || [];
27
+ function resolveDirectives(instance, server) {
28
+ const registeredDirectives = commons_2.Metadata.get(commons_1.REGISTERED_DIRECTIVES_KEY, (0, commons_3.getClass)(instance)) || [];
25
29
  registeredDirectives.forEach((options) => {
26
30
  // @ts-expect-error Settings can be any parameter
27
31
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
28
32
  server.set(options.name, ...options.settings);
29
33
  });
30
34
  }
31
- exports.resolveDirectives = resolveDirectives;
32
- async function resolveStatic(instance, server) {
33
- const registeredStatic = Metadata_1.default.get(constants_1.REGISTERED_STATIC_KEY, (0, object_helper_1.getClass)(instance)) || [];
35
+ function resolveStatic(instance, server) {
36
+ const registeredStatic = commons_2.Metadata.get(commons_1.REGISTERED_STATIC_KEY, (0, commons_3.getClass)(instance)) || [];
34
37
  registeredStatic.forEach((staticOptions) => {
35
38
  if (staticOptions.virtual) {
36
39
  server.use(staticOptions.virtual, express.static(staticOptions.root, staticOptions.options));
@@ -40,21 +43,23 @@ async function resolveStatic(instance, server) {
40
43
  }
41
44
  });
42
45
  }
43
- exports.resolveStatic = resolveStatic;
44
- async function resolveProxy(ProxyContainer, server) {
46
+ function resolveProxy(ProxyContainer, server) {
45
47
  const proxyContainer = new ProxyContainer();
46
48
  proxyContainer.__register(server);
47
49
  }
48
- exports.resolveProxy = resolveProxy;
49
- async function resolveModules(instance, server) {
50
- const registeredModules = Metadata_1.default.get(constants_1.REGISTERED_MODULE_KEY, instance, 'start') || [];
51
- registeredModules.forEach(Module => {
52
- const moduleInstance = new Module();
50
+ function resolveModules(instance, server) {
51
+ // Metadata is stored on the class by decorators, so we need to get the constructor
52
+ // If instance is already a class (typeof === 'function'), use it directly
53
+ // If instance is an object, get its constructor
54
+ const target = typeof instance === 'function' ? instance : instance.constructor;
55
+ const registeredModules = commons_2.Metadata.get(commons_1.REGISTERED_MODULE_KEY, target, 'start') || [];
56
+ for (const Module of registeredModules) {
57
+ const moduleInstance = (0, DependencyInjection_1.getInstanceOf)(Module);
53
58
  moduleInstance.__register(server);
54
- });
59
+ }
55
60
  }
56
61
  async function bootloaderResolve(STAGE, server, instance, ...args) {
57
- const bootLoader = Metadata_1.default.get(constants_1.BOOT_STAGES_KEY, (0, object_helper_1.getClass)(instance)) || constants_1.STAGES_INIT;
62
+ const bootLoader = commons_2.Metadata.get(commons_1.BOOT_STAGES_KEY, (0, commons_3.getClass)(instance)) || commons_1.STAGES_INIT;
58
63
  for (const loader of bootLoader[STAGE] || []) {
59
64
  try {
60
65
  await selectLoaderType(loader, server, ...args);
@@ -64,7 +69,7 @@ async function bootloaderResolve(STAGE, server, instance, ...args) {
64
69
  }
65
70
  }
66
71
  }
67
- async function selectLoaderType(loader, server, ...args) {
72
+ function selectLoaderType(loader, server, ...args) {
68
73
  return loader.method(server, ...args);
69
74
  }
70
75
  function checkIfStageFails(e) {
@@ -1,14 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addAnnotation = void 0;
4
- const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
5
- const constants_1 = require("@expressive-tea/commons/constants");
3
+ exports.addAnnotation = addAnnotation;
4
+ const commons_1 = require("@expressive-tea/commons");
5
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
6
+ const commons_2 = require("@expressive-tea/commons");
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
8
  function addAnnotation(type, target, propertyKey, ...args) {
7
- const annotations = Metadata_1.default.get(constants_1.ROUTER_ANNOTATIONS_KEY, target, propertyKey) || [];
9
+ const annotations = commons_1.Metadata.get(commons_2.ROUTER_ANNOTATIONS_KEY, target, propertyKey) || [];
8
10
  annotations.unshift({
9
11
  arguments: args,
10
12
  type
11
13
  });
12
- Metadata_1.default.set(constants_1.ROUTER_ANNOTATIONS_KEY, annotations, target, propertyKey);
14
+ commons_1.Metadata.set(commons_2.ROUTER_ANNOTATIONS_KEY, annotations, target, propertyKey);
13
15
  }
14
- exports.addAnnotation = addAnnotation;
@@ -1 +1 @@
1
- export declare function delay(ms: number): Promise<unknown>;
1
+ export declare function delay(ms: number): Promise<void>;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.delay = void 0;
3
+ exports.delay = delay;
4
4
  async function delay(ms) {
5
5
  return new Promise(resolve => setTimeout(resolve, ms));
6
6
  }
7
- exports.delay = delay;