@scpxl/nodejs-framework 1.0.14 → 1.0.19
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.
- package/README.md +29 -0
- package/dist/api-requester/api-requester.d.ts +27 -6
- package/dist/api-requester/api-requester.d.ts.map +1 -1
- package/dist/api-requester/api-requester.js +188 -26
- package/dist/api-requester/api-requester.js.map +2 -2
- package/dist/api-requester/index.d.ts +1 -0
- package/dist/api-requester/index.d.ts.map +1 -1
- package/dist/api-requester/index.js.map +1 -1
- package/dist/application/base-application.d.ts +16 -20
- package/dist/application/base-application.d.ts.map +1 -1
- package/dist/application/base-application.js +152 -109
- package/dist/application/base-application.js.map +2 -2
- package/dist/application/command-application.d.ts.map +1 -1
- package/dist/application/command-application.js +3 -4
- package/dist/application/command-application.js.map +2 -2
- package/dist/application/web-application.d.ts.map +1 -1
- package/dist/application/web-application.js +9 -2
- package/dist/application/web-application.js.map +2 -2
- package/dist/cache/manager.d.ts +87 -6
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +77 -30
- package/dist/cache/manager.js.map +2 -2
- package/dist/cluster/cluster-manager.d.ts.map +1 -1
- package/dist/cluster/cluster-manager.js +7 -9
- package/dist/cluster/cluster-manager.js.map +2 -2
- package/dist/config/env.d.ts +11 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +103 -0
- package/dist/config/env.js.map +7 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +7 -0
- package/dist/config/schema.d.ts +408 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +218 -0
- package/dist/config/schema.js.map +7 -0
- package/dist/database/dynamic-entity.d.ts.map +1 -1
- package/dist/database/dynamic-entity.js +6 -2
- package/dist/database/dynamic-entity.js.map +2 -2
- package/dist/database/instance.d.ts.map +1 -1
- package/dist/database/instance.js +0 -8
- package/dist/database/instance.js.map +2 -2
- package/dist/database/manager.d.ts.map +1 -1
- package/dist/database/manager.js +71 -9
- package/dist/database/manager.js.map +2 -2
- package/dist/error/error-reporter.d.ts +96 -0
- package/dist/error/error-reporter.d.ts.map +1 -0
- package/dist/error/error-reporter.js +228 -0
- package/dist/error/error-reporter.js.map +7 -0
- package/dist/error/error.interface.d.ts +126 -0
- package/dist/error/error.interface.d.ts.map +1 -0
- package/dist/error/error.interface.js +45 -0
- package/dist/error/error.interface.js.map +7 -0
- package/dist/error/framework-errors.d.ts +113 -0
- package/dist/error/framework-errors.d.ts.map +1 -0
- package/dist/error/framework-errors.js +176 -0
- package/dist/error/framework-errors.js.map +7 -0
- package/dist/error/index.d.ts +6 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/index.js +34 -0
- package/dist/error/index.js.map +7 -0
- package/dist/event/manager.d.ts.map +1 -1
- package/dist/event/manager.js +2 -9
- package/dist/event/manager.js.map +2 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +2 -2
- package/dist/lifecycle/exit.d.ts +11 -0
- package/dist/lifecycle/exit.d.ts.map +1 -0
- package/dist/lifecycle/exit.js +29 -0
- package/dist/lifecycle/exit.js.map +7 -0
- package/dist/lifecycle/index.d.ts +7 -0
- package/dist/lifecycle/index.d.ts.map +1 -0
- package/dist/lifecycle/index.js +12 -0
- package/dist/lifecycle/index.js.map +7 -0
- package/dist/lifecycle/lifecycle-manager.d.ts +66 -0
- package/dist/lifecycle/lifecycle-manager.d.ts.map +1 -0
- package/dist/lifecycle/lifecycle-manager.js +280 -0
- package/dist/lifecycle/lifecycle-manager.js.map +7 -0
- package/dist/lifecycle/shutdown-controller.d.ts +15 -0
- package/dist/lifecycle/shutdown-controller.d.ts.map +1 -0
- package/dist/lifecycle/shutdown-controller.js +38 -0
- package/dist/lifecycle/shutdown-controller.js.map +7 -0
- package/dist/lifecycle/types.d.ts +28 -0
- package/dist/lifecycle/types.d.ts.map +1 -0
- package/dist/lifecycle/types.js +13 -0
- package/dist/lifecycle/types.js.map +7 -0
- package/dist/logger/logger.d.ts +2 -1
- package/dist/logger/logger.d.ts.map +1 -1
- package/dist/logger/logger.js +35 -11
- package/dist/logger/logger.js.map +2 -2
- package/dist/performance/cache-performance.d.ts +6 -0
- package/dist/performance/cache-performance.d.ts.map +1 -1
- package/dist/performance/cache-performance.js +16 -0
- package/dist/performance/cache-performance.js.map +2 -2
- package/dist/performance/index.d.ts +1 -0
- package/dist/performance/index.d.ts.map +1 -1
- package/dist/performance/index.js +1 -0
- package/dist/performance/index.js.map +2 -2
- package/dist/performance/performance-monitor.d.ts.map +1 -1
- package/dist/performance/performance-monitor.js +47 -18
- package/dist/performance/performance-monitor.js.map +2 -2
- package/dist/performance/performance-monitor.plugin.d.ts +24 -0
- package/dist/performance/performance-monitor.plugin.d.ts.map +1 -0
- package/dist/performance/performance-monitor.plugin.js +89 -0
- package/dist/performance/performance-monitor.plugin.js.map +7 -0
- package/dist/performance/webserver-performance.js +1 -1
- package/dist/performance/webserver-performance.js.map +2 -2
- package/dist/queue/manager.d.ts.map +1 -1
- package/dist/queue/manager.js +3 -10
- package/dist/queue/manager.js.map +2 -2
- package/dist/queue/worker.d.ts.map +1 -1
- package/dist/queue/worker.js +2 -2
- package/dist/queue/worker.js.map +2 -2
- package/dist/redis/manager.d.ts.map +1 -1
- package/dist/redis/manager.js +228 -33
- package/dist/redis/manager.js.map +2 -2
- package/dist/request-context/index.d.ts +3 -0
- package/dist/request-context/index.d.ts.map +1 -0
- package/dist/request-context/index.js +25 -0
- package/dist/request-context/index.js.map +7 -0
- package/dist/request-context/request-context.d.ts +108 -0
- package/dist/request-context/request-context.d.ts.map +1 -0
- package/dist/request-context/request-context.interface.d.ts +46 -0
- package/dist/request-context/request-context.interface.d.ts.map +1 -0
- package/dist/request-context/request-context.interface.js +1 -0
- package/dist/request-context/request-context.interface.js.map +7 -0
- package/dist/request-context/request-context.js +79 -0
- package/dist/request-context/request-context.js.map +7 -0
- package/dist/services/aws/s3.js +4 -6
- package/dist/services/aws/s3.js.map +2 -2
- package/dist/util/file.d.ts +13 -0
- package/dist/util/file.d.ts.map +1 -1
- package/dist/util/file.js +46 -9
- package/dist/util/file.js.map +2 -2
- package/dist/util/helper.d.ts +16 -1
- package/dist/util/helper.d.ts.map +1 -1
- package/dist/util/helper.js +19 -43
- package/dist/util/helper.js.map +2 -2
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.d.ts.map +1 -1
- package/dist/util/index.js +18 -16
- package/dist/util/index.js.map +2 -2
- package/dist/util/loader.d.ts.map +1 -1
- package/dist/util/loader.js +13 -2
- package/dist/util/loader.js.map +2 -2
- package/dist/util/os.d.ts.map +1 -1
- package/dist/util/os.js +8 -14
- package/dist/util/os.js.map +2 -2
- package/dist/util/time.d.ts +8 -2
- package/dist/util/time.d.ts.map +1 -1
- package/dist/util/time.js +12 -7
- package/dist/util/time.js.map +2 -2
- package/dist/util/timing.d.ts +36 -0
- package/dist/util/timing.d.ts.map +1 -0
- package/dist/util/timing.interface.d.ts +47 -0
- package/dist/util/timing.interface.d.ts.map +1 -0
- package/dist/util/timing.interface.js +1 -0
- package/dist/util/timing.interface.js.map +7 -0
- package/dist/util/timing.js +98 -0
- package/dist/util/timing.js.map +7 -0
- package/dist/util/url.js +1 -1
- package/dist/util/url.js.map +2 -2
- package/dist/webserver/controller/base.d.ts +3 -1
- package/dist/webserver/controller/base.d.ts.map +1 -1
- package/dist/webserver/controller/base.interface.d.ts +2 -0
- package/dist/webserver/controller/base.interface.d.ts.map +1 -1
- package/dist/webserver/controller/base.js +4 -1
- package/dist/webserver/controller/base.js.map +2 -2
- package/dist/webserver/controller/health.d.ts +8 -1
- package/dist/webserver/controller/health.d.ts.map +1 -1
- package/dist/webserver/controller/health.js +36 -22
- package/dist/webserver/controller/health.js.map +2 -2
- package/dist/webserver/webserver.d.ts +16 -2
- package/dist/webserver/webserver.d.ts.map +1 -1
- package/dist/webserver/webserver.interface.d.ts +37 -0
- package/dist/webserver/webserver.interface.d.ts.map +1 -1
- package/dist/webserver/webserver.interface.js.map +2 -2
- package/dist/webserver/webserver.js +117 -20
- package/dist/webserver/webserver.js.map +2 -2
- package/dist/websocket/controllers/server/system.d.ts.map +1 -1
- package/dist/websocket/controllers/server/system.js.map +2 -2
- package/dist/websocket/websocket-base.d.ts.map +1 -1
- package/dist/websocket/websocket-base.js +2 -3
- package/dist/websocket/websocket-base.js.map +2 -2
- package/dist/websocket/websocket-server.d.ts +1 -1
- package/dist/websocket/websocket-server.d.ts.map +1 -1
- package/dist/websocket/websocket-server.js +7 -31
- package/dist/websocket/websocket-server.js.map +2 -2
- package/package.json +68 -25
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/application/web-application.ts"],
|
|
4
|
-
"sourcesContent": ["import type RedisInstance from '../redis/instance.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport WebServer from '../webserver/webserver.js';\nimport type QueueManager from '../queue/manager.js';\nimport BaseApplication from './base-application.js';\nimport type { WebApplicationConfig } from './web-application.interface.js';\nimport { Helper, Time } from '../util/index.js';\nimport { Logger } from '../logger/index.js';\nimport WebSocketServer from '../websocket/websocket-server.js';\nimport WebSocketClient from '../websocket/websocket-client.js';\nimport type EventManager from '../event/manager.js';\nimport { WebServerPerformanceWrapper, WebSocketPerformanceWrapper } from '../performance/index.js';\n\n/**\n * Application\n */\nexport default class WebApplication extends BaseApplication {\n /** Web application config */\n protected config: WebApplicationConfig;\n\n /** Web server */\n public webServer?: WebServer;\n\n /** WebSocket server */\n public webSocketServer?: WebSocketServer;\n\n /** WebSocket client */\n public webSocketClient?: WebSocketClient;\n\n constructor(config: WebApplicationConfig) {\n super(config);\n\n const defaultConfig: Partial<WebApplicationConfig> = {\n log: {\n startUp: true,\n },\n };\n\n const mergedConfig = Helper.defaultsDeep(config, defaultConfig);\n\n this.config = mergedConfig;\n }\n\n protected async startHandler({\n redisInstance,\n databaseInstance,\n queueManager,\n eventManager,\n }: {\n redisInstance: RedisInstance;\n databaseInstance: DatabaseInstance;\n queueManager: QueueManager;\n eventManager: EventManager;\n }): Promise<void> {\n if (this.config.webServer?.enabled) {\n // Initialize web server\n this.webServer = new WebServer({\n applicationConfig: this.config,\n
|
|
5
|
-
"mappings": ";;AAEA,OAAO,eAAe;AAEtB,OAAO,qBAAqB;AAE5B,SAAS,QAAQ,YAAY;AAC7B,SAAS,cAAc;AACvB,OAAO,qBAAqB;AAC5B,OAAO,qBAAqB;AAE5B,SAAS,6BAA6B,mCAAmC;AAKzE,MAAO,uBAAqC,gBAAgB;AAAA,EAhB5D,OAgB4D;AAAA;AAAA;AAAA;AAAA,EAEhD;AAAA;AAAA,EAGH;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA,EAEP,YAAY,QAA8B;AACxC,UAAM,MAAM;AAEZ,UAAM,gBAA+C;AAAA,MACnD,KAAK;AAAA,QACH,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,eAAe,OAAO,aAAa,QAAQ,aAAa;AAE9D,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAgB,aAAa;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKkB;AAChB,QAAI,KAAK,OAAO,WAAW,SAAS;AAElC,WAAK,YAAY,IAAI,UAAU;AAAA,QAC7B,mBAAmB,KAAK;AAAA
|
|
4
|
+
"sourcesContent": ["import type RedisInstance from '../redis/instance.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport WebServer from '../webserver/webserver.js';\nimport type QueueManager from '../queue/manager.js';\nimport BaseApplication from './base-application.js';\nimport type { WebApplicationConfig } from './web-application.interface.js';\nimport { Helper, Time } from '../util/index.js';\nimport { Logger } from '../logger/index.js';\nimport WebSocketServer from '../websocket/websocket-server.js';\nimport WebSocketClient from '../websocket/websocket-client.js';\nimport type EventManager from '../event/manager.js';\nimport { WebServerPerformanceWrapper, WebSocketPerformanceWrapper } from '../performance/index.js';\n\n/**\n * Application\n */\nexport default class WebApplication extends BaseApplication {\n /** Web application config */\n protected config: WebApplicationConfig;\n\n /** Web server */\n public webServer?: WebServer;\n\n /** WebSocket server */\n public webSocketServer?: WebSocketServer;\n\n /** WebSocket client */\n public webSocketClient?: WebSocketClient;\n\n constructor(config: WebApplicationConfig) {\n super(config);\n\n const defaultConfig: Partial<WebApplicationConfig> = {\n log: {\n startUp: true,\n },\n };\n\n const mergedConfig = Helper.defaultsDeep(config, defaultConfig);\n\n this.config = mergedConfig;\n }\n\n protected async startHandler({\n redisInstance,\n databaseInstance,\n queueManager,\n eventManager,\n }: {\n redisInstance: RedisInstance;\n databaseInstance: DatabaseInstance;\n queueManager: QueueManager;\n eventManager: EventManager;\n }): Promise<void> {\n if (this.config.webServer?.enabled) {\n // Initialize web server\n this.webServer = new WebServer({\n applicationConfig: this.config,\n options: {\n host: this.config.webServer.host,\n port: this.config.webServer.port,\n controllersDirectory: this.config.webServer.controllersDirectory,\n cors: this.config.webServer.cors,\n log: this.config.webServer.log,\n debug: this.config.webServer.debug,\n },\n\n routes: this.config.webServer.routes,\n\n redisInstance,\n databaseInstance,\n queueManager,\n eventManager,\n lifecycleManager: this.lifecycle,\n });\n\n // Set up performance monitoring for web server\n if (this.performanceMonitor && this.config.performanceMonitoring?.monitorHttpRequests !== false) {\n WebServerPerformanceWrapper.setPerformanceMonitor(this.performanceMonitor);\n }\n\n // Load web server\n await this.webServer.load();\n\n // Start web server\n await this.webServer.start();\n\n // Register readiness check for web server\n this.lifecycle.addReadinessCheck('webserver', async () => {\n try {\n return this.webServer?.isReady() ?? false;\n } catch {\n return false;\n }\n });\n }\n\n if (this.config.webSocket?.enabled) {\n if (!this.webServer) {\n throw new Error('WebSocket requires web server to be enabled');\n }\n\n let webSocketServer: WebSocketServer | undefined;\n let webSocketClient: WebSocketClient | undefined;\n\n switch (this.config.webSocket.type) {\n case 'server': {\n // Initialize WebSocket server\n webSocketServer = new WebSocketServer({\n uniqueInstanceId: this.uniqueInstanceId,\n applicationConfig: this.config,\n options: this.config.webSocket,\n redisInstance,\n databaseInstance,\n queueManager,\n routes: this.config.webSocket.routes,\n workerId: this.workerId,\n });\n\n // Set up performance monitoring for WebSocket\n if (this.performanceMonitor && this.config.performanceMonitoring?.monitorWebSocketOperations !== false) {\n WebSocketPerformanceWrapper.setPerformanceMonitor(this.performanceMonitor);\n }\n\n // Load WebSocket client\n await webSocketServer.load();\n\n // Start WebSocket server\n await webSocketServer.start({\n fastifyServer: this.webServer.fastifyServer,\n });\n\n break;\n }\n case 'client': {\n // Initialize WebSocket client\n webSocketClient = new WebSocketClient({\n applicationConfig: this.config,\n options: this.config.webSocket,\n redisInstance,\n databaseInstance,\n queueManager,\n routes: this.config.webSocket.routes,\n });\n\n // Load WebSocket client\n await webSocketClient.load();\n\n // Connect to WebSocket server\n await webSocketClient.connectToServer();\n\n break;\n }\n default: {\n if (!this.config.webSocket.type) {\n throw new Error('WebSocket type is required');\n } else {\n throw new Error(`WebSocket type is not supported (Type: ${this.config.webSocket.type})`);\n }\n }\n }\n\n this.webSocketServer = webSocketServer;\n this.webSocketClient = webSocketClient;\n }\n }\n\n /**\n * Stop application callback\n */\n protected async stopCallback(): Promise<void> {\n if (this.webServer) {\n // Stop web server\n await this.webServer.stop();\n }\n\n if (this.webSocketServer) {\n // Stop WebSocket server\n await this.webSocketServer.stop();\n }\n }\n\n /**\n * Application started event\n */\n protected async onStarted({ startupTime }: { startupTime: number }): Promise<void> {\n if (this.config.log?.startUp) {\n Logger.info({\n message: 'Application started',\n meta: {\n Name: this.config.name,\n 'Instance ID': this.config.instanceId,\n 'PXL Framework Version': this.applicationVersion,\n 'Startup Time': Time.formatTime({\n time: startupTime,\n format: 's',\n numDecimals: 2,\n showUnit: true,\n }),\n },\n });\n }\n\n if (this.config.events?.onStarted) {\n this.config.events.onStarted({\n app: this,\n startupTime,\n });\n }\n }\n\n protected async onStopped({ runtime }: { runtime: number }): Promise<void> {\n if (this.config.log?.shutdown) {\n Logger.info({\n message: 'Application stopped',\n meta: {\n Name: this.config.name,\n 'Instance ID': this.config.instanceId,\n Runtime: Time.formatTime({\n time: runtime,\n format: 's',\n numDecimals: 2,\n showUnit: true,\n }),\n },\n });\n }\n\n if (this.config.events?.onStopped) {\n this.config.events.onStopped({ app: this, runtime });\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/cache/manager.d.ts
CHANGED
|
@@ -1,26 +1,107 @@
|
|
|
1
|
-
import type { ApplicationConfig } from '../application/base-application.interface.js';
|
|
2
1
|
import type RedisManager from '../redis/manager.js';
|
|
2
|
+
/**
|
|
3
|
+
* CacheManager
|
|
4
|
+
*
|
|
5
|
+
* Thin abstraction over Redis for basic JSON value caching. Unifies all Redis
|
|
6
|
+
* access through the framework RedisManager / RedisInstance (ioredis) so we
|
|
7
|
+
* avoid maintaining a second client implementation (node-redis).
|
|
8
|
+
*
|
|
9
|
+
* Lazy acquisition: the first call to any cache method will either reuse an
|
|
10
|
+
* existing connected RedisInstance (if already established by application
|
|
11
|
+
* startup) or trigger a connection via RedisManager.
|
|
12
|
+
*
|
|
13
|
+
* **Important:** All values are stored as JSON strings. Only JSON-serializable
|
|
14
|
+
* values are supported. Complex types like Date, Map, Set, RegExp, etc. will
|
|
15
|
+
* lose their type information during serialization:
|
|
16
|
+
* - `Date` objects → ISO strings
|
|
17
|
+
* - `Map` / `Set` → empty objects `{}`
|
|
18
|
+
* - `undefined` → omitted from objects, `null` in arrays
|
|
19
|
+
* - Functions → omitted
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // Supported types
|
|
24
|
+
* await cache.setItem({ key: 'user', value: { id: 1, name: 'John' } }); // ✓
|
|
25
|
+
* await cache.setItem({ key: 'count', value: 42 }); // ✓
|
|
26
|
+
* await cache.setItem({ key: 'tags', value: ['a', 'b', 'c'] }); // ✓
|
|
27
|
+
*
|
|
28
|
+
* // Unsupported types (will lose type information)
|
|
29
|
+
* await cache.setItem({ key: 'date', value: new Date() }); // → ISO string
|
|
30
|
+
* await cache.setItem({ key: 'map', value: new Map() }); // → {}
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
3
33
|
export interface CacheManagerProps {
|
|
4
|
-
|
|
34
|
+
/** Redis manager (shared across the application) */
|
|
5
35
|
redisManager: RedisManager;
|
|
6
36
|
}
|
|
7
37
|
export default class CacheManager {
|
|
8
|
-
private client?;
|
|
9
|
-
private applicationConfig;
|
|
10
38
|
private redisManager;
|
|
11
|
-
|
|
12
|
-
|
|
39
|
+
private redisInstance?;
|
|
40
|
+
constructor({ redisManager }: CacheManagerProps);
|
|
41
|
+
/**
|
|
42
|
+
* Ensure we have a connected RedisInstance. Reuses the first existing
|
|
43
|
+
* instance if already connected by the application bootstrap.
|
|
44
|
+
*/
|
|
45
|
+
private getRedisInstance;
|
|
46
|
+
/**
|
|
47
|
+
* Get a cached JSON value (deserialized) or null if not present.
|
|
48
|
+
*
|
|
49
|
+
* @param key - Cache key
|
|
50
|
+
* @returns Deserialized value or null if not found
|
|
51
|
+
* @throws {Error} If the cached value is not valid JSON
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const user = await cache.getItem<{ id: number; name: string }>({ key: 'user:123' });
|
|
56
|
+
* if (user) {
|
|
57
|
+
* console.log(user.name);
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
13
61
|
getItem<T>({ key }: {
|
|
14
62
|
key: string;
|
|
15
63
|
}): Promise<T | null>;
|
|
64
|
+
/**
|
|
65
|
+
* Set a JSON-serializable value. Optionally specify lifetime (seconds).
|
|
66
|
+
*
|
|
67
|
+
* @param key - Cache key
|
|
68
|
+
* @param value - Value to cache (must be JSON-serializable)
|
|
69
|
+
* @param lifetime - Optional expiration in seconds
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* // Cache with no expiration
|
|
74
|
+
* await cache.setItem({ key: 'config', value: { theme: 'dark' } });
|
|
75
|
+
*
|
|
76
|
+
* // Cache with 1 hour expiration
|
|
77
|
+
* await cache.setItem({
|
|
78
|
+
* key: 'session:abc',
|
|
79
|
+
* value: { userId: 123 },
|
|
80
|
+
* lifetime: 3600
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
16
84
|
setItem<T>({ key, value, lifetime }: {
|
|
17
85
|
key: string;
|
|
18
86
|
value: T;
|
|
19
87
|
lifetime?: number;
|
|
20
88
|
}): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Delete a cached value.
|
|
91
|
+
*
|
|
92
|
+
* @param key - Cache key to delete
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* await cache.clearItem({ key: 'session:abc' });
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
21
99
|
clearItem({ key }: {
|
|
22
100
|
key: string;
|
|
23
101
|
}): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* No-op: lifecycle handles Redis disconnection globally.
|
|
104
|
+
*/
|
|
24
105
|
close(): Promise<void>;
|
|
25
106
|
}
|
|
26
107
|
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/cache/manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/cache/manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AAGpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,MAAM,WAAW,iBAAiB;IAChC,oDAAoD;IACpD,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,aAAa,CAAC,CAAgB;gBAE1B,EAAE,YAAY,EAAE,EAAE,iBAAiB;IAI/C;;;OAGG;YACW,gBAAgB;IAa9B;;;;;;;;;;;;;;OAcG;IACU,OAAO,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAkBpE;;;;;;;;;;;;;;;;;;;OAmBG;IACU,OAAO,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9G;;;;;;;;;OASG;IACU,SAAS,CAAC,EAAE,GAAG,EAAE,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/D;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGpC"}
|
package/dist/cache/manager.js
CHANGED
|
@@ -1,51 +1,98 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
-
import { createClient } from "redis";
|
|
4
3
|
class CacheManager {
|
|
5
4
|
static {
|
|
6
5
|
__name(this, "CacheManager");
|
|
7
6
|
}
|
|
8
|
-
client;
|
|
9
|
-
applicationConfig;
|
|
10
7
|
redisManager;
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
redisInstance;
|
|
9
|
+
constructor({ redisManager }) {
|
|
13
10
|
this.redisManager = redisManager;
|
|
14
11
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Ensure we have a connected RedisInstance. Reuses the first existing
|
|
14
|
+
* instance if already connected by the application bootstrap.
|
|
15
|
+
*/
|
|
16
|
+
async getRedisInstance() {
|
|
17
|
+
if (this.redisInstance) return this.redisInstance;
|
|
18
|
+
if (this.redisManager.instances.length > 0) {
|
|
19
|
+
this.redisInstance = this.redisManager.instances[0];
|
|
20
|
+
return this.redisInstance;
|
|
24
21
|
}
|
|
25
|
-
|
|
22
|
+
this.redisInstance = await this.redisManager.connect();
|
|
23
|
+
return this.redisInstance;
|
|
26
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Get a cached JSON value (deserialized) or null if not present.
|
|
27
|
+
*
|
|
28
|
+
* @param key - Cache key
|
|
29
|
+
* @returns Deserialized value or null if not found
|
|
30
|
+
* @throws {Error} If the cached value is not valid JSON
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const user = await cache.getItem<{ id: number; name: string }>({ key: 'user:123' });
|
|
35
|
+
* if (user) {
|
|
36
|
+
* console.log(user.name);
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
27
40
|
async getItem({ key }) {
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
41
|
+
const instance = await this.getRedisInstance();
|
|
42
|
+
const raw = await instance.getCache({ key });
|
|
43
|
+
if (raw === null) return null;
|
|
44
|
+
if (typeof raw !== "string") {
|
|
45
|
+
throw new Error(`Cache value for key "${key}" must be a string, got ${typeof raw}`);
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(raw);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
51
|
+
throw new Error(`Failed to parse cached value for key "${key}": ${errorMessage}`);
|
|
52
|
+
}
|
|
31
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Set a JSON-serializable value. Optionally specify lifetime (seconds).
|
|
56
|
+
*
|
|
57
|
+
* @param key - Cache key
|
|
58
|
+
* @param value - Value to cache (must be JSON-serializable)
|
|
59
|
+
* @param lifetime - Optional expiration in seconds
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* // Cache with no expiration
|
|
64
|
+
* await cache.setItem({ key: 'config', value: { theme: 'dark' } });
|
|
65
|
+
*
|
|
66
|
+
* // Cache with 1 hour expiration
|
|
67
|
+
* await cache.setItem({
|
|
68
|
+
* key: 'session:abc',
|
|
69
|
+
* value: { userId: 123 },
|
|
70
|
+
* lifetime: 3600
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
32
74
|
async setItem({ key, value, lifetime }) {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
if (lifetime) {
|
|
36
|
-
await client.setEx(key, lifetime, stringValue);
|
|
37
|
-
} else {
|
|
38
|
-
await client.set(key, stringValue);
|
|
39
|
-
}
|
|
75
|
+
const instance = await this.getRedisInstance();
|
|
76
|
+
await instance.setCache({ key, value, expiration: lifetime });
|
|
40
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Delete a cached value.
|
|
80
|
+
*
|
|
81
|
+
* @param key - Cache key to delete
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* await cache.clearItem({ key: 'session:abc' });
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
41
88
|
async clearItem({ key }) {
|
|
42
|
-
const
|
|
43
|
-
await
|
|
89
|
+
const instance = await this.getRedisInstance();
|
|
90
|
+
await instance.deleteCache({ key });
|
|
44
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* No-op: lifecycle handles Redis disconnection globally.
|
|
94
|
+
*/
|
|
45
95
|
async close() {
|
|
46
|
-
if (this.client) {
|
|
47
|
-
await this.client.quit();
|
|
48
|
-
}
|
|
49
96
|
}
|
|
50
97
|
}
|
|
51
98
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/cache/manager.ts"],
|
|
4
|
-
"sourcesContent": ["import
|
|
5
|
-
"mappings": ";;
|
|
4
|
+
"sourcesContent": ["import type RedisManager from '../redis/manager.js';\nimport type RedisInstance from '../redis/instance.js';\n\n/**\n * CacheManager\n *\n * Thin abstraction over Redis for basic JSON value caching. Unifies all Redis\n * access through the framework RedisManager / RedisInstance (ioredis) so we\n * avoid maintaining a second client implementation (node-redis).\n *\n * Lazy acquisition: the first call to any cache method will either reuse an\n * existing connected RedisInstance (if already established by application\n * startup) or trigger a connection via RedisManager.\n *\n * **Important:** All values are stored as JSON strings. Only JSON-serializable\n * values are supported. Complex types like Date, Map, Set, RegExp, etc. will\n * lose their type information during serialization:\n * - `Date` objects \u2192 ISO strings\n * - `Map` / `Set` \u2192 empty objects `{}`\n * - `undefined` \u2192 omitted from objects, `null` in arrays\n * - Functions \u2192 omitted\n *\n * @example\n * ```typescript\n * // Supported types\n * await cache.setItem({ key: 'user', value: { id: 1, name: 'John' } }); // \u2713\n * await cache.setItem({ key: 'count', value: 42 }); // \u2713\n * await cache.setItem({ key: 'tags', value: ['a', 'b', 'c'] }); // \u2713\n *\n * // Unsupported types (will lose type information)\n * await cache.setItem({ key: 'date', value: new Date() }); // \u2192 ISO string\n * await cache.setItem({ key: 'map', value: new Map() }); // \u2192 {}\n * ```\n */\n\nexport interface CacheManagerProps {\n /** Redis manager (shared across the application) */\n redisManager: RedisManager;\n}\n\nexport default class CacheManager {\n private redisManager: RedisManager;\n private redisInstance?: RedisInstance;\n\n constructor({ redisManager }: CacheManagerProps) {\n this.redisManager = redisManager;\n }\n\n /**\n * Ensure we have a connected RedisInstance. Reuses the first existing\n * instance if already connected by the application bootstrap.\n */\n private async getRedisInstance(): Promise<RedisInstance> {\n if (this.redisInstance) return this.redisInstance;\n\n if (this.redisManager.instances.length > 0) {\n this.redisInstance = this.redisManager.instances[0];\n return this.redisInstance;\n }\n\n // Lazily connect if no instances yet (e.g., used before app onBeforeStart)\n this.redisInstance = await this.redisManager.connect();\n return this.redisInstance;\n }\n\n /**\n * Get a cached JSON value (deserialized) or null if not present.\n *\n * @param key - Cache key\n * @returns Deserialized value or null if not found\n * @throws {Error} If the cached value is not valid JSON\n *\n * @example\n * ```typescript\n * const user = await cache.getItem<{ id: number; name: string }>({ key: 'user:123' });\n * if (user) {\n * console.log(user.name);\n * }\n * ```\n */\n public async getItem<T>({ key }: { key: string }): Promise<T | null> {\n const instance = await this.getRedisInstance();\n const raw = await instance.getCache({ key });\n if (raw === null) return null;\n\n // Validate that we received a string (Redis should always return string or null)\n if (typeof raw !== 'string') {\n throw new Error(`Cache value for key \"${key}\" must be a string, got ${typeof raw}`);\n }\n\n try {\n return JSON.parse(raw) as T;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to parse cached value for key \"${key}\": ${errorMessage}`);\n }\n }\n\n /**\n * Set a JSON-serializable value. Optionally specify lifetime (seconds).\n *\n * @param key - Cache key\n * @param value - Value to cache (must be JSON-serializable)\n * @param lifetime - Optional expiration in seconds\n *\n * @example\n * ```typescript\n * // Cache with no expiration\n * await cache.setItem({ key: 'config', value: { theme: 'dark' } });\n *\n * // Cache with 1 hour expiration\n * await cache.setItem({\n * key: 'session:abc',\n * value: { userId: 123 },\n * lifetime: 3600\n * });\n * ```\n */\n public async setItem<T>({ key, value, lifetime }: { key: string; value: T; lifetime?: number }): Promise<void> {\n const instance = await this.getRedisInstance();\n await instance.setCache({ key, value, expiration: lifetime });\n }\n\n /**\n * Delete a cached value.\n *\n * @param key - Cache key to delete\n *\n * @example\n * ```typescript\n * await cache.clearItem({ key: 'session:abc' });\n * ```\n */\n public async clearItem({ key }: { key: string }): Promise<void> {\n const instance = await this.getRedisInstance();\n await instance.deleteCache({ key });\n }\n\n /**\n * No-op: lifecycle handles Redis disconnection globally.\n */\n public async close(): Promise<void> {\n // Intentionally empty; RedisManager handles disconnect.\n }\n}\n"],
|
|
5
|
+
"mappings": ";;AAwCA,MAAO,aAA2B;AAAA,EAxClC,OAwCkC;AAAA;AAAA;AAAA,EACxB;AAAA,EACA;AAAA,EAER,YAAY,EAAE,aAAa,GAAsB;AAC/C,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBAA2C;AACvD,QAAI,KAAK,cAAe,QAAO,KAAK;AAEpC,QAAI,KAAK,aAAa,UAAU,SAAS,GAAG;AAC1C,WAAK,gBAAgB,KAAK,aAAa,UAAU,CAAC;AAClD,aAAO,KAAK;AAAA,IACd;AAGA,SAAK,gBAAgB,MAAM,KAAK,aAAa,QAAQ;AACrD,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAa,QAAW,EAAE,IAAI,GAAuC;AACnE,UAAM,WAAW,MAAM,KAAK,iBAAiB;AAC7C,UAAM,MAAM,MAAM,SAAS,SAAS,EAAE,IAAI,CAAC;AAC3C,QAAI,QAAQ,KAAM,QAAO;AAGzB,QAAI,OAAO,QAAQ,UAAU;AAC3B,YAAM,IAAI,MAAM,wBAAwB,GAAG,2BAA2B,OAAO,GAAG,EAAE;AAAA,IACpF;AAEA,QAAI;AACF,aAAO,KAAK,MAAM,GAAG;AAAA,IACvB,SAAS,OAAO;AACd,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,YAAM,IAAI,MAAM,yCAAyC,GAAG,MAAM,YAAY,EAAE;AAAA,IAClF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,MAAa,QAAW,EAAE,KAAK,OAAO,SAAS,GAAgE;AAC7G,UAAM,WAAW,MAAM,KAAK,iBAAiB;AAC7C,UAAM,SAAS,SAAS,EAAE,KAAK,OAAO,YAAY,SAAS,CAAC;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAa,UAAU,EAAE,IAAI,GAAmC;AAC9D,UAAM,WAAW,MAAM,KAAK,iBAAiB;AAC7C,UAAM,SAAS,YAAY,EAAE,IAAI,CAAC;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,QAAuB;AAAA,EAEpC;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cluster-manager.d.ts","sourceRoot":"","sources":["../../src/cluster/cluster-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,mBAAmB,EAEpB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"cluster-manager.d.ts","sourceRoot":"","sources":["../../src/cluster/cluster-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,mBAAmB,EAEpB,MAAM,gCAAgC,CAAC;AAIxC,MAAM,CAAC,OAAO,OAAO,cAAc;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAE9C,OAAO,CAAC,wBAAwB,CAAsB;IACtD,OAAO,CAAC,uBAAuB,CAAsB;IAErD,OAAO,CAAC,eAAe,CAA2C;IAClE,OAAO,CAAC,cAAc,CAAS;gBAEnB,EAAE,MAAM,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,EAAE,mBAAmB;IAOvF,KAAK,IAAI,IAAI;IAUpB,OAAO,CAAC,YAAY;YAqCN,WAAW;IAkBzB,OAAO,CAAC,cAAc;YAMR,gBAAgB;CA6B/B"}
|
|
@@ -3,6 +3,7 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
3
3
|
import cluster from "node:cluster";
|
|
4
4
|
import { cpus } from "node:os";
|
|
5
5
|
import { Logger } from "../logger/index.js";
|
|
6
|
+
import { requestExit } from "../lifecycle/exit.js";
|
|
6
7
|
class ClusterManager {
|
|
7
8
|
static {
|
|
8
9
|
__name(this, "ClusterManager");
|
|
@@ -79,20 +80,17 @@ class ClusterManager {
|
|
|
79
80
|
}
|
|
80
81
|
this.isShuttingDown = true;
|
|
81
82
|
if (cluster.isPrimary) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
continue;
|
|
83
|
+
Object.values(cluster.workers ?? {}).forEach((worker) => {
|
|
84
|
+
if (worker) {
|
|
85
|
+
worker.send("shutdown");
|
|
86
86
|
}
|
|
87
|
-
|
|
88
|
-
}
|
|
87
|
+
});
|
|
89
88
|
let exitedWorkers = 0;
|
|
90
89
|
cluster.on("exit", () => {
|
|
91
90
|
exitedWorkers++;
|
|
92
|
-
const
|
|
93
|
-
const numClusterWorkers = Object.keys(clusterWorkers).length;
|
|
91
|
+
const numClusterWorkers = Object.values(cluster.workers ?? {}).filter(Boolean).length;
|
|
94
92
|
if (exitedWorkers === numClusterWorkers) {
|
|
95
|
-
|
|
93
|
+
requestExit({ code: 0, reason: "cluster-workers-exited" });
|
|
96
94
|
}
|
|
97
95
|
});
|
|
98
96
|
} else {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/cluster/cluster-manager.ts"],
|
|
4
|
-
"sourcesContent": ["import cluster from 'node:cluster';\nimport { cpus } from 'node:os';\nimport type {\n ClusterManagerConfig,\n ClusterManagerProps,\n ClusterManagerWorkerModeManualConfig,\n} from './cluster-manager.interface.js';\nimport { Logger } from '../logger/index.js';\n\nexport default class ClusterManager {\n private readonly config: ClusterManagerConfig;\n\n private startApplicationCallback: () => Promise<void>;\n private stopApplicationCallback: () => Promise<void>;\n\n private shutdownSignals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];\n private isShuttingDown = false;\n\n constructor({ config, startApplicationCallback, stopApplicationCallback }: ClusterManagerProps) {\n this.config = config;\n\n this.startApplicationCallback = startApplicationCallback;\n this.stopApplicationCallback = stopApplicationCallback;\n }\n\n public start(): void {\n if (cluster.isPrimary) {\n this.setupPrimary();\n } else {\n this.setupWorker();\n }\n\n this.handleShutdown();\n }\n\n private setupPrimary(): void {\n const numCPUs: number = cpus().length;\n\n const numClusterWorkers =\n this.config.workerMode === 'auto' ? numCPUs : (this.config as ClusterManagerWorkerModeManualConfig).workerCount;\n\n for (let workerIndex = 0; workerIndex < numClusterWorkers; workerIndex++) {\n cluster.fork();\n }\n\n cluster.on('online', worker => {\n Logger.debug({\n message: 'Started cluster worker',\n meta: {\n ID: worker.id,\n PID: worker.process.pid,\n },\n });\n });\n\n cluster.on('exit', () => {\n if (!this.isShuttingDown) {\n // Restart worker on unexpected exit\n cluster.fork();\n }\n });\n\n Logger.debug({\n message: 'Started cluster master',\n meta: {\n Mode: this.config.workerMode,\n 'Worker Count': numClusterWorkers,\n CPUs: numCPUs,\n },\n });\n }\n\n private async setupWorker(): Promise<void> {\n await this.startApplicationCallback();\n\n process.on('message', async message => {\n if (message === 'shutdown') {\n Logger.debug({\n message: 'Worker received shutdown message, stopping...',\n meta: {\n PID: process.pid,\n },\n });\n\n // Stop application\n await this.stopApplicationCallback();\n }\n });\n }\n\n private handleShutdown(): void {\n this.shutdownSignals.forEach(signal => {\n process.on(signal, async () => await this.initiateShutdown());\n });\n }\n\n private async initiateShutdown(): Promise<void> {\n if (this.isShuttingDown) {\n return;\n }\n\n this.isShuttingDown = true;\n\n if (cluster.isPrimary) {\n
|
|
5
|
-
"mappings": ";;AAAA,OAAO,aAAa;AACpB,SAAS,YAAY;AAMrB,SAAS,cAAc;
|
|
4
|
+
"sourcesContent": ["import cluster from 'node:cluster';\nimport { cpus } from 'node:os';\nimport type {\n ClusterManagerConfig,\n ClusterManagerProps,\n ClusterManagerWorkerModeManualConfig,\n} from './cluster-manager.interface.js';\nimport { Logger } from '../logger/index.js';\nimport { requestExit } from '../lifecycle/exit.js';\n\nexport default class ClusterManager {\n private readonly config: ClusterManagerConfig;\n\n private startApplicationCallback: () => Promise<void>;\n private stopApplicationCallback: () => Promise<void>;\n\n private shutdownSignals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];\n private isShuttingDown = false;\n\n constructor({ config, startApplicationCallback, stopApplicationCallback }: ClusterManagerProps) {\n this.config = config;\n\n this.startApplicationCallback = startApplicationCallback;\n this.stopApplicationCallback = stopApplicationCallback;\n }\n\n public start(): void {\n if (cluster.isPrimary) {\n this.setupPrimary();\n } else {\n this.setupWorker();\n }\n\n this.handleShutdown();\n }\n\n private setupPrimary(): void {\n const numCPUs: number = cpus().length;\n\n const numClusterWorkers =\n this.config.workerMode === 'auto' ? numCPUs : (this.config as ClusterManagerWorkerModeManualConfig).workerCount;\n\n for (let workerIndex = 0; workerIndex < numClusterWorkers; workerIndex++) {\n cluster.fork();\n }\n\n cluster.on('online', worker => {\n Logger.debug({\n message: 'Started cluster worker',\n meta: {\n ID: worker.id,\n PID: worker.process.pid,\n },\n });\n });\n\n cluster.on('exit', () => {\n if (!this.isShuttingDown) {\n // Restart worker on unexpected exit\n cluster.fork();\n }\n });\n\n Logger.debug({\n message: 'Started cluster master',\n meta: {\n Mode: this.config.workerMode,\n 'Worker Count': numClusterWorkers,\n CPUs: numCPUs,\n },\n });\n }\n\n private async setupWorker(): Promise<void> {\n await this.startApplicationCallback();\n\n process.on('message', async message => {\n if (message === 'shutdown') {\n Logger.debug({\n message: 'Worker received shutdown message, stopping...',\n meta: {\n PID: process.pid,\n },\n });\n\n // Stop application\n await this.stopApplicationCallback();\n }\n });\n }\n\n private handleShutdown(): void {\n this.shutdownSignals.forEach(signal => {\n process.on(signal, async () => await this.initiateShutdown());\n });\n }\n\n private async initiateShutdown(): Promise<void> {\n if (this.isShuttingDown) {\n return;\n }\n\n this.isShuttingDown = true;\n\n if (cluster.isPrimary) {\n Object.values(cluster.workers ?? {}).forEach(worker => {\n if (worker) {\n worker.send('shutdown');\n }\n });\n\n let exitedWorkers = 0;\n\n cluster.on('exit', () => {\n exitedWorkers++;\n\n const numClusterWorkers = Object.values(cluster.workers ?? {}).filter(Boolean).length;\n\n if (exitedWorkers === numClusterWorkers) {\n requestExit({ code: 0, reason: 'cluster-workers-exited' });\n }\n });\n } else {\n await this.stopApplicationCallback();\n }\n }\n}\n"],
|
|
5
|
+
"mappings": ";;AAAA,OAAO,aAAa;AACpB,SAAS,YAAY;AAMrB,SAAS,cAAc;AACvB,SAAS,mBAAmB;AAE5B,MAAO,eAA6B;AAAA,EAVpC,OAUoC;AAAA;AAAA;AAAA,EACjB;AAAA,EAET;AAAA,EACA;AAAA,EAEA,kBAAoC,CAAC,WAAW,QAAQ;AAAA,EACxD,iBAAiB;AAAA,EAEzB,YAAY,EAAE,QAAQ,0BAA0B,wBAAwB,GAAwB;AAC9F,SAAK,SAAS;AAEd,SAAK,2BAA2B;AAChC,SAAK,0BAA0B;AAAA,EACjC;AAAA,EAEO,QAAc;AACnB,QAAI,QAAQ,WAAW;AACrB,WAAK,aAAa;AAAA,IACpB,OAAO;AACL,WAAK,YAAY;AAAA,IACnB;AAEA,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,eAAqB;AAC3B,UAAM,UAAkB,KAAK,EAAE;AAE/B,UAAM,oBACJ,KAAK,OAAO,eAAe,SAAS,UAAW,KAAK,OAAgD;AAEtG,aAAS,cAAc,GAAG,cAAc,mBAAmB,eAAe;AACxE,cAAQ,KAAK;AAAA,IACf;AAEA,YAAQ,GAAG,UAAU,YAAU;AAC7B,aAAO,MAAM;AAAA,QACX,SAAS;AAAA,QACT,MAAM;AAAA,UACJ,IAAI,OAAO;AAAA,UACX,KAAK,OAAO,QAAQ;AAAA,QACtB;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,YAAQ,GAAG,QAAQ,MAAM;AACvB,UAAI,CAAC,KAAK,gBAAgB;AAExB,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AAAA,MACX,SAAS;AAAA,MACT,MAAM;AAAA,QACJ,MAAM,KAAK,OAAO;AAAA,QAClB,gBAAgB;AAAA,QAChB,MAAM;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,cAA6B;AACzC,UAAM,KAAK,yBAAyB;AAEpC,YAAQ,GAAG,WAAW,OAAM,YAAW;AACrC,UAAI,YAAY,YAAY;AAC1B,eAAO,MAAM;AAAA,UACX,SAAS;AAAA,UACT,MAAM;AAAA,YACJ,KAAK,QAAQ;AAAA,UACf;AAAA,QACF,CAAC;AAGD,cAAM,KAAK,wBAAwB;AAAA,MACrC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,iBAAuB;AAC7B,SAAK,gBAAgB,QAAQ,YAAU;AACrC,cAAQ,GAAG,QAAQ,YAAY,MAAM,KAAK,iBAAiB,CAAC;AAAA,IAC9D,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,mBAAkC;AAC9C,QAAI,KAAK,gBAAgB;AACvB;AAAA,IACF;AAEA,SAAK,iBAAiB;AAEtB,QAAI,QAAQ,WAAW;AACrB,aAAO,OAAO,QAAQ,WAAW,CAAC,CAAC,EAAE,QAAQ,YAAU;AACrD,YAAI,QAAQ;AACV,iBAAO,KAAK,UAAU;AAAA,QACxB;AAAA,MACF,CAAC;AAED,UAAI,gBAAgB;AAEpB,cAAQ,GAAG,QAAQ,MAAM;AACvB;AAEA,cAAM,oBAAoB,OAAO,OAAO,QAAQ,WAAW,CAAC,CAAC,EAAE,OAAO,OAAO,EAAE;AAE/E,YAAI,kBAAkB,mBAAmB;AACvC,sBAAY,EAAE,MAAM,GAAG,QAAQ,yBAAyB,CAAC;AAAA,QAC3D;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,YAAM,KAAK,wBAAwB;AAAA,IACrC;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type InferFrameworkConfig } from './schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load a partial framework configuration from environment variables. This is intentionally
|
|
4
|
+
* conservative: only widely useful primitives are supported. Complex structures (e.g. routes)
|
|
5
|
+
* should be defined in code and merged before validation.
|
|
6
|
+
*
|
|
7
|
+
* Naming convention: PXL_<SECTION>_<FIELD>
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadFrameworkConfigFromEnv(): Partial<InferFrameworkConfig>;
|
|
10
|
+
/** Deep merge helper (shallow for primitives & plain objects) */
|
|
11
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/config/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAsBxD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAAC,oBAAoB,CAAC,CA6F1E;AAED,iEAAiE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
function parseBool(v) {
|
|
4
|
+
if (v == null) return void 0;
|
|
5
|
+
return /^(true|1|yes|on)$/i.test(v);
|
|
6
|
+
}
|
|
7
|
+
__name(parseBool, "parseBool");
|
|
8
|
+
function parseIntEnv(v) {
|
|
9
|
+
if (v == null) return void 0;
|
|
10
|
+
const n = Number(v);
|
|
11
|
+
return Number.isFinite(n) ? n : void 0;
|
|
12
|
+
}
|
|
13
|
+
__name(parseIntEnv, "parseIntEnv");
|
|
14
|
+
function splitCsv(v) {
|
|
15
|
+
if (!v) return void 0;
|
|
16
|
+
return v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
17
|
+
}
|
|
18
|
+
__name(splitCsv, "splitCsv");
|
|
19
|
+
function loadFrameworkConfigFromEnv() {
|
|
20
|
+
const env = process.env;
|
|
21
|
+
const redis = {
|
|
22
|
+
host: env.PXL_REDIS_HOST,
|
|
23
|
+
port: parseIntEnv(env.PXL_REDIS_PORT),
|
|
24
|
+
password: env.PXL_REDIS_PASSWORD
|
|
25
|
+
};
|
|
26
|
+
if (!redis.host) delete redis.host;
|
|
27
|
+
if (!redis.port) delete redis.port;
|
|
28
|
+
if (!redis.password) delete redis.password;
|
|
29
|
+
const databaseEnabled = parseBool(env.PXL_DB_ENABLED);
|
|
30
|
+
const database = {
|
|
31
|
+
enabled: databaseEnabled,
|
|
32
|
+
host: env.PXL_DB_HOST,
|
|
33
|
+
port: parseIntEnv(env.PXL_DB_PORT),
|
|
34
|
+
username: env.PXL_DB_USERNAME,
|
|
35
|
+
password: env.PXL_DB_PASSWORD,
|
|
36
|
+
databaseName: env.PXL_DB_NAME,
|
|
37
|
+
entitiesDirectory: env.PXL_DB_ENTITIES_DIR
|
|
38
|
+
};
|
|
39
|
+
const databaseFinal = {
|
|
40
|
+
...database.enabled !== void 0 ? { enabled: database.enabled } : {},
|
|
41
|
+
...database.host ? { host: database.host } : {},
|
|
42
|
+
...database.port !== void 0 ? { port: database.port } : {},
|
|
43
|
+
...database.username ? { username: database.username } : {},
|
|
44
|
+
...database.password ? { password: database.password } : {},
|
|
45
|
+
...database.databaseName ? { databaseName: database.databaseName } : {},
|
|
46
|
+
...database.entitiesDirectory ? { entitiesDirectory: database.entitiesDirectory } : {}
|
|
47
|
+
};
|
|
48
|
+
const hasDatabaseConfig = Object.keys(databaseFinal).length > 0;
|
|
49
|
+
const queueProcessorsDirectory = env.PXL_QUEUE_PROCESSORS_DIR;
|
|
50
|
+
const queueQueues = splitCsv(env.PXL_QUEUE_QUEUES)?.map((name2) => ({ name: name2, jobs: [] }));
|
|
51
|
+
const queue = {};
|
|
52
|
+
if (queueProcessorsDirectory) queue.processorsDirectory = queueProcessorsDirectory;
|
|
53
|
+
if (queueQueues) queue.queues = queueQueues;
|
|
54
|
+
const webEnabled = parseBool(env.PXL_WEB_ENABLED);
|
|
55
|
+
const webCorsEnabled = parseBool(env.PXL_WEB_CORS_ENABLED);
|
|
56
|
+
const webCorsUrls = splitCsv(env.PXL_WEB_CORS_URLS);
|
|
57
|
+
const webBodyLimit = parseIntEnv(env.PXL_WEB_BODY_LIMIT);
|
|
58
|
+
const webPort = parseIntEnv(env.PXL_WEB_PORT);
|
|
59
|
+
const web = {};
|
|
60
|
+
if (webEnabled !== void 0) web.enabled = webEnabled;
|
|
61
|
+
if (env.PXL_WEB_HOST) web.host = env.PXL_WEB_HOST;
|
|
62
|
+
if (webPort !== void 0) web.port = webPort;
|
|
63
|
+
if (webBodyLimit !== void 0) web.bodyLimit = webBodyLimit;
|
|
64
|
+
if (webCorsEnabled || webCorsUrls && webCorsUrls.length > 0) {
|
|
65
|
+
web.cors = { enabled: webCorsEnabled ?? true, urls: webCorsUrls ?? [] };
|
|
66
|
+
}
|
|
67
|
+
const auth = {};
|
|
68
|
+
if (env.PXL_AUTH_JWT_SECRET_KEY) auth.jwtSecretKey = env.PXL_AUTH_JWT_SECRET_KEY;
|
|
69
|
+
const cluster = {};
|
|
70
|
+
const clusterEnabled = parseBool(env.PXL_CLUSTER_ENABLED);
|
|
71
|
+
if (clusterEnabled !== void 0) cluster.enabled = clusterEnabled;
|
|
72
|
+
const clusterWorkers = parseIntEnv(env.PXL_CLUSTER_WORKERS);
|
|
73
|
+
if (clusterWorkers !== void 0) cluster.workers = clusterWorkers;
|
|
74
|
+
if (Object.keys(cluster).length === 0) {
|
|
75
|
+
}
|
|
76
|
+
const performanceMonitoring = {};
|
|
77
|
+
const perfEnabled = parseBool(env.PXL_PERF_ENABLED);
|
|
78
|
+
if (perfEnabled !== void 0) performanceMonitoring.enabled = perfEnabled;
|
|
79
|
+
const perfInterval = parseIntEnv(env.PXL_PERF_REPORT_INTERVAL_MS);
|
|
80
|
+
if (perfInterval !== void 0) performanceMonitoring.reportInterval = perfInterval;
|
|
81
|
+
if (Object.keys(performanceMonitoring).length === 0) {
|
|
82
|
+
}
|
|
83
|
+
const name = env.PXL_NAME;
|
|
84
|
+
const instanceId = env.PXL_INSTANCE_ID;
|
|
85
|
+
const rootDirectory = env.PXL_ROOT_DIR;
|
|
86
|
+
const partial = {};
|
|
87
|
+
if (name) partial.name = name;
|
|
88
|
+
if (instanceId) partial.instanceId = instanceId;
|
|
89
|
+
if (rootDirectory) partial.rootDirectory = rootDirectory;
|
|
90
|
+
if (redis.host || redis.port || redis.password) partial.redis = redis;
|
|
91
|
+
if (hasDatabaseConfig) partial.database = databaseFinal;
|
|
92
|
+
if (Object.keys(queue).length > 0) partial.queue = queue;
|
|
93
|
+
if (Object.keys(web).length > 0) partial.web = web;
|
|
94
|
+
if (Object.keys(auth).length > 0) partial.auth = auth;
|
|
95
|
+
if (Object.keys(cluster).length > 0) partial.cluster = cluster;
|
|
96
|
+
if (Object.keys(performanceMonitoring).length > 0) partial.performanceMonitoring = performanceMonitoring;
|
|
97
|
+
return partial;
|
|
98
|
+
}
|
|
99
|
+
__name(loadFrameworkConfigFromEnv, "loadFrameworkConfigFromEnv");
|
|
100
|
+
export {
|
|
101
|
+
loadFrameworkConfigFromEnv
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/config/env.ts"],
|
|
4
|
+
"sourcesContent": ["import { type InferFrameworkConfig } from './schema.js';\n\n// Helper to parse booleans like 'true', '1', 'yes'\nfunction parseBool(v: string | undefined): boolean | undefined {\n if (v == null) return undefined;\n return /^(true|1|yes|on)$/i.test(v);\n}\n\nfunction parseIntEnv(v: string | undefined): number | undefined {\n if (v == null) return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction splitCsv(v: string | undefined): string[] | undefined {\n if (!v) return undefined;\n return v\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n}\n\n/**\n * Load a partial framework configuration from environment variables. This is intentionally\n * conservative: only widely useful primitives are supported. Complex structures (e.g. routes)\n * should be defined in code and merged before validation.\n *\n * Naming convention: PXL_<SECTION>_<FIELD>\n */\nexport function loadFrameworkConfigFromEnv(): Partial<InferFrameworkConfig> {\n const env = process.env;\n\n const redis = {\n host: env.PXL_REDIS_HOST,\n port: parseIntEnv(env.PXL_REDIS_PORT),\n password: env.PXL_REDIS_PASSWORD,\n };\n if (!redis.host) delete (redis as any).host; // allow omission\n if (!redis.port) delete (redis as any).port;\n if (!redis.password) delete (redis as any).password;\n\n const databaseEnabled = parseBool(env.PXL_DB_ENABLED);\n const database = {\n enabled: databaseEnabled,\n host: env.PXL_DB_HOST,\n port: parseIntEnv(env.PXL_DB_PORT),\n username: env.PXL_DB_USERNAME,\n password: env.PXL_DB_PASSWORD,\n databaseName: env.PXL_DB_NAME,\n entitiesDirectory: env.PXL_DB_ENTITIES_DIR,\n };\n // prune undefined fields so Zod defaults/optionals apply\n const databaseFinal = {\n ...(database.enabled !== undefined ? { enabled: database.enabled } : {}),\n ...(database.host ? { host: database.host } : {}),\n ...(database.port !== undefined ? { port: database.port } : {}),\n ...(database.username ? { username: database.username } : {}),\n ...(database.password ? { password: database.password } : {}),\n ...(database.databaseName ? { databaseName: database.databaseName } : {}),\n ...(database.entitiesDirectory ? { entitiesDirectory: database.entitiesDirectory } : {}),\n } as any;\n const hasDatabaseConfig = Object.keys(databaseFinal).length > 0;\n\n const queueProcessorsDirectory = env.PXL_QUEUE_PROCESSORS_DIR;\n const queueQueues = splitCsv(env.PXL_QUEUE_QUEUES)?.map(name => ({ name, jobs: [] }));\n const queue: any = {};\n if (queueProcessorsDirectory) queue.processorsDirectory = queueProcessorsDirectory;\n if (queueQueues) queue.queues = queueQueues;\n\n const webEnabled = parseBool(env.PXL_WEB_ENABLED);\n const webCorsEnabled = parseBool(env.PXL_WEB_CORS_ENABLED);\n const webCorsUrls = splitCsv(env.PXL_WEB_CORS_URLS);\n const webBodyLimit = parseIntEnv(env.PXL_WEB_BODY_LIMIT);\n const webPort = parseIntEnv(env.PXL_WEB_PORT);\n const web: any = {};\n if (webEnabled !== undefined) web.enabled = webEnabled;\n if (env.PXL_WEB_HOST) web.host = env.PXL_WEB_HOST;\n if (webPort !== undefined) web.port = webPort;\n if (webBodyLimit !== undefined) web.bodyLimit = webBodyLimit;\n if (webCorsEnabled || (webCorsUrls && webCorsUrls.length > 0)) {\n web.cors = { enabled: webCorsEnabled ?? true, urls: webCorsUrls ?? [] };\n }\n\n const auth: any = {};\n if (env.PXL_AUTH_JWT_SECRET_KEY) auth.jwtSecretKey = env.PXL_AUTH_JWT_SECRET_KEY;\n\n const cluster: any = {};\n const clusterEnabled = parseBool(env.PXL_CLUSTER_ENABLED);\n if (clusterEnabled !== undefined) cluster.enabled = clusterEnabled;\n const clusterWorkers = parseIntEnv(env.PXL_CLUSTER_WORKERS);\n if (clusterWorkers !== undefined) cluster.workers = clusterWorkers;\n if (Object.keys(cluster).length === 0) {\n // leave cluster undefined later\n }\n\n const performanceMonitoring: any = {};\n const perfEnabled = parseBool(env.PXL_PERF_ENABLED);\n if (perfEnabled !== undefined) performanceMonitoring.enabled = perfEnabled;\n const perfInterval = parseIntEnv(env.PXL_PERF_REPORT_INTERVAL_MS);\n if (perfInterval !== undefined) performanceMonitoring.reportInterval = perfInterval;\n if (Object.keys(performanceMonitoring).length === 0) {\n // leave undefined later\n }\n\n const name = env.PXL_NAME;\n const instanceId = env.PXL_INSTANCE_ID;\n const rootDirectory = env.PXL_ROOT_DIR;\n\n // assemble partial, removing empty objects\n const partial: Partial<InferFrameworkConfig> = {};\n if (name) partial.name = name;\n if (instanceId) partial.instanceId = instanceId;\n if (rootDirectory) partial.rootDirectory = rootDirectory;\n if (redis.host || redis.port || redis.password) partial.redis = redis as any;\n if (hasDatabaseConfig) partial.database = databaseFinal;\n if (Object.keys(queue).length > 0) partial.queue = queue;\n if (Object.keys(web).length > 0) partial.web = web;\n if (Object.keys(auth).length > 0) partial.auth = auth;\n if (Object.keys(cluster).length > 0) partial.cluster = cluster;\n if (Object.keys(performanceMonitoring).length > 0) partial.performanceMonitoring = performanceMonitoring;\n\n return partial;\n}\n\n/** Deep merge helper (shallow for primitives & plain objects) */\n// mergeConfig intentionally removed (security lint). If needed later, implement with explicit key lists.\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["name"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|