@naman_deep_singh/server-utils 1.0.8 → 1.1.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.
- package/README.md +147 -7
- package/dist/{middleware.js → cjs/middleware.js} +37 -10
- package/dist/{utils.js → cjs/utils.js} +14 -8
- package/dist/esm/health.d.ts +5 -0
- package/dist/esm/health.js +40 -0
- package/dist/esm/index.d.ts +46 -0
- package/dist/esm/index.js +58 -0
- package/dist/esm/middleware.d.ts +37 -0
- package/dist/esm/middleware.js +229 -0
- package/dist/esm/periodic-health.d.ts +11 -0
- package/dist/esm/periodic-health.js +64 -0
- package/dist/esm/server.d.ts +69 -0
- package/dist/esm/server.js +271 -0
- package/dist/esm/shutdown.d.ts +5 -0
- package/dist/esm/shutdown.js +52 -0
- package/dist/esm/types.d.ts +70 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils.d.ts +3 -0
- package/dist/esm/utils.js +38 -0
- package/dist/types/health.d.ts +5 -0
- package/dist/types/index.d.ts +46 -0
- package/dist/types/middleware.d.ts +37 -0
- package/dist/types/periodic-health.d.ts +11 -0
- package/dist/types/server.d.ts +69 -0
- package/dist/types/shutdown.d.ts +5 -0
- package/dist/types/types.d.ts +70 -0
- package/dist/types/utils.d.ts +3 -0
- package/package.json +22 -7
- package/src/health.ts +0 -47
- package/src/index.ts +0 -126
- package/src/middleware.ts +0 -275
- package/src/periodic-health.ts +0 -83
- package/src/server.ts +0 -412
- package/src/shutdown.ts +0 -69
- package/src/types.ts +0 -80
- package/src/utils.ts +0 -34
- package/tsconfig.json +0 -21
- /package/dist/{health.d.ts → cjs/health.d.ts} +0 -0
- /package/dist/{health.js → cjs/health.js} +0 -0
- /package/dist/{index.d.ts → cjs/index.d.ts} +0 -0
- /package/dist/{index.js → cjs/index.js} +0 -0
- /package/dist/{middleware.d.ts → cjs/middleware.d.ts} +0 -0
- /package/dist/{periodic-health.d.ts → cjs/periodic-health.d.ts} +0 -0
- /package/dist/{periodic-health.js → cjs/periodic-health.js} +0 -0
- /package/dist/{server.d.ts → cjs/server.d.ts} +0 -0
- /package/dist/{server.js → cjs/server.js} +0 -0
- /package/dist/{shutdown.d.ts → cjs/shutdown.d.ts} +0 -0
- /package/dist/{shutdown.js → cjs/shutdown.js} +0 -0
- /package/dist/{types.d.ts → cjs/types.d.ts} +0 -0
- /package/dist/{types.js → cjs/types.js} +0 -0
- /package/dist/{utils.d.ts → cjs/utils.d.ts} +0 -0
|
@@ -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,70 @@
|
|
|
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
|
+
}
|
|
26
|
+
export interface PeriodicHealthCheckConfig {
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
interval?: number;
|
|
29
|
+
services?: HealthCheckService[];
|
|
30
|
+
}
|
|
31
|
+
export interface HealthCheckService {
|
|
32
|
+
name: string;
|
|
33
|
+
url: string;
|
|
34
|
+
timeout?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface SocketIOConfig {
|
|
37
|
+
enabled?: boolean;
|
|
38
|
+
cors?: boolean | {
|
|
39
|
+
origin?: string | string[] | boolean;
|
|
40
|
+
methods?: string[];
|
|
41
|
+
credentials?: boolean;
|
|
42
|
+
};
|
|
43
|
+
onConnection?: (socket: unknown) => void;
|
|
44
|
+
onDisconnection?: (socket: unknown, reason: string) => void;
|
|
45
|
+
path?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface HealthCheckConfig {
|
|
48
|
+
path?: string;
|
|
49
|
+
customChecks?: HealthCheck[];
|
|
50
|
+
}
|
|
51
|
+
export interface HealthCheck {
|
|
52
|
+
name: string;
|
|
53
|
+
check: () => Promise<boolean>;
|
|
54
|
+
}
|
|
55
|
+
export interface GracefulShutdownConfig {
|
|
56
|
+
timeout?: number;
|
|
57
|
+
onShutdown?: () => Promise<void>;
|
|
58
|
+
serverName?: string;
|
|
59
|
+
serverVersion?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface SocketInstance {
|
|
62
|
+
id: string;
|
|
63
|
+
emit: (event: string, data?: unknown) => void;
|
|
64
|
+
on: (event: string, handler: (...args: unknown[]) => void) => void;
|
|
65
|
+
broadcast: {
|
|
66
|
+
emit: (event: string, data?: unknown) => void;
|
|
67
|
+
};
|
|
68
|
+
disconnect: () => void;
|
|
69
|
+
}
|
|
70
|
+
export type ServerPlugin = (app: express.Application, config: ServerConfig) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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, 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,37 @@
|
|
|
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;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PeriodicHealthCheckConfig } from './types';
|
|
2
|
+
export declare class PeriodicHealthMonitor {
|
|
3
|
+
private intervals;
|
|
4
|
+
private config;
|
|
5
|
+
private serviceName;
|
|
6
|
+
constructor(config: PeriodicHealthCheckConfig, serviceName: string);
|
|
7
|
+
start(): void;
|
|
8
|
+
stop(): void;
|
|
9
|
+
private checkServiceHealth;
|
|
10
|
+
getHealthStatus(): Promise<Record<string, boolean>>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { Server } from 'http';
|
|
3
|
+
import { ServerConfig, SocketIOConfig } from './types';
|
|
4
|
+
export interface GrpcService {
|
|
5
|
+
service: Record<string, unknown>;
|
|
6
|
+
implementation: Record<string, (...args: unknown[]) => unknown>;
|
|
7
|
+
}
|
|
8
|
+
export interface RpcMethod {
|
|
9
|
+
[key: string]: (params: unknown[], callback: (error: Error | null, result?: unknown) => void) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface WebhookConfig {
|
|
12
|
+
path: string;
|
|
13
|
+
secret?: string;
|
|
14
|
+
handler: (payload: Record<string, unknown>, headers: Record<string, string | string[]>) => void | Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export interface GrpcServerInstance {
|
|
17
|
+
start(): void;
|
|
18
|
+
forceShutdown(): void;
|
|
19
|
+
addService(service: unknown, implementation: unknown): void;
|
|
20
|
+
bindAsync(address: string, credentials: unknown, callback: () => void): void;
|
|
21
|
+
}
|
|
22
|
+
export interface ServerInstanceConfig extends Required<Omit<ServerConfig, 'socketIO' | 'name' | 'version'>> {
|
|
23
|
+
name: string;
|
|
24
|
+
version: string;
|
|
25
|
+
startTime: Date;
|
|
26
|
+
socketIO?: SocketIOConfig;
|
|
27
|
+
}
|
|
28
|
+
export interface ServerInstance {
|
|
29
|
+
app: express.Application;
|
|
30
|
+
server?: Server;
|
|
31
|
+
config: ServerInstanceConfig;
|
|
32
|
+
start(): Promise<ServerInstance>;
|
|
33
|
+
stop(): Promise<void>;
|
|
34
|
+
getInfo(): ServerInfo;
|
|
35
|
+
addGrpcService(service: Record<string, unknown>, implementation: Record<string, (...args: unknown[]) => unknown>, port?: number): void;
|
|
36
|
+
addRpcMethods(methods: RpcMethod, path?: string): void;
|
|
37
|
+
addWebhook(config: WebhookConfig): void;
|
|
38
|
+
addSocketIO(config?: SocketIOConfig): unknown;
|
|
39
|
+
}
|
|
40
|
+
export interface ServerInfo {
|
|
41
|
+
name: string;
|
|
42
|
+
version: string;
|
|
43
|
+
port: number;
|
|
44
|
+
uptime: number;
|
|
45
|
+
status: 'starting' | 'running' | 'stopping' | 'stopped';
|
|
46
|
+
startTime: Date;
|
|
47
|
+
}
|
|
48
|
+
export declare class ExpressServer implements ServerInstance {
|
|
49
|
+
app: express.Application;
|
|
50
|
+
server?: Server;
|
|
51
|
+
config: ServerInstanceConfig;
|
|
52
|
+
private status;
|
|
53
|
+
private grpcServices;
|
|
54
|
+
private grpcServer?;
|
|
55
|
+
private rpcMethods;
|
|
56
|
+
private socketIO?;
|
|
57
|
+
private healthMonitor?;
|
|
58
|
+
constructor(name?: string, version?: string, config?: ServerConfig);
|
|
59
|
+
private setupMiddleware;
|
|
60
|
+
private setupPeriodicHealthMonitoring;
|
|
61
|
+
start(): Promise<ServerInstance>;
|
|
62
|
+
stop(): Promise<void>;
|
|
63
|
+
getInfo(): ServerInfo;
|
|
64
|
+
addGrpcService(service: Record<string, unknown>, implementation: Record<string, (...args: unknown[]) => unknown>, port?: number): void;
|
|
65
|
+
addRpcMethods(methods: RpcMethod, path?: string): void;
|
|
66
|
+
addWebhook(config: WebhookConfig): void;
|
|
67
|
+
addSocketIO(config?: SocketIOConfig): unknown;
|
|
68
|
+
}
|
|
69
|
+
export declare function createServer(name?: string, version?: string, config?: ServerConfig): ServerInstance;
|
|
@@ -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,70 @@
|
|
|
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
|
+
}
|
|
26
|
+
export interface PeriodicHealthCheckConfig {
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
interval?: number;
|
|
29
|
+
services?: HealthCheckService[];
|
|
30
|
+
}
|
|
31
|
+
export interface HealthCheckService {
|
|
32
|
+
name: string;
|
|
33
|
+
url: string;
|
|
34
|
+
timeout?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface SocketIOConfig {
|
|
37
|
+
enabled?: boolean;
|
|
38
|
+
cors?: boolean | {
|
|
39
|
+
origin?: string | string[] | boolean;
|
|
40
|
+
methods?: string[];
|
|
41
|
+
credentials?: boolean;
|
|
42
|
+
};
|
|
43
|
+
onConnection?: (socket: unknown) => void;
|
|
44
|
+
onDisconnection?: (socket: unknown, reason: string) => void;
|
|
45
|
+
path?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface HealthCheckConfig {
|
|
48
|
+
path?: string;
|
|
49
|
+
customChecks?: HealthCheck[];
|
|
50
|
+
}
|
|
51
|
+
export interface HealthCheck {
|
|
52
|
+
name: string;
|
|
53
|
+
check: () => Promise<boolean>;
|
|
54
|
+
}
|
|
55
|
+
export interface GracefulShutdownConfig {
|
|
56
|
+
timeout?: number;
|
|
57
|
+
onShutdown?: () => Promise<void>;
|
|
58
|
+
serverName?: string;
|
|
59
|
+
serverVersion?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface SocketInstance {
|
|
62
|
+
id: string;
|
|
63
|
+
emit: (event: string, data?: unknown) => void;
|
|
64
|
+
on: (event: string, handler: (...args: unknown[]) => void) => void;
|
|
65
|
+
broadcast: {
|
|
66
|
+
emit: (event: string, data?: unknown) => void;
|
|
67
|
+
};
|
|
68
|
+
disconnect: () => void;
|
|
69
|
+
}
|
|
70
|
+
export type ServerPlugin = (app: express.Application, config: ServerConfig) => void;
|
package/package.json
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naman_deep_singh/server-utils",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Extensible server utilities for Express.js microservices with TypeScript",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cjs/index.js",
|
|
7
|
+
"module": "./dist/esm/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/esm/index.js",
|
|
11
|
+
"require": "./dist/cjs/index.js",
|
|
12
|
+
"types": "./dist/types/index.d.ts"
|
|
13
|
+
}
|
|
9
14
|
},
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
10
20
|
"keywords": [
|
|
11
21
|
"server",
|
|
12
22
|
"express",
|
|
@@ -16,7 +26,6 @@
|
|
|
16
26
|
],
|
|
17
27
|
"author": "Naman Deep Singh",
|
|
18
28
|
"license": "ISC",
|
|
19
|
-
"packageManager": "pnpm@10.20.0",
|
|
20
29
|
"dependencies": {
|
|
21
30
|
"express": "^5.1.0",
|
|
22
31
|
"cors": "^2.8.5",
|
|
@@ -26,6 +35,12 @@
|
|
|
26
35
|
},
|
|
27
36
|
"devDependencies": {
|
|
28
37
|
"@types/cors": "^2.8.19",
|
|
29
|
-
"typescript": "^5.9.3"
|
|
38
|
+
"typescript": "^5.9.3",
|
|
39
|
+
"rimraf": "^5.0.5"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "pnpm run build:types && tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json",
|
|
43
|
+
"build:types": "tsc -p tsconfig.base.json --emitDeclarationOnly --outDir dist/types",
|
|
44
|
+
"clean": "rimraf dist"
|
|
30
45
|
}
|
|
31
46
|
}
|
package/src/health.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
import { HealthCheckConfig, HealthCheck, ServerPlugin } from './types';
|
|
3
|
-
|
|
4
|
-
export function createHealthCheck(config: HealthCheckConfig = {}): express.RequestHandler {
|
|
5
|
-
const { customChecks = [] } = config;
|
|
6
|
-
|
|
7
|
-
return async (req: express.Request, res: express.Response) => {
|
|
8
|
-
try {
|
|
9
|
-
const checks: Record<string, boolean> = {
|
|
10
|
-
server: true,
|
|
11
|
-
timestamp: Date.now() as any
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
// Run custom health checks
|
|
15
|
-
for (const check of customChecks) {
|
|
16
|
-
try {
|
|
17
|
-
checks[check.name] = await check.check();
|
|
18
|
-
} catch (error) {
|
|
19
|
-
checks[check.name] = false;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const isHealthy = Object.values(checks).every(status => status === true || typeof status === 'number');
|
|
24
|
-
|
|
25
|
-
res.status(isHealthy ? 200 : 503).json({
|
|
26
|
-
status: isHealthy ? 'healthy' : 'unhealthy',
|
|
27
|
-
checks
|
|
28
|
-
});
|
|
29
|
-
} catch (error) {
|
|
30
|
-
res.status(503).json({
|
|
31
|
-
status: 'unhealthy',
|
|
32
|
-
error: 'Health check failed'
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function withHealthCheck(path: string = '/health', config: HealthCheckConfig = {}): ServerPlugin {
|
|
39
|
-
return (app: express.Application) => {
|
|
40
|
-
app.get(path, createHealthCheck(config));
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Convenience function for direct use
|
|
45
|
-
export function addHealthCheck(app: express.Application, path: string = '/health', config: HealthCheckConfig = {}): void {
|
|
46
|
-
app.get(path, createHealthCheck(config));
|
|
47
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
// Core server utilities
|
|
2
|
-
export { ExpressServer, createServer } from './server';
|
|
3
|
-
export type { ServerInstance, ServerInfo, GrpcService, RpcMethod, WebhookConfig } from './server';
|
|
4
|
-
|
|
5
|
-
// Express re-exports (to avoid direct Express dependency in services)
|
|
6
|
-
export { Request, Response, NextFunction, Router, Application } from 'express';
|
|
7
|
-
export type { RequestHandler, ErrorRequestHandler } from 'express';
|
|
8
|
-
|
|
9
|
-
// Health check utilities
|
|
10
|
-
export { createHealthCheck, withHealthCheck, addHealthCheck } from './health';
|
|
11
|
-
|
|
12
|
-
// Graceful shutdown utilities
|
|
13
|
-
export { createGracefulShutdown, withGracefulShutdown, startServerWithShutdown } from './shutdown';
|
|
14
|
-
|
|
15
|
-
// Middleware utilities
|
|
16
|
-
export {
|
|
17
|
-
createLoggingMiddleware,
|
|
18
|
-
createErrorHandler,
|
|
19
|
-
createRequestIdMiddleware,
|
|
20
|
-
createValidationMiddleware,
|
|
21
|
-
createRateLimitMiddleware,
|
|
22
|
-
createAuthMiddleware,
|
|
23
|
-
withLogging,
|
|
24
|
-
withErrorHandler,
|
|
25
|
-
withRequestId,
|
|
26
|
-
withValidation,
|
|
27
|
-
withRateLimit,
|
|
28
|
-
withAuth,
|
|
29
|
-
validateFields,
|
|
30
|
-
rateLimit,
|
|
31
|
-
requireAuth,
|
|
32
|
-
type ValidationRule,
|
|
33
|
-
type RateLimitConfig,
|
|
34
|
-
type AuthConfig
|
|
35
|
-
} from './middleware';
|
|
36
|
-
|
|
37
|
-
// Utility functions
|
|
38
|
-
export {
|
|
39
|
-
getEnv,
|
|
40
|
-
getEnvNumber,
|
|
41
|
-
getEnvBoolean
|
|
42
|
-
} from './utils';
|
|
43
|
-
|
|
44
|
-
// Periodic health monitoring
|
|
45
|
-
export { PeriodicHealthMonitor } from './periodic-health';
|
|
46
|
-
|
|
47
|
-
// Types
|
|
48
|
-
export type {
|
|
49
|
-
ServerConfig,
|
|
50
|
-
HealthCheckConfig,
|
|
51
|
-
HealthCheck,
|
|
52
|
-
GracefulShutdownConfig,
|
|
53
|
-
ServerPlugin,
|
|
54
|
-
SocketIOConfig,
|
|
55
|
-
SocketInstance,
|
|
56
|
-
PeriodicHealthCheckConfig,
|
|
57
|
-
HealthCheckService
|
|
58
|
-
} from './types';
|
|
59
|
-
|
|
60
|
-
// Import all exports for default export
|
|
61
|
-
import { ExpressServer, createServer } from './server';
|
|
62
|
-
import { createHealthCheck, withHealthCheck, addHealthCheck } from './health';
|
|
63
|
-
import { createGracefulShutdown, withGracefulShutdown, startServerWithShutdown } from './shutdown';
|
|
64
|
-
import {
|
|
65
|
-
createLoggingMiddleware,
|
|
66
|
-
createErrorHandler,
|
|
67
|
-
createRequestIdMiddleware,
|
|
68
|
-
createValidationMiddleware,
|
|
69
|
-
createRateLimitMiddleware,
|
|
70
|
-
createAuthMiddleware,
|
|
71
|
-
withLogging,
|
|
72
|
-
withErrorHandler,
|
|
73
|
-
withRequestId,
|
|
74
|
-
withValidation,
|
|
75
|
-
withRateLimit,
|
|
76
|
-
withAuth,
|
|
77
|
-
validateFields,
|
|
78
|
-
rateLimit,
|
|
79
|
-
requireAuth
|
|
80
|
-
} from './middleware';
|
|
81
|
-
import { getEnv, getEnvNumber, getEnvBoolean } from './utils';
|
|
82
|
-
import { PeriodicHealthMonitor } from './periodic-health';
|
|
83
|
-
|
|
84
|
-
// Default export for namespace usage
|
|
85
|
-
const ServerUtils = {
|
|
86
|
-
// Server creation
|
|
87
|
-
createServer,
|
|
88
|
-
ExpressServer,
|
|
89
|
-
|
|
90
|
-
// Health checks
|
|
91
|
-
createHealthCheck,
|
|
92
|
-
withHealthCheck,
|
|
93
|
-
addHealthCheck,
|
|
94
|
-
|
|
95
|
-
// Graceful shutdown
|
|
96
|
-
createGracefulShutdown,
|
|
97
|
-
withGracefulShutdown,
|
|
98
|
-
startServerWithShutdown,
|
|
99
|
-
|
|
100
|
-
// Middleware
|
|
101
|
-
createLoggingMiddleware,
|
|
102
|
-
createErrorHandler,
|
|
103
|
-
createRequestIdMiddleware,
|
|
104
|
-
createValidationMiddleware,
|
|
105
|
-
createRateLimitMiddleware,
|
|
106
|
-
createAuthMiddleware,
|
|
107
|
-
withLogging,
|
|
108
|
-
withErrorHandler,
|
|
109
|
-
withRequestId,
|
|
110
|
-
withValidation,
|
|
111
|
-
withRateLimit,
|
|
112
|
-
withAuth,
|
|
113
|
-
validateFields,
|
|
114
|
-
rateLimit,
|
|
115
|
-
requireAuth,
|
|
116
|
-
|
|
117
|
-
// Utils
|
|
118
|
-
getEnv,
|
|
119
|
-
getEnvNumber,
|
|
120
|
-
getEnvBoolean,
|
|
121
|
-
|
|
122
|
-
// Periodic Health Monitoring
|
|
123
|
-
PeriodicHealthMonitor,
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
export default ServerUtils;
|