@catbee/utils 2.0.0-next.0 → 2.0.0-next.1
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 +52 -16
- package/array/index.cjs +180 -71
- package/array/index.d.ts +293 -1
- package/array/index.mjs +171 -72
- package/async/index.cjs +92 -36
- package/async/index.d.ts +275 -1
- package/async/index.mjs +92 -36
- package/cache/index.cjs +1 -1
- package/cache/index.d.ts +155 -1
- package/cache/index.mjs +2 -2
- package/config/index.cjs +78 -64
- package/config/index.d.ts +64 -2
- package/config/index.mjs +76 -64
- package/context-store/index.d.ts +192 -1
- package/crypto/index.d.ts +163 -1
- package/date/index.cjs +46 -1
- package/date/index.d.ts +190 -1
- package/date/index.mjs +45 -2
- package/decorators/index.cjs +1156 -18
- package/decorators/index.d.ts +684 -1
- package/decorators/index.mjs +1156 -18
- package/dir/index.cjs +4 -3
- package/dir/index.d.ts +195 -1
- package/dir/index.mjs +4 -3
- package/env/index.cjs +10 -26
- package/env/index.d.ts +379 -1
- package/env/index.mjs +10 -26
- package/exception/index.d.ts +232 -1
- package/fs/index.cjs +70 -36
- package/fs/index.d.ts +205 -1
- package/fs/index.mjs +64 -34
- package/http-status-codes/index.d.ts +267 -1
- package/id/index.d.ts +37 -1
- package/index.cjs +3 -3
- package/index.d.ts +1 -1
- package/index.mjs +1 -1
- package/logger/index.cjs +11 -11
- package/logger/index.d.ts +189 -1
- package/logger/index.mjs +12 -12
- package/middleware/index.d.ts +103 -1
- package/obj/index.cjs +150 -162
- package/obj/index.d.ts +136 -1
- package/obj/index.mjs +150 -162
- package/package.json +11 -11
- package/performance/index.cjs +2 -2
- package/performance/index.d.ts +138 -1
- package/performance/index.mjs +2 -2
- package/request/index.cjs +1 -1
- package/request/index.d.ts +241 -2
- package/request/index.mjs +1 -1
- package/response/index.d.ts +318 -2
- package/server/index.cjs +27 -23
- package/server/index.d.ts +785 -4
- package/server/index.mjs +28 -23
- package/stream/index.d.ts +90 -1
- package/string/index.d.ts +102 -1
- package/type/index.cjs +1 -1
- package/type/index.d.ts +107 -1
- package/type/index.mjs +1 -1
- package/types/index.d.ts +774 -4
- package/url/index.cjs +2 -4
- package/url/index.d.ts +142 -1
- package/url/index.mjs +2 -4
- package/{validate → validation}/index.cjs +89 -42
- package/{validate/validate.utils.d.ts → validation/index.d.ts} +32 -23
- package/{validate → validation}/index.mjs +85 -42
- package/array/array.utils.d.ts +0 -191
- package/async/async.utils.d.ts +0 -296
- package/cache/cache.utils.d.ts +0 -176
- package/config/config.d.ts +0 -57
- package/context-store/context-store.utils.d.ts +0 -212
- package/crypto/crypto.utils.d.ts +0 -183
- package/date/date.utils.d.ts +0 -190
- package/decorators/decorators.utils.d.ts +0 -705
- package/dir/dir.utils.d.ts +0 -216
- package/env/env.utils.d.ts +0 -400
- package/exception/exception.utils.d.ts +0 -253
- package/fs/fs.utils.d.ts +0 -196
- package/http-status-codes/http-status-codes.d.ts +0 -289
- package/id/id.utils.d.ts +0 -59
- package/logger/logger.utils.d.ts +0 -210
- package/middleware/middleware.utils.d.ts +0 -123
- package/obj/obj.utils.d.ts +0 -156
- package/performance/performance.utils.d.ts +0 -159
- package/request/request.utils.d.ts +0 -109
- package/response/response.utils.d.ts +0 -186
- package/server/server.builder.d.ts +0 -531
- package/server/server.d.ts +0 -303
- package/stream/stream.utils.d.ts +0 -111
- package/string/string.utils.d.ts +0 -124
- package/type/type.utils.d.ts +0 -129
- package/types/api-response.d.ts +0 -175
- package/types/common.d.ts +0 -148
- package/types/config.d.ts +0 -88
- package/types/server.d.ts +0 -291
- package/url/url.utils.d.ts +0 -164
- package/validate/index.d.ts +0 -25
package/types/index.d.ts
CHANGED
|
@@ -22,7 +22,777 @@
|
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
import { json, urlencoded, Request, Response, Express, NextFunction } from 'express';
|
|
26
|
+
import http from 'node:http';
|
|
27
|
+
import { ExpressServer } from '@catbee/utils/server';
|
|
28
|
+
import { HelmetOptions } from 'helmet';
|
|
29
|
+
import { CompressionOptions } from 'compression';
|
|
30
|
+
import { CookieParseOptions } from 'cookie-parser';
|
|
31
|
+
import { CorsOptions } from 'cors';
|
|
32
|
+
import { LoggerLevels } from '@catbee/utils/logger';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A type that represents a configurable toggle.
|
|
36
|
+
* Can be `true`, `false`, or a custom configuration object `T`.
|
|
37
|
+
*/
|
|
38
|
+
type ToggleConfig<T> = boolean | T;
|
|
39
|
+
/**
|
|
40
|
+
* A type representing a value that can be `null` or `undefined`.
|
|
41
|
+
*/
|
|
42
|
+
type Nullable<T> = T | null | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* A type representing a value that may or may not be present.
|
|
45
|
+
*/
|
|
46
|
+
type Optional<T> = T | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* A type that makes all properties of `T` deeply optional.
|
|
49
|
+
*/
|
|
50
|
+
type DeepPartial<T> = {
|
|
51
|
+
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* A type that makes all properties of `T` readonly, recursively.
|
|
55
|
+
*/
|
|
56
|
+
type DeepReadonly<T> = {
|
|
57
|
+
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* A type that converts a union of types into an intersection.
|
|
61
|
+
*/
|
|
62
|
+
type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
|
|
63
|
+
/**
|
|
64
|
+
* A type representing a promise or a plain value.
|
|
65
|
+
*/
|
|
66
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
67
|
+
/**
|
|
68
|
+
* A type representing a record with string keys and values of type `T`.
|
|
69
|
+
*/
|
|
70
|
+
type StringKeyedRecord<T> = Record<string, T>;
|
|
71
|
+
/**
|
|
72
|
+
* A type representing a function that returns `R` and optionally receives arguments `A`.
|
|
73
|
+
*/
|
|
74
|
+
type Func<A extends any[] = any[], R = any> = (...args: A) => R;
|
|
75
|
+
/**
|
|
76
|
+
* A type representing a partial pick from `T` (like Partial + Pick combined)
|
|
77
|
+
*/
|
|
78
|
+
type PartialPick<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>;
|
|
79
|
+
/**
|
|
80
|
+
* A type that deeply stringifies all properties of T or makes them null.
|
|
81
|
+
*/
|
|
82
|
+
type DeepStringifyOrNull<T> = T extends string | number | bigint | boolean | symbol | null | undefined ? string | null : T extends Array<infer U> ? Array<DeepStringifyOrNull<U>> : T extends object ? {
|
|
83
|
+
[K in keyof T]: DeepStringifyOrNull<T[K]>;
|
|
84
|
+
} : string | null;
|
|
85
|
+
/**
|
|
86
|
+
* A type representing a non-empty array of T.
|
|
87
|
+
*/
|
|
88
|
+
type NonEmptyArray<T> = [T, ...T[]];
|
|
89
|
+
/**
|
|
90
|
+
* A type representing the union of all property values of T.
|
|
91
|
+
*/
|
|
92
|
+
type ValueOf<T> = T[keyof T];
|
|
93
|
+
/**
|
|
94
|
+
* A type that makes all properties of T mutable (removes readonly).
|
|
95
|
+
*/
|
|
96
|
+
type Mutable<T> = {
|
|
97
|
+
-readonly [P in keyof T]: T[P];
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* A type that gets the keys of T whose values are assignable to U.
|
|
101
|
+
*/
|
|
102
|
+
type KeysOfType<T, U> = {
|
|
103
|
+
[K in keyof T]: T[K] extends U ? K : never;
|
|
104
|
+
}[keyof T];
|
|
105
|
+
/**
|
|
106
|
+
* Require at least one of the keys in K to be present in T.
|
|
107
|
+
*/
|
|
108
|
+
type RequireAtLeastOne<T, K extends keyof T = keyof T> = K extends keyof T ? {
|
|
109
|
+
[P in K]-?: T[P];
|
|
110
|
+
} & Omit<T, K> : never;
|
|
111
|
+
/**
|
|
112
|
+
* A record type with optional keys.
|
|
113
|
+
*/
|
|
114
|
+
type RecordOptional<K extends string | number | symbol, T> = {
|
|
115
|
+
[P in K]?: T;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Primitive types in TypeScript.
|
|
119
|
+
*/
|
|
120
|
+
type Primitive = string | number | boolean | bigint | symbol | undefined | null;
|
|
121
|
+
/**
|
|
122
|
+
* Recursively unwraps Promise types to get their resolved value type.
|
|
123
|
+
*/
|
|
124
|
+
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
|
|
125
|
+
/**
|
|
126
|
+
* Picks properties from T that are of type U.
|
|
127
|
+
*/
|
|
128
|
+
type PickByType<T, U> = {
|
|
129
|
+
[P in keyof T as T[P] extends U ? P : never]: T[P];
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Makes all properties of T required recursively.
|
|
133
|
+
*/
|
|
134
|
+
type DeepRequired<T> = {
|
|
135
|
+
[P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P];
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Checks if two types are exactly equal.
|
|
139
|
+
* Returns true or false as type.
|
|
140
|
+
*/
|
|
141
|
+
type IsEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? true : false;
|
|
142
|
+
/**
|
|
143
|
+
* Makes all properties of an object writable (removes readonly).
|
|
144
|
+
*/
|
|
145
|
+
type Writable<T> = {
|
|
146
|
+
-readonly [P in keyof T]: T[P];
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Makes specific keys K of type T optional.
|
|
150
|
+
*/
|
|
151
|
+
type Optional2<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
152
|
+
/**
|
|
153
|
+
* Creates a type with all properties of T except those with types assignable to U.
|
|
154
|
+
*/
|
|
155
|
+
type Without<T, U> = {
|
|
156
|
+
[P in keyof T as T[P] extends U ? never : P]: T[P];
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Server configuration for Catbee HTTP/Express server.
|
|
161
|
+
* Designed with secure and high-performance defaults for production use.
|
|
162
|
+
* All features remain fully overridable by consumers.
|
|
163
|
+
*/
|
|
164
|
+
interface CatbeeServerConfig {
|
|
165
|
+
/** Server port
|
|
166
|
+
* - **default**: `3000`
|
|
167
|
+
* - **env**: `SERVER_PORT` || `PORT`
|
|
168
|
+
*/
|
|
169
|
+
port: number;
|
|
170
|
+
/** Host address to bind the server
|
|
171
|
+
* - **default**: `'0.0.0.0'`
|
|
172
|
+
* - **env**: `SERVER_HOST` || `HOST`
|
|
173
|
+
*/
|
|
174
|
+
host?: string;
|
|
175
|
+
/** CORS configuration toggle or options
|
|
176
|
+
* - **default**: `false`
|
|
177
|
+
* - **env**: `SERVER_CORS_ENABLE`
|
|
178
|
+
* - `true` -> enable with default settings
|
|
179
|
+
* - `CorsOptions` -> enable with custom settings
|
|
180
|
+
*
|
|
181
|
+
* **example**:
|
|
182
|
+
* ```ts
|
|
183
|
+
* cors: {
|
|
184
|
+
* origin: 'https://example.com',
|
|
185
|
+
* methods: ['GET', 'POST'],
|
|
186
|
+
* credentials: true
|
|
187
|
+
* }
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
cors?: ToggleConfig<CorsOptions>;
|
|
191
|
+
/** Helmet security headers toggle or options
|
|
192
|
+
* - **default**: `false`
|
|
193
|
+
* - **env**: `SERVER_HELMET_ENABLE`
|
|
194
|
+
* - `true` -> enable with default settings
|
|
195
|
+
* - `HelmetOptions` -> enable with custom settings
|
|
196
|
+
*
|
|
197
|
+
* **example**:
|
|
198
|
+
* ```ts
|
|
199
|
+
* helmet: {
|
|
200
|
+
* contentSecurityPolicy: {
|
|
201
|
+
* directives: {
|
|
202
|
+
* defaultSrc: ["'self'"],
|
|
203
|
+
* scriptSrc: ["'self'", 'trusted.com']
|
|
204
|
+
* }
|
|
205
|
+
* }
|
|
206
|
+
* }
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
helmet?: ToggleConfig<HelmetOptions>;
|
|
210
|
+
/** HTTP response compression toggle or options
|
|
211
|
+
* - **default**: `false`
|
|
212
|
+
* - **env**: `SERVER_COMPRESSION_ENABLE`
|
|
213
|
+
* - `true` -> enable with default settings
|
|
214
|
+
* - `CompressionOptions` -> enable with custom settings
|
|
215
|
+
*
|
|
216
|
+
* **example**:
|
|
217
|
+
* ```ts
|
|
218
|
+
* compression: { level: 6 }
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
compression?: ToggleConfig<CompressionOptions>;
|
|
222
|
+
/** Body parser configuration for incoming requests
|
|
223
|
+
* - **default**: `{ json: { limit: '1mb' }, urlencoded: { extended: true, limit: '1mb' } }`
|
|
224
|
+
* - **env**:
|
|
225
|
+
* - `SERVER_BODY_PARSER_JSON_LIMIT`
|
|
226
|
+
* - `SERVER_BODY_PARSER_URLENCODED_LIMIT`
|
|
227
|
+
*/
|
|
228
|
+
bodyParser?: {
|
|
229
|
+
/** JSON body parser options
|
|
230
|
+
* - **default**: `{ limit: '1mb' }`
|
|
231
|
+
*/
|
|
232
|
+
json?: Parameters<typeof json>[0];
|
|
233
|
+
/** URL-encoded body parser options
|
|
234
|
+
* - **default**: `{ extended: true, limit: '1mb' }`
|
|
235
|
+
*/
|
|
236
|
+
urlencoded?: Parameters<typeof urlencoded>[0];
|
|
237
|
+
};
|
|
238
|
+
/** Cookie parser toggle or options
|
|
239
|
+
* - **default**: `false`
|
|
240
|
+
* - **env**: `SERVER_COOKIE_PARSER_ENABLE`
|
|
241
|
+
* - `true` -> enable with default decode
|
|
242
|
+
* - `CookieParseOptions` -> enable with custom settings
|
|
243
|
+
*
|
|
244
|
+
* **example**:
|
|
245
|
+
* ```ts
|
|
246
|
+
* cookieParser: {
|
|
247
|
+
* decode: (val) => decodeURIComponent(val)
|
|
248
|
+
* }
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
cookieParser?: ToggleConfig<CookieParseOptions>;
|
|
252
|
+
/** Trust proxy configuration
|
|
253
|
+
* - **default**: `false`
|
|
254
|
+
* - **env**: `SERVER_TRUST_PROXY_ENABLE`
|
|
255
|
+
* - `true` -> trust first proxy
|
|
256
|
+
* - `number` -> trust N proxies
|
|
257
|
+
* - `string | string[]` -> trust specific proxy IP(s)
|
|
258
|
+
*/
|
|
259
|
+
trustProxy?: boolean | number | string | string[];
|
|
260
|
+
/** Static folder serving configuration
|
|
261
|
+
* - **path**: file system path to serve
|
|
262
|
+
* - **route**: URL route prefix (default: "/")
|
|
263
|
+
* - **maxAge**: cache max age (default: 0)
|
|
264
|
+
* - **etag**: enable ETag headers (default: true)
|
|
265
|
+
* - **immutable**: enable immutable caching (default: false)
|
|
266
|
+
* - **lastModified**: enable last-modified caching (default: true)
|
|
267
|
+
* - **cacheControl**: enable Cache-Control headers (default: true)
|
|
268
|
+
*/
|
|
269
|
+
staticFolders?: Array<{
|
|
270
|
+
/** URL mount path prefix
|
|
271
|
+
* - **default**: `/`
|
|
272
|
+
*/
|
|
273
|
+
path?: string;
|
|
274
|
+
/** Local directory path to serve (required) */
|
|
275
|
+
directory: string;
|
|
276
|
+
/** Cache-Control max-age value
|
|
277
|
+
* - **default**: `0`
|
|
278
|
+
*/
|
|
279
|
+
maxAge?: string;
|
|
280
|
+
/** Enable ETag header
|
|
281
|
+
* - **default**: `true`
|
|
282
|
+
*/
|
|
283
|
+
etag?: boolean;
|
|
284
|
+
/** Immutable caching
|
|
285
|
+
* - **default**: `false`
|
|
286
|
+
*/
|
|
287
|
+
immutable?: boolean;
|
|
288
|
+
/** Last-Modified header support
|
|
289
|
+
* - **default**: `true`
|
|
290
|
+
*/
|
|
291
|
+
lastModified?: boolean;
|
|
292
|
+
/** Include Cache-Control header
|
|
293
|
+
* - **default**: `true`
|
|
294
|
+
*/
|
|
295
|
+
cacheControl?: boolean;
|
|
296
|
+
}>;
|
|
297
|
+
/** Enable microservice mode
|
|
298
|
+
* - **default**: `false`
|
|
299
|
+
* - **env**: `SERVER_IS_MICROSERVICE`
|
|
300
|
+
*/
|
|
301
|
+
isMicroservice?: boolean;
|
|
302
|
+
/** Application/service name used for logs, headers, and metrics
|
|
303
|
+
* - **default**: `'catbee_server'`
|
|
304
|
+
* - **env**: `SERVER_APP_NAME` or `npm_package_name`
|
|
305
|
+
*/
|
|
306
|
+
appName?: string;
|
|
307
|
+
/** Global headers applied to all responses
|
|
308
|
+
* - **default**: {}
|
|
309
|
+
* - **env**: `SERVER_GLOBAL_HEADERS` (JSON)
|
|
310
|
+
*/
|
|
311
|
+
globalHeaders?: Record<string, string | (() => string)>;
|
|
312
|
+
/** Rate limiting settings
|
|
313
|
+
* - **enable**: `false` - **env**: `SERVER_RATE_LIMIT_ENABLE`
|
|
314
|
+
* - **windowMs**: `900000` (15 minutes) - **env**: `SERVER_RATE_LIMIT_WINDOW_MS`
|
|
315
|
+
* - **max**: `100` - **env**: `SERVER_RATE_LIMIT_MAX`
|
|
316
|
+
* - **message**: `'Too many requests'` - **env**: `SERVER_RATE_LIMIT_MESSAGE`
|
|
317
|
+
* - **standardHeaders**: `true` - **env**: `SERVER_RATE_LIMIT_STANDARD_HEADERS`
|
|
318
|
+
* - **legacyHeaders**: `false` - **env**: `SERVER_RATE_LIMIT_LEGACY_HEADERS`
|
|
319
|
+
*/
|
|
320
|
+
rateLimit?: {
|
|
321
|
+
/** Enable rate-limiting
|
|
322
|
+
* - **default**: `false`
|
|
323
|
+
* - **env**: `SERVER_RATE_LIMIT_ENABLE`
|
|
324
|
+
*/
|
|
325
|
+
enable: boolean;
|
|
326
|
+
/** Window duration in ms
|
|
327
|
+
* - **default**: `900000` (15 minutes)
|
|
328
|
+
* - **env**: `SERVER_RATE_LIMIT_WINDOW_MS`
|
|
329
|
+
*/
|
|
330
|
+
windowMs?: number;
|
|
331
|
+
/** Max requests per window
|
|
332
|
+
* - **default**: `100`
|
|
333
|
+
* - **env**: `SERVER_RATE_LIMIT_MAX`
|
|
334
|
+
*/
|
|
335
|
+
max?: number;
|
|
336
|
+
/** Custom message when limit is reached
|
|
337
|
+
* - **default**: `'Too many requests'`
|
|
338
|
+
* - **env**: `SERVER_RATE_LIMIT_MESSAGE`
|
|
339
|
+
*/
|
|
340
|
+
message?: string;
|
|
341
|
+
/** Include standard rate-limit headers
|
|
342
|
+
* - **default**: `true`
|
|
343
|
+
* - **env**: `SERVER_RATE_LIMIT_STANDARD_HEADERS`
|
|
344
|
+
*/
|
|
345
|
+
standardHeaders?: boolean;
|
|
346
|
+
/** Include legacy rate-limit headers
|
|
347
|
+
* - **default**: `false`
|
|
348
|
+
* - **env**: `SERVER_RATE_LIMIT_LEGACY_HEADERS`
|
|
349
|
+
*/
|
|
350
|
+
legacyHeaders?: boolean;
|
|
351
|
+
};
|
|
352
|
+
/** Request logging configuration
|
|
353
|
+
* - **enable**: `true` in `development`, `false` in `production` - **env**: `SERVER_REQUEST_LOGGING_ENABLE`
|
|
354
|
+
* - **ignorePaths**: skips `/healthz`, `/favicon.ico`, `/metrics`, `/docs`, `/.well-known`
|
|
355
|
+
* - **skipNotFoundRoutes**: `false` - **env**: `SERVER_REQUEST_LOGGING_SKIP_NOT_FOUND_ROUTES`
|
|
356
|
+
*/
|
|
357
|
+
requestLogging?: {
|
|
358
|
+
/** Enable request logging
|
|
359
|
+
* - **default**: `true` in `development`, `false` in `production`
|
|
360
|
+
* - **env**: `SERVER_REQUEST_LOGGING_ENABLE`
|
|
361
|
+
*/
|
|
362
|
+
enable: boolean;
|
|
363
|
+
/** Ignore specific paths or apply custom logic to skip logging */
|
|
364
|
+
ignorePaths?: string[] | ((req: Request, res: Response) => boolean);
|
|
365
|
+
/** Skip 404 routes from logs
|
|
366
|
+
* - **default**: `false`
|
|
367
|
+
* - **env**: `SERVER_REQUEST_LOGGING_SKIP_NOT_FOUND_ROUTES`
|
|
368
|
+
*/
|
|
369
|
+
skipNotFoundRoutes?: boolean;
|
|
370
|
+
};
|
|
371
|
+
/** Health-check configuration
|
|
372
|
+
* - **path**: `/healthz`
|
|
373
|
+
* - **detailed**: `true`
|
|
374
|
+
* - **withGlobalPrefix**: `false`
|
|
375
|
+
*/
|
|
376
|
+
healthCheck?: {
|
|
377
|
+
/** Health-check endpoint path
|
|
378
|
+
* - **default**: `'/healthz'`
|
|
379
|
+
* - **env**: `SERVER_HEALTH_CHECK_PATH`
|
|
380
|
+
*/
|
|
381
|
+
path?: string;
|
|
382
|
+
/** Include detailed check results in the response
|
|
383
|
+
* - **default**: `true`
|
|
384
|
+
* - **env**: `SERVER_HEALTH_CHECK_DETAILED_OUTPUT`
|
|
385
|
+
*/
|
|
386
|
+
detailed?: boolean;
|
|
387
|
+
/** Apply global route prefix
|
|
388
|
+
* - **default**: `false`
|
|
389
|
+
* - **env**: `SERVER_HEALTH_CHECK_WITH_GLOBAL_PREFIX`
|
|
390
|
+
*/
|
|
391
|
+
withGlobalPrefix?: boolean;
|
|
392
|
+
/** Custom health checks */
|
|
393
|
+
checks?: Array<{
|
|
394
|
+
/** Name of the health check */
|
|
395
|
+
name: string;
|
|
396
|
+
/** Check function that returns boolean or Promise<boolean> */
|
|
397
|
+
check: () => Promise<boolean> | boolean;
|
|
398
|
+
}>;
|
|
399
|
+
};
|
|
400
|
+
/** Request timeout in ms
|
|
401
|
+
* - **default**: `30000` (30 seconds)
|
|
402
|
+
* - **env**: `SERVER_REQUEST_TIMEOUT_MS`
|
|
403
|
+
*/
|
|
404
|
+
requestTimeout?: number;
|
|
405
|
+
/** Response timing configuration
|
|
406
|
+
* - **enable**: `false`
|
|
407
|
+
* - **addHeader**: `true`
|
|
408
|
+
* - **logOnComplete**: `false`
|
|
409
|
+
*/
|
|
410
|
+
responseTime?: {
|
|
411
|
+
/** Enable timing
|
|
412
|
+
* - **default**: `false`
|
|
413
|
+
* - **env**: `SERVER_RESPONSE_TIME_ENABLE`
|
|
414
|
+
*/
|
|
415
|
+
enable: boolean;
|
|
416
|
+
/** Add X-Response-Time header
|
|
417
|
+
* - **default**: `true`
|
|
418
|
+
* - **env**: `SERVER_RESPONSE_TIME_ADD_HEADER`
|
|
419
|
+
*/
|
|
420
|
+
addHeader?: boolean;
|
|
421
|
+
/** Log completion time
|
|
422
|
+
* - **default**: `false`
|
|
423
|
+
* - **env**: `SERVER_RESPONSE_TIME_LOG_ON_COMPLETE`
|
|
424
|
+
*/
|
|
425
|
+
logOnComplete?: boolean;
|
|
426
|
+
};
|
|
427
|
+
/** Request ID tracking configuration
|
|
428
|
+
* - **enable**: `false` - **env**: `SERVER_REQUEST_ID_ENABLE`
|
|
429
|
+
* - **headerName**: `'x-request-id'` - **env**: `SERVER_REQUEST_ID_HEADER_NAME`
|
|
430
|
+
* - **exposeHeader**: `true` - **env**: `SERVER_REQUEST_ID_EXPOSE_HEADER`
|
|
431
|
+
* - **generator**: `uuid()`
|
|
432
|
+
*/
|
|
433
|
+
requestId?: {
|
|
434
|
+
/** Header name for request tracing
|
|
435
|
+
* - **default**: `'x-request-id'`
|
|
436
|
+
* - **env**: `SERVER_REQUEST_ID_HEADER_NAME`
|
|
437
|
+
*/
|
|
438
|
+
headerName?: string;
|
|
439
|
+
/** Expose request ID in response headers
|
|
440
|
+
* - **default**: `true`
|
|
441
|
+
* - **env**: `SERVER_REQUEST_ID_EXPOSE_HEADER`
|
|
442
|
+
*/
|
|
443
|
+
exposeHeader?: boolean;
|
|
444
|
+
/** Function to generate request ID
|
|
445
|
+
* - **default**: `uuid()`
|
|
446
|
+
*/
|
|
447
|
+
generator?: () => string;
|
|
448
|
+
};
|
|
449
|
+
/** Global route prefix for all endpoints
|
|
450
|
+
* - **default**: `/`
|
|
451
|
+
*/
|
|
452
|
+
globalPrefix?: string;
|
|
453
|
+
/** OpenAPI/Swagger documentation config
|
|
454
|
+
* - **enable**: `false` - **env**: `SERVER_OPENAPI_ENABLE`
|
|
455
|
+
* - **mountPath**: `'/docs'` - **env**: `SERVER_OPENAPI_MOUNT_PATH`
|
|
456
|
+
* - **verbose**: `false` - **env**: `SERVER_OPENAPI_VERBOSE`
|
|
457
|
+
* - **withGlobalPrefix**: `false` - **env**: `SERVER_OPENAPI_WITH_GLOBAL_PREFIX`
|
|
458
|
+
*/
|
|
459
|
+
openApi?: {
|
|
460
|
+
/** Enable OpenAPI spec serving
|
|
461
|
+
* - **default**: `false`
|
|
462
|
+
* - **env**: `SERVER_OPENAPI_ENABLE`
|
|
463
|
+
*/
|
|
464
|
+
enable: boolean;
|
|
465
|
+
/** Mount path for API docs UI
|
|
466
|
+
* - **default**: `'/docs'`
|
|
467
|
+
* - **env**: `SERVER_OPENAPI_MOUNT_PATH`
|
|
468
|
+
*/
|
|
469
|
+
mountPath?: string;
|
|
470
|
+
/** Local OpenAPI spec file path (required if enabled)
|
|
471
|
+
* - **env**: `SERVER_OPENAPI_FILE_PATH`
|
|
472
|
+
*/
|
|
473
|
+
filePath?: string;
|
|
474
|
+
/** Verbose OpenAPI logs
|
|
475
|
+
* - **default**: `false`
|
|
476
|
+
* - **env**: `SERVER_OPENAPI_VERBOSE`
|
|
477
|
+
*/
|
|
478
|
+
verbose?: boolean;
|
|
479
|
+
/** Apply global prefix to docs route
|
|
480
|
+
* - **default**: `false`
|
|
481
|
+
* - **env**: `SERVER_OPENAPI_WITH_GLOBAL_PREFIX`
|
|
482
|
+
*/
|
|
483
|
+
withGlobalPrefix?: boolean;
|
|
484
|
+
};
|
|
485
|
+
/** Prometheus metrics config
|
|
486
|
+
* - **enable**: `false` - **env**: `SERVER_METRICS_ENABLE`
|
|
487
|
+
* - **path**: `'/metrics'` - **env**: `SERVER_METRICS_PATH`
|
|
488
|
+
* - **withGlobalPrefix**: `false` - **env**: `SERVER_METRICS_WITH_GLOBAL_PREFIX`
|
|
489
|
+
*/
|
|
490
|
+
metrics?: {
|
|
491
|
+
/** Enable metrics endpoint
|
|
492
|
+
* - **default**: `false`
|
|
493
|
+
* - **env**: `SERVER_METRICS_ENABLE`
|
|
494
|
+
*/
|
|
495
|
+
enable: boolean;
|
|
496
|
+
/** Metrics endpoint path
|
|
497
|
+
* - **default**: `'/metrics'`
|
|
498
|
+
* - **env**: `SERVER_METRICS_PATH`
|
|
499
|
+
*/
|
|
500
|
+
path?: string;
|
|
501
|
+
/** Apply global prefix
|
|
502
|
+
* - **default**: `false`
|
|
503
|
+
* - **env**: `SERVER_METRICS_WITH_GLOBAL_PREFIX`
|
|
504
|
+
*/
|
|
505
|
+
withGlobalPrefix?: boolean;
|
|
506
|
+
};
|
|
507
|
+
/** Service version header config
|
|
508
|
+
* - **enable**: `false` - **env**: `SERVER_SERVICE_VERSION_ENABLE`
|
|
509
|
+
* - **headerName**: `'x-service-version'` - **env**: `SERVER_SERVICE_VERSION_HEADER_NAME`
|
|
510
|
+
* - **version**: `'0.0.0'` - **env**: `SERVER_SERVICE_VERSION`
|
|
511
|
+
*/
|
|
512
|
+
serviceVersion?: {
|
|
513
|
+
/** Enable version header
|
|
514
|
+
* - **default**: `false`
|
|
515
|
+
*/
|
|
516
|
+
enable: boolean;
|
|
517
|
+
/** Header name
|
|
518
|
+
* - **default**: `'x-service-version'`
|
|
519
|
+
* - **env**: `SERVER_SERVICE_VERSION_HEADER_NAME`
|
|
520
|
+
*/
|
|
521
|
+
headerName?: string;
|
|
522
|
+
/** Version value
|
|
523
|
+
* - **default**: `'0.0.0'`
|
|
524
|
+
* - **env**: `SERVER_SERVICE_VERSION`
|
|
525
|
+
*/
|
|
526
|
+
version?: string | (() => string);
|
|
527
|
+
};
|
|
528
|
+
/**
|
|
529
|
+
* HTTPS configuration (if provided, server will use HTTPS)
|
|
530
|
+
* Requires 'key' and 'cert' at minimum.
|
|
531
|
+
* @command - to generate self-signed certificates
|
|
532
|
+
* ```bash
|
|
533
|
+
* choco install mkcert
|
|
534
|
+
* mkcert -key-file localhost-key.pem -cert-file localhost-cert.pem localhost 127.0.0.1 ::1
|
|
535
|
+
* ```
|
|
536
|
+
*/
|
|
537
|
+
https?: {
|
|
538
|
+
/** SSL private key file path (PEM) */
|
|
539
|
+
key: string;
|
|
540
|
+
/** SSL certificate file path (PEM) */
|
|
541
|
+
cert: string;
|
|
542
|
+
/** Optional CA bundle path (PEM) */
|
|
543
|
+
ca?: string;
|
|
544
|
+
/** Optional private key passphrase */
|
|
545
|
+
passphrase?: string;
|
|
546
|
+
/** Additional Node.js `https.ServerOptions` */
|
|
547
|
+
[key: string]: any;
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Lifecycle hooks for Catbee server runtime.
|
|
552
|
+
* Allows injecting custom behavior without modifying Catbee core internals.
|
|
553
|
+
*/
|
|
554
|
+
interface CatbeeServerHooks {
|
|
555
|
+
/** Called before middleware & routes initialize */
|
|
556
|
+
beforeInit?: (server: ExpressServer) => Promise<void> | void;
|
|
557
|
+
/** Called after middleware & routes initialize */
|
|
558
|
+
afterInit?: (server: ExpressServer) => Promise<void> | void;
|
|
559
|
+
/** Called before server starts listening */
|
|
560
|
+
beforeStart?: (app: Express) => Promise<void> | void;
|
|
561
|
+
/** Called after server is ready */
|
|
562
|
+
afterStart?: (server: http.Server) => Promise<void> | void;
|
|
563
|
+
/** Called before graceful shutdown */
|
|
564
|
+
beforeStop?: (server: http.Server) => Promise<void> | void;
|
|
565
|
+
/** Called after server stops */
|
|
566
|
+
afterStop?: () => Promise<void> | void;
|
|
567
|
+
/** Custom error handler (overrides Catbee default if provided) */
|
|
568
|
+
onError?: (error: Error, req: Request, res: Response, next: NextFunction) => void;
|
|
569
|
+
/** Called when a request is received (middleware-style injection) */
|
|
570
|
+
onRequest?: (req: Request, res: Response, next: NextFunction) => void;
|
|
571
|
+
/** Called before response is sent */
|
|
572
|
+
onResponse?: (req: Request, res: Response, next: NextFunction) => void;
|
|
573
|
+
}
|
|
574
|
+
interface GlobalServerAddons {
|
|
575
|
+
/**
|
|
576
|
+
* Skip healthz endpoint even if health checks are configured
|
|
577
|
+
* - **default**: `false`
|
|
578
|
+
* - **env**: `SERVER_SKIP_HEALTHZ`
|
|
579
|
+
*
|
|
580
|
+
* @additionalInfo
|
|
581
|
+
* Set to true to return `200 OK` for `/healthz` without checks
|
|
582
|
+
* Useful in environments where a simple liveness probe is needed
|
|
583
|
+
* without performing actual health checks
|
|
584
|
+
* Example: Kubernetes liveness probe
|
|
585
|
+
* Note: This does not disable the health check functionality itself
|
|
586
|
+
* Health checks can still be performed programmatically
|
|
587
|
+
* or via other endpoints if needed
|
|
588
|
+
*/
|
|
589
|
+
skipHealthz: boolean;
|
|
590
|
+
}
|
|
591
|
+
/** Combined global server configuration type */
|
|
592
|
+
type CatbeeGlobalServerConfig = CatbeeServerConfig & GlobalServerAddons;
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Generic API response format.
|
|
596
|
+
* Used to wrap any successful or failed response from the server.
|
|
597
|
+
*/
|
|
598
|
+
interface ApiResponse<T = any> {
|
|
599
|
+
/** Payload returned from the API. Can be any shape depending on the endpoint. */
|
|
600
|
+
data: T | null;
|
|
601
|
+
/** Indicates whether an error occurred (true = error, false = success). */
|
|
602
|
+
error: boolean;
|
|
603
|
+
/** Success message describing the result of the operation. */
|
|
604
|
+
message: string;
|
|
605
|
+
/** Unique request ID for traceability in logs (e.g., from a middleware). */
|
|
606
|
+
requestId: string;
|
|
607
|
+
/** ISO timestamp when the response was generated. */
|
|
608
|
+
timestamp: string;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Generic pagination structure used for paged lists (e.g., /users?page=1).
|
|
612
|
+
*/
|
|
613
|
+
interface Pagination<T = any> {
|
|
614
|
+
/** List of records for the current page. */
|
|
615
|
+
content: T[];
|
|
616
|
+
/** Metadata about the pagination state. */
|
|
617
|
+
pagination: {
|
|
618
|
+
/** Total number of records across all pages. */
|
|
619
|
+
totalRecords: number;
|
|
620
|
+
/** Total number of pages available. */
|
|
621
|
+
totalPages: number;
|
|
622
|
+
/** Current page number (1-based index). */
|
|
623
|
+
page: number;
|
|
624
|
+
/** Number of records per page. */
|
|
625
|
+
limit: number;
|
|
626
|
+
/** Field by which the data is sorted. */
|
|
627
|
+
sortBy: string;
|
|
628
|
+
/** Sort order: ascending or descending. */
|
|
629
|
+
sortOrder: 'asc' | 'desc';
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Alias for paginated API response.
|
|
634
|
+
* Allows semantic naming like `PaginationResponse<User>` or `PaginationResponse<Post>`.
|
|
635
|
+
*/
|
|
636
|
+
type PaginationResponse<T = any> = Pagination<T>;
|
|
637
|
+
/**
|
|
638
|
+
* Error response structure with additional metadata.
|
|
639
|
+
* Used for providing richer error information to clients.
|
|
640
|
+
*/
|
|
641
|
+
interface ApiErrorResponse extends Omit<ApiResponse<never>, 'data'> {
|
|
642
|
+
/** Error always true for error responses */
|
|
643
|
+
error: true;
|
|
644
|
+
/** HTTP status code */
|
|
645
|
+
status: number;
|
|
646
|
+
/** Path to the resource that caused the error */
|
|
647
|
+
path: string;
|
|
648
|
+
/** Stack trace of the error (if available) */
|
|
649
|
+
stack?: string[];
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Success response structure with strongly typed data.
|
|
653
|
+
* Used for providing successful responses to clients.
|
|
654
|
+
*/
|
|
655
|
+
interface ApiSuccessResponse<T = any> extends ApiResponse<T> {
|
|
656
|
+
/** Error always false for success responses */
|
|
657
|
+
error: false;
|
|
658
|
+
/** HTTP status code (usually 200) */
|
|
659
|
+
status?: number;
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Response structure for batch operations.
|
|
663
|
+
* Used when multiple operations are performed in a single request.
|
|
664
|
+
*/
|
|
665
|
+
interface BatchResponse<T = any> {
|
|
666
|
+
/** Overall success/failure indicator */
|
|
667
|
+
success: boolean;
|
|
668
|
+
/** Total number of operations */
|
|
669
|
+
total: number;
|
|
670
|
+
/** Number of successful operations */
|
|
671
|
+
successful: number;
|
|
672
|
+
/** Number of failed operations */
|
|
673
|
+
failed: number;
|
|
674
|
+
/** Results of individual operations */
|
|
675
|
+
results: Array<{
|
|
676
|
+
/** Identifier for this operation */
|
|
677
|
+
id: string | number;
|
|
678
|
+
/** Success/failure indicator for this operation */
|
|
679
|
+
success: boolean;
|
|
680
|
+
/** Response data for this operation */
|
|
681
|
+
data?: T;
|
|
682
|
+
/** Error information if this operation failed */
|
|
683
|
+
error?: {
|
|
684
|
+
message: string;
|
|
685
|
+
code?: string;
|
|
686
|
+
};
|
|
687
|
+
}>;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Response structure for asynchronous operations.
|
|
691
|
+
* Used when the operation will complete in the future.
|
|
692
|
+
*/
|
|
693
|
+
interface AsyncOperationResponse {
|
|
694
|
+
/** Always true for async operations */
|
|
695
|
+
async: true;
|
|
696
|
+
/** Job or task ID to check status later */
|
|
697
|
+
jobId: string;
|
|
698
|
+
/** Estimated completion time in seconds (if known) */
|
|
699
|
+
estimatedTime?: number;
|
|
700
|
+
/** URL to check status */
|
|
701
|
+
statusUrl: string;
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Response structure for streaming operations.
|
|
705
|
+
* Used when data is returned as a stream rather than all at once.
|
|
706
|
+
*/
|
|
707
|
+
interface StreamResponse {
|
|
708
|
+
/** Stream identifier */
|
|
709
|
+
streamId: string;
|
|
710
|
+
/** Stream type (e.g., 'json', 'binary') */
|
|
711
|
+
streamType: string;
|
|
712
|
+
/** Total size in bytes (if known) */
|
|
713
|
+
totalSize?: number;
|
|
714
|
+
/** Chunk size in bytes */
|
|
715
|
+
chunkSize: number;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Sort direction enumeration.
|
|
719
|
+
*/
|
|
720
|
+
declare enum SortDirection {
|
|
721
|
+
/** Ascending sort order */
|
|
722
|
+
ASC = "asc",
|
|
723
|
+
/** Descending sort order */
|
|
724
|
+
DESC = "desc"
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Pagination parameters for API requests.
|
|
728
|
+
*/
|
|
729
|
+
interface PaginationParams {
|
|
730
|
+
/** Current page number (1-based index) */
|
|
731
|
+
page: number;
|
|
732
|
+
/** Number of records per page */
|
|
733
|
+
limit: number;
|
|
734
|
+
/** Field by which the data is sorted */
|
|
735
|
+
sortBy: string;
|
|
736
|
+
/** Sort order: ascending or descending */
|
|
737
|
+
sortOrder: SortDirection;
|
|
738
|
+
/** Optional search query */
|
|
739
|
+
search?: string;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Type that combines pagination parameters with additional data.
|
|
743
|
+
*/
|
|
744
|
+
type WithPagination<T = {}> = PaginationParams & T;
|
|
745
|
+
|
|
746
|
+
interface CatbeeConfig {
|
|
747
|
+
logger?: {
|
|
748
|
+
/**
|
|
749
|
+
* Logging level (e.g., 'info', 'debug', 'warn', 'error')
|
|
750
|
+
* Environment variable: LOGGER_LEVEL
|
|
751
|
+
* Default: 'info' in production, 'debug' in development
|
|
752
|
+
*/
|
|
753
|
+
level?: LoggerLevels;
|
|
754
|
+
/**
|
|
755
|
+
* Name of the logger instance (defaults to npm package name)
|
|
756
|
+
* Environment variable: LOGGER_NAME
|
|
757
|
+
* Default: value of npm_package_name or '@catbee/utils'
|
|
758
|
+
*/
|
|
759
|
+
name?: string;
|
|
760
|
+
/**
|
|
761
|
+
* Enables pretty-print logging in development.
|
|
762
|
+
* Has no effect in production.
|
|
763
|
+
* Environment variable: LOGGER_PRETTY
|
|
764
|
+
* Default: true in development, false in production
|
|
765
|
+
*/
|
|
766
|
+
pretty?: boolean;
|
|
767
|
+
/**
|
|
768
|
+
* Enables colorized output for pretty-print (default: true)
|
|
769
|
+
* Environment variable: LOGGER_PRETTY_COLORIZE
|
|
770
|
+
*/
|
|
771
|
+
colorize?: boolean;
|
|
772
|
+
/**
|
|
773
|
+
* Single line output for pretty-print (default: false)
|
|
774
|
+
* Environment variable: LOGGER_PRETTY_SINGLE_LINE
|
|
775
|
+
*/
|
|
776
|
+
singleLine?: boolean;
|
|
777
|
+
/**
|
|
778
|
+
* Directory to write log files to (if empty, file logging is disabled)
|
|
779
|
+
* Environment variable: LOGGER_DIR
|
|
780
|
+
* Eg: process.cwd() + '/logs'
|
|
781
|
+
* Note: Directory must exist, it is not created automatically
|
|
782
|
+
*/
|
|
783
|
+
dir?: string;
|
|
784
|
+
};
|
|
785
|
+
cache: {
|
|
786
|
+
/**
|
|
787
|
+
* Default TTL (time to live) for cache entries in milliseconds
|
|
788
|
+
* Environment variable: CACHE_DEFAULT_TTL_SECONDS
|
|
789
|
+
* Default: 3600000 (1 hour)
|
|
790
|
+
*/
|
|
791
|
+
defaultTtl: number;
|
|
792
|
+
};
|
|
793
|
+
/** Server configuration */
|
|
794
|
+
server: CatbeeGlobalServerConfig;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
export { SortDirection };
|
|
798
|
+
export type { ApiErrorResponse, ApiResponse, ApiSuccessResponse, AsyncOperationResponse, Awaited, BatchResponse, CatbeeConfig, CatbeeGlobalServerConfig, CatbeeServerConfig, CatbeeServerHooks, DeepPartial, DeepReadonly, DeepRequired, DeepStringifyOrNull, Func, GlobalServerAddons, IsEqual, KeysOfType, MaybePromise, Mutable, NonEmptyArray, Nullable, Optional, Optional2, Pagination, PaginationParams, PaginationResponse, PartialPick, PickByType, Primitive, RecordOptional, RequireAtLeastOne, StreamResponse, StringKeyedRecord, ToggleConfig, UnionToIntersection, ValueOf, WithPagination, Without, Writable };
|