@expressive-tea/core 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 (94) hide show
  1. package/.gitattributes +4 -0
  2. package/.swcrc +61 -0
  3. package/LICENSE +201 -0
  4. package/README.md +627 -0
  5. package/banner.png +0 -0
  6. package/classes/Boot.d.ts +145 -0
  7. package/classes/Boot.js +223 -0
  8. package/classes/Engine.d.ts +63 -0
  9. package/classes/Engine.js +90 -0
  10. package/classes/EngineRegistry.d.ts +154 -0
  11. package/classes/EngineRegistry.js +247 -0
  12. package/classes/LoadBalancer.d.ts +8 -0
  13. package/classes/LoadBalancer.js +28 -0
  14. package/classes/ProxyRoute.d.ts +14 -0
  15. package/classes/ProxyRoute.js +40 -0
  16. package/classes/Settings.d.ts +128 -0
  17. package/classes/Settings.js +172 -0
  18. package/decorators/annotations.d.ts +91 -0
  19. package/decorators/annotations.js +132 -0
  20. package/decorators/env.d.ts +145 -0
  21. package/decorators/env.js +177 -0
  22. package/decorators/health.d.ts +115 -0
  23. package/decorators/health.js +124 -0
  24. package/decorators/module.d.ts +34 -0
  25. package/decorators/module.js +39 -0
  26. package/decorators/proxy.d.ts +28 -0
  27. package/decorators/proxy.js +60 -0
  28. package/decorators/router.d.ts +199 -0
  29. package/decorators/router.js +252 -0
  30. package/decorators/server.d.ts +92 -0
  31. package/decorators/server.js +247 -0
  32. package/engines/constants/constants.d.ts +2 -0
  33. package/engines/constants/constants.js +5 -0
  34. package/engines/health/index.d.ts +120 -0
  35. package/engines/health/index.js +179 -0
  36. package/engines/http/index.d.ts +12 -0
  37. package/engines/http/index.js +59 -0
  38. package/engines/index.d.ts +32 -0
  39. package/engines/index.js +112 -0
  40. package/engines/socketio/index.d.ts +7 -0
  41. package/engines/socketio/index.js +30 -0
  42. package/engines/teacup/index.d.ts +27 -0
  43. package/engines/teacup/index.js +136 -0
  44. package/engines/teapot/index.d.ts +32 -0
  45. package/engines/teapot/index.js +167 -0
  46. package/engines/websocket/index.d.ts +9 -0
  47. package/engines/websocket/index.js +39 -0
  48. package/eslint.config.mjs +138 -0
  49. package/exceptions/BootLoaderExceptions.d.ts +26 -0
  50. package/exceptions/BootLoaderExceptions.js +31 -0
  51. package/exceptions/RequestExceptions.d.ts +75 -0
  52. package/exceptions/RequestExceptions.js +89 -0
  53. package/helpers/boot-helper.d.ts +7 -0
  54. package/helpers/boot-helper.js +84 -0
  55. package/helpers/decorators.d.ts +1 -0
  56. package/helpers/decorators.js +15 -0
  57. package/helpers/promise-helper.d.ts +1 -0
  58. package/helpers/promise-helper.js +6 -0
  59. package/helpers/server.d.ts +35 -0
  60. package/helpers/server.js +141 -0
  61. package/helpers/teapot-helper.d.ts +18 -0
  62. package/helpers/teapot-helper.js +88 -0
  63. package/helpers/websocket-helper.d.ts +3 -0
  64. package/helpers/websocket-helper.js +20 -0
  65. package/images/announcement-01.png +0 -0
  66. package/images/logo-sticky-01.png +0 -0
  67. package/images/logo-wp-01.png +0 -0
  68. package/images/logo.png +0 -0
  69. package/images/zero-oneit.png +0 -0
  70. package/interfaces/index.d.ts +4 -0
  71. package/interfaces/index.js +2 -0
  72. package/inversify.config.d.ts +9 -0
  73. package/inversify.config.js +8 -0
  74. package/libs/classNames.d.ts +1 -0
  75. package/libs/classNames.js +4 -0
  76. package/libs/utilities.d.ts +21910 -0
  77. package/libs/utilities.js +420 -0
  78. package/mixins/module.d.ts +45 -0
  79. package/mixins/module.js +71 -0
  80. package/mixins/proxy.d.ts +46 -0
  81. package/mixins/proxy.js +86 -0
  82. package/mixins/route.d.ts +48 -0
  83. package/mixins/route.js +96 -0
  84. package/package.json +137 -0
  85. package/services/DependencyInjection.d.ts +159 -0
  86. package/services/DependencyInjection.js +201 -0
  87. package/services/WebsocketService.d.ts +18 -0
  88. package/services/WebsocketService.js +47 -0
  89. package/types/core.d.ts +14 -0
  90. package/types/core.js +2 -0
  91. package/types/injection-types.d.ts +6 -0
  92. package/types/injection-types.js +10 -0
  93. package/types/inversify.d.ts +5 -0
  94. package/types/inversify.js +3 -0
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return */
5
+ const chalk = require("chalk");
6
+ const url_1 = require("url");
7
+ const socket_io_client_1 = require("socket.io-client");
8
+ const inversify_1 = require("inversify");
9
+ const commons_1 = require("@expressive-tea/commons");
10
+ const commons_2 = require("@expressive-tea/commons");
11
+ const teapot_helper_1 = require("../../helpers/teapot-helper");
12
+ const commons_3 = require("@expressive-tea/commons");
13
+ const Engine_1 = require("../../classes/Engine");
14
+ let TeacupEngine = class TeacupEngine extends Engine_1.default {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.isStopping = false;
18
+ }
19
+ header() {
20
+ console.log(chalk.white.bold('Teacup Engine is initializing...'));
21
+ console.log(chalk `
22
+ {grey ( (}
23
+ {white.bold ) )}
24
+ {magenta.bold ........}
25
+ {magenta.bold | |]}
26
+ {magenta.bold \\ /} {yellow.bold [${this.teacupSettings.address}]}
27
+ {magenta.bold \`----'}
28
+
29
+ {yellow.bold NOTICE:}
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.
31
+ `);
32
+ }
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ handshaked(key, signature, isSecure, cb) {
35
+ try {
36
+ console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {yellow.bold Server Verification Started}`);
37
+ if (!teapot_helper_1.default.verify(this.teacupSettings.clientKey, key.toString('ascii'), signature)) {
38
+ throw new Error('Fail to Verify Client on Teapod.');
39
+ }
40
+ console.log(chalk `{cyan.bold [TEACUP]} - [{magenta.bold ${this.client.id}}]: {green.bold Server Has Been Verified}`);
41
+ this.publicServerKey = key;
42
+ this.serverSignature = signature;
43
+ cb(Buffer.from(this.publicKey), this.clientSignature);
44
+ }
45
+ catch (e) {
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}`);
48
+ this.client.disconnect();
49
+ }
50
+ }
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ accepted(cb) {
53
+ var _a;
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}}`);
55
+ const encryptedMessage = teapot_helper_1.default.encrypt({
56
+ mountTo: this.teacupSettings.mountTo,
57
+ address: this.teacupSettings.address
58
+ }, this.serverSignature);
59
+ cb(encryptedMessage);
60
+ const onClose = () => {
61
+ try {
62
+ this.client.close();
63
+ }
64
+ catch (_a) {
65
+ // Intentionally empty - ignore close errors
66
+ }
67
+ };
68
+ this.server.on('close', onClose);
69
+ (_a = this.serverSecure) === null || _a === void 0 ? void 0 : _a.on('close', onClose);
70
+ }
71
+ async start() {
72
+ this.teacupSettings = commons_1.Metadata.get(commons_2.ASSIGN_TEACUP_KEY, (0, commons_3.getClass)(this.context));
73
+ const scheme = new url_1.URL(this.teacupSettings.serverUrl);
74
+ const { publicKey, privateKey } = teapot_helper_1.default.generateKeys(this.teacupSettings.clientKey);
75
+ const protocol = teapot_helper_1.default.httpSchema(scheme.protocol);
76
+ this.publicKey = publicKey;
77
+ this.privateKey = privateKey;
78
+ this.clientSignature = teapot_helper_1.default.sign(this.teacupSettings.clientKey, this.privateKey, this.teacupSettings.clientKey);
79
+ this.client = (0, socket_io_client_1.io)(`${protocol}//${scheme.host}/teapot`, {
80
+ path: '/exp-tea/',
81
+ reconnection: true,
82
+ autoConnect: false
83
+ });
84
+ this.header();
85
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
86
+ this.client.on('handshake', this.handshaked.bind(this));
87
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
88
+ this.client.on('accepted', this.accepted.bind(this));
89
+ this.client.on('error', console.log);
90
+ this.client.connect();
91
+ }
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
+ }
130
+ }
131
+ };
132
+ TeacupEngine = tslib_1.__decorate([
133
+ (0, inversify_1.injectable)(),
134
+ (0, inversify_1.injectFromBase)({ extendConstructorArguments: true })
135
+ ], TeacupEngine);
136
+ exports.default = TeacupEngine;
@@ -0,0 +1,32 @@
1
+ import ExpressiveTeaEngine from '../../classes/Engine';
2
+ import Boot from '../../classes/Boot';
3
+ export default class TeapotEngine extends ExpressiveTeaEngine {
4
+ private readonly clients;
5
+ private readonly registeredRoute;
6
+ private teapotSettings;
7
+ private publicKey;
8
+ private privateKey;
9
+ private serverSignature;
10
+ private socketServer;
11
+ private isStopped;
12
+ private static header;
13
+ private registerTeacup;
14
+ private clientVerification;
15
+ private registered;
16
+ private removeFromRoutes;
17
+ private findClientInRoutes;
18
+ private disconnected;
19
+ init(): Promise<void>;
20
+ start(): Promise<void>;
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;
32
+ }
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ var TeapotEngine_1;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const tslib_1 = require("tslib");
5
+ const chalk = require("chalk");
6
+ const inversify_1 = require("inversify");
7
+ const commons_1 = require("@expressive-tea/commons");
8
+ const commons_2 = require("@expressive-tea/commons");
9
+ const ProxyRoute_1 = require("../../classes/ProxyRoute");
10
+ const Engine_1 = require("../../classes/Engine");
11
+ const teapot_helper_1 = require("../../helpers/teapot-helper");
12
+ const constants_1 = require("../constants/constants");
13
+ const commons_3 = require("@expressive-tea/commons");
14
+ let TeapotEngine = TeapotEngine_1 = class TeapotEngine extends Engine_1.default {
15
+ constructor() {
16
+ super(...arguments);
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ this.clients = new Map();
19
+ this.registeredRoute = new Map();
20
+ this.isStopped = false;
21
+ }
22
+ static header(teapotSettings) {
23
+ console.log(chalk.white.bold('Teapot Engine is initializing...'));
24
+ console.log(chalk `
25
+ {white.bold ;,'}
26
+ {green _o_} {white.bold ;:;'}
27
+ {blue.bold ,-.}{green '---\`}{blue.bold .__} {white.bold ; }
28
+ {blue.bold ((j\`=====',-'}
29
+ {blue.bold \`-\\ /}
30
+ {blue.bold \`-=-'}
31
+
32
+ {white Please assign the next} {white.bold Client Key:} {magenta.bold ${teapotSettings.clientKey}} {white to all your}
33
+ {yellow.bold Teacups} {white and do not share the key with anyone}
34
+
35
+ {yellow.bold NOTICE:}
36
+ 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.
37
+ `);
38
+ }
39
+ registerTeacup(teacup) {
40
+ console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {grey.bold Connected}`);
41
+ teacup.emit('handshake', Buffer.from(this.publicKey), this.serverSignature, Boolean(this.serverSecure), this.clientVerification.bind(this, teacup));
42
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
43
+ teacup.on('disconnect', this.disconnected.bind(this, teacup));
44
+ }
45
+ clientVerification(teacup, userPublicKey, userSignature) {
46
+ console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {yellow.bold Client Verification Started}`);
47
+ try {
48
+ if (!teapot_helper_1.default.verify(this.teapotSettings.clientKey, userPublicKey.toString('ascii'), userSignature)) {
49
+ console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${teacup.id}}]: Failed to verify and will be disconnected...`);
50
+ return teacup.disconnect();
51
+ }
52
+ this.clients.set(teacup.id, {
53
+ publicKey: userPublicKey,
54
+ signature: userSignature
55
+ });
56
+ teacup.emit('accepted', this.registered.bind(this, teacup));
57
+ console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: {green.bold Client Verified}`);
58
+ }
59
+ catch (e) {
60
+ const error = e;
61
+ console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} [{magenta.bold ${teacup.id}}]: Failed wiht next message: ${error.message}`);
62
+ teacup.disconnect();
63
+ }
64
+ }
65
+ registered(teacup, encryptedMessage) {
66
+ try {
67
+ const message = teapot_helper_1.default.decrypt(encryptedMessage, this.serverSignature);
68
+ const isRegistered = this.registeredRoute.has(message.mountTo);
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
+ }
73
+ proxyRoute.registerServer(message.address, teacup.id);
74
+ if (!isRegistered) {
75
+ this.registeredRoute.set(message.mountTo, proxyRoute);
76
+ this.context.getApplication().use(message.mountTo, teapot_helper_1.default.proxyResponse.bind(this, proxyRoute));
77
+ }
78
+ console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}] {blue.bold <${message.address}>} <--> {white.bold ${message.mountTo}}`);
79
+ }
80
+ catch (e) {
81
+ const error = e;
82
+ console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${error.message}`);
83
+ }
84
+ }
85
+ removeFromRoutes(routes = [], id) {
86
+ routes.forEach(route => {
87
+ const proxyRoute = this.registeredRoute.get(route);
88
+ if (proxyRoute) {
89
+ proxyRoute.unregisterServer(id);
90
+ }
91
+ });
92
+ }
93
+ findClientInRoutes(teacupId) {
94
+ const routes = [];
95
+ this.registeredRoute.forEach((proxyRoute, route) => {
96
+ if (proxyRoute.isClientOnRoute(teacupId)) {
97
+ routes.push(route);
98
+ }
99
+ });
100
+ return routes;
101
+ }
102
+ disconnected(teacup, reason) {
103
+ try {
104
+ const routes = this.findClientInRoutes(teacup.id);
105
+ this.removeFromRoutes(routes, teacup.id);
106
+ console.log(chalk `{cyan.bold [TEAPOT]} - {blue TEACUP} [{magenta.bold ${teacup.id}}]: Got disconnected by ${reason}`);
107
+ }
108
+ catch (e) {
109
+ const error = e;
110
+ console.log(chalk `{cyan.bold [TEAPOT]} - {red.bold TEACUP} {magenta.bold ${teacup.id}}: Failed wiht next message: ${error.message}`);
111
+ }
112
+ }
113
+ async init() {
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));
116
+ const { publicKey, privateKey } = teapot_helper_1.default.generateKeys(this.teapotSettings.serverKey);
117
+ this.publicKey = publicKey;
118
+ this.privateKey = privateKey;
119
+ this.serverSignature = teapot_helper_1.default.sign(this.teapotSettings.clientKey, privateKey, this.teapotSettings.serverKey);
120
+ }
121
+ async start() {
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');
124
+ TeapotEngine_1.header(this.teapotSettings);
125
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
126
+ this.socketServer.on('connection', this.registerTeacup.bind(this));
127
+ }
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');
161
+ }
162
+ };
163
+ TeapotEngine = TeapotEngine_1 = tslib_1.__decorate([
164
+ (0, inversify_1.injectable)(),
165
+ (0, inversify_1.injectFromBase)({ extendConstructorArguments: true })
166
+ ], TeapotEngine);
167
+ exports.default = TeapotEngine;
@@ -0,0 +1,9 @@
1
+ import ExpressiveTeaEngine from '../../classes/Engine';
2
+ import Boot from '../../classes/Boot';
3
+ import Settings from '../../classes/Settings';
4
+ export default class WebsocketEngine extends ExpressiveTeaEngine {
5
+ canStart: boolean;
6
+ isDetached: boolean;
7
+ init(): void;
8
+ static canRegister(ctx?: Boot, settings?: Settings): boolean;
9
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const WebsocketService_1 = require("../../services/WebsocketService");
5
+ const WebSocket = require("ws");
6
+ const inversify_1 = require("inversify");
7
+ const Engine_1 = require("../../classes/Engine");
8
+ let WebsocketEngine = class WebsocketEngine extends Engine_1.default {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.canStart = false;
12
+ this.isDetached = false;
13
+ }
14
+ init() {
15
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
16
+ this.canStart = this.settings.get('startWebsocket');
17
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
18
+ this.isDetached = this.settings.get('detachWebsocket');
19
+ if (this.canStart) {
20
+ WebsocketService_1.default.init();
21
+ WebsocketService_1.default.getInstance().setWebSocket(new WebSocket.Server(this.isDetached ? { noServer: true } : { server: this.server }));
22
+ if (this.serverSecure) {
23
+ WebsocketService_1.default.getInstance().setSecureWebsocket(new WebSocket.Server(this.isDetached ? { noServer: true } : { server: this.serverSecure }));
24
+ }
25
+ WebsocketService_1.default.getInstance().setHttpServer(this.server);
26
+ WebsocketService_1.default.getInstance().setHttpServer(this.serverSecure);
27
+ }
28
+ }
29
+ static canRegister(ctx, settings) {
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;
33
+ }
34
+ };
35
+ WebsocketEngine = tslib_1.__decorate([
36
+ (0, inversify_1.injectable)(),
37
+ (0, inversify_1.injectFromBase)({ extendConstructorArguments: true })
38
+ ], WebsocketEngine);
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
+
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @namespace Exceptions
3
+ */
4
+ /**
5
+ * Exception Class for Hard Required Plugins.
6
+ * This Exception is used internally to describe when a required plugin fails, is the server returns this
7
+ * is meaning a module fails and the application it wont start since the plugin is marked as hard require to initialize
8
+ * the application.
9
+ * @export
10
+ * @class BootLoaderRequiredExceptions
11
+ * @extends {Error}
12
+ * @summary Required Module Exception
13
+ */
14
+ export declare class BootLoaderRequiredExceptions extends Error {
15
+ }
16
+ /**
17
+ * Exception Class for Soft Required Plugins
18
+ * This Exception is used internally to describe when a required plugin fails but allow to continue running
19
+ * the application and it means that plugin fails to initialize but is not critical to the app.
20
+ * @export
21
+ * @class BootLoaderSoftExceptions
22
+ * @extends {Error}
23
+ * @summary Not Required Plugin Exception
24
+ */
25
+ export declare class BootLoaderSoftExceptions extends Error {
26
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BootLoaderSoftExceptions = exports.BootLoaderRequiredExceptions = void 0;
4
+ /**
5
+ * @namespace Exceptions
6
+ */
7
+ /**
8
+ * Exception Class for Hard Required Plugins.
9
+ * This Exception is used internally to describe when a required plugin fails, is the server returns this
10
+ * is meaning a module fails and the application it wont start since the plugin is marked as hard require to initialize
11
+ * the application.
12
+ * @export
13
+ * @class BootLoaderRequiredExceptions
14
+ * @extends {Error}
15
+ * @summary Required Module Exception
16
+ */
17
+ class BootLoaderRequiredExceptions extends Error {
18
+ }
19
+ exports.BootLoaderRequiredExceptions = BootLoaderRequiredExceptions;
20
+ /**
21
+ * Exception Class for Soft Required Plugins
22
+ * This Exception is used internally to describe when a required plugin fails but allow to continue running
23
+ * the application and it means that plugin fails to initialize but is not critical to the app.
24
+ * @export
25
+ * @class BootLoaderSoftExceptions
26
+ * @extends {Error}
27
+ * @summary Not Required Plugin Exception
28
+ */
29
+ class BootLoaderSoftExceptions extends Error {
30
+ }
31
+ exports.BootLoaderSoftExceptions = BootLoaderSoftExceptions;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @namespace Exceptions
3
+ */
4
+ /**
5
+ * HTTP Generic Exception Use this Exception to easily return a HTTP Error on the endpoints handlers.
6
+ * @export
7
+ * @class GenericRequestException
8
+ * @extends {Error}
9
+ * @param {string} message='Server Error' Provide the Error message.
10
+ * @param {number} [statusCode=500] HTTP Response Code
11
+ * @summary HTTP Exception Helper
12
+ * @example
13
+ * {REPLACE-AT}Router('/')
14
+ * class ExceptionExampleController {
15
+ * {REPLACE-AT}Get('/exception')
16
+ * exceptionMethod(req, res, next) {
17
+ * try {
18
+ * throw new GenericRequestException('Page not found', 404);
19
+ * } catch (e) {
20
+ * res.status(e.code).send(e.message);
21
+ * }
22
+ * }
23
+ * }
24
+ */
25
+ export declare class GenericRequestException extends Error {
26
+ statusCode: number;
27
+ message: string;
28
+ constructor(message: string, statusCode?: number);
29
+ }
30
+ /**
31
+ * Shortcut Exception for 400 HTTP Errors (Bad Request).
32
+ * @export
33
+ * @class BadRequestException
34
+ * @extends {GenericRequestException}
35
+ * @param {string} [message='Bad Request'] Provide the Error message.
36
+ * @summary 400 Exception
37
+ * @example
38
+ * {REPLACE-AT}Router('/')
39
+ * class ExceptionExampleController {
40
+ * {REPLACE-AT}Get('/exception')
41
+ * exceptionMethod(req, res, next) {
42
+ * try {
43
+ * throw new BadRequestException();
44
+ * } catch (e) {
45
+ * res.status(e.code).send(e.message);
46
+ * }
47
+ * }
48
+ * }
49
+ */
50
+ export declare class BadRequestException extends GenericRequestException {
51
+ constructor(message?: string);
52
+ }
53
+ /**
54
+ * Shortcut Exception for 401 HTTP Errors (Unauthorized Request).
55
+ * @export
56
+ * @class UnauthorizedException
57
+ * @extends {GenericRequestException}
58
+ * @param {string} [message='Unauthorized Request'] Provide the Error message.
59
+ * @summary 401 Exception
60
+ * @example
61
+ * {REPLACE-AT}Router('/')
62
+ * class ExceptionExampleController {
63
+ * {REPLACE-AT}Get('/exception')
64
+ * exceptionMethod(req, res, next) {
65
+ * try {
66
+ * throw new UnauthorizedException();
67
+ * } catch (e) {
68
+ * res.status(e.code).send(e.message);
69
+ * }
70
+ * }
71
+ * }
72
+ */
73
+ export declare class UnauthorizedException extends GenericRequestException {
74
+ constructor(message?: string);
75
+ }