@naman_deep_singh/server-utils 1.0.1 → 1.0.3
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/dist/server.d.ts +1 -0
- package/dist/server.js +58 -10
- package/dist/shutdown.d.ts +1 -1
- package/dist/shutdown.js +15 -8
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
- package/src/server.ts +62 -10
- package/src/shutdown.ts +17 -8
- package/src/types.ts +2 -0
package/dist/server.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ export declare class ExpressServer implements ServerInstance {
|
|
|
55
55
|
private rpcMethods;
|
|
56
56
|
private socketIO?;
|
|
57
57
|
constructor(name?: string, version?: string, config?: ServerConfig);
|
|
58
|
+
private setupMiddleware;
|
|
58
59
|
start(): Promise<ServerInstance>;
|
|
59
60
|
stop(): Promise<void>;
|
|
60
61
|
getInfo(): ServerInfo;
|
package/dist/server.js
CHANGED
|
@@ -27,6 +27,54 @@ class ExpressServer {
|
|
|
27
27
|
gracefulShutdown: config.gracefulShutdown ?? true,
|
|
28
28
|
socketIO: config.socketIO
|
|
29
29
|
};
|
|
30
|
+
// Apply middleware based on configuration
|
|
31
|
+
this.setupMiddleware();
|
|
32
|
+
}
|
|
33
|
+
setupMiddleware() {
|
|
34
|
+
// Apply CORS if enabled
|
|
35
|
+
if (this.config.cors) {
|
|
36
|
+
try {
|
|
37
|
+
const cors = require('cors');
|
|
38
|
+
const corsOptions = typeof this.config.cors === 'object' ? this.config.cors : undefined;
|
|
39
|
+
this.app.use(cors(corsOptions));
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.warn(`${this.config.name}: CORS middleware not available. Install cors package.`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Apply Helmet if enabled
|
|
46
|
+
if (this.config.helmet) {
|
|
47
|
+
try {
|
|
48
|
+
const helmet = require('helmet');
|
|
49
|
+
this.app.use(helmet());
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.warn(`${this.config.name}: Helmet middleware not available. Install helmet package.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Apply JSON parser if enabled
|
|
56
|
+
if (this.config.json) {
|
|
57
|
+
this.app.use(express_1.default.json());
|
|
58
|
+
}
|
|
59
|
+
// Apply custom middleware
|
|
60
|
+
if (this.config.customMiddleware && this.config.customMiddleware.length > 0) {
|
|
61
|
+
this.config.customMiddleware.forEach(middleware => {
|
|
62
|
+
this.app.use(middleware);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
// Add health check if enabled
|
|
66
|
+
if (this.config.healthCheck) {
|
|
67
|
+
const healthPath = typeof this.config.healthCheck === 'string' ? this.config.healthCheck : '/health';
|
|
68
|
+
this.app.get(healthPath, (req, res) => {
|
|
69
|
+
res.status(200).json({
|
|
70
|
+
status: 'healthy',
|
|
71
|
+
service: this.config.name,
|
|
72
|
+
version: this.config.version,
|
|
73
|
+
uptime: Date.now() - this.config.startTime.getTime(),
|
|
74
|
+
timestamp: new Date().toISOString()
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
30
78
|
}
|
|
31
79
|
async start() {
|
|
32
80
|
this.status = 'starting';
|
|
@@ -98,11 +146,11 @@ class ExpressServer {
|
|
|
98
146
|
});
|
|
99
147
|
this.grpcServer.bindAsync(`0.0.0.0:${port}`, grpc.ServerCredentials.createInsecure(), () => {
|
|
100
148
|
this.grpcServer.start();
|
|
101
|
-
console.log(`🔗 gRPC server running on port ${port}`);
|
|
149
|
+
console.log(`🔗 ${this.config.name} gRPC server running on port ${port}`);
|
|
102
150
|
});
|
|
103
151
|
}
|
|
104
152
|
catch (error) {
|
|
105
|
-
console.warn(
|
|
153
|
+
console.warn(`${this.config.name}: gRPC not available. Install @grpc/grpc-js to use gRPC features.`);
|
|
106
154
|
}
|
|
107
155
|
}
|
|
108
156
|
}
|
|
@@ -113,10 +161,10 @@ class ExpressServer {
|
|
|
113
161
|
const jayson = require('jayson');
|
|
114
162
|
const rpcServer = jayson.server(this.rpcMethods);
|
|
115
163
|
this.app.use(path, rpcServer.middleware());
|
|
116
|
-
console.log(`📡 JSON-RPC server mounted on ${path}`);
|
|
164
|
+
console.log(`📡 ${this.config.name} JSON-RPC server mounted on ${path}`);
|
|
117
165
|
}
|
|
118
166
|
catch (error) {
|
|
119
|
-
console.warn(
|
|
167
|
+
console.warn(`${this.config.name}: JSON-RPC not available. Install jayson to use RPC features.`);
|
|
120
168
|
}
|
|
121
169
|
}
|
|
122
170
|
addWebhook(config) {
|
|
@@ -147,11 +195,11 @@ class ExpressServer {
|
|
|
147
195
|
res.status(500).json({ error: 'Webhook processing failed' });
|
|
148
196
|
}
|
|
149
197
|
});
|
|
150
|
-
console.log(`🪝
|
|
198
|
+
console.log(`🪝 ${this.config.name} webhook registered at ${config.path}${config.secret ? ' (with signature verification)' : ''}`);
|
|
151
199
|
}
|
|
152
200
|
addSocketIO(config = {}) {
|
|
153
201
|
if (!this.server) {
|
|
154
|
-
throw new Error(
|
|
202
|
+
throw new Error(`${this.config.name}: Server must be started before adding Socket.IO`);
|
|
155
203
|
}
|
|
156
204
|
try {
|
|
157
205
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
@@ -170,25 +218,25 @@ class ExpressServer {
|
|
|
170
218
|
// Handle connections
|
|
171
219
|
io.on('connection', (socket) => {
|
|
172
220
|
const typedSocket = socket;
|
|
173
|
-
console.log(`🔌 Socket connected
|
|
221
|
+
console.log(`🔌 ${this.config.name}: Socket connected [${typedSocket.id}]`);
|
|
174
222
|
// Call user-defined connection handler
|
|
175
223
|
if (config.onConnection) {
|
|
176
224
|
config.onConnection(socket);
|
|
177
225
|
}
|
|
178
226
|
// Handle disconnection
|
|
179
227
|
typedSocket.on('disconnect', (reason) => {
|
|
180
|
-
console.log(`🔌 Socket disconnected
|
|
228
|
+
console.log(`🔌 ${this.config.name}: Socket disconnected [${typedSocket.id}] - ${reason}`);
|
|
181
229
|
// Call user-defined disconnection handler
|
|
182
230
|
if (config.onDisconnection) {
|
|
183
231
|
config.onDisconnection(socket, reason);
|
|
184
232
|
}
|
|
185
233
|
});
|
|
186
234
|
});
|
|
187
|
-
console.log(`🔌 Socket.IO server attached${config.path ? ` at ${config.path}` : ''}`);
|
|
235
|
+
console.log(`🔌 ${this.config.name} Socket.IO server attached${config.path ? ` at ${config.path}` : ''}${config.cors ? ' (CORS enabled)' : ''}`);
|
|
188
236
|
return io;
|
|
189
237
|
}
|
|
190
238
|
catch (error) {
|
|
191
|
-
console.warn(
|
|
239
|
+
console.warn(`${this.config.name}: Socket.IO not available. Install socket.io to use WebSocket features.`);
|
|
192
240
|
return null;
|
|
193
241
|
}
|
|
194
242
|
}
|
package/dist/shutdown.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ import { Server } from 'http';
|
|
|
2
2
|
import { GracefulShutdownConfig, ServerPlugin } from './types';
|
|
3
3
|
export declare function createGracefulShutdown(server: Server, config?: GracefulShutdownConfig): void;
|
|
4
4
|
export declare function withGracefulShutdown(config?: GracefulShutdownConfig): ServerPlugin;
|
|
5
|
-
export declare function startServerWithShutdown(app: any, port: number, shutdownConfig?: GracefulShutdownConfig): Server;
|
|
5
|
+
export declare function startServerWithShutdown(app: any, port: number, shutdownConfig?: GracefulShutdownConfig, serverName?: string, serverVersion?: string): Server;
|
package/dist/shutdown.js
CHANGED
|
@@ -4,11 +4,12 @@ exports.createGracefulShutdown = createGracefulShutdown;
|
|
|
4
4
|
exports.withGracefulShutdown = withGracefulShutdown;
|
|
5
5
|
exports.startServerWithShutdown = startServerWithShutdown;
|
|
6
6
|
function createGracefulShutdown(server, config = {}) {
|
|
7
|
-
const { timeout = 10000, onShutdown } = config;
|
|
7
|
+
const { timeout = 10000, onShutdown, serverName, serverVersion } = config;
|
|
8
|
+
const nameVersion = serverName && serverVersion ? `${serverName} v${serverVersion}` : 'Server';
|
|
8
9
|
const shutdown = async (signal) => {
|
|
9
|
-
console.log(`🛑
|
|
10
|
+
console.log(`🛑 ${nameVersion} received ${signal}, shutting down gracefully...`);
|
|
10
11
|
const shutdownTimer = setTimeout(() => {
|
|
11
|
-
console.log(
|
|
12
|
+
console.log(`⏰ ${nameVersion} shutdown timeout reached, forcing exit`);
|
|
12
13
|
process.exit(1);
|
|
13
14
|
}, timeout);
|
|
14
15
|
try {
|
|
@@ -19,13 +20,13 @@ function createGracefulShutdown(server, config = {}) {
|
|
|
19
20
|
// Close server
|
|
20
21
|
server.close(() => {
|
|
21
22
|
clearTimeout(shutdownTimer);
|
|
22
|
-
console.log(
|
|
23
|
+
console.log(`👋 ${nameVersion} closed. Exiting now.`);
|
|
23
24
|
process.exit(0);
|
|
24
25
|
});
|
|
25
26
|
}
|
|
26
27
|
catch (error) {
|
|
27
28
|
clearTimeout(shutdownTimer);
|
|
28
|
-
console.error(
|
|
29
|
+
console.error(`❌ ${nameVersion} error during shutdown:`, error);
|
|
29
30
|
process.exit(1);
|
|
30
31
|
}
|
|
31
32
|
};
|
|
@@ -39,12 +40,18 @@ function withGracefulShutdown(config = {}) {
|
|
|
39
40
|
app.__gracefulShutdownConfig = config;
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
|
-
function startServerWithShutdown(app, port, shutdownConfig = {}) {
|
|
43
|
+
function startServerWithShutdown(app, port, shutdownConfig = {}, serverName, serverVersion) {
|
|
43
44
|
const server = app.listen(port, () => {
|
|
44
|
-
|
|
45
|
+
const nameVersion = serverName && serverVersion ? `${serverName} v${serverVersion}` : 'Server';
|
|
46
|
+
console.log(`🚀 ${nameVersion} running on http://localhost:${port}`);
|
|
45
47
|
});
|
|
46
48
|
// Apply graceful shutdown from stored config or provided config
|
|
47
49
|
const config = app.__gracefulShutdownConfig || shutdownConfig;
|
|
48
|
-
|
|
50
|
+
const enhancedConfig = {
|
|
51
|
+
...config,
|
|
52
|
+
serverName,
|
|
53
|
+
serverVersion
|
|
54
|
+
};
|
|
55
|
+
createGracefulShutdown(server, enhancedConfig);
|
|
49
56
|
return server;
|
|
50
57
|
}
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
package/src/server.ts
CHANGED
|
@@ -88,6 +88,58 @@ export class ExpressServer implements ServerInstance {
|
|
|
88
88
|
gracefulShutdown: config.gracefulShutdown ?? true,
|
|
89
89
|
socketIO: config.socketIO
|
|
90
90
|
};
|
|
91
|
+
|
|
92
|
+
// Apply middleware based on configuration
|
|
93
|
+
this.setupMiddleware();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private setupMiddleware(): void {
|
|
97
|
+
// Apply CORS if enabled
|
|
98
|
+
if (this.config.cors) {
|
|
99
|
+
try {
|
|
100
|
+
const cors = require('cors');
|
|
101
|
+
const corsOptions = typeof this.config.cors === 'object' ? this.config.cors : undefined;
|
|
102
|
+
this.app.use(cors(corsOptions));
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.warn(`${this.config.name}: CORS middleware not available. Install cors package.`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Apply Helmet if enabled
|
|
109
|
+
if (this.config.helmet) {
|
|
110
|
+
try {
|
|
111
|
+
const helmet = require('helmet');
|
|
112
|
+
this.app.use(helmet());
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.warn(`${this.config.name}: Helmet middleware not available. Install helmet package.`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Apply JSON parser if enabled
|
|
119
|
+
if (this.config.json) {
|
|
120
|
+
this.app.use(express.json());
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Apply custom middleware
|
|
124
|
+
if (this.config.customMiddleware && this.config.customMiddleware.length > 0) {
|
|
125
|
+
this.config.customMiddleware.forEach(middleware => {
|
|
126
|
+
this.app.use(middleware);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Add health check if enabled
|
|
131
|
+
if (this.config.healthCheck) {
|
|
132
|
+
const healthPath = typeof this.config.healthCheck === 'string' ? this.config.healthCheck : '/health';
|
|
133
|
+
this.app.get(healthPath, (req, res) => {
|
|
134
|
+
res.status(200).json({
|
|
135
|
+
status: 'healthy',
|
|
136
|
+
service: this.config.name,
|
|
137
|
+
version: this.config.version,
|
|
138
|
+
uptime: Date.now() - this.config.startTime.getTime(),
|
|
139
|
+
timestamp: new Date().toISOString()
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
91
143
|
}
|
|
92
144
|
|
|
93
145
|
async start(): Promise<ServerInstance> {
|
|
@@ -184,11 +236,11 @@ export class ExpressServer implements ServerInstance {
|
|
|
184
236
|
grpc.ServerCredentials.createInsecure(),
|
|
185
237
|
() => {
|
|
186
238
|
this.grpcServer!.start();
|
|
187
|
-
console.log(`🔗 gRPC server running on port ${port}`);
|
|
239
|
+
console.log(`🔗 ${this.config.name} gRPC server running on port ${port}`);
|
|
188
240
|
}
|
|
189
241
|
);
|
|
190
242
|
} catch (error: unknown) {
|
|
191
|
-
console.warn(
|
|
243
|
+
console.warn(`${this.config.name}: gRPC not available. Install @grpc/grpc-js to use gRPC features.`);
|
|
192
244
|
}
|
|
193
245
|
}
|
|
194
246
|
}
|
|
@@ -205,9 +257,9 @@ export class ExpressServer implements ServerInstance {
|
|
|
205
257
|
};
|
|
206
258
|
const rpcServer = jayson.server(this.rpcMethods);
|
|
207
259
|
this.app.use(path, rpcServer.middleware());
|
|
208
|
-
console.log(`📡 JSON-RPC server mounted on ${path}`);
|
|
260
|
+
console.log(`📡 ${this.config.name} JSON-RPC server mounted on ${path}`);
|
|
209
261
|
} catch (error: unknown) {
|
|
210
|
-
console.warn(
|
|
262
|
+
console.warn(`${this.config.name}: JSON-RPC not available. Install jayson to use RPC features.`);
|
|
211
263
|
}
|
|
212
264
|
}
|
|
213
265
|
|
|
@@ -243,12 +295,12 @@ export class ExpressServer implements ServerInstance {
|
|
|
243
295
|
}
|
|
244
296
|
});
|
|
245
297
|
|
|
246
|
-
console.log(`🪝
|
|
298
|
+
console.log(`🪝 ${this.config.name} webhook registered at ${config.path}${config.secret ? ' (with signature verification)' : ''}`);
|
|
247
299
|
}
|
|
248
300
|
|
|
249
301
|
addSocketIO(config: SocketIOConfig = {}): unknown {
|
|
250
302
|
if (!this.server) {
|
|
251
|
-
throw new Error(
|
|
303
|
+
throw new Error(`${this.config.name}: Server must be started before adding Socket.IO`);
|
|
252
304
|
}
|
|
253
305
|
|
|
254
306
|
try {
|
|
@@ -284,7 +336,7 @@ export class ExpressServer implements ServerInstance {
|
|
|
284
336
|
// Handle connections
|
|
285
337
|
io.on('connection', (socket: unknown) => {
|
|
286
338
|
const typedSocket = socket as SocketInstance;
|
|
287
|
-
console.log(`🔌 Socket connected
|
|
339
|
+
console.log(`🔌 ${this.config.name}: Socket connected [${typedSocket.id}]`);
|
|
288
340
|
|
|
289
341
|
// Call user-defined connection handler
|
|
290
342
|
if (config.onConnection) {
|
|
@@ -293,7 +345,7 @@ export class ExpressServer implements ServerInstance {
|
|
|
293
345
|
|
|
294
346
|
// Handle disconnection
|
|
295
347
|
typedSocket.on('disconnect', (reason) => {
|
|
296
|
-
console.log(`🔌 Socket disconnected
|
|
348
|
+
console.log(`🔌 ${this.config.name}: Socket disconnected [${typedSocket.id}] - ${reason}`);
|
|
297
349
|
|
|
298
350
|
// Call user-defined disconnection handler
|
|
299
351
|
if (config.onDisconnection) {
|
|
@@ -302,10 +354,10 @@ export class ExpressServer implements ServerInstance {
|
|
|
302
354
|
});
|
|
303
355
|
});
|
|
304
356
|
|
|
305
|
-
console.log(`🔌 Socket.IO server attached${config.path ? ` at ${config.path}` : ''}`);
|
|
357
|
+
console.log(`🔌 ${this.config.name} Socket.IO server attached${config.path ? ` at ${config.path}` : ''}${config.cors ? ' (CORS enabled)' : ''}`);
|
|
306
358
|
return io;
|
|
307
359
|
} catch (error: unknown) {
|
|
308
|
-
console.warn(
|
|
360
|
+
console.warn(`${this.config.name}: Socket.IO not available. Install socket.io to use WebSocket features.`);
|
|
309
361
|
return null;
|
|
310
362
|
}
|
|
311
363
|
}
|
package/src/shutdown.ts
CHANGED
|
@@ -2,13 +2,14 @@ import { Server } from 'http';
|
|
|
2
2
|
import { GracefulShutdownConfig, ServerPlugin } from './types';
|
|
3
3
|
|
|
4
4
|
export function createGracefulShutdown(server: Server, config: GracefulShutdownConfig = {}): void {
|
|
5
|
-
const { timeout = 10000, onShutdown } = config;
|
|
5
|
+
const { timeout = 10000, onShutdown, serverName, serverVersion } = config;
|
|
6
|
+
const nameVersion = serverName && serverVersion ? `${serverName} v${serverVersion}` : 'Server';
|
|
6
7
|
|
|
7
8
|
const shutdown = async (signal: string) => {
|
|
8
|
-
console.log(`🛑
|
|
9
|
+
console.log(`🛑 ${nameVersion} received ${signal}, shutting down gracefully...`);
|
|
9
10
|
|
|
10
11
|
const shutdownTimer = setTimeout(() => {
|
|
11
|
-
console.log(
|
|
12
|
+
console.log(`⏰ ${nameVersion} shutdown timeout reached, forcing exit`);
|
|
12
13
|
process.exit(1);
|
|
13
14
|
}, timeout);
|
|
14
15
|
|
|
@@ -21,12 +22,12 @@ export function createGracefulShutdown(server: Server, config: GracefulShutdownC
|
|
|
21
22
|
// Close server
|
|
22
23
|
server.close(() => {
|
|
23
24
|
clearTimeout(shutdownTimer);
|
|
24
|
-
console.log(
|
|
25
|
+
console.log(`👋 ${nameVersion} closed. Exiting now.`);
|
|
25
26
|
process.exit(0);
|
|
26
27
|
});
|
|
27
28
|
} catch (error) {
|
|
28
29
|
clearTimeout(shutdownTimer);
|
|
29
|
-
console.error(
|
|
30
|
+
console.error(`❌ ${nameVersion} error during shutdown:`, error);
|
|
30
31
|
process.exit(1);
|
|
31
32
|
}
|
|
32
33
|
};
|
|
@@ -46,15 +47,23 @@ export function withGracefulShutdown(config: GracefulShutdownConfig = {}): Serve
|
|
|
46
47
|
export function startServerWithShutdown(
|
|
47
48
|
app: any,
|
|
48
49
|
port: number,
|
|
49
|
-
shutdownConfig: GracefulShutdownConfig = {}
|
|
50
|
+
shutdownConfig: GracefulShutdownConfig = {},
|
|
51
|
+
serverName?: string,
|
|
52
|
+
serverVersion?: string
|
|
50
53
|
): Server {
|
|
51
54
|
const server = app.listen(port, () => {
|
|
52
|
-
|
|
55
|
+
const nameVersion = serverName && serverVersion ? `${serverName} v${serverVersion}` : 'Server';
|
|
56
|
+
console.log(`🚀 ${nameVersion} running on http://localhost:${port}`);
|
|
53
57
|
});
|
|
54
58
|
|
|
55
59
|
// Apply graceful shutdown from stored config or provided config
|
|
56
60
|
const config = app.__gracefulShutdownConfig || shutdownConfig;
|
|
57
|
-
|
|
61
|
+
const enhancedConfig = {
|
|
62
|
+
...config,
|
|
63
|
+
serverName,
|
|
64
|
+
serverVersion
|
|
65
|
+
};
|
|
66
|
+
createGracefulShutdown(server, enhancedConfig);
|
|
58
67
|
|
|
59
68
|
return server;
|
|
60
69
|
}
|