@zerooneit/expressive-tea 1.3.0-beta.5 → 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 (77) hide show
  1. package/.gitattributes +4 -0
  2. package/.swcrc +61 -0
  3. package/README.md +564 -174
  4. package/classes/Boot.d.ts +94 -3
  5. package/classes/Boot.js +171 -51
  6. package/classes/Engine.d.ts +59 -10
  7. package/classes/Engine.js +72 -11
  8. package/classes/EngineRegistry.d.ts +154 -0
  9. package/classes/EngineRegistry.js +247 -0
  10. package/classes/LoadBalancer.js +2 -5
  11. package/classes/ProxyRoute.d.ts +3 -3
  12. package/classes/ProxyRoute.js +5 -5
  13. package/classes/Settings.d.ts +31 -2
  14. package/classes/Settings.js +64 -11
  15. package/decorators/annotations.d.ts +1 -1
  16. package/decorators/annotations.js +17 -17
  17. package/decorators/env.d.ts +145 -0
  18. package/decorators/env.js +177 -0
  19. package/decorators/health.d.ts +115 -0
  20. package/decorators/health.js +124 -0
  21. package/decorators/module.d.ts +15 -15
  22. package/decorators/module.js +14 -23
  23. package/decorators/proxy.d.ts +26 -11
  24. package/decorators/proxy.js +35 -45
  25. package/decorators/router.d.ts +17 -16
  26. package/decorators/router.js +32 -52
  27. package/decorators/server.d.ts +8 -8
  28. package/decorators/server.js +48 -50
  29. package/engines/health/index.d.ts +120 -0
  30. package/engines/health/index.js +179 -0
  31. package/engines/http/index.d.ts +6 -7
  32. package/engines/http/index.js +22 -17
  33. package/engines/index.d.ts +32 -0
  34. package/engines/index.js +112 -0
  35. package/engines/socketio/index.d.ts +2 -1
  36. package/engines/socketio/index.js +16 -6
  37. package/engines/teacup/index.d.ts +13 -0
  38. package/engines/teacup/index.js +61 -11
  39. package/engines/teapot/index.d.ts +15 -2
  40. package/engines/teapot/index.js +61 -13
  41. package/engines/websocket/index.d.ts +4 -1
  42. package/engines/websocket/index.js +10 -2
  43. package/eslint.config.mjs +138 -0
  44. package/exceptions/RequestExceptions.d.ts +3 -3
  45. package/helpers/boot-helper.d.ts +6 -6
  46. package/helpers/boot-helper.js +30 -24
  47. package/helpers/decorators.js +7 -6
  48. package/helpers/promise-helper.d.ts +1 -1
  49. package/helpers/promise-helper.js +1 -2
  50. package/helpers/server.d.ts +32 -6
  51. package/helpers/server.js +101 -61
  52. package/helpers/teapot-helper.d.ts +5 -8
  53. package/helpers/teapot-helper.js +39 -11
  54. package/helpers/websocket-helper.d.ts +3 -5
  55. package/helpers/websocket-helper.js +3 -3
  56. package/interfaces/index.d.ts +1 -1
  57. package/inversify.config.d.ts +4 -4
  58. package/inversify.config.js +1 -1
  59. package/libs/utilities.d.ts +21910 -0
  60. package/libs/utilities.js +420 -0
  61. package/mixins/module.d.ts +45 -0
  62. package/mixins/module.js +71 -0
  63. package/mixins/proxy.d.ts +46 -0
  64. package/mixins/proxy.js +86 -0
  65. package/mixins/route.d.ts +48 -0
  66. package/mixins/route.js +96 -0
  67. package/package.json +91 -69
  68. package/services/DependencyInjection.d.ts +95 -7
  69. package/services/DependencyInjection.js +123 -5
  70. package/services/WebsocketService.d.ts +4 -6
  71. package/services/WebsocketService.js +5 -3
  72. package/types/core.d.ts +14 -0
  73. package/types/core.js +2 -0
  74. package/types/injection-types.d.ts +6 -0
  75. package/types/injection-types.js +10 -0
  76. package/types/inversify.d.ts +5 -0
  77. package/types/inversify.js +3 -0
@@ -1,10 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Teacup = exports.Teapot = exports.RegisterModule = exports.Proxies = exports.Modules = exports.Setting = exports.ExpressDirective = exports.Static = exports.ServerSettings = exports.Pour = exports.Plug = void 0;
4
- const lodash_1 = require("lodash");
5
- const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
3
+ exports.Plug = Plug;
4
+ exports.Pour = Pour;
5
+ exports.ServerSettings = ServerSettings;
6
+ exports.Static = Static;
7
+ exports.ExpressDirective = ExpressDirective;
8
+ exports.Setting = Setting;
9
+ exports.Modules = Modules;
10
+ exports.Proxies = Proxies;
11
+ exports.RegisterModule = RegisterModule;
12
+ exports.Teapot = Teapot;
13
+ exports.Teacup = Teacup;
14
+ const utilities_1 = require("../libs/utilities");
15
+ const commons_1 = require("@expressive-tea/commons");
6
16
  const Settings_1 = require("../classes/Settings");
7
- const constants_1 = require("@expressive-tea/commons/constants");
17
+ const commons_2 = require("@expressive-tea/commons");
18
+ const DependencyInjection_1 = require("../services/DependencyInjection");
8
19
  /**
9
20
  * Define the Main Plugins Properties.
10
21
  * @typedef {Object} ExpressiveTeaPluginProps
@@ -46,10 +57,10 @@ const constants_1 = require("@expressive-tea/commons/constants");
46
57
  * @module Decorators/Server
47
58
  */
48
59
  function getStages(target) {
49
- return Metadata_1.default.get(constants_1.BOOT_STAGES_KEY, target) || {};
60
+ return commons_1.Metadata.get(commons_2.BOOT_STAGES_KEY, target) || {};
50
61
  }
51
62
  function getRegisteredPlugins(target) {
52
- return Metadata_1.default.get(constants_1.PLUGINS_KEY, target) || [];
63
+ return commons_1.Metadata.get(commons_2.PLUGINS_KEY, target) || [];
53
64
  }
54
65
  function getStage(stage, target) {
55
66
  const stages = getStages(target);
@@ -61,10 +72,10 @@ function getStage(stage, target) {
61
72
  function setStage(stage, value, target) {
62
73
  const stages = getStages(target);
63
74
  stages[stage] = value;
64
- Metadata_1.default.set(constants_1.BOOT_STAGES_KEY, stages, target);
75
+ commons_1.Metadata.set(commons_2.BOOT_STAGES_KEY, stages, target);
65
76
  }
66
77
  function setPlugins(plugins, target) {
67
- Metadata_1.default.set(constants_1.PLUGINS_KEY, plugins, target);
78
+ commons_1.Metadata.set(commons_2.PLUGINS_KEY, plugins, target);
68
79
  }
69
80
  /**
70
81
  * Plug Class Decorator create a simple plugin to execute in one of the public stages defined on BOOT_STAGES, might
@@ -88,7 +99,6 @@ function Plug(stage, name, method, required = false) {
88
99
  setStage(stage, selectedStage, target);
89
100
  };
90
101
  }
91
- exports.Plug = Plug;
92
102
  /**
93
103
  * Since version 1.1.0 Expressive Tea allow to use external plugins using the node
94
104
  * package @expressive-tea/plugin. This plugin engine allows to create more complex plugin configuration and provision
@@ -104,15 +114,17 @@ exports.Plug = Plug;
104
114
  function Pour(Plugin, ...pluginArgs) {
105
115
  return (target) => {
106
116
  const stages = getStages(target);
107
- const instance = new Plugin(...pluginArgs);
117
+ DependencyInjection_1.default.Container.bind(Plugin)
118
+ .toDynamicValue(() => new Plugin(...pluginArgs))
119
+ .inSingletonScope();
120
+ const instance = DependencyInjection_1.default.Container.get(Plugin);
108
121
  const plugins = instance.register(Settings_1.default.getInstance(target).getOptions(), getRegisteredPlugins(target));
109
- constants_1.BOOT_STAGES_LIST.forEach(STAGE => {
122
+ commons_2.BOOT_STAGES_LIST.forEach(STAGE => {
110
123
  setStage(STAGE, (stages[STAGE] || []).concat(instance.getRegisteredStage(STAGE)), target);
111
124
  });
112
- setPlugins((0, lodash_1.orderBy)(plugins, ['priority'], ['asc']), target);
125
+ setPlugins((0, utilities_1.orderBy)(plugins, ['priority'], ['asc']), target);
113
126
  };
114
127
  }
115
- exports.Pour = Pour;
116
128
  /**
117
129
  * Server Settings Singleton Class Decorator this Provide the Configuration to the server or another component on
118
130
  * the projects,is working as a container to store user and library settings.
@@ -121,12 +133,11 @@ exports.Pour = Pour;
121
133
  * @param {ExpressiveTeaModuleProps} options
122
134
  */
123
135
  function ServerSettings(options = {}) {
124
- return target => {
136
+ return (target) => {
125
137
  Settings_1.default.getInstance(target).merge(options);
126
138
  return target;
127
139
  };
128
140
  }
129
- exports.ServerSettings = ServerSettings;
130
141
  /**
131
142
  * Create a new middleware function to serve files from within a given root directory. The file to serve will be
132
143
  * determined by combining req.url with the provided root directory. When a file is not found, instead of sending a 404
@@ -141,16 +152,15 @@ exports.ServerSettings = ServerSettings;
141
152
  * with virtual path if defined.
142
153
  */
143
154
  function Static(root, virtual = null, options = {}) {
144
- return target => {
145
- if ((0, lodash_1.isNil)(root)) {
155
+ return (target) => {
156
+ if ((0, utilities_1.isNil)(root)) {
146
157
  throw new Error('Root must be defined');
147
158
  }
148
- const registeredStatics = Metadata_1.default.get(constants_1.REGISTERED_STATIC_KEY, target) || [];
159
+ const registeredStatics = commons_1.Metadata.get(commons_2.REGISTERED_STATIC_KEY, target) || [];
149
160
  registeredStatics.unshift({ root, options, virtual });
150
- Metadata_1.default.set(constants_1.REGISTERED_STATIC_KEY, registeredStatics, target);
161
+ commons_1.Metadata.set(commons_2.REGISTERED_STATIC_KEY, registeredStatics, target);
151
162
  };
152
163
  }
153
- exports.Static = Static;
154
164
  /**
155
165
  * Set or Update Express application settings, and allow to change the behavior of the server where is listed on the
156
166
  * next link {@link http://expressjs.com/en/4x/api.html#app.settings.table Express Settings} as this is using the same
@@ -161,24 +171,22 @@ exports.Static = Static;
161
171
  * @decorator {ClassDecorator} ExpressDirective - Set a Express App Setting.
162
172
  */
163
173
  function ExpressDirective(name, ...settings) {
164
- return target => {
165
- if (!constants_1.EXPRESS_DIRECTIVES.includes(name)) {
174
+ return (target) => {
175
+ if (!commons_2.EXPRESS_DIRECTIVES.includes(name)) {
166
176
  throw new Error(`Directive Name ${name} is not valid express behavior setting`);
167
177
  }
168
- const registeredDirectives = Metadata_1.default.get(constants_1.REGISTERED_DIRECTIVES_KEY, target) || [];
178
+ const registeredDirectives = commons_1.Metadata.get(commons_2.REGISTERED_DIRECTIVES_KEY, target) || [];
169
179
  registeredDirectives.unshift({ name, settings });
170
- Metadata_1.default.set(constants_1.REGISTERED_DIRECTIVES_KEY, registeredDirectives, target);
180
+ commons_1.Metadata.set(commons_2.REGISTERED_DIRECTIVES_KEY, registeredDirectives, target);
171
181
  };
172
182
  }
173
- exports.ExpressDirective = ExpressDirective;
174
183
  /**
175
184
  * Setting Property Decorator Automatically assign a settings declared on Settings Service into the decorated property.
176
185
  * All properties will contains the settings value or undefined if current settings is not founded.
177
186
  * @decorator {PropertyDecorator} Setting - Assign Server Settings to Property as default value.
178
187
  * @summary Automatically assign a settings declared on the Server Settings decorator to a class property.
179
- * @param {string} settingName The Setting name tha
180
188
  */
181
- function Setting(settingName) {
189
+ function Setting() {
182
190
  return (target, propertyName) => {
183
191
  Object.defineProperty(target, propertyName, {
184
192
  configurable: false,
@@ -186,7 +194,6 @@ function Setting(settingName) {
186
194
  });
187
195
  };
188
196
  }
189
- exports.Setting = Setting;
190
197
  /**
191
198
  * Register Modules Method Decorator this Method Decorator is used at bootstrap level and should decorate bootstrap class
192
199
  * and register modules.
@@ -195,25 +202,23 @@ exports.Setting = Setting;
195
202
  * @param Modules
196
203
  */
197
204
  function Modules(Modules) {
198
- return target => {
205
+ return (target) => {
199
206
  for (const Module of Modules) {
200
- const registeredModules = Metadata_1.default.get(constants_1.REGISTERED_MODULE_KEY, target, 'start') || [];
207
+ const registeredModules = commons_1.Metadata.get(commons_2.REGISTERED_MODULE_KEY, target, 'start') || [];
201
208
  registeredModules.unshift(Module);
202
- Metadata_1.default.set(constants_1.REGISTERED_MODULE_KEY, registeredModules, target, 'start');
209
+ commons_1.Metadata.set(commons_2.REGISTERED_MODULE_KEY, registeredModules, target, 'start');
203
210
  }
204
211
  };
205
212
  }
206
- exports.Modules = Modules;
207
213
  function Proxies(proxyContainers) {
208
- return target => {
214
+ return (target) => {
209
215
  for (const proxyContainer of proxyContainers) {
210
- const registeredProxyContainers = Metadata_1.default.get(constants_1.ROUTER_PROXIES_KEY, target) || [];
216
+ const registeredProxyContainers = commons_1.Metadata.get(commons_2.ROUTER_PROXIES_KEY, target) || [];
211
217
  registeredProxyContainers.unshift(proxyContainer);
212
- Metadata_1.default.set(constants_1.ROUTER_PROXIES_KEY, registeredProxyContainers, target);
218
+ commons_1.Metadata.set(commons_2.ROUTER_PROXIES_KEY, registeredProxyContainers, target);
213
219
  }
214
220
  };
215
221
  }
216
- exports.Proxies = Proxies;
217
222
  /**
218
223
  * Register Module Method Decorator this Method Decorator is used at bootstrap level and should decorate the start
219
224
  * method with a Module Class.
@@ -222,28 +227,21 @@ exports.Proxies = Proxies;
222
227
  * @param {Class} Module
223
228
  * @deprecated Use the new decorator Modules that allow add modules into registered modules.
224
229
  */
230
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
225
231
  function RegisterModule(Module) {
226
- return (target, property) => {
227
- if (property !== 'start') {
228
- throw new Error('Register Module needs to decorate ONLY start method');
229
- }
230
- const registeredModules = Metadata_1.default.get(constants_1.REGISTERED_MODULE_KEY, target, property) || [];
231
- registeredModules.push(Module);
232
- Metadata_1.default.set(constants_1.REGISTERED_MODULE_KEY, registeredModules, target, property);
232
+ return (_, __) => {
233
+ throw new Error('RegisterModule is deprecated, use the new decorator Modules that allow add modules into registered modules.');
233
234
  };
234
235
  }
235
- exports.RegisterModule = RegisterModule;
236
236
  function Teapot(teapotSettings) {
237
237
  return (target) => {
238
- Metadata_1.default.set(constants_1.ASSIGN_TEAPOT_KEY, true, target, 'isTeapotActive');
239
- Metadata_1.default.set(constants_1.ASSIGN_TEAPOT_KEY, teapotSettings, target);
238
+ commons_1.Metadata.set(commons_2.ASSIGN_TEAPOT_KEY, true, target, 'isTeapotActive');
239
+ commons_1.Metadata.set(commons_2.ASSIGN_TEAPOT_KEY, teapotSettings, target);
240
240
  };
241
241
  }
242
- exports.Teapot = Teapot;
243
242
  function Teacup(teacupSettings) {
244
243
  return (target) => {
245
- Metadata_1.default.set(constants_1.ASSIGN_TEACUP_KEY, true, target, 'isTeacupActive');
246
- Metadata_1.default.set(constants_1.ASSIGN_TEACUP_KEY, teacupSettings, target);
244
+ commons_1.Metadata.set(commons_2.ASSIGN_TEACUP_KEY, true, target, 'isTeacupActive');
245
+ commons_1.Metadata.set(commons_2.ASSIGN_TEACUP_KEY, teacupSettings, target);
247
246
  };
248
247
  }
249
- exports.Teacup = Teacup;
@@ -0,0 +1,120 @@
1
+ import ExpressiveTeaEngine from '../../classes/Engine';
2
+ /**
3
+ * Health check status
4
+ * @since 2.0.0
5
+ */
6
+ export type HealthStatus = 'pass' | 'fail' | 'warn';
7
+ /**
8
+ * Individual health check result
9
+ * @since 2.0.0
10
+ */
11
+ export interface HealthCheckResult {
12
+ /** Check status */
13
+ status: HealthStatus;
14
+ /** Optional details about the check */
15
+ details?: Record<string, any>;
16
+ /** Optional error message if failed */
17
+ error?: string;
18
+ }
19
+ /**
20
+ * Health check function
21
+ * @since 2.0.0
22
+ */
23
+ export type HealthCheckFunction = () => Promise<HealthCheckResult> | HealthCheckResult;
24
+ /**
25
+ * Health check definition
26
+ * @since 2.0.0
27
+ */
28
+ export interface HealthCheck {
29
+ /** Unique name for this health check */
30
+ name: string;
31
+ /** The check function to execute */
32
+ check: HealthCheckFunction;
33
+ /** Whether this check is critical for readiness */
34
+ critical?: boolean;
35
+ /** Optional timeout in milliseconds */
36
+ timeout?: number;
37
+ }
38
+ /**
39
+ * Health Check Engine
40
+ *
41
+ * Provides standardized health check endpoints for monitoring and orchestration:
42
+ * - `/health` - Detailed health status with all checks
43
+ * - `/health/live` - Liveness probe (always 200 if server is running)
44
+ * - `/health/ready` - Readiness probe (200 only if all critical checks pass)
45
+ *
46
+ * Compatible with Kubernetes liveness and readiness probes.
47
+ *
48
+ * @class HealthCheckEngine
49
+ * @extends ExpressiveTeaEngine
50
+ * @since 2.0.0
51
+ * @summary Standardized health check endpoints for monitoring
52
+ *
53
+ * @example
54
+ * // Enable health checks with custom checks
55
+ * @HealthCheck({
56
+ * checks: [
57
+ * {
58
+ * name: 'database',
59
+ * check: async () => {
60
+ * const isConnected = await db.ping();
61
+ * return { status: isConnected ? 'pass' : 'fail' };
62
+ * },
63
+ * critical: true,
64
+ * timeout: 5000
65
+ * },
66
+ * {
67
+ * name: 'cache',
68
+ * check: async () => {
69
+ * const isReady = await redis.ping();
70
+ * return {
71
+ * status: isReady ? 'pass' : 'warn',
72
+ * details: { connected: isReady }
73
+ * };
74
+ * }
75
+ * }
76
+ * ]
77
+ * })
78
+ * class MyApp extends Boot {}
79
+ */
80
+ export default class HealthCheckEngine extends ExpressiveTeaEngine {
81
+ private checks;
82
+ /**
83
+ * Register a health check
84
+ * @param check - Health check configuration
85
+ * @since 2.0.0
86
+ */
87
+ registerCheck(check: HealthCheck): void;
88
+ /**
89
+ * Execute a single health check with timeout
90
+ * @param check - Health check to execute
91
+ * @returns Check result
92
+ * @private
93
+ */
94
+ private executeCheck;
95
+ /**
96
+ * Initialize health check routes
97
+ * @since 2.0.0
98
+ */
99
+ init(): Promise<void>;
100
+ /**
101
+ * Start the health check engine
102
+ * @since 2.0.0
103
+ */
104
+ start(): Promise<void>;
105
+ /**
106
+ * Stop the health check engine
107
+ * @since 2.0.0
108
+ */
109
+ stop(): Promise<void>;
110
+ /**
111
+ * Determine if this engine should be registered
112
+ *
113
+ * Health checks are enabled by default for all applications.
114
+ * To disable, set `enableHealthChecks: false` in ServerSettings.
115
+ *
116
+ * @returns true if health checks should be enabled
117
+ * @since 2.0.0
118
+ */
119
+ static canRegister(): boolean;
120
+ }
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const inversify_1 = require("inversify");
5
+ const Engine_1 = require("../../classes/Engine");
6
+ /**
7
+ * Health Check Engine
8
+ *
9
+ * Provides standardized health check endpoints for monitoring and orchestration:
10
+ * - `/health` - Detailed health status with all checks
11
+ * - `/health/live` - Liveness probe (always 200 if server is running)
12
+ * - `/health/ready` - Readiness probe (200 only if all critical checks pass)
13
+ *
14
+ * Compatible with Kubernetes liveness and readiness probes.
15
+ *
16
+ * @class HealthCheckEngine
17
+ * @extends ExpressiveTeaEngine
18
+ * @since 2.0.0
19
+ * @summary Standardized health check endpoints for monitoring
20
+ *
21
+ * @example
22
+ * // Enable health checks with custom checks
23
+ * @HealthCheck({
24
+ * checks: [
25
+ * {
26
+ * name: 'database',
27
+ * check: async () => {
28
+ * const isConnected = await db.ping();
29
+ * return { status: isConnected ? 'pass' : 'fail' };
30
+ * },
31
+ * critical: true,
32
+ * timeout: 5000
33
+ * },
34
+ * {
35
+ * name: 'cache',
36
+ * check: async () => {
37
+ * const isReady = await redis.ping();
38
+ * return {
39
+ * status: isReady ? 'pass' : 'warn',
40
+ * details: { connected: isReady }
41
+ * };
42
+ * }
43
+ * }
44
+ * ]
45
+ * })
46
+ * class MyApp extends Boot {}
47
+ */
48
+ let HealthCheckEngine = class HealthCheckEngine extends Engine_1.default {
49
+ constructor() {
50
+ super(...arguments);
51
+ this.checks = [];
52
+ }
53
+ /**
54
+ * Register a health check
55
+ * @param check - Health check configuration
56
+ * @since 2.0.0
57
+ */
58
+ registerCheck(check) {
59
+ this.checks.push(check);
60
+ }
61
+ /**
62
+ * Execute a single health check with timeout
63
+ * @param check - Health check to execute
64
+ * @returns Check result
65
+ * @private
66
+ */
67
+ async executeCheck(check) {
68
+ const timeout = check.timeout || 5000;
69
+ try {
70
+ const result = await Promise.race([
71
+ Promise.resolve(check.check()),
72
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Health check timeout')), timeout)),
73
+ ]);
74
+ return result;
75
+ }
76
+ catch (error) {
77
+ return {
78
+ status: 'fail',
79
+ error: error instanceof Error ? error.message : String(error),
80
+ };
81
+ }
82
+ }
83
+ /**
84
+ * Initialize health check routes
85
+ * @since 2.0.0
86
+ */
87
+ async init() {
88
+ const app = this.context.getApplication();
89
+ // Detailed health endpoint
90
+ app.get('/health', async (_req, res) => {
91
+ const results = {};
92
+ let overallStatus = 'pass';
93
+ // Execute all checks in parallel
94
+ await Promise.all(this.checks.map(async (check) => {
95
+ const result = await this.executeCheck(check);
96
+ results[check.name] = result;
97
+ // Update overall status
98
+ if (result.status === 'fail') {
99
+ overallStatus = 'fail';
100
+ }
101
+ else if (result.status === 'warn' && overallStatus === 'pass') {
102
+ overallStatus = 'warn';
103
+ }
104
+ }));
105
+ const statusCode = overallStatus === 'pass' ? 200 : overallStatus === 'warn' ? 200 : 503;
106
+ res.status(statusCode).json({
107
+ status: overallStatus,
108
+ timestamp: new Date().toISOString(),
109
+ checks: results,
110
+ });
111
+ });
112
+ // Liveness probe - always returns 200 if server is running
113
+ app.get('/health/live', (_req, res) => {
114
+ res.status(200).json({
115
+ status: 'pass',
116
+ timestamp: new Date().toISOString(),
117
+ });
118
+ });
119
+ // Readiness probe - returns 200 only if all critical checks pass
120
+ app.get('/health/ready', async (_req, res) => {
121
+ const criticalChecks = this.checks.filter((c) => c.critical);
122
+ if (criticalChecks.length === 0) {
123
+ // No critical checks, always ready
124
+ res.status(200).json({
125
+ status: 'pass',
126
+ timestamp: new Date().toISOString(),
127
+ });
128
+ return;
129
+ }
130
+ const results = {};
131
+ let isReady = true;
132
+ // Execute only critical checks
133
+ await Promise.all(criticalChecks.map(async (check) => {
134
+ const result = await this.executeCheck(check);
135
+ results[check.name] = result;
136
+ if (result.status === 'fail') {
137
+ isReady = false;
138
+ }
139
+ }));
140
+ res.status(isReady ? 200 : 503).json({
141
+ status: isReady ? 'pass' : 'fail',
142
+ timestamp: new Date().toISOString(),
143
+ checks: results,
144
+ });
145
+ });
146
+ }
147
+ /**
148
+ * Start the health check engine
149
+ * @since 2.0.0
150
+ */
151
+ async start() {
152
+ // Nothing to start - routes are already registered
153
+ }
154
+ /**
155
+ * Stop the health check engine
156
+ * @since 2.0.0
157
+ */
158
+ async stop() {
159
+ // Clear checks on shutdown
160
+ this.checks = [];
161
+ }
162
+ /**
163
+ * Determine if this engine should be registered
164
+ *
165
+ * Health checks are enabled by default for all applications.
166
+ * To disable, set `enableHealthChecks: false` in ServerSettings.
167
+ *
168
+ * @returns true if health checks should be enabled
169
+ * @since 2.0.0
170
+ */
171
+ static canRegister() {
172
+ return true;
173
+ }
174
+ };
175
+ HealthCheckEngine = tslib_1.__decorate([
176
+ (0, inversify_1.injectable)(),
177
+ (0, inversify_1.injectFromBase)({ extendConstructorArguments: true })
178
+ ], HealthCheckEngine);
179
+ exports.default = HealthCheckEngine;
@@ -1,13 +1,12 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- import * as http from 'http';
4
- import * as https from 'https';
5
- import { BOOT_STAGES } from '@expressive-tea/commons/constants';
1
+ import * as http from 'node:http';
2
+ import * as https from 'node:https';
3
+ import { BOOT_STAGES } from '@expressive-tea/commons';
6
4
  import ExpressiveTeaEngine from '../../classes/Engine';
7
5
  export default class HTTPEngine extends ExpressiveTeaEngine {
8
6
  private listen;
9
7
  start(): Promise<(http.Server | https.Server)[]>;
10
8
  init(): Promise<void>;
11
- resolveStages(stages: BOOT_STAGES[], ...extraArgs: any[]): Promise<void[]>;
12
- resolveProxyContainers(): Promise<void>;
9
+ resolveStages(stages: BOOT_STAGES[], ...extraArgs: unknown[]): Promise<unknown[]>;
10
+ resolveProxyContainers(): void;
11
+ static canRegister(): boolean;
13
12
  }
@@ -3,14 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const inversify_1 = require("inversify");
5
5
  const boot_helper_1 = require("../../helpers/boot-helper");
6
- const constants_1 = require("@expressive-tea/commons/constants");
7
- const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
8
- const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
6
+ const commons_1 = require("@expressive-tea/commons");
7
+ const commons_2 = require("@expressive-tea/commons");
8
+ const commons_3 = require("@expressive-tea/commons");
9
9
  const Engine_1 = require("../../classes/Engine");
10
10
  let HTTPEngine = class HTTPEngine extends Engine_1.default {
11
- listen(server, port) {
11
+ async listen(server, port) {
12
12
  return new Promise((resolve, reject) => {
13
- console.log('Listening on port', port, server.listen);
14
13
  server.listen(port);
15
14
  server.on('error', error => {
16
15
  reject(error);
@@ -22,33 +21,39 @@ let HTTPEngine = class HTTPEngine extends Engine_1.default {
22
21
  });
23
22
  }
24
23
  async start() {
25
- console.log(`Starting Server Test`);
26
- const listenerServers = [
24
+ const servers = [
25
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
27
26
  await this.listen(this.server, this.settings.get('port')),
28
27
  (this.serverSecure) ? await this.listen(this.serverSecure, this.settings.get('securePort')) : null
29
28
  ];
30
- await this.resolveStages([constants_1.BOOT_STAGES.START], ...listenerServers);
29
+ const listenerServers = servers.filter((server) => server !== null);
30
+ await this.resolveStages([commons_1.BOOT_STAGES.START], ...listenerServers);
31
31
  return listenerServers;
32
32
  }
33
33
  async init() {
34
- await (0, boot_helper_1.resolveDirectives)(this.context, this.context.getApplication());
35
- await (0, boot_helper_1.resolveStatic)(this.context, this.context.getApplication());
34
+ (0, boot_helper_1.resolveDirectives)(this.context, this.context.getApplication());
35
+ (0, boot_helper_1.resolveStatic)(this.context, this.context.getApplication());
36
36
  // HTTP Engine Resolve Stages
37
- await this.resolveProxyContainers();
38
- await this.resolveStages(constants_1.BOOT_ORDER);
39
- await this.resolveStages([constants_1.BOOT_STAGES.AFTER_APPLICATION_MIDDLEWARES, constants_1.BOOT_STAGES.ON_HTTP_CREATION], this.server, this.serverSecure);
37
+ this.resolveProxyContainers();
38
+ await this.resolveStages(commons_1.BOOT_ORDER);
39
+ await this.resolveStages([commons_1.BOOT_STAGES.AFTER_APPLICATION_MIDDLEWARES, commons_1.BOOT_STAGES.ON_HTTP_CREATION], this.server, this.serverSecure);
40
40
  }
41
41
  async resolveStages(stages, ...extraArgs) {
42
- return Promise.all(stages.map(s => (0, boot_helper_1.resolveStage)(s, this.context, this.context.getApplication(), ...extraArgs)));
42
+ return Promise.all(stages.map(async (s) => (0, boot_helper_1.resolveStage)(s, this.context, this.context.getApplication(), ...extraArgs)));
43
43
  }
44
- async resolveProxyContainers() {
45
- const ProxyContainers = Metadata_1.default.get(constants_1.ROUTER_PROXIES_KEY, (0, object_helper_1.getClass)(this.context)) || [];
44
+ resolveProxyContainers() {
45
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
46
+ const ProxyContainers = commons_3.Metadata.get(commons_1.ROUTER_PROXIES_KEY, (0, commons_2.getClass)(this.context)) || [];
46
47
  for (const Container of ProxyContainers) {
47
48
  (0, boot_helper_1.resolveProxy)(Container, this.context.getApplication());
48
49
  }
49
50
  }
51
+ static canRegister() {
52
+ return true;
53
+ }
50
54
  };
51
55
  HTTPEngine = tslib_1.__decorate([
52
- (0, inversify_1.injectable)()
56
+ (0, inversify_1.injectable)(),
57
+ (0, inversify_1.injectFromBase)({ extendConstructorArguments: true })
53
58
  ], HTTPEngine);
54
59
  exports.default = HTTPEngine;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Core Engine Registration
3
+ *
4
+ * Automatically registers all core Expressive Tea engines with the EngineRegistry.
5
+ * Import this file to enable all core engines with proper dependency order.
6
+ *
7
+ * Engine Priority Order:
8
+ * - 0: HTTPEngine (base engine, no dependencies)
9
+ * - 5: HealthCheckEngine (health endpoints, depends on http)
10
+ * - 10: SocketIOEngine, WebsocketEngine (depend on http)
11
+ * - 20: TeapotEngine, TeacupEngine (depend on http, socketio)
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import '@expressive-tea/core/engines'; // Registers all core engines
16
+ * import Boot from '@expressive-tea/core';
17
+ *
18
+ * class MyApp extends Boot {}
19
+ * ```
20
+ *
21
+ * @module engines
22
+ * @since 2.0.0
23
+ */
24
+ import EngineRegistry from '../classes/EngineRegistry';
25
+ import HTTPEngine from './http';
26
+ import HealthCheckEngine from './health';
27
+ import SocketIOEngine from './socketio';
28
+ import WebsocketEngine from './websocket';
29
+ import TeapotEngine from './teapot';
30
+ import TeacupEngine from './teacup';
31
+ export { HTTPEngine, HealthCheckEngine, SocketIOEngine, WebsocketEngine, TeapotEngine, TeacupEngine };
32
+ export default EngineRegistry;