@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
@@ -0,0 +1,154 @@
1
+ import ExpressiveTeaEngine from './Engine';
2
+ /**
3
+ * Engine constructor type with static canRegister method
4
+ */
5
+ export type EngineConstructor = typeof ExpressiveTeaEngine;
6
+ /**
7
+ * Metadata for registered engines
8
+ * @interface EngineMetadata
9
+ * @since 2.0.0
10
+ */
11
+ export interface EngineMetadata {
12
+ /** Engine class constructor */
13
+ engine: EngineConstructor;
14
+ /** Unique engine name */
15
+ name: string;
16
+ /** Engine version (semver) */
17
+ version: string;
18
+ /** Initialization priority (lower runs first) */
19
+ priority: number;
20
+ /** Array of engine names this engine depends on */
21
+ dependencies: string[];
22
+ }
23
+ /**
24
+ * Engine Registry - Manages engine registration, dependency resolution, and initialization order
25
+ *
26
+ * Replaces hardcoded engine arrays with an extensible plugin system that:
27
+ * - Registers engines with metadata (name, version, priority, dependencies)
28
+ * - Resolves engine dependencies using topological sort
29
+ * - Detects circular dependencies
30
+ * - Filters engines based on their `canRegister()` method
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * // Register a custom engine
35
+ * EngineRegistry.register({
36
+ * engine: MyCustomEngine,
37
+ * name: 'custom',
38
+ * version: '1.0.0',
39
+ * priority: 15,
40
+ * dependencies: ['http']
41
+ * });
42
+ *
43
+ * // Get engines in dependency order
44
+ * const engines = EngineRegistry.getRegisteredEngines(context, settings);
45
+ * ```
46
+ *
47
+ * @class EngineRegistry
48
+ * @since 2.0.0
49
+ */
50
+ export default class EngineRegistry {
51
+ private static engines;
52
+ /**
53
+ * Register an engine with metadata
54
+ *
55
+ * @param {EngineMetadata} metadata - Engine metadata including name, version, priority, and dependencies
56
+ * @throws {Error} If engine with same name is already registered
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * EngineRegistry.register({
61
+ * engine: HTTPEngine,
62
+ * name: 'http',
63
+ * version: '2.0.0',
64
+ * priority: 0,
65
+ * dependencies: []
66
+ * });
67
+ * ```
68
+ */
69
+ static register(metadata: EngineMetadata): void;
70
+ /**
71
+ * Unregister an engine by name
72
+ *
73
+ * @param {string} name - Engine name to unregister
74
+ * @returns {boolean} True if engine was unregistered, false if not found
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * EngineRegistry.unregister('custom');
79
+ * ```
80
+ */
81
+ static unregister(name: string): boolean;
82
+ /**
83
+ * Clear all registered engines (useful for testing)
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * EngineRegistry.clear();
88
+ * ```
89
+ */
90
+ static clear(): void;
91
+ /**
92
+ * Get all registered engine metadata
93
+ *
94
+ * @returns {EngineMetadata[]} Array of all registered engine metadata
95
+ */
96
+ static getAllEngines(): EngineMetadata[];
97
+ /**
98
+ * Get engine metadata by name
99
+ *
100
+ * @param {string} name - Engine name
101
+ * @returns {EngineMetadata | undefined} Engine metadata or undefined if not found
102
+ */
103
+ static getEngine(name: string): EngineMetadata | undefined;
104
+ /**
105
+ * Get registered engines filtered by canRegister() and sorted by dependency order
106
+ *
107
+ * This method:
108
+ * 1. Filters engines using their static `canRegister()` method
109
+ * 2. Validates all dependencies are registered
110
+ * 3. Detects circular dependencies
111
+ * 4. Sorts engines using topological sort (dependencies first)
112
+ * 5. Applies priority sorting within same dependency level
113
+ *
114
+ * @param {unknown} context - Boot context to pass to canRegister()
115
+ * @param {unknown} settings - Settings to pass to canRegister()
116
+ * @returns {EngineConstructor[]} Array of engine constructors in initialization order
117
+ * @throws {Error} If circular dependency is detected
118
+ * @throws {Error} If required dependency is not registered
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const engines = EngineRegistry.getRegisteredEngines(boot, settings);
123
+ * // Returns: [HTTPEngine, SocketIOEngine, TeapotEngine] in dependency order
124
+ * ```
125
+ */
126
+ static getRegisteredEngines(context?: unknown, settings?: unknown): EngineConstructor[];
127
+ /**
128
+ * Validate that all dependencies are registered
129
+ *
130
+ * @private
131
+ * @param {EngineMetadata[]} engines - Engines to validate
132
+ * @throws {Error} If a dependency is not registered
133
+ */
134
+ private static validateDependencies;
135
+ /**
136
+ * Detect circular dependencies using depth-first search
137
+ *
138
+ * @private
139
+ * @param {EngineMetadata[]} engines - Engines to check
140
+ * @throws {Error} If circular dependency is detected
141
+ */
142
+ private static detectCircularDependencies;
143
+ /**
144
+ * Topological sort with priority ordering
145
+ *
146
+ * Uses Kahn's algorithm for topological sorting, with priority-based ordering
147
+ * for engines at the same dependency level.
148
+ *
149
+ * @private
150
+ * @param {EngineMetadata[]} engines - Engines to sort
151
+ * @returns {EngineMetadata[]} Sorted engines (dependencies first, then by priority)
152
+ */
153
+ private static topologicalSort;
154
+ }
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Engine Registry - Manages engine registration, dependency resolution, and initialization order
5
+ *
6
+ * Replaces hardcoded engine arrays with an extensible plugin system that:
7
+ * - Registers engines with metadata (name, version, priority, dependencies)
8
+ * - Resolves engine dependencies using topological sort
9
+ * - Detects circular dependencies
10
+ * - Filters engines based on their `canRegister()` method
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // Register a custom engine
15
+ * EngineRegistry.register({
16
+ * engine: MyCustomEngine,
17
+ * name: 'custom',
18
+ * version: '1.0.0',
19
+ * priority: 15,
20
+ * dependencies: ['http']
21
+ * });
22
+ *
23
+ * // Get engines in dependency order
24
+ * const engines = EngineRegistry.getRegisteredEngines(context, settings);
25
+ * ```
26
+ *
27
+ * @class EngineRegistry
28
+ * @since 2.0.0
29
+ */
30
+ class EngineRegistry {
31
+ /**
32
+ * Register an engine with metadata
33
+ *
34
+ * @param {EngineMetadata} metadata - Engine metadata including name, version, priority, and dependencies
35
+ * @throws {Error} If engine with same name is already registered
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * EngineRegistry.register({
40
+ * engine: HTTPEngine,
41
+ * name: 'http',
42
+ * version: '2.0.0',
43
+ * priority: 0,
44
+ * dependencies: []
45
+ * });
46
+ * ```
47
+ */
48
+ static register(metadata) {
49
+ if (this.engines.has(metadata.name)) {
50
+ throw new Error(`Engine "${metadata.name}" is already registered`);
51
+ }
52
+ this.engines.set(metadata.name, metadata);
53
+ }
54
+ /**
55
+ * Unregister an engine by name
56
+ *
57
+ * @param {string} name - Engine name to unregister
58
+ * @returns {boolean} True if engine was unregistered, false if not found
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * EngineRegistry.unregister('custom');
63
+ * ```
64
+ */
65
+ static unregister(name) {
66
+ return this.engines.delete(name);
67
+ }
68
+ /**
69
+ * Clear all registered engines (useful for testing)
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * EngineRegistry.clear();
74
+ * ```
75
+ */
76
+ static clear() {
77
+ this.engines.clear();
78
+ }
79
+ /**
80
+ * Get all registered engine metadata
81
+ *
82
+ * @returns {EngineMetadata[]} Array of all registered engine metadata
83
+ */
84
+ static getAllEngines() {
85
+ return Array.from(this.engines.values());
86
+ }
87
+ /**
88
+ * Get engine metadata by name
89
+ *
90
+ * @param {string} name - Engine name
91
+ * @returns {EngineMetadata | undefined} Engine metadata or undefined if not found
92
+ */
93
+ static getEngine(name) {
94
+ return this.engines.get(name);
95
+ }
96
+ /**
97
+ * Get registered engines filtered by canRegister() and sorted by dependency order
98
+ *
99
+ * This method:
100
+ * 1. Filters engines using their static `canRegister()` method
101
+ * 2. Validates all dependencies are registered
102
+ * 3. Detects circular dependencies
103
+ * 4. Sorts engines using topological sort (dependencies first)
104
+ * 5. Applies priority sorting within same dependency level
105
+ *
106
+ * @param {unknown} context - Boot context to pass to canRegister()
107
+ * @param {unknown} settings - Settings to pass to canRegister()
108
+ * @returns {EngineConstructor[]} Array of engine constructors in initialization order
109
+ * @throws {Error} If circular dependency is detected
110
+ * @throws {Error} If required dependency is not registered
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const engines = EngineRegistry.getRegisteredEngines(boot, settings);
115
+ * // Returns: [HTTPEngine, SocketIOEngine, TeapotEngine] in dependency order
116
+ * ```
117
+ */
118
+ static getRegisteredEngines(context, settings) {
119
+ // Filter engines by canRegister()
120
+ const availableEngines = Array.from(this.engines.values())
121
+ .filter(metadata => metadata.engine.canRegister(context, settings));
122
+ // Validate dependencies
123
+ this.validateDependencies(availableEngines);
124
+ // Detect circular dependencies
125
+ this.detectCircularDependencies(availableEngines);
126
+ // Topological sort with priority
127
+ const sorted = this.topologicalSort(availableEngines);
128
+ return sorted.map(metadata => metadata.engine);
129
+ }
130
+ /**
131
+ * Validate that all dependencies are registered
132
+ *
133
+ * @private
134
+ * @param {EngineMetadata[]} engines - Engines to validate
135
+ * @throws {Error} If a dependency is not registered
136
+ */
137
+ static validateDependencies(engines) {
138
+ const engineNames = new Set(engines.map(e => e.name));
139
+ for (const engine of engines) {
140
+ for (const dep of engine.dependencies) {
141
+ if (!engineNames.has(dep)) {
142
+ throw new Error(`Engine "${engine.name}" depends on "${dep}" which is not registered or cannot be registered`);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ /**
148
+ * Detect circular dependencies using depth-first search
149
+ *
150
+ * @private
151
+ * @param {EngineMetadata[]} engines - Engines to check
152
+ * @throws {Error} If circular dependency is detected
153
+ */
154
+ static detectCircularDependencies(engines) {
155
+ const visited = new Set();
156
+ const recursionStack = new Set();
157
+ const engineMap = new Map(engines.map(e => [e.name, e]));
158
+ const visit = (engineName, path) => {
159
+ if (recursionStack.has(engineName)) {
160
+ const cycle = [...path, engineName].join(' -> ');
161
+ throw new Error(`Circular dependency detected: ${cycle}`);
162
+ }
163
+ if (visited.has(engineName)) {
164
+ return;
165
+ }
166
+ visited.add(engineName);
167
+ recursionStack.add(engineName);
168
+ const engine = engineMap.get(engineName);
169
+ if (engine) {
170
+ for (const dep of engine.dependencies) {
171
+ visit(dep, [...path, engineName]);
172
+ }
173
+ }
174
+ recursionStack.delete(engineName);
175
+ };
176
+ for (const engine of engines) {
177
+ if (!visited.has(engine.name)) {
178
+ visit(engine.name, []);
179
+ }
180
+ }
181
+ }
182
+ /**
183
+ * Topological sort with priority ordering
184
+ *
185
+ * Uses Kahn's algorithm for topological sorting, with priority-based ordering
186
+ * for engines at the same dependency level.
187
+ *
188
+ * @private
189
+ * @param {EngineMetadata[]} engines - Engines to sort
190
+ * @returns {EngineMetadata[]} Sorted engines (dependencies first, then by priority)
191
+ */
192
+ static topologicalSort(engines) {
193
+ var _a;
194
+ const engineMap = new Map(engines.map(e => [e.name, e]));
195
+ const inDegree = new Map();
196
+ const dependents = new Map();
197
+ // Initialize in-degree and dependents
198
+ for (const engine of engines) {
199
+ inDegree.set(engine.name, 0);
200
+ dependents.set(engine.name, []);
201
+ }
202
+ // Build dependency graph
203
+ for (const engine of engines) {
204
+ for (const dep of engine.dependencies) {
205
+ inDegree.set(engine.name, (inDegree.get(engine.name) || 0) + 1);
206
+ (_a = dependents.get(dep)) === null || _a === void 0 ? void 0 : _a.push(engine.name);
207
+ }
208
+ }
209
+ // Priority queue for engines with no dependencies
210
+ const queue = [];
211
+ for (const engine of engines) {
212
+ if (inDegree.get(engine.name) === 0) {
213
+ queue.push(engine);
214
+ }
215
+ }
216
+ // Sort queue by priority
217
+ queue.sort((a, b) => a.priority - b.priority);
218
+ const sorted = [];
219
+ while (queue.length > 0) {
220
+ // Remove engine with lowest priority
221
+ const current = queue.shift();
222
+ sorted.push(current);
223
+ // Reduce in-degree for dependents
224
+ const deps = dependents.get(current.name) || [];
225
+ for (const depName of deps) {
226
+ const newDegree = (inDegree.get(depName) || 0) - 1;
227
+ inDegree.set(depName, newDegree);
228
+ if (newDegree === 0) {
229
+ const engine = engineMap.get(depName);
230
+ if (engine) {
231
+ // Insert sorted by priority
232
+ const insertIndex = queue.findIndex(e => e.priority > engine.priority);
233
+ if (insertIndex === -1) {
234
+ queue.push(engine);
235
+ }
236
+ else {
237
+ queue.splice(insertIndex, 0, engine);
238
+ }
239
+ }
240
+ }
241
+ }
242
+ }
243
+ return sorted;
244
+ }
245
+ }
246
+ EngineRegistry.engines = new Map();
247
+ exports.default = EngineRegistry;
@@ -5,11 +5,8 @@ class LoadBalancer {
5
5
  * @offset should be used for unit testing and nothing else.
6
6
  */
7
7
  constructor(count, offset = 0) {
8
- this.bins = new Array(count);
9
- // Initializes the elements of the array to zero.
10
- for (let i = 0; i < this.bins.length; i++) {
11
- this.bins[i] = offset;
12
- }
8
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
9
+ this.bins = new Array(count).fill(offset);
13
10
  }
14
11
  pick() {
15
12
  const a = Math.trunc(Math.random() * this.bins.length);
@@ -1,9 +1,9 @@
1
- import { RequestHandler } from 'express';
1
+ import { type RequestHandler } from 'express';
2
2
  export default class ProxyRoute {
3
3
  readonly registeredOn: string;
4
4
  private balancer;
5
- private servers;
6
- private clients;
5
+ private readonly servers;
6
+ private readonly clients;
7
7
  private lastServerSelected;
8
8
  constructor(registeredOn: string);
9
9
  hasClients(): boolean;
@@ -2,19 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const proxy = require("express-http-proxy");
4
4
  const LoadBalancer_1 = require("./LoadBalancer");
5
- const lodash_1 = require("lodash");
5
+ const utilities_1 = require("../libs/utilities");
6
6
  class ProxyRoute {
7
7
  constructor(registeredOn) {
8
+ this.registeredOn = registeredOn;
8
9
  this.servers = [];
9
10
  this.clients = [];
10
11
  this.lastServerSelected = 0;
11
- this.registeredOn = registeredOn;
12
12
  }
13
13
  hasClients() {
14
- return (0, lodash_1.size)(this.clients) > 0;
14
+ return (0, utilities_1.size)(this.clients) > 0;
15
15
  }
16
16
  isClientOnRoute(teacupId) {
17
- return (0, lodash_1.includes)(this.clients, teacupId);
17
+ return (0, utilities_1.includes)(this.clients, teacupId);
18
18
  }
19
19
  registerServer(address, teacupId) {
20
20
  this.servers.push({ teacupId, address });
@@ -22,7 +22,7 @@ class ProxyRoute {
22
22
  this.balancer = new LoadBalancer_1.default(this.servers.length, this.lastServerSelected);
23
23
  }
24
24
  unregisterServer(teacupId) {
25
- const index = (0, lodash_1.indexOf)(this.clients, teacupId);
25
+ const index = (0, utilities_1.indexOf)(this.clients, teacupId);
26
26
  this.servers.splice(index, 1);
27
27
  this.clients.splice(index, 1);
28
28
  this.balancer = new LoadBalancer_1.default(this.servers.length);
@@ -1,4 +1,4 @@
1
- import { ExpressiveTeaServerProps } from '@expressive-tea/commons/interfaces';
1
+ import { ExpressiveTeaServerProps } from '@expressive-tea/commons';
2
2
  /**
3
3
  * Declare the properties which the server will save into settings, is a semi dynamic object since is allowed to save
4
4
  * any property but is contains only one defined property to keep the port of the server.
@@ -26,10 +26,11 @@ declare class Settings {
26
26
  * one time at the application starts.
27
27
  *
28
28
  * @static
29
+ * @param {boolean} [resetIsolated=true] - If true, also reset all isolated contexts
29
30
  * @summary Reset Singleton instance
30
31
  * @memberof Settings
31
32
  */
32
- static reset(): void;
33
+ static reset(resetIsolated?: boolean): void;
33
34
  /**
34
35
  * Get Current Singleton Instance or Created if not exists. If a new instance is created it will created with default
35
36
  * options.
@@ -95,5 +96,33 @@ declare class Settings {
95
96
  * @summary Merge Options
96
97
  */
97
98
  merge(options?: ExpressiveTeaServerProps): void;
99
+ /**
100
+ * Get environment variables with optional type safety.
101
+ *
102
+ * Returns transformed environment variables if a transform function was provided
103
+ * to the @Env decorator, otherwise returns process.env.
104
+ *
105
+ * Use this method for type-safe access to environment variables when using
106
+ * the @Env decorator with a transform function (e.g., Zod validation).
107
+ *
108
+ * @template T - Type of environment variables (defaults to NodeJS.ProcessEnv)
109
+ * @returns Typed environment variables
110
+ * @since 2.0.1
111
+ * @summary Get type-safe environment variables
112
+ *
113
+ * @example
114
+ * // Basic usage (returns process.env)
115
+ * const env = Settings.getInstance().getEnv();
116
+ * console.log(env.NODE_ENV);
117
+ *
118
+ * @example
119
+ * // With type-safe transform from @Env decorator
120
+ * type Env = { PORT: number; DATABASE_URL: string };
121
+ *
122
+ * const env = Settings.getInstance().getEnv<Env>();
123
+ * console.log(env.PORT); // Type: number (transformed)
124
+ * console.log(env.DATABASE_URL); // Type: string (validated)
125
+ */
126
+ getEnv<T = Record<string, string>>(): T;
98
127
  }
99
128
  export default Settings;
@@ -2,10 +2,11 @@
2
2
  var Settings_1;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const tslib_1 = require("tslib");
5
- const _ = require("lodash");
5
+ const utilities_1 = require("../libs/utilities");
6
+ const commons_1 = require("@expressive-tea/commons");
6
7
  const inversify_1 = require("inversify");
7
- const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
8
8
  const server_1 = require("../helpers/server");
9
+ const env_1 = require("../decorators/env");
9
10
  /**
10
11
  * Declare the properties which the server will save into settings, is a semi dynamic object since is allowed to save
11
12
  * any property but is contains only one defined property to keep the port of the server.
@@ -32,11 +33,15 @@ let Settings = Settings_1 = class Settings {
32
33
  * one time at the application starts.
33
34
  *
34
35
  * @static
36
+ * @param {boolean} [resetIsolated=true] - If true, also reset all isolated contexts
35
37
  * @summary Reset Singleton instance
36
38
  * @memberof Settings
37
39
  */
38
- static reset() {
39
- delete Settings_1.instance;
40
+ static reset(resetIsolated = true) {
41
+ Settings_1.instance = undefined;
42
+ if (resetIsolated) {
43
+ Settings_1.isolatedContext.clear();
44
+ }
40
45
  }
41
46
  /**
42
47
  * Get Current Singleton Instance or Created if not exists. If a new instance is created it will created with default
@@ -47,23 +52,34 @@ let Settings = Settings_1 = class Settings {
47
52
  * @memberof Settings
48
53
  * @summary Get Singleton Instance.
49
54
  */
55
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
56
  static getInstance(ctx) {
51
57
  if (ctx) {
52
- const context = (0, object_helper_1.nameOfClass)(ctx);
58
+ const context = (0, commons_1.nameOfClass)(ctx);
53
59
  if (!Settings_1.isolatedContext.has(context)) {
54
- Settings_1.isolatedContext.set(context, new Settings_1(null, true));
60
+ Settings_1.isolatedContext.set(context, new Settings_1(undefined, true));
55
61
  }
56
62
  return Settings_1.isolatedContext.get(context);
57
63
  }
58
64
  return Settings_1.instance || new Settings_1();
59
65
  }
60
- constructor(options = { port: 3000, securePort: 4443 }, isIsolated = false) {
66
+ constructor(options = {}, isIsolated = false) {
67
+ /**
68
+ * Server configuration options.
69
+ *
70
+ * @private
71
+ * @type {ExpressiveTeaServerProps}
72
+ * @memberof Settings
73
+ */
74
+ this.options = { port: 3000, securePort: 4443 };
61
75
  if (Settings_1.instance && !isIsolated) {
62
76
  return Settings_1.instance;
63
77
  }
64
78
  const settingsFile = (0, server_1.fileSettings)();
65
- this.options = Object.assign({}, { port: 3000, securePort: 4443 }, settingsFile, options);
66
- Settings_1.instance = this;
79
+ this.options = Object.assign(Object.assign(Object.assign({}, this.options), settingsFile.config), options);
80
+ if (!isIsolated) {
81
+ Settings_1.instance = this;
82
+ }
67
83
  }
68
84
  /**
69
85
  * It will return the latest snapshot options registered at the time that this method is called, as Expressive Tea
@@ -85,8 +101,9 @@ let Settings = Settings_1 = class Settings {
85
101
  * @memberof Settings
86
102
  * @summary Retrieve an option
87
103
  */
104
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
88
105
  get(settingName) {
89
- return _.get(this.options, settingName, null);
106
+ return (0, utilities_1.get)(this.options, settingName, null);
90
107
  }
91
108
  /**
92
109
  * Initialize or Edit a application options, this is only for in run options, as explained above initialization
@@ -97,8 +114,9 @@ let Settings = Settings_1 = class Settings {
97
114
  * @memberof Settings
98
115
  * @summary Initialize an option.
99
116
  */
117
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
118
  set(settingName, value) {
101
- _.set(this.options, settingName, value);
119
+ (0, utilities_1.set)(this.options, settingName, value);
102
120
  }
103
121
  /**
104
122
  * This Merge multiple options at the same time, this can edit or create the options.
@@ -110,7 +128,42 @@ let Settings = Settings_1 = class Settings {
110
128
  merge(options = { port: 3000, securePort: 4443 }) {
111
129
  this.options = Object.assign(this.options, options);
112
130
  }
131
+ /**
132
+ * Get environment variables with optional type safety.
133
+ *
134
+ * Returns transformed environment variables if a transform function was provided
135
+ * to the @Env decorator, otherwise returns process.env.
136
+ *
137
+ * Use this method for type-safe access to environment variables when using
138
+ * the @Env decorator with a transform function (e.g., Zod validation).
139
+ *
140
+ * @template T - Type of environment variables (defaults to NodeJS.ProcessEnv)
141
+ * @returns Typed environment variables
142
+ * @since 2.0.1
143
+ * @summary Get type-safe environment variables
144
+ *
145
+ * @example
146
+ * // Basic usage (returns process.env)
147
+ * const env = Settings.getInstance().getEnv();
148
+ * console.log(env.NODE_ENV);
149
+ *
150
+ * @example
151
+ * // With type-safe transform from @Env decorator
152
+ * type Env = { PORT: number; DATABASE_URL: string };
153
+ *
154
+ * const env = Settings.getInstance().getEnv<Env>();
155
+ * console.log(env.PORT); // Type: number (transformed)
156
+ * console.log(env.DATABASE_URL); // Type: string (validated)
157
+ */
158
+ getEnv() {
159
+ const transformed = (0, env_1.getTransformedEnv)();
160
+ if (transformed !== null) {
161
+ return transformed;
162
+ }
163
+ return process.env;
164
+ }
113
165
  };
166
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114
167
  Settings.isolatedContext = new Map();
115
168
  Settings = Settings_1 = tslib_1.__decorate([
116
169
  (0, inversify_1.injectable)(),
@@ -1,4 +1,4 @@
1
- import { ParameterDecorator } from '@expressive-tea/commons/types';
1
+ import { type ParameterDecorator } from '@expressive-tea/commons';
2
2
  /**
3
3
  * Is passing directly to the decorated argument described <a href="http://expressjs.com/en/4x/api.html#req">here</a>.
4
4
  * @decorator {ParameterDecorator} request - Assign express Request instance to parameter.