@smounters/imperium 1.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/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/core/app-tokens.d.ts +5 -0
- package/dist/core/app-tokens.js +4 -0
- package/dist/core/application.d.ts +34 -0
- package/dist/core/application.js +252 -0
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +1 -0
- package/dist/core/container.d.ts +76 -0
- package/dist/core/container.js +687 -0
- package/dist/core/errors.d.ts +31 -0
- package/dist/core/errors.js +169 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +4 -0
- package/dist/core/logger.d.ts +7 -0
- package/dist/core/logger.js +12 -0
- package/dist/core/reflector.d.ts +9 -0
- package/dist/core/reflector.js +39 -0
- package/dist/core/server.d.ts +10 -0
- package/dist/core/server.js +296 -0
- package/dist/core/types.d.ts +25 -0
- package/dist/core/types.js +1 -0
- package/dist/decorators/di.decorators.d.ts +10 -0
- package/dist/decorators/di.decorators.js +15 -0
- package/dist/decorators/filters.decorators.d.ts +6 -0
- package/dist/decorators/filters.decorators.js +16 -0
- package/dist/decorators/guards.decorators.d.ts +4 -0
- package/dist/decorators/guards.decorators.js +8 -0
- package/dist/decorators/http.decorators.d.ts +16 -0
- package/dist/decorators/http.decorators.js +60 -0
- package/dist/decorators/index.d.ts +8 -0
- package/dist/decorators/index.js +8 -0
- package/dist/decorators/interceptors.decorators.d.ts +4 -0
- package/dist/decorators/interceptors.decorators.js +8 -0
- package/dist/decorators/metadata.decorators.d.ts +4 -0
- package/dist/decorators/metadata.decorators.js +22 -0
- package/dist/decorators/pipes.decorators.d.ts +4 -0
- package/dist/decorators/pipes.decorators.js +8 -0
- package/dist/decorators/rpc.decorators.d.ts +11 -0
- package/dist/decorators/rpc.decorators.js +50 -0
- package/dist/http/adapter.d.ts +4 -0
- package/dist/http/adapter.js +199 -0
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.js +3 -0
- package/dist/http/router-builder.d.ts +4 -0
- package/dist/http/router-builder.js +30 -0
- package/dist/http/utils.d.ts +6 -0
- package/dist/http/utils.js +46 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/pipes/index.d.ts +1 -0
- package/dist/pipes/index.js +1 -0
- package/dist/pipes/zod.pipe.d.ts +7 -0
- package/dist/pipes/zod.pipe.js +8 -0
- package/dist/rpc/adapter.d.ts +7 -0
- package/dist/rpc/adapter.js +186 -0
- package/dist/rpc/index.d.ts +3 -0
- package/dist/rpc/index.js +3 -0
- package/dist/rpc/router-builder.d.ts +4 -0
- package/dist/rpc/router-builder.js +28 -0
- package/dist/rpc/utils.d.ts +6 -0
- package/dist/rpc/utils.js +46 -0
- package/dist/services/config.service.d.ts +10 -0
- package/dist/services/config.service.js +41 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.js +2 -0
- package/dist/services/logger.service.d.ts +30 -0
- package/dist/services/logger.service.js +52 -0
- package/dist/types.d.ts +167 -0
- package/dist/types.js +1 -0
- package/dist/validation/app-config.d.ts +30 -0
- package/dist/validation/app-config.js +25 -0
- package/dist/validation/common.d.ts +8 -0
- package/dist/validation/common.js +57 -0
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.js +2 -0
- package/package.json +98 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { ForbiddenException, toConnectError } from "../core/errors";
|
|
3
|
+
import { CATCH_EXCEPTIONS_KEY } from "../decorators/filters.decorators";
|
|
4
|
+
import { RPC_PARAMS_KEY } from "../decorators/rpc.decorators";
|
|
5
|
+
import { LoggerService } from "../services";
|
|
6
|
+
import { collectFiltersForRpc, collectGuardsForRpc, collectInterceptorsForRpc, collectPipesForRpc } from "./utils";
|
|
7
|
+
function logRpcError(app, scope, details, error) {
|
|
8
|
+
try {
|
|
9
|
+
scope.resolve(LoggerService).error(details, error);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// fallback below
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
app.getLogger().error(details, error);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// final fallback
|
|
21
|
+
}
|
|
22
|
+
console.error("[imperium] rpc_error", details, error);
|
|
23
|
+
}
|
|
24
|
+
function getPayloadValue(payload, key) {
|
|
25
|
+
if (!key) {
|
|
26
|
+
return payload;
|
|
27
|
+
}
|
|
28
|
+
if (!payload || typeof payload !== "object") {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return payload[key];
|
|
32
|
+
}
|
|
33
|
+
function buildRpcArgs(payload, context, handler) {
|
|
34
|
+
const metas = Reflect.getMetadata(RPC_PARAMS_KEY, handler) ?? [];
|
|
35
|
+
if (!metas.length) {
|
|
36
|
+
return [payload];
|
|
37
|
+
}
|
|
38
|
+
const args = [];
|
|
39
|
+
for (const meta of metas) {
|
|
40
|
+
switch (meta.source) {
|
|
41
|
+
case "data":
|
|
42
|
+
args[meta.index] = getPayloadValue(payload, meta.key);
|
|
43
|
+
break;
|
|
44
|
+
case "context":
|
|
45
|
+
args[meta.index] = context;
|
|
46
|
+
break;
|
|
47
|
+
case "headers":
|
|
48
|
+
args[meta.index] = context.requestHeader;
|
|
49
|
+
break;
|
|
50
|
+
case "header":
|
|
51
|
+
args[meta.index] = meta.key ? context.requestHeader.get(meta.key) : undefined;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return args;
|
|
56
|
+
}
|
|
57
|
+
function resolveEnhancer(scope, enhancer) {
|
|
58
|
+
if (typeof enhancer === "function") {
|
|
59
|
+
return scope.resolve(enhancer);
|
|
60
|
+
}
|
|
61
|
+
return enhancer;
|
|
62
|
+
}
|
|
63
|
+
function getRequestScope(app, controller) {
|
|
64
|
+
return app.createRequestScope(controller);
|
|
65
|
+
}
|
|
66
|
+
function canHandleException(error, filter) {
|
|
67
|
+
const exceptions = Reflect.getMetadata(CATCH_EXCEPTIONS_KEY, filter.constructor);
|
|
68
|
+
if (!exceptions || exceptions.length === 0) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
if (!(error instanceof Error)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return exceptions.some((ExceptionType) => error instanceof ExceptionType);
|
|
75
|
+
}
|
|
76
|
+
async function runRpcFilters(error, filters, ctx) {
|
|
77
|
+
let currentError = error;
|
|
78
|
+
for (const filter of filters) {
|
|
79
|
+
if (!canHandleException(currentError, filter)) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const result = await filter.catch(currentError, ctx);
|
|
84
|
+
if (result !== undefined) {
|
|
85
|
+
return {
|
|
86
|
+
handled: true,
|
|
87
|
+
error: currentError,
|
|
88
|
+
result: result,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (nextError) {
|
|
93
|
+
currentError = nextError;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
handled: false,
|
|
98
|
+
error: currentError,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export function createRpcHandler(app, controller, methodName) {
|
|
102
|
+
return async (req, context) => {
|
|
103
|
+
const scope = getRequestScope(app, controller);
|
|
104
|
+
const handler = controller.prototype[methodName];
|
|
105
|
+
return app.runInRequestScope(scope, async () => {
|
|
106
|
+
const ctx = {
|
|
107
|
+
type: "rpc",
|
|
108
|
+
method: methodName,
|
|
109
|
+
headers: context.requestHeader,
|
|
110
|
+
rpc: {
|
|
111
|
+
data: req,
|
|
112
|
+
context,
|
|
113
|
+
},
|
|
114
|
+
controller,
|
|
115
|
+
handler,
|
|
116
|
+
getType: () => "rpc",
|
|
117
|
+
getClass: () => controller,
|
|
118
|
+
getHandler: () => handler,
|
|
119
|
+
switchToHttp: () => ({
|
|
120
|
+
getRequest: () => undefined,
|
|
121
|
+
getResponse: () => undefined,
|
|
122
|
+
}),
|
|
123
|
+
switchToRpc: () => ({
|
|
124
|
+
getData: () => req,
|
|
125
|
+
getContext: () => context,
|
|
126
|
+
}),
|
|
127
|
+
};
|
|
128
|
+
try {
|
|
129
|
+
const instance = scope.resolve(controller);
|
|
130
|
+
const guards = collectGuardsForRpc(controller, methodName, app.getGlobalGuards()).map((guardLike) => resolveEnhancer(scope, guardLike));
|
|
131
|
+
for (const guard of guards) {
|
|
132
|
+
const ok = await guard.canActivate(ctx);
|
|
133
|
+
if (!ok) {
|
|
134
|
+
throw new ForbiddenException();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
let payload = req;
|
|
138
|
+
const pipes = collectPipesForRpc(controller, methodName, app.getGlobalPipes()).map((pipeLike) => resolveEnhancer(scope, pipeLike));
|
|
139
|
+
for (const pipe of pipes) {
|
|
140
|
+
payload = await pipe.transform(payload, ctx);
|
|
141
|
+
}
|
|
142
|
+
const interceptors = collectInterceptorsForRpc(controller, methodName, app.getGlobalInterceptors()).map((interceptorLike) => resolveEnhancer(scope, interceptorLike));
|
|
143
|
+
const args = buildRpcArgs(payload, context, handler);
|
|
144
|
+
const controllerHandler = instance[methodName];
|
|
145
|
+
let idx = -1;
|
|
146
|
+
const next = async () => {
|
|
147
|
+
idx++;
|
|
148
|
+
if (idx < interceptors.length) {
|
|
149
|
+
return (await interceptors[idx].intercept(ctx, next));
|
|
150
|
+
}
|
|
151
|
+
return controllerHandler(...args);
|
|
152
|
+
};
|
|
153
|
+
return next();
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
logRpcError(app, scope, {
|
|
157
|
+
type: "rpc_error",
|
|
158
|
+
controller: controller.name,
|
|
159
|
+
handler: methodName,
|
|
160
|
+
procedure: context.method.name,
|
|
161
|
+
}, error);
|
|
162
|
+
const filters = collectFiltersForRpc(controller, methodName, app.getGlobalFilters()).map((filterLike) => resolveEnhancer(scope, filterLike));
|
|
163
|
+
const filtered = await runRpcFilters(error, filters, ctx);
|
|
164
|
+
if (filtered.handled) {
|
|
165
|
+
return filtered.result;
|
|
166
|
+
}
|
|
167
|
+
throw toConnectError(filtered.error, {
|
|
168
|
+
exposeInternalErrors: app.shouldExposeInternalErrors(),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
try {
|
|
173
|
+
await app.disposeRequestScope(scope);
|
|
174
|
+
}
|
|
175
|
+
catch (disposeError) {
|
|
176
|
+
logRpcError(app, scope, {
|
|
177
|
+
type: "rpc_scope_dispose_error",
|
|
178
|
+
controller: controller.name,
|
|
179
|
+
handler: methodName,
|
|
180
|
+
procedure: context.method.name,
|
|
181
|
+
}, disposeError);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { RPC_METHODS_KEY, RPC_SERVICE_KEY } from "../decorators/rpc.decorators";
|
|
3
|
+
import { createRpcHandler } from "./adapter";
|
|
4
|
+
function assertUnaryRpcMethod(controller, handlerName, method) {
|
|
5
|
+
if (method.methodKind === "unary") {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const serviceName = method.parent.name;
|
|
9
|
+
const rpcName = method.name;
|
|
10
|
+
throw new Error(`Streaming RPC methods are not supported: ${serviceName}.${rpcName} (${method.methodKind}) ` +
|
|
11
|
+
`at ${controller.name}.${handlerName}. Only unary methods are supported.`);
|
|
12
|
+
}
|
|
13
|
+
export function buildConnectRoutes(di) {
|
|
14
|
+
return (router) => {
|
|
15
|
+
for (const ctrl of di.getControllers()) {
|
|
16
|
+
const controller = ctrl;
|
|
17
|
+
const service = Reflect.getMetadata(RPC_SERVICE_KEY, controller);
|
|
18
|
+
if (!service) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const methods = Reflect.getMetadata(RPC_METHODS_KEY, controller) ?? [];
|
|
22
|
+
for (const { method, handlerName } of methods) {
|
|
23
|
+
assertUnaryRpcMethod(controller, handlerName, method);
|
|
24
|
+
router.rpc(method, createRpcHandler(di, controller, handlerName));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import type { Constructor, ExceptionFilterLike, GuardLike, InterceptorLike, PipeLike } from "../types";
|
|
3
|
+
export declare function collectGuardsForRpc(controller: Constructor, method: string, global: GuardLike[]): GuardLike[];
|
|
4
|
+
export declare function collectInterceptorsForRpc(controller: Constructor, method: string, global: InterceptorLike[]): InterceptorLike[];
|
|
5
|
+
export declare function collectPipesForRpc(controller: Constructor, method: string, global: PipeLike[]): PipeLike[];
|
|
6
|
+
export declare function collectFiltersForRpc(controller: Constructor, method: string, global: ExceptionFilterLike[]): ExceptionFilterLike[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { Reflector } from "../core/reflector";
|
|
3
|
+
import { FILTERS_KEY } from "../decorators/filters.decorators";
|
|
4
|
+
import { GUARDS_KEY } from "../decorators/guards.decorators";
|
|
5
|
+
import { INTERCEPTORS_KEY } from "../decorators/interceptors.decorators";
|
|
6
|
+
import { PIPES_KEY } from "../decorators/pipes.decorators";
|
|
7
|
+
const reflector = new Reflector();
|
|
8
|
+
function enhancerKey(value) {
|
|
9
|
+
if (typeof value === "function") {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
if (value && typeof value === "object") {
|
|
13
|
+
const ctor = value.constructor;
|
|
14
|
+
if (ctor && ctor !== Object) {
|
|
15
|
+
return ctor;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
function uniqueByEnhancer(values) {
|
|
21
|
+
return values.filter((value, index, arr) => {
|
|
22
|
+
const key = enhancerKey(value);
|
|
23
|
+
return arr.findIndex((other) => enhancerKey(other) === key) === index;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function readClassAndMethodMeta(metadataKey, controller, method) {
|
|
27
|
+
const classValues = (reflector.get(metadataKey, controller) ?? []);
|
|
28
|
+
const methodValues = (reflector.get(metadataKey, controller.prototype[method]) ?? []);
|
|
29
|
+
return [...classValues, ...methodValues];
|
|
30
|
+
}
|
|
31
|
+
export function collectGuardsForRpc(controller, method, global) {
|
|
32
|
+
const local = readClassAndMethodMeta(GUARDS_KEY, controller, method);
|
|
33
|
+
return [...global, ...local];
|
|
34
|
+
}
|
|
35
|
+
export function collectInterceptorsForRpc(controller, method, global) {
|
|
36
|
+
const local = readClassAndMethodMeta(INTERCEPTORS_KEY, controller, method);
|
|
37
|
+
return uniqueByEnhancer([...global, ...local]);
|
|
38
|
+
}
|
|
39
|
+
export function collectPipesForRpc(controller, method, global) {
|
|
40
|
+
const local = readClassAndMethodMeta(PIPES_KEY, controller, method);
|
|
41
|
+
return [...global, ...local];
|
|
42
|
+
}
|
|
43
|
+
export function collectFiltersForRpc(controller, method, global) {
|
|
44
|
+
const local = readClassAndMethodMeta(FILTERS_KEY, controller, method);
|
|
45
|
+
return uniqueByEnhancer([...global, ...local]);
|
|
46
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type ConfigMap = Record<string, unknown>;
|
|
2
|
+
export declare class ConfigService<TConfig extends ConfigMap = ConfigMap> {
|
|
3
|
+
private readonly config;
|
|
4
|
+
constructor(config: TConfig);
|
|
5
|
+
getAll(): Readonly<TConfig>;
|
|
6
|
+
get<K extends keyof TConfig>(key: K): TConfig[K];
|
|
7
|
+
has(key: PropertyKey): boolean;
|
|
8
|
+
getOrThrow<K extends keyof TConfig>(key: K, message?: string): NonNullable<TConfig[K]>;
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { CONFIG_TOKEN } from "../core/config";
|
|
14
|
+
import { Inject, Injectable } from "../decorators";
|
|
15
|
+
let ConfigService = class ConfigService {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
}
|
|
19
|
+
getAll() {
|
|
20
|
+
return this.config;
|
|
21
|
+
}
|
|
22
|
+
get(key) {
|
|
23
|
+
return this.config[key];
|
|
24
|
+
}
|
|
25
|
+
has(key) {
|
|
26
|
+
return key in this.config;
|
|
27
|
+
}
|
|
28
|
+
getOrThrow(key, message) {
|
|
29
|
+
const value = this.config[key];
|
|
30
|
+
if (value === undefined || value === null) {
|
|
31
|
+
throw new Error(message ?? `Missing config key: ${String(key)}`);
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
ConfigService = __decorate([
|
|
37
|
+
Injectable(),
|
|
38
|
+
__param(0, Inject(CONFIG_TOKEN)),
|
|
39
|
+
__metadata("design:paramtypes", [Object])
|
|
40
|
+
], ConfigService);
|
|
41
|
+
export { ConfigService };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type AppLogger } from "../core/logger";
|
|
2
|
+
export declare class LoggerService {
|
|
3
|
+
private readonly logger;
|
|
4
|
+
constructor(logger: AppLogger);
|
|
5
|
+
getRawLogger(): AppLogger;
|
|
6
|
+
log(logLevelId: number, logLevelName: string, ...args: unknown[]): ({
|
|
7
|
+
[x: string]: unknown;
|
|
8
|
+
} & import("tslog").ILogObjMeta & import("tslog").ILogObj) | undefined;
|
|
9
|
+
silly(...args: unknown[]): ({
|
|
10
|
+
[x: string]: unknown;
|
|
11
|
+
} & import("tslog").ILogObjMeta) | undefined;
|
|
12
|
+
trace(...args: unknown[]): ({
|
|
13
|
+
[x: string]: unknown;
|
|
14
|
+
} & import("tslog").ILogObjMeta) | undefined;
|
|
15
|
+
debug(...args: unknown[]): ({
|
|
16
|
+
[x: string]: unknown;
|
|
17
|
+
} & import("tslog").ILogObjMeta) | undefined;
|
|
18
|
+
info(...args: unknown[]): ({
|
|
19
|
+
[x: string]: unknown;
|
|
20
|
+
} & import("tslog").ILogObjMeta) | undefined;
|
|
21
|
+
warn(...args: unknown[]): ({
|
|
22
|
+
[x: string]: unknown;
|
|
23
|
+
} & import("tslog").ILogObjMeta) | undefined;
|
|
24
|
+
error(...args: unknown[]): ({
|
|
25
|
+
[x: string]: unknown;
|
|
26
|
+
} & import("tslog").ILogObjMeta) | undefined;
|
|
27
|
+
fatal(...args: unknown[]): ({
|
|
28
|
+
[x: string]: unknown;
|
|
29
|
+
} & import("tslog").ILogObjMeta) | undefined;
|
|
30
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { LOGGER_TOKEN } from "../core/logger";
|
|
14
|
+
import { Inject, Injectable } from "../decorators";
|
|
15
|
+
let LoggerService = class LoggerService {
|
|
16
|
+
constructor(logger) {
|
|
17
|
+
this.logger = logger;
|
|
18
|
+
}
|
|
19
|
+
getRawLogger() {
|
|
20
|
+
return this.logger;
|
|
21
|
+
}
|
|
22
|
+
log(logLevelId, logLevelName, ...args) {
|
|
23
|
+
return this.logger.log(logLevelId, logLevelName, ...args);
|
|
24
|
+
}
|
|
25
|
+
silly(...args) {
|
|
26
|
+
return this.logger.silly(...args);
|
|
27
|
+
}
|
|
28
|
+
trace(...args) {
|
|
29
|
+
return this.logger.trace(...args);
|
|
30
|
+
}
|
|
31
|
+
debug(...args) {
|
|
32
|
+
return this.logger.debug(...args);
|
|
33
|
+
}
|
|
34
|
+
info(...args) {
|
|
35
|
+
return this.logger.info(...args);
|
|
36
|
+
}
|
|
37
|
+
warn(...args) {
|
|
38
|
+
return this.logger.warn(...args);
|
|
39
|
+
}
|
|
40
|
+
error(...args) {
|
|
41
|
+
return this.logger.error(...args);
|
|
42
|
+
}
|
|
43
|
+
fatal(...args) {
|
|
44
|
+
return this.logger.fatal(...args);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
LoggerService = __decorate([
|
|
48
|
+
Injectable(),
|
|
49
|
+
__param(0, Inject(LOGGER_TOKEN)),
|
|
50
|
+
__metadata("design:paramtypes", [Object])
|
|
51
|
+
], LoggerService);
|
|
52
|
+
export { LoggerService };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
|
|
2
|
+
import type { ISettingsParam } from "tslog";
|
|
3
|
+
import type { DependencyContainer, RegistrationOptions, InjectionToken as TsyringeInjectionToken } from "tsyringe";
|
|
4
|
+
import type { ZodType } from "zod";
|
|
5
|
+
export type Constructor<T = unknown> = new (...args: any[]) => T;
|
|
6
|
+
export type ContextType = "http" | "rpc";
|
|
7
|
+
export type LoggerOptions = ISettingsParam<Record<string, unknown>>;
|
|
8
|
+
export type InjectionToken<T = unknown> = TsyringeInjectionToken<T>;
|
|
9
|
+
export type MetadataKey = string | symbol;
|
|
10
|
+
export type ShutdownSignal = "SIGINT" | "SIGTERM";
|
|
11
|
+
export interface ClassProvider<T = unknown> {
|
|
12
|
+
provide: InjectionToken<T>;
|
|
13
|
+
useClass: Constructor<T>;
|
|
14
|
+
multi?: boolean;
|
|
15
|
+
options?: RegistrationOptions;
|
|
16
|
+
}
|
|
17
|
+
export interface ValueProvider<T = unknown> {
|
|
18
|
+
provide: InjectionToken<T>;
|
|
19
|
+
useValue: T;
|
|
20
|
+
multi?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface FactoryProvider<T = unknown> {
|
|
23
|
+
provide: InjectionToken<T>;
|
|
24
|
+
useFactory: (container: DependencyContainer) => T;
|
|
25
|
+
multi?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface ExistingProvider<T = unknown> {
|
|
28
|
+
provide: InjectionToken<T>;
|
|
29
|
+
useExisting: InjectionToken<T>;
|
|
30
|
+
multi?: boolean;
|
|
31
|
+
options?: RegistrationOptions;
|
|
32
|
+
}
|
|
33
|
+
export type Provider<T = unknown> = Constructor<T> | ClassProvider<T> | ValueProvider<T> | FactoryProvider<T> | ExistingProvider<T>;
|
|
34
|
+
interface BaseModuleMeta {
|
|
35
|
+
providers?: Provider[];
|
|
36
|
+
controllers?: Constructor[];
|
|
37
|
+
httpControllers?: Constructor[];
|
|
38
|
+
imports?: ModuleImport[];
|
|
39
|
+
exports?: InjectionToken[];
|
|
40
|
+
global?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface ModuleMeta extends BaseModuleMeta {
|
|
43
|
+
}
|
|
44
|
+
export interface DynamicModule extends BaseModuleMeta {
|
|
45
|
+
module: Constructor;
|
|
46
|
+
id?: string;
|
|
47
|
+
}
|
|
48
|
+
export type ModuleImport = Constructor | DynamicModule;
|
|
49
|
+
export interface OnModuleInit {
|
|
50
|
+
onModuleInit(): void | Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export interface OnApplicationBootstrap {
|
|
53
|
+
onApplicationBootstrap(): void | Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
export interface OnModuleDestroy {
|
|
56
|
+
onModuleDestroy(): void | Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
export interface BeforeApplicationShutdown {
|
|
59
|
+
beforeApplicationShutdown(signal?: string): void | Promise<void>;
|
|
60
|
+
}
|
|
61
|
+
export interface OnApplicationShutdown {
|
|
62
|
+
onApplicationShutdown(signal?: string): void | Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
export interface HttpArgumentsHost {
|
|
65
|
+
getRequest(): FastifyRequest | undefined;
|
|
66
|
+
getResponse(): FastifyReply | undefined;
|
|
67
|
+
}
|
|
68
|
+
export interface RpcArgumentsHost {
|
|
69
|
+
getData<T = unknown>(): T | undefined;
|
|
70
|
+
getContext<T = unknown>(): T | undefined;
|
|
71
|
+
}
|
|
72
|
+
export interface BaseContext {
|
|
73
|
+
type: ContextType;
|
|
74
|
+
method: string;
|
|
75
|
+
request?: Request;
|
|
76
|
+
headers?: Headers;
|
|
77
|
+
fastify?: {
|
|
78
|
+
req: FastifyRequest;
|
|
79
|
+
reply: FastifyReply;
|
|
80
|
+
};
|
|
81
|
+
rpc?: {
|
|
82
|
+
data: unknown;
|
|
83
|
+
context: unknown;
|
|
84
|
+
};
|
|
85
|
+
controller: Constructor;
|
|
86
|
+
handler: Function;
|
|
87
|
+
getType(): ContextType;
|
|
88
|
+
getClass(): Constructor;
|
|
89
|
+
getHandler(): Function;
|
|
90
|
+
switchToHttp(): HttpArgumentsHost;
|
|
91
|
+
switchToRpc(): RpcArgumentsHost;
|
|
92
|
+
}
|
|
93
|
+
export interface Guard {
|
|
94
|
+
canActivate(ctx: BaseContext): Promise<boolean> | boolean;
|
|
95
|
+
}
|
|
96
|
+
export type GuardLike = Constructor<Guard> | Guard;
|
|
97
|
+
export type NextFn = () => Promise<unknown>;
|
|
98
|
+
export interface Interceptor {
|
|
99
|
+
intercept(ctx: BaseContext, next: NextFn): Promise<unknown>;
|
|
100
|
+
}
|
|
101
|
+
export type InterceptorLike = Constructor<Interceptor> | Interceptor;
|
|
102
|
+
export interface PipeTransform<TIn = unknown, TOut = unknown> {
|
|
103
|
+
transform(value: TIn, ctx: BaseContext): Promise<TOut> | TOut;
|
|
104
|
+
}
|
|
105
|
+
export type PipeLike = Constructor<PipeTransform> | PipeTransform;
|
|
106
|
+
export interface ExceptionFilter<T = unknown> {
|
|
107
|
+
catch(exception: T, ctx: BaseContext): Promise<unknown> | unknown;
|
|
108
|
+
}
|
|
109
|
+
export type ExceptionFilterLike = Constructor<ExceptionFilter> | ExceptionFilter;
|
|
110
|
+
export interface ConfigServiceOptions<TSchema extends ZodType = ZodType> {
|
|
111
|
+
schema: TSchema;
|
|
112
|
+
source?: unknown;
|
|
113
|
+
}
|
|
114
|
+
export interface CorsOptions {
|
|
115
|
+
enabled?: boolean;
|
|
116
|
+
origin?: string | boolean | RegExp | Array<string | boolean | RegExp>;
|
|
117
|
+
credentials?: boolean;
|
|
118
|
+
exposedHeaders?: string | string[];
|
|
119
|
+
allowedHeaders?: string | string[];
|
|
120
|
+
methods?: string | string[];
|
|
121
|
+
maxAge?: number;
|
|
122
|
+
preflightContinue?: boolean;
|
|
123
|
+
optionsSuccessStatus?: number;
|
|
124
|
+
strictPreflight?: boolean;
|
|
125
|
+
}
|
|
126
|
+
export type HealthCheckResult = boolean | {
|
|
127
|
+
ok: boolean;
|
|
128
|
+
details?: unknown;
|
|
129
|
+
};
|
|
130
|
+
export type HealthCheck = () => HealthCheckResult | Promise<HealthCheckResult>;
|
|
131
|
+
export interface HealthOptions {
|
|
132
|
+
enabled?: boolean;
|
|
133
|
+
path?: string;
|
|
134
|
+
check?: HealthCheck;
|
|
135
|
+
}
|
|
136
|
+
export interface GracefulShutdownOptions {
|
|
137
|
+
enabled?: boolean;
|
|
138
|
+
signals?: ShutdownSignal[];
|
|
139
|
+
timeoutMs?: number;
|
|
140
|
+
forceExitOnFailure?: boolean;
|
|
141
|
+
}
|
|
142
|
+
export interface ServerOptions {
|
|
143
|
+
port?: number;
|
|
144
|
+
host?: string;
|
|
145
|
+
prefix?: string;
|
|
146
|
+
httpPrefix?: string;
|
|
147
|
+
rpcPrefix?: string;
|
|
148
|
+
trustProxy?: FastifyServerOptions["trustProxy"];
|
|
149
|
+
requestTimeout?: FastifyServerOptions["requestTimeout"];
|
|
150
|
+
connectionTimeout?: FastifyServerOptions["connectionTimeout"];
|
|
151
|
+
keepAliveTimeout?: FastifyServerOptions["keepAliveTimeout"];
|
|
152
|
+
bodyLimit?: FastifyServerOptions["bodyLimit"];
|
|
153
|
+
routerOptions?: FastifyServerOptions["routerOptions"];
|
|
154
|
+
/**
|
|
155
|
+
* @deprecated Use `routerOptions.maxParamLength` instead.
|
|
156
|
+
*/
|
|
157
|
+
maxParamLength?: FastifyServerOptions["maxParamLength"];
|
|
158
|
+
pluginTimeout?: FastifyServerOptions["pluginTimeout"];
|
|
159
|
+
accessLogs?: boolean;
|
|
160
|
+
exposeInternalErrors?: boolean;
|
|
161
|
+
cors?: boolean | CorsOptions;
|
|
162
|
+
health?: boolean | HealthOptions;
|
|
163
|
+
gracefulShutdown?: boolean | GracefulShutdownOptions;
|
|
164
|
+
loggerOptions?: LoggerOptions;
|
|
165
|
+
config?: ConfigServiceOptions;
|
|
166
|
+
}
|
|
167
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const appConfigSchema: z.ZodObject<{
|
|
3
|
+
APP_HOST: z.ZodDefault<z.ZodString>;
|
|
4
|
+
APP_PORT: z.ZodDefault<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>>;
|
|
5
|
+
APP_GLOBAL_PREFIX: z.ZodDefault<z.ZodString>;
|
|
6
|
+
APP_HTTP_PREFIX: z.ZodDefault<z.ZodString>;
|
|
7
|
+
APP_RPC_PREFIX: z.ZodDefault<z.ZodString>;
|
|
8
|
+
APP_ACCESS_LOGS: z.ZodDefault<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodBoolean>>;
|
|
9
|
+
APP_EXPOSE_INTERNAL_ERRORS: z.ZodDefault<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodBoolean>>;
|
|
10
|
+
MIDDLEWARE_CORS: z.ZodDefault<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodBoolean>>;
|
|
11
|
+
CORS_ALLOWED_ORIGINS: z.ZodDefault<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodArray<z.ZodString>>>;
|
|
12
|
+
CORS_ALLOWED_METHODS: z.ZodDefault<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodArray<z.ZodString>>>;
|
|
13
|
+
CORS_ALLOWED_HEADERS: z.ZodDefault<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodArray<z.ZodString>>>;
|
|
14
|
+
CORS_EXPOSE_HEADERS: z.ZodDefault<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodArray<z.ZodString>>>;
|
|
15
|
+
LOG_NAME: z.ZodDefault<z.ZodString>;
|
|
16
|
+
LOG_LEVEL: z.ZodDefault<z.ZodEnum<{
|
|
17
|
+
error: "error";
|
|
18
|
+
trace: "trace";
|
|
19
|
+
fatal: "fatal";
|
|
20
|
+
warn: "warn";
|
|
21
|
+
info: "info";
|
|
22
|
+
debug: "debug";
|
|
23
|
+
silly: "silly";
|
|
24
|
+
}>>;
|
|
25
|
+
LOG_TYPE: z.ZodDefault<z.ZodEnum<{
|
|
26
|
+
pretty: "pretty";
|
|
27
|
+
json: "json";
|
|
28
|
+
}>>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
export type AppConfig = z.infer<typeof appConfigSchema>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { booleanSchema, numberSchema, stringArraySchema } from "./common";
|
|
3
|
+
const LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
|
|
4
|
+
const LOG_TYPES = ["pretty", "json"];
|
|
5
|
+
export const appConfigSchema = z.object({
|
|
6
|
+
APP_HOST: z.string().default("0.0.0.0"),
|
|
7
|
+
APP_PORT: numberSchema()
|
|
8
|
+
.refine((value) => Number.isInteger(value) && value >= 1 && value <= 65535, {
|
|
9
|
+
message: "APP_PORT must be an integer in range 1..65535",
|
|
10
|
+
})
|
|
11
|
+
.default(8000),
|
|
12
|
+
APP_GLOBAL_PREFIX: z.string().default(""),
|
|
13
|
+
APP_HTTP_PREFIX: z.string().default(""),
|
|
14
|
+
APP_RPC_PREFIX: z.string().default(""),
|
|
15
|
+
APP_ACCESS_LOGS: booleanSchema().default(false),
|
|
16
|
+
APP_EXPOSE_INTERNAL_ERRORS: booleanSchema().default(false),
|
|
17
|
+
MIDDLEWARE_CORS: booleanSchema().default(false),
|
|
18
|
+
CORS_ALLOWED_ORIGINS: stringArraySchema(z.string()).default(["*"]),
|
|
19
|
+
CORS_ALLOWED_METHODS: stringArraySchema(z.string()).default(["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]),
|
|
20
|
+
CORS_ALLOWED_HEADERS: stringArraySchema(z.string()).default(["*"]),
|
|
21
|
+
CORS_EXPOSE_HEADERS: stringArraySchema(z.string()).default([]),
|
|
22
|
+
LOG_NAME: z.string().default("app"),
|
|
23
|
+
LOG_LEVEL: z.enum(LOG_LEVELS).default("info"),
|
|
24
|
+
LOG_TYPE: z.enum(LOG_TYPES).default("pretty"),
|
|
25
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
type NativeEnumLike = Record<string, string | number>;
|
|
3
|
+
export declare const booleanSchema: () => z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodBoolean>;
|
|
4
|
+
export declare const numberSchema: () => z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
|
|
5
|
+
export declare const nativeEnumSchema: <T extends NativeEnumLike>(enumType: T, normalize?: (value: string) => string) => z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<T>>;
|
|
6
|
+
export declare const stringArraySchema: <T extends z.ZodType>(itemSchema: T) => z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodArray<T>>;
|
|
7
|
+
export declare const enumArraySchema: <T extends NativeEnumLike>(enumType: T, normalize?: (value: string) => string) => z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodArray<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<T>>>>;
|
|
8
|
+
export {};
|