@naman_deep_singh/server-utils 1.0.8 → 1.2.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 (51) hide show
  1. package/README.md +401 -11
  2. package/dist/{index.d.ts → cjs/index.d.ts} +1 -1
  3. package/dist/{index.js → cjs/index.js} +3 -1
  4. package/dist/{middleware.d.ts → cjs/middleware.d.ts} +2 -0
  5. package/dist/{middleware.js → cjs/middleware.js} +137 -10
  6. package/dist/{server.d.ts → cjs/server.d.ts} +1 -0
  7. package/dist/{server.js → cjs/server.js} +119 -4
  8. package/dist/{types.d.ts → cjs/types.d.ts} +17 -0
  9. package/dist/{utils.js → cjs/utils.js} +14 -8
  10. package/dist/esm/health.d.ts +5 -0
  11. package/dist/esm/health.js +40 -0
  12. package/dist/esm/index.d.ts +46 -0
  13. package/dist/esm/index.js +58 -0
  14. package/dist/esm/middleware.d.ts +39 -0
  15. package/dist/esm/middleware.js +327 -0
  16. package/dist/esm/periodic-health.d.ts +11 -0
  17. package/dist/esm/periodic-health.js +64 -0
  18. package/dist/esm/server.d.ts +70 -0
  19. package/dist/esm/server.js +386 -0
  20. package/dist/esm/shutdown.d.ts +5 -0
  21. package/dist/esm/shutdown.js +52 -0
  22. package/dist/esm/types.d.ts +87 -0
  23. package/dist/esm/types.js +1 -0
  24. package/dist/esm/utils.d.ts +3 -0
  25. package/dist/esm/utils.js +38 -0
  26. package/dist/types/health.d.ts +5 -0
  27. package/dist/types/index.d.ts +46 -0
  28. package/dist/types/middleware.d.ts +39 -0
  29. package/dist/types/periodic-health.d.ts +11 -0
  30. package/dist/types/server.d.ts +70 -0
  31. package/dist/types/shutdown.d.ts +5 -0
  32. package/dist/types/types.d.ts +87 -0
  33. package/dist/types/utils.d.ts +3 -0
  34. package/package.json +26 -10
  35. package/src/health.ts +0 -47
  36. package/src/index.ts +0 -126
  37. package/src/middleware.ts +0 -275
  38. package/src/periodic-health.ts +0 -83
  39. package/src/server.ts +0 -412
  40. package/src/shutdown.ts +0 -69
  41. package/src/types.ts +0 -80
  42. package/src/utils.ts +0 -34
  43. package/tsconfig.json +0 -21
  44. /package/dist/{health.d.ts → cjs/health.d.ts} +0 -0
  45. /package/dist/{health.js → cjs/health.js} +0 -0
  46. /package/dist/{periodic-health.d.ts → cjs/periodic-health.d.ts} +0 -0
  47. /package/dist/{periodic-health.js → cjs/periodic-health.js} +0 -0
  48. /package/dist/{shutdown.d.ts → cjs/shutdown.d.ts} +0 -0
  49. /package/dist/{shutdown.js → cjs/shutdown.js} +0 -0
  50. /package/dist/{types.js → cjs/types.js} +0 -0
  51. /package/dist/{utils.d.ts → cjs/utils.d.ts} +0 -0
@@ -0,0 +1,386 @@
1
+ import express from 'express';
2
+ import { createGracefulShutdown } from './shutdown';
3
+ import { PeriodicHealthMonitor } from './periodic-health';
4
+ import crypto from 'crypto';
5
+ import { CacheFactory, SessionStore } from '@naman_deep_singh/cache';
6
+ export class ExpressServer {
7
+ constructor(name = 'Express Server', version = '1.0.0', config = {}) {
8
+ this.status = 'stopped';
9
+ this.grpcServices = [];
10
+ this.rpcMethods = {};
11
+ this.app = express();
12
+ this.config = {
13
+ name,
14
+ version,
15
+ startTime: new Date(),
16
+ port: config.port || 3000,
17
+ cors: config.cors ?? true,
18
+ helmet: config.helmet ?? true,
19
+ json: config.json ?? true,
20
+ cookieParser: config.cookieParser ?? false,
21
+ customMiddleware: config.customMiddleware || [],
22
+ healthCheck: config.healthCheck ?? true,
23
+ gracefulShutdown: config.gracefulShutdown ?? true,
24
+ socketIO: config.socketIO,
25
+ periodicHealthCheck: config.periodicHealthCheck || { enabled: false },
26
+ cache: config.cache || { enabled: false },
27
+ session: config.session || { enabled: false }
28
+ };
29
+ // Initialize locals for cache/session
30
+ this.app.locals.cache = undefined;
31
+ this.app.locals.sessionStore = undefined;
32
+ this.app.locals.cacheDefaultTTL = config.cache?.defaultTTL;
33
+ // Apply middleware based on configuration
34
+ this.setupMiddleware();
35
+ // Setup periodic health monitoring
36
+ this.setupPeriodicHealthMonitoring();
37
+ }
38
+ setupMiddleware() {
39
+ // Apply CORS if enabled
40
+ if (this.config.cors) {
41
+ try {
42
+ const cors = require('cors');
43
+ const corsOptions = typeof this.config.cors === 'object' ? this.config.cors : undefined;
44
+ this.app.use(cors(corsOptions));
45
+ }
46
+ catch (error) {
47
+ console.warn(`${this.config.name}: CORS middleware not available. Install cors package.`);
48
+ }
49
+ }
50
+ // Apply Helmet if enabled
51
+ if (this.config.helmet) {
52
+ try {
53
+ const helmet = require('helmet');
54
+ this.app.use(helmet());
55
+ }
56
+ catch (error) {
57
+ console.warn(`${this.config.name}: Helmet middleware not available. Install helmet package.`);
58
+ }
59
+ }
60
+ // Apply JSON parser if enabled
61
+ if (this.config.json) {
62
+ this.app.use(express.json());
63
+ }
64
+ // Apply cookie parser if enabled
65
+ if (this.config.cookieParser) {
66
+ try {
67
+ const cookieParser = require('cookie-parser');
68
+ this.app.use(cookieParser());
69
+ }
70
+ catch (error) {
71
+ console.warn(`${this.config.name}: Cookie parser middleware not available. Install cookie-parser package.`);
72
+ }
73
+ }
74
+ // Apply custom middleware
75
+ if (this.config.customMiddleware && this.config.customMiddleware.length > 0) {
76
+ this.config.customMiddleware.forEach(middleware => {
77
+ this.app.use(middleware);
78
+ });
79
+ }
80
+ // Add health check if enabled
81
+ if (this.config.healthCheck) {
82
+ const healthPath = typeof this.config.healthCheck === 'string' ? this.config.healthCheck : '/health';
83
+ this.app.get(healthPath, async (req, res) => {
84
+ const base = {
85
+ status: 'healthy',
86
+ service: this.config.name,
87
+ version: this.config.version,
88
+ uptime: Date.now() - this.config.startTime.getTime(),
89
+ timestamp: new Date().toISOString()
90
+ };
91
+ // If cache is enabled, include its health
92
+ const cache = req.app.locals.cache;
93
+ if (cache && typeof cache.isAlive === 'function') {
94
+ try {
95
+ base.cache = await cache.isAlive();
96
+ }
97
+ catch (e) {
98
+ base.cache = { isAlive: false, adapter: 'unknown', timestamp: new Date(), error: e.message };
99
+ }
100
+ }
101
+ res.status(200).json(base);
102
+ });
103
+ }
104
+ }
105
+ async setupCacheAndSession(config, serverName) {
106
+ try {
107
+ // Initialize cache if enabled
108
+ if (config.cache && config.cache.enabled) {
109
+ try {
110
+ const provided = config.cache.options;
111
+ let cacheConfig = provided && typeof provided === 'object' ? provided : undefined;
112
+ if (!cacheConfig) {
113
+ cacheConfig = { adapter: config.cache.adapter || 'memory' };
114
+ }
115
+ console.log(`🔄 [${serverName}] Initializing cache adapter: ${config.cache.adapter || 'memory'}...`);
116
+ // Use createWithFallback to prefer primary and fall back to memory when configured
117
+ const cache = await CacheFactory.createWithFallback({
118
+ ...(cacheConfig || {}),
119
+ ttl: cacheConfig?.ttl ?? config.cache?.defaultTTL
120
+ });
121
+ this.app.locals.cache = cache;
122
+ this.cache = cache;
123
+ this.app.locals.cacheDefaultTTL = config.cache?.defaultTTL;
124
+ // attach per-request helper middleware
125
+ this.app.use((req, _res, next) => {
126
+ req.cache = cache;
127
+ next();
128
+ });
129
+ console.log(`✅ [${serverName}] Cache initialized successfully (adapter: ${(cacheConfig.adapter || 'memory')})`);
130
+ }
131
+ catch (err) {
132
+ console.error(`❌ [${serverName}] Failed to initialize cache (fallback to memory if enabled):`, err instanceof Error ? err.message : err);
133
+ // Cache initialization error is critical but we continue to allow graceful fallback
134
+ }
135
+ }
136
+ // Initialize session if enabled
137
+ if (config.session && config.session.enabled) {
138
+ const cookieName = config.session.cookieName || `${serverName.replace(/\s+/g, '_').toLowerCase()}.sid`;
139
+ const ttl = config.session.ttl ?? 3600;
140
+ let cache = this.app.locals.cache;
141
+ if (!cache) {
142
+ // fallback to in-memory cache for session store
143
+ try {
144
+ cache = CacheFactory.create({ adapter: 'memory' });
145
+ this.app.locals.cache = cache;
146
+ this.cache = cache;
147
+ console.log(`📝 [${serverName}] Session store using in-memory cache`);
148
+ }
149
+ catch (e) {
150
+ console.error(`❌ [${serverName}] Failed to create in-memory cache for sessions:`, e instanceof Error ? e.message : e);
151
+ }
152
+ }
153
+ else {
154
+ console.log(`📝 [${serverName}] Session store initialized with configured cache adapter`);
155
+ }
156
+ if (!cache) {
157
+ console.error(`❌ [${serverName}] CRITICAL: Session enabled but no cache available to store sessions. Session functionality will be unavailable.`);
158
+ }
159
+ else {
160
+ const store = new SessionStore(cache, { ttl });
161
+ this.app.locals.sessionStore = store;
162
+ this.app.locals.sessionCookieName = cookieName;
163
+ this.sessionStore = store;
164
+ // attach session middleware globally so req.sessionStore is available
165
+ try {
166
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
167
+ const { useSession } = require('./middleware');
168
+ this.app.use(useSession(cookieName));
169
+ console.log(`✅ [${serverName}] Session middleware enabled (cookie: ${cookieName}, TTL: ${ttl}s)`);
170
+ }
171
+ catch (err) {
172
+ console.error(`❌ [${serverName}] Session middleware not available:`, err instanceof Error ? err.message : err);
173
+ }
174
+ }
175
+ }
176
+ }
177
+ catch (err) {
178
+ console.error(`❌ [${serverName}] Error during cache/session setup:`, err instanceof Error ? err.message : err);
179
+ }
180
+ }
181
+ setupPeriodicHealthMonitoring() {
182
+ if (this.config.periodicHealthCheck?.enabled) {
183
+ this.healthMonitor = new PeriodicHealthMonitor(this.config.periodicHealthCheck, this.config.name);
184
+ }
185
+ }
186
+ async start() {
187
+ this.status = 'starting';
188
+ // Initialize cache and session before starting the server
189
+ await this.setupCacheAndSession(this.config, this.config.name);
190
+ return new Promise((resolve, reject) => {
191
+ try {
192
+ this.server = this.app.listen(this.config.port, () => {
193
+ this.status = 'running';
194
+ console.log(`🚀 ${this.config.name} v${this.config.version} running on http://localhost:${this.config.port}`);
195
+ if (this.config.gracefulShutdown) {
196
+ createGracefulShutdown(this.server, {
197
+ onShutdown: async () => {
198
+ this.status = 'stopping';
199
+ // Stop health monitoring during shutdown
200
+ if (this.healthMonitor) {
201
+ this.healthMonitor.stop();
202
+ }
203
+ // Close cache and session store if present
204
+ try {
205
+ const cache = this.app.locals.cache;
206
+ if (cache && typeof cache.close === 'function') {
207
+ await cache.close();
208
+ }
209
+ }
210
+ catch (e) {
211
+ console.warn(`${this.config.name}: Error closing cache`, e);
212
+ }
213
+ try {
214
+ const store = this.app.locals.sessionStore;
215
+ if (store && typeof store.close === 'function') {
216
+ await store.close();
217
+ }
218
+ }
219
+ catch (e) {
220
+ // SessionStore may not have close; ignore
221
+ }
222
+ }
223
+ });
224
+ }
225
+ // Start periodic health monitoring after server is running
226
+ if (this.healthMonitor) {
227
+ this.healthMonitor.start();
228
+ }
229
+ resolve(this);
230
+ });
231
+ this.server.on('error', reject);
232
+ }
233
+ catch (error) {
234
+ this.status = 'stopped';
235
+ reject(error);
236
+ }
237
+ });
238
+ }
239
+ async stop() {
240
+ this.status = 'stopping';
241
+ // Stop gRPC server if running
242
+ if (this.grpcServer) {
243
+ this.grpcServer.forceShutdown();
244
+ }
245
+ // Stop periodic health monitoring
246
+ if (this.healthMonitor) {
247
+ this.healthMonitor.stop();
248
+ }
249
+ // Stop Socket.IO server if running
250
+ if (this.socketIO) {
251
+ this.socketIO.close();
252
+ }
253
+ if (!this.server) {
254
+ this.status = 'stopped';
255
+ return;
256
+ }
257
+ return new Promise((resolve) => {
258
+ this.server.close(() => {
259
+ this.status = 'stopped';
260
+ console.log(`👋 ${this.config.name} stopped`);
261
+ resolve();
262
+ });
263
+ });
264
+ }
265
+ getInfo() {
266
+ return {
267
+ name: this.config.name,
268
+ version: this.config.version,
269
+ port: this.config.port,
270
+ uptime: Date.now() - this.config.startTime.getTime(),
271
+ status: this.status,
272
+ startTime: this.config.startTime
273
+ };
274
+ }
275
+ addGrpcService(service, implementation, port = 50051) {
276
+ this.grpcServices.push({ service, implementation });
277
+ // Lazy load gRPC to avoid dependency issues
278
+ if (!this.grpcServer) {
279
+ try {
280
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
281
+ const grpc = require('@grpc/grpc-js');
282
+ this.grpcServer = new grpc.Server();
283
+ // Add all services
284
+ this.grpcServices.forEach(({ service, implementation }) => {
285
+ this.grpcServer.addService(service, implementation);
286
+ });
287
+ this.grpcServer.bindAsync(`0.0.0.0:${port}`, grpc.ServerCredentials.createInsecure(), () => {
288
+ this.grpcServer.start();
289
+ console.log(`🔗 ${this.config.name} gRPC server running on port ${port}`);
290
+ });
291
+ }
292
+ catch (error) {
293
+ console.warn(`${this.config.name}: gRPC not available. Install @grpc/grpc-js to use gRPC features.`);
294
+ }
295
+ }
296
+ }
297
+ addRpcMethods(methods, path = '/rpc') {
298
+ Object.assign(this.rpcMethods, methods);
299
+ try {
300
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
301
+ const jayson = require('jayson');
302
+ const rpcServer = jayson.server(this.rpcMethods);
303
+ this.app.use(path, rpcServer.middleware());
304
+ console.log(`📡 ${this.config.name} JSON-RPC server mounted on ${path}`);
305
+ }
306
+ catch (error) {
307
+ console.warn(`${this.config.name}: JSON-RPC not available. Install jayson to use RPC features.`);
308
+ }
309
+ }
310
+ addWebhook(config) {
311
+ this.app.post(config.path, express.raw({ type: 'application/json' }), async (req, res) => {
312
+ try {
313
+ // Verify signature if secret provided
314
+ if (config.secret) {
315
+ const signature = req.headers['x-hub-signature-256'] || req.headers['x-signature-256'];
316
+ if (signature) {
317
+ const expectedSignature = crypto
318
+ .createHmac('sha256', config.secret)
319
+ .update(req.body)
320
+ .digest('hex');
321
+ const providedSignature = Array.isArray(signature) ? signature[0] : signature;
322
+ if (!providedSignature.includes(expectedSignature)) {
323
+ return res.status(401).json({ error: 'Invalid signature' });
324
+ }
325
+ }
326
+ }
327
+ // Parse JSON payload
328
+ const payload = JSON.parse(req.body.toString());
329
+ // Call handler
330
+ await config.handler(payload, req.headers);
331
+ res.status(200).json({ success: true });
332
+ }
333
+ catch (error) {
334
+ console.error('Webhook error:', error);
335
+ res.status(500).json({ error: 'Webhook processing failed' });
336
+ }
337
+ });
338
+ console.log(`🪝 ${this.config.name} webhook registered at ${config.path}${config.secret ? ' (with signature verification)' : ''}`);
339
+ }
340
+ addSocketIO(config = {}) {
341
+ if (!this.server) {
342
+ throw new Error(`${this.config.name}: Server must be started before adding Socket.IO`);
343
+ }
344
+ try {
345
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
346
+ const { Server } = require('socket.io');
347
+ // Configure CORS
348
+ const corsConfig = config.cors === true
349
+ ? { origin: '*', methods: ['GET', 'POST'] }
350
+ : config.cors || undefined;
351
+ // Create Socket.IO server
352
+ const io = new Server(this.server, {
353
+ cors: config.cors ? corsConfig : undefined,
354
+ path: config.path || '/socket.io'
355
+ });
356
+ // Store reference for cleanup
357
+ this.socketIO = io;
358
+ // Handle connections
359
+ io.on('connection', (socket) => {
360
+ const typedSocket = socket;
361
+ console.log(`🔌 ${this.config.name}: Socket connected [${typedSocket.id}]`);
362
+ // Call user-defined connection handler
363
+ if (config.onConnection) {
364
+ config.onConnection(socket);
365
+ }
366
+ // Handle disconnection
367
+ typedSocket.on('disconnect', (reason) => {
368
+ console.log(`🔌 ${this.config.name}: Socket disconnected [${typedSocket.id}] - ${reason}`);
369
+ // Call user-defined disconnection handler
370
+ if (config.onDisconnection) {
371
+ config.onDisconnection(socket, reason);
372
+ }
373
+ });
374
+ });
375
+ console.log(`🔌 ${this.config.name} Socket.IO server attached${config.path ? ` at ${config.path}` : ''}${config.cors ? ' (CORS enabled)' : ''}`);
376
+ return io;
377
+ }
378
+ catch (error) {
379
+ console.warn(`${this.config.name}: Socket.IO not available. Install socket.io to use WebSocket features.`);
380
+ return null;
381
+ }
382
+ }
383
+ }
384
+ export function createServer(name, version, config) {
385
+ return new ExpressServer(name, version, config);
386
+ }
@@ -0,0 +1,5 @@
1
+ import { Server } from 'http';
2
+ import { GracefulShutdownConfig, ServerPlugin } from './types';
3
+ export declare function createGracefulShutdown(server: Server, config?: GracefulShutdownConfig): void;
4
+ export declare function withGracefulShutdown(config?: GracefulShutdownConfig): ServerPlugin;
5
+ export declare function startServerWithShutdown(app: any, port: number, shutdownConfig?: GracefulShutdownConfig, serverName?: string, serverVersion?: string): Server;
@@ -0,0 +1,52 @@
1
+ export function createGracefulShutdown(server, config = {}) {
2
+ const { timeout = 10000, onShutdown, serverName, serverVersion } = config;
3
+ const nameVersion = serverName && serverVersion ? `${serverName} v${serverVersion}` : 'Server';
4
+ const shutdown = async (signal) => {
5
+ console.log(`🛑 ${nameVersion} received ${signal}, shutting down gracefully...`);
6
+ const shutdownTimer = setTimeout(() => {
7
+ console.log(`⏰ ${nameVersion} shutdown timeout reached, forcing exit`);
8
+ process.exit(1);
9
+ }, timeout);
10
+ try {
11
+ // Run custom shutdown logic
12
+ if (onShutdown) {
13
+ await onShutdown();
14
+ }
15
+ // Close server
16
+ server.close(() => {
17
+ clearTimeout(shutdownTimer);
18
+ console.log(`👋 ${nameVersion} closed. Exiting now.`);
19
+ process.exit(0);
20
+ });
21
+ }
22
+ catch (error) {
23
+ clearTimeout(shutdownTimer);
24
+ console.error(`❌ ${nameVersion} error during shutdown:`, error);
25
+ process.exit(1);
26
+ }
27
+ };
28
+ process.on('SIGINT', () => shutdown('SIGINT'));
29
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
30
+ }
31
+ export function withGracefulShutdown(config = {}) {
32
+ return (app, serverConfig) => {
33
+ // This plugin needs to be applied after server.listen()
34
+ // Store config for later use
35
+ app.__gracefulShutdownConfig = config;
36
+ };
37
+ }
38
+ export function startServerWithShutdown(app, port, shutdownConfig = {}, serverName, serverVersion) {
39
+ const server = app.listen(port, () => {
40
+ const nameVersion = serverName && serverVersion ? `${serverName} v${serverVersion}` : 'Server';
41
+ console.log(`🚀 ${nameVersion} running on http://localhost:${port}`);
42
+ });
43
+ // Apply graceful shutdown from stored config or provided config
44
+ const config = app.__gracefulShutdownConfig || shutdownConfig;
45
+ const enhancedConfig = {
46
+ ...config,
47
+ serverName,
48
+ serverVersion
49
+ };
50
+ createGracefulShutdown(server, enhancedConfig);
51
+ return server;
52
+ }
@@ -0,0 +1,87 @@
1
+ import express from 'express';
2
+ export interface CorsOptions {
3
+ origin?: string | string[] | boolean | RegExp | ((origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => void);
4
+ methods?: string | string[];
5
+ allowedHeaders?: string | string[];
6
+ exposedHeaders?: string | string[];
7
+ credentials?: boolean;
8
+ maxAge?: number;
9
+ preflightContinue?: boolean;
10
+ optionsSuccessStatus?: number;
11
+ }
12
+ export interface ServerConfig {
13
+ port?: number;
14
+ cors?: boolean | CorsOptions;
15
+ helmet?: boolean;
16
+ json?: boolean;
17
+ cookieParser?: boolean;
18
+ customMiddleware?: express.RequestHandler[];
19
+ healthCheck?: boolean | string;
20
+ gracefulShutdown?: boolean;
21
+ socketIO?: SocketIOConfig;
22
+ periodicHealthCheck?: PeriodicHealthCheckConfig;
23
+ name?: string;
24
+ version?: string;
25
+ cache?: {
26
+ enabled?: boolean;
27
+ adapter?: 'redis' | 'memcache' | 'memory';
28
+ options?: unknown;
29
+ defaultTTL?: number;
30
+ };
31
+ session?: {
32
+ enabled?: boolean;
33
+ cookieName?: string;
34
+ ttl?: number;
35
+ cookieOptions?: {
36
+ path?: string;
37
+ httpOnly?: boolean;
38
+ secure?: boolean;
39
+ sameSite?: 'lax' | 'strict' | 'none';
40
+ };
41
+ };
42
+ }
43
+ export interface PeriodicHealthCheckConfig {
44
+ enabled?: boolean;
45
+ interval?: number;
46
+ services?: HealthCheckService[];
47
+ }
48
+ export interface HealthCheckService {
49
+ name: string;
50
+ url: string;
51
+ timeout?: number;
52
+ }
53
+ export interface SocketIOConfig {
54
+ enabled?: boolean;
55
+ cors?: boolean | {
56
+ origin?: string | string[] | boolean;
57
+ methods?: string[];
58
+ credentials?: boolean;
59
+ };
60
+ onConnection?: (socket: unknown) => void;
61
+ onDisconnection?: (socket: unknown, reason: string) => void;
62
+ path?: string;
63
+ }
64
+ export interface HealthCheckConfig {
65
+ path?: string;
66
+ customChecks?: HealthCheck[];
67
+ }
68
+ export interface HealthCheck {
69
+ name: string;
70
+ check: () => Promise<boolean>;
71
+ }
72
+ export interface GracefulShutdownConfig {
73
+ timeout?: number;
74
+ onShutdown?: () => Promise<void>;
75
+ serverName?: string;
76
+ serverVersion?: string;
77
+ }
78
+ export interface SocketInstance {
79
+ id: string;
80
+ emit: (event: string, data?: unknown) => void;
81
+ on: (event: string, handler: (...args: unknown[]) => void) => void;
82
+ broadcast: {
83
+ emit: (event: string, data?: unknown) => void;
84
+ };
85
+ disconnect: () => void;
86
+ }
87
+ export type ServerPlugin = (app: express.Application, config: ServerConfig) => void;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare function getEnv(key: string, defaultValue?: string): string;
2
+ export declare function getEnvNumber(key: string, defaultValue?: number): number;
3
+ export declare function getEnvBoolean(key: string, defaultValue?: boolean): boolean;
@@ -0,0 +1,38 @@
1
+ export function getEnv(key, defaultValue) {
2
+ const value = process.env[key];
3
+ if (value === undefined) {
4
+ if (defaultValue === undefined) {
5
+ throw new Error(`Environment variable ${key} is required`);
6
+ }
7
+ return defaultValue;
8
+ }
9
+ return value; // empty string allowed
10
+ }
11
+ export function getEnvNumber(key, defaultValue) {
12
+ const value = process.env[key];
13
+ if (value === undefined) {
14
+ if (defaultValue === undefined) {
15
+ throw new Error(`Environment variable ${key} is required`);
16
+ }
17
+ return defaultValue;
18
+ }
19
+ const parsed = Number(value);
20
+ if (Number.isNaN(parsed)) {
21
+ throw new Error(`Environment variable ${key} must be a valid number`);
22
+ }
23
+ return parsed;
24
+ }
25
+ export function getEnvBoolean(key, defaultValue) {
26
+ const value = process.env[key];
27
+ if (value === undefined) {
28
+ if (defaultValue === undefined) {
29
+ throw new Error(`Environment variable ${key} is required`);
30
+ }
31
+ return defaultValue;
32
+ }
33
+ const normalized = value.toLowerCase();
34
+ if (normalized !== "true" && normalized !== "false") {
35
+ throw new Error(`Environment variable ${key} must be 'true' or 'false'`);
36
+ }
37
+ return normalized === "true";
38
+ }
@@ -0,0 +1,5 @@
1
+ import express from 'express';
2
+ import { HealthCheckConfig, ServerPlugin } from './types';
3
+ export declare function createHealthCheck(config?: HealthCheckConfig): express.RequestHandler;
4
+ export declare function withHealthCheck(path?: string, config?: HealthCheckConfig): ServerPlugin;
5
+ export declare function addHealthCheck(app: express.Application, path?: string, config?: HealthCheckConfig): void;
@@ -0,0 +1,46 @@
1
+ export { ExpressServer, createServer } from './server';
2
+ export type { ServerInstance, ServerInfo, GrpcService, RpcMethod, WebhookConfig } from './server';
3
+ export { Request, Response, NextFunction, Router, Application } from 'express';
4
+ export type { RequestHandler, ErrorRequestHandler } from 'express';
5
+ export { createHealthCheck, withHealthCheck, addHealthCheck } from './health';
6
+ export { createGracefulShutdown, withGracefulShutdown, startServerWithShutdown } from './shutdown';
7
+ export { createLoggingMiddleware, createErrorHandler, createRequestIdMiddleware, createValidationMiddleware, createRateLimitMiddleware, createAuthMiddleware, withLogging, withErrorHandler, withRequestId, withValidation, withRateLimit, withAuth, validateFields, rateLimit, requireAuth, cacheResponse, useSession, type ValidationRule, type RateLimitConfig, type AuthConfig } from './middleware';
8
+ export { getEnv, getEnvNumber, getEnvBoolean } from './utils';
9
+ export { PeriodicHealthMonitor } from './periodic-health';
10
+ export type { ServerConfig, HealthCheckConfig, HealthCheck, GracefulShutdownConfig, ServerPlugin, SocketIOConfig, SocketInstance, PeriodicHealthCheckConfig, HealthCheckService } from './types';
11
+ import { ExpressServer, createServer } from './server';
12
+ import { createHealthCheck, withHealthCheck, addHealthCheck } from './health';
13
+ import { createGracefulShutdown, withGracefulShutdown, startServerWithShutdown } from './shutdown';
14
+ import { createLoggingMiddleware, createErrorHandler, createRequestIdMiddleware, createValidationMiddleware, createRateLimitMiddleware, createAuthMiddleware, withLogging, withErrorHandler, withRequestId, withValidation, withRateLimit, withAuth, validateFields, rateLimit, requireAuth } from './middleware';
15
+ import { getEnv, getEnvNumber, getEnvBoolean } from './utils';
16
+ import { PeriodicHealthMonitor } from './periodic-health';
17
+ declare const ServerUtils: {
18
+ createServer: typeof createServer;
19
+ ExpressServer: typeof ExpressServer;
20
+ createHealthCheck: typeof createHealthCheck;
21
+ withHealthCheck: typeof withHealthCheck;
22
+ addHealthCheck: typeof addHealthCheck;
23
+ createGracefulShutdown: typeof createGracefulShutdown;
24
+ withGracefulShutdown: typeof withGracefulShutdown;
25
+ startServerWithShutdown: typeof startServerWithShutdown;
26
+ createLoggingMiddleware: typeof createLoggingMiddleware;
27
+ createErrorHandler: typeof createErrorHandler;
28
+ createRequestIdMiddleware: typeof createRequestIdMiddleware;
29
+ createValidationMiddleware: typeof createValidationMiddleware;
30
+ createRateLimitMiddleware: typeof createRateLimitMiddleware;
31
+ createAuthMiddleware: typeof createAuthMiddleware;
32
+ withLogging: typeof withLogging;
33
+ withErrorHandler: typeof withErrorHandler;
34
+ withRequestId: typeof withRequestId;
35
+ withValidation: typeof withValidation;
36
+ withRateLimit: typeof withRateLimit;
37
+ withAuth: typeof withAuth;
38
+ validateFields: typeof validateFields;
39
+ rateLimit: typeof rateLimit;
40
+ requireAuth: typeof requireAuth;
41
+ getEnv: typeof getEnv;
42
+ getEnvNumber: typeof getEnvNumber;
43
+ getEnvBoolean: typeof getEnvBoolean;
44
+ PeriodicHealthMonitor: typeof PeriodicHealthMonitor;
45
+ };
46
+ export default ServerUtils;
@@ -0,0 +1,39 @@
1
+ import express from 'express';
2
+ import { ServerPlugin } from './types';
3
+ export declare function createLoggingMiddleware(format?: 'simple' | 'detailed'): express.RequestHandler;
4
+ export declare function createErrorHandler(): express.ErrorRequestHandler;
5
+ export declare function createRequestIdMiddleware(): express.RequestHandler;
6
+ export interface ValidationRule {
7
+ field: string;
8
+ required?: boolean;
9
+ type?: 'string' | 'number' | 'email' | 'boolean';
10
+ minLength?: number;
11
+ maxLength?: number;
12
+ pattern?: RegExp;
13
+ custom?: (value: unknown) => boolean | string;
14
+ }
15
+ export declare function createValidationMiddleware(rules: ValidationRule[]): express.RequestHandler;
16
+ export interface RateLimitConfig {
17
+ windowMs?: number;
18
+ maxRequests?: number;
19
+ message?: string;
20
+ keyGenerator?: (req: express.Request) => string;
21
+ }
22
+ export declare function createRateLimitMiddleware(config?: RateLimitConfig): express.RequestHandler;
23
+ export interface AuthConfig {
24
+ tokenExtractor?: (req: express.Request) => string | null;
25
+ tokenValidator?: (token: string) => Promise<unknown> | unknown;
26
+ unauthorizedMessage?: string;
27
+ }
28
+ export declare function createAuthMiddleware(config: AuthConfig): express.RequestHandler;
29
+ export declare function withLogging(format?: 'simple' | 'detailed'): ServerPlugin;
30
+ export declare function withErrorHandler(): ServerPlugin;
31
+ export declare function withRequestId(): ServerPlugin;
32
+ export declare function withValidation(rules: ValidationRule[]): ServerPlugin;
33
+ export declare function withRateLimit(config?: RateLimitConfig): ServerPlugin;
34
+ export declare function withAuth(config: AuthConfig): ServerPlugin;
35
+ export declare function validateFields(rules: ValidationRule[]): express.RequestHandler;
36
+ export declare function rateLimit(config?: RateLimitConfig): express.RequestHandler;
37
+ export declare function requireAuth(config: AuthConfig): express.RequestHandler;
38
+ export declare function cacheResponse(ttl?: number): express.RequestHandler;
39
+ export declare function useSession(cookieName?: string): express.RequestHandler;