@veloxts/core 0.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.
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Core TypeScript types for the VeloxTS framework
3
+ * @module types
4
+ */
5
+ import type { FastifyReply, FastifyRequest } from 'fastify';
6
+ /**
7
+ * Primitive JSON value types
8
+ */
9
+ export type JsonPrimitive = string | number | boolean | null;
10
+ /**
11
+ * JSON-serializable array type
12
+ */
13
+ export type JsonArray = JsonValue[];
14
+ /**
15
+ * JSON-serializable object type
16
+ */
17
+ export type JsonObject = {
18
+ [key: string]: JsonValue;
19
+ };
20
+ /**
21
+ * Any JSON-serializable value
22
+ *
23
+ * Represents values that can be safely serialized to JSON and sent in HTTP responses.
24
+ * Use this type to ensure handler return values are serializable.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // Valid JsonValue examples
29
+ * const str: JsonValue = "hello";
30
+ * const num: JsonValue = 42;
31
+ * const arr: JsonValue = [1, 2, 3];
32
+ * const obj: JsonValue = { name: "John", age: 30 };
33
+ *
34
+ * // Invalid - functions are not JSON serializable
35
+ * // const fn: JsonValue = () => {}; // Error!
36
+ * ```
37
+ */
38
+ export type JsonValue = JsonPrimitive | JsonArray | JsonObject;
39
+ /**
40
+ * Async request handler function signature
41
+ *
42
+ * Handlers return JSON-serializable data or void. The response type
43
+ * can be narrowed for better type safety in specific handlers.
44
+ *
45
+ * @template TContext - The context type available in the handler
46
+ * @template TResponse - The response type (must be JSON serializable or void)
47
+ * @param request - Fastify request object with context
48
+ * @param reply - Fastify reply object
49
+ * @returns Promise resolving to response data or void
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // Handler with inferred response type
54
+ * const handler: AsyncHandler<BaseContext> = async (request, reply) => {
55
+ * return { message: 'Hello World' };
56
+ * };
57
+ *
58
+ * // Handler with explicit response type
59
+ * type UserResponse = { id: string; name: string };
60
+ * const getUser: AsyncHandler<BaseContext, UserResponse> = async (request) => {
61
+ * return { id: '1', name: 'John' };
62
+ * };
63
+ * ```
64
+ */
65
+ export type AsyncHandler<TContext = unknown, TResponse extends JsonValue | undefined = JsonValue | undefined> = (request: FastifyRequest & {
66
+ context: TContext;
67
+ }, reply: FastifyReply) => Promise<TResponse>;
68
+ /**
69
+ * Synchronous request handler function signature
70
+ *
71
+ * @template TContext - The context type available in the handler
72
+ * @template TResponse - The response type (must be JSON serializable or void)
73
+ * @param request - Fastify request object with context
74
+ * @param reply - Fastify reply object
75
+ * @returns Response data or void
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * const handler: SyncHandler<BaseContext> = (request, reply) => {
80
+ * return { message: 'Hello World' };
81
+ * };
82
+ * ```
83
+ */
84
+ export type SyncHandler<TContext = unknown, TResponse extends JsonValue | undefined = JsonValue | undefined> = (request: FastifyRequest & {
85
+ context: TContext;
86
+ }, reply: FastifyReply) => TResponse;
87
+ /**
88
+ * Lifecycle hook function signature
89
+ * Hooks are called at specific points in the request/response lifecycle
90
+ *
91
+ * @param request - Fastify request object
92
+ * @param reply - Fastify reply object
93
+ * @returns Promise that resolves when hook processing is complete
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * const hook: LifecycleHook = async (request, reply) => {
98
+ * console.log('Request received:', request.url);
99
+ * };
100
+ * ```
101
+ */
102
+ export type LifecycleHook = (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
103
+ /**
104
+ * Shutdown handler function signature
105
+ * Called during graceful shutdown to clean up resources
106
+ *
107
+ * @returns Promise that resolves when cleanup is complete
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * const shutdownHandler: ShutdownHandler = async () => {
112
+ * await database.disconnect();
113
+ * console.log('Database connection closed');
114
+ * };
115
+ * ```
116
+ */
117
+ export type ShutdownHandler = () => Promise<void>;
118
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAM5D;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAM/D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,MAAM,YAAY,CACtB,QAAQ,GAAG,OAAO,EAClB,SAAS,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,IAC7D,CAAC,OAAO,EAAE,cAAc,GAAG;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAEjG;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,WAAW,CACrB,QAAQ,GAAG,OAAO,EAClB,SAAS,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,IAC7D,CAAC,OAAO,EAAE,cAAc,GAAG;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,EAAE,KAAK,EAAE,YAAY,KAAK,SAAS,CAAC;AAMxF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5F;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Core TypeScript types for the VeloxTS framework
3
+ * @module types
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Configuration types and utilities for VeloxTS application
3
+ * @module utils/config
4
+ */
5
+ import type { FastifyLoggerOptions, FastifyServerOptions } from 'fastify';
6
+ /**
7
+ * Brand symbol for validated port numbers
8
+ */
9
+ declare const ValidPortBrand: unique symbol;
10
+ /**
11
+ * Branded type for validated port numbers (0-65535)
12
+ *
13
+ * Values of this type have been validated and are guaranteed to be
14
+ * valid port numbers. Use `isValidPort()` to narrow a number to this type.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * function listen(port: ValidPort) {
19
+ * // port is guaranteed to be 0-65535
20
+ * }
21
+ *
22
+ * const port = 3000;
23
+ * if (isValidPort(port)) {
24
+ * listen(port); // TypeScript knows port is ValidPort here
25
+ * }
26
+ * ```
27
+ */
28
+ export type ValidPort = number & {
29
+ readonly [ValidPortBrand]: typeof ValidPortBrand;
30
+ };
31
+ /**
32
+ * Brand symbol for validated host strings
33
+ */
34
+ declare const ValidHostBrand: unique symbol;
35
+ /**
36
+ * Branded type for validated host strings
37
+ *
38
+ * Values of this type have been validated and are guaranteed to be
39
+ * non-empty strings. Use `isValidHost()` to narrow a string to this type.
40
+ */
41
+ export type ValidHost = string & {
42
+ readonly [ValidHostBrand]: typeof ValidHostBrand;
43
+ };
44
+ /**
45
+ * VeloxTS-specific Fastify options (excluding options VeloxTS controls)
46
+ *
47
+ * The `logger` option is excluded because VeloxTS controls logging
48
+ * through the top-level `logger` configuration option.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const config: VeloxAppConfig = {
53
+ * logger: true, // Use this for logging
54
+ * fastify: {
55
+ * // logger is NOT allowed here - TypeScript will error
56
+ * trustProxy: true,
57
+ * maxParamLength: 200,
58
+ * }
59
+ * };
60
+ * ```
61
+ */
62
+ export type VeloxFastifyOptions = Omit<FastifyServerOptions, 'logger'>;
63
+ /**
64
+ * Configuration options for creating a VeloxTS application
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const config: VeloxAppConfig = {
69
+ * port: 3000,
70
+ * host: '0.0.0.0',
71
+ * logger: true
72
+ * };
73
+ * ```
74
+ */
75
+ export interface VeloxAppConfig {
76
+ /**
77
+ * Port to listen on
78
+ * @default 3000
79
+ */
80
+ port?: number;
81
+ /**
82
+ * Host to bind to
83
+ * @default '0.0.0.0'
84
+ */
85
+ host?: string;
86
+ /**
87
+ * Enable Fastify logger
88
+ * - `true` enables default logger
89
+ * - `false` disables logging
90
+ * - Object provides custom logger configuration
91
+ *
92
+ * @default true in development, false in production
93
+ */
94
+ logger?: boolean | FastifyLoggerOptions;
95
+ /**
96
+ * Custom Fastify options (escape hatch for advanced usage)
97
+ * Allows full control over Fastify server configuration.
98
+ *
99
+ * Note: The `logger` option should be set via the top-level `logger`
100
+ * config, not here. TypeScript will prevent setting it in `fastify`.
101
+ *
102
+ * @default {}
103
+ */
104
+ fastify?: VeloxFastifyOptions;
105
+ }
106
+ /**
107
+ * Deeply readonly version of VeloxAppConfig after merging with defaults
108
+ *
109
+ * Configuration is frozen after initialization to prevent accidental mutation.
110
+ */
111
+ export type FrozenVeloxAppConfig = Readonly<{
112
+ port: ValidPort;
113
+ host: ValidHost;
114
+ logger: boolean | FastifyLoggerOptions;
115
+ fastify: VeloxFastifyOptions;
116
+ }>;
117
+ /**
118
+ * Default configuration values
119
+ */
120
+ export declare const DEFAULT_CONFIG: {
121
+ readonly port: 3000;
122
+ readonly host: "0.0.0.0";
123
+ readonly logger: boolean;
124
+ };
125
+ /**
126
+ * Type guard that validates and narrows port to ValidPort
127
+ *
128
+ * @param port - Port number to validate
129
+ * @returns true if port is valid (0-65535), narrowing to ValidPort
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * const port = 3000;
134
+ * if (isValidPort(port)) {
135
+ * // port is narrowed to ValidPort
136
+ * startServer(port);
137
+ * }
138
+ * ```
139
+ */
140
+ export declare function isValidPort(port: number): port is ValidPort;
141
+ /**
142
+ * Type guard that validates and narrows host to ValidHost
143
+ *
144
+ * @param host - Host string to validate
145
+ * @returns true if host is valid (non-empty string), narrowing to ValidHost
146
+ */
147
+ export declare function isValidHost(host: string): host is ValidHost;
148
+ /**
149
+ * Merges user configuration with defaults
150
+ *
151
+ * @param userConfig - User-provided configuration
152
+ * @returns Complete configuration with defaults applied (not yet validated)
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * const config = mergeConfig({ port: 4000 });
157
+ * // Result: { port: 4000, host: '0.0.0.0', logger: true, fastify: {} }
158
+ * ```
159
+ */
160
+ export declare function mergeConfig(userConfig?: VeloxAppConfig): Required<VeloxAppConfig>;
161
+ /**
162
+ * Validates configuration and returns a frozen, type-safe config object
163
+ *
164
+ * The returned config has branded types that guarantee validation has occurred.
165
+ * The object is frozen at runtime to prevent accidental mutation.
166
+ *
167
+ * @param config - Configuration to validate
168
+ * @returns Frozen configuration with branded types
169
+ * @throws {Error} If configuration is invalid
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * const merged = mergeConfig({ port: 3000 });
174
+ * const validated = validateConfig(merged);
175
+ * // validated.port is ValidPort (branded type)
176
+ * // validated is frozen (immutable at runtime)
177
+ * ```
178
+ */
179
+ export declare function validateConfig(config: Required<VeloxAppConfig>): FrozenVeloxAppConfig;
180
+ export {};
181
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAM1E;;GAEG;AACH,OAAO,CAAC,MAAM,cAAc,EAAE,OAAO,MAAM,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,OAAO,cAAc,CAAA;CAAE,CAAC;AAEtF;;GAEG;AACH,OAAO,CAAC,MAAM,cAAc,EAAE,OAAO,MAAM,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,OAAO,cAAc,CAAA;CAAE,CAAC;AAMtF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC;AAMvE;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAC;IAExC;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,OAAO,GAAG,oBAAoB,CAAC;IACvC,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,cAAc;;;;CAIjB,CAAC;AAMX;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,SAAS,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,SAAS,CAE3D;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,UAAU,GAAE,cAAmB,GAAG,QAAQ,CAAC,cAAc,CAAC,CAOrF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,oBAAoB,CAgBrF"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Configuration types and utilities for VeloxTS application
3
+ * @module utils/config
4
+ */
5
+ /**
6
+ * Default configuration values
7
+ */
8
+ export const DEFAULT_CONFIG = {
9
+ port: 3000,
10
+ host: '0.0.0.0',
11
+ logger: process.env.NODE_ENV !== 'production',
12
+ };
13
+ // ============================================================================
14
+ // Type Guards (Branded Type Validators)
15
+ // ============================================================================
16
+ /**
17
+ * Type guard that validates and narrows port to ValidPort
18
+ *
19
+ * @param port - Port number to validate
20
+ * @returns true if port is valid (0-65535), narrowing to ValidPort
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const port = 3000;
25
+ * if (isValidPort(port)) {
26
+ * // port is narrowed to ValidPort
27
+ * startServer(port);
28
+ * }
29
+ * ```
30
+ */
31
+ export function isValidPort(port) {
32
+ return Number.isInteger(port) && port >= 0 && port <= 65535;
33
+ }
34
+ /**
35
+ * Type guard that validates and narrows host to ValidHost
36
+ *
37
+ * @param host - Host string to validate
38
+ * @returns true if host is valid (non-empty string), narrowing to ValidHost
39
+ */
40
+ export function isValidHost(host) {
41
+ return typeof host === 'string' && host.length > 0;
42
+ }
43
+ // ============================================================================
44
+ // Configuration Functions
45
+ // ============================================================================
46
+ /**
47
+ * Merges user configuration with defaults
48
+ *
49
+ * @param userConfig - User-provided configuration
50
+ * @returns Complete configuration with defaults applied (not yet validated)
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const config = mergeConfig({ port: 4000 });
55
+ * // Result: { port: 4000, host: '0.0.0.0', logger: true, fastify: {} }
56
+ * ```
57
+ */
58
+ export function mergeConfig(userConfig = {}) {
59
+ return {
60
+ port: userConfig.port ?? DEFAULT_CONFIG.port,
61
+ host: userConfig.host ?? DEFAULT_CONFIG.host,
62
+ logger: userConfig.logger ?? DEFAULT_CONFIG.logger,
63
+ fastify: userConfig.fastify ?? {},
64
+ };
65
+ }
66
+ /**
67
+ * Validates configuration and returns a frozen, type-safe config object
68
+ *
69
+ * The returned config has branded types that guarantee validation has occurred.
70
+ * The object is frozen at runtime to prevent accidental mutation.
71
+ *
72
+ * @param config - Configuration to validate
73
+ * @returns Frozen configuration with branded types
74
+ * @throws {Error} If configuration is invalid
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const merged = mergeConfig({ port: 3000 });
79
+ * const validated = validateConfig(merged);
80
+ * // validated.port is ValidPort (branded type)
81
+ * // validated is frozen (immutable at runtime)
82
+ * ```
83
+ */
84
+ export function validateConfig(config) {
85
+ if (!isValidPort(config.port)) {
86
+ throw new Error(`Invalid port number: ${config.port}. Must be between 0 and 65535.`);
87
+ }
88
+ if (!isValidHost(config.host)) {
89
+ throw new Error('Host must be a non-empty string.');
90
+ }
91
+ // Return frozen config with branded types
92
+ return Object.freeze({
93
+ port: config.port, // Already narrowed to ValidPort by isValidPort
94
+ host: config.host, // Already narrowed to ValidHost by isValidHost
95
+ logger: config.logger,
96
+ fastify: config.fastify,
97
+ });
98
+ }
99
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqIH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;CACrC,CAAC;AAEX,+EAA+E;AAC/E,wCAAwC;AACxC,+EAA+E;AAE/E;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;AACrD,CAAC;AAED,+EAA+E;AAC/E,0BAA0B;AAC1B,+EAA+E;AAE/E;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,aAA6B,EAAE;IACzD,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,cAAc,CAAC,IAAI;QAC5C,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,cAAc,CAAC,IAAI;QAC5C,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,cAAc,CAAC,MAAM;QAClD,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,EAAE;KAClC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAAC,MAAgC;IAC7D,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,CAAC,IAAI,gCAAgC,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,0CAA0C;IAC1C,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,+CAA+C;QAClE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,+CAA+C;QAClE,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Lifecycle management utilities for VeloxTS application
3
+ * Handles graceful shutdown and cleanup
4
+ * @module utils/lifecycle
5
+ */
6
+ import type { ShutdownHandler } from '../types.js';
7
+ /**
8
+ * Manages graceful shutdown for the VeloxTS application
9
+ *
10
+ * Coordinates cleanup of resources when the application is stopped,
11
+ * either programmatically or via system signals (SIGINT, SIGTERM)
12
+ */
13
+ export declare class LifecycleManager {
14
+ private readonly shutdownHandlers;
15
+ private readonly signalHandlers;
16
+ private isShuttingDown;
17
+ private static readonly MAX_SHUTDOWN_HANDLERS;
18
+ /**
19
+ * Adds a shutdown handler to be called during graceful shutdown
20
+ *
21
+ * Handlers are called in insertion order. Duplicate handlers are
22
+ * automatically prevented.
23
+ *
24
+ * @param handler - Async function to call during shutdown
25
+ * @throws {Error} If maximum number of handlers is exceeded
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * lifecycleManager.addShutdownHandler(async () => {
30
+ * await database.disconnect();
31
+ * console.log('Database connection closed');
32
+ * });
33
+ * ```
34
+ */
35
+ addShutdownHandler(handler: ShutdownHandler): void;
36
+ /**
37
+ * Removes a shutdown handler
38
+ *
39
+ * @param handler - Handler to remove
40
+ * @returns true if handler was removed, false if not found
41
+ */
42
+ removeShutdownHandler(handler: ShutdownHandler): boolean;
43
+ /**
44
+ * Executes all shutdown handlers in sequence
45
+ *
46
+ * Called automatically during server stop() or when receiving
47
+ * termination signals (SIGINT, SIGTERM)
48
+ *
49
+ * @internal
50
+ */
51
+ executeShutdownHandlers(): Promise<void>;
52
+ /**
53
+ * Sets up process signal handlers for graceful shutdown
54
+ *
55
+ * Listens for SIGINT (Ctrl+C) and SIGTERM (kill command) and
56
+ * executes shutdown sequence before exiting
57
+ *
58
+ * @param onShutdown - Callback to execute during shutdown
59
+ *
60
+ * @internal
61
+ */
62
+ setupSignalHandlers(onShutdown: () => Promise<void>): void;
63
+ /**
64
+ * Removes all signal handlers
65
+ *
66
+ * Should be called during stop() to prevent memory leaks in test environments
67
+ *
68
+ * @internal
69
+ */
70
+ cleanupSignalHandlers(): void;
71
+ /**
72
+ * Clears all registered shutdown handlers
73
+ *
74
+ * @internal
75
+ */
76
+ clearHandlers(): void;
77
+ }
78
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/utils/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmC;IACpE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA8C;IAC7E,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAQ;IAErD;;;;;;;;;;;;;;;;OAgBG;IACH,kBAAkB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAalD;;;;;OAKG;IACH,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO;IAIxD;;;;;;;OAOG;IACG,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB9C;;;;;;;;;OASG;IACH,mBAAmB,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAuB1D;;;;;;OAMG;IACH,qBAAqB,IAAI,IAAI;IAO7B;;;;OAIG;IACH,aAAa,IAAI,IAAI;CAGtB"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Lifecycle management utilities for VeloxTS application
3
+ * Handles graceful shutdown and cleanup
4
+ * @module utils/lifecycle
5
+ */
6
+ /**
7
+ * Manages graceful shutdown for the VeloxTS application
8
+ *
9
+ * Coordinates cleanup of resources when the application is stopped,
10
+ * either programmatically or via system signals (SIGINT, SIGTERM)
11
+ */
12
+ export class LifecycleManager {
13
+ shutdownHandlers = new Set();
14
+ signalHandlers = new Map();
15
+ isShuttingDown = false;
16
+ static MAX_SHUTDOWN_HANDLERS = 1000;
17
+ /**
18
+ * Adds a shutdown handler to be called during graceful shutdown
19
+ *
20
+ * Handlers are called in insertion order. Duplicate handlers are
21
+ * automatically prevented.
22
+ *
23
+ * @param handler - Async function to call during shutdown
24
+ * @throws {Error} If maximum number of handlers is exceeded
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * lifecycleManager.addShutdownHandler(async () => {
29
+ * await database.disconnect();
30
+ * console.log('Database connection closed');
31
+ * });
32
+ * ```
33
+ */
34
+ addShutdownHandler(handler) {
35
+ // Prevent memory leaks from unbounded growth
36
+ if (this.shutdownHandlers.size >= LifecycleManager.MAX_SHUTDOWN_HANDLERS) {
37
+ throw new Error(`Maximum number of shutdown handlers (${LifecycleManager.MAX_SHUTDOWN_HANDLERS}) exceeded. ` +
38
+ 'This may indicate a memory leak.');
39
+ }
40
+ // Set automatically prevents duplicates
41
+ this.shutdownHandlers.add(handler);
42
+ }
43
+ /**
44
+ * Removes a shutdown handler
45
+ *
46
+ * @param handler - Handler to remove
47
+ * @returns true if handler was removed, false if not found
48
+ */
49
+ removeShutdownHandler(handler) {
50
+ return this.shutdownHandlers.delete(handler);
51
+ }
52
+ /**
53
+ * Executes all shutdown handlers in sequence
54
+ *
55
+ * Called automatically during server stop() or when receiving
56
+ * termination signals (SIGINT, SIGTERM)
57
+ *
58
+ * @internal
59
+ */
60
+ async executeShutdownHandlers() {
61
+ if (this.isShuttingDown) {
62
+ return; // Already shutting down, avoid duplicate execution
63
+ }
64
+ this.isShuttingDown = true;
65
+ for (const handler of this.shutdownHandlers) {
66
+ try {
67
+ await handler();
68
+ }
69
+ catch (error) {
70
+ // Log error but continue with other handlers
71
+ console.error('Error during shutdown handler execution:', error);
72
+ }
73
+ }
74
+ this.isShuttingDown = false;
75
+ }
76
+ /**
77
+ * Sets up process signal handlers for graceful shutdown
78
+ *
79
+ * Listens for SIGINT (Ctrl+C) and SIGTERM (kill command) and
80
+ * executes shutdown sequence before exiting
81
+ *
82
+ * @param onShutdown - Callback to execute during shutdown
83
+ *
84
+ * @internal
85
+ */
86
+ setupSignalHandlers(onShutdown) {
87
+ const signals = ['SIGINT', 'SIGTERM'];
88
+ signals.forEach((signal) => {
89
+ const handler = async () => {
90
+ console.log(`\nReceived ${signal}, initiating graceful shutdown...`);
91
+ try {
92
+ await onShutdown();
93
+ console.log('Graceful shutdown completed');
94
+ process.exit(0);
95
+ }
96
+ catch (error) {
97
+ console.error('Error during graceful shutdown:', error);
98
+ process.exit(1);
99
+ }
100
+ };
101
+ // Store handler reference so it can be removed later
102
+ this.signalHandlers.set(signal, handler);
103
+ process.once(signal, handler);
104
+ });
105
+ }
106
+ /**
107
+ * Removes all signal handlers
108
+ *
109
+ * Should be called during stop() to prevent memory leaks in test environments
110
+ *
111
+ * @internal
112
+ */
113
+ cleanupSignalHandlers() {
114
+ for (const [signal, handler] of this.signalHandlers) {
115
+ process.removeListener(signal, handler);
116
+ }
117
+ this.signalHandlers.clear();
118
+ }
119
+ /**
120
+ * Clears all registered shutdown handlers
121
+ *
122
+ * @internal
123
+ */
124
+ clearHandlers() {
125
+ this.shutdownHandlers.clear();
126
+ }
127
+ }
128
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/utils/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;;GAKG;AACH,MAAM,OAAO,gBAAgB;IACV,gBAAgB,GAAyB,IAAI,GAAG,EAAE,CAAC;IACnD,cAAc,GAAoC,IAAI,GAAG,EAAE,CAAC;IACrE,cAAc,GAAG,KAAK,CAAC;IACvB,MAAM,CAAU,qBAAqB,GAAG,IAAI,CAAC;IAErD;;;;;;;;;;;;;;;;OAgBG;IACH,kBAAkB,CAAC,OAAwB;QACzC,6CAA6C;QAC7C,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,IAAI,gBAAgB,CAAC,qBAAqB,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CACb,wCAAwC,gBAAgB,CAAC,qBAAqB,cAAc;gBAC1F,kCAAkC,CACrC,CAAC;QACJ,CAAC;QAED,wCAAwC;QACxC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACH,qBAAqB,CAAC,OAAwB;QAC5C,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,uBAAuB;QAC3B,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,CAAC,mDAAmD;QAC7D,CAAC;QAED,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAE3B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC5C,IAAI,CAAC;gBACH,MAAM,OAAO,EAAE,CAAC;YAClB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,6CAA6C;gBAC7C,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QAED,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;IAC9B,CAAC;IAED;;;;;;;;;OASG;IACH,mBAAmB,CAAC,UAA+B;QACjD,MAAM,OAAO,GAAqB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAExD,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YACzB,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;gBACzB,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,mCAAmC,CAAC,CAAC;gBAErE,IAAI,CAAC;oBACH,MAAM,UAAU,EAAE,CAAC;oBACnB,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;oBAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;oBACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;YACH,CAAC,CAAC;YAEF,qDAAqD;YACrD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,qBAAqB;QACnB,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACpD,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACH,aAAa;QACX,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;IAChC,CAAC"}