@expressive-tea/core 2.0.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/.gitattributes +4 -0
- package/.swcrc +61 -0
- package/LICENSE +201 -0
- package/README.md +627 -0
- package/banner.png +0 -0
- package/classes/Boot.d.ts +145 -0
- package/classes/Boot.js +223 -0
- package/classes/Engine.d.ts +63 -0
- package/classes/Engine.js +90 -0
- package/classes/EngineRegistry.d.ts +154 -0
- package/classes/EngineRegistry.js +247 -0
- package/classes/LoadBalancer.d.ts +8 -0
- package/classes/LoadBalancer.js +28 -0
- package/classes/ProxyRoute.d.ts +14 -0
- package/classes/ProxyRoute.js +40 -0
- package/classes/Settings.d.ts +128 -0
- package/classes/Settings.js +172 -0
- package/decorators/annotations.d.ts +91 -0
- package/decorators/annotations.js +132 -0
- package/decorators/env.d.ts +145 -0
- package/decorators/env.js +177 -0
- package/decorators/health.d.ts +115 -0
- package/decorators/health.js +124 -0
- package/decorators/module.d.ts +34 -0
- package/decorators/module.js +39 -0
- package/decorators/proxy.d.ts +28 -0
- package/decorators/proxy.js +60 -0
- package/decorators/router.d.ts +199 -0
- package/decorators/router.js +252 -0
- package/decorators/server.d.ts +92 -0
- package/decorators/server.js +247 -0
- package/engines/constants/constants.d.ts +2 -0
- package/engines/constants/constants.js +5 -0
- package/engines/health/index.d.ts +120 -0
- package/engines/health/index.js +179 -0
- package/engines/http/index.d.ts +12 -0
- package/engines/http/index.js +59 -0
- package/engines/index.d.ts +32 -0
- package/engines/index.js +112 -0
- package/engines/socketio/index.d.ts +7 -0
- package/engines/socketio/index.js +30 -0
- package/engines/teacup/index.d.ts +27 -0
- package/engines/teacup/index.js +136 -0
- package/engines/teapot/index.d.ts +32 -0
- package/engines/teapot/index.js +167 -0
- package/engines/websocket/index.d.ts +9 -0
- package/engines/websocket/index.js +39 -0
- package/eslint.config.mjs +138 -0
- package/exceptions/BootLoaderExceptions.d.ts +26 -0
- package/exceptions/BootLoaderExceptions.js +31 -0
- package/exceptions/RequestExceptions.d.ts +75 -0
- package/exceptions/RequestExceptions.js +89 -0
- package/helpers/boot-helper.d.ts +7 -0
- package/helpers/boot-helper.js +84 -0
- package/helpers/decorators.d.ts +1 -0
- package/helpers/decorators.js +15 -0
- package/helpers/promise-helper.d.ts +1 -0
- package/helpers/promise-helper.js +6 -0
- package/helpers/server.d.ts +35 -0
- package/helpers/server.js +141 -0
- package/helpers/teapot-helper.d.ts +18 -0
- package/helpers/teapot-helper.js +88 -0
- package/helpers/websocket-helper.d.ts +3 -0
- package/helpers/websocket-helper.js +20 -0
- package/images/announcement-01.png +0 -0
- package/images/logo-sticky-01.png +0 -0
- package/images/logo-wp-01.png +0 -0
- package/images/logo.png +0 -0
- package/images/zero-oneit.png +0 -0
- package/interfaces/index.d.ts +4 -0
- package/interfaces/index.js +2 -0
- package/inversify.config.d.ts +9 -0
- package/inversify.config.js +8 -0
- package/libs/classNames.d.ts +1 -0
- package/libs/classNames.js +4 -0
- package/libs/utilities.d.ts +21910 -0
- package/libs/utilities.js +420 -0
- package/mixins/module.d.ts +45 -0
- package/mixins/module.js +71 -0
- package/mixins/proxy.d.ts +46 -0
- package/mixins/proxy.js +86 -0
- package/mixins/route.d.ts +48 -0
- package/mixins/route.js +96 -0
- package/package.json +137 -0
- package/services/DependencyInjection.d.ts +159 -0
- package/services/DependencyInjection.js +201 -0
- package/services/WebsocketService.d.ts +18 -0
- package/services/WebsocketService.js +47 -0
- package/types/core.d.ts +14 -0
- package/types/core.js +2 -0
- package/types/injection-types.d.ts +6 -0
- package/types/injection-types.js +10 -0
- package/types/inversify.d.ts +5 -0
- package/types/inversify.js +3 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type ParameterDecorator } from '@expressive-tea/commons';
|
|
2
|
+
/**
|
|
3
|
+
* Is passing directly to the decorated argument described <a href="http://expressjs.com/en/4x/api.html#req">here</a>.
|
|
4
|
+
* @decorator {ParameterDecorator} request - Assign express Request instance to parameter.
|
|
5
|
+
* @summary Assign Express Request Instance.
|
|
6
|
+
* @example
|
|
7
|
+
* class GenericController {
|
|
8
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
9
|
+
* methodError({REPLACE-AT}request req) {}
|
|
10
|
+
* }
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
export declare function request(target: object, propertyKey: string | symbol, parameterIndex: number): void;
|
|
14
|
+
/**
|
|
15
|
+
* Is passing directly to the decorated argument described <a href="http://expressjs.com/en/4x/api.html#res">here</a>.
|
|
16
|
+
* @decorator {ParameterDecorator} response - Assign express Response instance to parameter.
|
|
17
|
+
* @summary Assign Express Response Instance.
|
|
18
|
+
* @example
|
|
19
|
+
* class GenericController {
|
|
20
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
21
|
+
* methodError({REPLACE-AT}response res) {}
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
export declare function response(target: object, propertyKey: string | symbol, parameterIndex: number): void;
|
|
26
|
+
/**
|
|
27
|
+
* Is passing directly to the decorated argument and you can check how is working following the next guide
|
|
28
|
+
* <a href="http://expressjs.com/en/guide/using-middleware.html">here</a>.
|
|
29
|
+
* @decorator {ParameterDecorator} next - Assign express Next Callback function to parameter.
|
|
30
|
+
* @summary Assign Express Next Callback function.
|
|
31
|
+
* @example
|
|
32
|
+
* class GenericController {
|
|
33
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
34
|
+
* methodError({REPLACE-AT}next next) {}
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
*/
|
|
38
|
+
export declare function next(target: object, propertyKey: string | symbol, parameterIndex: number): void;
|
|
39
|
+
/**
|
|
40
|
+
* It will pass a get query parameters which it must be defined on the query parameters string unless it will get a
|
|
41
|
+
* undefined result. This decorator provides the way to return query parameters in one of the next ways: <br>
|
|
42
|
+
* <b>whole</b> query object when no parameters is passing to the decorator. <br>
|
|
43
|
+
* <b>partial</b> query object when a list of parameters name is passing to the decorator. <br>
|
|
44
|
+
* <b>single</b> query parameter when pass a field name directly to the decorator.
|
|
45
|
+
* @decorator {ParameterDecorator} query - Assign a single, partial or whole url query parameters.
|
|
46
|
+
* @summary Get URL Query Parameters.
|
|
47
|
+
* @param {string | string[] | undefined } parameter - Name or parameter's list name.
|
|
48
|
+
* @example
|
|
49
|
+
* class GenericController {
|
|
50
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
51
|
+
* method({REPLACE-AT}query() req) {}
|
|
52
|
+
* method2({REPLACE-AT}query('username') username) {}
|
|
53
|
+
* method3({REPLACE-AT}query(['username', 'password']) credentials) {}
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
*/
|
|
57
|
+
export declare function query(parameter?: string | string[]): ParameterDecorator;
|
|
58
|
+
/**
|
|
59
|
+
* It will pass a get body parameters which it must be defined on the request body, unless it will get a
|
|
60
|
+
* undefined result. This decorator provides the way to return body parameters in one of the next ways: <br>
|
|
61
|
+
* <b>whole</b> body object when no parameters is passing to the decorator. <br>
|
|
62
|
+
* <b>partial</b> body object when a list of parameters name is passing to the decorator. <br>
|
|
63
|
+
* <b>single</b> body parameter when pass a field name directly to the decorator.
|
|
64
|
+
* @decorator {ParameterDecorator} body - Assign a single, partial or whole request body parameters.
|
|
65
|
+
* @summary Assign parameter(s) from body request object.
|
|
66
|
+
* @param {string | string[] | undefined } bodyParam - Name or parameter's list name.
|
|
67
|
+
* @example
|
|
68
|
+
* class GenericController {
|
|
69
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
70
|
+
* method({REPLACE-AT}body() req) {}
|
|
71
|
+
* method2({REPLACE-AT}body('username') username) {}
|
|
72
|
+
* method3({REPLACE-AT}body(['username', 'password']) credentials) {}
|
|
73
|
+
* }
|
|
74
|
+
*
|
|
75
|
+
*/
|
|
76
|
+
export declare function body(bodyParam?: string | string[]): ParameterDecorator;
|
|
77
|
+
/**
|
|
78
|
+
* It will return the value defined on the url path for the current method or a global middleware, this only works
|
|
79
|
+
* for single parameter, and also might be side affected if there is an any <b>param</b> decorator is declared for the
|
|
80
|
+
* the selected parameter it will transformed first and passed the value.
|
|
81
|
+
* @decorator {ParameterDecorator} param - Assign url parameter.
|
|
82
|
+
* @summary Get a parameter value defined on the url by path.
|
|
83
|
+
* @param {string} parameter id name.
|
|
84
|
+
* @example
|
|
85
|
+
* class GenericController {
|
|
86
|
+
* {REPLACE-AT}Get('/:userId') // This Response to all GET Requests for controller route.
|
|
87
|
+
* method({REPLACE-AT}param('userId') username) {}
|
|
88
|
+
* }
|
|
89
|
+
*
|
|
90
|
+
*/
|
|
91
|
+
export declare function param(parameter: string): ParameterDecorator;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.request = request;
|
|
4
|
+
exports.response = response;
|
|
5
|
+
exports.next = next;
|
|
6
|
+
exports.query = query;
|
|
7
|
+
exports.body = body;
|
|
8
|
+
exports.param = param;
|
|
9
|
+
const commons_1 = require("@expressive-tea/commons");
|
|
10
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
11
|
+
const commons_2 = require("@expressive-tea/commons");
|
|
12
|
+
/**
|
|
13
|
+
* @module Decorators/Annotations
|
|
14
|
+
*/
|
|
15
|
+
function addToArguments(target, propertyKey, parameterIndex, type, args) {
|
|
16
|
+
const decoratedParameters = commons_1.Metadata.get(commons_2.ARGUMENTS_KEY, target, propertyKey) || [];
|
|
17
|
+
decoratedParameters.unshift({
|
|
18
|
+
arguments: args,
|
|
19
|
+
index: parameterIndex,
|
|
20
|
+
key: propertyKey,
|
|
21
|
+
type
|
|
22
|
+
});
|
|
23
|
+
commons_1.Metadata.set(commons_2.ARGUMENTS_KEY, decoratedParameters, target, propertyKey);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Is passing directly to the decorated argument described <a href="http://expressjs.com/en/4x/api.html#req">here</a>.
|
|
27
|
+
* @decorator {ParameterDecorator} request - Assign express Request instance to parameter.
|
|
28
|
+
* @summary Assign Express Request Instance.
|
|
29
|
+
* @example
|
|
30
|
+
* class GenericController {
|
|
31
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
32
|
+
* methodError({REPLACE-AT}request req) {}
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
function request(target, propertyKey, parameterIndex) {
|
|
37
|
+
addToArguments(target, propertyKey, parameterIndex, commons_2.ARGUMENT_TYPES.REQUEST);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Is passing directly to the decorated argument described <a href="http://expressjs.com/en/4x/api.html#res">here</a>.
|
|
41
|
+
* @decorator {ParameterDecorator} response - Assign express Response instance to parameter.
|
|
42
|
+
* @summary Assign Express Response Instance.
|
|
43
|
+
* @example
|
|
44
|
+
* class GenericController {
|
|
45
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
46
|
+
* methodError({REPLACE-AT}response res) {}
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
function response(target, propertyKey, parameterIndex) {
|
|
51
|
+
addToArguments(target, propertyKey, parameterIndex, commons_2.ARGUMENT_TYPES.RESPONSE);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Is passing directly to the decorated argument and you can check how is working following the next guide
|
|
55
|
+
* <a href="http://expressjs.com/en/guide/using-middleware.html">here</a>.
|
|
56
|
+
* @decorator {ParameterDecorator} next - Assign express Next Callback function to parameter.
|
|
57
|
+
* @summary Assign Express Next Callback function.
|
|
58
|
+
* @example
|
|
59
|
+
* class GenericController {
|
|
60
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
61
|
+
* methodError({REPLACE-AT}next next) {}
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
*/
|
|
65
|
+
function next(target, propertyKey, parameterIndex) {
|
|
66
|
+
addToArguments(target, propertyKey, parameterIndex, commons_2.ARGUMENT_TYPES.NEXT);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* It will pass a get query parameters which it must be defined on the query parameters string unless it will get a
|
|
70
|
+
* undefined result. This decorator provides the way to return query parameters in one of the next ways: <br>
|
|
71
|
+
* <b>whole</b> query object when no parameters is passing to the decorator. <br>
|
|
72
|
+
* <b>partial</b> query object when a list of parameters name is passing to the decorator. <br>
|
|
73
|
+
* <b>single</b> query parameter when pass a field name directly to the decorator.
|
|
74
|
+
* @decorator {ParameterDecorator} query - Assign a single, partial or whole url query parameters.
|
|
75
|
+
* @summary Get URL Query Parameters.
|
|
76
|
+
* @param {string | string[] | undefined } parameter - Name or parameter's list name.
|
|
77
|
+
* @example
|
|
78
|
+
* class GenericController {
|
|
79
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
80
|
+
* method({REPLACE-AT}query() req) {}
|
|
81
|
+
* method2({REPLACE-AT}query('username') username) {}
|
|
82
|
+
* method3({REPLACE-AT}query(['username', 'password']) credentials) {}
|
|
83
|
+
* }
|
|
84
|
+
*
|
|
85
|
+
*/
|
|
86
|
+
function query(parameter) {
|
|
87
|
+
return (target, propertyKey, parameterIndex) => {
|
|
88
|
+
addToArguments(target, propertyKey, parameterIndex, commons_2.ARGUMENT_TYPES.QUERY, parameter);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* It will pass a get body parameters which it must be defined on the request body, unless it will get a
|
|
93
|
+
* undefined result. This decorator provides the way to return body parameters in one of the next ways: <br>
|
|
94
|
+
* <b>whole</b> body object when no parameters is passing to the decorator. <br>
|
|
95
|
+
* <b>partial</b> body object when a list of parameters name is passing to the decorator. <br>
|
|
96
|
+
* <b>single</b> body parameter when pass a field name directly to the decorator.
|
|
97
|
+
* @decorator {ParameterDecorator} body - Assign a single, partial or whole request body parameters.
|
|
98
|
+
* @summary Assign parameter(s) from body request object.
|
|
99
|
+
* @param {string | string[] | undefined } bodyParam - Name or parameter's list name.
|
|
100
|
+
* @example
|
|
101
|
+
* class GenericController {
|
|
102
|
+
* {REPLACE-AT}Get('/') // This Response to all GET Requests for controller route.
|
|
103
|
+
* method({REPLACE-AT}body() req) {}
|
|
104
|
+
* method2({REPLACE-AT}body('username') username) {}
|
|
105
|
+
* method3({REPLACE-AT}body(['username', 'password']) credentials) {}
|
|
106
|
+
* }
|
|
107
|
+
*
|
|
108
|
+
*/
|
|
109
|
+
function body(bodyParam) {
|
|
110
|
+
return (target, propertyKey, parameterIndex) => {
|
|
111
|
+
addToArguments(target, propertyKey, parameterIndex, commons_2.ARGUMENT_TYPES.BODY, bodyParam);
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* It will return the value defined on the url path for the current method or a global middleware, this only works
|
|
116
|
+
* for single parameter, and also might be side affected if there is an any <b>param</b> decorator is declared for the
|
|
117
|
+
* the selected parameter it will transformed first and passed the value.
|
|
118
|
+
* @decorator {ParameterDecorator} param - Assign url parameter.
|
|
119
|
+
* @summary Get a parameter value defined on the url by path.
|
|
120
|
+
* @param {string} parameter id name.
|
|
121
|
+
* @example
|
|
122
|
+
* class GenericController {
|
|
123
|
+
* {REPLACE-AT}Get('/:userId') // This Response to all GET Requests for controller route.
|
|
124
|
+
* method({REPLACE-AT}param('userId') username) {}
|
|
125
|
+
* }
|
|
126
|
+
*
|
|
127
|
+
*/
|
|
128
|
+
function param(parameter) {
|
|
129
|
+
return (target, propertyKey, parameterIndex) => {
|
|
130
|
+
addToArguments(target, propertyKey, parameterIndex, commons_2.ARGUMENT_TYPES.GET_PARAM, parameter);
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable loading options with optional transformation
|
|
3
|
+
* @interface EnvOptions
|
|
4
|
+
* @template T - Type of transformed environment variables
|
|
5
|
+
* @since 2.0.0
|
|
6
|
+
*/
|
|
7
|
+
export interface EnvOptions<T = Record<string, string>> {
|
|
8
|
+
/**
|
|
9
|
+
* Path to the .env file (relative to project root)
|
|
10
|
+
* @default '.env'
|
|
11
|
+
*/
|
|
12
|
+
path?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Whether to override existing environment variables
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
override?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* List of required environment variables (will throw if missing)
|
|
20
|
+
*/
|
|
21
|
+
required?: string[];
|
|
22
|
+
/**
|
|
23
|
+
* Whether to ignore missing .env file
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
silent?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Optional transformation function for type-safe environment variables.
|
|
29
|
+
* Receives parsed env vars and returns transformed result.
|
|
30
|
+
* Use with validation libraries like Zod for runtime type safety.
|
|
31
|
+
*
|
|
32
|
+
* @param env - Parsed environment variables
|
|
33
|
+
* @returns Transformed and validated environment variables
|
|
34
|
+
* @since 2.0.1
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* import { z } from 'zod';
|
|
38
|
+
* const EnvSchema = z.object({
|
|
39
|
+
* PORT: z.string().transform(Number),
|
|
40
|
+
* DATABASE_URL: z.string().url()
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* @Env({
|
|
44
|
+
* transform: (env) => EnvSchema.parse(env),
|
|
45
|
+
* onTransformError: 'throw'
|
|
46
|
+
* })
|
|
47
|
+
*/
|
|
48
|
+
transform?: (env: Record<string, string>) => T;
|
|
49
|
+
/**
|
|
50
|
+
* Behavior when transform function throws an error
|
|
51
|
+
* - 'throw': Re-throw error immediately (fail-fast, recommended for production)
|
|
52
|
+
* - 'warn': Log warning and continue with unvalidated env
|
|
53
|
+
* - 'ignore': Silent failure, continue without transform
|
|
54
|
+
*
|
|
55
|
+
* @default 'throw'
|
|
56
|
+
* @since 2.0.1
|
|
57
|
+
*/
|
|
58
|
+
onTransformError?: 'throw' | 'warn' | 'ignore';
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Retrieve transformed environment variables from global storage.
|
|
62
|
+
* Returns null if no transform was applied.
|
|
63
|
+
*
|
|
64
|
+
* @template T - Type of transformed environment variables
|
|
65
|
+
* @returns Transformed environment variables or null
|
|
66
|
+
* @since 2.0.1
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* const env = getTransformedEnv<MyEnvType>();
|
|
70
|
+
* if (env) {
|
|
71
|
+
* console.log(env.PORT); // Type-safe access
|
|
72
|
+
* }
|
|
73
|
+
*/
|
|
74
|
+
export declare function getTransformedEnv<T>(): T | null;
|
|
75
|
+
/**
|
|
76
|
+
* Class decorator to load environment variables from .env files before application initialization.
|
|
77
|
+
*
|
|
78
|
+
* This decorator can be stacked to load multiple .env files in order, allowing for
|
|
79
|
+
* environment-specific overrides (e.g., .env → .env.local → .env.production).
|
|
80
|
+
*
|
|
81
|
+
* Environment variables are loaded BEFORE the Settings singleton is initialized,
|
|
82
|
+
* ensuring they're available during the entire application lifecycle.
|
|
83
|
+
*
|
|
84
|
+
* **New in v2.0.1:** Optional type-safe transformation with validation libraries like Zod.
|
|
85
|
+
*
|
|
86
|
+
* @decorator {ClassDecorator} Env - Load environment variables from .env file
|
|
87
|
+
* @template T - Type of transformed environment variables
|
|
88
|
+
* @param options - Environment loading options
|
|
89
|
+
* @returns Class decorator function
|
|
90
|
+
* @since 2.0.0
|
|
91
|
+
* @summary Load environment variables from .env files with optional type-safe transformation
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* // Basic usage - load from .env
|
|
95
|
+
* @Env()
|
|
96
|
+
* class MyApp extends Boot {}
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* // Load from custom path with required variables
|
|
100
|
+
* @Env({
|
|
101
|
+
* path: '.env.production',
|
|
102
|
+
* required: ['DATABASE_URL', 'API_KEY']
|
|
103
|
+
* })
|
|
104
|
+
* class MyApp extends Boot {}
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* // Stack multiple .env files (loaded in order)
|
|
108
|
+
* @Env({ path: '.env' })
|
|
109
|
+
* @Env({ path: '.env.local', override: true, silent: true })
|
|
110
|
+
* class MyApp extends Boot {}
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* // Type-safe transformation with Zod
|
|
114
|
+
* import { z } from 'zod';
|
|
115
|
+
*
|
|
116
|
+
* const EnvSchema = z.object({
|
|
117
|
+
* PORT: z.string().transform(Number),
|
|
118
|
+
* DATABASE_URL: z.string().url(),
|
|
119
|
+
* API_KEY: z.string().min(32)
|
|
120
|
+
* });
|
|
121
|
+
*
|
|
122
|
+
* type Env = z.infer<typeof EnvSchema>;
|
|
123
|
+
*
|
|
124
|
+
* @Env<Env>({
|
|
125
|
+
* path: '.env',
|
|
126
|
+
* required: ['DATABASE_URL', 'API_KEY'],
|
|
127
|
+
* transform: (env) => EnvSchema.parse(env),
|
|
128
|
+
* onTransformError: 'throw' // Fail fast on invalid env
|
|
129
|
+
* })
|
|
130
|
+
* class MyApp extends Boot {
|
|
131
|
+
* constructor() {
|
|
132
|
+
* super();
|
|
133
|
+
* // Access type-safe env
|
|
134
|
+
* const env = Settings.getInstance().getEnv<Env>();
|
|
135
|
+
* console.log(env.PORT); // Type: number
|
|
136
|
+
* }
|
|
137
|
+
* }
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* // In your .env file:
|
|
141
|
+
* // DATABASE_URL=postgres://localhost:5432/mydb
|
|
142
|
+
* // API_KEY="secret-key-with-special-chars"
|
|
143
|
+
* // PORT=3000
|
|
144
|
+
*/
|
|
145
|
+
export declare function Env<T = Record<string, string>>(options?: EnvOptions<T>): ClassDecorator;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTransformedEnv = getTransformedEnv;
|
|
4
|
+
exports.Env = Env;
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const dotenv = require("dotenv");
|
|
8
|
+
/**
|
|
9
|
+
* Global storage for transformed environment variables.
|
|
10
|
+
* Set by @Env decorator when transform option is provided.
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
let transformedEnv = null;
|
|
14
|
+
/**
|
|
15
|
+
* Store transformed environment variables in global storage.
|
|
16
|
+
* Used internally by @Env decorator.
|
|
17
|
+
*
|
|
18
|
+
* @template T - Type of transformed environment variables
|
|
19
|
+
* @param env - Transformed environment variables
|
|
20
|
+
* @private
|
|
21
|
+
* @since 2.0.1
|
|
22
|
+
*/
|
|
23
|
+
function storeTransformedEnv(env) {
|
|
24
|
+
transformedEnv = env;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Retrieve transformed environment variables from global storage.
|
|
28
|
+
* Returns null if no transform was applied.
|
|
29
|
+
*
|
|
30
|
+
* @template T - Type of transformed environment variables
|
|
31
|
+
* @returns Transformed environment variables or null
|
|
32
|
+
* @since 2.0.1
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const env = getTransformedEnv<MyEnvType>();
|
|
36
|
+
* if (env) {
|
|
37
|
+
* console.log(env.PORT); // Type-safe access
|
|
38
|
+
* }
|
|
39
|
+
*/
|
|
40
|
+
function getTransformedEnv() {
|
|
41
|
+
return transformedEnv;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Load environment variables from a .env file using dotenv.
|
|
45
|
+
* Supports transformation and validation via optional transform function.
|
|
46
|
+
*
|
|
47
|
+
* @template T - Type of transformed environment variables
|
|
48
|
+
* @param options - Environment loading options
|
|
49
|
+
* @throws {Error} If required variables are missing, file is not found (when not silent), or transform fails (when onTransformError='throw')
|
|
50
|
+
* @since 2.0.0
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
function loadEnvFile(options) {
|
|
54
|
+
const { path: envPath = '.env', override = false, required = [], silent = false, transform, onTransformError = 'throw' } = options;
|
|
55
|
+
const fullPath = (0, path_1.resolve)(process.cwd(), envPath);
|
|
56
|
+
// Check if file exists
|
|
57
|
+
if (!(0, fs_1.existsSync)(fullPath)) {
|
|
58
|
+
if (!silent) {
|
|
59
|
+
throw new Error(`Environment file not found: ${fullPath}`);
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
// Load with dotenv
|
|
64
|
+
const result = dotenv.config({
|
|
65
|
+
path: fullPath,
|
|
66
|
+
override
|
|
67
|
+
});
|
|
68
|
+
if (result.error && !silent) {
|
|
69
|
+
throw new Error(`Failed to load ${fullPath}: ${result.error.message}`);
|
|
70
|
+
}
|
|
71
|
+
// Validate required variables
|
|
72
|
+
const missing = required.filter((key) => process.env[key] === undefined);
|
|
73
|
+
if (missing.length > 0) {
|
|
74
|
+
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
|
|
75
|
+
}
|
|
76
|
+
// Apply transform if provided
|
|
77
|
+
if (transform) {
|
|
78
|
+
try {
|
|
79
|
+
const envVars = result.parsed || {};
|
|
80
|
+
const transformed = transform(envVars);
|
|
81
|
+
// Store transformed result globally
|
|
82
|
+
storeTransformedEnv(transformed);
|
|
83
|
+
return transformed;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
const errorMsg = `Environment transformation failed: ${error.message}`;
|
|
87
|
+
if (onTransformError === 'throw') {
|
|
88
|
+
throw new Error(errorMsg);
|
|
89
|
+
}
|
|
90
|
+
else if (onTransformError === 'warn') {
|
|
91
|
+
console.warn(`[Expressive Tea] ${errorMsg}`);
|
|
92
|
+
if (error.stack) {
|
|
93
|
+
console.warn(error.stack);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// 'ignore' - do nothing, return undefined
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Class decorator to load environment variables from .env files before application initialization.
|
|
103
|
+
*
|
|
104
|
+
* This decorator can be stacked to load multiple .env files in order, allowing for
|
|
105
|
+
* environment-specific overrides (e.g., .env → .env.local → .env.production).
|
|
106
|
+
*
|
|
107
|
+
* Environment variables are loaded BEFORE the Settings singleton is initialized,
|
|
108
|
+
* ensuring they're available during the entire application lifecycle.
|
|
109
|
+
*
|
|
110
|
+
* **New in v2.0.1:** Optional type-safe transformation with validation libraries like Zod.
|
|
111
|
+
*
|
|
112
|
+
* @decorator {ClassDecorator} Env - Load environment variables from .env file
|
|
113
|
+
* @template T - Type of transformed environment variables
|
|
114
|
+
* @param options - Environment loading options
|
|
115
|
+
* @returns Class decorator function
|
|
116
|
+
* @since 2.0.0
|
|
117
|
+
* @summary Load environment variables from .env files with optional type-safe transformation
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* // Basic usage - load from .env
|
|
121
|
+
* @Env()
|
|
122
|
+
* class MyApp extends Boot {}
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* // Load from custom path with required variables
|
|
126
|
+
* @Env({
|
|
127
|
+
* path: '.env.production',
|
|
128
|
+
* required: ['DATABASE_URL', 'API_KEY']
|
|
129
|
+
* })
|
|
130
|
+
* class MyApp extends Boot {}
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* // Stack multiple .env files (loaded in order)
|
|
134
|
+
* @Env({ path: '.env' })
|
|
135
|
+
* @Env({ path: '.env.local', override: true, silent: true })
|
|
136
|
+
* class MyApp extends Boot {}
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* // Type-safe transformation with Zod
|
|
140
|
+
* import { z } from 'zod';
|
|
141
|
+
*
|
|
142
|
+
* const EnvSchema = z.object({
|
|
143
|
+
* PORT: z.string().transform(Number),
|
|
144
|
+
* DATABASE_URL: z.string().url(),
|
|
145
|
+
* API_KEY: z.string().min(32)
|
|
146
|
+
* });
|
|
147
|
+
*
|
|
148
|
+
* type Env = z.infer<typeof EnvSchema>;
|
|
149
|
+
*
|
|
150
|
+
* @Env<Env>({
|
|
151
|
+
* path: '.env',
|
|
152
|
+
* required: ['DATABASE_URL', 'API_KEY'],
|
|
153
|
+
* transform: (env) => EnvSchema.parse(env),
|
|
154
|
+
* onTransformError: 'throw' // Fail fast on invalid env
|
|
155
|
+
* })
|
|
156
|
+
* class MyApp extends Boot {
|
|
157
|
+
* constructor() {
|
|
158
|
+
* super();
|
|
159
|
+
* // Access type-safe env
|
|
160
|
+
* const env = Settings.getInstance().getEnv<Env>();
|
|
161
|
+
* console.log(env.PORT); // Type: number
|
|
162
|
+
* }
|
|
163
|
+
* }
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* // In your .env file:
|
|
167
|
+
* // DATABASE_URL=postgres://localhost:5432/mydb
|
|
168
|
+
* // API_KEY="secret-key-with-special-chars"
|
|
169
|
+
* // PORT=3000
|
|
170
|
+
*/
|
|
171
|
+
function Env(options = {}) {
|
|
172
|
+
return (target) => {
|
|
173
|
+
// Load env file immediately when decorator is applied
|
|
174
|
+
loadEnvFile(options);
|
|
175
|
+
return target;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { HealthCheck as HealthCheckConfig } from '../engines/health';
|
|
2
|
+
/**
|
|
3
|
+
* Health check decorator options
|
|
4
|
+
* @since 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
export interface HealthCheckOptions {
|
|
7
|
+
/** Array of health checks to register */
|
|
8
|
+
checks: HealthCheckConfig[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Class decorator to register health checks for monitoring and orchestration.
|
|
12
|
+
*
|
|
13
|
+
* Adds standardized health check endpoints:
|
|
14
|
+
* - `/health` - Detailed health status with all checks
|
|
15
|
+
* - `/health/live` - Liveness probe (Kubernetes compatible)
|
|
16
|
+
* - `/health/ready` - Readiness probe (only passes if all critical checks pass)
|
|
17
|
+
*
|
|
18
|
+
* Health checks are executed asynchronously and can be marked as critical for readiness.
|
|
19
|
+
* Non-critical checks only affect the detailed `/health` endpoint.
|
|
20
|
+
*
|
|
21
|
+
* @decorator {ClassDecorator} HealthCheck - Register health checks
|
|
22
|
+
* @param options - Health check configuration
|
|
23
|
+
* @returns Class decorator function
|
|
24
|
+
* @since 2.0.0
|
|
25
|
+
* @summary Register application health checks for monitoring
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Basic health check
|
|
29
|
+
* @HealthCheck({
|
|
30
|
+
* checks: [
|
|
31
|
+
* {
|
|
32
|
+
* name: 'database',
|
|
33
|
+
* check: async () => {
|
|
34
|
+
* const isConnected = await db.ping();
|
|
35
|
+
* return { status: isConnected ? 'pass' : 'fail' };
|
|
36
|
+
* },
|
|
37
|
+
* critical: true,
|
|
38
|
+
* timeout: 5000
|
|
39
|
+
* }
|
|
40
|
+
* ]
|
|
41
|
+
* })
|
|
42
|
+
* class MyApp extends Boot {}
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // Multiple health checks with different priorities
|
|
46
|
+
* @HealthCheck({
|
|
47
|
+
* checks: [
|
|
48
|
+
* {
|
|
49
|
+
* name: 'database',
|
|
50
|
+
* check: async () => {
|
|
51
|
+
* const connected = await db.ping();
|
|
52
|
+
* return {
|
|
53
|
+
* status: connected ? 'pass' : 'fail',
|
|
54
|
+
* details: { connections: db.poolSize }
|
|
55
|
+
* };
|
|
56
|
+
* },
|
|
57
|
+
* critical: true // Required for readiness
|
|
58
|
+
* },
|
|
59
|
+
* {
|
|
60
|
+
* name: 'cache',
|
|
61
|
+
* check: async () => {
|
|
62
|
+
* const ready = await redis.ping();
|
|
63
|
+
* return {
|
|
64
|
+
* status: ready ? 'pass' : 'warn', // Warn but don't fail
|
|
65
|
+
* details: { cached_items: await redis.dbsize() }
|
|
66
|
+
* };
|
|
67
|
+
* },
|
|
68
|
+
* critical: false // Optional, won't block readiness
|
|
69
|
+
* },
|
|
70
|
+
* {
|
|
71
|
+
* name: 'external_api',
|
|
72
|
+
* check: async () => {
|
|
73
|
+
* try {
|
|
74
|
+
* const response = await fetch('https://api.example.com/status');
|
|
75
|
+
* return { status: response.ok ? 'pass' : 'warn' };
|
|
76
|
+
* } catch (error) {
|
|
77
|
+
* return {
|
|
78
|
+
* status: 'warn',
|
|
79
|
+
* error: error.message
|
|
80
|
+
* };
|
|
81
|
+
* }
|
|
82
|
+
* },
|
|
83
|
+
* timeout: 3000
|
|
84
|
+
* }
|
|
85
|
+
* ]
|
|
86
|
+
* })
|
|
87
|
+
* class MyApp extends Boot {}
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* // Kubernetes deployment.yaml example
|
|
91
|
+
* // spec:
|
|
92
|
+
* // containers:
|
|
93
|
+
* // - name: my-app
|
|
94
|
+
* // livenessProbe:
|
|
95
|
+
* // httpGet:
|
|
96
|
+
* // path: /health/live
|
|
97
|
+
* // port: 3000
|
|
98
|
+
* // initialDelaySeconds: 30
|
|
99
|
+
* // periodSeconds: 10
|
|
100
|
+
* // readinessProbe:
|
|
101
|
+
* // httpGet:
|
|
102
|
+
* // path: /health/ready
|
|
103
|
+
* // port: 3000
|
|
104
|
+
* // initialDelaySeconds: 5
|
|
105
|
+
* // periodSeconds: 5
|
|
106
|
+
*/
|
|
107
|
+
export declare function HealthCheck(options: HealthCheckOptions): ClassDecorator;
|
|
108
|
+
/**
|
|
109
|
+
* Get health checks from a class
|
|
110
|
+
* @param target - Target class
|
|
111
|
+
* @returns Array of health checks
|
|
112
|
+
* @since 2.0.0
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
export declare function getHealthChecks(target: any): HealthCheckConfig[];
|